rbvmomi 1.0.2 → 1.1.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.
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
@@ -0,0 +1,5 @@
1
+ --title "RbVmomi - a Ruby interface to the vSphere API"
2
+ --no-private
3
+ --readme README.rdoc
4
+ lib/rbvmomi/vim.rb
5
+ lib/rbvmomi/vim/*.rb
@@ -0,0 +1,71 @@
1
+ = RbVmomi
2
+
3
+ == Introduction
4
+
5
+ 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. RbVmomi specific documentation is
8
+ online[http://rdoc.info/github/rlane/rbvmomi/master/frames] and is meant to
9
+ be used alongside the official documentation[http://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/index.html].
10
+
11
+ == Usage
12
+
13
+ A simple example of turning on a VM:
14
+
15
+ require 'rbvmomi'
16
+ vim = RbVmomi::VIM.connect host: 'foo', user: 'bar', password: 'baz'
17
+ dc = vim.serviceInstance.find_datacenter("mydatacenter") or fail "datacenter not found"
18
+ vm = dc.find_vm("myvm") or fail "VM not found"
19
+ vm.PowerOnVM_Task.wait_for_completion
20
+
21
+ This code uses several RbVmomi extensions to the VI API for concision. The
22
+ expanded snippet below uses only standard API calls and should be familiar to
23
+ users of the Java SDK:
24
+
25
+ require 'rbvmomi'
26
+ vim = RbVmomi::VIM.connect host: 'foo', user: 'bar', password: 'baz'
27
+ rootFolder = vim.serviceInstance.content.rootFolder
28
+ dc = rootFolder.childEntity.grep(RbVmomi::VIM::Datacenter).find { |x| x.name == "mydatacenter" } or fail "datacenter not found"
29
+ vm = dc.vmFolder.childEntity.grep(RbVmomi::VIM::VirtualMachine).find { |x| x.name == "myvm" } or fail "VM not found"
30
+ task = vm.PowerOnVM_Task
31
+ filter = vim.propertyCollector.CreateFilter(
32
+ spec: {
33
+ propSet: [{ type: 'Task', all: false, pathSet: ['info.state']}],
34
+ objectSet: [{ obj: task }]
35
+ },
36
+ partialUpdates: false
37
+ )
38
+ ver = ''
39
+ while true
40
+ result = vim.propertyCollector.WaitForUpdates(version: ver)
41
+ ver = result.version
42
+ break if ['success', 'error'].member? task.info.state
43
+ end
44
+ filter.DestroyPropertyFilter
45
+ raise task.info.error if task.info.state == 'error'
46
+
47
+ 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.
52
+
53
+ A few important points:
54
+
55
+ * Ruby 1.9 is required.
56
+ * Properties are exposed as accessor methods.
57
+ * All class, method, parameter, and property names match the official documentation[http://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/index.html].
58
+ * Data object types can usually be inferred from context, so you may use a hash instead.
59
+ * Enumeration values are simply strings.
60
+ * Example code is included in the examples/ directory.
61
+ * A set of helper methods for Trollop is included to speed up development of
62
+ command line apps. See the included examples for usage.
63
+ * This is a side project of a VMware employee and is entirely unsupported by VMware.
64
+
65
+ Built-in extensions are under +lib/rbvmomi/vim/+. You are encouraged to
66
+ reopen VIM classes in your applications and add extensions of your own. If you
67
+ write something generally useful please send it to me and I'll add it in.
68
+
69
+ == Development
70
+
71
+ Send patches to rlane@vmware.com.
data/Rakefile CHANGED
@@ -1,3 +1,7 @@
1
+ require 'rake/testtask'
2
+ require 'rake/rdoctask'
3
+ require 'yard'
4
+
1
5
  begin
2
6
  require 'jeweler'
3
7
  Jeweler::Tasks.new do |gem|
@@ -18,3 +22,10 @@ rescue LoadError
18
22
  puts "Jeweler not available. Install it with: gem install jeweler"
19
23
  end
20
24
 
25
+ Rake::TestTask.new do |t|
26
+ t.libs << "test"
27
+ t.test_files = FileList['test/test_*.rb']
28
+ t.verbose = true
29
+ end
30
+
31
+ YARD::Rake::YardocTask.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.2
1
+ 1.1.0
@@ -2,45 +2,45 @@ require 'nokogiri'
2
2
 
3
3
  # removes line breaks and whitespace between xml nodes.
4
4
  def prepare_xml(xml)
5
- xml = xml.gsub(/\n+/, "")
6
- xml = xml.gsub(/(>)\s*(<)/, '\1\2')
5
+ xml = xml.gsub(/\n+/, "")
6
+ xml = xml.gsub(/(>)\s*(<)/, '\1\2')
7
7
  end
8
8
 
9
9
  def analyze_xml x, tree
10
- subtree = (tree[x.name] ||= { :attributes => [], :min_occur => nil, :max_occur => nil })
11
- attrs = x.attributes.keys.sort
12
- subtree[:attributes] << attrs unless subtree[:attributes].member? attrs
10
+ subtree = (tree[x.name] ||= { :attributes => [], :min_occur => nil, :max_occur => nil })
11
+ attrs = x.attributes.keys.sort
12
+ subtree[:attributes] << attrs unless subtree[:attributes].member? attrs
13
13
 
14
- child_occurs = Hash.new 0
15
- x.children.select(&:element?).each do |c|
16
- child_occurs[c.name] += 1
17
- analyze_xml c, subtree
18
- end
14
+ child_occurs = Hash.new 0
15
+ x.children.select(&:element?).each do |c|
16
+ child_occurs[c.name] += 1
17
+ analyze_xml c, subtree
18
+ end
19
19
 
20
- subtree.select { |k,v| k.is_a? String }.each do |k,v|
21
- v[:min_occur] = [v[:min_occur], child_occurs[k]].compact.min
22
- v[:max_occur] = [v[:max_occur], child_occurs[k]].compact.max
23
- end
20
+ subtree.select { |k,v| k.is_a? String }.each do |k,v|
21
+ v[:min_occur] = [v[:min_occur], child_occurs[k]].compact.min
22
+ v[:max_occur] = [v[:max_occur], child_occurs[k]].compact.max
23
+ end
24
24
  end
25
25
 
26
26
  def print_tree tree, indent=0
27
- tree.select { |k,v| k.is_a? String }.sort.each do |k,v|
28
- attrs = v[:attributes] || []
29
- min, max = v[:min_occur], v[:max_occur]
30
- numsym = if min == 0 and max == 0 then fail
31
- elsif min == 0 and max == 1 then '?'
32
- elsif min == 0 then '*'
33
- elsif min == 1 and max == 1 then ''
34
- else '+'
35
- end
36
- puts "#{' '*indent}#{k}#{numsym}: #{attrs.sort.map { |a| "[#{a * ' '}]"} * ', '} {#{min},#{max}}"
37
- print_tree v, (indent+1)
38
- end
39
- end
27
+ tree.select { |k,v| k.is_a? String }.sort.each do |k,v|
28
+ attrs = v[:attributes] || []
29
+ min, max = v[:min_occur], v[:max_occur]
30
+ numsym = if min == 0 and max == 0 then fail
31
+ elsif min == 0 and max == 1 then '?'
32
+ elsif min == 0 then '*'
33
+ elsif min == 1 and max == 1 then ''
34
+ else '+'
35
+ end
36
+ puts "#{' '*indent}#{k}#{numsym}: #{attrs.sort.map { |a| "[#{a * ' '}]"} * ', '} {#{min},#{max}}"
37
+ print_tree v, (indent+1)
38
+ end
39
+ end
40
40
 
41
41
  tree = {}
42
42
  ARGV.each do |fn|
43
- nk = Nokogiri(prepare_xml(File.read fn))
44
- analyze_xml nk.root, tree
43
+ nk = Nokogiri(prepare_xml(File.read fn))
44
+ analyze_xml nk.root, tree
45
45
  end
46
46
  print_tree tree
@@ -1,23 +1,51 @@
1
1
  #!/usr/bin/env ruby
2
+ require 'trollop'
2
3
  require 'rbvmomi'
3
- include RbVmomi
4
+ require 'rbvmomi/trollop'
4
5
 
5
- vim = RbVmomi.connect ENV['RBVMOMI_URI']
6
+ VIM = RbVmomi::VIM
7
+ N = 2
8
+
9
+ opts = Trollop.options do
10
+ banner <<-EOS
11
+ Create and destroy a couple of VMs.
12
+
13
+ Usage:
14
+ create_vm.rb [options]
15
+
16
+ VIM connection options:
17
+ EOS
18
+
19
+ rbvmomi_connection_opts
20
+
21
+ text <<-EOS
6
22
 
7
- rootFolder = vim.serviceInstance.RetrieveServiceContent.rootFolder
23
+ VM location options:
24
+ EOS
8
25
 
9
- dc = rootFolder.childEntity.first
26
+ rbvmomi_datacenter_opt
27
+
28
+ text <<-EOS
29
+
30
+ Other options:
31
+ EOS
32
+ end
33
+
34
+ Trollop.die("must specify host") unless opts[:host]
35
+ vm_name = ARGV[0] or abort "must specify VM name"
36
+
37
+ vim = VIM.connect opts
38
+ dc = vim.serviceInstance.find_datacenter(opts[:datacenter]) or abort "datacenter not found"
10
39
  vmFolder = dc.vmFolder
11
- vms = vmFolder.childEntity
12
- hosts = dc.hostFolder.childEntity
40
+ hosts = dc.hostFolder.children
13
41
  rp = hosts.first.resourcePool
14
42
 
15
43
  vm_cfg = {
16
- name: 'vm',
17
- guestId: 'otherGuest64',
44
+ name: vm_name,
45
+ guestId: 'otherGuest',
18
46
  files: { vmPathName: '[datastore1]' },
19
- numCPUs: 2,
20
- memoryMB: 3072,
47
+ numCPUs: 1,
48
+ memoryMB: 128,
21
49
  deviceChange: [
22
50
  {
23
51
  operation: :add,
@@ -58,12 +86,9 @@ vm_cfg = {
58
86
  extraConfig: [
59
87
  {
60
88
  key: 'bios.bootOrder',
61
- value: XSD.string('ethernet0')
89
+ value: 'ethernet0'
62
90
  }
63
91
  ]
64
92
  }
65
93
 
66
- N = 2
67
- create_tasks = (0...N).map { vmFolder.CreateVM_Task(:config => vm_cfg, :pool => rp) }
68
- destroy_tasks = create_tasks.map { |x| x.wait_task.Destroy_Task }
69
- destroy_tasks.each { |x| x.wait_task }
94
+ vmFolder.CreateVM_Task(:config => vm_cfg, :pool => rp).wait_for_completion
@@ -0,0 +1,54 @@
1
+ require 'trollop'
2
+ require 'rbvmomi'
3
+ require 'rbvmomi/trollop'
4
+
5
+ VIM = RbVmomi::VIM
6
+ CMDS = %w(list set)
7
+
8
+ opts = Trollop.options do
9
+ banner <<-EOS
10
+ View and modify VM extraConfig options.
11
+
12
+ Usage:
13
+ extraConfig.rb [options] VM list
14
+ extraConfig.rb [options] VM set key=value [key=value...]
15
+
16
+ Commands: #{CMDS * ' '}
17
+
18
+ VIM connection options:
19
+ EOS
20
+
21
+ rbvmomi_connection_opts
22
+
23
+ text <<-EOS
24
+
25
+ VM location options:
26
+ EOS
27
+
28
+ rbvmomi_datacenter_opt
29
+
30
+ text <<-EOS
31
+
32
+ Other options:
33
+ EOS
34
+
35
+ stop_on CMDS
36
+ end
37
+
38
+ vm_name = ARGV[0] or Trollop.die("no VM name given")
39
+ cmd = ARGV[1] or Trollop.die("no command given")
40
+ abort "invalid command" unless CMDS.member? cmd
41
+ Trollop.die("must specify host") unless opts[:host]
42
+
43
+ vim = VIM.connect opts
44
+
45
+ dc = vim.serviceInstance.find_datacenter(opts[:datacenter]) or abort "datacenter not found"
46
+ vm = dc.find_vm(vm_name) or abort "VM not found"
47
+
48
+ case cmd
49
+ when 'list'
50
+ vm.config.extraConfig.each { |x| puts "#{x.key}: #{x.value}" }
51
+ when 'set'
52
+ extraConfig = ARGV.map { |x| x.split("=", 2) }.map { |k,v| { key: k, value: v } }
53
+ vm.ReconfigVM_Task(spec: VIM.VirtualMachineConfigSpec(extraConfig: extraConfig)).wait_for_completion
54
+ end
@@ -0,0 +1,57 @@
1
+ require 'trollop'
2
+ require 'rbvmomi'
3
+ require 'rbvmomi/trollop'
4
+
5
+ VIM = RbVmomi::VIM
6
+ CMDS = %w(on off reset suspend)
7
+
8
+ opts = Trollop.options do
9
+ banner <<-EOS
10
+ Perform VM power operations.
11
+
12
+ Usage:
13
+ power.rb [options] cmd VM
14
+
15
+ Commands: #{CMDS * ' '}
16
+
17
+ VIM connection options:
18
+ EOS
19
+
20
+ rbvmomi_connection_opts
21
+
22
+ text <<-EOS
23
+
24
+ VM location options:
25
+ EOS
26
+
27
+ rbvmomi_datacenter_opt
28
+
29
+ text <<-EOS
30
+
31
+ Other options:
32
+ EOS
33
+
34
+ stop_on CMDS
35
+ end
36
+
37
+ cmd = ARGV[0] or Trollop.die("no command given")
38
+ vm_name = ARGV[1] or Trollop.die("no VM name given")
39
+ Trollop.die("must specify host") unless opts[:host]
40
+
41
+ vim = VIM.connect opts
42
+
43
+ dc = vim.serviceInstance.content.rootFolder.traverse(opts[:datacenter], VIM::Datacenter) or abort "datacenter not found"
44
+ vm = dc.vmFolder.traverse(vm_name, VIM::VirtualMachine) or abort "VM not found"
45
+
46
+ case cmd
47
+ when 'on'
48
+ vm.PowerOnVM_Task.wait_for_completion
49
+ when 'off'
50
+ vm.PowerOffVM_Task.wait_for_completion
51
+ when 'reset'
52
+ vm.ResetVM_Task.wait_for_completion
53
+ when 'suspend'
54
+ vm.SuspendVM_Task.wait_for_completion
55
+ else
56
+ abort "invalid command"
57
+ end
@@ -0,0 +1,35 @@
1
+ require 'rbvmomi'
2
+ require 'rbvmomi/trollop'
3
+
4
+ opts = Trollop.options do
5
+ banner <<-EOS
6
+ Example 1 from the README: Power on a VM.
7
+
8
+ Usage:
9
+ readme-1.rb [options] VM name
10
+
11
+ VIM connection options:
12
+ EOS
13
+
14
+ rbvmomi_connection_opts
15
+
16
+ text <<-EOS
17
+
18
+ VM location options:
19
+ EOS
20
+
21
+ rbvmomi_datacenter_opt
22
+
23
+ text <<-EOS
24
+
25
+ Other options:
26
+ EOS
27
+ end
28
+
29
+ Trollop.die("must specify host") unless opts[:host]
30
+ vm_name = ARGV[0] or abort "must specify VM name"
31
+
32
+ vim = RbVmomi::VIM.connect opts
33
+ dc = vim.serviceInstance.find_datacenter(opts[:datacenter]) or fail "datacenter not found"
34
+ vm = dc.find_vm(vm_name) or fail "VM not found"
35
+ vm.PowerOnVM_Task.wait_for_completion
@@ -0,0 +1,51 @@
1
+ require 'rbvmomi'
2
+ require 'rbvmomi/trollop'
3
+
4
+ opts = Trollop.options do
5
+ banner <<-EOS
6
+ Example 2 from the README: Power on a VM the hard way.
7
+
8
+ Usage:
9
+ readme-2.rb [options] VM name
10
+
11
+ VIM connection options:
12
+ EOS
13
+
14
+ rbvmomi_connection_opts
15
+
16
+ text <<-EOS
17
+
18
+ VM location options:
19
+ EOS
20
+
21
+ rbvmomi_datacenter_opt
22
+
23
+ text <<-EOS
24
+
25
+ Other options:
26
+ EOS
27
+ end
28
+
29
+ Trollop.die("must specify host") unless opts[:host]
30
+ vm_name = ARGV[0] or abort "must specify VM name"
31
+
32
+ vim = RbVmomi::VIM.connect opts
33
+ rootFolder = vim.serviceInstance.content.rootFolder
34
+ dc = rootFolder.childEntity.grep(RbVmomi::VIM::Datacenter).find { |x| x.name == opts[:datacenter] } or fail "datacenter not found"
35
+ vm = dc.vmFolder.childEntity.grep(RbVmomi::VIM::VirtualMachine).find { |x| x.name == vm_name } or fail "VM not found"
36
+ task = vm.PowerOnVM_Task
37
+ filter = vim.propertyCollector.CreateFilter(
38
+ spec: {
39
+ propSet: [{ type: 'Task', all: false, pathSet: ['info.state']}],
40
+ objectSet: [{ obj: task }]
41
+ },
42
+ partialUpdates: false
43
+ )
44
+ ver = ''
45
+ while true
46
+ result = vim.propertyCollector.WaitForUpdates(version: ver)
47
+ ver = result.version
48
+ break if ['success', 'error'].member? task.info.state
49
+ end
50
+ filter.DestroyPropertyFilter
51
+ raise task.info.error if task.info.state == 'error'