rbvmomi 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.yardopts +5 -0
  2. data/README.rdoc +71 -0
  3. data/Rakefile +11 -0
  4. data/VERSION +1 -1
  5. data/devel/analyze-xml.rb +29 -29
  6. data/{test/test.rb → examples/create_vm.rb} +40 -15
  7. data/examples/extraConfig.rb +54 -0
  8. data/examples/power.rb +57 -0
  9. data/examples/readme-1.rb +35 -0
  10. data/examples/readme-2.rb +51 -0
  11. data/lib/rbvmomi.rb +3 -282
  12. data/lib/rbvmomi/{types.rb → basic_types.rb} +37 -97
  13. data/lib/rbvmomi/connection.rb +239 -0
  14. data/lib/rbvmomi/fault.rb +17 -0
  15. data/lib/{trivial_soap.rb → rbvmomi/trivial_soap.rb} +31 -13
  16. data/lib/rbvmomi/trollop.rb +6 -2
  17. data/lib/rbvmomi/type_loader.rb +72 -0
  18. data/lib/rbvmomi/vim.rb +76 -0
  19. data/lib/rbvmomi/vim/ComputeResource.rb +51 -0
  20. data/lib/rbvmomi/vim/Datacenter.rb +17 -0
  21. data/lib/rbvmomi/vim/Datastore.rb +68 -0
  22. data/lib/rbvmomi/vim/Folder.rb +112 -0
  23. data/lib/rbvmomi/vim/ManagedEntity.rb +46 -0
  24. data/lib/rbvmomi/vim/ManagedObject.rb +55 -0
  25. data/lib/rbvmomi/vim/ObjectContent.rb +23 -0
  26. data/lib/rbvmomi/vim/ObjectUpdate.rb +23 -0
  27. data/lib/rbvmomi/vim/OvfManager.rb +93 -0
  28. data/lib/rbvmomi/vim/ResourcePool.rb +18 -0
  29. data/lib/rbvmomi/vim/ServiceInstance.rb +53 -0
  30. data/lib/rbvmomi/vim/Task.rb +31 -0
  31. data/lib/rbvmomi/vim/VirtualMachine.rb +7 -0
  32. data/test/test_deserialization.rb +11 -55
  33. data/test/test_emit_request.rb +13 -10
  34. data/test/test_exceptions.rb +16 -0
  35. data/test/test_parse_response.rb +2 -10
  36. data/test/test_serialization.rb +14 -11
  37. metadata +41 -25
  38. data/.gitignore +0 -4
  39. data/README.md +0 -12
  40. data/lib/rbvmomi/extensions.rb +0 -491
  41. data/lib/rbvmomi/profile.rb +0 -22
  42. data/test/runner.rb +0 -3
data/.gitignore DELETED
@@ -1,4 +0,0 @@
1
- *.swp
2
- pkg/
3
- *.gemspec
4
- vmodl
data/README.md DELETED
@@ -1,12 +0,0 @@
1
- RbVmomi
2
- =======
3
-
4
- Introduction
5
- ------------
6
-
7
- RbVmomi is a Ruby interface to the VI API.
8
-
9
- Contributing
10
- ------------
11
-
12
- Send patches to rlane@vmware.com.
@@ -1,491 +0,0 @@
1
- # Copyright (c) 2010 VMware, Inc. All Rights Reserved.
2
- CURLBIN = ENV['CURL'] || "curl"
3
-
4
- module RbVmomi::VIM
5
-
6
- class ManagedObject
7
- def wait version, *pathSet
8
- version ||= ''
9
- all = pathSet.empty?
10
- filter = @soap.propertyCollector.CreateFilter :spec => {
11
- :propSet => [{ :type => self.class.wsdl_name, :all => all, :pathSet => pathSet }],
12
- :objectSet => [{ :obj => self }],
13
- }, :partialUpdates => false
14
- result = @soap.propertyCollector.WaitForUpdates(version: version)
15
- filter.DestroyPropertyFilter
16
- changes = result.filterSet[0].objectSet[0].changeSet
17
- changes.map { |h| [h.name.split('.').map(&:to_sym), h.val] }.each do |path,v|
18
- k = path.pop
19
- o = path.inject(self) { |b,k| b[k] }
20
- o._set_property k, v unless o == self
21
- end
22
- result.version
23
- end
24
-
25
- def wait_until *pathSet, &b
26
- ver = nil
27
- loop do
28
- ver = wait ver, *pathSet
29
- if x = b.call
30
- return x
31
- end
32
- end
33
- end
34
-
35
- def collect! *props
36
- spec = {
37
- objectSet: [{ obj: self }],
38
- propSet: [{
39
- pathSet: props,
40
- type: self.class.wsdl_name
41
- }]
42
- }
43
- @soap.propertyCollector.RetrieveProperties(specSet: [spec])[0].to_hash
44
- end
45
-
46
- def collect *props
47
- h = collect! *props
48
- a = props.map { |k| h[k.to_s] }
49
- if block_given?
50
- yield a
51
- else
52
- a
53
- end
54
- end
55
- end
56
-
57
- ManagedEntity
58
- class ManagedEntity
59
- def path
60
- filterSpec = VIM.PropertyFilterSpec(
61
- objectSet: [{
62
- obj: self,
63
- selectSet: [
64
- VIM.TraversalSpec(
65
- name: 'tsME',
66
- type: 'ManagedEntity',
67
- path: 'parent',
68
- skip: false,
69
- selectSet: [
70
- VIM.SelectionSpec(name: 'tsME')
71
- ]
72
- )
73
- ]
74
- }],
75
- propSet: [{
76
- pathSet: %w(name parent),
77
- type: 'ManagedEntity'
78
- }]
79
- )
80
-
81
- result = @soap.propertyCollector.RetrieveProperties(specSet: [filterSpec])
82
-
83
- tree = {}
84
- result.each { |x| tree[x.obj] = [x['parent'], x['name']] }
85
- a = []
86
- cur = self
87
- while cur
88
- parent, name = *tree[cur]
89
- a << [cur, name]
90
- cur = parent
91
- end
92
- a.reverse
93
- end
94
- end
95
-
96
- Task
97
- class Task
98
- def wait_for_completion
99
- wait_until('info.state') { %w(success error).member? info.state }
100
- case info.state
101
- when 'success'
102
- info.result
103
- when 'error'
104
- raise info.error
105
- end
106
- end
107
-
108
- def wait_for_progress
109
- wait_until('info.state', 'info.progress') do
110
- yield info.progress if block_given?
111
- %w(success error).member? info.state
112
- end
113
- case info.state
114
- when 'success'
115
- info.result
116
- when 'error'
117
- raise info.error
118
- end
119
- end
120
- end
121
-
122
- Folder
123
- class Folder
124
- def find name, type=Object
125
- x = @soap.searchIndex.FindChild(entity: self, name: name)
126
- x if x.is_a? type
127
- end
128
-
129
- def traverse! path, type=Object
130
- traverse path, type, true
131
- end
132
-
133
- def traverse path, type=Object, create=false
134
- es = path.split('/').reject(&:empty?)
135
- return self if es.empty?
136
- final = es.pop
137
-
138
- p = es.inject(self) do |f,e|
139
- f.find(e, Folder) || (create && f.CreateFolder(name: e)) || return
140
- end
141
-
142
- if x = p.find(final, type)
143
- x
144
- elsif create and type == Folder
145
- p.CreateFolder(name: final)
146
- else
147
- nil
148
- end
149
- end
150
-
151
- def children
152
- childEntity
153
- end
154
-
155
- def ls
156
- Hash[children.map { |x| [x.name, x] }]
157
- end
158
-
159
- def inventory propSpecs={}
160
- propSet = [{ type: 'Folder', pathSet: ['name', 'parent'] }]
161
- propSpecs.each do |k,v|
162
- case k
163
- when VIM::ManagedEntity
164
- k = k.wsdl_name
165
- when Symbol, String
166
- k = k.to_s
167
- else
168
- fail "key must be a ManagedEntity"
169
- end
170
-
171
- h = { type: k }
172
- if v == :all
173
- h[:all] = true
174
- elsif v.is_a? Array
175
- h[:pathSet] = v + %w(parent)
176
- else
177
- fail "value must be an array of property paths or :all"
178
- end
179
- propSet << h
180
- end
181
-
182
- filterSpec = VIM.PropertyFilterSpec(
183
- objectSet: [
184
- obj: self,
185
- selectSet: [
186
- VIM.TraversalSpec(
187
- name: 'tsFolder',
188
- type: 'Folder',
189
- path: 'childEntity',
190
- skip: false,
191
- selectSet: [
192
- VIM.SelectionSpec(name: 'tsFolder')
193
- ]
194
- )
195
- ]
196
- ],
197
- propSet: propSet
198
- )
199
-
200
- result = @soap.propertyCollector.RetrieveProperties(specSet: [filterSpec])
201
-
202
- tree = { self => {} }
203
- result.each do |x|
204
- obj = x.obj
205
- next if obj == self
206
- h = Hash[x.propSet.map { |y| [y.name, y.val] }]
207
- tree[h['parent']][h['name']] = [obj, h]
208
- tree[obj] = {} if obj.is_a? VIM::Folder
209
- end
210
- tree
211
- end
212
- end
213
-
214
- Datastore
215
- class Datastore
216
- def datacenter
217
- return @datacenter if @datacenter
218
- x = parent
219
- while not x.is_a? Datacenter
220
- x = x.parent
221
- end
222
- fail unless x.is_a? Datacenter
223
- @datacenter = x
224
- end
225
-
226
- def mkuripath path
227
- "/folder/#{URI.escape path}?dcPath=#{URI.escape datacenter.name}&dsName=#{URI.escape name}"
228
- end
229
-
230
- def exists? path
231
- req = Net::HTTP::Head.new mkuripath(path)
232
- req.initialize_http_header 'cookie' => @soap.cookie
233
- resp = @soap.http.request req
234
- case resp
235
- when Net::HTTPSuccess
236
- true
237
- when Net::HTTPNotFound
238
- false
239
- else
240
- fail resp.inspect
241
- end
242
- end
243
-
244
- def download remote_path, local_path
245
- url = "http#{@soap.http.use_ssl? ? 's' : ''}://#{@soap.http.address}:#{@soap.http.port}#{mkuripath(remote_path)}"
246
- pid = spawn CURLBIN, "-k", '--noproxy', '*', '-f',
247
- "-o", local_path,
248
- "-b", @soap.cookie,
249
- url,
250
- out: '/dev/null'
251
- Process.waitpid(pid, 0)
252
- fail "download failed" unless $?.success?
253
- end
254
-
255
- def upload remote_path, local_path
256
- url = "http#{@soap.http.use_ssl? ? 's' : ''}://#{@soap.http.address}:#{@soap.http.port}#{mkuripath(remote_path)}"
257
- pid = spawn CURLBIN, "-k", '--noproxy', '*', '-f',
258
- "-T", local_path,
259
- "-b", @soap.cookie,
260
- url,
261
- out: '/dev/null'
262
- Process.waitpid(pid, 0)
263
- fail "upload failed" unless $?.success?
264
- end
265
- end
266
-
267
- ServiceInstance
268
- class ServiceInstance
269
- def find_datacenter path=nil
270
- if path
271
- content.rootFolder.traverse path, VIM::Datacenter
272
- else
273
- content.rootFolder.childEntity.grep(VIM::Datacenter).first
274
- end
275
- end
276
-
277
- def wait_for_multiple_tasks interested, tasks
278
- version = ''
279
- interested = (interested + ['info.state']).uniq
280
- task_props = Hash.new { |h,k| h[k] = {} }
281
-
282
- filter = @soap.propertyCollector.CreateFilter :spec => {
283
- :propSet => [{ :type => 'Task', :all => false, :pathSet => interested }],
284
- :objectSet => tasks.map { |x| { :obj => x } },
285
- }, :partialUpdates => false
286
-
287
- begin
288
- until task_props.size == tasks.size and task_props.all? { |k,h| %w(success error).member? h['info.state'] }
289
- result = @soap.propertyCollector.WaitForUpdates(version: version)
290
- version = result.version
291
- os = result.filterSet[0].objectSet
292
-
293
- os.each do |o|
294
- changes = Hash[o.changeSet.map { |x| [x.name, x.val] }]
295
-
296
- interested.each do |k|
297
- task = tasks.find { |x| x._ref == o.obj._ref }
298
- task_props[task][k] = changes[k] if changes.member? k
299
- end
300
- end
301
-
302
- yield task_props
303
- end
304
- ensure
305
- @soap.propertyCollector.CancelWaitForUpdates
306
- filter.DestroyPropertyFilter
307
- end
308
- end
309
- end
310
-
311
- Datacenter
312
- class Datacenter
313
- def find_compute_resource path=nil
314
- if path
315
- hostFolder.traverse path, VIM::ComputeResource
316
- else
317
- hostFolder.childEntity.grep(VIM::ComputeResource).first
318
- end
319
- end
320
-
321
- def find_datastore name
322
- datastore.find { |x| x.name == name }
323
- end
324
-
325
- def find_vm folder_path, name
326
- vmFolder.traverse "#{folder_path}/#{name}", VIM::VirtualMachine
327
- end
328
- end
329
-
330
- VirtualMachine
331
- class VirtualMachine
332
- def macs
333
- Hash[self.config.hardware.device.grep(VIM::VirtualEthernetCard).map { |x| [x.deviceInfo.label, x.macAddress] }]
334
- end
335
- end
336
-
337
- ObjectContent
338
- class ObjectContent
339
- def [](k)
340
- to_hash[k]
341
- end
342
-
343
- def to_hash_uncached
344
- h = {}
345
- propSet.each do |x|
346
- fail if h.member? x.name
347
- h[x.name] = x.val
348
- end
349
- h
350
- end
351
-
352
- def to_hash
353
- @cached_hash ||= to_hash_uncached
354
- end
355
- end
356
-
357
- OvfManager
358
- class OvfManager
359
-
360
- # Parameters:
361
- # uri
362
- # vmName
363
- # vmFolder
364
- # host
365
- # resourcePool
366
- # datastore
367
- # networkMappings = {}
368
- # propertyMappings = {}
369
- # diskProvisioning = :thin
370
- def deployOVF opts={}
371
- opts = { networkMappings: {},
372
- propertyMappings: {},
373
- diskProvisioning: :thin }.merge opts
374
-
375
- %w(uri vmName vmFolder host resourcePool datastore).each do |k|
376
- fail "parameter #{k} required" unless opts[k.to_sym]
377
- end
378
-
379
- ovfImportSpec = VIM::OvfCreateImportSpecParams(
380
- hostSystem: opts[:host],
381
- locale: "US",
382
- entityName: opts[:vmName],
383
- deploymentOption: "",
384
- networkMapping: opts[:networkMappings].map{|from, to| VIM::OvfNetworkMapping(name: from, network: to)},
385
- propertyMapping: opts[:propertyMappings].map{|key, value| VIM::KeyValue(key: key, value: value)},
386
- diskProvisioning: opts[:diskProvisioning]
387
- )
388
-
389
- result = CreateImportSpec(
390
- ovfDescriptor: open(opts[:uri]).read,
391
- resourcePool: opts[:resourcePool],
392
- datastore: opts[:datastore],
393
- cisp: ovfImportSpec
394
- )
395
-
396
- raise result.error[0].localizedMessage if result.error && !result.error.empty?
397
-
398
- if result.warning
399
- result.warning.each{|x| puts "OVF Warning: #{x.localizedMessage.chomp}" }
400
- end
401
-
402
- nfcLease = opts[:resourcePool].ImportVApp(spec: result.importSpec,
403
- folder: opts[:vmFolder],
404
- host: opts[:host])
405
-
406
- nfcLease.wait_until(:state) { nfcLease.state != "initializing" }
407
- raise nfcLease.error if nfcLease.state == "error"
408
-
409
- begin
410
- nfcLease.HttpNfcLeaseProgress(percent: 5)
411
- progress = 0.0
412
- result.fileItem.each do |fileItem|
413
- deviceUrl = nfcLease.info.deviceUrl.find{|x| x.importKey == fileItem.deviceId}
414
- if !deviceUrl
415
- raise "Couldn't find deviceURL for device '#{fileItem.deviceId}'"
416
- end
417
-
418
- # XXX handle file:// URIs
419
- ovfFilename = opts[:uri].to_s
420
- tmp = ovfFilename.split(/\//)
421
- tmp.pop
422
- tmp << fileItem.path
423
- filename = tmp.join("/")
424
-
425
- method = fileItem.create ? "PUT" : "POST"
426
-
427
- href = deviceUrl.url.gsub("*", opts[:host].config.network.vnic[0].spec.ip.ipAddress)
428
- downloadCmd = "#{CURLBIN} -L '#{filename}'"
429
- uploadCmd = "#{CURLBIN} -X #{method} --insecure -T - -H 'Content-Type: application/x-vnd.vmware-streamVmdk' -H 'Content-Length: #{fileItem.size}' '#{href}'"
430
- system("#{downloadCmd} | #{uploadCmd}")
431
- progress += (95.0 / result.fileItem.length)
432
- nfcLease.HttpNfcLeaseProgress(percent: progress.to_i)
433
- end
434
-
435
- nfcLease.HttpNfcLeaseProgress(percent: 100)
436
- vm = nfcLease.info.entity
437
- nfcLease.HttpNfcLeaseComplete
438
- vm
439
- end
440
- rescue Exception
441
- nfcLease.HttpNfcLeaseAbort
442
- raise
443
- end
444
- end
445
-
446
- ComputeResource
447
- class ComputeResource
448
- def stats
449
- filterSpec = VIM.PropertyFilterSpec(
450
- objectSet: [{
451
- obj: self,
452
- selectSet: [
453
- VIM.TraversalSpec(
454
- name: 'tsHosts',
455
- type: 'ComputeResource',
456
- path: 'host',
457
- skip: false,
458
- )
459
- ]
460
- }],
461
- propSet: [{
462
- pathSet: %w(name overallStatus summary.hardware.cpuMhz
463
- summary.hardware.numCpuCores summary.hardware.memorySize
464
- summary.quickStats.overallCpuUsage
465
- summary.quickStats.overallMemoryUsage),
466
- type: 'HostSystem'
467
- }]
468
- )
469
-
470
- result = @soap.propertyCollector.RetrieveProperties(specSet: [filterSpec])
471
-
472
- stats = {
473
- totalCPU: 0,
474
- totalMem: 0,
475
- usedCPU: 0,
476
- usedMem: 0,
477
- }
478
-
479
- result.each do |x|
480
- next if x['overallStatus'] == 'red'
481
- stats[:totalCPU] += x['summary.hardware.cpuMhz'] * x['summary.hardware.numCpuCores']
482
- stats[:totalMem] += x['summary.hardware.memorySize'] / (1024*1024)
483
- stats[:usedCPU] += x['summary.quickStats.overallCpuUsage']
484
- stats[:usedMem] += x['summary.quickStats.overallMemoryUsage']
485
- end
486
-
487
- stats
488
- end
489
- end
490
-
491
- end