virtualbox 0.5.4 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. data/.gitignore +2 -1
  2. data/Gemfile +1 -1
  3. data/Rakefile +1 -1
  4. data/Readme.md +5 -21
  5. data/VERSION +1 -1
  6. data/docs/WhatsNew.md +9 -47
  7. data/lib/virtualbox.rb +7 -30
  8. data/lib/virtualbox/abstract_model.rb +25 -5
  9. data/lib/virtualbox/abstract_model/attributable.rb +5 -1
  10. data/lib/virtualbox/abstract_model/dirty.rb +2 -0
  11. data/lib/virtualbox/abstract_model/interface_attributes.rb +96 -0
  12. data/lib/virtualbox/abstract_model/relatable.rb +19 -8
  13. data/lib/virtualbox/appliance.rb +59 -0
  14. data/lib/virtualbox/audio_adapter.rb +44 -0
  15. data/lib/virtualbox/bios.rb +44 -0
  16. data/lib/virtualbox/com.rb +23 -0
  17. data/lib/virtualbox/com/abstract_enum.rb +42 -0
  18. data/lib/virtualbox/com/abstract_implementer.rb +43 -0
  19. data/lib/virtualbox/com/abstract_interface.rb +165 -0
  20. data/lib/virtualbox/com/ffi/interface.rb +141 -0
  21. data/lib/virtualbox/com/ffi/interfaces.rb +42 -0
  22. data/lib/virtualbox/com/ffi/util.rb +101 -0
  23. data/lib/virtualbox/com/ffi/vboxxpcomc.rb +31 -0
  24. data/lib/virtualbox/com/ffi_interface.rb +65 -0
  25. data/lib/virtualbox/com/implementer/base.rb +52 -0
  26. data/lib/virtualbox/com/implementer/ffi.rb +350 -0
  27. data/lib/virtualbox/com/implementer/mscom.rb +165 -0
  28. data/lib/virtualbox/com/implementer/nil.rb +10 -0
  29. data/lib/virtualbox/com/interface/appliance.rb +20 -0
  30. data/lib/virtualbox/com/interface/audio_adapter.rb +13 -0
  31. data/lib/virtualbox/com/interface/audio_controller_type.rb +9 -0
  32. data/lib/virtualbox/com/interface/audio_driver_type.rb +9 -0
  33. data/lib/virtualbox/com/interface/bios_boot_menu_mode.rb +9 -0
  34. data/lib/virtualbox/com/interface/bios_settings.rb +19 -0
  35. data/lib/virtualbox/com/interface/clipboard_mode.rb +9 -0
  36. data/lib/virtualbox/com/interface/console.rb +48 -0
  37. data/lib/virtualbox/com/interface/cpu_property_type.rb +9 -0
  38. data/lib/virtualbox/com/interface/device_type.rb +9 -0
  39. data/lib/virtualbox/com/interface/dhcp_server.rb +20 -0
  40. data/lib/virtualbox/com/interface/firmware_type.rb +9 -0
  41. data/lib/virtualbox/com/interface/guest_os_type.rb +21 -0
  42. data/lib/virtualbox/com/interface/host.rb +40 -0
  43. data/lib/virtualbox/com/interface/host_network_interface.rb +28 -0
  44. data/lib/virtualbox/com/interface/host_network_interface_medium_type.rb +9 -0
  45. data/lib/virtualbox/com/interface/host_network_interface_status.rb +9 -0
  46. data/lib/virtualbox/com/interface/host_network_interface_type.rb +9 -0
  47. data/lib/virtualbox/com/interface/host_usb_device.rb +11 -0
  48. data/lib/virtualbox/com/interface/host_usb_device_filter.rb +11 -0
  49. data/lib/virtualbox/com/interface/hw_virt_ex_property_type.rb +9 -0
  50. data/lib/virtualbox/com/interface/machine.rb +103 -0
  51. data/lib/virtualbox/com/interface/machine_state.rb +12 -0
  52. data/lib/virtualbox/com/interface/medium.rb +48 -0
  53. data/lib/virtualbox/com/interface/medium_attachment.rb +16 -0
  54. data/lib/virtualbox/com/interface/medium_format.rb +16 -0
  55. data/lib/virtualbox/com/interface/medium_state.rb +9 -0
  56. data/lib/virtualbox/com/interface/medium_type.rb +9 -0
  57. data/lib/virtualbox/com/interface/medium_variant.rb +9 -0
  58. data/lib/virtualbox/com/interface/network_adapter.rb +28 -0
  59. data/lib/virtualbox/com/interface/network_adapter_type.rb +9 -0
  60. data/lib/virtualbox/com/interface/network_attachment_type.rb +9 -0
  61. data/lib/virtualbox/com/interface/nsiexception.rb +21 -0
  62. data/lib/virtualbox/com/interface/nsisupports.rb +13 -0
  63. data/lib/virtualbox/com/interface/parallel_port.rb +15 -0
  64. data/lib/virtualbox/com/interface/port_mode.rb +9 -0
  65. data/lib/virtualbox/com/interface/progress.rb +58 -0
  66. data/lib/virtualbox/com/interface/serial_port.rb +17 -0
  67. data/lib/virtualbox/com/interface/session.rb +16 -0
  68. data/lib/virtualbox/com/interface/session_state.rb +9 -0
  69. data/lib/virtualbox/com/interface/session_type.rb +9 -0
  70. data/lib/virtualbox/com/interface/shared_folder.rb +15 -0
  71. data/lib/virtualbox/com/interface/snapshot.rb +18 -0
  72. data/lib/virtualbox/com/interface/storage_bus.rb +9 -0
  73. data/lib/virtualbox/com/interface/storage_controller.rb +21 -0
  74. data/lib/virtualbox/com/interface/storage_controller_type.rb +9 -0
  75. data/lib/virtualbox/com/interface/system_properties.rb +35 -0
  76. data/lib/virtualbox/com/interface/usb_controller.rb +18 -0
  77. data/lib/virtualbox/com/interface/usb_device.rb +22 -0
  78. data/lib/virtualbox/com/interface/usb_device_filter.rb +21 -0
  79. data/lib/virtualbox/com/interface/usb_device_filter_action.rb +9 -0
  80. data/lib/virtualbox/com/interface/usb_device_state.rb +9 -0
  81. data/lib/virtualbox/com/interface/virtual_box_error_info.rb +15 -0
  82. data/lib/virtualbox/com/interface/virtual_system_description.rb +17 -0
  83. data/lib/virtualbox/com/interface/virtual_system_description_type.rb +12 -0
  84. data/lib/virtualbox/com/interface/virtual_system_description_value_type.rb +9 -0
  85. data/lib/virtualbox/com/interface/virtualbox.rb +54 -0
  86. data/lib/virtualbox/com/interface/vrdp_auth_type.rb +9 -0
  87. data/lib/virtualbox/com/interface/vrdp_server.rb +17 -0
  88. data/lib/virtualbox/com/mscom_interface.rb +22 -0
  89. data/lib/virtualbox/com/util.rb +18 -0
  90. data/lib/virtualbox/dvd.rb +7 -94
  91. data/lib/virtualbox/exceptions.rb +24 -0
  92. data/lib/virtualbox/ext/glob_loader.rb +22 -0
  93. data/lib/virtualbox/ext/logger.rb +38 -0
  94. data/lib/virtualbox/ext/platform.rb +1 -1
  95. data/lib/virtualbox/extra_data.rb +25 -37
  96. data/lib/virtualbox/forwarded_port.rb +35 -13
  97. data/lib/virtualbox/global.rb +22 -80
  98. data/lib/virtualbox/hard_drive.rb +30 -97
  99. data/lib/virtualbox/lib.rb +82 -0
  100. data/lib/virtualbox/media.rb +7 -6
  101. data/lib/virtualbox/medium.rb +138 -0
  102. data/lib/virtualbox/medium_attachment.rb +61 -0
  103. data/lib/virtualbox/network_adapter.rb +134 -0
  104. data/lib/virtualbox/shared_folder.rb +53 -78
  105. data/lib/virtualbox/storage_controller.rb +76 -20
  106. data/lib/virtualbox/system_properties.rb +74 -0
  107. data/lib/virtualbox/usb_controller.rb +55 -0
  108. data/lib/virtualbox/version.rb +15 -0
  109. data/lib/virtualbox/virtual_system_description.rb +47 -0
  110. data/lib/virtualbox/vm.rb +160 -272
  111. data/test/test_helper.rb +0 -108
  112. data/test/virtualbox/abstract_model/attributable_test.rb +7 -1
  113. data/test/virtualbox/abstract_model/dirty_test.rb +1 -1
  114. data/test/virtualbox/abstract_model/interface_attributes_test.rb +169 -0
  115. data/test/virtualbox/abstract_model/relatable_test.rb +20 -0
  116. data/test/virtualbox/abstract_model_test.rb +40 -5
  117. data/test/virtualbox/appliance_test.rb +152 -0
  118. data/test/virtualbox/audio_adapter_test.rb +83 -0
  119. data/test/virtualbox/bios_test.rb +83 -0
  120. data/test/virtualbox/com/abstract_enum_test.rb +48 -0
  121. data/test/virtualbox/com/abstract_implementer_test.rb +39 -0
  122. data/test/virtualbox/com/abstract_interface_test.rb +139 -0
  123. data/test/virtualbox/com/ffi/interface_test.rb +249 -0
  124. data/test/virtualbox/com/ffi/util_test.rb +86 -0
  125. data/test/virtualbox/com/ffi_interface_test.rb +42 -0
  126. data/test/virtualbox/com/implementer/base_test.rb +37 -0
  127. data/test/virtualbox/com/implementer/ffi_test.rb +519 -0
  128. data/test/virtualbox/com/implementer/mscom_test.rb +208 -0
  129. data/test/virtualbox/com/mscom_interface_test.rb +17 -0
  130. data/test/virtualbox/com/util_test.rb +17 -0
  131. data/test/virtualbox/dvd_test.rb +4 -95
  132. data/test/virtualbox/ext/platform_test.rb +8 -0
  133. data/test/virtualbox/extra_data_test.rb +78 -102
  134. data/test/virtualbox/forwarded_port_test.rb +57 -7
  135. data/test/virtualbox/global_test.rb +25 -115
  136. data/test/virtualbox/hard_drive_test.rb +49 -212
  137. data/test/virtualbox/lib_test.rb +93 -0
  138. data/test/virtualbox/medium_attachment_test.rb +147 -0
  139. data/test/virtualbox/medium_test.rb +192 -0
  140. data/test/virtualbox/network_adapter_test.rb +160 -0
  141. data/test/virtualbox/shared_folder_test.rb +144 -160
  142. data/test/virtualbox/storage_controller_test.rb +166 -45
  143. data/test/virtualbox/system_properties_test.rb +87 -0
  144. data/test/virtualbox/usb_controller_test.rb +104 -0
  145. data/test/virtualbox/version_test.rb +34 -0
  146. data/test/virtualbox/virtual_system_description_test.rb +61 -0
  147. data/test/virtualbox/vm_test.rb +288 -322
  148. data/test/virtualbox_test.rb +1 -9
  149. data/virtualbox.gemspec +139 -23
  150. metadata +143 -27
  151. data/lib/virtualbox/attached_device.rb +0 -249
  152. data/lib/virtualbox/command.rb +0 -109
  153. data/lib/virtualbox/image.rb +0 -137
  154. data/lib/virtualbox/nic.rb +0 -111
  155. data/lib/virtualbox/system_property.rb +0 -55
  156. data/lib/virtualbox/usb.rb +0 -72
  157. data/test/virtualbox/attached_device_test.rb +0 -303
  158. data/test/virtualbox/command_test.rb +0 -152
  159. data/test/virtualbox/image_test.rb +0 -190
  160. data/test/virtualbox/nic_test.rb +0 -76
  161. data/test/virtualbox/system_property_test.rb +0 -71
  162. data/test/virtualbox/usb_test.rb +0 -35
@@ -0,0 +1,9 @@
1
+ module VirtualBox
2
+ module COM
3
+ module Interface
4
+ class VRDPAuthType < AbstractEnum
5
+ map [:null, :external, :guest]
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ module VirtualBox
2
+ module COM
3
+ module Interface
4
+ class VRDPServer < AbstractInterface
5
+ IID = "72e671bc-1712-4052-ad6b-e45e76d9d3e4"
6
+
7
+ property :enabled, T_BOOL
8
+ property :ports, WSTRING
9
+ property :net_address, WSTRING
10
+ property :auth_type, :VRDPAuthType
11
+ property :auth_timeout, T_UINT32
12
+ property :allow_multi_connection, T_BOOL
13
+ property :reuse_single_connection, T_BOOL
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,22 @@
1
+ module VirtualBox
2
+ module COM
3
+ class MSCOMInterface
4
+ # The VirtualBox and Session interfaces, both of which are extremely
5
+ # important in interfacing with the VirtualBox API. Once these have been
6
+ # initialized, all other parts of the API can be accessed via these
7
+ # instances.
8
+ attr_reader :virtualbox
9
+ attr_reader :session
10
+
11
+ def initialize
12
+ initialize_mscom
13
+ end
14
+
15
+ def initialize_mscom
16
+ require 'win32ole'
17
+ @virtualbox = Interface::VirtualBox.new(Implementer::MSCOM, self, WIN32OLE.new("VirtualBox.VirtualBox"))
18
+ @session = Interface::Session.new(Implementer::MSCOM, self, WIN32OLE.new("VirtualBox.Session"))
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ module VirtualBox
2
+ module COM
3
+ class Util
4
+ class <<self
5
+ # Returns a boolean true/false whether the given COM interface
6
+ # exists.
7
+ #
8
+ # @return [Boolean]
9
+ def interface?(name)
10
+ COM::Interface.const_get(name.to_sym)
11
+ true
12
+ rescue NameError
13
+ false
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,6 +1,8 @@
1
1
  module VirtualBox
2
2
  # Represents a DVD image stored by VirtualBox. These DVD images can be
3
- # mounted onto virtual machines.
3
+ # mounted onto virtual machines. Because DVD just inherits from {Medium},
4
+ # it also inherits all methods and attributes which are on {Medium}. For more
5
+ # attributes, the ability to destroy, etc, please view {Medium}.
4
6
  #
5
7
  # # Finding all DVDs
6
8
  #
@@ -9,106 +11,17 @@ module VirtualBox
9
11
  #
10
12
  # DVD.all
11
13
  #
12
- # # Empty Drives
13
- #
14
- # Sometimes it is useful to have an empty drive. This is the case where you
15
- # may have a DVD drive but it has no disk in it. To create an {AttachedDevice},
16
- # an image _must_ be specified, and an empty drive is a simple option. Creating
17
- # an empty drive is simple:
18
- #
19
- # DVD.empty_drive
20
- #
21
- class DVD < Image
14
+ class DVD < Medium
22
15
  class <<self
23
16
  # Returns an array of all available DVDs as DVD objects
24
17
  def all
25
18
  Global.global.media.dvds
26
19
  end
27
20
 
28
- # Returns an array of all available DVDs by parsing the VBoxManage
29
- # output
30
- def all_from_command
31
- raw = Command.vboxmanage("list", "dvds")
32
- parse_raw(raw)
33
- end
34
-
35
- # Returns an empty drive. This is useful for creating new
36
- # or modifyingn existing {AttachedDevice} objects and
37
- # attaching an empty drive to them.
38
- #
39
- # @return [DVD]
40
- def empty_drive
41
- new(:empty_drive)
42
- end
43
-
44
- def populate_relationship(caller, doc)
45
- result = Proxies::Collection.new(caller)
46
-
47
- # TODO: Location in this case is relative the vboxconfig path.
48
- # We need to expand it. Also, size/accessible is not available.
49
- doc.css("MediaRegistry DVDImages Image").each do |hd_node|
50
- data = {}
51
- hd_node.attributes.each do |key, value|
52
- data[key.downcase.to_sym] = value.to_s
53
- end
54
-
55
- # Massage UUID to proper format
56
- data[:uuid] = data[:uuid][1..-2]
57
-
58
- result << new(data)
59
- end
60
-
61
- result
62
- end
63
- end
64
-
65
- def initialize(*args)
66
- if args.length == 1 && args[0] == :empty_drive
67
- @empty_drive = true
68
- else
69
- super
21
+ # Override of {Medium.device_type}.
22
+ def device_type
23
+ :dvd
70
24
  end
71
25
  end
72
-
73
- # Override of {Image#empty_drive?}. This will only be true if
74
- # the DVD was created with {DVD.empty_drive}.
75
- #
76
- # @return [Boolean]
77
- def empty_drive?
78
- @empty_drive || false
79
- end
80
-
81
- # Override of {Image#image_type}.
82
- def image_type
83
- "dvddrive"
84
- end
85
-
86
- # Deletes the DVD from VBox managed list and also from disk.
87
- # This method will fail if the disk is currently mounted to any
88
- # virtual machine. This method also does nothing for empty drives
89
- # (see {DVD.empty_drive}) and will return false automatically in
90
- # that case.
91
- #
92
- # @param [Boolean] raise_errors If true, {Exceptions::CommandFailedException}
93
- # will be raised if the command failed.
94
- # @return [Boolean] True if command was successful, false otherwise.
95
- def destroy(raise_errors=false)
96
- return false if empty_drive?
97
-
98
- Command.vboxmanage("closemedium", "dvd", uuid, "--delete")
99
- Global.reload!
100
- true
101
- rescue Exceptions::CommandFailedException
102
- raise if raise_errors
103
- false
104
- end
105
-
106
- # Lazy load the lazy attributes for this model.
107
- def load_attribute(name)
108
- # Since the lazy attributes are related, we just load them all at once
109
- loaded_image = self.class.all_from_command.detect { |o| o.uuid == self.uuid }
110
-
111
- write_attribute(:accessible, loaded_image.accessible)
112
- end
113
26
  end
114
27
  end
@@ -9,5 +9,29 @@ module VirtualBox
9
9
  class InvalidRelationshipObjectException < Exception; end
10
10
  class NonSettableRelationshipException < Exception; end
11
11
  class ValidationFailedException < Exception; end
12
+
13
+ class FFIException < Exception
14
+ attr_accessor :data
15
+
16
+ def initialize(data={})
17
+ @data = data
18
+ super("Error in API call to #{data[:function]}: #{data[:result_code]}")
19
+ end
20
+ end
21
+
22
+ # FFI Exceptions, these exceptions are only raised on *nix machines
23
+ # when some error occurs in the foreign function interface.
24
+ class ObjectNotFoundException < FFIException; end
25
+ class InvalidVMStateException < FFIException; end
26
+ class VMErrorException < FFIException; end
27
+ class FileErrorException < FFIException; end
28
+ class SubsystemException < FFIException; end
29
+ class PDMException < FFIException; end
30
+ class InvalidObjectStateException < FFIException; end
31
+ class HostErrorException < FFIException; end
32
+ class NotSupportedException < FFIException; end
33
+ class XMLErrorException < FFIException; end
34
+ class InvalidSessionStateException < FFIException; end
35
+ class ObjectInUseException < FFIException; end
12
36
  end
13
37
  end
@@ -0,0 +1,22 @@
1
+ module VirtualBox
2
+ # Eases the processes of loading specific files then globbing
3
+ # the rest from a specified directory.
4
+ module GlobLoader
5
+ # Glob requires all ruby files in a directory, optionally loading select
6
+ # files initially (since others may depend on them).
7
+ #
8
+ # @param [String] dir The directory to glob
9
+ # @param [Array<String>] initial_files Initial files (relative to `dir`)
10
+ # to load
11
+ def self.glob_require(dir, initial_files=[])
12
+ initial_files.each do |file|
13
+ require File.expand_path(file, dir)
14
+ end
15
+
16
+ # Glob require the rest
17
+ Dir[File.join(dir, "**", "*.rb")].each do |f|
18
+ require File.expand_path(f)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,38 @@
1
+ require 'logger'
2
+
3
+ module VirtualBox
4
+ # Provides logger functionality for VirtualBox. This class is available on most
5
+ # VirtualBox classes through mixins. To access the logger, simply call the {logger}
6
+ # method. This returns a standard Ruby logger which can be modified.
7
+ module Logger
8
+ @@logger = nil
9
+ @@logger_output = nil
10
+
11
+ # Make the logger available both on a class and instance level
12
+ # once included.
13
+ def self.included(base)
14
+ base.extend self
15
+ end
16
+
17
+ # Sets up the output stream for the logger. This should be called before any
18
+ # calls to {logger}. If the logger has already been instantiated, then a new
19
+ # logger will be created on the next call with the new output setup.
20
+ def logger_output=(value)
21
+ @@logger_output = value
22
+ @@logger = nil
23
+ end
24
+
25
+ # Accesses the logger. If logger output is specified and this is the first load,
26
+ # then the logger will be properly setup to point to that output. Logging
27
+ # levels should also be set once the logger is created. The logger is a standard
28
+ # Ruby `Logger`.
29
+ #
30
+ # The VirtualBox gem can get very verybose very quickly, so choose a log level
31
+ # which suits the granularity needed.
32
+ #
33
+ # @return [Logger]
34
+ def logger
35
+ @@logger ||= ::Logger.new(@@logger_output)
36
+ end
37
+ end
38
+ end
@@ -6,7 +6,7 @@ module VirtualBox
6
6
  end
7
7
 
8
8
  def windows?
9
- platform.include?("mswin") || platform.include?("mingw")
9
+ platform.include?("mswin") || platform.include?("mingw") || platform.include?("cygwin")
10
10
  end
11
11
 
12
12
  def linux?
@@ -35,6 +35,7 @@ module VirtualBox
35
35
  include AbstractModel::Dirty
36
36
 
37
37
  attr_accessor :parent
38
+ attr_reader :interface
38
39
 
39
40
  @@global_data = nil
40
41
 
@@ -57,11 +58,11 @@ module VirtualBox
57
58
  # **This method typically won't be used except internally.**
58
59
  #
59
60
  # @return [Array<ExtraData>]
60
- def populate_relationship(caller, doc)
61
- data = new(caller)
61
+ def populate_relationship(caller, interface)
62
+ data = new(caller, interface)
62
63
 
63
- doc.css("ExtraData ExtraDataItem").each do |extradata|
64
- data[extradata["name"].to_s] = extradata["value"].to_s
64
+ interface.get_extra_data_keys.each do |key|
65
+ data[key] = interface.get_extra_data(key)
65
66
  end
66
67
 
67
68
  data.clear_dirty!
@@ -80,8 +81,9 @@ module VirtualBox
80
81
  # Initializes an extra data object.
81
82
  #
82
83
  # @param [Hash] data Initial attributes to populate.
83
- def initialize(parent=nil)
84
- @parent = parent || "global"
84
+ def initialize(parent, interface)
85
+ @parent = parent
86
+ @interface = interface
85
87
  end
86
88
 
87
89
  # Set an extradata key-value pair. Overrides ruby hash implementation
@@ -91,19 +93,6 @@ module VirtualBox
91
93
  super
92
94
  end
93
95
 
94
- # Special accessor for parent name attribute. This returns
95
- # either the parent name if its a VM object, otherwise
96
- # just returns the default.
97
- #
98
- # @return [String]
99
- def parent_name
100
- if parent.is_a?(VM)
101
- parent.name
102
- else
103
- parent
104
- end
105
- end
106
-
107
96
  # Saves extra data. This method does the same thing for both new
108
97
  # and existing extra data, since virtualbox will overwrite old data or
109
98
  # create it if it doesn't exist.
@@ -111,30 +100,29 @@ module VirtualBox
111
100
  # @param [Boolean] raise_errors If true, {Exceptions::CommandFailedException}
112
101
  # will be raised if the command failed.
113
102
  # @return [Boolean] True if command was successful, false otherwise.
114
- def save(raise_errors=false)
103
+ def save
115
104
  changes.each do |key, value|
116
- Command.vboxmanage("setextradata", parent_name, key, value[1])
105
+ interface.set_extra_data(key.to_s, value[1].to_s)
106
+
117
107
  clear_dirty!(key)
118
- end
119
108
 
120
- true
121
- rescue Exceptions::CommandFailedException
122
- raise if raise_errors
123
- false
109
+ if value[1].nil?
110
+ # Remove the key from the hash altogether
111
+ hash_delete(key.to_s)
112
+ end
113
+ end
124
114
  end
125
115
 
126
- # Deletes the extra data.
116
+ # Alias away the old delete method so its still accessible somehow
117
+ alias :hash_delete :delete
118
+
119
+ # Deletes the specified extra data. This method is deferred, meaning that
120
+ # although the key itself is marked to be deleted (by setting the value
121
+ # to nil), the deletion itself does not occur until {#save} is called.
127
122
  #
128
- # @param [Boolean] raise_errors If true, {Exceptions::CommandFailedException}
129
- # will be raised if the command failed.
130
- # @return [Boolean] True if command was successful, false otherwise.
131
- def delete(key, raise_errors=false)
132
- Command.vboxmanage("setextradata", parent_name, key)
133
- super(key)
134
- true
135
- rescue Exceptions::CommandFailedException
136
- raise if raise_errors
137
- false
123
+ # @param [String] key The extra data key to delete
124
+ def delete(key)
125
+ self[key] = nil
138
126
  end
139
127
  end
140
128
  end
@@ -132,25 +132,47 @@ module VirtualBox
132
132
  validates_presence_of :hostport
133
133
  end
134
134
 
135
+ # Retrieves the device for the forwarded port. This tries to "do the
136
+ # right thing" depending on the first NIC of the VM parent by either
137
+ # setting the forwarded port type to "pcnet" or "e1000." If the device
138
+ # was already set manually, this method will simply return that value
139
+ # instead.
140
+ #
141
+ # @return [String] Device type for the forwarded port
142
+ def device
143
+ # Return the current or default value if it is:
144
+ # * an existing record, since it was already mucked with, no need to
145
+ # modify it again
146
+ # * device setting changed, since we should return what the user set
147
+ # it to
148
+ # * If the parent is nil, since we can't infer the type without a parent
149
+ return read_attribute(:device) if !new_record? || device_changed? || parent.nil?
150
+
151
+ device_map = {
152
+ :Am79C970A => "pcnet",
153
+ :Am79C973 => "pcnet",
154
+ :I82540EM => "e1000",
155
+ :I82543GC => "e1000",
156
+ :I82545EM => "e1000"
157
+ }
158
+
159
+ return device_map[parent.network_adapters[0].adapter_type]
160
+ end
161
+
135
162
  # Saves the forwarded port.
136
163
  #
137
- # @param [Boolean] raise_errors If true, {Exceptions::CommandFailedException}
138
- # will be raised if the command failed.
139
164
  # @return [Boolean] True if command was successful, false otherwise.
140
- def save(raise_errors=false)
165
+ def save
141
166
  return true if !new_record? && !changed?
142
167
 
143
- if !valid?
144
- raise Exceptions::ValidationFailedException.new(errors) if raise_errors
145
- return false
146
- end
168
+ raise Exceptions::ValidationFailedException.new(errors) if !valid?
147
169
 
148
- destroy(raise_errors) if name_changed?
170
+ destroy if name_changed?
149
171
 
150
172
  parent.extra_data["#{key_prefix}Protocol"] = protocol
151
173
  parent.extra_data["#{key_prefix}GuestPort"] = guestport
152
174
  parent.extra_data["#{key_prefix}HostPort"] = hostport
153
- result = parent.extra_data.save(raise_errors)
175
+ result = parent.extra_data.save
154
176
 
155
177
  clear_dirty!
156
178
  existing_record!
@@ -163,13 +185,13 @@ module VirtualBox
163
185
  # @param [Boolean] raise_errors If true, {Exceptions::CommandFailedException}
164
186
  # will be raised if the command failed.
165
187
  # @return [Boolean] True if command was successful, false otherwise.
166
- def destroy(raise_errors=false)
188
+ def destroy
167
189
  results = []
168
190
 
169
191
  if !new_record?
170
- results << parent.extra_data.delete("#{key_prefix(true)}Protocol", raise_errors)
171
- results << parent.extra_data.delete("#{key_prefix(true)}GuestPort", raise_errors)
172
- results << parent.extra_data.delete("#{key_prefix(true)}HostPort", raise_errors)
192
+ results << parent.extra_data.delete("#{key_prefix(true)}Protocol")
193
+ results << parent.extra_data.delete("#{key_prefix(true)}GuestPort")
194
+ results << parent.extra_data.delete("#{key_prefix(true)}HostPort")
173
195
 
174
196
  new_record!
175
197
  end