vbox-ng 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/vbox-ng.rb +10 -0
- data/lib/vbox.rb +10 -0
- data/lib/vbox/cli.rb +0 -236
- data/lib/vbox/cmdlineapi.rb +266 -0
- data/lib/vbox/vm.rb +61 -0
- data/spec/vm_spec.rb +54 -0
- data/vbox-ng.gemspec +5 -2
- metadata +6 -3
- data/spec/vbox-ng_spec.rb +0 -7
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/lib/vbox-ng.rb
ADDED
data/lib/vbox.rb
CHANGED
data/lib/vbox/cli.rb
CHANGED
@@ -2,21 +2,10 @@
|
|
2
2
|
require 'awesome_print'
|
3
3
|
require 'optparse'
|
4
4
|
|
5
|
-
# for natural sort order
|
6
|
-
# http://stackoverflow.com/questions/4078906/is-there-a-natural-sort-by-method-for-ruby
|
7
|
-
class String
|
8
|
-
def naturalized
|
9
|
-
scan(/[^\d]+|\d+/).collect { |f| f.match(/\d+/) ? f.to_i : f }
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
5
|
module VBOX
|
14
6
|
|
15
|
-
COMMANDS = %w'start pause resume reset poweroff savestate acpipowerbutton acpisleepbutton clone delete show'
|
16
7
|
ALIASES = {'clonevm'=>'clone', 'destroy'=>'delete', 'rm'=>'delete'}
|
17
8
|
|
18
|
-
UUID_RE = /\{\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\}/
|
19
|
-
|
20
9
|
class CLI
|
21
10
|
def initialize argv = ARGV
|
22
11
|
@argv = argv
|
@@ -178,231 +167,6 @@ module VBOX
|
|
178
167
|
end
|
179
168
|
end
|
180
169
|
|
181
|
-
VMInfo = Struct.new :name, :uuid, :memory_size, :dir_size, :state
|
182
|
-
Snapshot = Struct.new :name, :uuid
|
183
|
-
|
184
|
-
class CmdLineAPI
|
185
|
-
def initialize options={}
|
186
|
-
@options = options
|
187
|
-
@options[:verbose] ||= 2 if @options[:dry_run]
|
188
|
-
@options[:verbose] ||= 0
|
189
|
-
end
|
190
|
-
|
191
|
-
# run as in backtick operator, and return result
|
192
|
-
def ` cmd
|
193
|
-
puts "[.] #{cmd}".gray if @options[:verbose] >= 2
|
194
|
-
exit if @options[:dry_run]
|
195
|
-
r = super
|
196
|
-
#exit 1 unless $?.success?
|
197
|
-
r
|
198
|
-
end
|
199
|
-
|
200
|
-
# run as in system() call
|
201
|
-
def system *args
|
202
|
-
puts "[.] #{args.inspect}".gray if @options[:verbose] >= 2
|
203
|
-
exit if @options[:dry_run]
|
204
|
-
r = super
|
205
|
-
exit 1 unless $?.success?
|
206
|
-
r
|
207
|
-
end
|
208
|
-
|
209
|
-
def get_vm_details vm
|
210
|
-
data = `VBoxManage showvminfo #{vm.uuid} --machinereadable`
|
211
|
-
data.each_line do |line|
|
212
|
-
a = line.strip.split('=',2)
|
213
|
-
next unless a.size == 2
|
214
|
-
k,v = a
|
215
|
-
case k
|
216
|
-
when 'memory'
|
217
|
-
vm.memory_size = v.to_i
|
218
|
-
when 'VMState'
|
219
|
-
vm.state = v.tr('"','').to_sym
|
220
|
-
when 'CfgFile'
|
221
|
-
dir = File.dirname(v.tr('"',''))
|
222
|
-
s = `du -s -BM "#{dir}"`
|
223
|
-
vm.dir_size = s.split("\t").first.tr("M","")
|
224
|
-
end
|
225
|
-
end
|
226
|
-
vm
|
227
|
-
end
|
228
|
-
|
229
|
-
def list_vms params = {}
|
230
|
-
if params[:running]
|
231
|
-
data = `VBoxManage list runningvms`
|
232
|
-
else
|
233
|
-
data = `VBoxManage list vms`
|
234
|
-
end
|
235
|
-
r = []
|
236
|
-
data.strip.each_line do |line|
|
237
|
-
if line[UUID_RE]
|
238
|
-
vm = VMInfo.new
|
239
|
-
vm.uuid = $&
|
240
|
-
vm.name = line.gsub($&, '').strip.sub(/^"/,'').sub(/"$/,'')
|
241
|
-
r << vm
|
242
|
-
end
|
243
|
-
end
|
244
|
-
r.sort_by{ |vm| vm.name.naturalized }
|
245
|
-
end
|
246
|
-
|
247
|
-
def get_vm_info name
|
248
|
-
data = `VBoxManage showvminfo "#{name}" --machinereadable`
|
249
|
-
h = {}
|
250
|
-
data.each_line do |line|
|
251
|
-
line.strip!
|
252
|
-
k,v = line.split('=',2)
|
253
|
-
h[k] = v
|
254
|
-
end
|
255
|
-
h
|
256
|
-
end
|
257
|
-
|
258
|
-
def show name
|
259
|
-
get_vm_info(name).each do |k,v|
|
260
|
-
next if ['"none"', '"off"', '""'].include?(v)
|
261
|
-
puts "#{k}=#{v}"
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
COMMANDS.each do |cmd|
|
266
|
-
class_eval <<-EOF unless instance_methods.include?(cmd.to_sym)
|
267
|
-
def #{cmd} name
|
268
|
-
system "VBoxManage", "controlvm", name, "#{cmd}"
|
269
|
-
end
|
270
|
-
EOF
|
271
|
-
end
|
272
|
-
|
273
|
-
def start name
|
274
|
-
if ENV['DISPLAY'] && !@options[:headless]
|
275
|
-
system "VBoxManage", "startvm", name
|
276
|
-
else
|
277
|
-
puts "[.] $DISPLAY is not set, assuming --headless".gray unless @options[:headless]
|
278
|
-
@options[:headless] = true
|
279
|
-
system "VBoxManage", "startvm", name, "--type", "headless"
|
280
|
-
end
|
281
|
-
end
|
282
|
-
|
283
|
-
|
284
|
-
def get_snapshots _name
|
285
|
-
r = []
|
286
|
-
name = uuid = nil
|
287
|
-
`VBoxManage snapshot "#{_name}" list --machinereadable`.strip.each_line do |line|
|
288
|
-
k,v = line.strip.split('=',2)
|
289
|
-
next unless v
|
290
|
-
v = v.strip.sub(/^"/,'').sub(/"$/,'')
|
291
|
-
case k
|
292
|
-
when /SnapshotName/
|
293
|
-
name = v
|
294
|
-
when /SnapshotUUID/
|
295
|
-
uuid = v
|
296
|
-
end
|
297
|
-
if name && uuid
|
298
|
-
r << Snapshot.new(name, uuid)
|
299
|
-
name = uuid = nil
|
300
|
-
end
|
301
|
-
end
|
302
|
-
r
|
303
|
-
end
|
304
|
-
|
305
|
-
# d0 -> d1, d2, d3
|
306
|
-
# d1 -> d1.1, d1.2, d1.3
|
307
|
-
# d1.1 -> d1.1.1, d1.1.2, d1.1.3
|
308
|
-
def _gen_vm_name parent_name
|
309
|
-
# try to guess new name
|
310
|
-
numbers = parent_name.scan /\d+/
|
311
|
-
if numbers.any?
|
312
|
-
lastnum = numbers.last
|
313
|
-
names = list_vms.map(&:name)
|
314
|
-
if lastnum.to_i == 0
|
315
|
-
# d0 -> d1, d2, d3
|
316
|
-
newnum = lastnum.to_i + 1
|
317
|
-
while true
|
318
|
-
newname = parent_name.dup
|
319
|
-
newname[parent_name.rindex(lastnum),lastnum.size] = newnum.to_s
|
320
|
-
return newname unless names.include?(newname)
|
321
|
-
newnum += 1
|
322
|
-
end
|
323
|
-
else
|
324
|
-
# d1 -> d1.1, d1.2, d1.3
|
325
|
-
# d1.1 -> d1.1.1, d1.1.2, d1.1.3
|
326
|
-
newnum = 1
|
327
|
-
while true
|
328
|
-
newname = "#{parent_name}.#{newnum}"
|
329
|
-
return newname unless names.include?(newname)
|
330
|
-
newnum += 1
|
331
|
-
end
|
332
|
-
end
|
333
|
-
end
|
334
|
-
nil
|
335
|
-
end
|
336
|
-
|
337
|
-
def take_snapshot vm_name, params = {}
|
338
|
-
system "VBoxManage", "snapshot", vm_name, "take", params[:name] || "noname"
|
339
|
-
exit 1 unless $?.success?
|
340
|
-
get_snapshots(vm_name).last
|
341
|
-
end
|
342
|
-
|
343
|
-
def _name2macpart name
|
344
|
-
r = name.scan(/\d+/).map{ |x| "%02x" % x }.join
|
345
|
-
r == '' ? nil : r
|
346
|
-
end
|
347
|
-
|
348
|
-
def clone old_vm_name
|
349
|
-
@clone_use_snapshot = nil
|
350
|
-
(@options[:clones] || 1).times{ _clone(old_vm_name) }
|
351
|
-
end
|
352
|
-
|
353
|
-
def _clone old_vm_name
|
354
|
-
args = []
|
355
|
-
if new_vm_name = @options['name'] || _gen_vm_name(old_vm_name)
|
356
|
-
args += ["--name", new_vm_name]
|
357
|
-
end
|
358
|
-
|
359
|
-
snapshot = @clone_use_snapshot ||= case @options[:snapshot]
|
360
|
-
when 'new', 'take', 'make'
|
361
|
-
take_snapshot(old_vm_name, new_vm_name ? {:name => "for #{new_vm_name}"} : {})
|
362
|
-
when 'last'
|
363
|
-
get_snapshots(old_vm_name).last
|
364
|
-
else
|
365
|
-
puts "[!] please gimme --snapshot=LAST OR --snapshot=NEW option"
|
366
|
-
exit 1
|
367
|
-
end
|
368
|
-
unless snapshot
|
369
|
-
puts "[!] failed to get snapshot, cannot continue".red
|
370
|
-
exit 1
|
371
|
-
end
|
372
|
-
|
373
|
-
args += ["--options","link"]
|
374
|
-
args += ["--register"]
|
375
|
-
args += ["--snapshot", snapshot.uuid]
|
376
|
-
|
377
|
-
system "VBoxManage", "clonevm", old_vm_name, *args
|
378
|
-
|
379
|
-
get_vm_info(old_vm_name).each do |k,v|
|
380
|
-
if k =~ /^macaddress/
|
381
|
-
old_mac = v.tr('"','').downcase
|
382
|
-
puts "[.] old #{k}=#{old_mac}"
|
383
|
-
old_automac = _name2macpart(old_vm_name)
|
384
|
-
if old_automac && old_mac[-old_automac.size..-1] == old_automac
|
385
|
-
new_automac = _name2macpart(new_vm_name)
|
386
|
-
new_mac = old_mac[0,old_mac.size-new_automac.size] + new_automac
|
387
|
-
puts "[.] new #{k}=#{new_mac}"
|
388
|
-
modify new_vm_name, k, new_mac, :quiet => true
|
389
|
-
end
|
390
|
-
end
|
391
|
-
end
|
392
|
-
end
|
393
|
-
|
394
|
-
def modify name, k, v, params = {}
|
395
|
-
system "VBoxManage", "modifyvm", name, "--#{k}", v
|
396
|
-
if $?.success? && !params[:quiet]
|
397
|
-
h = get_vm_info(k == 'name' ? v : name)
|
398
|
-
puts "#{k}=#{h[k]}"
|
399
|
-
end
|
400
|
-
end
|
401
|
-
|
402
|
-
def delete name
|
403
|
-
system "VBoxManage", "unregistervm", name, "--delete"
|
404
|
-
end
|
405
|
-
end
|
406
170
|
end
|
407
171
|
|
408
172
|
|
@@ -0,0 +1,266 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'awesome_print'
|
3
|
+
|
4
|
+
module VBOX
|
5
|
+
|
6
|
+
COMMANDS = %w'start pause resume reset poweroff savestate acpipowerbutton acpisleepbutton clone delete show'
|
7
|
+
|
8
|
+
Snapshot = Struct.new :name, :uuid
|
9
|
+
|
10
|
+
class CmdLineAPI
|
11
|
+
attr_accessor :options
|
12
|
+
|
13
|
+
def initialize options={}
|
14
|
+
@options = options
|
15
|
+
@options[:verbose] ||= 2 if @options[:dry_run]
|
16
|
+
@options[:verbose] ||= 0
|
17
|
+
end
|
18
|
+
|
19
|
+
# run as in backtick operator, and return result
|
20
|
+
def ` cmd
|
21
|
+
puts "[.] #{cmd}".gray if @options[:verbose] >= 2
|
22
|
+
exit if @options[:dry_run]
|
23
|
+
r = super
|
24
|
+
#exit 1 unless $?.success?
|
25
|
+
r
|
26
|
+
end
|
27
|
+
|
28
|
+
# run as in system() call
|
29
|
+
def system *args
|
30
|
+
puts "[.] #{args.inspect}".gray if @options[:verbose] >= 2
|
31
|
+
exit if @options[:dry_run]
|
32
|
+
r = super
|
33
|
+
#exit 1 unless $?.success?
|
34
|
+
r
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_vm_details vm_or_name_or_uuid
|
38
|
+
name_or_uuid = case vm_or_name_or_uuid
|
39
|
+
when String
|
40
|
+
vm = VM.new
|
41
|
+
vm_or_name_or_uuid
|
42
|
+
when VM
|
43
|
+
vm = vm_or_name_or_uuid
|
44
|
+
vm.uuid
|
45
|
+
end
|
46
|
+
|
47
|
+
data = `VBoxManage showvminfo "#{name_or_uuid}" --machinereadable`
|
48
|
+
data.each_line do |line|
|
49
|
+
k,v = line.strip.split('=',2)
|
50
|
+
next unless v
|
51
|
+
vm.all_vars[k] = v # not stripping quotes here to save some CPU time
|
52
|
+
case k
|
53
|
+
when 'name'
|
54
|
+
vm.name = v.strip.sub(/^"/,'').sub(/"$/,'')
|
55
|
+
when 'UUID'
|
56
|
+
vm.uuid = v.strip.sub(/^"/,'').sub(/"$/,'')
|
57
|
+
when 'memory'
|
58
|
+
vm.memory_size = v.to_i
|
59
|
+
when 'VMState'
|
60
|
+
vm.state = v.tr('"','').to_sym
|
61
|
+
# when 'CfgFile'
|
62
|
+
# dir = File.dirname(v.tr('"',''))
|
63
|
+
# s = `du -s -BM "#{dir}"`
|
64
|
+
# vm.dir_size = s.split("\t").first.tr("M","")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
vm
|
68
|
+
end
|
69
|
+
|
70
|
+
# for natural string sort order
|
71
|
+
# http://stackoverflow.com/questions/4078906/is-there-a-natural-sort-by-method-for-ruby
|
72
|
+
def _naturalize s
|
73
|
+
s.scan(/[^\d]+|\d+/).collect { |f| f.match(/\d+/) ? f.to_i : f }
|
74
|
+
end
|
75
|
+
|
76
|
+
def list_vms params = {}
|
77
|
+
if params[:running]
|
78
|
+
data = `VBoxManage list runningvms`
|
79
|
+
else
|
80
|
+
data = `VBoxManage list vms`
|
81
|
+
end
|
82
|
+
r = []
|
83
|
+
data.strip.each_line do |line|
|
84
|
+
if line[UUID_RE]
|
85
|
+
vm = VM.new
|
86
|
+
vm.uuid = $&
|
87
|
+
vm.name = line.gsub($&, '').strip.sub(/^"/,'').sub(/"$/,'')
|
88
|
+
r << vm
|
89
|
+
end
|
90
|
+
end
|
91
|
+
r.sort_by{ |vm| _naturalize(vm.name) }
|
92
|
+
end
|
93
|
+
|
94
|
+
def get_vm_info name
|
95
|
+
data = `VBoxManage showvminfo "#{name}" --machinereadable`
|
96
|
+
h = {}
|
97
|
+
data.each_line do |line|
|
98
|
+
line.strip!
|
99
|
+
k,v = line.split('=',2)
|
100
|
+
h[k] = v
|
101
|
+
end
|
102
|
+
h
|
103
|
+
end
|
104
|
+
|
105
|
+
def show name
|
106
|
+
get_vm_info(name).each do |k,v|
|
107
|
+
next if ['"none"', '"off"', '""'].include?(v)
|
108
|
+
puts "#{k}=#{v}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
COMMANDS.each do |cmd|
|
113
|
+
class_eval <<-EOF unless instance_methods.include?(cmd.to_sym)
|
114
|
+
def #{cmd} name
|
115
|
+
system "VBoxManage", "controlvm", name, "#{cmd}"
|
116
|
+
end
|
117
|
+
EOF
|
118
|
+
end
|
119
|
+
|
120
|
+
def start name
|
121
|
+
if ENV['DISPLAY'] && !@options[:headless]
|
122
|
+
system "VBoxManage", "startvm", name
|
123
|
+
else
|
124
|
+
puts "[.] $DISPLAY is not set, assuming --headless".gray unless @options[:headless]
|
125
|
+
@options[:headless] = true
|
126
|
+
system "VBoxManage", "startvm", name, "--type", "headless"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
def get_snapshots _name
|
132
|
+
r = []
|
133
|
+
name = uuid = nil
|
134
|
+
`VBoxManage snapshot "#{_name}" list --machinereadable`.strip.each_line do |line|
|
135
|
+
k,v = line.strip.split('=',2)
|
136
|
+
next unless v
|
137
|
+
v = v.strip.sub(/^"/,'').sub(/"$/,'')
|
138
|
+
case k
|
139
|
+
when /SnapshotName/
|
140
|
+
name = v
|
141
|
+
when /SnapshotUUID/
|
142
|
+
uuid = v
|
143
|
+
end
|
144
|
+
if name && uuid
|
145
|
+
r << Snapshot.new(name, uuid)
|
146
|
+
name = uuid = nil
|
147
|
+
end
|
148
|
+
end
|
149
|
+
r
|
150
|
+
end
|
151
|
+
|
152
|
+
# d0 -> d1, d2, d3
|
153
|
+
# d1 -> d1.1, d1.2, d1.3
|
154
|
+
# d1.1 -> d1.1.1, d1.1.2, d1.1.3
|
155
|
+
def _gen_vm_name parent_name
|
156
|
+
# try to guess new name
|
157
|
+
numbers = parent_name.scan /\d+/
|
158
|
+
if numbers.any?
|
159
|
+
lastnum = numbers.last
|
160
|
+
names = list_vms.map(&:name)
|
161
|
+
if lastnum.to_i == 0
|
162
|
+
# d0 -> d1, d2, d3
|
163
|
+
newnum = lastnum.to_i + 1
|
164
|
+
while true
|
165
|
+
newname = parent_name.dup
|
166
|
+
newname[parent_name.rindex(lastnum),lastnum.size] = newnum.to_s
|
167
|
+
return newname unless names.include?(newname)
|
168
|
+
newnum += 1
|
169
|
+
end
|
170
|
+
else
|
171
|
+
# d1 -> d1.1, d1.2, d1.3
|
172
|
+
# d1.1 -> d1.1.1, d1.1.2, d1.1.3
|
173
|
+
newnum = 1
|
174
|
+
while true
|
175
|
+
newname = "#{parent_name}.#{newnum}"
|
176
|
+
return newname unless names.include?(newname)
|
177
|
+
newnum += 1
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
nil
|
182
|
+
end
|
183
|
+
|
184
|
+
def take_snapshot vm_name, params = {}
|
185
|
+
system "VBoxManage", "snapshot", vm_name, "take", params[:name] || "noname"
|
186
|
+
exit 1 unless $?.success?
|
187
|
+
get_snapshots(vm_name).last
|
188
|
+
end
|
189
|
+
|
190
|
+
def _name2macpart name
|
191
|
+
r = name.scan(/\d+/).map{ |x| "%02x" % x }.join
|
192
|
+
r == '' ? nil : r
|
193
|
+
end
|
194
|
+
|
195
|
+
def clone old_vm_name, params = {}
|
196
|
+
@clone_use_snapshot = nil
|
197
|
+
params = @options.merge(params)
|
198
|
+
n = params[:clones] || 1
|
199
|
+
if n > 1
|
200
|
+
# return array of clones
|
201
|
+
n.times.map{ _clone(old_vm_name, params) }
|
202
|
+
elsif n == 1
|
203
|
+
# return one clone
|
204
|
+
_clone(old_vm_name, params)
|
205
|
+
else
|
206
|
+
raise "invalid count of clones = #{n.inspect}"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def _clone old_vm_name, params
|
211
|
+
args = []
|
212
|
+
if new_vm_name = params['name'] || _gen_vm_name(old_vm_name)
|
213
|
+
args += ["--name", new_vm_name]
|
214
|
+
end
|
215
|
+
|
216
|
+
snapshot = @clone_use_snapshot ||= case params[:snapshot].to_s
|
217
|
+
when 'new', 'take', 'make'
|
218
|
+
take_snapshot(old_vm_name, new_vm_name ? {:name => "for #{new_vm_name}"} : {})
|
219
|
+
when 'last'
|
220
|
+
get_snapshots(old_vm_name).last
|
221
|
+
else
|
222
|
+
puts "[!] please gimme --snapshot=LAST OR --snapshot=NEW option"
|
223
|
+
exit 1
|
224
|
+
end
|
225
|
+
unless snapshot
|
226
|
+
puts "[!] failed to get snapshot, cannot continue".red
|
227
|
+
exit 1
|
228
|
+
end
|
229
|
+
|
230
|
+
args += ["--options","link"]
|
231
|
+
args += ["--register"]
|
232
|
+
args += ["--snapshot", snapshot.uuid]
|
233
|
+
|
234
|
+
system "VBoxManage", "clonevm", old_vm_name, *args
|
235
|
+
return false unless $?.success?
|
236
|
+
|
237
|
+
get_vm_info(old_vm_name).each do |k,v|
|
238
|
+
if k =~ /^macaddress/
|
239
|
+
old_mac = v.tr('"','').downcase
|
240
|
+
puts "[.] old #{k}=#{old_mac}"
|
241
|
+
old_automac = _name2macpart(old_vm_name)
|
242
|
+
if old_automac && old_mac[-old_automac.size..-1] == old_automac
|
243
|
+
new_automac = _name2macpart(new_vm_name)
|
244
|
+
new_mac = old_mac[0,old_mac.size-new_automac.size] + new_automac
|
245
|
+
puts "[.] new #{k}=#{new_mac}"
|
246
|
+
modify new_vm_name, k, new_mac, :quiet => true
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
new_vm_name
|
251
|
+
end
|
252
|
+
|
253
|
+
def modify name, k, v, params = {}
|
254
|
+
system "VBoxManage", "modifyvm", name, "--#{k}", v
|
255
|
+
if $?.success? && !params[:quiet]
|
256
|
+
h = get_vm_info(k == 'name' ? v : name)
|
257
|
+
puts "#{k}=#{h[k]}"
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def delete name
|
262
|
+
system "VBoxManage", "unregistervm", name, "--delete"
|
263
|
+
end
|
264
|
+
alias :destroy :delete
|
265
|
+
end
|
266
|
+
end
|
data/lib/vbox/vm.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module VBOX
|
2
|
+
class VM
|
3
|
+
attr_accessor :name, :uuid, :memory_size, :dir_size, :state, :all_vars
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@all_vars = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
%w'start pause resume reset poweroff savestate acpipowerbutton acpisleepbutton destroy'.each do |action|
|
10
|
+
define_method "#{action}!" do
|
11
|
+
VBOX.api.send( action, uuid || name )
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def clone! params
|
16
|
+
raise "argument must be a Hash" unless params.is_a?(Hash)
|
17
|
+
raise "no :snapshot key" unless params[:snapshot]
|
18
|
+
r = VBOX.api.clone self.name, params
|
19
|
+
case r
|
20
|
+
when Array
|
21
|
+
if r.first.is_a?(VM)
|
22
|
+
r
|
23
|
+
else
|
24
|
+
r.map{ |name| VM.find(name) }
|
25
|
+
end
|
26
|
+
when String
|
27
|
+
VM.find(r)
|
28
|
+
when nil
|
29
|
+
nil
|
30
|
+
else
|
31
|
+
r
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def dir_size
|
36
|
+
@dir_size ||=
|
37
|
+
begin
|
38
|
+
VBOX.api.get_vm_details(self) unless @all_vars['CfgFile']
|
39
|
+
return nil unless v=@all_vars['CfgFile']
|
40
|
+
dir = File.dirname(v.tr('"',''))
|
41
|
+
`du -s -BM "#{dir}"`.split("\t").first.tr("M","").to_i
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class << self
|
46
|
+
def all
|
47
|
+
VBOX.api.list_vms
|
48
|
+
end
|
49
|
+
|
50
|
+
def first
|
51
|
+
all.first
|
52
|
+
end
|
53
|
+
|
54
|
+
def find name_or_uuid
|
55
|
+
VBOX.api.get_vm_details name_or_uuid
|
56
|
+
end
|
57
|
+
|
58
|
+
alias :[] :find
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/spec/vm_spec.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "VBOX::VM" do
|
4
|
+
describe "all()" do
|
5
|
+
it "returns array" do
|
6
|
+
VBOX::VM.all.should be_instance_of(Array)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "returns array of VBOX::VM" do
|
10
|
+
VBOX::VM.all.map(&:class).uniq.should == [VBOX::VM]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe :first do
|
15
|
+
it "returns VBOX::VM" do
|
16
|
+
VBOX::VM.first.should be_instance_of(VBOX::VM)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
TEST_VM_NAME = "d0"
|
21
|
+
TEST_VM_UUID = 'ae340207-f472-4d63-80e7-855fca6808cb'
|
22
|
+
|
23
|
+
[:find, :[]].each do |method|
|
24
|
+
describe method do
|
25
|
+
it "finds VM by name" do
|
26
|
+
vm = VBOX::VM.send(method, TEST_VM_NAME)
|
27
|
+
vm.should be_instance_of(VBOX::VM)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "finds VM by uuid" do
|
31
|
+
vm = VBOX::VM.send(method, TEST_VM_UUID)
|
32
|
+
vm.should be_instance_of(VBOX::VM)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "finds VM by {uuid}" do
|
36
|
+
vm = VBOX::VM.send(method, "{#{TEST_VM_UUID}}")
|
37
|
+
vm.should be_instance_of(VBOX::VM)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe :dir_size do
|
43
|
+
VBOX::VM.first.dir_size.should > 0
|
44
|
+
end
|
45
|
+
|
46
|
+
%w'start pause resume reset poweroff savestate acpipowerbutton acpisleepbutton destroy clone'.each do |action|
|
47
|
+
action << "!"
|
48
|
+
describe action do
|
49
|
+
it "should respond to #{action}" do
|
50
|
+
VBOX::VM.first.should respond_to(action)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/vbox-ng.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "vbox-ng"
|
8
|
-
s.version = "0.0
|
8
|
+
s.version = "0.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Andrey \"Zed\" Zaikin"]
|
@@ -27,11 +27,14 @@ Gem::Specification.new do |s|
|
|
27
27
|
"Rakefile",
|
28
28
|
"VERSION",
|
29
29
|
"bin/vbox",
|
30
|
+
"lib/vbox-ng.rb",
|
30
31
|
"lib/vbox.rb",
|
31
32
|
"lib/vbox/api41.rb",
|
32
33
|
"lib/vbox/cli.rb",
|
34
|
+
"lib/vbox/cmdlineapi.rb",
|
35
|
+
"lib/vbox/vm.rb",
|
33
36
|
"spec/spec_helper.rb",
|
34
|
-
"spec/
|
37
|
+
"spec/vm_spec.rb",
|
35
38
|
"vbox-ng.gemspec"
|
36
39
|
]
|
37
40
|
s.homepage = "http://github.com/zed-0xff/vbox-ng"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vbox-ng
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -94,11 +94,14 @@ files:
|
|
94
94
|
- Rakefile
|
95
95
|
- VERSION
|
96
96
|
- bin/vbox
|
97
|
+
- lib/vbox-ng.rb
|
97
98
|
- lib/vbox.rb
|
98
99
|
- lib/vbox/api41.rb
|
99
100
|
- lib/vbox/cli.rb
|
101
|
+
- lib/vbox/cmdlineapi.rb
|
102
|
+
- lib/vbox/vm.rb
|
100
103
|
- spec/spec_helper.rb
|
101
|
-
- spec/
|
104
|
+
- spec/vm_spec.rb
|
102
105
|
- vbox-ng.gemspec
|
103
106
|
homepage: http://github.com/zed-0xff/vbox-ng
|
104
107
|
licenses:
|
@@ -115,7 +118,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
115
118
|
version: '0'
|
116
119
|
segments:
|
117
120
|
- 0
|
118
|
-
hash: -
|
121
|
+
hash: -1266878119588599901
|
119
122
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
123
|
none: false
|
121
124
|
requirements:
|