rbvmomi 1.3.0 → 1.4.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.
- data/VERSION +1 -1
- data/bin/rbvmomish +5 -0
- data/devel/merge-internal-vmodl.rb +52 -0
- data/lib/rbvmomi/basic_types.rb +22 -3
- data/lib/rbvmomi/connection.rb +30 -5
- data/lib/rbvmomi/type_loader.rb +17 -17
- data/lib/rbvmomi/vim/DynamicTypeMgrAllTypeInfo.rb +75 -0
- data/lib/rbvmomi/vim/DynamicTypeMgrDataTypeInfo.rb +20 -0
- data/lib/rbvmomi/vim/DynamicTypeMgrManagedTypeInfo.rb +46 -0
- data/lib/rbvmomi/vim/HostSystem.rb +162 -0
- data/lib/rbvmomi/vim/ReflectManagedMethodExecuter.rb +26 -0
- data/test/test_deserialization.rb +10 -0
- data/test/test_serialization.rb +18 -0
- data/vmodl.db +0 -0
- metadata +8 -4
- data/README.html +0 -76
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.4.0
|
data/bin/rbvmomish
CHANGED
@@ -17,6 +17,7 @@ Usage:
|
|
17
17
|
rbvmomish [options]
|
18
18
|
|
19
19
|
Predefined methods:
|
20
|
+
conn: Returns the VIM connection
|
20
21
|
si: Returns the ServiceInstance
|
21
22
|
help: Displays this text.
|
22
23
|
|
@@ -92,6 +93,10 @@ def cookie str
|
|
92
93
|
$vim.cookie = str
|
93
94
|
end
|
94
95
|
|
96
|
+
def conn
|
97
|
+
$vim
|
98
|
+
end
|
99
|
+
|
95
100
|
def si
|
96
101
|
$vim.serviceInstance
|
97
102
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# These types are not public and so may change between releases. Do not
|
3
|
+
# use them directly.
|
4
|
+
|
5
|
+
public_vmodl_filename = ARGV[0] or abort "public vmodl filename required"
|
6
|
+
internal_vmodl_filename = ARGV[1] or abort "internal vmodl filename required"
|
7
|
+
output_vmodl_filename = ARGV[2] or abort "output vmodl filename required"
|
8
|
+
|
9
|
+
TYPES = %w(
|
10
|
+
DynamicTypeEnumTypeInfo
|
11
|
+
DynamicTypeMgrAllTypeInfo
|
12
|
+
DynamicTypeMgrAnnotation
|
13
|
+
DynamicTypeMgrDataTypeInfo
|
14
|
+
DynamicTypeMgrFilterSpec
|
15
|
+
DynamicTypeMgrManagedTypeInfo
|
16
|
+
DynamicTypeMgrMethodTypeInfo
|
17
|
+
DynamicTypeMgrMethodTypeInfoAnnotationType
|
18
|
+
DynamicTypeMgrMoFilterSpec
|
19
|
+
DynamicTypeMgrMoInstance
|
20
|
+
DynamicTypeMgrParamTypeInfo
|
21
|
+
DynamicTypeMgrParamTypeInfoAnnotationType
|
22
|
+
DynamicTypeMgrPropertyTypeInfo
|
23
|
+
DynamicTypeMgrPropertyTypeInfoAnnotationType
|
24
|
+
DynamicTypeMgrTypeFilterSpec
|
25
|
+
InternalDynamicTypeManager
|
26
|
+
ReflectManagedMethodExecuter
|
27
|
+
ReflectManagedMethodExecuterSoapArgument
|
28
|
+
ReflectManagedMethodExecuterSoapFault
|
29
|
+
ReflectManagedMethodExecuterSoapResult
|
30
|
+
)
|
31
|
+
|
32
|
+
METHODS = %w(
|
33
|
+
HostSystem.RetrieveDynamicTypeManager
|
34
|
+
HostSystem.RetrieveManagedMethodExecuter
|
35
|
+
)
|
36
|
+
|
37
|
+
public_vmodl = File.open(public_vmodl_filename, 'r') { |io| Marshal.load io }
|
38
|
+
internal_vmodl = File.open(internal_vmodl_filename, 'r') { |io| Marshal.load io }
|
39
|
+
|
40
|
+
TYPES.each do |k|
|
41
|
+
puts "Merging in #{k}"
|
42
|
+
fail unless internal_vmodl.member? k
|
43
|
+
public_vmodl[k] = internal_vmodl[k]
|
44
|
+
end
|
45
|
+
|
46
|
+
METHODS.each do |x|
|
47
|
+
puts "Merging in #{x}"
|
48
|
+
type, method = x.split '.'
|
49
|
+
public_vmodl[type]['methods'][method] = internal_vmodl[type]['methods'][method] or fail
|
50
|
+
end
|
51
|
+
|
52
|
+
File.open(output_vmodl_filename, 'w') { |io| Marshal.dump public_vmodl, io }
|
data/lib/rbvmomi/basic_types.rb
CHANGED
@@ -4,7 +4,7 @@ require 'pp'
|
|
4
4
|
module RbVmomi
|
5
5
|
module BasicTypes
|
6
6
|
|
7
|
-
BUILTIN = %w(ManagedObject DataObject TypeName PropertyPath ManagedObjectReference MethodName MethodFault LocalizedMethodFault)
|
7
|
+
BUILTIN = %w(ManagedObject DataObject TypeName PropertyPath ManagedObjectReference MethodName MethodFault LocalizedMethodFault KeyValue)
|
8
8
|
|
9
9
|
class Base
|
10
10
|
class << self
|
@@ -36,9 +36,8 @@ class ObjectWithProperties < Base
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
# XXX cache
|
40
39
|
def full_props_desc
|
41
|
-
(self == ObjectWithProperties ? [] : superclass.full_props_desc) + props_desc
|
40
|
+
@full_props_desc ||= (self == ObjectWithProperties ? [] : superclass.full_props_desc) + props_desc
|
42
41
|
end
|
43
42
|
|
44
43
|
def find_prop_desc name
|
@@ -121,6 +120,8 @@ class DataObject < ObjectWithProperties
|
|
121
120
|
keys.all? { |k| props[k] == o.props[k] }
|
122
121
|
end
|
123
122
|
|
123
|
+
alias eql? ==
|
124
|
+
|
124
125
|
def hash
|
125
126
|
props.hash
|
126
127
|
end
|
@@ -318,5 +319,23 @@ class ::Float
|
|
318
319
|
def self.wsdl_name; 'xsd:float' end
|
319
320
|
end
|
320
321
|
|
322
|
+
class KeyValue
|
323
|
+
def self.wsdl_name; 'xsd:float' end
|
324
|
+
attr_accessor :key, :value
|
325
|
+
|
326
|
+
def initialize k, v
|
327
|
+
@key = k
|
328
|
+
@value = v
|
329
|
+
end
|
330
|
+
|
331
|
+
def [] i
|
332
|
+
if i == 0 then @key
|
333
|
+
elsif i == 1 then @value
|
334
|
+
else fail "invalid index #{i.inspect}"
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
|
321
340
|
end
|
322
341
|
end
|
data/lib/rbvmomi/connection.rb
CHANGED
@@ -118,6 +118,13 @@ class Connection < TrivialSoap
|
|
118
118
|
type(xml['type'] || t.wsdl_name).new self, xml.text
|
119
119
|
elsif t <= BasicTypes::Enum
|
120
120
|
xml.text
|
121
|
+
elsif t <= BasicTypes::KeyValue
|
122
|
+
h = {}
|
123
|
+
xml.children.each do |c|
|
124
|
+
next unless c.element?
|
125
|
+
h[c.name] = c.text
|
126
|
+
end
|
127
|
+
[h['key'], h['value']]
|
121
128
|
elsif t <= String
|
122
129
|
xml.text
|
123
130
|
elsif t <= Symbol
|
@@ -136,6 +143,10 @@ class Connection < TrivialSoap
|
|
136
143
|
fail "attempted to deserialize an AnyType"
|
137
144
|
else fail "unexpected type #{t.inspect}"
|
138
145
|
end
|
146
|
+
rescue
|
147
|
+
$stderr.puts "#{$!.class} while deserializing #{xml.name} (#{typename}):"
|
148
|
+
$stderr.puts xml.to_s
|
149
|
+
raise
|
139
150
|
end
|
140
151
|
|
141
152
|
# hic sunt dracones
|
@@ -143,10 +154,19 @@ class Connection < TrivialSoap
|
|
143
154
|
expected = type(type)
|
144
155
|
fail "expected array, got #{o.class.wsdl_name}" if is_array and not o.is_a? Array
|
145
156
|
case o
|
146
|
-
when Array
|
147
|
-
|
148
|
-
|
149
|
-
|
157
|
+
when Array, BasicTypes::KeyValue
|
158
|
+
if o.is_a? BasicTypes::KeyValue and expected != BasicTypes::KeyValue
|
159
|
+
fail "expected #{expected.wsdl_name}, got KeyValue"
|
160
|
+
elsif expected == BasicTypes::KeyValue
|
161
|
+
xml.tag! name, attrs do
|
162
|
+
xml.tag! 'key', o[0]
|
163
|
+
xml.tag! 'value', o[1]
|
164
|
+
end
|
165
|
+
else
|
166
|
+
fail "expected #{expected.wsdl_name}, got array" unless is_array
|
167
|
+
o.each do |e|
|
168
|
+
obj2xml xml, name, expected.wsdl_name, false, e, attrs
|
169
|
+
end
|
150
170
|
end
|
151
171
|
when BasicTypes::ManagedObject
|
152
172
|
fail "expected #{expected.wsdl_name}, got #{o.class.wsdl_name} for field #{name.inspect}" if expected and not expected >= o.class
|
@@ -168,7 +188,7 @@ class Connection < TrivialSoap
|
|
168
188
|
fail "expected #{expected.wsdl_name}, got a hash" unless expected <= BasicTypes::DataObject
|
169
189
|
obj2xml xml, name, type, false, expected.new(o), attrs
|
170
190
|
when true, false
|
171
|
-
fail "expected #{expected.wsdl_name}, got a boolean" unless
|
191
|
+
fail "expected #{expected.wsdl_name}, got a boolean" unless [BasicTypes::Boolean, BasicTypes::AnyType].member? expected
|
172
192
|
attrs['xsi:type'] = 'xsd:boolean' if expected == BasicTypes::AnyType
|
173
193
|
xml.tag! name, (o ? '1' : '0'), attrs
|
174
194
|
when Symbol, String
|
@@ -191,6 +211,10 @@ class Connection < TrivialSoap
|
|
191
211
|
else fail "unexpected object class #{o.class}"
|
192
212
|
end
|
193
213
|
xml
|
214
|
+
rescue
|
215
|
+
$stderr.puts "#{$!.class} while serializing #{name} (#{type}):"
|
216
|
+
PP.pp o, $stderr
|
217
|
+
raise
|
194
218
|
end
|
195
219
|
|
196
220
|
def self.type name
|
@@ -204,6 +228,7 @@ class Connection < TrivialSoap
|
|
204
228
|
when :float, :double then Float
|
205
229
|
when :dateTime then Time
|
206
230
|
when :base64Binary then BasicTypes::Binary
|
231
|
+
when :KeyValue then BasicTypes::KeyValue
|
207
232
|
else
|
208
233
|
if @loader.has_type? name
|
209
234
|
const_get(name)
|
data/lib/rbvmomi/type_loader.rb
CHANGED
@@ -4,29 +4,19 @@ require 'monitor'
|
|
4
4
|
|
5
5
|
module RbVmomi
|
6
6
|
|
7
|
-
class TypeStore
|
8
|
-
def initialize fn
|
9
|
-
File.open(fn, 'r') do |io|
|
10
|
-
@db = Marshal.load io
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def [](k)
|
15
|
-
@db[k]
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
7
|
class TypeLoader
|
20
|
-
attr_reader :typenames
|
21
|
-
|
22
8
|
def initialize target, fn
|
23
9
|
@target = target
|
24
|
-
@db = TypeStore.new fn
|
25
10
|
@lock = Monitor.new
|
11
|
+
@db = {}
|
12
|
+
@id2wsdl = {}
|
13
|
+
add_types Hash[BasicTypes::BUILTIN.map { |k| [k,nil] }]
|
14
|
+
vmodl_database = File.open(fn, 'r') { |io| Marshal.load io }
|
15
|
+
vmodl_database.reject! { |k,v| k =~ /^_/ }
|
16
|
+
add_types vmodl_database
|
26
17
|
end
|
27
18
|
|
28
19
|
def init
|
29
|
-
@typenames = Set.new(@db['_typenames'] + BasicTypes::BUILTIN)
|
30
20
|
@target.constants.select { |x| has_type? x.to_s }.each { |x| load_type x.to_s }
|
31
21
|
BasicTypes::BUILTIN.each do |x|
|
32
22
|
@target.const_set x, BasicTypes.const_get(x)
|
@@ -39,7 +29,7 @@ class TypeLoader
|
|
39
29
|
|
40
30
|
def has_type? name
|
41
31
|
fail unless name.is_a? String
|
42
|
-
@
|
32
|
+
@db.member? name
|
43
33
|
end
|
44
34
|
|
45
35
|
def load_type name
|
@@ -51,6 +41,16 @@ class TypeLoader
|
|
51
41
|
nil
|
52
42
|
end
|
53
43
|
|
44
|
+
def add_types types
|
45
|
+
@lock.synchronize do
|
46
|
+
@db.merge! types
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def typenames
|
51
|
+
@db.keys
|
52
|
+
end
|
53
|
+
|
54
54
|
private
|
55
55
|
|
56
56
|
def load_extension name
|
@@ -0,0 +1,75 @@
|
|
1
|
+
class RbVmomi::VIM::DynamicTypeMgrAllTypeInfo
|
2
|
+
def toRbvmomiTypeHash
|
3
|
+
id2name = {}
|
4
|
+
id2name.merge!({
|
5
|
+
'string' => 'xsd:string',
|
6
|
+
'java.lang.String' => 'xsd:string',
|
7
|
+
'BOOLEAN' => 'xsd:boolean',
|
8
|
+
'BYTE' => 'xsd:byte',
|
9
|
+
'SHORT' => 'xsd:short',
|
10
|
+
'INT' => 'xsd:int',
|
11
|
+
'LONG' => 'xsd:long',
|
12
|
+
'FLOAT' => 'xsd:float',
|
13
|
+
'DOUBLE' => 'xsd:double',
|
14
|
+
'boolean' => 'xsd:boolean',
|
15
|
+
'byte' => 'xsd:byte',
|
16
|
+
'short' => 'xsd:short',
|
17
|
+
'int' => 'xsd:int',
|
18
|
+
'long' => 'xsd:long',
|
19
|
+
'float' => 'xsd:float',
|
20
|
+
'double' => 'xsd:double',
|
21
|
+
'vmodl.DateTime' => 'xsd:dateTime',
|
22
|
+
'vmodl.Binary' => 'xsd:base64Binary',
|
23
|
+
'vmodl.Any' => 'xsd:anyType',
|
24
|
+
'vim.KeyValue' => 'KeyValue',
|
25
|
+
'void' => nil,
|
26
|
+
})
|
27
|
+
|
28
|
+
%w(DataObject ManagedObject MethodFault MethodName DynamicData
|
29
|
+
PropertyPath RuntimeFault TypeName).each do |x|
|
30
|
+
id2name['vmodl.' + x] = x
|
31
|
+
end
|
32
|
+
|
33
|
+
types = {}
|
34
|
+
self.managedTypeInfo.each{|x| types.merge!(x.toRbvmomiTypeHash) }
|
35
|
+
self.dataTypeInfo.each{|x| types.merge!(x.toRbvmomiTypeHash) }
|
36
|
+
|
37
|
+
types.each do |k,t|
|
38
|
+
id2name[t['type-id']] = k
|
39
|
+
end
|
40
|
+
|
41
|
+
types = Hash[types.map do |k,t|
|
42
|
+
case t['kind']
|
43
|
+
when 'data'
|
44
|
+
t['wsdl_base'] = t['base-type-id'] ? id2name[t['base-type-id']] : 'DataObject'
|
45
|
+
#t.delete 'base-type-id'
|
46
|
+
t['props'].each do |x|
|
47
|
+
x['wsdl_type'] = id2name[x['type-id-ref']]
|
48
|
+
x.delete 'type-id-ref'
|
49
|
+
end
|
50
|
+
when 'managed'
|
51
|
+
t['wsdl_base'] = t['base-type-id'] ? id2name[t['base-type-id']] : 'ManagedObject'
|
52
|
+
#t.delete 'base-type-id'
|
53
|
+
t['props'].each do |x|
|
54
|
+
x['wsdl_type'] = id2name[x['type-id-ref']]
|
55
|
+
x.delete 'type-id-ref'
|
56
|
+
end
|
57
|
+
t['methods'].each do |mName,x|
|
58
|
+
if y = x['result']
|
59
|
+
y['wsdl_type'] = id2name[y['type-id-ref']]
|
60
|
+
#y.delete 'type-id-ref'
|
61
|
+
end
|
62
|
+
x['params'].each do |r|
|
63
|
+
r['wsdl_type'] = id2name[r['type-id-ref']]
|
64
|
+
r.delete 'type-id-ref'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
when 'enum'
|
68
|
+
else fail
|
69
|
+
end
|
70
|
+
[k, t]
|
71
|
+
end]
|
72
|
+
|
73
|
+
types
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class RbVmomi::VIM::DynamicTypeMgrDataTypeInfo
|
2
|
+
def toRbvmomiTypeHash
|
3
|
+
{
|
4
|
+
self.wsdlName => {
|
5
|
+
'kind' => 'data',
|
6
|
+
'type-id' => self.name,
|
7
|
+
'base-type-id' => self.base.first,
|
8
|
+
'props' => self.property.map do |prop|
|
9
|
+
{
|
10
|
+
'name' => prop.name,
|
11
|
+
'type-id-ref' => prop.type.gsub("[]", ""),
|
12
|
+
'is-array' => (prop.type =~ /\[\]$/) ? true : false,
|
13
|
+
'is-optional' => prop.annotation.find{|a| a.name == "optional"} ? true : false,
|
14
|
+
'version-id-ref' => prop.version,
|
15
|
+
}
|
16
|
+
end,
|
17
|
+
}
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class RbVmomi::VIM::DynamicTypeMgrManagedTypeInfo
|
2
|
+
def toRbvmomiTypeHash
|
3
|
+
{
|
4
|
+
self.wsdlName => {
|
5
|
+
'kind' => 'managed',
|
6
|
+
'type-id' => self.name,
|
7
|
+
'base-type-id' => self.base.first,
|
8
|
+
'props' => self.property.map do |prop|
|
9
|
+
{
|
10
|
+
'name' => prop.name,
|
11
|
+
'type-id-ref' => prop.type.gsub("[]", ""),
|
12
|
+
'is-array' => (prop.type =~ /\[\]$/) ? true : false,
|
13
|
+
'is-optional' => prop.annotation.find{|a| a.name == "optional"} ? true : false,
|
14
|
+
'version-id-ref' => prop.version,
|
15
|
+
}
|
16
|
+
end,
|
17
|
+
'methods' => Hash[
|
18
|
+
self.method.map do |method|
|
19
|
+
result = method.returnTypeInfo
|
20
|
+
|
21
|
+
[method.wsdlName,
|
22
|
+
{
|
23
|
+
'params' => method.paramTypeInfo.map do |param|
|
24
|
+
{
|
25
|
+
'name' => param.name,
|
26
|
+
'type-id-ref' => param.type.gsub("[]", ""),
|
27
|
+
'is-array' => (param.type =~ /\[\]$/) ? true : false,
|
28
|
+
'is-optional' => param.annotation.find{|a| a.name == "optional"} ? true : false,
|
29
|
+
'version-id-ref' => param.version,
|
30
|
+
}
|
31
|
+
end,
|
32
|
+
'result' => {
|
33
|
+
'name' => result.name,
|
34
|
+
'type-id-ref' => result.type.gsub("[]", ""),
|
35
|
+
'is-array' => (result.type =~ /\[\]$/) ? true : false,
|
36
|
+
'is-optional' => result.annotation.find{|a| a.name == "optional"} ? true : false,
|
37
|
+
'version-id-ref' => result.version,
|
38
|
+
}
|
39
|
+
}
|
40
|
+
]
|
41
|
+
end
|
42
|
+
]
|
43
|
+
}
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
module RbVmomi
|
2
|
+
|
3
|
+
class VIM::HostSystem
|
4
|
+
def esxcli
|
5
|
+
@cached_esxcli ||= VIM::EsxcliNamespace.root(self)
|
6
|
+
end
|
7
|
+
|
8
|
+
def dtm
|
9
|
+
@cached_dtm ||= RetrieveDynamicTypeManager()
|
10
|
+
end
|
11
|
+
|
12
|
+
def dti
|
13
|
+
@cached_dti ||= dtm.DynamicTypeMgrQueryTypeInfo
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_dynamic_managed_object inst
|
17
|
+
wsdlName = dti.managedTypeInfo.find { |x| x.name == inst.moType }.wsdlName
|
18
|
+
_connection.type(wsdlName).new(_connection, inst.id)
|
19
|
+
end
|
20
|
+
|
21
|
+
def cli_info_fetcher
|
22
|
+
# XXX there can be more than one
|
23
|
+
return @cached_cli_info_fetcher if @cached_cli_info_fetcher
|
24
|
+
inst = dtm.DynamicTypeMgrQueryMoInstances.find { |x| x.moType == 'vim.CLIInfo' }
|
25
|
+
@cached_cli_info_fetcher = create_dynamic_managed_object inst
|
26
|
+
end
|
27
|
+
|
28
|
+
def mme
|
29
|
+
@cached_mme ||= RetrieveManagedMethodExecuter()
|
30
|
+
end
|
31
|
+
|
32
|
+
def direct?
|
33
|
+
@ref == 'ha-host'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class VIM::EsxcliNamespace
|
38
|
+
ESXCLI_PREFIX = 'vim.EsxCLI.'
|
39
|
+
|
40
|
+
attr_reader :name, :parent, :host, :type, :instance, :type_info, :namespaces, :commands
|
41
|
+
|
42
|
+
def self.root host
|
43
|
+
type_hash = host.dti.toRbvmomiTypeHash
|
44
|
+
VIM.loader.add_types type_hash
|
45
|
+
all_instances = host.dtm.DynamicTypeMgrQueryMoInstances
|
46
|
+
instances = Hash[all_instances.select { |x| x.moType.start_with? ESXCLI_PREFIX }.
|
47
|
+
map { |x| [x.moType,x.id] }]
|
48
|
+
type_infos = Hash[host.dti.managedTypeInfo.map { |x| [x.name,x] }]
|
49
|
+
new('root', nil, host).tap do |root|
|
50
|
+
instances.each do |type,instance|
|
51
|
+
path = type.split('.')[2..-1]
|
52
|
+
ns = path.inject(root) { |b,v| b.namespaces[v] }
|
53
|
+
ns.realize type, instance, type_infos[type]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def initialize name, parent, host
|
59
|
+
@name = name
|
60
|
+
@parent = parent
|
61
|
+
@host = host
|
62
|
+
@type = nil
|
63
|
+
@instance = nil
|
64
|
+
@type_info = nil
|
65
|
+
@namespaces = Hash.new { |h,k| h[k] = self.class.new k, self, host }
|
66
|
+
@commands = {}
|
67
|
+
@cached_cli_info = nil
|
68
|
+
end
|
69
|
+
|
70
|
+
def realize type, instance, type_info
|
71
|
+
fail if @type or @instance
|
72
|
+
@type = type
|
73
|
+
@instance = instance
|
74
|
+
@type_info = type_info
|
75
|
+
@type_info.method.each do |method_type_info|
|
76
|
+
name = method_type_info.name
|
77
|
+
@commands[name] = VIM::EsxcliCommand.new self, method_type_info
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def type_name
|
82
|
+
if @type then @type
|
83
|
+
elsif @parent then "#{@parent.type_name}.#{@name}"
|
84
|
+
else 'vim.EsxCLI'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def cli_info
|
89
|
+
@cached_cli_info ||=
|
90
|
+
if @host.direct?
|
91
|
+
@host.cli_info_fetcher.VimCLIInfoFetchCLIInfo(:typeName => type_name)
|
92
|
+
else
|
93
|
+
@host.mme.execute(@host.cli_info_fetcher._ref,
|
94
|
+
"vim.CLIInfo.FetchCLIInfo", :typeName => type_name)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def obj
|
99
|
+
conn = @host._connection
|
100
|
+
conn.type(@type_info.wsdlName).new(conn, @instance)
|
101
|
+
end
|
102
|
+
|
103
|
+
def method_missing name, *args
|
104
|
+
name = name.to_s
|
105
|
+
if @namespaces.member? name and args.empty?
|
106
|
+
@namespaces[name]
|
107
|
+
elsif @commands.member? name
|
108
|
+
@commands[name].call *args
|
109
|
+
else
|
110
|
+
raise NoMethodError
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def pretty_print q
|
115
|
+
q.text @name
|
116
|
+
q.text ' '
|
117
|
+
q.group 2 do
|
118
|
+
q.text '{'
|
119
|
+
q.breakable
|
120
|
+
items = (@namespaces.values+@commands.values).sort_by(&:name)
|
121
|
+
q.seplist items, nil, :each do |v|
|
122
|
+
if v.is_a? VIM::EsxcliNamespace
|
123
|
+
q.pp v
|
124
|
+
else
|
125
|
+
q.text v.name
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
q.breakable
|
130
|
+
q.text '}'
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
class VIM::EsxcliCommand
|
135
|
+
attr_reader :ns, :type_info, :cli_info
|
136
|
+
|
137
|
+
def initialize ns, type_info
|
138
|
+
@ns = ns
|
139
|
+
@type_info = type_info
|
140
|
+
@cached_cli_info = nil
|
141
|
+
end
|
142
|
+
|
143
|
+
def name
|
144
|
+
@type_info.name
|
145
|
+
end
|
146
|
+
|
147
|
+
def cli_info
|
148
|
+
@cached_cli_info ||= @ns.cli_info.method.find { |x| x.name == @type_info.name }
|
149
|
+
end
|
150
|
+
|
151
|
+
def call args={}
|
152
|
+
if @ns.host.direct?
|
153
|
+
@ns.obj._call @type_info.wsdlName, args
|
154
|
+
else
|
155
|
+
real_args = Set.new(type_info.paramTypeInfo.map(&:name))
|
156
|
+
args = args.reject { |k,v| !real_args.member?(k.to_s) }
|
157
|
+
@ns.host.mme.execute(@ns.obj._ref, "#{@ns.type_name}.#{@type_info.name}", args)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RbVmomi
|
2
|
+
|
3
|
+
class VIM::ReflectManagedMethodExecuter
|
4
|
+
def fetch moid, prop
|
5
|
+
result = FetchSoap(:moid => moid, :version => 'urn:vim25/5.0', :prop => prop)
|
6
|
+
xml = Nokogiri(result.response)
|
7
|
+
_connection.xml2obj xml.root, nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute moid, method, args
|
11
|
+
soap_args = args.map do |k,v|
|
12
|
+
VIM::ReflectManagedMethodExecuterSoapArgument.new.tap do |soap_arg|
|
13
|
+
soap_arg.name = k
|
14
|
+
xml = Builder::XmlMarkup.new :indent => 0
|
15
|
+
_connection.obj2xml xml, k, :anyType, false, v
|
16
|
+
soap_arg.val = xml.target!
|
17
|
+
end
|
18
|
+
end
|
19
|
+
result = ExecuteSoap(:moid => moid, :version => 'urn:vim25/5.0',
|
20
|
+
:method => method, :argument => soap_args)
|
21
|
+
_connection.xml2obj Nokogiri(result.response).root, nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
data/test/test_serialization.rb
CHANGED
@@ -208,4 +208,22 @@ class SerializationTest < Test::Unit::TestCase
|
|
208
208
|
EOS
|
209
209
|
|
210
210
|
end
|
211
|
+
|
212
|
+
def test_keyvalue
|
213
|
+
obj = RbVmomi::BasicTypes::KeyValue.new('a', 'b')
|
214
|
+
check <<-EOS, obj, 'KeyValue', false
|
215
|
+
<root>
|
216
|
+
<key>a</key>
|
217
|
+
<value>b</value>
|
218
|
+
</root>
|
219
|
+
EOS
|
220
|
+
|
221
|
+
obj = ['a', 'b']
|
222
|
+
check <<-EOS, obj, 'KeyValue', false
|
223
|
+
<root>
|
224
|
+
<key>a</key>
|
225
|
+
<value>b</value>
|
226
|
+
</root>
|
227
|
+
EOS
|
228
|
+
end
|
211
229
|
end
|
data/vmodl.db
CHANGED
Binary file
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: rbvmomi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 1.
|
5
|
+
version: 1.4.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Rich Lane
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-10-19 00:00:00 -07:00
|
14
14
|
default_executable: rbvmomish
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -54,7 +54,6 @@ extensions: []
|
|
54
54
|
|
55
55
|
extra_rdoc_files:
|
56
56
|
- LICENSE
|
57
|
-
- README.html
|
58
57
|
- README.rdoc
|
59
58
|
files:
|
60
59
|
- .yardopts
|
@@ -65,6 +64,7 @@ files:
|
|
65
64
|
- bin/rbvmomish
|
66
65
|
- devel/analyze-vim-declarations.rb
|
67
66
|
- devel/analyze-xml.rb
|
67
|
+
- devel/merge-internal-vmodl.rb
|
68
68
|
- examples/annotate.rb
|
69
69
|
- examples/clone_vm.rb
|
70
70
|
- examples/create_vm-1.9.rb
|
@@ -91,13 +91,18 @@ files:
|
|
91
91
|
- lib/rbvmomi/vim/ComputeResource.rb
|
92
92
|
- lib/rbvmomi/vim/Datacenter.rb
|
93
93
|
- lib/rbvmomi/vim/Datastore.rb
|
94
|
+
- lib/rbvmomi/vim/DynamicTypeMgrAllTypeInfo.rb
|
95
|
+
- lib/rbvmomi/vim/DynamicTypeMgrDataTypeInfo.rb
|
96
|
+
- lib/rbvmomi/vim/DynamicTypeMgrManagedTypeInfo.rb
|
94
97
|
- lib/rbvmomi/vim/Folder.rb
|
98
|
+
- lib/rbvmomi/vim/HostSystem.rb
|
95
99
|
- lib/rbvmomi/vim/ManagedEntity.rb
|
96
100
|
- lib/rbvmomi/vim/ManagedObject.rb
|
97
101
|
- lib/rbvmomi/vim/ObjectContent.rb
|
98
102
|
- lib/rbvmomi/vim/ObjectUpdate.rb
|
99
103
|
- lib/rbvmomi/vim/OvfManager.rb
|
100
104
|
- lib/rbvmomi/vim/PropertyCollector.rb
|
105
|
+
- lib/rbvmomi/vim/ReflectManagedMethodExecuter.rb
|
101
106
|
- lib/rbvmomi/vim/ResourcePool.rb
|
102
107
|
- lib/rbvmomi/vim/ServiceInstance.rb
|
103
108
|
- lib/rbvmomi/vim/Task.rb
|
@@ -109,7 +114,6 @@ files:
|
|
109
114
|
- test/test_parse_response.rb
|
110
115
|
- test/test_serialization.rb
|
111
116
|
- vmodl.db
|
112
|
-
- README.html
|
113
117
|
has_rdoc: true
|
114
118
|
homepage: https://github.com/rlane/rbvmomi
|
115
119
|
licenses: []
|
data/README.html
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
<h1>RbVmomi</h1>
|
2
|
-
|
3
|
-
<h2>Introduction</h2>
|
4
|
-
|
5
|
-
<p>RbVmomi is a Ruby interface to the vSphere API. Like the Perl and Java SDKs,
|
6
|
-
you can use it to manage ESX and VirtualCenter servers. The current release
|
7
|
-
supports the vSphere 4.1 API.</p>
|
8
|
-
|
9
|
-
<h2>Usage</h2>
|
10
|
-
|
11
|
-
<p>A simple example of turning on a VM:</p>
|
12
|
-
|
13
|
-
<pre><code>require 'rbvmomi'
|
14
|
-
conn = RbVmomi.connect host: 'foo', user: 'bar', password: 'baz'
|
15
|
-
dc = conn.serviceInstance.find_datacenter("mydatacenter") or fail "datacenter not found"
|
16
|
-
vm = dc.find_vm("myvm") or fail "VM not found"
|
17
|
-
vm.PowerOn_Task.wait_for_completion
|
18
|
-
</code></pre>
|
19
|
-
|
20
|
-
<p>This code uses several RbVmomi extensions to the VI API for concision. The
|
21
|
-
expanded snippet below uses only standard API calls and should be familiar to
|
22
|
-
users of the Java SDK:</p>
|
23
|
-
|
24
|
-
<pre><code>require 'rbvmomi'
|
25
|
-
conn = RbVmomi.connect host: 'foo', user: 'bar', password: 'baz'
|
26
|
-
rootFolder = conn.serviceInstance.content.rootFolder
|
27
|
-
dc = rootFolder.childEntity.grep(RbVmomi::VIM::Datacenter).find { |x| x.name == "mydatacenter" } or fail "datacenter not found"
|
28
|
-
vm = dc.vmFolder.childEntity.grep(RbVmomi::VIM::VirtualMachine).find { |x| x.name == "myvm" } or fail "VM not found"
|
29
|
-
task = vm.PowerOn_Task
|
30
|
-
filter = conn.propertyCollector.CreateFilter(
|
31
|
-
spec: {
|
32
|
-
propSet: [{ type => 'Task', all: false, pathSet: ['info.state']}],
|
33
|
-
objectSet: [{ obj: task }]
|
34
|
-
},
|
35
|
-
partialUpdates: false
|
36
|
-
)
|
37
|
-
ver = ''
|
38
|
-
while true
|
39
|
-
result = conn.propertyCollector.WaitForUpdates(version: ver)
|
40
|
-
ver = result.version
|
41
|
-
break if ['success', ['error'].member? task.info.state
|
42
|
-
end
|
43
|
-
filter.DestroyPropertyFilter
|
44
|
-
raise task.info.error if task.info.state == 'error'
|
45
|
-
</code></pre>
|
46
|
-
|
47
|
-
<p>As you can see, the extensions RbVmomi adds can dramatically decrease the code
|
48
|
-
needed to perform simple tasks while still letting you use the full power of
|
49
|
-
the API when necessary. RbVmomi extensions are often more efficient than a
|
50
|
-
naive implementation; for example, the find_vm method on VIM::Datacenter used
|
51
|
-
in the first example uses the SearchIndex for fast lookups.</p>
|
52
|
-
|
53
|
-
<p>A few important points:</p>
|
54
|
-
|
55
|
-
<ul>
|
56
|
-
<li>Ruby 1.9 is required.</li>
|
57
|
-
<li>Properties are exposed as methods: vm.summary</li>
|
58
|
-
<li>All class, method, parameter, and property names match the <a href="http://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/index.html">official documentation</a>.</li>
|
59
|
-
<li>Data object types can usually be inferred from context, so you may simply use a hash instead.</li>
|
60
|
-
<li>Enumeration values are simply strings.</li>
|
61
|
-
<li>Example code is included in the examples/ directory.</li>
|
62
|
-
<li>A set of helper methods for Trollop is included to speed up development of
|
63
|
-
command line apps. See the included examples for usage.</li>
|
64
|
-
<li>This is a side project of a VMware developer and is entirely unsupported by VMware.</li>
|
65
|
-
</ul>
|
66
|
-
|
67
|
-
<p>Built-in extensions are in lib/rbvmomi/extensions.rb. You are encouraged to
|
68
|
-
reopen VIM classes in your applications and add extensions of your own. If you
|
69
|
-
write something generally useful please send it to me and I'll add it in. One
|
70
|
-
important point about extensions is that since VIM classes are lazily loaded,
|
71
|
-
you need to trigger this loading before you can reopen the class. Putting the
|
72
|
-
class name on a line by itself before reopening is enough.</p>
|
73
|
-
|
74
|
-
<h2>Development</h2>
|
75
|
-
|
76
|
-
<p>Send patches to rlane@vmware.com.</p>
|