Class: ChefProvisioningVsphere::VsphereHelper

Inherits:
Object
  • Object
show all
Defined in:
lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb

Overview

A namespace to use for vSphere Helpers

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(connect_options, datacenter_name) ⇒ VsphereHelper

Returns a new instance of VsphereHelper.



13
14
15
16
17
18
19
20
21
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 13

def initialize(connect_options, datacenter_name)
  http = Net::HTTP.new(connect_options[:host], connect_options[:port])
  if http.proxy?
    connect_options[:proxyHost] = http.proxy_address
    connect_options[:proxyPort] = http.proxy_port
  end
  @connect_options = connect_options
  @datacenter_name = datacenter_name
end

Instance Attribute Details

#connect_optionsObject (readonly)

Returns the value of attribute connect_options.



23
24
25
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 23

def connect_options
  @connect_options
end

#datacenter_nameObject (readonly)

Returns the value of attribute datacenter_name.



24
25
26
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 24

def datacenter_name
  @datacenter_name
end

Instance Method Details

#add_extra_nic(action_handler, vm_template, options, vm) ⇒ Object

Add another NIC to the VM

Parameters:

  • action_handler (Object)

    TODO

  • vm_template (String)

    the Name of the Template to clone

  • options (Object)

    the options from Chef Provisioning to help configure the VM.

  • vm (Object)

    the actual VM object to connect the VM to.



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 178

def add_extra_nic(action_handler, vm_template, options, vm)
  deviceAdditions, changes = network_device_changes(action_handler, vm_template, options)

  if deviceAdditions.count.positive?
    current_networks = find_ethernet_cards_for(vm).map { |card| network_id_for(card.backing) }
    new_devices = deviceAdditions.reject { |device| current_networks.include?(network_id_for(device.device.backing)) }

    if new_devices.count.positive?
      action_handler.report_progress 'Adding extra NICs'
      task = vm.ReconfigVM_Task(spec: RbVmomi::VIM.VirtualMachineConfigSpec(deviceChange: new_devices))
      task.wait_for_completion
      new_devices
    end
  end
end

#backing_info_for(action_handler, network_name) ⇒ Object

Discover and identity network names

Parameters:

  • action_handler (Object)

    TODO

  • network_name (String)

    The network name to attach to



383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 383

def backing_info_for(action_handler, network_name)
  action_handler.report_progress('finding networks...')
  network = find_network(network_name)
  action_handler.report_progress(
    "network: #{network_name} is a #{network.class}"
  )
  if network.is_a?(RbVmomi::VIM::DistributedVirtualPortgroup)
    port = RbVmomi::VIM::DistributedVirtualSwitchPortConnection(
      switchUuid: network.config.distributedVirtualSwitch.uuid,
      portgroupKey: network.key
    )
    RbVmomi::VIM::VirtualEthernetCardDistributedVirtualPortBackingInfo(
      port: port
    )
  else
    RbVmomi::VIM::VirtualEthernetCardNetworkBackingInfo(
      deviceName: network_name.split('/').last
    )
  end
end

#create_delta_disk(vm_template) ⇒ Object

Creates a delta disk for a vm template

Parameters:

  • vm_template (String)

    the Name of the Template to clone.



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 208

def create_delta_disk(vm_template)
  disks = vm_template.config.hardware.device.grep(RbVmomi::VIM::VirtualDisk)
  disks.select { |disk| disk.backing.parent.nil? }.each do |disk|
    spec = {
      deviceChange: [
        {
          operation: :remove,
          device: disk
        },
        {
          operation: :add,
          fileOperation: :create,
          device: disk.dup.tap do |new_disk|
            new_disk.backing = new_disk.backing.dup
            new_disk.backing.fileName = "[#{disk.backing.datastore.name}]"
            new_disk.backing.parent = disk.backing
          end
        }
      ]
    }
    vm_template.ReconfigVM_Task(spec: spec).wait_for_completion
  end
end

#datacenterObject

Connects to the Datacenter and creates Object

Returns:

  • (Object)

    Creates the dc object to know where to create the VMs.



132
133
134
135
136
137
138
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 132

def datacenter
  vim # ensure connection is valid
  @datacenter ||= begin
    rootFolder = vim.serviceInstance.content.rootFolder
    dc = traverse_folders_for_dc(vim.rootFolder, datacenter_name) || abort("vSphere Datacenter not found [#{datacenter_name}]")
  end
end

#find_customization_spec(customization_spec) ⇒ Object

Locate the Customization Spec in vSphere.

Parameters:

  • customization_spec (String)

    The name of the Customization Spec.



517
518
519
520
521
522
523
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 517

def find_customization_spec(customization_spec)
  csm = vim.serviceContent.customizationSpecManager
  csi = csm.GetCustomizationSpec(name: customization_spec)
  spec = csi.spec
  raise "Customization Spec not found [#{customization_spec}]" if spec.nil?
  spec
end

#find_datastore(datastore_name) ⇒ Object

Find the datastore name.

Parameters:

  • datastore_name (String)

    The datastore name.



407
408
409
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 407

def find_datastore(datastore_name)
  datacenter.datastore.find { |f| f.info.name == datastore_name } || raise("no such datastore #{datastore_name}")
end

#find_entity(name, parent_folder) ⇒ Object

Locate the object/vm/whatever in the vSphere cluster

Parameters:

  • name (String)

    The name of the “thing.”

  • parent_folder (String)

    The name of the folder to start from.



415
416
417
418
419
420
421
422
423
424
425
426
427
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 415

def find_entity(name, parent_folder)
  parts = name.split('/').reject(&:empty?)
  parts.each do |item|
    Chef::Log.debug("Identifying entity part: #{item} in folder type: #{parent_folder.class}")
    if parent_folder.is_a? RbVmomi::VIM::Folder
      Chef::Log.debug('Parent folder is a folder')
      parent_folder = parent_folder.childEntity.find { |f| f.name == item }
    else
      parent_folder = yield(parent_folder, item)
    end
  end
  parent_folder
end

#find_ethernet_cards_for(vm) ⇒ Object

Finds the Network cards from the VM

Parameters:

  • vm (Object)

    the VM object to do the query against.



168
169
170
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 168

def find_ethernet_cards_for(vm)
  vm.config.hardware.device.select { |d| d.is_a?(RbVmomi::VIM::VirtualEthernetCard) }
end

#find_folder(folder_name) ⇒ Object

Find the folder it could be like: /Level1/Level2/folder_name

Parameters:

  • folder_name (String)

    the name of the folder.

Returns:

  • (Object)

    base the location of the folder.



100
101
102
103
104
105
106
107
108
109
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 100

def find_folder(folder_name)
  base = datacenter.vmFolder
  unless folder_name.nil?
    folder_name.split('/').reject(&:empty?).each do |item|
      base = base.find(item, RbVmomi::VIM::Folder) ||
             raise("vSphere Folder not found [#{folder_name}]")
    end
  end
  base
end

#find_host(host_name) ⇒ Object

Find the (ESXi) host.

Parameters:

  • host_name (String)

    Name of the (ESXi) VM host.



432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 432

def find_host(host_name)
  host = find_entity(host_name, datacenter.hostFolder) do |parent, part|
    case parent
    when RbVmomi::VIM::ClusterComputeResource || RbVmomi::VIM::ComputeResource
      parent.host.find { |f| f.name == part }
    when RbVmomi::VIM::HostSystem
      parent.host.find { |f| f.name == part }
    end
  end

  raise "vSphere Host not found [#{host_name}]" if host.nil?

  host = host.host.first if host.is_a?(RbVmomi::VIM::ComputeResource)
  host
end

#find_network(name) ⇒ Object

Find the Network name.

Parameters:

  • name (String)

    Name of the Network.



482
483
484
485
486
487
488
489
490
491
492
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 482

def find_network(name)
  base = datacenter.networkFolder
  entity_array = name.split('/').reject(&:empty?)
  entity_array.each do |item|
    base = traverse_folders_for_network(base, item)
  end

  raise "vSphere Network not found [#{name}]" if base.nil?

  base
end

#find_pool(pool_name) ⇒ Object

Find the Resource pool.

Parameters:

  • pool_name (String)

    Name of the Resource Pool.



451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 451

def find_pool(pool_name)
  Chef::Log.debug("Finding pool: #{pool_name}")
  pool = find_entity(pool_name, datacenter.hostFolder) do |parent, part|
    case parent
    when RbVmomi::VIM::ClusterComputeResource, RbVmomi::VIM::ComputeResource
      Chef::Log.debug("finding #{part} in a #{parent.class}: #{parent.name}")
      Chef::Log.debug("Parent root pool has #{parent.resourcePool.resourcePool.count} pools")
      parent.resourcePool.resourcePool.each { |p| Chef::Log.debug(p.name) }
      parent.resourcePool.resourcePool.find { |f| f.name == part }
    when RbVmomi::VIM::ResourcePool
      Chef::Log.debug("finding #{part} in a Resource Pool: #{parent.name}")
      Chef::Log.debug("Pool has #{parent.resourcePool.count} pools")
      parent.resourcePool.each { |p| Chef::Log.debug(p.name) }
      parent.resourcePool.find { |f| f.name == part }
    else
      Chef::Log.debug("parent of #{part} is unexpected type: #{parent.class}")
      nil
    end
  end

  raise "vSphere ResourcePool not found [#{pool_name}]" if pool.nil?

  if !pool.is_a?(RbVmomi::VIM::ResourcePool) && pool.respond_to?(:resourcePool)
    pool = pool.resourcePool
  end
  pool
end

#find_vm(folder, vm_name) ⇒ Object

Finds the vm using RbVmomi

Parameters:

  • folder (String)

    the folder name for to look into.

  • vm_name (String)

    the name of the machine.



52
53
54
55
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 52

def find_vm(folder, vm_name)
  folder = find_folder(folder) unless folder.is_a? RbVmomi::VIM::Folder
  folder.find(vm_name, RbVmomi::VIM::VirtualMachine)
end

#find_vm_by_id(uuid) ⇒ Object

Finds the vm using the UUID

Parameters:

  • uuid (String)

    the UUID of the machine



60
61
62
63
64
65
66
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 60

def find_vm_by_id(uuid)
  vm = vim.searchIndex.FindByUuid(
    uuid: uuid,
    vmSearch: true,
    instanceUuid: true
  )
end

#network_adapter_for(operation, network_name, network_label, device_key, backing_info) ⇒ Object

Creates the network adapter for Rbvmomi

Parameters:

  • operation (Object)

    what you need to do to RBvmomi

  • network_name (String)

    the name of the network the adapter needs to connect to

  • network_label (String)

    the more verbose name of the network the adapter needs to connect to

  • device_key (String)

    TODO

  • backing_info (String)

    TODO



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 147

def network_adapter_for(operation, network_name, network_label, device_key, backing_info)
  connectable = RbVmomi::VIM::VirtualDeviceConnectInfo(
    allowGuestControl: true,
    connected: true,
    startConnected: true
  )
  device = RbVmomi::VIM::VirtualVmxnet3(
    backing: backing_info,
    deviceInfo: RbVmomi::VIM::Description(label: network_label, summary: network_name.split('/').last),
    key: device_key,
    connectable: connectable
  )
  RbVmomi::VIM::VirtualDeviceConfigSpec(
    operation: operation,
    device: device
  )
end

#network_device_changes(action_handler, vm_template, options) ⇒ Object

Add a new network card via the boot_options

Parameters:

  • action_handler (Object)

    TODO

  • vm_template (String)

    the Name of the Template to clone

  • options (Object)

    the options from Chef Provisioning to help configure the VM.



348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 348

def network_device_changes(action_handler, vm_template, options)
  additions = []
  changes = []
  networks = options[:network_name]
  networks = [networks] if networks.is_a?(String)

  cards = find_ethernet_cards_for(vm_template)

  key = 4000
  networks.each_index do |i|
    label = "Ethernet #{i + 1}"
    backing_info = backing_info_for(action_handler, networks[i])
    if card = cards.shift
      key = card.key
      operation = RbVmomi::VIM::VirtualDeviceConfigSpecOperation('edit')
      action_handler.report_progress "changing template nic for #{networks[i]}"
      changes.push(
        network_adapter_for(operation, networks[i], label, key, backing_info)
      )
    else
      key += 1
      operation = RbVmomi::VIM::VirtualDeviceConfigSpecOperation('add')
      action_handler.report_progress "will be adding nic for #{networks[i]}"
      additions.push(
        network_adapter_for(operation, networks[i], label, key, backing_info)
      )
    end
  end
  [additions, changes]
end

#network_id_for(backing_info) ⇒ Object

Gets the network id for a specific thing?

Parameters:

  • backing_info (String)

    TODO



197
198
199
200
201
202
203
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 197

def network_id_for(backing_info)
  if backing_info.is_a?(RbVmomi::VIM::VirtualEthernetCardDistributedVirtualPortBackingInfo)
    backing_info.port.portgroupKey
  else
    backing_info.deviceName
  end
end

#set_additional_disks_for(vm, datastore, additional_disk_size_gb) ⇒ Object

Creates the additional virtual disk for the VM

Parameters:

  • vm (Object)

    the VM object.

  • datastore (Subject)

    the datastore the disk will be created on.

  • size_gb (Subject)

    the size of the disk.



261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 261

def set_additional_disks_for(vm, datastore, additional_disk_size_gb)
  raise ':datastore must be specified when adding a disk to a cloned vm' if datastore.to_s.empty? && additional_disk_size_gb

  Array(additional_disk_size_gb).each do |size|
    size = size.to_i
    next if size <= 0

    task = vm.ReconfigVM_Task(
      spec: RbVmomi::VIM.VirtualMachineConfigSpec(
        deviceChange: [
          virtual_disk_for(
            vm,
            datastore,
            size
          )
        ]
      )
    )
    task.wait_for_completion
  end
end

#set_initial_iso(vm, initial_iso_image) ⇒ Object

Mounts the an iso on the first virtual CD ROm

Parameters:

  • vm (Object)

    the VM object.

  • name (Subject)

    of the iso file



287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 287

def set_initial_iso(vm, initial_iso_image)
  return unless initial_iso_image

  d_obj = vm.config.hardware.device.select { |hw| hw.class == RbVmomi::VIM::VirtualCdrom }.first
  backing = RbVmomi::VIM::VirtualCdromIsoBackingInfo(fileName: initial_iso_image)

  task = vm.ReconfigVM_Task(
    spec: RbVmomi::VIM.VirtualMachineConfigSpec(
      deviceChange: [
        operation: :edit,
        device: RbVmomi::VIM::VirtualCdrom(
          backing: backing,
          key: d_obj.key,
          controllerKey: d_obj.controllerKey,
          connectable: RbVmomi::VIM::VirtualDeviceConnectInfo(
            startConnected: true,
            connected: true,

            allowGuestControl: true
          )
        )
      ]
    )
  )
  task.wait_for_completion
end

#start_vm(vm, _wait_on_port = 22) ⇒ Object

Starts the VM

Parameters:

  • vm (Object)

    the main VM object to talk to vSphere.

  • _wait_on_port (Object) (defaults to: 22)

    Defaults to port 22, to connect and verify it’s up.



72
73
74
75
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 72

def start_vm(vm, _wait_on_port = 22)
  state = vm.runtime.powerState
  vm.PowerOnVM_Task.wait_for_completion unless state == 'poweredOn'
end

#stop_vm(vm, timeout = 600) ⇒ Object

Stops the VM

Parameters:

  • vm (Object)

    the main VM object to talk to vSphere.

  • timeout (Object) (defaults to: 600)

    Defaults to 600 seconds or 10 mins before giving up.



81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 81

def stop_vm(vm, timeout = 600)
  start = Time.now.utc
  return if vm.runtime.powerState == 'poweredOff'
  begin
    vm.ShutdownGuest
    until (Time.now.utc - start) > timeout ||
          vm.runtime.powerState == 'poweredOff'
      print '.'
      sleep 2
    end
  rescue
    vm.PowerOffVM_Task.wait_for_completion
  end
end

#traverse_folders_for_dc(folder, dcname) ⇒ False

Walks through the folders to if needed

Parameters:

  • folder (String)

    the name of the folder.

  • dcname (String)

    the name of the DC.

Returns:

  • (False)

    Returns false if not needed.



116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 116

def traverse_folders_for_dc(folder, dcname)
  children = folder.children.find_all
  children.each do |child|
    if child.class == RbVmomi::VIM::Datacenter && child.name == dcname
      return child
    elsif child.class == RbVmomi::VIM::Folder
      dc = traverse_folders_for_dc(child, dcname)
      return dc if dc
    end
  end
  false
end

#traverse_folders_for_network(base, item) ⇒ Object

Search the item through the base’s children

Parameters:

  • base

    vSphere object where to search

  • item (String)

    the name of the network to look for



497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 497

def traverse_folders_for_network(base, item)
  Chef::Log.debug("Searching #{item} in #{base.name}")
  case base
  when RbVmomi::VIM::Folder
    res = base.find(item)
    return res unless res.nil?
    base.childEntity.each do |child|
      res = traverse_folders_for_network(child, item)
      return res unless res.nil?
    end
    nil
  when RbVmomi::VIM::VmwareDistributedVirtualSwitch
    idx = base.summary.portgroupName.find_index(item)
    idx.nil? ? nil : base.portgroup[idx]
  end
end

#update_main_disk_size_for(vm, size_gb) ⇒ Object

Updates the main virtual disk for the VM This can only add capacity to the main disk, it is not possible to reduce the capacity.

Parameters:

  • vm (Object)

    the VM object.

  • size_gb (Subject)

    the final size of the disk.



319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 319

def update_main_disk_size_for(vm, size_gb)
  disk = vm.disks.first
  size_kb = size_gb.to_i * 1024 * 1024
  if disk.capacityInKB > size_kb
    if size_gb.to_i > 0
      msg = "Specified disk size #{size_gb}GB is inferior to the template's disk size (#{disk.capacityInKB / 1024**2}GB)."
      msg += "\nThe VM disk size will remain the same."
      Chef::Log.warn(msg)
    end
    return false
  end
  disk.capacityInKB = size_kb
  vm.ReconfigVM_Task(
    spec: RbVmomi::VIM.VirtualMachineConfigSpec(
      deviceChange: [
        {
          operation: :edit,
          device: disk
        }
      ]
    )
  ).wait_for_completion
end

#upload_file_to_vm(vm, username, password, local, remote) ⇒ Object

Upload a file to the VM using RbVmomi

Parameters:

  • vm (Object)

    The VM object.

  • username (String)

    The username to access the machine.

  • password (String)

    The password to access the machine.

  • local (String)

    The local file to upload.

  • remote (String)

    The remote file to upload location.



532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 532

def upload_file_to_vm(vm, username, password, local, remote)
  auth = RbVmomi::VIM::NamePasswordAuthentication(username: username, password: password, interactiveSession: false)
  size = File.size(local)
  endpoint = $guest_op_managers[vim.pretty_inspect].fileManager.InitiateFileTransferToGuest(
    vm: vm,
    auth: auth,
    guestFilePath: remote,
    overwrite: true,
    fileAttributes: RbVmomi::VIM::GuestWindowsFileAttributes.new,
    fileSize: size
  )

  uri = URI.parse(endpoint)
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE

  req = Net::HTTP::Put.new("#{uri.path}?#{uri.query}")
  req.body_stream = File.open(local)
  req['Content-Type'] = 'application/octet-stream'
  req['Content-Length'] = size
  res = http.request(req)
  unless res.is_a?(Net::HTTPSuccess)
    raise "Error: #{res.inspect} :: #{res.body} :: sending #{local} to #{remote} at #{vm.name} via #{endpoint} with a size of #{size}"
  end
end

#vimObject

Establishes the connection to the vSphere cluster



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 28

def vim
  if @current_connection.nil? || @current_connection.serviceContent.sessionManager.currentSession.nil?
    @datacenter = nil
    puts "establishing connection to #{connect_options[:host]}"
    @current_connection = RbVmomi::VIM.connect connect_options
    str_conn = @current_connection.pretty_inspect # a string in the format of VIM(host ip)

    # we are caching guest operation managers in a global variable...terrible i know
    # this object is available from the serviceContent object on API version 5 forward
    # Its a singleton and if another connection is made for the same host and user
    # that object is not available on any subsequent connection
    # I could find no documentation that discusses this
    unless $guest_op_managers.key?(str_conn)
      $guest_op_managers[str_conn] = @current_connection.serviceContent.guestOperationsManager
    end
  end

  @current_connection
end

#virtual_disk_for(vm, datastore, size_gb) ⇒ Object

Creates a virtual disk for the VM

Parameters:

  • vm (Object)

    the VM object.

  • datastore (Subject)

    the datastore the disk will be created on.

  • size_gb (Subject)

    the size of the disk.



237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/chef/provisioning/vsphere_driver/vsphere_helpers.rb', line 237

def virtual_disk_for(vm, datastore, size_gb)
  idx = vm.disks.count
  RbVmomi::VIM::VirtualDeviceConfigSpec(
    operation: :add,
    fileOperation: :create,
    device: RbVmomi::VIM.VirtualDisk(
      key: idx,
      backing: RbVmomi::VIM.VirtualDiskFlatVer2BackingInfo(
        fileName: "[#{datastore}]",
        diskMode: 'persistent',
        thinProvisioned: true
      ),
      capacityInKB: size_gb * 1024 * 1024,
      controllerKey: 1000,
      unitNumber: idx
    )
  )
end