awsum 0.5 → 0.5.1

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