rbvmomi 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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>
|