class Fog::Compute::Vsphere::Real

The Real and Mock classes share the same method because #list_virtual_machines will be properly mocked for us

Public Class Methods

new(options={}) click to toggle source
# File lib/fog/vsphere/compute.rb, line 111
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_expected_pubkey_hash = options[:vsphere_expected_pubkey_hash]
  @vsphere_must_reauthenticate = false

  @connection = nil
  # This is a state variable to allow digest validation of the SSL cert
  bad_cert = false
  loop do
    begin
      @connection = RbVmomi::VIM.new :host => @vsphere_server,
                                     :port => @vsphere_port,
                                     :path => @vsphere_path,
                                     :ns   => @vsphere_ns,
                                     :rev  => @vsphere_rev,
                                     :ssl  => @vsphere_ssl,
                                     :insecure => bad_cert
      break
    rescue OpenSSL::SSL::SSLError
      raise if bad_cert
      bad_cert = true
    end
  end

  if bad_cert then
    validate_ssl_connection
  end

  # Negotiate the API revision
  if not options[:vsphere_rev]
    rev = @connection.serviceContent.about.apiVersion
    @connection.rev = [ rev, ENV['FOG_VSPHERE_REV'] || '4.1' ].min
  end

  @vsphere_is_vcenter = @connection.serviceContent.about.apiType == "VirtualCenter"
  @vsphere_rev = @connection.rev

  authenticate
end

Public Instance Methods

current_time() click to toggle source
# File lib/fog/vsphere/requests/compute/current_time.rb, line 6
def current_time
  current_time = @connection.serviceInstance.CurrentTime
  { 'current_time' => current_time }
end
datacenters() click to toggle source
# File lib/fog/vsphere/requests/compute/datacenters.rb, line 5
def datacenters
  @datacenters ||= datacenters_reload
  # Hide the values which are the RbVmomi instances
  @datacenters.keys
end
list_virtual_machines(options = {}) click to toggle source
# 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.
  if options['instance_uuid'] then
    list_all_virtual_machines_by_instance_uuid(options)
  elsif options['folder'] then
    list_all_virtual_machines_in_folder(options)
  else
    list_all_virtual_machines
  end
end
vm_clone(options = {}) click to toggle source
# File lib/fog/vsphere/requests/compute/vm_clone.rb, line 33
def vm_clone(options = {})
  # Option handling
  options = vm_clone_check_options(options)

  notfound = lambda { raise Fog::Compute::Vsphere::NotFound, "Could not find VM template" }

  # Find the template in the folder.  This is more efficient than
  # searching ALL VM's looking for the template.
  # Tap gets rid of the leading empty string and "Datacenters" element
  # and returns the array.
  path_elements = options['path'].split('/').tap { |ary| ary.shift 2 }
  # The DC name itself.
  template_dc = path_elements.shift
  # If the first path element contains "vm" this denotes the vmFolder
  # and needs to be shifted out
  path_elements.shift if path_elements[0] == 'vm'
  # The template name.  The remaining elements are the folders in the
  # datacenter.
  template_name = path_elements.pop
  # Make sure @datacenters is populated.  We need the instances from the Hash keys.
  self.datacenters
  # Get the datacenter managed object from the hash
  dc = @datacenters[template_dc]
  # Get the VM Folder (Group) efficiently
  vm_folder = dc.vmFolder
  # Walk the tree resetting the folder pointer as we go
  folder = path_elements.inject(vm_folder) do |current_folder, sub_folder_name|
    # JJM VIM::Folder#find appears to be quite efficient as it uses the
    # searchIndex It certainly appears to be faster than
    # VIM::Folder#inventory since that returns _all_ managed objects of
    # a certain type _and_ their properties.
    sub_folder = current_folder.find(sub_folder_name, RbVmomi::VIM::Folder)
    raise ArgumentError, "Could not descend into #{sub_folder_name}.  Please check your path." unless sub_folder
    sub_folder
  end

  # Now find the template itself using the efficient find method
  vm_mob_ref = folder.find(template_name, RbVmomi::VIM::VirtualMachine)

  # Now find _a_ resource pool of the template's host (REVISIT: We need
  # to support cloning into a specific RP)
  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
  relocation_spec=nil
  if ( options['linked_clone'] )
    # 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{|disk_backing|
              disk_backing.backing = disk_backing.backing.dup;
              disk_backing.backing.fileName = "[#{disk.backing.datastore.name}]";
              disk_backing.backing.parent = disk.backing
            }
          },
        ]
      }
      vm_mob_ref.ReconfigVM_Task(:spec => disk_spec).wait_for_completion
    end
    # Next, create a Relocation Spec instance
    relocation_spec = RbVmomi::VIM.VirtualMachineRelocateSpec(:pool => resource_pool,
                                                              :diskMoveType => :moveChildMostDiskBacking)
  else
    relocation_spec = RbVmomi::VIM.VirtualMachineRelocateSpec(:pool => resource_pool,
                                                              :transform => options['transform'] || 'sparse')
  end
  # And the clone specification
  clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec(:location => relocation_spec,
                                                    :powerOn  => options['power_on'] || true,
                                                    :template => false)
  task = vm_mob_ref.CloneVM_Task(:folder => vm_mob_ref.parent, :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['wait'] then
    # 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
    tries = 0
    new_vm = begin
      # Try and find the new VM (folder.find is quite efficient)
      folder.find(options['name'], RbVmomi::VIM::VirtualMachine) or raise Fog::Vsphere::Errors::NotFound
    rescue Fog::Vsphere::Errors::NotFound
      tries += 1
      if tries <= 10 then
        sleep 15
        retry
      end
      nil
    end
  end

  # Return hash
  {
    'vm_ref'        => new_vm ? new_vm._ref : nil,
    'vm_attributes' => new_vm ? convert_vm_mob_ref_to_attr_hash(new_vm) : {},
    'task_ref'      => task._ref
  }
end
vm_config_vnc(options = { }) click to toggle source
# 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.has_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_create(options = {}) click to toggle source
# File lib/fog/vsphere/requests/compute/vm_create.rb, line 29
def vm_create(options = {})
  # Option handling
  options = vm_create_check_options(options)
  path_elements = options['path'].split('/').tap { |ary| ary.shift 2 }
  dc_name = path_elements.shift
  vm_cfg = {
    :name                => options['name'],
    :guestId             => options['guest_id'] ? options['guest_id'] : 'otherGuest',
    :files               => { :vmPathName => "[#{options['datastore']}]" },
    :numCPUs             => options['num_cpus'] ? options['num_cpus'] : 1 ,
    :memoryMB            => options['memory'] ? options['memory'] : 512,
    :memoryHotAddEnabled => options['memory_hot_add_enabled'] ? options['memory_hot_add_enabled'] : 0,
    :cpuHotAddEnabled    => options['cpu_hot_add_enabled'] ? options['cpu_hot_add_enabled'] : 0,
    :deviceChange        => options['device_array'].class == Array ? options['device_array'] : nil,
    :extraConfig         => options['extra_config'].class == Array ? options['extra_config'] : nil,
  }
  self.datacenters
  dc = @datacenters[dc_name]
  vm_folder = dc.vmFolder
  folder = path_elements.inject(vm_folder) do |current_folder, sub_folder_name|
    sub_folder = current_folder.find(sub_folder_name, RbVmomi::VIM::Folder)
    raise ArgumentError, "Could not descend into #{sub_folder_name}.  Please check your path." unless sub_folder
    sub_folder
  end
  clusters = dc.hostFolder.children
  build_cluster=''
  clusters.each { |my_cluster|
    if "#{my_cluster.name}" == "#{options['cluster']}"
      build_cluster=my_cluster
    end
  }
  resource_pool = build_cluster.resourcePool
  task=folder.CreateVM_Task(:config => vm_cfg, :pool => resource_pool)
  if options['wait'] then
    new_vm = task.wait_for_completion
  else
    tries = 0
    new_vm = begin
      folder.find(options['name'], RbVmomi::VIM::VirtualMachine) or raise Fog::Vsphere::Errors::NotFound
    rescue Fog::Vsphere::Errors::NotFound
      tries += 1
      if tries <= 10 then
        sleep 15
        retry
      end
        nil
    end
  end
  {
    'vm_ref'        => new_vm ? new_vm._ref : nil,
    'vm_attributes' => new_vm ? convert_vm_mob_ref_to_attr_hash(new_vm) : {},
    'task_ref'      => task._ref
  }
end
vm_destroy(options = {}) click to toggle source
# File lib/fog/vsphere/requests/compute/vm_destroy.rb, line 6
def vm_destroy(options = {})
  raise ArgumentError, "instance_uuid is a required parameter" unless options.has_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.kind_of? RbVmomi::VIM::VirtualMachine
    raise Fog::Vsphere::Errors::NotFound,
      "Could not find VirtualMachine with instance uuid #{options['instance_uuid']}"
  end
  task = vm_mob_ref.Destroy_Task
  task.wait_for_completion
  { 'task_state' => task.info.state }
end
vm_get_vnc(uuid) click to toggle source

return a hash of VNC attributes required to view the console

# 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 =~ %r^RemoteDisplay\.vnc\.(\w+)$/
      [$1.to_sym, config.value]
    end
  end.compact]
end
vm_migrate(options = {}) click to toggle source
# File lib/fog/vsphere/requests/compute/vm_migrate.rb, line 6
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.has_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.kind_of? RbVmomi::VIM::VirtualMachine
    raise Fog::Vsphere::Errors::NotFound,
      "Could not find VirtualMachine with instance uuid #{options['instance_uuid']}"
  end
  task = vm_mob_ref.MigrateVM_Task(:pool => options['pool'], :host => options['host'], :priority => "#{priority}", :state => options['state'] )
  task.wait_for_completion
  { 'task_state' => task.info.state }
end
vm_power_off(options = {}) click to toggle source
# File lib/fog/vsphere/requests/compute/vm_power_off.rb, line 6
def vm_power_off(options = {})
  options = { 'force' => false }.merge(options)
  raise ArgumentError, "instance_uuid is a required parameter" unless options.has_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'] then
    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 = {}) click to toggle source
# File lib/fog/vsphere/requests/compute/vm_power_on.rb, line 6
def vm_power_on(options = {})
  raise ArgumentError, "instance_uuid is a required parameter" unless options.has_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 = {}) click to toggle source
# File lib/fog/vsphere/requests/compute/vm_reboot.rb, line 6
def vm_reboot(options = {})
  options = { 'force' => false }.merge(options)
  raise ArgumentError, "instance_uuid is a required parameter" unless options.has_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'] then
    task = vm_mob_ref.ResetVM_Task
    task.wait_for_completion
    { 'task_state' => task.info.result, 'reboot_type' => 'reset_power' }
  else
    vm_mob_ref.ShutdownGuest
    { 'task_state' => "running", 'reboot_type' => 'reboot_guest' }
  end
end
vm_reconfig_cpus(options = {}) click to toggle source
# 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.has_key? 'cpus'
  raise ArgumentError, "instance_uuid is a required parameter" unless options.has_key? 'instance_uuid'
  hardware_spec={'numCPUs' => options['cpus']}
  vm_reconfig_hardware('instance_uuid' => options['instance_uuid'], 'hardware_spec' => hardware_spec )
end
vm_reconfig_hardware(options = {}) click to toggle source
# 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.has_key? 'hardware_spec'
  raise ArgumentError, "instance_uuid is a required parameter" unless options.has_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 => RbVmomi::VIM.VirtualMachineConfigSpec(options['hardware_spec']))
  task.wait_for_completion
   { 'task_state' => task.info.state }
end
vm_reconfig_memory(options = {}) click to toggle source
# 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.has_key? 'memory'
  raise ArgumentError, "instance_uuid is a required parameter" unless options.has_key? 'instance_uuid'
  hardware_spec={'memoryMB' => options['memory']}
  vm_reconfig_hardware('instance_uuid' => options['instance_uuid'], 'hardware_spec' => hardware_spec )
end