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
@@ -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'