Class: VirtualBox::Vm

Inherits:
Object
  • Object
show all
Defined in:
lib/virtual_box/vm.rb,
lib/virtual_box/vm/nic.rb,
lib/virtual_box/vm/disk.rb,
lib/virtual_box/vm/board.rb,
lib/virtual_box/vm/io_bus.rb

Overview

VirtualBox virtual machine.

Defined Under Namespace

Classes: Board, Disk, IoBus, Nic

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Vm

Creates a new virtual machine specification based on the given attributes.



89
90
91
92
93
94
95
# File 'lib/virtual_box/vm.rb', line 89

def initialize(options = {})
  self.board = {}
  self.io_buses = []
  self.nics = []
  self.gui = false
  options.each { |k, v| self.send :"#{k}=", v }
end

Instance Attribute Details

#boardVirtualBox::Vm::Board

The general VM configuration.



22
23
24
# File 'lib/virtual_box/vm.rb', line 22

def board
  @board
end

#guiBoolean

If true, the VM’s screen will be displayed in a GUI.

This is only intended for manual testing. Many continuous integration servers cannot display the VirtualBox GUI, so this attribute should not be set to true in test suites.



38
39
40
# File 'lib/virtual_box/vm.rb', line 38

def gui
  @gui
end

#io_busesArray<VirtualBox::Vm::IoBus>

The IO controllers (and disks) connected to the VM.



26
27
28
# File 'lib/virtual_box/vm.rb', line 26

def io_buses
  @io_buses
end

#nameString

A user-friendly name for this virtual machine.

If not assigned, a unique name will be generated based on the VM’s UUID.



18
19
20
# File 'lib/virtual_box/vm.rb', line 18

def name
  @name
end

#nicsArray<VirtualBox::Vm::Nic>

The network cards connected to this virtual machine.



30
31
32
# File 'lib/virtual_box/vm.rb', line 30

def nics
  @nics
end

#uidString

The UUID used to register this virtual machine with VirtualBox.

The UUID is used to identify the VM in many VirtualBox commands. It should not be changed once the VM is registered. In fact, the UUID should not be manually assigned under normal use.



11
12
13
# File 'lib/virtual_box/vm.rb', line 11

def uid
  @uid
end

Class Method Details

.parse_machine_readable(output) ⇒ Hash<String, Object>

Parses the output of the ‘VBoxManage showvminfo –machinereadable’ command.



290
291
292
293
294
295
296
297
# File 'lib/virtual_box/vm.rb', line 290

def self.parse_machine_readable(output)
  Hash[output.split("\n").map { |line|
    key, value = *line.split('=', 2)
    key = key[1...-1] if key[0] == ?"  # Remove string quotes ("").
    value = value[1...-1] if value[0] == ?"  # Remove string quotes ("").
    [key, value]
  }]    
end

.registered_uidsArray<String>

The UUIDs of all VMs that are registered with VirtualBox.



211
212
213
214
215
216
217
# File 'lib/virtual_box/vm.rb', line 211

def self.registered_uids
  output = VirtualBox.run_command! ['VBoxManage', '--nologo', 'list', 'vms']
  output.split("\n").map do |id_info|
    uid_offset = id_info.rindex(?{) + 1
    uid = id_info[uid_offset...-1]  # Exclude the closing }
  end
end

.started_uidsArray<String>

The UUIDs of all VirtualBox VMs that are started.



222
223
224
225
226
227
228
229
# File 'lib/virtual_box/vm.rb', line 222

def self.started_uids
  output = VirtualBox.run_command! ['VBoxManage', '--nologo', 'list',
                                    'runningvms']
  output.split("\n").map do |id_info|
    uid_offset = id_info.rindex(?{) + 1
    uid = id_info[uid_offset...-1]  # Exclude the closing }
  end
end

Instance Method Details

#control(action) ⇒ VirtualBox::Vm

Controls a started virtual machine.

Raises:



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/virtual_box/vm.rb', line 169

def control(action)
  result = nil
  
  3.times do
    action_arg = case action
    when :kill
      'poweroff'
    when :power_button
      'acpipowerbutton'
    when :nmi
      'injectnmi'
    else
      action
    end

    result =  VirtualBox.run_command ['VBoxManage', '--nologo', 'controlvm',
                                      uid, action_arg]
    return self if result[:status] == 0
    
    # Perhaps the VM is already powered off?
    if action == :kill || action == :power_button
      return self unless live?
      sleep 0.1
    else
      break
    end
  end
  raise VirtualBox::Error, result
  
  self
end

#live?Boolean

True if this virtual machine is running inside VirtualBox.



204
205
206
# File 'lib/virtual_box/vm.rb', line 204

def live?
  (uid && self.class.started_uids.include?(uid)) ? true : false
end

#pull_configVirtualBox::Vm

Updates this VM’s configuration to reflect the VirtualBox configuration.



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/virtual_box/vm.rb', line 254

def pull_config
  output = VirtualBox.run_command! ['VBoxManage', '--nologo', 'showvminfo',
                                    '--machinereadable', uid]
  config = self.class.parse_machine_readable output
  
  self.name = config['name']
  self.uid = config['UUID']
  board.from_params config
  
  nic_count = config.keys.select { |key| /^nic\d+$/ =~ key }.max[3..-1].to_i
  1.upto nic_count do |index|
    if config["nic#{index}"] == 'none'
      nics[index - 1] = nil
    else
      nics[index - 1] ||= VirtualBox::Vm::Nic.new
      nics[index - 1].from_params config, index
    end
  end

  bus_count = 1 + (config.keys.select { |key|
    /^storagecontrollername\d+$/ =~ key
  }.max || "storagecontrollername-1")[21..-1].to_i
  0.upto bus_count - 1 do |index|
    io_buses[index] ||= VirtualBox::Vm::IoBus.new
    io_buses[index].from_params config, index
  end
  
  self
end

#push_configVirtualBox::Vm

Updates the configuration in VirtualBox to reflect this VM’s configuration.



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/virtual_box/vm.rb', line 234

def push_config
  command = ['VBoxManage', 'modifyvm', uid]
  command.concat board.to_params
  nics.each_with_index do |nic, index|
    if nic.nil?
      command.push "--nic#{index + 1}", 'none'
    else
      command.concat nic.to_params(index + 1)
    end
  end
  VirtualBox.run_command! command
  
  io_buses.each { |bus| bus.add_to self }
   
  self
end

#registerVirtualBox::Vm

Registers this VM with VirtualBox.



121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/virtual_box/vm.rb', line 121

def register
  VirtualBox.run_command! ['VBoxManage', 'createvm', '--name', name,
                           '--uuid', uid, '--register']
  begin
    push_config
  rescue
    unregister
    raise
  end
  
  self
end

#registered?Boolean

True if this VM has been registered with VirtualBox.



114
115
116
# File 'lib/virtual_box/vm.rb', line 114

def registered?
  self.class.registered_uids.include? uid
end

#startVirtualBox::Vm

Starts the virtual machine.



145
146
147
148
149
150
151
# File 'lib/virtual_box/vm.rb', line 145

def start
  register unless registered?
  
  VirtualBox.run_command! ['VBoxManage', '--nologo', 'startvm', uid,
                           '--type', gui ? 'gui' : 'headless']
  self
end

#stopVirtualBox::Vm

Stops the virtual machine simulation.

This is equivalent to pulling the power cord from a physical machine.



157
158
159
160
# File 'lib/virtual_box/vm.rb', line 157

def stop
  control :kill
  self
end

#to_hashHash<Symbol, Object>

Hash capturing this specification. Can be passed to Vm#new.



101
102
103
104
105
106
107
108
109
# File 'lib/virtual_box/vm.rb', line 101

def to_hash
  {
    :name => name, :uid => uid, :gui => gui,
    :board => board.to_hash, :io_buses => io_buses.map(&:to_hash),
    :nics => nics.map.
         with_index { |nic, i| nic && nic.to_hash.merge!(:port => i) }.
         reject!(&:nil?)
  }
end

#unregisterVirtualBox::Vm

De-registers this VM from VirtualBox’s database.



137
138
139
140
# File 'lib/virtual_box/vm.rb', line 137

def unregister
  VirtualBox.run_command ['VBoxManage', 'unregistervm', uid, '--delete']
  self
end