awsum 0.5 → 0.5.1

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 (43) hide show
  1. data/Gemfile +1 -1
  2. data/Gemfile.lock +14 -20
  3. data/README.rdoc +1 -1
  4. data/Rakefile +3 -3
  5. data/functional/ec2/instances_spec.rb +46 -0
  6. data/functional/spec_helper.rb +71 -0
  7. data/lib/awsum.rb +2 -2
  8. data/lib/awsum/ec2.rb +85 -68
  9. data/lib/awsum/ec2/image.rb +1 -1
  10. data/lib/awsum/ec2/instance.rb +35 -6
  11. data/lib/awsum/ec2/parsers/image_parser.rb +3 -5
  12. data/lib/awsum/ec2/parsers/instance_parser.rb +24 -15
  13. data/lib/awsum/ec2/parsers/snapshot_parser.rb +3 -3
  14. data/lib/awsum/ec2/parsers/tag_parser.rb +56 -0
  15. data/lib/awsum/ec2/parsers/volume_parser.rb +3 -5
  16. data/lib/awsum/ec2/region.rb +8 -5
  17. data/lib/awsum/ec2/security_group.rb +12 -16
  18. data/lib/awsum/ec2/snapshot.rb +9 -0
  19. data/lib/awsum/ec2/state.rb +22 -0
  20. data/lib/awsum/ec2/tag.rb +17 -0
  21. data/lib/awsum/ec2/volume.rb +12 -2
  22. data/lib/awsum/requestable.rb +53 -3
  23. data/spec/fixtures/ec2/authorize_group_access.xml +12 -0
  24. data/spec/fixtures/ec2/create_security_group.xml +3 -3
  25. data/spec/fixtures/ec2/delete_security_group.xml +3 -3
  26. data/spec/fixtures/ec2/purchase_reserved_instances_offering2.xml +5 -0
  27. data/spec/fixtures/ec2/tags.xml +12 -0
  28. data/spec/lib/awsum/ec2/image_spec.rb +60 -0
  29. data/spec/lib/awsum/ec2/instance_spec.rb +39 -1
  30. data/spec/lib/awsum/ec2/parsers/instance_parser_spec.rb +4 -3
  31. data/spec/lib/awsum/ec2/parsers/tag_parser_spec.rb +29 -0
  32. data/spec/lib/awsum/ec2/region_spec.rb +31 -2
  33. data/spec/lib/awsum/ec2/reserved_instance_spec.rb +3 -19
  34. data/spec/lib/awsum/ec2/security_group_spec.rb +123 -51
  35. data/spec/lib/awsum/ec2/snapshots_spec.rb +27 -1
  36. data/spec/lib/awsum/ec2/state_spec.rb +11 -0
  37. data/spec/lib/awsum/ec2/tag_spec.rb +45 -0
  38. data/spec/lib/awsum/ec2/volume_spec.rb +47 -0
  39. data/spec/lib/awsum/requestable_spec.rb +1 -1
  40. data/tools/dump.rb +55 -0
  41. metadata +176 -32
  42. data/.gitignore +0 -5
  43. data/spec/fixtures/ec2/purchase_reserved_instances_offerings.xml +0 -6
@@ -48,7 +48,7 @@ module Awsum
48
48
  # * <tt>:key_name</tt> - The name of the key pair with which to launch instances
49
49
  # * <tt>:security_groups</tt> - The names of security groups to associate launched instances with
50
50
  # * <tt>:user_data</tt> - User data made available to instances (Note: Must be 16K or less, will be base64 encoded by Awsum)
51
- # * <tt>:instance_type</tt> - The size of the instances to launch, can be one of [m1.small, m1.large, m1.xlarge, c1.medium, c1.xlarge], default is m1.small
51
+ # * <tt>:instance_type</tt> - The size of the instances to launch, can be one of [m1.small, m1.large, m1.xlarge, c1.medium, c1.xlarge, m2.xlarge, m2.2xlarge, m2.4xlarge, cc1.4xlarge, cg1.4xlarge, t1.micro], default is m1.small
52
52
  # * <tt>:availability_zone</tt> - The name of the availability zone to launch this instance in
53
53
  # * <tt>:kernel_id</tt> - The ID of the kernel with which to launch instances
54
54
  # * <tt>:ramdisk_id</tt> - The ID of the RAM disk with which to launch instances
@@ -23,6 +23,24 @@ module Awsum
23
23
  @launch_index = launch_index
24
24
  end
25
25
 
26
+ def reload
27
+ replacement_instance = @ec2.instance id
28
+ #TODO: Make this easier
29
+ @image_id = replacement_instance.image_id
30
+ @type = replacement_instance.type
31
+ @state = replacement_instance.state
32
+ @dns_name = replacement_instance.dns_name
33
+ @private_dns_name = replacement_instance.private_dns_name
34
+ @key_name = replacement_instance.key_name
35
+ @kernel_id = replacement_instance.kernel_id
36
+ @launch_time = replacement_instance.launch_time
37
+ @availability_zone = replacement_instance.availability_zone
38
+ @product_codes = replacement_instance.product_codes
39
+ @ramdisk_id = replacement_instance.ramdisk_id
40
+ @reason = replacement_instance.reason
41
+ @launch_index = replacement_instance.launch_index
42
+ end
43
+
26
44
  # Terminates this instance
27
45
  def terminate
28
46
  @ec2.terminate_instances(id)
@@ -36,15 +54,26 @@ module Awsum
36
54
 
37
55
  # Will create and attach a Volume to this Instance
38
56
  # You must specify a size or a snapshot_id
39
- def create_volume(size = nil, snapshot_id = nil, device = '/dev/sdh')
40
- raise ArgumentError.new('You must specify a size if not creating a volume from a snapshot') if size.blank? && snapshot_id.blank?
41
- raise ArgumentError.new('You must specify a device to attach the volume to') unless device
42
-
43
- volume = @ec2.create_volume availability_zone, :size => size, :snapshot_id => snapshot_id
57
+ #
58
+ # ===Options:
59
+ # :tags => Hash of tags
60
+ # :device => Will automatically attach the volume to the specified device
61
+ def create_volume(size_or_snapshot_id, options = {})
62
+ options = {:device => '/dev/sdh'}.merge(options)
63
+ if size_or_snapshot_id.is_a?(Numeric)
64
+ volume = @ec2.create_volume availability_zone, :size => size_or_snapshot_id
65
+ else
66
+ volume = @ec2.create_volume availability_zone, :snapshot_id => size_or_snapshot_id
67
+ end
68
+ if options[:tags]
69
+ @ec2.create_tags(volume.id, options[:tags])
70
+ end
44
71
  while volume.status != 'available'
45
72
  volume.reload
46
73
  end
47
- attach volume, device
74
+ if options[:device]
75
+ attach volume, options[:device]
76
+ end
48
77
  volume
49
78
  end
50
79
 
@@ -10,8 +10,8 @@ module Awsum
10
10
 
11
11
  def tag_start(tag, attributes)
12
12
  case tag
13
- when 'imagesSet'
14
- @stack << 'imagesSet'
13
+ when 'imagesSet', 'blockDeviceMapping', 'productCodes'
14
+ @stack << tag
15
15
  when 'item'
16
16
  case @stack[-1]
17
17
  when 'imagesSet'
@@ -21,8 +21,6 @@ module Awsum
21
21
  @product_codes = []
22
22
  @text = ''
23
23
  end
24
- when 'productCodes'
25
- @stack << 'productCodes'
26
24
  end
27
25
  end
28
26
 
@@ -34,7 +32,7 @@ module Awsum
34
32
  case tag
35
33
  when 'DescribeImagesResponse', 'requestId'
36
34
  #no-op
37
- when 'imagesSet', 'productCodes'
35
+ when 'imagesSet', 'productCodes', 'blockDeviceMapping'
38
36
  @stack.pop
39
37
  when 'item'
40
38
  case @stack[-1]
@@ -12,16 +12,8 @@ module Awsum
12
12
 
13
13
  def tag_start(tag, attributes)
14
14
  case tag
15
- when 'reservationSet'
16
- @stack << 'reservationSet'
17
- when 'instancesSet'
18
- @stack << 'instancesSet'
19
- when 'productCodes'
20
- @stack << 'productCodes'
21
- when 'instanceState'
22
- @stack << 'instanceState'
23
- when 'placement'
24
- @stack << 'placement'
15
+ when 'reservationSet', 'instancesSet', 'productCodes', 'instanceState', 'blockDeviceMapping', 'tagSet', 'placement'
16
+ @stack << tag
25
17
  when 'item'
26
18
  case @stack[-1]
27
19
  when 'reservationSet'
@@ -30,6 +22,10 @@ module Awsum
30
22
  @state = {}
31
23
  when 'productCodes'
32
24
  @product_codes = []
25
+ when 'blockDeviceMapping'
26
+ @blockDeviceMapping = {}
27
+ when 'tagSet'
28
+ @tagSet = {}
33
29
  end
34
30
  end
35
31
  @text = ''
@@ -43,7 +39,7 @@ module Awsum
43
39
  case tag
44
40
  when 'DescribeInstancesResponse', 'requestId', 'reservationId'
45
41
  #no-op
46
- when 'reservationSet', 'instancesSet', 'productCodes', 'instanceState', 'placement'
42
+ when 'reservationSet', 'instancesSet', 'productCodes', 'instanceState', 'placement', 'blockDeviceMapping', 'tagSet'
47
43
  @stack.pop
48
44
  when 'item'
49
45
  case @stack[-1]
@@ -53,7 +49,7 @@ module Awsum
53
49
  @current['instanceId'],
54
50
  @current['imageId'],
55
51
  @current['instanceType'],
56
- @state,
52
+ State.new(@state[:code], @state[:name]),
57
53
  @current['dnsName'],
58
54
  @current['privateDnsName'],
59
55
  @current['keyName'],
@@ -75,9 +71,22 @@ module Awsum
75
71
  when 'name'
76
72
  @state[:name] = @text.strip if @stack[-1] == 'instanceState'
77
73
  else
78
- unless @text.nil? || @current.nil?
79
- text = @text.strip
80
- @current[tag] = (text == '' ? nil : text)
74
+ case @stack[-1]
75
+ when 'blockDeviceMapping'
76
+ unless @text.nil? || @blockDeviceMapping.nil?
77
+ text = @text.strip
78
+ @blockDeviceMapping[tag] = (text == '' ? nil : text)
79
+ end
80
+ when 'tagSet'
81
+ unless @text.nil? || @blockDeviceMapping.nil?
82
+ text = @text.strip
83
+ @blockDeviceMapping[tag] = (text == '' ? nil : text)
84
+ end
85
+ else
86
+ unless @text.nil? || @current.nil?
87
+ text = @text.strip
88
+ @current[tag] = (text == '' ? nil : text)
89
+ end
81
90
  end
82
91
  end
83
92
  end
@@ -15,8 +15,8 @@ module Awsum
15
15
  end
16
16
 
17
17
  case tag
18
- when 'snapshotSet'
19
- @stack << 'snapshotSet'
18
+ when 'snapshotSet', 'tagSet'
19
+ @stack << tag
20
20
  when 'item', 'CreateSnapshotResponse'
21
21
  case @stack[-1]
22
22
  when 'snapshotSet'
@@ -34,7 +34,7 @@ module Awsum
34
34
  case tag
35
35
  when 'DescribeSnapshotsResponts'
36
36
  #no-op
37
- when 'snapshotSet'
37
+ when 'snapshotSet', 'tagSet'
38
38
  @stack.pop
39
39
  when 'item', 'CreateSnapshotResponse'
40
40
  case @stack[-1]
@@ -0,0 +1,56 @@
1
+ module Awsum
2
+ class Ec2
3
+ class TagParser < Awsum::Parser #:nodoc:
4
+ def initialize(ec2)
5
+ @ec2 = ec2
6
+ @tags = []
7
+ @text = nil
8
+ @stack = []
9
+ end
10
+
11
+ def tag_start(tag, attributes)
12
+ case tag
13
+ when 'tagSet'
14
+ @stack << tag
15
+ when 'item'
16
+ case @stack[-1]
17
+ when 'tagSet'
18
+ @current = {}
19
+ end
20
+ end
21
+ @text = ''
22
+ end
23
+
24
+ def text(text)
25
+ @text << text unless @text.nil?
26
+ end
27
+
28
+ def tag_end(tag)
29
+ case tag
30
+ when 'tagSet'
31
+ @stack.pop
32
+ when 'item'
33
+ case @stack[-1]
34
+ when 'tagSet'
35
+ @tags << Tag.new(
36
+ @ec2,
37
+ @current['resourceId'],
38
+ @current['resourceType'],
39
+ @current['key'],
40
+ @current['value']
41
+ )
42
+ end
43
+ else
44
+ unless @text.nil? || @current.nil?
45
+ text = @text.strip
46
+ @current[tag] = (text == '' ? nil : text)
47
+ end
48
+ end
49
+ end
50
+
51
+ def result
52
+ @tags
53
+ end
54
+ end
55
+ end
56
+ end
@@ -15,10 +15,8 @@ module Awsum
15
15
  end
16
16
 
17
17
  case tag
18
- when 'volumeSet'
19
- @stack << 'volumeSet'
20
- when 'attachmentSet'
21
- @stack << 'attachmentSet'
18
+ when 'volumeSet', 'attachmentSet', 'tagSet'
19
+ @stack << tag
22
20
  when 'item', 'CreateVolumeResponse'
23
21
  case @stack[-1]
24
22
  when 'volumeSet'
@@ -37,7 +35,7 @@ module Awsum
37
35
  case tag
38
36
  when 'DescribeVolumesResponse'
39
37
  #no-op
40
- when 'volumeSet', 'attachmentSet'
38
+ when 'volumeSet', 'attachmentSet', 'tagSet'
41
39
  @stack.pop
42
40
  when 'item', 'CreateVolumeResponse'
43
41
  case @stack[-1]
@@ -30,15 +30,18 @@ module Awsum
30
30
  # region.availability_zones
31
31
  # end
32
32
  def use(&block)
33
- old_host = @ec2.host
34
- @ec2.host = end_point
35
33
  if block_given?
36
- block.arity < 1 ? instance_eval(&block) : block[self]
34
+ begin
35
+ old_host = @ec2.host
36
+ @ec2.host = end_point
37
+ block.arity < 1 ? instance_eval(&block) : block[self]
38
+ ensure
39
+ @ec2.host = old_host
40
+ end
37
41
  else
42
+ @ec2.host = end_point
38
43
  self
39
44
  end
40
- ensure
41
- @ec2.host = old_host
42
45
  end
43
46
 
44
47
  private
@@ -14,24 +14,20 @@ module Awsum
14
14
  @group_permissions = group_permissions
15
15
  end
16
16
 
17
- # Authorize access for a group
18
- def authorize_group(group_name, owner_id)
19
- @ec2.authorize_security_group_ingress(@name, :source_security_group_name => group_name, :source_security_group_owner_id => owner_id)
17
+ # Authorize access
18
+ #
19
+ # ===Options:
20
+ # See Ec2#authorize_security_group_ingress
21
+ def authorize(arguments)
22
+ @ec2.authorize_security_group_ingress(@name, arguments)
20
23
  end
21
24
 
22
- # Revoke access for a group
23
- def revoke_group(group_name, owner_id)
24
- @ec2.revoke_security_group_ingress(@name, :source_security_group_name => group_name, :source_security_group_owner_id => owner_id)
25
- end
26
-
27
- # Authorize access for an ip address
28
- def authorize_ip(from_port, to_port, protocol = 'tcp', cidr_ip = '0.0.0.0/0')
29
- @ec2.authorize_security_group_ingress(@name, :ip_protocol => protocol, :from_port => from_port, :to_port => to_port, :cidr_ip => cidr_ip)
30
- end
31
-
32
- # Revoke access from an ip address
33
- def revoke_ip(from_port, to_port, protocol = 'tcp', cidr_ip = '0.0.0.0/0')
34
- @ec2.revoke_security_group_ingress(@name, :ip_protocol => protocol, :from_port => from_port, :to_port => to_port, :cidr_ip => cidr_ip)
25
+ # Revoke access
26
+ #
27
+ # ===Options:
28
+ # See Ec2#revoke_security_group_ingress
29
+ def revoke(arguments)
30
+ @ec2.revoke_security_group_ingress(@name, arguments)
35
31
  end
36
32
 
37
33
  # Delete this SecurityGroup
@@ -18,6 +18,15 @@ module Awsum
18
18
  def delete
19
19
  @ec2.delete_snapshot id
20
20
  end
21
+
22
+ def reload
23
+ reloaded_snapshot = @ec2.snapshot id
24
+
25
+ @volume_id = reloaded_snapshot.volume_id
26
+ @status = reloaded_snapshot.status
27
+ @start_time = reloaded_snapshot.start_time
28
+ @progress = reloaded_snapshot.progress
29
+ end
21
30
  end
22
31
  end
23
32
  end
@@ -0,0 +1,22 @@
1
+ module Awsum
2
+ class Ec2
3
+ class State
4
+ attr_reader :code, :name
5
+
6
+ def initialize(code, name)
7
+ @code = code.to_i
8
+ @name = name
9
+ end
10
+
11
+ def ==(other)
12
+ if other.is_a?(Numeric)
13
+ @code == other
14
+ elsif other.is_a?(String)
15
+ @name == other
16
+ else
17
+ @code = other.code && @name == other.name
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ require 'awsum/ec2/parsers/tag_parser'
2
+
3
+ module Awsum
4
+ class Ec2
5
+ class Tag
6
+ attr_reader :resource_id, :resource_type, :key, :value
7
+
8
+ def initialize(ec2, resource_id, resource_type, key, value) #:nodoc:
9
+ @ec2 = ec2
10
+ @resource_id = resource_id
11
+ @resource_type = resource_type
12
+ @key = key
13
+ @value = value
14
+ end
15
+ end
16
+ end
17
+ end
@@ -50,9 +50,19 @@ module Awsum
50
50
  @ec2.delete_volume id
51
51
  end
52
52
 
53
+ # Force delete this volume
54
+ # will detach it first
55
+ def delete!
56
+ detach true
57
+ while status != 'available'
58
+ reload
59
+ end
60
+ @ec2.delete_volume id
61
+ end
62
+
53
63
  # Creates a Snapshot of this Volume
54
- def create_snapshot
55
- @ec2.create_snapshot id
64
+ def create_snapshot(options = {})
65
+ @ec2.create_snapshot id, options
56
66
  end
57
67
 
58
68
  # Lists the Snapshot(s) of this Volume
@@ -197,14 +197,64 @@ module Awsum
197
197
 
198
198
  # Converts an array of paramters into <param_name>.<num> format
199
199
  def array_to_params(arr, param_name)
200
- arr = [arr] unless arr.is_a?(Array)
200
+ arr = [arr].flatten
201
201
  params = {}
202
- arr.each_with_index do |value,i|
203
- params["#{param_name}.#{i+1}"] = value
202
+ arr.each_with_index do |value, i|
203
+ if value.respond_to?(:keys)
204
+ value.each do |key, val|
205
+ param_key = "#{param_name}.#{i+1}.#{parameterize(key)}"
206
+ if val.is_a?(Array) || val.respond_to?(:keys)
207
+ params.merge! array_to_params(val, param_key)
208
+ else
209
+ params[param_key] = val
210
+ end
211
+ end
212
+ else
213
+ params["#{param_name}.#{i+1}"] = value
214
+ end
204
215
  end
205
216
  params
206
217
  end
207
218
 
219
+ def parameterize(string)
220
+ string.to_s.split(/_/).map{ |w| w.downcase.sub(/^(.)/){ $1.upcase } }.join
221
+ end
222
+
223
+ def parse_filters(filters, tags = nil)
224
+ result = []
225
+ if filters
226
+ filters.each do |k,v|
227
+ values = v.is_a?(Array) ? v : [v]
228
+ result << {:name => k, :value => values}
229
+ end
230
+ end
231
+ if tags
232
+ tags.each do |k,v|
233
+ values = v.is_a?(Array) ? v : [v]
234
+ result << {:name => "tag:#{k}", :value => values}
235
+ end
236
+ end
237
+ if result.size > 0
238
+ array_to_params(result, "Filter")
239
+ else
240
+ {}
241
+ end
242
+ end
243
+
244
+ def parse_tag_keys(tags)
245
+ result = []
246
+ if tags
247
+ tags.each do |k,v|
248
+ result << {:key => k, :value => v}
249
+ end
250
+ end
251
+ if result.size > 0
252
+ array_to_params(result, "Tag")
253
+ else
254
+ {}
255
+ end
256
+ end
257
+
208
258
  # Sign a string with a digest, wrap in HMAC digest and base64 encode
209
259
  #
210
260
  # ===Returns