vagrant-zones 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +27 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/codeql-analysis.yml +72 -0
- data/.github/workflows/lint-release-and-publish.yml +70 -0
- data/.github/workflows/ruby-lint.yml +35 -0
- data/.gitignore +35 -0
- data/.rspec +2 -0
- data/.rubocop.yml +143 -0
- data/CHANGELOG.md +0 -0
- data/CODE_OF_CONDUCT.md +128 -0
- data/CONTRIBUTING.md +96 -0
- data/Gemfile +14 -0
- data/LICENSE +651 -0
- data/PULL_REQUEST_TEMPLATE.md +39 -0
- data/README.md +81 -0
- data/RELEASE.md +15 -0
- data/Rakefile +32 -0
- data/SECURITY.md +19 -0
- data/docs/CNAME +1 -0
- data/docs/_config.yml +1 -0
- data/docs/css/main.css +55 -0
- data/docs/css/styles.css +8678 -0
- data/docs/index.html +127 -0
- data/lib/vagrant-zones/action/create.rb +29 -0
- data/lib/vagrant-zones/action/destroy.rb +27 -0
- data/lib/vagrant-zones/action/halt.rb +24 -0
- data/lib/vagrant-zones/action/import.rb +112 -0
- data/lib/vagrant-zones/action/is_created.rb +22 -0
- data/lib/vagrant-zones/action/network.rb +26 -0
- data/lib/vagrant-zones/action/not_created.rb +20 -0
- data/lib/vagrant-zones/action/package.rb +134 -0
- data/lib/vagrant-zones/action/prepare_nfs_valid_ids.rb +24 -0
- data/lib/vagrant-zones/action/restart.rb +53 -0
- data/lib/vagrant-zones/action/setup.rb +26 -0
- data/lib/vagrant-zones/action/shutdown.rb +47 -0
- data/lib/vagrant-zones/action/start.rb +25 -0
- data/lib/vagrant-zones/action/wait_till_boot.rb +59 -0
- data/lib/vagrant-zones/action/wait_till_up.rb +65 -0
- data/lib/vagrant-zones/action.rb +204 -0
- data/lib/vagrant-zones/command/configure_snapshots.rb +49 -0
- data/lib/vagrant-zones/command/console.rb +63 -0
- data/lib/vagrant-zones/command/create_snapshots.rb +46 -0
- data/lib/vagrant-zones/command/delete_snapshots.rb +38 -0
- data/lib/vagrant-zones/command/guest_power_controls.rb +58 -0
- data/lib/vagrant-zones/command/list_snapshots.rb +44 -0
- data/lib/vagrant-zones/command/restart_guest.rb +29 -0
- data/lib/vagrant-zones/command/shutdown_guest.rb +29 -0
- data/lib/vagrant-zones/command/vnc_console.rb +48 -0
- data/lib/vagrant-zones/command/webvnc_console.rb +49 -0
- data/lib/vagrant-zones/command/zfssnapshot.rb +67 -0
- data/lib/vagrant-zones/command/zlogin_console.rb +40 -0
- data/lib/vagrant-zones/command/zone.rb +73 -0
- data/lib/vagrant-zones/config.rb +78 -0
- data/lib/vagrant-zones/driver.rb +1710 -0
- data/lib/vagrant-zones/errors.rb +61 -0
- data/lib/vagrant-zones/executor.rb +38 -0
- data/lib/vagrant-zones/plugin.rb +79 -0
- data/lib/vagrant-zones/provider.rb +83 -0
- data/lib/vagrant-zones/util/subprocess.rb +31 -0
- data/lib/vagrant-zones/util/timer.rb +19 -0
- data/lib/vagrant-zones/version.rb +7 -0
- data/lib/vagrant-zones.rb +29 -0
- data/locales/en.yml +326 -0
- data/vagrant-zones.gemspec +51 -0
- metadata +412 -0
@@ -0,0 +1,1710 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'log4r'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'digest/md5'
|
6
|
+
require 'io/console'
|
7
|
+
require 'ruby_expect'
|
8
|
+
require 'netaddr'
|
9
|
+
require 'ipaddr'
|
10
|
+
require 'vagrant/util/numeric'
|
11
|
+
require 'pty'
|
12
|
+
require 'expect'
|
13
|
+
require 'vagrant'
|
14
|
+
require 'resolv'
|
15
|
+
require 'vagrant-zones/util/timer'
|
16
|
+
require 'vagrant-zones/util/subprocess'
|
17
|
+
require 'vagrant/util/retryable'
|
18
|
+
|
19
|
+
module VagrantPlugins
|
20
|
+
module ProviderZone
|
21
|
+
# This class does the heavy lifting of the zone provider
|
22
|
+
class Driver
|
23
|
+
include Vagrant::Util::Retryable
|
24
|
+
attr_accessor :executor
|
25
|
+
|
26
|
+
def initialize(machine)
|
27
|
+
@logger = Log4r::Logger.new('vagrant_zones::driver')
|
28
|
+
@machine = machine
|
29
|
+
@executor = Executor::Exec.new
|
30
|
+
@pfexec = if Process.uid.zero?
|
31
|
+
''
|
32
|
+
elsif system('sudo -v')
|
33
|
+
'sudo'
|
34
|
+
else
|
35
|
+
'pfexec'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def state(machine)
|
40
|
+
name = machine.name
|
41
|
+
vm_state = execute(false, "#{@pfexec} zoneadm -z #{name} list -p | awk -F: '{ print $3 }'")
|
42
|
+
case vm_state
|
43
|
+
when 'running'
|
44
|
+
:running
|
45
|
+
when 'configured'
|
46
|
+
:preparing
|
47
|
+
when 'installed'
|
48
|
+
:stopped
|
49
|
+
when 'incomplete'
|
50
|
+
:incomplete
|
51
|
+
else
|
52
|
+
:not_created
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Execute System commands
|
57
|
+
def execute(*cmd, **opts, &block)
|
58
|
+
@executor.execute(*cmd, **opts, &block)
|
59
|
+
end
|
60
|
+
|
61
|
+
## Begin installation for zone
|
62
|
+
def install(uii)
|
63
|
+
config = @machine.provider_config
|
64
|
+
name = @machine.name
|
65
|
+
case config.brand
|
66
|
+
when 'lx'
|
67
|
+
box = "#{@machine.data_dir}/#{@machine.config.vm.box}"
|
68
|
+
results = execute(false, "#{@pfexec} zoneadm -z #{name} install -s #{box}")
|
69
|
+
raise Errors::InvalidLXBrand if results.include? 'unknown brand'
|
70
|
+
when 'bhyve'
|
71
|
+
results = execute(false, "#{@pfexec} zoneadm -z #{name} install")
|
72
|
+
raise Errors::InvalidbhyveBrand if results.include? 'unknown brand'
|
73
|
+
when 'kvm' || 'illumos'
|
74
|
+
raise Errors::NotYetImplemented
|
75
|
+
end
|
76
|
+
uii.info(I18n.t('vagrant_zones.installing_zone'))
|
77
|
+
uii.info(" #{config.brand}")
|
78
|
+
end
|
79
|
+
|
80
|
+
## Control the zone from inside the zone OS
|
81
|
+
def control(uii, control)
|
82
|
+
config = @machine.provider_config
|
83
|
+
uii.info(I18n.t('vagrant_zones.control')) if config.debug
|
84
|
+
case control
|
85
|
+
when 'restart'
|
86
|
+
command = 'sudo shutdown -r'
|
87
|
+
command = config.safe_restart unless config.safe_restart.nil?
|
88
|
+
ssh_run_command(uii, command)
|
89
|
+
when 'shutdown'
|
90
|
+
command = 'sudo init 0 || true'
|
91
|
+
command = config.safe_shutdown unless config.safe_shutdown.nil?
|
92
|
+
ssh_run_command(uii, command)
|
93
|
+
else
|
94
|
+
uii.info(I18n.t('vagrant_zones.control_no_cmd'))
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
## Run commands over SSH instead of ZLogin
|
99
|
+
def ssh_run_command(uii, command)
|
100
|
+
config = @machine.provider_config
|
101
|
+
ip = get_ip_address('runsshcommmand')
|
102
|
+
user = user(@machine)
|
103
|
+
key = userprivatekeypath(@machine).to_s
|
104
|
+
port = sshport(@machine).to_s
|
105
|
+
port = 22 if sshport(@machine).to_s.nil?
|
106
|
+
execute_return = ''
|
107
|
+
Util::Timer.time do
|
108
|
+
retryable(on: Errors::TimeoutError, tries: 60) do
|
109
|
+
# If we're interrupted don't worry about waiting
|
110
|
+
ssh_string = "#{@pfexec} ssh -o 'StrictHostKeyChecking=no' -p"
|
111
|
+
execute_return = execute(false, %(#{ssh_string} #{port} -i #{key} #{user}@#{ip} "#{command}"))
|
112
|
+
uii.info(I18n.t('vagrant_zones.ssh_run_command')) if config.debug
|
113
|
+
uii.info(I18n.t('vagrant_zones.ssh_run_command') + command) if config.debug
|
114
|
+
loop do
|
115
|
+
break if @machine.communicate.ready?
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
execute_return
|
120
|
+
end
|
121
|
+
|
122
|
+
## Function to provide console, vnc, or webvnc access
|
123
|
+
## Future To-Do: Should probably split this up
|
124
|
+
def console(uii, command, ip, port, exit)
|
125
|
+
uii.info(I18n.t('vagrant_zones.console'))
|
126
|
+
detach = exit[:detach]
|
127
|
+
kill = exit[:kill]
|
128
|
+
name = @machine.name
|
129
|
+
config = @machine.provider_config
|
130
|
+
if port.nil?
|
131
|
+
port = if config.consoleport.nil?
|
132
|
+
''
|
133
|
+
else
|
134
|
+
config.consoleport
|
135
|
+
end
|
136
|
+
end
|
137
|
+
ipaddr = '0.0.0.0'
|
138
|
+
ipaddr = config.consolehost if config.consolehost =~ Resolv::IPv4::Regex
|
139
|
+
ipaddr = ip if ip =~ Resolv::IPv4::Regex
|
140
|
+
netport = "#{ipaddr}:#{port}"
|
141
|
+
pid = 0
|
142
|
+
if File.exist?("#{name}.pid")
|
143
|
+
pid = File.readlines("#{name}.pid")[0].strip
|
144
|
+
ctype = File.readlines("#{name}.pid")[1].strip
|
145
|
+
ts = File.readlines("#{name}.pid")[2].strip
|
146
|
+
vmname = File.readlines("#{name}.pid")[3].strip
|
147
|
+
nport = File.readlines("#{name}.pid")[4].strip
|
148
|
+
uii.info("Session running with PID: #{pid} since: #{ts} as console type: #{ctype} served at: #{nport}\n") if vmname[name.to_s]
|
149
|
+
if kill == 'yes'
|
150
|
+
File.delete("#{name}.pid")
|
151
|
+
Process.kill 'TERM', pid.to_i
|
152
|
+
Process.detach pid.to_i
|
153
|
+
uii.info('Session Terminated')
|
154
|
+
end
|
155
|
+
else
|
156
|
+
case command
|
157
|
+
when /vnc/
|
158
|
+
run = "pfexec zadm #{command} #{netport} #{name}"
|
159
|
+
pid = spawn(run)
|
160
|
+
Process.wait pid if detach == 'no'
|
161
|
+
Process.detach(pid) if detach == 'yes'
|
162
|
+
time = Time.new.strftime('%Y-%m-%d-%H:%M:%S')
|
163
|
+
File.write("#{name}.pid", "#{pid}\n#{command}\n#{time}\n#{name}\n#{netport}") if detach == 'yes'
|
164
|
+
uii.info("Session running with PID: #{pid} as console type: #{command} served at: #{netport}") if detach == 'yes'
|
165
|
+
when 'zlogin'
|
166
|
+
run = "#{@pfexec} zadm console #{name}"
|
167
|
+
exec(run)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
## Boot the Machine
|
173
|
+
def boot(uii)
|
174
|
+
name = @machine.name
|
175
|
+
uii.info(I18n.t('vagrant_zones.starting_zone'))
|
176
|
+
execute(false, "#{@pfexec} zoneadm -z #{name} boot")
|
177
|
+
end
|
178
|
+
|
179
|
+
# This filters the VM usage for VNIC Naming Purposes
|
180
|
+
def vtype(uii)
|
181
|
+
config = @machine.provider_config
|
182
|
+
uii.info(I18n.t('vagrant_zones.vtype')) if config.debug
|
183
|
+
case config.vm_type
|
184
|
+
when /template/
|
185
|
+
'1'
|
186
|
+
when /development/
|
187
|
+
'2'
|
188
|
+
when /production/ || nil
|
189
|
+
'3'
|
190
|
+
when /firewall/
|
191
|
+
'4'
|
192
|
+
when /other/
|
193
|
+
'5'
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# This filters the NIC Types
|
198
|
+
def nictype(opts)
|
199
|
+
case opts[:nictype]
|
200
|
+
when /external/ || nil
|
201
|
+
'e'
|
202
|
+
when /internal/
|
203
|
+
'i'
|
204
|
+
when /carp/
|
205
|
+
'c'
|
206
|
+
when /management/
|
207
|
+
'm'
|
208
|
+
when /host/
|
209
|
+
'h'
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# This Sanitizes the DNS Records
|
214
|
+
def dnsservers(uii)
|
215
|
+
config = @machine.provider_config
|
216
|
+
servers = []
|
217
|
+
config.dns.each do |server|
|
218
|
+
servers.append(server)
|
219
|
+
end
|
220
|
+
servers = [{ 'nameserver' => '1.1.1.1' }, { 'nameserver' => '8.8.8.8' }] if config.dns.nil?
|
221
|
+
uii.info(I18n.t('vagrant_zones.nsservers') + servers.to_s) if config.debug
|
222
|
+
servers
|
223
|
+
end
|
224
|
+
|
225
|
+
# This Sanitizes the Mac Address
|
226
|
+
def macaddress(uii, opts)
|
227
|
+
config = @machine.provider_config
|
228
|
+
regex = /^(?:[[:xdigit:]]{2}([-:]))(?:[[:xdigit:]]{2}\1){4}[[:xdigit:]]{2}$/
|
229
|
+
mac = opts[:mac] unless opts[:mac].nil?
|
230
|
+
mac = 'auto' unless mac.match(regex)
|
231
|
+
uii.info(I18n.t('vagrant_zones.mac') + mac) if config.debug
|
232
|
+
mac
|
233
|
+
end
|
234
|
+
|
235
|
+
# This Sanitizes the IP Address to set
|
236
|
+
def ipaddress(uii, opts)
|
237
|
+
config = @machine.provider_config
|
238
|
+
ip = if opts[:ip].empty?
|
239
|
+
nil
|
240
|
+
else
|
241
|
+
opts[:ip].gsub(/\t/, '')
|
242
|
+
end
|
243
|
+
uii.info(I18n.t('vagrant_zones.ipaddress') + ip) if config.debug
|
244
|
+
ip
|
245
|
+
end
|
246
|
+
|
247
|
+
# This Sanitizes the AllowedIP Address to set for Cloudinit
|
248
|
+
def allowedaddress(uii, opts)
|
249
|
+
config = @machine.provider_config
|
250
|
+
ip = ipaddress(uii, opts)
|
251
|
+
shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
|
252
|
+
allowed_address = "#{ip}/#{shrtsubnet}"
|
253
|
+
uii.info(I18n.t('vagrant_zones.allowedaddress') + allowed_address) if config.debug
|
254
|
+
allowed_address
|
255
|
+
end
|
256
|
+
|
257
|
+
# This Sanitizes the VNIC Name
|
258
|
+
def vname(uii, opts)
|
259
|
+
config = @machine.provider_config
|
260
|
+
vnic_name = "vnic#{nictype(opts)}#{vtype(uii)}_#{config.partition_id}_#{opts[:nic_number]}"
|
261
|
+
uii.info(I18n.t('vagrant_zones.vnic_name') + vnic_name) if config.debug
|
262
|
+
vnic_name
|
263
|
+
end
|
264
|
+
|
265
|
+
## If DHCP and Zlogin, get the IP address
|
266
|
+
def get_ip_address(_function)
|
267
|
+
config = @machine.provider_config
|
268
|
+
name = @machine.name
|
269
|
+
# uii.info(I18n.t('vagrant_zones.get_ip_address')) if config.debug
|
270
|
+
@machine.config.vm.networks.each do |_adaptertype, opts|
|
271
|
+
responses = []
|
272
|
+
nic_type = nictype(opts)
|
273
|
+
if opts[:dhcp] && opts[:managed]
|
274
|
+
vnic_name = "vnic#{nic_type}#{vtype(uii)}_#{config.partition_id}_#{opts[:nic_number]}"
|
275
|
+
PTY.spawn("pfexec zlogin -C #{name}") do |zlogin_read, zlogin_write, pid|
|
276
|
+
command = "ip -4 addr show dev #{vnic_name} | head -n -1 | tail -1 | awk '{ print $2 }' | cut -f1 -d\"/\" \n"
|
277
|
+
zlogin_read.expect(/\n/) { zlogin_write.printf(command) }
|
278
|
+
Timeout.timeout(config.clean_shutdown_time) do
|
279
|
+
loop do
|
280
|
+
zlogin_read.expect(/\r\n/) { |line| responses.push line }
|
281
|
+
if responses[-1].to_s.match(/(?:[0-9]{1,3}\.){3}[0-9]{1,3}/)
|
282
|
+
ip = responses[-1][0].rstrip.gsub(/\e\[\?2004l/, '').lstrip
|
283
|
+
return nil if ip.empty?
|
284
|
+
return ip.gsub(/\t/, '') unless ip.empty?
|
285
|
+
|
286
|
+
break
|
287
|
+
end
|
288
|
+
errormessage = "==> #{name} ==> Command ==> #{cmd} \nFailed with ==> #{responses[-1]}"
|
289
|
+
raise errormessage if responses[-1].to_s.match(/Error Code: \b(?!0\b)\d{1,4}\b/)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
Process.kill('HUP', pid)
|
293
|
+
end
|
294
|
+
elsif (opts[:dhcp] == false || opts[:dhcp].nil?) && opts[:managed]
|
295
|
+
ip = opts[:ip].to_s
|
296
|
+
return nil if ip.empty?
|
297
|
+
|
298
|
+
return ip.gsub(/\t/, '')
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
## Manage Network Interfaces
|
304
|
+
def network(uii, state)
|
305
|
+
config = @machine.provider_config
|
306
|
+
uii.info(I18n.t('vagrant_zones.creating_networking_interfaces')) if state == 'create'
|
307
|
+
@machine.config.vm.networks.each do |adaptertype, opts|
|
308
|
+
case adaptertype.to_s
|
309
|
+
when 'public_network'
|
310
|
+
zonenicdel(uii, opts) if state == 'delete'
|
311
|
+
zonecfgnicconfig(uii, opts) if state == 'config'
|
312
|
+
zoneniccreate(uii, opts) if state == 'create'
|
313
|
+
zonenicstpzloginsetup(uii, opts, config) if state == 'setup' && config.setup_method == 'zlogin'
|
314
|
+
when 'private_network'
|
315
|
+
zonenicdel(uii, opts) if state == 'delete'
|
316
|
+
zonedhcpentriesrem(uii, opts) if state == 'delete'
|
317
|
+
zonenatclean(uii, opts) if state == 'delete'
|
318
|
+
etherstubdelhvnic(uii, opts) if state == 'delete'
|
319
|
+
etherstubdelete(uii, opts) if state == 'delete'
|
320
|
+
natnicconfig(uii, opts) if state == 'config'
|
321
|
+
etherstub = etherstubcreate(uii, opts) if state == 'create'
|
322
|
+
zonenatniccreate(uii, opts, etherstub) if state == 'create'
|
323
|
+
etherstubcreatehvnic(uii, opts, etherstub) if state == 'create'
|
324
|
+
zonenatforward(uii, opts) if state == 'create'
|
325
|
+
zonenatentries(uii, opts) if state == 'create'
|
326
|
+
zonedhcpentries(uii, opts) if state == 'create'
|
327
|
+
zonedhcpcheckaddr(uii, opts) if state == 'setup'
|
328
|
+
zonenicnatsetup(uii, opts) if state == 'setup'
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
## Delete DHCP entries for Zones
|
334
|
+
def zonedhcpentriesrem(uii, opts)
|
335
|
+
config = @machine.provider_config
|
336
|
+
|
337
|
+
ip = ipaddress(uii, opts)
|
338
|
+
name = @machine.name
|
339
|
+
defrouter = opts[:gateway].to_s
|
340
|
+
shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
|
341
|
+
hvnic_name = "h_vnic_#{config.partition_id}_#{opts[:nic_number]}"
|
342
|
+
mac = macaddress(uii, opts)
|
343
|
+
|
344
|
+
## if mac is auto, then grab NIC from VNIC
|
345
|
+
if mac == 'auto'
|
346
|
+
mac = ''
|
347
|
+
cmd = "#{@pfexec} dladm show-vnic #{hvnic_name} | tail -n +2 | awk '{ print $4 }'"
|
348
|
+
vnicmac = execute(false, cmd.to_s)
|
349
|
+
vnicmac.split(':').each { |x| mac += "#{format('%02x', x.to_i(16))}:" }
|
350
|
+
mac = mac[0..-2]
|
351
|
+
end
|
352
|
+
uii.info(I18n.t('vagrant_zones.deconfiguring_dhcp'))
|
353
|
+
uii.info(" #{hvnic_name}")
|
354
|
+
broadcast = IPAddr.new(defrouter).mask(shrtsubnet).to_s
|
355
|
+
subnet = %(subnet #{broadcast} netmask #{opts[:netmask]} { option routers #{defrouter}; })
|
356
|
+
subnetopts = %(host #{name} { option host-name "#{name}"; hardware ethernet #{mac}; fixed-address #{ip}; })
|
357
|
+
File.open('/etc/dhcpd.conf-temp', 'w') do |out_file|
|
358
|
+
File.foreach('/etc/dhcpd.conf') do |entry|
|
359
|
+
out_file.puts line unless entry == subnet || subnetopts
|
360
|
+
end
|
361
|
+
end
|
362
|
+
FileUtils.mv('/etc/dhcpd.conf-temp', '/etc/dhcpd.conf')
|
363
|
+
subawk = '{ $1=""; $2=""; sub(/^[ \\t]+/, ""); print}'
|
364
|
+
awk = %(| awk '#{subawk}' | tr ' ' '\\n' | tr -d '"')
|
365
|
+
cmd = 'svccfg -s dhcp:ipv4 listprop config/listen_ifnames '
|
366
|
+
nicsused = execute(false, cmd + awk.to_s).split("\n")
|
367
|
+
newdhcpnics = []
|
368
|
+
nicsused.each do |nic|
|
369
|
+
newdhcpnics << nic unless nic.to_s == hvnic_name.to_s
|
370
|
+
end
|
371
|
+
if newdhcpnics.empty?
|
372
|
+
dhcpcmdnewstr = '\(\"\"\)'
|
373
|
+
else
|
374
|
+
dhcpcmdnewstr = '\('
|
375
|
+
newdhcpnics.each do |nic|
|
376
|
+
dhcpcmdnewstr += %(\\"#{nic}\\")
|
377
|
+
end
|
378
|
+
dhcpcmdnewstr += '\)'
|
379
|
+
end
|
380
|
+
execute(false, "#{@pfexec} svccfg -s dhcp:ipv4 setprop config/listen_ifnames = #{dhcpcmdnewstr}")
|
381
|
+
execute(false, "#{@pfexec} svcadm refresh dhcp:ipv4")
|
382
|
+
execute(false, "#{@pfexec} svcadm disable dhcp:ipv4")
|
383
|
+
execute(false, "#{@pfexec} svcadm enable dhcp:ipv4")
|
384
|
+
end
|
385
|
+
|
386
|
+
def zonenatclean(uii, opts)
|
387
|
+
vnic_name = vname(uii, opts)
|
388
|
+
defrouter = opts[:gateway].to_s
|
389
|
+
shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
|
390
|
+
broadcast = IPAddr.new(defrouter).mask(shrtsubnet).to_s
|
391
|
+
uii.info(I18n.t('vagrant_zones.deconfiguring_nat'))
|
392
|
+
uii.info(" #{vnic_name}")
|
393
|
+
line1 = %(map #{opts[:bridge]} #{broadcast}/#{shrtsubnet} -> 0/32 portmap tcp/udp auto)
|
394
|
+
line2 = %(map #{opts[:bridge]} #{broadcast}/#{shrtsubnet} -> 0/32)
|
395
|
+
File.open('/etc/ipf/ipnat.conf-temp', 'w') do |out_file|
|
396
|
+
File.foreach('/etc/ipf/ipnat.conf') do |entry|
|
397
|
+
out_file.puts line unless entry == line1 || line2
|
398
|
+
end
|
399
|
+
end
|
400
|
+
FileUtils.mv('/etc/ipf/ipnat.conf-temp', '/etc/ipf/ipnat.conf')
|
401
|
+
execute(false, "#{@pfexec} svcadm refresh network/ipfilter")
|
402
|
+
end
|
403
|
+
|
404
|
+
def zonenicdel(uii, opts)
|
405
|
+
vnic_name = vname(uii, opts)
|
406
|
+
vnic_configured = execute(false, "#{@pfexec} dladm show-vnic | grep #{vnic_name} | awk '{ print $1 }' ")
|
407
|
+
uii.info(I18n.t('vagrant_zones.removing_vnic')) if vnic_configured == vnic_name.to_s
|
408
|
+
uii.info(" #{vnic_name}") if vnic_configured == vnic_name.to_s
|
409
|
+
execute(false, "#{@pfexec} dladm delete-vnic #{vnic_name}") if vnic_configured == vnic_name.to_s
|
410
|
+
uii.info(I18n.t('vagrant_zones.no_removing_vnic')) unless vnic_configured == vnic_name.to_s
|
411
|
+
end
|
412
|
+
|
413
|
+
## Delete etherstubs vnic
|
414
|
+
def etherstubdelhvnic(uii, opts)
|
415
|
+
config = @machine.provider_config
|
416
|
+
hvnic_name = "h_vnic_#{config.partition_id}_#{opts[:nic_number]}"
|
417
|
+
vnic_configured = execute(false, "#{@pfexec} dladm show-vnic | grep #{hvnic_name} | awk '{ print $1 }' ")
|
418
|
+
uii.info(I18n.t('vagrant_zones.removing_host_vnic')) if vnic_configured == hvnic_name.to_s
|
419
|
+
uii.info(" #{hvnic_name}") if vnic_configured == hvnic_name.to_s
|
420
|
+
execute(false, "#{@pfexec} ipadm delete-if #{hvnic_name}") if vnic_configured == hvnic_name.to_s
|
421
|
+
execute(false, "#{@pfexec} dladm delete-vnic #{hvnic_name}") if vnic_configured == hvnic_name.to_s
|
422
|
+
uii.info(I18n.t('vagrant_zones.no_removing_host_vnic')) unless vnic_configured == hvnic_name.to_s
|
423
|
+
end
|
424
|
+
|
425
|
+
## Delete etherstubs
|
426
|
+
def etherstubdelete(uii, opts)
|
427
|
+
config = @machine.provider_config
|
428
|
+
ether_name = "stub_#{config.partition_id}_#{opts[:nic_number]}"
|
429
|
+
ether_configured = execute(false, "#{@pfexec} dladm show-etherstub | grep #{ether_name} | awk '{ print $1 }' ")
|
430
|
+
uii.info(I18n.t('vagrant_zones.delete_ethervnic')) if ether_configured == ether_name
|
431
|
+
uii.info(" #{ether_name}") if ether_configured == ether_name
|
432
|
+
uii.info(I18n.t('vagrant_zones.no_delete_ethervnic')) unless ether_configured == ether_name
|
433
|
+
execute(false, "#{@pfexec} dladm delete-etherstub #{ether_name}") if ether_configured == ether_name
|
434
|
+
end
|
435
|
+
|
436
|
+
## Create etherstubs for Zones
|
437
|
+
def etherstubcreate(uii, opts)
|
438
|
+
config = @machine.provider_config
|
439
|
+
ether_name = "stub_#{config.partition_id}_#{opts[:nic_number]}"
|
440
|
+
ether_configured = execute(false, "#{@pfexec} dladm show-etherstub | grep #{ether_name} | awk '{ print $1 }' ")
|
441
|
+
uii.info(I18n.t('vagrant_zones.creating_etherstub')) unless ether_configured == ether_name
|
442
|
+
uii.info(" #{ether_name}") unless ether_configured == ether_name
|
443
|
+
execute(false, "#{@pfexec} dladm create-etherstub #{ether_name}") unless ether_configured == ether_name
|
444
|
+
ether_name
|
445
|
+
end
|
446
|
+
|
447
|
+
## Create ethervnics for Zones
|
448
|
+
def zonenatniccreate(uii, opts, etherstub)
|
449
|
+
vnic_name = vname(uii, opts)
|
450
|
+
mac = macaddress(uii, opts)
|
451
|
+
uii.info(I18n.t('vagrant_zones.creating_ethervnic'))
|
452
|
+
uii.info(" #{vnic_name}")
|
453
|
+
execute(false, "#{@pfexec} dladm create-vnic -l #{etherstub} -m #{mac} #{vnic_name}")
|
454
|
+
end
|
455
|
+
|
456
|
+
## Create Host VNIC on etherstubs for IP for Zones DHCP
|
457
|
+
def etherstubcreatehvnic(uii, opts, etherstub)
|
458
|
+
config = @machine.provider_config
|
459
|
+
defrouter = opts[:gateway].to_s
|
460
|
+
shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
|
461
|
+
hvnic_name = "h_vnic_#{config.partition_id}_#{opts[:nic_number]}"
|
462
|
+
uii.info(I18n.t('vagrant_zones.creating_etherhostvnic'))
|
463
|
+
uii.info(" #{hvnic_name}")
|
464
|
+
execute(false, "#{@pfexec} dladm create-vnic -l #{etherstub} #{hvnic_name}")
|
465
|
+
execute(false, "#{@pfexec} ipadm create-if #{hvnic_name}")
|
466
|
+
execute(false, "#{@pfexec} ipadm create-addr -T static -a local=#{defrouter}/#{shrtsubnet} #{hvnic_name}/v4")
|
467
|
+
end
|
468
|
+
|
469
|
+
## Setup vnics for Zones using nat/dhcp
|
470
|
+
def zonenicnatsetup(uii, opts)
|
471
|
+
config = @machine.provider_config
|
472
|
+
return if config.cloud_init_enabled
|
473
|
+
|
474
|
+
vnic_name = vname(uii, opts)
|
475
|
+
mac = macaddress(uii, opts)
|
476
|
+
## if mac is auto, then grab NIC from VNIC
|
477
|
+
if mac == 'auto'
|
478
|
+
mac = ''
|
479
|
+
cmd = "#{@pfexec} dladm show-vnic #{vnic_name} | tail -n +2 | awk '{ print $4 }'"
|
480
|
+
vnicmac = execute(false, cmd.to_s)
|
481
|
+
vnicmac.split(':').each { |x| mac += "#{format('%02x', x.to_i(16))}:" }
|
482
|
+
mac = mac[0..-2]
|
483
|
+
end
|
484
|
+
|
485
|
+
## Code Block to Detect OS
|
486
|
+
uii.info(I18n.t('vagrant_zones.os_detect'))
|
487
|
+
cmd = 'uname -a'
|
488
|
+
os_type = config.os_type
|
489
|
+
uii.info("Zone OS configured as: #{os_type}")
|
490
|
+
os_detected = ssh_run_command(uii, cmd.to_s)
|
491
|
+
uii.info("Zone OS detected as: #{os_detected}")
|
492
|
+
|
493
|
+
## Check if Ansible is Installed to enable easier configuration
|
494
|
+
uii.info(I18n.t('vagrant_zones.ansible_detect'))
|
495
|
+
cmd = 'which ansible > /dev/null 2>&1 ; echo $?'
|
496
|
+
ansible_detected = ssh_run_command(uii, cmd.to_s)
|
497
|
+
uii.info('Ansible detected') if ansible_detected == '0'
|
498
|
+
|
499
|
+
# Run Network Configuration
|
500
|
+
zonenicnatsetup_netplan(uii, opts, mac) unless os_detected.to_s.match(/SunOS/)
|
501
|
+
zonenicnatsetup_dladm(uii, opts, mac) if os_detected.to_s.match(/SunOS/)
|
502
|
+
end
|
503
|
+
|
504
|
+
## Setup vnics for Zones using nat/dhcp using netplan
|
505
|
+
def zonenicnatsetup_netplan(uii, opts, mac)
|
506
|
+
ssh_run_command(uii, 'sudo rm -rf /etc/netplan/*.yaml')
|
507
|
+
ip = ipaddress(uii, opts)
|
508
|
+
defrouter = opts[:gateway].to_s
|
509
|
+
vnic_name = vname(uii, opts)
|
510
|
+
shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
|
511
|
+
servers = dnsservers(uii)
|
512
|
+
## Begin of code block to move to Netplan function
|
513
|
+
uii.info(I18n.t('vagrant_zones.configure_interface_using_vnic'))
|
514
|
+
uii.info(" #{vnic_name}")
|
515
|
+
|
516
|
+
netplan1 = %(network:\n version: 2\n ethernets:\n #{vnic_name}:\n match:\n macaddress: #{mac}\n)
|
517
|
+
netplan2 = %( dhcp-identifier: mac\n dhcp4: #{opts[:dhcp]}\n dhcp6: #{opts[:dhcp6]}\n)
|
518
|
+
netplan3 = %( set-name: #{vnic_name}\n addresses: [#{ip}/#{shrtsubnet}]\n gateway4: #{defrouter}\n)
|
519
|
+
netplan4 = %( nameservers:\n addresses: [#{servers[0]['nameserver']} , #{servers[1]['nameserver']}] )
|
520
|
+
netplan = netplan1 + netplan2 + netplan3 + netplan4
|
521
|
+
cmd = "echo -e '#{netplan}' | sudo tee /etc/netplan/#{vnic_name}.yaml"
|
522
|
+
infomessage = I18n.t('vagrant_zones.netplan_applied_static') + "/etc/netplan/#{vnic_name}.yaml"
|
523
|
+
uii.info(infomessage) if ssh_run_command(uii, cmd)
|
524
|
+
|
525
|
+
## Apply the Configuration
|
526
|
+
uii.info(I18n.t('vagrant_zones.netplan_applied')) if ssh_run_command(uii, 'sudo netplan apply')
|
527
|
+
## End of code block to move to Netplan function
|
528
|
+
end
|
529
|
+
|
530
|
+
## Setup vnics for Zones using nat/dhcp over dladm
|
531
|
+
def zonenicnatsetup_dladm(uii, opts, mac)
|
532
|
+
ip = ipaddress(uii, opts)
|
533
|
+
defrouter = opts[:gateway].to_s
|
534
|
+
vnic_name = vname(uii, opts)
|
535
|
+
shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
|
536
|
+
servers = dnsservers(uii)
|
537
|
+
uii.info(I18n.t('vagrant_zones.configure_interface_using_vnic_dladm'))
|
538
|
+
uii.info(" #{vnic_name}")
|
539
|
+
|
540
|
+
# loop through each phys if and run code if physif matches #{mac}
|
541
|
+
phys_if = 'pfexec dladm show-phys -m -o LINK,ADDRESS,CLIENT | tail -n +2'
|
542
|
+
phys_if_results = ssh_run_command(uii, phys_if).split("\n")
|
543
|
+
device = ''
|
544
|
+
phys_if_results.each do |entry|
|
545
|
+
e_mac = ''
|
546
|
+
entries = entry.strip.split
|
547
|
+
entries[1].split(':').each { |x| e_mac += "#{format('%02x', x.to_i(16))}:" }
|
548
|
+
e_mac = e_mac[0..-2]
|
549
|
+
device = entries[0] if e_mac.match(/#{mac}/)
|
550
|
+
end
|
551
|
+
|
552
|
+
delete_if = "pfexec ipadm delete-if #{device}"
|
553
|
+
rename_link = "pfexec dladm rename-link #{device} #{vnic_name}"
|
554
|
+
if_create = "pfexec ipadm create-if #{vnic_name}"
|
555
|
+
static_addr = "pfexec ipadm create-addr -T static -a #{ip}/#{shrtsubnet} #{vnic_name}/v4vagrant"
|
556
|
+
net_cmd = "#{delete_if} && #{rename_link} && #{if_create} && #{static_addr}"
|
557
|
+
uii.info(I18n.t('vagrant_zones.dladm_applied')) if ssh_run_command(uii, net_cmd)
|
558
|
+
|
559
|
+
route_add = "pfexec route -p add default #{defrouter}"
|
560
|
+
uii.info(I18n.t('vagrant_zones.dladm_route_applied')) if ssh_run_command(uii, route_add)
|
561
|
+
|
562
|
+
ns_string = "nameserver #{servers[0]['nameserver']}\nnameserver #{servers[1]['nameserver']}"
|
563
|
+
dns_set = "pfexec echo '#{ns_string}' | pfexec tee /etc/resolv.conf"
|
564
|
+
uii.info(I18n.t('vagrant_zones.dladm_dns_applied')) if ssh_run_command(uii, dns_set.to_s)
|
565
|
+
end
|
566
|
+
|
567
|
+
## zonecfg function for for nat Networking
|
568
|
+
def natnicconfig(uii, opts)
|
569
|
+
config = @machine.provider_config
|
570
|
+
allowed_address = allowedaddress(uii, opts)
|
571
|
+
defrouter = opts[:gateway].to_s
|
572
|
+
vnic_name = vname(uii, opts)
|
573
|
+
uii.info(I18n.t('vagrant_zones.nat_vnic_setup'))
|
574
|
+
uii.info(" #{vnic_name}")
|
575
|
+
strt = "#{@pfexec} zonecfg -z #{@machine.name} "
|
576
|
+
cie = config.cloud_init_enabled
|
577
|
+
case config.brand
|
578
|
+
when 'lx'
|
579
|
+
shrtstr1 = %(set allowed-address=#{allowed_address}; add property (name=gateway,value="#{defrouter}"); )
|
580
|
+
shrtstr2 = %(add property (name=ips,value="#{allowed_address}"); add property (name=primary,value="true"); end;)
|
581
|
+
execute(false, %(#{strt}set global-nic=auto; #{shrtstr1} #{shrtstr2}"))
|
582
|
+
when 'bhyve'
|
583
|
+
execute(false, %(#{strt}"add net; set physical=#{vnic_name}; end;")) unless cie
|
584
|
+
execute(false, %(#{strt}"add net; set physical=#{vnic_name}; set allowed-address=#{allowed_address}; end;")) if cie
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
## Set NatForwarding on global interface
|
589
|
+
def zonenatforward(uii, opts)
|
590
|
+
config = @machine.provider_config
|
591
|
+
hvnic_name = "h_vnic_#{config.partition_id}_#{opts[:nic_number]}"
|
592
|
+
uii.info(I18n.t('vagrant_zones.forwarding_nat'))
|
593
|
+
uii.info(" #{hvnic_name}")
|
594
|
+
execute(false, "#{@pfexec} routeadm -u -e ipv4-forwarding")
|
595
|
+
execute(false, "#{@pfexec} ipadm set-ifprop -p forwarding=on -m ipv4 #{opts[:bridge]}")
|
596
|
+
execute(false, "#{@pfexec} ipadm set-ifprop -p forwarding=on -m ipv4 #{hvnic_name}")
|
597
|
+
end
|
598
|
+
|
599
|
+
## Create nat entries for the zone
|
600
|
+
def zonenatentries(uii, opts)
|
601
|
+
vnic_name = vname(uii, opts)
|
602
|
+
defrouter = opts[:gateway].to_s
|
603
|
+
shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
|
604
|
+
uii.info(I18n.t('vagrant_zones.configuring_nat'))
|
605
|
+
uii.info(" #{vnic_name}")
|
606
|
+
broadcast = IPAddr.new(defrouter).mask(shrtsubnet).to_s
|
607
|
+
## Read NAT File, Check for these lines, if exist, warn, but continue
|
608
|
+
natentries = execute(false, "#{@pfexec} cat /etc/ipf/ipnat.conf").split("\n")
|
609
|
+
line1 = %(map #{opts[:bridge]} #{broadcast}/#{shrtsubnet} -> 0/32 portmap tcp/udp auto)
|
610
|
+
line2 = %(map #{opts[:bridge]} #{broadcast}/#{shrtsubnet} -> 0/32)
|
611
|
+
line1exists = false
|
612
|
+
line2exists = false
|
613
|
+
natentries.each do |entry|
|
614
|
+
line1exists = true if entry == line1
|
615
|
+
line2exists = true if entry == line2
|
616
|
+
end
|
617
|
+
execute(false, %(#{@pfexec} echo "#{line1}" | #{@pfexec} tee -a /etc/ipf/ipnat.conf)) unless line1exists
|
618
|
+
execute(false, %(#{@pfexec} echo "#{line2}" | #{@pfexec} tee -a /etc/ipf/ipnat.conf)) unless line2exists
|
619
|
+
execute(false, "#{@pfexec} svcadm refresh network/ipfilter")
|
620
|
+
execute(false, "#{@pfexec} svcadm disable network/ipfilter")
|
621
|
+
execute(false, "#{@pfexec} svcadm enable network/ipfilter")
|
622
|
+
end
|
623
|
+
|
624
|
+
## Create dhcp entries for the zone
|
625
|
+
def zonedhcpentries(uii, opts)
|
626
|
+
config = @machine.provider_config
|
627
|
+
ip = ipaddress(uii, opts)
|
628
|
+
name = @machine.name
|
629
|
+
vnic_name = vname(uii, opts)
|
630
|
+
defrouter = opts[:gateway].to_s
|
631
|
+
shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
|
632
|
+
hvnic_name = "h_vnic_#{config.partition_id}_#{opts[:nic_number]}"
|
633
|
+
## Set Mac address from VNIC
|
634
|
+
mac = macaddress(uii, opts)
|
635
|
+
if mac == 'auto'
|
636
|
+
mac = ''
|
637
|
+
cmd = "#{@pfexec} dladm show-vnic #{vnic_name} | tail -n +2 | awk '{ print $4 }'"
|
638
|
+
vnicmac = execute(false, cmd.to_s)
|
639
|
+
vnicmac.split(':').each { |x| mac += "#{format('%02x', x.to_i(16))}:" }
|
640
|
+
mac = mac[0..-2]
|
641
|
+
end
|
642
|
+
uii.info(I18n.t('vagrant_zones.configuring_dhcp'))
|
643
|
+
broadcast = IPAddr.new(defrouter).mask(shrtsubnet).to_s
|
644
|
+
dhcpentries = execute(false, "#{@pfexec} cat /etc/dhcpd.conf").split("\n")
|
645
|
+
subnet = %(subnet #{broadcast} netmask #{opts[:netmask]} { option routers #{defrouter}; })
|
646
|
+
subnetopts = %(host #{name} { option host-name "#{name}"; hardware ethernet #{mac}; fixed-address #{ip}; })
|
647
|
+
subnetexists = false
|
648
|
+
subnetoptsexists = false
|
649
|
+
dhcpentries.each do |entry|
|
650
|
+
subnetexists = true if entry == subnet
|
651
|
+
subnetoptsexists = true if entry == subnetopts
|
652
|
+
end
|
653
|
+
execute(false, "#{@pfexec} echo '#{subnet}' | #{@pfexec} tee -a /etc/dhcpd.conf") unless subnetexists
|
654
|
+
execute(false, "#{@pfexec} echo '#{subnetopts}' | #{@pfexec} tee -a /etc/dhcpd.conf") unless subnetoptsexists
|
655
|
+
execute(false, "#{@pfexec} svccfg -s dhcp:ipv4 setprop config/listen_ifnames = #{hvnic_name}")
|
656
|
+
execute(false, "#{@pfexec} svcadm refresh dhcp:ipv4")
|
657
|
+
execute(false, "#{@pfexec} svcadm disable dhcp:ipv4")
|
658
|
+
execute(false, "#{@pfexec} svcadm enable dhcp:ipv4")
|
659
|
+
end
|
660
|
+
|
661
|
+
## Check if Address shows up in lease list /var/db/dhcpd ping address after
|
662
|
+
def zonedhcpcheckaddr(uii, opts)
|
663
|
+
# vnic_name = vname(uii, opts)
|
664
|
+
# ip = ipaddress(uii, opts)
|
665
|
+
uii.info(I18n.t('vagrant_zones.chk_dhcp_addr'))
|
666
|
+
uii.info(" #{opts[:ip]}")
|
667
|
+
# execute(false, "#{@pfexec} ping #{ip} ")
|
668
|
+
end
|
669
|
+
|
670
|
+
## Create vnics for Zones
|
671
|
+
def zoneniccreate(uii, opts)
|
672
|
+
mac = macaddress(uii, opts)
|
673
|
+
vnic_name = vname(uii, opts)
|
674
|
+
if opts[:vlan].nil?
|
675
|
+
uii.info(I18n.t('vagrant_zones.creating_vnic'))
|
676
|
+
uii.info(" #{vnic_name}")
|
677
|
+
execute(false, "#{@pfexec} dladm create-vnic -l #{opts[:bridge]} -m #{mac} #{vnic_name}")
|
678
|
+
else
|
679
|
+
vlan = opts[:vlan]
|
680
|
+
uii.info(I18n.t('vagrant_zones.creating_vnic'))
|
681
|
+
uii.info(" #{vnic_name}")
|
682
|
+
execute(false, "#{@pfexec} dladm create-vnic -l #{opts[:bridge]} -m #{mac} -v #{vlan} #{vnic_name}")
|
683
|
+
end
|
684
|
+
end
|
685
|
+
|
686
|
+
# This helps us create all the datasets for the zone
|
687
|
+
def create_dataset(uii)
|
688
|
+
config = @machine.provider_config
|
689
|
+
name = @machine.name
|
690
|
+
bootconfigs = config.boot
|
691
|
+
datasetpath = "#{bootconfigs['array']}/#{bootconfigs['dataset']}/#{name}"
|
692
|
+
datasetroot = "#{datasetpath}/#{bootconfigs['volume_name']}"
|
693
|
+
sparse = '-s '
|
694
|
+
sparse = '' unless bootconfigs['sparse']
|
695
|
+
refres = "-o refreservation=#{bootconfigs['refreservation']}" unless bootconfigs['refreservation'].nil?
|
696
|
+
refres = '-o refreservation=none' if bootconfigs['refreservation'] == 'none' || bootconfigs['refreservation'].nil?
|
697
|
+
uii.info(I18n.t('vagrant_zones.begin_create_datasets'))
|
698
|
+
## Create Boot Volume
|
699
|
+
case config.brand
|
700
|
+
when 'lx'
|
701
|
+
uii.info(I18n.t('vagrant_zones.lx_zone_dataset'))
|
702
|
+
uii.info(" #{datasetroot}")
|
703
|
+
execute(false, "#{@pfexec} zfs create -o zoned=on -p #{datasetroot}")
|
704
|
+
when 'bhyve'
|
705
|
+
## Create root dataset
|
706
|
+
uii.info(I18n.t('vagrant_zones.bhyve_zone_dataset_root'))
|
707
|
+
uii.info(" #{datasetpath}")
|
708
|
+
execute(false, "#{@pfexec} zfs create #{datasetpath}")
|
709
|
+
|
710
|
+
# Create boot volume
|
711
|
+
cinfo = "#{datasetroot}, #{bootconfigs['size']}"
|
712
|
+
uii.info(I18n.t('vagrant_zones.bhyve_zone_dataset_boot'))
|
713
|
+
uii.info(" #{cinfo}")
|
714
|
+
execute(false, "#{@pfexec} zfs create #{sparse} #{refres} -V #{bootconfigs['size']} #{datasetroot}")
|
715
|
+
|
716
|
+
## Import template to boot volume
|
717
|
+
commandtransfer = "#{@pfexec} pv -n #{@machine.box.directory.join('box.zss')} | #{@pfexec} zfs recv -u -v -F #{datasetroot} "
|
718
|
+
uii.info(I18n.t('vagrant_zones.template_import_path'))
|
719
|
+
uii.info(" #{@machine.box.directory.join('box.zss')}")
|
720
|
+
Util::Subprocess.new commandtransfer do |_stdout, stderr, _thread|
|
721
|
+
uii.rewriting do |uiprogress|
|
722
|
+
uiprogress.clear_line
|
723
|
+
uiprogress.info(I18n.t('vagrant_zones.importing_box_image_to_disk') + "#{datasetroot} ", new_line: false)
|
724
|
+
uiprogress.report_progress(stderr, 100, false)
|
725
|
+
end
|
726
|
+
end
|
727
|
+
uii.clear_line
|
728
|
+
when 'illumos' || 'kvm'
|
729
|
+
raise Errors::NotYetImplemented
|
730
|
+
else
|
731
|
+
raise Errors::InvalidBrand
|
732
|
+
end
|
733
|
+
## Create Additional Disks
|
734
|
+
return if config.additional_disks.nil?
|
735
|
+
|
736
|
+
config.additional_disks.each do |disk|
|
737
|
+
shrtpath = "#{disk['array']}/#{disk['dataset']}/#{name}"
|
738
|
+
dataset = "#{shrtpath}/#{disk['volume_name']}"
|
739
|
+
sparse = '-s '
|
740
|
+
sparse = '' unless disk['sparse']
|
741
|
+
refres = "-o refreservation=#{bootconfigs['refreservation']}" unless bootconfigs['refreservation'].nil?
|
742
|
+
refres = '-o refreservation=none' if bootconfigs['refreservation'] == 'none' || bootconfigs['refreservation'].nil?
|
743
|
+
## If the root data set doesn't exist create it
|
744
|
+
addsrtexists = execute(false, "#{@pfexec} zfs list | grep #{shrtpath} | awk '{ print $1 }' | head -n 1 || true")
|
745
|
+
cinfo = shrtpath.to_s
|
746
|
+
uii.info(I18n.t('vagrant_zones.bhyve_zone_dataset_additional_volume_root')) unless addsrtexists == shrtpath.to_s
|
747
|
+
uii.info(" #{cinfo}") unless addsrtexists == shrtpath.to_s
|
748
|
+
## Create the Additional volume
|
749
|
+
execute(false, "#{@pfexec} zfs create #{shrtpath}") unless addsrtexists == shrtpath.to_s
|
750
|
+
cinfo = "#{dataset}, #{disk['size']}"
|
751
|
+
uii.info(I18n.t('vagrant_zones.bhyve_zone_dataset_additional_volume'))
|
752
|
+
uii.info(" #{cinfo}")
|
753
|
+
execute(false, "#{@pfexec} zfs create #{sparse} #{refres} -V #{disk['size']} #{dataset}")
|
754
|
+
end
|
755
|
+
end
|
756
|
+
|
757
|
+
# This helps us delete any associated datasets of the zone
|
758
|
+
## Future To-Do: Should probably split this up and clean it up
|
759
|
+
def delete_dataset(uii)
|
760
|
+
config = @machine.provider_config
|
761
|
+
name = @machine.name
|
762
|
+
# datadir = machine.data_dir
|
763
|
+
bootconfigs = config.boot
|
764
|
+
datasetpath = "#{bootconfigs['array']}/#{bootconfigs['dataset']}/#{name}"
|
765
|
+
datasetroot = "#{datasetpath}/#{bootconfigs['volume_name']}"
|
766
|
+
uii.info(I18n.t('vagrant_zones.delete_disks'))
|
767
|
+
|
768
|
+
## Check if Boot Dataset exists
|
769
|
+
zp = datasetpath.delete_prefix('/').to_s
|
770
|
+
dataset_boot_exists = execute(false, "#{@pfexec} zfs list | grep #{datasetroot} | awk '{ print $1 }' || true")
|
771
|
+
|
772
|
+
## Destroy Boot dataset
|
773
|
+
uii.info(I18n.t('vagrant_zones.destroy_dataset')) if dataset_boot_exists == datasetroot.to_s
|
774
|
+
uii.info(" #{datasetroot}") if dataset_boot_exists == datasetroot.to_s
|
775
|
+
execute(false, "#{@pfexec} zfs destroy -r #{datasetroot}") if dataset_boot_exists == datasetroot.to_s
|
776
|
+
## Insert Error Checking Here in case disk is busy
|
777
|
+
uii.info(I18n.t('vagrant_zones.boot_dataset_nil')) unless dataset_boot_exists == datasetroot.to_s
|
778
|
+
|
779
|
+
## Destroy Additional Disks
|
780
|
+
unless config.additional_disks.nil?
|
781
|
+
disks = config.additional_disks
|
782
|
+
disks.each do |disk|
|
783
|
+
diskpath = "#{disk['array']}/#{disk['dataset']}/#{name}"
|
784
|
+
addataset = "#{diskpath}/#{disk['volume_name']}"
|
785
|
+
cinfo = addataset.to_s
|
786
|
+
dataset_exists = execute(false, "#{@pfexec} zfs list | grep #{addataset} | awk '{ print $1 }' || true")
|
787
|
+
uii.info(I18n.t('vagrant_zones.bhyve_zone_dataset_additional_volume_destroy')) if dataset_exists == addataset
|
788
|
+
uii.info(" #{cinfo}") if dataset_exists == addataset
|
789
|
+
execute(false, "#{@pfexec} zfs destroy -r #{addataset}") if dataset_exists == addataset
|
790
|
+
uii.info(I18n.t('vagrant_zones.additional_dataset_nil')) unless dataset_exists == addataset
|
791
|
+
cinfo = diskpath.to_s
|
792
|
+
addsrtexists = execute(false, "#{@pfexec} zfs list | grep #{diskpath} | awk '{ print $1 }' | head -n 1 || true")
|
793
|
+
uii.info(I18n.t('vagrant_zones.addtl_volume_destroy_root')) if addsrtexists == diskpath && addsrtexists != zp.to_s
|
794
|
+
uii.info(" #{cinfo}") if addsrtexists == diskpath && addsrtexists != zp.to_s
|
795
|
+
execute(false, "#{@pfexec} zfs destroy -r #{diskpath}") if addsrtexists == diskpath && addsrtexists != zp.to_s
|
796
|
+
end
|
797
|
+
end
|
798
|
+
|
799
|
+
## Check if root dataset exists
|
800
|
+
dataset_root_exists = execute(false, "#{@pfexec} zfs list | grep #{zp} | awk '{ print $1 }' | grep -v path || true")
|
801
|
+
uii.info(I18n.t('vagrant_zones.destroy_root_dataset')) if dataset_root_exists == zp.to_s
|
802
|
+
uii.info(" #{zp}") if dataset_root_exists == zp.to_s
|
803
|
+
execute(false, "#{@pfexec} zfs destroy -r #{zp}") if dataset_root_exists == zp.to_s
|
804
|
+
uii.info(I18n.t('vagrant_zones.root_dataset_nil')) unless dataset_root_exists == zp.to_s
|
805
|
+
end
|
806
|
+
|
807
|
+
## zonecfg function for bhyve
|
808
|
+
def zonecfgbhyve(uii, name, config, zcfg)
|
809
|
+
return unless config.brand == 'bhyve'
|
810
|
+
|
811
|
+
bootconfigs = config.boot
|
812
|
+
datasetpath = "#{bootconfigs['array']}/#{bootconfigs['dataset']}/#{name}"
|
813
|
+
datasetroot = "#{datasetpath}/#{bootconfigs['volume_name']}"
|
814
|
+
execute(false, %(#{zcfg}"create ; set zonepath=/#{datasetpath}/path"))
|
815
|
+
execute(false, %(#{zcfg}"set brand=#{config.brand}"))
|
816
|
+
execute(false, %(#{zcfg}"set autoboot=#{config.autoboot}"))
|
817
|
+
execute(false, %(#{zcfg}"set ip-type=exclusive"))
|
818
|
+
execute(false, %(#{zcfg}"add attr; set name=acpi; set value=#{config.acpi}; set type=string; end;"))
|
819
|
+
execute(false, %(#{zcfg}"add attr; set name=ram; set value=#{config.memory}; set type=string; end;"))
|
820
|
+
execute(false, %(#{zcfg}"add attr; set name=bootrom; set value=#{firmware(uii)}; set type=string; end;"))
|
821
|
+
execute(false, %(#{zcfg}"add attr; set name=hostbridge; set value=#{config.hostbridge}; set type=string; end;"))
|
822
|
+
execute(false, %(#{zcfg}"add attr; set name=diskif; set value=#{config.diskif}; set type=string; end;"))
|
823
|
+
execute(false, %(#{zcfg}"add attr; set name=netif; set value=#{config.netif}; set type=string; end;"))
|
824
|
+
execute(false, %(#{zcfg}"add attr; set name=bootdisk; set value=#{datasetroot.delete_prefix('/')}; set type=string; end;"))
|
825
|
+
execute(false, %(#{zcfg}"add attr; set name=type; set value=#{config.os_type}; set type=string; end;"))
|
826
|
+
execute(false, %(#{zcfg}"add attr; set name=xhci; set value=#{config.xhci_enabled}; set type=string; end;"))
|
827
|
+
execute(false, %(#{zcfg}"add device; set match=/dev/zvol/rdsk/#{datasetroot}; end;"))
|
828
|
+
uii.info(I18n.t('vagrant_zones.bhyve_zone_config_gen'))
|
829
|
+
end
|
830
|
+
|
831
|
+
## zonecfg function for lx
|
832
|
+
def zonecfglx(uii, name, config, zcfg)
|
833
|
+
return unless config.brand == 'lx'
|
834
|
+
|
835
|
+
datasetpath = "#{config.boot['array']}/#{config.boot['dataset']}/#{name}"
|
836
|
+
datasetroot = "#{datasetpath}/#{config.boot['volume_name']}"
|
837
|
+
uii.info(I18n.t('vagrant_zones.lx_zone_config_gen'))
|
838
|
+
@machine.config.vm.networks.each do |adaptertype, opts|
|
839
|
+
next unless adaptertype.to_s == 'public_network'
|
840
|
+
|
841
|
+
@ip = opts[:ip].to_s
|
842
|
+
cinfo = "#{opts[:ip]}/#{opts[:netmask]}"
|
843
|
+
@network = NetAddr.parse_net(cinfo)
|
844
|
+
@defrouter = opts[:gateway]
|
845
|
+
end
|
846
|
+
execute(false, %(#{zcfg}"create ; set zonepath=/#{datasetpath}/path"))
|
847
|
+
execute(false, %(#{zcfg}"set brand=#{config.brand}"))
|
848
|
+
execute(false, %(#{zcfg}"set autoboot=#{config.autoboot}"))
|
849
|
+
execute(false, %(#{zcfg}"add attr; set name=kernel-version; set value=#{config.kernel}; set type=string; end;"))
|
850
|
+
cmss = ' add capped-memory; set physical='
|
851
|
+
execute(false, %(#{zcfg + cmss}"#{config.memory}; set swap=#{config.kernel}; set locked=#{config.memory}; end;"))
|
852
|
+
execute(false, %(#{zcfg}"add dataset; set name=#{datasetroot}; end;"))
|
853
|
+
execute(false, %(#{zcfg}"set max-lwps=2000"))
|
854
|
+
end
|
855
|
+
|
856
|
+
## zonecfg function for KVM
|
857
|
+
def zonecfgkvm(uii, name, config, _zcfg)
|
858
|
+
return unless config.brand == 'kvm'
|
859
|
+
|
860
|
+
bootconfigs = config.boot
|
861
|
+
config = @machine.provider_config
|
862
|
+
datasetpath = "#{bootconfigs['array']}/#{bootconfigs['dataset']}/#{name}"
|
863
|
+
datasetroot = "#{datasetpath}/#{bootconfigs['volume_name']}"
|
864
|
+
uii.info(datasetroot) if config.debug
|
865
|
+
###### RESERVED ######
|
866
|
+
end
|
867
|
+
|
868
|
+
## zonecfg function for Shared Disk Configurations
|
869
|
+
def zonecfgshareddisks(uii, _name, config, zcfg)
|
870
|
+
return unless config.shared_disk_enabled
|
871
|
+
|
872
|
+
uii.info(I18n.t('vagrant_zones.setting_alt_shared_disk_configurations') + path.path)
|
873
|
+
execute(false, %(#{zcfg}"add fs; set dir=/vagrant; set special=#{config.shared_dir}; set type=lofs; end;"))
|
874
|
+
end
|
875
|
+
|
876
|
+
## zonecfg function for CPU Configurations
|
877
|
+
def zonecfgcpu(uii, _name, config, zcfg)
|
878
|
+
uii.info(I18n.t('vagrant_zones.zonecfgcpu')) if config.debug
|
879
|
+
if config.cpu_configuration == 'simple' && (config.brand == 'bhyve' || config.brand == 'kvm')
|
880
|
+
execute(false, %(#{zcfg}"add attr; set name=vcpus; set value=#{config.cpus}; set type=string; end;"))
|
881
|
+
elsif config.cpu_configuration == 'complex' && (config.brand == 'bhyve' || config.brand == 'kvm')
|
882
|
+
hash = config.complex_cpu_conf[0]
|
883
|
+
cstring = %(sockets=#{hash['sockets']},cores=#{hash['cores']},threads=#{hash['threads']})
|
884
|
+
execute(false, %(#{zcfg}'add attr; set name=vcpus; set value="#{cstring}"; set type=string; end;'))
|
885
|
+
end
|
886
|
+
end
|
887
|
+
|
888
|
+
## zonecfg function for CDROM Configurations
|
889
|
+
def zonecfgcdrom(uii, _name, config, zcfg)
|
890
|
+
return if config.cdroms.nil?
|
891
|
+
|
892
|
+
cdroms = config.cdroms
|
893
|
+
cdrun = 0
|
894
|
+
cdroms.each do |cdrom|
|
895
|
+
cdname = 'cdrom'
|
896
|
+
uii.info(I18n.t('vagrant_zones.setting_cd_rom_configurations'))
|
897
|
+
uii.info(" #{cdrom['path']}")
|
898
|
+
cdname += cdrun.to_s if cdrun.positive?
|
899
|
+
cdrun += 1
|
900
|
+
shrtstrng = 'set type=lofs; add options nodevices; add options ro; end;'
|
901
|
+
execute(false, %(#{zcfg}"add attr; set name=#{cdname}; set value=#{cdrom['path']}; set type=string; end;"))
|
902
|
+
execute(false, %(#{zcfg}"add fs; set dir=#{cdrom['path']}; set special=#{cdrom['path']}; #{shrtstrng}"))
|
903
|
+
end
|
904
|
+
end
|
905
|
+
|
906
|
+
## zonecfg function for PCI Configurations
|
907
|
+
def zonecfgpci(uii, _name, config, _zcfg)
|
908
|
+
return if config.debug
|
909
|
+
|
910
|
+
uii.info(I18n.t('vagrant_zones.pci')) if config.debug
|
911
|
+
##### RESERVED
|
912
|
+
end
|
913
|
+
|
914
|
+
## zonecfg function for AdditionalDisks
|
915
|
+
def zonecfgadditionaldisks(uii, name, config, zcfg)
|
916
|
+
return if config.additional_disks.nil?
|
917
|
+
|
918
|
+
diskrun = 0
|
919
|
+
config.additional_disks.each do |disk|
|
920
|
+
diskname = 'disk'
|
921
|
+
dset = "#{disk['array']}/#{disk['dataset']}/#{name}/#{disk['volume_name']}"
|
922
|
+
cinfo = "#{dset}, #{disk['size']}"
|
923
|
+
uii.info(I18n.t('vagrant_zones.setting_additional_disks_configurations'))
|
924
|
+
uii.info(" #{cinfo}")
|
925
|
+
diskname += diskrun.to_s if diskrun.positive?
|
926
|
+
diskrun += 1
|
927
|
+
execute(false, %(#{zcfg}"add device; set match=/dev/zvol/rdsk/#{dset}; end;"))
|
928
|
+
execute(false, %(#{zcfg}"add attr; set name=#{diskname}; set value=#{dset}; set type=string; end;"))
|
929
|
+
end
|
930
|
+
end
|
931
|
+
|
932
|
+
## zonecfg function for Console Access
|
933
|
+
def zonecfgconsole(uii, _name, config, zcfg)
|
934
|
+
return if config.console.nil? || config.console == 'disabled'
|
935
|
+
|
936
|
+
port = if %w[console].include?(config.console) && config.consoleport.nil?
|
937
|
+
'socket,/tmp/vm.com1'
|
938
|
+
elsif %w[webvnc].include?(config.console) || %w[vnc].include?(config.console)
|
939
|
+
config.console = 'vnc'
|
940
|
+
'on'
|
941
|
+
else
|
942
|
+
config.consoleport
|
943
|
+
end
|
944
|
+
port += ',wait' if config.console_onboot
|
945
|
+
cp = config.consoleport
|
946
|
+
ch = config.consolehost
|
947
|
+
cb = config.console_onboot
|
948
|
+
ct = config.console
|
949
|
+
cinfo = "Console type: #{ct}, State: #{port}, Port: #{cp}, Host: #{ch}, Wait: #{cb}"
|
950
|
+
uii.info(I18n.t('vagrant_zones.setting_console_access'))
|
951
|
+
uii.info(" #{cinfo}")
|
952
|
+
execute(false, %(#{zcfg}"add attr; set name=#{ct}; set value=#{port}; set type=string; end;"))
|
953
|
+
end
|
954
|
+
|
955
|
+
## zonecfg function for Cloud-init
|
956
|
+
def zonecfgcloudinit(uii, _name, config, zcfg)
|
957
|
+
return unless config.cloud_init_enabled
|
958
|
+
|
959
|
+
cloudconfig = 'on' if config.cloud_init_conf.nil?
|
960
|
+
cloudconfig = config.cloud_init_conf.to_s unless config.cloud_init_conf.nil?
|
961
|
+
|
962
|
+
uii.info(I18n.t('vagrant_zones.setting_cloud_init_access'))
|
963
|
+
execute(false, %(#{zcfg}"add attr; set name=cloud-init; set value=#{cloudconfig}; set type=string; end;"))
|
964
|
+
|
965
|
+
ccid = config.cloud_init_dnsdomain
|
966
|
+
uii.info(I18n.t('vagrant_zones.setting_cloud_dnsdomain')) unless ccid.nil?
|
967
|
+
uii.info(" #{ccid}") unless ccid.nil?
|
968
|
+
execute(false, %(#{zcfg}"add attr; set name=dns-domain; set value=#{ccid}; set type=string; end;")) unless ccid.nil?
|
969
|
+
|
970
|
+
ccip = config.cloud_init_password
|
971
|
+
uii.info(I18n.t('vagrant_zones.setting_cloud_password')) unless ccip.nil?
|
972
|
+
uii.info(" #{ccip}") unless ccip.nil?
|
973
|
+
execute(false, %(#{zcfg}"add attr; set name=password; set value=#{ccip}; set type=string; end;")) unless ccip.nil?
|
974
|
+
|
975
|
+
cclir = config.cloud_init_resolvers
|
976
|
+
uii.info(I18n.t('vagrant_zones.setting_cloud_resolvers')) unless cclir.nil?
|
977
|
+
uii.info(" #{cclir}") unless cclir.nil?
|
978
|
+
execute(false, %(#{zcfg}"add attr; set name=resolvers; set value=#{cclir}; set type=string; end;")) unless cclir.nil?
|
979
|
+
|
980
|
+
ccisk = config.cloud_init_sshkey
|
981
|
+
uii.info(I18n.t('vagrant_zones.setting_cloud_ssh_key')) unless ccisk.nil?
|
982
|
+
uii.info(" #{ccisk}") unless ccisk.nil?
|
983
|
+
execute(false, %(#{zcfg}"add attr; set name=sshkey; set value=#{ccisk}; set type=string; end;")) unless ccisk.nil?
|
984
|
+
end
|
985
|
+
|
986
|
+
## zonecfg function for for Networking
|
987
|
+
def zonecfgnicconfig(uii, opts)
|
988
|
+
allowed_address = allowedaddress(uii, opts)
|
989
|
+
defrouter = opts[:gateway].to_s
|
990
|
+
vnic_name = vname(uii, opts)
|
991
|
+
config = @machine.provider_config
|
992
|
+
uii.info(I18n.t('vagrant_zones.vnic_setup'))
|
993
|
+
uii.info(" #{vnic_name}")
|
994
|
+
strt = "#{@pfexec} zonecfg -z #{@machine.name} "
|
995
|
+
cie = config.cloud_init_enabled
|
996
|
+
aa = config.allowed_address
|
997
|
+
case config.brand
|
998
|
+
when 'lx'
|
999
|
+
shrtstr1 = %(set allowed-address=#{allowed_address}; add property (name=gateway,value="#{defrouter}"); )
|
1000
|
+
shrtstr2 = %(add property (name=ips,value="#{allowed_address}"); add property (name=primary,value="true"); end;)
|
1001
|
+
execute(false, %(#{strt}set global-nic=auto; #{shrtstr1} #{shrtstr2}"))
|
1002
|
+
when 'bhyve'
|
1003
|
+
execute(false, %(#{strt}"add net; set physical=#{vnic_name}; end;")) unless cie
|
1004
|
+
execute(false, %(#{strt}"add net; set physical=#{vnic_name}; set allowed-address=#{allowed_address}; end;")) if cie && aa
|
1005
|
+
execute(false, %(#{strt}"add net; set physical=#{vnic_name}; end;")) if cie && !aa
|
1006
|
+
end
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
# This helps us set the zone configurations for the zone
|
1010
|
+
def zonecfg(uii)
|
1011
|
+
name = @machine.name
|
1012
|
+
config = @machine.provider_config
|
1013
|
+
zcfg = "#{@pfexec} zonecfg -z #{name} "
|
1014
|
+
## Create LX zonecfg
|
1015
|
+
zonecfglx(uii, name, config, zcfg)
|
1016
|
+
## Create bhyve zonecfg
|
1017
|
+
zonecfgbhyve(uii, name, config, zcfg)
|
1018
|
+
## Create kvm zonecfg
|
1019
|
+
zonecfgkvm(uii, name, config, zcfg)
|
1020
|
+
## Shared Disk Configurations
|
1021
|
+
zonecfgshareddisks(uii, name, config, zcfg)
|
1022
|
+
## CPU Configurations
|
1023
|
+
zonecfgcpu(uii, name, config, zcfg)
|
1024
|
+
## CDROM Configurations
|
1025
|
+
zonecfgcdrom(uii, name, config, zcfg)
|
1026
|
+
### Passthrough PCI Devices
|
1027
|
+
zonecfgpci(uii, name, config, zcfg)
|
1028
|
+
## Additional Disk Configurations
|
1029
|
+
zonecfgadditionaldisks(uii, name, config, zcfg)
|
1030
|
+
## Console access configuration
|
1031
|
+
zonecfgconsole(uii, name, config, zcfg)
|
1032
|
+
## Cloud-init settings
|
1033
|
+
zonecfgcloudinit(uii, name, config, zcfg)
|
1034
|
+
## Nic Configurations
|
1035
|
+
network(uii, 'config')
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
## Setup vnics for Zones using Zlogin
|
1039
|
+
def zonenicstpzloginsetup(uii, opts, config)
|
1040
|
+
vnic_name = vname(uii, opts)
|
1041
|
+
mac = macaddress(uii, opts)
|
1042
|
+
## if mac is auto, then grab NIC from VNIC
|
1043
|
+
if mac == 'auto'
|
1044
|
+
mac = ''
|
1045
|
+
cmd = "#{@pfexec} dladm show-vnic #{vnic_name} | tail -n +2 | awk '{ print $4 }'"
|
1046
|
+
vnicmac = execute(false, cmd.to_s)
|
1047
|
+
vnicmac.split(':').each { |x| mac += "#{format('%02x', x.to_i(16))}:" }
|
1048
|
+
mac = mac[0..-2]
|
1049
|
+
end
|
1050
|
+
|
1051
|
+
zoneniczloginsetup_windows(uii, opts, mac) if config.os_type.to_s.match(/windows/)
|
1052
|
+
zoneniczloginsetup_netplan(uii, opts, mac) unless config.os_type.to_s.match(/windows/)
|
1053
|
+
end
|
1054
|
+
|
1055
|
+
## This setups the Netplan based OS Networking via Zlogin
|
1056
|
+
def zoneniczloginsetup_netplan(uii, opts, mac)
|
1057
|
+
zlogin(uii, 'rm -rf /etc/netplan/*.yaml')
|
1058
|
+
ip = ipaddress(uii, opts)
|
1059
|
+
vnic_name = vname(uii, opts)
|
1060
|
+
servers = dnsservers(uii)
|
1061
|
+
shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
|
1062
|
+
defrouter = opts[:gateway].to_s
|
1063
|
+
uii.info(I18n.t('vagrant_zones.configure_interface_using_vnic'))
|
1064
|
+
uii.info(" #{vnic_name}")
|
1065
|
+
netplan1 = %(network:\n version: 2\n ethernets:\n #{vnic_name}:\n match:\n macaddress: #{mac}\n)
|
1066
|
+
netplan2 = %( dhcp-identifier: mac\n dhcp4: #{opts[:dhcp]}\n dhcp6: #{opts[:dhcp6]}\n)
|
1067
|
+
netplan3 = %( set-name: #{vnic_name}\n addresses: [#{ip}/#{shrtsubnet}]\n gateway4: #{defrouter}\n)
|
1068
|
+
netplan4 = %( nameservers:\n addresses: [#{servers[0]['nameserver']} , #{servers[1]['nameserver']}] )
|
1069
|
+
netplan = netplan1 + netplan2 + netplan3 + netplan4
|
1070
|
+
cmd = "echo '#{netplan}' > /etc/netplan/#{vnic_name}.yaml"
|
1071
|
+
infomessage = I18n.t('vagrant_zones.netplan_applied_static') + "/etc/netplan/#{vnic_name}.yaml"
|
1072
|
+
uii.info(infomessage) if zlogin(uii, cmd)
|
1073
|
+
## Apply the Configuration
|
1074
|
+
uii.info(I18n.t('vagrant_zones.netplan_applied')) if zlogin(uii, 'netplan apply')
|
1075
|
+
end
|
1076
|
+
|
1077
|
+
# This ensures the zone is safe to boot
|
1078
|
+
def check_zone_support(uii)
|
1079
|
+
uii.info(I18n.t('vagrant_zones.preflight_checks'))
|
1080
|
+
config = @machine.provider_config
|
1081
|
+
## Detect if Virtualbox is Running
|
1082
|
+
## LX, KVM, and Bhyve cannot run conncurently with Virtualbox:
|
1083
|
+
### https://illumos.topicbox-beta.com/groups/omnios-discuss/Tce3bbd08cace5349-M5fc864e9c1a7585b94a7c080
|
1084
|
+
uii.info(I18n.t('vagrant_zones.vbox_run_check'))
|
1085
|
+
result = execute(true, "#{@pfexec} VBoxManage list runningvms")
|
1086
|
+
raise Errors::VirtualBoxRunningConflictDetected if result.zero?
|
1087
|
+
|
1088
|
+
## https://man.omnios.org/man5/brands
|
1089
|
+
case config.brand
|
1090
|
+
when 'lx'
|
1091
|
+
uii.info(I18n.t('vagrant_zones.lx_check'))
|
1092
|
+
when 'ipkg'
|
1093
|
+
uii.info(I18n.t('vagrant_zones.ipkg_check'))
|
1094
|
+
when 'lipkg'
|
1095
|
+
uii.info(I18n.t('vagrant_zones.lipkg_check'))
|
1096
|
+
when 'pkgsrc'
|
1097
|
+
uii.info(I18n.t('vagrant_zones.pkgsrc_check'))
|
1098
|
+
when 'sparse'
|
1099
|
+
uii.info(I18n.t('vagrant_zones.sparse_check'))
|
1100
|
+
when 'kvm'
|
1101
|
+
## https://man.omnios.org/man5/kvm
|
1102
|
+
uii.info(I18n.t('vagrant_zones.kvm_check'))
|
1103
|
+
when 'illumos'
|
1104
|
+
uii.info(I18n.t('vagrant_zones.illumos_check'))
|
1105
|
+
when 'bhyve'
|
1106
|
+
## https://man.omnios.org/man5/bhyve
|
1107
|
+
## Check for bhhwcompat
|
1108
|
+
result = execute(true, "#{@pfexec} test -f /usr/sbin/bhhwcompat ; echo $?")
|
1109
|
+
if result == 1
|
1110
|
+
bhhwcompaturl = 'https://downloads.omnios.org/misc/bhyve/bhhwcompat'
|
1111
|
+
execute(true, "#{@pfexec} curl -o /usr/sbin/bhhwcompat #{bhhwcompaturl} && #{@pfexec} chmod +x /usr/sbin/bhhwcompat")
|
1112
|
+
result = execute(true, "#{@pfexec} test -f /usr/sbin/bhhwcompat ; echo $?")
|
1113
|
+
raise Errors::MissingCompatCheckTool if result.zero?
|
1114
|
+
end
|
1115
|
+
|
1116
|
+
# Check whether OmniOS version is lower than r30
|
1117
|
+
cutoff_release = '1510380'
|
1118
|
+
cutoff_release = cutoff_release[0..-2].to_i
|
1119
|
+
uii.info(I18n.t('vagrant_zones.bhyve_check'))
|
1120
|
+
uii.info(" #{cutoff_release}")
|
1121
|
+
release = File.open('/etc/release', &:readline)
|
1122
|
+
release = release.scan(/\w+/).values_at(-1)
|
1123
|
+
release = release[0][1..-2].to_i
|
1124
|
+
raise Errors::SystemVersionIsTooLow if release < cutoff_release
|
1125
|
+
|
1126
|
+
# Check Bhyve compatability
|
1127
|
+
uii.info(I18n.t('vagrant_zones.bhyve_compat_check'))
|
1128
|
+
result = execute(false, "#{@pfexec} bhhwcompat -s")
|
1129
|
+
raise Errors::MissingBhyve if result.length == 1
|
1130
|
+
end
|
1131
|
+
end
|
1132
|
+
|
1133
|
+
# This helps us set up the networking of the VM
|
1134
|
+
def setup(uii)
|
1135
|
+
config = @machine.provider_config
|
1136
|
+
uii.info(I18n.t('vagrant_zones.network_setup')) if config.brand && !config.cloud_init_enabled
|
1137
|
+
network(uii, 'setup') if config.brand == 'bhyve' && !config.cloud_init_enabled
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
## this allows us a terminal to pass commands and manipulate the VM OS via serial/tty
|
1141
|
+
def zloginboot(uii)
|
1142
|
+
name = @machine.name
|
1143
|
+
config = @machine.provider_config
|
1144
|
+
lcheck = config.lcheck
|
1145
|
+
lcheck = ':~' if config.lcheck.nil?
|
1146
|
+
alcheck = config.alcheck
|
1147
|
+
alcheck = 'login:' if config.alcheck.nil?
|
1148
|
+
bstring = ' OK ' if config.booted_string.nil?
|
1149
|
+
bstring = config.booted_string unless config.booted_string.nil?
|
1150
|
+
zunlockboot = 'Importing ZFS root pool'
|
1151
|
+
zunlockbootkey = config.zunlockbootkey unless config.zunlockbootkey.nil?
|
1152
|
+
pcheck = 'Password:'
|
1153
|
+
uii.info(I18n.t('vagrant_zones.automated-zlogin'))
|
1154
|
+
PTY.spawn("pfexec zlogin -C #{name}") do |zlogin_read, zlogin_write, pid|
|
1155
|
+
Timeout.timeout(config.setup_wait) do
|
1156
|
+
rsp = []
|
1157
|
+
|
1158
|
+
loop do
|
1159
|
+
zlogin_read.expect(/\r\n/) { |line| rsp.push line }
|
1160
|
+
uii.info(rsp[-1]) if config.debug_boot
|
1161
|
+
sleep(2) if rsp[-1].to_s.match(/#{zunlockboot}/)
|
1162
|
+
zlogin_write.printf("#{zunlockbootkey}\n") if rsp[-1].to_s.match(/#{zunlockboot}/)
|
1163
|
+
zlogin_write.printf("\n") if rsp[-1].to_s.match(/#{zunlockboot}/)
|
1164
|
+
uii.info(I18n.t('vagrant_zones.automated-zbootunlock')) if rsp[-1].to_s.match(/#{zunlockboot}/)
|
1165
|
+
sleep(15) if rsp[-1].to_s.match(/#{bstring}/)
|
1166
|
+
zlogin_write.printf("\n") if rsp[-1].to_s.match(/#{bstring}/)
|
1167
|
+
break if rsp[-1].to_s.match(/#{bstring}/)
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
if zlogin_read.expect(/#{alcheck}/)
|
1171
|
+
uii.info(I18n.t('vagrant_zones.automated-zlogin-user'))
|
1172
|
+
zlogin_write.printf("#{user(@machine)}\n")
|
1173
|
+
sleep(5)
|
1174
|
+
end
|
1175
|
+
|
1176
|
+
if zlogin_read.expect(/#{pcheck}/)
|
1177
|
+
uii.info(I18n.t('vagrant_zones.automated-zlogin-pass'))
|
1178
|
+
zlogin_write.printf("#{vagrantuserpass(@machine)}\n")
|
1179
|
+
sleep(10)
|
1180
|
+
end
|
1181
|
+
|
1182
|
+
zlogin_write.printf("\n")
|
1183
|
+
if zlogin_read.expect(/#{lcheck}/)
|
1184
|
+
uii.info(I18n.t('vagrant_zones.automated-zlogin-root'))
|
1185
|
+
zlogin_write.printf("sudo su\n")
|
1186
|
+
sleep(10)
|
1187
|
+
Process.kill('HUP', pid)
|
1188
|
+
end
|
1189
|
+
end
|
1190
|
+
end
|
1191
|
+
end
|
1192
|
+
|
1193
|
+
def natloginboot(uii, metrics, interrupted)
|
1194
|
+
metrics ||= {}
|
1195
|
+
metrics['instance_dhcp_ssh_time'] = Util::Timer.time do
|
1196
|
+
retryable(on: Errors::TimeoutError, tries: 60) do
|
1197
|
+
# If we're interrupted don't worry about waiting
|
1198
|
+
next if interrupted
|
1199
|
+
|
1200
|
+
loop do
|
1201
|
+
break if interrupted
|
1202
|
+
break if @machine.communicate.ready?
|
1203
|
+
end
|
1204
|
+
end
|
1205
|
+
end
|
1206
|
+
uii.info(I18n.t('vagrant_zones.dhcp_boot_ready') + " in #{metrics['instance_dhcp_ssh_time']} Seconds")
|
1207
|
+
end
|
1208
|
+
|
1209
|
+
# This helps up wait for the boot of the vm by using zlogin
|
1210
|
+
def waitforboot(uii, metrics, interrupted)
|
1211
|
+
config = @machine.provider_config
|
1212
|
+
uii.info(I18n.t('vagrant_zones.wait_for_boot'))
|
1213
|
+
case config.brand
|
1214
|
+
when 'bhyve'
|
1215
|
+
return if config.cloud_init_enabled
|
1216
|
+
|
1217
|
+
zloginboot(uii) if config.setup_method == 'zlogin' && !config.os_type.to_s.match(/windows/)
|
1218
|
+
zlogin_win_boot(uii) if config.setup_method == 'zlogin' && config.os_type.to_s.match(/windows/)
|
1219
|
+
natloginboot(uii, metrics, interrupted) if config.setup_method == 'dhcp'
|
1220
|
+
when 'lx'
|
1221
|
+
unless user_exists?(uii, config.vagrant_user)
|
1222
|
+
# zlogincommand(uii, %('echo nameserver 1.1.1.1 >> /etc/resolv.conf'))
|
1223
|
+
# zlogincommand(uii, %('echo nameserver 1.0.0.1 >> /etc/resolv.conf'))
|
1224
|
+
zlogincommand(uii, 'useradd -m -s /bin/bash -U vagrant')
|
1225
|
+
zlogincommand(uii, 'echo "vagrant ALL=(ALL:ALL) NOPASSWD:ALL" \\> /etc/sudoers.d/vagrant')
|
1226
|
+
zlogincommand(uii, 'mkdir -p /home/vagrant/.ssh')
|
1227
|
+
key_url = 'https://raw.githubusercontent.com/hashicorp/vagrant/master/keys/vagrant.pub'
|
1228
|
+
zlogincommand(uii, "curl #{key_url} -O /home/vagrant/.ssh/authorized_keys")
|
1229
|
+
|
1230
|
+
id_rsa = 'https://raw.githubusercontent.com/hashicorp/vagrant/master/keys/vagrant'
|
1231
|
+
command = "#{@pfexec} curl #{id_rsa} -O id_rsa"
|
1232
|
+
Util::Subprocess.new command do |_stdout, stderr, _thread|
|
1233
|
+
uii.rewriting do |uisp|
|
1234
|
+
uisp.clear_line
|
1235
|
+
uisp.info(I18n.t('vagrant_zones.importing_vagrant_key'), new_line: false)
|
1236
|
+
uisp.report_progress(stderr, 100, false)
|
1237
|
+
end
|
1238
|
+
end
|
1239
|
+
uii.clear_line
|
1240
|
+
zlogincommand(uii, 'chown -R vagrant:vagrant /home/vagrant/.ssh')
|
1241
|
+
zlogincommand(uii, 'chmod 600 /home/vagrant/.ssh/authorized_keys')
|
1242
|
+
end
|
1243
|
+
end
|
1244
|
+
end
|
1245
|
+
|
1246
|
+
## This setups the Windows Networking via Zlogin
|
1247
|
+
def zoneniczloginsetup_windows(uii, opts, _mac)
|
1248
|
+
ip = ipaddress(uii, opts)
|
1249
|
+
vnic_name = vname(uii, opts)
|
1250
|
+
servers = dnsservers(uii)
|
1251
|
+
defrouter = opts[:gateway].to_s
|
1252
|
+
uii.info(I18n.t('vagrant_zones.configure_win_interface_using_vnic'))
|
1253
|
+
sleep(60)
|
1254
|
+
|
1255
|
+
## Insert code to get the list of interfaces by mac address in order
|
1256
|
+
## to set the proper VNIC name if using multiple adapters
|
1257
|
+
rename_adapter = %(netsh interface set interface name = "Ethernet" newname = "#{vnic_name}")
|
1258
|
+
cmd = %(netsh interface ipv4 set address name="#{vnic_name}" static #{ip} #{opts[:netmask]} #{defrouter})
|
1259
|
+
dns1 = %(netsh int ipv4 set dns name="#{vnic_name}" static #{servers[0]['nameserver']} primary validate=no)
|
1260
|
+
dns2 = %(netsh int ipv4 add dns name="#{vnic_name}" #{servers[1]['nameserver']} index=2 validate=no)
|
1261
|
+
|
1262
|
+
uii.info(I18n.t('vagrant_zones.win_applied_rename_adapter')) if zlogin(uii, rename_adapter)
|
1263
|
+
uii.info(I18n.t('vagrant_zones.win_applied_static')) if zlogin(uii, cmd)
|
1264
|
+
uii.info(I18n.t('vagrant_zones.win_applied_dns1')) if zlogin(uii, dns1)
|
1265
|
+
uii.info(I18n.t('vagrant_zones.win_applied_dns2')) if zlogin(uii, dns2)
|
1266
|
+
end
|
1267
|
+
|
1268
|
+
def zlogin_win_boot(uii)
|
1269
|
+
## use Windows SAC to setup networking
|
1270
|
+
name = @machine.name
|
1271
|
+
config = @machine.provider_config
|
1272
|
+
event_cmd_available = 'EVENT: The CMD command is now available'
|
1273
|
+
event_channel_created = 'EVENT: A new channel has been created'
|
1274
|
+
channel_access_prompt = 'Use any other key to view this channel'
|
1275
|
+
cmd = 'system32>'
|
1276
|
+
uii.info(I18n.t('vagrant_zones.automated-windows-zlogin'))
|
1277
|
+
PTY.spawn("pfexec zlogin -C #{name}") do |zlogin_read, zlogin_write, pid|
|
1278
|
+
Timeout.timeout(config.setup_wait) do
|
1279
|
+
uii.info(I18n.t('vagrant_zones.windows_skip_first_boot')) if zlogin_read.expect(/#{event_cmd_available}/)
|
1280
|
+
sleep(3)
|
1281
|
+
if zlogin_read.expect(/#{event_cmd_available}/)
|
1282
|
+
uii.info(I18n.t('vagrant_zones.windows_start_cmd'))
|
1283
|
+
zlogin_write.printf("cmd\n")
|
1284
|
+
end
|
1285
|
+
if zlogin_read.expect(/#{event_channel_created}/)
|
1286
|
+
uii.info(I18n.t('vagrant_zones.windows_access_session'))
|
1287
|
+
zlogin_write.printf("\e\t")
|
1288
|
+
end
|
1289
|
+
if zlogin_read.expect(/#{channel_access_prompt}/)
|
1290
|
+
uii.info(I18n.t('vagrant_zones.windows_access_session_presskey'))
|
1291
|
+
zlogin_write.printf('o')
|
1292
|
+
end
|
1293
|
+
if zlogin_read.expect(/Username:/)
|
1294
|
+
uii.info(I18n.t('vagrant_zones.windows_enter_username'))
|
1295
|
+
zlogin_write.printf("Administrator\n")
|
1296
|
+
end
|
1297
|
+
if zlogin_read.expect(/Domain/)
|
1298
|
+
uii.info(I18n.t('vagrant_zones.windows_enter_domain'))
|
1299
|
+
zlogin_write.printf("\n")
|
1300
|
+
end
|
1301
|
+
if zlogin_read.expect(/Password/)
|
1302
|
+
uii.info(I18n.t('vagrant_zones.windows_enter_password'))
|
1303
|
+
zlogin_write.printf("P@ssWord22\n")
|
1304
|
+
end
|
1305
|
+
if zlogin_read.expect(/#{cmd}/)
|
1306
|
+
uii.info(I18n.t('vagrant_zones.windows_cmd_accessible'))
|
1307
|
+
sleep(5)
|
1308
|
+
Process.kill('HUP', pid)
|
1309
|
+
end
|
1310
|
+
end
|
1311
|
+
end
|
1312
|
+
end
|
1313
|
+
|
1314
|
+
# This gives us a console to the VM to issue commands
|
1315
|
+
def zlogin(uii, cmd)
|
1316
|
+
name = @machine.name
|
1317
|
+
config = @machine.provider_config
|
1318
|
+
rsp = []
|
1319
|
+
PTY.spawn("pfexec zlogin -C #{name}") do |zread, zwrite, pid|
|
1320
|
+
Timeout.timeout(config.setup_wait) do
|
1321
|
+
error_check = "echo \"Error Code: $?\"\n"
|
1322
|
+
error_check = "echo Error Code: %%ERRORLEVEL%% \r\n\r\n" if config.os_type.to_s.match(/windows/)
|
1323
|
+
runonce = true
|
1324
|
+
loop do
|
1325
|
+
zread.expect(/\n/) { |line| rsp.push line }
|
1326
|
+
puts(rsp[-1].to_s) if config.debug
|
1327
|
+
zwrite.printf("#{cmd}\r\n") if runonce
|
1328
|
+
zwrite.printf(error_check.to_s) if runonce
|
1329
|
+
runonce = false
|
1330
|
+
break if rsp[-1].to_s.match(/Error Code: 0/)
|
1331
|
+
|
1332
|
+
em = "#{cmd} \nFailed with ==> #{rsp[-1]}"
|
1333
|
+
uii.info(I18n.t('vagrant_zones.console_failed') + em) if rsp[-1].to_s.match(/Error Code: \b(?!0\b)\d{1,4}\b/)
|
1334
|
+
raise Errors::ConsoleFailed if rsp[-1].to_s.match(/Error Code: \b(?!0\b)\d{1,4}\b/)
|
1335
|
+
end
|
1336
|
+
end
|
1337
|
+
Process.kill('HUP', pid)
|
1338
|
+
end
|
1339
|
+
end
|
1340
|
+
|
1341
|
+
# This checks if the user exists on the VM, usually for LX zones
|
1342
|
+
def user_exists?(uii, user = 'vagrant')
|
1343
|
+
name = @machine.name
|
1344
|
+
config = @machine.provider_config
|
1345
|
+
ret = execute(true, "#{@pfexec} zlogin #{name} id -u #{user}")
|
1346
|
+
uii.info(I18n.t('vagrant_zones.userexists')) if config.debug
|
1347
|
+
return true if ret.zero?
|
1348
|
+
|
1349
|
+
false
|
1350
|
+
end
|
1351
|
+
|
1352
|
+
# This gives the user a terminal console
|
1353
|
+
def zlogincommand(uii, cmd)
|
1354
|
+
name = @machine.name
|
1355
|
+
config = @machine.provider_config
|
1356
|
+
uii.info(I18n.t('vagrant_zones.zonelogincmd')) if config.debug
|
1357
|
+
execute(false, "#{@pfexec} zlogin #{name} #{cmd}")
|
1358
|
+
end
|
1359
|
+
|
1360
|
+
# This filters the vagrantuser
|
1361
|
+
def user(machine)
|
1362
|
+
config = machine.provider_config
|
1363
|
+
user = config.vagrant_user unless config.vagrant_user.nil?
|
1364
|
+
user = 'vagrant' if config.vagrant_user.nil?
|
1365
|
+
user
|
1366
|
+
end
|
1367
|
+
|
1368
|
+
# This filters the userprivatekeypath
|
1369
|
+
def userprivatekeypath(machine)
|
1370
|
+
config = machine.provider_config
|
1371
|
+
userkey = config.vagrant_user_private_key_path.to_s
|
1372
|
+
if config.vagrant_user_private_key_path.to_s.nil?
|
1373
|
+
id_rsa = 'https://raw.githubusercontent.com/hashicorp/vagrant/master/keys/vagrant'
|
1374
|
+
file = './id_rsa'
|
1375
|
+
command = "#{@pfexec} curl #{id_rsa} -O #{file}"
|
1376
|
+
Util::Subprocess.new command do |_stdout, stderr, _thread|
|
1377
|
+
uii.rewriting do |uipkp|
|
1378
|
+
uipkp.clear_line
|
1379
|
+
uipkp.info(I18n.t('vagrant_zones.importing_vagrant_key'), new_line: false)
|
1380
|
+
uipkp.report_progress(stderr, 100, false)
|
1381
|
+
end
|
1382
|
+
end
|
1383
|
+
uii.clear_line
|
1384
|
+
userkey = './id_rsa'
|
1385
|
+
end
|
1386
|
+
userkey
|
1387
|
+
end
|
1388
|
+
|
1389
|
+
# This filters the sshport
|
1390
|
+
def sshport(machine)
|
1391
|
+
config = machine.provider_config
|
1392
|
+
sshport = '22'
|
1393
|
+
sshport = config.sshport.to_s unless config.sshport.to_s.nil? || config.sshport.to_i.zero?
|
1394
|
+
# uii.info(I18n.t('vagrant_zones.sshport')) if config.debug
|
1395
|
+
sshport
|
1396
|
+
end
|
1397
|
+
|
1398
|
+
# This filters the firmware
|
1399
|
+
def firmware(uii)
|
1400
|
+
config = @machine.provider_config
|
1401
|
+
uii.info(I18n.t('vagrant_zones.firmware')) if config.debug
|
1402
|
+
ft = case config.firmware_type
|
1403
|
+
when /compatability/
|
1404
|
+
'BHYVE_RELEASE_CSM'
|
1405
|
+
when /UEFI/
|
1406
|
+
'BHYVE_RELEASE'
|
1407
|
+
when /BIOS/
|
1408
|
+
'BHYVE_CSM'
|
1409
|
+
when /BHYVE_DEBUG/
|
1410
|
+
'UEFI_DEBUG'
|
1411
|
+
when /BHYVE_RELEASE_CSM/
|
1412
|
+
'BIOS_DEBUG'
|
1413
|
+
end
|
1414
|
+
ft.to_s
|
1415
|
+
end
|
1416
|
+
|
1417
|
+
# This filters the rdpport
|
1418
|
+
def rdpport(uii)
|
1419
|
+
config = @machine.provider_config
|
1420
|
+
uii.info(I18n.t('vagrant_zones.rdpport')) if config.debug
|
1421
|
+
config.rdpport.to_s unless config.rdpport.to_s.nil?
|
1422
|
+
end
|
1423
|
+
|
1424
|
+
# This filters the vagrantuserpass
|
1425
|
+
def vagrantuserpass(machine)
|
1426
|
+
config = machine.provider_config
|
1427
|
+
# uii.info(I18n.t('vagrant_zones.vagrantuserpass')) if config.debug
|
1428
|
+
config.vagrant_user_pass unless config.vagrant_user_pass.to_s.nil?
|
1429
|
+
end
|
1430
|
+
|
1431
|
+
## List ZFS Snapshots, helper function to sort and display
|
1432
|
+
def zfssnaplistdisp(zfs_snapshots, uii, index, disk)
|
1433
|
+
uii.info("\n Disk Number: #{index}\n Disk Path: #{disk}")
|
1434
|
+
zfssnapshots = zfs_snapshots.split(/\n/).reverse
|
1435
|
+
zfssnapshots << "Snapshot\t\t\t\tUsed\tAvailable\tRefer\tPath"
|
1436
|
+
pml, rml, aml, uml, sml = 0
|
1437
|
+
zfssnapshots.reverse.each do |snapshot|
|
1438
|
+
ar = snapshot.gsub(/\s+/m, ' ').strip.split
|
1439
|
+
sml = ar[0].length.to_i if ar[0].length.to_i > sml.to_i
|
1440
|
+
uml = ar[1].length.to_i if ar[1].length.to_i > uml.to_i
|
1441
|
+
aml = ar[2].length.to_i if ar[2].length.to_i > aml.to_i
|
1442
|
+
rml = ar[3].length.to_i if ar[3].length.to_i > rml.to_i
|
1443
|
+
pml = ar[4].length.to_i if ar[4].length.to_i > pml.to_i
|
1444
|
+
end
|
1445
|
+
zfssnapshots.reverse.each_with_index do |snapshot, si|
|
1446
|
+
ar = snapshot.gsub(/\s+/m, ' ').strip.split
|
1447
|
+
strg1 = "%<sym>5s %<s>-#{sml}s %<u>-#{uml}s %<a>-#{aml}s %<r>-#{rml}s %<p>-#{pml}s"
|
1448
|
+
strg2 = "%<si>5s %<s>-#{sml}s %<u>-#{uml}s %<a>-#{aml}s %<r>-#{rml}s %<p>-#{pml}s"
|
1449
|
+
if si.zero?
|
1450
|
+
puts format strg1.to_s, sym: '#', s: ar[0], u: ar[1], a: ar[2], r: ar[3], p: ar[4]
|
1451
|
+
else
|
1452
|
+
puts format strg2.to_s, si: si - 2, s: ar[0], u: ar[1], a: ar[2], r: ar[3], p: ar[4]
|
1453
|
+
end
|
1454
|
+
end
|
1455
|
+
end
|
1456
|
+
|
1457
|
+
## List ZFS Snapshots
|
1458
|
+
def zfssnaplist(datasets, opts, uii)
|
1459
|
+
# config = @machine.provider_config
|
1460
|
+
# name = @machine.name
|
1461
|
+
uii.info(I18n.t('vagrant_zones.zfs_snapshot_list'))
|
1462
|
+
datasets.each_with_index do |disk, index|
|
1463
|
+
zfs_snapshots = execute(false, "#{@pfexec} zfs list -t snapshot | grep #{disk} || true")
|
1464
|
+
next if zfs_snapshots.nil?
|
1465
|
+
|
1466
|
+
ds = opts[:dataset].scan(/\D/).empty? unless opts[:dataset].nil?
|
1467
|
+
if ds
|
1468
|
+
next if opts[:dataset].to_i != index
|
1469
|
+
else
|
1470
|
+
next unless opts[:dataset] == disk || opts[:dataset].nil? || opts[:dataset] == 'all'
|
1471
|
+
end
|
1472
|
+
zfssnaplistdisp(zfs_snapshots, uii, index, disk)
|
1473
|
+
end
|
1474
|
+
end
|
1475
|
+
|
1476
|
+
## Create ZFS Snapshots
|
1477
|
+
def zfssnapcreate(datasets, opts, uii)
|
1478
|
+
uii.info(I18n.t('vagrant_zones.zfs_snapshot_create'))
|
1479
|
+
if opts[:dataset] == 'all'
|
1480
|
+
datasets.each do |disk|
|
1481
|
+
uii.info(" - #{disk}@#{opts[:snapshot_name]}")
|
1482
|
+
execute(false, "#{@pfexec} zfs snapshot #{disk}@#{opts[:snapshot_name]}")
|
1483
|
+
end
|
1484
|
+
else
|
1485
|
+
ds = opts[:dataset].scan(/\D/).empty? unless opts[:dataset].nil?
|
1486
|
+
if ds
|
1487
|
+
datasets.each_with_index do |disk, index|
|
1488
|
+
next unless opts[:dataset].to_i == index.to_i
|
1489
|
+
|
1490
|
+
execute(false, "#{@pfexec} zfs snapshot #{disk}@#{opts[:snapshot_name]}")
|
1491
|
+
uii.info(" - #{disk}@#{opts[:snapshot_name]}")
|
1492
|
+
end
|
1493
|
+
else
|
1494
|
+
execute(false, "#{@pfexec} zfs snapshot #{opts[:dataset]}@#{opts[:snapshot_name]}") if datasets.include?(opts[:dataset])
|
1495
|
+
uii.info(" - #{opts[:dataset]}@#{opts[:snapshot_name]}") if datasets.include?(opts[:dataset])
|
1496
|
+
end
|
1497
|
+
end
|
1498
|
+
end
|
1499
|
+
|
1500
|
+
## Destroy ZFS Snapshots
|
1501
|
+
def zfssnapdestroy(datasets, opts, uii)
|
1502
|
+
uii.info(I18n.t('vagrant_zones.zfs_snapshot_destroy'))
|
1503
|
+
if opts[:dataset].to_s == 'all'
|
1504
|
+
datasets.each do |disk|
|
1505
|
+
output = execute(false, "#{@pfexec} zfs list -t snapshot -o name | grep #{disk}")
|
1506
|
+
## Never delete the source when doing all
|
1507
|
+
output = output.split(/\n/).drop(1)
|
1508
|
+
## Delete in Reverse order
|
1509
|
+
output.reverse.each do |snaps|
|
1510
|
+
cmd = "#{@pfexec} zfs destroy #{snaps}"
|
1511
|
+
execute(false, cmd)
|
1512
|
+
uii.info(" - #{snaps}")
|
1513
|
+
end
|
1514
|
+
end
|
1515
|
+
else
|
1516
|
+
## Specify the dataset by number
|
1517
|
+
datasets.each_with_index do |disk, dindex|
|
1518
|
+
next unless dindex.to_i == opts[:dataset].to_i
|
1519
|
+
|
1520
|
+
output = execute(false, "#{@pfexec} zfs list -t snapshot -o name | grep #{disk}")
|
1521
|
+
output = output.split(/\n/).drop(1)
|
1522
|
+
output.each_with_index do |snaps, spindex|
|
1523
|
+
if opts[:snapshot_name].to_i == spindex && opts[:snapshot_name].to_s != 'all'
|
1524
|
+
uii.info(" - #{snaps}")
|
1525
|
+
execute(false, "#{@pfexec} zfs destroy #{snaps}")
|
1526
|
+
end
|
1527
|
+
if opts[:snapshot_name].to_s == 'all'
|
1528
|
+
uii.info(" - #{snaps}")
|
1529
|
+
execute(false, "#{@pfexec} zfs destroy #{snaps}")
|
1530
|
+
end
|
1531
|
+
end
|
1532
|
+
end
|
1533
|
+
## Specify the Dataset by path
|
1534
|
+
cmd = "#{@pfexec} zfs destroy #{opts[:dataset]}@#{opts[:snapshot_name]}"
|
1535
|
+
execute(false, cmd) if datasets.include?("#{opts[:dataset]}@#{opts[:snapshot_name]}")
|
1536
|
+
end
|
1537
|
+
end
|
1538
|
+
|
1539
|
+
## This will list Cron Jobs for Snapshots to take place
|
1540
|
+
def zfssnapcronlist(uii, disk, opts, cronjobs)
|
1541
|
+
return unless opts[:dataset].to_s == disk.to_s || opts[:dataset].to_s == 'all'
|
1542
|
+
|
1543
|
+
# config = @machine.provider_config
|
1544
|
+
# name = @machine.name
|
1545
|
+
uii.info(I18n.t('vagrant_zones.cron_entries'))
|
1546
|
+
h = { h: 'hourly', d: 'daily', w: 'weekly', m: 'monthly' }
|
1547
|
+
h.each do |_k, d|
|
1548
|
+
next unless opts[:list] == d || opts[:list] == 'all'
|
1549
|
+
|
1550
|
+
uii.info(cronjobs[d.to_sym]) unless cronjobs[d.to_sym].nil?
|
1551
|
+
end
|
1552
|
+
end
|
1553
|
+
|
1554
|
+
## This will delete Cron Jobs for Snapshots to take place
|
1555
|
+
def zfssnapcrondelete(uii, disk, opts, cronjobs)
|
1556
|
+
return unless opts[:dataset].to_s == disk.to_s || opts[:dataset].to_s == 'all'
|
1557
|
+
|
1558
|
+
sc = "#{@pfexec} crontab"
|
1559
|
+
rmcr = "#{sc} -l | grep -v "
|
1560
|
+
h = { h: 'hourly', d: 'daily', w: 'weekly', m: 'monthly' }
|
1561
|
+
uii.info(I18n.t('vagrant_zones.cron_delete'))
|
1562
|
+
h.each do |_k, d|
|
1563
|
+
next unless opts[:delete] == d || opts[:delete] == 'all'
|
1564
|
+
|
1565
|
+
cj = cronjobs[d.to_sym].to_s.gsub(/\*/, '\*')
|
1566
|
+
rc = "#{rmcr}'#{cj}' | #{sc}"
|
1567
|
+
uii.info(" - Removing Cron: #{cj}") unless cronjobs[d.to_sym].nil?
|
1568
|
+
execute(false, rc) unless cronjobs[d.to_sym].nil?
|
1569
|
+
end
|
1570
|
+
end
|
1571
|
+
|
1572
|
+
## This will set Cron Jobs for Snapshots to take place
|
1573
|
+
def zfssnapcronset(uii, disk, opts, cronjobs)
|
1574
|
+
return unless opts[:dataset].to_s == disk.to_s || opts[:dataset].to_s == 'all'
|
1575
|
+
|
1576
|
+
config = @machine.provider_config
|
1577
|
+
name = @machine.name
|
1578
|
+
uii.info(I18n.t('vagrant_zones.cron_set'))
|
1579
|
+
snpshtr = config.snapshot_script.to_s
|
1580
|
+
shrtcr = "( #{@pfexec} crontab -l; echo "
|
1581
|
+
h = {}
|
1582
|
+
sf = { freq: opts[:set_frequency], rtn: opts[:set_frequency_rtn] }
|
1583
|
+
rtn = { h: 24, d: 8, w: 5, m: 1 }
|
1584
|
+
ct = { h: '0 1-23 * * * ', d: '0 0 * * 0-5 ', w: '0 0 * * 6 ', m: '0 0 1 * * ' }
|
1585
|
+
h[:hourly] = { rtn: rtn[:h], ct: ct[:h] }
|
1586
|
+
h[:daily] = { rtn: rtn[:d], ct: ct[:d] }
|
1587
|
+
h[:weekly] = { rtn: rtn[:w], ct: ct[:w] }
|
1588
|
+
h[:monthly] = { rtn: rtn[:m], ct: ct[:m] }
|
1589
|
+
h.each do |k, d|
|
1590
|
+
next unless (k.to_s == sf[:freq] || sf[:freq] == 'all') && cronjobs[k].nil?
|
1591
|
+
|
1592
|
+
cj = "#{d[:ct]}#{snpshtr} -p #{k} -r -n #{sf[:rtn]} #{disk} # #{name}" unless sf[:rtn].nil?
|
1593
|
+
cj = "#{d[:ct]}#{snpshtr} -p #{k} -r -n #{d[:rtn]} #{disk} # #{name}" if sf[:rtn].nil?
|
1594
|
+
h[k] = { rtn: rtn[:h], ct: ct[:h], cj: cj }
|
1595
|
+
setcron = "#{shrtcr}'#{cj}' ) | #{@pfexec} crontab"
|
1596
|
+
uii.info("Setting Cron: #{setcron}")
|
1597
|
+
execute(false, setcron)
|
1598
|
+
end
|
1599
|
+
end
|
1600
|
+
|
1601
|
+
## Configure ZFS Snapshots Crons
|
1602
|
+
def zfssnapcron(datasets, opts, uii)
|
1603
|
+
name = @machine.name
|
1604
|
+
# config = @machine.provider_config
|
1605
|
+
crons = execute(false, "#{@pfexec} crontab -l").split("\n")
|
1606
|
+
rtnregex = '-p (weekly|monthly|daily|hourly)'
|
1607
|
+
opts[:dataset] = 'all' if opts[:dataset].nil?
|
1608
|
+
datasets.each do |disk|
|
1609
|
+
cronjobs = {}
|
1610
|
+
crons.each do |tasks|
|
1611
|
+
next if tasks.empty? || tasks[/^#/]
|
1612
|
+
|
1613
|
+
case tasks[/#{rtnregex}/, 1]
|
1614
|
+
when 'hourly'
|
1615
|
+
hourly = tasks if tasks[/# #{name}/] && tasks[/#{disk}/]
|
1616
|
+
cronjobs.merge!(hourly: hourly) if tasks[/# #{name}/] && tasks[/#{disk}/]
|
1617
|
+
when 'daily'
|
1618
|
+
daily = tasks if tasks[/# #{name}/] && tasks[/#{disk}/]
|
1619
|
+
cronjobs.merge!(daily: daily) if tasks[/# #{name}/] && tasks[/#{disk}/]
|
1620
|
+
when 'weekly'
|
1621
|
+
weekly = tasks if tasks[/# #{name}/] && tasks[/#{disk}/]
|
1622
|
+
cronjobs.merge!(weekly: weekly) if tasks[/# #{name}/] && tasks[/#{disk}/]
|
1623
|
+
when 'monthly'
|
1624
|
+
monthly = tasks if tasks[/# #{name}/] && tasks[/#{disk}/]
|
1625
|
+
cronjobs.merge!(monthly: monthly) if tasks[/# #{name}/] && tasks[/#{disk}/]
|
1626
|
+
end
|
1627
|
+
end
|
1628
|
+
zfssnapcronlist(uii, disk, opts, cronjobs) unless opts[:list].nil?
|
1629
|
+
zfssnapcrondelete(uii, disk, opts, cronjobs) unless opts[:delete].nil?
|
1630
|
+
zfssnapcronset(uii, disk, opts, cronjobs) unless opts[:set_frequency].nil?
|
1631
|
+
end
|
1632
|
+
end
|
1633
|
+
|
1634
|
+
# This helps us manage ZFS Snapshots
|
1635
|
+
def zfs(uii, job, opts)
|
1636
|
+
name = @machine.name
|
1637
|
+
config = @machine.provider_config
|
1638
|
+
bootconfigs = config.boot
|
1639
|
+
datasetroot = "#{bootconfigs['array']}/#{bootconfigs['dataset']}/#{name}/#{bootconfigs['volume_name']}"
|
1640
|
+
datasets = []
|
1641
|
+
datasets << datasetroot.to_s
|
1642
|
+
config.additional_disks&.each do |disk|
|
1643
|
+
additionaldataset = "#{disk['array']}/#{disk['dataset']}/#{name}/#{disk['volume_name']}"
|
1644
|
+
datasets << additionaldataset.to_s
|
1645
|
+
end
|
1646
|
+
case job
|
1647
|
+
when 'list'
|
1648
|
+
zfssnaplist(datasets, opts, uii)
|
1649
|
+
when 'create'
|
1650
|
+
zfssnapcreate(datasets, opts, uii)
|
1651
|
+
when 'destroy'
|
1652
|
+
zfssnapdestroy(datasets, opts, uii)
|
1653
|
+
when 'cron'
|
1654
|
+
zfssnapcron(datasets, opts, uii)
|
1655
|
+
end
|
1656
|
+
end
|
1657
|
+
|
1658
|
+
# Halts the Zone, first via shutdown command, then a halt.
|
1659
|
+
def halt(uii)
|
1660
|
+
name = @machine.name
|
1661
|
+
config = @machine.provider_config
|
1662
|
+
|
1663
|
+
## Check state in zoneadm
|
1664
|
+
vm_state = execute(false, "#{@pfexec} zoneadm -z #{name} list -p | awk -F: '{ print $3 }'")
|
1665
|
+
uii.info(I18n.t('vagrant_zones.graceful_shutdown'))
|
1666
|
+
begin
|
1667
|
+
Timeout.timeout(config.clean_shutdown_time) do
|
1668
|
+
execute(false, "#{@pfexec} zoneadm -z #{name} shutdown") if vm_state == 'running'
|
1669
|
+
end
|
1670
|
+
rescue Timeout::Error
|
1671
|
+
uii.info(I18n.t('vagrant_zones.graceful_shutdown_failed') + config.clean_shutdown_time.to_s)
|
1672
|
+
begin
|
1673
|
+
Timeout.timeout(config.clean_shutdown_time) do
|
1674
|
+
execute(false, "#{@pfexec} zoneadm -z #{name} halt")
|
1675
|
+
end
|
1676
|
+
rescue Timeout::Error
|
1677
|
+
raise Errors::TimeoutHalt
|
1678
|
+
end
|
1679
|
+
end
|
1680
|
+
end
|
1681
|
+
|
1682
|
+
# Destroys the Zone configurations and path
|
1683
|
+
def destroy(id)
|
1684
|
+
name = @machine.name
|
1685
|
+
id.info(I18n.t('vagrant_zones.leaving'))
|
1686
|
+
id.info(I18n.t('vagrant_zones.destroy_zone'))
|
1687
|
+
vm_state = execute(false, "#{@pfexec} zoneadm -z #{name} list -p | awk -F: '{ print $3 }'")
|
1688
|
+
|
1689
|
+
## If state is installed, uninstall from zoneadm and destroy from zonecfg
|
1690
|
+
if vm_state == 'installed'
|
1691
|
+
id.info(I18n.t('vagrant_zones.bhyve_zone_config_uninstall'))
|
1692
|
+
execute(false, "#{@pfexec} zoneadm -z #{name} uninstall -F")
|
1693
|
+
id.info(I18n.t('vagrant_zones.bhyve_zone_config_remove'))
|
1694
|
+
execute(false, "#{@pfexec} zonecfg -z #{name} delete -F")
|
1695
|
+
end
|
1696
|
+
|
1697
|
+
## If state is configured or incomplete, uninstall from destroy from zonecfg
|
1698
|
+
if %w[incomplete configured].include?(vm_state)
|
1699
|
+
id.info(I18n.t('vagrant_zones.bhyve_zone_config_remove'))
|
1700
|
+
execute(false, "#{@pfexec} zonecfg -z #{name} delete -F")
|
1701
|
+
end
|
1702
|
+
|
1703
|
+
### Nic Configurations
|
1704
|
+
state = 'delete'
|
1705
|
+
id.info(I18n.t('vagrant_zones.networking_int_remove'))
|
1706
|
+
network(id, state)
|
1707
|
+
end
|
1708
|
+
end
|
1709
|
+
end
|
1710
|
+
end
|