clc-chef-provisioning-vsphere 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/Gemfile +5 -0
- data/README.md +90 -0
- data/Rakefile +17 -0
- data/chef-provisioning-vsphere.gemspec +28 -0
- data/lib/chef/provisioning/driver_init/vsphere.rb +3 -0
- data/lib/chef/provisioning/vsphere_driver.rb +13 -0
- data/lib/chef/provisioning/vsphere_driver/driver.rb +526 -0
- data/lib/chef/provisioning/vsphere_driver/version.rb +3 -0
- data/lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb +506 -0
- data/lib/chef/provisioning/vsphere_driver/vsphere_url.rb +31 -0
- data/lib/kitchen/driver/vsphere.rb +85 -0
- data/spec/integration_tests/.gitignore +1 -0
- data/spec/integration_tests/vsphere_driver_spec.rb +147 -0
- data/spec/unit_tests/VsphereDriver_spec.rb +206 -0
- data/spec/unit_tests/VsphereUrl_spec.rb +60 -0
- metadata +127 -0
@@ -0,0 +1,506 @@
|
|
1
|
+
require 'rbvmomi'
|
2
|
+
|
3
|
+
module ChefProvisioningVsphere
|
4
|
+
module Helpers
|
5
|
+
|
6
|
+
if !$guest_op_managers
|
7
|
+
$guest_op_managers = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def vim(options = connect_options)
|
11
|
+
if @current_connection.nil? or @current_connection.serviceContent.sessionManager.currentSession.nil?
|
12
|
+
puts "establishing connection to #{options[:host]}"
|
13
|
+
@current_connection = RbVmomi::VIM.connect options
|
14
|
+
str_conn = @current_connection.pretty_inspect # a string in the format of VIM(host ip)
|
15
|
+
|
16
|
+
# we are caching guest operation managers in a global variable...terrible i know
|
17
|
+
# this object is available from the serviceContent object on API version 5 forward
|
18
|
+
# Its a singleton and if another connection is made for the same host and user
|
19
|
+
# that object is not available on any subsequent connection
|
20
|
+
# I could find no documentation that discusses this
|
21
|
+
if !$guest_op_managers.has_key?(str_conn)
|
22
|
+
$guest_op_managers[str_conn] = @current_connection.serviceContent.guestOperationsManager
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
@current_connection
|
27
|
+
end
|
28
|
+
|
29
|
+
def find_vm(dc_name, vm_folder, vm_name)
|
30
|
+
folder = find_folder(dc_name, vm_folder) or raise("vSphere Folder not found [#{vm_folder}] for vm #{vm_name}")
|
31
|
+
vm = folder.find(vm_name, RbVmomi::VIM::VirtualMachine)
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_vm_by_id(uuid, connection = vim)
|
35
|
+
vm = connection.searchIndex.FindByUuid({:uuid => uuid, :vmSearch => true, :instanceUuid => true})
|
36
|
+
end
|
37
|
+
|
38
|
+
def vm_started?(vm, wait_on_port = 22)
|
39
|
+
return false if vm.nil?
|
40
|
+
state = vm.runtime.powerState
|
41
|
+
return false unless state == 'poweredOn'
|
42
|
+
return false unless port_ready?(vm, wait_on_port)
|
43
|
+
return true
|
44
|
+
end
|
45
|
+
|
46
|
+
def vm_stopped?(vm)
|
47
|
+
return true if vm.nil?
|
48
|
+
state = vm.runtime.powerState
|
49
|
+
return false unless state == 'poweredOff'
|
50
|
+
return false
|
51
|
+
end
|
52
|
+
|
53
|
+
def start_vm(vm, wait_on_port = 22)
|
54
|
+
state = vm.runtime.powerState
|
55
|
+
unless state == 'poweredOn'
|
56
|
+
vm.PowerOnVM_Task.wait_for_completion
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def stop_vm(vm)
|
61
|
+
begin
|
62
|
+
vm.ShutdownGuest
|
63
|
+
sleep 2 until vm.runtime.powerState == 'poweredOff'
|
64
|
+
rescue
|
65
|
+
vm.PowerOffVM_Task.wait_for_completion
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def port_ready?(vm, port)
|
70
|
+
vm_ip = vm.guest.ipAddress
|
71
|
+
return false if vm_ip.nil?
|
72
|
+
|
73
|
+
begin
|
74
|
+
tcp_socket = TCPSocket.new(vm_ip, port)
|
75
|
+
readable = IO.select([tcp_socket], nil, nil, 5)
|
76
|
+
if readable
|
77
|
+
true
|
78
|
+
else
|
79
|
+
false
|
80
|
+
end
|
81
|
+
rescue Errno::ETIMEDOUT
|
82
|
+
false
|
83
|
+
rescue Errno::EPERM
|
84
|
+
false
|
85
|
+
rescue Errno::ECONNREFUSED
|
86
|
+
false
|
87
|
+
rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH
|
88
|
+
false
|
89
|
+
ensure
|
90
|
+
tcp_socket && tcp_socket.close
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
#folder could be like: /Level1/Level2/folder_name
|
95
|
+
def find_folder(dc_name, folder_name)
|
96
|
+
baseEntity = dc(dc_name).vmFolder
|
97
|
+
if folder_name && folder_name.length > 0
|
98
|
+
entityArray = folder_name.split('/')
|
99
|
+
entityArray.each do |entityArrItem|
|
100
|
+
if entityArrItem != ''
|
101
|
+
baseEntity = baseEntity.childEntity.grep(RbVmomi::VIM::Folder).find { |f| f.name == entityArrItem }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
baseEntity
|
106
|
+
end
|
107
|
+
|
108
|
+
def dc(dc_name)
|
109
|
+
vim.serviceInstance.find_datacenter(dc_name) or raise("vSphere Datacenter not found [#{dc_name}]")
|
110
|
+
end
|
111
|
+
|
112
|
+
def network_adapter_for(operation, network_name, network_label, device_key, backing_info)
|
113
|
+
connectable = RbVmomi::VIM::VirtualDeviceConnectInfo(
|
114
|
+
:allowGuestControl => true,
|
115
|
+
:connected => true,
|
116
|
+
:startConnected => true)
|
117
|
+
device = RbVmomi::VIM::VirtualVmxnet3(
|
118
|
+
:backing => backing_info,
|
119
|
+
:deviceInfo => RbVmomi::VIM::Description(:label => network_label, :summary => network_name),
|
120
|
+
:key => device_key,
|
121
|
+
:connectable => connectable)
|
122
|
+
RbVmomi::VIM::VirtualDeviceConfigSpec(
|
123
|
+
:operation => operation,
|
124
|
+
:device => device)
|
125
|
+
end
|
126
|
+
|
127
|
+
def find_ethernet_cards_for(vm)
|
128
|
+
vm.config.hardware.device.select {|d| d.is_a?(RbVmomi::VIM::VirtualEthernetCard)}
|
129
|
+
end
|
130
|
+
|
131
|
+
def do_vm_clone(action_handler, dc_name, vm_template, vm_name, options)
|
132
|
+
deviceAdditions = []
|
133
|
+
|
134
|
+
clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(
|
135
|
+
location: relocate_spec_for(dc_name, vm_template, options),
|
136
|
+
powerOn: false,
|
137
|
+
template: false,
|
138
|
+
config: RbVmomi::VIM.VirtualMachineConfigSpec(
|
139
|
+
:cpuHotAddEnabled => true,
|
140
|
+
:memoryHotAddEnabled => true,
|
141
|
+
:cpuHotRemoveEnabled => true,
|
142
|
+
:deviceChange => Array.new)
|
143
|
+
)
|
144
|
+
|
145
|
+
clone_spec.customization = customization_options_from(action_handler, vm_template, vm_name, options)
|
146
|
+
|
147
|
+
unless options[:annotation].to_s.nil?
|
148
|
+
clone_spec.config.annotation = options[:annotation]
|
149
|
+
end
|
150
|
+
|
151
|
+
unless options[:num_cpus].to_s.nil?
|
152
|
+
clone_spec.config.numCPUs = options[:num_cpus]
|
153
|
+
end
|
154
|
+
|
155
|
+
unless options[:memory_mb].to_s.nil?
|
156
|
+
clone_spec.config.memoryMB = options[:memory_mb]
|
157
|
+
end
|
158
|
+
|
159
|
+
unless options[:network_name].nil?
|
160
|
+
deviceAdditions, changes = network_device_changes(action_handler, vm_template, options)
|
161
|
+
clone_spec.config.deviceChange = changes
|
162
|
+
end
|
163
|
+
|
164
|
+
vm_template.CloneVM_Task(
|
165
|
+
name: vm_name,
|
166
|
+
folder: find_folder(dc_name, options[:vm_folder]),
|
167
|
+
spec: clone_spec
|
168
|
+
).wait_for_completion
|
169
|
+
|
170
|
+
vm = find_vm(dc_name, options[:vm_folder], vm_name)
|
171
|
+
|
172
|
+
if options[:additional_disk_size_gb].to_i > 0
|
173
|
+
task = vm.ReconfigVM_Task(:spec => RbVmomi::VIM.VirtualMachineConfigSpec(:deviceChange => [virtual_disk_for(vm, options)]))
|
174
|
+
task.wait_for_completion
|
175
|
+
end
|
176
|
+
|
177
|
+
vm
|
178
|
+
end
|
179
|
+
|
180
|
+
def add_extra_nic(action_handler, vm_template, options, vm)
|
181
|
+
deviceAdditions, changes = network_device_changes(action_handler, vm_template, options)
|
182
|
+
|
183
|
+
if deviceAdditions.count > 0
|
184
|
+
current_networks = find_ethernet_cards_for(vm).map{|card| network_id_for(card.backing)}
|
185
|
+
new_devices = deviceAdditions.select { |device| !current_networks.include?(network_id_for(device.device.backing))}
|
186
|
+
|
187
|
+
if new_devices.count > 0
|
188
|
+
action_handler.report_progress "Adding extra NICs"
|
189
|
+
task = vm.ReconfigVM_Task(:spec => RbVmomi::VIM.VirtualMachineConfigSpec(:deviceChange => new_devices))
|
190
|
+
task.wait_for_completion
|
191
|
+
new_devices
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def network_id_for(backing_info)
|
197
|
+
if backing_info.is_a?(RbVmomi::VIM::VirtualEthernetCardDistributedVirtualPortBackingInfo)
|
198
|
+
backing_info.port.portgroupKey
|
199
|
+
else
|
200
|
+
backing_info.network
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def relocate_spec_for(dc_name, vm_template, options)
|
205
|
+
datacenter = dc(dc_name)
|
206
|
+
if options.has_key?(:host)
|
207
|
+
host = find_host(datacenter, options[:host])
|
208
|
+
rspec = RbVmomi::VIM.VirtualMachineRelocateSpec(host: host)
|
209
|
+
else
|
210
|
+
pool = options[:resource_pool] ? find_pool(datacenter, options[:resource_pool]) : vm_template.resourcePool
|
211
|
+
rspec = RbVmomi::VIM.VirtualMachineRelocateSpec(pool: pool)
|
212
|
+
raise 'either :host or :resource_pool must be specified when cloning from a VM Template' if pool.nil?
|
213
|
+
end
|
214
|
+
|
215
|
+
if options.has_key?(:use_linked_clone)
|
216
|
+
create_delta_disk(vm_template)
|
217
|
+
rspec.diskMoveType = :moveChildMostDiskBacking
|
218
|
+
end
|
219
|
+
|
220
|
+
unless options[:datastore].to_s.empty?
|
221
|
+
rspec.datastore = find_datastore(datacenter, options[:datastore])
|
222
|
+
end
|
223
|
+
|
224
|
+
rspec
|
225
|
+
end
|
226
|
+
|
227
|
+
def create_delta_disk(vm_template)
|
228
|
+
disks = vm_template.config.hardware.device.grep(RbVmomi::VIM::VirtualDisk)
|
229
|
+
disks.select { |disk| disk.backing.parent == nil }.each do |disk|
|
230
|
+
spec = {
|
231
|
+
:deviceChange => [
|
232
|
+
{
|
233
|
+
:operation => :remove,
|
234
|
+
:device => disk
|
235
|
+
},
|
236
|
+
{
|
237
|
+
:operation => :add,
|
238
|
+
:fileOperation => :create,
|
239
|
+
:device => disk.dup.tap { |new_disk|
|
240
|
+
new_disk.backing = new_disk.backing.dup
|
241
|
+
new_disk.backing.fileName = "[#{disk.backing.datastore.name}]"
|
242
|
+
new_disk.backing.parent = disk.backing
|
243
|
+
},
|
244
|
+
}
|
245
|
+
]
|
246
|
+
}
|
247
|
+
vm_template.ReconfigVM_Task(:spec => spec).wait_for_completion
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def virtual_disk_for(vm, options)
|
252
|
+
if options[:datastore].to_s.empty?
|
253
|
+
raise ":datastore must be specified when adding a disk to a cloned vm"
|
254
|
+
end
|
255
|
+
idx = vm.disks.count
|
256
|
+
RbVmomi::VIM::VirtualDeviceConfigSpec(
|
257
|
+
:operation => :add,
|
258
|
+
:fileOperation => :create,
|
259
|
+
:device => RbVmomi::VIM.VirtualDisk(
|
260
|
+
:key => idx,
|
261
|
+
:backing => RbVmomi::VIM.VirtualDiskFlatVer2BackingInfo(
|
262
|
+
:fileName => "[#{options[:datastore]}]",
|
263
|
+
:diskMode => 'persistent',
|
264
|
+
:thinProvisioned => true
|
265
|
+
),
|
266
|
+
:capacityInKB => options[:additional_disk_size_gb] * 1024 * 1024,
|
267
|
+
:controllerKey => 1000,
|
268
|
+
:unitNumber => idx
|
269
|
+
)
|
270
|
+
)
|
271
|
+
end
|
272
|
+
|
273
|
+
def network_device_changes(action_handler, vm_template, options)
|
274
|
+
additions = []
|
275
|
+
changes = []
|
276
|
+
networks=options[:network_name]
|
277
|
+
if networks.kind_of?(String)
|
278
|
+
networks=[networks]
|
279
|
+
end
|
280
|
+
|
281
|
+
cards = find_ethernet_cards_for(vm_template)
|
282
|
+
|
283
|
+
key = 4000
|
284
|
+
networks.each_index do | i |
|
285
|
+
label = "Ethernet #{i+1}"
|
286
|
+
backing_info = backing_info_for(action_handler, dc(options[:datacenter]), networks[i])
|
287
|
+
if card = cards.shift
|
288
|
+
key = card.key
|
289
|
+
operation = RbVmomi::VIM::VirtualDeviceConfigSpecOperation('edit')
|
290
|
+
action_handler.report_progress "changing template nic for #{networks[i]}"
|
291
|
+
changes.push(
|
292
|
+
network_adapter_for(operation, networks[i], label, key, backing_info))
|
293
|
+
else
|
294
|
+
key = key + 1
|
295
|
+
operation = RbVmomi::VIM::VirtualDeviceConfigSpecOperation('add')
|
296
|
+
action_handler.report_progress "will be adding nic for #{networks[i]}"
|
297
|
+
additions.push(
|
298
|
+
network_adapter_for(operation, networks[i], label, key, backing_info))
|
299
|
+
end
|
300
|
+
end
|
301
|
+
[additions, changes]
|
302
|
+
end
|
303
|
+
|
304
|
+
def backing_info_for(action_handler, datacenter, network_name)
|
305
|
+
networks = datacenter.network.select {|net| net.name == network_name}
|
306
|
+
if networks.count > 0
|
307
|
+
dpg = networks.select { |net| net.is_a?(RbVmomi::VIM::DistributedVirtualPortgroup) }
|
308
|
+
networks = dpg unless dpg.empty?
|
309
|
+
end
|
310
|
+
action_handler.report_progress "network: #{network_name} is a #{networks[0].class}}"
|
311
|
+
if networks[0].is_a?(RbVmomi::VIM::DistributedVirtualPortgroup)
|
312
|
+
port = RbVmomi::VIM::DistributedVirtualSwitchPortConnection(
|
313
|
+
:switchUuid => networks[0].config.distributedVirtualSwitch.uuid,
|
314
|
+
:portgroupKey => networks[0].key
|
315
|
+
)
|
316
|
+
RbVmomi::VIM::VirtualEthernetCardDistributedVirtualPortBackingInfo(:port => port)
|
317
|
+
else
|
318
|
+
RbVmomi::VIM::VirtualEthernetCardNetworkBackingInfo(:deviceName => network_name)
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
def find_datastore(dc, datastore_name)
|
323
|
+
baseEntity = dc.datastore
|
324
|
+
baseEntity.find { |f| f.info.name == datastore_name } or raise "no such datastore #{datastore_name}"
|
325
|
+
end
|
326
|
+
|
327
|
+
def customization_options_from(action_handler, vm_template, vm_name, options)
|
328
|
+
if options.has_key?(:customization_spec)
|
329
|
+
if(options[:customization_spec].is_a?(Hash))
|
330
|
+
cust_options = options[:customization_spec]
|
331
|
+
raise ArgumentError, "domain is required" unless cust_options.key?(:domain)
|
332
|
+
cust_ip_settings = nil
|
333
|
+
if cust_options.key?(:ipsettings) and cust_options[:ipsettings].key?(:ip)
|
334
|
+
raise ArgumentError, "ip and subnetMask is required for static ip" unless cust_options[:ipsettings].key?(:ip) and
|
335
|
+
cust_options[:ipsettings].key?(:subnetMask)
|
336
|
+
cust_ip_settings = RbVmomi::VIM::CustomizationIPSettings.new(cust_options[:ipsettings])
|
337
|
+
action_handler.report_progress "customizing #{vm_name} with static IP #{cust_options[:ipsettings][:ip]}"
|
338
|
+
cust_ip_settings.ip = RbVmomi::VIM::CustomizationFixedIp(:ipAddress => cust_options[:ipsettings][:ip])
|
339
|
+
end
|
340
|
+
cust_domain = cust_options[:domain]
|
341
|
+
if cust_ip_settings.nil?
|
342
|
+
cust_ip_settings= RbVmomi::VIM::CustomizationIPSettings.new(:ip => RbVmomi::VIM::CustomizationDhcpIpGenerator.new())
|
343
|
+
cust_ip_settings.dnsServerList = cust_options[:ipsettings][:dnsServerList]
|
344
|
+
action_handler.report_progress "customizing #{vm_name} with dynamic IP and DNS: #{cust_options[:ipsettings][:dnsServerList]}"
|
345
|
+
end
|
346
|
+
|
347
|
+
cust_ip_settings.dnsDomain = cust_domain
|
348
|
+
cust_global_ip_settings = RbVmomi::VIM::CustomizationGlobalIPSettings.new
|
349
|
+
cust_global_ip_settings.dnsServerList = cust_ip_settings.dnsServerList
|
350
|
+
cust_global_ip_settings.dnsSuffixList = [cust_domain]
|
351
|
+
cust_hostname = hostname_from(options[:customization_spec], vm_name)
|
352
|
+
cust_hwclockutc = cust_options[:hw_clock_utc]
|
353
|
+
cust_timezone = cust_options[:time_zone]
|
354
|
+
|
355
|
+
if vm_template.config.guestId.start_with?('win')
|
356
|
+
cust_prep = windows_prep_for(action_handler, options, vm_name)
|
357
|
+
else
|
358
|
+
cust_prep = RbVmomi::VIM::CustomizationLinuxPrep.new(
|
359
|
+
:domain => cust_domain,
|
360
|
+
:hostName => cust_hostname,
|
361
|
+
:hwClockUTC => cust_hwclockutc,
|
362
|
+
:timeZone => cust_timezone)
|
363
|
+
end
|
364
|
+
cust_adapter_mapping = [RbVmomi::VIM::CustomizationAdapterMapping.new(:adapter => cust_ip_settings)]
|
365
|
+
RbVmomi::VIM::CustomizationSpec.new(
|
366
|
+
:identity => cust_prep,
|
367
|
+
:globalIPSettings => cust_global_ip_settings,
|
368
|
+
:nicSettingMap => cust_adapter_mapping)
|
369
|
+
else
|
370
|
+
find_customization_spec(options[:customization_spec])
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
def windows_prep_for(action_handler, options, vm_name)
|
376
|
+
cust_options = options[:customization_spec]
|
377
|
+
cust_runonce = RbVmomi::VIM::CustomizationGuiRunOnce.new(
|
378
|
+
:commandList => [
|
379
|
+
'winrm set winrm/config/client/auth @{Basic="true"}',
|
380
|
+
'winrm set winrm/config/service/auth @{Basic="true"}',
|
381
|
+
'winrm set winrm/config/service @{AllowUnencrypted="true"}',
|
382
|
+
'shutdown -l'])
|
383
|
+
|
384
|
+
cust_login_password = RbVmomi::VIM::CustomizationPassword(
|
385
|
+
:plainText => true,
|
386
|
+
:value => options[:ssh][:password])
|
387
|
+
if cust_options.has_key?(:domain) and cust_options[:domain] != 'local'
|
388
|
+
cust_domain_password = RbVmomi::VIM::CustomizationPassword(
|
389
|
+
:plainText => true,
|
390
|
+
:value => ENV['domainAdminPassword'] || cust_options[:domainAdminPassword])
|
391
|
+
cust_id = RbVmomi::VIM::CustomizationIdentification.new(
|
392
|
+
:joinDomain => cust_options[:domain],
|
393
|
+
:domainAdmin => cust_options[:domainAdmin],
|
394
|
+
:domainAdminPassword => cust_domain_password)
|
395
|
+
#puts "my env passwd is: #{ENV['domainAdminPassword']}"
|
396
|
+
action_handler.report_progress "joining domain #{cust_options[:domain]} with user: #{cust_options[:domainAdmin]}"
|
397
|
+
else
|
398
|
+
cust_id = RbVmomi::VIM::CustomizationIdentification.new(
|
399
|
+
:joinWorkgroup => 'WORKGROUP')
|
400
|
+
end
|
401
|
+
cust_gui_unattended = RbVmomi::VIM::CustomizationGuiUnattended.new(
|
402
|
+
:autoLogon => true,
|
403
|
+
:autoLogonCount => 1,
|
404
|
+
:password => cust_login_password,
|
405
|
+
:timeZone => cust_options[:win_time_zone])
|
406
|
+
cust_userdata = RbVmomi::VIM::CustomizationUserData.new(
|
407
|
+
:computerName => hostname_from(cust_options, vm_name),
|
408
|
+
:fullName => cust_options[:org_name],
|
409
|
+
:orgName => cust_options[:org_name],
|
410
|
+
:productId => cust_options[:product_id])
|
411
|
+
RbVmomi::VIM::CustomizationSysprep.new(
|
412
|
+
:guiRunOnce => cust_runonce,
|
413
|
+
:identification => cust_id,
|
414
|
+
:guiUnattended => cust_gui_unattended,
|
415
|
+
:userData => cust_userdata)
|
416
|
+
end
|
417
|
+
|
418
|
+
def hostname_from(options, vm_name)
|
419
|
+
if options.key?(:hostname)
|
420
|
+
RbVmomi::VIM::CustomizationFixedName.new(:name => options[:hostname])
|
421
|
+
else
|
422
|
+
RbVmomi::VIM::CustomizationFixedName.new(:name => vm_name)
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
def find_host(dc, host_name)
|
427
|
+
baseEntity = dc.hostFolder
|
428
|
+
entityArray = host_name.split('/')
|
429
|
+
entityArray.each do |entityArrItem|
|
430
|
+
if entityArrItem != ''
|
431
|
+
if baseEntity.is_a? RbVmomi::VIM::Folder
|
432
|
+
baseEntity = baseEntity.childEntity.find { |f| f.name == entityArrItem } or nil
|
433
|
+
elsif baseEntity.is_a? RbVmomi::VIM::ClusterComputeResource or baseEntity.is_a? RbVmomi::VIM::ComputeResource
|
434
|
+
baseEntity = baseEntity.host.find { |f| f.name == entityArrItem } or nil
|
435
|
+
elsif baseEntity.is_a? RbVmomi::VIM::HostSystem
|
436
|
+
baseEntity = baseEntity.host.find { |f| f.name == entityArrItem } or nil
|
437
|
+
else
|
438
|
+
baseEntity = nil
|
439
|
+
end
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
raise "vSphere Host not found [#{host_name}]" if baseEntity.nil?
|
444
|
+
|
445
|
+
baseEntity = baseEntity.host if not baseEntity.is_a?(RbVmomi::VIM::HostSystem) and baseEntity.respond_to?(:host)
|
446
|
+
baseEntity
|
447
|
+
end
|
448
|
+
|
449
|
+
def find_pool(dc, pool_name)
|
450
|
+
baseEntity = dc.hostFolder
|
451
|
+
entityArray = pool_name.split('/')
|
452
|
+
entityArray.each do |entityArrItem|
|
453
|
+
if entityArrItem != ''
|
454
|
+
if baseEntity.is_a? RbVmomi::VIM::Folder
|
455
|
+
baseEntity = baseEntity.childEntity.find { |f| f.name == entityArrItem } or nil
|
456
|
+
elsif baseEntity.is_a? RbVmomi::VIM::ClusterComputeResource or baseEntity.is_a? RbVmomi::VIM::ComputeResource
|
457
|
+
baseEntity = baseEntity.resourcePool.resourcePool.find { |f| f.name == entityArrItem } or nil
|
458
|
+
elsif baseEntity.is_a? RbVmomi::VIM::ResourcePool
|
459
|
+
baseEntity = baseEntity.resourcePool.find { |f| f.name == entityArrItem } or nil
|
460
|
+
else
|
461
|
+
baseEntity = nil
|
462
|
+
end
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
raise "vSphere ResourcePool not found [#{pool_name}]" if baseEntity.nil?
|
467
|
+
|
468
|
+
baseEntity = baseEntity.resourcePool if not baseEntity.is_a?(RbVmomi::VIM::ResourcePool) and baseEntity.respond_to?(:resourcePool)
|
469
|
+
baseEntity
|
470
|
+
end
|
471
|
+
|
472
|
+
def find_customization_spec(customization_spec)
|
473
|
+
csm = vim.serviceContent.customizationSpecManager
|
474
|
+
csi = csm.GetCustomizationSpec(:name => customization_spec)
|
475
|
+
spec = csi.spec
|
476
|
+
raise "Customization Spec not found [#{customization_spec}]" if spec.nil?
|
477
|
+
spec
|
478
|
+
end
|
479
|
+
|
480
|
+
def upload_file_to_vm(vm, username, password, local, remote)
|
481
|
+
auth = RbVmomi::VIM::NamePasswordAuthentication({:username => username, :password => password, :interactiveSession => false})
|
482
|
+
size = File.size(local)
|
483
|
+
endpoint = $guest_op_managers[vim.pretty_inspect].fileManager.InitiateFileTransferToGuest(
|
484
|
+
:vm => vm,
|
485
|
+
:auth => auth,
|
486
|
+
:guestFilePath => remote,
|
487
|
+
:overwrite => true,
|
488
|
+
:fileAttributes => RbVmomi::VIM::GuestWindowsFileAttributes.new,
|
489
|
+
:fileSize => size)
|
490
|
+
|
491
|
+
uri = URI.parse(endpoint)
|
492
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
493
|
+
http.use_ssl = true
|
494
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
495
|
+
|
496
|
+
req = Net::HTTP::Put.new("#{uri.path}?#{uri.query}")
|
497
|
+
req.body_stream = File.open(local)
|
498
|
+
req["Content-Type"] = "application/octet-stream"
|
499
|
+
req["Content-Length"] = size
|
500
|
+
res = http.request(req)
|
501
|
+
unless res.kind_of?(Net::HTTPSuccess)
|
502
|
+
raise "Error: #{res.inspect} :: #{res.body} :: sending #{local} to #{remote} at #{vm.name} via #{endpoint} with a size of #{size}"
|
503
|
+
end
|
504
|
+
end
|
505
|
+
end
|
506
|
+
end
|