Class: VirtualBox::VM
- Inherits:
-
AbstractModel
- Object
- AbstractModel
- VirtualBox::VM
- 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](ar.rubyonrails.org/) objects. This is best shown through example:
vm = VirtualBox::VM.find("MyWindowsXP")
vm.memory_size = 256
vm.name = "WindowsXP"
vm.save
# Controlling Virtual Machines
Virtual machines can be controlled using the basic #start, #stop, etc. methods. The current state of the VM can also be retrieved via the #state method. An example of this use is shown below:
if vm.powered_off?
vm.start
end
# Taking a Snapshot
Snapshots allow virtual machine states to be saved at a given point in time without having to stop the machine. This state can then be restored later. VirtualBox handles this by creating a differencing image which allows the hard drive to even retain its exact state. Taking a snapshot is extremely simple:
vm = VirtualBox::VM.find("MyWindowsXP")
vm.take_snapshot("My Snapshot", "A description of my snapshot")
# Traversing Snapshots
Snapshots are represented by a tree-like structure. There is a root snapshot and that snapshot has many children which may in turn have their own children. The easiest way to traverse this structure is to use the #root_snapshot VM method and traverse the structure like any tree structure:
vm = VirtualBox::VM.find("MyWindowsXP")
p vm.root_snapshot.children.length
# Finding Snapshots
While traversing the entire snapshot tree can be useful, it is often more useful to be able to simply find a snapshot by name. For this, use the #find_snapshot method:
vm = VirtualBox::VM.find("MyWindowsXP")
p vm.find_snapshot("PreSP3")
# 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 AbstractModel::Attributable.
attribute :uuid, :readonly => true, :property => :id
attribute :name
attribute :os_type_id
attribute :description
attribute :memory_size
attribute :memory_balloon_size
attribute :vram_size
attribute :cpu_count
attribute :accelerate_3d_enabled, :boolean => true
attribute :accelerate_2d_video_enabled, :boolean => true
attribute :clipboard_mode
attribute :monitor_count
attribute :state, :readonly => true
attribute :accessible, :readonly => true, :boolean => true
attribute :hardware_version
attribute :hardware_uuid
attribute :firmware_type
attribute :snapshot_folder
attribute :settings_file_path, :readonly => true
attribute :last_state_change, :readonly => true
attribute :state_file_path, :readonly => true
attribute :log_folder, :readonly => true
attribute :snapshot_count, :readonly => true
attribute :current_state_modified, :readonly => true
attribute :guest_property_notification_patterns
attribute :teleporter_enabled, :boolean => true
attribute :teleporter_port
attribute :teleporter_address
attribute :teleporter_password
attribute :interface, :readonly => true, :property => false
## 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 AbstractModel::Relatable.
relationship :audio_adapter, :AudioAdapter
relationship :bios, :BIOS
relationship :hw_virt, :HWVirtualization
relationship :cpu, :CPU
relationship :vrdp_server, :VRDPServer
relationship :storage_controllers, :StorageController, :dependent => :destroy
relationship :medium_attachments, :MediumAttachment
relationship :shared_folders, :SharedFolder
relationship :extra_data, :ExtraData
relationship :forwarded_ports, :ForwardedPort
relationship :network_adapters, :NetworkAdapter
relationship :usb_controller, :USBController
relationship :current_snapshot, :Snapshot
Class Method Summary collapse
-
.all ⇒ Array<VM>
Returns an array of all available VMs.
-
.find(name) ⇒ VM
Finds a VM by UUID or registered name and returns a new VM object.
-
.import(source_path, &block) ⇒ VM
Imports a VM, blocking the entire thread during this time.
- .populate_array_relationship(caller, machines) ⇒ Object
- .populate_relationship(caller, machines) ⇒ Object
- .populate_single_relationship(caller, machine) ⇒ Object
Instance Method Summary collapse
-
#aborted? ⇒ Boolean
Returns true if the virtual machine state is aborted.
-
#control(command, *args) ⇒ Boolean
Controls the virtual machine.
-
#destroy(opts = {}) ⇒ Object
Destroys the virtual machine.
-
#discard_state ⇒ Boolean
Discards any saved state on the current VM.
-
#export(filename, options = {}, &block) ⇒ Object
Exports a virtual machine.
-
#find_snapshot(name) ⇒ Object
Find a snapshot by name or UUID.
-
#get_boot_order(interface, key) ⇒ Object
Loads the boot order for this virtual machine.
-
#initialize(imachine) ⇒ VM
constructor
Creates a new instance of a virtual machine.
- #initialize_attributes(machine) ⇒ Object
-
#pause ⇒ Boolean
Pauses the VM, putting it on hold temporarily.
-
#paused? ⇒ Boolean
Returns true if the virtual machine state is paused.
-
#powered_off? ⇒ Boolean
Returns true if the virtual machine state is powered off.
-
#reload ⇒ Object
Reload the model so that all the attributes and relationships are up to date.
-
#resume ⇒ Boolean
Resume a paused VM.
-
#root_snapshot ⇒ Snapshot
Returns the root snapshot of this virtual machine.
-
#running? ⇒ Boolean
Returns true if the virtual machine state is running.
-
#save ⇒ Object
Saves the virtual machine if modified.
-
#save_state ⇒ Boolean
Saves the state of a VM and stops it.
-
#saved? ⇒ Boolean
Returns true if the virtual machine state is saved.
-
#set_boot_order(interface, key, value) ⇒ Object
Sets the boot order for this virtual machine.
-
#shutdown ⇒ Boolean
Shuts down the VM by directly calling “acpipowerbutton”.
-
#start(mode = "gui") ⇒ Boolean
Starts the virtual machine.
-
#starting? ⇒ Boolean
Returns true if the virtual machine state is starting.
-
#state(suppress_state_reload = false) ⇒ String
State of the virtual machine.
-
#stop ⇒ Boolean
Stops the VM by directly calling “poweroff.” Immediately halts the virtual machine without saving state.
-
#take_snapshot(name, description = "", &block) ⇒ Object
Take a snapshot of the current state of the machine.
-
#validate ⇒ Object
Validates the virtual machine.
-
#with_open_session(mode = :write) ⇒ Object
Opens a direct session with the machine this VM represents and yields the session object to a block.
Methods inherited from AbstractModel
#errors, errors_for_relationship, #existing_record!, #inspect, #lazy_attribute?, #lazy_relationship?, #new_record!, #new_record?, #parent_machine, #populate_attributes, #populate_relationship, #populate_relationships, reload!, #reload!, reload?, reloaded!, #save!, #save_attribute, #save_changed_interface_attributes, #save_interface_attribute, #set_relationship, #write_attribute
Methods included from AbstractModel::Validatable
#__validates_extract_options, #add_error, #clear_errors, #errors, #errors_on, #full_error_messages, #valid?, #validates_format_of, #validates_inclusion_of, #validates_numericality_of, #validates_presence_of
Methods included from AbstractModel::Relatable
#destroy_relationship, #destroy_relationships, #has_relationship?, included, #lazy_relationship?, #loaded_relationship?, #populate_relationship, #populate_relationships, #read_relationship, #relationship_class, #relationship_data, #save_relationship, #save_relationships, #set_relationship
Methods included from AbstractModel::VersionMatcher
#assert_version_match, #split_version, #version_match?
Methods included from AbstractModel::Dirty
#changed?, #changes, #clear_dirty!, #ignore_dirty, #method_missing, #set_dirty!
Methods included from AbstractModel::InterfaceAttributes
#load_interface_attribute, #load_interface_attributes, #save_interface_attribute, #save_interface_attributes, #spec_to_proc
Methods included from AbstractModel::Attributable
#attributes, #has_attribute?, included, #lazy_attribute?, #loaded_attribute?, #populate_attributes, #read_attribute, #readonly_attribute?, #write_attribute
Methods included from Logger
included, #logger, #logger_output=
Constructor Details
#initialize(imachine) ⇒ VM
245 246 247 248 249 250 |
# File 'lib/virtualbox/vm.rb', line 245 def initialize(imachine) super() write_attribute(:interface, imachine) initialize_attributes(imachine) end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class VirtualBox::AbstractModel::Dirty
Class Method Details
.all ⇒ Array<VM>
Returns an array of all available VMs.
187 188 189 |
# File 'lib/virtualbox/vm.rb', line 187 def all Global.global(true).vms end |
.find(name) ⇒ VM
Finds a VM by UUID or registered name and returns a new VM object. If the VM doesn’t exist, will return ‘nil`.
195 196 197 |
# File 'lib/virtualbox/vm.rb', line 195 def find(name) all.detect { |o| o.name == name || o.uuid == name } end |
.import(source_path, &block) ⇒ VM
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.).
If there are multiple VMs in the OVF file being imported, the first virtual machine will be returned, although all will be imported.
If a block is given, it will be yielded with the progress of the import operation, so that the progress of the import can be tracked.
213 214 215 216 217 218 |
# File 'lib/virtualbox/vm.rb', line 213 def import(source_path, &block) appliance = Appliance.new(source_path) appliance.import(&block) find(appliance.virtual_systems.first.descriptions[:name][:auto]) end |
.populate_array_relationship(caller, machines) ⇒ Object
228 229 230 231 232 233 234 235 236 |
# File 'lib/virtualbox/vm.rb', line 228 def populate_array_relationship(caller, machines) result = Proxies::Collection.new(caller) machines.each do |machine| result << new(machine) end result end |
.populate_relationship(caller, machines) ⇒ Object
220 221 222 |
# File 'lib/virtualbox/vm.rb', line 220 def populate_relationship(caller, machines) machines.is_a?(Array) ? populate_array_relationship(caller, machines) : populate_single_relationship(caller, machines) end |
.populate_single_relationship(caller, machine) ⇒ Object
224 225 226 |
# File 'lib/virtualbox/vm.rb', line 224 def populate_single_relationship(caller, machine) new(machine) end |
Instance Method Details
#aborted? ⇒ Boolean
Returns true if the virtual machine state is aborted
621 622 623 |
# File 'lib/virtualbox/vm.rb', line 621 def aborted? state == :aborted end |
#control(command, *args) ⇒ Boolean
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.
539 540 541 542 543 544 |
# File 'lib/virtualbox/vm.rb', line 539 def control(command, *args) with_open_session(:shared) do |session| result = session.console.send(command, *args) result.wait if result.is_a?(COM::Util.versioned_interface(:Progress)) end end |
#destroy(opts = {}) ⇒ Object
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.
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 |
# File 'lib/virtualbox/vm.rb', line 557 def destroy(*args) # Do a full cleanup on the machine, then delete all the media attached media = interface.unregister(:full) if !media.empty? if Platform.windows? && !Platform.jruby? # The MSCOM interface in CRuby to delete media is broken, # so we do this ghettoness. path = interface.settings_file_path # A simple sanity check to make sure we don't attempt to delete # the root or something if path.length > 10 Pathname.new(path).parent.rmtree end else interface.delete(media) # TODO: This sleep is silly. The progress object returned by the media # delete always fails to "wait" for some reason, so I do this. I hope # to solve this issue soon. sleep 1 end end end |
#discard_state ⇒ Boolean
Discards any saved state on the current VM. The VM is not destroyed though and can still be started by calling #start.
528 529 530 |
# File 'lib/virtualbox/vm.rb', line 528 def discard_state control(:discard_saved_state, true) end |
#export(filename, options = {}, &block) ⇒ Object
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.
If a block is given to the method, then it will be yielded with the progress of the operation.
438 439 440 441 442 443 |
# File 'lib/virtualbox/vm.rb', line 438 def export(filename, = {}, &block) app = Appliance.new app.path = filename app.add_machine(self, ) app.export(&block) end |
#find_snapshot(name) ⇒ Object
Find a snapshot by name or UUID. This allows you to find a snapshot by a given name, rather than having to resort to traversing the entire tree structure manually.
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
# File 'lib/virtualbox/vm.rb', line 361 def find_snapshot(name) find_helper = lambda do |name, root| return nil if root.nil? return root if root.name == name || root.uuid == name root.children.each do |child| result = find_helper.call(name, child) return result unless result.nil? end nil end find_helper.call(name, root_snapshot) end |
#get_boot_order(interface, key) ⇒ Object
Loads the boot order for this virtual machine. This method should never be called directly. Instead, use the ‘boot_order` attribute to read and modify the boot order.
628 629 630 631 632 633 634 635 |
# File 'lib/virtualbox/vm.rb', line 628 def get_boot_order(interface, key) max_boot = Global.global.system_properties.max_boot_position (1..max_boot).inject([]) do |order, position| order << interface.get_boot_order(position) order end end |
#initialize_attributes(machine) ⇒ Object
252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
# File 'lib/virtualbox/vm.rb', line 252 def initialize_attributes(machine) # Load the interface attributes load_interface_attributes(machine) # Setup the relationships populate_relationships(machine) # 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 |
#pause ⇒ Boolean
Pauses the VM, putting it on hold temporarily. The VM can be resumed again by calling #resume
505 506 507 |
# File 'lib/virtualbox/vm.rb', line 505 def pause control(:pause) end |
#paused? ⇒ Boolean
Returns true if the virtual machine state is paused
607 608 609 |
# File 'lib/virtualbox/vm.rb', line 607 def paused? state == :paused end |
#powered_off? ⇒ Boolean
Returns true if the virtual machine state is powered off
600 601 602 |
# File 'lib/virtualbox/vm.rb', line 600 def powered_off? state == :powered_off end |
#reload ⇒ Object
Reload the model so that all the attributes and relationships are up to date. This method will automatically discard any changes to the VM and any of its relationships.
270 271 272 273 |
# File 'lib/virtualbox/vm.rb', line 270 def reload initialize_attributes(interface) self end |
#resume ⇒ Boolean
Resume a paused VM.
512 513 514 |
# File 'lib/virtualbox/vm.rb', line 512 def resume control(:resume) end |
#root_snapshot ⇒ Snapshot
Returns the root snapshot of this virtual machine. This root snapshot can be used to traverse the tree of snapshots.
350 351 352 353 354 355 356 |
# File 'lib/virtualbox/vm.rb', line 350 def root_snapshot return nil if current_snapshot.nil? current = current_snapshot current = current.parent while current.parent != nil current end |
#running? ⇒ Boolean
Returns true if the virtual machine state is running
593 594 595 |
# File 'lib/virtualbox/vm.rb', line 593 def running? state == :running end |
#save ⇒ Object
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.
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 |
# File 'lib/virtualbox/vm.rb', line 324 def save return false unless valid? raise Exceptions::ReadonlyVMStateException.new("VM must not be in saved state to modify.") if saved? with_open_session do |session| # Use setters to save the attributes on the locked machine and persist # the settings machine = session.machine # Save the boot order save_interface_attribute(:boot_order, machine) # Save all the attributes and relationships save_changed_interface_attributes(machine) # Save relationships, which may open their own sessions if necessary save_relationships end true end |
#save_state ⇒ Boolean
Saves the state of a VM and stops it. The VM can be resumed again by calling “#start” again.
520 521 522 |
# File 'lib/virtualbox/vm.rb', line 520 def save_state control(:save_state) end |
#saved? ⇒ Boolean
Returns true if the virtual machine state is saved
614 615 616 |
# File 'lib/virtualbox/vm.rb', line 614 def saved? state == :saved end |
#set_boot_order(interface, key, value) ⇒ Object
Sets the boot order for this virtual machine. This method should never be called directly. Instead, modify the ‘boot_order` array.
639 640 641 642 643 644 645 646 647 |
# File 'lib/virtualbox/vm.rb', line 639 def set_boot_order(interface, key, value) max_boot = Global.global.system_properties.max_boot_position value = value.dup value.concat(Array.new(max_boot - value.size)) if value.size < max_boot (1..max_boot).each do |position| interface.set_boot_order(position, value[position - 1]) end end |
#shutdown ⇒ Boolean
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.
488 489 490 |
# File 'lib/virtualbox/vm.rb', line 488 def shutdown control(:power_button) end |
#start(mode = "gui") ⇒ Boolean
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.
-
vrdp – The VM will run in the background. No GUI will be present at all.
This method blocks while the external processes are starting.
471 472 473 474 475 476 477 478 479 480 |
# File 'lib/virtualbox/vm.rb', line 471 def start(mode="gui") return false if running? # Open a new remote session, this will automatically start the machine # as well session = Lib.lib.session interface.launch_vm_process(session, mode.to_s, "").wait session.unlock_machine if session.state == :open true end |
#starting? ⇒ Boolean
Returns true if the virtual machine state is starting
586 587 588 |
# File 'lib/virtualbox/vm.rb', line 586 def starting? state == :starting end |
#state(suppress_state_reload = false) ⇒ String
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`.
282 283 284 285 286 287 288 289 |
# File 'lib/virtualbox/vm.rb', line 282 def state(suppress_state_reload=false) if !suppress_state_reload load_interface_attribute(:state, interface) clear_dirty!(:state) end read_attribute(:state) end |
#stop ⇒ Boolean
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
497 498 499 |
# File 'lib/virtualbox/vm.rb', line 497 def stop control(:power_down) end |
#take_snapshot(name, description = "", &block) ⇒ Object
Take a snapshot of the current state of the machine. This method can be called while the VM is running and also while it is powered off. This method will block while the snapshot is being taken.
If a block is given to this method, it will yield with a progress object which can be used to get the progress of the operation.
454 455 456 457 458 |
# File 'lib/virtualbox/vm.rb', line 454 def take_snapshot(name, description="", &block) with_open_session do |session| session.console.take_snapshot(name, description).wait(&block) end end |
#validate ⇒ Object
Validates the virtual machine
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 |
# File 'lib/virtualbox/vm.rb', line 292 def validate super validates_presence_of :name, :os_type_id, :memory_size, :vram_size, :cpu_count validates_numericality_of :memory_balloon_size, :monitor_count validates_inclusion_of :accelerate_3d_enabled, :accelerate_2d_video_enabled, :teleporter_enabled, :in => [true, false] if !errors_on(:name) # Only validate the name if the name has no errors already vms_of_same_name = self.class.find(name) add_error(:name, 'must not be used by another virtual machine.') if vms_of_same_name && vms_of_same_name.uuid != uuid end validates_inclusion_of :os_type_id, :in => VirtualBox::Global.global.lib.virtualbox.guest_os_types.collect { |os| os.id } min_guest_ram, max_guest_ram = Global.global.system_properties.min_guest_ram, Global.global.system_properties.max_guest_ram validates_inclusion_of :memory_size, :in => (min_guest_ram..max_guest_ram), :message => "must be between #{min_guest_ram} and #{max_guest_ram}." validates_inclusion_of :memory_balloon_size, :in => (0..max_guest_ram), :message => "must be between 0 and #{max_guest_ram}." min_guest_vram, max_guest_vram = Global.global.system_properties.min_guest_vram, Global.global.system_properties.max_guest_vram validates_inclusion_of :vram_size, :in => (min_guest_vram..max_guest_vram), :message => "must be between #{min_guest_vram} and #{max_guest_vram}." min_guest_cpu_count, max_guest_cpu_count = Global.global.system_properties.min_guest_cpu_count, Global.global.system_properties.max_guest_cpu_count validates_inclusion_of :cpu_count, :in => (min_guest_cpu_count..max_guest_cpu_count), :message => "must be between #{min_guest_cpu_count} and #{max_guest_cpu_count}." validates_inclusion_of :clipboard_mode, :in => COM::Util.versioned_interface(:ClipboardMode).map validates_inclusion_of :firmware_type, :in => COM::Util.versioned_interface(:FirmwareType).map end |
#with_open_session(mode = :write) ⇒ Object
Opens a direct session with the machine this VM represents and yields the session object to a block. Many of the VirtualBox’s settings can only be modified with an open session on a machine. An open session is similar to a write-lock. Once the session is completed, it must be closed, which this method does as well.
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 |
# File 'lib/virtualbox/vm.rb', line 382 def with_open_session(mode=:write) # Set the session up session = Lib.lib.session close_session = false if session.state != :open # Open up a session for this virtual machine interface.lock_machine(session, mode) # Mark the session to be closed close_session = true end # Yield the block with the session yield session if block_given? # Close the session if close_session # Save these settings only if we're closing and only if the state # is not saved, since that doesn't allow the machine to be saved. session.machine.save_settings if mode == :write && session.machine.state != :saved # Close the session session.unlock_machine end rescue Exception # Close the session so we don't get locked out. We use a rescue block # here instead of an "ensure" since we ONLY want this to occur if an # exception is raised. Otherwise, we may or may not close the session, # depending how deeply nested this call to `with_open_session` is. # (see close_session boolean above) session.unlock_machine if session.state == :open # Reraise the exception, we're not actually catching it to handle it raise end |