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
@@ -0,0 +1,213 @@
1
+ require 'securerandom'
2
+
3
+ module VirtualBox
4
+
5
+ # Configuration for a network card.
6
+ class Nic
7
+ # The kind of network emulation implemented on this card.
8
+ #
9
+ # Can be one of the following values:
10
+ # :nat:: uses VirtualBox internal NAT engine to hide under host OS
11
+ # :bridged:: bypasses host OS, connects directly to a network interface
12
+ # :host:: virtual network connecting guest to host
13
+ # :virtual:: virtual network connecting multiple guests
14
+ # @return [Symbol]
15
+ attr_accessor :mode
16
+
17
+ # The NIC controller chip.
18
+ #
19
+ # Can be one of the following values:
20
+ # :amd:: AMD PCNet FAST III (good default)
21
+ # :intel:: Intel PRO/1000 MT Server (for newer Windows systems)
22
+ # :intel_xp:: Intel PRO/1000 MT Server (for Windows XP)
23
+ # :virtio:: fake card optimized for virtualization (custom drivers needed)
24
+ # @return [Symbol]
25
+ attr_accessor :chip
26
+
27
+ # Name of the virtual network that the NIC is connected to.
28
+ #
29
+ # The identifier differs depending on the networking mode:
30
+ # :nat:: not applicable
31
+ # :bridged:: name of the bridge network interface on the host
32
+ # :host:: name of the host-only network interface
33
+ # :virtual:: virtual network name
34
+ # @return [Symbol]
35
+ attr_accessor :net_name
36
+
37
+ # MAC address for the network card, as a hexadecimal string.
38
+ #
39
+ # The format for specifying MACs is '0123456789AB'. A random MAC will be
40
+ # generated if one is not assigned.
41
+ # @return [String]
42
+ attr_accessor :mac
43
+
44
+ # Path to a file that logs a network trace for the VM.
45
+ #
46
+ # Can be null to disable tracing.
47
+ # @return [String]
48
+ attr_accessor :trace_file
49
+
50
+ undef :mode
51
+ def mode
52
+ @mode ||= :nat
53
+ end
54
+
55
+ undef :chip
56
+ def chip
57
+ @chip ||= (:mode == :virtual) ? :virtual : :amd
58
+ end
59
+
60
+ undef :mac
61
+ def mac
62
+ return @mac if @mac
63
+ @mac = SecureRandom.hex(6).upcase
64
+ @mac[1] = 'A' # Set the OUI bits to unicast and globally unique
65
+ @mac
66
+ end
67
+ undef :mac=
68
+ def mac=(new_mac)
69
+ @mac = new_mac && new_mac.upcase.gsub(/[^0-9A-F]/, '')
70
+ end
71
+
72
+ # Creates a NIC with the given attributes.
73
+ #
74
+ # @param [Hash<Symbol, Object>] options ActiveRecord-style initial values for
75
+ # attributes; can be used together with Nic#to_hash to save and restore
76
+ def initialize(options = {})
77
+ options.each { |k, v| self.send :"#{k}=", v }
78
+ end
79
+
80
+ # Arguments to "VBoxManage modifyvm" describing the NIC.
81
+ #
82
+ # @param [Number] nic_id the number of the card (1-4) connected to the host
83
+ # @return [Array<String>] arguments that can be concatenated to a "VBoxManage
84
+ # modifyvm" command to express this NIC specification
85
+ def to_params(nic_id)
86
+ params = []
87
+
88
+ params.push "--nic#{nic_id}"
89
+ case mode
90
+ when :nat
91
+ params.push 'nat'
92
+ when :bridged
93
+ params.push 'bridged', "--bridgeadapter#{nic_id}", net_name
94
+ when :virtual
95
+ params.push 'intnet', "--intnet#{nic_id}", net_name
96
+ when :host
97
+ params.push 'hostonly', "--hostonlyadapter#{nic_id}", net_name
98
+ else
99
+ params.push 'null'
100
+ end
101
+
102
+ params.push "--nictype#{nic_id}", case chip
103
+ when :amd
104
+ 'Am79C973'
105
+ when :intel
106
+ '82545EM'
107
+ when :intel_xp
108
+ '82543GC'
109
+ when :virtual
110
+ 'virtio'
111
+ end
112
+
113
+ params.push "--cableconnected#{nic_id}", 'on'
114
+ params.push "--macaddress#{nic_id}", mac if mac
115
+
116
+ params.push "--nictrace#{nic_id}"
117
+ if trace_file
118
+ params.push 'on', "--nictracefile#{nic_id}", trace_file
119
+ else
120
+ params.push 'off'
121
+ end
122
+
123
+ params
124
+ end
125
+
126
+ # Parses "VBoxManage showvminfo --machinereadable" output into this instance.
127
+ #
128
+ # @param [Hash<String, String>] params the "VBoxManage showvminfo" output,
129
+ # parsed by Vm.parse_machine_readble
130
+ # @param [Integer] nic_id the NIC's number in the VM
131
+ # @return [VirtualBox::Nic] self, for easy call chaining
132
+ def from_params(params, nic_id)
133
+ case params["nic#{nic_id}"]
134
+ when 'nat'
135
+ self.mode = :nat
136
+ when 'bridged'
137
+ self.mode = :bridged
138
+ self.net_name = params["bridgeadapter#{nic_id}"]
139
+ when 'intnet'
140
+ self.mode = :virtual
141
+ self.net_name = params["intnet#{nic_id}"]
142
+ when 'hostonly'
143
+ self.mode = :host
144
+ self.net_name = params["hostonlyadapter#{nic_id}"]
145
+ end
146
+
147
+ self.chip = case params["nictype#{nic_id}"]
148
+ when 'Am79C970A', 'Am79C973',
149
+ :amd
150
+ when '82543GC'
151
+ :intel_xp
152
+ when '82540OEM', '82545EM'
153
+ :intel
154
+ when 'virtio'
155
+ :virtual
156
+ else
157
+ (self.mode == :virtual) ? :virtual : :amd
158
+ end
159
+
160
+ self.mac = params["macaddress#{nic_id}"]
161
+ if params["nictrace#{nic_id}"] == 'on'
162
+ self.trace_file = params["nictracefile#{nic_id}"]
163
+ else
164
+ self.trace_file = nil
165
+ end
166
+
167
+ self
168
+ end
169
+
170
+ # Hash capturing this specification. Can be passed to Nic#new.
171
+ #
172
+ # @return [Hash<Symbol, Object>] Ruby-friendly Hash that can be used to
173
+ # re-create this NIC specification
174
+ def to_hash
175
+ { :mode => mode, :chip => chip, :net_name => net_name, :mac => mac,
176
+ :trace_file => trace_file }
177
+ end
178
+
179
+ # Information about the NICs attached to the computer.
180
+ #
181
+ # @return [Array<Hash<Symbol, Object>>] an array with one hash per NIC; hashes
182
+ # have the following keys:
183
+ # :id:: the inteface id (use when setting a Nic's net_id)
184
+ # :ip:: the IP address (check for 0.0.0.0 to see if it's live)
185
+ # :mask:: the netmask
186
+ # :mac:: the NICs MAC address
187
+ def self.host_nics
188
+ @host_nics ||= get_host_nics
189
+ end
190
+
191
+ # Queries VirtualBox for the network interfaces on the computer.
192
+ #
193
+ # @return (see .host_nics)
194
+ def self.get_host_nics
195
+ result = VirtualBox.run_command ['VBoxManage', '--nologo', 'list',
196
+ '--long', 'hostifs']
197
+ if result.status != 0
198
+ raise 'Unexpected error code returned by VirtualBox'
199
+ end
200
+
201
+ result.output.split("\n\n").map do |nic_info|
202
+ i = Hash[nic_info.split("\n").map { |line|
203
+ line.split(':', 2).map(&:strip)
204
+ }]
205
+ {
206
+ :id => i['Name'], :ip => i['IPAddress'], :mask => i['NetworkMask'],
207
+ :mac => i['HardwareAddress'].upcase.gsub(/[^0-9A-F]/, '')
208
+ }
209
+ end
210
+ end
211
+ end # class VirtualBox::Nic
212
+
213
+ end # namespace VirtualBox
@@ -1,46 +1,59 @@
1
1
  # VirtualBox version detection.
2
- #
3
- # Author:: Victor Costan
4
- # Copyright:: Copyright (C) 2009 Zergling.Net
5
- # License:: MIT
6
2
 
7
- # :nodoc: namespace
8
3
  module VirtualBox
9
4
  @version_info = nil
10
5
 
11
6
  # True if the installed VirtualBox is the open-source edition.
12
7
  #
13
- # The open-source edition of VirtualBox has some limitations, such as no support
14
- # for RDP and USB devices.
8
+ # The open-source edition of VirtualBox has some limitations, such as no
9
+ # support for RDP and USB devices.
15
10
  def self.ose?
16
- version_info ? (version_info[:edition] == 'OSE') : nil
11
+ unless version.edition
12
+ raise 'VirtualBox is not installed on this machine.'
13
+ end
14
+ version.edition == 'OSE'
17
15
  end
18
16
 
19
- # Version information about the installed VirtualBox.
17
+ # Version information about the VirtualBox package installed on this machine.
20
18
  #
21
- # Returns:
22
- # false if VirtualBox is not installed; otherwise, a hash with the keys:
23
- # revision:: (number) the SVN revision that VirtualBox is built off of
24
- # edition:: the VirtualBox edition (nil for the personal edition, 'OSE'
25
- # for the open-source edition)
26
- # version:: the VirtualBox version (e.g. '3.0.4')
27
- def self.version_info
19
+ # @return [Hash<Symbol, Object>, Boolean] false if VirtualBox is not
20
+ # installed; otherwise, a hash with the following keys:
21
+ # :svn:: (number) the SVN revision that VirtualBox is built off of
22
+ # :edition:: the VirtualBox edition ('' for the personal edition, 'OSE'
23
+ # for the open-source edition)
24
+ # :release:: the public release number (e.g. '3.0.4')
25
+ def self.version
28
26
  return @version_info unless @version_info.nil?
29
27
 
30
- cmd_result = shell_command 'VBoxManage --version'
31
- return @version_info = false if cmd_result[:status] != 0
28
+ cmd_result = run_command ['VBoxManage', '--version']
29
+ if cmd_result.status != 0
30
+ @version_info = Hashie::Mash.new
31
+ return @version_info
32
+ end
32
33
 
33
- output = cmd_result[:output].strip
34
- @version_info = {}
34
+ output = cmd_result.output.strip
35
+
35
36
  if revision_offset = output.rindex('r')
36
- @version_info[:revision] = output[revision_offset + 1, output.length].to_i
37
+ revision = output[revision_offset + 1, output.length].to_i
37
38
  output.slice! revision_offset..-1
39
+ else
40
+ revision = nil
38
41
  end
42
+
39
43
  if edition_offset = output.rindex('_')
40
- @version_info[:edition] = output[edition_offset + 1, output.length]
44
+ edition = output[edition_offset + 1, output.length]
41
45
  output.slice! edition_offset..-1
46
+ else
47
+ edition = ''
42
48
  end
43
- @version_info[:version] = output
44
- @version_info
49
+
50
+ @version_info = Hashie::Mash.new :release => output, :svn => revision,
51
+ :edition => edition
52
+ end
53
+
54
+ # Removes the cached information on the VirtualBox package version.
55
+ # @return <NilObject> nil
56
+ def self.reset_version_info!
57
+ @version_info = nil
45
58
  end
46
59
  end # namespace VirtualBox
@@ -1,35 +1,300 @@
1
- # Definition for the main VM class.
2
- #
3
- # Author:: Victor Costan
4
- # Copyright:: Copyright (C) 2009 Zergling.Net
5
- # License:: MIT
6
-
7
- # :nodoc: namespace
8
1
  module VirtualBox
2
+
3
+ # VirtualBox virtual machine.
4
+ class Vm
5
+ # The UUID used to register this virtual machine with VirtualBox.
6
+ #
7
+ # The UUID is used to identify the VM in many VirtualBox commands. It should
8
+ # not be changed once the VM is registered. In fact, the UUID should not
9
+ # be manually assigned under normal use.
10
+ # @return [String]
11
+ attr_accessor :uid
12
+
13
+ # A user-friendly name for this virtual machine.
14
+ #
15
+ # If not assigned, a unique name will be generated based on the VM's UUID.
16
+ #
17
+ # @return [String]
18
+ attr_accessor :name
19
+
20
+ # The general VM configuration.
21
+ # @return [VirtualBox::Board]
22
+ attr_accessor :board
9
23
 
10
- # A VirtualBox virtual machine.
11
- class VM
12
- include GeneralSettings
13
- include Identity
14
- include Lifecycle
24
+ # The IO controllers (and disks) connected to the VM.
25
+ # @return [Array<VirtualBox::IoBus>]
26
+ attr_accessor :io_buses
15
27
 
16
- def initialize
17
- reset_identity
18
- reset_settings
28
+ # The network cards connected to this virtual machine.
29
+ # @return [Array<VirtualBox::Nic>]
30
+ attr_accessor :nics
31
+
32
+ # If true, the VM's screen will be displayed in a GUI.
33
+ #
34
+ # This is only intended for manual testing. Many continuous integration
35
+ # servers cannot display the VirtualBox GUI, so this attribute should not be
36
+ # set to true in test suites.
37
+ # @return [Boolean]
38
+ attr_accessor :gui
39
+
40
+ undef :uid
41
+ def uid
42
+ @uid ||= UUID.generate
43
+ end
44
+
45
+ undef :name
46
+ def name
47
+ @name ||= 'rbx_' + uid.gsub('-', '')
19
48
  end
20
49
 
21
- # Resets the VM's settings to their defaults.
50
+ undef :board=
51
+ def board=(new_board)
52
+ @board = if new_board.kind_of?(VirtualBox::Board)
53
+ new_board
54
+ else
55
+ VirtualBox::Board.new new_board
56
+ end
57
+ end
58
+
59
+ undef :io_buses=
60
+ def io_buses=(new_io_buses)
61
+ @io_buses = new_io_buses.map do |io_bus|
62
+ if io_bus.kind_of?(VirtualBox::IoBus)
63
+ io_bus
64
+ else
65
+ VirtualBox::IoBus.new io_bus
66
+ end
67
+ end
68
+ end
69
+
70
+ undef :nics=
71
+ def nics=(new_nics)
72
+ @nics = []
73
+ new_nics.each do |nic|
74
+ if nic.kind_of?(VirtualBox::Nic) || nic.nil?
75
+ @nics << nic
76
+ else
77
+ options = nic.dup
78
+ port = options.delete(:port) || @nics.length
79
+ @nics[port] = VirtualBox::Nic.new options
80
+ end
81
+ end
82
+ new_nics
83
+ end
84
+
85
+ # Creates a new virtual machine specification based on the given attributes.
22
86
  #
23
- # The defaults are chosen somewhat arbitrarily by the gem's author.
24
- def reset_settings
25
- reset_general_settings
87
+ # @param [Hash<Symbol, Object>] options ActiveRecord-style initial values for
88
+ # attributes; can be used together with Vm#to_hash to save and restore
89
+ def initialize(options = {})
90
+ self.board = {}
91
+ self.io_buses = []
92
+ self.nics = []
93
+ self.gui = false
94
+ options.each { |k, v| self.send :"#{k}=", v }
95
+ end
96
+
97
+ # Hash capturing this specification. Can be passed to Vm#new.
98
+ #
99
+ # @return [Hash<Symbol, Object>] Ruby-friendly Hash that can be used to
100
+ # re-create this virtual machine specification
101
+ def to_hash
102
+ {
103
+ :name => name, :uid => uid, :gui => gui,
104
+ :board => board.to_hash, :io_buses => io_buses.map(&:to_hash),
105
+ :nics => nics.map.
106
+ with_index { |nic, i| nic && nic.to_hash.merge!(:port => i) }.
107
+ reject!(&:nil?)
108
+ }
109
+ end
110
+
111
+ # True if this VM has been registered with VirtualBox.
112
+ #
113
+ # @return [Boolean] true for VMs that are already registered with VirtualBox
114
+ def registered?
115
+ self.class.registered_uids.include? uid
116
+ end
117
+
118
+ # Registers this VM with VirtualBox.
119
+ #
120
+ # @return [VirtualBox::Vm] self, for easy call chaining
121
+ def register
122
+ unregister if registered?
123
+
124
+ result = VirtualBox.run_command ['VBoxManage', 'createvm',
125
+ '--name', name, '--uuid', uid, '--register']
126
+ if result.status != 0
127
+ raise 'Unexpected error code returned by VirtualBox'
128
+ end
129
+
130
+ begin
131
+ push_config
132
+ rescue
133
+ unregister
134
+ raise
135
+ end
136
+
137
+ self
138
+ end
139
+
140
+ # De-registers this VM from VirtualBox's database.
141
+ #
142
+ # @return [VirtualBox::Vm] self, for easy call chaining
143
+ def unregister
144
+ VirtualBox.run_command ['VBoxManage', 'unregistervm', uid, '--delete']
145
+ self
146
+ end
147
+
148
+ # Starts the virtual machine.
149
+ #
150
+ # @return [VirtualBox::Vm] self, for easy call chaining
151
+ def start
152
+ register unless registered?
153
+
154
+ result = VirtualBox.run_command ['VBoxManage', '--nologo', 'startvm', uid,
155
+ '--type', gui ? 'gui' : 'headless']
156
+ if result.status != 0
157
+ raise 'Unexpected error code returned by VirtualBox'
158
+ end
159
+ self
160
+ end
161
+
162
+ # Stops the virtual machine simulation.
163
+ #
164
+ # This is equivalent to pulling the power cord from a physical machine.
165
+ # @return [VirtualBox::Vm] self, for easy call chaining
166
+ def stop
167
+ control :kill
168
+ self
169
+ end
170
+
171
+ # Controls a started virtual machine.
172
+ #
173
+ # @param [Symbol] action the following actions are supported:
174
+ # :kill:: hard power-off (pulling the power cord from the machine)
175
+ # :power_button:: Power button press
176
+ # :nmi:: NMI (non-maskable interrupt)
177
+ # @return [VirtualBox::Vm] self, for easy call chaining
178
+ def control(action)
179
+ action = case action
180
+ when :kill
181
+ 'poweroff'
182
+ when :power_button
183
+ 'acpipowerbutton'
184
+ when :nmi
185
+ 'injectnmi'
186
+ end
187
+
188
+ result = VirtualBox.run_command ['VBoxManage', '--nologo', 'controlvm', uid,
189
+ action]
190
+ if result.status != 0
191
+ raise 'Unexpected error code returned by VirtualBox'
192
+ end
193
+ self
194
+ end
195
+
196
+ # The UUIDs of all VMs that are registered with VirtualBox.
197
+ #
198
+ # @return [Array<String>] UUIDs for VMs that VirtualBox is aware of
199
+ def self.registered_uids
200
+ result = VirtualBox.run_command ['VBoxManage', '--nologo', 'list', 'vms']
201
+ if result.status != 0
202
+ raise 'Unexpected error code returned by VirtualBox'
203
+ end
204
+ result.output.split("\n").map do |id_info|
205
+ uid_offset = id_info.rindex(?{) + 1
206
+ uid = id_info[uid_offset...-1] # Exclude the closing }
207
+ end
26
208
  end
27
209
 
28
- # Arguments to "VBoxManage modifyvm" describing the VM's settings.
29
- def modifyvm_params
30
- params = ''
31
- params << modifyvm_general_params
210
+ # The UUIDs of all VirtualBox VMs that are started.
211
+ #
212
+ # @return [Array<String>] UUIDs for VMs that are running in VirtualBox
213
+ def self.started_uids
214
+ result = VirtualBox.run_command ['VBoxManage', '--nologo', 'list',
215
+ 'runningvms']
216
+ if result.status != 0
217
+ raise 'Unexpected error code returned by VirtualBox'
218
+ end
219
+ result.output.split("\n").map do |id_info|
220
+ uid_offset = id_info.rindex(?{) + 1
221
+ uid = id_info[uid_offset...-1] # Exclude the closing }
222
+ end
32
223
  end
33
- end # class VM
34
224
 
225
+ # Updates the configuration in VirtualBox to reflect this VM's configuration.
226
+ #
227
+ # @return [VirtualBox::Vm] self, for easy call chaining
228
+ def push_config
229
+ command = ['VBoxManage', 'modifyvm', uid]
230
+ command.concat board.to_params
231
+ nics.each_with_index do |nic, index|
232
+ if nic.nil?
233
+ command.push "--nic#{index + 1}", 'none'
234
+ else
235
+ command.concat nic.to_params(index + 1)
236
+ end
237
+ end
238
+ if VirtualBox.run_command(command).status != 0
239
+ raise 'Unexpected error code returned by VirtualBox'
240
+ end
241
+
242
+ io_buses.each { |bus| bus.add_to self }
243
+
244
+ self
245
+ end
246
+
247
+ # Updates this VM's configuration to reflect the VirtualBox configuration.
248
+ #
249
+ # @return [VirtualBox::Vm] self, for easy call chaining
250
+ def pull_config
251
+ result = VirtualBox.run_command ['VBoxManage', '--nologo', 'showvminfo',
252
+ '--machinereadable', uid]
253
+ if result.status != 0
254
+ raise 'Unexpected error code returned by VirtualBox'
255
+ end
256
+
257
+ config = self.class.parse_machine_readable result.output
258
+
259
+ self.name = config['name']
260
+ self.uid = config['UUID']
261
+ board.from_params config
262
+
263
+ nic_count = config.keys.select { |key| /^nic\d+$/ =~ key }.max[3..-1].to_i
264
+ 1.upto nic_count do |index|
265
+ if config["nic#{index}"] == 'none'
266
+ nics[index - 1] = nil
267
+ else
268
+ nics[index - 1] ||= VirtualBox::Nic.new
269
+ nics[index - 1].from_params config, index
270
+ end
271
+ end
272
+
273
+ bus_count = 1 + (config.keys.select { |key|
274
+ /^storagecontrollername\d+$/ =~ key
275
+ }.max || "storagecontrollername-1")[21..-1].to_i
276
+ 0.upto bus_count - 1 do |index|
277
+ io_buses[index] ||= VirtualBox::IoBus.new
278
+ io_buses[index].from_params config, index
279
+ end
280
+
281
+ self
282
+ end
283
+
284
+ # Parses the output of the 'VBoxManage showvminfo --machinereadable' command.
285
+ #
286
+ # @param [String] output the command output
287
+ # @return [Hash<String, Object>] a Hash whose keys are the strings on the left
288
+ # side of "=" on each line, and whose values are the strings on the right
289
+ # side
290
+ def self.parse_machine_readable(output)
291
+ Hash[output.split("\n").map { |line|
292
+ key, value = *line.split('=', 2)
293
+ key = key[1...-1] if key[0] == ?" # Remove string quotes ("").
294
+ value = value[1...-1] if value[0] == ?" # Remove string quotes ("").
295
+ [key, value]
296
+ }]
297
+ end
298
+ end # class VirtualBox::Vm
299
+
35
300
  end # namespace VirtualBox
data/lib/virtual_box.rb CHANGED
@@ -1,12 +1,17 @@
1
- # Main include file for the virtual_box gem.
2
- #
3
- # Author:: Victor Costan
4
- # Copyright:: Copyright (C) 2009 Zergling.Net
5
- # License:: MIT
1
+ # TODO(pwnall): documentation for the top-level VirtualBox module
2
+ module VirtualBox
3
+
4
+ end
6
5
 
7
- require 'virtual_box/command_line.rb'
6
+ require 'hashie/mash'
7
+ require 'uuid'
8
+
9
+ require 'virtual_box/board.rb'
10
+ require 'virtual_box/cli.rb'
11
+ require 'virtual_box/dhcp.rb'
12
+ require 'virtual_box/disk.rb'
13
+ require 'virtual_box/io_bus.rb'
14
+ require 'virtual_box/net.rb'
15
+ require 'virtual_box/nic.rb'
8
16
  require 'virtual_box/version.rb'
9
- require 'virtual_box/vm/general_settings.rb'
10
- require 'virtual_box/vm/identity.rb'
11
- require 'virtual_box/vm/lifecycle.rb'
12
17
  require 'virtual_box/vm.rb'
data/test/helper.rb ADDED
@@ -0,0 +1,24 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'minitest/unit'
11
+ require 'minitest/spec'
12
+ require 'mocha'
13
+
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
16
+ require 'virtual_box'
17
+
18
+ class MiniTest::Unit::TestCase
19
+ end
20
+
21
+ Dir[File.expand_path('helpers/**/*.rb', File.dirname(__FILE__))].
22
+ each { |h| require h }
23
+
24
+ MiniTest::Unit.autorun