Class: VirtualBox::VM

Inherits:
AbstractModel show all
Defined in:
lib/virtualbox/vm.rb

Overview

Represents a single VirtualBox virtual machine. All attributes which are not read-only can be modified and saved.

Finding Virtual Machines

Two methods are used to find virtual machines: VM.all and VM.find. Each return a VM object. An example is shown below:

vm = VirtualBox::VM.find("MyWindowsXP")
puts vm.name # => "MyWindowsXP"

Modifying Virtual Machines

Virtual machines can be modified a lot like ActiveRecord objects. This is best shown through example:

vm = VirtualBox::VM.find("MyWindowsXP")
vm.memory = 256
vm.name = "WindowsXP"
vm.save

Attributes and Relationships

Properties of the virtual machine are exposed using standard ruby instance methods which are generated on the fly. Because of this, they are not listed below as available instance methods.

These attributes can be accessed and modified via standard ruby-style instance.attribute and instance.attribute= methods. The attributes are listed below.

Relationships are also accessed like attributes but can't be set. Instead, they are typically references to other objects such as a HardDrive which in turn have their own attributes which can be modified.

Attributes

This is copied directly from the class header, but lists all available attributes. If you don't understand what this means, read Attributable.

attribute :uuid, :readonly => true
attribute :name
attribute :ostype
attribute :description, :readonly => true
attribute :memory
attribute :vram
attribute :acpi
attribute :ioapic
attribute :cpus
attribute :synthcpu
attribute :pae
attribute :hwvirtex
attribute :hwvirtexexcl
attribute :nestedpaging
attribute :vtxvpid
attribute :accelerate3d
attribute :accelerate2dvideo
attribute :biosbootmenu, :populate_key => :bootmenu
attribute :boot1
attribute :boot2
attribute :boot3
attribute :boot4
attribute :clipboard
attribute :monitorcount
attribute :usb
attribute :ehci
attribute :audio
attribute :audiocontroller
attribute :audiodriver
attribute :vrdp
attribute :vrdpport
attribute :vrdpauthtype
attribute :vrdpauthtimeout
attribute :state, :populate_key => :vmstate, :readonly => true

Relationships

In addition to the basic attributes, a virtual machine is related to other things. The relationships are listed below. If you don't understand this, read Relatable.

relationship :nics, Nic
relationship :usbs, USB
relationship :storage_controllers, StorageController, :dependent => :destroy
relationship :shared_folders, SharedFolder
relationship :extra_data, ExtraData
relationship :forwarded_ports, ForwardedPort

Class Method Summary

Instance Method Summary

Methods inherited from AbstractModel

#errors, #existing_record!, #inspect, #lazy_attribute?, #lazy_relationship?, #new_record!, #new_record?, #populate_attributes, #populate_relationship, #populate_relationships, reload!, #reload!, reload?, reloaded!, #set_relationship, #validate, #write_attribute

Methods included from AbstractModel::Attributable

#attributes, #has_attribute?, included, #lazy_attribute?, #loaded_attribute?, #populate_attributes, #read_attribute, #readonly_attribute?, #write_attribute

Methods included from AbstractModel::Dirty

#changed?, #changes, #clear_dirty!, #ignore_dirty, #method_missing, #set_dirty!

Methods included from AbstractModel::Relatable

#destroy_relationship, #destroy_relationships, #has_relationship?, included, #lazy_relationship?, #loaded_relationship?, #populate_relationship, #populate_relationships, #read_relationship, #relationship_data, #save_relationship, #save_relationships, #set_relationship

Methods included from AbstractModel::Validatable

#add_error, #clear_errors, #errors, #valid?, #validate, #validates_presence_of

Constructor Details

- (VM) initialize(data)

Creates a new instance of a virtual machine.

Currently can NOT be used to create a NEW virtual machine. Support for creating new virtual machines will be added shortly. For now, this is only used by VM.find and VM.all to initialize the VMs.



240
241
242
243
244
245
246
# File 'lib/virtualbox/vm.rb', line 240

def initialize(data)
  super()

  initialize_attributes(data)
  populate_relationships(data)
  @original_name = name
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class VirtualBox::AbstractModel::Dirty

Class Method Details

+ (Array<VM>) all(reload = false)

Returns an array of all available VMs.

Returns:

  • (Array<VM>)


136
137
138
# File 'lib/virtualbox/vm.rb', line 136

def all(reload=false)
  Global.global(reload).vms
end

+ (VM) find(name)

Finds a VM by UUID or registered name and returns a new VM object. If the VM doesn't exist, will return nil.

Returns:



144
145
146
# File 'lib/virtualbox/vm.rb', line 144

def find(name)
  all(true).detect { |o| o.name == name || o.uuid == name }
end

+ (VM) import(source_path)

Imports a VM, blocking the entire thread during this time. When finished, on success, will return the VM object. This VM object can be used to make any modifications necessary (RAM, cpus, etc.).

Returns:

  • (VM) — The newly imported virtual machine


167
168
169
170
171
172
# File 'lib/virtualbox/vm.rb', line 167

def import(source_path)
  raw = Command.vboxmanage("import", source_path)
  return nil unless raw

  find(parse_vm_name(raw))
end

+ (VM) load_from_xml(location)

Loads a VM from its XML configuration file. All VMs managed by VirtualBox have an XML configuration file somewhere. If given the path, this will instantiate the VM that way. Typically this method will only be called internally. Users of the class should use all or find instead.

Parameters:

  • (String) location — Full path to the XML file.

Returns:



156
157
158
159
# File 'lib/virtualbox/vm.rb', line 156

def load_from_xml(location)
  vm_doc = Command.parse_xml(location)
  new(vm_doc)
end

+ (Object) parse_vm_info(raw)

Parses the machine-readable format outputted by VBoxManage showvminfo into a hash. Ignores lines which don't match the format.



185
186
187
188
189
190
191
192
193
194
# File 'lib/virtualbox/vm.rb', line 185

def parse_vm_info(raw)
  parsed = {}
  raw.split("\n").each do |line|
    # Some lines aren't configuration, we just ignore them
    next unless line =~ /^"?(.+?)"?="?(.+?)"?$/
    parsed[$1.downcase.to_sym] = $2.strip
  end

  parsed
end

+ (Array) parse_vm_list(raw)

Parses the list of VMs returned by the "list vms" command used in VM.all.

This method typically won't be used except internally.

Returns:

  • (Array) — Array of virtual machines.


202
203
204
205
206
207
208
209
210
# File 'lib/virtualbox/vm.rb', line 202

def parse_vm_list(raw)
  results = []
  raw.split("\n").each do |line|
    next unless line =~ /^"(.+?)"\s+\{(.+?)\}$/
    results.push(find($1.to_s))
  end

  results
end

+ (String) parse_vm_name(raw)

Parses the vm name from the import results.

This method typically won't be used except internally.

Returns:

  • (String) — Parsed VM name


217
218
219
220
# File 'lib/virtualbox/vm.rb', line 217

def parse_vm_name(raw)
  return nil unless raw =~ /VM name "(.+?)"/
  $1.to_s
end

+ (Object) populate_relationship(caller, doc)



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

def populate_relationship(caller, doc)
  result = Proxies::Collection.new(caller)

  doc.css("Global MachineRegistry MachineEntry").each do |entry|
    location = Global.expand_path(entry[:src])
    result << load_from_xml(location)
  end

  result
end

+ (Hash) raw_info(name)

Gets the VM info (machine readable) for a given VM and returns it as a hash.

Returns:

  • (Hash) — Parsed VM info.


178
179
180
181
# File 'lib/virtualbox/vm.rb', line 178

def raw_info(name)
  raw = Command.vboxmanage("showvminfo", name, "--machinereadable")
  parse_vm_info(raw)
end

Instance Method Details

- (Boolean) aborted?

Returns true if the virtual machine state is aborted

Returns:

  • (Boolean) — True if virtual machine state is aborted


558
559
560
# File 'lib/virtualbox/vm.rb', line 558

def aborted?
  state == 'aborted'
end

- (Boolean) control(command, raise_errors = false)

Controls the virtual machine. This method is used by #stop, #pause, #resume, and #save_state to control the virtual machine. Typically, you won't ever have to call this method and should instead call those.

Parameters:

  • (String) command — The command to run on controlvm
  • (Boolean) raise_errors (defaults to: false) — If true, Exceptions::CommandFailedException will be raised if the command failed.

Returns:

  • (Boolean) — True if command was successful, false otherwise.


496
497
498
499
500
501
502
# File 'lib/virtualbox/vm.rb', line 496

def control(command, raise_errors=false)
  Command.vboxmanage("controlvm", @original_name, command)
  true
rescue Exceptions::CommandFailedException
  raise if raise_errors
  false
end

- (Object) destroy(opts = {})

Destroys the virtual machine. This method also removes all attached media (required by VirtualBox to destroy a VM). By default, this will not destroy attached hard drives, but will if given the destroy_image option.

Passes options to the destroy method.

Options Hash (opts):

  • (Boolean) :destroy_image — default: false —If true, will also destroy all attached images such as hard drives, disk images, etc.


514
515
516
517
518
519
520
521
522
523
524
525
# File 'lib/virtualbox/vm.rb', line 514

def destroy(*args)
  # Call super first to destroy relationships, necessary before
  # unregistering a VM
  super

  if Command.vboxmanage("unregistervm", @original_name, "--delete")
    Global.reload!
    return true
  else
    return false
  end
end

- (Boolean) discard_state(raise_errors = false)

Discards any saved state on the current VM. The VM is not destroyed though and can still be started by calling #start.

Parameters:

Returns:

  • (Boolean) — True if command was successful, false otherwise.


479
480
481
482
483
484
485
# File 'lib/virtualbox/vm.rb', line 479

def discard_state(raise_errors=false)
  Command.vboxmanage("discardstate", @original_name)
  true
rescue Exceptions::CommandFailedException
  raise if raise_errors
  false
end

- (Object) export(filename, options = {}, raise_error = false)

Exports a virtual machine. The virtual machine will be exported to the specified OVF file name. This directory will also have the mf file which contains the file checksums and also the virtual drives of the machine.

Export also supports an additional options hash which can contain information that will be embedded with the virtual machine. View below for more information on the available options.

This method will block until the export is complete, which takes about 60 to 90 seconds on my 2.2 GHz 2009 model MacBook Pro.

Parameters:

  • (String) filename — The file (not directory) to save the exported OVF file. This directory will also receive the checksum file and virtual disks.

Options Hash (options):

  • (String) :product — default: nil —The name of the product
  • (String) :producturl — default: nil —The URL of the product
  • (String) :vendor — default: nil —The name of the vendor
  • (String) :vendorurl — default: nil —The URL for the vendor
  • (String) :version — default: nil —The version information
  • (String) :eula — default: nil —License text
  • (String) :eulafile — default: nil —License file


384
385
386
387
388
389
390
391
392
393
394
395
396
397
# File 'lib/virtualbox/vm.rb', line 384

def export(filename, options={}, raise_error=false)
  options = options.inject([]) do |acc, kv|
    acc.push("--#{kv[0]}")
    acc.push(kv[1])
  end

  options.unshift("0").unshift("--vsys") unless options.empty?

  raw = Command.vboxmanage("export", @original_name, "-o", filename, *options)
  true
rescue Exceptions::CommandFailedException
  raise if raise_error
  false
end

- (Object) initialize_attributes(doc)



248
249
250
251
252
253
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
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'lib/virtualbox/vm.rb', line 248

def initialize_attributes(doc)
  attribute_associations = {
    :uuid     => ["Machine", :uuid],
    :name     => ["Machine", :name],
    :ostype   => ["Machine", :OSType],
    :description => ["Machine Description"],
    :memory   => ["Hardware Memory", :RAMSize],
    :vram     => ["Hardware Display", :VRAMSize],
    :acpi     => ["Hardware BIOS ACPI", :enabled],
    :ioapic   => ["Hardware BIOS IOAPIC", :enabled],
    :cpus     => ["Hardware CPU", :count],
    :pae      => ["Hardware CPU PAE", :enabled],
    :hwvirtex => ["Hardware CPU HardwareVirtEx", :enabled],
    :hwvirtexexcl => ["Hardware CPU HardwareVirtEx", :exclusive],
    :nestedpaging => ["Hardware CPU HardwareVirtExNestedPaging", :enabled],
    :vtxvpid  => ["Hardware CPU HardwareVirtExVPID", :enabled],
    :accelerate3d => ["Hardware Display", :accelerate3D],
    :accelerate2dvideo => ["Hardware Display", :accelerate2DVideo],
    :biosbootmenu => ["Hardware BIOS BootMenu", :mode],
    :boot1    => ["Hardware Boot Order[position=\"1\"]", :device],
    :boot2    => ["Hardware Boot Order[position=\"2\"]", :device],
    :boot3    => ["Hardware Boot Order[position=\"3\"]", :device],
    :boot4    => ["Hardware Boot Order[position=\"4\"]", :device],
    :clipboard  => ["Hardware Clipboard", :mode],
    :monitorcount => ["Hardware Display", :monitorCount],
    :usb  => ["Hardware USBController", :enabled],
    :ehci => ["Hardware USBController", :enabledEhci],
    :audio            => ["Hardware AudioAdapter", :enabled],
    :audiocontroller => ["Hardware AudioAdapter", :controller],
    :audiodriver     => ["Hardware AudioAdapter", :driver],
    :vrdp            => ["Hardware RemoteDisplay", :enabled],
    :vrdpport        => ["Hardware RemoteDisplay", :port],
    :vrdpauthtype    => ["Hardware RemoteDisplay", :authType],
    :vrdpauthtimeout => ["Hardware RemoteDisplay", :authTimeout],
  }

  attribute_associations.each do |name, search_data|
    css, key = search_data
    node = doc.css(css)[0]

    # key is passed in for attributes, else you get the element inner text
    value = (key ? node[key] : node.inner_text) if node

    # Special cases
    value = value[1..-2] if name == :uuid

    write_attribute(name, value)
  end

  # Clear dirtiness, since this should only be called initially and
  # therefore shouldn't affect dirtiness
  clear_dirty!

  # But this is an existing record
  existing_record!
end

- (Object) load_attribute(name)



305
306
307
308
309
310
311
312
313
314
# File 'lib/virtualbox/vm.rb', line 305

def load_attribute(name)
  info = self.class.raw_info(@original_name)

  if name == :state
    # Simply force a state reload, and it'll write the attribute up
    write_attribute(:state, info[:vmstate])
  end

  write_attribute(:synthcpu, info[:synthcpu]) unless loaded_attribute?(:synthcpu)
end

- (Boolean) pause(raise_errors = false)

Pauses the VM, putting it on hold temporarily. The VM can be resumed again by calling #resume

Parameters:

Returns:

  • (Boolean) — True if command was successful, false otherwise.


450
451
452
# File 'lib/virtualbox/vm.rb', line 450

def pause(raise_errors=false)
  control(:pause, raise_errors)
end

- (Boolean) paused?

Returns true if the virtual machine state is paused

Returns:

  • (Boolean) — True if virtual machine state is paused


544
545
546
# File 'lib/virtualbox/vm.rb', line 544

def paused?
  state == 'paused'
end

- (Boolean) powered_off?

Returns true if the virtual machine state is powered off

Returns:

  • (Boolean) — True if virtual machine state is powered off


537
538
539
# File 'lib/virtualbox/vm.rb', line 537

def powered_off?
  state == 'poweroff'
end

- (Boolean) resume(raise_errors = false)

Resume a paused VM.

Parameters:

Returns:

  • (Boolean) — True if command was successful, false otherwise.


459
460
461
# File 'lib/virtualbox/vm.rb', line 459

def resume(raise_errors=false)
  control(:resume, raise_errors)
end

- (Boolean) running?

Returns true if the virtual machine state is running

Returns:

  • (Boolean) — True if virtual machine state is running


530
531
532
# File 'lib/virtualbox/vm.rb', line 530

def running?
  state == 'running'
end

- (Object) save(raise_errors = false)

Saves the virtual machine if modified. This method saves any modified attributes of the virtual machine. If any related attributes were saved as well (such as storage controllers), those will be saved, too.



334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
# File 'lib/virtualbox/vm.rb', line 334

def save(raise_errors=false)
  # Make sure we save the new name first if that was changed, or
  # we'll get some inconsistencies later
  if name_changed?
    save_attribute(:name, name)
    @original_name = name
  end

  super()

  # Force reload
  Global.reload!

  true
rescue Exceptions::CommandFailedException
  raise if raise_errors
  return false
end

- (Object) save_attribute(key, value)

Saves a single attribute of the virtual machine. This should not be called except interally. Instead, you're probably looking for #save.

This method typically won't be used except internally.



357
358
359
360
# File 'lib/virtualbox/vm.rb', line 357

def save_attribute(key, value)
  Command.vboxmanage("modifyvm", @original_name, "--#{key}", value)
  super
end

- (Boolean) save_state(raise_errors = false)

Saves the state of a VM and stops it. The VM can be resumed again by calling "#start" again.

Parameters:

Returns:

  • (Boolean) — True if command was successful, false otherwise.


469
470
471
# File 'lib/virtualbox/vm.rb', line 469

def save_state(raise_errors=false)
  control(:savestate, raise_errors)
end

- (Boolean) saved?

Returns true if the virtual machine state is saved

Returns:

  • (Boolean) — True if virtual machine state is saved


551
552
553
# File 'lib/virtualbox/vm.rb', line 551

def saved?
  state == 'saved'
end

- (Boolean) shutdown(raise_errors = false)

Shuts down the VM by directly calling "acpipowerbutton". Depending on the settings of the Virtual Machine, this may not work. For example, some linux installations don't respond to the ACPI power button at all. In such cases, #stop or #save_state may be used instead.

Parameters:

Returns:

  • (Boolean) — True if command was successful, false otherwise.


429
430
431
# File 'lib/virtualbox/vm.rb', line 429

def shutdown(raise_errors=false)
  control(:acpipowerbutton, raise_errors)
end

- (Boolean) start(mode = :gui, raise_errors = false)

Starts the virtual machine. The virtual machine can be started in a variety of modes:

  • gui -- The VirtualBox GUI will open with the screen of the VM.
  • headless -- The VM will run in the background. No GUI will be present at all.

All modes will start their processes and return almost immediately. Both the GUI and headless mode will not block the ruby process.

Parameters:

  • (Symbol) mode (defaults to: :gui) — Described above.
  • (Boolean) raise_errors (defaults to: false) — If true, Exceptions::CommandFailedException will be raised if the command failed.

Returns:

  • (Boolean) — True if command was successful, false otherwise.


413
414
415
416
417
418
419
# File 'lib/virtualbox/vm.rb', line 413

def start(mode=:gui, raise_errors=false)
  Command.vboxmanage("startvm", @original_name, "--type", mode)
  true
rescue Exceptions::CommandFailedException
  raise if raise_errors
  false
end

- (String) state(reload = false)

State of the virtual machine. Returns the state of the virtual machine. This state will represent the state that was assigned when the VM was found unless reload is set to true.

Parameters:

  • (Boolean) reload (defaults to: false) — If true, will reload the state to current value.

Returns:

  • (String) — Virtual machine state.


323
324
325
326
327
328
329
# File 'lib/virtualbox/vm.rb', line 323

def state(reload=false)
  if reload
    load_attribute(:state)
  end

  read_attribute(:state)
end

- (Boolean) stop(raise_errors = false)

Stops the VM by directly calling "poweroff." Immediately halts the virtual machine without saving state. This could result in a loss of data. To prevent data loss, see #shutdown

Parameters:

Returns:

  • (Boolean) — True if command was successful, false otherwise.


440
441
442
# File 'lib/virtualbox/vm.rb', line 440

def stop(raise_errors=false)
  control(:poweroff, raise_errors)
end