vagrant-zones 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|