vbox-ng 0.0.1 → 0.1.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.
- 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:
|