rbvmomi2 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|