chef-provisioning-vsphere 0.5.7.dev6 → 0.5.7
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 +4 -4
- data/lib/chef/provisioning/vsphere_driver/driver.rb +13 -41
- data/lib/chef/provisioning/vsphere_driver/version.rb +1 -1
- data/lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb +221 -29
- data/spec/integration_tests/vsphere_driver_spec.rb +6 -8
- metadata +4 -9
- data/lib/chef/provisioning/vsphere_driver/clone_spec_builder.rb +0 -200
- data/spec/unit_tests/clone_spec_builder_spec.rb +0 -102
- data/spec/unit_tests/support/vsphere_helper_stub.rb +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7308c027bc21589567543a1144202d7b8868641
|
4
|
+
data.tar.gz: 0f7ce9c37b7ae5662446ca99feb473c61fbbb6ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f9c2f84cabb77cd7cc0540e3a4c648129d97360d4430d2c6ff9d1dd31f1afeb3429191aae723e82c8b2c5c033af5a6e54c779aebf4de851df138ce68a6ae02ec
|
7
|
+
data.tar.gz: 5fa9251bbca1fe98791fe01d27bdf015118d32f5c1832172d0bdf4af075b5fb6d07ba8a13170773628a540852f32d5026c7b3b1e8e374a3a515ca899a2fc2c1e
|
@@ -3,7 +3,6 @@ require 'cheffish/merged_config'
|
|
3
3
|
require 'chef/provisioning/driver'
|
4
4
|
require 'chef/provisioning/machine/windows_machine'
|
5
5
|
require 'chef/provisioning/machine/unix_machine'
|
6
|
-
require 'chef/provisioning/vsphere_driver/clone_spec_builder'
|
7
6
|
require 'chef/provisioning/vsphere_driver/version'
|
8
7
|
require 'chef/provisioning/vsphere_driver/vsphere_helpers'
|
9
8
|
require 'chef/provisioning/vsphere_driver/vsphere_url'
|
@@ -12,6 +11,7 @@ module ChefProvisioningVsphere
|
|
12
11
|
# Provisions machines in vSphere.
|
13
12
|
class VsphereDriver < Chef::Provisioning::Driver
|
14
13
|
include Chef::Mixin::ShellOut
|
14
|
+
include ChefProvisioningVsphere::Helpers
|
15
15
|
|
16
16
|
def self.from_url(driver_url, config)
|
17
17
|
VsphereDriver.new(driver_url, config)
|
@@ -163,7 +163,7 @@ module ChefProvisioningVsphere
|
|
163
163
|
end
|
164
164
|
|
165
165
|
def find_or_create_vm(bootstrap_options, machine_spec, action_handler)
|
166
|
-
vm =
|
166
|
+
vm = find_vm(
|
167
167
|
bootstrap_options[:vm_folder],
|
168
168
|
machine_spec.name
|
169
169
|
)
|
@@ -231,7 +231,7 @@ module ChefProvisioningVsphere
|
|
231
231
|
end
|
232
232
|
return if networks.nil? || networks.count < 2
|
233
233
|
|
234
|
-
new_nics =
|
234
|
+
new_nics = add_extra_nic(
|
235
235
|
action_handler,
|
236
236
|
vm_template_for(bootstrap_options),
|
237
237
|
bootstrap_options,
|
@@ -313,7 +313,7 @@ module ChefProvisioningVsphere
|
|
313
313
|
msg << vm.guest.toolsRunningStatus
|
314
314
|
msg << '. powering up server...'
|
315
315
|
action_handler.report_progress(msg.join)
|
316
|
-
|
316
|
+
start_vm(vm)
|
317
317
|
else
|
318
318
|
restart_server(action_handler, machine_spec, machine_options)
|
319
319
|
end
|
@@ -395,7 +395,7 @@ module ChefProvisioningVsphere
|
|
395
395
|
vm = vm_for(machine_spec)
|
396
396
|
if vm
|
397
397
|
action_handler.perform_action "Shutdown guest OS and power off VM [#{vm.parent.name}/#{vm.name}]" do
|
398
|
-
|
398
|
+
stop_vm(vm)
|
399
399
|
end
|
400
400
|
end
|
401
401
|
end
|
@@ -405,7 +405,7 @@ module ChefProvisioningVsphere
|
|
405
405
|
vm = vm_for(machine_spec)
|
406
406
|
if vm
|
407
407
|
action_handler.perform_action "Power on VM [#{vm.parent.name}/#{vm.name}]" do
|
408
|
-
|
408
|
+
start_vm(vm, machine_options[:bootstrap_options][:ssh][:port])
|
409
409
|
end
|
410
410
|
end
|
411
411
|
vm
|
@@ -484,53 +484,25 @@ module ChefProvisioningVsphere
|
|
484
484
|
|
485
485
|
def vm_for(machine_spec)
|
486
486
|
if machine_spec.location
|
487
|
-
|
487
|
+
find_vm_by_id(machine_spec.location['server_id'])
|
488
488
|
else
|
489
489
|
nil
|
490
490
|
end
|
491
491
|
end
|
492
492
|
|
493
493
|
def clone_vm(action_handler, bootstrap_options, machine_name)
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
vm_folder = vsphere_helper.find_folder(bootstrap_options[:vm_folder])
|
501
|
-
vm_template.CloneVM_Task(
|
502
|
-
name: machine_name,
|
503
|
-
folder: vm_folder,
|
504
|
-
spec: clone_spec
|
505
|
-
).wait_for_completion
|
506
|
-
|
507
|
-
vm = vsphere_helper.find_vm(vm_folder, machine_name)
|
508
|
-
|
509
|
-
if bootstrap_options[:additional_disk_size_gb].to_i > 0
|
510
|
-
task = vm.ReconfigVM_Task(
|
511
|
-
spec: RbVmomi::VIM.VirtualMachineConfigSpec(
|
512
|
-
deviceChange: [
|
513
|
-
vsphere_helper.virtual_disk_for(vm, bootstrap_options)
|
514
|
-
]
|
515
|
-
)
|
516
|
-
)
|
517
|
-
task.wait_for_completion
|
518
|
-
end
|
519
|
-
|
520
|
-
vm
|
521
|
-
end
|
522
|
-
|
523
|
-
def vsphere_helper
|
524
|
-
@vsphere_helper ||= VsphereHelper.new(
|
525
|
-
connect_options,
|
526
|
-
config[:machine_options][:bootstrap_options][:datacenter]
|
494
|
+
do_vm_clone(
|
495
|
+
action_handler,
|
496
|
+
vm_template_for(bootstrap_options),
|
497
|
+
machine_name,
|
498
|
+
bootstrap_options
|
527
499
|
)
|
528
500
|
end
|
529
501
|
|
530
502
|
def vm_template_for(bootstrap_options)
|
531
503
|
template_folder = bootstrap_options[:template_folder]
|
532
504
|
template_name = bootstrap_options[:template_name]
|
533
|
-
|
505
|
+
find_vm(template_folder, template_name) ||
|
534
506
|
raise("vSphere VM Template not found [#{template_folder}/#{template_name}]")
|
535
507
|
end
|
536
508
|
|
@@ -1,24 +1,16 @@
|
|
1
1
|
require 'rbvmomi'
|
2
2
|
|
3
3
|
module ChefProvisioningVsphere
|
4
|
-
|
4
|
+
module Helpers
|
5
5
|
|
6
6
|
if !$guest_op_managers
|
7
7
|
$guest_op_managers = {}
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
@connect_options = connect_options
|
12
|
-
@datacenter_name = datacenter_name
|
13
|
-
end
|
14
|
-
|
15
|
-
attr_reader :connect_options
|
16
|
-
attr_reader :datacenter_name
|
17
|
-
|
18
|
-
def vim
|
10
|
+
def vim(options = connect_options)
|
19
11
|
if @current_connection.nil? or @current_connection.serviceContent.sessionManager.currentSession.nil?
|
20
|
-
puts "establishing connection to #{
|
21
|
-
@current_connection = RbVmomi::VIM.connect
|
12
|
+
puts "establishing connection to #{options[:host]}"
|
13
|
+
@current_connection = RbVmomi::VIM.connect options
|
22
14
|
str_conn = @current_connection.pretty_inspect # a string in the format of VIM(host ip)
|
23
15
|
|
24
16
|
# we are caching guest operation managers in a global variable...terrible i know
|
@@ -39,14 +31,22 @@ module ChefProvisioningVsphere
|
|
39
31
|
folder.find(vm_name, RbVmomi::VIM::VirtualMachine)
|
40
32
|
end
|
41
33
|
|
42
|
-
def find_vm_by_id(uuid)
|
43
|
-
vm =
|
34
|
+
def find_vm_by_id(uuid, connection = vim)
|
35
|
+
vm = connection.searchIndex.FindByUuid(
|
44
36
|
uuid: uuid,
|
45
37
|
vmSearch: true,
|
46
38
|
instanceUuid: true
|
47
39
|
)
|
48
40
|
end
|
49
41
|
|
42
|
+
def vm_started?(vm, wait_on_port = 22)
|
43
|
+
return false if vm.nil?
|
44
|
+
state = vm.runtime.powerState
|
45
|
+
return false unless state == 'poweredOn'
|
46
|
+
return false unless port_ready?(vm, wait_on_port)
|
47
|
+
return true
|
48
|
+
end
|
49
|
+
|
50
50
|
def vm_stopped?(vm)
|
51
51
|
return true if vm.nil?
|
52
52
|
state = vm.runtime.powerState
|
@@ -70,6 +70,31 @@ module ChefProvisioningVsphere
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
+
def port_ready?(vm, port)
|
74
|
+
vm_ip = vm.guest.ipAddress
|
75
|
+
return false if vm_ip.nil?
|
76
|
+
|
77
|
+
begin
|
78
|
+
tcp_socket = TCPSocket.new(vm_ip, port)
|
79
|
+
readable = IO.select([tcp_socket], nil, nil, 5)
|
80
|
+
if readable
|
81
|
+
true
|
82
|
+
else
|
83
|
+
false
|
84
|
+
end
|
85
|
+
rescue Errno::ETIMEDOUT
|
86
|
+
false
|
87
|
+
rescue Errno::EPERM
|
88
|
+
false
|
89
|
+
rescue Errno::ECONNREFUSED
|
90
|
+
false
|
91
|
+
rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH
|
92
|
+
false
|
93
|
+
ensure
|
94
|
+
tcp_socket && tcp_socket.close
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
73
98
|
#folder could be like: /Level1/Level2/folder_name
|
74
99
|
def find_folder(folder_name)
|
75
100
|
base = datacenter.vmFolder
|
@@ -83,8 +108,9 @@ module ChefProvisioningVsphere
|
|
83
108
|
end
|
84
109
|
|
85
110
|
def datacenter
|
86
|
-
|
87
|
-
|
111
|
+
dc_name = config[:machine_options][:bootstrap_options][:datacenter]
|
112
|
+
@datacenter ||= vim.serviceInstance.find_datacenter(dc_name) ||
|
113
|
+
raise("vSphere Datacenter not found [#{dc_name}]")
|
88
114
|
end
|
89
115
|
|
90
116
|
def network_adapter_for(operation, network_name, network_label, device_key, backing_info)
|
@@ -106,6 +132,56 @@ module ChefProvisioningVsphere
|
|
106
132
|
vm.config.hardware.device.select {|d| d.is_a?(RbVmomi::VIM::VirtualEthernetCard)}
|
107
133
|
end
|
108
134
|
|
135
|
+
def do_vm_clone(action_handler, vm_template, vm_name, options)
|
136
|
+
deviceAdditions = []
|
137
|
+
|
138
|
+
clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(
|
139
|
+
location: relocate_spec_for(vm_template, options),
|
140
|
+
powerOn: false,
|
141
|
+
template: false,
|
142
|
+
config: RbVmomi::VIM.VirtualMachineConfigSpec(
|
143
|
+
:cpuHotAddEnabled => true,
|
144
|
+
:memoryHotAddEnabled => true,
|
145
|
+
:cpuHotRemoveEnabled => true,
|
146
|
+
:deviceChange => Array.new)
|
147
|
+
)
|
148
|
+
|
149
|
+
clone_spec.customization = customization_options_from(action_handler, vm_template, vm_name, options)
|
150
|
+
|
151
|
+
unless options[:annotation].to_s.nil?
|
152
|
+
clone_spec.config.annotation = options[:annotation]
|
153
|
+
end
|
154
|
+
|
155
|
+
unless options[:num_cpus].to_s.nil?
|
156
|
+
clone_spec.config.numCPUs = options[:num_cpus]
|
157
|
+
end
|
158
|
+
|
159
|
+
unless options[:memory_mb].to_s.nil?
|
160
|
+
clone_spec.config.memoryMB = options[:memory_mb]
|
161
|
+
end
|
162
|
+
|
163
|
+
unless options[:network_name].nil?
|
164
|
+
deviceAdditions, changes = network_device_changes(action_handler, vm_template, options)
|
165
|
+
clone_spec.config.deviceChange = changes
|
166
|
+
end
|
167
|
+
|
168
|
+
vm_folder = find_folder(options[:vm_folder])
|
169
|
+
vm_template.CloneVM_Task(
|
170
|
+
name: vm_name,
|
171
|
+
folder: vm_folder,
|
172
|
+
spec: clone_spec
|
173
|
+
).wait_for_completion
|
174
|
+
|
175
|
+
vm = find_vm(vm_folder, vm_name)
|
176
|
+
|
177
|
+
if options[:additional_disk_size_gb].to_i > 0
|
178
|
+
task = vm.ReconfigVM_Task(:spec => RbVmomi::VIM.VirtualMachineConfigSpec(:deviceChange => [virtual_disk_for(vm, options)]))
|
179
|
+
task.wait_for_completion
|
180
|
+
end
|
181
|
+
|
182
|
+
vm
|
183
|
+
end
|
184
|
+
|
109
185
|
def add_extra_nic(action_handler, vm_template, options, vm)
|
110
186
|
deviceAdditions, changes = network_device_changes(action_handler, vm_template, options)
|
111
187
|
|
@@ -130,6 +206,28 @@ module ChefProvisioningVsphere
|
|
130
206
|
end
|
131
207
|
end
|
132
208
|
|
209
|
+
def relocate_spec_for(vm_template, options)
|
210
|
+
if options.has_key?(:host)
|
211
|
+
host = find_host(options[:host])
|
212
|
+
rspec = RbVmomi::VIM.VirtualMachineRelocateSpec(host: host)
|
213
|
+
else
|
214
|
+
pool = options[:resource_pool] ? find_pool(options[:resource_pool]) : vm_template.resourcePool
|
215
|
+
rspec = RbVmomi::VIM.VirtualMachineRelocateSpec(pool: pool)
|
216
|
+
raise 'either :host or :resource_pool must be specified when cloning from a VM Template' if pool.nil?
|
217
|
+
end
|
218
|
+
|
219
|
+
if options.has_key?(:use_linked_clone)
|
220
|
+
create_delta_disk(vm_template)
|
221
|
+
rspec.diskMoveType = :moveChildMostDiskBacking
|
222
|
+
end
|
223
|
+
|
224
|
+
unless options[:datastore].to_s.empty?
|
225
|
+
rspec.datastore = find_datastore(options[:datastore])
|
226
|
+
end
|
227
|
+
|
228
|
+
rspec
|
229
|
+
end
|
230
|
+
|
133
231
|
def create_delta_disk(vm_template)
|
134
232
|
disks = vm_template.config.hardware.device.grep(RbVmomi::VIM::VirtualDisk)
|
135
233
|
disks.select { |disk| disk.backing.parent == nil }.each do |disk|
|
@@ -228,12 +326,114 @@ module ChefProvisioningVsphere
|
|
228
326
|
datacenter.datastore.find { |f| f.info.name == datastore_name } or raise "no such datastore #{datastore_name}"
|
229
327
|
end
|
230
328
|
|
329
|
+
def customization_options_from(action_handler, vm_template, vm_name, options)
|
330
|
+
if options.has_key?(:customization_spec)
|
331
|
+
if(options[:customization_spec].is_a?(Hash))
|
332
|
+
cust_options = options[:customization_spec]
|
333
|
+
ip_settings = cust_options[:ipsettings]
|
334
|
+
cust_domain = cust_options[:domain]
|
335
|
+
|
336
|
+
raise ArgumentError, 'domain is required' unless cust_domain
|
337
|
+
cust_ip_settings = nil
|
338
|
+
if ip_settings && ip_settings.key?(:ip)
|
339
|
+
unless cust_options[:ipsettings].key?(:subnetMask)
|
340
|
+
raise ArgumentError, 'subnetMask is required for static ip'
|
341
|
+
end
|
342
|
+
cust_ip_settings = RbVmomi::VIM::CustomizationIPSettings.new(ip_settings)
|
343
|
+
action_handler.report_progress "customizing #{vm_name} with static IP #{ip_settings[:ip]}"
|
344
|
+
cust_ip_settings.ip = RbVmomi::VIM::CustomizationFixedIp(:ipAddress => ip_settings[:ip])
|
345
|
+
end
|
346
|
+
if cust_ip_settings.nil?
|
347
|
+
cust_ip_settings= RbVmomi::VIM::CustomizationIPSettings.new(:ip => RbVmomi::VIM::CustomizationDhcpIpGenerator.new())
|
348
|
+
cust_ip_settings.dnsServerList = ip_settings[:dnsServerList]
|
349
|
+
action_handler.report_progress "customizing #{vm_name} with dynamic IP and DNS: #{ip_settings[:dnsServerList]}"
|
350
|
+
end
|
351
|
+
|
352
|
+
cust_ip_settings.dnsDomain = cust_domain
|
353
|
+
cust_global_ip_settings = RbVmomi::VIM::CustomizationGlobalIPSettings.new
|
354
|
+
cust_global_ip_settings.dnsServerList = cust_ip_settings.dnsServerList
|
355
|
+
cust_global_ip_settings.dnsSuffixList = [cust_domain]
|
356
|
+
cust_hostname = hostname_from(cust_options, vm_name)
|
357
|
+
cust_hwclockutc = cust_options[:hw_clock_utc]
|
358
|
+
cust_timezone = cust_options[:time_zone]
|
359
|
+
|
360
|
+
if vm_template.config.guestId.start_with?('win')
|
361
|
+
cust_prep = windows_prep_for(action_handler, options, vm_name)
|
362
|
+
else
|
363
|
+
cust_prep = RbVmomi::VIM::CustomizationLinuxPrep.new(
|
364
|
+
:domain => cust_domain,
|
365
|
+
:hostName => cust_hostname,
|
366
|
+
:hwClockUTC => cust_hwclockutc,
|
367
|
+
:timeZone => cust_timezone
|
368
|
+
)
|
369
|
+
end
|
370
|
+
cust_adapter_mapping = [RbVmomi::VIM::CustomizationAdapterMapping.new(:adapter => cust_ip_settings)]
|
371
|
+
RbVmomi::VIM::CustomizationSpec.new(
|
372
|
+
:identity => cust_prep,
|
373
|
+
:globalIPSettings => cust_global_ip_settings,
|
374
|
+
:nicSettingMap => cust_adapter_mapping
|
375
|
+
)
|
376
|
+
else
|
377
|
+
find_customization_spec(cust_options)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
def windows_prep_for(action_handler, options, vm_name)
|
383
|
+
cust_options = options[:customization_spec]
|
384
|
+
cust_runonce = RbVmomi::VIM::CustomizationGuiRunOnce.new(
|
385
|
+
:commandList => [
|
386
|
+
'winrm set winrm/config/client/auth @{Basic="true"}',
|
387
|
+
'winrm set winrm/config/service/auth @{Basic="true"}',
|
388
|
+
'winrm set winrm/config/service @{AllowUnencrypted="true"}',
|
389
|
+
'shutdown -l'])
|
390
|
+
|
391
|
+
cust_login_password = RbVmomi::VIM::CustomizationPassword(
|
392
|
+
:plainText => true,
|
393
|
+
:value => options[:ssh][:password])
|
394
|
+
if cust_options.has_key?(:domain) and cust_options[:domain] != 'local'
|
395
|
+
cust_domain_password = RbVmomi::VIM::CustomizationPassword(
|
396
|
+
:plainText => true,
|
397
|
+
:value => ENV['domainAdminPassword'] || cust_options[:domainAdminPassword])
|
398
|
+
cust_id = RbVmomi::VIM::CustomizationIdentification.new(
|
399
|
+
:joinDomain => cust_options[:domain],
|
400
|
+
:domainAdmin => cust_options[:domainAdmin],
|
401
|
+
:domainAdminPassword => cust_domain_password)
|
402
|
+
#puts "my env passwd is: #{ENV['domainAdminPassword']}"
|
403
|
+
action_handler.report_progress "joining domain #{cust_options[:domain]} with user: #{cust_options[:domainAdmin]}"
|
404
|
+
else
|
405
|
+
cust_id = RbVmomi::VIM::CustomizationIdentification.new(
|
406
|
+
:joinWorkgroup => 'WORKGROUP')
|
407
|
+
end
|
408
|
+
cust_gui_unattended = RbVmomi::VIM::CustomizationGuiUnattended.new(
|
409
|
+
:autoLogon => true,
|
410
|
+
:autoLogonCount => 1,
|
411
|
+
:password => cust_login_password,
|
412
|
+
:timeZone => cust_options[:win_time_zone])
|
413
|
+
cust_userdata = RbVmomi::VIM::CustomizationUserData.new(
|
414
|
+
:computerName => hostname_from(cust_options, vm_name),
|
415
|
+
:fullName => cust_options[:org_name],
|
416
|
+
:orgName => cust_options[:org_name],
|
417
|
+
:productId => cust_options[:product_id])
|
418
|
+
RbVmomi::VIM::CustomizationSysprep.new(
|
419
|
+
:guiRunOnce => cust_runonce,
|
420
|
+
:identification => cust_id,
|
421
|
+
:guiUnattended => cust_gui_unattended,
|
422
|
+
:userData => cust_userdata)
|
423
|
+
end
|
424
|
+
|
425
|
+
def hostname_from(options, vm_name)
|
426
|
+
if options.key?(:hostname)
|
427
|
+
RbVmomi::VIM::CustomizationFixedName.new(:name => options[:hostname])
|
428
|
+
else
|
429
|
+
RbVmomi::VIM::CustomizationFixedName.new(:name => vm_name)
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
231
433
|
def find_entity(name, parent_folder, &block)
|
232
434
|
parts = name.split('/').reject(&:empty?)
|
233
435
|
parts.each do |item|
|
234
|
-
Chef::Log.debug("Identifying entity part: #{item} in folder type: #{parent_folder.class}")
|
235
436
|
if parent_folder.is_a? RbVmomi::VIM::Folder
|
236
|
-
Chef::Log.debug('Parent folder is a folder')
|
237
437
|
parent_folder = parent_folder.childEntity.find { |f| f.name == item }
|
238
438
|
else
|
239
439
|
parent_folder = block.call(parent_folder, item)
|
@@ -256,28 +456,20 @@ module ChefProvisioningVsphere
|
|
256
456
|
|
257
457
|
raise "vSphere Host not found [#{host_name}]" if host.nil?
|
258
458
|
|
259
|
-
if host.is_a?(RbVmomi::VIM::
|
260
|
-
host = host.host
|
459
|
+
if !host.is_a?(RbVmomi::VIM::HostSystem) && host.respond_to?(:host)
|
460
|
+
host = host.host
|
261
461
|
end
|
262
462
|
host
|
263
463
|
end
|
264
464
|
|
265
465
|
def find_pool(pool_name)
|
266
|
-
Chef::Log.debug("Finding pool: #{pool_name}")
|
267
466
|
pool = find_entity(pool_name, datacenter.hostFolder) do |parent, part|
|
268
467
|
case parent
|
269
|
-
when RbVmomi::VIM::ClusterComputeResource
|
270
|
-
Chef::Log.debug("finding #{part} in a #{parent.class}: #{parent.name}")
|
271
|
-
Chef::Log.debug("Parent root pool has #{parent.resourcePool.resourcePool.count} pools")
|
272
|
-
parent.resourcePool.resourcePool.each { |p| Chef::Log.debug(p.name ) }
|
468
|
+
when RbVmomi::VIM::ClusterComputeResource || RbVmomi::VIM::ComputeResource
|
273
469
|
parent.resourcePool.resourcePool.find { |f| f.name == part }
|
274
470
|
when RbVmomi::VIM::ResourcePool
|
275
|
-
Chef::Log.debug("finding #{part} in a Resource Pool: #{parent.name}")
|
276
|
-
Chef::Log.debug("Pool has #{parent.resourcePool.count} pools")
|
277
|
-
parent.resourcePool.each { |p| Chef::Log.debug(p.name ) }
|
278
471
|
parent.resourcePool.find { |f| f.name == part }
|
279
472
|
else
|
280
|
-
Chef::Log.debug("parent of #{part} is unexpected type: #{parent.class}")
|
281
473
|
nil
|
282
474
|
end
|
283
475
|
end
|
@@ -34,11 +34,12 @@ require 'chef/provisioning/machine_spec'
|
|
34
34
|
# }
|
35
35
|
|
36
36
|
describe 'vsphere_driver' do
|
37
|
+
include ChefProvisioningVsphere::Helpers
|
38
|
+
|
37
39
|
before :all do
|
38
40
|
@vm_name = "cmvd-test-#{SecureRandom.hex}"
|
39
41
|
@metal_config = eval File.read(File.expand_path('../config.rb', __FILE__))
|
40
42
|
Cheffish.honor_local_mode do
|
41
|
-
Chef::Log.level = :debug
|
42
43
|
chef_server = Cheffish.default_chef_server
|
43
44
|
@machine_spec = Chef::Provisioning.chef_managed_entry_store(chef_server).new_entry(:machine, @vm_name)
|
44
45
|
url = URI::VsphereUrl.from_config(@metal_config[:driver_options]).to_s
|
@@ -48,11 +49,8 @@ describe 'vsphere_driver' do
|
|
48
49
|
@metal_config[:machine_options][:convergence_options] = {:chef_server => chef_server}
|
49
50
|
machine = @driver.ready_machine(action_handler, @machine_spec, @metal_config[:machine_options])
|
50
51
|
@server_id = @machine_spec.location['server_id']
|
51
|
-
@
|
52
|
-
|
53
|
-
@metal_config[:machine_options][:bootstrap_options][:datacenter]
|
54
|
-
)
|
55
|
-
@vm = @vsphere_helper.find_vm_by_id(@server_id)
|
52
|
+
@connection = vim(@metal_config[:driver_options])
|
53
|
+
@vm = find_vm_by_id(@server_id, @connection)
|
56
54
|
end
|
57
55
|
end
|
58
56
|
|
@@ -103,7 +101,7 @@ describe 'vsphere_driver' do
|
|
103
101
|
end
|
104
102
|
end
|
105
103
|
it 'is in the correct datacenter' do
|
106
|
-
expect(@
|
104
|
+
expect(@connection.serviceInstance.find_datacenter(@metal_config[:machine_options][:bootstrap_options][:datacenter]).find_vm("#{@vm.parent.name}/#{@vm_name}")).not_to eq(nil)
|
107
105
|
end
|
108
106
|
it 'has an added disk of the correct size' do
|
109
107
|
disk_count = @vm.disks.count
|
@@ -148,7 +146,7 @@ describe 'vsphere_driver' do
|
|
148
146
|
@metal_config[:machine_options]
|
149
147
|
)
|
150
148
|
end
|
151
|
-
vm =
|
149
|
+
vm = find_vm_by_id(@server_id, @connection)
|
152
150
|
expect(vm).to eq(nil)
|
153
151
|
end
|
154
152
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chef-provisioning-vsphere
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.7
|
4
|
+
version: 0.5.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- CenturyLink Cloud
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-06-
|
11
|
+
date: 2015-06-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rbvmomi
|
@@ -103,7 +103,6 @@ files:
|
|
103
103
|
- contribution-notice
|
104
104
|
- lib/chef/provisioning/driver_init/vsphere.rb
|
105
105
|
- lib/chef/provisioning/vsphere_driver.rb
|
106
|
-
- lib/chef/provisioning/vsphere_driver/clone_spec_builder.rb
|
107
106
|
- lib/chef/provisioning/vsphere_driver/driver.rb
|
108
107
|
- lib/chef/provisioning/vsphere_driver/version.rb
|
109
108
|
- lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb
|
@@ -113,8 +112,6 @@ files:
|
|
113
112
|
- spec/integration_tests/vsphere_driver_spec.rb
|
114
113
|
- spec/unit_tests/VsphereDriver_spec.rb
|
115
114
|
- spec/unit_tests/VsphereUrl_spec.rb
|
116
|
-
- spec/unit_tests/clone_spec_builder_spec.rb
|
117
|
-
- spec/unit_tests/support/vsphere_helper_stub.rb
|
118
115
|
homepage: https://github.com/tier3/chef-provisioning-vsphere
|
119
116
|
licenses:
|
120
117
|
- MIT
|
@@ -130,9 +127,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
130
127
|
version: '0'
|
131
128
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
129
|
requirements:
|
133
|
-
- - "
|
130
|
+
- - ">="
|
134
131
|
- !ruby/object:Gem::Version
|
135
|
-
version:
|
132
|
+
version: '0'
|
136
133
|
requirements: []
|
137
134
|
rubyforge_project:
|
138
135
|
rubygems_version: 2.4.4
|
@@ -144,6 +141,4 @@ test_files:
|
|
144
141
|
- spec/integration_tests/vsphere_driver_spec.rb
|
145
142
|
- spec/unit_tests/VsphereDriver_spec.rb
|
146
143
|
- spec/unit_tests/VsphereUrl_spec.rb
|
147
|
-
- spec/unit_tests/clone_spec_builder_spec.rb
|
148
|
-
- spec/unit_tests/support/vsphere_helper_stub.rb
|
149
144
|
has_rdoc:
|
@@ -1,200 +0,0 @@
|
|
1
|
-
module ChefProvisioningVsphere
|
2
|
-
class CloneSpecBuilder
|
3
|
-
def initialize(vsphere_helper, action_handler)
|
4
|
-
@vsphere_helper = vsphere_helper
|
5
|
-
@action_handler = action_handler
|
6
|
-
end
|
7
|
-
|
8
|
-
attr_reader :vsphere_helper
|
9
|
-
attr_reader :action_handler
|
10
|
-
|
11
|
-
def build(vm_template, vm_name, options)
|
12
|
-
clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(
|
13
|
-
location: relocate_spec_for(vm_template, options),
|
14
|
-
powerOn: false,
|
15
|
-
template: false,
|
16
|
-
config: RbVmomi::VIM.VirtualMachineConfigSpec(
|
17
|
-
:cpuHotAddEnabled => true,
|
18
|
-
:memoryHotAddEnabled => true,
|
19
|
-
:cpuHotRemoveEnabled => true,
|
20
|
-
:deviceChange => Array.new)
|
21
|
-
)
|
22
|
-
|
23
|
-
unless options[:annotation].to_s.nil?
|
24
|
-
clone_spec.config.annotation = options[:annotation]
|
25
|
-
end
|
26
|
-
|
27
|
-
unless options[:num_cpus].to_s.nil?
|
28
|
-
clone_spec.config.numCPUs = options[:num_cpus]
|
29
|
-
end
|
30
|
-
|
31
|
-
unless options[:memory_mb].to_s.nil?
|
32
|
-
clone_spec.config.memoryMB = options[:memory_mb]
|
33
|
-
end
|
34
|
-
|
35
|
-
unless options[:network_name].nil?
|
36
|
-
deviceAdditions, changes = vsphere_helper.network_device_changes(
|
37
|
-
action_handler,
|
38
|
-
vm_template,
|
39
|
-
options
|
40
|
-
)
|
41
|
-
clone_spec.config.deviceChange = changes
|
42
|
-
end
|
43
|
-
|
44
|
-
clone_spec.customization = customization_options_from(
|
45
|
-
vm_template,
|
46
|
-
vm_name,
|
47
|
-
options
|
48
|
-
)
|
49
|
-
|
50
|
-
clone_spec
|
51
|
-
end
|
52
|
-
|
53
|
-
def relocate_spec_for(vm_template, options)
|
54
|
-
rspec = RbVmomi::VIM.VirtualMachineRelocateSpec
|
55
|
-
host = nil
|
56
|
-
|
57
|
-
if options.has_key?(:host)
|
58
|
-
host = vsphere_helper.find_host(options[:host])
|
59
|
-
rspec.host = host
|
60
|
-
end
|
61
|
-
|
62
|
-
if options[:resource_pool]
|
63
|
-
rspec.pool = vsphere_helper.find_pool(options[:resource_pool])
|
64
|
-
elsif vm_template.config.template && !host.nil?
|
65
|
-
rspec.pool = host.parent.resourcePool # assign to the "invisible" pool root
|
66
|
-
elsif vm_template.config.template
|
67
|
-
raise 'either :host or :resource_pool must be specified when cloning from a VM Template'
|
68
|
-
end
|
69
|
-
|
70
|
-
|
71
|
-
if options[:use_linked_clone]
|
72
|
-
if vm_template.config.template
|
73
|
-
Chef::Log.warn("Using a VM Template, ignoring use_linked_clone.")
|
74
|
-
else
|
75
|
-
vsphere_helper.create_delta_disk(vm_template)
|
76
|
-
rspec.diskMoveType = :moveChildMostDiskBacking
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
unless options[:datastore].to_s.empty?
|
81
|
-
rspec.datastore = vsphere_helper.find_datastore(options[:datastore])
|
82
|
-
end
|
83
|
-
|
84
|
-
rspec
|
85
|
-
end
|
86
|
-
|
87
|
-
def customization_options_from(vm_template, vm_name, options)
|
88
|
-
if options.has_key?(:customization_spec)
|
89
|
-
if(options[:customization_spec].is_a?(Hash))
|
90
|
-
cust_options = options[:customization_spec]
|
91
|
-
ip_settings = cust_options[:ipsettings]
|
92
|
-
cust_domain = cust_options[:domain]
|
93
|
-
|
94
|
-
raise ArgumentError, 'domain is required' unless cust_domain
|
95
|
-
cust_ip_settings = nil
|
96
|
-
if ip_settings && ip_settings.key?(:ip)
|
97
|
-
unless cust_options[:ipsettings].key?(:subnetMask)
|
98
|
-
raise ArgumentError, 'subnetMask is required for static ip'
|
99
|
-
end
|
100
|
-
cust_ip_settings = RbVmomi::VIM::CustomizationIPSettings.new(
|
101
|
-
ip_settings)
|
102
|
-
action_handler.report_progress "customizing #{vm_name} \
|
103
|
-
with static IP #{ip_settings[:ip]}"
|
104
|
-
cust_ip_settings.ip = RbVmomi::VIM::CustomizationFixedIp(
|
105
|
-
:ipAddress => ip_settings[:ip])
|
106
|
-
end
|
107
|
-
if cust_ip_settings.nil?
|
108
|
-
cust_ip_settings= RbVmomi::VIM::CustomizationIPSettings.new(
|
109
|
-
:ip => RbVmomi::VIM::CustomizationDhcpIpGenerator.new())
|
110
|
-
cust_ip_settings.dnsServerList = ip_settings[:dnsServerList]
|
111
|
-
action_handler.report_progress "customizing #{vm_name} with /
|
112
|
-
dynamic IP and DNS: #{ip_settings[:dnsServerList]}"
|
113
|
-
end
|
114
|
-
|
115
|
-
cust_ip_settings.dnsDomain = cust_domain
|
116
|
-
global_ip_settings = RbVmomi::VIM::CustomizationGlobalIPSettings.new
|
117
|
-
global_ip_settings.dnsServerList = cust_ip_settings.dnsServerList
|
118
|
-
global_ip_settings.dnsSuffixList = [cust_domain]
|
119
|
-
cust_hostname = hostname_from(cust_options, vm_name)
|
120
|
-
cust_hwclockutc = cust_options[:hw_clock_utc]
|
121
|
-
cust_timezone = cust_options[:time_zone]
|
122
|
-
|
123
|
-
if vm_template.config.guestId.start_with?('win')
|
124
|
-
cust_prep = windows_prep_for(options, vm_name)
|
125
|
-
else
|
126
|
-
cust_prep = RbVmomi::VIM::CustomizationLinuxPrep.new(
|
127
|
-
:domain => cust_domain,
|
128
|
-
:hostName => cust_hostname,
|
129
|
-
:hwClockUTC => cust_hwclockutc,
|
130
|
-
:timeZone => cust_timezone
|
131
|
-
)
|
132
|
-
end
|
133
|
-
cust_adapter_mapping = [
|
134
|
-
RbVmomi::VIM::CustomizationAdapterMapping.new(
|
135
|
-
:adapter => cust_ip_settings)
|
136
|
-
]
|
137
|
-
RbVmomi::VIM::CustomizationSpec.new(
|
138
|
-
:identity => cust_prep,
|
139
|
-
:globalIPSettings => global_ip_settings,
|
140
|
-
:nicSettingMap => cust_adapter_mapping
|
141
|
-
)
|
142
|
-
else
|
143
|
-
vsphere_helper.find_customization_spec(cust_options)
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
def hostname_from(options, vm_name)
|
149
|
-
if options.key?(:hostname)
|
150
|
-
RbVmomi::VIM::CustomizationFixedName.new(:name => options[:hostname])
|
151
|
-
else
|
152
|
-
RbVmomi::VIM::CustomizationFixedName.new(:name => vm_name)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
def windows_prep_for(options, vm_name)
|
157
|
-
cust_options = options[:customization_spec]
|
158
|
-
cust_runonce = RbVmomi::VIM::CustomizationGuiRunOnce.new(
|
159
|
-
:commandList => [
|
160
|
-
'winrm set winrm/config/client/auth @{Basic="true"}',
|
161
|
-
'winrm set winrm/config/service/auth @{Basic="true"}',
|
162
|
-
'winrm set winrm/config/service @{AllowUnencrypted="true"}',
|
163
|
-
'shutdown -l'])
|
164
|
-
|
165
|
-
cust_login_password = RbVmomi::VIM::CustomizationPassword(
|
166
|
-
:plainText => true,
|
167
|
-
:value => options[:ssh][:password])
|
168
|
-
if cust_options.has_key?(:domain) and cust_options[:domain] != 'local'
|
169
|
-
cust_domain_password = RbVmomi::VIM::CustomizationPassword(
|
170
|
-
:plainText => true,
|
171
|
-
:value => ENV['domainAdminPassword'] || cust_options[:domainAdminPassword])
|
172
|
-
cust_id = RbVmomi::VIM::CustomizationIdentification.new(
|
173
|
-
:joinDomain => cust_options[:domain],
|
174
|
-
:domainAdmin => cust_options[:domainAdmin],
|
175
|
-
:domainAdminPassword => cust_domain_password)
|
176
|
-
#puts "my env passwd is: #{ENV['domainAdminPassword']}"
|
177
|
-
action_handler.report_progress "joining domain #{cust_options[:domain]} /
|
178
|
-
with user: #{cust_options[:domainAdmin]}"
|
179
|
-
else
|
180
|
-
cust_id = RbVmomi::VIM::CustomizationIdentification.new(
|
181
|
-
:joinWorkgroup => 'WORKGROUP')
|
182
|
-
end
|
183
|
-
cust_gui_unattended = RbVmomi::VIM::CustomizationGuiUnattended.new(
|
184
|
-
:autoLogon => true,
|
185
|
-
:autoLogonCount => 1,
|
186
|
-
:password => cust_login_password,
|
187
|
-
:timeZone => cust_options[:win_time_zone])
|
188
|
-
cust_userdata = RbVmomi::VIM::CustomizationUserData.new(
|
189
|
-
:computerName => hostname_from(cust_options, vm_name),
|
190
|
-
:fullName => cust_options[:org_name],
|
191
|
-
:orgName => cust_options[:org_name],
|
192
|
-
:productId => cust_options[:product_id])
|
193
|
-
RbVmomi::VIM::CustomizationSysprep.new(
|
194
|
-
:guiRunOnce => cust_runonce,
|
195
|
-
:identification => cust_id,
|
196
|
-
:guiUnattended => cust_gui_unattended,
|
197
|
-
:userData => cust_userdata)
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
@@ -1,102 +0,0 @@
|
|
1
|
-
require 'chef/provisioning/vsphere_driver'
|
2
|
-
|
3
|
-
require_relative 'support/vsphere_helper_stub'
|
4
|
-
|
5
|
-
describe ChefProvisioningVsphere::CloneSpecBuilder do
|
6
|
-
let(:options) { Hash.new }
|
7
|
-
let(:vm_template) { double('template') }
|
8
|
-
|
9
|
-
before do
|
10
|
-
allow(vm_template).to receive_message_chain(:config, :guestId)
|
11
|
-
allow(vm_template).to receive_message_chain(:config, :template)
|
12
|
-
.and_return(false)
|
13
|
-
end
|
14
|
-
|
15
|
-
subject do
|
16
|
-
builder = ChefProvisioningVsphere::CloneSpecBuilder.new(
|
17
|
-
ChefProvisioningVsphereStubs::VsphereHelperStub.new,
|
18
|
-
Chef::Provisioning::ActionHandler.new
|
19
|
-
)
|
20
|
-
builder.build(vm_template, 'machine_name', options)
|
21
|
-
end
|
22
|
-
|
23
|
-
context 'using linked clones' do
|
24
|
-
before { options[:use_linked_clone] = true }
|
25
|
-
|
26
|
-
it 'sets the disk move type of the relocation spec' do
|
27
|
-
expect(subject.location.diskMoveType).to be :moveChildMostDiskBacking
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
context 'using linked clone on a template source' do
|
32
|
-
before do
|
33
|
-
options[:use_linked_clone] = true
|
34
|
-
options[:host] = 'host'
|
35
|
-
allow(vm_template).to receive_message_chain(:config, :template)
|
36
|
-
.and_return(true)
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'does not set the disk move type of the relocation spec' do
|
40
|
-
expect(subject.location.diskMoveType).to be nil
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
context 'not using linked clones' do
|
45
|
-
before { options[:use_linked_clone] = false }
|
46
|
-
|
47
|
-
it 'does not set the disk move type of the relocation spec' do
|
48
|
-
expect(subject.location.diskMoveType).to be nil
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
context 'specifying a host' do
|
53
|
-
before { options[:host] = 'host' }
|
54
|
-
|
55
|
-
it 'sets the host' do
|
56
|
-
expect(subject.location.host).to_not be nil
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
context 'not specifying a host' do
|
61
|
-
it 'does not set the host' do
|
62
|
-
expect(subject.location.host).to be nil
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
context 'specifying a pool' do
|
67
|
-
before { options[:resource_pool] = 'pool' }
|
68
|
-
|
69
|
-
it 'sets the pool' do
|
70
|
-
expect(subject.location.pool).to_not be nil
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
context 'not specifying a pool' do
|
75
|
-
it 'does not set the pool' do
|
76
|
-
expect(subject.location.pool).to be nil
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
context 'not specifying a pool but specifying a host on a template' do
|
81
|
-
before do
|
82
|
-
options[:host] = 'host'
|
83
|
-
allow(vm_template).to receive_message_chain(:config, :template)
|
84
|
-
.and_return(true)
|
85
|
-
end
|
86
|
-
|
87
|
-
it 'sets the pool to the hosts parent root pool' do
|
88
|
-
expect(subject.location.pool).to be subject.location.host.parent.resourcePool
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
context 'not specifying a pool or host when cloning from a template' do
|
93
|
-
before do
|
94
|
-
allow(vm_template).to receive_message_chain(:config, :template)
|
95
|
-
.and_return(true)
|
96
|
-
end
|
97
|
-
|
98
|
-
it 'raises an error' do
|
99
|
-
expect { subject.to raise_error }
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
module ChefProvisioningVsphereStubs
|
2
|
-
class VsphereHelperStub < ChefProvisioningVsphere::VsphereHelper
|
3
|
-
def initialize
|
4
|
-
end
|
5
|
-
|
6
|
-
def network_device_changes(action_handler, vm_template, options)
|
7
|
-
[
|
8
|
-
[RbVmomi::VIM::VirtualDeviceConfigSpec.new],
|
9
|
-
[RbVmomi::VIM::VirtualDeviceConfigSpec.new]
|
10
|
-
]
|
11
|
-
end
|
12
|
-
|
13
|
-
def find_host(host_name)
|
14
|
-
RbVmomi::VIM::HostSystem.new
|
15
|
-
end
|
16
|
-
|
17
|
-
def find_pool(pool_name)
|
18
|
-
RbVmomi::VIM::ResourcePool.new(nil, nil)
|
19
|
-
end
|
20
|
-
|
21
|
-
def find_datastore(datastore_name)
|
22
|
-
RbVmomi::VIM::Datastore.new
|
23
|
-
end
|
24
|
-
|
25
|
-
def find_customization_spec(options)
|
26
|
-
RbVmomi::VIM::CustomizationSpec.new
|
27
|
-
end
|
28
|
-
|
29
|
-
def create_delta_disk(vm_template)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
module RbVmomi
|
35
|
-
class VIM::HostSystem
|
36
|
-
attr_reader :parent
|
37
|
-
|
38
|
-
def parent
|
39
|
-
@parent ||= RbVmomi::VIM::ComputeResource.new
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
module RbVmomi
|
45
|
-
class VIM::ComputeResource
|
46
|
-
attr_reader :resourcePool
|
47
|
-
|
48
|
-
def resourcePool
|
49
|
-
@resourcePool ||= RbVmomi::VIM::ResourcePool.new(nil, nil)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|