bosh_vsphere_cpi 0.6.0 → 1.5.0.pre.1100
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/vsphere_cpi_console +35 -0
- data/db/migrations/20120123235022_initial.rb +5 -0
- data/lib/cloud/vsphere/client.rb +4 -5
- data/lib/cloud/vsphere/cloud.rb +245 -226
- data/lib/cloud/vsphere/config.rb +0 -4
- data/lib/cloud/vsphere/models/disk.rb +3 -0
- data/lib/cloud/vsphere/path_finder.rb +12 -0
- data/lib/cloud/vsphere/resources.rb +0 -2
- data/lib/cloud/vsphere/version.rb +1 -1
- data/lib/cloud/vsphere.rb +5 -3
- data/lib/ruby_vim_sdk/base_type.rb +15 -0
- data/lib/ruby_vim_sdk/const.rb +32 -0
- data/lib/ruby_vim_sdk/core_types.rb +68 -0
- data/lib/ruby_vim_sdk/data_type.rb +14 -0
- data/lib/ruby_vim_sdk/enum_type.rb +12 -0
- data/lib/ruby_vim_sdk/ext.rb +9 -0
- data/lib/ruby_vim_sdk/managed_type.rb +12 -0
- data/lib/ruby_vim_sdk/method.rb +37 -0
- data/lib/ruby_vim_sdk/missing_types.rb +11 -0
- data/lib/ruby_vim_sdk/property.rb +49 -0
- data/lib/ruby_vim_sdk/server_objects.rb +2718 -0
- data/lib/ruby_vim_sdk/soap/deserializer.rb +301 -0
- data/lib/ruby_vim_sdk/soap/serializer.rb +225 -0
- data/lib/ruby_vim_sdk/soap/stub_adapter.rb +123 -0
- data/lib/ruby_vim_sdk/soap_exception.rb +12 -0
- data/lib/ruby_vim_sdk/typed_array.rb +9 -0
- data/lib/ruby_vim_sdk/types.rb +22 -0
- data/lib/ruby_vim_sdk/version.rb +5 -0
- data/lib/ruby_vim_sdk/vmodl/data_object.rb +102 -0
- data/lib/ruby_vim_sdk/vmodl/managed_object.rb +78 -0
- data/lib/ruby_vim_sdk/vmodl/method_name.rb +7 -0
- data/lib/ruby_vim_sdk/vmodl/property_path.rb +7 -0
- data/lib/ruby_vim_sdk/vmodl/type_name.rb +7 -0
- data/lib/ruby_vim_sdk/vmodl_helper.rb +33 -0
- data/lib/ruby_vim_sdk/vmomi_support.rb +280 -0
- data/lib/ruby_vim_sdk.rb +45 -0
- metadata +65 -53
- data/Rakefile +0 -50
- data/spec/spec_helper.rb +0 -33
- data/spec/unit/cloud/vsphere/resources/cluster_spec.rb +0 -383
- data/spec/unit/cloud/vsphere/resources/datacenter_spec.rb +0 -72
- data/spec/unit/cloud/vsphere/resources/datastore_spec.rb +0 -43
- data/spec/unit/cloud/vsphere/resources/folder_spec.rb +0 -63
- data/spec/unit/cloud/vsphere/resources/resource_pool_spec.rb +0 -42
- data/spec/unit/cloud/vsphere/resources/scorer_spec.rb +0 -73
- data/spec/unit/cloud/vsphere/resources/util_spec.rb +0 -35
- data/spec/unit/cloud/vsphere/resources_spec.rb +0 -216
data/lib/cloud/vsphere/cloud.rb
CHANGED
@@ -1,26 +1,27 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
1
|
+
require 'json'
|
2
|
+
require 'membrane'
|
3
|
+
require 'ruby_vim_sdk'
|
4
|
+
require 'cloud/vsphere/client'
|
5
|
+
require 'cloud/vsphere/config'
|
6
|
+
require 'cloud/vsphere/lease_updater'
|
7
|
+
require 'cloud/vsphere/resources'
|
8
|
+
require 'cloud/vsphere/resources/cluster'
|
9
|
+
require 'cloud/vsphere/resources/datacenter'
|
10
|
+
require 'cloud/vsphere/resources/datastore'
|
11
|
+
require 'cloud/vsphere/resources/folder'
|
12
|
+
require 'cloud/vsphere/resources/resource_pool'
|
13
|
+
require 'cloud/vsphere/resources/scorer'
|
14
|
+
require 'cloud/vsphere/resources/util'
|
15
|
+
require 'cloud/vsphere/models/disk'
|
16
|
+
require 'cloud/vsphere/path_finder'
|
17
17
|
|
18
18
|
module VSphereCloud
|
19
19
|
|
20
20
|
class Cloud < Bosh::Cloud
|
21
21
|
include VimSdk
|
22
22
|
|
23
|
-
class TimeoutException < StandardError;
|
23
|
+
class TimeoutException < StandardError;
|
24
|
+
end
|
24
25
|
|
25
26
|
attr_accessor :client
|
26
27
|
|
@@ -47,10 +48,21 @@ module VSphereCloud
|
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
51
|
+
setup_at_exit
|
52
|
+
end
|
53
|
+
|
54
|
+
def setup_at_exit
|
50
55
|
# HACK: finalizer not getting called, so we'll rely on at_exit
|
51
56
|
at_exit { @client.logout }
|
52
57
|
end
|
53
58
|
|
59
|
+
def has_vm?(vm_cid)
|
60
|
+
get_vm_by_cid(vm_cid)
|
61
|
+
true
|
62
|
+
rescue Bosh::Clouds::VMNotFound
|
63
|
+
false
|
64
|
+
end
|
65
|
+
|
54
66
|
def create_stemcell(image, _)
|
55
67
|
with_thread_name("create_stemcell(#{image}, _)") do
|
56
68
|
result = nil
|
@@ -59,14 +71,13 @@ module VSphereCloud
|
|
59
71
|
output = `tar -C #{temp_dir} -xzf #{image} 2>&1`
|
60
72
|
raise "Corrupt image, tar exit status: #{$?.exitstatus} output: #{output}" if $?.exitstatus != 0
|
61
73
|
|
62
|
-
ovf_file = Dir.entries(temp_dir).find { |entry| File.extname(entry) ==
|
63
|
-
raise
|
74
|
+
ovf_file = Dir.entries(temp_dir).find { |entry| File.extname(entry) == '.ovf' }
|
75
|
+
raise 'Missing OVF' if ovf_file.nil?
|
64
76
|
ovf_file = File.join(temp_dir, ovf_file)
|
65
77
|
|
66
78
|
name = "sc-#{generate_unique_name}"
|
67
79
|
@logger.info("Generated name: #{name}")
|
68
80
|
|
69
|
-
# TODO: make stemcell friendly version of the calls below
|
70
81
|
stemcell_size = File.size(image) / (1024 * 1024)
|
71
82
|
cluster, datastore = @resources.place(0, stemcell_size, [])
|
72
83
|
@logger.info("Deploying to: #{cluster.mob} / #{datastore.mob}")
|
@@ -74,16 +85,16 @@ module VSphereCloud
|
|
74
85
|
import_spec_result = import_ovf(name, ovf_file, cluster.resource_pool.mob, datastore.mob)
|
75
86
|
lease = obtain_nfc_lease(cluster.resource_pool.mob, import_spec_result.import_spec,
|
76
87
|
cluster.datacenter.template_folder.mob)
|
77
|
-
@logger.info(
|
88
|
+
@logger.info('Waiting for NFC lease')
|
78
89
|
state = wait_for_nfc_lease(lease)
|
79
|
-
raise "Could not acquire HTTP NFC lease" unless state == Vim::HttpNfcLease::State::READY
|
90
|
+
raise "Could not acquire HTTP NFC lease (state is: #{state})" unless state == Vim::HttpNfcLease::State::READY
|
80
91
|
|
81
|
-
@logger.info(
|
92
|
+
@logger.info('Uploading')
|
82
93
|
vm = upload_ovf(ovf_file, lease, import_spec_result.file_item)
|
83
94
|
result = name
|
84
95
|
|
85
|
-
@logger.info(
|
86
|
-
devices = client.get_property(vm, Vim::VirtualMachine,
|
96
|
+
@logger.info('Removing NICs')
|
97
|
+
devices = client.get_property(vm, Vim::VirtualMachine, 'config.hardware.device', ensure_all: true)
|
87
98
|
config = Vim::Vm::ConfigSpec.new
|
88
99
|
config.device_change = []
|
89
100
|
|
@@ -94,8 +105,11 @@ module VSphereCloud
|
|
94
105
|
end
|
95
106
|
client.reconfig_vm(vm, config)
|
96
107
|
|
97
|
-
@logger.info(
|
98
|
-
|
108
|
+
@logger.info('Taking initial snapshot')
|
109
|
+
|
110
|
+
# Despite the naming, this has nothing to do with the Cloud notion of a disk snapshot
|
111
|
+
# (which comes from AWS). This is a vm snapshot.
|
112
|
+
task = vm.create_snapshot('initial', nil, false, false)
|
99
113
|
client.wait_for_task(task)
|
100
114
|
end
|
101
115
|
result
|
@@ -104,14 +118,14 @@ module VSphereCloud
|
|
104
118
|
|
105
119
|
def delete_stemcell(stemcell)
|
106
120
|
with_thread_name("delete_stemcell(#{stemcell})") do
|
107
|
-
Bosh::ThreadPool.new(:
|
121
|
+
Bosh::ThreadPool.new(max_threads: 32, logger: @logger).wrap do |pool|
|
108
122
|
@resources.datacenters.each_value do |datacenter|
|
109
123
|
@logger.info("Looking for stemcell replicas in: #{datacenter.name}")
|
110
|
-
templates = client.get_property(datacenter.template_folder.mob, Vim::Folder,
|
111
|
-
template_properties = client.get_properties(templates, Vim::VirtualMachine, [
|
124
|
+
templates = client.get_property(datacenter.template_folder.mob, Vim::Folder, 'childEntity', ensure_all: true)
|
125
|
+
template_properties = client.get_properties(templates, Vim::VirtualMachine, ['name'])
|
112
126
|
template_properties.each_value do |properties|
|
113
|
-
template_name = properties[
|
114
|
-
if template_name.split(
|
127
|
+
template_name = properties['name'].gsub('%2f', '/')
|
128
|
+
if template_name.split('/').first.strip == stemcell
|
115
129
|
@logger.info("Found: #{template_name}")
|
116
130
|
pool.process do
|
117
131
|
@logger.info("Deleting: #{template_name}")
|
@@ -129,11 +143,11 @@ module VSphereCloud
|
|
129
143
|
disks = []
|
130
144
|
if persistent_disks
|
131
145
|
persistent_disks.each do |disk_cid|
|
132
|
-
disk = Models::Disk.first(:
|
146
|
+
disk = Models::Disk.first(uuid: disk_cid)
|
133
147
|
disks << {
|
134
|
-
|
135
|
-
|
136
|
-
|
148
|
+
size: disk.size,
|
149
|
+
dc_name: disk.datacenter,
|
150
|
+
ds_name: disk.datastore
|
137
151
|
}
|
138
152
|
end
|
139
153
|
end
|
@@ -142,15 +156,14 @@ module VSphereCloud
|
|
142
156
|
|
143
157
|
def stemcell_vm(name)
|
144
158
|
dc = @resources.datacenters.values.first
|
145
|
-
client.find_by_inventory_path(
|
146
|
-
[dc.name, "vm", dc.template_folder.name, name])
|
159
|
+
client.find_by_inventory_path([dc.name, 'vm', dc.template_folder.name, name])
|
147
160
|
end
|
148
161
|
|
149
162
|
def create_vm(agent_id, stemcell, resource_pool, networks, disk_locality = nil, environment = nil)
|
150
163
|
with_thread_name("create_vm(#{agent_id}, ...)") do
|
151
|
-
memory = resource_pool[
|
152
|
-
disk = resource_pool[
|
153
|
-
cpu = resource_pool[
|
164
|
+
memory = resource_pool['ram']
|
165
|
+
disk = resource_pool['disk']
|
166
|
+
cpu = resource_pool['cpu']
|
154
167
|
|
155
168
|
# Make sure number of cores is a power of 2. kb.vmware.com/kb/2003484
|
156
169
|
if cpu & cpu - 1 != 0
|
@@ -160,9 +173,8 @@ module VSphereCloud
|
|
160
173
|
stemcell_vm = stemcell_vm(stemcell)
|
161
174
|
raise "Could not find stemcell: #{stemcell}" if stemcell_vm.nil?
|
162
175
|
|
163
|
-
stemcell_size =
|
164
|
-
|
165
|
-
:ensure_all => true)
|
176
|
+
stemcell_size =
|
177
|
+
client.get_property(stemcell_vm, Vim::VirtualMachine, 'summary.storage.committed', ensure_all: true)
|
166
178
|
stemcell_size /= 1024 * 1024
|
167
179
|
|
168
180
|
disks = disk_spec(disk_locality)
|
@@ -175,27 +187,27 @@ module VSphereCloud
|
|
175
187
|
|
176
188
|
replicated_stemcell_vm = replicate_stemcell(cluster, datastore, stemcell)
|
177
189
|
replicated_stemcell_properties = client.get_properties(replicated_stemcell_vm, Vim::VirtualMachine,
|
178
|
-
[
|
179
|
-
:
|
190
|
+
['config.hardware.device', 'snapshot'],
|
191
|
+
ensure_all: true)
|
180
192
|
|
181
|
-
devices = replicated_stemcell_properties[
|
182
|
-
snapshot = replicated_stemcell_properties[
|
193
|
+
devices = replicated_stemcell_properties['config.hardware.device']
|
194
|
+
snapshot = replicated_stemcell_properties['snapshot']
|
183
195
|
|
184
|
-
config = Vim::Vm::ConfigSpec.new(:
|
196
|
+
config = Vim::Vm::ConfigSpec.new(memory_mb: memory, num_cpus: cpu)
|
185
197
|
config.device_change = []
|
186
198
|
|
187
199
|
system_disk = devices.find { |device| device.kind_of?(Vim::Vm::Device::VirtualDisk) }
|
188
200
|
pci_controller = devices.find { |device| device.kind_of?(Vim::Vm::Device::VirtualPCIController) }
|
189
201
|
|
190
202
|
file_name = "[#{datastore.name}] #{name}/ephemeral_disk.vmdk"
|
191
|
-
ephemeral_disk_config =
|
192
|
-
|
203
|
+
ephemeral_disk_config =
|
204
|
+
create_disk_config_spec(datastore.mob, file_name, system_disk.controller_key, disk, create: true)
|
193
205
|
config.device_change << ephemeral_disk_config
|
194
206
|
|
195
207
|
dvs_index = {}
|
196
208
|
networks.each_value do |network|
|
197
|
-
v_network_name = network[
|
198
|
-
network_mob = client.find_by_inventory_path([cluster.datacenter.name,
|
209
|
+
v_network_name = network['cloud_properties']['name']
|
210
|
+
network_mob = client.find_by_inventory_path([cluster.datacenter.name, 'network', v_network_name])
|
199
211
|
nic_config = create_nic_config_spec(v_network_name, network_mob, pci_controller.key, dvs_index)
|
200
212
|
config.device_change << nic_config
|
201
213
|
end
|
@@ -210,16 +222,18 @@ module VSphereCloud
|
|
210
222
|
|
211
223
|
@logger.info("Cloning vm: #{replicated_stemcell_vm} to #{name}")
|
212
224
|
|
213
|
-
task = clone_vm(replicated_stemcell_vm,
|
214
|
-
|
215
|
-
|
225
|
+
task = clone_vm(replicated_stemcell_vm,
|
226
|
+
name,
|
227
|
+
cluster.datacenter.vm_folder.mob,
|
228
|
+
cluster.resource_pool.mob,
|
229
|
+
datastore: datastore.mob, linked: true, snapshot: snapshot.current_snapshot, config: config)
|
216
230
|
vm = client.wait_for_task(task)
|
217
231
|
|
218
232
|
begin
|
219
|
-
upload_file(cluster.datacenter.name, datastore.name, "#{name}/env.iso",
|
233
|
+
upload_file(cluster.datacenter.name, datastore.name, "#{name}/env.iso", '')
|
220
234
|
|
221
|
-
vm_properties = client.get_properties(vm, Vim::VirtualMachine, [
|
222
|
-
devices = vm_properties[
|
235
|
+
vm_properties = client.get_properties(vm, Vim::VirtualMachine, ['config.hardware.device'], ensure_all: true)
|
236
|
+
devices = vm_properties['config.hardware.device']
|
223
237
|
|
224
238
|
# Configure the ENV CDROM
|
225
239
|
config = Vim::Vm::ConfigSpec.new
|
@@ -232,12 +246,11 @@ module VSphereCloud
|
|
232
246
|
network_env = generate_network_env(devices, networks, dvs_index)
|
233
247
|
disk_env = generate_disk_env(system_disk, ephemeral_disk_config.device)
|
234
248
|
env = generate_agent_env(name, vm, agent_id, network_env, disk_env)
|
235
|
-
env[
|
249
|
+
env['env'] = environment
|
236
250
|
@logger.info("Setting VM env: #{env.pretty_inspect}")
|
237
251
|
|
238
|
-
location =
|
239
|
-
|
240
|
-
:vm => name)
|
252
|
+
location =
|
253
|
+
get_vm_location(vm, datacenter: cluster.datacenter.name, datastore: datastore.name, vm: name)
|
241
254
|
set_agent_env(vm, location, env)
|
242
255
|
|
243
256
|
@logger.info("Powering on VM: #{vm} (#{name})")
|
@@ -258,7 +271,7 @@ module VSphereCloud
|
|
258
271
|
result = yield
|
259
272
|
break
|
260
273
|
rescue RuntimeError
|
261
|
-
raise if i + 1
|
274
|
+
raise if i + 1 >= num
|
262
275
|
end
|
263
276
|
end
|
264
277
|
result
|
@@ -270,20 +283,24 @@ module VSphereCloud
|
|
270
283
|
|
271
284
|
vm = get_vm_by_cid(vm_cid)
|
272
285
|
datacenter = client.find_parent(vm, Vim::Datacenter)
|
273
|
-
properties =
|
274
|
-
|
275
|
-
|
286
|
+
properties =
|
287
|
+
client.get_properties(
|
288
|
+
vm,
|
289
|
+
Vim::VirtualMachine,
|
290
|
+
['runtime.powerState', 'runtime.question', 'config.hardware.device', 'name'],
|
291
|
+
ensure: ['config.hardware.device']
|
292
|
+
)
|
276
293
|
|
277
294
|
retry_block do
|
278
|
-
question = properties[
|
295
|
+
question = properties['runtime.question']
|
279
296
|
if question
|
280
297
|
choices = question.choice
|
281
298
|
@logger.info("VM is blocked on a question: #{question.text}, " +
|
282
|
-
|
299
|
+
"providing default answer: #{choices.choice_info[choices.default_index].label}")
|
283
300
|
client.answer_vm(vm, question.id, choices.choice_info[choices.default_index].key)
|
284
|
-
power_state = client.get_property(vm, Vim::VirtualMachine,
|
301
|
+
power_state = client.get_property(vm, Vim::VirtualMachine, 'runtime.powerState')
|
285
302
|
else
|
286
|
-
power_state = properties[
|
303
|
+
power_state = properties['runtime.powerState']
|
287
304
|
end
|
288
305
|
|
289
306
|
if power_state != Vim::VirtualMachine::PowerState::POWERED_OFF
|
@@ -293,9 +310,9 @@ module VSphereCloud
|
|
293
310
|
end
|
294
311
|
|
295
312
|
# Detach any persistent disks in case they were not detached from the instance
|
296
|
-
devices = properties[
|
313
|
+
devices = properties['config.hardware.device']
|
297
314
|
persistent_disks = devices.select { |device| device.kind_of?(Vim::Vm::Device::VirtualDisk) &&
|
298
|
-
|
315
|
+
device.backing.disk_mode == Vim::Vm::Device::VirtualDiskOption::DiskMode::INDEPENDENT_PERSISTENT }
|
299
316
|
|
300
317
|
unless persistent_disks.empty?
|
301
318
|
@logger.info("Found #{persistent_disks.size} persistent disk(s)")
|
@@ -315,19 +332,18 @@ module VSphereCloud
|
|
315
332
|
# Delete env.iso and VM specific files managed by the director
|
316
333
|
retry_block do
|
317
334
|
datastore = get_primary_datastore(devices)
|
318
|
-
datastore_name = client.get_property(datastore, Vim::Datastore,
|
319
|
-
vm_name = properties[
|
335
|
+
datastore_name = client.get_property(datastore, Vim::Datastore, 'name')
|
336
|
+
vm_name = properties['name']
|
320
337
|
client.delete_path(datacenter, "[#{datastore_name}] #{vm_name}")
|
321
338
|
end
|
322
339
|
end
|
323
340
|
end
|
324
341
|
|
325
|
-
# TODO add option to force hard/soft reboot
|
326
342
|
def reboot_vm(vm_cid)
|
327
343
|
with_thread_name("reboot_vm(#{vm_cid})") do
|
328
344
|
vm = get_vm_by_cid(vm_cid)
|
329
345
|
datacenter = client.find_parent(vm, Vim::Datacenter)
|
330
|
-
power_state = client.get_property(vm, Vim::VirtualMachine,
|
346
|
+
power_state = client.get_property(vm, Vim::VirtualMachine, 'runtime.powerState')
|
331
347
|
|
332
348
|
@logger.info("Reboot vm = #{vm_cid}")
|
333
349
|
if power_state != Vim::VirtualMachine::PowerState::POWERED_ON
|
@@ -337,7 +353,7 @@ module VSphereCloud
|
|
337
353
|
vm.reboot_guest
|
338
354
|
rescue => e
|
339
355
|
@logger.error("Soft reboot failed #{e} -#{e.backtrace.join("\n")}")
|
340
|
-
@logger.info(
|
356
|
+
@logger.info('Try hard reboot')
|
341
357
|
# if we fail to perform a soft-reboot we force a hard-reboot
|
342
358
|
if power_state == Vim::VirtualMachine::PowerState::POWERED_ON
|
343
359
|
retry_block { client.power_off_vm(vm) }
|
@@ -356,10 +372,9 @@ module VSphereCloud
|
|
356
372
|
|
357
373
|
metadata.each_key do |name|
|
358
374
|
field = custom_fields.find { |field| field.name == name.to_s &&
|
359
|
-
|
375
|
+
field.managed_object_type == Vim::VirtualMachine }
|
360
376
|
unless field
|
361
|
-
field = fields_manager.add_field_definition(
|
362
|
-
name.to_s, Vim::VirtualMachine, nil, nil)
|
377
|
+
field = fields_manager.add_field_definition(name.to_s, Vim::VirtualMachine, nil, nil)
|
363
378
|
end
|
364
379
|
name_to_key_id[name] = field.key
|
365
380
|
end
|
@@ -367,13 +382,13 @@ module VSphereCloud
|
|
367
382
|
vm = get_vm_by_cid(vm_cid)
|
368
383
|
|
369
384
|
metadata.each do |name, value|
|
370
|
-
value =
|
385
|
+
value = '' if value.nil? # value is required
|
371
386
|
fields_manager.set_field(vm, name_to_key_id[name], value)
|
372
387
|
end
|
373
388
|
rescue SoapException => e
|
374
389
|
if e.fault.kind_of?(Vim::Fault::NoPermission)
|
375
390
|
@logger.warn("Can't set custom fields due to lack of " +
|
376
|
-
|
391
|
+
"permission: #{e.message}")
|
377
392
|
else
|
378
393
|
raise e
|
379
394
|
end
|
@@ -385,33 +400,32 @@ module VSphereCloud
|
|
385
400
|
with_thread_name("configure_networks(#{vm_cid}, ...)") do
|
386
401
|
vm = get_vm_by_cid(vm_cid)
|
387
402
|
|
388
|
-
@logger.debug(
|
403
|
+
@logger.debug('Waiting for the VM to shutdown')
|
389
404
|
state = :initial
|
390
405
|
begin
|
391
406
|
wait_until_off(vm, 30)
|
392
407
|
rescue TimeoutException
|
393
408
|
case state
|
394
409
|
when :initial
|
395
|
-
@logger.debug(
|
410
|
+
@logger.debug('The guest did not shutdown in time, requesting it to shutdown')
|
396
411
|
begin
|
397
412
|
vm.shutdown_guest
|
398
413
|
rescue => e
|
399
|
-
@logger.debug("Ignoring possible race condition when a VM has "
|
400
|
-
"powered off by the time we ask it to shutdown: #{e.message}")
|
414
|
+
@logger.debug("Ignoring possible race condition when a VM has powered off by the time we ask it to shutdown: #{e.message}")
|
401
415
|
end
|
402
416
|
state = :shutdown_guest
|
403
417
|
retry
|
404
418
|
else
|
405
|
-
@logger.error(
|
419
|
+
@logger.error('The guest did not shutdown in time, even after a request')
|
406
420
|
raise
|
407
421
|
end
|
408
422
|
end
|
409
423
|
|
410
424
|
@logger.info("Configuring: #{vm_cid} to use the following network settings: #{networks.pretty_inspect}")
|
411
425
|
vm = get_vm_by_cid(vm_cid)
|
412
|
-
devices = client.get_property(vm, Vim::VirtualMachine,
|
426
|
+
devices = client.get_property(vm, Vim::VirtualMachine, 'config.hardware.device', ensure_all: true)
|
413
427
|
datacenter = client.find_parent(vm, Vim::Datacenter)
|
414
|
-
datacenter_name = client.get_property(datacenter, Vim::Datacenter,
|
428
|
+
datacenter_name = client.get_property(datacenter, Vim::Datacenter, 'name')
|
415
429
|
pci_controller = devices.find { |device| device.kind_of?(Vim::Vm::Device::VirtualPCIController) }
|
416
430
|
|
417
431
|
config = Vim::Vm::ConfigSpec.new
|
@@ -424,63 +438,61 @@ module VSphereCloud
|
|
424
438
|
|
425
439
|
dvs_index = {}
|
426
440
|
networks.each_value do |network|
|
427
|
-
v_network_name = network[
|
428
|
-
network_mob = client.find_by_inventory_path([datacenter_name,
|
441
|
+
v_network_name = network['cloud_properties']['name']
|
442
|
+
network_mob = client.find_by_inventory_path([datacenter_name, 'network', v_network_name])
|
429
443
|
nic_config = create_nic_config_spec(v_network_name, network_mob, pci_controller.key, dvs_index)
|
430
444
|
config.device_change << nic_config
|
431
445
|
end
|
432
446
|
|
433
447
|
fix_device_unit_numbers(devices, config.device_change)
|
434
|
-
@logger.debug(
|
448
|
+
@logger.debug('Reconfiguring the networks')
|
435
449
|
@client.reconfig_vm(vm, config)
|
436
450
|
|
437
|
-
location = get_vm_location(vm, :
|
451
|
+
location = get_vm_location(vm, datacenter: datacenter_name)
|
438
452
|
env = get_current_agent_env(location)
|
439
453
|
@logger.debug("Reading current agent env: #{env.pretty_inspect}")
|
440
454
|
|
441
|
-
devices = client.get_property(vm, Vim::VirtualMachine,
|
442
|
-
env[
|
455
|
+
devices = client.get_property(vm, Vim::VirtualMachine, 'config.hardware.device', ensure_all: true)
|
456
|
+
env['networks'] = generate_network_env(devices, networks, dvs_index)
|
443
457
|
|
444
458
|
@logger.debug("Updating agent env to: #{env.pretty_inspect}")
|
445
459
|
set_agent_env(vm, location, env)
|
446
460
|
|
447
|
-
@logger.debug(
|
461
|
+
@logger.debug('Powering the VM back on')
|
448
462
|
client.power_on_vm(datacenter, vm)
|
449
463
|
end
|
450
464
|
end
|
451
465
|
|
452
466
|
def get_vm_host_info(vm_ref)
|
453
|
-
vm = @client.get_properties(vm_ref, Vim::VirtualMachine,
|
454
|
-
vm_runtime = vm[
|
467
|
+
vm = @client.get_properties(vm_ref, Vim::VirtualMachine, 'runtime')
|
468
|
+
vm_runtime = vm['runtime']
|
455
469
|
|
456
|
-
properties = @client.get_properties(vm_runtime.host, Vim::HostSystem, [
|
457
|
-
:ensure_all => true)
|
470
|
+
properties = @client.get_properties(vm_runtime.host, Vim::HostSystem, ['datastore', 'parent'], ensure_all: true)
|
458
471
|
|
459
472
|
# Get the cluster that the vm's host belongs to.
|
460
|
-
cluster = @client.get_properties(properties[
|
473
|
+
cluster = @client.get_properties(properties['parent'], Vim::ClusterComputeResource, 'name')
|
461
474
|
|
462
475
|
# Get the datastores that are accessible to the vm's host.
|
463
476
|
datastores_accessible = []
|
464
|
-
properties[
|
465
|
-
ds = @client.get_properties(store, Vim::Datastore,
|
466
|
-
datastores_accessible << ds[
|
467
|
-
|
477
|
+
properties['datastore'].each do |store|
|
478
|
+
ds = @client.get_properties(store, Vim::Datastore, 'info', ensure_all: true)
|
479
|
+
datastores_accessible << ds['info'].name
|
480
|
+
end
|
468
481
|
|
469
|
-
{
|
482
|
+
{ 'cluster' => cluster['name'], 'datastores' => datastores_accessible }
|
470
483
|
end
|
471
484
|
|
472
485
|
def find_persistent_datastore(datacenter_name, host_info, disk_size)
|
473
486
|
# Find datastore
|
474
|
-
datastore = @resources.place_persistent_datastore(
|
475
|
-
datacenter_name, host_info["cluster"], disk_size)
|
487
|
+
datastore = @resources.place_persistent_datastore(datacenter_name, host_info['cluster'], disk_size)
|
476
488
|
|
477
489
|
if datastore.nil?
|
478
|
-
raise Bosh::Clouds::NoDiskSpace.new(true), "Not enough persistent space on cluster #{host_info[
|
490
|
+
raise Bosh::Clouds::NoDiskSpace.new(true), "Not enough persistent space on cluster #{host_info['cluster']}, #{disk_size}"
|
479
491
|
end
|
480
492
|
|
481
493
|
# Sanity check, verify that the vm's host can access this datastore
|
482
|
-
unless host_info[
|
483
|
-
raise "Datastore not accessible to host, #{datastore.name}, #{host_info[
|
494
|
+
unless host_info['datastores'].include?(datastore.name)
|
495
|
+
raise "Datastore not accessible to host, #{datastore.name}, #{host_info['datastores']}"
|
484
496
|
end
|
485
497
|
datastore
|
486
498
|
end
|
@@ -488,25 +500,29 @@ module VSphereCloud
|
|
488
500
|
def attach_disk(vm_cid, disk_cid)
|
489
501
|
with_thread_name("attach_disk(#{vm_cid}, #{disk_cid})") do
|
490
502
|
@logger.info("Attaching disk: #{disk_cid} on vm: #{vm_cid}")
|
491
|
-
disk = Models::Disk.first(:
|
503
|
+
disk = Models::Disk.first(uuid: disk_cid)
|
492
504
|
raise "Disk not found: #{disk_cid}" if disk.nil?
|
493
505
|
|
494
506
|
vm = get_vm_by_cid(vm_cid)
|
495
507
|
|
496
508
|
datacenter = client.find_parent(vm, Vim::Datacenter)
|
497
|
-
datacenter_name = client.get_property(datacenter, Vim::Datacenter,
|
509
|
+
datacenter_name = client.get_property(datacenter, Vim::Datacenter, 'name')
|
498
510
|
|
499
|
-
vm_properties = client.get_properties(vm, Vim::VirtualMachine,
|
511
|
+
vm_properties = client.get_properties(vm, Vim::VirtualMachine, 'config.hardware.device', ensure_all: true)
|
500
512
|
host_info = get_vm_host_info(vm)
|
501
513
|
|
502
514
|
create_disk = false
|
503
515
|
if disk.path
|
504
|
-
|
505
|
-
|
506
|
-
|
516
|
+
|
517
|
+
disk_in_correct_datacenter =
|
518
|
+
(disk.datacenter == datacenter_name &&
|
519
|
+
@resources.validate_persistent_datastore(datacenter_name, disk.datastore) &&
|
520
|
+
host_info['datastores'].include?(disk.datastore))
|
521
|
+
|
522
|
+
if disk_in_correct_datacenter
|
507
523
|
@logger.info("Disk already in the right datastore #{datacenter_name} #{disk.datastore}")
|
508
|
-
persistent_datastore =
|
509
|
-
|
524
|
+
persistent_datastore =
|
525
|
+
@resources.persistent_datastore(datacenter_name, host_info['cluster'], disk.datastore)
|
510
526
|
@logger.debug("Datastore: #{persistent_datastore}")
|
511
527
|
else
|
512
528
|
@logger.info("Disk needs to move from #{datacenter_name} #{disk.datastore}")
|
@@ -523,10 +539,10 @@ module VSphereCloud
|
|
523
539
|
|
524
540
|
if Config.copy_disks
|
525
541
|
client.copy_disk(source_datacenter, source_path, datacenter, destination_path)
|
526
|
-
@logger.info(
|
542
|
+
@logger.info('Copied disk successfully')
|
527
543
|
else
|
528
544
|
client.move_disk(source_datacenter, source_path, datacenter, destination_path)
|
529
|
-
@logger.info(
|
545
|
+
@logger.info('Moved disk successfully')
|
530
546
|
end
|
531
547
|
|
532
548
|
disk.datacenter = datacenter_name
|
@@ -535,7 +551,7 @@ module VSphereCloud
|
|
535
551
|
disk.save
|
536
552
|
end
|
537
553
|
else
|
538
|
-
@logger.info(
|
554
|
+
@logger.info('Need to create disk')
|
539
555
|
|
540
556
|
# Find the destination datastore
|
541
557
|
persistent_datastore = find_persistent_datastore(datacenter_name, host_info, disk.size)
|
@@ -549,43 +565,47 @@ module VSphereCloud
|
|
549
565
|
create_disk = true
|
550
566
|
end
|
551
567
|
|
552
|
-
devices = vm_properties[
|
568
|
+
devices = vm_properties['config.hardware.device']
|
553
569
|
system_disk = devices.find { |device| device.kind_of?(Vim::Vm::Device::VirtualDisk) }
|
554
570
|
|
555
571
|
vmdk_path = "#{disk.path}.vmdk"
|
556
|
-
attached_disk_config = create_disk_config_spec(persistent_datastore.mob,
|
557
|
-
|
558
|
-
|
572
|
+
attached_disk_config = create_disk_config_spec(persistent_datastore.mob,
|
573
|
+
vmdk_path,
|
574
|
+
system_disk.controller_key,
|
575
|
+
disk.size.to_i,
|
576
|
+
create: create_disk, independent: true)
|
559
577
|
config = Vim::Vm::ConfigSpec.new
|
560
578
|
config.device_change = []
|
561
579
|
config.device_change << attached_disk_config
|
562
580
|
fix_device_unit_numbers(devices, config.device_change)
|
563
581
|
|
564
|
-
location = get_vm_location(vm, :
|
582
|
+
location = get_vm_location(vm, datacenter: datacenter_name)
|
565
583
|
env = get_current_agent_env(location)
|
566
584
|
@logger.info("Reading current agent env: #{env.pretty_inspect}")
|
567
|
-
env[
|
585
|
+
env['disks']['persistent'][disk.uuid] = attached_disk_config.device.unit_number
|
568
586
|
@logger.info("Updating agent env to: #{env.pretty_inspect}")
|
569
587
|
set_agent_env(vm, location, env)
|
570
|
-
@logger.info(
|
588
|
+
@logger.info('Attaching disk')
|
571
589
|
client.reconfig_vm(vm, config)
|
572
|
-
@logger.info(
|
590
|
+
@logger.info('Finished attaching disk')
|
573
591
|
end
|
574
592
|
end
|
575
593
|
|
576
594
|
def detach_disk(vm_cid, disk_cid)
|
577
595
|
with_thread_name("detach_disk(#{vm_cid}, #{disk_cid})") do
|
578
596
|
@logger.info("Detaching disk: #{disk_cid} from vm: #{vm_cid}")
|
579
|
-
disk = Models::Disk.first(:
|
597
|
+
disk = Models::Disk.first(uuid: disk_cid)
|
580
598
|
raise "Disk not found: #{disk_cid}" if disk.nil?
|
581
599
|
|
582
600
|
vm = get_vm_by_cid(vm_cid)
|
583
601
|
|
584
|
-
devices = client.get_property(vm, Vim::VirtualMachine,
|
602
|
+
devices = client.get_property(vm, Vim::VirtualMachine, 'config.hardware.device', ensure_all: true)
|
585
603
|
|
586
604
|
vmdk_path = "#{disk.path}.vmdk"
|
587
|
-
virtual_disk =
|
588
|
-
|
605
|
+
virtual_disk =
|
606
|
+
devices.find do |device|
|
607
|
+
device.kind_of?(Vim::Vm::Device::VirtualDisk) && device.backing.file_name == vmdk_path
|
608
|
+
end
|
589
609
|
raise Bosh::Clouds::DiskNotAttached.new(true), "Disk (#{disk_cid}) is not attached to VM (#{vm_cid})" if virtual_disk.nil?
|
590
610
|
|
591
611
|
config = Vim::Vm::ConfigSpec.new
|
@@ -595,10 +615,10 @@ module VSphereCloud
|
|
595
615
|
location = get_vm_location(vm)
|
596
616
|
env = get_current_agent_env(location)
|
597
617
|
@logger.info("Reading current agent env: #{env.pretty_inspect}")
|
598
|
-
env[
|
618
|
+
env['disks']['persistent'].delete(disk.uuid)
|
599
619
|
@logger.info("Updating agent env to: #{env.pretty_inspect}")
|
600
620
|
set_agent_env(vm, location, env)
|
601
|
-
@logger.info(
|
621
|
+
@logger.info('Detaching disk')
|
602
622
|
client.reconfig_vm(vm, config)
|
603
623
|
|
604
624
|
# detach-disk is async and task completion does not necessarily mean
|
@@ -606,15 +626,18 @@ module VSphereCloud
|
|
606
626
|
# that the change has been applied. This is a known issue for vsphere 4.
|
607
627
|
# Fixed in vsphere 5.
|
608
628
|
5.times do
|
609
|
-
devices = client.get_property(vm, Vim::VirtualMachine,
|
610
|
-
virtual_disk =
|
611
|
-
|
629
|
+
devices = client.get_property(vm, Vim::VirtualMachine, 'config.hardware.device', ensure_all: true)
|
630
|
+
virtual_disk =
|
631
|
+
devices.find do |device|
|
632
|
+
device.kind_of?(Vim::Vm::Device::VirtualDisk) &&
|
633
|
+
device.backing.file_name == vmdk_path
|
634
|
+
end
|
612
635
|
break if virtual_disk.nil?
|
613
636
|
sleep(1.0)
|
614
637
|
end
|
615
638
|
raise "Failed to detach disk: #{disk_cid} from vm: #{vm_cid}" unless virtual_disk.nil?
|
616
639
|
|
617
|
-
@logger.info(
|
640
|
+
@logger.info('Finished detaching disk')
|
618
641
|
end
|
619
642
|
end
|
620
643
|
|
@@ -633,7 +656,7 @@ module VSphereCloud
|
|
633
656
|
def delete_disk(disk_cid)
|
634
657
|
with_thread_name("delete_disk(#{disk_cid})") do
|
635
658
|
@logger.info("Deleting disk: #{disk_cid}")
|
636
|
-
disk = Models::Disk.first(:
|
659
|
+
disk = Models::Disk.first(uuid: disk_cid)
|
637
660
|
if disk
|
638
661
|
if disk.path
|
639
662
|
datacenter = client.find_by_inventory_path(disk.datacenter)
|
@@ -642,7 +665,7 @@ module VSphereCloud
|
|
642
665
|
client.delete_disk(datacenter, disk.path)
|
643
666
|
end
|
644
667
|
disk.destroy
|
645
|
-
@logger.info(
|
668
|
+
@logger.info('Finished deleting disk')
|
646
669
|
else
|
647
670
|
raise "Could not find disk: #{disk_cid}"
|
648
671
|
end
|
@@ -650,32 +673,27 @@ module VSphereCloud
|
|
650
673
|
end
|
651
674
|
|
652
675
|
def validate_deployment(old_manifest, new_manifest)
|
653
|
-
# TODO: still needed? what does it verify? cloud properties? should be replaced by normalize cloud properties?
|
654
676
|
end
|
655
677
|
|
656
678
|
def get_vm_by_cid(vm_cid)
|
657
679
|
@resources.datacenters.each_value do |datacenter|
|
658
|
-
vm = client.find_by_inventory_path(
|
659
|
-
|
660
|
-
unless vm.nil?
|
661
|
-
return vm
|
662
|
-
end
|
680
|
+
vm = client.find_by_inventory_path([datacenter.name, 'vm', datacenter.vm_folder.name, vm_cid])
|
681
|
+
return vm unless vm.nil?
|
663
682
|
end
|
664
683
|
raise Bosh::Clouds::VMNotFound, "VM `#{vm_cid}' not found"
|
665
684
|
end
|
666
685
|
|
667
686
|
def replicate_stemcell(cluster, datastore, stemcell)
|
668
|
-
|
669
|
-
stemcell_vm = client.find_by_inventory_path([cluster.datacenter.name, "vm",
|
687
|
+
stemcell_vm = client.find_by_inventory_path([cluster.datacenter.name, 'vm',
|
670
688
|
cluster.datacenter.template_folder.name, stemcell])
|
671
689
|
raise "Could not find stemcell: #{stemcell}" if stemcell_vm.nil?
|
672
|
-
stemcell_datastore = client.get_property(stemcell_vm, Vim::VirtualMachine,
|
690
|
+
stemcell_datastore = client.get_property(stemcell_vm, Vim::VirtualMachine, 'datastore', ensure_all: true)
|
673
691
|
|
674
692
|
if stemcell_datastore != datastore.mob
|
675
693
|
@logger.info("Stemcell lives on a different datastore, looking for a local copy of: #{stemcell}.")
|
676
|
-
local_stemcell_name
|
677
|
-
local_stemcell_path
|
678
|
-
|
694
|
+
local_stemcell_name = "#{stemcell} %2f #{datastore.mob.__mo_id__}"
|
695
|
+
local_stemcell_path =
|
696
|
+
[cluster.datacenter.name, 'vm', cluster.datacenter.template_folder.name, local_stemcell_name]
|
679
697
|
replicated_stemcell_vm = client.find_by_inventory_path(local_stemcell_path)
|
680
698
|
|
681
699
|
if replicated_stemcell_vm.nil?
|
@@ -692,13 +710,17 @@ module VSphereCloud
|
|
692
710
|
replicated_stemcell_vm = client.find_by_inventory_path(local_stemcell_path)
|
693
711
|
if replicated_stemcell_vm.nil?
|
694
712
|
@logger.info("Replicating #{stemcell} (#{stemcell_vm}) to #{local_stemcell_name}")
|
695
|
-
task = clone_vm(stemcell_vm,
|
696
|
-
|
713
|
+
task = clone_vm(stemcell_vm,
|
714
|
+
local_stemcell_name,
|
715
|
+
cluster.datacenter.template_folder.mob,
|
716
|
+
cluster.resource_pool.mob,
|
717
|
+
datastore: datastore.mob)
|
697
718
|
replicated_stemcell_vm = client.wait_for_task(task)
|
698
|
-
@logger.info("Replicated #{stemcell} (#{stemcell_vm}) to "
|
699
|
-
"#{local_stemcell_name} (#{replicated_stemcell_vm})")
|
719
|
+
@logger.info("Replicated #{stemcell} (#{stemcell_vm}) to #{local_stemcell_name} (#{replicated_stemcell_vm})")
|
700
720
|
@logger.info("Creating initial snapshot for linked clones on #{replicated_stemcell_vm}")
|
701
|
-
|
721
|
+
# Despite the naming, this has nothing to do with the Cloud notion of a disk snapshot
|
722
|
+
# (which comes from AWS). This is a vm snapshot.
|
723
|
+
task = replicated_stemcell_vm.create_snapshot('initial', nil, false, false)
|
702
724
|
client.wait_for_task(task)
|
703
725
|
@logger.info("Created initial snapshot for linked clones on #{replicated_stemcell_vm}")
|
704
726
|
end
|
@@ -724,9 +746,9 @@ module VSphereCloud
|
|
724
746
|
if device.kind_of?(Vim::Vm::Device::VirtualEthernetCard)
|
725
747
|
backing = device.backing
|
726
748
|
if backing.kind_of?(Vim::Vm::Device::VirtualEthernetCard::DistributedVirtualPortBackingInfo)
|
727
|
-
v_network_name = dvs_index[
|
749
|
+
v_network_name = dvs_index[backing.port.portgroup_key]
|
728
750
|
else
|
729
|
-
v_network_name =
|
751
|
+
v_network_name = PathFinder.new.path(backing.network)
|
730
752
|
end
|
731
753
|
allocated_networks = nics[v_network_name] || []
|
732
754
|
allocated_networks << device
|
@@ -737,9 +759,9 @@ module VSphereCloud
|
|
737
759
|
network_env = {}
|
738
760
|
networks.each do |network_name, network|
|
739
761
|
network_entry = network.dup
|
740
|
-
v_network_name = network[
|
762
|
+
v_network_name = network['cloud_properties']['name']
|
741
763
|
nic = nics[v_network_name].pop
|
742
|
-
network_entry[
|
764
|
+
network_entry['mac'] = nic.mac_address
|
743
765
|
network_env[network_name] = network_entry
|
744
766
|
end
|
745
767
|
network_env
|
@@ -747,23 +769,23 @@ module VSphereCloud
|
|
747
769
|
|
748
770
|
def generate_disk_env(system_disk, ephemeral_disk)
|
749
771
|
{
|
750
|
-
|
751
|
-
|
752
|
-
|
772
|
+
'system' => system_disk.unit_number,
|
773
|
+
'ephemeral' => ephemeral_disk.unit_number,
|
774
|
+
'persistent' => {}
|
753
775
|
}
|
754
776
|
end
|
755
777
|
|
756
778
|
def generate_agent_env(name, vm, agent_id, networking_env, disk_env)
|
757
779
|
vm_env = {
|
758
|
-
|
759
|
-
|
780
|
+
'name' => name,
|
781
|
+
'id' => vm.__mo_id__
|
760
782
|
}
|
761
783
|
|
762
784
|
env = {}
|
763
|
-
env[
|
764
|
-
env[
|
765
|
-
env[
|
766
|
-
env[
|
785
|
+
env['vm'] = vm_env
|
786
|
+
env['agent_id'] = agent_id
|
787
|
+
env['networks'] = networking_env
|
788
|
+
env['disks'] = disk_env
|
767
789
|
env.merge!(Config.agent)
|
768
790
|
env
|
769
791
|
end
|
@@ -775,32 +797,32 @@ module VSphereCloud
|
|
775
797
|
|
776
798
|
unless datacenter_name
|
777
799
|
datacenter = client.find_parent(vm, Vim::Datacenter)
|
778
|
-
datacenter_name = client.get_property(datacenter, Vim::Datacenter,
|
800
|
+
datacenter_name = client.get_property(datacenter, Vim::Datacenter, 'name')
|
779
801
|
end
|
780
802
|
|
781
803
|
if vm_name.nil? || datastore_name.nil?
|
782
|
-
vm_properties =
|
783
|
-
|
784
|
-
vm_name = vm_properties[
|
804
|
+
vm_properties =
|
805
|
+
client.get_properties(vm, Vim::VirtualMachine, ['config.hardware.device', 'name'], ensure_all: true)
|
806
|
+
vm_name = vm_properties['name']
|
785
807
|
|
786
808
|
unless datastore_name
|
787
|
-
devices = vm_properties[
|
809
|
+
devices = vm_properties['config.hardware.device']
|
788
810
|
datastore = get_primary_datastore(devices)
|
789
|
-
datastore_name = client.get_property(datastore, Vim::Datastore,
|
811
|
+
datastore_name = client.get_property(datastore, Vim::Datastore, 'name')
|
790
812
|
end
|
791
813
|
end
|
792
814
|
|
793
|
-
{:
|
815
|
+
{ datacenter: datacenter_name, datastore: datastore_name, vm: vm_name }
|
794
816
|
end
|
795
817
|
|
796
818
|
def get_primary_datastore(devices)
|
797
819
|
ephemeral_disks = devices.select { |device| device.kind_of?(Vim::Vm::Device::VirtualDisk) &&
|
798
|
-
|
820
|
+
device.backing.disk_mode != Vim::Vm::Device::VirtualDiskOption::DiskMode::INDEPENDENT_PERSISTENT }
|
799
821
|
|
800
822
|
datastore = nil
|
801
823
|
ephemeral_disks.each do |disk|
|
802
824
|
if datastore
|
803
|
-
raise
|
825
|
+
raise 'Ephemeral disks should all be on the same datastore.' unless datastore.eql?(disk.backing.datastore)
|
804
826
|
else
|
805
827
|
datastore = disk.backing.datastore
|
806
828
|
end
|
@@ -811,11 +833,11 @@ module VSphereCloud
|
|
811
833
|
|
812
834
|
def get_current_agent_env(location)
|
813
835
|
contents = fetch_file(location[:datacenter], location[:datastore], "#{location[:vm]}/env.json")
|
814
|
-
contents ?
|
836
|
+
contents ? JSON.load(contents) : nil
|
815
837
|
end
|
816
838
|
|
817
839
|
def set_agent_env(vm, location, env)
|
818
|
-
env_json =
|
840
|
+
env_json = JSON.dump(env)
|
819
841
|
|
820
842
|
connect_cdrom(vm, false)
|
821
843
|
upload_file(location[:datacenter], location[:datastore], "#{location[:vm]}/env.json", env_json)
|
@@ -824,7 +846,7 @@ module VSphereCloud
|
|
824
846
|
end
|
825
847
|
|
826
848
|
def connect_cdrom(vm, connected = true)
|
827
|
-
devices = client.get_property(vm, Vim::VirtualMachine,
|
849
|
+
devices = client.get_property(vm, Vim::VirtualMachine, 'config.hardware.device', ensure_all: true)
|
828
850
|
cdrom = devices.find { |device| device.kind_of?(Vim::Vm::Device::VirtualCdrom) }
|
829
851
|
|
830
852
|
if cdrom.connectable.connected != connected
|
@@ -868,19 +890,19 @@ module VSphereCloud
|
|
868
890
|
|
869
891
|
def generate_env_iso(env)
|
870
892
|
Dir.mktmpdir do |path|
|
871
|
-
env_path = File.join(path,
|
872
|
-
iso_path = File.join(path,
|
873
|
-
File.open(env_path,
|
893
|
+
env_path = File.join(path, 'env')
|
894
|
+
iso_path = File.join(path, 'env.iso')
|
895
|
+
File.open(env_path, 'w') { |f| f.write(env) }
|
874
896
|
output = `#{genisoimage} -o #{iso_path} #{env_path} 2>&1`
|
875
897
|
raise "#{$?.exitstatus} -#{output}" if $?.exitstatus != 0
|
876
|
-
File.open(iso_path,
|
898
|
+
File.open(iso_path, 'r') { |f| f.read }
|
877
899
|
end
|
878
900
|
end
|
879
901
|
|
880
902
|
def fetch_file(datacenter_name, datastore_name, path)
|
881
903
|
retry_block do
|
882
|
-
url =
|
883
|
-
|
904
|
+
url =
|
905
|
+
"https://#{Config.vcenter.host}/folder/#{path}?dcPath=#{URI.escape(datacenter_name)}&dsName=#{URI.escape(datastore_name)}"
|
884
906
|
|
885
907
|
response = @rest_client.get(url)
|
886
908
|
|
@@ -896,17 +918,18 @@ module VSphereCloud
|
|
896
918
|
|
897
919
|
def upload_file(datacenter_name, datastore_name, path, contents)
|
898
920
|
retry_block do
|
899
|
-
url =
|
900
|
-
|
901
|
-
response = @rest_client.put(url,
|
902
|
-
|
921
|
+
url =
|
922
|
+
"https://#{Config.vcenter.host}/folder/#{path}?dcPath=#{URI.escape(datacenter_name)}&dsName=#{URI.escape(datastore_name)}"
|
923
|
+
response = @rest_client.put(url,
|
924
|
+
contents,
|
925
|
+
{ 'Content-Type' => 'application/octet-stream', 'Content-Length' => contents.length })
|
903
926
|
|
904
927
|
raise "Could not upload file: #{url}, status code: #{response.code}" unless response.code < 400
|
905
928
|
end
|
906
929
|
end
|
907
930
|
|
908
931
|
def clone_vm(vm, name, folder, resource_pool, options={})
|
909
|
-
relocation_spec =Vim::Vm::RelocateSpec.new
|
932
|
+
relocation_spec = Vim::Vm::RelocateSpec.new
|
910
933
|
relocation_spec.datastore = options[:datastore] if options[:datastore]
|
911
934
|
if options[:linked]
|
912
935
|
relocation_spec.disk_move_type = Vim::Vm::RelocateSpec::DiskMoveOptions::CREATE_NEW_CHILD_DISK_BACKING
|
@@ -923,12 +946,8 @@ module VSphereCloud
|
|
923
946
|
vm.clone(folder, name, clone_spec)
|
924
947
|
end
|
925
948
|
|
926
|
-
def take_snapshot(vm, name)
|
927
|
-
vm.create_snapshot(name, nil, false, false)
|
928
|
-
end
|
929
|
-
|
930
949
|
def generate_unique_name
|
931
|
-
|
950
|
+
SecureRandom.uuid
|
932
951
|
end
|
933
952
|
|
934
953
|
def create_disk_config_spec(datastore, file_name, controller_key, space, options = {})
|
@@ -959,16 +978,17 @@ module VSphereCloud
|
|
959
978
|
def create_nic_config_spec(v_network_name, network, controller_key, dvs_index)
|
960
979
|
raise "Can't find network: #{v_network_name}" if network.nil?
|
961
980
|
if network.class == Vim::Dvs::DistributedVirtualPortgroup
|
962
|
-
portgroup_properties = client.get_properties(network,
|
963
|
-
|
964
|
-
|
981
|
+
portgroup_properties = client.get_properties(network,
|
982
|
+
Vim::Dvs::DistributedVirtualPortgroup,
|
983
|
+
['config.key', 'config.distributedVirtualSwitch'],
|
984
|
+
ensure_all: true)
|
965
985
|
|
966
|
-
switch = portgroup_properties[
|
967
|
-
switch_uuid = client.get_property(switch, Vim::DistributedVirtualSwitch,
|
986
|
+
switch = portgroup_properties['config.distributedVirtualSwitch']
|
987
|
+
switch_uuid = client.get_property(switch, Vim::DistributedVirtualSwitch, 'uuid', ensure_all: true)
|
968
988
|
|
969
989
|
port = Vim::Dvs::PortConnection.new
|
970
990
|
port.switch_uuid = switch_uuid
|
971
|
-
port.portgroup_key = portgroup_properties[
|
991
|
+
port.portgroup_key = portgroup_properties['config.key']
|
972
992
|
|
973
993
|
backing_info = Vim::Vm::Device::VirtualEthernetCard::DistributedVirtualPortBackingInfo.new
|
974
994
|
backing_info.port = port
|
@@ -976,7 +996,7 @@ module VSphereCloud
|
|
976
996
|
dvs_index[port.portgroup_key] = v_network_name
|
977
997
|
else
|
978
998
|
backing_info = Vim::Vm::Device::VirtualEthernetCard::NetworkBackingInfo.new
|
979
|
-
backing_info.device_name =
|
999
|
+
backing_info.device_name = network.name
|
980
1000
|
backing_info.network = network
|
981
1001
|
end
|
982
1002
|
|
@@ -1039,8 +1059,10 @@ module VSphereCloud
|
|
1039
1059
|
ovf_descriptor = ovf_file.read
|
1040
1060
|
ovf_file.close
|
1041
1061
|
|
1042
|
-
@client.service_content.ovf_manager.create_import_spec(ovf_descriptor,
|
1043
|
-
|
1062
|
+
@client.service_content.ovf_manager.create_import_spec(ovf_descriptor,
|
1063
|
+
resource_pool,
|
1064
|
+
datastore,
|
1065
|
+
import_spec_params)
|
1044
1066
|
end
|
1045
1067
|
|
1046
1068
|
def obtain_nfc_lease(resource_pool, import_spec, folder)
|
@@ -1049,16 +1071,14 @@ module VSphereCloud
|
|
1049
1071
|
|
1050
1072
|
def wait_for_nfc_lease(lease)
|
1051
1073
|
loop do
|
1052
|
-
state = client.get_property(lease, Vim::HttpNfcLease,
|
1053
|
-
unless state == Vim::HttpNfcLease::State::INITIALIZING
|
1054
|
-
return state
|
1055
|
-
end
|
1074
|
+
state = client.get_property(lease, Vim::HttpNfcLease, 'state')
|
1075
|
+
return state unless state == Vim::HttpNfcLease::State::INITIALIZING
|
1056
1076
|
sleep(1.0)
|
1057
1077
|
end
|
1058
1078
|
end
|
1059
1079
|
|
1060
1080
|
def upload_ovf(ovf, lease, file_items)
|
1061
|
-
info = client.get_property(lease, Vim::HttpNfcLease,
|
1081
|
+
info = client.get_property(lease, Vim::HttpNfcLease, 'info', ensure_all: true)
|
1062
1082
|
lease_updater = LeaseUpdater.new(client, lease)
|
1063
1083
|
|
1064
1084
|
info.device_url.each do |device_url|
|
@@ -1070,13 +1090,11 @@ module VSphereCloud
|
|
1070
1090
|
http_client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
1071
1091
|
|
1072
1092
|
disk_file_path = File.join(File.dirname(ovf), file_item.path)
|
1073
|
-
# TODO; capture the error if file is not found a provide a more meaningful error
|
1074
1093
|
disk_file = File.open(disk_file_path)
|
1075
1094
|
disk_file_size = File.size(disk_file_path)
|
1076
1095
|
|
1077
1096
|
progress_thread = Thread.new do
|
1078
1097
|
loop do
|
1079
|
-
# TODO: fix progress calculation to work across multiple disks
|
1080
1098
|
lease_updater.progress = disk_file.pos * 100 / disk_file_size
|
1081
1099
|
sleep(2)
|
1082
1100
|
end
|
@@ -1084,8 +1102,9 @@ module VSphereCloud
|
|
1084
1102
|
|
1085
1103
|
@logger.info("Uploading disk to: #{device_url.url}")
|
1086
1104
|
|
1087
|
-
http_client.post(device_url.url,
|
1088
|
-
|
1105
|
+
http_client.post(device_url.url,
|
1106
|
+
disk_file,
|
1107
|
+
{ 'Content-Type' => 'application/x-vnd.vmware-streamVmdk', 'Content-Length' => disk_file_size })
|
1089
1108
|
|
1090
1109
|
progress_thread.kill
|
1091
1110
|
disk_file.close
|
@@ -1097,13 +1116,13 @@ module VSphereCloud
|
|
1097
1116
|
end
|
1098
1117
|
|
1099
1118
|
def wait_until_off(vm, timeout)
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1119
|
+
started = Time.now
|
1120
|
+
loop do
|
1121
|
+
power_state = client.get_property(vm, Vim::VirtualMachine, 'runtime.powerState')
|
1122
|
+
break if power_state == Vim::VirtualMachine::PowerState::POWERED_OFF
|
1123
|
+
raise TimeoutException if Time.now - started > timeout
|
1124
|
+
sleep(1.0)
|
1125
|
+
end
|
1107
1126
|
end
|
1108
1127
|
end
|
1109
1128
|
end
|