right_aws 2.0.0 → 2.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 (50) hide show
  1. data/History.txt +22 -1
  2. data/Manifest.txt +11 -1
  3. data/README.txt +0 -4
  4. data/Rakefile +19 -25
  5. data/lib/acf/right_acf_interface.rb +199 -135
  6. data/lib/acf/right_acf_invalidations.rb +144 -0
  7. data/lib/acf/right_acf_origin_access_identities.rb +4 -4
  8. data/lib/acf/right_acf_streaming_interface.rb +19 -26
  9. data/lib/acw/right_acw_interface.rb +1 -2
  10. data/lib/as/right_as_interface.rb +6 -7
  11. data/lib/awsbase/right_awsbase.rb +287 -91
  12. data/lib/awsbase/support.rb +2 -82
  13. data/lib/awsbase/version.rb +9 -0
  14. data/lib/ec2/right_ec2.rb +101 -38
  15. data/lib/ec2/right_ec2_ebs.rb +71 -58
  16. data/lib/ec2/right_ec2_images.rb +82 -42
  17. data/lib/ec2/right_ec2_instances.rb +74 -44
  18. data/lib/ec2/right_ec2_placement_groups.rb +108 -0
  19. data/lib/ec2/right_ec2_reserved_instances.rb +50 -46
  20. data/lib/ec2/right_ec2_security_groups.rb +148 -32
  21. data/lib/ec2/right_ec2_spot_instances.rb +53 -27
  22. data/lib/ec2/right_ec2_tags.rb +139 -0
  23. data/lib/ec2/right_ec2_vpc.rb +151 -139
  24. data/lib/ec2/right_ec2_windows_mobility.rb +84 -0
  25. data/lib/elb/right_elb_interface.rb +93 -18
  26. data/lib/iam/right_iam_access_keys.rb +71 -0
  27. data/lib/iam/right_iam_groups.rb +195 -0
  28. data/lib/iam/right_iam_interface.rb +341 -0
  29. data/lib/iam/right_iam_mfa_devices.rb +67 -0
  30. data/lib/iam/right_iam_users.rb +251 -0
  31. data/lib/rds/right_rds_interface.rb +513 -202
  32. data/lib/right_aws.rb +12 -12
  33. data/lib/route_53/right_route_53_interface.rb +630 -0
  34. data/lib/s3/right_s3.rb +9 -12
  35. data/lib/s3/right_s3_interface.rb +10 -11
  36. data/lib/sdb/active_sdb.rb +18 -33
  37. data/lib/sdb/right_sdb_interface.rb +36 -4
  38. data/lib/sqs/right_sqs.rb +1 -2
  39. data/lib/sqs/right_sqs_gen2.rb +0 -1
  40. data/lib/sqs/right_sqs_gen2_interface.rb +4 -5
  41. data/lib/sqs/right_sqs_interface.rb +6 -7
  42. data/right_aws.gemspec +91 -0
  43. data/test/awsbase/test_helper.rb +2 -0
  44. data/test/awsbase/test_right_awsbase.rb +12 -0
  45. data/test/s3/test_right_s3.rb +1 -1
  46. data/test/sdb/test_active_sdb.rb +1 -1
  47. data/test/sdb/test_batch_put_attributes.rb +54 -0
  48. data/test/sqs/test_right_sqs.rb +0 -6
  49. data/test/sqs/test_right_sqs_gen2.rb +1 -1
  50. metadata +109 -58
@@ -35,32 +35,28 @@ module RightAws
35
35
  # 'Owner' => ['self', ..., 'userN'],
36
36
  # 'ExecutableBy' => ['self', 'all', ..., 'userN']
37
37
  # }
38
- def ec2_describe_images(params={}, image_type=nil, cache_for=nil) #:nodoc:
38
+ def ec2_describe_images(params={}, options={}, cache_for=nil) #:nodoc:
39
39
  request_hash = {}
40
- params.each do |list_by, list|
41
- request_hash.merge! amazonize_list(list_by, Array(list))
42
- end
43
- request_hash['ImageType'] = image_type if image_type
40
+ params.each { |list_by, list| request_hash.merge! amazonize_list(list_by, Array(list)) }
41
+ request_hash.merge!(amazonize_list(['Filter.?.Name', 'Filter.?.Value.?'], options[:filters])) unless options[:filters].right_blank?
44
42
  link = generate_request("DescribeImages", request_hash)
45
43
  request_cache_or_info cache_for, link, QEc2DescribeImagesParser, @@bench, cache_for
46
44
  rescue Exception
47
45
  on_exception
48
46
  end
49
47
 
50
- # Retrieve a list of images. Returns array of hashes describing the images or an exception:
51
- # +image_type+ = 'machine' || 'kernel' || 'ramdisk'
48
+ # Retrieve a list of images.
49
+ #
50
+ # Accepts a list of images and/or a set of filters as the last parameter.
51
+ #
52
+ # Filters: architecture, block-device-mapping.delete-on-termination block-device-mapping.device-name,
53
+ # block-device-mapping.snapshot-id, block-device-mapping.volume-size, description, image-id, image-type,
54
+ # is-public, kernel-id, manifest-location, name, owner-alias, owner-id, platform, product-code,
55
+ # ramdisk-id, root-device-name, root-device-type, state, state-reason-code, state-reason-message,
56
+ # tag-key, tag-value, tag:key, virtualization-type
52
57
  #
53
58
  # ec2.describe_images #=>
54
- # [{:aws_id=>"ami-b0a1f7a6",
55
- # :aws_image_type=>"machine",
56
- # :root_device_name=>"/dev/sda1",
57
- # :image_class=>"static",
58
- # :aws_owner=>"826693181925",
59
- # :aws_location=>"bucket_for_k_dzreyev/image_bundles/kd__CentOS_1_10_2009_10_21_13_30_43_MSD/image.manifest.xml",
60
- # :aws_state=>"available",
61
- # :aws_is_public=>false,
62
- # :aws_architecture=>"i386"},
63
- # {:description=>"EBS backed Fedora core 8 i386",
59
+ # [{:description=>"EBS backed Fedora core 8 i386",
64
60
  # :aws_architecture=>"i386",
65
61
  # :aws_id=>"ami-c2a3f5d4",
66
62
  # :aws_image_type=>"machine",
@@ -75,43 +71,79 @@ module RightAws
75
71
  # :device_name=>"/dev/sda1"}],
76
72
  # :name=>"EBS backed FC8 i386",
77
73
  # :aws_is_public=>true}, ... ]
78
- #
79
- # If +list+ param is set, then retrieve information about the listed images only:
80
74
  #
81
- # ec2.describe_images(['ami-5aa1f74c'])
75
+ # ec2.describe_images(:filters => { 'image-type' => 'kernel', 'state' => 'available', 'tag:MyTag' => 'MyValue'})
76
+ #
77
+ # ec2.describe_images("ari-fda54b94", "ami-2ee80247", "aki-00896a69",
78
+ # :filters => { 'image-type' => 'kernel', 'state' => 'available' }) #=>
79
+ # [{:root_device_type=>"instance-store",
80
+ # :aws_id=>"aki-00896a69",
81
+ # :aws_image_type=>"kernel",
82
+ # :aws_location=>
83
+ # "karmic-kernel-zul/ubuntu-kernel-2.6.31-300-ec2-i386-20091002-test-04.manifest.xml",
84
+ # :virtualization_type=>"paravirtual",
85
+ # :aws_state=>"available",
86
+ # :aws_owner=>"099720109477",
87
+ # :tags=>{},
88
+ # :aws_is_public=>true,
89
+ # :aws_architecture=>"i386"}]
90
+ #
91
+ # P.S. filters: http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference-query-DescribeImages.html
82
92
  #
83
- def describe_images(images=[], image_type=nil)
84
- images = Array(images)
85
- cache_for = images.empty? && !image_type ? :describe_images : nil
86
- ec2_describe_images({ 'ImageId' => images }, image_type, cache_for)
93
+ def describe_images(*list_and_options)
94
+ list, options = AwsUtils::split_items_and_params(list_and_options)
95
+ cache_for = (list.right_blank? && options[:filters].right_blank?) ? :describe_images : nil
96
+ ec2_describe_images( {'ImageId'=>list}, options, cache_for)
87
97
  end
88
98
 
89
- # Example:
99
+ # Retrieve a list of images by image owner.
100
+ #
101
+ # Accepts a list of images and/or a set of filters as the last parameter.
102
+ #
103
+ # Filters: architecture, block-device-mapping.delete-on-termination block-device-mapping.device-name,
104
+ # block-device-mapping.snapshot-id, block-device-mapping.volume-size, description, image-id, image-type,
105
+ # is-public, kernel-id, manifest-location, name, owner-alias, owner-id, platform, product-code,
106
+ # ramdisk-id, root-device-name, root-device-type, state, state-reason-code, state-reason-message,
107
+ # tag-key, tag-value, tag:key, virtualization-type
90
108
  #
91
109
  # ec2.describe_images_by_owner('522821470517')
92
- # ec2.describe_images_by_owner('self')
110
+ # ec2.describe_images_by_owner('self', :filters => { 'block-device-mapping.delete-on-termination' => 'false' })
93
111
  #
94
- def describe_images_by_owner(owners=['self'], image_type=nil)
95
- owners = Array(owners)
96
- cache_for = (owners == ['self']) && (!image_type ? :describe_images_by_owner : nil)
97
- ec2_describe_images({ 'Owner' => owners }, image_type, cache_for)
112
+ # P.S. filters: http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference-query-DescribeImages.html
113
+ #
114
+ def describe_images_by_owner(*list_and_options)
115
+ list, options = AwsUtils::split_items_and_params(list_and_options)
116
+ list = ['self'] if list.right_blank?
117
+ cache_for = (list==['self'] && options[:filters].right_blank?) ? :describe_images_by_owner : nil
118
+ ec2_describe_images( {'Owner'=>list}, options, cache_for)
98
119
  end
99
120
 
100
- # Example:
121
+ # Retrieve a list of images by image executable by.
122
+ #
123
+ # Accepts a list of images and/or a set of filters as the last parameter.
124
+ #
125
+ # Filters: architecture, block-device-mapping.delete-on-termination block-device-mapping.device-name,
126
+ # block-device-mapping.snapshot-id, block-device-mapping.volume-size, description, image-id, image-type,
127
+ # is-public, kernel-id, manifest-location, name, owner-alias, owner-id, platform, product-code,
128
+ # ramdisk-id, root-device-name, root-device-type, state, state-reason-code, state-reason-message,
129
+ # tag-key, tag-value, tag:key, virtualization-type
101
130
  #
102
131
  # ec2.describe_images_by_executable_by('522821470517')
103
132
  # ec2.describe_images_by_executable_by('self')
104
- # ec2.describe_images_by_executable_by('all')
133
+ # ec2.describe_images_by_executable_by('all', :filters => { 'architecture' => 'i386' })
134
+ #
135
+ # P.S. filters: http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference-query-DescribeImages.html
105
136
  #
106
- def describe_images_by_executable_by(executable_by=['self'], image_type=nil)
107
- executable_by = Array(executable_by)
108
- cache_for = (executable_by==['self']) && (!image_type ? :describe_images_by_executable_by : nil)
109
- ec2_describe_images({ 'ExecutableBy' => executable_by }, image_type, cache_for)
137
+ def describe_images_by_executable_by(*list_and_options)
138
+ list, options = AwsUtils::split_items_and_params(list_and_options)
139
+ list = ['self'] if list.right_blank?
140
+ cache_for = (list==['self'] && options[:filters].right_blank?) ? :describe_images_by_executable_by : nil
141
+ ec2_describe_images( {'ExecutableBy'=>list}, options, cache_for)
110
142
  end
111
143
 
112
-
113
144
  # Register new image at Amazon.
114
- # Options: :image_location, :name, :description, :architecture, :kernel_id, :ramdisk_id, :root_device_name, :block_device_mappings.
145
+ # Options: :image_location, :name, :description, :architecture, :kernel_id, :ramdisk_id,
146
+ # :root_device_name, :block_device_mappings, :virtualizationt_type(hvm|paravirtual)
115
147
  #
116
148
  # Returns new image id.
117
149
  #
@@ -148,6 +180,7 @@ module RightAws
148
180
  params['KernelId'] = options[:kernel_id] if options[:kernel_id]
149
181
  params['RamdiskId'] = options[:ramdisk_id] if options[:ramdisk_id]
150
182
  params['RootDeviceName'] = options[:root_device_name] if options[:root_device_name]
183
+ params['VirtualizationType'] = options[:virtualization_type] if options[:virtualization_type]
151
184
  # params['SnapshotId'] = options[:snapshot_id] if options[:snapshot_id]
152
185
  params.merge!(amazonize_block_device_mappings(options[:block_device_mappings]))
153
186
  link = generate_request("RegisterImage", params)
@@ -269,8 +302,8 @@ module RightAws
269
302
  #
270
303
  def create_image(instance_aws_id, options={})
271
304
  params = { 'InstanceId' => instance_aws_id }
272
- params['Name'] = options[:name] unless options[:name].blank?
273
- params['Description'] = options[:description] unless options[:description].blank?
305
+ params['Name'] = options[:name] unless options[:name].right_blank?
306
+ params['Description'] = options[:description] unless options[:description].right_blank?
274
307
  params['NoReboot'] = options[:no_reboot].to_s unless options[:no_reboot].nil?
275
308
  link = generate_request("CreateImage", params)
276
309
  request_info(link, QEc2RegisterImageParser.new(:logger => @logger))
@@ -283,10 +316,13 @@ module RightAws
283
316
  class QEc2DescribeImagesParser < RightAWSParser #:nodoc:
284
317
  def tagstart(name, attributes)
285
318
  case full_tag_name
286
- when %r{/imagesSet/item$} then @item = {}
319
+ when %r{/imagesSet/item$}
320
+ @item = { :tags => {} }
287
321
  when %r{/blockDeviceMapping/item$}
288
322
  @item[:block_device_mappings] ||= []
289
323
  @block_device_mapping = {}
324
+ when %r{/tagSet/item$}
325
+ @aws_tag = {}
290
326
  end
291
327
  end
292
328
  def tagend(name)
@@ -308,6 +344,7 @@ module RightAws
308
344
  when 'rootDeviceType' then @item[:root_device_type] = @text
309
345
  when 'rootDeviceName' then @item[:root_device_name] = @text
310
346
  when 'imageClass' then @item[:image_class] = @text
347
+ when 'virtualizationType' then @item[:virtualization_type] = @text
311
348
  else
312
349
  case full_tag_name
313
350
  when %r{/stateReason/code$} then @item[:state_reason_code] = @text.to_i
@@ -321,7 +358,10 @@ module RightAws
321
358
  when 'deleteOnTermination' then @block_device_mapping[:ebs_delete_on_termination] = @text == 'true' ? true : false
322
359
  when 'item' then @item[:block_device_mappings] << @block_device_mapping
323
360
  end
324
- when %r{/imagesSet/item$} then @result << @item
361
+ when %r{/tagSet/item/key$} then @aws_tag[:key] = @text
362
+ when %r{/tagSet/item/value$} then @aws_tag[:value] = @text
363
+ when %r{/tagSet/item$} then @item[:tags][@aws_tag[:key]] = @aws_tag[:value]
364
+ when %r{/imagesSet/item$} then @result << @item
325
365
  end
326
366
  end
327
367
  end
@@ -47,8 +47,18 @@ module RightAws
47
47
  on_exception
48
48
  end
49
49
 
50
- # Retrieve information about EC2 instances. If +list+ is omitted then returns the
51
- # list of all instances.
50
+ # Retrieve information about EC2 instances.
51
+ #
52
+ # Accepts a list of instances and/or a set of filters as the last parameter.
53
+ #
54
+ # Filters: architecture, availability-zone, block-device-mapping.attach-time, block-device-mapping.delete-on-termination,
55
+ # block-device-mapping.device-name, block-device-mapping.status, block-device-mapping.volume-id, client-token, dns-name,
56
+ # group-id, image-id, instance-id, instance-lifecycle, instance-state-code, instance-state-name, instance-type, ip-address,
57
+ # kernel-id, key-name, launch-index, launch-time, monitoring-state, owner-id, placement-group-name, platform,
58
+ # private-dns-name, private-ip-address, product-code, ramdisk-id, reason, requester-id, reservation-id, root-device-name,
59
+ # root-device-type, spot-instance-request-id, state-reason-code, state-reason-message, subnet-id, tag-key, tag-value,
60
+ # tag:key, virtualization-type, vpc-id,
61
+ #
52
62
  #
53
63
  # ec2.describe_instances #=>
54
64
  # [{:private_ip_address=>"10.240.7.99",
@@ -84,14 +94,15 @@ module RightAws
84
94
  # :ebs_volume_id=>"vol-f900f990"}],
85
95
  # :aws_instance_id=>"i-8ce84ae4"} , ... ]
86
96
  #
87
- def describe_instances(*instances)
88
- instances = instances.flatten
89
- link = generate_request("DescribeInstances", amazonize_list('InstanceId', instances))
90
- request_cache_or_info(:describe_instances, link, QEc2DescribeInstancesParser, @@bench, instances.blank?) do |parser|
97
+ # ec2.describe_instances("i-8ce84ae6", "i-8ce84ae8", "i-8ce84ae0")
98
+ # ec2.describe_instances(:filters => { 'availability-zone' => 'us-east-1a', 'instance-type' => 'c1.medium' })
99
+ #
100
+ # P.S. filters: http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference-query-DescribeInstances.html
101
+ #
102
+ def describe_instances(*list_and_options)
103
+ describe_resources_with_list_and_options('DescribeInstances', 'InstanceId', QEc2DescribeInstancesParser, list_and_options) do |parser|
91
104
  get_desc_instances(parser.result)
92
105
  end
93
- rescue Exception
94
- on_exception
95
106
  end
96
107
 
97
108
  # Return the product code attached to instance or +nil+ otherwise.
@@ -131,7 +142,8 @@ module RightAws
131
142
  addressing_type = nil, instance_type = nil,
132
143
  kernel_id = nil, ramdisk_id = nil, availability_zone = nil,
133
144
  monitoring_enabled = nil, subnet_id = nil, disable_api_termination = nil,
134
- instance_initiated_shutdown_behavior = nil, block_device_mappings = nil)
145
+ instance_initiated_shutdown_behavior = nil, block_device_mappings = nil,
146
+ placement_group_name = nil, client_token = nil)
135
147
  launch_instances(image_id, { :min_count => min_count,
136
148
  :max_count => max_count,
137
149
  :user_data => user_data,
@@ -146,14 +158,16 @@ module RightAws
146
158
  :subnet_id => subnet_id,
147
159
  :disable_api_termination => disable_api_termination,
148
160
  :instance_initiated_shutdown_behavior => instance_initiated_shutdown_behavior,
149
- :block_device_mappings => block_device_mappings
161
+ :block_device_mappings => block_device_mappings,
162
+ :placement_group_name => placement_group_name,
163
+ :client_token => client_token
150
164
  })
151
165
  end
152
166
 
153
167
  # Launch new EC2 instances.
154
168
  # Options: :image_id, :addressing_type, :min_count, max_count, :key_name, :kernel_id, :ramdisk_id,
155
169
  # :availability_zone, :monitoring_enabled, :subnet_id, :disable_api_termination, :instance_initiated_shutdown_behavior,
156
- # :block_device_mappings
170
+ # :block_device_mappings, :placement_group_name, :license_pool
157
171
  #
158
172
  # Returns a list of launched instances or an exception.
159
173
  #
@@ -191,12 +205,12 @@ module RightAws
191
205
  # :aws_instance_id=>"i-8ce84ae4"}]
192
206
  #
193
207
  def launch_instances(image_id, options={})
194
- @logger.info("Launching instance of image #{image_id} for #{@aws_access_key_id}, " +
195
- "key: #{options[:key_name]}, groups: #{Array(options[:group_ids]).join(',')}")
196
208
  options[:image_id] = image_id
197
209
  options[:min_count] ||= 1
198
210
  options[:max_count] ||= options[:min_count]
199
211
  params = prepare_instance_launch_params(options)
212
+ # Log debug information
213
+ @logger.info("Launching instance of image #{image_id}. Options: #{params.inspect}")
200
214
  link = generate_request("RunInstances", params)
201
215
  instances = request_info(link, QEc2DescribeInstancesParser.new(:logger => @logger))
202
216
  get_desc_instances(instances)
@@ -207,30 +221,32 @@ module RightAws
207
221
  def prepare_instance_launch_params(options={}) # :nodoc:
208
222
  params = amazonize_list('SecurityGroup', Array(options[:group_ids]))
209
223
  params['InstanceType'] = options[:instance_type] || DEFAULT_INSTANCE_TYPE
210
- params['ImageId'] = options[:image_id] unless options[:image_id].blank?
211
- params['AddressingType'] = options[:addressing_type] unless options[:addressing_type].blank?
212
- params['MinCount'] = options[:min_count] unless options[:min_count].blank?
213
- params['MaxCount'] = options[:max_count] unless options[:max_count].blank?
214
- params['KeyName'] = options[:key_name] unless options[:key_name].blank?
215
- params['KernelId'] = options[:kernel_id] unless options[:kernel_id].blank?
216
- params['RamdiskId'] = options[:ramdisk_id] unless options[:ramdisk_id].blank?
217
- params['Placement.AvailabilityZone'] = options[:availability_zone] unless options[:availability_zone].blank?
224
+ params['ImageId'] = options[:image_id] unless options[:image_id].right_blank?
225
+ params['AddressingType'] = options[:addressing_type] unless options[:addressing_type].right_blank?
226
+ params['MinCount'] = options[:min_count] unless options[:min_count].right_blank?
227
+ params['MaxCount'] = options[:max_count] unless options[:max_count].right_blank?
228
+ params['KeyName'] = options[:key_name] unless options[:key_name].right_blank?
229
+ params['KernelId'] = options[:kernel_id] unless options[:kernel_id].right_blank?
230
+ params['RamdiskId'] = options[:ramdisk_id] unless options[:ramdisk_id].right_blank?
231
+ params['Placement.AvailabilityZone'] = options[:availability_zone] unless options[:availability_zone].right_blank?
218
232
  params['Monitoring.Enabled'] = options[:monitoring_enabled].to_s if options[:monitoring_enabled]
219
- params['SubnetId'] = options[:subnet_id] unless options[:subnet_id].blank?
220
- params['AdditionalInfo'] = options[:additional_info] unless options[:additional_info].blank?
233
+ params['SubnetId'] = options[:subnet_id] unless options[:subnet_id].right_blank?
234
+ params['AdditionalInfo'] = options[:additional_info] unless options[:additional_info].right_blank?
221
235
  params['DisableApiTermination'] = options[:disable_api_termination].to_s unless options[:disable_api_termination].nil?
222
- params['InstanceInitiatedShutdownBehavior'] = options[:instance_initiated_shutdown_behavior] unless options[:instance_initiated_shutdown_behavior].blank?
223
- # params['VolumeId'] = options[:volume_id] unless options[:volume_id].blank?
224
- # params['RootDeviceName'] = options[:root_device_name] unless options[:root_device_name].blank?
225
- # params['RootDeviceType'] = options[:root_device_type] unless options[:root_device_type].blank?
236
+ params['InstanceInitiatedShutdownBehavior'] = options[:instance_initiated_shutdown_behavior] unless options[:instance_initiated_shutdown_behavior].right_blank?
237
+ params['Placement.GroupName'] = options[:placement_group_name] unless options[:placement_group_name].right_blank?
238
+ params['License.Pool'] = options[:license_pool] unless options[:license_pool].right_blank?
239
+ params['ClientToken'] = options[:client_token] || AwsUtils::generate_unique_token
226
240
  params.merge!(amazonize_block_device_mappings(options[:block_device_mappings]))
227
- unless options[:user_data].blank?
228
- options[:user_data].strip!
229
- # Do not use CGI::escape(encode64(...)) as it is done in Amazons EC2 library.
230
- # Amazon 169.254.169.254 does not like escaped symbols!
231
- # And it doesn't like "\n" inside of encoded string! Grrr....
232
- # Otherwise, some of UserData symbols will be lost...
233
- params['UserData'] = Base64.encode64(options[:user_data]).delete("\n") unless options[:user_data].blank?
241
+ # KD: https://github.com/rightscale/right_aws/issues#issue/11
242
+ # Do not modify user data and pass it as is: one may pass there a hex-binary data
243
+ options[:user_data] = options[:user_data].to_s
244
+ unless options[:user_data].empty?
245
+ # Do not use CGI::escape(encode64(...)) as it is done in Amazons EC2 library.
246
+ # Amazon 169.254.169.254 does not like escaped symbols!
247
+ # And it doesn't like "\n" inside of encoded string! Grrr....
248
+ # Otherwise, some of UserData symbols will be lost...
249
+ params['UserData'] = Base64.encode64(options[:user_data]).delete("\n")
234
250
  end
235
251
  params
236
252
  end
@@ -429,7 +445,7 @@ module RightAws
429
445
  link = generate_request('GetPasswordData',
430
446
  'InstanceId' => instance_id )
431
447
  response = request_info(link, QEc2GetPasswordDataParser.new(:logger => @logger))
432
- if response[:password_data].blank?
448
+ if response[:password_data].right_blank?
433
449
  raise AwsError.new("Initial password is not yet created for #{instance_id}")
434
450
  else
435
451
  OpenSSL::PKey::RSA.new(private_key).private_decrypt(Base64.decode64(response[:password_data]))
@@ -483,9 +499,13 @@ module RightAws
483
499
  end
484
500
 
485
501
  # Describe the status of the Windows AMI bundlings.
486
- # If +list+ is omitted the returns the whole list of tasks.
487
502
  #
488
- # ec2.describe_bundle_tasks(['bun-4fa74226']) #=>
503
+ # Accepts a list of tasks and/or a set of filters as the last parameter.
504
+ #
505
+ # Filters" bundle-id, error-code, error-message, instance-id, progress, s3-aws-access-key-id, s3-bucket, s3-prefix,
506
+ # start-time, state, update-time
507
+ #
508
+ # ec2.describe_bundle_tasks('bun-4fa74226') #=>
489
509
  # [{:s3_bucket => "my-awesome-bucket"
490
510
  # :aws_id => "bun-0fa70206",
491
511
  # :s3_prefix => "win1pr",
@@ -497,12 +517,12 @@ module RightAws
497
517
  # :aws_state => "failed",
498
518
  # :aws_instance_id => "i-e3e24e8a"}]
499
519
  #
500
- def describe_bundle_tasks(*tasks)
501
- tasks = tasks.flatten
502
- link = generate_request("DescribeBundleTasks", amazonize_list('BundleId', tasks))
503
- request_info(link, QEc2DescribeBundleTasksParser.new)
504
- rescue Exception
505
- on_exception
520
+ # ec2.describe_bundle_tasks(:filters => { 'state' => 'pending' })
521
+ #
522
+ # P.S. filters: http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeBundleTasks.html
523
+ #
524
+ def describe_bundle_tasks(*list_and_options)
525
+ describe_resources_with_list_and_options('DescribeBundleTasks', 'BundleId', QEc2DescribeBundleTasksParser, list_and_options)
506
526
  end
507
527
 
508
528
  # Cancel an in‐progress or pending bundle task by id.
@@ -545,10 +565,13 @@ module RightAws
545
565
  :ami_launch_index => '',
546
566
  :ssh_key_name => '',
547
567
  :aws_state => '',
548
- :aws_product_codes => [] }
568
+ :aws_product_codes => [],
569
+ :tags => {} }
549
570
  when %r{blockDeviceMapping/item$}
550
571
  @item[:block_device_mappings] ||= []
551
572
  @block_device_mapping = {}
573
+ when %r{/tagSet/item$}
574
+ @aws_tag = {}
552
575
  end
553
576
  end
554
577
  def tagend(name)
@@ -581,6 +604,9 @@ module RightAws
581
604
  when 'instanceLifecycle' then @item[:instance_lifecycle] = @text
582
605
  when 'spotInstanceRequestId' then @item[:spot_instance_request_id] = @text
583
606
  when 'requesterId' then @item[:requester_id] = @text
607
+ when 'groupName' then @item[:placement_group_name] = @text
608
+ when 'virtualizationType' then @item[:virtualization_type] = @text
609
+ when 'clientToken' then @item[:client_token] = @text
584
610
  else
585
611
  case full_tag_name
586
612
  when %r{/stateReason/code$} then @item[:state_reason_code] = @text
@@ -588,6 +614,7 @@ module RightAws
588
614
  when %r{/instanceState/code$} then @item[:aws_state_code] = @text.to_i
589
615
  when %r{/instanceState/name$} then @item[:aws_state] = @text
590
616
  when %r{/monitoring/state$} then @item[:monitoring_state] = @text
617
+ when %r{/license/pool$} then @item[:license_pool] = @text
591
618
  when %r{/blockDeviceMapping/item} # no trailing $
592
619
  case name
593
620
  when 'deviceName' then @block_device_mapping[:device_name] = @text
@@ -599,6 +626,9 @@ module RightAws
599
626
  when 'item' then @item[:block_device_mappings] << @block_device_mapping
600
627
  end
601
628
  when %r{/instancesSet/item$} then @reservation[:instances_set] << @item
629
+ when %r{/tagSet/item/key$} then @aws_tag[:key] = @text
630
+ when %r{/tagSet/item/value$} then @aws_tag[:value] = @text
631
+ when %r{/tagSet/item$} then @item[:tags][@aws_tag[:key]] = @aws_tag[:value]
602
632
  when 'DescribeInstancesResponse/reservationSet/item',
603
633
  'RunInstancesResponse'
604
634
  @result << @reservation
@@ -0,0 +1,108 @@
1
+ #
2
+ # Copyright (c) 2010 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+
24
+ module RightAws
25
+
26
+ class Ec2
27
+
28
+ #-----------------------------------------------------------------
29
+ # Placement Groups
30
+ #-----------------------------------------------------------------
31
+
32
+ # Describe placement groups.
33
+ #
34
+ # Accepts a list of placement groups and/or a set of filters as the last parameter.
35
+ #
36
+ # Filters: group-name, state, strategy
37
+ #
38
+ # If you don’t specify a particular placement group, the response includes
39
+ # information about all of them. The information includes the group name, the strategy,
40
+ # and the group state (e.g., pending, available, etc.).
41
+ #
42
+ # ec2.describe_placement_groups #=>
43
+ # [{:state=>"available", :strategy=>"cluster", :group_name=>"kd_first"},
44
+ # {:state=>"available", :strategy=>"cluster", :group_name=>"kd_second"}]
45
+ #
46
+ # ec2.describe_placement_groups('kd_second') #=>
47
+ # [{:strategy=>"cluster", :group_name=>"kd_second", :state=>"available"}]
48
+ #
49
+ # P.S. filters: http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference_query_DescribePlacementGroups.html
50
+ #
51
+ def describe_placement_groups(*list_and_options)
52
+ describe_resources_with_list_and_options('DescribePlacementGroups', 'GroupName', QEc2DescribePlacementGroupsParser, list_and_options)
53
+ end
54
+
55
+ # Create placement group creates a placement group (i.e. logical cluster group)
56
+ # into which you can then launch instances. You must provide a name for the group
57
+ # that is unique within the scope of your account. You must also provide a strategy
58
+ # value. Currently the only value accepted is cluster.
59
+ #
60
+ # ec2.create_placement_group('kd_second') #=> true
61
+ #
62
+ def create_placement_group(placement_group_name, strategy = 'cluster')
63
+ link = generate_request('CreatePlacementGroup',
64
+ 'GroupName' => placement_group_name.to_s,
65
+ 'Strategy' => strategy.to_s)
66
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
67
+ rescue Exception
68
+ on_exception
69
+ end
70
+
71
+ # Delete placement group deletes a placement group that you own. The group must not
72
+ # contain any instances.
73
+ #
74
+ # ec2.delete_placement_group('kd_second') #=> true
75
+ #
76
+ def delete_placement_group(placement_group_name)
77
+ link = generate_request('DeletePlacementGroup',
78
+ 'GroupName' => placement_group_name.to_s)
79
+ request_info(link, RightBoolResponseParser.new(:logger => @logger))
80
+ rescue Exception
81
+ on_exception
82
+ end
83
+
84
+ #-----------------------------------------------------------------
85
+ # PARSERS: Placement Groups
86
+ #-----------------------------------------------------------------
87
+
88
+ class QEc2DescribePlacementGroupsParser < RightAWSParser #:nodoc:
89
+ def tagstart(name, attributes)
90
+ case name
91
+ when 'item' then @item = {}
92
+ end
93
+ end
94
+ def tagend(name)
95
+ case name
96
+ when 'groupName' then @item[:group_name] = @text
97
+ when 'strategy' then @item[:strategy] = @text
98
+ when 'state' then @item[:state] = @text
99
+ when 'item' then @result << @item
100
+ end
101
+ end
102
+ def reset
103
+ @result = []
104
+ end
105
+ end
106
+
107
+ end
108
+ end