chef-provisioning-vsphere 0.5.7 → 0.5.8
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/README.md +1 -0
- data/lib/chef/provisioning/vsphere_driver/clone_spec_builder.rb +201 -0
- data/lib/chef/provisioning/vsphere_driver/driver.rb +41 -13
- data/lib/chef/provisioning/vsphere_driver/version.rb +1 -1
- data/lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb +29 -221
- data/spec/integration_tests/vsphere_driver_spec.rb +8 -6
- data/spec/unit_tests/clone_spec_builder_spec.rb +161 -0
- data/spec/unit_tests/support/fake_action_handler.rb +7 -0
- data/spec/unit_tests/support/vsphere_helper_stub.rb +52 -0
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12dda7faea087859dd1c57ca94de5f57075f34ac
|
4
|
+
data.tar.gz: 8ed3e2836949def6569e148c067f4ee427405218
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2daa6f17429a7bc45099cf006178fd36da7f4dd684d288b67569f91dccbc2b2562271dfb049c209a237b64fc98efbd7127a4b97b2e5e4a542a020a36ebbaca8b
|
7
|
+
data.tar.gz: a7adc29123fade718ff1e960ac89d57c2a46811c11ce95ac32cf75252f6c4b95879a55fcf9e56920423861c737c765260e3db13846de2e298b2a81a2807a84e8
|
data/README.md
CHANGED
@@ -76,6 +76,7 @@ This will use chef-zero and needs no chef server (only works for ssh). Note that
|
|
76
76
|
- `[:use_linked_clone]` - (true/false) great for testing but not recommended for production.
|
77
77
|
- `[:datacenter]` - Name of vsphere datacenter (*required*)
|
78
78
|
- `[:template_name]` - path to vmware template (can be template or a shutown vm) (*required*)
|
79
|
+
- `[:template_folder]` - path to a folder containing the template (do not use if template is in the root vm folder)
|
79
80
|
- `[:vm_folder]` - path to a folder where the machine will be created.
|
80
81
|
- `[:datastore]` - name of datastore to use
|
81
82
|
- `[:num_cpus]` - number of cpus to allocate to machine
|
@@ -0,0 +1,201 @@
|
|
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
|
+
hostname = options[:hostname] || vm_name
|
150
|
+
test = /^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])$/
|
151
|
+
if !(hostname =~ test)
|
152
|
+
raise 'Only letters, numbers or hyphens in hostnames allowed'
|
153
|
+
end
|
154
|
+
RbVmomi::VIM::CustomizationFixedName.new(:name => hostname)
|
155
|
+
end
|
156
|
+
|
157
|
+
def windows_prep_for(options, vm_name)
|
158
|
+
cust_options = options[:customization_spec]
|
159
|
+
cust_runonce = RbVmomi::VIM::CustomizationGuiRunOnce.new(
|
160
|
+
:commandList => [
|
161
|
+
'winrm set winrm/config/client/auth @{Basic="true"}',
|
162
|
+
'winrm set winrm/config/service/auth @{Basic="true"}',
|
163
|
+
'winrm set winrm/config/service @{AllowUnencrypted="true"}',
|
164
|
+
'shutdown -l'])
|
165
|
+
|
166
|
+
cust_login_password = RbVmomi::VIM::CustomizationPassword(
|
167
|
+
:plainText => true,
|
168
|
+
:value => options[:ssh][:password])
|
169
|
+
if cust_options.has_key?(:domain) and cust_options[:domain] != 'local'
|
170
|
+
cust_domain_password = RbVmomi::VIM::CustomizationPassword(
|
171
|
+
:plainText => true,
|
172
|
+
:value => ENV['domainAdminPassword'] || cust_options[:domainAdminPassword])
|
173
|
+
cust_id = RbVmomi::VIM::CustomizationIdentification.new(
|
174
|
+
:joinDomain => cust_options[:domain],
|
175
|
+
:domainAdmin => cust_options[:domainAdmin],
|
176
|
+
:domainAdminPassword => cust_domain_password)
|
177
|
+
#puts "my env passwd is: #{ENV['domainAdminPassword']}"
|
178
|
+
action_handler.report_progress "joining domain #{cust_options[:domain]} /
|
179
|
+
with user: #{cust_options[:domainAdmin]}"
|
180
|
+
else
|
181
|
+
cust_id = RbVmomi::VIM::CustomizationIdentification.new(
|
182
|
+
:joinWorkgroup => 'WORKGROUP')
|
183
|
+
end
|
184
|
+
cust_gui_unattended = RbVmomi::VIM::CustomizationGuiUnattended.new(
|
185
|
+
:autoLogon => true,
|
186
|
+
:autoLogonCount => 1,
|
187
|
+
:password => cust_login_password,
|
188
|
+
:timeZone => cust_options[:win_time_zone])
|
189
|
+
cust_userdata = RbVmomi::VIM::CustomizationUserData.new(
|
190
|
+
:computerName => hostname_from(cust_options, vm_name),
|
191
|
+
:fullName => cust_options[:org_name],
|
192
|
+
:orgName => cust_options[:org_name],
|
193
|
+
:productId => cust_options[:product_id])
|
194
|
+
RbVmomi::VIM::CustomizationSysprep.new(
|
195
|
+
:guiRunOnce => cust_runonce,
|
196
|
+
:identification => cust_id,
|
197
|
+
:guiUnattended => cust_gui_unattended,
|
198
|
+
:userData => cust_userdata)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
@@ -3,6 +3,7 @@ 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'
|
6
7
|
require 'chef/provisioning/vsphere_driver/version'
|
7
8
|
require 'chef/provisioning/vsphere_driver/vsphere_helpers'
|
8
9
|
require 'chef/provisioning/vsphere_driver/vsphere_url'
|
@@ -11,7 +12,6 @@ module ChefProvisioningVsphere
|
|
11
12
|
# Provisions machines in vSphere.
|
12
13
|
class VsphereDriver < Chef::Provisioning::Driver
|
13
14
|
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 = find_vm(
|
166
|
+
vm = vsphere_helper.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 = add_extra_nic(
|
234
|
+
new_nics = vsphere_helper.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
|
-
start_vm(vm)
|
316
|
+
vsphere_helper.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
|
-
stop_vm(vm)
|
398
|
+
vsphere_helper.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
|
-
start_vm(vm, machine_options[:bootstrap_options][:ssh][:port])
|
408
|
+
vsphere_helper.start_vm(vm, machine_options[:bootstrap_options][:ssh][:port])
|
409
409
|
end
|
410
410
|
end
|
411
411
|
vm
|
@@ -484,25 +484,53 @@ module ChefProvisioningVsphere
|
|
484
484
|
|
485
485
|
def vm_for(machine_spec)
|
486
486
|
if machine_spec.location
|
487
|
-
find_vm_by_id(machine_spec.location['server_id'])
|
487
|
+
vsphere_helper.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
|
-
|
494
|
+
vm_template = vm_template_for(bootstrap_options)
|
495
|
+
|
496
|
+
spec_builder = CloneSpecBuilder.new(vsphere_helper, action_handler)
|
497
|
+
clone_spec = spec_builder.build(vm_template, machine_name, bootstrap_options)
|
498
|
+
Chef::Log.debug("Clone spec: #{clone_spec.pretty_inspect}")
|
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]
|
499
527
|
)
|
500
528
|
end
|
501
529
|
|
502
530
|
def vm_template_for(bootstrap_options)
|
503
531
|
template_folder = bootstrap_options[:template_folder]
|
504
532
|
template_name = bootstrap_options[:template_name]
|
505
|
-
find_vm(template_folder, template_name) ||
|
533
|
+
vsphere_helper.find_vm(template_folder, template_name) ||
|
506
534
|
raise("vSphere VM Template not found [#{template_folder}/#{template_name}]")
|
507
535
|
end
|
508
536
|
|
@@ -1,16 +1,24 @@
|
|
1
1
|
require 'rbvmomi'
|
2
2
|
|
3
3
|
module ChefProvisioningVsphere
|
4
|
-
|
4
|
+
class VsphereHelper
|
5
5
|
|
6
6
|
if !$guest_op_managers
|
7
7
|
$guest_op_managers = {}
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
10
|
+
def initialize(connect_options, datacenter_name)
|
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
|
11
19
|
if @current_connection.nil? or @current_connection.serviceContent.sessionManager.currentSession.nil?
|
12
|
-
puts "establishing connection to #{
|
13
|
-
@current_connection = RbVmomi::VIM.connect
|
20
|
+
puts "establishing connection to #{connect_options[:host]}"
|
21
|
+
@current_connection = RbVmomi::VIM.connect connect_options
|
14
22
|
str_conn = @current_connection.pretty_inspect # a string in the format of VIM(host ip)
|
15
23
|
|
16
24
|
# we are caching guest operation managers in a global variable...terrible i know
|
@@ -31,22 +39,14 @@ module ChefProvisioningVsphere
|
|
31
39
|
folder.find(vm_name, RbVmomi::VIM::VirtualMachine)
|
32
40
|
end
|
33
41
|
|
34
|
-
def find_vm_by_id(uuid
|
35
|
-
vm =
|
42
|
+
def find_vm_by_id(uuid)
|
43
|
+
vm = vim.searchIndex.FindByUuid(
|
36
44
|
uuid: uuid,
|
37
45
|
vmSearch: true,
|
38
46
|
instanceUuid: true
|
39
47
|
)
|
40
48
|
end
|
41
49
|
|
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,31 +70,6 @@ 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
|
-
|
98
73
|
#folder could be like: /Level1/Level2/folder_name
|
99
74
|
def find_folder(folder_name)
|
100
75
|
base = datacenter.vmFolder
|
@@ -108,9 +83,8 @@ module ChefProvisioningVsphere
|
|
108
83
|
end
|
109
84
|
|
110
85
|
def datacenter
|
111
|
-
|
112
|
-
|
113
|
-
raise("vSphere Datacenter not found [#{dc_name}]")
|
86
|
+
@datacenter ||= vim.serviceInstance.find_datacenter(datacenter_name) ||
|
87
|
+
raise("vSphere Datacenter not found [#{datacenter_name}]")
|
114
88
|
end
|
115
89
|
|
116
90
|
def network_adapter_for(operation, network_name, network_label, device_key, backing_info)
|
@@ -132,56 +106,6 @@ module ChefProvisioningVsphere
|
|
132
106
|
vm.config.hardware.device.select {|d| d.is_a?(RbVmomi::VIM::VirtualEthernetCard)}
|
133
107
|
end
|
134
108
|
|
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
|
-
|
185
109
|
def add_extra_nic(action_handler, vm_template, options, vm)
|
186
110
|
deviceAdditions, changes = network_device_changes(action_handler, vm_template, options)
|
187
111
|
|
@@ -206,28 +130,6 @@ module ChefProvisioningVsphere
|
|
206
130
|
end
|
207
131
|
end
|
208
132
|
|
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
|
-
|
231
133
|
def create_delta_disk(vm_template)
|
232
134
|
disks = vm_template.config.hardware.device.grep(RbVmomi::VIM::VirtualDisk)
|
233
135
|
disks.select { |disk| disk.backing.parent == nil }.each do |disk|
|
@@ -326,114 +228,12 @@ module ChefProvisioningVsphere
|
|
326
228
|
datacenter.datastore.find { |f| f.info.name == datastore_name } or raise "no such datastore #{datastore_name}"
|
327
229
|
end
|
328
230
|
|
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
|
-
|
433
231
|
def find_entity(name, parent_folder, &block)
|
434
232
|
parts = name.split('/').reject(&:empty?)
|
435
233
|
parts.each do |item|
|
234
|
+
Chef::Log.debug("Identifying entity part: #{item} in folder type: #{parent_folder.class}")
|
436
235
|
if parent_folder.is_a? RbVmomi::VIM::Folder
|
236
|
+
Chef::Log.debug('Parent folder is a folder')
|
437
237
|
parent_folder = parent_folder.childEntity.find { |f| f.name == item }
|
438
238
|
else
|
439
239
|
parent_folder = block.call(parent_folder, item)
|
@@ -456,20 +256,28 @@ module ChefProvisioningVsphere
|
|
456
256
|
|
457
257
|
raise "vSphere Host not found [#{host_name}]" if host.nil?
|
458
258
|
|
459
|
-
if
|
460
|
-
host = host.host
|
259
|
+
if host.is_a?(RbVmomi::VIM::ComputeResource)
|
260
|
+
host = host.host.first
|
461
261
|
end
|
462
262
|
host
|
463
263
|
end
|
464
264
|
|
465
265
|
def find_pool(pool_name)
|
266
|
+
Chef::Log.debug("Finding pool: #{pool_name}")
|
466
267
|
pool = find_entity(pool_name, datacenter.hostFolder) do |parent, part|
|
467
268
|
case parent
|
468
|
-
when RbVmomi::VIM::ClusterComputeResource
|
269
|
+
when RbVmomi::VIM::ClusterComputeResource, RbVmomi::VIM::ComputeResource
|
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 ) }
|
469
273
|
parent.resourcePool.resourcePool.find { |f| f.name == part }
|
470
274
|
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 ) }
|
471
278
|
parent.resourcePool.find { |f| f.name == part }
|
472
279
|
else
|
280
|
+
Chef::Log.debug("parent of #{part} is unexpected type: #{parent.class}")
|
473
281
|
nil
|
474
282
|
end
|
475
283
|
end
|
@@ -34,12 +34,11 @@ require 'chef/provisioning/machine_spec'
|
|
34
34
|
# }
|
35
35
|
|
36
36
|
describe 'vsphere_driver' do
|
37
|
-
include ChefProvisioningVsphere::Helpers
|
38
|
-
|
39
37
|
before :all do
|
40
38
|
@vm_name = "cmvd-test-#{SecureRandom.hex}"
|
41
39
|
@metal_config = eval File.read(File.expand_path('../config.rb', __FILE__))
|
42
40
|
Cheffish.honor_local_mode do
|
41
|
+
Chef::Log.level = :debug
|
43
42
|
chef_server = Cheffish.default_chef_server
|
44
43
|
@machine_spec = Chef::Provisioning.chef_managed_entry_store(chef_server).new_entry(:machine, @vm_name)
|
45
44
|
url = URI::VsphereUrl.from_config(@metal_config[:driver_options]).to_s
|
@@ -49,8 +48,11 @@ describe 'vsphere_driver' do
|
|
49
48
|
@metal_config[:machine_options][:convergence_options] = {:chef_server => chef_server}
|
50
49
|
machine = @driver.ready_machine(action_handler, @machine_spec, @metal_config[:machine_options])
|
51
50
|
@server_id = @machine_spec.location['server_id']
|
52
|
-
@
|
53
|
-
|
51
|
+
@vsphere_helper = ChefProvisioningVsphere::VsphereHelper.new(
|
52
|
+
@metal_config[:driver_options],
|
53
|
+
@metal_config[:machine_options][:bootstrap_options][:datacenter]
|
54
|
+
)
|
55
|
+
@vm = @vsphere_helper.find_vm_by_id(@server_id)
|
54
56
|
end
|
55
57
|
end
|
56
58
|
|
@@ -101,7 +103,7 @@ describe 'vsphere_driver' do
|
|
101
103
|
end
|
102
104
|
end
|
103
105
|
it 'is in the correct datacenter' do
|
104
|
-
expect(@
|
106
|
+
expect(@vsphere_helper.vim.serviceInstance.find_datacenter(@metal_config[:machine_options][:bootstrap_options][:datacenter]).find_vm("#{@vm.parent.name}/#{@vm_name}")).not_to eq(nil)
|
105
107
|
end
|
106
108
|
it 'has an added disk of the correct size' do
|
107
109
|
disk_count = @vm.disks.count
|
@@ -146,7 +148,7 @@ describe 'vsphere_driver' do
|
|
146
148
|
@metal_config[:machine_options]
|
147
149
|
)
|
148
150
|
end
|
149
|
-
vm = find_vm_by_id(@server_id
|
151
|
+
vm = @vsphere_helper.find_vm_by_id(@server_id)
|
150
152
|
expect(vm).to eq(nil)
|
151
153
|
end
|
152
154
|
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'chef/provisioning/vsphere_driver'
|
2
|
+
require_relative 'support/fake_action_handler'
|
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
|
+
.and_return('guest')
|
12
|
+
allow(vm_template).to receive_message_chain(:config, :template)
|
13
|
+
.and_return(false)
|
14
|
+
end
|
15
|
+
|
16
|
+
subject do
|
17
|
+
builder = ChefProvisioningVsphere::CloneSpecBuilder.new(
|
18
|
+
ChefProvisioningVsphereStubs::VsphereHelperStub.new,
|
19
|
+
ChefProvisioningVsphereStubs::FakeActionHandler.new
|
20
|
+
)
|
21
|
+
builder.build(vm_template, 'machine_name', options)
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'using linked clones' do
|
25
|
+
before { options[:use_linked_clone] = true }
|
26
|
+
|
27
|
+
it 'sets the disk move type of the relocation spec' do
|
28
|
+
expect(subject.location.diskMoveType).to be :moveChildMostDiskBacking
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'using linked clone on a template source' do
|
33
|
+
before do
|
34
|
+
options[:use_linked_clone] = true
|
35
|
+
options[:host] = 'host'
|
36
|
+
allow(vm_template).to receive_message_chain(:config, :template)
|
37
|
+
.and_return(true)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'does not set the disk move type of the relocation spec' do
|
41
|
+
expect(subject.location.diskMoveType).to be nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'not using linked clones' do
|
46
|
+
before { options[:use_linked_clone] = false }
|
47
|
+
|
48
|
+
it 'does not set the disk move type of the relocation spec' do
|
49
|
+
expect(subject.location.diskMoveType).to be nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'specifying a host' do
|
54
|
+
before { options[:host] = 'host' }
|
55
|
+
|
56
|
+
it 'sets the host' do
|
57
|
+
expect(subject.location.host).to_not be nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'not specifying a host' do
|
62
|
+
it 'does not set the host' do
|
63
|
+
expect(subject.location.host).to be nil
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'specifying a pool' do
|
68
|
+
before { options[:resource_pool] = 'pool' }
|
69
|
+
|
70
|
+
it 'sets the pool' do
|
71
|
+
expect(subject.location.pool).to_not be nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'not specifying a pool' do
|
76
|
+
it 'does not set the pool' do
|
77
|
+
expect(subject.location.pool).to be nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'not specifying a pool but specifying a host on a template' do
|
82
|
+
before do
|
83
|
+
options[:host] = 'host'
|
84
|
+
allow(vm_template).to receive_message_chain(:config, :template)
|
85
|
+
.and_return(true)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'sets the pool to the hosts parent root pool' do
|
89
|
+
expect(subject.location.pool).to be subject.location.host.parent.resourcePool
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'not specifying a pool or host when cloning from a template' do
|
94
|
+
before do
|
95
|
+
allow(vm_template).to receive_message_chain(:config, :template)
|
96
|
+
.and_return(true)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'raises an error' do
|
100
|
+
expect { subject }.to raise_error
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'specifying a hostname' do
|
105
|
+
before do
|
106
|
+
options[:customization_spec] = {
|
107
|
+
ipsettings: {},
|
108
|
+
hostname: hostname,
|
109
|
+
domain: 'local'
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'alpha characters only' do
|
114
|
+
let(:hostname) { 'myhost' }
|
115
|
+
|
116
|
+
it 'sets the spec hostname' do
|
117
|
+
expect(subject.customization.identity.hostName.name).to eq hostname
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'alpha numeric characters only' do
|
122
|
+
let(:hostname) { 'myhost01' }
|
123
|
+
|
124
|
+
it 'sets the spec hostname' do
|
125
|
+
expect(subject.customization.identity.hostName.name).to eq hostname
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'containing a dash' do
|
130
|
+
let(:hostname) { 'my-host01' }
|
131
|
+
|
132
|
+
it 'sets the spec hostname' do
|
133
|
+
expect(subject.customization.identity.hostName.name).to eq hostname
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context 'containing an underscore' do
|
138
|
+
let(:hostname) { 'my_host' }
|
139
|
+
|
140
|
+
it 'raises an error' do
|
141
|
+
expect { subject }.to raise_error
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'starting with a dash' do
|
146
|
+
let(:hostname) { '-myhost' }
|
147
|
+
|
148
|
+
it 'raises an error' do
|
149
|
+
expect { subject }.to raise_error
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'ending with a dash' do
|
154
|
+
let(:hostname) { 'myhost-' }
|
155
|
+
|
156
|
+
it 'raises an error' do
|
157
|
+
expect { subject }.to raise_error
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,52 @@
|
|
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
|
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.
|
4
|
+
version: 0.5.8
|
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-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rbvmomi
|
@@ -103,6 +103,7 @@ 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
|
106
107
|
- lib/chef/provisioning/vsphere_driver/driver.rb
|
107
108
|
- lib/chef/provisioning/vsphere_driver/version.rb
|
108
109
|
- lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb
|
@@ -112,6 +113,9 @@ files:
|
|
112
113
|
- spec/integration_tests/vsphere_driver_spec.rb
|
113
114
|
- spec/unit_tests/VsphereDriver_spec.rb
|
114
115
|
- spec/unit_tests/VsphereUrl_spec.rb
|
116
|
+
- spec/unit_tests/clone_spec_builder_spec.rb
|
117
|
+
- spec/unit_tests/support/fake_action_handler.rb
|
118
|
+
- spec/unit_tests/support/vsphere_helper_stub.rb
|
115
119
|
homepage: https://github.com/tier3/chef-provisioning-vsphere
|
116
120
|
licenses:
|
117
121
|
- MIT
|
@@ -141,4 +145,7 @@ test_files:
|
|
141
145
|
- spec/integration_tests/vsphere_driver_spec.rb
|
142
146
|
- spec/unit_tests/VsphereDriver_spec.rb
|
143
147
|
- spec/unit_tests/VsphereUrl_spec.rb
|
148
|
+
- spec/unit_tests/clone_spec_builder_spec.rb
|
149
|
+
- spec/unit_tests/support/fake_action_handler.rb
|
150
|
+
- spec/unit_tests/support/vsphere_helper_stub.rb
|
144
151
|
has_rdoc:
|