gapinc-rbvmomi 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/.gitignore +11 -0
  2. data/.yardopts +6 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE +19 -0
  5. data/README.rdoc +78 -0
  6. data/Rakefile +47 -0
  7. data/VERSION +1 -0
  8. data/bin/rbvmomish +138 -0
  9. data/devel/analyze-vim-declarations.rb +200 -0
  10. data/devel/analyze-xml.rb +46 -0
  11. data/devel/benchmark.rb +117 -0
  12. data/devel/collisions.rb +18 -0
  13. data/devel/merge-internal-vmodl.rb +59 -0
  14. data/examples/annotate.rb +54 -0
  15. data/examples/cached_ovf_deploy.rb +120 -0
  16. data/examples/clone_vm.rb +84 -0
  17. data/examples/create_vm-1.9.rb +93 -0
  18. data/examples/create_vm.rb +93 -0
  19. data/examples/extraConfig.rb +54 -0
  20. data/examples/lease_tool.rb +102 -0
  21. data/examples/logbundle.rb +63 -0
  22. data/examples/logtail.rb +60 -0
  23. data/examples/nfs_datastore.rb +95 -0
  24. data/examples/power.rb +59 -0
  25. data/examples/readme-1.rb +35 -0
  26. data/examples/readme-2.rb +51 -0
  27. data/examples/run.sh +41 -0
  28. data/examples/screenshot.rb +48 -0
  29. data/examples/vdf.rb +81 -0
  30. data/examples/vm_drs_behavior.rb +76 -0
  31. data/lib/rbvmomi/basic_types.rb +373 -0
  32. data/lib/rbvmomi/connection.rb +268 -0
  33. data/lib/rbvmomi/deserialization.rb +238 -0
  34. data/lib/rbvmomi/fault.rb +17 -0
  35. data/lib/rbvmomi/pbm.rb +66 -0
  36. data/lib/rbvmomi/trivial_soap.rb +114 -0
  37. data/lib/rbvmomi/trollop.rb +70 -0
  38. data/lib/rbvmomi/type_loader.rb +136 -0
  39. data/lib/rbvmomi/utils/admission_control.rb +392 -0
  40. data/lib/rbvmomi/utils/deploy.rb +308 -0
  41. data/lib/rbvmomi/utils/leases.rb +142 -0
  42. data/lib/rbvmomi/utils/perfdump.rb +572 -0
  43. data/lib/rbvmomi/version.rb +3 -0
  44. data/lib/rbvmomi/vim/ComputeResource.rb +51 -0
  45. data/lib/rbvmomi/vim/Datacenter.rb +17 -0
  46. data/lib/rbvmomi/vim/Datastore.rb +68 -0
  47. data/lib/rbvmomi/vim/DynamicTypeMgrAllTypeInfo.rb +75 -0
  48. data/lib/rbvmomi/vim/DynamicTypeMgrDataTypeInfo.rb +20 -0
  49. data/lib/rbvmomi/vim/DynamicTypeMgrManagedTypeInfo.rb +46 -0
  50. data/lib/rbvmomi/vim/Folder.rb +204 -0
  51. data/lib/rbvmomi/vim/HostSystem.rb +174 -0
  52. data/lib/rbvmomi/vim/ManagedEntity.rb +57 -0
  53. data/lib/rbvmomi/vim/ManagedObject.rb +55 -0
  54. data/lib/rbvmomi/vim/ObjectContent.rb +23 -0
  55. data/lib/rbvmomi/vim/ObjectUpdate.rb +23 -0
  56. data/lib/rbvmomi/vim/OvfManager.rb +107 -0
  57. data/lib/rbvmomi/vim/PerfCounterInfo.rb +26 -0
  58. data/lib/rbvmomi/vim/PerformanceManager.rb +85 -0
  59. data/lib/rbvmomi/vim/PropertyCollector.rb +25 -0
  60. data/lib/rbvmomi/vim/ReflectManagedMethodExecuter.rb +30 -0
  61. data/lib/rbvmomi/vim/ResourcePool.rb +55 -0
  62. data/lib/rbvmomi/vim/ServiceInstance.rb +55 -0
  63. data/lib/rbvmomi/vim/Task.rb +65 -0
  64. data/lib/rbvmomi/vim/VirtualMachine.rb +59 -0
  65. data/lib/rbvmomi/vim.rb +99 -0
  66. data/lib/rbvmomi.rb +15 -0
  67. data/test/test_deserialization.rb +380 -0
  68. data/test/test_emit_request.rb +128 -0
  69. data/test/test_exceptions.rb +14 -0
  70. data/test/test_helper.rb +14 -0
  71. data/test/test_misc.rb +24 -0
  72. data/test/test_parse_response.rb +69 -0
  73. data/test/test_serialization.rb +311 -0
  74. data/vmodl.db +0 -0
  75. metadata +175 -0
@@ -0,0 +1,373 @@
1
+ # Copyright (c) 2010 VMware, Inc. All Rights Reserved.
2
+ require 'pp'
3
+ require 'set'
4
+
5
+ module RbVmomi
6
+ module BasicTypes
7
+
8
+ BUILTIN = Set.new %w(ManagedObject DataObject TypeName PropertyPath ManagedObjectReference MethodName MethodFault LocalizedMethodFault KeyValue)
9
+
10
+ class Base
11
+ class << self
12
+ attr_accessor :wsdl_name
13
+
14
+ def init wsdl_name=self.name
15
+ @wsdl_name = wsdl_name
16
+ end
17
+
18
+ def to_s
19
+ @wsdl_name
20
+ end
21
+ end
22
+
23
+ init
24
+ end
25
+
26
+ class ObjectWithProperties < Base
27
+ class << self
28
+ attr_accessor :props_desc
29
+
30
+ def init name=self.name, props=[]
31
+ super name
32
+ @props_desc = props
33
+ @props_desc.each do |d|
34
+ sym = d['name'].to_sym
35
+ define_method(sym) { _get_property sym }
36
+ define_method(:"#{sym}=") { |x| _set_property sym, x }
37
+ end
38
+ end
39
+
40
+ def full_props_set
41
+ @full_props_set ||= Set.new(full_props_desc.map { |x| x['name'] })
42
+ end
43
+
44
+ def full_props_desc
45
+ @full_props_desc ||= (self == ObjectWithProperties ? [] : superclass.full_props_desc) + props_desc
46
+ end
47
+
48
+ def find_prop_desc name
49
+ full_props_desc.find { |x| x['name'] == name.to_s }
50
+ end
51
+ end
52
+
53
+ def _get_property sym
54
+ fail 'unimplemented'
55
+ end
56
+
57
+ def _set_property sym, val
58
+ fail 'unimplemented'
59
+ end
60
+
61
+ init
62
+ end
63
+
64
+ class ObjectWithMethods < ObjectWithProperties
65
+ class << self
66
+ attr_accessor :methods_desc
67
+
68
+ def init name=self.name, props=[], methods={}
69
+ super name, props
70
+ @methods_desc = methods
71
+
72
+ @methods_desc.each do |k,d|
73
+ sym = k.to_sym
74
+ define_method(sym) { |*args| _call sym, *args }
75
+ define_method(:"#{sym}!") { |*args| _call sym, *args }
76
+ end
77
+ end
78
+
79
+ # XXX cache
80
+ def full_methods_desc
81
+ (self == ObjectWithMethods ? {} : superclass.full_methods_desc).merge methods_desc
82
+ end
83
+ end
84
+
85
+ init
86
+ end
87
+
88
+ class DataObject < ObjectWithProperties
89
+ attr_reader :props
90
+
91
+ def self.kind; :data end
92
+
93
+ def initialize props={}
94
+ # Deserialization fast path
95
+ if props == nil
96
+ @props = {}
97
+ return
98
+ end
99
+
100
+ @props = Hash[props.map { |k,v| [k.to_sym, v] }]
101
+ #self.class.full_props_desc.each do |desc|
102
+ #fail "missing required property #{desc['name'].inspect} of #{self.class.wsdl_name}" if @props[desc['name'].to_sym].nil? and not desc['is-optional']
103
+ #end
104
+ @props.each do |k,v|
105
+ fail "unexpected property name #{k}" unless self.class.find_prop_desc(k)
106
+ end
107
+ end
108
+
109
+ def initialize_copy(source)
110
+ super
111
+ @props = @props.dup
112
+ end
113
+
114
+ def _get_property sym
115
+ @props[sym]
116
+ end
117
+
118
+ def [] sym
119
+ _get_property sym
120
+ end
121
+
122
+ def _set_property sym, val
123
+ @props[sym] = val
124
+ end
125
+
126
+ def []= sym, val
127
+ _set_property sym, val
128
+ end
129
+
130
+ def == o
131
+ return false unless o.class == self.class
132
+ keys = (props.keys + o.props.keys).uniq
133
+ keys.all? { |k| props[k] == o.props[k] }
134
+ end
135
+
136
+ alias eql? ==
137
+
138
+ def hash
139
+ props.hash
140
+ end
141
+
142
+ def pretty_print q
143
+ q.text self.class.wsdl_name
144
+ q.group 2 do
145
+ q.text '('
146
+ q.breakable
147
+ props = @props.sort_by { |k,v| k.to_s }
148
+ q.seplist props, nil, :each do |e|
149
+ k, v = e
150
+ q.group do
151
+ q.text k.to_s
152
+ q.text ': '
153
+ q.pp v
154
+ end
155
+ end
156
+ end
157
+ q.breakable
158
+ q.text ')'
159
+ end
160
+
161
+ init
162
+ end
163
+
164
+ class ManagedObject < ObjectWithMethods
165
+ def self.kind; :managed end
166
+
167
+ def initialize connection, ref
168
+ super()
169
+ @connection = connection
170
+ @soap = @connection # XXX deprecated
171
+ @ref = ref
172
+ end
173
+
174
+ def _connection
175
+ @connection
176
+ end
177
+
178
+ def _ref
179
+ @ref
180
+ end
181
+
182
+ def _get_property sym
183
+ ret = @connection.propertyCollector.RetrieveProperties(:specSet => [{
184
+ :propSet => [{ :type => self.class.wsdl_name, :pathSet => [sym.to_s] }],
185
+ :objectSet => [{ :obj => self }],
186
+ }])[0]
187
+
188
+ if ret.propSet.empty?
189
+ return nil if ret.missingSet.empty?
190
+ raise ret.missingSet[0].fault
191
+ else
192
+ ret.propSet[0].val
193
+ end
194
+ end
195
+
196
+ def _set_property sym, val
197
+ fail 'unimplemented'
198
+ end
199
+
200
+ def _call method, o={}
201
+ fail "parameters must be passed as a hash" unless o.is_a? Hash
202
+ desc = self.class.full_methods_desc[method.to_s] or fail "unknown method"
203
+ @connection.call method, desc, self, o
204
+ end
205
+
206
+ def to_s
207
+ "#{self.class.wsdl_name}(#{@ref.inspect})"
208
+ end
209
+
210
+ def pretty_print pp
211
+ pp.text to_s
212
+ end
213
+
214
+ def [] k
215
+ _get_property k
216
+ end
217
+
218
+ def == x
219
+ out = (x.class == self.class && x._ref == @ref)
220
+ out = (out && x._connection.instanceUuid == self._connection.instanceUuid)
221
+ out
222
+ end
223
+
224
+ alias eql? ==
225
+
226
+ def hash
227
+ [self.class, @ref].hash
228
+ end
229
+
230
+ init 'ManagedObject'
231
+ end
232
+
233
+ class Enum < Base
234
+ class << self
235
+ attr_accessor :values
236
+
237
+ def init name=self.name, values=[]
238
+ super name
239
+ @values = values
240
+ end
241
+ end
242
+
243
+ def self.kind; :enum end
244
+
245
+ attr_reader :value
246
+
247
+ def initialize value
248
+ @value = value
249
+ end
250
+
251
+ init
252
+ end
253
+
254
+ class MethodFault < DataObject
255
+ init 'MethodFault', [
256
+ {
257
+ 'name' => 'faultCause',
258
+ 'wsdl_type' => 'LocalizedMethodFault',
259
+ 'is-array' => false,
260
+ 'is-optional' => true,
261
+ }, {
262
+ 'name' => 'faultMessage',
263
+ 'wsdl_type' => 'LocalizableMessage',
264
+ 'is-array' => true,
265
+ 'is-optional' => true,
266
+ },
267
+ ]
268
+
269
+ def self.=== exn
270
+ exn.class == RbVmomi::Fault and self <= exn.fault.class
271
+ end
272
+ end
273
+
274
+ class LocalizedMethodFault < DataObject
275
+ init 'LocalizedMethodFault', [
276
+ {
277
+ 'name' => 'fault',
278
+ 'wsdl_type' => 'MethodFault',
279
+ 'is-array' => false,
280
+ 'is-optional' => false,
281
+ }, {
282
+ 'name' => 'localizedMessage',
283
+ 'wsdl_type' => 'xsd:string',
284
+ 'is-array' => false,
285
+ 'is-optional' => true,
286
+ },
287
+ ]
288
+
289
+ def exception
290
+ RbVmomi::Fault.new(self.localizedMessage, self.fault)
291
+ end
292
+ end
293
+
294
+ class RuntimeFault < MethodFault
295
+ init
296
+ end
297
+
298
+ class MethodName < String
299
+ def self.wsdl_name; 'MethodName' end
300
+ end
301
+
302
+ class PropertyPath < String
303
+ def self.wsdl_name; 'PropertyPath' end
304
+ end
305
+
306
+ class TypeName < String
307
+ def self.wsdl_name; 'TypeName' end
308
+ end
309
+
310
+ class ManagedObjectReference
311
+ def self.wsdl_name; 'ManagedObjectReference' end
312
+ end
313
+
314
+ class Boolean
315
+ def self.wsdl_name; 'xsd:boolean' end
316
+ end
317
+
318
+ class AnyType
319
+ def self.wsdl_name; 'xsd:anyType' end
320
+ end
321
+
322
+ class Binary
323
+ def self.wsdl_name; 'xsd:base64Binary' end
324
+ end
325
+
326
+ class ::Class
327
+ def wsdl_name; self.class.name end
328
+ end
329
+
330
+ class ::String
331
+ def self.wsdl_name; 'xsd:string' end
332
+ end
333
+
334
+ class ::Integer
335
+ def self.wsdl_name; 'xsd:int' end
336
+ end
337
+
338
+ class ::Float
339
+ def self.wsdl_name; 'xsd:float' end
340
+ end
341
+
342
+ class Int
343
+ def self.wsdl_name; 'xsd:int' end
344
+
345
+ def initialize x
346
+ @val = x
347
+ end
348
+
349
+ def to_s
350
+ @val.to_s
351
+ end
352
+ end
353
+
354
+ class KeyValue
355
+ def self.wsdl_name; 'KeyValue' end
356
+ attr_accessor :key, :value
357
+
358
+ def initialize k, v
359
+ @key = k
360
+ @value = v
361
+ end
362
+
363
+ def [] i
364
+ if i == 0 then @key
365
+ elsif i == 1 then @value
366
+ else fail "invalid index #{i.inspect}"
367
+ end
368
+ end
369
+ end
370
+
371
+
372
+ end
373
+ end
@@ -0,0 +1,268 @@
1
+ # Copyright (c) 2010 VMware, Inc. All Rights Reserved.
2
+ require 'time'
3
+ require 'date'
4
+ require 'rbvmomi/trivial_soap'
5
+ require 'rbvmomi/basic_types'
6
+ require 'rbvmomi/fault'
7
+ require 'rbvmomi/type_loader'
8
+ require 'rbvmomi/deserialization'
9
+
10
+ module RbVmomi
11
+
12
+ IS_JRUBY = RUBY_PLATFORM == 'java'
13
+
14
+ class DeserializationFailed < Exception; end
15
+
16
+ class Connection < TrivialSoap
17
+ NS_XSI = 'http://www.w3.org/2001/XMLSchema-instance'
18
+
19
+ attr_accessor :rev
20
+ attr_reader :profile
21
+ attr_reader :profile_summary
22
+ attr_accessor :profiling
23
+ attr_reader :deserializer
24
+
25
+ def initialize opts
26
+ @ns = opts[:ns] or fail "no namespace specified"
27
+ @rev = opts[:rev] or fail "no revision specified"
28
+ @deserializer = Deserializer.new self
29
+ reset_profiling
30
+ @profiling = false
31
+ super opts
32
+ end
33
+
34
+ def reset_profiling
35
+ @profile = {}
36
+ @profile_summary = {:network_latency => 0, :request_emit => 0, :response_parse => 0, :num_calls => 0}
37
+ end
38
+
39
+ def emit_request xml, method, descs, this, params
40
+ xml.tag! method, :xmlns => @ns do
41
+ obj2xml xml, '_this', 'ManagedObject', false, this
42
+ descs.each do |d|
43
+ k = d['name']
44
+ k = k.to_sym if !params.member?(k) && params.member?(k.to_sym)
45
+ v = params[k]
46
+ if not v == nil
47
+ obj2xml xml, d['name'], d['wsdl_type'], d['is-array'], v
48
+ else
49
+ fail "missing required parameter #{d['name']}" unless d['is-optional']
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ def parse_response resp, desc
56
+ if resp.at('faultcode')
57
+ detail = resp.at('detail')
58
+ fault = detail && @deserializer.deserialize(detail.children.first, 'MethodFault')
59
+ msg = resp.at('faultstring').text
60
+ if fault
61
+ raise RbVmomi::Fault.new(msg, fault)
62
+ else
63
+ fail "#{resp.at('faultcode').text}: #{msg}"
64
+ end
65
+ else
66
+ if desc
67
+ type = desc['is-task'] ? 'Task' : desc['wsdl_type']
68
+ returnvals = resp.children.select(&:element?).map { |c| @deserializer.deserialize c, type }
69
+ (desc['is-array'] && !desc['is-task']) ? returnvals : returnvals.first
70
+ else
71
+ nil
72
+ end
73
+ end
74
+ end
75
+
76
+ def call method, desc, this, params
77
+ fail "this is not a managed object" unless this.is_a? BasicTypes::ManagedObject
78
+ fail "parameters must be passed as a hash" unless params.is_a? Hash
79
+ fail unless desc.is_a? Hash
80
+
81
+ t1 = Time.now
82
+ body = soap_envelope do |xml|
83
+ emit_request xml, method, desc['params'], this, params
84
+ end.target!
85
+
86
+ t2 = Time.now
87
+ resp, resp_size = request "#{@ns}/#{@rev}", body
88
+
89
+ t3 = Time.now
90
+ out = parse_response resp, desc['result']
91
+
92
+ if @profiling
93
+ t4 = Time.now
94
+ @profile[method] ||= []
95
+ profile_info = {
96
+ :network_latency => (t3 - t2),
97
+ :request_emit => t2 - t1,
98
+ :response_parse => t4 - t3,
99
+ :params => params,
100
+ :obj => this,
101
+ :backtrace => caller,
102
+ :request_size => body.length,
103
+ :response_size => resp_size,
104
+ }
105
+ @profile[method] << profile_info
106
+ @profile_summary[:network_latency] += profile_info[:network_latency]
107
+ @profile_summary[:response_parse] += profile_info[:response_parse]
108
+ @profile_summary[:request_emit] += profile_info[:request_emit]
109
+ @profile_summary[:num_calls] += 1
110
+ end
111
+
112
+ out
113
+ end
114
+
115
+ # hic sunt dracones
116
+ def obj2xml xml, name, type, is_array, o, attrs={}
117
+ expected = type(type)
118
+ fail "expected array, got #{o.class.wsdl_name}" if is_array and not (o.is_a? Array or (o.is_a? Hash and expected == BasicTypes::KeyValue))
119
+ case o
120
+ when Array, BasicTypes::KeyValue
121
+ if o.is_a? BasicTypes::KeyValue and expected != BasicTypes::KeyValue
122
+ fail "expected #{expected.wsdl_name}, got KeyValue"
123
+ elsif expected == BasicTypes::KeyValue and not is_array
124
+ xml.tag! name, attrs do
125
+ xml.tag! 'key', o[0].to_s
126
+ xml.tag! 'value', o[1].to_s
127
+ end
128
+ else
129
+ fail "expected #{expected.wsdl_name}, got array" unless is_array
130
+ o.each do |e|
131
+ obj2xml xml, name, expected.wsdl_name, false, e, attrs
132
+ end
133
+ end
134
+ when BasicTypes::ManagedObject
135
+ fail "expected #{expected.wsdl_name}, got #{o.class.wsdl_name} for field #{name.inspect}" if expected and not expected >= o.class and not expected == BasicTypes::AnyType
136
+ xml.tag! name, o._ref, :type => o.class.wsdl_name
137
+ when BasicTypes::DataObject
138
+ fail "expected #{expected.wsdl_name}, got #{o.class.wsdl_name} for field #{name.inspect}" if expected and not expected >= o.class and not expected == BasicTypes::AnyType
139
+ xml.tag! name, attrs.merge("xsi:type" => o.class.wsdl_name) do
140
+ o.class.full_props_desc.each do |desc|
141
+ if o.props.member? desc['name'].to_sym
142
+ v = o.props[desc['name'].to_sym]
143
+ next if v.nil?
144
+ obj2xml xml, desc['name'], desc['wsdl_type'], desc['is-array'], v
145
+ end
146
+ end
147
+ end
148
+ when BasicTypes::Enum
149
+ xml.tag! name, o.value.to_s, attrs
150
+ when Hash
151
+ if expected == BasicTypes::KeyValue and is_array
152
+ obj2xml xml, name, type, is_array, o.to_a, attrs
153
+ else
154
+ fail "expected #{expected.wsdl_name}, got a hash" unless expected <= BasicTypes::DataObject
155
+ obj2xml xml, name, type, false, expected.new(o), attrs
156
+ end
157
+ when true, false
158
+ fail "expected #{expected.wsdl_name}, got a boolean" unless [BasicTypes::Boolean, BasicTypes::AnyType].member? expected
159
+ attrs['xsi:type'] = 'xsd:boolean' if expected == BasicTypes::AnyType
160
+ xml.tag! name, (o ? '1' : '0'), attrs
161
+ when Symbol, String
162
+ if expected == BasicTypes::Binary
163
+ attrs['xsi:type'] = 'xsd:base64Binary' if expected == BasicTypes::AnyType
164
+ xml.tag! name, [o].pack('m').chomp.gsub("\n", ""), attrs
165
+ else
166
+ attrs['xsi:type'] = 'xsd:string' if expected == BasicTypes::AnyType
167
+ xml.tag! name, o.to_s, attrs
168
+ end
169
+ when Integer
170
+ attrs['xsi:type'] = 'xsd:long' if expected == BasicTypes::AnyType
171
+ xml.tag! name, o.to_s, attrs
172
+ when Float
173
+ attrs['xsi:type'] = 'xsd:double' if expected == BasicTypes::AnyType
174
+ xml.tag! name, o.to_s, attrs
175
+ when DateTime
176
+ attrs['xsi:type'] = 'xsd:dateTime' if expected == BasicTypes::AnyType
177
+ xml.tag! name, o.strftime('%FT%T%:z'), attrs
178
+ when Time
179
+ attrs['xsi:type'] = 'xsd:dateTime' if expected == BasicTypes::AnyType
180
+ xml.tag! name, o.iso8601, attrs
181
+ when BasicTypes::Int
182
+ attrs['xsi:type'] = 'xsd:int'
183
+ xml.tag! name, o.to_s, attrs
184
+ else fail "unexpected object class #{o.class}"
185
+ end
186
+ xml
187
+ rescue
188
+ $stderr.puts "#{$!.class} while serializing #{name} (#{type}):"
189
+ PP.pp o, $stderr
190
+ raise
191
+ end
192
+
193
+ def self.type name
194
+ fail unless name and (name.is_a? String or name.is_a? Symbol)
195
+ name = $' if name.to_s =~ /^xsd:/
196
+ case name.to_sym
197
+ when :anyType then BasicTypes::AnyType
198
+ when :boolean then BasicTypes::Boolean
199
+ when :string then String
200
+ when :int, :long, :short, :byte then Integer
201
+ when :float, :double then Float
202
+ when :dateTime then Time
203
+ when :base64Binary then BasicTypes::Binary
204
+ when :KeyValue then BasicTypes::KeyValue
205
+ else
206
+ first_char = name[0].chr
207
+ if first_char.downcase == first_char
208
+ name = "%s%s" % [first_char.upcase, name[1..-1]]
209
+ end
210
+
211
+ if @loader.has? name
212
+ const_get(name)
213
+ else
214
+ fail "no such type #{name.inspect}"
215
+ end
216
+ end
217
+ end
218
+
219
+ def type name
220
+ self.class.type name
221
+ end
222
+
223
+ def instanceUuid
224
+ nil
225
+ end
226
+
227
+ def self.extension_dirs
228
+ @extension_dirs ||= []
229
+ end
230
+
231
+ def self.add_extension_dir dir
232
+ extension_dirs << dir
233
+ @loader.reload_extensions_dir dir if @loader
234
+ end
235
+
236
+ def self.reload_extensions
237
+ @loader.reload_extensions
238
+ end
239
+
240
+ def self.loader; @loader; end
241
+
242
+ protected
243
+
244
+ def self.const_missing sym
245
+ name = sym.to_s
246
+ if @loader and @loader.has? name
247
+ @loader.get(name)
248
+ else
249
+ super
250
+ end
251
+ end
252
+
253
+ def self.method_missing sym, *a
254
+ name = sym.to_s
255
+ if @loader and @loader.has? name
256
+ @loader.get(name).new(*a)
257
+ else
258
+ super
259
+ end
260
+ end
261
+
262
+ def self.load_vmodl fn
263
+ @loader = RbVmomi::TypeLoader.new fn, extension_dirs, self
264
+ nil
265
+ end
266
+ end
267
+
268
+ end