Class: Fog::Vsphere::Compute::Real

Inherits:
Object
  • Object
show all
Includes:
Shared
Defined in:
lib/fog/vsphere/requests/compute/vm_clone.rb,
lib/fog/vsphere/compute.rb,
lib/fog/vsphere/requests/compute/get_host.rb,
lib/fog/vsphere/requests/compute/create_vm.rb,
lib/fog/vsphere/requests/compute/update_vm.rb,
lib/fog/vsphere/requests/compute/vm_reboot.rb,
lib/fog/vsphere/requests/compute/vm_rename.rb,
lib/fog/vsphere/requests/compute/get_folder.rb,
lib/fog/vsphere/requests/compute/list_hosts.rb,
lib/fog/vsphere/requests/compute/list_rules.rb,
lib/fog/vsphere/requests/compute/upload_iso.rb,
lib/fog/vsphere/requests/compute/vm_destroy.rb,
lib/fog/vsphere/requests/compute/vm_execute.rb,
lib/fog/vsphere/requests/compute/vm_migrate.rb,
lib/fog/vsphere/requests/compute/vm_suspend.rb,
lib/fog/vsphere/requests/compute/create_rule.rb,
lib/fog/vsphere/requests/compute/get_cluster.rb,
lib/fog/vsphere/requests/compute/get_network.rb,
lib/fog/vsphere/requests/compute/list_groups.rb,
lib/fog/vsphere/requests/compute/vm_power_on.rb,
lib/fog/vsphere/requests/compute/vm_relocate.rb,
lib/fog/vsphere/requests/compute/create_group.rb,
lib/fog/vsphere/requests/compute/current_time.rb,
lib/fog/vsphere/requests/compute/destroy_rule.rb,
lib/fog/vsphere/requests/compute/get_template.rb,
lib/fog/vsphere/requests/compute/list_folders.rb,
lib/fog/vsphere/requests/compute/vm_power_off.rb,
lib/fog/vsphere/requests/compute/create_folder.rb,
lib/fog/vsphere/requests/compute/destroy_group.rb,
lib/fog/vsphere/requests/compute/get_datastore.rb,
lib/fog/vsphere/requests/compute/host_shutdown.rb,
lib/fog/vsphere/requests/compute/list_clusters.rb,
lib/fog/vsphere/requests/compute/list_networks.rb,
lib/fog/vsphere/requests/compute/vm_config_vnc.rb,
lib/fog/vsphere/requests/compute/folder_destroy.rb,
lib/fog/vsphere/requests/compute/get_datacenter.rb,
lib/fog/vsphere/requests/compute/list_processes.rb,
lib/fog/vsphere/requests/compute/list_templates.rb,
lib/fog/vsphere/requests/compute/list_vm_cdroms.rb,
lib/fog/vsphere/requests/compute/get_server_type.rb,
lib/fog/vsphere/requests/compute/get_storage_pod.rb,
lib/fog/vsphere/requests/compute/list_datastores.rb,
lib/fog/vsphere/requests/compute/list_vm_volumes.rb,
lib/fog/vsphere/requests/compute/modify_vm_cdrom.rb,
lib/fog/vsphere/requests/compute/list_datacenters.rb,
lib/fog/vsphere/requests/compute/modify_vm_volume.rb,
lib/fog/vsphere/requests/compute/vm_reconfig_cpus.rb,
lib/fog/vsphere/requests/compute/vm_take_snapshot.rb,
lib/fog/vsphere/requests/compute/get_resource_pool.rb,
lib/fog/vsphere/requests/compute/list_customfields.rb,
lib/fog/vsphere/requests/compute/list_server_types.rb,
lib/fog/vsphere/requests/compute/list_storage_pods.rb,
lib/fog/vsphere/requests/compute/list_vm_snapshots.rb,
lib/fog/vsphere/requests/compute/vm_acquire_ticket.rb,
lib/fog/vsphere/requests/compute/vm_reconfig_cdrom.rb,
lib/fog/vsphere/requests/compute/get_interface_type.rb,
lib/fog/vsphere/requests/compute/list_vm_interfaces.rb,
lib/fog/vsphere/requests/compute/revert_to_snapshot.rb,
lib/fog/vsphere/requests/compute/set_vm_customvalue.rb,
lib/fog/vsphere/requests/compute/vm_reconfig_memory.rb,
lib/fog/vsphere/requests/compute/vm_remove_snapshot.rb,
lib/fog/vsphere/requests/compute/vm_revert_snapshot.rb,
lib/fog/vsphere/requests/compute/get_virtual_machine.rb,
lib/fog/vsphere/requests/compute/list_resource_pools.rb,
lib/fog/vsphere/requests/compute/modify_vm_interface.rb,
lib/fog/vsphere/requests/compute/vm_reconfig_volumes.rb,
lib/fog/vsphere/requests/compute/create_resource_pool.rb,
lib/fog/vsphere/requests/compute/get_compute_resource.rb,
lib/fog/vsphere/requests/compute/list_child_snapshots.rb,
lib/fog/vsphere/requests/compute/list_interface_types.rb,
lib/fog/vsphere/requests/compute/list_vm_customvalues.rb,
lib/fog/vsphere/requests/compute/modify_vm_controller.rb,
lib/fog/vsphere/requests/compute/update_resource_pool.rb,
lib/fog/vsphere/requests/compute/vm_reconfig_hardware.rb,
lib/fog/vsphere/requests/compute/destroy_resource_pool.rb,
lib/fog/vsphere/requests/compute/list_virtual_machines.rb,
lib/fog/vsphere/requests/compute/host_start_maintenance.rb,
lib/fog/vsphere/requests/compute/list_compute_resources.rb,
lib/fog/vsphere/requests/compute/cloudinit_to_customspec.rb,
lib/fog/vsphere/requests/compute/host_finish_maintenance.rb,
lib/fog/vsphere/requests/compute/list_vm_scsi_controllers.rb,
lib/fog/vsphere/requests/compute/get_vm_first_scsi_controller.rb

Overview

rubocop:disable Metrics/ClassLength

Instance Attribute Summary

Attributes included from Shared

#vsphere_is_vcenter, #vsphere_rev, #vsphere_server, #vsphere_username

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Real

Returns a new instance of Real.



643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
# File 'lib/fog/vsphere/compute.rb', line 643

def initialize(options = {})
  require 'rbvmomi'
  @vsphere_username = options[:vsphere_username]
  @vsphere_password = options[:vsphere_password]
  @vsphere_server   = options[:vsphere_server]
  @vsphere_port     = options[:vsphere_port] || 443
  @vsphere_path     = options[:vsphere_path] || '/sdk'
  @vsphere_ns       = options[:vsphere_ns] || 'urn:vim25'
  @vsphere_rev      = options[:vsphere_rev] || '4.0'
  @vsphere_ssl      = options[:vsphere_ssl] || true
  @vsphere_debug    = options[:vsphere_debug] || false
  @vsphere_expected_pubkey_hash = options[:vsphere_expected_pubkey_hash]
  @vsphere_must_reauthenticate = false
  @vsphere_is_vcenter = nil
  @connection = nil
  connect
  negotiate_revision(options[:vsphere_rev])
  authenticate
end

Instance Method Details

#add_new_volumes_specs(vm_mob_ref, volumes, default_storage_pod: nil) ⇒ Object



861
862
863
# File 'lib/fog/vsphere/requests/compute/vm_clone.rb', line 861

def add_new_volumes_specs(vm_mob_ref, volumes, default_storage_pod: nil)
  new_volumes(vm_mob_ref, volumes).map { |volume| create_disk(volume, :add, storage_pod: default_storage_pod) }
end

#add_vm_cdrom(cdrom) ⇒ Object



5
6
7
# File 'lib/fog/vsphere/requests/compute/modify_vm_cdrom.rb', line 5

def add_vm_cdrom(cdrom)
  vm_reconfig_hardware('instance_uuid' => cdrom.server.instance_uuid, 'hardware_spec' => { 'deviceChange' => [create_cdrom(cdrom, cdrom.unit_number, :add)] })
end

#add_vm_controller(controller) ⇒ Object



5
6
7
# File 'lib/fog/vsphere/requests/compute/modify_vm_controller.rb', line 5

def add_vm_controller(controller)
  vm_reconfig_hardware('instance_uuid' => controller.server_id, 'hardware_spec' => { 'deviceChange' => [create_controller(controller)] })
end

#add_vm_interface(vmid, options = {}) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
# File 'lib/fog/vsphere/requests/compute/modify_vm_interface.rb', line 5

def add_vm_interface(vmid, options = {})
  raise ArgumentError, 'instance id is a required parameter' unless vmid

  interface = get_interface_from_options(vmid, options.merge(server_id: vmid))
  vm_reconfig_hardware('instance_uuid' => vmid, 'hardware_spec' => { 'deviceChange' => [create_interface(interface, 0, :add, options)] })
end

#add_vm_volume(volume) ⇒ Object



5
6
7
# File 'lib/fog/vsphere/requests/compute/modify_vm_volume.rb', line 5

def add_vm_volume(volume)
  vm_reconfig_hardware('instance_uuid' => volume.server_id, 'hardware_spec' => { 'deviceChange' => [create_disk(volume, :add)] })
end

#cloudinit_to_customspec(user_data) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
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
41
42
# File 'lib/fog/vsphere/requests/compute/cloudinit_to_customspec.rb', line 5

def cloudinit_to_customspec(user_data)
  raise ArgumentError, "user_data can't be nil" if user_data.nil?
  custom_spec = { 'customization_spec' => {} }
  user_data = YAML.safe_load(user_data)
  # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.Specification.html
  # encryptionKey expects an array
  # globalIPSettings expects a hash, REQUIRED
  # identity expects an hash, REQUIRED
  # nicSettingMap expects an array
  # options expects an hash
  # extraConfig expects a hash

  custom_spec['encryptionKey']    = user_data['encryptionKey'] if user_data.key?('encryptionKey')
  custom_spec['globalIPSettings'] = user_data['globalIPSettings'] if user_data.key?('globalIPSettings')
  custom_spec['identity']         = user_data['identity'] if user_data.key?('identity')
  custom_spec['identity']         = { 'Sysprep' => { 'guiRunOnce' => { 'commandList' => user_data['runcmd'] } } } if user_data.key?('runcmd') && !user_data.key?('identity')
  custom_spec['nicSettingMap']    = user_data['nicSettingMap'] if user_data.key?('nicSettingMap')
  custom_spec['options']          = user_data['options'] if user_data.key?('options')
  custom_spec['extraConfig']      = user_data['extraConfig'] if user_data.key?('extraConfig')

  # for backwards compatability
  # hostname expects a string, REQUIRED
  # netmask expects a string
  # dns expects an array
  # gateway expects an array
  # domain expects a string, REQUIRED
  # domainsuffixlist expects an array, REQUIRED
  # timezone expects a string, for example Europe/Copenhagen, REQUIRED
  custom_spec['hostname']                    =  user_data['hostname'] if user_data.key?('hostname')
  custom_spec['ipsettings']                  =  { 'ip' => user_data['ip'] } if user_data.key?('ip')
  custom_spec['ipsettings']['subnetMask']    =  user_data['netmask'] if user_data.key?('netmask')
  custom_spec['ipsettings']['dnsServerList'] =  user_data['dns'] if user_data.key?('dns')
  custom_spec['ipsettings']['gateway']       =  user_data['gateway'] if user_data.key?('gateway')
  custom_spec['domain']                      =  user_data['domain'] if user_data.key?('domain')
  custom_spec['dnsSuffixList']               =  user_data['domainsuffixlist'] if user_data.key?('domainsuffixlist')
  custom_spec['time_zone']                   =  user_data['timezone'] if user_data.key?('timezone')
  custom_spec
end

#connectionObject



663
664
665
666
667
668
669
670
# File 'lib/fog/vsphere/compute.rb', line 663

def connection
  if @connection.nil? || @connection.serviceContent.sessionManager.currentSession.nil?
    Fog::Logger.debug('Reconnecting to vSphere.')
    @connection = nil
    reload
  end
  @connection
end

#create_folder(datacenter, path, name) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
13
14
15
16
# File 'lib/fog/vsphere/requests/compute/create_folder.rb', line 5

def create_folder(datacenter, path, name)
  # Path cannot be nil but it can be an empty string
  raise ArgumentError, 'Path cannot be nil' if path.nil?

  parent_folder = get_raw_vmfolder(path, datacenter)
  begin
    new_folder = parent_folder.CreateFolder(name: name)
    # output is cleaned up to return the new path
    # new path will be path/name, example: "Production/Pool1"
    new_folder.path.reject { |a| a.first.class == 'Folder' }.map { |a| a.first.name }.join('/').sub(/^\/?Datacenters\/#{datacenter}\/vm\/?/, '')
  end
end

#create_group(attributes = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/fog/vsphere/requests/compute/create_group.rb', line 5

def create_group(attributes = {})
  cluster = get_raw_cluster(attributes[:cluster], attributes[:datacenter])
  group = cluster.configurationEx.group.find { |n| n[:name] == attributes[:name] }
  if group
    raise ArgumentError, "Group #{attributes[:name]} already exists!"
  end
  spec = get_group_spec attributes
  cluster_spec = RbVmomi::VIM.ClusterConfigSpecEx(groupSpec: [
                                                    RbVmomi::VIM.ClusterGroupSpec(
                                                      operation: RbVmomi::VIM.ArrayUpdateOperation('add'),
                                                      info: spec
                                                    )
                                                  ])
  cluster.ReconfigureComputeResource_Task(spec: cluster_spec, modify: true).wait_for_completion
  group = cluster.configurationEx.group.find { |n| n[:name] == attributes[:name] }
  if group
    return group[:name]
  else
    raise Fog::Vsphere::Errors::ServiceError, "Unknown error creating group #{attributes[:name]}"
  end
end

#create_resource_pool(attributes = {}) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/fog/vsphere/requests/compute/create_resource_pool.rb', line 5

def create_resource_pool(attributes = {})
  cluster = get_raw_cluster(attributes[:cluster], attributes[:datacenter])

  root_resource_pool = if attributes[:root_resource_pool_name]
                         cluster.resourcePool.find attributes[:root_resource_pool_name].gsub('/', '%2f')
                       else
                         cluster.resourcePool
                       end

  raise ArgumentError, 'Root resource pool could not be found' if root_resource_pool.nil?

  resource_pool = root_resource_pool.CreateResourcePool(
    name: attributes[:name],
    spec: get_resource_pool_spec(attributes)
  )

  resource_pool_attributes(resource_pool, attributes[:cluster], attributes[:datacenter])
end

#create_rule(attributes = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/fog/vsphere/requests/compute/create_rule.rb', line 5

def create_rule(attributes = {})
  cluster = get_raw_cluster(attributes[:cluster], attributes[:datacenter])
  rule = cluster.configurationEx.rule.find { |n| n[:name] == attributes[:name] }
  if rule
    raise ArgumentError, "Rule #{attributes[:name]} already exists!"
  end
  spec = get_rule_spec attributes
  # Now, attach it to the cluster
  cluster_spec = RbVmomi::VIM.ClusterConfigSpecEx(rulesSpec: [
                                                    RbVmomi::VIM.ClusterRuleSpec(
                                                      operation: RbVmomi::VIM.ArrayUpdateOperation('add'),
                                                      info: spec
                                                    )
                                                  ])
  ret = cluster.ReconfigureComputeResource_Task(spec: cluster_spec, modify: true).wait_for_completion
  rule = cluster.configurationEx.rule.find { |n| n[:name] == attributes[:name] }
  if rule
    return rule[:key]
  else
    raise Fog::Vsphere::Errors::ServiceError, "Unknown error creating rule #{attributes[:name]}"
  end
end

#create_vm(attributes = {}) ⇒ Object

Raises:

  • (Fog::Vsphere::Compute::NotFound)


5
6
7
8
9
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
41
42
43
# File 'lib/fog/vsphere/requests/compute/create_vm.rb', line 5

def create_vm(attributes = {})
  # build up vm configuration
  cluster = get_raw_cluster(attributes[:cluster], attributes[:datacenter])
  raise Fog::Vsphere::Compute::NotFound, "Cluster #{attributes[:cluster]} Doesn't Exist in the DC!" unless cluster

  vm_cfg = {
    name: attributes[:name],
    annotation: attributes[:annotation],
    guestId: attributes[:guest_id],
    version: attributes[:hardware_version],
    files: { vmPathName: vm_path_name(attributes) },
    numCPUs: attributes[:cpus],
    numCoresPerSocket: attributes[:corespersocket],
    memoryMB: attributes[:memory_mb],
    deviceChange: device_change(attributes),
    extraConfig: extra_config(attributes)
  }
  vm_cfg[:cpuHotAddEnabled] = attributes[:cpuHotAddEnabled] if attributes.key?(:cpuHotAddEnabled)
  vm_cfg[:memoryHotAddEnabled] = attributes[:memoryHotAddEnabled] if attributes.key?(:memoryHotAddEnabled)
  vm_cfg[:firmware] = attributes[:firmware] if attributes.key?(:firmware)
  vm_cfg[:bootOptions] = boot_options(attributes, vm_cfg) if attributes.key?(:boot_order) || attributes.key?(:boot_retry)
  resource_pool = if attributes[:resource_pool] && attributes[:resource_pool] != 'Resources'
                    get_raw_resource_pool(attributes[:resource_pool], attributes[:cluster], attributes[:datacenter])
                  else
                    cluster.resourcePool
                  end
  vmFolder      = get_raw_vmfolder(attributes[:path], attributes[:datacenter])
  host = if attributes.key?(:host)
           get_raw_host(attributes[:host], attributes[:cluster], attributes[:datacenter])
         end
  # if any volume has a storage_pod set, we deploy the vm on a storage pod instead of the defined datastores
  pod = get_storage_pod_from_volumes(attributes)
  vm = if pod
         create_vm_on_storage_pod(pod, attributes[:volumes], vm_cfg, vmFolder, resource_pool, attributes[:datacenter], host)
       else
         create_vm_on_datastore(vm_cfg, vmFolder, resource_pool, host)
       end
  vm.config.instanceUuid
end

#current_timeObject



5
6
7
8
# File 'lib/fog/vsphere/requests/compute/current_time.rb', line 5

def current_time
  current_time = connection.serviceInstance.CurrentTime
  { 'current_time' => current_time }
end

#destroy_group(attributes = {}) ⇒ Object

Raises:

  • (Fog::Vsphere::Error::NotFound)


5
6
7
8
9
10
11
12
13
14
15
16
# File 'lib/fog/vsphere/requests/compute/destroy_group.rb', line 5

def destroy_group(attributes = {})
  cluster = get_raw_cluster(attributes[:cluster], attributes[:datacenter])
  group   = cluster.configurationEx.group.find { |g| g.name == attributes[:name] }
  raise Fog::Vsphere::Error::NotFound, "group #{attributes[:name]} not found" unless group
  delete_spec = RbVmomi::VIM.ClusterConfigSpecEx(groupSpec: [
                                                   RbVmomi::VIM.ClusterGroupSpec(
                                                     operation: RbVmomi::VIM.ArrayUpdateOperation('remove'),
                                                     removeKey: group.name
                                                   )
                                                 ])
  cluster.ReconfigureComputeResource_Task(spec: delete_spec, modify: true).wait_for_completion
end

#destroy_resource_pool(attributes = {}) ⇒ Object



5
6
7
# File 'lib/fog/vsphere/requests/compute/destroy_resource_pool.rb', line 5

def destroy_resource_pool(attributes = {})
  get_raw_resource_pool_by_ref(attributes).Destroy_Task().wait_for_completion
end

#destroy_rule(attributes = {}) ⇒ Object

Raises:

  • (Fog::Vsphere::Error::NotFound)


5
6
7
8
9
10
11
12
13
14
15
16
# File 'lib/fog/vsphere/requests/compute/destroy_rule.rb', line 5

def destroy_rule(attributes = {})
  cluster = get_raw_cluster(attributes[:cluster], attributes[:datacenter])
  rule    = cluster.configurationEx.rule.find { |rule| rule.key == attributes[:key] }
  raise Fog::Vsphere::Error::NotFound, "rule #{attributes[:key]} not found" unless rule
  delete_spec = RbVmomi::VIM.ClusterConfigSpecEx(rulesSpec: [
                                                   RbVmomi::VIM.ClusterRuleSpec(
                                                     operation: RbVmomi::VIM.ArrayUpdateOperation('remove'),
                                                     removeKey: rule.key
                                                   )
                                                 ])
  cluster.ReconfigureComputeResource_Task(spec: delete_spec, modify: true).wait_for_completion
end

#destroy_vm_cdrom(cdrom) ⇒ Object



9
10
11
# File 'lib/fog/vsphere/requests/compute/modify_vm_cdrom.rb', line 9

def destroy_vm_cdrom(cdrom)
  vm_reconfig_hardware('instance_uuid' => cdrom.server.instance_uuid, 'hardware_spec' => { 'deviceChange' => [create_cdrom(cdrom, cdrom.unit_number, :remove)] })
end

#destroy_vm_interface(vmid, options = {}) ⇒ Object

Raises:

  • (ArgumentError)


12
13
14
15
16
17
# File 'lib/fog/vsphere/requests/compute/modify_vm_interface.rb', line 12

def destroy_vm_interface(vmid, options = {})
  raise ArgumentError, 'instance id is a required parameter' unless vmid

  interface = get_interface_from_options(vmid, options.merge(server_id: vmid))
  vm_reconfig_hardware('instance_uuid' => vmid, 'hardware_spec' => { 'deviceChange' => [create_interface(interface, interface.key, :remove, options)] })
end

#destroy_vm_volume(volume) ⇒ Object



13
14
15
16
17
# File 'lib/fog/vsphere/requests/compute/modify_vm_volume.rb', line 13

def destroy_vm_volume(volume)
  vm_reconfig_hardware('instance_uuid' => volume.server_id, 'hardware_spec' => {
                         'deviceChange' => [create_disk(volume, :remove, file_operation: :destroy)]
                       })
end

#folder_destroy(path, datacenter_name) ⇒ Object



5
6
7
8
9
10
11
12
13
# File 'lib/fog/vsphere/requests/compute/folder_destroy.rb', line 5

def folder_destroy(path, datacenter_name)
  folder = get_raw_vmfolder(path, datacenter_name)
  raise Fog::Vsphere::Errors::NotFound, "No such folder #{path}" unless folder
  raise Fog::Vsphere::Errors::ServiceError, "Folder #{path} is not empty" unless folder.childEntity.empty?

  task = folder.Destroy_Task
  task.wait_for_completion
  { 'task_state' => task.info.state }
end

#get_cluster(name, datacenter_name) ⇒ Object

Raises:

  • (Fog::Vsphere::Compute::NotFound)


5
6
7
8
9
# File 'lib/fog/vsphere/requests/compute/get_cluster.rb', line 5

def get_cluster(name, datacenter_name)
  cluster = get_raw_cluster(name, datacenter_name)
  raise(Fog::Vsphere::Compute::NotFound) unless cluster
  cluster_attributes(cluster, datacenter_name)
end

#get_compute_resource(name, datacenter_name) ⇒ Object

Raises:

  • (Fog::Vsphere::Compute::NotFound)


5
6
7
8
9
# File 'lib/fog/vsphere/requests/compute/get_compute_resource.rb', line 5

def get_compute_resource(name, datacenter_name)
  compute_resource = get_raw_compute_resource(name, datacenter_name)
  raise(Fog::Vsphere::Compute::NotFound) unless compute_resource
  compute_resource_attributes(compute_resource, datacenter_name)
end

#get_datacenter(name) ⇒ Object

Raises:

  • (Fog::Vsphere::Compute::NotFound)


5
6
7
8
9
# File 'lib/fog/vsphere/requests/compute/get_datacenter.rb', line 5

def get_datacenter(name)
  dc = find_raw_datacenter(name)
  raise(Fog::Vsphere::Compute::NotFound) unless dc
  { name: dc.name, status: dc.overallStatus, path: raw_getpathmo(dc) }
end

#get_datastore(name, datacenter_name) ⇒ Object

Raises:

  • (Fog::Vsphere::Compute::NotFound)


5
6
7
8
9
# File 'lib/fog/vsphere/requests/compute/get_datastore.rb', line 5

def get_datastore(name, datacenter_name)
  datastore = list_datastores(datacenter: datacenter_name).detect { |ds| ds[:name] == name }
  raise(Fog::Vsphere::Compute::NotFound) unless datastore
  datastore
end

#get_folder(path, datacenter_name, type = nil) ⇒ Object

Raises:

  • (Fog::Vsphere::Compute::NotFound)


5
6
7
8
9
10
11
# File 'lib/fog/vsphere/requests/compute/get_folder.rb', line 5

def get_folder(path, datacenter_name, type = nil)
  type ||= 'vm'
  # Cycle through all types of folders.
  folder = get_raw_folder(path, datacenter_name, type)
  raise(Fog::Vsphere::Compute::NotFound) unless folder
  folder_attributes(folder, datacenter_name)
end

#get_host(name, cluster_name, datacenter_name) ⇒ Object



5
6
7
# File 'lib/fog/vsphere/requests/compute/get_host.rb', line 5

def get_host(name, cluster_name, datacenter_name)
  get_raw_host(name, cluster_name, datacenter_name)
end

#get_interface_type(id, servertype, datacenter, _filter = {}) ⇒ Object

Raises:

  • (Fog::Vsphere::Compute::NotFound)


5
6
7
8
9
10
11
# File 'lib/fog/vsphere/requests/compute/get_interface_type.rb', line 5

def get_interface_type(id, servertype, datacenter, _filter = {})
  interfacetype = list_interface_types(filters = { id: id,
                                                   datacenter: datacenter,
                                                   servertype: servertype.id }).first
  raise(Fog::Vsphere::Compute::NotFound) unless interfacetype
  interfacetype
end

#get_network(ref_or_name, datacenter_name) ⇒ Object

Raises:

  • (Fog::Vsphere::Compute::NotFound)


5
6
7
8
9
# File 'lib/fog/vsphere/requests/compute/get_network.rb', line 5

def get_network(ref_or_name, datacenter_name)
  network = get_raw_network(ref_or_name, datacenter_name)
  raise(Fog::Vsphere::Compute::NotFound) unless network
  network_attributes(network, datacenter_name)
end

#get_raw_interface(vm_id, options = {}) ⇒ Object

Raises:

  • (ArgumentError)


44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/fog/vsphere/requests/compute/list_vm_interfaces.rb', line 44

def get_raw_interface(vm_id, options = {})
  raise ArgumentError, 'instance id is a required parameter' unless vm_id

  if options.is_a? Fog::Vsphere::Compute::Interface
    options

  else
    raise ArgumentError, "Either key or name is a required parameter. options: #{options}" unless options.key?(:key) || options.key?(:mac) || options.key?(:name)
    raise ArgumentError, "'datacenter' is a required parameter in options: #{options}" unless options.key?(:datacenter)

    get_raw_interfaces(vm_id, options[:datacenter]).find do |nic|
      (options.key?(:key) && (nic.key == options[:key].to_i)) ||
        (options.key?(:mac) && (nic.macAddress == options[:mac])) ||
        (options.key?(:name) && (nic.deviceInfo.label == options[:name]))
    end
  end
end

#get_raw_interfaces(vm_id, datacenter = nil) ⇒ Object



40
41
42
# File 'lib/fog/vsphere/requests/compute/list_vm_interfaces.rb', line 40

def get_raw_interfaces(vm_id, datacenter = nil)
  get_vm_ref(vm_id, datacenter).config.hardware.device.grep(RbVmomi::VIM::VirtualEthernetCard)
end

#get_resource_pool(name, cluster_name, datacenter_name) ⇒ Object

Raises:

  • (Fog::Vsphere::Compute::NotFound)


5
6
7
8
9
# File 'lib/fog/vsphere/requests/compute/get_resource_pool.rb', line 5

def get_resource_pool(name, cluster_name, datacenter_name)
  resource_pool = get_raw_resource_pool(name, cluster_name, datacenter_name)
  raise(Fog::Vsphere::Compute::NotFound) unless resource_pool
  resource_pool_attributes(resource_pool, cluster_name, datacenter_name)
end

#get_server_type(id, datacenter, _filter = {}) ⇒ Object

Raises:

  • (Fog::Vsphere::Compute::NotFound)


5
6
7
8
9
# File 'lib/fog/vsphere/requests/compute/get_server_type.rb', line 5

def get_server_type(id, datacenter, _filter = {})
  server_type = get_raw_server_type(id, datacenter)
  raise(Fog::Vsphere::Compute::NotFound) unless server_type
  server_type_attributes(server_type, datacenter)
end

#get_storage_pod(name, datacenter_name) ⇒ Object

Raises:

  • (Fog::Vsphere::Compute::NotFound)


5
6
7
8
9
# File 'lib/fog/vsphere/requests/compute/get_storage_pod.rb', line 5

def get_storage_pod(name, datacenter_name)
  storage_pod = list_storage_pods(datacenter: datacenter_name).detect { |pod| pod[:name] == name }
  raise(Fog::Vsphere::Compute::NotFound) unless storage_pod
  storage_pod
end

#get_template(id, datacenter_name = nil) ⇒ Object



5
6
7
# File 'lib/fog/vsphere/requests/compute/get_template.rb', line 5

def get_template(id, datacenter_name = nil)
  convert_vm_mob_ref_to_attr_hash(get_vm_ref(id, datacenter_name))
end

#get_virtual_machine(id, datacenter_name = nil, folder = nil, recursive = false) ⇒ Object



5
6
7
8
# File 'lib/fog/vsphere/requests/compute/get_virtual_machine.rb', line 5

def get_virtual_machine(id, datacenter_name = nil, folder = nil, recursive = false)
  # The larger the VM list the longer it will take if not searching based on UUID.
  convert_vm_mob_ref_to_attr_hash(get_vm_ref(id, datacenter_name, folder, recursive))
end

#get_vm_cluster(vm_mob_ref) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
# File 'lib/fog/vsphere/requests/compute/vm_relocate.rb', line 81

def get_vm_cluster(vm_mob_ref)
  parent = vm_mob_ref.runtime.host.parent
  until parent.is_a?(RbVmomi::VIM::ClusterComputeResource)
    if vm_mob_ref.respond_to?(:parent)
      parent = parent.parent
    else
      return
    end
  end
  parent.name
end

#get_vm_datacenter(vm_mob_ref) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
# File 'lib/fog/vsphere/requests/compute/vm_relocate.rb', line 69

def get_vm_datacenter(vm_mob_ref)
  parent = vm_mob_ref.parent
  until parent.is_a?(RbVmomi::VIM::Datacenter)
    if vm_mob_ref.respond_to?(:parent)
      parent = parent.parent
    else
      return
    end
  end
  parent.name
end

#get_vm_first_scsi_controller(vm_id) ⇒ Object



6
7
8
# File 'lib/fog/vsphere/requests/compute/get_vm_first_scsi_controller.rb', line 6

def get_vm_first_scsi_controller(vm_id)
  Fog::Vsphere::Compute::SCSIController.new(get_vm_first_scsi_controller_raw(vm_id))
end

#get_vm_first_scsi_controller_raw(vm_id) ⇒ Object



10
11
12
13
14
15
16
17
18
# File 'lib/fog/vsphere/requests/compute/get_vm_first_scsi_controller.rb', line 10

def get_vm_first_scsi_controller_raw(vm_id)
  ctrl = get_vm_ref(vm_id).config.hardware.device.grep(RbVmomi::VIM::VirtualSCSIController).select { |ctrl| ctrl.key == 1000 }.first
  {
    type: ctrl.class.to_s,
    shared_bus: ctrl.sharedBus.to_s,
    unit_number: ctrl.scsiCtlrUnitNumber,
    key: ctrl.key
  }
end

#get_vm_interface(vm_id, options = {}) ⇒ Object



35
36
37
38
# File 'lib/fog/vsphere/requests/compute/list_vm_interfaces.rb', line 35

def get_vm_interface(vm_id, options = {})
  raw = get_raw_interface(vm_id, options)
  raw_to_hash(raw, options[:datacenter]) if raw
end

#host_finish_maintenance(name, cluster_name, datacenter_name, timeout = 0) ⇒ Object



5
6
7
8
9
10
# File 'lib/fog/vsphere/requests/compute/host_finish_maintenance.rb', line 5

def host_finish_maintenance(name, cluster_name, datacenter_name, timeout = 0)
  host_ref = get_host(name, cluster_name, datacenter_name)
  task = host_ref.ExitMaintenanceMode_Task(timeout: timeout)
  task.wait_for_completion
  { 'task_state' => task.info.state }
end

#host_shutdown(name, cluster_name, datacenter_name, force = false) ⇒ Object



5
6
7
8
9
10
# File 'lib/fog/vsphere/requests/compute/host_shutdown.rb', line 5

def host_shutdown(name, cluster_name, datacenter_name, force = false)
  host_ref = get_host(name, cluster_name, datacenter_name)
  task = host_ref.ShutdownHost_Task(force: force)
  task.wait_for_completion
  { 'task_state' => task.info.state }
end

#host_start_maintenance(name, cluster_name, datacenter_name, timeout = 0, evacuate_powered_off_vms = false) ⇒ Object



5
6
7
8
9
10
# File 'lib/fog/vsphere/requests/compute/host_start_maintenance.rb', line 5

def host_start_maintenance(name, cluster_name, datacenter_name, timeout = 0, evacuate_powered_off_vms = false)
  host_ref = get_host(name, cluster_name, datacenter_name)
  task = host_ref.EnterMaintenanceMode_Task(timeout: timeout, evacuatePoweredOffVms: evacuate_powered_off_vms)
  task.wait_for_completion
  { 'task_state' => task.info.state }
end

#interface_type_attributes(nic, servertype, datacenter) ⇒ Object



14
15
16
17
18
19
20
21
# File 'lib/fog/vsphere/requests/compute/list_interface_types.rb', line 14

def interface_type_attributes(nic, servertype, datacenter)
  {
    id: nic,
    name: nic,
    datacenter: datacenter,
    servertype: servertype
  }
end

#list_child_snapshots(snapshot, opts = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/fog/vsphere/requests/compute/list_child_snapshots.rb', line 5

def list_child_snapshots(snapshot, opts = {})
  normalized_snapshot = Hash === snapshot ?
    Snapshot.new(snapshot.update(service: self)) : snapshot

  child_snapshots = normalized_snapshot.tree_node.childSnapshotList.map do |snap|
    item = child_snapshot_info(snap, normalized_snapshot)
    [
      item,
      opts[:recursive] ? list_child_snapshots(item, opts) : nil
    ]
  end

  child_snapshots.flatten.compact
end

#list_clusters(filters = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
# File 'lib/fog/vsphere/requests/compute/list_clusters.rb', line 5

def list_clusters(filters = {})
  datacenter_name = filters[:datacenter] if filters.key? :datacenter
  if datacenter_name.nil?
    list_datacenters.map { |dc| list_clusters(datacenter: dc[:name]) }.flatten
  else
    raw_clusters(datacenter_name).map do |cluster|
      cluster_attributes(cluster, datacenter_name)
    end.compact
  end
end

#list_compute_resources(filters = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
# File 'lib/fog/vsphere/requests/compute/list_compute_resources.rb', line 5

def list_compute_resources(filters = {})
  datacenter_name = filters[:datacenter]
  # default to show all compute_resources
  only_active = filters[:effective] || false
  compute_resources = raw_compute_resources datacenter_name

  compute_resources.map do |compute_resource|
    next if compute_resource.instance_of? RbVmomi::VIM::Folder
    summary = compute_resource.summary
    next if only_active && (summary.numEffectiveHosts == 0)
    compute_resource_attributes(compute_resource, datacenter_name)
  end.compact
end

#list_customfieldsObject



5
6
7
8
9
10
11
12
13
# File 'lib/fog/vsphere/requests/compute/list_customfields.rb', line 5

def list_customfields
  connection.serviceContent.customFieldsManager.field.map do |customfield|
    {
      key: customfield.key.to_i,
      name: customfield.name,
      type: customfield.type
    }
  end
end

#list_datacenters(_filters = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
# File 'lib/fog/vsphere/requests/compute/list_datacenters.rb', line 5

def list_datacenters(_filters = {})
  raw_datacenters.map do |dc|
    {
      id: managed_obj_id(dc),
      name: dc.name,
      path: raw_getpathmo(dc),
      status: dc.overallStatus
    }
  end
end

#list_datastores(filters = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/fog/vsphere/requests/compute/list_datastores.rb', line 5

def list_datastores(filters = {})
  datacenter_name = filters[:datacenter]
  cluster_name = filters.fetch(:cluster, nil)
  # default to show all datastores
  only_active = filters[:accessible] || false

  dc = find_raw_datacenter(datacenter_name)

  datastores = if cluster_name
                 cluster = get_raw_cluster(cluster_name, dc)
                 property_collector_results(datastore_cluster_filter_spec(cluster))
               else
                 property_collector_results(datastore_filter_spec(dc))
               end

  datastores.map do |datastore|
    next if only_active && !datastore['summary.accessible']
    map_attrs_to_hash(datastore, datastore_attribute_mapping).merge(
      datacenter: datacenter_name,
      id: managed_obj_id(datastore.obj)
    )
  end.compact
end

#list_folders(filters = {}) ⇒ Object

Grabs all sub folders within a given path folder.

Parameters

  • filters<~Hash>:

    • :datacenter<~String> - REQUIRED Your datacenter where you’re looking for folders. Example: ‘my-datacenter-name’ (passed if you are using the models/collections)

      eg: vspconn.datacenters.first.vm_folders('mypath')
      
    • :path<~String> - Your path where you’re looking for more folders, if return = none you will get an error. If you don’t define it will look in the main datacenter folder for any folders in that datacenter.

Example Usage Testing Only:

vspconn = Fog::Compute[:vsphere]
mydc = vspconn.datacenters.first
folders = mydc.vm_folders


23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/fog/vsphere/requests/compute/list_folders.rb', line 23

def list_folders(filters = {})
  path            = filters[:path] || filters['path'] || ''
  datacenter_name = filters[:datacenter]

  # if we don't need to display folders for a specific path
  # we can easily use a property collector to get the
  # data in an efficient manner from vsphere
  # otherwise we use a much slower implementation
  unless path.nil? || path.empty?
    return get_raw_vmfolders(path, datacenter_name).map do |folder|
      folder_attributes(folder, datacenter_name)
    end
  end

  root_folder = connection.serviceContent.rootFolder

  results = property_collector_results(folder_filter_spec(root_folder))

  folder_inventory = generate_folder_inventory(results)

  folders = results.select { |result| result.obj.is_a?(RbVmomi::VIM::Folder) && result['childType'].include?('VirtualMachine') }

  folders.map do |folder|
    folder_id = managed_obj_id(folder.obj)
    parent_id = folder['parent']._ref if folder['parent']
    path = lookup_folder_path(folder_inventory, folder_id)
    next unless path.include?(datacenter_name) # skip folders from another datacenter
    map_attrs_to_hash(folder, folder_attribute_mapping).merge(
      datacenter: datacenter_name,
      parent: lookup_folder_name(folder_inventory, parent_id),
      path: path.join('/'),
      type: folder_type(folder['childType']),
      id: folder_id
    )
  end.compact
end

#list_groups(filters = {}) ⇒ Object



5
6
7
8
# File 'lib/fog/vsphere/requests/compute/list_groups.rb', line 5

def list_groups(filters = {})
  cluster = get_raw_cluster(filters[:cluster], filters[:datacenter])
  cluster.configurationEx.group.map { |g| group_attributes g, filters }
end

#list_hosts(filters = {}) ⇒ Object



6
7
8
9
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
# File 'lib/fog/vsphere/requests/compute/list_hosts.rb', line 6

def list_hosts(filters = {})
  cluster = get_raw_cluster(filters[:cluster], filters[:datacenter])

  results = property_collector_results(host_system_filter_spec(cluster))

  results.map do |host|
    hsh = map_attrs_to_hash(host, host_system_attribute_mapping)
    hsh.merge(
      datacenter: filters[:datacenter],
      cluster: filters[:cluster],
      ipaddress: (begin
                    host['config.network.vnic'].first.spec.ip.ipAddress
                  rescue
                    nil
                  end),
      ipaddress6: (begin
                     host['config.network.vnic'].first.spec.ip.ipV6Config.ipV6Address.first.ipAddress
                   rescue
                     nil
                   end),
      vm_ids: proc {
        host['vm'].map do |vm|
          begin
                                   vm.config.instanceUuid
                                 rescue
                                   nil
                                 end
        end
      }
    )
  end
end

#list_interface_types(filters = {}) ⇒ Object



5
6
7
8
9
10
11
12
# File 'lib/fog/vsphere/requests/compute/list_interface_types.rb', line 5

def list_interface_types(filters = {})
  datacenter_name = filters[:datacenter]
  servertype_name = filters[:servertype]
  get_raw_server_type(servertype_name, datacenter_name)[:supportedEthernetCard].map do |nictype|
    next if filters.key?(:id) && (filters[:id] != nictype)
    interface_type_attributes(nictype, servertype_name, datacenter_name)
  end.compact
end

#list_networks(filters = {}) ⇒ Object



5
6
7
8
9
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
41
42
43
44
45
46
# File 'lib/fog/vsphere/requests/compute/list_networks.rb', line 5

def list_networks(filters = {})
  datacenter_name = filters[:datacenter]
  cluster_name = filters.fetch(:cluster, nil)
  # default to show all networks
  only_active = filters[:accessible] || false

  dc = find_raw_datacenter(datacenter_name)

  results = property_collector_results(network_filter_spec(dc))

  dvswitches = results.select { |result| result.obj.is_a?(RbVmomi::VIM::DistributedVirtualSwitch) }.each_with_object({}) do |dvswitch, obj|
    obj[dvswitch.obj._ref] = dvswitch['summary.name']
  end

  if cluster_name
    cluster = get_raw_cluster(cluster_name, datacenter_name)
    cluster_networks = cluster.network.map(&:_ref)
  end

  results.select { |result| result.obj.is_a?(RbVmomi::VIM::DistributedVirtualPortgroup) || result.obj.is_a?(RbVmomi::VIM::Network) }.map do |network|
    next if cluster_name && !cluster_networks.include?(network.obj._ref)
    next if only_active && !network['summary.accessible']
    if network.obj.is_a?(RbVmomi::VIM::DistributedVirtualPortgroup)
      map_attrs_to_hash(network, network_dvportgroup_attribute_mapping).merge(
        vlanid: raw_network_vlan(network['config.defaultPortConfig']),
        virtualswitch: dvswitches[network['config.distributedVirtualSwitch']._ref]
      )
    elsif network.obj.is_a?(RbVmomi::VIM::OpaqueNetwork)
      map_attrs_to_hash(network, network_dvportgroup_attribute_mapping).merge(
        id: network.obj._ref,
        opaqueNetworkId: network.obj.summary.opaqueNetworkId
      )
    else
      map_attrs_to_hash(network, network_attribute_mapping).merge(
        id: network.obj._ref
      )
    end.merge(
      datacenter: datacenter_name,
      _ref: network.obj._ref
    )
  end.compact
end

#list_processes(vm_id, opts) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/fog/vsphere/requests/compute/list_processes.rb', line 5

def list_processes(vm_id, opts)
  vm = get_vm_ref(vm_id)

  auth = RbVmomi::VIM::NamePasswordAuthentication(
    username: opts[:user],
    password: opts[:password],
    interactiveSession: false
  )

  p_manager = connection.serviceContent.guestOperationsManager.processManager
  processes = p_manager.ListProcessesInGuest(vm: vm, auth: auth)
  processes.map do |pi|
    Process.new(
      cmd_line: pi.cmdLine,
      end_time: pi.endTime,
      exit_code: pi.exitCode,
      name: pi.name,
      owner: pi.owner,
      pid: pi.pid,
      start_time: pi.startTime
    )
  end
end

#list_resource_pools(filters = {}) ⇒ Object



5
6
7
8
9
10
11
12
# File 'lib/fog/vsphere/requests/compute/list_resource_pools.rb', line 5

def list_resource_pools(filters = {})
  datacenter_name = filters[:datacenter]
  cluster_name    = filters[:cluster]
  cluster         = get_raw_cluster(cluster_name, datacenter_name)
  list_raw_resource_pools(cluster).map do |resource_pool|
    resource_pool_attributes(resource_pool, cluster_name, datacenter_name)
  end
end

#list_rules(filters = {}) ⇒ Object



5
6
7
8
# File 'lib/fog/vsphere/requests/compute/list_rules.rb', line 5

def list_rules(filters = {})
  cluster = get_raw_cluster(filters[:cluster], filters[:datacenter])
  cluster.configurationEx.rule.map { |r| rule_attributes r, filters }
end

#list_server_types(filters = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
# File 'lib/fog/vsphere/requests/compute/list_server_types.rb', line 5

def list_server_types(filters = {})
  datacenter_name = filters[:datacenter]
  servertypes = raw_server_types(datacenter_name)
  if servertypes
    servertypes.map do |servertype|
      server_type_attributes(servertype, datacenter_name)
    end.compact
  end
  # select{ | guestdesc | guestdesc.select{ | k, v | filter.has_key?(k) and filter[k] == v }==filter }
end

#list_storage_pods(filters = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/fog/vsphere/requests/compute/list_storage_pods.rb', line 5

def list_storage_pods(filters = {})
  datacenter_name = filters[:datacenter]

  dc = find_raw_datacenter(datacenter_name)

  storage_pods = property_collector_results(storage_pod_filter_spec(dc))

  storage_pods.map do |storage_pod|
    map_attrs_to_hash(storage_pod, storage_pod_attribute_mapping).merge(
      datacenter: datacenter_name,
      id: managed_obj_id(storage_pod.obj)
    )
  end
end

#list_templates(options = {}) ⇒ Object



5
6
7
8
9
10
11
12
# File 'lib/fog/vsphere/requests/compute/list_templates.rb', line 5

def list_templates(options = {})
  options[:folder] ||= options['folder']
  if options[:folder]
    list_all_templates_in_folder(options[:folder], options[:datacenter])
  else
    list_all_templates(options)
  end
end

#list_virtual_machines(options = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/fog/vsphere/requests/compute/list_virtual_machines.rb', line 5

def list_virtual_machines(options = {})
  # Listing all VM's can be quite slow and expensive.  Try and optimize
  # based on the available options we have.  These conditions are in
  # ascending order of time to complete for large deployments.

  options[:folder] ||= options['folder']
  if options['instance_uuid']
    [get_virtual_machine(options['instance_uuid'])]
  elsif options[:folder] && options[:datacenter]
    list_all_virtual_machines_in_folder(options[:folder], options[:datacenter], options[:recursive])
  else
    list_all_virtual_machines(options)
  end
end

#list_vm_cdroms(vm_id) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/fog/vsphere/requests/compute/list_vm_cdroms.rb', line 6

def list_vm_cdroms(vm_id)
  get_vm_ref(vm_id).config.hardware.device.select { |hw| hw.class == RbVmomi::VIM::VirtualCdrom }.map do |cdrom|
    {
      filename: (begin
                      cdrom.backing.fileName
                    rescue
                      (nil)
                    end),
      name: cdrom.deviceInfo.label,
      key: cdrom.key,
      controller_key: cdrom.controllerKey,
      unit_number: cdrom.unitNumber,
      start_connected: cdrom.connectable.startConnected,
      allow_guest_control: cdrom.connectable.allowGuestControl,
      connected: cdrom.connectable.connected,
      instance_uuid: vm_id
    }
  end
end

#list_vm_customvalues(vm_id) ⇒ Object



5
6
7
8
9
10
11
12
# File 'lib/fog/vsphere/requests/compute/list_vm_customvalues.rb', line 5

def list_vm_customvalues(vm_id)
  get_vm_ref(vm_id).summary.customValue.map do |customvalue|
    {
      key: customvalue.key.to_i,
      value: customvalue.value
    }
  end
end

#list_vm_interfaces(vm_id, datacenter = nil) ⇒ Object

> VirtualE1000(

addressType: “assigned”, backing: VirtualEthernetCardNetworkBackingInfo(

deviceName: "VM Network",
dynamicProperty: [],
network: Network("network-163"),
useAutoDetect: false

), connectable: VirtualDeviceConnectInfo(

allowGuestControl: true,
connected: true,
dynamicProperty: [],
startConnected: true,
status: "ok"

), controllerKey: 100, deviceInfo: Description(

dynamicProperty: [],
label: "Network adapter 1",
summary: "VM Network"

), dynamicProperty: [], key: 4000, macAddress: “00:50:56:a9:00:28”, unitNumber: 7,



31
32
33
# File 'lib/fog/vsphere/requests/compute/list_vm_interfaces.rb', line 31

def list_vm_interfaces(vm_id, datacenter = nil)
  get_raw_interfaces(vm_id, datacenter).map { |nic| raw_to_hash(nic, datacenter) }
end

#list_vm_scsi_controllers(vm_id) ⇒ Object



5
6
7
8
9
# File 'lib/fog/vsphere/requests/compute/list_vm_scsi_controllers.rb', line 5

def list_vm_scsi_controllers(vm_id)
  list_vm_scsi_controllers_raw(vm_id).map do |raw_controller|
    Fog::Vsphere::Compute::SCSIController.new(raw_controller)
  end
end

#list_vm_scsi_controllers_raw(vm_id) ⇒ Object



11
12
13
14
15
16
17
18
19
20
# File 'lib/fog/vsphere/requests/compute/list_vm_scsi_controllers.rb', line 11

def list_vm_scsi_controllers_raw(vm_id)
  get_vm_ref(vm_id).config.hardware.device.grep(RbVmomi::VIM::VirtualSCSIController).map do |ctrl|
    {
      type: ctrl.class.to_s,
      shared_bus: ctrl.sharedBus.to_s,
      unit_number: ctrl.scsiCtlrUnitNumber,
      key: ctrl.key
    }
  end
end

#list_vm_snapshots(vm_id, opts = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# File 'lib/fog/vsphere/requests/compute/list_vm_snapshots.rb', line 5

def list_vm_snapshots(vm_id, opts = {})
  vm_snapshot_info = get_vm_ref(vm_id).snapshot

  return [] unless vm_snapshot_info

  root_snapshots = vm_snapshot_info.rootSnapshotList.map do |snap|
    item = snapshot_info(snap, vm_id)
    [
      item,
      opts[:recursive] ? list_child_snapshots(item, opts) : nil
    ]
  end

  root_snapshots.flatten.compact
end

#list_vm_volumes(vm_id) ⇒ Object

[VirtualDisk(

backing: VirtualDiskFlatVer2BackingInfo(
  contentId: "a172d19487e878e17d6b16ff2505d7eb",
  datastore: Datastore("datastore-162"),
  diskMode: "persistent",
  dynamicProperty: [],
  fileName: "[Storage1] rhel6-mfojtik/rhel6-mfojtik.vmdk",
  split: false,
  thinProvisioned: true,
  uuid: "6000C29c-a47d-4cd9-5249-c371de775f06",
  writeThrough: false
),
capacityInKB: 8388608,
controllerKey: 1000,
deviceInfo: Description(
  dynamicProperty: [],
  label: "Hard disk 1",
  summary: "8,388,608 KB"
),
dynamicProperty: [],
key: 2001,
shares: SharesInfo( dynamicProperty: [], level: "normal", shares: 1000 ),
unitNumber: 1

)]



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/fog/vsphere/requests/compute/list_vm_volumes.rb', line 31

def list_vm_volumes(vm_id)
  get_vm_ref(vm_id).disks.map do |vol|
    {
      id: vol.backing.uuid,
      thin: (begin
                  vol.backing.thinProvisioned
                rescue
                  (nil)
                end),
      eager_zero: (begin
                  vol.backing.eagerlyScrub
                rescue
                  (nil)
                end),
      mode: vol.backing.diskMode,
      filename: vol.backing.fileName,
      datastore: (begin
                       vol.backing.datastore.name
                     rescue
                       (nil)
                     end),
      size: vol.capacityInKB,
      name: vol.deviceInfo.label,
      key: vol.key,
      unit_number: vol.unitNumber,
      controller_key: vol.controllerKey
    }
  end
end

#modified_volumes(vm_mob_ref, volumes) ⇒ Object



824
825
826
827
# File 'lib/fog/vsphere/requests/compute/vm_clone.rb', line 824

def modified_volumes(vm_mob_ref, volumes)
  template_volumes = vm_mob_ref.config.hardware.device.grep(RbVmomi::VIM::VirtualDisk)
  volumes.take(template_volumes.size)
end

#modify_template_nics_simple_spec(network_label, nic_type, network_adapter_device_key, datacenter) ⇒ Object

Build up the network config spec for simple case: simple case: apply just the network_label, nic_type and network_adapter_device_key



753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
# File 'lib/fog/vsphere/requests/compute/vm_clone.rb', line 753

def modify_template_nics_simple_spec(network_label, nic_type, network_adapter_device_key, datacenter)
  config_spec_operation = RbVmomi::VIM::VirtualDeviceConfigSpecOperation('edit')
  # Get the portgroup and handle it from there.
  network = get_raw_network(network_label, datacenter)
  nic_backing_info = if network.is_a? RbVmomi::VIM::DistributedVirtualPortgroup
                       # Create the NIC backing for the distributed virtual portgroup
                       RbVmomi::VIM::VirtualEthernetCardDistributedVirtualPortBackingInfo(
                         port: RbVmomi::VIM::DistributedVirtualSwitchPortConnection(
                           portgroupKey: network.key,
                           switchUuid: network.config.distributedVirtualSwitch.uuid
                         )
                       )
                     else
                       # Otherwise it's a non distributed port group
                       RbVmomi::VIM::VirtualEthernetCardNetworkBackingInfo(deviceName: network_label)
                     end
  connectable = RbVmomi::VIM::VirtualDeviceConnectInfo(
    allowGuestControl: true,
    connected: true,
    startConnected: true
  )
  device = RbVmomi::VIM.public_send nic_type.to_s,
                                    backing: nic_backing_info,
                                    deviceInfo: RbVmomi::VIM::Description(label: 'Network adapter 1', summary: network_label),
                                    key: network_adapter_device_key,
                                    connectable: connectable
  device_spec = RbVmomi::VIM::VirtualDeviceConfigSpec(
    operation: config_spec_operation,
    device: device
  )
  device_spec
end

#modify_template_nics_specs(vm_mob_ref, nics, datacenter) ⇒ Object



786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
# File 'lib/fog/vsphere/requests/compute/vm_clone.rb', line 786

def modify_template_nics_specs(vm_mob_ref, nics, datacenter)
  specs = []
  template_nics = vm_mob_ref.config.hardware.device.grep(RbVmomi::VIM::VirtualEthernetCard)
  modified_nics = nics.take(template_nics.size)
  new_nics      = nics.drop(template_nics.size)

  template_nics.zip(modified_nics).each do |template_nic, new_nic|
    if new_nic
      backing = create_nic_backing(new_nic, datacenter: datacenter)
      template_nic.backing = backing
      template_nic.addressType = 'generated'
      template_nic.macAddress = nil
      connectable = RbVmomi::VIM::VirtualDeviceConnectInfo(
        allowGuestControl: true,
        connected: true,
        startConnected: true
      )
      template_nic.connectable = connectable
      specs << {
        operation: :edit,
        device: template_nic
      }
    else
      interface = Fog::Vsphere::Compute::Interface.new(raw_to_hash(template_nic, datacenter))
      specs << create_interface(interface, interface.key, :remove, datacenter: datacenter)
    end
  end

  new_nic_baseid = -rand(25000..29999)
  new_nics.each do |interface|
    new_nic_id = new_nic_baseid
    new_nic_baseid-=1
    specs << create_interface(interface, new_nic_id, :add, datacenter: datacenter)
  end

  specs
end

#modify_template_volumes_specs(vm_mob_ref, volumes) ⇒ Object



834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
# File 'lib/fog/vsphere/requests/compute/vm_clone.rb', line 834

def modify_template_volumes_specs(vm_mob_ref, volumes)
  template_volumes = vm_mob_ref.config.hardware.device.grep(RbVmomi::VIM::VirtualDisk)

  specs = []
  template_volumes.zip(modified_volumes(vm_mob_ref, volumes)).each do |template_volume, new_volume|
    if new_volume
      # copy identifiers to fog device to mark them as used
      new_volume.unit_number = template_volume.unitNumber
      new_volume.key = template_volume.key
      # updated the attribtues on the existing volume
      # it's not allowed to reduce the size of the volume when cloning
      if new_volume.size > template_volume.capacityInKB
        template_volume.capacityInKB = new_volume.size
      end
      template_volume.backing.diskMode = new_volume.mode
      template_volume.backing.thinProvisioned = new_volume.thin
      template_volume.backing.eagerlyScrub = !new_volume.thin && new_volume.eager_zero
      specs << { operation: :edit, device: template_volume }
    else
      specs << { operation: :remove,
                 fileOperation: :destroy,
                 device: template_volume }
    end
  end
  specs
end

#new_volumes(vm_mob_ref, volumes) ⇒ Object



829
830
831
832
# File 'lib/fog/vsphere/requests/compute/vm_clone.rb', line 829

def new_volumes(vm_mob_ref, volumes)
  template_volumes = vm_mob_ref.config.hardware.device.grep(RbVmomi::VIM::VirtualDisk)
  volumes.drop(template_volumes.size)
end

#raw_clusters(datacenter) ⇒ Object



16
17
18
19
# File 'lib/fog/vsphere/requests/compute/list_clusters.rb', line 16

def raw_clusters(datacenter)
  folder ||= find_raw_datacenter(datacenter).hostFolder
  @raw_clusters = get_raw_clusters_from_folder(folder)
end

#raw_compute_resources(datacenter_name) ⇒ Object



19
20
21
# File 'lib/fog/vsphere/requests/compute/list_compute_resources.rb', line 19

def raw_compute_resources(datacenter_name)
  find_raw_datacenter(datacenter_name).find_compute_resource('').children
end

#raw_server_types(datacenter_name, _filter = {}) ⇒ Object



16
17
18
19
20
21
22
# File 'lib/fog/vsphere/requests/compute/list_server_types.rb', line 16

def raw_server_types(datacenter_name, _filter = {})
  datacenter = find_raw_datacenter(datacenter_name)
  environmentBrowser = datacenter.hostFolder.childEntity.grep(RbVmomi::VIM::ComputeResource).first.environmentBrowser
  if environmentBrowser
    environmentBrowser.QueryConfigOption[:guestOSDescriptor]
  end
end

#reloadObject



672
673
674
675
676
677
# File 'lib/fog/vsphere/compute.rb', line 672

def reload
  connect
  # Check if the negotiation was ever run
  negotiate if @vsphere_is_vcenter.nil?
  authenticate
end

#relocate_template_volumes_specs(vm_mob_ref, volumes, datacenter) ⇒ Object



865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
# File 'lib/fog/vsphere/requests/compute/vm_clone.rb', line 865

def relocate_template_volumes_specs(vm_mob_ref, volumes, datacenter)
  template_volumes = vm_mob_ref.config.hardware.device.grep(RbVmomi::VIM::VirtualDisk)
  modified_volumes = volumes.take(template_volumes.size)

  specs = []
  template_volumes.zip(modified_volumes).each do |template_volume, new_volume|
    next unless new_volume
    specs << RbVmomi::VIM.VirtualMachineRelocateSpecDiskLocator(
      diskId: template_volume.key,
      datastore: get_raw_datastore(new_volume.datastore, datacenter),
      diskBackingInfo: relocation_volume_backing(new_volume)
    )
  end
  specs
end

#relocation_volume_backing(volume) ⇒ Object



881
882
883
884
885
886
887
# File 'lib/fog/vsphere/requests/compute/vm_clone.rb', line 881

def relocation_volume_backing(volume)
  RbVmomi::VIM.VirtualDiskFlatVer2BackingInfo(
    diskMode: volume.mode.to_sym,
    fileName: '',
    thinProvisioned: volume.thin
  )
end

#remove_vm_volume(volume) ⇒ Object



9
10
11
# File 'lib/fog/vsphere/requests/compute/modify_vm_volume.rb', line 9

def remove_vm_volume(volume)
  vm_reconfig_hardware('instance_uuid' => volume.server_id, 'hardware_spec' => { 'deviceChange' => [create_disk(volume, :remove)] })
end

#revert_to_snapshot(snapshot) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
# File 'lib/fog/vsphere/requests/compute/revert_to_snapshot.rb', line 5

def revert_to_snapshot(snapshot)
  unless Snapshot === snapshot
    raise ArgumentError, 'snapshot is a required parameter'
  end

  task = snapshot.mo_ref.RevertToSnapshot_Task
  task.wait_for_completion

  {
    'state' => task.info.state
  }
end

#set_vm_customvalue(vm_id, key, value) ⇒ Object



5
6
7
8
# File 'lib/fog/vsphere/requests/compute/set_vm_customvalue.rb', line 5

def set_vm_customvalue(vm_id, key, value)
  vm_ref = get_vm_ref(vm_id)
  vm_ref.setCustomValue(key: key, value: value)
end

#update_resource_pool(attributes = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
# File 'lib/fog/vsphere/requests/compute/update_resource_pool.rb', line 5

def update_resource_pool(attributes = {})
  raw_resource_pool = get_raw_resource_pool_by_ref(attributes)

  raw_resource_pool.UpdateConfig(
    name: attributes[:name],
    config: get_resource_pool_spec(attributes)
  )

  resource_pool_attributes(raw_resource_pool, attributes[:cluster], attributes[:datacenter])
end

#update_vm(server) ⇒ Object



5
6
7
8
9
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
# File 'lib/fog/vsphere/requests/compute/update_vm.rb', line 5

def update_vm(server)
  attributes = server.attributes
  datacenter = attributes[:datacenter]
  vm_mob_ref = get_vm_ref(attributes[:instance_uuid], datacenter)

  device_change = []
  spec = {}

  # Name
  spec[:name] = attributes[:name]

  # CPUs
  spec[:numCPUs] = attributes[:cpus]
  spec[:numCoresPerSocket] = attributes[:corespersocket]

  # Memory
  spec[:memoryMB] = attributes[:memory_mb]

  # HotAdd
  spec[:cpuHotAddEnabled] = attributes[:cpuHotAddEnabled]
  spec[:memoryHotAddEnabled] = attributes[:memoryHotAddEnabled]

  # Volumes
  device_change.concat(update_vm_volumes_specs(vm_mob_ref, server.volumes))

  # Networks
  device_change.concat(update_vm_interfaces_specs(vm_mob_ref, server.interfaces, datacenter))

  spec[:deviceChange] = device_change unless device_change.empty?

  vm_reconfig_hardware('instance_uuid' => attributes[:instance_uuid], 'hardware_spec' => spec) unless spec.empty?
end

#update_vm_interface(vmid, options = {}) ⇒ Object

Raises:

  • (ArgumentError)


19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/fog/vsphere/requests/compute/modify_vm_interface.rb', line 19

def update_vm_interface(vmid, options = {})
  raise ArgumentError, 'instance id is a required parameter' unless vmid
  raise ArgumentError, "'datacenter' is a required key in options: #{options}" unless options.key?(:datacenter)

  datacenter_name = options[:datacenter]

  interface = get_interface_from_options(vmid, options)
  raw_interface = get_raw_interface(vmid, key: interface.key, datacenter: datacenter_name)

  if options[:network]
    interface.network = options[:network]
    backing = create_nic_backing(interface, datacenter: datacenter_name)
    raw_interface.backing = backing
  end

  apply_options_to_raw_interface(raw_interface, options)

  spec = {
    operation: :edit,
    device: raw_interface
  }

  vm_reconfig_hardware('instance_uuid' => vmid, 'hardware_spec' => { 'deviceChange' => [spec] })
end

#upload_iso(options = {}) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/fog/vsphere/requests/compute/upload_iso.rb', line 19

def upload_iso(options = {})
  options = upload_iso_check_options(options)
  datastore = get_raw_datastore(options['datastore'], options['datacenter'])
  datacenter = get_raw_datacenter(options['datacenter'])
  filename = options['filename'] || File.basename(options['local_path'])
  unless datastore.exists?(options['upload_directory'])
    connection.serviceContent.fileManager.MakeDirectory name: "[#{options['datastore']}] #{options['upload_directory']}",
                                                        datacenter: datacenter,
                                                        createParentDirectories: false
  end
  datastore.upload options['upload_directory'] + '/' + filename, options['local_path']
  datastore.exists? options['upload_directory'] + '/' + filename
end

#upload_iso_check_options(options) ⇒ Object

Raises:

  • (Fog::Vsphere::Compute::NotFound)


5
6
7
8
9
10
11
12
13
14
15
16
17
# File 'lib/fog/vsphere/requests/compute/upload_iso.rb', line 5

def upload_iso_check_options(options)
  default_options = {
    'upload_directory' => 'isos'
  }
  options = default_options.merge(options)
  required_options = %w[datacenter datastore local_path]
  required_options.each do |param|
    raise ArgumentError, "#{required_options.join(', ')} are required" unless options.key? param
  end
  raise Fog::Vsphere::Compute::NotFound, "Datacenter #{options['datacenter']} Doesn't Exist!" unless get_datacenter(options['datacenter'])
  raise Fog::Vsphere::Compute::NotFound, "Datastore #{options['datastore']} Doesn't Exist!" unless get_raw_datastore(options['datastore'], options['datacenter'])
  options
end

#vm_acquire_ticket(options = {}) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/fog/vsphere/requests/compute/vm_acquire_ticket.rb', line 5

def vm_acquire_ticket(options = {})
  raise ArgumentError, 'instance_uuid is a required parameter' unless options.key?('instance_uuid')
  ticket_type = options['ticket_type'] || 'webmks'

  vm_mob_ref = get_vm_ref(options['instance_uuid'])

  ticket = vm_mob_ref.AcquireTicket(ticketType: ticket_type)
  {
    'ticket' => ticket.ticket,
    'host' => ticket.host,
    'port' => ticket.port,
    'ssl_thumbprint' => ticket.sslThumbprint
  }
end

#vm_clone(options = {}) ⇒ Object

Clones a VM from a template or existing machine on your vSphere Server.

Parameters

  • options<~Hash>:

    • ‘datacenter’<~String> - REQUIRED Datacenter name your cloning in. Make sure this datacenter exists, should if you’re using the clone function in server.rb model.

    • ‘template_path’<~String> - REQUIRED The path to the machine you want to clone FROM. Relative to Datacenter (Example: “FolderNameHere/VMNameHere”)

    • ‘name’<~String> - REQUIRED The VMName of the Destination

    • ‘template_datacenter’<~String> - Datacenter name where template is. Make sure this datacenter exists, should if you’re using the clone function in server.rb model.

    • ‘dest_folder’<~String> - Destination Folder of where ‘name’ will be placed on your cluster. Relative Path to Datacenter E.G. “FolderPlaceHere/anotherSub Folder/onemore”

    • ‘power_on’<~Boolean> - Whether to power on machine after clone. Defaults to true.

    • ‘wait’<~Boolean> - Whether the method should wait for the virtual machine to finish cloning before returning information from vSphere. Broken right now as you cannot return a model of a serer that isn’t finished cloning. Defaults to True

    • ‘resource_pool’<~Array> - The resource pool on your datacenter cluster you want to use. Only works with clusters within same same datacenter as where you’re cloning from. Datacenter grabbed from template_path option. Example: [‘cluster_name_here’,‘resource_pool_name_here’]

    • ‘datastore’<~String> - The datastore you’d like to use.

      (datacenterObj.datastoreFolder.find('name') in API)
      
    • ‘storage_pod’<~String> - The storage pod / datastore cluster you’d like to use.

    • ‘transform’<~String> - Not documented - see www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.vm.RelocateSpec.html

    • ‘numCPUs’<~Integer> - the number of Virtual CPUs of the Destination VM

    • ‘numCoresPerSocket’<~Integer> - the number of cores per socket of the Destination VM

    • ‘memoryMB’<~Integer> - the size of memory of the Destination VM in MB

    • customization_spec<~Hash>: Options are marked as required if you use this customization_spec. As defined pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.Specification.html

      • encryptionKey <~array of bytes> Used to encrypt/decrypt password

      • globalIPSettings expects a hash, REQUIRED

      • identity expects a hash, REQUIRED - either LinuxPrep, Sysprep or SysprepText

      • nicSettingMap expects an array

      • options expects a hash

      • All options can be parsed using a yaml template with cloudinit_to_customspec.rb

      OLD Values still supported: This only support cloning and setting DHCP on the first interface

      • ‘domain’<~String> - REQUIRED This is put into /etc/resolve.conf (we hope)

      • ‘hostname’<~String> - Hostname of the Guest Os - default is options

      • ‘hw_utc_clock’<~Boolean> - REQUIRED Is hardware clock UTC? Default true

      • ‘time_zone’<~String> - REQUIRED Only valid linux options are valid - example: ‘America/Denver’

      • ‘interfaces’ <~Array> - interfaces object to apply to

        the template when cloning: overrides the
        network_label, network_adapter_device_key and nic_type attributes
        
      • ‘volumes’ <~Array> - volumes object to apply to

        the template when cloning: this allows to resize the
        existing disks as well as add or remove them. The
        resizing is applied only when the size is bigger then the
        in size in the template
        

rubocop:disable Metrics/MethodLength



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
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
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
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
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
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
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
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
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
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
# File 'lib/fog/vsphere/requests/compute/vm_clone.rb', line 109

def vm_clone(options = {})
  # Option handling
  options = vm_clone_check_options(options)

  # Options['template_path']<~String>
  # Added for people still using options['path']
  template_path = options['path'] || options['template_path']
  # Now find the template itself using the efficient find method
  vm_mob_ref = get_vm_ref(template_path, options['template_datacenter'] || options['datacenter'])

  # Options['dest_folder']<~String>
  # Grab the destination folder object if it exists else use cloned mach
  dest_folder_path = options.fetch('dest_folder', '/') # default to root path ({dc_name}/vm/)
  dest_folder = get_raw_vmfolder(dest_folder_path, options['datacenter'])

  # Options['resource_pool']<~Array>
  # Now find _a_ resource pool to use for the clone if one is not specified
  if options.key?('resource_pool') && options['resource_pool'].is_a?(Array) && options['resource_pool'].length == 2 && options['resource_pool'][1] != 'Resources'
    cluster_name = options['resource_pool'][0]
    pool_name = options['resource_pool'][1]
    resource_pool = get_raw_resource_pool(pool_name, cluster_name, options['datacenter'])
  elsif options.key?('resource_pool') && options['resource_pool'].is_a?(Array) && options['resource_pool'].length == 2 && options['resource_pool'][1] == 'Resources'
    cluster_name = options['resource_pool'][0]
    resource_pool = get_raw_resource_pool(nil, cluster_name, options['datacenter'])
  elsif vm_mob_ref.resourcePool.nil?
    # If the template is really a template then there is no associated resource pool,
    # so we need to find one using the template's parent host or cluster
    esx_host = vm_mob_ref.collect!('runtime.host')['runtime.host']
    # The parent of the ESX host itself is a ComputeResource which has a resourcePool
    resource_pool = esx_host.parent.resourcePool
    cluster_name = nil
  end
  # If the vm given did return a valid resource pool, default to using it for the clone.
  # Even if specific pools aren't implemented in this environment, we will still get back
  # at least the cluster or host we can pass on to the clone task
  # This catches if resource_pool option is set but comes back nil and if resourcePool is
  # already set.
  resource_pool ||= vm_mob_ref.resourcePool.nil? ? esx_host.parent.resourcePool : vm_mob_ref.resourcePool

  # Options['host']<~String>
  # The target host for the virtual machine. Optional.
  host = if options.key?('host') && !options['host'].empty? && !cluster_name.nil?
           get_raw_host(options['host'], cluster_name, options['datacenter'])
         end

  # Options['datastore']<~String>
  # Grab the datastore object if option is set
  datastore_obj = get_raw_datastore(options['datastore'], options['datacenter']) if options.key?('datastore')
  # confirm nil if nil or option is not set
  datastore_obj ||= nil
  virtual_machine_config_spec = RbVmomi::VIM::VirtualMachineConfigSpec()

  device_change = []
  # fully futured interfaces api: replace the current nics
  # with the new based on the specification
  if options.key?('interfaces')
    if options.key?('network_label')
      raise ArgumentError, "interfaces option can't be specified together with network_label"
    end
    device_change.concat(modify_template_nics_specs(vm_mob_ref, options['interfaces'], options['datacenter']))
  elsif options.key?('network_label')
    device_change << modify_template_nics_simple_spec(options['network_label'], options['nic_type'], options['network_adapter_device_key'], options['datacenter'])
  end
  if disks = options['volumes']
    device_change.concat(modify_template_volumes_specs(vm_mob_ref, options['volumes']))
    device_change.concat(add_new_volumes_specs(vm_mob_ref, options['volumes'])) unless options['storage_pod']
  end
  virtual_machine_config_spec.deviceChange = device_change if device_change.any?
  # Options['numCPUs'] or Options['memoryMB']
  # Build up the specification for Hardware, for more details see ____________
  # https://github.com/rlane/rbvmomi/blob/master/test/test_serialization.rb
  # http://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.vm.ConfigSpec.html
  # FIXME: pad this out with the rest of the useful things in VirtualMachineConfigSpec
  virtual_machine_config_spec.numCPUs = options['numCPUs'] if options.key?('numCPUs')
  virtual_machine_config_spec.numCoresPerSocket = options['numCoresPerSocket'] if options.key?('numCoresPerSocket')
  virtual_machine_config_spec.memoryMB = options['memoryMB'] if options.key?('memoryMB')
  virtual_machine_config_spec.cpuHotAddEnabled = options['cpuHotAddEnabled'] if options.key?('cpuHotAddEnabled')
  virtual_machine_config_spec.memoryHotAddEnabled = options['memoryHotAddEnabled'] if options.key?('memoryHotAddEnabled')
  virtual_machine_config_spec.firmware = options['firmware'] if options.key?('firmware')
  virtual_machine_config_spec.annotation = options['annotation'] if options.key?('annotation')
  virtual_machine_config_spec.extraConfig = extra_config(extra_config: options['extraConfig']) if options.key?('extraConfig')
  if @vsphere_rev.to_f >= 5 && options.key?('boot_order')
    boot_order = options['boot_order'].flat_map do |boot_device|
      case boot_device.to_sym
      when :network
        interfaces = device_change.select do |change|
          %i[edit add].include?(change[:operation]) &&
            change[:device].class <= RbVmomi::VIM::VirtualEthernetCard
        end.map { |change| change[:device] }
        interfaces.map do |interface|
          RbVmomi::VIM::VirtualMachineBootOptionsBootableEthernetDevice.new(
            deviceKey: interface.key
          )
        end
      when :disk
        disks = device_change.select do |change|
          %i[edit add].include?(change[:operation]) &&
            change[:device].is_a?(RbVmomi::VIM::VirtualDisk)
        end.map { |change| change[:device] }
        disks.map do |disk|
          RbVmomi::VIM::VirtualMachineBootOptionsBootableDiskDevice.new(
            deviceKey: disk.key
          )
        end
      when :cdrom
        RbVmomi::VIM::VirtualMachineBootOptionsBootableCdromDevice.new
      when :floppy
        RbVmomi::VIM::VirtualMachineBootOptionsBootableFloppyDevice.new
      end
    end
    virtual_machine_config_spec.bootOptions = { bootOrder: boot_order }
  end
  # Options['customization_spec']
  # OLD Options still supported
  # * domain <~String> - *REQUIRED* - Sets the server's domain for customization
  # * dnsSuffixList <~Array> - Optional - Sets the dns search paths in resolv - Example: ["dev.example.com", "example.com"]
  # * time_zone <~String> - Required - Only valid linux options are valid - example: 'America/Denver'
  # * ipsettings <~Hash> - Optional - If not set defaults to dhcp
  #  * ip <~String> - *REQUIRED* Sets the ip address of the VM - Example: 10.0.0.10
  #  * dnsServerList <~Array> - Optional - Sets the nameservers in resolv - Example: ["10.0.0.2", "10.0.0.3"]
  #  * gateway <~Array> - Optional - Sets the gateway for the interface - Example: ["10.0.0.1"]
  #  * subnetMask <~String> - *REQUIRED* - Set the netmask of the interface - Example: "255.255.255.0"
  #    For other ip settings options see http://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.vm.customization.IPSettings.html
  #
  #  Implement complete customization spec as per https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.Specification.html
  #   * encryptionKey <~Array> - Optional, encryption key used to encypt any encrypted passwords
  #   https://pubs.vmware.com/vsphere-51/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.GlobalIPSettings.html
  #   * globalIPSettings <~Hash> - REQUIRED
  #   *   dnsServerList <~Array> - Optional, list of dns servers - Example: ["10.0.0.2", "10.0.0.3"]
  #   *   dnsSuffixList <~Array> - Optional, List of name resolution suffixes - Example: ["dev.example.com", "example.com"]
  #   * identity <~Hash> - REQUIRED, Network identity and settings, similar to Microsoft's Sysprep tool. This is a Sysprep, LinuxPrep, or SysprepText object
  #   *   Sysprep <~Hash> - Optional, representation of a Windows sysprep.inf answer file.
  #   *     guiRunOnce: <~Hash> -Optional, representation of the sysprep GuiRunOnce key
  #   *       commandList: <~Array> - REQUIRED, list of commands to run at first user logon, after guest customization. - Example: ["c:\sysprep\runaftersysprep.cmd", "c:\sysprep\installpuppet.ps1"]
  #   *     guiUnattended: <~Hash> - REQUIRED, representation of the sysprep GuiUnattended key
  #   *       autoLogin: boolean - REQUIRED, Flag to determine whether or not the machine automatically logs on as Administrator.
  #   *       autoLogonCount: int - REQUIRED, specifies the number of times the machine should automatically log on as Administrator
  #   *       password: <~Hash> - REQUIRED, new administrator password for the machine
  #   *         plainText: boolean - REQUIRED, specify whether or not the password is in plain text, rather than encrypted
  #   *         value: <~String> - REQUIRED, password string
  #   *       timeZone: <~int> - REQUIRED, (see here for values https://msdn.microsoft.com/en-us/library/ms912391(v=winembedded.11).aspx)
  #   *     identification: <~Hash> - REQUIRED, representation of the sysprep Identification key
  #   *       domainAdmin: <~String> - Optional, domain user account used for authentication if the virtual machine is joining a domain
  #   *       domainAdminPassword: <~Hash> - Optional, password for the domain user account used for authentication
  #   *         plainText: boolean - REQUIRED, specify whether or not the password is in plain text, rather than encrypted
  #   *         value: <~String> - REQUIRED, password string
  #   *       joinDomain: <~String> - Optional, The domain that the virtual machine should join. If this value is supplied, then domainAdmin and domainAdminPassword must also be supplied
  #   *       joinWorkgroup: <~String> - Optional, The workgroup that the virtual machine should join.
  #   *     licenseFilePrintData: <~Hash> - Optional, representation of the sysprep LicenseFilePrintData key
  #   *       autoMode: <~String> - REQUIRED, Server licensing mode. Two strings are supported: 'perSeat' or 'perServer'
  #   *       autoUsers: <~Int> - Optional, This key is valid only if AutoMode = PerServer. The integer value indicates the number of client licenses
  #   *     userData: <~Hash> - REQUIRED, representation of the sysprep UserData key
  #   *       computerName: <~String> - REQUIRED, The computer name of the (Windows) virtual machine. Will be truncates to 15 characters
  #   *       fullName: <~String> - REQUIRED, User's full name
  #   *       orgName: <~String> - REQUIRED, User's organization
  #   *       productId: <~String> - REQUIRED, serial number for os, ignored if using volume licensed instance
  #   *   LinuxPrep: <~Hash> - Optional, contains machine-wide settings (note the uppercase P)
  #   *     domain: <~String> - REQUIRED, The fully qualified domain name.
  #   *     hostName: <~String> - REQUIRED, the network host name
  #   *     hwClockUTC: <~Boolean> - Optional, Specifies whether the hardware clock is in UTC or local time
  #   *     timeZone: <~String> - Optional, Case sensistive timezone, valid values can be found at https://pubs.vmware.com/vsphere-51/topic/com.vmware.wssdk.apiref.doc/timezone.html
  #   *   SysprepText: <~Hash> - Optional, alternate way to specify the sysprep.inf answer file.
  #   *     value: <~String> - REQUIRED, Text for the sysprep.inf answer file.
  #   * nicSettingMap: <~Array> - Optional, IP settings that are specific to a particular virtual network adapter
  #   *   Each item in array:
  #   *   adapter: <~Hash> - REQUIRED, IP settings for the associated virtual network adapter
  #   *     dnsDomain: <~String> - Optional, DNS domain suffix for adapter
  #   *     dnsServerList: <~Array> - Optional, list of dns server ip addresses - Example: ["10.0.0.2", "10.0.0.3"]
  #   *     gateway: <~Array> - Optional, list of gateways - Example: ["10.0.0.2", "10.0.0.3"]
  #   *     ip: <~String> - Optional, but required if static IP
  #   *     ipV6Spec: <~Hash> - Optional, IPv^ settings
  #   *       ipAddress: <~String> - Optional, but required if setting static IP
  #   *       gateway: <~Array> - Optional, list of ipv6 gateways
  #   *     netBIOS: <~String> - Optional, NetBIOS settings, if supplied must be one of: disableNetBIOS','enableNetBIOS','enableNetBIOSViaDhcp'
  #   *     primaryWINS: <~String> - Optional, IP address of primary WINS server
  #   *     secondaryWINS: <~String> - Optional, IP address of secondary WINS server
  #   *     subnetMask: <~String> - Optional, subnet mask for adapter
  #   *   macAddress: <~String> - Optional, MAC address of adapter being customized. This cannot be set by the client
  #   * options: <~Hash> Optional operations, currently only win options have any value
  #   *   changeSID: <~Boolean> - REQUIRED, The customization process should modify the machine's security identifier
  #   *   deleteAccounts: <~Boolean> - REQUIRED, If deleteAccounts is true, then all user accounts are removed from the system
  #   *   reboot: <~String> - Optional, (defaults to reboot), Action to be taken after running sysprep, must be one of: 'noreboot', 'reboot', 'shutdown'
  #
  if options.key?('customization_spec')
    custom_spec = options['customization_spec']

    # backwards compatablity
    if custom_spec.key?('domain')
      # doing this means the old options quash any new ones passed as well... might not be the best way to do it?
      # any 'old' options overwrite the following:
      #   - custom_spec['identity']['LinuxPrep']
      #   - custom_spec['globalIPSettings['['dnsServerList']
      #   - custom_spec['globalIPSettings']['dnsSuffixList']
      #   - custom_spec['nicSettingMap'][0]['adapter']['ip']
      #   - custom_spec['nicSettingMap'][0]['adapter']['gateway']
      #   - custom_spec['nicSettingMap'][0]['adapter']['subnetMask']
      #   - custom_spec['nicSettingMap'][0]['adapter']['dnsDomain']
      #   - custom_spec['nicSettingMap'][0]['adapter']['dnsServerList']
      #
      # we can assume old parameters being passed
      cust_hostname = custom_spec['hostname'] || options['name']
      custom_spec['identity'] = {} unless custom_spec.key?('identity')
      custom_spec['identity']['LinuxPrep'] = { 'domain' => custom_spec['domain'], 'hostName' => cust_hostname, 'timeZone' => custom_spec['time_zone'] }

      if custom_spec.key?('ipsettings')
        custom_spec['globalIPSettings'] = {} unless custom_spec.key?('globalIPSettings')
        custom_spec['globalIPSettings']['dnsServerList'] = custom_spec['ipsettings']['dnsServerList'] if custom_spec['ipsettings'].key?('dnsServerList')
        custom_spec['globalIPSettings']['dnsSuffixList'] = custom_spec['dnsSuffixList'] || [custom_spec['domain']] if custom_spec['dnsSuffixList'] || custom_spec['domain']
        if custom_spec['ipsettings'].key?('ip') || custom_spec['ipsettings'].key?('gateway') || custom_spec['ipsettings'].key?('subnetMask') || custom_spec['ipsettings'].key?('domain') || custom_spec['ipsettings'].key?('dnsServerList')
          if custom_spec['ipsettings'].key?('ip') && !custom_spec['ipsettings'].key?('subnetMask')
            raise ArgumentError, 'subnetMask is required for static ip'
          end
          custom_spec['nicSettingMap'] = [] unless custom_spec.key?('nicSettingMap')
          custom_spec['nicSettingMap'][0] = {} if custom_spec['nicSettingMap'].empty?
          custom_spec['nicSettingMap'][0]['adapter'] = {} unless custom_spec['nicSettingMap'][0].key?('adapter')
          custom_spec['nicSettingMap'][0]['adapter']['ip'] = custom_spec['ipsettings']['ip'] if custom_spec['ipsettings'].key?('ip')
          custom_spec['nicSettingMap'][0]['adapter']['gateway'] = custom_spec['ipsettings']['gateway'] if custom_spec['ipsettings'].key?('gateway')
          custom_spec['nicSettingMap'][0]['adapter']['subnetMask'] = custom_spec['ipsettings']['subnetMask'] if custom_spec['ipsettings'].key?('subnetMask')
          custom_spec['nicSettingMap'][0]['adapter']['dnsDomain'] = custom_spec['ipsettings']['domain'] if custom_spec['ipsettings'].key?('domain')
          custom_spec['nicSettingMap'][0]['adapter']['dnsServerList'] = custom_spec['ipsettings']['dnsServerList'] if custom_spec['ipsettings'].key?('dnsServerList')
        end
      end
    end
    ### End of backwards compatability

    ## requirements check here ##
    raise ArgumentError, 'globalIPSettings are required when using Customization Spec' unless custom_spec.key?('globalIPSettings')
    raise ArgumentError, 'identity is required when using Customization Spec' unless custom_spec.key?('identity')

    # encryptionKey
    custom_encryptionKey = custom_spec['encryptionKey'] if custom_spec.key?('encryptionKey')
    custom_encryptionKey ||= nil

    # globalIPSettings
    # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.GlobalIPSettings.html
    custom_globalIPSettings = RbVmomi::VIM::CustomizationGlobalIPSettings.new
    custom_globalIPSettings.dnsServerList = custom_spec['globalIPSettings']['dnsServerList'] if custom_spec['globalIPSettings'].key?('dnsServerList')
    custom_globalIPSettings.dnsSuffixList = custom_spec['globalIPSettings']['dnsSuffixList'] if custom_spec['globalIPSettings'].key?('dnsSuffixList')

    # identity
    # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.IdentitySettings.html
    # Accepts the 3 supported CustomizationIdentitySettings Types:
    # 1. CustomizationLinuxPrep (LinuxPrep) - note the uppercase P
    # 2. CustomizationSysprep (Sysprep)
    # 3. CustomizationSysprepText (SysprepText)
    # At least one of these is required
    #
    identity = custom_spec['identity']
    if identity.key?('LinuxPrep')
      # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.LinuxPrep.html
      # Fields:
      #   * domain: string **REQUIRED**
      #   * hostName: string (CustomizationName)  **REQUIRED** Will use options['name'] if not provided.
      #   * hwClockUTC: boolean
      #   * timeZone: string (https://pubs.vmware.com/vsphere-55/topic/com.vmware.wssdk.apiref.doc/timezone.html)
      raise ArgumentError, 'domain is required when using LinuxPrep identity' unless identity['LinuxPrep'].key?('domain')
      custom_identity = RbVmomi::VIM::CustomizationLinuxPrep(domain: identity['LinuxPrep']['domain'])
      cust_hostname = RbVmomi::VIM::CustomizationFixedName(name: identity['LinuxPrep']['hostName']) if identity['LinuxPrep'].key?('hostName')
      cust_hostname ||= RbVmomi::VIM::CustomizationFixedName(name: options['name'])
      custom_identity.hostName = cust_hostname
      custom_identity.hwClockUTC = identity['LinuxPrep']['hwClockUTC'] if identity['LinuxPrep'].key?('hwClockUTC')
      custom_identity.timeZone = identity['LinuxPrep']['timeZone'] if identity['LinuxPrep'].key?('timeZone')
    elsif identity.key?('Sysprep')
      # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.Sysprep.html
      # Fields:
      #   * guiRunOnce: CustomizationGuiRunOnce
      #   * guiUnattended: CustomizationGuiUnattended  **REQUIRED**
      #   * identification: CustomizationIdentification  **REQUIRED**
      #   * licenseFilePrintData: CustomizationLicenseFilePrintData
      #   * userData: CustomizationUserData **REQUIRED**
      #
      raise ArgumentError, 'guiUnattended is required when using Sysprep identity' unless identity['Sysprep'].key?('guiUnattended')
      raise ArgumentError, 'identification is required when using Sysprep identity' unless identity['Sysprep'].key?('identification')
      raise ArgumentError, 'userData is required when using Sysprep identity' unless identity['Sysprep'].key?('userData')
      if identity['Sysprep']['guiRunOnce']
        # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.GuiRunOnce.html
        # Fields:
        #  * commandList: array of string **REQUIRED***
        #
        raise ArgumentError, 'commandList is required when using Sysprep identity and guiRunOnce' unless identity['Sysprep']['guiRunOnce'].key?('commandList')
        cust_guirunonce = RbVmomi::VIM.CustomizationGuiRunOnce(commandList: identity['Sysprep']['guiRunOnce']['commandList'])
      end
      # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.GuiUnattended.html
      # Fields:
      #   * autoLogin: boolean **REQUIRED**
      #   * autoLogonCount: int **REQUIRED**
      #   * timeZone: int (see here for values https://msdn.microsoft.com/en-us/library/ms912391(v=winembedded.11).aspx) **REQUIRED**
      #   * password: CustomizationPassword
      raise ArgumentError, 'guiUnattended->autoLogon is required when using Sysprep identity' unless identity['Sysprep']['guiUnattended'].key?('autoLogon')
      raise ArgumentError, 'guiUnattended->autoLogonCount is required when using Sysprep identity' unless identity['Sysprep']['guiUnattended'].key?('autoLogonCount')
      raise ArgumentError, 'guiUnattended->timeZone is required when using Sysprep identity' unless identity['Sysprep']['guiUnattended'].key?('timeZone')
      custom_guiUnattended = RbVmomi::VIM.CustomizationGuiUnattended(
        autoLogon: identity['Sysprep']['guiUnattended']['autoLogon'],
        autoLogonCount: identity['Sysprep']['guiUnattended']['autoLogonCount'],
        timeZone: identity['Sysprep']['guiUnattended']['timeZone']
      )
      if identity['Sysprep']['guiUnattended']['password']
        # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.Password.html
        # Fields:
        #   * plainText: boolean  **REQUIRED**
        #   * value: string  **REQUIRED**
        raise ArgumentError, 'guiUnattended->password->plainText is required when using Sysprep identity and guiUnattended -> password' unless identity['Sysprep']['guiUnattended']['password'].key?('plainText')
        raise ArgumentError, 'guiUnattended->password->value is required when using Sysprep identity and guiUnattended -> password' unless identity['Sysprep']['guiUnattended']['password'].key?('value')
        custom_guiUnattended.password = RbVmomi::VIM.CustomizationPassword(
          plainText: identity['Sysprep']['guiUnattended']['password']['plainText'],
          value: identity['Sysprep']['guiUnattended']['password']['value']
        )
      end
      # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.Identification.html
      # Fields:
      #   * domainAdmin: string
      #   * domainAdminPassword: CustomizationPassword
      #   * joinDomain: string *If supplied domainAdmin and domainAdminPassword must be set
      #   * joinWorkgroup: string *If supplied, joinDomain, domainAdmin and domainAdminPassword will be ignored
      custom_identification = RbVmomi::VIM.CustomizationIdentification()
      if identity['Sysprep']['identification'].key?('joinWorkgroup')
        custom_identification.joinWorkgroup = identity['Sysprep']['identification']['joinWorkgroup']
      elsif identity['Sysprep']['identification'].key?('joinDomain')
        raise ArgumentError, 'identification->domainAdmin is required when using Sysprep identity and identification -> joinDomain' unless identity['Sysprep']['identification'].key?('domainAdmin')
        raise ArgumentError, 'identification->domainAdminPassword is required when using Sysprep identity and identification -> joinDomain' unless identity['Sysprep']['identification'].key?('domainAdmin')
        raise ArgumentError, 'identification->domainAdminPassword->plainText is required when using Sysprep identity and identification -> joinDomain' unless identity['Sysprep']['identification']['domainAdminPassword'].key?('plainText')
        raise ArgumentError, 'identification->domainAdminPassword->value is required when using Sysprep identity and identification -> joinDomain' unless identity['Sysprep']['identification']['domainAdminPassword'].key?('value')
        custom_identification.joinDomain = identity['Sysprep']['identification']['joinDomain']
        custom_identification.domainAdmin = identity['Sysprep']['identification']['domainAdmin']
        # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.Password.html
        # Fields:
        #   * plainText: boolean **REQUIRED**
        #   * value: string **REQUIRED**
        custom_identification.domainAdminPassword = RbVmomi::VIM.CustomizationPassword(
          plainText: identity['Sysprep']['identification']['domainAdminPassword']['plainText'],
          value: identity['Sysprep']['identification']['domainAdminPassword']['value']
        )
      else
        raise ArgumentError, "No valid Indentification found, valid values are 'joinWorkgroup' and 'joinDomain'"
      end
      if identity['Sysprep'].key?('licenseFilePrintData')
        # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.LicenseFilePrintData.html
        # Fields:
        #   * autoMode: string (CustomizationLicenseDataMode) ** REQUIRED **, valid strings are: 'perSeat' or 'perServer'
        #   * autoUsers: int (valid only if AutoMode = PerServer)
        raise ArgumentError, 'licenseFilePrintData->autoMode is required when using Sysprep identity and licenseFilePrintData' unless identity['Sysprep']['licenseFilePrintData'].key?('autoMode')
        raise ArgumentError, "Unsupported autoMode, supported modes are : 'perSeat' or 'perServer'" unless %w[perSeat perServer].include? identity['Sysprep']['licenseFilePrintData']['autoMode']
        custom_licenseFilePrintData = RbVmomi::VIM.CustomizationLicenseFilePrintData(
          autoMode: RbVmomi::VIM.CustomizationLicenseDataMode(identity['Sysprep']['licenseFilePrintData']['autoMode'])
        )
        if identity['Sysprep']['licenseFilePrintData'].key?('autoUsers')
          custom_licenseFilePrintData.autoUsers = identity['Sysprep']['licenseFilePrintData']['autoUsers'] if identity['Sysprep']['licenseFilePrintData']['autoMode'] == 'PerServer'
        end
      end
      # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.UserData.html
      # Fields:
      #   * computerName: string (CustomizationFixedName)  **REQUIRED**
      #   * fullName: string **REQUIRED**
      #   * orgName: string **REQUIRED**
      #   * productID: string **REQUIRED**
      raise ArgumentError, 'userData->computerName is required when using Sysprep identity' unless identity['Sysprep']['userData'].key?('computerName')
      raise ArgumentError, 'userData->fullName is required when using Sysprep identity' unless identity['Sysprep']['userData'].key?('fullName')
      raise ArgumentError, 'userData->orgName is required when using Sysprep identity' unless identity['Sysprep']['userData'].key?('orgName')
      raise ArgumentError, 'userData->productId is required when using Sysprep identity' unless identity['Sysprep']['userData'].key?('productId')
      custom_userData = RbVmomi::VIM.CustomizationUserData(
        fullName: identity['Sysprep']['userData']['fullName'],
        orgName: identity['Sysprep']['userData']['orgName'],
        productId: identity['Sysprep']['userData']['productId'],
        computerName: RbVmomi::VIM.CustomizationFixedName(name: identity['Sysprep']['userData']['computerName'])
      )

      custom_identity = RbVmomi::VIM::CustomizationSysprep(
        guiUnattended: custom_guiUnattended,
        identification: custom_identification,
        userData: custom_userData
      )
      custom_identity.guiRunOnce = cust_guirunonce if defined?(cust_guirunonce)
      custom_identity.licenseFilePrintData = custom_licenseFilePrintData if defined?(custom_licenseFilePrintData)
    elsif identity.key?('SysprepText')
      # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.SysprepText.html
      # Fields:
      #   * value: string **REQUIRED**
      raise ArgumentError, 'SysprepText -> value is required when using SysprepText identity' unless identity['SysprepText'].key?('value')
      custom_identity = RbVmomi::VIM::CustomizationSysprepText(value: identity['SysprepText']['value'])
    else
      raise ArgumentError, 'At least one of the following valid identities must be supplied: LinuxPrep, Sysprep, SysprepText'
    end

    if custom_spec.key?('nicSettingMap')
      # custom_spec['nicSettingMap'] is an array of adapater mappings:
      # custom_spec['nicSettingMap'][0]['macAddress']
      # custom_spec['nicSettingMap'][0]['adapter']['ip']
      # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.AdapterMapping.html
      # Fields:
      #   * adapter: CustomizationIPSettings **REQUIRED**
      #   * macAddress: string
      raise ArgumentError, 'At least one nicSettingMap is required when using nicSettingMap' if custom_spec['nicSettingMap'].empty?
      raise ArgumentError, 'Adapter is required when using nicSettingMap' unless custom_spec['nicSettingMap'][0].key?('adapter')

      custom_nicSettingMap = []
      # need to go through array here for each apapter
      custom_spec['nicSettingMap'].each do |nic|
        # https://pubs.vmware.com/vsphere-55/index.jsp?topic=%2Fcom.vmware.wssdk.apiref.doc%2Fvim.vm.customization.IPSettings.html
        # Fields:
        #   * dnsDomain: string
        #   * gateway: array of string
        #   * ip: CustomizationIpGenerator (string) **REQUIRED IF Assigning Static IP***
        #   * ipV6Spec: CustomizationIPSettingsIpV6AddressSpec
        #   * netBIOS: CustomizationNetBIOSMode (string)
        #   * primaryWINS: string
        #   * secondaryWINS: string
        #   * subnetMask: string - Required if assigning static IP
        if nic['adapter'].key?('ip')
          raise ArgumentError, 'SubnetMask is required when assigning static IP when using nicSettingMap -> Adapter' unless nic['adapter'].key?('subnetMask')
          custom_ip = RbVmomi::VIM.CustomizationFixedIp(ipAddress: nic['adapter']['ip'])
        else
          custom_ip = RbVmomi::VIM::CustomizationDhcpIpGenerator.new
        end
        custom_adapter = RbVmomi::VIM.CustomizationIPSettings(ip: custom_ip)
        custom_adapter.dnsDomain = nic['adapter']['dnsDomain'] if nic['adapter'].key?('dnsDomain')
        custom_adapter.dnsServerList = nic['adapter']['dnsServerList'] if nic['adapter'].key?('dnsServerList')
        custom_adapter.gateway = nic['adapter']['gateway'] if nic['adapter'].key?('gateway')
        if nic['adapter'].key?('ipV6Spec')
          # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.IPSettings.IpV6AddressSpec.html
          # Fields:
          #   * gateway: array of string
          #   * ip: CustomizationIpV6Generator[] **Required if setting static IP **
          if nic['adapter']['ipV6Spec'].key?('ipAddress')
            raise ArgumentError, 'SubnetMask is required when assigning static IPv6 when using nicSettingMap -> Adapter -> ipV6Spec' unless nic['adapter']['ipV6Spec'].key?('subnetMask')
            # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.FixedIpV6.html
            #   * ipAddress: string **REQUIRED**
            #   * subnetMask: int **REQUIRED**
            custom_ipv6 = RbVmomi::VIM.CustomizationFixedIpV6(
              ipAddress: nic['adapter']['ipV6Spec']['ipAddress'],
              subnetMask: nic['adapter']['ipV6Spec']['subnetMask']
            )
          else
            custom_ipv6 = RbVmomi::VIM::CustomizationDhcpIpV6Generator.new
          end
          custom_ipv6Spec = RbVmomi::VIM.CustomizationIPSettingsIpV6AddressSpec(ip: custom_ipv6)
          custom_ipv6Spec.gateway = nic['adapter']['ipV6Spec']['gateway'] if nic['adapter']['ipV6Spec'].key?('gateway')
          custom_adapter.ipV6Spec = custom_ipv6Spec
        end
        if nic['adapter'].key?('netBIOS')
          # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.IPSettings.NetBIOSMode.html
          # Fields:
          #   netBIOS: string matching: 'disableNetBIOS','enableNetBIOS' or 'enableNetBIOSViaDhcp' ** REQUIRED **
          #
          raise ArgumentError, "Unsupported NetBIOSMode, supported modes are : 'disableNetBIOS','enableNetBIOS' or 'enableNetBIOSViaDhcp'" unless %w[disableNetBIOS enableNetBIOS enableNetBIOSViaDhcp].include? nic['adapter']['netBIOS']
          custom_adapter.netBIOS = RbVmomi::VIM.CustomizationNetBIOSMode(nic['adapter']['netBIOS'])
        end
        custom_adapter.primaryWINS = nic['adapter']['primaryWINS'] if nic['adapter'].key?('primaryWINS')
        custom_adapter.secondaryWINS = nic['adapter']['secondaryWINS'] if nic['adapter'].key?('secondaryWINS')
        custom_adapter.subnetMask = nic['adapter']['subnetMask'] if nic['adapter'].key?('subnetMask')

        custom_adapter_mapping = RbVmomi::VIM::CustomizationAdapterMapping(adapter: custom_adapter)
        custom_adapter_mapping.macAddress = nic['macAddress'] if nic.key?('macAddress')

        # build the adapters array
        custom_nicSettingMap << custom_adapter_mapping
      end
    end

    if custom_spec.key?('options')
      # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.Options.html
      # this currently doesn't have any Linux options, just windows
      # Fields:
      #   * changeSID: boolean **REQUIRED**
      #   * deleteAccounts: boolean **REQUIRED** **note deleteAccounts is deprecated as of VI API 2.5 so can be ignored
      #   * reboot: CustomizationSysprepRebootOption: (string) one of following 'noreboot', reboot' or 'shutdown' (defaults to reboot)
      raise ArgumentError, 'changeSID id required when using Windows Options' unless custom_spec['options'].key?('changeSID')
      raise ArgumentError, 'deleteAccounts id required when using Windows Options' unless custom_spec['options'].key?('deleteAccounts')
      custom_options = RbVmomi::VIM::CustomizationWinOptions(
        changeSID: custom_spec['options']['changeSID'],
        deleteAccounts: custom_spec['options']['deleteAccounts']
      )
      if custom_spec['options'].key?('reboot')
        raise ArgumentError, "Unsupported reboot option, supported options are : 'noreboot', 'reboot' or 'shutdown'" unless %w[noreboot reboot shutdown].include? custom_spec['options']['reboot']
        custom_options.reboot = RBVmomi::VIM.CustomizationSysprepRebootOption(custom_spec['options']['reboot'])
      end
    end
    custom_options ||= nil

    # https://pubs.vmware.com/vsphere-55/index.jsp#com.vmware.wssdk.apiref.doc/vim.vm.customization.Specification.html
    customization_spec = RbVmomi::VIM::CustomizationSpec(
      globalIPSettings: custom_globalIPSettings,
      identity: custom_identity
    )
    customization_spec.encryptionKey = custom_encryptionKey if defined?(custom_encryptionKey)
    customization_spec.nicSettingMap = custom_nicSettingMap if defined?(custom_nicSettingMap)
    customization_spec.options = custom_options if defined?(custom_options)

  end
  customization_spec ||= nil

  relocation_spec = nil
  if options['linked_clone']
    # Storage DRS does not support vSphere linked clones.
    # http://www.vmware.com/files/pdf/techpaper/vsphere-storage-drs-interoperability.pdf
    raise ArgumentError, 'linked clones are not supported on storage pods' unless options.key?('storage_pod')
    # cribbed heavily from the rbvmomi clone_vm.rb
    # this chunk of code reconfigures the disk of the clone source to be read only,
    # and then creates a delta disk on top of that, this is required by the API in order to create
    # linked clondes
    disks = vm_mob_ref.config.hardware.device.select do |vm_device|
      vm_device.class == RbVmomi::VIM::VirtualDisk
    end
    disks.select { |vm_device| vm_device.backing.parent.nil? }.each do |disk|
      disk_spec = {
        deviceChange: [
          {
            operation: :remove,
            device: disk
          },
          {
            operation: :add,
            fileOperation: :create,
            device: disk.dup.tap do |disk_backing|
              disk_backing.backing = disk_backing.backing.dup
              disk_backing.backing.fileName = "[#{disk.backing.datastore.name}]"
              disk_backing.backing.parent = disk.backing
            end
          }
        ]
      }
      vm_mob_ref.ReconfigVM_Task(spec: disk_spec).wait_for_completion
    end
    # Next, create a Relocation Spec instance
    relocation_spec = RbVmomi::VIM.VirtualMachineRelocateSpec(datastore: datastore_obj,
                                                              pool: resource_pool,
                                                              host: host,
                                                              diskMoveType: :moveChildMostDiskBacking)
  else
    relocation_spec = RbVmomi::VIM.VirtualMachineRelocateSpec(pool: resource_pool,
                                                              host: host)
    unless options['storage_pod'] && datastore_obj.nil?
      relocation_spec[:datastore] = datastore_obj
    end
  end
  # relocate templates is not supported by fog-vsphere when vm is cloned on a storage pod
  if !options['storage_pod'] && options['volumes'] && !options['volumes'].empty?
    relocation_spec[:disk] = relocate_template_volumes_specs(vm_mob_ref, options['volumes'], options['datacenter'])
  end

  # And the clone specification
  clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(location: relocation_spec,
                                                    config: virtual_machine_config_spec,
                                                    customization: customization_spec,
                                                    powerOn: options.key?('power_on') ? options['power_on'] : true,
                                                    template: options.key?('template') ? options['template'] : false)

  # Perform the actual Clone Task
  # Clone VM on a storage pod
  if options['storage_pod']
    raise ArgumentError, 'need to use at least vsphere revision 5.0 or greater to use storage pods' unless @vsphere_rev.to_f >= 5
    vm_pod_name = options['storage_pod']
    disks_per_pod = group_disks_by_storage_pod(modified_volumes(vm_mob_ref, options['volumes']), vm_pod_name: options['storage_pod'])

    storage_spec = RbVmomi::VIM::StoragePlacementSpec.new(
      type: 'clone',
      folder: dest_folder,
      resourcePool: resource_pool,
      podSelectionSpec: pod_selection_spec(vm_pod_name, disks_per_pod, options['datacenter'], with_relocation: true),
      cloneSpec: clone_spec,
      cloneName: options['name'],
      vm: vm_mob_ref
    )
    srm = connection.serviceContent.storageResourceManager
    result = srm.RecommendDatastores(storageSpec: storage_spec)

    # if result array contains recommendation, we can apply it
    # we need one recomendation for one storagePod
    grouped_recoms = result.recommendations.group_by { |rec| rec.target._ref }
    if grouped_recoms.keys.size == disks_per_pod.size
      keys = grouped_recoms.map { |_ref, recoms| recoms.first.key }
      task = srm.ApplyStorageDrsRecommendation_Task(key: keys)
      if options.fetch('wait', true)
        result = task.wait_for_completion
        new_vm = result.vm
      else
        new_vm = nil
        Fog.wait_for(150, 15) do
          begin
            (new_vm = dest_folder.find(options['name'], RbVmomi::VIM::VirtualMachine)) || raise(Fog::Vsphere::Errors::NotFound)
          rescue Fog::Vsphere::Errors::NotFound
            new_vm = nil
          end
        end
        raise Fog::Vsphere::Errors::NotFound unless new_vm
      end
    end

    new_volumes = new_volumes(vm_mob_ref, options['volumes'])
    if new_vm && !new_volumes.empty?
      new_disks_per_pod = group_disks_by_storage_pod(new_volumes, vm_pod_name: options['storage_pod'])
      add_vols_config_spec = {
        deviceChange: add_new_volumes_specs(vm_mob_ref, options['volumes'], default_storage_pod: options['storage_pod'])
      }
      placement_spec = RbVmomi::VIM::StoragePlacementSpec.new(
        type: 'reconfigure',
        vm: new_vm,
        configSpec: add_vols_config_spec,
        podSelectionSpec: pod_selection_spec(vm_pod_name, new_disks_per_pod, options['datacenter'], only_volumes: true)
      )
      result = srm.RecommendDatastores(storageSpec: placement_spec)
      grouped_recoms = result.recommendations.group_by { |rec| rec.target._ref }
      if grouped_recoms.keys.size == new_disks_per_pod.size
        keys = grouped_recoms.map { |_ref, recoms| recoms.first.key }
        srm.ApplyStorageDrsRecommendation_Task(key: keys).wait_for_completion
      end
    end
  else
    task = vm_mob_ref.CloneVM_Task(folder: dest_folder,
                                   name: options['name'],
                                   spec: clone_spec)
    # Waiting for the VM to complete allows us to get the VirtulMachine
    # object of the new machine when it's done.  It is HIGHLY recommended
    # to set 'wait' => true if your app wants to wait.  Otherwise, you're
    # going to have to reload the server model over and over which
    # generates a lot of time consuming API calls to vmware.
    if options.fetch('wait', true)
      # REVISIT: It would be awesome to call a block passed to this
      # request to notify the application how far along in the process we
      # are.  I'm thinking of updating a progress bar, etc...
      new_vm = task.wait_for_completion
    else
      new_vm = nil
      Fog.wait_for(150, 15) do
        begin
          (new_vm = dest_folder.find(options['name'], RbVmomi::VIM::VirtualMachine)) || raise(Fog::Vsphere::Errors::NotFound)
        rescue Fog::Vsphere::Errors::NotFound
          new_vm = nil
        end
      end
      raise Fog::Vsphere::Errors::NotFound unless new_vm
    end
  end

  # Return hash
  {
    'vm_ref'        => new_vm ? new_vm._ref : nil,
    'new_vm'        => new_vm ? convert_vm_mob_ref_to_attr_hash(new_vm) : nil,
    'task_ref'      => task._ref
  }
end

#vm_config_vnc(options = {}) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# File 'lib/fog/vsphere/requests/compute/vm_config_vnc.rb', line 5

def vm_config_vnc(options = {})
  raise ArgumentError, 'instance_uuid is a required parameter' unless options.key? 'instance_uuid'

  search_filter = { :uuid => options['instance_uuid'], 'vmSearch' => true, 'instanceUuid' => true }
  vm_mob_ref    = connection.searchIndex.FindAllByUuid(search_filter).first
  task          = vm_mob_ref.ReconfigVM_Task(spec: {
                                               extraConfig: [
                                                 { key: 'RemoteDisplay.vnc.enabled',  value: options[:enabled] ? 'true' : 'false' },
                                                 { key: 'RemoteDisplay.vnc.password', value: options[:password].to_s },
                                                 { key: 'RemoteDisplay.vnc.port',     value: options[:port].to_s || '5910' }
                                               ]
                                             })
  task.wait_for_completion
  { 'task_state' => task.info.state }
end

#vm_destroy(options = {}) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
# File 'lib/fog/vsphere/requests/compute/vm_destroy.rb', line 5

def vm_destroy(options = {})
  raise ArgumentError, 'instance_uuid is a required parameter' unless options.key? 'instance_uuid'

  vm_mob_ref = get_vm_ref(options['instance_uuid'])
  task = vm_mob_ref.Destroy_Task
  task.wait_for_completion
  { 'task_state' => task.info.state }
end

#vm_execute(options = {}) ⇒ Object

NOTE: you must be using vsphere_rev 5.0 or greater to use this functionality e.g. Fog::Compute.new(provider: “vsphere”, vsphere_rev: “5.5”, etc)

  • options<~Hash>:

    • ‘instance_uuid’<~String> - REQUIRED the instance uuid you would like to operate on

    • ‘command’<~String> REQUIRED the command to execute

    • ‘args’<~String> arguments to pass the command

    • ‘working_dir’<~String> path to the working directory

    • ‘user’<~String> REQUIRED the ssh username you would like to login as

    • ‘password’<~String> REQUIRED the ssh password for the user you would like to log in as

Raises:

  • (ArgumentError)


14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/fog/vsphere/requests/compute/vm_execute.rb', line 14

def vm_execute(options = {})
  raise ArgumentError, 'instance_uuid is a required parameter' unless options.key? 'instance_uuid'
  raise ArgumentError, 'command is a required parameter' unless options.key? 'command'
  raise ArgumentError, 'user is a required parameter' unless options.key? 'user'
  raise ArgumentError, 'password is a required parameter' unless options.key? 'password'

  search_filter = { :uuid => options['instance_uuid'], 'vmSearch' => true, 'instanceUuid' => true }
  vm_mob_ref = connection.searchIndex.FindAllByUuid(search_filter).first

  auth = RbVmomi::VIM::NamePasswordAuthentication(interactiveSession: false,
                                                  username: options['user'],
                                                  password: options['password'])

  spec = RbVmomi::VIM::GuestProgramSpec(programPath: options['command'],
                                        arguments: options['args'],
                                        workingDirectory: options['working_dir'])

  gom = connection.serviceContent.guestOperationsManager
  gom.processManager.StartProgramInGuest(vm: vm_mob_ref, auth: auth, spec: spec)
end

#vm_get_vnc(uuid) ⇒ Object

return a hash of VNC attributes required to view the console



22
23
24
25
26
27
28
29
30
# File 'lib/fog/vsphere/requests/compute/vm_config_vnc.rb', line 22

def vm_get_vnc(uuid)
  search_filter = { :uuid => uuid, 'vmSearch' => true, 'instanceUuid' => true }
  vm = connection.searchIndex.FindAllByUuid(search_filter).first
  Hash[vm.config.extraConfig.map do |config|
    if config.key =~ /^RemoteDisplay\.vnc\.(\w+)$/
      [Regexp.last_match(1).to_sym, config.value]
    end
  end.compact]
end

#vm_migrate(options = {}) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/fog/vsphere/requests/compute/vm_migrate.rb', line 5

def vm_migrate(options = {})
  # priority is the only required option, and it has a sane default option.
  priority = options['priority'].nil? ? 'defaultPriority' : options['priority']
  raise ArgumentError, 'instance_uuid is a required parameter' unless options.key? 'instance_uuid'

  # Find the VM Object
  search_filter = { :uuid => options['instance_uuid'], 'vmSearch' => true, 'instanceUuid' => true }
  vm_mob_ref = connection.searchIndex.FindAllByUuid(search_filter).first

  unless vm_mob_ref.is_a? RbVmomi::VIM::VirtualMachine
    raise Fog::Vsphere::Errors::NotFound,
          "Could not find VirtualMachine with instance uuid #{options['instance_uuid']}"
  end
  options['host'] = get_raw_host(options['host'], options['cluster'], options['datacenter']) if options['host']
  task_options = { pool: options['pool'], host: options['host'], state: options['state'] }
  if options['check']
    checker = connection.serviceContent.vmProvisioningChecker
    task = checker.CheckMigrate_Task(task_options.merge(vm: vm_mob_ref))
    task.wait_for_completion
    { 'error' => task.info.result[0].error, 'warning' => task.info.result[0].warning }
  else
    task = vm_mob_ref.MigrateVM_Task(task_options.merge(priority: priority.to_s))
    task.wait_for_completion
    { 'task_state' => task.info.state }
  end
end

#vm_power_off(options = {}) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/fog/vsphere/requests/compute/vm_power_off.rb', line 5

def vm_power_off(options = {})
  options = { 'force' => false }.merge(options)
  raise ArgumentError, 'instance_uuid is a required parameter' unless options.key? 'instance_uuid'

  search_filter = { :uuid => options['instance_uuid'], 'vmSearch' => true, 'instanceUuid' => true }
  vm_mob_ref = connection.searchIndex.FindAllByUuid(search_filter).first

  if options['force']
    task = vm_mob_ref.PowerOffVM_Task
    task.wait_for_completion
    { 'task_state' => task.info.result, 'power_off_type' => 'cut_power' }
  else
    vm_mob_ref.ShutdownGuest
    {
      'task_state'     => 'running',
      'power_off_type' => 'shutdown_guest'
    }
  end
end

#vm_power_on(options = {}) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
13
14
15
# File 'lib/fog/vsphere/requests/compute/vm_power_on.rb', line 5

def vm_power_on(options = {})
  raise ArgumentError, 'instance_uuid is a required parameter' unless options.key? 'instance_uuid'

  search_filter = { :uuid => options['instance_uuid'], 'vmSearch' => true, 'instanceUuid' => true }
  vm_mob_ref = connection.searchIndex.FindAllByUuid(search_filter).first

  task = vm_mob_ref.PowerOnVM_Task
  task.wait_for_completion
  # 'success', 'running', 'queued', 'error'
  { 'task_state' => task.info.state }
end

#vm_reboot(options = {}) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/fog/vsphere/requests/compute/vm_reboot.rb', line 5

def vm_reboot(options = {})
  options = { 'force' => false }.merge(options)
  raise ArgumentError, 'instance_uuid is a required parameter' unless options.key? 'instance_uuid'

  search_filter = { :uuid => options['instance_uuid'], 'vmSearch' => true, 'instanceUuid' => true }
  vm_mob_ref = connection.searchIndex.FindAllByUuid(search_filter).first

  if options['force']
    task = vm_mob_ref.ResetVM_Task
    task.wait_for_completion
    { 'task_state' => task.info.result, 'reboot_type' => 'reset_power' }
  else
    vm_mob_ref.RebootGuest
    { 'task_state' => 'running', 'reboot_type' => 'reboot_guest' }
  end
end

#vm_reconfig_cdrom(options = {}) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/fog/vsphere/requests/compute/vm_reconfig_cdrom.rb', line 5

def vm_reconfig_cdrom(options = {})
  raise ArgumentError, 'instance_uuid is a required parameter' unless options.key? 'instance_uuid'
  # Attach iso / disattach
  if options.key?('iso')
    raise ArgumentError, 'datastore is a required parameter' unless options.key? 'datastore'
    backing = RbVmomi::VIM::VirtualCdromIsoBackingInfo(
      fileName: "[#{options['datastore']}] #{options['iso']}"
    )
  else
    backing = RbVmomi::VIM::VirtualCdromRemoteAtapiBackingInfo(deviceName: '')
  end
  cdrom_obj = get_vm_ref(options['instance_uuid']).config.hardware.device.grep(RbVmomi::VIM::VirtualCdrom).first
  hardware_spec = {
    deviceChange: [{
      operation: :edit,
      device: RbVmomi::VIM::VirtualCdrom(
        backing: backing,
        key: cdrom_obj.key,
        controllerKey: cdrom_obj.controllerKey,
        connectable: RbVmomi::VIM::VirtualDeviceConnectInfo(
          startConnected: options['start_connected'] || false,
          connected: options['connected'] || false,
          allowGuestControl: options['allow_guest_control'] || true
        )
      )
    }]
  }
  vm_reconfig_hardware('instance_uuid' => options['instance_uuid'], 'hardware_spec' => hardware_spec)
end

#vm_reconfig_cpus(options = {}) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
# File 'lib/fog/vsphere/requests/compute/vm_reconfig_cpus.rb', line 5

def vm_reconfig_cpus(options = {})
  raise ArgumentError, 'cpus is a required parameter' unless options.key? 'cpus'
  raise ArgumentError, 'instance_uuid is a required parameter' unless options.key? 'instance_uuid'
  hardware_spec = { 'numCPUs' => options['cpus'], 'numCoresPerSocket' => options['corespersocket'] }
  vm_reconfig_hardware('instance_uuid' => options['instance_uuid'], 'hardware_spec' => hardware_spec)
end

#vm_reconfig_hardware(options = {}) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
# File 'lib/fog/vsphere/requests/compute/vm_reconfig_hardware.rb', line 5

def vm_reconfig_hardware(options = {})
  raise ArgumentError, 'hardware_spec is a required parameter' unless options.key? 'hardware_spec'
  raise ArgumentError, 'instance_uuid is a required parameter' unless options.key? 'instance_uuid'
  vm_mob_ref = get_vm_ref(options['instance_uuid'])
  task = vm_mob_ref.ReconfigVM_Task(spec: RbVmomi::VIM.VirtualMachineConfigSpec(options['hardware_spec']))
  task.wait_for_completion
  { 'task_state' => task.info.state }
end

#vm_reconfig_memory(options = {}) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
# File 'lib/fog/vsphere/requests/compute/vm_reconfig_memory.rb', line 5

def vm_reconfig_memory(options = {})
  raise ArgumentError, 'memory is a required parameter' unless options.key? 'memory'
  raise ArgumentError, 'instance_uuid is a required parameter' unless options.key? 'instance_uuid'
  hardware_spec = { 'memoryMB' => options['memory'] }
  vm_reconfig_hardware('instance_uuid' => options['instance_uuid'], 'hardware_spec' => hardware_spec)
end

#vm_reconfig_volumes(options = {}) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
13
14
15
# File 'lib/fog/vsphere/requests/compute/vm_reconfig_volumes.rb', line 5

def vm_reconfig_volumes(options = {})
  raise ArgumentError, 'instance_uuid is a required parameter' unless options.key? 'instance_uuid'
  raise ArgumentError, 'volumes is a required parameter' unless options.key? 'volumes'
  hardware_spec = {
    deviceChange: []
  }
  options['volumes'].each do |volume|
    hardware_spec[:deviceChange].push(create_disk(volume, :edit, filename: volume.filename))
  end
  vm_reconfig_hardware('instance_uuid' => options['instance_uuid'], 'hardware_spec' => hardware_spec)
end

#vm_relocate(options = {}) ⇒ Object

Relocates a VM to different host or datastore.

Parameters

  • options<~Hash>:

    • ‘instance_uuid’<~String> - REQUIRED VM to relocate

    • ‘host’<~String> - name of host which will run the VM.

    • ‘cluster’<~String> - name of cluster where host is.

      Only works with clusters within same datacenter as
      where vm is running. Defaults to vm's host's cluster.
      
    • ‘datacenter’<~String> - name of datacenter where host is.

      It must be same datacenter as where vm is running.
      Defaults to vm's datacenter.
      
    • ‘datastore’<~String> - name of datastore where VM will

      be located.
      
    • ‘pool’<~String> - name of pool which the VM should be

      attached.
      
    • ‘disks’<~Array> - disks to relocate. Each disk is a

      hash with diskId wich is key attribute of volume,
      and datastore to relocate to. diskBackingInfo can be provided,
      with type FlatVer2 or SeSparse
      Example: [{
        'diskId' => 2000,
        'datastore' => 'datastore_name',
        'diskBackingInfo' => {'type' => 'FlatVer2', ...}
      }]
      

Raises:

  • (ArgumentError)


30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/fog/vsphere/requests/compute/vm_relocate.rb', line 30

def vm_relocate(options = {})
  raise ArgumentError, 'instance_uuid is a required parameter' unless options.key? 'instance_uuid'

  # Find the VM Object
  search_filter = { :uuid => options['instance_uuid'], 'vmSearch' => true, 'instanceUuid' => true }
  vm_mob_ref = connection.searchIndex.FindAllByUuid(search_filter).first

  unless vm_mob_ref.is_a? RbVmomi::VIM::VirtualMachine
    raise Fog::Vsphere::Errors::NotFound,
          "Could not find VirtualMachine with instance uuid #{options['instance_uuid']}"
  end
  datacenter = options['datacenter'] || get_vm_datacenter(vm_mob_ref)
  cluster_name = options['cluster'] || get_vm_cluster(vm_mob_ref)

  options['host'] = get_raw_host(options['host'], cluster_name, datacenter) if options['host']
  options['datastore'] = get_raw_datastore(options['datastore'], datacenter) if options.key?('datastore')

  if options['disks']
    options['disks'] = options['disks'].map do |disk|
      disk['datastore'] = get_raw_datastore(disk['datastore'], datacenter)
      if disk['diskBackingInfo'] && disk['diskBackingInfo']['type']
        backing_type = "VirtualDisk#{disk['diskBackingInfo'].delete('type')}BackingInfo"
        disk['diskBackingInfo'] = RbVmomi::VIM.send(backing_type, disk['diskBackingInfo'])
      end
      RbVmomi::VIM::VirtualMachineRelocateSpecDiskLocator(disk)
    end
  end

  spec = RbVmomi::VIM::VirtualMachineRelocateSpec(
    datastore: options['datastore'],
    pool: options['pool'],
    host: options['host'],
    disk: options['disks']
  )
  task = vm_mob_ref.RelocateVM_Task(spec: spec, priority: options['priority'])
  task.wait_for_completion
  { 'task_state' => task.info.state }
end

#vm_remove_snapshot(vm_id, snapshot_id, remove_children = false) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
# File 'lib/fog/vsphere/requests/compute/vm_remove_snapshot.rb', line 5

def vm_remove_snapshot(vm_id, snapshot_id, remove_children = false)
  vm = servers.get(vm_id)
  snapshot = vm.snapshots.get(snapshot_id).mo_ref
  task = snapshot.RemoveSnapshot_Task(removeChildren: remove_children)

  task.wait_for_completion

  {
    'task_state' => task.info.state,
    'was_cancelled' => task.info.cancelled
  }
end

#vm_rename(options = {}) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
# File 'lib/fog/vsphere/requests/compute/vm_rename.rb', line 5

def vm_rename(options = {})
  raise ArgumentError, 'name is a required parameter' unless options.key? 'name'
  raise ArgumentError, 'instance_uuid is a required parameter' unless options.key? 'instance_uuid'
  vm_mob_ref = get_vm_ref(options['instance_uuid'])
  task = vm_mob_ref.Rename_Task(newName: options['name'])
  task.wait_for_completion
  { 'task_state' => task.info.state }
end

#vm_revert_snapshot(vm_id, snapshot_id) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
# File 'lib/fog/vsphere/requests/compute/vm_revert_snapshot.rb', line 5

def vm_revert_snapshot(vm_id, snapshot_id)
  vm = servers.get(vm_id)
  snapshot = vm.snapshots.get(snapshot_id).mo_ref
  task = snapshot.RevertToSnapshot_Task

  task.wait_for_completion

  {
    'task_state' => task.info.state,
    'was_cancelled' => task.info.cancelled
  }
end

#vm_suspend(options = {}) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
13
14
15
16
17
# File 'lib/fog/vsphere/requests/compute/vm_suspend.rb', line 5

def vm_suspend(options = {})
  raise(ArgumentError, 'instance_uuid is a required parameter') unless options.key?('instance_uuid')
  options = { 'force' => false }.merge(options)

  search_filter = { :uuid => options['instance_uuid'], 'vmSearch' => true, 'instanceUuid' => true }
  vm = connection.searchIndex.FindAllByUuid(search_filter).first

  if options['force']
    suspend_forcefully(vm)
  else
    suspend_gracefully(vm)
  end
end

#vm_take_snapshot(options = {}) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/fog/vsphere/requests/compute/vm_take_snapshot.rb', line 5

def vm_take_snapshot(options = {})
  raise ArgumentError, 'instance_uuid is a required parameter' unless options.key? 'instance_uuid'
  raise ArgumentError, 'name is a required parameter' unless options.key? 'name'
  defaults = {
    description: '',
    memory: true,
    quiesce: false
  }
  opts = options.clone
  defaults.each do |k, v|
    opts[k] = v unless opts.key?(k) || opts.key?(k.to_s)
  end
  vm = get_vm_ref(options['instance_uuid'])
  task = vm.CreateSnapshot_Task(opts)

  task.wait_for_completion

  {
    'task_state' => task.info.state,
    'was_cancelled' => task.info.cancelled
  }
end