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
@@ -1,7 +1,7 @@
1
1
  module VirtualBox
2
2
  class AbstractModel
3
3
  # Tracks "dirtiness" of values for a class. Its not tied to AbstractModel
4
- # in any way other than the namespace.
4
+ # in any way other than the namespace.
5
5
  #
6
6
  # # Checking if a Value was Changed
7
7
  #
@@ -12,7 +12,7 @@ module VirtualBox
12
12
  # # Previous Value
13
13
  #
14
14
  # Can also view the previous value of an attribute:
15
- #
15
+ #
16
16
  # obj.foo # => "foo" initially
17
17
  # obj.foo = "bar"
18
18
  # obj.foo_was # => "foo"
@@ -56,14 +56,14 @@ module VirtualBox
56
56
  # on an attribute.
57
57
  #
58
58
  # # Ignoring Dirtiness Tracking
59
- #
59
+ #
60
60
  # Sometimes, for features such as mass assignment, dirtiness tracking
61
61
  # should be disabled. This can be done with the `ignore_dirty` method.
62
62
  #
63
63
  # ignore_dirty do |obj|
64
64
  # obj.name = "Foo"
65
65
  # end
66
- #
66
+ #
67
67
  # obj.changed? # => false
68
68
  #
69
69
  # # Clearing Dirty State
@@ -107,7 +107,7 @@ module VirtualBox
107
107
  end
108
108
  end
109
109
  end
110
-
110
+
111
111
  # Clears dirty state for a field.
112
112
  #
113
113
  # @param [Symbol] key The field to clear dirty state.
@@ -119,8 +119,8 @@ module VirtualBox
119
119
  end
120
120
  end
121
121
 
122
- # Ignores any dirty changes during the duration of the block.
123
- # Guarantees the dirty state will be the same before and after
122
+ # Ignores any dirty changes during the duration of the block.
123
+ # Guarantees the dirty state will be the same before and after
124
124
  # the method call, but not within the block itself.
125
125
  def ignore_dirty(&block)
126
126
  current_changes = @changed_attributes.dup rescue nil
@@ -149,13 +149,13 @@ module VirtualBox
149
149
  def changes
150
150
  @changed_attributes ||= {}
151
151
  end
152
-
152
+
153
153
  # Method missing is used to implement the "magic" methods of
154
154
  # `field_changed`, `field_change`, and `field_was`.
155
155
  def method_missing(meth, *args)
156
156
  meth_string = meth.to_s
157
-
158
- if meth_string =~ /^(.+?)_changed\?$/
157
+
158
+ if meth_string =~ /^(.+?)_changed\?$/
159
159
  changed?($1.to_sym)
160
160
  elsif meth_string =~ /^(.+?)_change$/
161
161
  changes[$1.to_sym]
@@ -2,10 +2,10 @@ module VirtualBox
2
2
  class AbstractModel
3
3
  # Provides simple relationship features to any class. These relationships
4
4
  # can be anything, since this module makes no assumptions and doesn't
5
- # differentiate between "has many" or "belongs to" or any of that.
5
+ # differentiate between "has many" or "belongs to" or any of that.
6
6
  #
7
7
  # The way it works is simple:
8
- #
8
+ #
9
9
  # 1. Relationships are defined with a relationship name and a
10
10
  # class of the relationship objects.
11
11
  # 2. When {#populate_relationships} is called, `populate_relationship` is
@@ -50,7 +50,7 @@ module VirtualBox
50
50
  #
51
51
  # If `Foo` has the `set_relationship` method, then it will be called by
52
52
  # `foos=`. It is expected to return the new value for the relationship. To
53
- # facilitate this need, the `set_relationship` method is given three
53
+ # facilitate this need, the `set_relationship` method is given three
54
54
  # parameters: caller, old value, and new value. An example implementation,
55
55
  # albeit a silly one, is below:
56
56
  #
@@ -66,7 +66,7 @@ module VirtualBox
66
66
  # instance.foos = "bar"
67
67
  # instance.foos # => "Changed to: bar"
68
68
  #
69
- # If the relationship class _does not implement_ the `set_relationship`
69
+ # If the relationship class _does not implement_ the `set_relationship`
70
70
  # method, then a {Exceptions::NonSettableRelationshipException} will be raised if
71
71
  # a user attempts to set that relationship.
72
72
  #
@@ -82,10 +82,10 @@ module VirtualBox
82
82
  def self.included(base)
83
83
  base.extend ClassMethods
84
84
  end
85
-
85
+
86
86
  module ClassMethods
87
87
  # Define a relationship. The name and class must be specified. This
88
- # class will be used to call the `populate_relationship,
88
+ # class will be used to call the `populate_relationship,
89
89
  # `save_relationship`, etc. methods.
90
90
  #
91
91
  # @param [Symbol] name Relationship name. This will also be used for
@@ -95,23 +95,23 @@ module VirtualBox
95
95
  # {AbstractModel#destroy} will propagate through to relationships.
96
96
  def relationship(name, klass, options = {})
97
97
  name = name.to_sym
98
-
98
+
99
99
  relationships << [name, { :klass => klass }.merge(options)]
100
-
100
+
101
101
  # Define the method to read the relationship
102
102
  define_method(name) { relationship_data[name] }
103
-
103
+
104
104
  # Define the method to set the relationship
105
105
  define_method("#{name}=") { |*args| set_relationship(name, *args) }
106
106
  end
107
-
107
+
108
108
  # Returns a hash of all the relationships.
109
109
  #
110
110
  # @return [Hash]
111
111
  def relationships_hash
112
112
  Hash[*relationships.flatten]
113
113
  end
114
-
114
+
115
115
  # Returns an array of the relationships in order of being added.
116
116
  #
117
117
  # @return [Array]
@@ -125,19 +125,19 @@ module VirtualBox
125
125
  def has_relationship?(name)
126
126
  !!relationships.detect { |r| r[0] == name }
127
127
  end
128
-
128
+
129
129
  # Used to propagate relationships to subclasses. This method makes sure that
130
130
  # subclasses of a class with {Relatable} included will inherit the
131
131
  # relationships as well, which would be the expected behaviour.
132
132
  def inherited(subclass)
133
133
  super rescue NoMethodError
134
-
134
+
135
135
  relationships.each do |name, options|
136
136
  subclass.relationship(name, nil, options)
137
137
  end
138
138
  end
139
139
  end
140
-
140
+
141
141
  # Saves the model, calls save_relationship on all relations. It is up to
142
142
  # the relation to determine whether anything changed, etc. Simply
143
143
  # calls `save_relationship` on each relationshp class passing in the
@@ -154,7 +154,7 @@ module VirtualBox
154
154
  options[:klass].save_relationship(self, relationship_data[name], *args)
155
155
  end
156
156
  end
157
-
157
+
158
158
  # The equivalent to {Attributable#populate_attributes}, but with
159
159
  # relationships.
160
160
  def populate_relationships(data)
@@ -163,7 +163,7 @@ module VirtualBox
163
163
  relationship_data[name] = options[:klass].populate_relationship(self, data)
164
164
  end
165
165
  end
166
-
166
+
167
167
  # Calls `destroy_relationship` on each of the relationships. Any
168
168
  # arbitrary args may be added and they will be forarded to the
169
169
  # relationship's `destroy_relationship` method.
@@ -172,7 +172,7 @@ module VirtualBox
172
172
  destroy_relationship(name, *args)
173
173
  end
174
174
  end
175
-
175
+
176
176
  # Destroys only a single relationship. Any arbitrary args
177
177
  # may be added to the end and they will be pushed through to
178
178
  # the class's `destroy_relationship` method.
@@ -183,7 +183,7 @@ module VirtualBox
183
183
  return unless options && options[:klass].respond_to?(:destroy_relationship)
184
184
  options[:klass].destroy_relationship(self, relationship_data[name], *args)
185
185
  end
186
-
186
+
187
187
  # Hash to data associated with relationships. You should instead
188
188
  # use the accessors created by Relatable.
189
189
  #
@@ -191,18 +191,18 @@ module VirtualBox
191
191
  def relationship_data
192
192
  @relationship_data ||= {}
193
193
  end
194
-
194
+
195
195
  # Returns boolean denoting if a relationship exists.
196
196
  #
197
197
  # @return [Boolean]
198
198
  def has_relationship?(key)
199
199
  self.class.has_relationship?(key.to_sym)
200
200
  end
201
-
201
+
202
202
  # Sets a relationship to the given value. This is not guaranteed to
203
203
  # do anything, since "set_relationship" will be called on the class
204
204
  # that the relationship is associated with and its expected to return
205
- # the resulting relationship to set.
205
+ # the resulting relationship to set.
206
206
  #
207
207
  # If the relationship class doesn't respond to the set_relationship
208
208
  # method, then an exception {Exceptions::NonSettableRelationshipException} will
@@ -216,7 +216,7 @@ module VirtualBox
216
216
  key = key.to_sym
217
217
  relationship = self.class.relationships_hash[key]
218
218
  return unless relationship
219
-
219
+
220
220
  raise Exceptions::NonSettableRelationshipException.new unless relationship[:klass].respond_to?(:set_relationship)
221
221
  relationship_data[key] = relationship[:klass].set_relationship(self, relationship_data[key], value)
222
222
  end
@@ -6,12 +6,12 @@ module VirtualBox
6
6
  def errors
7
7
  @errors ||= {}
8
8
  end
9
-
9
+
10
10
  def add_error(field, error)
11
11
  errors[field] ||= []
12
12
  errors[field].push(error)
13
13
  end
14
-
14
+
15
15
  def clear_errors
16
16
  @errors = {}
17
17
  end
@@ -20,12 +20,12 @@ module VirtualBox
20
20
  validate
21
21
  errors.empty?
22
22
  end
23
-
23
+
24
24
  # Subclasses should override this method.
25
25
  def validate
26
26
  true
27
27
  end
28
-
28
+
29
29
  def validates_presence_of(field)
30
30
  if field.is_a?(Array)
31
31
  field.map { |v| validates_presence_of(v) }.all? { |v| v == true }
@@ -13,7 +13,7 @@ module VirtualBox
13
13
  # storage_controller.devices << ad
14
14
  # ad.save
15
15
  #
16
- # The only quirk is that the attached device **must** be attached to a
16
+ # The only quirk is that the attached device **must** be attached to a
17
17
  # storage controller. The above assumes that `storage_controller` exists,
18
18
  # which adds the device.
19
19
  #
@@ -25,7 +25,7 @@ module VirtualBox
25
25
  # ad = VirtualBox::AttachedDevice.new
26
26
  # ad.port = 0
27
27
  # ad.image = VirtualBox::DVD.empty_drive
28
- #
28
+ #
29
29
  # # Now attaching to existing VM
30
30
  # vm = VirtualBox::VM.find("FooVM")
31
31
  # vm.storage_controllers[0].devices << ad
@@ -40,7 +40,7 @@ module VirtualBox
40
40
  #
41
41
  # Properties of the model are exposed using standard ruby instance
42
42
  # methods which are generated on the fly. Because of this, they are not listed
43
- # below as available instance methods.
43
+ # below as available instance methods.
44
44
  #
45
45
  # These attributes can be accessed and modified via standard ruby-style
46
46
  # `instance.attribute` and `instance.attribute=` methods. The attributes are
@@ -73,7 +73,7 @@ module VirtualBox
73
73
  attribute :uuid, :readonly => true
74
74
  attribute :port
75
75
  relationship :image, Image
76
-
76
+
77
77
  class <<self
78
78
  # Populate relationship with another model.
79
79
  #
@@ -82,7 +82,7 @@ module VirtualBox
82
82
  # @return [Array<AttachedDevice>]
83
83
  def populate_relationship(caller, data)
84
84
  relation = Proxies::Collection.new(caller)
85
-
85
+
86
86
  counter = 0
87
87
  loop do
88
88
  break unless data["#{caller.name}-#{counter}-0".downcase.to_sym]
@@ -90,17 +90,17 @@ module VirtualBox
90
90
  relation.push(nic)
91
91
  counter += 1
92
92
  end
93
-
93
+
94
94
  relation
95
95
  end
96
-
96
+
97
97
  # Destroy attached devices associated with another model.
98
98
  #
99
99
  # **This method typically won't be used except internally.**
100
100
  def destroy_relationship(caller, data, *args)
101
101
  data.each { |v| v.destroy(*args) }
102
102
  end
103
-
103
+
104
104
  # Saves the relationship. This simply calls {#save} on every
105
105
  # member of the relationship.
106
106
  #
@@ -112,7 +112,7 @@ module VirtualBox
112
112
  end
113
113
  end
114
114
  end
115
-
115
+
116
116
  # @overload initialize(data={})
117
117
  # Creates a new AttachedDevice which is a new record. This
118
118
  # should be attached to a storage controller and saved.
@@ -127,7 +127,7 @@ module VirtualBox
127
127
  # to extract the relationship data.
128
128
  def initialize(*args)
129
129
  super()
130
-
130
+
131
131
  if args.length == 3
132
132
  populate_from_data(*args)
133
133
  elsif args.length == 1
@@ -139,29 +139,29 @@ module VirtualBox
139
139
  raise NoMethodError.new
140
140
  end
141
141
  end
142
-
142
+
143
143
  # Validates an attached device.
144
144
  def validate
145
145
  super
146
-
146
+
147
147
  validates_presence_of :parent
148
148
  validates_presence_of :image
149
149
  validates_presence_of :port
150
150
  end
151
-
151
+
152
152
  # Saves or creates an attached device.
153
153
  #
154
154
  # @param [Boolean] raise_errors If true, {Exceptions::CommandFailedException}
155
155
  # will be raised if the command failed.
156
156
  # @return [Boolean] True if command was successful, false otherwise.
157
- def save(raise_errors=false)
157
+ def save(raise_errors=false)
158
158
  return true unless changed?
159
-
159
+
160
160
  if !valid?
161
161
  raise Exceptions::ValidationFailedException.new(errors) if raise_errors
162
162
  return false
163
163
  end
164
-
164
+
165
165
  # If the port changed, we have to destroy the old one, then create
166
166
  # a new one
167
167
  destroy({:port => port_was}, raise_errors) if port_changed? && !port_was.nil?
@@ -169,13 +169,13 @@ module VirtualBox
169
169
  Command.vboxmanage("storageattach #{Command.shell_escape(parent.parent.name)} --storagectl #{Command.shell_escape(parent.name)} --port #{port} --device 0 --type #{image.image_type} --medium #{medium}")
170
170
  existing_record!
171
171
  clear_dirty!
172
-
172
+
173
173
  true
174
174
  rescue Exceptions::CommandFailedException
175
175
  raise if raise_errors
176
176
  false
177
177
  end
178
-
178
+
179
179
  # Medium of the attached image. This attribute will be dependent
180
180
  # on the attached image and will return one of the following values:
181
181
  #
@@ -194,7 +194,7 @@ module VirtualBox
194
194
  image.uuid
195
195
  end
196
196
  end
197
-
197
+
198
198
  # Destroys the attached device. By default, this only removes any
199
199
  # media inserted within the device, but does not destroy it. This
200
200
  # option can be specified, however, through the `destroy_image`
@@ -209,21 +209,21 @@ module VirtualBox
209
209
  # parent = storagecontroller
210
210
  # parent.parent = vm
211
211
  destroy_port = options[:port] || port
212
- Command.vboxmanage("storageattach #{Command.shell_escape(parent.parent.name)} --storagectl #{Command.shell_escape(parent.name)} --port #{destroy_port} --device 0 --medium none")
212
+ Command.vboxmanage("storageattach #{Command.shell_escape(parent.parent.name)} --storagectl #{Command.shell_escape(parent.name)} --port #{destroy_port} --device 0 --medium none")
213
213
  image.destroy(raise_errors) if options[:destroy_image] && image
214
214
  rescue Exceptions::CommandFailedException
215
215
  raise if raise_errors
216
216
  false
217
217
  end
218
-
218
+
219
219
  # Relationship callback when added to a collection. This is automatically
220
220
  # called by any relationship collection when this object is added.
221
221
  def added_to_relationship(parent)
222
222
  write_attribute(:parent, parent)
223
223
  end
224
-
224
+
225
225
  protected
226
-
226
+
227
227
  # Populates the model based on data from a parsed vminfo. This
228
228
  # method is used to create a model which already exists and is
229
229
  # part of a relationship.
@@ -12,7 +12,7 @@ module VirtualBox
12
12
  #
13
13
  class Command
14
14
  @@vboxmanage = "VBoxManage"
15
-
15
+
16
16
  class <<self
17
17
  # Returns true if the last run command was a success. Obviously this
18
18
  # will introduce all sorts of thread-safe problems. Those will have to
@@ -20,36 +20,36 @@ module VirtualBox
20
20
  def success?
21
21
  $?.to_i == 0
22
22
  end
23
-
23
+
24
24
  # Sets the path to VBoxManage, which is required for this gem to
25
25
  # work.
26
26
  def vboxmanage=(path)
27
27
  @@vboxmanage = path
28
28
  end
29
-
29
+
30
30
  # Runs a VBoxManage command and returns the output.
31
31
  def vboxmanage(command)
32
- result = execute("#{@@vboxmanage} #{command}")
32
+ result = execute("#{@@vboxmanage} -q #{command}")
33
33
  raise Exceptions::CommandFailedException.new(result) if !Command.success?
34
34
  result
35
35
  end
36
-
36
+
37
37
  # Runs a command and returns a boolean result showing
38
- # if the command ran successfully or not based on the
38
+ # if the command ran successfully or not based on the
39
39
  # exit code.
40
40
  def test(command)
41
41
  execute(command)
42
42
  success?
43
43
  end
44
-
44
+
45
45
  # Runs a command and returns the STDOUT result. The reason this is
46
- # a method at the moment is because in the future we may want to
46
+ # a method at the moment is because in the future we may want to
47
47
  # change the way commands are run (replace the backticks), plus it
48
48
  # makes testing easier.
49
49
  def execute(command)
50
50
  `#{command}`
51
51
  end
52
-
52
+
53
53
  # Shell escapes a string. This is almost a direct copy/paste from
54
54
  # the ruby mailing list. I'm not sure how well it works but so far
55
55
  # it hasn't failed!