rvc 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
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