virtualbox 0.4.1 → 0.4.2

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 (44) hide show
  1. data/Readme.md +9 -9
  2. data/VERSION +1 -1
  3. data/docs/GettingStarted.md +11 -11
  4. data/docs/WhatsNew.md +1 -1
  5. data/lib/virtualbox.rb +10 -1
  6. data/lib/virtualbox/abstract_model.rb +47 -29
  7. data/lib/virtualbox/abstract_model/attributable.rb +16 -16
  8. data/lib/virtualbox/abstract_model/dirty.rb +10 -10
  9. data/lib/virtualbox/abstract_model/relatable.rb +22 -22
  10. data/lib/virtualbox/abstract_model/validatable.rb +4 -4
  11. data/lib/virtualbox/attached_device.rb +23 -23
  12. data/lib/virtualbox/command.rb +9 -9
  13. data/lib/virtualbox/dvd.rb +7 -7
  14. data/lib/virtualbox/ext/subclass_listing.rb +1 -1
  15. data/lib/virtualbox/extra_data.rb +17 -17
  16. data/lib/virtualbox/forwarded_port.rb +23 -23
  17. data/lib/virtualbox/hard_drive.rb +27 -27
  18. data/lib/virtualbox/image.rb +25 -18
  19. data/lib/virtualbox/nic.rb +22 -22
  20. data/lib/virtualbox/proxies/collection.rb +4 -4
  21. data/lib/virtualbox/shared_folder.rb +25 -25
  22. data/lib/virtualbox/storage_controller.rb +16 -16
  23. data/lib/virtualbox/vm.rb +95 -42
  24. data/test/virtualbox/abstract_model/attributable_test.rb +28 -28
  25. data/test/virtualbox/abstract_model/dirty_test.rb +13 -13
  26. data/test/virtualbox/abstract_model/relatable_test.rb +36 -36
  27. data/test/virtualbox/abstract_model/validatable_test.rb +22 -22
  28. data/test/virtualbox/abstract_model_test.rb +46 -36
  29. data/test/virtualbox/attached_device_test.rb +47 -47
  30. data/test/virtualbox/command_test.rb +12 -12
  31. data/test/virtualbox/dvd_test.rb +15 -19
  32. data/test/virtualbox/ext/subclass_listing_test.rb +2 -2
  33. data/test/virtualbox/extra_data_test.rb +37 -37
  34. data/test/virtualbox/forwarded_port_test.rb +31 -31
  35. data/test/virtualbox/hard_drive_test.rb +40 -48
  36. data/test/virtualbox/image_test.rb +36 -33
  37. data/test/virtualbox/nic_test.rb +22 -22
  38. data/test/virtualbox/proxies/collection_test.rb +6 -6
  39. data/test/virtualbox/shared_folder_test.rb +36 -36
  40. data/test/virtualbox/storage_controller_test.rb +14 -14
  41. data/test/virtualbox/vm_test.rb +121 -70
  42. data/test/virtualbox_test.rb +19 -0
  43. data/virtualbox.gemspec +5 -3
  44. metadata +4 -2
@@ -16,11 +16,11 @@ module VirtualBox
16
16
  # @abstract
17
17
  class Image < AbstractModel
18
18
  include SubclassListing
19
-
19
+
20
20
  attribute :uuid, :readonly => true
21
21
  attribute :location
22
22
  attribute :accessible, :readonly => true
23
-
23
+
24
24
  class <<self
25
25
  # Parses the raw output of virtualbox into image objects. Used by
26
26
  # subclasses to parse the output of their respective listing functions.
@@ -31,7 +31,7 @@ module VirtualBox
31
31
  def parse_raw(raw)
32
32
  parse_blocks(raw).collect { |v| new(v) }
33
33
  end
34
-
34
+
35
35
  # Parses the blocks of the output from virtualbox. VirtualBox outputs
36
36
  # image listing in "blocks" which are then parsed down to their attributes.
37
37
  #
@@ -41,8 +41,8 @@ module VirtualBox
41
41
  def parse_blocks(raw)
42
42
  raw.split(/\n\n/).collect { |v| parse_block(v.chomp) }.compact
43
43
  end
44
-
45
- # Parses a single block from VirtualBox output.
44
+
45
+ # Parses a single block from VirtualBox output.
46
46
  #
47
47
  # **This method typically won't be used except internally.**
48
48
  #
@@ -57,14 +57,14 @@ module VirtualBox
57
57
  next unless line =~ /^(.+?):\s+(.+?)$/
58
58
  hd[$1.downcase.to_sym] = $2.to_s
59
59
  end
60
-
60
+
61
61
  # If we don't have a location but have a path, use that, as they
62
62
  # are equivalent but not consistent.
63
63
  hd[:location] = hd[:path] if hd.has_key?(:path)
64
-
64
+
65
65
  hd
66
66
  end
67
-
67
+
68
68
  # Searches the subclasses which implement all method, searching for
69
69
  # a matching UUID and returning that as the relationship.
70
70
  #
@@ -74,17 +74,17 @@ module VirtualBox
74
74
  def populate_relationship(caller, data)
75
75
  return DVD.empty_drive if data[:medium] == "emptydrive"
76
76
  return nil if data[:uuid].nil?
77
-
77
+
78
78
  subclasses.each do |subclass|
79
79
  next unless subclass.respond_to?(:all)
80
-
80
+
81
81
  matching = subclass.all.find { |obj| obj.uuid == data[:uuid] }
82
82
  return matching unless matching.nil?
83
83
  end
84
-
84
+
85
85
  nil
86
86
  end
87
-
87
+
88
88
  # Sets an image onto a relationship and/or removes it from a
89
89
  # relationship. This method is automatically called by {Relatable}.
90
90
  #
@@ -95,29 +95,29 @@ module VirtualBox
95
95
  # We don't actually destroy any images using this method,
96
96
  # so just return the new value as long as its a valid object
97
97
  raise Exceptions::InvalidRelationshipObjectException.new if new_value && !new_value.is_a?(Image)
98
-
98
+
99
99
  return new_value
100
100
  end
101
101
  end
102
-
102
+
103
103
  # **This should never be called directly on {Image}.** Instead, initialize
104
104
  # one of the subclasses.
105
105
  def initialize(info=nil)
106
106
  super()
107
-
107
+
108
108
  populate_attributes(info) if info
109
109
  end
110
-
110
+
111
111
  # The image type as a string for the virtualbox command line. This
112
112
  # method should be overridden by any subclass and is expected to
113
- # return the type which is used in command line parameters for
113
+ # return the type which is used in command line parameters for
114
114
  # attaching to storage controllers.
115
115
  #
116
116
  # @return [String]
117
117
  def image_type
118
118
  raise "This must be implemented by any subclasses"
119
119
  end
120
-
120
+
121
121
  # Returns boolean showing if empty drive or not. This method should be
122
122
  # overriden by any subclass and is expected to return true of false
123
123
  # showing if this image represents an empty drive of whatever type
@@ -127,5 +127,12 @@ module VirtualBox
127
127
  def empty_drive?
128
128
  false
129
129
  end
130
+
131
+ # Returns the basename of the images location (the file name +extension)
132
+ #
133
+ # @return [String]
134
+ def filename
135
+ File.basename(location.to_s)
136
+ end
130
137
  end
131
138
  end
@@ -18,7 +18,7 @@ module VirtualBox
18
18
  #
19
19
  # Properties of the model are exposed using standard ruby instance
20
20
  # methods which are generated on the fly. Because of this, they are not listed
21
- # below as available instance methods.
21
+ # below as available instance methods.
22
22
  #
23
23
  # These attributes can be accessed and modified via standard ruby-style
24
24
  # `instance.attribute` and `instance.attribute=` methods. The attributes are
@@ -39,7 +39,7 @@ module VirtualBox
39
39
  attribute :macaddress
40
40
  attribute :cableconnected
41
41
  attribute :bridgeadapter
42
-
42
+
43
43
  class <<self
44
44
  # Retrives the Nic data from human-readable vminfo. Since some data about
45
45
  # nics is not exposed in the machine-readable virtual machine info, some
@@ -51,16 +51,16 @@ module VirtualBox
51
51
  # @return [Hash]
52
52
  def nic_data(vmname)
53
53
  raw = VM.human_info(vmname)
54
-
54
+
55
55
  # Complicated chain of methods just maps parse_nic over each line,
56
56
  # removing invalid ones, and then converting it into a single hash.
57
57
  raw.split("\n").collect { |v| parse_nic(v) }.compact.inject({}) do |acc, obj|
58
58
  acc.merge({ obj[0] => obj[1] })
59
59
  end
60
60
  end
61
-
61
+
62
62
  # Parses nic data out of a single line of the human readable output
63
- # of vm info.
63
+ # of vm info.
64
64
  #
65
65
  # **This method typically won't be used except internally.**
66
66
  #
@@ -68,18 +68,18 @@ module VirtualBox
68
68
  def parse_nic(raw)
69
69
  return unless raw =~ /^NIC\s(\d):\s+(.+?)$/
70
70
  return if $2.to_s.strip == "disabled"
71
-
71
+
72
72
  data = {}
73
73
  nicname = "nic#{$1}"
74
74
  $2.to_s.split(/,\s+/).each do |raw_property|
75
75
  next unless raw_property =~ /^(.+?):\s+(.+?)$/
76
-
76
+
77
77
  data[$1.downcase.to_sym] = $2.to_s
78
78
  end
79
-
79
+
80
80
  return nicname.to_sym, data
81
81
  end
82
-
82
+
83
83
  # Populates the nic relationship for anything which is related to it.
84
84
  #
85
85
  # **This method typically won't be used except internally.**
@@ -87,25 +87,25 @@ module VirtualBox
87
87
  # @return [Array<Nic>]
88
88
  def populate_relationship(caller, data)
89
89
  nic_data = nic_data(caller.name)
90
-
90
+
91
91
  relation = []
92
-
92
+
93
93
  counter = 1
94
94
  loop do
95
95
  break unless data["nic#{counter}".to_sym]
96
-
96
+
97
97
  nictype = nic_data["nic#{counter}".to_sym][:type] rescue nil
98
-
98
+
99
99
  nic = new(counter, caller, data.merge({
100
100
  "nictype#{counter}".to_sym => nictype
101
101
  }))
102
102
  relation.push(nic)
103
103
  counter += 1
104
104
  end
105
-
105
+
106
106
  relation
107
107
  end
108
-
108
+
109
109
  # Saves the relationship. This simply calls {#save} on every
110
110
  # member of the relationship.
111
111
  #
@@ -117,32 +117,32 @@ module VirtualBox
117
117
  end
118
118
  end
119
119
  end
120
-
121
- # Since there is currently no way to create a _new_ nic, this is
120
+
121
+ # Since there is currently no way to create a _new_ nic, this is
122
122
  # only used internally. Developers should NOT try to initialize their
123
123
  # own nic objects.
124
124
  def initialize(index, caller, data)
125
125
  super()
126
-
126
+
127
127
  @index = index
128
-
128
+
129
129
  # Setup the index specific attributes
130
130
  populate_data = {}
131
131
  self.class.attributes.each do |name, options|
132
132
  value = data["#{name}#{index}".to_sym]
133
133
  populate_data[name] = value
134
134
  end
135
-
135
+
136
136
  populate_attributes(populate_data.merge({
137
137
  :parent => caller
138
138
  }))
139
139
  end
140
-
140
+
141
141
  # Saves a single attribute of the nic. This method is automatically
142
142
  # called on {#save}.
143
143
  #
144
144
  # **This method typically won't be used except internally.**
145
- def save_attribute(key, value, vmname)
145
+ def save_attribute(key, value, vmname)
146
146
  Command.vboxmanage("modifyvm #{Command.shell_escape(vmname)} --#{key}#{@index} #{Command.shell_escape(value)}")
147
147
  super
148
148
  end
@@ -5,21 +5,21 @@ module VirtualBox
5
5
  class Collection < Array
6
6
  def initialize(parent)
7
7
  super()
8
-
8
+
9
9
  @parent = parent
10
10
  end
11
-
11
+
12
12
  def <<(item)
13
13
  item.added_to_relationship(@parent) if item.respond_to?(:added_to_relationship)
14
14
  push(item)
15
15
  end
16
-
16
+
17
17
  def clear
18
18
  each do |item|
19
19
  delete(item)
20
20
  end
21
21
  end
22
-
22
+
23
23
  def delete(item)
24
24
  return unless super
25
25
  item.removed_from_relationship(@parent) if item.respond_to?(:removed_from_relationship)
@@ -2,7 +2,7 @@ module VirtualBox
2
2
  # Represents a shared folder in VirtualBox. In VirtualBox, shared folders are a
3
3
  # method for basically "symlinking" a folder on the guest system to a folder which
4
4
  # exists on the host system. This allows for sharing of files across the virtual
5
- # machine.
5
+ # machine.
6
6
  #
7
7
  # **Note:** Whenever modifying shared folders on a VM, the changes won't take
8
8
  # effect until a _cold reboot_ occurs. This means actually closing the virtual
@@ -36,7 +36,7 @@ module VirtualBox
36
36
  # a local variable named `vm`.**
37
37
  #
38
38
  # Nothing tricky here: You treat existing shared folder objects just as if they
39
- # were new ones. Assign a new name and/or a new path, then save.
39
+ # were new ones. Assign a new name and/or a new path, then save.
40
40
  #
41
41
  # folder = vm.shared_folders.first
42
42
  # folder.name = "rufus"
@@ -65,7 +65,7 @@ module VirtualBox
65
65
  #
66
66
  # Properties of the model are exposed using standard ruby instance
67
67
  # methods which are generated on the fly. Because of this, they are not listed
68
- # below as available instance methods.
68
+ # below as available instance methods.
69
69
  #
70
70
  # These attributes can be accessed and modified via standard ruby-style
71
71
  # `instance.attribute` and `instance.attribute=` methods. The attributes are
@@ -88,7 +88,7 @@ module VirtualBox
88
88
  attribute :parent, :readonly => :readonly
89
89
  attribute :name, :populate_key => "SharedFolderNameMachineMapping"
90
90
  attribute :hostpath, :populate_key => "SharedFolderPathMachineMapping"
91
-
91
+
92
92
  class <<self
93
93
  # Populates the shared folder relationship for anything which is related to it.
94
94
  #
@@ -97,19 +97,19 @@ module VirtualBox
97
97
  # @return [Array<SharedFolder>]
98
98
  def populate_relationship(caller, data)
99
99
  relation = Proxies::Collection.new(caller)
100
-
100
+
101
101
  counter = 1
102
102
  loop do
103
103
  break unless data["SharedFolderNameMachineMapping#{counter}".downcase.to_sym]
104
-
104
+
105
105
  folder = new(counter, caller, data)
106
106
  relation.push(folder)
107
107
  counter += 1
108
108
  end
109
-
109
+
110
110
  relation
111
111
  end
112
-
112
+
113
113
  # Saves the relationship. This simply calls {#save} on every
114
114
  # member of the relationship.
115
115
  #
@@ -121,7 +121,7 @@ module VirtualBox
121
121
  end
122
122
  end
123
123
  end
124
-
124
+
125
125
  # @overload initialize(data={})
126
126
  # Creates a new SharedFolder which is a new record. This
127
127
  # should be attached to a VM and saved.
@@ -136,7 +136,7 @@ module VirtualBox
136
136
  # to extract the relationship data.
137
137
  def initialize(*args)
138
138
  super()
139
-
139
+
140
140
  if args.length == 3
141
141
  initialize_for_relationship(*args)
142
142
  elsif args.length == 1
@@ -147,7 +147,7 @@ module VirtualBox
147
147
  raise NoMethodError.new
148
148
  end
149
149
  end
150
-
150
+
151
151
  # Initializes the record for use in a relationship. This
152
152
  # is automatically called by {#initialize} if it has three
153
153
  # parameters.
@@ -161,12 +161,12 @@ module VirtualBox
161
161
  value = data["#{key}#{index}".downcase.to_sym]
162
162
  populate_data[key] = value
163
163
  end
164
-
164
+
165
165
  populate_attributes(populate_data.merge({
166
166
  :parent => caller
167
167
  }))
168
168
  end
169
-
169
+
170
170
  # Initializes a record with initial data but keeping it a "new
171
171
  # record." This is called automatically if {#initialize} is given
172
172
  # only a single parameter. View {#initialize} for documentation.
@@ -174,52 +174,52 @@ module VirtualBox
174
174
  self.class.attributes.each do |name, options|
175
175
  data[options[:populate_key]] = data[name]
176
176
  end
177
-
177
+
178
178
  populate_attributes(data)
179
179
  new_record!
180
180
  end
181
-
181
+
182
182
  # Validates a shared folder.
183
183
  def validate
184
184
  super
185
-
185
+
186
186
  validates_presence_of :parent
187
187
  validates_presence_of :name
188
188
  validates_presence_of :hostpath
189
189
  end
190
-
190
+
191
191
  # Saves or creates a shared folder.
192
192
  #
193
193
  # @param [Boolean] raise_errors If true, {Exceptions::CommandFailedException}
194
194
  # will be raised if the command failed.
195
195
  # @return [Boolean] True if command was successful, false otherwise.
196
- def save(raise_errors=false)
196
+ def save(raise_errors=false)
197
197
  return true unless changed?
198
-
198
+
199
199
  if !valid?
200
200
  raise Exceptions::ValidationFailedException.new(errors) if raise_errors
201
201
  return false
202
202
  end
203
-
203
+
204
204
  # If this isn't a new record, we destroy it first
205
205
  destroy(raise_errors) if !new_record?
206
-
206
+
207
207
  Command.vboxmanage("sharedfolder add #{Command.shell_escape(parent.name)} --name #{Command.shell_escape(name)} --hostpath #{Command.shell_escape(hostpath)}")
208
208
  existing_record!
209
209
  clear_dirty!
210
-
210
+
211
211
  true
212
212
  rescue Exceptions::CommandFailedException
213
213
  raise if raise_errors
214
214
  false
215
215
  end
216
-
216
+
217
217
  # Relationship callback when added to a collection. This is automatically
218
218
  # called by any relationship collection when this object is added.
219
219
  def added_to_relationship(parent)
220
220
  write_attribute(:parent, parent)
221
221
  end
222
-
222
+
223
223
  # Destroys the shared folder. This doesn't actually delete the folder
224
224
  # from the host system. Instead, it simply removes the mapping to the
225
225
  # virtual machine, meaning it will no longer be possible to mount it
@@ -232,7 +232,7 @@ module VirtualBox
232
232
  # If the name changed, we have to be sure to use the previous
233
233
  # one.
234
234
  name_value = name_changed? ? name_was : name
235
-
235
+
236
236
  Command.vboxmanage("sharedfolder remove #{Command.shell_escape(parent.name)} --name #{Command.shell_escape(name_value)}")
237
237
  true
238
238
  rescue Exceptions::CommandFailedException
@@ -1,7 +1,7 @@
1
1
  module VirtualBox
2
2
  # Represents a single storage controller which can be attached to a
3
3
  # virtual machine.
4
- #
4
+ #
5
5
  # **Currently, storage controllers can not be created from scratch.
6
6
  # Therefore, the only way to use this model is through a relationship
7
7
  # of a {VM} object.**
@@ -10,7 +10,7 @@ module VirtualBox
10
10
  #
11
11
  # Properties of the storage controller are exposed using standard ruby instance
12
12
  # methods which are generated on the fly. Because of this, they are not listed
13
- # below as available instance methods.
13
+ # below as available instance methods.
14
14
  #
15
15
  # These attributes can be accessed and modified via standard ruby-style
16
16
  # `instance.attribute` and `instance.attribute=` methods. The attributes are
@@ -46,7 +46,7 @@ module VirtualBox
46
46
  attribute :max_ports, :populate_key => :maxportcount
47
47
  attribute :ports, :populate_key => :portcount
48
48
  relationship :devices, AttachedDevice, :dependent => :destroy
49
-
49
+
50
50
  class <<self
51
51
  # Populates a relationship with another model.
52
52
  #
@@ -55,7 +55,7 @@ module VirtualBox
55
55
  # @return [Array<StorageController>]
56
56
  def populate_relationship(caller, data)
57
57
  relation = []
58
-
58
+
59
59
  counter = 0
60
60
  loop do
61
61
  break unless data["storagecontrollername#{counter}".to_sym]
@@ -63,17 +63,17 @@ module VirtualBox
63
63
  relation.push(nic)
64
64
  counter += 1
65
65
  end
66
-
66
+
67
67
  relation
68
68
  end
69
-
69
+
70
70
  # Destroys a relationship with another model.
71
71
  #
72
72
  # **This method typically won't be used except internally.**
73
73
  def destroy_relationship(caller, data, *args)
74
74
  data.each { |v| v.destroy(*args) }
75
75
  end
76
-
76
+
77
77
  # Saves the relationship. This simply calls {#save} on every
78
78
  # member of the relationship.
79
79
  #
@@ -84,16 +84,16 @@ module VirtualBox
84
84
  end
85
85
  end
86
86
  end
87
-
87
+
88
88
  # Since storage controllers still can't be created from scratch,
89
89
  # this method shouldn't be called. Instead, storage controllers
90
90
  # can be retrieved through relationships of other models such
91
91
  # as {VM}.
92
92
  def initialize(index, caller, data)
93
93
  super()
94
-
94
+
95
95
  @index = index
96
-
96
+
97
97
  # Setup the index specific attributes
98
98
  populate_data = {}
99
99
  self.class.attributes.each do |name, options|
@@ -101,16 +101,16 @@ module VirtualBox
101
101
  value = data["storagecontroller#{key}#{index}".to_sym]
102
102
  populate_data[key] = value
103
103
  end
104
-
104
+
105
105
  # Make sure to merge in device data so those relationships will be
106
106
  # setup properly
107
107
  populate_data.merge!(extract_devices(index, data))
108
-
108
+
109
109
  populate_attributes(populate_data.merge({
110
110
  :parent => caller
111
111
  }))
112
112
  end
113
-
113
+
114
114
  # Extracts related devices for a storage controller.
115
115
  #
116
116
  # **This method typically won't be used except internally.**
@@ -118,14 +118,14 @@ module VirtualBox
118
118
  # @return [Hash]
119
119
  def extract_devices(index, data)
120
120
  name = data["storagecontrollername#{index}".downcase.to_sym].downcase
121
-
121
+
122
122
  device_data = {}
123
123
  data.each do |k,v|
124
124
  next unless k.to_s =~ /^#{name}-/
125
-
125
+
126
126
  device_data[k] = v
127
127
  end
128
-
128
+
129
129
  device_data
130
130
  end
131
131
  end