rvc 1.5.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +1 -1
- data/Rakefile +2 -1
- data/VERSION +1 -1
- data/bin/rvc +53 -9
- data/lib/rvc/completion.rb +57 -19
- data/lib/rvc/extensions/ComputeResource.rb +2 -2
- data/lib/rvc/extensions/DVPortSetting.rb +108 -0
- data/lib/rvc/extensions/Datacenter.rb +19 -4
- data/lib/rvc/extensions/Datastore.rb +6 -1
- data/lib/rvc/extensions/DistributedVirtualPort.rb +146 -0
- data/lib/rvc/extensions/DistributedVirtualPortgroup.rb +274 -10
- data/lib/rvc/extensions/DistributedVirtualSwitch.rb +124 -3
- data/lib/rvc/extensions/Folder.rb +9 -2
- data/lib/rvc/extensions/HostSystem.rb +60 -0
- data/lib/rvc/extensions/ManagedEntity.rb +19 -0
- data/lib/rvc/extensions/ParaVirtualSCSIController.rb +25 -0
- data/lib/rvc/extensions/PerfCounterInfo.rb +26 -0
- data/lib/rvc/extensions/PerformanceManager.rb +83 -0
- data/lib/rvc/extensions/ResourcePool.rb +21 -0
- data/lib/rvc/extensions/VirtualDevice.rb +59 -0
- data/lib/rvc/extensions/VirtualDisk.rb +25 -0
- data/lib/rvc/extensions/VirtualEthernetCard.rb +32 -0
- data/lib/rvc/extensions/VirtualMachine.rb +112 -1
- data/lib/rvc/field.rb +122 -0
- data/lib/rvc/filesystem_session.rb +20 -0
- data/lib/rvc/inventory.rb +35 -12
- data/lib/rvc/known_hosts.rb +20 -0
- data/lib/rvc/memory_session.rb +20 -0
- data/lib/rvc/modules.rb +67 -7
- data/lib/rvc/modules/alarm.rb +37 -0
- data/lib/rvc/modules/basic.rb +172 -41
- data/lib/rvc/modules/cluster.rb +18 -2
- data/lib/rvc/modules/core.rb +63 -0
- data/lib/rvc/modules/datastore.rb +158 -0
- data/lib/rvc/modules/device.rb +275 -0
- data/lib/rvc/modules/esxcli.rb +193 -0
- data/lib/rvc/modules/find.rb +125 -0
- data/lib/rvc/modules/issue.rb +33 -0
- data/lib/rvc/modules/perf.rb +284 -0
- data/lib/rvc/modules/permissions.rb +20 -0
- data/lib/rvc/modules/resource_pool.rb +69 -0
- data/lib/rvc/modules/role.rb +23 -3
- data/lib/rvc/modules/snapshot.rb +20 -0
- data/lib/rvc/modules/vds.rb +605 -0
- data/lib/rvc/modules/vim.rb +103 -26
- data/lib/rvc/modules/vm.rb +93 -220
- data/lib/rvc/modules/vnc.rb +50 -13
- data/lib/rvc/option_parser.rb +50 -2
- data/lib/rvc/readline-ffi.rb +2 -1
- data/lib/rvc/shell.rb +34 -33
- data/lib/rvc/util.rb +120 -2
- data/test/test_fs.rb +9 -5
- data/test/test_metric.rb +79 -0
- metadata +33 -3
data/lib/rvc/modules/vim.rb
CHANGED
@@ -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
|
-
|
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 =>
|
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
|
-
|
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
|
-
|
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
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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'] =~ /^
|
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
|
data/lib/rvc/modules/vm.rb
CHANGED
@@ -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 => '
|
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 :
|
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
|
-
|
113
|
-
|
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 =>
|
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
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
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 :
|
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
|
427
|
-
|
342
|
+
def extra_config vm, regexes
|
343
|
+
_extra_config(vm, *regexes.map { |x| /#{x}/ })
|
428
344
|
end
|
429
345
|
|
430
346
|
|
431
|
-
opts :
|
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
|
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
|
-
|
355
|
+
_set_extra_config vm, h
|
440
356
|
end
|
441
357
|
|
442
358
|
|
443
|
-
def
|
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
|
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 => '
|
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 => '
|
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 :
|
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[:
|
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
|
|