1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-01-27 14:03:40 +03:00

Update vendorized rbvmomi to version 1.8.2

This commit is contained in:
Javi Fontan 2016-03-10 17:40:31 +01:00
parent 8474dd89a5
commit 1fb5f9aeff
22 changed files with 408 additions and 140 deletions

View File

@ -1,5 +1,5 @@
require 'rake/testtask'
require 'rake/rdoctask'
require 'rdoc/task'
require 'yard'
begin

View File

@ -1 +1 @@
1.6.0
1.8.2

View File

@ -185,7 +185,9 @@ class ManagedObject < ObjectWithMethods
:objectSet => [{ :obj => self }],
}])[0]
if ret.propSet.empty?
if !ret
return nil
elsif ret.propSet.empty?
return nil if ret.missingSet.empty?
raise ret.missingSet[0].fault
else
@ -217,7 +219,7 @@ class ManagedObject < ObjectWithMethods
def == x
out = (x.class == self.class && x._ref == @ref)
out = (out && x._connection.instanceUuid == self._connection.instanceUuid)
out = (x._connection.instanceUuid == self._connection.instanceUuid) if out && x._connection.host
out
end

View File

@ -115,27 +115,29 @@ class Connection < TrivialSoap
# hic sunt dracones
def obj2xml xml, name, type, is_array, o, attrs={}
expected = type(type)
fail "expected array, got #{o.class.wsdl_name}" if is_array and not (o.is_a? Array or (o.is_a? Hash and expected == BasicTypes::KeyValue))
fail "expected array for '#{name}', got #{o.class.wsdl_name}" if is_array and not (o.is_a? Array or (o.is_a? Hash and expected == BasicTypes::KeyValue))
case o
when Array, BasicTypes::KeyValue
if o.is_a? BasicTypes::KeyValue and expected != BasicTypes::KeyValue
fail "expected #{expected.wsdl_name}, got KeyValue"
fail "expected #{expected.wsdl_name} for '#{name}', got KeyValue"
elsif expected == BasicTypes::KeyValue and not is_array
xml.tag! name, attrs do
xml.tag! 'key', o[0].to_s
xml.tag! 'value', o[1].to_s
end
else
fail "expected #{expected.wsdl_name}, got array" unless is_array
fail "expected #{expected.wsdl_name} for '#{name}', got array" unless is_array
o.each do |e|
obj2xml xml, name, expected.wsdl_name, false, e, attrs
end
end
when BasicTypes::ManagedObject
fail "expected #{expected.wsdl_name}, got #{o.class.wsdl_name} for field #{name.inspect}" if expected and not expected >= o.class and not expected == BasicTypes::AnyType
fail "expected #{expected.wsdl_name} for '#{name}', got #{o.class.wsdl_name} for field #{name.inspect}" if expected and not expected >= o.class and not expected == BasicTypes::AnyType
xml.tag! name, o._ref, :type => o.class.wsdl_name
when BasicTypes::DataObject
fail "expected #{expected.wsdl_name}, got #{o.class.wsdl_name} for field #{name.inspect}" if expected and not expected >= o.class and not expected == BasicTypes::AnyType
if expected and not expected >= o.class and not expected == BasicTypes::AnyType
fail "expected #{expected.wsdl_name} for '#{name}', got #{o.class.wsdl_name} for field #{name.inspect}"
end
xml.tag! name, attrs.merge("xsi:type" => o.class.wsdl_name) do
o.class.full_props_desc.each do |desc|
if o.props.member? desc['name'].to_sym
@ -151,11 +153,11 @@ class Connection < TrivialSoap
if expected == BasicTypes::KeyValue and is_array
obj2xml xml, name, type, is_array, o.to_a, attrs
else
fail "expected #{expected.wsdl_name}, got a hash" unless expected <= BasicTypes::DataObject
fail "expected #{expected.wsdl_name} for '#{name}', got a hash" unless expected <= BasicTypes::DataObject
obj2xml xml, name, type, false, expected.new(o), attrs
end
when true, false
fail "expected #{expected.wsdl_name}, got a boolean" unless [BasicTypes::Boolean, BasicTypes::AnyType].member? expected
fail "expected #{expected.wsdl_name} for '#{name}', got a boolean" unless [BasicTypes::Boolean, BasicTypes::AnyType].member? expected
attrs['xsi:type'] = 'xsd:boolean' if expected == BasicTypes::AnyType
xml.tag! name, (o ? '1' : '0'), attrs
when Symbol, String
@ -181,7 +183,7 @@ class Connection < TrivialSoap
when BasicTypes::Int
attrs['xsi:type'] = 'xsd:int'
xml.tag! name, o.to_s, attrs
else fail "unexpected object class #{o.class}"
else fail "unexpected object class #{o.class} for '#{name}'"
end
xml
rescue

View File

@ -43,6 +43,13 @@ class NewDeserializer
def deserialize node, type=nil
type_attr = node['type']
# Work around for 1.5.x which doesn't populate node['type']
# XXX what changed
if node.attributes['type'] and not type_attr
type_attr = node.attributes['type'].value
end
type = type_attr if type_attr
if action = BUILTIN_TYPE_ACTIONS[type]
@ -64,15 +71,18 @@ class NewDeserializer
else fail
end
else
if type =~ /:/
type = type.split(":", 2)[1]
end
if type =~ /^ArrayOf/
type = DEMANGLED_ARRAY_TYPES[$'] || $'
return node.children.select(&:element?).map { |c| deserialize c, type }
end
if type =~ /:/
type = type.split(":", 2)[1]
end
klass = @loader.get(type) or fail "no such type #{type}"
klass = @loader.get(type) or fail "no such type '#{type}'"
case klass.kind
when :data
traverse_data node, klass
@ -229,7 +239,7 @@ class OldDeserializer
end
end
if ENV['RBVMOMI_NEW_DESERIALIZER'] == '1'
if ENV['RBVMOMI_NEW_DESERIALIZER'] == '1' || true # Always use new one now
Deserializer = NewDeserializer
else
Deserializer = OldDeserializer

View File

@ -49,9 +49,9 @@ class PBM < Connection
@serviceInstance ||= VIM::PbmServiceInstance self, 'ServiceInstance'
end
# Alias to serviceInstance.RetrieveServiceContent
# Alias to serviceInstance.PbmRetrieveServiceContent
def serviceContent
@serviceContent ||= serviceInstance.RetrieveServiceContent
@serviceContent ||= serviceInstance.PbmRetrieveServiceContent
end
# @private

View File

@ -0,0 +1,61 @@
# Copyright (c) 2013 VMware, Inc. All Rights Reserved.
require 'rbvmomi'
module RbVmomi
# A connection to one vSphere SMS endpoint.
# @see #serviceInstance
class SMS < Connection
# Connect to a vSphere SMS endpoint
#
# @param [VIM] Connection to main vSphere API endpoint
# @param [Hash] opts The options hash.
# @option opts [String] :host Host to connect to.
# @option opts [Numeric] :port (443) Port to connect to.
# @option opts [Boolean] :ssl (true) Whether to use SSL.
# @option opts [Boolean] :insecure (false) If true, ignore SSL certificate errors.
# @option opts [String] :path (/sms/sdk) SDK endpoint path.
# @option opts [Boolean] :debug (false) If true, print SOAP traffic to stderr.
def self.connect vim, opts = {}
fail unless opts.is_a? Hash
opts[:host] = vim.host
opts[:ssl] = true unless opts.member? :ssl or opts[:"no-ssl"]
opts[:insecure] ||= true
opts[:port] ||= (opts[:ssl] ? 443 : 80)
opts[:path] ||= '/sms/sdk'
opts[:ns] ||= 'urn:sms'
rev_given = opts[:rev] != nil
opts[:rev] = '4.0' unless rev_given
opts[:debug] = (!ENV['RBVMOMI_DEBUG'].empty? rescue false) unless opts.member? :debug
new(opts).tap do |sms|
sms.vcSessionCookie = vim.cookie.split('"')[1]
end
end
def vcSessionCookie= cookie
@vcSessionCookie = cookie
end
def rev= x
super
@serviceContent = nil
end
# Return the ServiceInstance
#
# The ServiceInstance is the root of the vSphere inventory.
def serviceInstance
@serviceInstance ||= VIM::SmsServiceInstance self, 'ServiceInstance'
end
# @private
def pretty_print pp
pp.text "SMS(#{@opts[:host]})"
end
add_extension_dir File.join(File.dirname(__FILE__), "sms")
load_vmodl(ENV['VMODL'] || File.join(File.dirname(__FILE__), "../../vmodl.db"))
end
end

View File

@ -0,0 +1,7 @@
class RbVmomi::SMS::SmsStorageManager
def RegisterProvider_Task2 providerSpec
self.RegisterProvider_Task providerSpec
end
end

View File

@ -14,7 +14,7 @@ class RbVmomi::TrivialSoap
@opts = opts
return unless @opts[:host] # for testcases
@debug = @opts[:debug]
@cookie = nil
@cookie = @opts[:cookie]
@lock = Mutex.new
@http = nil
restart_http
@ -36,7 +36,6 @@ class RbVmomi::TrivialSoap
puts ex.backtrace.join("\n")
end
@http = Net::HTTP.new(@opts[:host], @opts[:port], @opts[:proxyHost], @opts[:proxyPort])
if @opts[:ssl]
require 'net/https'
@http.use_ssl = true
@ -45,10 +44,6 @@ class RbVmomi::TrivialSoap
else
@http.verify_mode = OpenSSL::SSL::VERIFY_PEER
end
@http.ssl_version = :TLSv1
@http.cert = OpenSSL::X509::Certificate.new(@opts[:cert]) if @opts[:cert]
@http.key = OpenSSL::PKey::RSA.new(@opts[:key]) if @opts[:key]
end

View File

@ -52,7 +52,7 @@ class TypeLoader
end
def get name
fail unless name.is_a? String
fail "name '#{name}' is #{name.class} expecting String" unless name.is_a? String
first_char = name[0].chr
if first_char.downcase == first_char

View File

@ -41,6 +41,8 @@
# computer (cluster), resource pool, vm_folder and datastore. Currently once
# computed, a new updated placement can't be generated.
class AdmissionControlledResourceScheduler
attr_reader :rp
def initialize vim, opts = {}
@vim = vim
@ -330,6 +332,10 @@ class AdmissionControlledResourceScheduler
# datastore without much intelligence, as long as it passes admission control.
# @return [VIM::Datastore] Chosen datastore
def datastore placementHint = nil
if @datastore
return @datastore
end
pod_datastores = pick_computer.datastore & datastores
eligible = pod_datastores.select do |ds|

View File

@ -102,6 +102,13 @@ class CachedOvfDeployer
# simplicity this function assumes we need to read the OVF file
# ourselves to know the names, and we map all of them to the same
# VIM::Network.
# If we're handling a file:// URI we need to strip the scheme as open-uri
# can't handle them.
if URI(ovf_url).scheme == "file" && URI(ovf_url).host.nil?
ovf_url = URI(ovf_url).path
end
ovf = open(ovf_url, 'r'){|io| Nokogiri::XML(io.read)}
ovf.remove_namespaces!
networks = ovf.xpath('//NetworkSection/Network').map{|x| x['name']}
@ -178,11 +185,10 @@ class CachedOvfDeployer
# prepare it for (linked) cloning and mark it as a template to signal
# we are done.
if !wait_for_template
vm.add_delta_disk_layer_on_all_disks
if opts[:config]
# XXX: Should we add a version that does retries?
vm.ReconfigVM_Task(:spec => opts[:config]).wait_for_completion
end
config = opts[:config] || {}
config = vm.update_spec_add_delta_disk_layer_on_all_disks(config)
# XXX: Should we add a version that does retries?
vm.ReconfigVM_Task(:spec => config).wait_for_completion
vm.MarkAsTemplate
end
end
@ -207,7 +213,7 @@ class CachedOvfDeployer
# or nil
def lookup_template template_name
template_path = "#{template_name}-#{@computer.name}"
template = @template_folder.traverse(template_path, VIM::VirtualMachine)
template = @template_folder.traverse(template_path, RbVmomi::VIM::VirtualMachine)
if template
config = template.config
is_template = config && config.template

View File

@ -93,7 +93,8 @@ class PerfAggregator
RbVmomi::VIM.SelectionSpec(:name => 'tsFolder'),
RbVmomi::VIM.SelectionSpec(:name => 'tsDatacenterVmFolder'),
RbVmomi::VIM.SelectionSpec(:name => 'tsDatacenterHostFolder'),
RbVmomi::VIM.SelectionSpec(:name => 'tsCluster'),
RbVmomi::VIM.SelectionSpec(:name => 'tsClusterRP'),
RbVmomi::VIM.SelectionSpec(:name => 'tsClusterHost'),
]
),
RbVmomi::VIM.TraversalSpec(
@ -115,7 +116,7 @@ class PerfAggregator
]
),
RbVmomi::VIM.TraversalSpec(
:name => 'tsCluster',
:name => 'tsClusterRP',
:type => 'ClusterComputeResource',
:path => 'resourcePool',
:skip => false,
@ -123,6 +124,13 @@ class PerfAggregator
RbVmomi::VIM.SelectionSpec(:name => 'tsRP'),
]
),
RbVmomi::VIM.TraversalSpec(
:name => 'tsClusterHost',
:type => 'ClusterComputeResource',
:path => 'host',
:skip => false,
:selectSet => []
),
RbVmomi::VIM.TraversalSpec(
:name => 'tsRP',
:type => 'ResourcePool',
@ -141,6 +149,7 @@ class PerfAggregator
:pathSet => ['name', 'parent', 'summary.effectiveCpu', 'summary.effectiveMemory']
},
{ :type => 'ResourcePool', :pathSet => ['name', 'parent'] },
{ :type => 'HostSystem', :pathSet => ['name', 'parent', 'runtime.connectionState'] },
{ :type => 'VirtualMachine', :pathSet => vm_prop_names },
]
)
@ -316,9 +325,18 @@ class PerfAggregator
'virtualDisk.totalWriteLatency' => :avg_ignore_zero,
}
end
host_perf_metrics = opts[:host_perf_metrics]
if !host_perf_metrics
host_perf_metrics = {
'cpu.usage' => :avg,
'mem.usage' => :avg,
}
end
vms_props, inventory = all_inventory_flat root_folder, prop_names
vms = vms_props.keys
hosts_props = inventory.select{|k, v| k.is_a?(VIM::HostSystem)}
conn = root_folder._connection
sc = conn.serviceContent
@ -349,8 +367,31 @@ class PerfAggregator
end
raise
end
connected_hosts = hosts_props.select do |k,v|
v['runtime.connectionState'] != "disconnected"
end
if connected_hosts.length > 0
hosts_stats = pm.retrieve_stats(
connected_hosts.keys, host_perf_metrics.keys,
:max_samples => 3
)
end
hosts_props.each do |host, props|
if !connected_hosts[host]
next
end
stats = hosts_stats[host] || {}
stats = stats[:metrics] || {}
stats = _aggregate_metrics [stats], host_perf_metrics
props.merge!(stats)
end
vms_props.each do |vm, props|
if !connected_vms.member?(vm)
next
end
props['num.vm'] = 1
powered_on = (props['runtime.powerState'] == 'poweredOn')
props['num.poweredonvm'] = powered_on ? 1 : 0
@ -392,25 +433,35 @@ class PerfAggregator
props['vc_uuid'] = vc_uuid
end
[vms_props, inventory]
[vms_props, inventory, hosts_props]
end
def collect_info_on_all_vms root_folders, opts = {}
log "Fetching information from all VCs ..."
vms_props = {}
hosts_props = {}
inventory = {}
lock = Mutex.new
root_folders.map do |root_folder|
Thread.new do
single_vms_props, single_inventory =
_collect_info_on_all_vms_single(root_folder, opts)
lock.synchronize do
vms_props.merge!(single_vms_props)
if inventory['root']
single_inventory['root']['children'] += inventory['root']['children']
begin
single_vms_props, single_inventory, single_hosts_props =
_collect_info_on_all_vms_single(root_folder, opts)
lock.synchronize do
vms_props.merge!(single_vms_props)
if inventory['root']
single_inventory['root']['children'] += inventory['root']['children']
end
inventory.merge!(single_inventory)
hosts_props.merge!(single_hosts_props)
end
inventory.merge!(single_inventory)
rescue Exception => ex
log "#{ex.class}: #{ex.message}"
ex.backtrace.each do |line|
log line
end
raise
end
end
end.each{|t| t.join}
@ -418,6 +469,7 @@ class PerfAggregator
log "Make data marshal friendly ..."
inventory = _make_marshal_friendly(inventory)
vms_props = _make_marshal_friendly(vms_props)
hosts_props = _make_marshal_friendly(hosts_props)
log "Perform external post processing ..."
if @vm_processing_callback
@ -442,7 +494,11 @@ class PerfAggregator
@inventory = inventory
@vms_props = vms_props
nil
{
'inventory' => inventory,
'vms_props' => vms_props,
'hosts_props' => hosts_props,
}
end
def _make_marshal_friendly hash

View File

@ -13,6 +13,7 @@ class VIM < Connection
# @option opts [Numeric] :port (443) Port to connect to.
# @option opts [Boolean] :ssl (true) Whether to use SSL.
# @option opts [Boolean] :insecure (false) If true, ignore SSL certificate errors.
# @option opts [String] :cookie If set, use cookie to connect instead of user/password
# @option opts [String] :user (root) Username.
# @option opts [String] :password Password.
# @option opts [String] :path (/sdk) SDK endpoint path.
@ -20,6 +21,7 @@ class VIM < Connection
def self.connect opts
fail unless opts.is_a? Hash
fail "host option required" unless opts[:host]
opts[:cookie] ||= nil
opts[:user] ||= 'root'
opts[:password] ||= ''
opts[:ssl] = true unless opts.member? :ssl or opts[:"no-ssl"]
@ -32,10 +34,12 @@ class VIM < Connection
opts[:debug] = (!ENV['RBVMOMI_DEBUG'].empty? rescue false) unless opts.member? :debug
new(opts).tap do |vim|
vim.serviceContent.sessionManager.Login :userName => opts[:user], :password => opts[:password]
unless opts[:cookie]
vim.serviceContent.sessionManager.Login :userName => opts[:user], :password => opts[:password]
end
unless rev_given
rev = vim.serviceContent.about.apiVersion
vim.rev = [rev, '5.0'].min
vim.rev = [rev, '5.5'].min
end
end
end
@ -45,7 +49,7 @@ class VIM < Connection
self.cookie = nil
super
end
def rev= x
super
@serviceContent = nil
@ -85,11 +89,36 @@ class VIM < Connection
def pretty_print pp
pp.text "VIM(#{@opts[:host]})"
end
def instanceUuid
serviceContent.about.instanceUuid
end
def get_log_lines logKey, lines=5, start=nil, host=nil
diagMgr = self.serviceContent.diagnosticManager
if !start
log = diagMgr.BrowseDiagnosticLog(:host => host, :key => logKey, :start => 999999999)
lineEnd = log.lineEnd
start = lineEnd - lines
end
start = start < 0 ? 0 : start
log = diagMgr.BrowseDiagnosticLog(:host => host, :key => logKey, :start => start)
if log.lineText.size > 0
[log.lineText.slice(-lines, log.lineText.size), log.lineEnd]
else
[log.lineText, log.lineEnd]
end
end
def get_log_keys host=nil
diagMgr = self.serviceContent.diagnosticManager
keys = []
diagMgr.QueryDescriptions(:host => host).each do |desc|
keys << "#{desc.key}"
end
keys
end
add_extension_dir File.join(File.dirname(__FILE__), "vim")
(ENV['RBVMOMI_VIM_EXTENSION_PATH']||'').split(':').each { |dir| add_extension_dir dir }

View File

@ -14,3 +14,4 @@ class RbVmomi::VIM::Datacenter
vmFolder.traverse path, RbVmomi::VIM::VirtualMachine
end
end

View File

@ -35,61 +35,6 @@ class RbVmomi::VIM::Datastore
fail "download failed" unless $?.success?
end
# Download a file from this datastore.
# @param remote_path [String] Source path on the datastore.
# @param local_path [String] Destination path on the local machine.
# @return [void]
def download_to_stdout remote_path
url = "http#{_connection.http.use_ssl? ? 's' : ''}://#{_connection.http.address}:#{_connection.http.port}#{mkuripath(remote_path)}"
pid = spawn CURLBIN, "-k", '--noproxy', '*', '-f',
"-b", _connection.cookie,
url
Process.waitpid(pid, 0)
fail "download failed" unless $?.success?
end
def is_descriptor? remote_path
url = "http#{_connection.http.use_ssl? ? 's' : ''}://#{_connection.http.address}:#{_connection.http.port}#{mkuripath(remote_path)}"
rout, wout = IO.pipe
pid = spawn CURLBIN, "-I", "-k", '--noproxy', '*', '-f',
"-b", _connection.cookie,
url,
:out => wout,
:err => '/dev/null'
Process.waitpid(pid, 0)
fail "read image header failed" unless $?.success?
wout.close
size = rout.readlines.select{|l| l.start_with?("Content-Length")}[0].sub("Content-Length: ","")
rout.close
size.chomp.to_i < 4096 # If <4k, then is a descriptor
end
def get_text_file remote_path
url = "http#{_connection.http.use_ssl? ? 's' : ''}://#{_connection.http.address}:#{_connection.http.port}#{mkuripath(remote_path)}"
rout, wout = IO.pipe
pid = spawn CURLBIN, "-k", '--noproxy', '*', '-f',
"-b", _connection.cookie,
url,
:out => wout,
:err => '/dev/null'
Process.waitpid(pid, 0)
fail "get text file failed" unless $?.success?
wout.close
output = rout.readlines
rout.close
return output
end
# Upload a file to this datastore.
# @param remote_path [String] Destination path on the datastore.
# @param local_path [String] Source path on the local machine.

View File

@ -53,6 +53,16 @@ class RbVmomi::VIM::Folder
x if x.is_a? type
end
# Retrieve a managed entity by inventory path.
# @param path [String] A path of the form "My Folder/My Datacenter/vm/Discovered VM/VM1"
# @return [VIM::ManagedEntity]
def findByInventoryPath path
propSpecs = {
:entity => self, :inventoryPath => path
}
x = _connection.searchIndex.FindByInventoryPath(propSpecs)
end
# Alias to <tt>traverse path, type, true</tt>
# @see #traverse
def traverse! path, type=Object

View File

@ -35,7 +35,12 @@ class RbVmomi::VIM::ManagedObject
:type => self.class.wsdl_name
}]
}
_connection.propertyCollector.RetrieveProperties(:specSet => [spec])[0].to_hash
ret = _connection.propertyCollector.RetrieveProperties(:specSet => [spec])
if ret && ret.length > 0
ret[0].to_hash
else
{}
end
end
# Efficiently retrieve multiple properties from an object.

View File

@ -48,7 +48,16 @@ class RbVmomi::VIM::OvfManager
result.warning.each{|x| puts "OVF Warning: #{x.localizedMessage.chomp}" }
end
nfcLease = opts[:resourcePool].ImportVApp(:spec => result.importSpec,
importSpec = result.importSpec
if importSpec && importSpec.instantiationOst && importSpec.instantiationOst.child
importSpec.instantiationOst.child.each do |child|
child.section.map do |section|
section.xml = _handle_ost(section.xml, opts)
end
end
end
nfcLease = opts[:resourcePool].ImportVApp(:spec => importSpec,
:folder => opts[:vmFolder],
:host => opts[:host])
@ -56,30 +65,70 @@ class RbVmomi::VIM::OvfManager
raise nfcLease.error if nfcLease.state == "error"
begin
nfcLease.HttpNfcLeaseProgress(:percent => 5)
timeout, = nfcLease.collect 'info.leaseTimeout'
puts "DEBUG: Timeout: #{timeout}"
if timeout < 4 * 60
puts "WARNING: OVF upload NFC lease timeout less than 4 minutes"
end
progress = 5.0
result.fileItem.each do |fileItem|
deviceUrl = nfcLease.info.deviceUrl.find{|x| x.importKey == fileItem.deviceId}
leaseInfo, leaseState, leaseError = nfcLease.collect 'info', 'state', 'error'
# Retry nfcLease.collect because of PR 969599:
# If retrying property collector works, this means there is a network
# or VC overloading problem.
retrynum = 5
i = 1
while i <= retrynum && !leaseState
puts "Retrying at iteration #{i}"
sleep 1
leaseInfo, leaseState, leaseError = nfcLease.collect 'info', 'state', 'error'
i += 1
end
if leaseState != "ready"
raise "NFC lease is no longer ready: #{leaseState}: #{leaseError}"
end
if leaseInfo == nil
raise "NFC lease disappeared?"
end
deviceUrl = leaseInfo.deviceUrl.find{|x| x.importKey == fileItem.deviceId}
if !deviceUrl
raise "Couldn't find deviceURL for device '#{fileItem.deviceId}'"
end
# XXX handle file:// URIs
ovfFilename = opts[:uri].to_s
tmp = ovfFilename.split(/\//)
tmp.pop
tmp << fileItem.path
filename = tmp.join("/")
# If filename doesn't have a URI scheme, we're considering it a local file
if URI(filename).scheme.nil?
filename = "file://" + filename
end
method = fileItem.create ? "PUT" : "POST"
keepAliveThread = Thread.new do
while true
sleep 2 * 60
nfcLease.HttpNfcLeaseProgress(:percent => progress.to_i)
sleep 1 * 60
end
end
href = deviceUrl.url.gsub("*", opts[:host].config.network.vnic[0].spec.ip.ipAddress)
i = 1
ip = nil
begin
begin
puts "Iteration #{i}: Trying to get host's IP address ..."
ip = opts[:host].config.network.vnic[0].spec.ip.ipAddress
rescue Exception=>e
puts "Iteration #{i}: Couldn't get host's IP address: #{e}"
end
sleep 1
i += 1
end while i <= 5 && !ip
raise "Couldn't get host's IP address" unless ip
href = deviceUrl.url.gsub("*", ip)
downloadCmd = "#{CURLBIN} -L '#{URI::escape(filename)}'"
uploadCmd = "#{CURLBIN} -Ss -X #{method} --insecure -T - -H 'Content-Type: application/x-vnd.vmware-streamVmdk' '#{URI::escape(href)}'"
# Previously we used to append "-H 'Content-Length: #{fileItem.size}'"
@ -96,12 +145,56 @@ class RbVmomi::VIM::OvfManager
end
nfcLease.HttpNfcLeaseProgress(:percent => 100)
vm = nfcLease.info.entity
nfcLease.HttpNfcLeaseComplete
raise nfcLease.error if nfcLease.state == "error"
i = 1
vm = nil
begin
begin
puts "Iteration #{i}: Trying to access nfcLease.info.entity ..."
vm = nfcLease.info.entity
rescue Exception=>e
puts "Iteration #{i}: Couldn't access nfcLease.info.entity: #{e}"
end
sleep 1
i += 1
end while i <= 5 && !vm
raise "Couldn't access nfcLease.info.entity" unless vm
# Ignore sporadic connection errors caused by PR 1019166..
# Three attempts are made to execute HttpNfcLeaseComplete.
# Not critical if none goes through, as long as vm is obtained
#
# TODO: find the reason why HttpNfcLeaseComplete gets a wrong
# response (RetrievePropertiesResponse)
i = 0
begin
nfcLease.HttpNfcLeaseComplete
puts "HttpNfcLeaseComplete succeeded"
rescue RbVmomi::VIM::InvalidState
puts "HttpNfcLeaseComplete already finished.."
rescue Exception => e
puts "HttpNfcLeaseComplete failed at iteration #{i} with exception: #{e}"
i += 1
retry if i < 3
puts "Giving up HttpNfcLeaseComplete.."
end
vm
end
rescue Exception
(nfcLease.HttpNfcLeaseAbort rescue nil) if nfcLease
raise
end
def _handle_ost ost, opts = {}
ost = Nokogiri::XML(ost)
if opts[:vservice] == ['com.vmware.vim.vsm:extension_vservice']
ost.xpath('//vmw:Annotations/vmw:Providers/vmw:Provider').each do |x|
x['vmw:selected'] = 'selected'
end
ost.xpath('//vmw:Annotations/vmw:Providers').each do |x|
x['vmw:selected'] = 'com.vmware.vim.vsm:extension_vservice'
end
end
ost.to_s
end
end

View File

@ -46,13 +46,21 @@ class RbVmomi::VIM::PerformanceManager
end
end
metric_ids = metrics.map do |x|
instances = opts[:instance] || '*'
if !instances.is_a?(Array)
instances = [instances]
end
metric_ids = []
metrics.each do |x|
counter = perfcounter_hash[x]
if !counter
pp perfcounter_hash.keys
fail "Counter for #{x} couldn't be found"
end
RbVmomi::VIM::PerfMetricId(:counterId => counter.key, :instance => '*')
instances.each do |instance|
metric_ids << RbVmomi::VIM::PerfMetricId(:counterId => counter.key,
:instance => instance)
end
end
query_specs = objects.map do |obj|
RbVmomi::VIM::PerfQuerySpec({
@ -65,19 +73,36 @@ class RbVmomi::VIM::PerformanceManager
end
stats = QueryPerf(:querySpec => query_specs)
Hash[stats.map do |res|
[
res.entity,
{
:sampleInfo => res.sampleInfo,
:metrics => Hash[res.value.map do |metric|
[perfcounter_idhash[metric.id.counterId].name, metric.value]
end]
}
]
end]
if !opts[:multi_instance]
Hash[stats.map do |res|
[
res.entity,
{
:sampleInfo => res.sampleInfo,
:metrics => Hash[res.value.map do |metric|
metric_name = perfcounter_idhash[metric.id.counterId].name
[metric_name, metric.value]
end]
}
]
end]
else
Hash[stats.map do |res|
[
res.entity,
{
:sampleInfo => res.sampleInfo,
:metrics => Hash[res.value.map do |metric|
metric_name = perfcounter_idhash[metric.id.counterId].name
[[metric_name, metric.id.instance], metric.value]
end]
}
]
end]
end
end
def active_intervals
intervals = historicalInterval
Hash[(1..4).map { |level| [level, intervals.select { |x| x.enabled && x.level >= level }] }]

View File

@ -34,26 +34,41 @@ class RbVmomi::VIM::VirtualMachine
def add_delta_disk_layer_on_all_disks
devices, = self.collect 'config.hardware.device'
disks = devices.grep(RbVmomi::VIM::VirtualDisk)
# XXX: Should create a single reconfig spec instead of one per disk
spec = update_spec_add_delta_disk_layer_on_all_disks
self.ReconfigVM_Task(:spec => spec).wait_for_completion
end
# Updates a passed in spec to perform the task of adding a delta disk layer
# on top of all disks. Does the same as add_delta_disk_layer_on_all_disks
# but instead of issuing the ReconfigVM_Task, it just constructs the
# spec, so that the caller can batch a couple of updates into one
# ReconfigVM_Task.
def update_spec_add_delta_disk_layer_on_all_disks spec = {}
devices, = self.collect 'config.hardware.device'
disks = devices.grep(RbVmomi::VIM::VirtualDisk)
device_change = []
disks.each do |disk|
spec = {
:deviceChange => [
{
:operation => :remove,
:device => disk
},
{
:operation => :add,
:fileOperation => :create,
:device => disk.dup.tap { |x|
x.backing = x.backing.dup
x.backing.fileName = "[#{disk.backing.datastore.name}]"
x.backing.parent = disk.backing
},
}
]
device_change << {
:operation => :remove,
:device => disk
}
device_change << {
:operation => :add,
:fileOperation => :create,
:device => disk.dup.tap { |x|
x.backing = x.backing.dup
x.backing.fileName = "[#{disk.backing.datastore.name}]"
x.backing.parent = disk.backing
},
}
self.ReconfigVM_Task(:spec => spec).wait_for_completion
end
if spec.is_a?(RbVmomi::VIM::VirtualMachineConfigSpec)
spec.deviceChange ||= []
spec.deviceChange += device_change
else
spec[:deviceChange] ||= []
spec[:deviceChange] += device_change
end
spec
end
end

Binary file not shown.