rvc 1.5.0 → 1.6.0

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 (54) hide show
  1. data/README.rdoc +1 -1
  2. data/Rakefile +2 -1
  3. data/VERSION +1 -1
  4. data/bin/rvc +53 -9
  5. data/lib/rvc/completion.rb +57 -19
  6. data/lib/rvc/extensions/ComputeResource.rb +2 -2
  7. data/lib/rvc/extensions/DVPortSetting.rb +108 -0
  8. data/lib/rvc/extensions/Datacenter.rb +19 -4
  9. data/lib/rvc/extensions/Datastore.rb +6 -1
  10. data/lib/rvc/extensions/DistributedVirtualPort.rb +146 -0
  11. data/lib/rvc/extensions/DistributedVirtualPortgroup.rb +274 -10
  12. data/lib/rvc/extensions/DistributedVirtualSwitch.rb +124 -3
  13. data/lib/rvc/extensions/Folder.rb +9 -2
  14. data/lib/rvc/extensions/HostSystem.rb +60 -0
  15. data/lib/rvc/extensions/ManagedEntity.rb +19 -0
  16. data/lib/rvc/extensions/ParaVirtualSCSIController.rb +25 -0
  17. data/lib/rvc/extensions/PerfCounterInfo.rb +26 -0
  18. data/lib/rvc/extensions/PerformanceManager.rb +83 -0
  19. data/lib/rvc/extensions/ResourcePool.rb +21 -0
  20. data/lib/rvc/extensions/VirtualDevice.rb +59 -0
  21. data/lib/rvc/extensions/VirtualDisk.rb +25 -0
  22. data/lib/rvc/extensions/VirtualEthernetCard.rb +32 -0
  23. data/lib/rvc/extensions/VirtualMachine.rb +112 -1
  24. data/lib/rvc/field.rb +122 -0
  25. data/lib/rvc/filesystem_session.rb +20 -0
  26. data/lib/rvc/inventory.rb +35 -12
  27. data/lib/rvc/known_hosts.rb +20 -0
  28. data/lib/rvc/memory_session.rb +20 -0
  29. data/lib/rvc/modules.rb +67 -7
  30. data/lib/rvc/modules/alarm.rb +37 -0
  31. data/lib/rvc/modules/basic.rb +172 -41
  32. data/lib/rvc/modules/cluster.rb +18 -2
  33. data/lib/rvc/modules/core.rb +63 -0
  34. data/lib/rvc/modules/datastore.rb +158 -0
  35. data/lib/rvc/modules/device.rb +275 -0
  36. data/lib/rvc/modules/esxcli.rb +193 -0
  37. data/lib/rvc/modules/find.rb +125 -0
  38. data/lib/rvc/modules/issue.rb +33 -0
  39. data/lib/rvc/modules/perf.rb +284 -0
  40. data/lib/rvc/modules/permissions.rb +20 -0
  41. data/lib/rvc/modules/resource_pool.rb +69 -0
  42. data/lib/rvc/modules/role.rb +23 -3
  43. data/lib/rvc/modules/snapshot.rb +20 -0
  44. data/lib/rvc/modules/vds.rb +605 -0
  45. data/lib/rvc/modules/vim.rb +103 -26
  46. data/lib/rvc/modules/vm.rb +93 -220
  47. data/lib/rvc/modules/vnc.rb +50 -13
  48. data/lib/rvc/option_parser.rb +50 -2
  49. data/lib/rvc/readline-ffi.rb +2 -1
  50. data/lib/rvc/shell.rb +34 -33
  51. data/lib/rvc/util.rb +120 -2
  52. data/test/test_fs.rb +9 -5
  53. data/test/test_metric.rb +79 -0
  54. metadata +33 -3
@@ -30,10 +30,31 @@ URI_REGEX = %r{
30
30
  @
31
31
  )?
32
32
  ([^@:]+)
33
- (?::(.*))?
33
+ (?::(\d{1,5}))?
34
+ (?::([0-9a-z]{64}))?
34
35
  $
35
36
  }x
36
37
 
38
+ class RbVmomi::VIM
39
+ include RVC::InventoryObject
40
+
41
+ def children
42
+ rootFolder.children
43
+ end
44
+
45
+ def self.folder?
46
+ true
47
+ end
48
+
49
+ def display_info
50
+ puts serviceContent.about.fullName
51
+ end
52
+
53
+ def _connection
54
+ self
55
+ end
56
+ end
57
+
37
58
  opts :connect do
38
59
  summary 'Open a connection to ESX/VC'
39
60
  arg :uri, "Host to connect to"
@@ -49,14 +70,15 @@ def connect uri, opts
49
70
  username = match[1] || ENV['RBVMOMI_USER']
50
71
  password = match[2] || ENV['RBVMOMI_PASSWORD']
51
72
  host = match[3]
52
- path = match[4]
73
+ port = match[4] || 443
74
+ certdigest = match[5] || opts[:certdigest]
53
75
  bad_cert = false
54
76
 
55
77
  vim = nil
56
78
  loop do
57
79
  begin
58
80
  vim = RbVmomi::VIM.new :host => host,
59
- :port => 443,
81
+ :port => port,
60
82
  :path => '/sdk',
61
83
  :ns => 'urn:vim25',
62
84
  :rev => (opts[:rev]||'4.0'),
@@ -73,15 +95,27 @@ def connect uri, opts
73
95
  end
74
96
 
75
97
  if bad_cert
76
- # Fall back to SSH-style known_hosts
77
98
  peer_public_key = vim.http.peer_cert.public_key
78
- check_known_hosts(host, peer_public_key)
99
+ # if user specified a hash on the commandline, verify against that
100
+ if certdigest
101
+ if certdigest != Digest::SHA2.hexdigest(peer_public_key.to_s())
102
+ err "Bad certificate digest specified for #{host}!"
103
+ end
104
+ else
105
+ # Fall back to SSH-style known_hosts
106
+ check_known_hosts(host, peer_public_key)
107
+ end
79
108
  end
80
109
 
81
110
  unless opts[:rev]
82
111
  # negotiate API version
83
112
  rev = vim.serviceContent.about.apiVersion
84
- vim.rev = [rev, ENV['RVC_VIMREV'] || '5.0'].min
113
+ env_rev = ENV['RVC_VIMREV']
114
+ if env_rev && env_rev.to_f == 0
115
+ vim.rev = env_rev
116
+ else
117
+ vim.rev = [rev, env_rev || '5.0'].min
118
+ end
85
119
  end
86
120
 
87
121
  isVC = vim.serviceContent.about.apiType == "VirtualCenter"
@@ -106,15 +140,19 @@ def connect uri, opts
106
140
  loaded_from_keychain = password
107
141
  end
108
142
 
109
- password_given = password != nil
110
- loop do
111
- begin
112
- password = prompt_password unless password_given
113
- vim.serviceContent.sessionManager.Login :userName => username,
114
- :password => password
115
- break
116
- rescue RbVmomi::VIM::InvalidLogin
117
- err $!.message if password_given
143
+ if opts[:cookie]
144
+ vim.cookie = opts[:cookie]
145
+ else
146
+ password_given = password != nil
147
+ loop do
148
+ begin
149
+ password = prompt_password unless password_given
150
+ vim.serviceContent.sessionManager.Login :userName => username,
151
+ :password => password
152
+ break
153
+ rescue RbVmomi::VIM::InvalidLogin
154
+ err $!.message if password_given
155
+ end
118
156
  end
119
157
  end
120
158
 
@@ -147,7 +185,7 @@ def prompt_password
147
185
  end
148
186
 
149
187
  def keychain_password username , hostname
150
- return nil unless RbConfig::CONFIG['host_os'] =~ /^darwin10/
188
+ return nil unless RbConfig::CONFIG['host_os'] =~ /^darwin1[01]/
151
189
 
152
190
  begin
153
191
  require 'osx_keychain'
@@ -198,16 +236,6 @@ def check_known_hosts host, peer_public_key
198
236
  end
199
237
  end
200
238
 
201
- class RbVmomi::VIM
202
- def display_info
203
- puts serviceContent.about.fullName
204
- end
205
-
206
- def _connection
207
- self
208
- end
209
- end
210
-
211
239
 
212
240
  opts :tasks do
213
241
  summary "Watch tasks in progress"
@@ -269,3 +297,52 @@ def tasks
269
297
  view.DestroyView if view
270
298
  end
271
299
  end
300
+
301
+
302
+ opts :logbundles do
303
+ summary "Download log bundles"
304
+ arg :servers, "VIM connection and/or ESX hosts", :lookup => [RbVmomi::VIM, VIM::HostSystem], :multi => true
305
+ opt :dest, "Destination directory", :default => '.'
306
+ end
307
+
308
+ DEFAULT_SERVER_PLACEHOLDER = '0.0.0.0'
309
+
310
+ def logbundles servers, opts
311
+ vim = single_connection servers
312
+ diagMgr = vim.serviceContent.diagnosticManager
313
+ name = vim.host
314
+ FileUtils.mkdir_p opts[:dest]
315
+
316
+ hosts = servers.grep VIM::HostSystem
317
+ include_default = servers.member? vim
318
+
319
+ puts "#{Time.now}: Generating log bundles..."
320
+ bundles =
321
+ begin
322
+ diagMgr.GenerateLogBundles_Task(:includeDefault => include_default, :host => hosts).wait_for_completion
323
+ rescue VIM::TaskInProgress
324
+ $!.task.wait_for_completion
325
+ end
326
+
327
+ dest_path = nil
328
+ bundles.each do |b|
329
+ uri = URI.parse(b.url.sub('*', DEFAULT_SERVER_PLACEHOLDER))
330
+ bundle_name = b.system ? b.system.name : name
331
+ dest_path = File.join(opts[:dest], "#{bundle_name}-" + File.basename(uri.path))
332
+ puts "#{Time.now}: Downloading bundle #{b.url} to #{dest_path}"
333
+ uri.host = vim.http.address if uri.host == DEFAULT_SERVER_PLACEHOLDER
334
+ Net::HTTP.get_response uri do |res|
335
+ File.open dest_path, 'w' do |io|
336
+ res.read_body do |data|
337
+ io.write data
338
+ if $stdout.tty?
339
+ $stdout.write '.'
340
+ $stdout.flush
341
+ end
342
+ end
343
+ end
344
+ puts if $stdout.tty?
345
+ end
346
+ end
347
+ dest_path
348
+ end
@@ -68,13 +68,39 @@ def suspend vms
68
68
  end
69
69
 
70
70
 
71
+ opts :wait_for_shutdown do
72
+ summary "Waits for a VM to shutdown"
73
+ arg :vm, nil, :multi => true, :lookup => VIM::VirtualMachine
74
+ opt :timeout, "Timeout in seconds", :type => :int, :default => 300
75
+ opt :delay, "Interval in seconds", :type => :int, :default => 5
76
+ end
77
+
78
+ def wait_for_shutdown vms, opts
79
+ finish_time = Time.now + opts[:timeout]
80
+ while Time.now < finish_time
81
+ all_off = true
82
+ vms.each do |vm|
83
+ if vm.summary.runtime.powerState == 'poweredOn'
84
+ all_off = false
85
+ end
86
+ end
87
+ return if all_off
88
+ sleep [opts[:delay], finish_time - Time.now].min
89
+ end
90
+ puts "WARNING: At least one VM did not shut down!"
91
+ end
92
+
93
+
71
94
  opts :shutdown_guest do
72
95
  summary "Shut down guest OS"
73
96
  arg :vm, nil, :multi => true, :lookup => VIM::VirtualMachine
97
+ opt :timeout, "Timeout for guest shut down in seconds", :type => :int, :default => nil
98
+ opt :delay, "Interval between checks for guest shut down in seconds", :type => :int, :default => nil
74
99
  end
75
100
 
76
- def shutdown_guest vms
101
+ def shutdown_guest vms, opts
77
102
  vms.each(&:ShutdownGuest)
103
+ wait_for_shutdown vms, opts unless opts[:timeout].nil?
78
104
  end
79
105
 
80
106
 
@@ -102,44 +128,25 @@ opts :create do
102
128
  summary "Create a new VM"
103
129
  arg :name, "Destination", :lookup_parent => VIM::Folder
104
130
  opt :pool, "Resource pool", :short => 'p', :type => :string, :lookup => VIM::ResourcePool
105
- opt :host, "Host", :short => 'h', :type => :string, :lookup => VIM::HostSystem
131
+ opt :host, "Host", :short => 'o', :type => :string, :lookup => VIM::HostSystem
106
132
  opt :datastore, "Datastore", :short => 'd', :type => :string, :lookup => VIM::Datastore
107
- opt :disksize, "Size in KB of primary disk (or add a unit of <M|G|T>)", :short => 's', :type => :string, :default => "4000000"
108
133
  opt :memory, "Size in MB of memory", :short => 'm', :type => :int, :default => 128
109
- opt :cpucount, "Number of CPUs", :short => 'c', :type => :int, :default => 1
134
+ opt :cpus, "Number of CPUs", :short => 'c', :type => :int, :default => 1
135
+ opt :guest_id, "Guest OS", :short => 'g', :default => "otherGuest" # XXX tab complete
136
+
110
137
  text <<-EOB
111
138
 
112
- Example:
113
- vm.create -p ~foo/resourcePool/pools/prod -d ~data/bigdisk -s 10g ~vms/new
139
+ No disks or network adapters are initially present. Use device.add_disk and
140
+ device.add_net to do this.
114
141
 
142
+ Example:
143
+ vm.create ~/vm/foo --pool ~/host/my_cluster/resourcePool --datastore ~/datastore/my_datastore
144
+ device.add_disk ~/vm/foo -s 30G
145
+ device.add_net ~/vm/foo ~/network/VM\\ Network
115
146
  EOB
116
147
  end
117
148
 
118
149
 
119
- def realdisksize( size )
120
- size.downcase!
121
- if size =~ /([0-9][0-9,]*)([mgt])?/i
122
- size = $1.delete(',').to_i
123
- unit = $2
124
-
125
- case unit
126
- when 'm'
127
- return size * 1024
128
- when 'g'
129
- return size * ( 1024 ** 2 )
130
- when 't'
131
- return size * ( 1024 ** 3 )
132
- when nil
133
- return size
134
- else
135
- err "Unknown size modifer of '#{unit}'"
136
- end
137
- else
138
- err "Problem with #{size}"
139
- end
140
- end
141
-
142
-
143
150
  def create dest, opts
144
151
  err "must specify resource pool (--pool)" unless opts[:pool]
145
152
  err "must specify datastore (--datastore)" unless opts[:datastore]
@@ -148,33 +155,12 @@ def create dest, opts
148
155
  datastore_path = "[#{opts[:datastore].name}]"
149
156
  config = {
150
157
  :name => name,
151
- :guestId => 'otherGuest',
158
+ :guestId => opts[:guest_id],
152
159
  :files => { :vmPathName => datastore_path },
153
160
  :numCPUs => opts[:cpucount],
154
161
  :memoryMB => opts[:memory],
155
162
  :deviceChange => [
156
163
  {
157
- :operation => :add,
158
- :device => VIM.VirtualLsiLogicController(
159
- :key => 1000,
160
- :busNumber => 0,
161
- :sharedBus => :noSharing
162
- )
163
- }, {
164
- :operation => :add,
165
- :fileOperation => :create,
166
- :device => VIM.VirtualDisk(
167
- :key => -1,
168
- :backing => VIM.VirtualDiskFlatVer2BackingInfo(
169
- :fileName => datastore_path,
170
- :diskMode => :persistent,
171
- :thinProvisioned => true
172
- ),
173
- :controllerKey => 1000,
174
- :unitNumber => 0,
175
- :capacityInKB => realdisksize( opts[:disksize] )
176
- )
177
- }, {
178
164
  :operation => :add,
179
165
  :device => VIM.VirtualCdrom(
180
166
  :key => -2,
@@ -189,19 +175,6 @@ def create dest, opts
189
175
  :controllerKey => 200,
190
176
  :unitNumber => 0
191
177
  )
192
- }, {
193
- :operation => :add,
194
- :device => VIM.VirtualE1000(
195
- :key => -3,
196
- :deviceInfo => {
197
- :label => 'Network Adapter 1',
198
- :summary => 'VM Network'
199
- },
200
- :backing => VIM.VirtualEthernetCardNetworkBackingInfo(
201
- :deviceName => 'VM Network'
202
- ),
203
- :addressType => 'generated'
204
- )
205
178
  }
206
179
  ],
207
180
  }
@@ -211,30 +184,6 @@ def create dest, opts
211
184
  end
212
185
 
213
186
 
214
- opts :insert_cdrom do
215
- summary "Put a disc in a virtual CDROM drive"
216
- arg :vm, nil, :lookup => VIM::VirtualMachine
217
- arg :iso, "Path to the ISO image on a datastore", :lookup => VIM::Datastore::FakeDatastoreFile
218
- end
219
-
220
- def insert_cdrom vm, iso
221
- device = vm.config.hardware.device.grep(VIM::VirtualCdrom)[0]
222
- err "No virtual CDROM drive found" unless device
223
-
224
- device.backing = VIM.VirtualCdromIsoBackingInfo(:fileName => iso.datastore_path)
225
-
226
- spec = {
227
- :deviceChange => [
228
- {
229
- :operation => :edit,
230
- :device => device
231
- }
232
- ]
233
- }
234
-
235
- vm.ReconfigVM_Task(:spec => spec)
236
- end
237
-
238
187
  opts :register do
239
188
  summary "Register a VM already in a datastore"
240
189
  arg :file, "RVC path to the VMX file", :lookup => VIM::Datastore::FakeDatastoreFile
@@ -326,22 +275,26 @@ def kill vms
326
275
  CMD.basic.destroy vms unless vms.empty?
327
276
  end
328
277
 
329
-
330
278
  opts :answer do
331
279
  summary "Answer a VM question"
332
- arg :vm, nil, :lookup => VIM::VirtualMachine
333
280
  arg :choice, "Answer ID"
281
+ arg :vm, nil, :lookup => VIM::VirtualMachine, :multi => true
334
282
  end
335
283
 
336
- def answer vm, str
337
- q = vm.runtime.question
338
- err "no question" unless q
339
- choice = q.choice.choiceInfo.find { |x| x.label == str }
340
- err("invalid answer") unless choice
341
- vm.AnswerVM :questionid => q.path, :answerChoice => choice.key
284
+ def answer str, vms
285
+ vms.each do |vm|
286
+ begin
287
+ if q = vm.runtime.question
288
+ choice = q.choice.choiceInfo.find { |x| x.label == str }
289
+ err("invalid answer") unless choice
290
+ vm.AnswerVM :questionId => q.id, :answerChoice => choice.key
291
+ end
292
+ rescue
293
+ puts "#{vm.name rescue vm}: #{$!.message}"
294
+ end
295
+ end
342
296
  end
343
297
 
344
-
345
298
  opts :layout do
346
299
  summary "Display info about VM files"
347
300
  arg :vm, nil, :lookup => VIM::VirtualMachine
@@ -354,43 +307,6 @@ def layout vm
354
307
  end
355
308
 
356
309
 
357
- opts :devices do
358
- summary "Display info about VM devices"
359
- arg :vm, nil, :lookup => VIM::VirtualMachine
360
- end
361
-
362
- def devices vm
363
- devs = vm.config.hardware.device
364
- devs.each do |dev|
365
- tags = []
366
- tags << (dev.connectable.connected ? :connected : :disconnected) if dev.props.member? :connectable
367
- puts "#{dev.deviceInfo.label} (#{dev.class}): #{dev.deviceInfo.summary}; #{tags * ' '}"
368
- end
369
- end
370
-
371
-
372
- opts :connect do
373
- summary "Connect a virtual device"
374
- arg :vm, nil, :lookup => VIM::VirtualMachine
375
- arg :label, "Device label"
376
- end
377
-
378
- def connect vm, label
379
- change_device_connectivity vm, label, true
380
- end
381
-
382
-
383
- opts :disconnect do
384
- summary "Disconnect a virtual device"
385
- arg :vm, nil, :lookup => VIM::VirtualMachine
386
- arg :label, "Device label"
387
- end
388
-
389
- def disconnect vm, label
390
- change_device_connectivity vm, label, false
391
- end
392
-
393
-
394
310
  opts :find do
395
311
  summary "Display a menu of VMX files to register"
396
312
  arg :datastore, nil, :lookup => VIM::Datastore
@@ -417,37 +333,37 @@ def find ds, opts
417
333
  end
418
334
 
419
335
 
420
- opts :extraConfig do
336
+ opts :extra_config do
421
337
  summary "Display extraConfig options"
422
338
  arg :vm, nil, :lookup => VIM::VirtualMachine
423
339
  arg :regex, "Regexes to filter keys", :multi => true, :required => false
424
340
  end
425
341
 
426
- def extraConfig vm, regexes
427
- _extraConfig(vm, *regexes.map { |x| /#{x}/ })
342
+ def extra_config vm, regexes
343
+ _extra_config(vm, *regexes.map { |x| /#{x}/ })
428
344
  end
429
345
 
430
346
 
431
- opts :setExtraConfig do
347
+ opts :set_extra_config do
432
348
  summary "Set extraConfig options"
433
349
  arg :vm, nil, :lookup => VIM::VirtualMachine
434
350
  arg 'key=value', "extraConfig key/value pairs", :multi => true
435
351
  end
436
352
 
437
- def setExtraConfig vm, pairs
353
+ def set_extra_config vm, pairs
438
354
  h = Hash[pairs.map { |x| x.split('=', 2).tap { |a| a << '' if a.size == 1 } }]
439
- _setExtraConfig vm, h
355
+ _set_extra_config vm, h
440
356
  end
441
357
 
442
358
 
443
- def _setExtraConfig vm, hash
359
+ def _set_extra_config vm, hash
444
360
  cfg = {
445
361
  :extraConfig => hash.map { |k,v| { :key => k, :value => v } },
446
362
  }
447
363
  vm.ReconfigVM_Task(:spec => cfg).wait_for_completion
448
364
  end
449
365
 
450
- def _extraConfig vm, *regexes
366
+ def _extra_config vm, *regexes
451
367
  vm.config.extraConfig.each do |h|
452
368
  if regexes.empty? or regexes.any? { |r| h[:key] =~ r }
453
369
  puts "#{h[:key]}: #{h[:value]}"
@@ -492,6 +408,34 @@ def rvc vm, opts
492
408
  system_fg(cmd, env)
493
409
  end
494
410
 
411
+ opts :rdp do
412
+ summary "Connect via RDP"
413
+ arg :vms, nil, :lookup => VIM::VirtualMachine, :multi => true
414
+ opt :resolution, "Desired resolution", :type => :string, :default => ($rdpResolution ? $rdpResolution : '1024x768')
415
+ opt :username, "Username", :type => :string, :default => 'Administrator'
416
+ opt :password, "Password", :type => :string, :default => ($rdpDefaultPassword ? $rdpDefaultPassword : '')
417
+ end
418
+
419
+ rvc_alias :rdp, :rdp
420
+
421
+ def rdp vms, h
422
+ resolution = h[:resolution]
423
+ if !resolution
424
+ resolution = $rdpResolution ? $rdpResolution : '1024x768'
425
+ end
426
+ vms.each do |vm|
427
+ ip = vm_ip vm
428
+
429
+ begin
430
+ timeout(1) { TCPSocket.new ip, 3389; up = true }
431
+ rescue
432
+ puts "#{vm.name}: Warning: Looks like the RDP port is not responding"
433
+ end
434
+
435
+ cmd = "rdesktop -u '#{h[:username]}' -p '#{h[:password]}' -g#{resolution} #{ip} >/dev/null 2>&1 &"
436
+ system(cmd)
437
+ end
438
+ end
495
439
 
496
440
  opts :ping do
497
441
  summary "Ping a VM"
@@ -542,71 +486,11 @@ ensure
542
486
  end
543
487
 
544
488
 
545
- opts :add_net_device do
546
- summary "Add a network adapter to a virtual machine"
547
- arg :vm, nil, :lookup => VIM::VirtualMachine
548
- opt :type, "Adapter type", :default => 'e1000'
549
- opt :network, "Network to connect to", :default => 'VM Network'
550
- end
551
-
552
- def add_net_device vm, opts
553
- case opts[:type]
554
- when 'e1000'
555
- _add_net_device vm, VIM::VirtualE1000, opts[:network]
556
- when 'vmxnet3'
557
- _add_net_device vm, VIM::VirtualVmxnet3, opts[:network]
558
- else err "unknown device"
559
- end
560
- end
561
-
562
-
563
- def _add_device vm, dev
564
- spec = {
565
- :deviceChange => [
566
- { :operation => :add, :device => dev },
567
- ]
568
- }
569
- vm.ReconfigVM_Task(:spec => spec).wait_for_completion
570
- end
571
-
572
- def _add_net_device vm, klass, network
573
- _add_device vm, klass.new(
574
- :key => -1,
575
- :deviceInfo => {
576
- :summary => network,
577
- :label => `uuidgen`.chomp
578
- },
579
- :backing => VIM.VirtualEthernetCardNetworkBackingInfo(
580
- :deviceName => network
581
- ),
582
- :addressType => 'generated'
583
- )
584
- end
585
-
586
-
587
- opts :remove_device do
588
- summary "Remove a virtual device"
589
- arg :vm, nil, :lookup => VIM::VirtualMachine
590
- arg :label, "Device label"
591
- end
592
-
593
- def remove_device vm, label
594
- dev = vm.config.hardware.device.find { |x| x.deviceInfo.label == label }
595
- err "no such device" unless dev
596
- spec = {
597
- :deviceChange => [
598
- { :operation => :remove, :device => dev },
599
- ]
600
- }
601
- vm.ReconfigVM_Task(:spec => spec).wait_for_completion
602
- end
603
-
604
-
605
489
  opts :migrate do
606
490
  summary "Migrate a VM"
607
491
  arg :vm, nil, :lookup => VIM::VirtualMachine, :multi => true
608
492
  opt :pool, "Resource pool", :short => 'p', :type => :string, :lookup => VIM::ResourcePool
609
- opt :host, "Host", :short => 'h', :type => :string, :lookup => VIM::HostSystem
493
+ opt :host, "Host", :short => 'o', :type => :string, :lookup => VIM::HostSystem
610
494
  end
611
495
 
612
496
  def migrate vms, opts
@@ -621,10 +505,10 @@ opts :clone do
621
505
  arg :src, nil, :lookup => VIM::VirtualMachine
622
506
  arg :dst, "Path to new VM", :lookup_parent => VIM::Folder
623
507
  opt :pool, "Resource pool", :short => 'p', :type => :string, :lookup => VIM::ResourcePool
624
- opt :host, "Host", :short => 'h', :type => :string, :lookup => VIM::HostSystem
508
+ opt :host, "Host", :short => 'o', :type => :string, :lookup => VIM::HostSystem
625
509
  opt :template, "Create a template", :short => 't'
626
510
  opt :linked, "Create a linked clone", :short => 'l'
627
- opt :powerOn, "Power on VM after clone"
511
+ opt :power_on, "Power on VM after clone"
628
512
  end
629
513
 
630
514
  def clone src, dst, opts
@@ -645,12 +529,11 @@ def clone src, dst, opts
645
529
  :pool => opts[:pool],
646
530
  },
647
531
  :template => opts[:template],
648
- :powerOn => opts[:powerOn],
532
+ :powerOn => opts[:power_on],
649
533
  })
650
534
  progress [task]
651
535
  end
652
536
 
653
-
654
537
  def deltaize_disks vm
655
538
  real_disks = vm.config.hardware.device.grep(VIM::VirtualDisk).select { |x| x.backing.parent == nil }
656
539
  unless real_disks.empty?
@@ -703,6 +586,8 @@ opts :modify_memory do
703
586
  end
704
587
 
705
588
  def modify_memory vm, opts
589
+ err "VM needs to be off" unless vm.summary.runtime.powerState == 'poweredOff'
590
+ err "memory must be a multiple of 4MB" unless ( opts[:size] % 4 ) == 0
706
591
  spec = { :memoryMB => opts[:size] }
707
592
  tasks [vm], :ReconfigVM, :spec => spec
708
593
  end
@@ -730,18 +615,6 @@ def find_vmx_files ds
730
615
  files
731
616
  end
732
617
 
733
- def change_device_connectivity vm, label, connected
734
- dev = vm.config.hardware.device.find { |x| x.deviceInfo.label == label }
735
- err "no such device" unless dev
736
- dev.connectable.connected = connected
737
- spec = {
738
- :deviceChange => [
739
- { :operation => :edit, :device => dev },
740
- ]
741
- }
742
- vm.ReconfigVM_Task(:spec => spec).wait_for_completion
743
- end
744
-
745
618
  def vm_ip vm
746
619
  summary = vm.summary
747
620