mkuzmin-rbvmomi 1.8.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +6 -0
  3. data/LICENSE +19 -0
  4. data/README.rdoc +78 -0
  5. data/Rakefile +45 -0
  6. data/VERSION +1 -0
  7. data/bin/rbvmomish +138 -0
  8. data/devel/analyze-vim-declarations.rb +213 -0
  9. data/devel/analyze-xml.rb +46 -0
  10. data/devel/benchmark.rb +117 -0
  11. data/devel/collisions.rb +18 -0
  12. data/devel/merge-internal-vmodl.rb +59 -0
  13. data/devel/merge-manual-vmodl.rb +32 -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.rb +12 -0
  32. data/lib/rbvmomi/basic_types.rb +375 -0
  33. data/lib/rbvmomi/connection.rb +270 -0
  34. data/lib/rbvmomi/deserialization.rb +248 -0
  35. data/lib/rbvmomi/fault.rb +17 -0
  36. data/lib/rbvmomi/pbm.rb +66 -0
  37. data/lib/rbvmomi/sms.rb +61 -0
  38. data/lib/rbvmomi/sms/SmsStorageManager.rb +7 -0
  39. data/lib/rbvmomi/trivial_soap.rb +114 -0
  40. data/lib/rbvmomi/trollop.rb +70 -0
  41. data/lib/rbvmomi/type_loader.rb +136 -0
  42. data/lib/rbvmomi/utils/admission_control.rb +398 -0
  43. data/lib/rbvmomi/utils/deploy.rb +314 -0
  44. data/lib/rbvmomi/utils/leases.rb +142 -0
  45. data/lib/rbvmomi/utils/perfdump.rb +628 -0
  46. data/lib/rbvmomi/vim.rb +128 -0
  47. data/lib/rbvmomi/vim/ComputeResource.rb +51 -0
  48. data/lib/rbvmomi/vim/Datacenter.rb +17 -0
  49. data/lib/rbvmomi/vim/Datastore.rb +68 -0
  50. data/lib/rbvmomi/vim/DynamicTypeMgrAllTypeInfo.rb +75 -0
  51. data/lib/rbvmomi/vim/DynamicTypeMgrDataTypeInfo.rb +20 -0
  52. data/lib/rbvmomi/vim/DynamicTypeMgrManagedTypeInfo.rb +46 -0
  53. data/lib/rbvmomi/vim/Folder.rb +207 -0
  54. data/lib/rbvmomi/vim/HostSystem.rb +174 -0
  55. data/lib/rbvmomi/vim/ManagedEntity.rb +57 -0
  56. data/lib/rbvmomi/vim/ManagedObject.rb +60 -0
  57. data/lib/rbvmomi/vim/ObjectContent.rb +23 -0
  58. data/lib/rbvmomi/vim/ObjectUpdate.rb +23 -0
  59. data/lib/rbvmomi/vim/OvfManager.rb +200 -0
  60. data/lib/rbvmomi/vim/PerfCounterInfo.rb +26 -0
  61. data/lib/rbvmomi/vim/PerformanceManager.rb +110 -0
  62. data/lib/rbvmomi/vim/PropertyCollector.rb +25 -0
  63. data/lib/rbvmomi/vim/ReflectManagedMethodExecuter.rb +30 -0
  64. data/lib/rbvmomi/vim/ResourcePool.rb +55 -0
  65. data/lib/rbvmomi/vim/ServiceInstance.rb +55 -0
  66. data/lib/rbvmomi/vim/Task.rb +65 -0
  67. data/lib/rbvmomi/vim/VirtualMachine.rb +74 -0
  68. data/test/test_deserialization.rb +383 -0
  69. data/test/test_emit_request.rb +128 -0
  70. data/test/test_exceptions.rb +14 -0
  71. data/test/test_helper.rb +14 -0
  72. data/test/test_misc.rb +24 -0
  73. data/test/test_parse_response.rb +69 -0
  74. data/test/test_serialization.rb +311 -0
  75. data/vmodl.db +0 -0
  76. metadata +163 -0
@@ -0,0 +1,26 @@
1
+ # Copyright (c) 2011 VMware, Inc. All Rights Reserved.
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ class RbVmomi::VIM::PerfCounterInfo
22
+ def name
23
+ "#{groupInfo.key}.#{nameInfo.key}"
24
+ end
25
+ end
26
+
@@ -0,0 +1,110 @@
1
+ require 'date'
2
+
3
+ class Time
4
+ def to_datetime
5
+ # Convert seconds + microseconds into a fractional number of seconds
6
+ seconds = sec + Rational(usec, 10**6)
7
+
8
+ # Convert a UTC offset measured in minutes to one measured in a
9
+ # fraction of a day.
10
+ offset = Rational(utc_offset, 60 * 60 * 24)
11
+ DateTime.new(year, month, day, hour, min, seconds, offset)
12
+ end
13
+ end
14
+
15
+ RbVmomi::VIM::PerformanceManager
16
+ class RbVmomi::VIM::PerformanceManager
17
+ def perfcounter_cached
18
+ @perfcounter ||= perfCounter
19
+ end
20
+
21
+ def perfcounter_hash
22
+ @perfcounter_hash ||= Hash[perfcounter_cached.map{|x| [x.name, x]}]
23
+ end
24
+
25
+ def perfcounter_idhash
26
+ @perfcounter_idhash ||= Hash[perfcounter_cached.map{|x| [x.key, x]}]
27
+ end
28
+
29
+ def provider_summary obj
30
+ @provider_summary ||= {}
31
+ @provider_summary[obj.class] ||= QueryPerfProviderSummary(:entity => obj)
32
+ end
33
+
34
+ def retrieve_stats objects, metrics, opts = {}
35
+ opts = opts.dup
36
+ max_samples = opts[:max_samples] || 1
37
+ realtime = false
38
+ if not opts[:interval]
39
+ provider = provider_summary objects.first
40
+ opts[:interval] = provider.refreshRate
41
+ realtime = true
42
+ else
43
+ provider = provider_summary objects.first
44
+ if opts[:interval] == provider.refreshRate
45
+ realtime = true
46
+ end
47
+ end
48
+
49
+ instances = opts[:instance] || '*'
50
+ if !instances.is_a?(Array)
51
+ instances = [instances]
52
+ end
53
+ metric_ids = []
54
+ metrics.each do |x|
55
+ counter = perfcounter_hash[x]
56
+ if !counter
57
+ pp perfcounter_hash.keys
58
+ fail "Counter for #{x} couldn't be found"
59
+ end
60
+ instances.each do |instance|
61
+ metric_ids << RbVmomi::VIM::PerfMetricId(:counterId => counter.key,
62
+ :instance => instance)
63
+ end
64
+ end
65
+ query_specs = objects.map do |obj|
66
+ RbVmomi::VIM::PerfQuerySpec({
67
+ :maxSample => max_samples,
68
+ :entity => obj,
69
+ :metricId => metric_ids,
70
+ :intervalId => opts[:interval],
71
+ :startTime => (realtime == false ? opts[:start_time].to_datetime : nil),
72
+ })
73
+ end
74
+ stats = QueryPerf(:querySpec => query_specs)
75
+
76
+ if !opts[:multi_instance]
77
+ Hash[stats.map do |res|
78
+ [
79
+ res.entity,
80
+ {
81
+ :sampleInfo => res.sampleInfo,
82
+ :metrics => Hash[res.value.map do |metric|
83
+ metric_name = perfcounter_idhash[metric.id.counterId].name
84
+ [metric_name, metric.value]
85
+ end]
86
+ }
87
+ ]
88
+ end]
89
+ else
90
+ Hash[stats.map do |res|
91
+ [
92
+ res.entity,
93
+ {
94
+ :sampleInfo => res.sampleInfo,
95
+ :metrics => Hash[res.value.map do |metric|
96
+ metric_name = perfcounter_idhash[metric.id.counterId].name
97
+ [[metric_name, metric.id.instance], metric.value]
98
+ end]
99
+ }
100
+ ]
101
+ end]
102
+ end
103
+ end
104
+
105
+
106
+ def active_intervals
107
+ intervals = historicalInterval
108
+ Hash[(1..4).map { |level| [level, intervals.select { |x| x.enabled && x.level >= level }] }]
109
+ end
110
+ end
@@ -0,0 +1,25 @@
1
+ class RbVmomi::VIM::PropertyCollector
2
+ def collectMultiple objs, *pathSet
3
+ return {} if objs.empty?
4
+
5
+ klasses = objs.map{|x| x.class}.uniq
6
+ klass = if klasses.length > 1
7
+ # common superclass
8
+ klasses.map(&:ancestors).inject(&:&)[0]
9
+ else
10
+ klasses.first
11
+ end
12
+
13
+ spec = {
14
+ :objectSet => objs.map{|x| { :obj => x }},
15
+ :propSet => [{
16
+ :pathSet => pathSet,
17
+ :type => klass.wsdl_name
18
+ }]
19
+ }
20
+ res = RetrieveProperties(:specSet => [spec])
21
+ Hash[res.map do |x|
22
+ [x.obj, x.to_hash]
23
+ end]
24
+ end
25
+ end
@@ -0,0 +1,30 @@
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.deserializer.deserialize 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
+ if result
22
+ _connection.deserializer.deserialize Nokogiri(result.response).root, nil
23
+ else
24
+ nil
25
+ end
26
+ end
27
+ end
28
+
29
+ end
30
+
@@ -0,0 +1,55 @@
1
+ class RbVmomi::VIM::ResourcePool
2
+ # Retrieve a child ResourcePool.
3
+ # @param name [String] Name of the child.
4
+ # @return [VIM::ResourcePool]
5
+ def find name
6
+ _connection.searchIndex.FindChild(:entity => self, :name => name)
7
+ end
8
+
9
+ # Retrieve a descendant of this ResourcePool.
10
+ # @param path [String] Path delimited by '/'.
11
+ # @return [VIM::ResourcePool]
12
+ def traverse path
13
+ es = path.split('/').reject(&:empty?)
14
+ es.inject(self) do |f,e|
15
+ f.find(e) || return
16
+ end
17
+ end
18
+
19
+ def resourcePoolSubTree fields = []
20
+ self.class.resourcePoolSubTree [self], fields
21
+ end
22
+
23
+ def self.resourcePoolSubTree objs, fields = []
24
+ fields = (fields + ['name', 'resourcePool']).uniq
25
+ filterSpec = RbVmomi::VIM.PropertyFilterSpec(
26
+ :objectSet => objs.map do |obj|
27
+ RbVmomi::VIM.ObjectSpec(
28
+ :obj => obj,
29
+ :selectSet => [
30
+ RbVmomi::VIM.TraversalSpec(
31
+ :name => "tsRP",
32
+ :type => 'ResourcePool',
33
+ :path => 'resourcePool',
34
+ :skip => false,
35
+ :selectSet => [
36
+ RbVmomi::VIM.SelectionSpec(:name => "tsRP")
37
+ ]
38
+ )
39
+ ]
40
+ )
41
+ end,
42
+ :propSet => [{
43
+ :pathSet => fields,
44
+ :type => 'ResourcePool'
45
+ }]
46
+ )
47
+
48
+ propCollector = objs.first._connection.propertyCollector
49
+ result = propCollector.RetrieveProperties(:specSet => [filterSpec])
50
+
51
+ Hash[result.map do |x|
52
+ [x.obj, x.to_hash]
53
+ end]
54
+ end
55
+ end
@@ -0,0 +1,55 @@
1
+ class RbVmomi::VIM::ServiceInstance
2
+ # Retrieve a Datacenter.
3
+ # If no path is given the first datacenter will be returned.
4
+ # @param path (see Folder#traverse)
5
+ # @return [Datacenter]
6
+ def find_datacenter path=nil
7
+ if path
8
+ content.rootFolder.traverse path, RbVmomi::VIM::Datacenter
9
+ else
10
+ content.rootFolder.childEntity.grep(RbVmomi::VIM::Datacenter).first
11
+ end
12
+ end
13
+
14
+ # Wait for several tasks to complete.
15
+ # @param interested [Array] Property paths to watch for updates.
16
+ # @param tasks [Array] Tasks to wait on.
17
+ # @yield [Hash] Called when a property is updated on a task.
18
+ # The parameter is a hash from tasks to hashes from
19
+ # property path to value.
20
+ # @return [void]
21
+ def wait_for_multiple_tasks interested, tasks
22
+ version = ''
23
+ interested = (interested + ['info.state']).uniq
24
+ task_props = Hash.new { |h,k| h[k] = {} }
25
+
26
+ filter = _connection.propertyCollector.CreateFilter :spec => {
27
+ :propSet => [{ :type => 'Task', :all => false, :pathSet => interested }],
28
+ :objectSet => tasks.map { |x| { :obj => x } },
29
+ }, :partialUpdates => false
30
+
31
+ begin
32
+ until task_props.size == tasks.size and task_props.all? { |k,h| %w(success error).member? h['info.state'] }
33
+ result = _connection.propertyCollector.WaitForUpdates(:version => version)
34
+ version = result.version
35
+ os = result.filterSet[0].objectSet
36
+
37
+ os.each do |o|
38
+ changes = Hash[o.changeSet.map { |x| [x.name, x.val] }]
39
+
40
+ interested.each do |k|
41
+ task = tasks.find { |x| x._ref == o.obj._ref }
42
+ task_props[task][k] = changes[k] if changes.member? k
43
+ end
44
+ end
45
+
46
+ yield task_props if block_given?
47
+ end
48
+ ensure
49
+ _connection.propertyCollector.CancelWaitForUpdates
50
+ filter.DestroyPropertyFilter
51
+ end
52
+
53
+ task_props
54
+ end
55
+ end
@@ -0,0 +1,65 @@
1
+ class RbVmomi::VIM::Task
2
+ # Wait for a task to finish.
3
+ # @return +info.result+ on success.
4
+ # @raise +info.error+ on error.
5
+ def wait_for_completion
6
+ wait_until('info.state') { %w(success error).member? info.state }
7
+ case info.state
8
+ when 'success'
9
+ info.result
10
+ when 'error'
11
+ raise info.error
12
+ end
13
+ end
14
+
15
+ # Wait for all child tasks to finish. If any one child task failed,
16
+ # the exception of the first failing task is thrown.
17
+ # @return [Hash] Map of tasks to their +info.result+ on success.
18
+ # @raise +info.error+ on error.
19
+ def wait_for_childtask_completion
20
+ si = _connection.serviceInstance
21
+ tasks_props = si.wait_for_multiple_tasks(
22
+ ['info.state', 'info.result', 'info.error'],
23
+ self.child_tasks
24
+ )
25
+ Hash[tasks_props.map do |task, props|
26
+ case props['info.state']
27
+ when 'success'
28
+ [task, props['info.result']]
29
+ when 'error'
30
+ raise props['info.error']
31
+ end
32
+ end]
33
+ end
34
+
35
+ # Wait for a task to finish, with progress notifications.
36
+ # @return (see #wait_for_completion)
37
+ # @raise (see #wait_for_completion)
38
+ # @yield [info.progress]
39
+ def wait_for_progress
40
+ wait_until('info.state', 'info.progress') do
41
+ yield info.progress if block_given?
42
+ %w(success error).member? info.state
43
+ end
44
+ case info.state
45
+ when 'success'
46
+ info.result
47
+ when 'error'
48
+ raise info.error
49
+ end
50
+ end
51
+
52
+ # Get child tasks of this task.
53
+ # @return [Array] List of VIM::Task objects
54
+ def child_tasks
55
+ tm = _connection.serviceContent.taskManager
56
+ col = tm.CreateCollectorForTasks(:filter => {
57
+ :rootTaskKey => [self.info.key],
58
+ })
59
+ # XXX: Likely this is not enough and we need to collect pages other
60
+ # than the latest.
61
+ tasks = col.latestPage.map{|x| x.task}
62
+ col.DestroyCollector()
63
+ tasks
64
+ end
65
+ end
@@ -0,0 +1,74 @@
1
+ class RbVmomi::VIM::VirtualMachine
2
+ # Retrieve the MAC addresses for all virtual NICs.
3
+ # @return [Hash] Keyed by device label.
4
+ def macs
5
+ Hash[self.config.hardware.device.grep(RbVmomi::VIM::VirtualEthernetCard).map { |x| [x.deviceInfo.label, x.macAddress] }]
6
+ end
7
+
8
+ # Retrieve all virtual disk devices.
9
+ # @return [Array] Array of virtual disk devices.
10
+ def disks
11
+ self.config.hardware.device.grep(RbVmomi::VIM::VirtualDisk)
12
+ end
13
+
14
+ # Get the IP of the guest, but only if it is not stale
15
+ # @return [String] Current IP reported (as per VMware Tools) or nil
16
+ def guest_ip
17
+ g = self.guest
18
+ if g.ipAddress && (g.toolsStatus == "toolsOk" || g.toolsStatus == "toolsOld")
19
+ g.ipAddress
20
+ else
21
+ nil
22
+ end
23
+ end
24
+
25
+ # Add a layer of delta disks (redo logs) in front of every disk on the VM.
26
+ # This is similar to taking a snapshot and makes the VM a valid target for
27
+ # creating a linked clone.
28
+ #
29
+ # Background: The API for linked clones is quite strange. We can't create
30
+ # a linked straight from any VM. The disks of the VM for which we can create a
31
+ # linked clone need to be read-only and thus VC demands that the VM we
32
+ # are cloning from uses delta-disks. Only then it will allow us to
33
+ # share the base disk.
34
+ def add_delta_disk_layer_on_all_disks
35
+ devices, = self.collect 'config.hardware.device'
36
+ disks = devices.grep(RbVmomi::VIM::VirtualDisk)
37
+ spec = update_spec_add_delta_disk_layer_on_all_disks
38
+ self.ReconfigVM_Task(:spec => spec).wait_for_completion
39
+ end
40
+
41
+ # Updates a passed in spec to perform the task of adding a delta disk layer
42
+ # on top of all disks. Does the same as add_delta_disk_layer_on_all_disks
43
+ # but instead of issuing the ReconfigVM_Task, it just constructs the
44
+ # spec, so that the caller can batch a couple of updates into one
45
+ # ReconfigVM_Task.
46
+ def update_spec_add_delta_disk_layer_on_all_disks spec = {}
47
+ devices, = self.collect 'config.hardware.device'
48
+ disks = devices.grep(RbVmomi::VIM::VirtualDisk)
49
+ device_change = []
50
+ disks.each do |disk|
51
+ device_change << {
52
+ :operation => :remove,
53
+ :device => disk
54
+ }
55
+ device_change << {
56
+ :operation => :add,
57
+ :fileOperation => :create,
58
+ :device => disk.dup.tap { |x|
59
+ x.backing = x.backing.dup
60
+ x.backing.fileName = "[#{disk.backing.datastore.name}]"
61
+ x.backing.parent = disk.backing
62
+ },
63
+ }
64
+ end
65
+ if spec.is_a?(RbVmomi::VIM::VirtualMachineConfigSpec)
66
+ spec.deviceChange ||= []
67
+ spec.deviceChange += device_change
68
+ else
69
+ spec[:deviceChange] ||= []
70
+ spec[:deviceChange] += device_change
71
+ end
72
+ spec
73
+ end
74
+ end