aws-sdk 1.0.4 → 1.1.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 (71) hide show
  1. data/lib/aws.rb +10 -9
  2. data/lib/aws/api_config/IAM-2010-07-15.yml +632 -0
  3. data/lib/aws/base_client.rb +1 -1
  4. data/lib/aws/cacheable.rb +34 -46
  5. data/lib/aws/client_logging.rb +19 -14
  6. data/lib/aws/collections.rb +230 -0
  7. data/lib/aws/common.rb +4 -0
  8. data/lib/aws/configuration.rb +7 -0
  9. data/lib/aws/ec2.rb +2 -2
  10. data/lib/aws/ec2/attachment.rb +64 -71
  11. data/lib/aws/ec2/attachment_collection.rb +11 -9
  12. data/lib/aws/ec2/availability_zone.rb +40 -31
  13. data/lib/aws/ec2/availability_zone_collection.rb +2 -3
  14. data/lib/aws/ec2/elastic_ip.rb +25 -22
  15. data/lib/aws/ec2/elastic_ip_collection.rb +5 -2
  16. data/lib/aws/ec2/image.rb +113 -129
  17. data/lib/aws/ec2/image_collection.rb +5 -6
  18. data/lib/aws/ec2/instance.rb +290 -233
  19. data/lib/aws/ec2/instance_collection.rb +72 -67
  20. data/lib/aws/ec2/key_pair.rb +16 -18
  21. data/lib/aws/ec2/region.rb +25 -17
  22. data/lib/aws/ec2/reserved_instances.rb +7 -1
  23. data/lib/aws/ec2/reserved_instances_collection.rb +3 -3
  24. data/lib/aws/ec2/reserved_instances_offering.rb +7 -1
  25. data/lib/aws/ec2/reserved_instances_offering_collection.rb +3 -3
  26. data/lib/aws/ec2/resource.rb +41 -222
  27. data/lib/aws/ec2/security_group.rb +22 -18
  28. data/lib/aws/ec2/security_group_collection.rb +2 -5
  29. data/lib/aws/ec2/snapshot.rb +44 -35
  30. data/lib/aws/ec2/snapshot_collection.rb +43 -1
  31. data/lib/aws/ec2/tag.rb +14 -18
  32. data/lib/aws/ec2/volume.rb +59 -72
  33. data/lib/aws/ec2/volume_collection.rb +16 -12
  34. data/lib/aws/errors.rb +14 -5
  35. data/lib/aws/http/httparty_handler.rb +2 -2
  36. data/lib/aws/iam.rb +306 -0
  37. data/lib/aws/iam/access_key.rb +183 -0
  38. data/lib/aws/iam/access_key_collection.rb +131 -0
  39. data/lib/aws/iam/account_alias_collection.rb +81 -0
  40. data/lib/aws/iam/client.rb +44 -0
  41. data/lib/aws/iam/client/xml.rb +38 -0
  42. data/lib/aws/iam/collection.rb +87 -0
  43. data/lib/aws/iam/errors.rb +29 -0
  44. data/lib/aws/iam/group.rb +117 -0
  45. data/lib/aws/iam/group_collection.rb +135 -0
  46. data/lib/aws/iam/group_policy_collection.rb +49 -0
  47. data/lib/aws/iam/group_user_collection.rb +94 -0
  48. data/lib/aws/iam/login_profile.rb +97 -0
  49. data/lib/aws/iam/mfa_device.rb +52 -0
  50. data/lib/aws/iam/mfa_device_collection.rb +119 -0
  51. data/lib/aws/iam/policy.rb +48 -0
  52. data/lib/aws/iam/policy_collection.rb +191 -0
  53. data/lib/aws/iam/request.rb +27 -0
  54. data/lib/aws/iam/resource.rb +74 -0
  55. data/lib/aws/iam/server_certificate.rb +143 -0
  56. data/lib/aws/iam/server_certificate_collection.rb +174 -0
  57. data/lib/aws/iam/signing_certificate.rb +171 -0
  58. data/lib/aws/iam/signing_certificate_collection.rb +134 -0
  59. data/lib/aws/iam/user.rb +196 -0
  60. data/lib/aws/iam/user_collection.rb +136 -0
  61. data/lib/aws/iam/user_group_collection.rb +101 -0
  62. data/lib/aws/iam/user_policy.rb +90 -0
  63. data/lib/aws/iam/user_policy_collection.rb +48 -0
  64. data/lib/aws/resource.rb +381 -0
  65. data/lib/aws/resource_cache.rb +1 -2
  66. data/lib/aws/response.rb +5 -1
  67. data/lib/aws/response_cache.rb +1 -1
  68. data/lib/aws/s3/client.rb +3 -1
  69. data/lib/aws/s3/presigned_post.rb +1 -1
  70. data/lib/aws/simple_db.rb +1 -1
  71. metadata +113 -50
@@ -21,26 +21,29 @@ module AWS
21
21
 
22
22
  # Represents an Amazon Machine Image (AMI).
23
23
  #
24
+ # @attr_reader [String] name The name of the AMI that was provided
25
+ # during image creation.
26
+ #
24
27
  # @attr [String] description A description of the image.
25
28
  #
26
29
  # @attr_reader [String] location The location of the AMI.
27
30
  #
28
31
  # @attr_reader [Symbol] state Current state of the AMI. If the
29
- # state is +:available+, the image is successfully registered
30
- # and available for launching. Valid values:
32
+ # state is +:available+, the image is successfully registered
33
+ # and available for launching. Valid values:
34
+ # * +:available+
35
+ # * +:pending+
36
+ # * +:failed+
31
37
  #
32
- # * +:available+
33
- # * +:pending+
34
- # * +:failed+
38
+ # @attr_reader [String] owner_id The AWS account ID of the image owner.
35
39
  #
36
- # @attr_reader [String] owner_id AWS account ID of the image
37
- # owner.
40
+ # @attr_reader [String] owner_alias The AWS account alias (e.g.,
41
+ # +"amazon"+) or AWS account ID that owns the AMI.
38
42
  #
39
- # @attr_reader [Symbol] architecture The architecture of the
43
+ # @attr_reader [Symbol] architecture The architecture of the
40
44
  # image (e.g. +:i386+).
41
45
  #
42
- # @attr_reader [Symbol] type The type of image. Valid values:
43
- #
46
+ # @attr_reader [Symbol] type The type of image. Valid values are:
44
47
  # * +:machine+
45
48
  # * +:kernel+
46
49
  # * +:ramdisk+
@@ -62,140 +65,152 @@ module AWS
62
65
  #
63
66
  # [message] A textual description of the state change.
64
67
  #
65
- # @attr_reader [String] owner_alias The AWS account alias (e.g.,
66
- # +"amazon"+) or AWS account ID that owns the AMI.
67
- #
68
- # @attr_reader [String] name The name of the AMI that was
69
- # provided during image creation.
70
- #
71
- # @attr [String] description A free-form description of the AMI.
72
- # May contain up to 255 characters.
73
- #
74
68
  # @attr_reader [Symbol] root_device_type The root device type
75
69
  # used by the AMI. Possible values:
76
- #
77
70
  # * +:ebs+
78
71
  # * +:instance_store+
79
72
  #
80
73
  # @attr_reader [String] root_device_name The root device name
81
74
  # (e.g., +"/dev/sda1"+, or +"xvda"+).
82
75
  #
83
- # @attr_reader [Hash] block_device_mappings A hash of block
84
- # device mappings for the image. In each entry, the key is
85
- # the device name (e.g. +"/dev/sda1"+) and the value is an
86
- # object with the following methods that return information
87
- # about the block device:
88
- #
89
- # [snapshot_id] The ID of the snapshot that will be used to
90
- # create this device (may be nil).
91
- #
92
- # [volume_size] The size of the volume, in GiBs.
93
- #
94
- # [delete_on_termination] True if the Amazon EBS volume is
95
- # deleted on instance termination.
96
- #
97
- # @attr_reader [Array<String>] product_codes Returns an array of
98
- # product codes attached to this instance.
99
- #
100
76
  # @attr_reader [Symbol] virtualization_type The type of
101
77
  # virtualization of the AMI. Possible values:
102
- #
103
78
  # * +:paravirtual+
104
79
  # * +:hvm+
105
80
  #
106
- # @attr_reader [Symbol] hypervisor The image's hypervisor type.
107
- # Possible values:
108
- #
81
+ # @attr_reader [Symbol] hypervisor The image's hypervisor type.
82
+ # Possible values are:
109
83
  # * +:ovm+
110
84
  # * +:xen+
85
+ #
86
+ # @attr_reader [Array<String>] product_codes Returns an array of
87
+ # product codes attached to this instance.
88
+ #
111
89
  class Image < Resource
112
90
 
113
91
  include TaggedItem
114
92
  include HasPermissions
115
- alias_method :launch_permissions, :permissions
116
-
117
- # The ID of the AMI.
118
- attr_reader :id
119
93
 
120
94
  # @private
121
- def initialize(id, opts = {})
95
+ def initialize id, options = {}
122
96
  @id = id
123
- super(opts)
97
+ super
98
+ end
99
+
100
+ # @return [String] The ID of the AMI.
101
+ attr_reader :id
102
+
103
+ attribute :name, :static => true
104
+
105
+ mutable_attribute :description
106
+
107
+ attribute :location, :as => :image_location, :static => true
108
+
109
+ attribute :state, :as => :image_state, :to_sym => true
110
+
111
+ attribute :owner_id, :as => :image_owner_id, :static => true
112
+
113
+ attribute :owner_alias, :as => :image_owner_alias, :static => true
114
+
115
+ attribute :architecture, :to_sym => true, :static => true
116
+
117
+ attribute :type, :as => :image_type, :to_sym => true, :static => true
118
+
119
+ attribute :kernel_id, :static => true
120
+
121
+ attribute :ramdisk_id, :static => true
122
+
123
+ attribute :platform, :static => true
124
+
125
+ attribute :state_reason
126
+
127
+ attribute :root_device_type, :to_sym => true, :static => true
128
+
129
+ attribute :root_device_name, :static => true
130
+
131
+ attribute :virtualization_type, :to_sym => true, :static => true
132
+
133
+ attribute :hypervisor, :to_sym => true, :static => true
134
+
135
+ attribute :block_device_mapping
136
+ protected :block_device_mapping
137
+
138
+ attribute :product_codes, :static => true do
139
+ translates_output do |list|
140
+ (list || []).collect{|item| item.product_code }
141
+ end
142
+ end
143
+
144
+ populates_from(:describe_images) do |resp|
145
+ resp.image_index[id]
146
+ end
147
+
148
+ alias_method :launch_permissions, :permissions
149
+
150
+ # @return [Hash] Returns a hash of block
151
+ # device mappings for the image. In each entry, the key is
152
+ # the device name (e.g. +"/dev/sda1"+) and the value is an
153
+ # object with the following methods that return information
154
+ # about the block device:
155
+ #
156
+ # [snapshot_id] The ID of the snapshot that will be used to
157
+ # create this device (may be nil).
158
+ #
159
+ # [volume_size] The size of the volume, in GiBs.
160
+ #
161
+ # [delete_on_termination] True if the Amazon EBS volume is
162
+ # deleted on instance termination.
163
+ def block_device_mappings
164
+ (block_device_mapping || []).inject({}) do |h,mapping|
165
+ h[mapping.device_name] = mapping.ebs
166
+ h
167
+ end
124
168
  end
125
169
 
126
170
  # Deregisters this AMI. Once deregistered, the AMI cannot be
127
171
  # used to launch new instances.
172
+ # @return [nil]
128
173
  def deregister
129
174
  client.deregister_image(:image_id => id)
175
+ nil
130
176
  end
177
+
131
178
  alias_method :delete, :deregister
132
179
 
133
- # Runs a single instance of this image.
134
- #
135
- # @param [Hash] opts Additional options for running the
136
- # instance. See {InstanceCollection#create} for a full list
137
- # of supported options.
180
+ # Runs a single instance of this image.
138
181
  #
139
- # @return [Instance] An object representing the new instance.
140
- def run_instance(opts = {})
141
- InstanceCollection.new(:config => config).
142
- create(opts.merge(:image => self))
182
+ # @param [Hash] options
183
+ # @option (see InstanceCollection#create)
184
+ # @return (see InstanceCollection#create)
185
+ def run_instance options = {}
186
+ instances = InstanceCollection.new(:config => config)
187
+ instances.create(options.merge(:image => self))
143
188
  end
144
189
 
145
190
  # Runs multiple instances of this image.
146
191
  #
147
- # @param count How many instances to request. You can specify
192
+ # @param [Integer] count How many instances to request. You can specify
148
193
  # this either as an integer or as a Range, to indicate the
149
194
  # minimum and maximum number of instances to run. Note that
150
195
  # for a new account you can request at most 20 instances at
151
196
  # a time.
152
- #
153
- # @param [Hash] opts Additional options for running the
154
- # instance. See {InstanceCollection#create} for a full list
155
- # of supported options.
156
- #
157
- # @return [Array] An array containing an {Instance} object for
197
+ # @param [Hash] options
198
+ # @option (see InstanceCollection#create)
199
+ # @return [Array<Instance>] An array containing an {Instance} object for
158
200
  # each instance that was run.
159
- def run_instances(count, opts = {})
160
- InstanceCollection.new(:config => config).
161
- create(opts.merge(:image => self,
162
- :count => count))
201
+ def run_instances count, options = {}
202
+ run_instance(options.merge(:count => count))
163
203
  end
164
204
 
165
- # @return [Boolean] +true+ if the AMI exists (is returned by
166
- # the DescribeImages action).
205
+ # @return [Boolean] Returns +true+ if the AMI exists (is returned by
206
+ # the DescribeImages action).
167
207
  def exists?
168
- resp = client.describe_images(:filters =>
169
- [{ :name => "image-id",
170
- :values => [id] }]) and
171
- !resp.images_set.empty?
208
+ resp = client.describe_images(:filters => [
209
+ { :name => "image-id", :values => [id] }
210
+ ])
211
+ !resp.images_set.empty?
172
212
  end
173
213
 
174
- mutable_attribute :description
175
- # use describe_images to get it, so it will work with public images
176
- describe_call_attribute :description
177
-
178
- describe_call_attribute :name, :memoize => true
179
- describe_call_attribute(:image_location,
180
- :getter => :location,
181
- :memoize => true)
182
- describe_call_attribute :image_state, :getter => :state, :to_sym => true
183
- describe_call_attribute(:image_owner_id,
184
- :getter => :owner_id,
185
- :memoize => true)
186
- describe_call_attribute(:image_owner_alias,
187
- :getter => :owner_alias,
188
- :memoize => true)
189
- describe_call_attribute(:architecture,
190
- :to_sym => true,
191
- :memoize => true)
192
- describe_call_attribute(:image_type,
193
- :getter => :type,
194
- :to_sym => true,
195
- :memoize => true)
196
-
197
- describe_call_attribute :kernel_id, :memoize => true
198
-
199
214
  # @return [Image] The kernel associated with the image, if
200
215
  # any. Only applicable for machine images.
201
216
  def kernel
@@ -204,8 +219,6 @@ module AWS
204
219
  end
205
220
  end
206
221
 
207
- describe_call_attribute :ramdisk_id, :memoize => true
208
-
209
222
  # @return [Image] The RAM disk associated with the image, if
210
223
  # any. Only applicable for machine images.
211
224
  def ramdisk
@@ -214,30 +227,6 @@ module AWS
214
227
  end
215
228
  end
216
229
 
217
- describe_call_attribute :platform, :memoize => true
218
- describe_call_attribute :state_reason
219
- describe_call_attribute(:root_device_type,
220
- :to_sym => true,
221
- :memoize => true)
222
- describe_call_attribute :root_device_name
223
- describe_call_attribute :virtualization_type, :to_sym => true
224
- describe_call_attribute :hypervisor, :to_sym => true
225
- describe_call_attribute(:block_device_mapping,
226
- :getter => :block_device_mappings) do
227
- translate_output do |mappings|
228
- (mappings || []).inject({}) do |h, mapping|
229
- h[mapping.device_name] = mapping.ebs
230
- h
231
- end
232
- end
233
- end
234
-
235
- describe_call_attribute :product_codes, :memoize => true do
236
- translate_output do |list|
237
- (list || []).collect{|item| item.product_code }
238
- end
239
- end
240
-
241
230
  # Adds one or more product codes:
242
231
  #
243
232
  # image.add_product_codes 'ABCXYZ', 'MNOPQR'
@@ -261,11 +250,6 @@ module AWS
261
250
  "launchPermission"
262
251
  end
263
252
 
264
- protected
265
- def find_in_response(resp)
266
- resp.image_index[id]
267
- end
268
-
269
253
  end
270
254
 
271
255
  end
@@ -79,15 +79,14 @@ module AWS
79
79
 
80
80
  # @yield [image] Each image in the collection.
81
81
  # @return [nil]
82
- def each(&block)
82
+ def each &block
83
83
  opts = {}
84
- opts[:owners] = @owners.map { |id| id.to_s } unless
85
- @owners.empty?
84
+ opts[:owners] = @owners.map { |id| id.to_s } unless @owners.empty?
86
85
  opts[:executable_users] = @executable_users.map { |id| id.to_s } unless
87
86
  @executable_users.empty?
88
87
  response = filtered_request(:describe_images, opts)
89
88
  response.images_set.each do |i|
90
- image = Image.new(i.image_id, :config => config)
89
+ image = Image.new_from(:describe_images, i, i.image_id, :config => config)
91
90
  yield(image)
92
91
  end
93
92
  nil
@@ -194,7 +193,7 @@ module AWS
194
193
  # to delete the volume when the
195
194
  # instance is terminated.
196
195
  # @return [Image]
197
- def create(options = {})
196
+ def create options = {}
198
197
  resp = case
199
198
  when options[:instance_id]
200
199
  client.create_image(options)
@@ -214,7 +213,7 @@ module AWS
214
213
  "expected instance_id, image_location, " +
215
214
  "or root_device_name")
216
215
  end
217
- self[resp.image_id]
216
+ Image.new(resp.image_id, :config => config)
218
217
  end
219
218
 
220
219
  # @private
@@ -33,11 +33,11 @@ module AWS
33
33
  # The instance must be in a stopped state to change user data;
34
34
  # for example:
35
35
  #
36
- # i.user_data # => "HELLO"
37
- # i.status # => :running
38
- # i.user_data = "GOODBYE" # raises an exception
39
- # i.stop; sleep 1 until i.status == :stopped
40
- # i.user_data = "GOODBYE" # => "GOODBYE"
36
+ # i.user_data # => "HELLO"
37
+ # i.status # => :running
38
+ # i.user_data = "GOODBYE" # raises an exception
39
+ # i.stop; sleep 1 until i.status == :stopped
40
+ # i.user_data = "GOODBYE" # => "GOODBYE"
41
41
  #
42
42
  # @attr [String] instance_type The instance type,
43
43
  # e.g. "m1.small". The instance must be in a stopped state to
@@ -73,7 +73,6 @@ module AWS
73
73
  # @attr_reader [Symbol] root_device_type The root device type
74
74
  # used by the AMI. The AMI can use an Amazon EBS or instance
75
75
  # store root device. Valid values:
76
- #
77
76
  # * +:ebs+
78
77
  # * +:instance_store+
79
78
  #
@@ -96,12 +95,21 @@ module AWS
96
95
  # @attr_reader [String] ip_address The IP address of the
97
96
  # instance.
98
97
  #
98
+ # @attr_reader [Symbol] status The instance status. Valid values are:
99
+ # * +:pending+
100
+ # * +:running+
101
+ # * +:shutting_down+
102
+ # * +:terminated+
103
+ # * +:stopping+
104
+ # * +:stopped+
105
+ #
106
+ # @attr_reader [Integer] status_code The numeric instance status code.
107
+ #
99
108
  # @attr_reader [Symbol] architecture The architecture of the
100
109
  # image.
101
110
  #
102
111
  # @attr_reader [Symbol] virtualization_type The instance's
103
112
  # virtualization type. Valid values:
104
- #
105
113
  # * +:paravirtual+
106
114
  # * +:hvm+
107
115
  #
@@ -117,7 +125,6 @@ module AWS
117
125
  #
118
126
  # @attr_reader [Symbol] monitoring The status of CloudWatch
119
127
  # monitoring for the instance. Valid values:
120
- #
121
128
  # * +:enabled+
122
129
  # * +:disabled+
123
130
  # * +:pending+
@@ -133,12 +140,12 @@ module AWS
133
140
  #
134
141
  # @attr_reader [Symbol] hypervisor The instance's hypervisor
135
142
  # type. Valid values:
136
- #
137
143
  # * +:ovm+
138
144
  # * +:xen+
139
145
  #
140
146
  # @attr_reader [String] client_token Idempotency token you
141
147
  # provided when you launched the instance.
148
+ #
142
149
  class Instance < Resource
143
150
 
144
151
  include TaggedItem
@@ -150,111 +157,251 @@ module AWS
150
157
  def initialize(instance_id, opts = {})
151
158
  super
152
159
  @id = instance_id
153
- @reservation_attributes = {}
154
160
  end
155
161
 
156
162
  # @return [String] Returns the instance id.
157
163
  attr_reader :id
158
164
 
159
- # @return [Boolean] True if the instance exists according to
160
- # EC2.
161
- def exists?
162
- client.describe_instances(:filters =>
163
- [{
164
- :name => "instance-id",
165
- :values => [id]
166
- }]).instance_index.key?(id)
165
+ # @private
166
+ def self.reservation_attributes
167
+ @reservation_attributes ||= {}
167
168
  end
168
169
 
169
170
  # @private
170
- def self.instance_action(name)
171
- define_method(name) do
172
- client.send("#{name}_instances", :instance_ids => [id])
173
- nil
174
- end
171
+ def self.reservation_attribute name, options = {}, &block
172
+ attr = attribute(name, options, &block)
173
+ reservation_attributes[attr.name] = attr
174
+ end
175
+
176
+ # @private
177
+ def self.describe_call_attributes
178
+ @describe_call_attributes ||= {}
175
179
  end
176
180
 
177
- # Terminates the instance.
178
- # @return [nil]
179
- def terminate; end
180
- instance_action :terminate
181
- alias_method :delete, :terminate
181
+ # @private
182
+ def self.mutable_describe_attributes
183
+ @mutable_describe_attributes ||= {}
184
+ end
182
185
 
183
- # Reboots the instance.
184
- # @return [nil]
185
- def reboot; end
186
- instance_action :reboot
186
+ # @private
187
+ def self.describe_call_attribute name, options = {}, &block
188
+ attr = attribute(name, options, &block)
189
+ describe_call_attributes[attr.name] = attr
190
+ end
187
191
 
188
- # Starts the instance, assuming it is in a stopped state.
189
- # @see stop
190
- # @return [nil]
191
- def start; end
192
- instance_action :start
192
+ # @private
193
+ def self.mutable_describe_call_attribute name, options = {}, &block
194
+ attr = mutable_attribute(name, options, &block)
195
+ describe_call_attributes[attr.name] = attr
196
+ end
193
197
 
194
- # Stops the instance, eventually putting it into a stopped state.
195
- # @return [nil]
196
- def stop; end
197
- instance_action :stop
198
+ # @private
199
+ def self.mutable_describe_attribute name, options = {}, &block
200
+ attr = mutable_attribute(name, options, &block)
201
+ mutable_describe_attributes[attr.name] = attr
202
+ end
203
+
204
+ reservation_attribute :reservation_id, :static => true
205
+
206
+ reservation_attribute :owner_id, :static => true
207
+
208
+ reservation_attribute :requester_id, :static => true
198
209
 
199
210
  describe_call_attribute :private_dns_name
211
+
200
212
  describe_call_attribute :dns_name
213
+
201
214
  alias_method :public_dns_name, :dns_name
202
- describe_call_attribute :ami_launch_index
203
215
 
204
- describe_call_attribute :monitoring do
205
- translate_output { |v| v.state.to_sym if v }
216
+ describe_call_attribute :product_codes, :static => true
217
+
218
+ describe_call_attribute :ami_launch_index, :static => true
219
+
220
+ describe_call_attribute :monitoring do
221
+ translates_output {|v| v.state.to_sym }
206
222
  end
207
223
 
208
- # @return true if CloudWatch monitoring is enabled for this
209
- # instance.
210
- def monitoring_enabled?
211
- monitoring == :enabled
224
+ describe_call_attribute :private_ip_address
225
+
226
+ describe_call_attribute :ip_address
227
+
228
+ alias_method :public_ip_address, :ip_address
229
+
230
+ describe_call_attribute :architecture, :to_sym => true, :static => true
231
+
232
+ describe_call_attribute :root_device_type, :to_sym => true, :static => true
233
+
234
+ describe_call_attribute :root_device_name, :static => true
235
+
236
+ describe_call_attribute :block_device_mapping
237
+ protected :block_device_mapping
238
+
239
+ describe_call_attribute :instance_lifecycle, :to_sym => true
240
+
241
+ describe_call_attribute :virtualization_type, :to_sym => true, :static => true
242
+
243
+ describe_call_attribute :hypervisor, :to_sym => true, :static => true
244
+
245
+ describe_call_attribute :placement, :static => true
246
+
247
+ describe_call_attribute :state_transition_reason, :get_as => :reason
248
+
249
+ describe_call_attribute :launch_time, :static => true
250
+
251
+ describe_call_attribute :platform, :static => true
252
+
253
+ describe_call_attribute :client_token
254
+
255
+ describe_call_attribute :image_id
256
+
257
+ describe_call_attribute :key_name, :static => true
258
+
259
+ attribute :status do
260
+ translates_output{|state| state.name.tr("-","_").to_sym }
212
261
  end
213
262
 
214
- # Enables or disables monitoring for this instance.
215
- def monitoring_enabled=(value)
216
- if value
217
- client.monitor_instances(:instance_ids => [id])
218
- true
219
- else
220
- client.unmonitor_instances(:instance_ids => [id])
221
- false
263
+ attribute :status_code do
264
+ translates_output{|state| state.code }
265
+ end
266
+
267
+ mutable_describe_call_attribute :instance_type
268
+
269
+ mutable_describe_call_attribute :kernel_id, :set_as => :kernel
270
+
271
+ mutable_describe_call_attribute :ramdisk_id, :set_as => :ramdisk
272
+
273
+ mutable_describe_call_attribute :source_dest_check?,
274
+ :as => :source_dest_check
275
+
276
+ mutable_describe_call_attribute :group_set
277
+
278
+ mutable_describe_attribute(:user_data) do
279
+ translates_output {|v| Base64.decode64(v) if v }
280
+ translates_input {|v| Base64.encode64(v).strip }
281
+ end
282
+
283
+ mutable_describe_attribute :api_termination_disabled?,
284
+ :as => :disable_api_termination
285
+
286
+ mutable_describe_attribute :instance_initiated_shutdown_behavior
287
+
288
+ provider(:describe_instances) do |provider|
289
+ provider.find {|resp| resp.reservation_index[id] }
290
+ provider.provides *reservation_attributes.keys
291
+ end
292
+
293
+ provider(:describe_instances) do |provider|
294
+ provider.find {|resp| resp.instance_index[id] }
295
+ provider.provides *describe_call_attributes.keys
296
+ provider.provides :status, :get_as => :instance_state
297
+ provider.provides :status_code, :get_as => :instance_state
298
+ end
299
+
300
+ provider(:run_instances) do |provider|
301
+ provider.find {|resp| resp.instances_set.find{|i| i.instance_id == id } }
302
+ provider.provides *describe_call_attributes.keys
303
+ provider.provides :status, :get_as => :instance_state
304
+ provider.provides :status_code, :get_as => :instance_state
305
+ end
306
+
307
+ provider(:run_instances) do |provider|
308
+ provider.find {|resp| resp if resp.instances_set.find{|i| i.instance_id == id } }
309
+ provider.provides *reservation_attributes.keys
310
+ end
311
+
312
+ # These are the few attributes that are only returned by
313
+ # :desribe_instance_attribute and are *NOT* returned by
314
+ # :describe_instances. To make matters worse, only one of
315
+ # them is returned per :describe_instance_attribute call.
316
+ mutable_describe_attributes.values.each do |attr|
317
+
318
+ attr_opt_name = Inflection.class_name(attr.get_as.to_s)
319
+ attr_opt_name = attr_opt_name[0,1].downcase + attr_opt_name[1..-1]
320
+
321
+ provider(:describe_instance_attribute) do |provider|
322
+ provider.find do |resp|
323
+ if
324
+ resp.request_options[:instance_id] == id and
325
+ resp.request_options[:attribute] == attr_opt_name
326
+ then
327
+ return resp
328
+ end
329
+ end
330
+ provider.provides(attr.name, :value_wrapped => true)
222
331
  end
332
+
223
333
  end
224
334
 
225
- # @return [Array] A list of security groups
226
- # the instance is in. Each member is an instance of
227
- # {SecurityGroup}.
335
+ provider(:terminate_instances, :start_instances, :stop_instances) do |provider|
336
+ provider.find do |resp|
337
+ resp.instances_set.find { |i| i.instance_id == id }
338
+ end
339
+ provider.provides :status, :get_as => :current_state
340
+ provider.provides :status_code, :get_as => :current_state
341
+ end
342
+
343
+ provider(:monitor_instances, :unmonitor_instances) do |provider|
344
+ provider.find do |resp|
345
+ resp.instances_set.find { |i| i.instance_id == id }
346
+ end
347
+ provider.provides :monitoring
348
+ end
349
+
350
+ # @return [Array<SecurityGroup>] Returns a list of security
351
+ # groups the instance belongs to.
228
352
  def security_groups
229
- group_set
230
- end
231
- describe_call_attribute :group_set do
232
- translate_output do |groups|
233
- (groups || []).map do |g|
234
- SecurityGroup.new(g.group_id,
235
- :name => g.group_name,
236
- :config => config)
237
- end
353
+ (group_set || []).collect do |g|
354
+ SecurityGroup.new(g.group_id, :name => g.group_name, :config => config)
238
355
  end
239
356
  end
357
+
240
358
  alias_method :groups, :security_groups
241
359
 
242
- describe_call_attribute :private_ip_address
243
- describe_call_attribute :ip_address
244
- alias_method :public_ip_address, :ip_address
245
- describe_call_attribute :architecture, :to_sym => true
246
- describe_call_attribute :root_device_type, :to_sym => true
247
- describe_call_attribute :instance_lifecycle, :to_sym => true
360
+ # @return [Hash<String,Attachment>] Returns a hash of device mappings.
361
+ # The keys are device name strings (e.g. '/dev/sda') and the values
362
+ # are {Attachment} objects.
363
+ def block_device_mappings
364
+ (block_device_mapping || []).inject({}) do |m, mapping|
365
+ device = mapping.device_name
366
+ volume = Volume.new(mapping.ebs.volume_id, :config => config)
367
+ attachment = Attachment.new(volume, self, device, :config => config)
368
+ m[device] = attachment
369
+ m
370
+ end
371
+ end
372
+
373
+ # Enables monitoring for this instance.
374
+ # @return [nil]
375
+ def enable_monitoring
376
+ client.monitor_instances(:instance_ids => [id])
377
+ nil
378
+ end
379
+
380
+ # Disables monitoring for this instance.
381
+ # @return [nil]
382
+ def disable_monitoring
383
+ client.unmonitor_instances(:instance_ids => [id])
384
+ nil
385
+ end
386
+
387
+ # Enables or disables monitoring for this instance.
388
+ # @param [Boolean] state A true or false value. Enables monintoring
389
+ # for a true value, disables it for a false value.
390
+ def monitoring_enabled= value
391
+ value ? enable_monitoring : disable_monitoring
392
+ end
393
+
394
+ # @return [Booelan] Returns +true+ if CloudWatch monitoring is
395
+ # enabled for this instance.
396
+ def monitoring_enabled?
397
+ monitoring == :enabled
398
+ end
248
399
 
249
400
  # @return [Boolean] true if the instance is a Spot instance.
250
401
  def spot_instance?
251
402
  instance_lifecycle == :spot
252
403
  end
253
404
 
254
- describe_call_attribute :virtualization_type, :to_sym => true
255
- describe_call_attribute :hypervisor, :to_sym => true
256
- describe_call_attribute :placement
257
-
258
405
  # @return [String] The availability zone where the instance is
259
406
  # running.
260
407
  def availability_zone
@@ -263,20 +410,11 @@ module AWS
263
410
  end
264
411
  end
265
412
 
266
- describe_call_attribute :reason, :getter => :state_transition_reason
267
-
268
- describe_call_attribute :launch_time
269
- describe_call_attribute :platform
270
- describe_call_attribute :client_token
271
- describe_call_attribute :image_id
272
-
273
413
  # @return [Image] The AMI used to launch the instance.
274
414
  def image
275
415
  Image.new(image_id, :config => config)
276
416
  end
277
417
 
278
- describe_call_attribute :key_name
279
-
280
418
  # @return [KeyPair] The key pair with which this instance was
281
419
  # associated at launch.
282
420
  def key_pair
@@ -306,110 +444,9 @@ module AWS
306
444
  # be guaranteed.
307
445
  #
308
446
  # @return [Image] The newly created image.
309
- def create_image(name, options = {})
310
- ImageCollection.new(:config => config).
311
- create(options.merge(:instance_id => id,
312
- :name => name))
313
- end
314
-
315
- # @private
316
- def self.reservation_attribute(name)
317
- define_method(name) do
318
- @reservation_attributes[name] ||= retrieve_attribute(name) do
319
- client.describe_instances(:instance_ids => [id])
320
- end
321
- end
322
- MetaUtils.class_extend_method(self, :attributes_from_reservation) do |r, i|
323
- if atts = super(r, i)
324
- atts[name] = (r.send(name) if r.respond_to?(name))
325
- atts
326
- end
327
- end
328
- end
329
-
330
- MetaUtils.class_extend_method(self, :attributes_from_reservation) do |r, i|
331
- attributes_from_response_object(i) if i
332
- end
333
-
334
- reservation_attribute :reservation_id
335
- reservation_attribute :owner_id
336
- reservation_attribute :requester_id
337
-
338
- mutable_attribute :user_data do
339
- # mutable_attribute unwraps the ".value" unless you translate
340
- # the output yourself
341
- translate_output { |v| Base64.decode64(v.value) if v }
342
- translate_input { |v| Base64.encode64(v).strip }
343
- end
344
-
345
- describe_call_attribute :instance_type
346
- mutable_attribute :instance_type
347
-
348
- mutable_attribute :source_dest_check, :getter => :source_dest_check?
349
- mutable_attribute(:disable_api_termination,
350
- :getter => :api_termination_disabled?,
351
- :setter => :api_termination_disabled=)
352
- mutable_attribute :instance_initiated_shutdown_behavior
353
- describe_call_attribute :kernel_id
354
- mutable_attribute :kernel, :getter => :kernel_id, :setter => :kernel_id=
355
-
356
- ##
357
- # Resets the kernel to its default value.
358
- def reset_kernel_id
359
- client.reset_instance_attribute(:instance_id => id,
360
- :attribute => "kernel").return
361
- end
362
-
363
- describe_call_attribute :ramdisk_id
364
- mutable_attribute :ramdisk, :getter => :ramdisk_id, :setter => :ramdisk_id=
365
-
366
- ##
367
- # Resets the RAM disk to its default value.
368
- def reset_ramdisk_id
369
- client.reset_instance_attribute(:instance_id => id,
370
- :attribute => "ramdisk").return
371
- end
372
-
373
- describe_call_attribute :root_device_name
374
- mutable_attribute :root_device_name, :setter => false
375
-
376
- # @return [Hash] A hash in which each key is the name of a
377
- # device that is mapped to an EBS volume. The value of each
378
- # entry is an object describing the volume, including the
379
- # following fields:
380
- #
381
- # [status] The status of the attachment (e.g. "attached").
382
- #
383
- # [volume_id] The ID of the EBS volume.
384
- #
385
- # [attach_time] The time at which the volume was attached.
386
- #
387
- # [delete_on_termination?] True if the volume will be
388
- # automatically deleted when the
389
- # instance terminates.
390
- def block_device_mappings; end
391
-
392
- describe_call_attribute(:block_device_mapping,
393
- :getter => :block_device_mappings) do
394
- translate_output { |v| translate_block_device_mappings(v) }
395
- end
396
- mutable_attribute(:block_device_mapping,
397
- :setter => false,
398
- :getter => :block_device_mappings) do
399
- translate_output { |v| translate_block_device_mappings(v) }
400
- end
401
-
402
- # @return [Symbol] The status of the instance. Valid values:
403
- # * +:pending+
404
- # * +:running+
405
- # * +:shutting_down+
406
- # * +:terminated+
407
- # * +:stopping+
408
- # * +:stopped+
409
- def status
410
- retrieve_attribute(:status) do
411
- client.describe_instances(:instance_ids => [id])
412
- end
447
+ def create_image name, options = {}
448
+ images = ImageCollection.new(:config => config)
449
+ images.create(options.merge(:instance_id => id, :name => name))
413
450
  end
414
451
 
415
452
  # Associates the elastic IP address with this instance.
@@ -421,7 +458,8 @@ module AWS
421
458
  def associate_elastic_ip elastic_ip
422
459
  client.associate_address(
423
460
  :public_ip => elastic_ip.to_s,
424
- :instance_id => self.id)
461
+ :instance_id => self.id
462
+ )
425
463
  nil
426
464
  end
427
465
 
@@ -438,66 +476,85 @@ module AWS
438
476
  end
439
477
  end
440
478
 
479
+ # @return [ElasticIp,nil] Returns an elastic IP address if one
480
+ # is associated with this instance, nil otherwise.
481
+ def elastic_ip
482
+ ips = ElasticIpCollection.new(:config => config)
483
+ ips.filter('instance-id', id).first
484
+ end
485
+
441
486
  # @return [Boolean] Returns true if an elastic IP address is
442
487
  # associated with this instance, false otherwise.
443
488
  def has_elastic_ip?
444
489
  !elastic_ip.nil?
445
490
  end
446
491
 
447
- # @return [ElasticIp,nil] Returns an elastic IP address if one
448
- # is associated with this instance, nil otherwise.
449
- def elastic_ip
450
- ElasticIpCollection.new(:config => config).
451
- filter('instance-id', id).first
492
+ # @return [Boolean] Returns true if the instance exists according to
493
+ # EC2.
494
+ def exists?
495
+ client.describe_instances(:filters => [
496
+ { :name => "instance-id", :values => [id] }
497
+ ]).instance_index.key?(id)
452
498
  end
453
499
 
454
- protected
455
- def find_in_response(resp)
456
- resp.instance_index[id]
500
+ # Resets the kernel to its default value.
501
+ def reset_kernel_id
502
+ client.reset_instance_attribute(
503
+ :instance_id => id, :attribute => "kernel").return
457
504
  end
458
505
 
459
- populate_from :describe_instances do |resp|
460
- if r = resp.reservation_index[id]
461
- attributes_from_reservation(r, resp.instance_index[id])
462
- end
506
+ # Resets the RAM disk to its default value.
507
+ def reset_ramdisk_id
508
+ client.reset_instance_attribute(
509
+ :instance_id => id, :attribute => "ramdisk").return
463
510
  end
464
511
 
465
- populate_from :run_instances do |resp|
466
- attributes_from_reservation(resp,
467
- resp.instances_set.
468
- find { |i| i.instance_id == id })
512
+ # Terminates the instance.
513
+ # @return [nil]
514
+ def terminate
515
+ instance_action :terminate
469
516
  end
517
+ alias_method :delete, :terminate
470
518
 
471
- [:terminate_instances,
472
- :start_instances,
473
- :stop_instances].each do |op|
474
- populate_from op do |resp|
475
- if i = resp.instances_set.find { |i| i.instance_id == id }
476
- { :status => i.current_state.name.tr("-","_").to_sym }
477
- end
478
- end
519
+ # Reboots the instance.
520
+ # @return [nil]
521
+ def reboot
522
+ instance_action :reboot
479
523
  end
480
524
 
481
- [:monitor_instances,
482
- :unmonitor_instances].each do |op|
483
- populate_from op do |resp|
484
- if i = resp.instances_set.find { |i| i.instance_id == id }
485
- { :monitoring =>
486
- attributes_from_response_object(i)[:monitoring] }
487
- end
488
- end
525
+ # Starts the instance, assuming it is in a stopped state.
526
+ # @see stop
527
+ # @return [nil]
528
+ def start
529
+ instance_action :start
530
+ end
531
+
532
+ # Stops the instance, eventually putting it into a stopped state.
533
+ # @return [nil]
534
+ def stop
535
+ instance_action :stop
489
536
  end
490
537
 
538
+ # @private
491
539
  protected
492
- def translate_block_device_mappings(mappings)
493
- mappings.inject({}) do |m, mapping|
494
- m[mapping.device_name] =
495
- Attachment.new(Volume.new(mapping.ebs.volume_id, :config => config),
496
- self,
497
- mapping.device_name,
498
- :config => config)
499
- m
500
- end if mappings
540
+ def find_in_response resp
541
+ resp.instance_index[id]
542
+ end
543
+
544
+ # @private
545
+ protected
546
+ def instance_action name
547
+ client.send("#{name}_instances", :instance_ids => [id])
548
+ nil
549
+ end
550
+
551
+ protected
552
+ def get_resource attribute
553
+ if self.class.mutable_describe_attributes.include?(attribute.name)
554
+ describe_attribute_call(attribute)
555
+ else
556
+ describe_call
557
+ end
501
558
  end
502
559
 
503
560
  protected