virtual_box 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.autotest +9 -0
  2. data/.document +5 -0
  3. data/.project +12 -0
  4. data/.rspec +1 -0
  5. data/Gemfile +14 -0
  6. data/Gemfile.lock +44 -0
  7. data/LICENSE.txt +20 -0
  8. data/README.markdown +67 -0
  9. data/Rakefile +35 -22
  10. data/VERSION +1 -0
  11. data/lib/virtual_box/board.rb +287 -0
  12. data/lib/virtual_box/cli.rb +20 -0
  13. data/lib/virtual_box/dhcp.rb +149 -0
  14. data/lib/virtual_box/disk.rb +138 -0
  15. data/lib/virtual_box/io_bus.rb +261 -0
  16. data/lib/virtual_box/net.rb +144 -0
  17. data/lib/virtual_box/nic.rb +213 -0
  18. data/lib/virtual_box/version.rb +37 -24
  19. data/lib/virtual_box/vm.rb +289 -24
  20. data/lib/virtual_box.rb +14 -9
  21. data/test/helper.rb +24 -0
  22. data/test/tasks/tinycore.rake +378 -0
  23. data/test/virtual_box/board_test.rb +39 -0
  24. data/test/virtual_box/cli_test.rb +33 -0
  25. data/test/virtual_box/dhcp_test.rb +52 -0
  26. data/test/virtual_box/disk_test.rb +116 -0
  27. data/test/virtual_box/integration_test.rb +53 -0
  28. data/test/virtual_box/io_bus_test.rb +54 -0
  29. data/test/virtual_box/net_test.rb +80 -0
  30. data/test/virtual_box/nic_test.rb +50 -0
  31. data/test/virtual_box/version_test.rb +71 -0
  32. data/test/virtual_box/vm_test.rb +55 -0
  33. data/virtual_box.gemspec +81 -22
  34. metadata +208 -89
  35. data/CHANGELOG +0 -1
  36. data/LICENSE +0 -21
  37. data/Manifest +0 -17
  38. data/README.textile +0 -19
  39. data/lib/virtual_box/command_line.rb +0 -27
  40. data/lib/virtual_box/vm/general_settings.rb +0 -136
  41. data/lib/virtual_box/vm/identity.rb +0 -43
  42. data/lib/virtual_box/vm/lifecycle.rb +0 -42
  43. data/test/command_line_test.rb +0 -19
  44. data/test/general_settings_test.rb +0 -20
  45. data/test/lifecycle_test.rb +0 -64
  46. data/test/version_test.rb +0 -56
  47. data/testdata/golden_general_params.txt +0 -1
data/.autotest ADDED
@@ -0,0 +1,9 @@
1
+ Autotest.add_hook :initialize do |autotest|
2
+ autotest.add_exception '.git'
3
+ autotest.add_mapping %r{lib/virtual_box/.*\.rb$} do |file, match|
4
+ p match
5
+ autotest.files_matching %r{spec/.*_spec\.rb$}
6
+ end
7
+ p autotest.mappings
8
+ false
9
+ end
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.project ADDED
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <projectDescription>
3
+ <name>virtual_box</name>
4
+ <comment></comment>
5
+ <projects>
6
+ </projects>
7
+ <buildSpec>
8
+ </buildSpec>
9
+ <natures>
10
+ <nature>org.radrails.rails.core.railsnature</nature>
11
+ </natures>
12
+ </projectDescription>
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source :rubygems
2
+
3
+ gem 'hashie', '>= 0.4.0'
4
+ gem 'uuid', '>= 2.3.5'
5
+
6
+ group :development do
7
+ gem 'bundler', '>= 1.1.3'
8
+ gem 'jeweler', '>= 1.8.3'
9
+ gem 'minitest', '>= 2.12.1'
10
+ gem 'mocha', '>= 0.11.0', :require => false
11
+ gem 'net-ssh', '>= 2.3.0', :require => 'net/ssh'
12
+ gem 'simplecov', '>= 0.6.1'
13
+ gem 'yard', '>= 0.7.5'
14
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,44 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ git (1.2.5)
5
+ hashie (1.2.0)
6
+ jeweler (1.8.3)
7
+ bundler (~> 1.0)
8
+ git (>= 1.2.5)
9
+ rake
10
+ rdoc
11
+ json (1.7.0)
12
+ macaddr (1.5.0)
13
+ systemu (>= 2.4.0)
14
+ metaclass (0.0.1)
15
+ minitest (2.12.1)
16
+ mocha (0.11.3)
17
+ metaclass (~> 0.0.1)
18
+ multi_json (1.3.4)
19
+ net-ssh (2.3.0)
20
+ rake (0.9.2.2)
21
+ rdoc (3.12)
22
+ json (~> 1.4)
23
+ simplecov (0.6.2)
24
+ multi_json (~> 1.3)
25
+ simplecov-html (~> 0.5.3)
26
+ simplecov-html (0.5.3)
27
+ systemu (2.5.0)
28
+ uuid (2.3.5)
29
+ macaddr (~> 1.0)
30
+ yard (0.8.0)
31
+
32
+ PLATFORMS
33
+ ruby
34
+
35
+ DEPENDENCIES
36
+ bundler (>= 1.1.3)
37
+ hashie (>= 0.4.0)
38
+ jeweler (>= 1.8.3)
39
+ minitest (>= 2.12.1)
40
+ mocha (>= 0.11.0)
41
+ net-ssh (>= 2.3.0)
42
+ simplecov (>= 0.6.1)
43
+ uuid (>= 2.3.5)
44
+ yard (>= 0.7.5)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Victor Costan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,67 @@
1
+ # virtual_box
2
+
3
+ This gem is a Ruby API for VirtualBox, Sun's open-source virtualization software
4
+ that supports Linux, Mac OS X, and Windows.
5
+
6
+
7
+ ## Features
8
+
9
+ Currently, the gem supports the following features:
10
+ * VM creation and removal
11
+ * VM start, and stop
12
+ * Disk (VDI, VMDK, VHD) and DVD (ISO) images
13
+ * NAT, bridged, host-only and internal networking
14
+ * DHCP configuration for host-only and internal networks
15
+ * VirtualBox version detection (OSE vs. regular)
16
+
17
+
18
+ ## Dependencies
19
+
20
+ The gem uses the VirtualBox CLI (command-line tools), so they must be installed
21
+ and on the system's path. The gem is developed against the documentation for
22
+ VirtualBox 4.
23
+
24
+ ## Development Dependencies
25
+
26
+ Running tests relies on a few command-line tools.
27
+
28
+ On Fedora, use the following command to install the packages.
29
+
30
+ ```bash
31
+ sudo yum install advancecomp curl mkisofs p7zip squashfs-tools
32
+ ```
33
+
34
+ On OSX, run the following command.
35
+
36
+ ```bash
37
+ brew install advancecomp cdrtools curl p7zip squashfs
38
+ ```
39
+
40
+
41
+ ## Limitations
42
+
43
+ This gem makes some simplifying assumptions (rails people would say it is
44
+ opinionated).
45
+
46
+ * VM configuration XML file management is completely delegated to VirtualBox;
47
+ the gem assumes and enforces the invariant that all XML files map to registered
48
+ VMs
49
+
50
+
51
+ ## Contributing to virtual_box
52
+
53
+ * Check out the latest master to make sure the feature hasn't been implemented
54
+ or the bug hasn't been fixed yet.
55
+ * Check out the issue tracker to make sure someone already hasn't requested it
56
+ and/or contributed it.
57
+ * Fork the project.
58
+ * Start a feature/bugfix branch.
59
+ * Commit and push until you are happy with your contribution.
60
+ * Make sure to add tests for it. This is important so I don't break it in a
61
+ future version unintentionally.
62
+ * Please do not mess with the Rakefile, version, or history.
63
+
64
+
65
+ ## Copyright
66
+
67
+ Copyright (c) 2010-2012 Victor Costan. See LICENSE.txt for further details.
data/Rakefile CHANGED
@@ -1,28 +1,41 @@
1
- # Rakefile that uses echoe to manage virtual_box's gemspec.
2
- #
3
- # Author:: Victor Costan
4
- # Copyright:: Copyright (C) 2009 Zergling.Net
5
- # License:: MIT
1
+ # encoding: utf-8
6
2
 
7
3
  require 'rubygems'
8
- require 'echoe'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
9
13
 
10
- Echoe.new('virtual_box') do |p|
11
- p.project = 'zerglings' # rubyforge project
12
-
13
- p.author = 'Victor Costan'
14
- p.email = 'victor@zergling.net'
15
- p.summary = "Ruby API for VirtualBox (Sun's OSS virtualization software)."
16
- p.url = 'http://github.com/costan/virtual_box'
17
- p.dependencies = []
18
- p.development_dependencies = ["echoe >=3.1.1", "flexmock >=0.8.6"]
19
-
20
- p.need_tar_gz = true
21
- p.need_zip = true
22
- p.rdoc_pattern = /^(lib|bin|tasks|ext)|^BUILD|^README|^CHANGELOG|^TODO|^LICENSE|^COPYING$/
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "virtual_box"
18
+ gem.homepage = "http://github.com/csail/police"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{VirtualBox driver}
21
+ gem.description = %Q{Drives the VirtualBox command-line to manage VMs}
22
+ gem.email = "victor@costan.us"
23
+ gem.authors = ["Victor Costan"]
24
+ # dependencies defined in Gemfile
23
25
  end
26
+ Jeweler::RubygemsDotOrgTasks.new
24
27
 
25
- if $0 == __FILE__
26
- Rake.application = Rake::Application.new
27
- Rake.application.run
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/*_test.rb'
32
+ test.verbose = true
28
33
  end
34
+
35
+ load './test/tasks/tinycore.rake'
36
+
37
+ task :test => :fixtures
38
+ task :default => :test
39
+
40
+ require 'yard'
41
+ YARD::Rake::YardocTask.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,287 @@
1
+ module VirtualBox
2
+
3
+ # Specification for a virtual machine's motherboard.
4
+ class Board
5
+ # The number of CPUs (cores) on this board.
6
+ # @return [Integer]
7
+ attr_accessor :cpus
8
+
9
+ # The amount of megabytes of RAM on this board.
10
+ # @return [Integer]
11
+ attr_accessor :ram
12
+ # The amount of megabytes of video RAM on this board's video card.
13
+ # @return [Integer]
14
+ attr_accessor :video_ram
15
+
16
+ # The UUID presented to the guest OS.
17
+ # @return [String]
18
+ attr_accessor :hardware_id
19
+
20
+ # The OS that will be running in the virtualized VM.
21
+ #
22
+ # Used to improve the virtualization performance.
23
+ # @return [Symbol]
24
+ attr_accessor :os
25
+
26
+ # Whether the VM supports PAE (36-bit address space).
27
+ # @return [Boolean]
28
+ attr_accessor :pae
29
+ # Whether the VM supports ACPI.
30
+ # @return [Boolean]
31
+ attr_accessor :acpi
32
+ # Whether the VM supports I/O APIC.
33
+ #
34
+ # This is necessary for 64-bit OSes, but makes the virtualization slower.
35
+ # @return [Boolean]
36
+ attr_accessor :io_apic
37
+
38
+ # Whether the VMM attempts to use hardware support (Intel VT-x or AMD-V).
39
+ #
40
+ # Hardware virtualization can increase VM performance, especially used in
41
+ # conjunction with the other hardware virtualization options. However, using
42
+ # hardware virtualization in conjunction with other hypervisors can crash the
43
+ # host machine.
44
+ # @return [Boolean]
45
+ attr_accessor :hardware_virtualization
46
+ # Whether the VMM uses hardware support for nested paging.
47
+ #
48
+ # The option is used only if hardware_virtualization is set.
49
+ # @return [Boolean]
50
+ attr_accessor :nested_paging
51
+ # Whether the VMM uses hardware support for tagged TLB (VPID).
52
+ #
53
+ # The option is used only if hardware_virtualization is set.
54
+ # @return [Boolean]
55
+ attr_accessor :tagged_tlb
56
+
57
+ # Whether the VM supports 3D acceleration.
58
+ #
59
+ # 3D acceleration will only work with the proper guest extensions.
60
+ # @return [Boolean]
61
+ attr_accessor :accelerate_3d
62
+
63
+ # Whether the BIOS logo will fade in when the board boots.
64
+ # @return [Boolean]
65
+ attr_accessor :bios_logo_fade_in
66
+ # Whether the BIOS logo will fade out when the board boots.
67
+ # @return [Boolean]
68
+ attr_accessor :bios_logo_fade_out
69
+ # The number of seconds to display the BIOS logo when the board boots.
70
+ # @return [Integer]
71
+ attr_accessor :bios_logo_display_time
72
+ # Whether the BIOS allows the user to temporarily override the boot VM device.
73
+ #
74
+ # If false, no override is allowed. Otherwise, the user can press F12 at
75
+ # boot time to select a boot device. The user gets a prompt at boot time if
76
+ # the value is true. If the value is :menu_only the user does not get a
77
+ # prompt, but can still press F12 to select a device.
78
+ # @return [Boolean, Symbol]
79
+ attr_accessor :bios_boot_menu
80
+ # Indicates the boot device search order for the VM's BIOS.
81
+ #
82
+ # This is an array that can contain the following symbols: :floppy+, :dvd,
83
+ # :disk, :net. Symbols should not be repeated.
84
+ # @return [Array<Symbol>]
85
+ attr_accessor :boot_order
86
+
87
+ # True if the motherboard includes an audio chipset.
88
+ # @return [Boolean]
89
+ attr_accessor :audio
90
+
91
+ # If +true+, EFI firmware will be used instead of BIOS, for booting.
92
+ #
93
+ # The VirtualBox documentation states that EFI booting is highly experimental,
94
+ # and should only be used to virtualize MacOS.
95
+ # @return [Boolean]
96
+ attr_accessor :efi
97
+
98
+ # Creates a new motherboard specification based on the given attributes.
99
+ #
100
+ # @param [Hash<Symbol, Object>] options ActiveRecord-style initial values for
101
+ # attributes; can be used together with Board#to_hash to save and restore
102
+ def initialize(options = {})
103
+ reset
104
+ options.each { |k, v| self.send :"#{k}=", v }
105
+ end
106
+
107
+ # Arguments to "VBoxManage modifyvm" describing the VM's general settings.
108
+ #
109
+ # @return [Array<String>] arguments that can be concatenated to a "VBoxManage
110
+ # modifyvm" command
111
+ def to_params
112
+ params = []
113
+ params.push '--cpus', cpus.to_s
114
+ params.push '--memory', ram.to_s
115
+ params.push '--vram', video_ram.to_s
116
+ params.push '--hardwareuuid', hardware_id
117
+ params.push '--ostype',
118
+ self.class.os_types[self.class.os_types[os.to_s]]
119
+
120
+ params.push '--pae', pae ? 'on' : 'off'
121
+ params.push '--acpi', acpi ? 'on' : 'off'
122
+ params.push '--ioapic', io_apic ? 'on' : 'off'
123
+
124
+ params.push '--hwvirtex', hardware_virtualization ? 'on' : 'off'
125
+ params.push '--nestedpaging',
126
+ (hardware_virtualization && nested_paging) ? 'on' : 'off'
127
+ params.push '--vtxvpid',
128
+ (hardware_virtualization && tagged_tlb) ? 'on' : 'off'
129
+
130
+ params.push '--firmware', efi ? 'efi' : 'bios'
131
+ params.push '--bioslogofadein', bios_logo_fade_in ? 'on' : 'off'
132
+ params.push '--bioslogofadeout', bios_logo_fade_out ? 'on' : 'off'
133
+ params.push '--bioslogodisplaytime', bios_logo_display_time.to_s
134
+
135
+ bios_boot_menu_str = case bios_boot_menu
136
+ when false
137
+ 'disabled'
138
+ when :menu_only
139
+ 'message'
140
+ else
141
+ 'messageandmenu'
142
+ end
143
+ params.push '--biosbootmenu', bios_boot_menu_str
144
+ unique_boot_order = boot_order.uniq
145
+ 1.upto(4) do |i|
146
+ device = unique_boot_order[i - 1]
147
+ params.push "--boot#{i}", (device ? device.to_s : 'none')
148
+ end
149
+
150
+ params.push '--audio', (audio ? 'null' : 'none')
151
+
152
+ params
153
+ end
154
+
155
+ # Parses "VBoxManage showvminfo --machinereadable" output into this instance.
156
+ #
157
+ # @param [Hash<String, String>] params the "VBoxManage showvminfo" output,
158
+ # parsed by Vm.parse_machine_readble
159
+ # @return [VirtualBox::Board] self, for easy call chaining
160
+ def from_params(params)
161
+ self.cpus = params['cpus'].to_i
162
+ self.ram = params['memory'].to_i
163
+ self.video_ram = params['vram'].to_i
164
+ self.hardware_id = params['hardwareuuid']
165
+ self.os = self.class.os_types[params['ostype']]
166
+
167
+ self.pae = params['pae'] == 'on'
168
+ self.acpi = params['acpi'] == 'on'
169
+ self.io_apic = params['io_apic'] == 'on'
170
+
171
+ self.hardware_virtualization = params['hwvirtex'] == 'on'
172
+ self.nested_paging = params['nestedpaging'] == 'on'
173
+ self.tagged_tlb = params['vtxvpid'] == 'on'
174
+
175
+ self.efi = params['firmware'] == 'efi'
176
+ self.bios_logo_fade_in = params['bioslogofadein'] == 'on'
177
+ self.bios_logo_fade_out = params['bioslogofadeout'] == 'on'
178
+ self.bios_logo_display_time = params['bioslogodisplaytime'].to_i
179
+
180
+ self.bios_boot_menu = case params['bootmenu']
181
+ when 'disabled'
182
+ false
183
+ when 'message'
184
+ :menu_only
185
+ else
186
+ true
187
+ end
188
+
189
+ self.boot_order = []
190
+ %w(boot1 boot2 boot3 boot4).each do |boot_key|
191
+ next unless params[boot_key] && params[boot_key] != 'none'
192
+ boot_order << params[boot_key].to_sym
193
+ end
194
+
195
+ self.audio = params['audio'] != 'none'
196
+
197
+ self
198
+ end
199
+
200
+ # Resets to default settings.
201
+ #
202
+ # The defaults are chosen somewhat arbitrarily by the gem's author.
203
+ # @return [VirtualBox::Board] self, for easy call chaining
204
+ def reset
205
+ self.cpus = 1
206
+ self.ram = 512
207
+ self.video_ram = 18
208
+ self.hardware_id = UUID.generate
209
+
210
+ self.os = :other
211
+ self.pae = false
212
+ self.acpi = true
213
+ self.io_apic = false
214
+
215
+ self.hardware_virtualization = true
216
+ self.nested_paging = true
217
+ self.tagged_tlb = true
218
+ self.accelerate_3d = false
219
+
220
+ self.efi = false
221
+ self.bios_logo_fade_in = false
222
+ self.bios_logo_fade_out = false
223
+ self.bios_logo_display_time = 0
224
+ self.bios_boot_menu = false
225
+
226
+ self.boot_order = [:disk, :net, :dvd]
227
+
228
+ self.audio = false
229
+ self
230
+ end
231
+
232
+ # Hash capturing this motherboard specification. Can be passed to Board#new.
233
+ #
234
+ # @return [Hash<Symbol, Object>] Ruby-friendly Hash that can be used to
235
+ # re-create this motherboard specification
236
+ def to_hash
237
+ { :cpus => cpus, :ram => ram, :video_ram => video_ram,
238
+ :hardware_id => hardware_id, :os => os, :pae => pae, :acpi => acpi,
239
+ :io_apic => io_apic, :hardware_virtualization => hardware_virtualization,
240
+ :nested_paging => nested_paging, :tagged_tlb => tagged_tlb,
241
+ :accelerate_3d => accelerate_3d, :efi => efi,
242
+ :bios_logo_fade_in => bios_logo_fade_in,
243
+ :bios_logo_fade_out => bios_logo_fade_out,
244
+ :bios_logo_display_time => bios_logo_display_time,
245
+ :bios_boot_menu => bios_boot_menu, :audio => audio }
246
+ end
247
+
248
+ # The OS types supported by the VirtualBox installation.
249
+ #
250
+ # @return [Hash<Symbol|String, String|Symbol>] mapping from
251
+ # programmer-friendly symbols (e.g. :linux26) to proper VirtualBox OS IDs,
252
+ # and from VirtualBox IDs and description strings to programmer-friendly
253
+ # symbols
254
+ def self.os_types
255
+ return @os_types if @os_types
256
+
257
+ @os_types = {}
258
+ list_os_types.each do |key, value|
259
+ os_id = key.downcase.to_sym
260
+ @os_types[key] = os_id
261
+ @os_types[key.downcase] = os_id
262
+ @os_types[value] = os_id
263
+ @os_types[os_id] = key
264
+ end
265
+ @os_types
266
+ end
267
+
268
+ # Queries VirtualBox for available OS types.
269
+ #
270
+ # @return [Hash<String, String> mapping from each VirtualBox OS type ID to its
271
+ # description
272
+ def self.list_os_types
273
+ result = VirtualBox.run_command ['VBoxManage', '--nologo', 'list',
274
+ '--long', 'ostypes']
275
+ if result.status != 0
276
+ raise 'Unexpected error code returned by VirtualBox'
277
+ end
278
+
279
+ types = result.output.split("\n\n").map do |os_info|
280
+ i = Hash[os_info.split("\n").map { |line| line.split(':').map(&:strip) }]
281
+ [i['ID'], i['Description']]
282
+ end
283
+ Hash[types]
284
+ end
285
+ end # class VirtualBox::Board
286
+
287
+ end # namespace VirtualBox
@@ -0,0 +1,20 @@
1
+ # Run code via the command-line interface.
2
+
3
+ require 'English'
4
+ require 'shellwords'
5
+
6
+ module VirtualBox
7
+
8
+ # Runs a command in a sub-shell, waiting until the command completes.
9
+ #
10
+ # @param [Array<String>] args the name and arguments for the command to be run
11
+ #
12
+ # @return [Hashie::Mash<Symbol, String>] hash with the following keys / methods:
13
+ # :status:: the command's exit status
14
+ # :output:: a string with the command's output
15
+ def self.run_command(args)
16
+ output = Kernel.`(Shellwords.shelljoin(args))
17
+ Hashie::Mash.new :status => $CHILD_STATUS.exitstatus, :output => output
18
+ end
19
+
20
+ end # namespace VirtualBox