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,23 @@
1
+ class RbVmomi::VIM::ObjectContent
2
+ # Represent this ObjectContent as a hash.
3
+ # @return [Hash] A hash from property paths to values.
4
+ def to_hash
5
+ @cached_hash ||= to_hash_uncached
6
+ end
7
+
8
+ # Alias for +to_hash[k]+.
9
+ def [](k)
10
+ to_hash[k]
11
+ end
12
+
13
+ private
14
+
15
+ def to_hash_uncached
16
+ h = {}
17
+ propSet.each do |x|
18
+ fail if h.member? x.name
19
+ h[x.name] = x.val
20
+ end
21
+ h
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ class RbVmomi::VIM::ObjectUpdate
2
+ # Represent this ObjectUpdate as a hash.
3
+ # @return [Hash] A hash from property paths to values.
4
+ def to_hash
5
+ @cached_hash ||= to_hash_uncached
6
+ end
7
+
8
+ # Alias for +to_hash[k]+.
9
+ def [](k)
10
+ to_hash[k]
11
+ end
12
+
13
+ private
14
+
15
+ def to_hash_uncached
16
+ h = {}
17
+ changeSet.each do |x|
18
+ fail if h.member? x.name
19
+ h[x.name] = x.val
20
+ end
21
+ h
22
+ end
23
+ end
@@ -0,0 +1,107 @@
1
+ # @note +deployOVF+ and requires +curl+. If +curl+ is not in your +PATH+
2
+ # then set the +CURL+ environment variable to point to it.
3
+ # @todo Use an HTTP library instead of executing +curl+.
4
+ class RbVmomi::VIM::OvfManager
5
+ CURLBIN = ENV['CURL'] || "curl" #@private
6
+
7
+ # Deploy an OVF.
8
+ #
9
+ # @param [Hash] opts The options hash.
10
+ # @option opts [String] :uri Location of the OVF.
11
+ # @option opts [String] :vmName Name of the new VM.
12
+ # @option opts [VIM::Folder] :vmFolder Folder to place the VM in.
13
+ # @option opts [VIM::HostSystem] :host Host to use.
14
+ # @option opts [VIM::ResourcePool] :resourcePool Resource pool to use.
15
+ # @option opts [VIM::Datastore] :datastore Datastore to use.
16
+ # @option opts [String] :diskProvisioning (thin) Disk provisioning mode.
17
+ # @option opts [Hash] :networkMappings Network mappings.
18
+ # @option opts [Hash] :propertyMappings Property mappings.
19
+ def deployOVF opts
20
+ opts = { :networkMappings => {},
21
+ :propertyMappings => {},
22
+ :diskProvisioning => :thin }.merge opts
23
+
24
+ %w(uri vmName vmFolder host resourcePool datastore).each do |k|
25
+ fail "parameter #{k} required" unless opts[k.to_sym]
26
+ end
27
+
28
+ ovfImportSpec = RbVmomi::VIM::OvfCreateImportSpecParams(
29
+ :hostSystem => opts[:host],
30
+ :locale => "US",
31
+ :entityName => opts[:vmName],
32
+ :deploymentOption => "",
33
+ :networkMapping => opts[:networkMappings].map{|from, to| RbVmomi::VIM::OvfNetworkMapping(:name => from, :network => to)},
34
+ :propertyMapping => opts[:propertyMappings].to_a,
35
+ :diskProvisioning => opts[:diskProvisioning]
36
+ )
37
+
38
+ result = CreateImportSpec(
39
+ :ovfDescriptor => open(opts[:uri]).read,
40
+ :resourcePool => opts[:resourcePool],
41
+ :datastore => opts[:datastore],
42
+ :cisp => ovfImportSpec
43
+ )
44
+
45
+ raise result.error[0].localizedMessage if result.error && !result.error.empty?
46
+
47
+ if result.warning
48
+ result.warning.each{|x| puts "OVF Warning: #{x.localizedMessage.chomp}" }
49
+ end
50
+
51
+ nfcLease = opts[:resourcePool].ImportVApp(:spec => result.importSpec,
52
+ :folder => opts[:vmFolder],
53
+ :host => opts[:host])
54
+
55
+ nfcLease.wait_until(:state) { nfcLease.state != "initializing" }
56
+ raise nfcLease.error if nfcLease.state == "error"
57
+ begin
58
+ nfcLease.HttpNfcLeaseProgress(:percent => 5)
59
+ progress = 5.0
60
+ result.fileItem.each do |fileItem|
61
+ deviceUrl = nfcLease.info.deviceUrl.find{|x| x.importKey == fileItem.deviceId}
62
+ if !deviceUrl
63
+ raise "Couldn't find deviceURL for device '#{fileItem.deviceId}'"
64
+ end
65
+
66
+ # XXX handle file:// URIs
67
+ ovfFilename = opts[:uri].to_s
68
+ tmp = ovfFilename.split(/\//)
69
+ tmp.pop
70
+ tmp << fileItem.path
71
+ filename = tmp.join("/")
72
+
73
+ method = fileItem.create ? "PUT" : "POST"
74
+
75
+ keepAliveThread = Thread.new do
76
+ while true
77
+ sleep 2 * 60
78
+ nfcLease.HttpNfcLeaseProgress(:percent => progress.to_i)
79
+ end
80
+ end
81
+
82
+ href = deviceUrl.url.gsub("*", opts[:host].config.network.vnic[0].spec.ip.ipAddress)
83
+ downloadCmd = "#{CURLBIN} -L '#{URI::escape(filename)}'"
84
+ uploadCmd = "#{CURLBIN} -Ss -X #{method} --insecure -T - -H 'Content-Type: application/x-vnd.vmware-streamVmdk' '#{URI::escape(href)}'"
85
+ # Previously we used to append "-H 'Content-Length: #{fileItem.size}'"
86
+ # to the uploadCmd. It is not clear to me why, but that leads to
87
+ # trucation of the uploaded disk. Without this option curl can't tell
88
+ # the progress, but who cares
89
+ system("#{downloadCmd} | #{uploadCmd}", STDOUT => "/dev/null")
90
+
91
+ keepAliveThread.kill
92
+ keepAliveThread.join
93
+
94
+ progress += (90.0 / result.fileItem.length)
95
+ nfcLease.HttpNfcLeaseProgress(:percent => progress.to_i)
96
+ end
97
+
98
+ nfcLease.HttpNfcLeaseProgress(:percent => 100)
99
+ vm = nfcLease.info.entity
100
+ nfcLease.HttpNfcLeaseComplete
101
+ vm
102
+ end
103
+ rescue Exception
104
+ (nfcLease.HttpNfcLeaseAbort rescue nil) if nfcLease
105
+ raise
106
+ end
107
+ end
@@ -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,85 @@
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
+ metric_ids = metrics.map do |x|
50
+ counter = perfcounter_hash[x]
51
+ if !counter
52
+ pp perfcounter_hash.keys
53
+ fail "Counter for #{x} couldn't be found"
54
+ end
55
+ RbVmomi::VIM::PerfMetricId(:counterId => counter.key, :instance => '*')
56
+ end
57
+ query_specs = objects.map do |obj|
58
+ RbVmomi::VIM::PerfQuerySpec({
59
+ :maxSample => max_samples,
60
+ :entity => obj,
61
+ :metricId => metric_ids,
62
+ :intervalId => opts[:interval],
63
+ :startTime => (realtime == false ? opts[:start_time].to_datetime : nil),
64
+ })
65
+ end
66
+ stats = QueryPerf(:querySpec => query_specs)
67
+
68
+ Hash[stats.map do |res|
69
+ [
70
+ res.entity,
71
+ {
72
+ :sampleInfo => res.sampleInfo,
73
+ :metrics => Hash[res.value.map do |metric|
74
+ [perfcounter_idhash[metric.id.counterId].name, metric.value]
75
+ end]
76
+ }
77
+ ]
78
+ end]
79
+ end
80
+
81
+ def active_intervals
82
+ intervals = historicalInterval
83
+ Hash[(1..4).map { |level| [level, intervals.select { |x| x.enabled && x.level >= level }] }]
84
+ end
85
+ 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,59 @@
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
+ # XXX: Should create a single reconfig spec instead of one per disk
38
+ disks.each do |disk|
39
+ spec = {
40
+ :deviceChange => [
41
+ {
42
+ :operation => :remove,
43
+ :device => disk
44
+ },
45
+ {
46
+ :operation => :add,
47
+ :fileOperation => :create,
48
+ :device => disk.dup.tap { |x|
49
+ x.backing = x.backing.dup
50
+ x.backing.fileName = "[#{disk.backing.datastore.name}]"
51
+ x.backing.parent = disk.backing
52
+ },
53
+ }
54
+ ]
55
+ }
56
+ self.ReconfigVM_Task(:spec => spec).wait_for_completion
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,99 @@
1
+ # Copyright (c) 2011 VMware, Inc. All Rights Reserved.
2
+ require 'rbvmomi'
3
+
4
+ module RbVmomi
5
+
6
+ # A connection to one vSphere SDK endpoint.
7
+ # @see #serviceInstance
8
+ class VIM < Connection
9
+ # Connect to a vSphere SDK endpoint
10
+ #
11
+ # @param [Hash] opts The options hash.
12
+ # @option opts [String] :host Host to connect to.
13
+ # @option opts [Numeric] :port (443) Port to connect to.
14
+ # @option opts [Boolean] :ssl (true) Whether to use SSL.
15
+ # @option opts [Boolean] :insecure (false) If true, ignore SSL certificate errors.
16
+ # @option opts [String] :user (root) Username.
17
+ # @option opts [String] :password Password.
18
+ # @option opts [String] :path (/sdk) SDK endpoint path.
19
+ # @option opts [Boolean] :debug (false) If true, print SOAP traffic to stderr.
20
+ def self.connect opts
21
+ fail unless opts.is_a? Hash
22
+ fail "host option required" unless opts[:host]
23
+ opts[:user] ||= 'root'
24
+ opts[:password] ||= ''
25
+ opts[:ssl] = true unless opts.member? :ssl or opts[:"no-ssl"]
26
+ opts[:insecure] ||= false
27
+ opts[:port] ||= (opts[:ssl] ? 443 : 80)
28
+ opts[:path] ||= '/sdk'
29
+ opts[:ns] ||= 'urn:vim25'
30
+ rev_given = opts[:rev] != nil
31
+ opts[:rev] = '4.0' unless rev_given
32
+ opts[:debug] = (!ENV['RBVMOMI_DEBUG'].empty? rescue false) unless opts.member? :debug
33
+
34
+ new(opts).tap do |vim|
35
+ vim.serviceContent.sessionManager.Login :userName => opts[:user], :password => opts[:password]
36
+ unless rev_given
37
+ rev = vim.serviceContent.about.apiVersion
38
+ vim.rev = [rev, '5.0'].min
39
+ end
40
+ end
41
+ end
42
+
43
+ def close
44
+ VIM::SessionManager(self, 'SessionManager').Logout rescue RbVmomi::Fault
45
+ self.cookie = nil
46
+ super
47
+ end
48
+
49
+ def rev= x
50
+ super
51
+ @serviceContent = nil
52
+ end
53
+
54
+ # Return the ServiceInstance
55
+ #
56
+ # The ServiceInstance is the root of the vSphere inventory.
57
+ # @see http://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.ServiceInstance.html
58
+ def serviceInstance
59
+ VIM::ServiceInstance self, 'ServiceInstance'
60
+ end
61
+
62
+ # Alias to serviceInstance.RetrieveServiceContent
63
+ def serviceContent
64
+ @serviceContent ||= serviceInstance.RetrieveServiceContent
65
+ end
66
+
67
+ # Alias to serviceContent.rootFolder
68
+ def rootFolder
69
+ serviceContent.rootFolder
70
+ end
71
+
72
+ alias root rootFolder
73
+
74
+ # Alias to serviceContent.propertyCollector
75
+ def propertyCollector
76
+ serviceContent.propertyCollector
77
+ end
78
+
79
+ # Alias to serviceContent.searchIndex
80
+ def searchIndex
81
+ serviceContent.searchIndex
82
+ end
83
+
84
+ # @private
85
+ def pretty_print pp
86
+ pp.text "VIM(#{@opts[:host]})"
87
+ end
88
+
89
+ def instanceUuid
90
+ serviceContent.about.instanceUuid
91
+ end
92
+
93
+ add_extension_dir File.join(File.dirname(__FILE__), "vim")
94
+ (ENV['RBVMOMI_VIM_EXTENSION_PATH']||'').split(':').each { |dir| add_extension_dir dir }
95
+
96
+ load_vmodl(ENV['VMODL'] || File.join(File.dirname(__FILE__), "../../vmodl.db"))
97
+ end
98
+
99
+ end
data/lib/rbvmomi.rb ADDED
@@ -0,0 +1,15 @@
1
+ # Copyright (c) 2010 VMware, Inc. All Rights Reserved.
2
+ module RbVmomi
3
+
4
+ # @private
5
+ # @deprecated Use +RbVmomi::VIM.connect+.
6
+ def self.connect opts
7
+ VIM.connect opts
8
+ end
9
+
10
+ end
11
+
12
+ require 'rbvmomi/version'
13
+ require 'rbvmomi/connection'
14
+ require 'rbvmomi/vim'
15
+