vagrant-rbvmomi 1.8.1

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 (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 +31 -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 +336 -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,174 @@
1
+ module RbVmomi
2
+
3
+ class VIM::HostSystem
4
+ def esxcli
5
+ @cached_esxcli ||= VIM::EsxcliNamespace.root(self)
6
+ end
7
+
8
+ def dtm
9
+ @cached_dtm ||= begin
10
+ RetrieveDynamicTypeManager()
11
+ rescue VIM::MethodNotFound
12
+ if summary.config.product.version >= '4.1.0'
13
+ if summary.config.product.version < '5.0.0' and direct?
14
+ VIM::InternalDynamicTypeManager(_connection, 'ha-dynamic-type-manager')
15
+ else
16
+ raise "esxcli not supported through VC before 5.0.0"
17
+ end
18
+ else
19
+ raise "esxcli not supported before 4.1.0"
20
+ end
21
+ end
22
+ end
23
+
24
+ def dti
25
+ @cached_dti ||= dtm.DynamicTypeMgrQueryTypeInfo
26
+ end
27
+
28
+ def create_dynamic_managed_object inst
29
+ wsdlName = dti.managedTypeInfo.find { |x| x.name == inst.moType }.wsdlName
30
+ _connection.type(wsdlName).new(_connection, inst.id)
31
+ end
32
+
33
+ def cli_info_fetcher
34
+ # XXX there can be more than one
35
+ return @cached_cli_info_fetcher if @cached_cli_info_fetcher
36
+ inst = dtm.DynamicTypeMgrQueryMoInstances.find { |x| x.moType == 'vim.CLIInfo' }
37
+ @cached_cli_info_fetcher = create_dynamic_managed_object inst
38
+ end
39
+
40
+ def mme
41
+ @cached_mme ||= RetrieveManagedMethodExecuter()
42
+ end
43
+
44
+ def direct?
45
+ @ref == 'ha-host'
46
+ end
47
+ end
48
+
49
+ class VIM::EsxcliNamespace
50
+ ESXCLI_PREFIX = 'vim.EsxCLI.'
51
+
52
+ attr_reader :name, :parent, :host, :type, :instance, :type_info, :namespaces, :commands
53
+
54
+ def self.root host
55
+ type_hash = host.dti.toRbvmomiTypeHash
56
+ VIM.loader.add_types type_hash
57
+ all_instances = host.dtm.DynamicTypeMgrQueryMoInstances
58
+ instances = Hash[all_instances.select { |x| x.moType.start_with? ESXCLI_PREFIX }.
59
+ map { |x| [x.moType,x.id] }]
60
+ type_infos = Hash[host.dti.managedTypeInfo.map { |x| [x.name,x] }]
61
+ new('root', nil, host).tap do |root|
62
+ instances.each do |type,instance|
63
+ path = type.split('.')[2..-1]
64
+ ns = path.inject(root) { |b,v| b.namespaces[v] }
65
+ ns.realize type, instance, type_infos[type]
66
+ end
67
+ end
68
+ end
69
+
70
+ def initialize name, parent, host
71
+ @name = name
72
+ @parent = parent
73
+ @host = host
74
+ @type = nil
75
+ @instance = nil
76
+ @type_info = nil
77
+ @namespaces = Hash.new { |h,k| h[k] = self.class.new k, self, host }
78
+ @commands = {}
79
+ @cached_cli_info = nil
80
+ end
81
+
82
+ def realize type, instance, type_info
83
+ fail if @type or @instance
84
+ @type = type
85
+ @instance = instance
86
+ @type_info = type_info
87
+ @type_info.method.each do |method_type_info|
88
+ name = method_type_info.name
89
+ @commands[name] = VIM::EsxcliCommand.new self, method_type_info
90
+ end
91
+ end
92
+
93
+ def type_name
94
+ if @type then @type
95
+ elsif @parent then "#{@parent.type_name}.#{@name}"
96
+ else 'vim.EsxCLI'
97
+ end
98
+ end
99
+
100
+ def cli_info
101
+ @cached_cli_info ||=
102
+ if @host.direct?
103
+ @host.cli_info_fetcher.VimCLIInfoFetchCLIInfo(:typeName => type_name)
104
+ else
105
+ @host.mme.execute(@host.cli_info_fetcher._ref,
106
+ "vim.CLIInfo.FetchCLIInfo", :typeName => type_name)
107
+ end
108
+ end
109
+
110
+ def obj
111
+ conn = @host._connection
112
+ conn.type(@type_info.wsdlName).new(conn, @instance)
113
+ end
114
+
115
+ def method_missing name, *args
116
+ name = name.to_s
117
+ if @namespaces.member? name and args.empty?
118
+ @namespaces[name]
119
+ elsif @commands.member? name
120
+ @commands[name].call *args
121
+ else
122
+ raise NoMethodError
123
+ end
124
+ end
125
+
126
+ def pretty_print q
127
+ q.text @name
128
+ q.text ' '
129
+ q.group 2 do
130
+ q.text '{'
131
+ q.breakable
132
+ items = (@namespaces.values+@commands.values).sort_by(&:name)
133
+ q.seplist items, nil, :each do |v|
134
+ if v.is_a? VIM::EsxcliNamespace
135
+ q.pp v
136
+ else
137
+ q.text v.name
138
+ end
139
+ end
140
+ end
141
+ q.breakable
142
+ q.text '}'
143
+ end
144
+ end
145
+
146
+ class VIM::EsxcliCommand
147
+ attr_reader :ns, :type_info, :cli_info
148
+
149
+ def initialize ns, type_info
150
+ @ns = ns
151
+ @type_info = type_info
152
+ @cached_cli_info = nil
153
+ end
154
+
155
+ def name
156
+ @type_info.name
157
+ end
158
+
159
+ def cli_info
160
+ @cached_cli_info ||= @ns.cli_info.method.find { |x| x.name == @type_info.name }
161
+ end
162
+
163
+ def call args={}
164
+ if @ns.host.direct?
165
+ @ns.obj._call @type_info.wsdlName, args
166
+ else
167
+ real_args = Set.new(type_info.paramTypeInfo.map(&:name))
168
+ args = args.reject { |k,v| !real_args.member?(k.to_s) }
169
+ @ns.host.mme.execute(@ns.obj._ref, "#{@ns.type_name}.#{@type_info.name}", args)
170
+ end
171
+ end
172
+ end
173
+
174
+ end
@@ -0,0 +1,57 @@
1
+ class RbVmomi::VIM::ManagedEntity
2
+ # Retrieve the ancestors of the entity.
3
+ # @return [Array] Ancestors of this entity, starting with the root.
4
+ def path
5
+ self.class.paths([self])[self]
6
+ end
7
+
8
+ # Retrieve the ancestors of a list of entries.
9
+ # @return [Hash] Object-indexed hash of ancestors of entities, starting with the root.
10
+ def self.paths objs
11
+ filterSpec = RbVmomi::VIM.PropertyFilterSpec(
12
+ :objectSet => objs.map do |obj|
13
+ RbVmomi::VIM.ObjectSpec(
14
+ :obj => obj,
15
+ :selectSet => [
16
+ RbVmomi::VIM.TraversalSpec(
17
+ :name => "tsME",
18
+ :type => 'ManagedEntity',
19
+ :path => 'parent',
20
+ :skip => false,
21
+ :selectSet => [
22
+ RbVmomi::VIM.SelectionSpec(:name => "tsME")
23
+ ]
24
+ )
25
+ ]
26
+ )
27
+ end,
28
+ :propSet => [{
29
+ :pathSet => %w(name parent),
30
+ :type => 'ManagedEntity'
31
+ }]
32
+ )
33
+
34
+ propCollector = objs.first._connection.propertyCollector
35
+ result = propCollector.RetrieveProperties(:specSet => [filterSpec])
36
+
37
+ Hash[objs.map do |obj|
38
+ tree = {}
39
+ result.each { |x| tree[x.obj] = [x['parent'], x['name']] }
40
+ a = []
41
+ cur = obj
42
+ while cur
43
+ parent, name = *tree[cur]
44
+ a << [cur, name]
45
+ cur = parent
46
+ end
47
+ [obj, a.reverse]
48
+ end]
49
+ end
50
+
51
+ # Return a string representation of +path+ suitable for display.
52
+ # @return [String]
53
+ # @see #path
54
+ def pretty_path
55
+ path[1..-1].map { |x| x[1] } * '/'
56
+ end
57
+ end
@@ -0,0 +1,60 @@
1
+ class RbVmomi::VIM::ManagedObject
2
+ # Wait for updates on an object until a condition becomes true.
3
+ #
4
+ # @param pathSet [Array] Property paths to wait for updates to.
5
+ # @yield Called when an update to a subscribed property occurs.
6
+ # @yieldreturn [Boolean] Whether to stop waiting.
7
+ #
8
+ # @todo Pass the current property values to the block.
9
+ def wait_until *pathSet, &b
10
+ all = pathSet.empty?
11
+ filter = _connection.propertyCollector.CreateFilter :spec => {
12
+ :propSet => [{ :type => self.class.wsdl_name, :all => all, :pathSet => pathSet }],
13
+ :objectSet => [{ :obj => self }],
14
+ }, :partialUpdates => false
15
+ ver = ''
16
+ loop do
17
+ result = _connection.propertyCollector.WaitForUpdates(:version => ver)
18
+ ver = result.version
19
+ if x = b.call
20
+ return x
21
+ end
22
+ end
23
+ ensure
24
+ filter.DestroyPropertyFilter if filter
25
+ end
26
+
27
+ # Efficiently retrieve multiple properties from an object.
28
+ # @param pathSet [Array] Properties to return.
29
+ # @return [Hash] Hash from property paths to values.
30
+ def collect! *pathSet
31
+ spec = {
32
+ :objectSet => [{ :obj => self }],
33
+ :propSet => [{
34
+ :pathSet => pathSet,
35
+ :type => self.class.wsdl_name
36
+ }]
37
+ }
38
+ ret = _connection.propertyCollector.RetrieveProperties(:specSet => [spec])
39
+ if ret && ret.length > 0
40
+ ret[0].to_hash
41
+ else
42
+ {}
43
+ end
44
+ end
45
+
46
+ # Efficiently retrieve multiple properties from an object.
47
+ # @param pathSet (see #collect!)
48
+ # @yield [*values] Property values in same order as +pathSet+.
49
+ # @return [Array] Property values in same order as +pathSet+, or the return
50
+ # value from the block if it is given.
51
+ def collect *pathSet
52
+ h = collect! *pathSet
53
+ a = pathSet.map { |k| h[k.to_s] }
54
+ if block_given?
55
+ yield a
56
+ else
57
+ a
58
+ end
59
+ end
60
+ end
@@ -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,200 @@
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
+ importSpec = result.importSpec
52
+ if importSpec && importSpec.instantiationOst && importSpec.instantiationOst.child
53
+ importSpec.instantiationOst.child.each do |child|
54
+ child.section.map do |section|
55
+ section.xml = _handle_ost(section.xml, opts)
56
+ end
57
+ end
58
+ end
59
+
60
+ nfcLease = opts[:resourcePool].ImportVApp(:spec => importSpec,
61
+ :folder => opts[:vmFolder],
62
+ :host => opts[:host])
63
+
64
+ nfcLease.wait_until(:state) { nfcLease.state != "initializing" }
65
+ raise nfcLease.error if nfcLease.state == "error"
66
+ begin
67
+ nfcLease.HttpNfcLeaseProgress(:percent => 5)
68
+ timeout, = nfcLease.collect 'info.leaseTimeout'
69
+ puts "DEBUG: Timeout: #{timeout}"
70
+ if timeout < 4 * 60
71
+ puts "WARNING: OVF upload NFC lease timeout less than 4 minutes"
72
+ end
73
+ progress = 5.0
74
+ result.fileItem.each do |fileItem|
75
+ leaseInfo, leaseState, leaseError = nfcLease.collect 'info', 'state', 'error'
76
+ # Retry nfcLease.collect because of PR 969599:
77
+ # If retrying property collector works, this means there is a network
78
+ # or VC overloading problem.
79
+ retrynum = 5
80
+ i = 1
81
+ while i <= retrynum && !leaseState
82
+ puts "Retrying at iteration #{i}"
83
+ sleep 1
84
+ leaseInfo, leaseState, leaseError = nfcLease.collect 'info', 'state', 'error'
85
+ i += 1
86
+ end
87
+ if leaseState != "ready"
88
+ raise "NFC lease is no longer ready: #{leaseState}: #{leaseError}"
89
+ end
90
+ if leaseInfo == nil
91
+ raise "NFC lease disappeared?"
92
+ end
93
+ deviceUrl = leaseInfo.deviceUrl.find{|x| x.importKey == fileItem.deviceId}
94
+ if !deviceUrl
95
+ raise "Couldn't find deviceURL for device '#{fileItem.deviceId}'"
96
+ end
97
+
98
+ ovfFilename = opts[:uri].to_s
99
+ tmp = ovfFilename.split(/\//)
100
+ tmp.pop
101
+ tmp << fileItem.path
102
+ filename = tmp.join("/")
103
+
104
+ # If filename doesn't have a URI scheme, we're considering it a local file
105
+ if URI(filename).scheme.nil?
106
+ filename = "file://" + filename
107
+ end
108
+
109
+ method = fileItem.create ? "PUT" : "POST"
110
+
111
+ keepAliveThread = Thread.new do
112
+ while true
113
+ nfcLease.HttpNfcLeaseProgress(:percent => progress.to_i)
114
+ sleep 1 * 60
115
+ end
116
+ end
117
+
118
+ i = 1
119
+ ip = nil
120
+ begin
121
+ begin
122
+ puts "Iteration #{i}: Trying to get host's IP address ..."
123
+ ip = opts[:host].config.network.vnic[0].spec.ip.ipAddress
124
+ rescue Exception=>e
125
+ puts "Iteration #{i}: Couldn't get host's IP address: #{e}"
126
+ end
127
+ sleep 1
128
+ i += 1
129
+ end while i <= 5 && !ip
130
+ raise "Couldn't get host's IP address" unless ip
131
+ href = deviceUrl.url.gsub("*", ip)
132
+ downloadCmd = "#{CURLBIN} -L '#{URI::escape(filename)}'"
133
+ uploadCmd = "#{CURLBIN} -Ss -X #{method} --insecure -T - -H 'Content-Type: application/x-vnd.vmware-streamVmdk' '#{URI::escape(href)}'"
134
+ # Previously we used to append "-H 'Content-Length: #{fileItem.size}'"
135
+ # to the uploadCmd. It is not clear to me why, but that leads to
136
+ # trucation of the uploaded disk. Without this option curl can't tell
137
+ # the progress, but who cares
138
+ system("#{downloadCmd} | #{uploadCmd}", STDOUT => "/dev/null")
139
+
140
+ keepAliveThread.kill
141
+ keepAliveThread.join
142
+
143
+ progress += (90.0 / result.fileItem.length)
144
+ nfcLease.HttpNfcLeaseProgress(:percent => progress.to_i)
145
+ end
146
+
147
+ nfcLease.HttpNfcLeaseProgress(:percent => 100)
148
+ raise nfcLease.error if nfcLease.state == "error"
149
+ i = 1
150
+ vm = nil
151
+ begin
152
+ begin
153
+ puts "Iteration #{i}: Trying to access nfcLease.info.entity ..."
154
+ vm = nfcLease.info.entity
155
+ rescue Exception=>e
156
+ puts "Iteration #{i}: Couldn't access nfcLease.info.entity: #{e}"
157
+ end
158
+ sleep 1
159
+ i += 1
160
+ end while i <= 5 && !vm
161
+ raise "Couldn't access nfcLease.info.entity" unless vm
162
+
163
+ # Ignore sporadic connection errors caused by PR 1019166..
164
+ # Three attempts are made to execute HttpNfcLeaseComplete.
165
+ # Not critical if none goes through, as long as vm is obtained
166
+ #
167
+ # TODO: find the reason why HttpNfcLeaseComplete gets a wrong
168
+ # response (RetrievePropertiesResponse)
169
+ i = 0
170
+ begin
171
+ nfcLease.HttpNfcLeaseComplete
172
+ puts "HttpNfcLeaseComplete succeeded"
173
+ rescue RbVmomi::VIM::InvalidState
174
+ puts "HttpNfcLeaseComplete already finished.."
175
+ rescue Exception => e
176
+ puts "HttpNfcLeaseComplete failed at iteration #{i} with exception: #{e}"
177
+ i += 1
178
+ retry if i < 3
179
+ puts "Giving up HttpNfcLeaseComplete.."
180
+ end
181
+ vm
182
+ end
183
+ rescue Exception
184
+ (nfcLease.HttpNfcLeaseAbort rescue nil) if nfcLease
185
+ raise
186
+ end
187
+
188
+ def _handle_ost ost, opts = {}
189
+ ost = Nokogiri::XML(ost)
190
+ if opts[:vservice] == ['com.vmware.vim.vsm:extension_vservice']
191
+ ost.xpath('//vmw:Annotations/vmw:Providers/vmw:Provider').each do |x|
192
+ x['vmw:selected'] = 'selected'
193
+ end
194
+ ost.xpath('//vmw:Annotations/vmw:Providers').each do |x|
195
+ x['vmw:selected'] = 'com.vmware.vim.vsm:extension_vservice'
196
+ end
197
+ end
198
+ ost.to_s
199
+ end
200
+ end