2011-08-30 15:25:28 -04:00
require 'digest/sha2'
2011-08-29 23:04:04 -04:00
module Fog
module Compute
class Vsphere < Fog :: Service
requires :vsphere_username , :vsphere_password , :vsphere_server
recognizes :vsphere_port , :vsphere_path , :vsphere_ns
2011-08-30 15:25:28 -04:00
recognizes :vsphere_rev , :vsphere_ssl , :vsphere_expected_pubkey_hash
2011-08-29 23:04:04 -04:00
2011-09-01 18:10:57 -04:00
model_path 'fog/vsphere/models/compute'
model :server
collection :servers
2011-08-30 16:44:31 -04:00
request_path 'fog/vsphere/requests/compute'
request :current_time
2011-09-10 16:27:52 -04:00
request :find_vm_by_ref
2011-09-01 18:10:57 -04:00
request :list_virtual_machines
2011-09-02 14:04:24 -04:00
request :vm_power_off
request :vm_power_on
request :vm_reboot
2011-09-06 19:46:42 -04:00
request :vm_clone
2012-01-11 21:35:55 -05:00
request :vm_create
2011-09-06 19:41:37 -04:00
request :vm_destroy
2012-02-24 23:47:41 -05:00
request :vm_migrate
2011-11-10 19:01:22 -05:00
request :datacenters
2012-01-31 14:43:45 -05:00
request :vm_reconfig_hardware
request :vm_reconfig_memory
request :vm_reconfig_cpus
2012-03-28 06:34:36 -04:00
request :vm_config_vnc
2011-09-10 16:27:52 -04:00
module Shared
attr_reader :vsphere_is_vcenter
attr_reader :vsphere_rev
2011-09-12 18:50:49 -04:00
attr_reader :vsphere_server
attr_reader :vsphere_username
2011-09-10 16:27:52 -04:00
2011-10-18 00:46:30 -04:00
ATTR_TO_PROP = {
:id = > 'config.instanceUuid' ,
:name = > 'name' ,
:uuid = > 'config.uuid' ,
:instance_uuid = > 'config.instanceUuid' ,
:hostname = > 'summary.guest.hostName' ,
:operatingsystem = > 'summary.guest.guestFullName' ,
:ipaddress = > 'guest.ipAddress' ,
:power_state = > 'runtime.powerState' ,
:connection_state = > 'runtime.connectionState' ,
2011-11-07 07:08:54 -05:00
:hypervisor = > 'runtime.host' ,
2011-10-18 00:46:30 -04:00
:tools_state = > 'guest.toolsStatus' ,
:tools_version = > 'guest.toolsVersionStatus' ,
:is_a_template = > 'config.template' ,
2012-03-28 04:20:27 -04:00
:memory_mb = > 'config.hardware.memoryMB' ,
:cpus = > 'config.hardware.numCPU' ,
2011-10-18 00:46:30 -04:00
}
2011-09-10 16:27:52 -04:00
# Utility method to convert a VMware managed object into an attribute hash.
# This should only really be necessary for the real class.
# This method is expected to be called by the request methods
# in order to massage VMware Managed Object References into Attribute Hashes.
def convert_vm_mob_ref_to_attr_hash ( vm_mob_ref )
return nil unless vm_mob_ref
2011-10-18 00:46:30 -04:00
props = vm_mob_ref . collect! * ATTR_TO_PROP . values . uniq
2011-11-07 07:08:54 -05:00
# NOTE: Object.tap is in 1.8.7 and later.
# Here we create the hash object that this method returns, but first we need
# to add a few more attributes that require additional calls to the vSphere
# API. The hypervisor name and mac_addresses attributes may not be available
# so we need catch any exceptions thrown during lookup and set them to nil.
#
2012-03-28 04:20:27 -04:00
# The use of the "tap" method here is a convenience, it allows us to update the
# hash object without explicitly returning the hash at the end of the method.
2011-10-18 00:46:30 -04:00
Hash [ ATTR_TO_PROP . map { | k , v | [ k . to_s , props [ v ] ] } ] . tap do | attrs |
attrs [ 'id' ] || = vm_mob_ref . _ref
attrs [ 'mo_ref' ] = vm_mob_ref . _ref
2011-11-07 07:08:54 -05:00
# The name method "magically" appears after a VM is ready and
# finished cloning.
if attrs [ 'hypervisor' ] . kind_of? ( RbVmomi :: VIM :: HostSystem ) then
# If it's not ready, set the hypervisor to nil
attrs [ 'hypervisor' ] = attrs [ 'hypervisor' ] . name rescue nil
end
# This inline rescue catches any standard error. While a VM is
# cloning, a call to the macs method will throw and NoMethodError
attrs [ 'mac_addresses' ] = vm_mob_ref . macs rescue nil
2011-10-28 10:10:37 -04:00
attrs [ 'path' ] = get_folder_path ( vm_mob_ref . parent )
2011-09-10 16:27:52 -04:00
end
end
end
2011-08-30 16:44:31 -04:00
2011-08-29 23:04:04 -04:00
class Mock
2011-09-10 16:27:52 -04:00
include Shared
2011-08-29 23:04:04 -04:00
def initialize ( options = { } )
2011-11-08 00:47:27 -05:00
require 'rbvmomi'
2011-08-30 17:55:21 -04:00
@vsphere_username = options [ :vsphere_username ]
2011-09-10 16:27:52 -04:00
@vsphere_password = 'REDACTED'
2011-08-30 17:55:21 -04:00
@vsphere_server = options [ :vsphere_server ]
@vsphere_expected_pubkey_hash = options [ :vsphere_expected_pubkey_hash ]
2011-09-10 16:27:52 -04:00
@vsphere_is_vcenter = true
@vsphere_rev = '4.0'
2011-08-29 23:04:04 -04:00
end
end
class Real
2011-09-10 16:27:52 -04:00
include Shared
2011-08-30 15:25:28 -04:00
2011-08-29 23:04:04 -04:00
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
2011-08-30 15:25:28 -04:00
@vsphere_expected_pubkey_hash = options [ :vsphere_expected_pubkey_hash ]
2011-08-29 23:04:04 -04:00
@vsphere_must_reauthenticate = false
2011-08-30 15:25:28 -04:00
@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
2011-08-29 23:04:04 -04:00
# 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 "
2011-09-12 18:50:49 -04:00
@vsphere_rev = @connection . rev
2011-08-29 23:04:04 -04:00
authenticate
end
private
def authenticate
begin
@connection . serviceContent . sessionManager . Login :userName = > @vsphere_username ,
:password = > @vsphere_password
rescue RbVmomi :: VIM :: InvalidLogin = > e
raise Fog :: Vsphere :: Errors :: ServiceError , e . message
end
end
2011-08-30 15:25:28 -04:00
# Verify a SSL certificate based on the hashed public key
def validate_ssl_connection
pubkey = @connection . http . peer_cert . public_key
pubkey_hash = Digest :: SHA2 . hexdigest ( pubkey . to_s )
expected_pubkey_hash = @vsphere_expected_pubkey_hash
if pubkey_hash != expected_pubkey_hash then
raise Fog :: Vsphere :: Errors :: SecurityError , " The remote system presented a public key with hash #{ pubkey_hash } but we're expecting a hash of #{ expected_pubkey_hash || '<unset>' } . If you are sure the remote system is authentic set vsphere_expected_pubkey_hash: <the hash printed in this message> in ~/.fog "
end
end
2011-08-29 23:04:04 -04:00
end
end
end
end