virtualbox 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
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!