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
@@ -46,45 +46,43 @@ module AWS
46
46
  include TaggedCollection
47
47
  include BlockDeviceMappings
48
48
 
49
- ##
50
49
  # Runs one or more EC2 instances.
51
50
  #
52
51
  # @example Running a single instance
53
- # i = ec2.instances.create(:image_id => "ami-8c1fece5")
54
- # sleep 1 while i.status == :pending
52
+ # i = ec2.instances.create(:image_id => "ami-8c1fece5")
53
+ # sleep 1 while i.status == :pending
55
54
  #
56
55
  # @example Running multiple instances with the same parameters
57
- # instances =
58
- # ec2.instances.create(:image_id => "ami-8c1fece5",
59
- # :count => 10)
60
- # sleep 1 while instances.any? { |i| i.status == :pending }
56
+ #
57
+ # instances = ec2.instances.create(
58
+ # :image_id => "ami-8c1fece5",
59
+ # :count => 10)
60
+ #
61
+ # sleep 1 while instances.any? {|i| i.status == :pending }
61
62
  #
62
63
  # @example Specifying block device mappings
63
- # ec2.instances.create(:image_id => "ami-8c1fece5",
64
- # :block_device_mappings => {
65
- # "/dev/sda2" => {
66
- # # 15 GiB
67
- # :volume_size => 15,
68
- # :delete_on_termination => true
69
- # }
70
- # })
71
64
  #
72
- # @return [Instance or Array] If a single instance is being created, this returns
73
- # an instance of {EC2::Instance} to represent the newly
74
- # created instance. Otherwise it returns an array of
75
- # EC2::Instance objects.
65
+ # ec2.instances.create({
66
+ # :image_id => "ami-8c1fece5",
67
+ # :block_device_mappings => {
68
+ # "/dev/sda2" => {
69
+ # :volume_size => 15, # 15 GiB
70
+ # :delete_on_termination => true
71
+ # }
72
+ # }
73
+ # })
76
74
  #
77
- # @param [Hash] opts Options for new instance. +:image_id+ is
75
+ # @param [Hash] options Options for new instance. +:image_id+ is
78
76
  # the only required option.
79
77
  #
80
- # @option opts :count How many instances to request. By
78
+ # @option options :count How many instances to request. By
81
79
  # default one instance is requested. You can specify this
82
80
  # either as an integer or as a Range, to indicate the
83
81
  # minimum and maximum number of instances to run. Note that
84
82
  # for a new account you can request at most 20 instances at
85
83
  # once.
86
84
  #
87
- # @option opts [Hash] :block_device_mappings This must be a
85
+ # @option options [Hash] :block_device_mappings This must be a
88
86
  # hash; the keys are device names to map, and the value for
89
87
  # each entry determines how that device is mapped. Valid
90
88
  # values include:
@@ -110,43 +108,43 @@ module AWS
110
108
  # to delete the volume when the
111
109
  # instance is terminated.
112
110
  #
113
- # @option opts [Boolean] :monitoring Setting this to true
111
+ # @option options [Boolean] :monitoring Setting this to true
114
112
  # enables CloudWatch monitoring on the instances once they
115
113
  # are started.
116
114
  #
117
- # @option opts [String] :availability_zone Specifies the
115
+ # @option options [String] :availability_zone Specifies the
118
116
  # availability zone where the instance should run. Without
119
117
  # this option, EC2 will choose an availability zone for you.
120
118
  #
121
- # @option opts [String] :image_id ID of the AMI you want to
119
+ # @option options [String] :image_id ID of the AMI you want to
122
120
  # launch.
123
121
  #
124
- # @option opts [String] :key_name The name of the key pair to
122
+ # @option options [String] :key_name The name of the key pair to
125
123
  # use. Note: Launching public images without a key pair ID
126
124
  # will leave them inaccessible.
127
125
  #
128
- # @option opts [Array] :security_groups The names of the
126
+ # @option options [Array] :security_groups The names of the
129
127
  # security groups that will be used to determine network
130
128
  # access rules for the instances. You may pass instances of
131
129
  # {SecurityGroup} as well.
132
130
  #
133
- # @option opts [String] :user_data Arbitrary user data. You
131
+ # @option options [String] :user_data Arbitrary user data. You
134
132
  # do not need to encode this value.
135
133
  #
136
- # @option opts [String] :instance_type The type of instance to
134
+ # @option options [String] :instance_type The type of instance to
137
135
  # launch, for example "m1.small".
138
136
  #
139
- # @option opts [String] :kernel_id The ID of the kernel with
137
+ # @option options [String] :kernel_id The ID of the kernel with
140
138
  # which to launch the instance.
141
139
  #
142
- # @option opts [String] :ramdisk_id The ID of the RAM disk to
140
+ # @option options [String] :ramdisk_id The ID of the RAM disk to
143
141
  # select. Some kernels require additional drivers at
144
142
  # launch. Check the kernel requirements for information on
145
143
  # whether you need to specify a RAM disk. To find kernel
146
144
  # requirements, refer to the Resource Center and search for
147
145
  # the kernel ID.
148
146
  #
149
- # @option opts [Boolean] :disable_api_termination Specifies
147
+ # @option options [Boolean] :disable_api_termination Specifies
150
148
  # whether you can terminate the instance using the EC2
151
149
  # API. A value of true means you can't terminate the
152
150
  # instance using the API (i.e., the instance is "locked"); a
@@ -161,54 +159,61 @@ module AWS
161
159
  # i.api_termination_disabled = false
162
160
  # i.terminate # terminates the instance
163
161
  #
164
- # @option opts [String] :instance_initiated_shutdown_behavior
162
+ # @option options [String] :instance_initiated_shutdown_behavior
165
163
  # Determines whether the instance stops or terminates on
166
164
  # instance-initiated shutdown.
167
- def create(opts = {})
168
- if image = opts.delete(:image)
169
- opts[:image_id] = image.id
165
+ #
166
+ # @return [Instance or Array] If a single instance is being created,
167
+ # this returns an {EC2::Instance} to represent the newly
168
+ # created instance. Otherwise it returns an array of instance
169
+ # objects.
170
+ #
171
+ def create options = {}
172
+
173
+ if image = options.delete(:image)
174
+ options[:image_id] = image.id
170
175
  end
171
176
 
172
- if kernel = opts.delete(:kernel)
173
- opts[:kernel_id] = kernel.id
177
+ if kernel = options.delete(:kernel)
178
+ options[:kernel_id] = kernel.id
174
179
  end
175
180
 
176
- if ramdisk = opts.delete(:ramdisk)
177
- opts[:ramdisk_id] = ramdisk.id
181
+ if ramdisk = options.delete(:ramdisk)
182
+ options[:ramdisk_id] = ramdisk.id
178
183
  end
179
184
 
180
- if key_pair = opts.delete(:key_pair)
181
- opts[:key_name] = key_pair.name
185
+ if key_pair = options.delete(:key_pair)
186
+ options[:key_name] = key_pair.name
182
187
  end
183
188
 
184
- opts = count_opts(opts).merge(opts)
185
- opts.delete(:count)
189
+ options = count_options(options).merge(options)
190
+ options.delete(:count)
186
191
 
187
- opts[:user_data] = Base64.encode64(opts[:user_data]).strip if
188
- opts[:user_data]
192
+ options[:user_data] = Base64.encode64(options[:user_data]).strip if
193
+ options[:user_data]
189
194
 
190
- opts[:block_device_mappings] =
191
- translate_block_device_mappings(opts[:block_device_mappings]) if
192
- opts[:block_device_mappings]
195
+ options[:block_device_mappings] =
196
+ translate_block_device_mappings(options[:block_device_mappings]) if
197
+ options[:block_device_mappings]
193
198
 
194
- opts[:monitoring] = { :enabled => true } if
195
- opts[:monitoring_enabled]
196
- opts.delete(:monitoring_enabled)
199
+ options[:monitoring] = { :enabled => true } if
200
+ options[:monitoring_enabled]
201
+ options.delete(:monitoring_enabled)
197
202
 
198
- opts[:placement] = {
199
- :availability_zone => opts[:availability_zone].to_s
200
- } if opts[:availability_zone]
201
- opts.delete(:availability_zone)
203
+ options[:placement] = {
204
+ :availability_zone => options[:availability_zone].to_s
205
+ } if options[:availability_zone]
206
+ options.delete(:availability_zone)
202
207
 
203
- opts[:security_groups] = group_opts(opts[:security_groups]) if
204
- opts[:security_groups]
208
+ options[:security_groups] = group_opts(options[:security_groups]) if
209
+ options[:security_groups]
205
210
 
206
- opts[:client_token] = UUIDTools::UUID.timestamp_create.to_s
211
+ options[:client_token] = UUIDTools::UUID.timestamp_create.to_s
207
212
 
208
- resp = client.run_instances(opts)
213
+ resp = client.run_instances(options)
209
214
 
210
- if opts[:min_count] == opts[:max_count] and
211
- opts[:min_count] == 1
215
+ if options[:min_count] == options[:max_count] and
216
+ options[:min_count] == 1
212
217
  self[resp.instances_set.first.instance_id]
213
218
  else
214
219
  resp.instances_set.map do |i|
@@ -216,6 +221,7 @@ module AWS
216
221
  end
217
222
  end
218
223
  end
224
+
219
225
  alias_method :run, :create
220
226
 
221
227
  # @yield [Instance] Yields each instance in the collection.
@@ -242,18 +248,17 @@ module AWS
242
248
 
243
249
  # @private
244
250
  private
245
- def count_opts(opts)
251
+ def count_options options
246
252
  min = max = 1
247
- count = opts[:count]
253
+ count = options[:count]
248
254
  case count
249
255
  when Range
250
256
  min = count.begin
251
- max = (count.exclude_end? ? count.end-1 : count.end)
257
+ max = (count.exclude_end? ? count.end - 1 : count.end)
252
258
  when Integer
253
259
  min = max = count
254
260
  end
255
- { :min_count => min,
256
- :max_count => max }
261
+ { :min_count => min, :max_count => max }
257
262
  end
258
263
 
259
264
  # @private
@@ -17,11 +17,12 @@ module AWS
17
17
  class EC2
18
18
 
19
19
  # Represents an EC2 key pair.
20
+ # @attr_reader [String] fingerprint A SHA-1 digest of the DER encoded
21
+ # private key
20
22
  class KeyPair < Resource
21
23
 
22
24
  def initialize name, options = {}
23
25
  @name = name.to_s
24
- @fingerprint = options[:fingerprint]
25
26
  @private_key = options[:private_key]
26
27
  super
27
28
  end
@@ -29,19 +30,24 @@ module AWS
29
30
  # @return [String] The name of the key pair.
30
31
  attr_reader :name
31
32
 
33
+ attribute :fingerprint, :as => :key_fingerprint, :static => true
34
+
35
+ populates_from(:create_key_pair, :import_key_pair) do |resp|
36
+ resp if resp.key_name == name
37
+ end
38
+
39
+ populates_from(:describe_key_pairs) do |resp|
40
+ resp.key_set.find{|k| k.key_name == name }
41
+ end
42
+
32
43
  # @return [Boolean] True if the key pair exists.
33
44
  def exists?
34
- !client.describe_key_pairs(:filters => [{ :name => "key-name",
35
- :values => [name] }]).
36
- key_set.empty?
45
+ resp = client.describe_key_pairs(:filters => [
46
+ { :name => "key-name", :values => [name] }
47
+ ])
48
+ !resp.key_set.empty?
37
49
  end
38
50
 
39
- # @return [String] A SHA-1 digest of the DER encoded private key
40
- def fingerprint; end
41
- describe_call_attribute(:key_fingerprint,
42
- :getter => :fingerprint,
43
- :memoize => true)
44
-
45
51
  # Returns the private key. Raises an exception if called
46
52
  # against an existing key. You can only get the private key
47
53
  # at the time of creation.
@@ -63,14 +69,6 @@ module AWS
63
69
  true
64
70
  end
65
71
 
66
- [:create_key_pair,
67
- :import_key_pair].each do |op|
68
- populate_from op do |resp|
69
- attributes_from_response_object(resp) if
70
- resp.key_name == name
71
- end
72
- end
73
-
74
72
  protected
75
73
  def response_id_method
76
74
  :key_name
@@ -29,19 +29,25 @@ module AWS
29
29
  # h[region.name] = region.instances.map(&:id)
30
30
  # h
31
31
  # end
32
+ #
33
+ # @attr_reader [String] endpoint The endpoint to use for this region
34
+ # (e.g. "ec2.eu-west-1.amazonaws.com").
35
+ #
32
36
  class Region < Resource
33
37
 
34
- # The name of the region (e.g. "us-east-1")
35
- attr_reader :name
36
-
37
38
  def initialize(name, options = {})
38
39
  @name = name
39
40
  super(options)
40
41
  end
41
42
 
42
- # @return [String] The endpoint to use for this region.
43
- def endpoint; end
44
- describe_call_attribute :region_endpoint, :getter => :endpoint, :memoize => true
43
+ # @return [String] The name of the region (e.g. "us-east-1").
44
+ attr_reader :name
45
+
46
+ attribute :endpoint, :as => :region_endpoint, :static => true
47
+
48
+ populates_from(:describe_regions) do |resp|
49
+ resp.region_info.find{|r| r.region_name == name }
50
+ end
45
51
 
46
52
  # @return [Boolean] True if the region is available for this
47
53
  # account.
@@ -51,17 +57,19 @@ module AWS
51
57
  region_info.empty?
52
58
  end
53
59
 
54
- PROXIED_METHODS = [:instances,
55
- :security_groups,
56
- :key_pairs,
57
- :elastic_ips,
58
- :tags,
59
- :availability_zones,
60
- :images,
61
- :volumes,
62
- :snapshots,
63
- :reserved_instances,
64
- :reserved_instances_offerings]
60
+ PROXIED_METHODS = [
61
+ :instances,
62
+ :security_groups,
63
+ :key_pairs,
64
+ :elastic_ips,
65
+ :tags,
66
+ :availability_zones,
67
+ :images,
68
+ :volumes,
69
+ :snapshots,
70
+ :reserved_instances,
71
+ :reserved_instances_offerings
72
+ ]
65
73
 
66
74
  PROXIED_METHODS.each do |method|
67
75
  define_method(method) do
@@ -42,7 +42,13 @@ module AWS
42
42
  attr_reader :id
43
43
 
44
44
  ATTRIBUTES.each do |attr_name|
45
- describe_call_attribute attr_name, :memoize => true
45
+ attribute(attr_name, :static => true)
46
+ end
47
+
48
+ populates_from(:describe_reserved_instances) do |resp|
49
+ resp.reserved_instances_set.find do |r|
50
+ r.reserved_instances_id == id
51
+ end
46
52
  end
47
53
 
48
54
  end
@@ -30,9 +30,9 @@ module AWS
30
30
  response = filtered_request(:describe_reserved_instances)
31
31
  response.reserved_instances_set.each do |item|
32
32
 
33
- reserved_instance = ReservedInstances.new(
34
- item.reserved_instances_id,
35
- :config => config)
33
+ reserved_instance = ReservedInstances.new_from(
34
+ :describe_reserved_instances, item,
35
+ item.reserved_instances_id, :config => config)
36
36
 
37
37
  yield(reserved_instance)
38
38
 
@@ -40,7 +40,13 @@ module AWS
40
40
  attr_reader :id
41
41
 
42
42
  ATTRIBUTES.each do |attr_name|
43
- describe_call_attribute attr_name, :memoize => true
43
+ attribute(attr_name, :static => true)
44
+ end
45
+
46
+ populates_from(:describe_reserved_instances_offerings) do |resp|
47
+ resp.reserved_instances_offerings_set.find do |r|
48
+ r.reserved_instances_offering_id == id
49
+ end
44
50
  end
45
51
 
46
52
  def purchase options = {}
@@ -29,9 +29,9 @@ module AWS
29
29
  response = filtered_request(:describe_reserved_instances_offerings)
30
30
  response.reserved_instances_offerings_set.each do |item|
31
31
 
32
- reserved_instance_offering = ReservedInstancesOffering.new(
33
- item.reserved_instances_offering_id,
34
- :config => config)
32
+ reserved_instance_offering = ReservedInstancesOffering.new_from(
33
+ :describe_reserved_instances_offerings, item,
34
+ item.reserved_instances_offering_id, :config => config)
35
35
 
36
36
  yield(reserved_instance_offering)
37
37
 
@@ -11,64 +11,25 @@
11
11
  # ANY KIND, either express or implied. See the License for the specific
12
12
  # language governing permissions and limitations under the License.
13
13
 
14
- require 'aws/model'
15
- require 'aws/cacheable'
14
+ require 'aws/resource'
16
15
 
17
16
  module AWS
18
17
  class EC2
19
18
 
20
19
  # @private
21
- class Resource
20
+ class Resource < AWS::Resource
22
21
 
23
- include Model
24
- include Cacheable
25
-
26
- def initialize(*args)
27
- super
28
- @memoized_attributes = {}
29
- if options = args.last and options.kind_of?(Hash)
30
- self.class.memoized_attributes.each do |att|
31
- @memoized_attributes[att] = options[att] if options.key?(att)
32
- end
33
- end
34
- end
35
-
36
- def inspect
37
- "<#{self.class}:#{__resource_id__}>"
38
- end
39
-
40
- def local_cache_key
41
- "#{self.class}:#{__resource_id__}"
42
- end
43
-
44
- def attributes_from_response(response)
45
- if atts = super
46
- self.class.memoized_attributes.each do |att|
47
- @memoized_attributes[att] = atts[att]
48
- end
49
- atts
50
- end
51
- end
52
-
53
- def ==(other)
54
- other.kind_of?(self.class) and
55
- __resource_id__ == other.__resource_id__
22
+ # @private
23
+ protected
24
+ def resource_identifiers
25
+ [[resource_id_method, send(resource_id_method)]]
56
26
  end
57
27
 
58
- alias_method :eql?, :==
59
-
60
28
  protected
61
29
  def __resource_id__
62
30
  send(resource_id_method)
63
31
  end
64
32
 
65
- protected
66
- def find_in_response(resp)
67
- resp.send(plural_name + "_set").find do |obj|
68
- obj.send(response_id_method) == __resource_id__
69
- end
70
- end
71
-
72
33
  protected
73
34
  def response_id_method
74
35
  # e.g. instance_id
@@ -93,74 +54,54 @@ module AWS
93
54
  end
94
55
 
95
56
  protected
96
- def describe_call
97
- name = self.class.describe_call_name
98
- if client.respond_to?(name)
99
- client.send(name, Hash[[[(response_id_method.to_s + "s").to_sym,
100
- [__resource_id__]]]])
101
- else
102
- raise NotImplementedError
103
- end
104
- end
105
-
106
- protected
107
- def describe_attribute_call(attribute_name)
108
- name = describe_attribute_call_name
109
- client.send(name, Hash[[[response_id_method.to_sym,
110
- __resource_id__],
111
- [:attribute, attribute_name]]])
57
+ def get_resource attribute
58
+ describe_call
112
59
  end
113
60
 
114
61
  protected
115
- def get_mutable_attribute(name)
116
- att_name = Inflection.class_name(name.to_s)
117
- att_name = att_name[0,1].downcase + att_name[1..-1]
118
- method_name = "describe_#{inflected_name}_attribute"
119
- resp = client.send(method_name,
120
- Hash[[[:"#{inflected_name}_id", __resource_id__],
121
- [:attribute, att_name]]])
122
- if att = resp.send(name) and
123
- att.respond_to?(:value)
124
- att.value
62
+ def retrieve_attribute attribute_or_attribute_name, &block
63
+ if attribute_or_attribute_name.is_a?(Symbol)
64
+ attribute = self.class.attributes[attribute_or_attribute_name]
125
65
  else
126
- nil
66
+ attribute = attribute_or_attribute_name
127
67
  end
68
+ super(attribute, &block)
128
69
  end
129
70
 
130
71
  protected
131
- def set_mutable_attribute(name, input_value)
132
- value = send("translate_input_for_#{name}", input_value) if
133
- respond_to?("translate_input_for_#{name}")
134
- opts = {}
135
- opts[name] = { :value => value }
136
- opts["#{inflected_name}_id".to_sym] = __resource_id__
137
- method_name = "modify_#{inflected_name}_attribute"
138
- resp = client.send(method_name, opts)
139
- input_value
72
+ def describe_call
73
+ options = { :"#{response_id_method}s" => [__resource_id__] }
74
+ client.send(describe_call_name, options)
140
75
  end
141
76
 
142
77
  protected
143
- def attributes_from_response_object(obj)
144
- atts = {}
145
- self.class.describe_call_attributes.each do |att, response_att|
146
- raw_value = (obj.send(response_att) if obj.respond_to?(response_att))
147
- translated = send("translate_describe_output_for_#{response_att}", raw_value)
148
- atts[att] = translated
149
- end
150
- atts
78
+ def describe_attribute_call(attribute)
79
+ name = describe_attribute_call_name
80
+
81
+ attr_opt_name = Inflection.class_name(attribute.get_as.to_s)
82
+ attr_opt_name = attr_opt_name[0,1].downcase + attr_opt_name[1..-1]
83
+
84
+ client.send(name, Hash[[[response_id_method.to_sym,
85
+ __resource_id__],
86
+ [:attribute, attr_opt_name]]])
151
87
  end
152
88
 
153
89
  protected
154
- def attributes_from_describe_attribute_response(resp)
155
- requested_att = resp.request_options[:attribute]
156
- return nil unless
157
- resp.request_options[response_id_method.to_sym] == __resource_id__
90
+ def update_resource attribute, value
91
+ options = {}
92
+ options[attribute.set_as] = { :value => value }
93
+ options[:"#{inflected_name}_id"] = __resource_id__
94
+ method_name = "modify_#{inflected_name}_attribute"
95
+ client.send(method_name, options)
96
+ end
158
97
 
159
- response_att = Inflection.ruby_name(requested_att)
160
- if getter = self.class.mutable_attributes[response_att.to_sym]
161
- raw_value = resp.send(response_att)
162
- translated = send("translate_describe_attribute_output_for_#{response_att}", raw_value)
163
- Hash[[[getter, translated]]]
98
+ # required for tagged item, which most ec2 resources are
99
+ protected
100
+ def find_in_response response
101
+ self.class.attribute_providers.each do |provider|
102
+ if provider.request_types.include?(response.request_type)
103
+ return send(provider.finder_method, response)
104
+ end
164
105
  end
165
106
  end
166
107
 
@@ -168,7 +109,7 @@ module AWS
168
109
 
169
110
  protected
170
111
  def describe_call_name
171
- name = "describe_#{plural_name}"
112
+ :"describe_#{plural_name}"
172
113
  end
173
114
 
174
115
  protected
@@ -202,134 +143,12 @@ module AWS
202
143
  extend InflectionMethods
203
144
  include InflectionMethods
204
145
 
205
- # @private
206
- class AttributeBuilder
207
-
208
- include InflectionMethods
209
-
210
- def initialize(klass, name, type)
211
- @klass = klass
212
- @name = name
213
- @type = type
214
- translate_input { |v| v }
215
- translate_output { |v| v }
216
- end
217
-
218
- def translate_input(&blk)
219
- @klass.send(:define_method, "translate_input_for_#{@name}", &blk)
220
- end
221
-
222
- def translate_output(&blk)
223
- @klass.send(:define_method, output_translator(@name, @type), &blk)
224
- end
225
-
226
- def self.eval(klass, name, type, opts = {}, &blk)
227
- i = new(klass, name, type)
228
- i.instance_eval do
229
- translate_output { |v| v.tr("-","_").to_sym if v } if opts[:to_sym]
230
- translate_output { |v| v.value if v } if opts[:value_wrapper]
231
- instance_eval(&blk) if blk
232
- end
233
- end
234
- end
235
-
236
- class NotFound < StandardError; end
237
-
238
146
  class << self
239
147
 
240
- def memoized_attributes; []; end
241
-
242
148
  # @private
243
149
  protected
244
150
  def describe_call_attribute(name, opts = {}, &blk)
245
- getter_name = opts[:getter] || name
246
-
247
- # define the accessor
248
- define_describe_call_getter(getter_name, opts) do |*args|
249
- begin
250
- retrieve_attribute(getter_name) { describe_call }
251
- rescue Cacheable::NoData => e
252
- name = Inflection.ruby_name(self.class.name).tr("_", " ")
253
- raise NotFound, "unable to find the #{name}"
254
- end
255
- end
256
-
257
- # ensure we are populating from the describe call
258
- populate_from describe_call_name do |resp|
259
- if obj = find_in_response(resp)
260
- attributes_from_response_object(obj)
261
- end
262
- end
263
-
264
- # add it to the list of attributes to populate from the response object
265
- add_to_attribute_map(:describe_call_attributes, getter_name, name)
266
-
267
- if opts[:memoize]
268
- all_memoized = memoized_attributes
269
- all_memoized << getter_name
270
- MetaUtils.extend_method(self, :memoized_attributes) { all_memoized }
271
- end
272
-
273
- # evaluate translators
274
- AttributeBuilder.eval(self, name, :describe, opts, &blk)
275
- end
276
-
277
- protected
278
- def add_to_attribute_map(map_name, key, value)
279
- all_attributes = {}
280
- all_attributes = send(map_name) if respond_to?(map_name)
281
- all_attributes[key] = value
282
- MetaUtils.extend_method(self, map_name) do
283
- all_attributes
284
- end
285
- end
286
-
287
- protected
288
- def define_describe_call_getter(getter_name, opts, &block)
289
- if opts[:memoize]
290
- original_block = block
291
- block = lambda do
292
- if @memoized_attributes.has_key?(getter_name)
293
- @memoized_attributes[getter_name]
294
- else
295
- instance_eval(&original_block)
296
- end
297
- end
298
- end
299
- define_method(getter_name, &block)
300
- end
301
-
302
- # @private
303
- def mutable_attribute(name, opts = {}, &blk)
304
- getter = opts[:getter] || name
305
- setter = opts[:setter] || "#{name}="
306
-
307
- # e.g. "instanceType" or "blockDeviceMapping"
308
- # as passed to the :attribute option of the service call
309
- request_name = Inflection.class_name(name.to_s)
310
- request_name = request_name[0,1].downcase + request_name[1..-1]
311
-
312
- # define getter
313
- define_method(getter) do
314
- retrieve_attribute(getter) { describe_attribute_call(request_name) }
315
- end
316
-
317
- # define setter
318
- define_method(setter) do |input_value|
319
- set_mutable_attribute(name, input_value)
320
- end unless opts[:setter] == false
321
-
322
- # make sure we will populate from this type of response
323
- populate_from describe_attribute_call_name do |resp|
324
- attributes_from_describe_attribute_response(resp)
325
- end
326
-
327
- # describe how to populate this attribute
328
- add_to_attribute_map(:mutable_attributes, name, getter)
329
-
330
- # evaluate translations, etc.
331
- AttributeBuilder.eval(self, name, :describe_attribute,
332
- { :value_wrapper => true }.merge(opts), &blk)
151
+ attribute(name, opts, &blk)
333
152
  end
334
153
 
335
154
  end