Class: Vmpooler::PoolManager::Provider::VSphere

Inherits:
Base
  • Object
show all
Defined in:
lib/vmpooler/providers/vsphere.rb

Constant Summary collapse

ADAPTER_TYPE =

vSphere helper methods

'lsiLogic'.freeze
DISK_TYPE =
'thin'.freeze
DISK_MODE =
'persistent'.freeze

Instance Attribute Summary collapse

Attributes inherited from Base

#logger, #metrics, #provider_options

Instance Method Summary collapse

Methods inherited from Base

#find_least_used_compatible_host, #get_vm_host, #global_config, #migrate_vm_to_host, #pool_config, #provided_pools, #provider_config, #vm_exists?

Constructor Details

#initialize(config, logger, metrics, name, options) ⇒ VSphere

Returns a new instance of VSphere.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/vmpooler/providers/vsphere.rb', line 10

def initialize(config, logger, metrics, name, options)
  super(config, logger, metrics, name, options)

  task_limit = global_config[:config].nil? || global_config[:config]['task_limit'].nil? ? 10 : global_config[:config]['task_limit'].to_i
  # The default connection pool size is:
  # Whatever is biggest from:
  #   - How many pools this provider services
  #   - Maximum number of cloning tasks allowed
  #   - Need at least 2 connections so that a pool can have inventory functions performed while cloning etc.
  default_connpool_size = [provided_pools.count, task_limit, 2].max
  connpool_size = provider_config['connection_pool_size'].nil? ? default_connpool_size : provider_config['connection_pool_size'].to_i
  # The default connection pool timeout should be quite large - 60 seconds
  connpool_timeout = provider_config['connection_pool_timeout'].nil? ? 60 : provider_config['connection_pool_timeout'].to_i
  logger.log('d', "[#{name}] ConnPool - Creating a connection pool of size #{connpool_size} with timeout #{connpool_timeout}")
  @connection_pool = Vmpooler::PoolManager::GenericConnectionPool.new(
    metrics: metrics,
    metric_prefix: "#{name}_provider_connection_pool",
    size: connpool_size,
    timeout: connpool_timeout
  ) do
    logger.log('d', "[#{name}] Connection Pool - Creating a connection object")
    # Need to wrap the vSphere connection object in another object. The generic connection pooler will preserve
    # the object reference for the connection, which means it cannot "reconnect" by creating an entirely new connection
    # object.  Instead by wrapping it in a Hash, the Hash object reference itself never changes but the content of the
    # Hash can change, and is preserved across invocations.
    new_conn = connect_to_vsphere
    { connection: new_conn }
  end
  @provider_hosts = {}
  @provider_hosts_lock = Mutex.new
end

Instance Attribute Details

#connection_poolObject (readonly)

The connection_pool method is normally used only for testing



8
9
10
# File 'lib/vmpooler/providers/vsphere.rb', line 8

def connection_pool
  @connection_pool
end

Instance Method Details

#add_disk(vm, size, datastore, connection, datacentername) ⇒ Object



558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
# File 'lib/vmpooler/providers/vsphere.rb', line 558

def add_disk(vm, size, datastore, connection, datacentername)
  return false unless size.to_i > 0

  vmdk_datastore = find_datastore(datastore, connection, datacentername)
  raise("Datastore '#{datastore}' does not exist in datacenter '#{datacentername}'") if vmdk_datastore.nil?

  datacenter = connection.serviceInstance.find_datacenter(datacentername)
  controller = find_disk_controller(vm)
  disk_unit_number = find_disk_unit_number(vm, controller)
  disk_count = vm.config.hardware.device.grep(RbVmomi::VIM::VirtualDisk).count
  vmdk_file_name = "#{vm['name']}/#{vm['name']}_#{disk_count}.vmdk"

  vmdk_spec = RbVmomi::VIM::FileBackedVirtualDiskSpec(
    capacityKb: size.to_i * 1024 * 1024,
    adapterType: ADAPTER_TYPE,
    diskType: DISK_TYPE
  )

  vmdk_backing = RbVmomi::VIM::VirtualDiskFlatVer2BackingInfo(
    datastore: vmdk_datastore,
    diskMode: DISK_MODE,
    fileName: "[#{datastore}] #{vmdk_file_name}"
  )

  device = RbVmomi::VIM::VirtualDisk(
    backing: vmdk_backing,
    capacityInKB: size.to_i * 1024 * 1024,
    controllerKey: controller.key,
    key: -1,
    unitNumber: disk_unit_number
  )

  device_config_spec = RbVmomi::VIM::VirtualDeviceConfigSpec(
    device: device,
    operation: RbVmomi::VIM::VirtualDeviceConfigSpecOperation('add')
  )

  vm_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec(
    deviceChange: [device_config_spec]
  )

  connection.serviceContent.virtualDiskManager.CreateVirtualDisk_Task(
    datacenter: datacenter,
    name: "[#{datastore}] #{vmdk_file_name}",
    spec: vmdk_spec
  ).wait_for_completion

  vm.ReconfigVM_Task(spec: vm_config_spec).wait_for_completion

  true
end

#build_compatible_hosts_lists(hosts, percentage) ⇒ Object



771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
# File 'lib/vmpooler/providers/vsphere.rb', line 771

def build_compatible_hosts_lists(hosts, percentage)
  hosts_with_arch_versions = hosts.map { |h|
    {
    'utilization' => h[0],
    'host_object' => h[1],
    'architecture' => get_host_cpu_arch_version(h[1])
    }
  }
  versions = hosts_with_arch_versions.map { |host| host['architecture'] }.uniq
  architectures = {}
  versions.each do |version|
    architectures[version] = []
  end

  hosts_with_arch_versions.each do |h|
    architectures[h['architecture']] << [h['utilization'], h['host_object'], h['architecture']]
  end

  versions.each do |version|
    targets = []
    targets = select_least_used_hosts(architectures[version], percentage)
    architectures[version] = targets
  end
  architectures
end

#build_propSpecs(datacenter, folder, vmname) ⇒ Object



868
869
870
871
872
873
874
# File 'lib/vmpooler/providers/vsphere.rb', line 868

def build_propSpecs(datacenter, folder, vmname)
  propSpecs = {
    entity => self,
    :inventoryPath => "#{datacenter}/vm/#{folder}/#{vmname}"
  }
  propSpecs
end

#connect_to_vsphereObject



500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
# File 'lib/vmpooler/providers/vsphere.rb', line 500

def connect_to_vsphere
  max_tries = global_config[:config]['max_tries'] || 3
  retry_factor = global_config[:config]['retry_factor'] || 10
  try = 1
  begin
    connection = RbVmomi::VIM.connect host: provider_config['server'],
                                      user: provider_config['username'],
                                      password: provider_config['password'],
                                      insecure: provider_config['insecure'] || false
    metrics.increment('connect.open')
    return connection
  rescue => err
    metrics.increment('connect.fail')
    raise err if try >= max_tries
    sleep(try * retry_factor)
    try += 1
    retry
  end
end

#cpu_utilization_for(host) ⇒ Object



752
753
754
755
756
757
# File 'lib/vmpooler/providers/vsphere.rb', line 752

def cpu_utilization_for(host)
  cpu_usage = host.summary.quickStats.overallCpuUsage
  return nil if cpu_usage.nil?
  cpu_size = host.summary.hardware.cpuMhz * host.summary.hardware.numCpuCores
  (cpu_usage.to_f / cpu_size.to_f) * 100
end

#create_disk(pool_name, vm_name, disk_size) ⇒ Object



363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
# File 'lib/vmpooler/providers/vsphere.rb', line 363

def create_disk(pool_name, vm_name, disk_size)
  pool = pool_config(pool_name)
  raise("Pool #{pool_name} does not exist for the provider #{name}") if pool.nil?

  datastore_name = pool['datastore']
  raise("Pool #{pool_name} does not have a datastore defined for the provider #{name}") if datastore_name.nil?

  @connection_pool.with_metrics do |pool_object|
    connection = ensured_vsphere_connection(pool_object)
    vm_object = find_vm(pool_name, vm_name, connection)
    raise("VM #{vm_name} in pool #{pool_name} does not exist for the provider #{name}") if vm_object.nil?

    add_disk(vm_object, disk_size, datastore_name, connection, get_target_datacenter_from_config(pool_name))
  end
  true
end

#create_folder(connection, new_folder, datacenter) ⇒ Object



994
995
996
997
998
999
# File 'lib/vmpooler/providers/vsphere.rb', line 994

def create_folder(connection, new_folder, datacenter)
  dc = connection.serviceInstance.find_datacenter(datacenter)
  folder_object = dc.vmFolder.traverse(new_folder, type=RbVmomi::VIM::Folder, create=true)
  raise("Cannot create folder #{new_folder}") if folder_object.nil?
  folder_object
end

#create_snapshot(pool_name, vm_name, new_snapshot_name) ⇒ Object



380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
# File 'lib/vmpooler/providers/vsphere.rb', line 380

def create_snapshot(pool_name, vm_name, new_snapshot_name)
  @connection_pool.with_metrics do |pool_object|
    connection = ensured_vsphere_connection(pool_object)
    vm_object = find_vm(pool_name, vm_name, connection)
    raise("VM #{vm_name} in pool #{pool_name} does not exist for the provider #{name}") if vm_object.nil?

    old_snap = find_snapshot(vm_object, new_snapshot_name)
    raise("Snapshot #{new_snapshot_name} for VM #{vm_name} in pool #{pool_name} already exists for the provider #{name}") unless old_snap.nil?

    vm_object.CreateSnapshot_Task(
      name: new_snapshot_name,
      description: 'vmpooler',
      memory: true,
      quiesce: true
    ).wait_for_completion
  end
  true
end

#create_template_delta_disks(pool) ⇒ Object



1016
1017
1018
1019
1020
1021
1022
1023
# File 'lib/vmpooler/providers/vsphere.rb', line 1016

def create_template_delta_disks(pool)
  @connection_pool.with_metrics do |pool_object|
    connection = ensured_vsphere_connection(pool_object)
    template_vm_object = find_template_vm(pool, connection)

    template_vm_object.add_delta_disk_layer_on_all_disks
  end
end

#create_vm(pool_name, new_vmname) ⇒ Object



280
281
282
283
284
285
286
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
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/vmpooler/providers/vsphere.rb', line 280

def create_vm(pool_name, new_vmname)
  pool = pool_config(pool_name)
  raise("Pool #{pool_name} does not exist for the provider #{name}") if pool.nil?
  vm_hash = nil
  @connection_pool.with_metrics do |pool_object|
    connection = ensured_vsphere_connection(pool_object)
    # Assume all pool config is valid i.e. not missing
    template_path = pool['template']
    target_folder_path = pool['folder']
    target_datastore = pool['datastore']
    target_cluster_name = get_target_cluster_from_config(pool_name)
    target_datacenter_name = get_target_datacenter_from_config(pool_name)

    # Get the template VM object
    raise("Pool #{pool_name} did not specify a full path for the template for the provider #{name}") unless valid_template_path? template_path

    template_vm_object = find_template_vm(pool, connection)

    # Annotate with creation time, origin template, etc.
    # Add extraconfig options that can be queried by vmtools
    config_spec = RbVmomi::VIM.VirtualMachineConfigSpec(
      annotation: JSON.pretty_generate(
        name: new_vmname,
        created_by: provider_config['username'],
        base_template: template_path,
        creation_timestamp: Time.now.utc
      ),
      extraConfig: [
        { key: 'guestinfo.hostname', value: new_vmname }
      ]
    )

    # Put the VM in the specified folder and resource pool
    relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec(
      datastore: find_datastore(target_datastore, connection, target_datacenter_name),
      diskMoveType: :moveChildMostDiskBacking
    )

    manage_host_selection = @config[:config]['manage_host_selection'] if @config[:config].key?('manage_host_selection')
    if manage_host_selection
      run_select_hosts(pool_name, @provider_hosts)
      target_host = select_next_host(pool_name, @provider_hosts)
      host_object = find_host_by_dnsname(connection, target_host)
      relocate_spec.host = host_object
    else
    # Choose a cluster/host to place the new VM on
      target_cluster_object = find_cluster(target_cluster_name, connection, target_datacenter_name)
      relocate_spec.pool = target_cluster_object.resourcePool
    end

    # Create a clone spec
    clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(
      location: relocate_spec,
      config: config_spec,
      powerOn: true,
      template: false
    )

    begin
      vm_target_folder = find_vm_folder(pool_name, connection)
      if vm_target_folder.nil? and @config[:config].key?('create_folders') and @config[:config]['create_folders'] == true
        vm_target_folder = create_folder(connection, target_folder_path, target_datacenter_name)
      end
    rescue => _err
      if @config[:config].key?('create_folders') and @config[:config]['create_folders'] == true
        vm_target_folder = create_folder(connection, target_folder_path, target_datacenter_name)
      else
        raise(_err)
      end
    end

    # Create the new VM
    new_vm_object = template_vm_object.CloneVM_Task(
      folder: vm_target_folder,
      name: new_vmname,
      spec: clone_spec
    ).wait_for_completion

    vm_hash = generate_vm_hash(new_vm_object, pool_name)
  end
  vm_hash
end

#destroy_folder(folder_object) ⇒ Object



102
103
104
105
106
107
108
109
110
# File 'lib/vmpooler/providers/vsphere.rb', line 102

def destroy_folder(folder_object)
  try = 0 if try.nil?
  max_tries = 3
  logger.log('s', "[-] [#{folder_object.name}] removing unconfigured folder")
  folder_object.Destroy_Task.wait_for_completion
rescue
  try += 1
  try >= max_tries ? raise : retry
end

#destroy_folder_and_children(folder_object) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/vmpooler/providers/vsphere.rb', line 86

def destroy_folder_and_children(folder_object)
  vms = {}
  data_ttl = $config[:redis]['data_ttl'].to_i
  folder_name = folder_object.name
  unless folder_object.childEntity.count == 0
    folder_object.childEntity.each do |vm|
      vms[vm.name] = vm
    end

    vms.each do |vm_name, vm_object|
      destroy_vm_and_log(vm_name, vm_object, folder_name, data_ttl)
    end
  end
  destroy_folder(folder_object)
end

#destroy_vm(pool_name, vm_name) ⇒ Object



413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
# File 'lib/vmpooler/providers/vsphere.rb', line 413

def destroy_vm(pool_name, vm_name)
  @connection_pool.with_metrics do |pool_object|
    connection = ensured_vsphere_connection(pool_object)
    vm_object = find_vm(pool_name, vm_name, connection)
    # If a VM doesn't exist then it is effectively deleted
    return true if vm_object.nil?

    # Poweroff the VM if it's running
    vm_object.PowerOffVM_Task.wait_for_completion if vm_object.runtime && vm_object.runtime.powerState && vm_object.runtime.powerState == 'poweredOn'

    # Kill it with fire
    vm_object.Destroy_Task.wait_for_completion
  end
  true
end

#destroy_vm_and_log(vm_name, vm_object, pool, data_ttl) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/vmpooler/providers/vsphere.rb', line 56

def destroy_vm_and_log(vm_name, vm_object, pool, data_ttl)
  try = 0 if try.nil?
  max_tries = 3
  $redis.srem("vmpooler__completed__#{pool}", vm_name)
  $redis.hdel("vmpooler__active__#{pool}", vm_name)
  $redis.hset("vmpooler__vm__#{vm_name}", 'destroy', Time.now)

  # Auto-expire metadata key
  $redis.expire('vmpooler__vm__' + vm_name, (data_ttl * 60 * 60))

  start = Time.now

  if vm_object.is_a? RbVmomi::VIM::Folder
    logger.log('s', "[!] [#{pool}] '#{vm_name}' is a folder, bailing on destroying")
    raise('Expected VM, but received a folder object')
  end
  vm_object.PowerOffVM_Task.wait_for_completion if vm_object.runtime && vm_object.runtime.powerState && vm_object.runtime.powerState == 'poweredOn'
  vm_object.Destroy_Task.wait_for_completion

  finish = format('%.2f', Time.now - start)
  logger.log('s', "[-] [#{pool}] '#{vm_name}' destroyed in #{finish} seconds")
  metrics.timing("destroy.#{pool}", finish)
rescue RuntimeError
  raise
rescue => err
  try += 1
  logger.log('s', "[!] [#{pool}] failed to destroy '#{vm_name}' with an error: #{err}")
  try >= max_tries ? raise : retry
end

#ensured_vsphere_connection(connection_pool_object) ⇒ Object



488
489
490
491
# File 'lib/vmpooler/providers/vsphere.rb', line 488

def ensured_vsphere_connection(connection_pool_object)
  connection_pool_object[:connection] = connect_to_vsphere unless vsphere_connection_ok?(connection_pool_object[:connection])
  connection_pool_object[:connection]
end

#find_cluster(cluster, connection, datacentername) ⇒ Object



839
840
841
842
843
# File 'lib/vmpooler/providers/vsphere.rb', line 839

def find_cluster(cluster, connection, datacentername)
  datacenter = connection.serviceInstance.find_datacenter(datacentername)
  raise("Datacenter #{datacentername} does not exist") if datacenter.nil?
  datacenter.hostFolder.children.find { |cluster_object| cluster_object.name == cluster }
end

#find_datastore(datastorename, connection, datacentername) ⇒ Object



610
611
612
613
614
# File 'lib/vmpooler/providers/vsphere.rb', line 610

def find_datastore(datastorename, connection, datacentername)
  datacenter = connection.serviceInstance.find_datacenter(datacentername)
  raise("Datacenter #{datacentername} does not exist") if datacenter.nil?
  datacenter.find_datastore(datastorename)
end

#find_device(vm, device_name) ⇒ Object



616
617
618
619
620
621
622
# File 'lib/vmpooler/providers/vsphere.rb', line 616

def find_device(vm, device_name)
  vm.config.hardware.device.each do |device|
    return device if device.deviceInfo.label == device_name
  end

  nil
end

#find_disk_controller(vm) ⇒ Object



624
625
626
627
628
629
630
631
632
633
634
# File 'lib/vmpooler/providers/vsphere.rb', line 624

def find_disk_controller(vm)
  devices = find_disk_devices(vm)

  devices.keys.sort.each do |device|
    if devices[device]['children'].length < 15
      return find_device(vm, devices[device]['device'].deviceInfo.label)
    end
  end

  nil
end

#find_disk_devices(vm) ⇒ Object



636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
# File 'lib/vmpooler/providers/vsphere.rb', line 636

def find_disk_devices(vm)
  devices = {}

  vm.config.hardware.device.each do |device|
    if device.is_a? RbVmomi::VIM::VirtualSCSIController
      if devices[device.controllerKey].nil?
        devices[device.key] = {}
        devices[device.key]['children'] = []
      end

      devices[device.key]['device'] = device
    end

    if device.is_a? RbVmomi::VIM::VirtualDisk
      if devices[device.controllerKey].nil?
        devices[device.controllerKey] = {}
        devices[device.controllerKey]['children'] = []
      end

      devices[device.controllerKey]['children'].push(device)
    end
  end

  devices
end

#find_disk_unit_number(vm, controller) ⇒ Object



662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
# File 'lib/vmpooler/providers/vsphere.rb', line 662

def find_disk_unit_number(vm, controller)
  used_unit_numbers = []
  available_unit_numbers = []

  devices = find_disk_devices(vm)

  devices.keys.sort.each do |c|
    next unless controller.key == devices[c]['device'].key
    used_unit_numbers.push(devices[c]['device'].scsiCtlrUnitNumber)
    devices[c]['children'].each do |disk|
      used_unit_numbers.push(disk.unitNumber)
    end
  end

  (0..15).each do |scsi_id|
    if used_unit_numbers.grep(scsi_id).length <= 0
      available_unit_numbers.push(scsi_id)
    end
  end

  available_unit_numbers.sort[0]
end

#find_host_by_dnsname(connection, dnsname) ⇒ Object



825
826
827
828
829
# File 'lib/vmpooler/providers/vsphere.rb', line 825

def find_host_by_dnsname(connection, dnsname)
  host_object = connection.searchIndex.FindByDnsName(dnsName: dnsname, vmSearch: false)
  return nil if host_object.nil?
  host_object
end

#find_least_used_host(cluster, connection, datacentername) ⇒ Object



831
832
833
834
835
836
837
# File 'lib/vmpooler/providers/vsphere.rb', line 831

def find_least_used_host(cluster, connection, datacentername)
  cluster_object = find_cluster(cluster, connection, datacentername)
  target_hosts = get_cluster_host_utilization(cluster_object)
  raise("There is no host candidate in vcenter that meets all the required conditions, check that the cluster has available hosts in a 'green' status, not in maintenance mode and not overloaded CPU and memory'") if target_hosts.empty?
  least_used_host = target_hosts.sort[0][1]
  least_used_host
end

#find_least_used_hosts(cluster, datacentername, percentage) ⇒ Object



809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
# File 'lib/vmpooler/providers/vsphere.rb', line 809

def find_least_used_hosts(cluster, datacentername, percentage)
  @connection_pool.with_metrics do |pool_object|
    connection = ensured_vsphere_connection(pool_object)
    cluster_object = find_cluster(cluster, connection, datacentername)
    raise("Cluster #{cluster} cannot be found") if cluster_object.nil?
    target_hosts = get_cluster_host_utilization(cluster_object)
    raise("there is no candidate in vcenter that meets all the required conditions, that the cluster has available hosts in a 'green' status, not in maintenance mode and not overloaded CPU and memory'") if target_hosts.empty?
    architectures = build_compatible_hosts_lists(target_hosts, percentage)
    least_used_hosts = select_least_used_hosts(target_hosts, percentage)
    {
      'hosts' => least_used_hosts,
      'architectures' => architectures
    }
  end
end

#find_least_used_vpshere_compatible_host(vm) ⇒ Object



854
855
856
857
858
859
860
861
862
# File 'lib/vmpooler/providers/vsphere.rb', line 854

def find_least_used_vpshere_compatible_host(vm)
  source_host = vm.summary.runtime.host
  model = get_host_cpu_arch_version(source_host)
  cluster = source_host.parent
  target_hosts = get_cluster_host_utilization(cluster, model)
  raise("There is no host candidate in vcenter that meets all the required conditions, check that the cluster has available hosts in a 'green' status, not in maintenance mode and not overloaded CPU and memory'") if target_hosts.empty?
  target_host = target_hosts.sort[0][1]
  [target_host, target_host.name]
end

#find_snapshot(vm, snapshotname) ⇒ Object



864
865
866
# File 'lib/vmpooler/providers/vsphere.rb', line 864

def find_snapshot(vm, snapshotname)
  get_snapshot_list(vm.snapshot.rootSnapshotList, snapshotname) if vm.snapshot
end

#find_template_vm(pool, connection) ⇒ Object



1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
# File 'lib/vmpooler/providers/vsphere.rb', line 1001

def find_template_vm(pool, connection)
  datacenter = get_target_datacenter_from_config(pool['name'])
  raise('cannot find datacenter') if datacenter.nil?

  propSpecs = {
    :entity => self,
    :inventoryPath => "#{datacenter}/vm/#{pool['template']}"
  }

  template_vm_object = connection.searchIndex.FindByInventoryPath(propSpecs)
  raise("Pool #{pool['name']} specifies a template VM of #{pool['template']} which does not exist for the provider #{name}") if template_vm_object.nil?

  template_vm_object
end

#find_vm(pool_name, vmname, connection) ⇒ Object



876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
# File 'lib/vmpooler/providers/vsphere.rb', line 876

def find_vm(pool_name, vmname, connection)
  # Find a VM by its inventory path and return the VM object
  # Returns nil when a VM, or pool configuration, cannot be found
  pool_configuration = pool_config(pool_name)
  return nil if pool_configuration.nil?
  folder = pool_configuration['folder']
  datacenter = get_target_datacenter_from_config(pool_name)
  return nil if datacenter.nil?

  propSpecs = {
    :entity => self,
    :inventoryPath => "#{datacenter}/vm/#{folder}/#{vmname}"
  }

  connection.searchIndex.FindByInventoryPath(propSpecs)
end

#find_vm_folder(pool_name, connection) ⇒ Object

Finds a folder object by inventory path Params:

pool_name

the pool to find the folder for

connection

the vsphere connection object

returns a ManagedObjectReference for the folder found or nil if not found



690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
# File 'lib/vmpooler/providers/vsphere.rb', line 690

def find_vm_folder(pool_name, connection)
  # Find a folder by its inventory path and return the object
  # Returns nil when the object found is not a folder
  pool_configuration = pool_config(pool_name)
  return nil if pool_configuration.nil?
  folder = pool_configuration['folder']
  datacenter = get_target_datacenter_from_config(pool_name)
  return nil if datacenter.nil?

  propSpecs = {
    :entity => self,
    :inventoryPath => "#{datacenter}/vm/#{folder}"
  }

  folder_object = connection.searchIndex.FindByInventoryPath(propSpecs)
  return nil unless folder_object.class == RbVmomi::VIM::Folder
  folder_object
end

#folder_configured?(folder_title, base_folder, configured_folders, whitelist) ⇒ Boolean

Returns:

  • (Boolean)


47
48
49
50
51
52
53
54
# File 'lib/vmpooler/providers/vsphere.rb', line 47

def folder_configured?(folder_title, base_folder, configured_folders, whitelist)
  if whitelist
    return true if whitelist.include?(folder_title)
  end
  return false unless configured_folders.keys.include?(folder_title)
  return false unless configured_folders[folder_title] == base_folder
  return true
end

#generate_vm_hash(vm_object, pool_name) ⇒ Object

Return a hash of VM data Provides vmname, hostname, template, poolname, boottime and powerstate information



463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
# File 'lib/vmpooler/providers/vsphere.rb', line 463

def generate_vm_hash(vm_object, pool_name)
  pool_configuration = pool_config(pool_name)
  return nil if pool_configuration.nil?

  hostname = vm_object.summary.guest.hostName if vm_object.summary && vm_object.summary.guest && vm_object.summary.guest.hostName
  boottime = vm_object.runtime.bootTime if vm_object.runtime && vm_object.runtime.bootTime
  powerstate = vm_object.runtime.powerState if vm_object.runtime && vm_object.runtime.powerState

  hash = {
    'name' => vm_object.name,
    'hostname' => hostname,
    'template' => pool_configuration['template'],
    'poolname' => pool_name,
    'boottime' => boottime,
    'powerstate' => powerstate,
  }

  hash
end

#get_average_cluster_utilization(hosts) ⇒ Object



766
767
768
769
# File 'lib/vmpooler/providers/vsphere.rb', line 766

def get_average_cluster_utilization(hosts)
  utilization_counts = hosts.map { |host| host[0] }
  utilization_counts.inject(:+) / hosts.count
end

#get_base_vm_container_from(connection) ⇒ Object



893
894
895
896
897
898
899
900
# File 'lib/vmpooler/providers/vsphere.rb', line 893

def get_base_vm_container_from(connection)
  view_manager = connection.serviceContent.viewManager
  view_manager.CreateContainerView(
    container: connection.serviceContent.rootFolder,
    recursive: true,
    type: ['VirtualMachine']
  )
end

#get_cluster_host_utilization(cluster, model = nil) ⇒ Object



845
846
847
848
849
850
851
852
# File 'lib/vmpooler/providers/vsphere.rb', line 845

def get_cluster_host_utilization(cluster, model = nil)
  cluster_hosts = []
  cluster.host.each do |host|
    host_usage = get_host_utilization(host, model)
    cluster_hosts << host_usage if host_usage
  end
  cluster_hosts
end

#get_folder_children(folder_name, connection) ⇒ Object



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/vmpooler/providers/vsphere.rb', line 131

def get_folder_children(folder_name, connection)
  folders = []

  propSpecs = {
    :entity => self,
    :inventoryPath => folder_name
  }
  folder_object = connection.searchIndex.FindByInventoryPath(propSpecs)

  return folders if folder_object.nil?

  folder_object.childEntity.each do |folder|
    next unless folder.is_a? RbVmomi::VIM::Folder
    folders << { folder.name => folder }
  end

  folders
end

#get_host_cpu_arch_version(host) ⇒ Object



745
746
747
748
749
750
# File 'lib/vmpooler/providers/vsphere.rb', line 745

def get_host_cpu_arch_version(host)
  cpu_model = host.hardware.cpuPkg[0].description
  cpu_model_parts = cpu_model.split
  arch_version = cpu_model_parts[4]
  arch_version
end

#get_host_utilization(host, model = nil, limit = 90) ⇒ Object

Returns an array containing cumulative CPU and memory utilization of a host, and its object reference Params:

model

CPU arch version to match on

limit

Hard limit for CPU or memory utilization beyond which a host is excluded for deployments

returns nil if one on these conditions is true:

the model param is defined and cannot be found
the host is in maintenance mode
the host status is not 'green'
the cpu or memory utilization is bigger than the limit param


718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
# File 'lib/vmpooler/providers/vsphere.rb', line 718

def get_host_utilization(host, model = nil, limit = 90)
  limit = @config[:config]['utilization_limit'] if @config[:config].key?('utilization_limit')
  if model
    return nil unless host_has_cpu_model?(host, model)
  end
  return nil if host.runtime.inMaintenanceMode
  return nil unless host.overallStatus == 'green'
  return nil unless host.configIssue.empty?

  cpu_utilization = cpu_utilization_for host
  memory_utilization = memory_utilization_for host

  return nil if cpu_utilization.nil?
  return nil if cpu_utilization == 0.0
  return nil if memory_utilization.nil?
  return nil if memory_utilization == 0.0

  return nil if cpu_utilization > limit
  return nil if memory_utilization > limit

  [cpu_utilization, host]
end

#get_snapshot_list(tree, snapshotname) ⇒ Object



902
903
904
905
906
907
908
909
910
911
912
913
914
# File 'lib/vmpooler/providers/vsphere.rb', line 902

def get_snapshot_list(tree, snapshotname)
  snapshot = nil

  tree.each do |child|
    if child.name == snapshotname
      snapshot ||= child.snapshot
    else
      snapshot ||= get_snapshot_list(child.childSnapshotList, snapshotname)
    end
  end

  snapshot
end

#get_target_cluster_from_config(pool_name) ⇒ Object

VSphere Helper methods



441
442
443
444
445
446
447
448
449
# File 'lib/vmpooler/providers/vsphere.rb', line 441

def get_target_cluster_from_config(pool_name)
  pool = pool_config(pool_name)
  return nil if pool.nil?

  return pool['clone_target'] unless pool['clone_target'].nil?
  return global_config[:config]['clone_target'] unless global_config[:config]['clone_target'].nil?

  nil
end

#get_target_datacenter_from_config(pool_name) ⇒ Object



451
452
453
454
455
456
457
458
459
# File 'lib/vmpooler/providers/vsphere.rb', line 451

def get_target_datacenter_from_config(pool_name)
  pool = pool_config(pool_name)
  return nil if pool.nil?

  return pool['datacenter']            unless pool['datacenter'].nil?
  return provider_config['datacenter'] unless provider_config['datacenter'].nil?

  nil
end

#get_vm(pool_name, vm_name) ⇒ Object



268
269
270
271
272
273
274
275
276
277
278
# File 'lib/vmpooler/providers/vsphere.rb', line 268

def get_vm(pool_name, vm_name)
  vm_hash = nil
  @connection_pool.with_metrics do |pool_object|
    connection = ensured_vsphere_connection(pool_object)
    vm_object = find_vm(pool_name, vm_name, connection)
    return vm_hash if vm_object.nil?

    vm_hash = generate_vm_hash(vm_object, pool_name)
  end
  vm_hash
end

#get_vm_details(pool_name, vm_name, connection) ⇒ Object



916
917
918
919
920
921
922
923
924
925
926
927
928
# File 'lib/vmpooler/providers/vsphere.rb', line 916

def get_vm_details(pool_name, vm_name, connection)
  vm_object = find_vm(pool_name, vm_name, connection)
  return nil if vm_object.nil?
  parent_host_object = vm_object.summary.runtime.host if vm_object.summary && vm_object.summary.runtime && vm_object.summary.runtime.host
  raise('Unable to determine which host the VM is running on') if parent_host_object.nil?
  parent_host = parent_host_object.name
  architecture = get_host_cpu_arch_version(parent_host_object)
  {
    'host_name' => parent_host,
    'object' => vm_object,
    'architecture' => architecture
  }
end

#get_vm_folder_path(vm_object) ⇒ Object



534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
# File 'lib/vmpooler/providers/vsphere.rb', line 534

def get_vm_folder_path(vm_object)
  # This gives an array starting from the root Datacenters folder all the way to the VM
  # [ [Object, String], [Object, String ] ... ]
  # It's then reversed so that it now goes from the VM to the Datacenter
  full_path = vm_object.path.reverse

  # Find the Datacenter object
  dc_index = full_path.index { |p| p[0].is_a?(RbVmomi::VIM::Datacenter) }
  return nil if dc_index.nil?
  # The Datacenter should be at least 2 otherwise there's something
  # wrong with the array passed in
  # This is the minimum:
  # [ VM (0), VM ROOT FOLDER (1), DC (2)]
  return nil if dc_index <= 1

  # Remove the VM name (Starting position of 1 in the slice)
  # Up until the Root VM Folder of DataCenter Node (dc_index - 2)
  full_path = full_path.slice(1..dc_index - 2)

  # Reverse the array back to normal and
  # then convert the array of paths into a '/' seperated string
  (full_path.reverse.map { |p| p[1] }).join('/')
end

#host_has_cpu_model?(host, model) ⇒ Boolean

Returns:

  • (Boolean)


741
742
743
# File 'lib/vmpooler/providers/vsphere.rb', line 741

def host_has_cpu_model?(host, model)
  get_host_cpu_arch_version(host) == model
end

#memory_utilization_for(host) ⇒ Object



759
760
761
762
763
764
# File 'lib/vmpooler/providers/vsphere.rb', line 759

def memory_utilization_for(host)
  memory_usage = host.summary.quickStats.overallMemoryUsage
  return nil if memory_usage.nil?
  memory_size = host.summary.hardware.memorySize / 1024 / 1024
  (memory_usage.to_f / memory_size.to_f) * 100
end

#migrate_vm(pool_name, vm_name) ⇒ Object



937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
# File 'lib/vmpooler/providers/vsphere.rb', line 937

def migrate_vm(pool_name, vm_name)
  @connection_pool.with_metrics do |pool_object|
    begin
      connection = ensured_vsphere_connection(pool_object)
      vm_hash = get_vm_details(pool_name, vm_name, connection)
      migration_limit = @config[:config]['migration_limit'] if @config[:config].key?('migration_limit')
      migration_count = $redis.scard('vmpooler__migration')
      if migration_enabled? @config
        if migration_count >= migration_limit
          logger.log('s', "[ ] [#{pool_name}] '#{vm_name}' is running on #{vm_hash['host_name']}. No migration will be evaluated since the migration_limit has been reached")
          return
        end
        run_select_hosts(pool_name, @provider_hosts)
        if vm_in_target?(pool_name, vm_hash['host_name'], vm_hash['architecture'], @provider_hosts)
          logger.log('s', "[ ] [#{pool_name}] No migration required for '#{vm_name}' running on #{vm_hash['host_name']}")
        else
          migrate_vm_to_new_host(pool_name, vm_name, vm_hash, connection)
        end
      else
        logger.log('s', "[ ] [#{pool_name}] '#{vm_name}' is running on #{vm_hash['host_name']}")
      end
    rescue => _err
      logger.log('s', "[!] [#{pool_name}] '#{vm_name}' is running on #{vm_hash['host_name']}")
      raise _err
    end
  end
end

#migrate_vm_and_record_timing(pool_name, vm_name, vm_hash, target_host_object, dest_host_name) ⇒ Object



976
977
978
979
980
981
982
983
984
985
986
987
# File 'lib/vmpooler/providers/vsphere.rb', line 976

def migrate_vm_and_record_timing(pool_name, vm_name, vm_hash, target_host_object, dest_host_name)
  start = Time.now
  migrate_vm_host(vm_hash['object'], target_host_object)
  finish = format('%.2f', Time.now - start)
  metrics.timing("migrate.#{pool_name}", finish)
  metrics.increment("migrate_from.#{vm_hash['host_name']}")
  metrics.increment("migrate_to.#{dest_host_name}")
  checkout_to_migration = format('%.2f', Time.now - Time.parse($redis.hget("vmpooler__vm__#{vm_name}", 'checkout')))
  $redis.hset("vmpooler__vm__#{vm_name}", 'migration_time', finish)
  $redis.hset("vmpooler__vm__#{vm_name}", 'checkout_to_migration', checkout_to_migration)
  finish
end

#migrate_vm_host(vm_object, host) ⇒ Object



989
990
991
992
# File 'lib/vmpooler/providers/vsphere.rb', line 989

def migrate_vm_host(vm_object, host)
  relospec = RbVmomi::VIM.VirtualMachineRelocateSpec(host: host)
  vm_object.RelocateVM_Task(spec: relospec).wait_for_completion
end

#migrate_vm_to_new_host(pool_name, vm_name, vm_hash, connection) ⇒ Object



965
966
967
968
969
970
971
972
973
974
# File 'lib/vmpooler/providers/vsphere.rb', line 965

def migrate_vm_to_new_host(pool_name, vm_name, vm_hash, connection)
  $redis.sadd('vmpooler__migration', vm_name)
  target_host_name = select_next_host(pool_name, @provider_hosts, vm_hash['architecture'])
  target_host_object = find_host_by_dnsname(connection, target_host_name)
  finish = migrate_vm_and_record_timing(pool_name, vm_name, vm_hash, target_host_object, target_host_name)
  #logger.log('s', "Provider_hosts is: #{provider.provider_hosts}")
  logger.log('s', "[>] [#{pool_name}] '#{vm_name}' migrated from #{vm_hash['host_name']} to #{target_host_name} in #{finish} seconds")
ensure
  $redis.srem('vmpooler__migration', vm_name)
end

#migration_enabled?(config) ⇒ Boolean

Returns:

  • (Boolean)


930
931
932
933
934
935
# File 'lib/vmpooler/providers/vsphere.rb', line 930

def migration_enabled?(config)
  migration_limit = config[:config]['migration_limit']
  return false unless migration_limit.is_a? Integer
  return true if migration_limit > 0
  false
end

#nameObject

name of the provider class



43
44
45
# File 'lib/vmpooler/providers/vsphere.rb', line 43

def name
  'vsphere'
end

#open_socket(host, domain = nil, timeout = 5, port = 22, &_block) ⇒ Object

This should supercede the open_socket method in the Pool Manager



521
522
523
524
525
526
527
528
529
530
531
532
# File 'lib/vmpooler/providers/vsphere.rb', line 521

def open_socket(host, domain = nil, timeout = 5, port = 22, &_block)
  Timeout.timeout(timeout) do
    target_host = host
    target_host = "#{host}.#{domain}" if domain
    sock = TCPSocket.new target_host, port
    begin
      yield sock if block_given?
    ensure
      sock.close
    end
  end
end

#purge_unconfigured_folders(base_folders, configured_folders, whitelist) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/vmpooler/providers/vsphere.rb', line 112

def purge_unconfigured_folders(base_folders, configured_folders, whitelist)
  @connection_pool.with_metrics do |pool_object|
    connection = ensured_vsphere_connection(pool_object)

    base_folders.each do |base_folder|
      folder_children = get_folder_children(base_folder, connection)
      unless folder_children.empty?
        folder_children.each do |folder_hash|
          folder_hash.each do |folder_title, folder_object|
            unless folder_configured?(folder_title, base_folder, configured_folders, whitelist)
              destroy_folder_and_children(folder_object)
            end
          end
        end
      end
    end
  end
end

#revert_snapshot(pool_name, vm_name, snapshot_name) ⇒ Object



399
400
401
402
403
404
405
406
407
408
409
410
411
# File 'lib/vmpooler/providers/vsphere.rb', line 399

def revert_snapshot(pool_name, vm_name, snapshot_name)
  @connection_pool.with_metrics do |pool_object|
    connection = ensured_vsphere_connection(pool_object)
    vm_object = find_vm(pool_name, vm_name, connection)
    raise("VM #{vm_name} in pool #{pool_name} does not exist for the provider #{name}") if vm_object.nil?

    snapshot_object = find_snapshot(vm_object, snapshot_name)
    raise("Snapshot #{snapshot_name} for VM #{vm_name} in pool #{pool_name} does not exist for the provider #{name}") if snapshot_object.nil?

    snapshot_object.RevertToSnapshot_Task.wait_for_completion
  end
  true
end

#run_select_hosts(pool_name, target) ⇒ Object



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/vmpooler/providers/vsphere.rb', line 183

def run_select_hosts(pool_name, target)
  now = Time.now
  max_age = @config[:config]['host_selection_max_age'] || 60
  loop_delay = 5
  datacenter = get_target_datacenter_from_config(pool_name)
  cluster = get_target_cluster_from_config(pool_name)
  raise("cluster for pool #{pool_name} cannot be identified") if cluster.nil?
  raise("datacenter for pool #{pool_name} cannot be identified") if datacenter.nil?
  dc = "#{datacenter}_#{cluster}"
  unless target.key?(dc)
    select_target_hosts(target, cluster, datacenter)
    return
  end
  if target[dc].key?('checking')
    wait_for_host_selection(dc, target, loop_delay, max_age)
  end
  if target[dc].key?('check_time_finished')
    if now - target[dc]['check_time_finished'] > max_age
      select_target_hosts(target, cluster, datacenter)
    end
  end
end

#select_least_used_hosts(hosts, percentage) ⇒ Object



797
798
799
800
801
802
803
804
805
806
807
# File 'lib/vmpooler/providers/vsphere.rb', line 797

def select_least_used_hosts(hosts, percentage)
  raise('Provided hosts list to select_least_used_hosts is empty') if hosts.empty?
  average_utilization = get_average_cluster_utilization(hosts)
  least_used_hosts = []
  hosts.each do |host|
    least_used_hosts << host if host[0] <= average_utilization
  end
  hosts_to_select = (hosts.count * (percentage  / 100.0)).to_int
  hosts_to_select = hosts.count - 1 if percentage == 100
  least_used_hosts.sort[0..hosts_to_select].map { |host| host[1].name }
end

#select_next_host(pool_name, target, architecture = nil) ⇒ Object



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/vmpooler/providers/vsphere.rb', line 226

def select_next_host(pool_name, target, architecture = nil)
  datacenter = get_target_datacenter_from_config(pool_name)
  cluster = get_target_cluster_from_config(pool_name)
  raise("cluster for pool #{pool_name} cannot be identified") if cluster.nil?
  raise("datacenter for pool #{pool_name} cannot be identified") if datacenter.nil?
  dc = "#{datacenter}_#{cluster}"
  @provider_hosts_lock.synchronize do
    if architecture
      raise("there is no candidate in vcenter that meets all the required conditions, that the cluster has available hosts in a 'green' status, not in maintenance mode and not overloaded CPU and memory") unless target[dc].key?('architectures')
      host = target[dc]['architectures'][architecture].shift
      target[dc]['architectures'][architecture] << host
      if target[dc]['hosts'].include?(host)
        target[dc]['hosts'].delete(host)
        target[dc]['hosts'] << host
      end
      return host
    else
      raise("there is no candidate in vcenter that meets all the required conditions, that the cluster has available hosts in a 'green' status, not in maintenance mode and not overloaded CPU and memory") unless target[dc].key?('hosts')
      host = target[dc]['hosts'].shift
      target[dc]['hosts'] << host
      target[dc]['architectures'].each do |arch|
        if arch.include?(host)
          target[dc]['architectures'][arch] = arch.partition { |v| v != host }.flatten
        end
      end
      return host
    end
  end
end

#select_target_hosts(target, cluster, datacenter) ⇒ Object



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/vmpooler/providers/vsphere.rb', line 165

def select_target_hosts(target, cluster, datacenter)
  percentage = 100
  dc = "#{datacenter}_#{cluster}"
  @provider_hosts_lock.synchronize do
    begin
      target[dc] = {} unless target.key?(dc)
      target[dc]['checking'] = true
      hosts_hash = find_least_used_hosts(cluster, datacenter, percentage)
      target[dc] = hosts_hash
    rescue => _err
      target[dc] = {}
      raise(_err)
    ensure
      target[dc]['check_time_finished'] = Time.now
    end
  end
end

#valid_template_path?(template) ⇒ Boolean

Returns:

  • (Boolean)


1025
1026
1027
1028
1029
1030
# File 'lib/vmpooler/providers/vsphere.rb', line 1025

def valid_template_path?(template)
  return false unless template.include?('/')
  return false if template[0] == '/'
  return false if template[-1] == '/'
  return true
end

#vm_in_target?(pool_name, parent_host, architecture, target) ⇒ Boolean

Returns:

  • (Boolean)


256
257
258
259
260
261
262
263
264
265
266
# File 'lib/vmpooler/providers/vsphere.rb', line 256

def vm_in_target?(pool_name, parent_host, architecture, target)
  datacenter = get_target_datacenter_from_config(pool_name)
  cluster = get_target_cluster_from_config(pool_name)
  raise("cluster for pool #{pool_name} cannot be identified") if cluster.nil?
  raise("datacenter for pool #{pool_name} cannot be identified") if datacenter.nil?
  dc = "#{datacenter}_#{cluster}"
  raise("there is no candidate in vcenter that meets all the required conditions, that the cluster has available hosts in a 'green' status, not in maintenance mode and not overloaded CPU and memory") unless target[dc].key?('hosts')
  return true if target[dc]['hosts'].include?(parent_host)
  return true if target[dc]['architectures'][architecture].include?(parent_host)
  return false
end

#vm_ready?(_pool_name, vm_name) ⇒ Boolean

Returns:

  • (Boolean)


429
430
431
432
433
434
435
436
437
# File 'lib/vmpooler/providers/vsphere.rb', line 429

def vm_ready?(_pool_name, vm_name)
  begin
    open_socket(vm_name, global_config[:config]['domain'])
  rescue => _err
    return false
  end

  true
end

#vms_in_pool(pool_name) ⇒ Object



150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/vmpooler/providers/vsphere.rb', line 150

def vms_in_pool(pool_name)
  vms = []
  @connection_pool.with_metrics do |pool_object|
    connection = ensured_vsphere_connection(pool_object)
    folder_object = find_vm_folder(pool_name, connection)

    return vms if folder_object.nil?

    folder_object.childEntity.each do |vm|
      vms << { 'name' => vm.name } if vm.is_a? RbVmomi::VIM::VirtualMachine
    end
  end
  vms
end

#vsphere_connection_ok?(connection) ⇒ Boolean

Returns:

  • (Boolean)


493
494
495
496
497
498
# File 'lib/vmpooler/providers/vsphere.rb', line 493

def vsphere_connection_ok?(connection)
  _result = connection.serviceInstance.CurrentTime
  return true
rescue
  return false
end

#wait_for_host_selection(dc, target, maxloop = 0, loop_delay = 1, max_age = 60) ⇒ Object



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/vmpooler/providers/vsphere.rb', line 206

def wait_for_host_selection(dc, target, maxloop = 0, loop_delay = 1, max_age = 60)
  loop_count = 1
  until target.key?(dc) and target[dc].key?('check_time_finished')
    sleep(loop_delay)
    unless maxloop.zero?
      break if loop_count >= maxloop
      loop_count += 1
    end
  end
  return unless target[dc].key?('check_time_finished')
  loop_count = 1
  while Time.now - target[dc]['check_time_finished'] > max_age
    sleep(loop_delay)
    unless maxloop.zero?
      break if loop_count >= maxloop
      loop_count += 1
    end
  end
end