rbvmomi 1.6.0 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -13,6 +13,7 @@ class VIM < Connection
13
13
  # @option opts [Numeric] :port (443) Port to connect to.
14
14
  # @option opts [Boolean] :ssl (true) Whether to use SSL.
15
15
  # @option opts [Boolean] :insecure (false) If true, ignore SSL certificate errors.
16
+ # @option opts [String] :cookie If set, use cookie to connect instead of user/password
16
17
  # @option opts [String] :user (root) Username.
17
18
  # @option opts [String] :password Password.
18
19
  # @option opts [String] :path (/sdk) SDK endpoint path.
@@ -20,6 +21,7 @@ class VIM < Connection
20
21
  def self.connect opts
21
22
  fail unless opts.is_a? Hash
22
23
  fail "host option required" unless opts[:host]
24
+ opts[:cookie] ||= nil
23
25
  opts[:user] ||= 'root'
24
26
  opts[:password] ||= ''
25
27
  opts[:ssl] = true unless opts.member? :ssl or opts[:"no-ssl"]
@@ -32,10 +34,12 @@ class VIM < Connection
32
34
  opts[:debug] = (!ENV['RBVMOMI_DEBUG'].empty? rescue false) unless opts.member? :debug
33
35
 
34
36
  new(opts).tap do |vim|
35
- vim.serviceContent.sessionManager.Login :userName => opts[:user], :password => opts[:password]
37
+ unless opts[:cookie]
38
+ vim.serviceContent.sessionManager.Login :userName => opts[:user], :password => opts[:password]
39
+ end
36
40
  unless rev_given
37
41
  rev = vim.serviceContent.about.apiVersion
38
- vim.rev = [rev, '5.0'].min
42
+ vim.rev = [rev, '5.5'].min
39
43
  end
40
44
  end
41
45
  end
@@ -45,7 +49,7 @@ class VIM < Connection
45
49
  self.cookie = nil
46
50
  super
47
51
  end
48
-
52
+
49
53
  def rev= x
50
54
  super
51
55
  @serviceContent = nil
@@ -86,6 +90,35 @@ class VIM < Connection
86
90
  pp.text "VIM(#{@opts[:host]})"
87
91
  end
88
92
 
93
+ def instanceUuid
94
+ serviceContent.about.instanceUuid
95
+ end
96
+
97
+ def get_log_lines logKey, lines=5, start=nil, host=nil
98
+ diagMgr = self.serviceContent.diagnosticManager
99
+ if !start
100
+ log = diagMgr.BrowseDiagnosticLog(host: host, key: logKey, start: 999999999)
101
+ lineEnd = log.lineEnd
102
+ start = lineEnd - lines
103
+ end
104
+ start = start < 0 ? 0 : start
105
+ log = diagMgr.BrowseDiagnosticLog(host: host, key: logKey, start: start)
106
+ if log.lineText.size > 0
107
+ [log.lineText.slice(-lines, log.lineText.size), log.lineEnd]
108
+ else
109
+ [log.lineText, log.lineEnd]
110
+ end
111
+ end
112
+
113
+ def get_log_keys host=nil
114
+ diagMgr = self.serviceContent.diagnosticManager
115
+ keys = []
116
+ diagMgr.QueryDescriptions(host: host).each do |desc|
117
+ keys << "#{desc.key}"
118
+ end
119
+ keys
120
+ end
121
+
89
122
  add_extension_dir File.join(File.dirname(__FILE__), "vim")
90
123
  (ENV['RBVMOMI_VIM_EXTENSION_PATH']||'').split(':').each { |dir| add_extension_dir dir }
91
124
 
@@ -53,6 +53,16 @@ class RbVmomi::VIM::Folder
53
53
  x if x.is_a? type
54
54
  end
55
55
 
56
+ # Retrieve a managed entity by inventory path.
57
+ # @param path [String] A path of the form "My Folder/My Datacenter/vm/Discovered VM/VM1"
58
+ # @return [VIM::ManagedEntity]
59
+ def findByInventoryPath path
60
+ propSpecs = {
61
+ :entity => self, :inventoryPath => path
62
+ }
63
+ x = _connection.searchIndex.FindByInventoryPath(propSpecs)
64
+ end
65
+
56
66
  # Alias to <tt>traverse path, type, true</tt>
57
67
  # @see #traverse
58
68
  def traverse! path, type=Object
@@ -35,7 +35,12 @@ class RbVmomi::VIM::ManagedObject
35
35
  :type => self.class.wsdl_name
36
36
  }]
37
37
  }
38
- _connection.propertyCollector.RetrieveProperties(:specSet => [spec])[0].to_hash
38
+ ret = _connection.propertyCollector.RetrieveProperties(:specSet => [spec])
39
+ if ret && ret.length > 0
40
+ ret[0].to_hash
41
+ else
42
+ {}
43
+ end
39
44
  end
40
45
 
41
46
  # Efficiently retrieve multiple properties from an object.
@@ -48,7 +48,16 @@ class RbVmomi::VIM::OvfManager
48
48
  result.warning.each{|x| puts "OVF Warning: #{x.localizedMessage.chomp}" }
49
49
  end
50
50
 
51
- nfcLease = opts[:resourcePool].ImportVApp(:spec => result.importSpec,
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,
52
61
  :folder => opts[:vmFolder],
53
62
  :host => opts[:host])
54
63
 
@@ -56,9 +65,32 @@ class RbVmomi::VIM::OvfManager
56
65
  raise nfcLease.error if nfcLease.state == "error"
57
66
  begin
58
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
59
73
  progress = 5.0
60
74
  result.fileItem.each do |fileItem|
61
- deviceUrl = nfcLease.info.deviceUrl.find{|x| x.importKey == fileItem.deviceId}
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}
62
94
  if !deviceUrl
63
95
  raise "Couldn't find deviceURL for device '#{fileItem.deviceId}'"
64
96
  end
@@ -74,12 +106,25 @@ class RbVmomi::VIM::OvfManager
74
106
 
75
107
  keepAliveThread = Thread.new do
76
108
  while true
77
- sleep 2 * 60
78
109
  nfcLease.HttpNfcLeaseProgress(:percent => progress.to_i)
110
+ sleep 1 * 60
79
111
  end
80
112
  end
81
113
 
82
- href = deviceUrl.url.gsub("*", opts[:host].config.network.vnic[0].spec.ip.ipAddress)
114
+ i = 1
115
+ ip = nil
116
+ begin
117
+ begin
118
+ puts "Iteration #{i}: Trying to get host's IP address ..."
119
+ ip = opts[:host].config.network.vnic[0].spec.ip.ipAddress
120
+ rescue Exception=>e
121
+ puts "Iteration #{i}: Couldn't get host's IP address: #{e}"
122
+ end
123
+ sleep 1
124
+ i += 1
125
+ end while i <= 5 && !ip
126
+ raise "Couldn't get host's IP address" unless ip
127
+ href = deviceUrl.url.gsub("*", ip)
83
128
  downloadCmd = "#{CURLBIN} -L '#{URI::escape(filename)}'"
84
129
  uploadCmd = "#{CURLBIN} -Ss -X #{method} --insecure -T - -H 'Content-Type: application/x-vnd.vmware-streamVmdk' '#{URI::escape(href)}'"
85
130
  # Previously we used to append "-H 'Content-Length: #{fileItem.size}'"
@@ -96,12 +141,56 @@ class RbVmomi::VIM::OvfManager
96
141
  end
97
142
 
98
143
  nfcLease.HttpNfcLeaseProgress(:percent => 100)
99
- vm = nfcLease.info.entity
100
- nfcLease.HttpNfcLeaseComplete
144
+ raise nfcLease.error if nfcLease.state == "error"
145
+ i = 1
146
+ vm = nil
147
+ begin
148
+ begin
149
+ puts "Iteration #{i}: Trying to access nfcLease.info.entity ..."
150
+ vm = nfcLease.info.entity
151
+ rescue Exception=>e
152
+ puts "Iteration #{i}: Couldn't access nfcLease.info.entity: #{e}"
153
+ end
154
+ sleep 1
155
+ i += 1
156
+ end while i <= 5 && !vm
157
+ raise "Couldn't access nfcLease.info.entity" unless vm
158
+
159
+ # Ignore sporadic connection errors caused by PR 1019166..
160
+ # Three attempts are made to execute HttpNfcLeaseComplete.
161
+ # Not critical if none goes through, as long as vm is obtained
162
+ #
163
+ # TODO: find the reason why HttpNfcLeaseComplete gets a wrong
164
+ # response (RetrievePropertiesResponse)
165
+ i = 0
166
+ begin
167
+ nfcLease.HttpNfcLeaseComplete
168
+ puts "HttpNfcLeaseComplete succeeded"
169
+ rescue RbVmomi::VIM::InvalidState
170
+ puts "HttpNfcLeaseComplete already finished.."
171
+ rescue Exception => e
172
+ puts "HttpNfcLeaseComplete failed at iteration #{i} with exception: #{e}"
173
+ i += 1
174
+ retry if i < 3
175
+ puts "Giving up HttpNfcLeaseComplete.."
176
+ end
101
177
  vm
102
178
  end
103
179
  rescue Exception
104
180
  (nfcLease.HttpNfcLeaseAbort rescue nil) if nfcLease
105
181
  raise
106
182
  end
183
+
184
+ def _handle_ost ost, opts = {}
185
+ ost = Nokogiri::XML(ost)
186
+ if opts[:vservice] == ['com.vmware.vim.vsm:extension_vservice']
187
+ ost.xpath('//vmw:Annotations/vmw:Providers/vmw:Provider').each do |x|
188
+ x['vmw:selected'] = 'selected'
189
+ end
190
+ ost.xpath('//vmw:Annotations/vmw:Providers').each do |x|
191
+ x['vmw:selected'] = 'com.vmware.vim.vsm:extension_vservice'
192
+ end
193
+ end
194
+ ost.to_s
195
+ end
107
196
  end
@@ -46,13 +46,21 @@ class RbVmomi::VIM::PerformanceManager
46
46
  end
47
47
  end
48
48
 
49
- metric_ids = metrics.map do |x|
49
+ instances = opts[:instance] || '*'
50
+ if !instances.is_a?(Array)
51
+ instances = [instances]
52
+ end
53
+ metric_ids = []
54
+ metrics.each do |x|
50
55
  counter = perfcounter_hash[x]
51
56
  if !counter
52
57
  pp perfcounter_hash.keys
53
58
  fail "Counter for #{x} couldn't be found"
54
59
  end
55
- RbVmomi::VIM::PerfMetricId(:counterId => counter.key, :instance => '*')
60
+ instances.each do |instance|
61
+ metric_ids << RbVmomi::VIM::PerfMetricId(:counterId => counter.key,
62
+ :instance => instance)
63
+ end
56
64
  end
57
65
  query_specs = objects.map do |obj|
58
66
  RbVmomi::VIM::PerfQuerySpec({
@@ -65,19 +73,36 @@ class RbVmomi::VIM::PerformanceManager
65
73
  end
66
74
  stats = QueryPerf(:querySpec => query_specs)
67
75
 
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]
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
79
103
  end
80
104
 
105
+
81
106
  def active_intervals
82
107
  intervals = historicalInterval
83
108
  Hash[(1..4).map { |level| [level, intervals.select { |x| x.enabled && x.level >= level }] }]
@@ -54,7 +54,7 @@ class RbVmomi::VIM::Task
54
54
  def child_tasks
55
55
  tm = _connection.serviceContent.taskManager
56
56
  col = tm.CreateCollectorForTasks(:filter => {
57
- :rootTaskKey => self.info.key
57
+ :rootTaskKey => [self.info.key],
58
58
  })
59
59
  # XXX: Likely this is not enough and we need to collect pages other
60
60
  # than the latest.
@@ -34,26 +34,41 @@ class RbVmomi::VIM::VirtualMachine
34
34
  def add_delta_disk_layer_on_all_disks
35
35
  devices, = self.collect 'config.hardware.device'
36
36
  disks = devices.grep(RbVmomi::VIM::VirtualDisk)
37
- # XXX: Should create a single reconfig spec instead of one per disk
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 = []
38
50
  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
- ]
51
+ device_change << {
52
+ :operation => :remove,
53
+ :device => disk
55
54
  }
56
- self.ReconfigVM_Task(:spec => spec).wait_for_completion
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
57
71
  end
72
+ spec
58
73
  end
59
74
  end
@@ -252,11 +252,14 @@ end
252
252
  :connectionState => "connected",
253
253
  :dynamicProperty => [],
254
254
  :faultToleranceState => "notConfigured",
255
+ :featureMask => [],
256
+ :featureRequirement => [],
255
257
  :host => VIM::HostSystem(nil, "host-32"),
256
258
  :maxCpuUsage => 5612,
257
259
  :maxMemoryUsage => 3072,
258
260
  :memoryOverhead => 128671744,
259
261
  :numMksConnections => 1,
262
+ :offlineFeatureRequirement => [],
260
263
  :powerState => "poweredOn",
261
264
  :recordReplayState => "inactive",
262
265
  :suspendInterval => 0,
@@ -287,9 +287,9 @@ class SerializationTest < Test::Unit::TestCase
287
287
  end
288
288
 
289
289
  def test_time
290
- obj = Time.at DateTime.new(2011, 11, 16, 13, 36, 8, Rational(-8,24)).strftime("%s").to_i
290
+ obj = Time.at(DateTime.new(2011, 11, 16, 13, 36, 8, Rational(-8,24)).strftime("%s").to_i).getgm
291
291
  check <<-EOS, obj, 'xsd:dateTime', false
292
- <root>2011-11-16T13:36:08-08:00</root>
292
+ <root>2011-11-16T21:36:08Z</root>
293
293
  EOS
294
294
  end
295
295
 
data/vmodl.db CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbvmomi
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.8.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-09-19 00:00:00.000000000 Z
13
+ date: 2013-12-18 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: nokogiri
@@ -80,6 +80,7 @@ files:
80
80
  - devel/benchmark.rb
81
81
  - devel/collisions.rb
82
82
  - devel/merge-internal-vmodl.rb
83
+ - devel/merge-manual-vmodl.rb
83
84
  - examples/annotate.rb
84
85
  - examples/cached_ovf_deploy.rb
85
86
  - examples/clone_vm.rb
@@ -102,12 +103,16 @@ files:
102
103
  - lib/rbvmomi/connection.rb
103
104
  - lib/rbvmomi/deserialization.rb
104
105
  - lib/rbvmomi/fault.rb
106
+ - lib/rbvmomi/pbm.rb
107
+ - lib/rbvmomi/sms.rb
108
+ - lib/rbvmomi/sms/SmsStorageManager.rb
105
109
  - lib/rbvmomi/trivial_soap.rb
106
110
  - lib/rbvmomi/trollop.rb
107
111
  - lib/rbvmomi/type_loader.rb
108
112
  - lib/rbvmomi/utils/admission_control.rb
109
113
  - lib/rbvmomi/utils/deploy.rb
110
114
  - lib/rbvmomi/utils/leases.rb
115
+ - lib/rbvmomi/utils/perfdump.rb
111
116
  - lib/rbvmomi/vim.rb
112
117
  - lib/rbvmomi/vim/ComputeResource.rb
113
118
  - lib/rbvmomi/vim/Datacenter.rb