rbvmomi2 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +19 -0
- data/README.md +114 -0
- data/exe/rbvmomish +138 -0
- data/lib/rbvmomi/basic_types.rb +383 -0
- data/lib/rbvmomi/connection.rb +272 -0
- data/lib/rbvmomi/deserialization.rb +249 -0
- data/lib/rbvmomi/fault.rb +19 -0
- data/lib/rbvmomi/optimist.rb +72 -0
- data/lib/rbvmomi/pbm.rb +68 -0
- data/lib/rbvmomi/sms/SmsStorageManager.rb +10 -0
- data/lib/rbvmomi/sms.rb +63 -0
- data/lib/rbvmomi/sso.rb +313 -0
- data/lib/rbvmomi/trivial_soap.rb +122 -0
- data/lib/rbvmomi/type_loader.rb +138 -0
- data/lib/rbvmomi/utils/admission_control.rb +401 -0
- data/lib/rbvmomi/utils/deploy.rb +318 -0
- data/lib/rbvmomi/utils/leases.rb +145 -0
- data/lib/rbvmomi/utils/perfdump.rb +631 -0
- data/lib/rbvmomi/version.rb +6 -0
- data/lib/rbvmomi/vim/ComputeResource.rb +54 -0
- data/lib/rbvmomi/vim/Datacenter.rb +25 -0
- data/lib/rbvmomi/vim/Datastore.rb +72 -0
- data/lib/rbvmomi/vim/DynamicTypeMgrAllTypeInfo.rb +78 -0
- data/lib/rbvmomi/vim/DynamicTypeMgrDataTypeInfo.rb +23 -0
- data/lib/rbvmomi/vim/DynamicTypeMgrManagedTypeInfo.rb +54 -0
- data/lib/rbvmomi/vim/Folder.rb +214 -0
- data/lib/rbvmomi/vim/HostSystem.rb +177 -0
- data/lib/rbvmomi/vim/ManagedEntity.rb +60 -0
- data/lib/rbvmomi/vim/ManagedObject.rb +63 -0
- data/lib/rbvmomi/vim/ObjectContent.rb +26 -0
- data/lib/rbvmomi/vim/ObjectUpdate.rb +26 -0
- data/lib/rbvmomi/vim/OvfManager.rb +204 -0
- data/lib/rbvmomi/vim/PerfCounterInfo.rb +28 -0
- data/lib/rbvmomi/vim/PerformanceManager.rb +113 -0
- data/lib/rbvmomi/vim/PropertyCollector.rb +28 -0
- data/lib/rbvmomi/vim/ReflectManagedMethodExecuter.rb +33 -0
- data/lib/rbvmomi/vim/ResourcePool.rb +58 -0
- data/lib/rbvmomi/vim/ServiceInstance.rb +58 -0
- data/lib/rbvmomi/vim/Task.rb +68 -0
- data/lib/rbvmomi/vim/VirtualMachine.rb +75 -0
- data/lib/rbvmomi/vim.rb +157 -0
- data/lib/rbvmomi.rb +16 -0
- data/lib/rbvmomi2.rb +3 -0
- data/vmodl.db +0 -0
- metadata +214 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
# Copyright (c) 2011-2017 VMware, Inc. All Rights Reserved.
|
2
|
+
# SPDX-License-Identifier: MIT
|
3
|
+
|
4
|
+
class RbVmomi::VIM::ManagedEntity
|
5
|
+
# Retrieve the ancestors of the entity.
|
6
|
+
# @return [Array] Ancestors of this entity, starting with the root.
|
7
|
+
def path
|
8
|
+
self.class.paths([self])[self]
|
9
|
+
end
|
10
|
+
|
11
|
+
# Retrieve the ancestors of a list of entries.
|
12
|
+
# @return [Hash] Object-indexed hash of ancestors of entities, starting with the root.
|
13
|
+
def self.paths objs
|
14
|
+
filterSpec = RbVmomi::VIM.PropertyFilterSpec(
|
15
|
+
:objectSet => objs.map do |obj|
|
16
|
+
RbVmomi::VIM.ObjectSpec(
|
17
|
+
:obj => obj,
|
18
|
+
:selectSet => [
|
19
|
+
RbVmomi::VIM.TraversalSpec(
|
20
|
+
:name => "tsME",
|
21
|
+
:type => 'ManagedEntity',
|
22
|
+
:path => 'parent',
|
23
|
+
:skip => false,
|
24
|
+
:selectSet => [
|
25
|
+
RbVmomi::VIM.SelectionSpec(:name => "tsME")
|
26
|
+
]
|
27
|
+
)
|
28
|
+
]
|
29
|
+
)
|
30
|
+
end,
|
31
|
+
:propSet => [{
|
32
|
+
:pathSet => %w(name parent),
|
33
|
+
:type => 'ManagedEntity'
|
34
|
+
}]
|
35
|
+
)
|
36
|
+
|
37
|
+
propCollector = objs.first._connection.propertyCollector
|
38
|
+
result = propCollector.RetrieveProperties(:specSet => [filterSpec])
|
39
|
+
|
40
|
+
Hash[objs.map do |obj|
|
41
|
+
tree = {}
|
42
|
+
result.each { |x| tree[x.obj] = [x['parent'], x['name']] }
|
43
|
+
a = []
|
44
|
+
cur = obj
|
45
|
+
while cur
|
46
|
+
parent, name = *tree[cur]
|
47
|
+
a << [cur, name]
|
48
|
+
cur = parent
|
49
|
+
end
|
50
|
+
[obj, a.reverse]
|
51
|
+
end]
|
52
|
+
end
|
53
|
+
|
54
|
+
# Return a string representation of +path+ suitable for display.
|
55
|
+
# @return [String]
|
56
|
+
# @see #path
|
57
|
+
def pretty_path
|
58
|
+
path[1..-1].map { |x| x[1] } * '/'
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# Copyright (c) 2011-2017 VMware, Inc. All Rights Reserved.
|
2
|
+
# SPDX-License-Identifier: MIT
|
3
|
+
|
4
|
+
class RbVmomi::VIM::ManagedObject
|
5
|
+
# Wait for updates on an object until a condition becomes true.
|
6
|
+
#
|
7
|
+
# @param pathSet [Array] Property paths to wait for updates to.
|
8
|
+
# @yield Called when an update to a subscribed property occurs.
|
9
|
+
# @yieldreturn [Boolean] Whether to stop waiting.
|
10
|
+
#
|
11
|
+
# @todo Pass the current property values to the block.
|
12
|
+
def wait_until *pathSet, &b
|
13
|
+
all = pathSet.empty?
|
14
|
+
filter = _connection.propertyCollector.CreateFilter :spec => {
|
15
|
+
:propSet => [{ :type => self.class.wsdl_name, :all => all, :pathSet => pathSet }],
|
16
|
+
:objectSet => [{ :obj => self }],
|
17
|
+
}, :partialUpdates => false
|
18
|
+
ver = ''
|
19
|
+
loop do
|
20
|
+
result = _connection.propertyCollector.WaitForUpdates(:version => ver)
|
21
|
+
ver = result.version
|
22
|
+
if x = b.call
|
23
|
+
return x
|
24
|
+
end
|
25
|
+
end
|
26
|
+
ensure
|
27
|
+
filter.DestroyPropertyFilter if filter
|
28
|
+
end
|
29
|
+
|
30
|
+
# Efficiently retrieve multiple properties from an object.
|
31
|
+
# @param pathSet [Array] Properties to return.
|
32
|
+
# @return [Hash] Hash from property paths to values.
|
33
|
+
def collect! *pathSet
|
34
|
+
spec = {
|
35
|
+
:objectSet => [{ :obj => self }],
|
36
|
+
:propSet => [{
|
37
|
+
:pathSet => pathSet,
|
38
|
+
:type => self.class.wsdl_name
|
39
|
+
}]
|
40
|
+
}
|
41
|
+
ret = _connection.propertyCollector.RetrieveProperties(:specSet => [spec])
|
42
|
+
if ret && ret.length > 0
|
43
|
+
ret[0].to_hash
|
44
|
+
else
|
45
|
+
{}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Efficiently retrieve multiple properties from an object.
|
50
|
+
# @param pathSet (see #collect!)
|
51
|
+
# @yield [*values] Property values in same order as +pathSet+.
|
52
|
+
# @return [Array] Property values in same order as +pathSet+, or the return
|
53
|
+
# value from the block if it is given.
|
54
|
+
def collect *pathSet
|
55
|
+
h = collect!(*pathSet)
|
56
|
+
a = pathSet.map { |k| h[k.to_s] }
|
57
|
+
if block_given?
|
58
|
+
yield a
|
59
|
+
else
|
60
|
+
a
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Copyright (c) 2011-2017 VMware, Inc. All Rights Reserved.
|
2
|
+
# SPDX-License-Identifier: MIT
|
3
|
+
|
4
|
+
class RbVmomi::VIM::ObjectContent
|
5
|
+
# Represent this ObjectContent as a hash.
|
6
|
+
# @return [Hash] A hash from property paths to values.
|
7
|
+
def to_hash
|
8
|
+
@cached_hash ||= to_hash_uncached
|
9
|
+
end
|
10
|
+
|
11
|
+
# Alias for +to_hash[k]+.
|
12
|
+
def [](k)
|
13
|
+
to_hash[k]
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def to_hash_uncached
|
19
|
+
h = {}
|
20
|
+
propSet.each do |x|
|
21
|
+
fail if h.member? x.name
|
22
|
+
h[x.name] = x.val
|
23
|
+
end
|
24
|
+
h
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Copyright (c) 2011-2017 VMware, Inc. All Rights Reserved.
|
2
|
+
# SPDX-License-Identifier: MIT
|
3
|
+
|
4
|
+
class RbVmomi::VIM::ObjectUpdate
|
5
|
+
# Represent this ObjectUpdate as a hash.
|
6
|
+
# @return [Hash] A hash from property paths to values.
|
7
|
+
def to_hash
|
8
|
+
@cached_hash ||= to_hash_uncached
|
9
|
+
end
|
10
|
+
|
11
|
+
# Alias for +to_hash[k]+.
|
12
|
+
def [](k)
|
13
|
+
to_hash[k]
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def to_hash_uncached
|
19
|
+
h = {}
|
20
|
+
changeSet.each do |x|
|
21
|
+
fail if h.member? x.name
|
22
|
+
h[x.name] = x.val
|
23
|
+
end
|
24
|
+
h
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
# Copyright (c) 2011-2017 VMware, Inc. All Rights Reserved.
|
2
|
+
# SPDX-License-Identifier: MIT
|
3
|
+
|
4
|
+
# @note +deployOVF+ and requires +curl+. If +curl+ is not in your +PATH+
|
5
|
+
# then set the +CURL+ environment variable to point to it.
|
6
|
+
# @todo Use an HTTP library instead of executing +curl+.
|
7
|
+
class RbVmomi::VIM::OvfManager
|
8
|
+
CURLBIN = ENV['CURL'] || "curl" #@private
|
9
|
+
|
10
|
+
# Deploy an OVF.
|
11
|
+
#
|
12
|
+
# @param [Hash] opts The options hash.
|
13
|
+
# @option opts [String] :uri Location of the OVF.
|
14
|
+
# @option opts [String] :vmName Name of the new VM.
|
15
|
+
# @option opts [VIM::Folder] :vmFolder Folder to place the VM in.
|
16
|
+
# @option opts [VIM::HostSystem] :host Host to use.
|
17
|
+
# @option opts [VIM::ResourcePool] :resourcePool Resource pool to use.
|
18
|
+
# @option opts [VIM::Datastore] :datastore Datastore to use.
|
19
|
+
# @option opts [String] :diskProvisioning (thin) Disk provisioning mode.
|
20
|
+
# @option opts [Hash] :networkMappings Network mappings.
|
21
|
+
# @option opts [Hash] :propertyMappings Property mappings.
|
22
|
+
# @option opts [String] :deploymentOption Deployment option key.
|
23
|
+
def deployOVF opts
|
24
|
+
opts = { :networkMappings => {},
|
25
|
+
:propertyMappings => {},
|
26
|
+
:diskProvisioning => :thin }.merge opts
|
27
|
+
|
28
|
+
%w(uri vmName vmFolder host resourcePool datastore).each do |k|
|
29
|
+
fail "parameter #{k} required" unless opts[k.to_sym]
|
30
|
+
end
|
31
|
+
|
32
|
+
ovfImportSpec = RbVmomi::VIM::OvfCreateImportSpecParams(
|
33
|
+
:hostSystem => opts[:host],
|
34
|
+
:locale => "US",
|
35
|
+
:entityName => opts[:vmName],
|
36
|
+
:deploymentOption => opts[:deploymentOption] || "",
|
37
|
+
:networkMapping => opts[:networkMappings].map{|from, to| RbVmomi::VIM::OvfNetworkMapping(:name => from, :network => to)},
|
38
|
+
:propertyMapping => opts[:propertyMappings].to_a,
|
39
|
+
:diskProvisioning => opts[:diskProvisioning]
|
40
|
+
)
|
41
|
+
|
42
|
+
result = CreateImportSpec(
|
43
|
+
:ovfDescriptor => open(opts[:uri]).read,
|
44
|
+
:resourcePool => opts[:resourcePool],
|
45
|
+
:datastore => opts[:datastore],
|
46
|
+
:cisp => ovfImportSpec
|
47
|
+
)
|
48
|
+
|
49
|
+
raise result.error[0].localizedMessage if result.error && !result.error.empty?
|
50
|
+
|
51
|
+
if result.warning
|
52
|
+
result.warning.each{|x| puts "OVF Warning: #{x.localizedMessage.chomp}" }
|
53
|
+
end
|
54
|
+
|
55
|
+
importSpec = result.importSpec
|
56
|
+
if importSpec && importSpec.instantiationOst && importSpec.instantiationOst.child
|
57
|
+
importSpec.instantiationOst.child.each do |child|
|
58
|
+
child.section.map do |section|
|
59
|
+
section.xml = _handle_ost(section.xml, opts)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
nfcLease = opts[:resourcePool].ImportVApp(:spec => importSpec,
|
65
|
+
:folder => opts[:vmFolder],
|
66
|
+
:host => opts[:host])
|
67
|
+
|
68
|
+
nfcLease.wait_until(:state) { nfcLease.state != "initializing" }
|
69
|
+
raise nfcLease.error if nfcLease.state == "error"
|
70
|
+
begin
|
71
|
+
nfcLease.HttpNfcLeaseProgress(:percent => 5)
|
72
|
+
timeout, = nfcLease.collect 'info.leaseTimeout'
|
73
|
+
puts "DEBUG: Timeout: #{timeout}"
|
74
|
+
if timeout < 4 * 60
|
75
|
+
puts "WARNING: OVF upload NFC lease timeout less than 4 minutes"
|
76
|
+
end
|
77
|
+
progress = 5.0
|
78
|
+
result.fileItem.each do |fileItem|
|
79
|
+
leaseInfo, leaseState, leaseError = nfcLease.collect 'info', 'state', 'error'
|
80
|
+
# Retry nfcLease.collect because of PR 969599:
|
81
|
+
# If retrying property collector works, this means there is a network
|
82
|
+
# or VC overloading problem.
|
83
|
+
retrynum = 5
|
84
|
+
i = 1
|
85
|
+
while i <= retrynum && !leaseState
|
86
|
+
puts "Retrying at iteration #{i}"
|
87
|
+
sleep 1
|
88
|
+
leaseInfo, leaseState, leaseError = nfcLease.collect 'info', 'state', 'error'
|
89
|
+
i += 1
|
90
|
+
end
|
91
|
+
if leaseState != "ready"
|
92
|
+
raise "NFC lease is no longer ready: #{leaseState}: #{leaseError}"
|
93
|
+
end
|
94
|
+
if leaseInfo == nil
|
95
|
+
raise "NFC lease disappeared?"
|
96
|
+
end
|
97
|
+
deviceUrl = leaseInfo.deviceUrl.find{|x| x.importKey == fileItem.deviceId}
|
98
|
+
if !deviceUrl
|
99
|
+
raise "Couldn't find deviceURL for device '#{fileItem.deviceId}'"
|
100
|
+
end
|
101
|
+
|
102
|
+
ovfFilename = opts[:uri].to_s
|
103
|
+
tmp = ovfFilename.split(/\//)
|
104
|
+
tmp.pop
|
105
|
+
tmp << fileItem.path
|
106
|
+
filename = tmp.join("/")
|
107
|
+
|
108
|
+
# If filename doesn't have a URI scheme, we're considering it a local file
|
109
|
+
if URI(filename).scheme.nil?
|
110
|
+
filename = "file://" + filename
|
111
|
+
end
|
112
|
+
|
113
|
+
method = fileItem.create ? "PUT" : "POST"
|
114
|
+
|
115
|
+
keepAliveThread = Thread.new do
|
116
|
+
while true
|
117
|
+
nfcLease.HttpNfcLeaseProgress(:percent => progress.to_i)
|
118
|
+
sleep 1 * 60
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
i = 1
|
123
|
+
ip = nil
|
124
|
+
begin
|
125
|
+
begin
|
126
|
+
puts "Iteration #{i}: Trying to get host's IP address ..."
|
127
|
+
ip = opts[:host].config.network.vnic[0].spec.ip.ipAddress
|
128
|
+
rescue Exception=>e
|
129
|
+
puts "Iteration #{i}: Couldn't get host's IP address: #{e}"
|
130
|
+
end
|
131
|
+
sleep 1
|
132
|
+
i += 1
|
133
|
+
end while i <= 5 && !ip
|
134
|
+
raise "Couldn't get host's IP address" unless ip
|
135
|
+
href = deviceUrl.url.gsub("*", ip)
|
136
|
+
downloadCmd = "#{CURLBIN} -L '#{URI::escape(filename)}'"
|
137
|
+
uploadCmd = "#{CURLBIN} -Ss -X #{method} --insecure -T - -H 'Content-Type: application/x-vnd.vmware-streamVmdk' '#{URI::escape(href)}'"
|
138
|
+
# Previously we used to append "-H 'Content-Length: #{fileItem.size}'"
|
139
|
+
# to the uploadCmd. It is not clear to me why, but that leads to
|
140
|
+
# trucation of the uploaded disk. Without this option curl can't tell
|
141
|
+
# the progress, but who cares
|
142
|
+
system("#{downloadCmd} | #{uploadCmd}", :out => "/dev/null")
|
143
|
+
|
144
|
+
keepAliveThread.kill
|
145
|
+
keepAliveThread.join
|
146
|
+
|
147
|
+
progress += (90.0 / result.fileItem.length)
|
148
|
+
nfcLease.HttpNfcLeaseProgress(:percent => progress.to_i)
|
149
|
+
end
|
150
|
+
|
151
|
+
nfcLease.HttpNfcLeaseProgress(:percent => 100)
|
152
|
+
raise nfcLease.error if nfcLease.state == "error"
|
153
|
+
i = 1
|
154
|
+
vm = nil
|
155
|
+
begin
|
156
|
+
begin
|
157
|
+
puts "Iteration #{i}: Trying to access nfcLease.info.entity ..."
|
158
|
+
vm = nfcLease.info.entity
|
159
|
+
rescue Exception=>e
|
160
|
+
puts "Iteration #{i}: Couldn't access nfcLease.info.entity: #{e}"
|
161
|
+
end
|
162
|
+
sleep 1
|
163
|
+
i += 1
|
164
|
+
end while i <= 5 && !vm
|
165
|
+
raise "Couldn't access nfcLease.info.entity" unless vm
|
166
|
+
|
167
|
+
# Ignore sporadic connection errors caused by PR 1019166..
|
168
|
+
# Three attempts are made to execute HttpNfcLeaseComplete.
|
169
|
+
# Not critical if none goes through, as long as vm is obtained
|
170
|
+
#
|
171
|
+
# TODO: find the reason why HttpNfcLeaseComplete gets a wrong
|
172
|
+
# response (RetrievePropertiesResponse)
|
173
|
+
i = 0
|
174
|
+
begin
|
175
|
+
nfcLease.HttpNfcLeaseComplete
|
176
|
+
puts "HttpNfcLeaseComplete succeeded"
|
177
|
+
rescue RbVmomi::VIM::InvalidState
|
178
|
+
puts "HttpNfcLeaseComplete already finished.."
|
179
|
+
rescue Exception => e
|
180
|
+
puts "HttpNfcLeaseComplete failed at iteration #{i} with exception: #{e}"
|
181
|
+
i += 1
|
182
|
+
retry if i < 3
|
183
|
+
puts "Giving up HttpNfcLeaseComplete.."
|
184
|
+
end
|
185
|
+
vm
|
186
|
+
end
|
187
|
+
rescue Exception
|
188
|
+
(nfcLease.HttpNfcLeaseAbort rescue nil) if nfcLease
|
189
|
+
raise
|
190
|
+
end
|
191
|
+
|
192
|
+
def _handle_ost ost, opts = {}
|
193
|
+
ost = Nokogiri::XML(ost)
|
194
|
+
if opts[:vservice] == ['com.vmware.vim.vsm:extension_vservice']
|
195
|
+
ost.xpath('//vmw:Annotations/vmw:Providers/vmw:Provider').each do |x|
|
196
|
+
x['vmw:selected'] = 'selected'
|
197
|
+
end
|
198
|
+
ost.xpath('//vmw:Annotations/vmw:Providers').each do |x|
|
199
|
+
x['vmw:selected'] = 'com.vmware.vim.vsm:extension_vservice'
|
200
|
+
end
|
201
|
+
end
|
202
|
+
ost.to_s
|
203
|
+
end
|
204
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Copyright (c) 2012-2017 VMware, Inc. All Rights Reserved.
|
2
|
+
# SPDX-License-Identifier: MIT
|
3
|
+
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
# THE SOFTWARE.
|
22
|
+
|
23
|
+
class RbVmomi::VIM::PerfCounterInfo
|
24
|
+
def name
|
25
|
+
"#{groupInfo.key}.#{nameInfo.key}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# Copyright (c) 2012-2017 VMware, Inc. All Rights Reserved.
|
2
|
+
# SPDX-License-Identifier: MIT
|
3
|
+
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
class Time
|
7
|
+
def to_datetime
|
8
|
+
# Convert seconds + microseconds into a fractional number of seconds
|
9
|
+
seconds = sec + Rational(usec, 10**6)
|
10
|
+
|
11
|
+
# Convert a UTC offset measured in minutes to one measured in a
|
12
|
+
# fraction of a day.
|
13
|
+
offset = Rational(utc_offset, 60 * 60 * 24)
|
14
|
+
DateTime.new(year, month, day, hour, min, seconds, offset)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
RbVmomi::VIM::PerformanceManager
|
19
|
+
class RbVmomi::VIM::PerformanceManager
|
20
|
+
def perfcounter_cached
|
21
|
+
@perfcounter ||= perfCounter
|
22
|
+
end
|
23
|
+
|
24
|
+
def perfcounter_hash
|
25
|
+
@perfcounter_hash ||= Hash[perfcounter_cached.map{|x| [x.name, x]}]
|
26
|
+
end
|
27
|
+
|
28
|
+
def perfcounter_idhash
|
29
|
+
@perfcounter_idhash ||= Hash[perfcounter_cached.map{|x| [x.key, x]}]
|
30
|
+
end
|
31
|
+
|
32
|
+
def provider_summary obj
|
33
|
+
@provider_summary ||= {}
|
34
|
+
@provider_summary[obj.class] ||= QueryPerfProviderSummary(:entity => obj)
|
35
|
+
end
|
36
|
+
|
37
|
+
def retrieve_stats objects, metrics, opts = {}
|
38
|
+
opts = opts.dup
|
39
|
+
max_samples = opts[:max_samples] || 1
|
40
|
+
realtime = false
|
41
|
+
if not opts[:interval]
|
42
|
+
provider = provider_summary objects.first
|
43
|
+
opts[:interval] = provider.refreshRate
|
44
|
+
realtime = true
|
45
|
+
else
|
46
|
+
provider = provider_summary objects.first
|
47
|
+
if opts[:interval] == provider.refreshRate
|
48
|
+
realtime = true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
instances = opts[:instance] || '*'
|
53
|
+
if !instances.is_a?(Array)
|
54
|
+
instances = [instances]
|
55
|
+
end
|
56
|
+
metric_ids = []
|
57
|
+
metrics.each do |x|
|
58
|
+
counter = perfcounter_hash[x]
|
59
|
+
if !counter
|
60
|
+
pp perfcounter_hash.keys
|
61
|
+
fail "Counter for #{x} couldn't be found"
|
62
|
+
end
|
63
|
+
instances.each do |instance|
|
64
|
+
metric_ids << RbVmomi::VIM::PerfMetricId(:counterId => counter.key,
|
65
|
+
:instance => instance)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
query_specs = objects.map do |obj|
|
69
|
+
RbVmomi::VIM::PerfQuerySpec({
|
70
|
+
:maxSample => max_samples,
|
71
|
+
:entity => obj,
|
72
|
+
:metricId => metric_ids,
|
73
|
+
:intervalId => opts[:interval],
|
74
|
+
:startTime => (realtime == false ? opts[:start_time].to_datetime : nil),
|
75
|
+
})
|
76
|
+
end
|
77
|
+
stats = QueryPerf(:querySpec => query_specs)
|
78
|
+
|
79
|
+
if !opts[:multi_instance]
|
80
|
+
Hash[stats.map do |res|
|
81
|
+
[
|
82
|
+
res.entity,
|
83
|
+
{
|
84
|
+
:sampleInfo => res.sampleInfo,
|
85
|
+
:metrics => Hash[res.value.map do |metric|
|
86
|
+
metric_name = perfcounter_idhash[metric.id.counterId].name
|
87
|
+
[metric_name, metric.value]
|
88
|
+
end]
|
89
|
+
}
|
90
|
+
]
|
91
|
+
end]
|
92
|
+
else
|
93
|
+
Hash[stats.map do |res|
|
94
|
+
[
|
95
|
+
res.entity,
|
96
|
+
{
|
97
|
+
:sampleInfo => res.sampleInfo,
|
98
|
+
:metrics => Hash[res.value.map do |metric|
|
99
|
+
metric_name = perfcounter_idhash[metric.id.counterId].name
|
100
|
+
[[metric_name, metric.id.instance], metric.value]
|
101
|
+
end]
|
102
|
+
}
|
103
|
+
]
|
104
|
+
end]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
def active_intervals
|
110
|
+
intervals = historicalInterval
|
111
|
+
Hash[(1..4).map { |level| [level, intervals.select { |x| x.enabled && x.level >= level }] }]
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Copyright (c) 2011-2017 VMware, Inc. All Rights Reserved.
|
2
|
+
# SPDX-License-Identifier: MIT
|
3
|
+
|
4
|
+
class RbVmomi::VIM::PropertyCollector
|
5
|
+
def collectMultiple objs, *pathSet
|
6
|
+
return {} if objs.empty?
|
7
|
+
|
8
|
+
klasses = objs.map{|x| x.class}.uniq
|
9
|
+
klass = if klasses.length > 1
|
10
|
+
# common superclass
|
11
|
+
klasses.map(&:ancestors).inject(&:&)[0]
|
12
|
+
else
|
13
|
+
klasses.first
|
14
|
+
end
|
15
|
+
|
16
|
+
spec = {
|
17
|
+
:objectSet => objs.map{|x| { :obj => x }},
|
18
|
+
:propSet => [{
|
19
|
+
:pathSet => pathSet,
|
20
|
+
:type => klass.wsdl_name
|
21
|
+
}]
|
22
|
+
}
|
23
|
+
res = RetrieveProperties(:specSet => [spec])
|
24
|
+
Hash[res.map do |x|
|
25
|
+
[x.obj, x.to_hash]
|
26
|
+
end]
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Copyright (c) 2011-2017 VMware, Inc. All Rights Reserved.
|
2
|
+
# SPDX-License-Identifier: MIT
|
3
|
+
|
4
|
+
module RbVmomi
|
5
|
+
|
6
|
+
class VIM::ReflectManagedMethodExecuter
|
7
|
+
def fetch moid, prop
|
8
|
+
result = FetchSoap(:moid => moid, :version => 'urn:vim25/6.5', :prop => prop)
|
9
|
+
xml = Nokogiri(result.response)
|
10
|
+
_connection.deserializer.deserialize xml.root, nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute moid, method, args
|
14
|
+
soap_args = args.map do |k,v|
|
15
|
+
VIM::ReflectManagedMethodExecuterSoapArgument.new.tap do |soap_arg|
|
16
|
+
soap_arg.name = k
|
17
|
+
xml = Builder::XmlMarkup.new :indent => 0
|
18
|
+
_connection.obj2xml xml, k, :anyType, false, v
|
19
|
+
soap_arg.val = xml.target!
|
20
|
+
end
|
21
|
+
end
|
22
|
+
result = ExecuteSoap(:moid => moid, :version => 'urn:vim25/6.5',
|
23
|
+
:method => method, :argument => soap_args)
|
24
|
+
if result
|
25
|
+
_connection.deserializer.deserialize Nokogiri(result.response).root, nil
|
26
|
+
else
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Copyright (c) 2011-2017 VMware, Inc. All Rights Reserved.
|
2
|
+
# SPDX-License-Identifier: MIT
|
3
|
+
|
4
|
+
class RbVmomi::VIM::ResourcePool
|
5
|
+
# Retrieve a child ResourcePool.
|
6
|
+
# @param name [String] Name of the child.
|
7
|
+
# @return [VIM::ResourcePool]
|
8
|
+
def find name
|
9
|
+
_connection.searchIndex.FindChild(:entity => self, :name => name)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Retrieve a descendant of this ResourcePool.
|
13
|
+
# @param path [String] Path delimited by '/'.
|
14
|
+
# @return [VIM::ResourcePool]
|
15
|
+
def traverse path
|
16
|
+
es = path.split('/').reject(&:empty?)
|
17
|
+
es.inject(self) do |f,e|
|
18
|
+
f.find(e) || return
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def resourcePoolSubTree fields = []
|
23
|
+
self.class.resourcePoolSubTree [self], fields
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.resourcePoolSubTree objs, fields = []
|
27
|
+
fields = (fields + ['name', 'resourcePool']).uniq
|
28
|
+
filterSpec = RbVmomi::VIM.PropertyFilterSpec(
|
29
|
+
:objectSet => objs.map do |obj|
|
30
|
+
RbVmomi::VIM.ObjectSpec(
|
31
|
+
:obj => obj,
|
32
|
+
:selectSet => [
|
33
|
+
RbVmomi::VIM.TraversalSpec(
|
34
|
+
:name => "tsRP",
|
35
|
+
:type => 'ResourcePool',
|
36
|
+
:path => 'resourcePool',
|
37
|
+
:skip => false,
|
38
|
+
:selectSet => [
|
39
|
+
RbVmomi::VIM.SelectionSpec(:name => "tsRP")
|
40
|
+
]
|
41
|
+
)
|
42
|
+
]
|
43
|
+
)
|
44
|
+
end,
|
45
|
+
:propSet => [{
|
46
|
+
:pathSet => fields,
|
47
|
+
:type => 'ResourcePool'
|
48
|
+
}]
|
49
|
+
)
|
50
|
+
|
51
|
+
propCollector = objs.first._connection.propertyCollector
|
52
|
+
result = propCollector.RetrieveProperties(:specSet => [filterSpec])
|
53
|
+
|
54
|
+
Hash[result.map do |x|
|
55
|
+
[x.obj, x.to_hash]
|
56
|
+
end]
|
57
|
+
end
|
58
|
+
end
|