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,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