skippy-amazon-ec2 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,175 @@
1
+ #--
2
+ # Amazon Web Services EC2 Query API Ruby library
3
+ #
4
+ # Ruby Gem Name:: amazon-ec2
5
+ # Author:: Glenn Rempe (mailto:grempe@rubyforge.org)
6
+ # Copyright:: Copyright (c) 2007-2008 Glenn Rempe
7
+ # License:: Distributes under the same terms as Ruby
8
+ # Home:: http://amazon-ec2.rubyforge.org
9
+ #++
10
+
11
+ module EC2
12
+
13
+ # The make_request() and ec2_error? methods, which are shared by all, will raise any
14
+ # exceptions encountered along the way as it converses with EC2.
15
+ #
16
+ # Exception Handling: If for some reason an error occurrs when executing a method
17
+ # (e.g. its arguments were incorrect, or it simply failed) then an exception will
18
+ # be thrown. The exceptions are defined in exceptions.rb as individual classes and should
19
+ # match the exceptions that Amazon has defined for EC2. If the exception raised cannot be
20
+ # identified then a more generic exception class will be thrown.
21
+ #
22
+ # The implication of this is that you need to be prepared to handle any exceptions that
23
+ # may be raised by this library in YOUR code with a 'rescue' clauses. It is up to you
24
+ # how gracefully you want to handle these exceptions that are raised.
25
+
26
+ # Credits :
27
+ # I learned the magic of making an OpenStruct object able to respond as a fully Enumerable
28
+ # object (responds to .each, etc.) thanks to a great blog article on Struct and OpenStruct
29
+ # at http://errtheblog.com/post/30
30
+ #
31
+ # Thanks to Sean Knapp for the XmlSimple response patch which greatly simplified the response
32
+ # mechanism for the whole library while making it more accurate and much less brittle to boot!
33
+ #
34
+
35
+ require 'rubygems'
36
+ begin
37
+ require 'xmlsimple' unless defined? XmlSimple
38
+ rescue Exception => e
39
+ require 'xml-simple' unless defined? XmlSimple
40
+ end
41
+
42
+
43
+ class Response < OpenStruct
44
+
45
+ include Enumerable
46
+
47
+
48
+ def self.parse(options = {})
49
+ options = {
50
+ :xml => "",
51
+ :parse_options => { 'ForceArray' => ['item'], 'SuppressEmpty' => nil }
52
+ }.merge(options)
53
+ response = Response.new(XmlSimple.xml_in(options[:xml], options[:parse_options]))
54
+
55
+ # set the xml attribute of the response object to contain the original XML that was
56
+ # returned by amazon. This allows anyone to bypass our parsing if desired and just
57
+ # get right at the raw XML response.
58
+ response.xml = options[:xml]
59
+ return response
60
+ end
61
+
62
+
63
+ # Every member of an OpenStruct object has getters and setters, the latter of which
64
+ # has a method ending in "=". Find all of these methods, excluding those defined on
65
+ # parent classes.
66
+ def members
67
+ methods(false).sort.grep(/=/).map { |m| m[0...-1] }
68
+ end
69
+
70
+
71
+ # Required by the Enumerable module. Iterate over each item in the members array
72
+ # and pass as a value the block passed to each using yield.
73
+ def each
74
+ members.each do |method|
75
+ yield send(method)
76
+ end
77
+ self
78
+ end
79
+
80
+
81
+ # Same as the each method, but with both key and value.
82
+ #
83
+ #Sample Use:
84
+ # obj.each_pair { |k,v| puts "key: #{k}, value: #{v}" }
85
+ def each_pair
86
+ members.each do |method|
87
+ yield method, send(method)
88
+ end
89
+ self
90
+ end
91
+
92
+
93
+ # Alternative method for getting members.
94
+ def [](member)
95
+ send(member)
96
+ end
97
+
98
+
99
+ # Alternative method for setting members.
100
+ def []=(member, value)
101
+ send("#{member}=", value)
102
+ end
103
+
104
+
105
+ # Helper for converting to string which support a long and short version
106
+ # to avoid recursion problems with parents.
107
+ def to_string(short=false)
108
+ s = "#<#{self.class}:0x#{(2 ** 32 + object_id).to_s(16).upcase}"
109
+ if (short)
110
+ s += " ..."
111
+ else
112
+ each_pair { |k,v|
113
+ if (v == self.parent && v.kind_of?(Response))
114
+ v = v.to_string(true)
115
+ elsif (v.kind_of?(String))
116
+ v = "\"#{v.gsub("\"", "\\\"")}\""
117
+ elsif (v.kind_of?(NilClass))
118
+ v = "nil"
119
+ end
120
+ s += " #{k}=#{v}"
121
+ }
122
+ end
123
+ s += ">"
124
+ return s
125
+ end
126
+
127
+
128
+ # Override of to string method.
129
+ def to_s
130
+ return to_string
131
+ end
132
+
133
+
134
+ private
135
+
136
+ # Initialize the object by passing data to the OpenStruct initialize method
137
+ # and then converting ourself to guarantee we have top-to-bottom data
138
+ # representation as a Response object.
139
+ def initialize(data, parent=nil)
140
+ super(data)
141
+ self.parent = parent
142
+ Response.convert(self, parent)
143
+ end
144
+
145
+
146
+ # The "brains" of our Response class. This method takes an arbitray object and
147
+ # depending on its class attempts to convert it.
148
+ def self.convert(obj, parent)
149
+ if (obj.kind_of?(Response))
150
+ # Recursively convert the object.
151
+ obj.each_pair { |k,v|
152
+ if (v != obj.parent)
153
+ obj[k] = convert(v, obj)
154
+ end
155
+ }
156
+ return obj
157
+ elsif (obj.kind_of?(Hash))
158
+ # Hashes make good Responses already thanks to OpenStruct.
159
+ return Response.new(obj, parent)
160
+ elsif (obj.kind_of?(Array))
161
+ # With arrays, make sure each element is appropriately converted.
162
+ new_arr = []
163
+ obj.each { |elem|
164
+ new_arr << convert(elem, parent)
165
+ }
166
+ return new_arr
167
+ else
168
+ # At this point we're out of ideas, so let's hope it is a string.
169
+ return obj
170
+ end
171
+ end
172
+
173
+ end # class Response < OpenStruct
174
+
175
+ end # module EC2
@@ -0,0 +1,232 @@
1
+ #--
2
+ # Amazon Web Services EC2 Query API Ruby library
3
+ #
4
+ # Ruby Gem Name:: amazon-ec2
5
+ # Author:: Glenn Rempe (mailto:grempe@rubyforge.org)
6
+ # Copyright:: Copyright (c) 2007-2008 Glenn Rempe
7
+ # License:: Distributes under the same terms as Ruby
8
+ # Home:: http://amazon-ec2.rubyforge.org
9
+ #++
10
+
11
+ module EC2
12
+
13
+ class Base
14
+
15
+
16
+ #Amazon Developer Guide Docs:
17
+ #
18
+ # The CreateSecurityGroup operation creates a new security group. Every instance is launched
19
+ # in a security group. If none is specified as part of the launch request then instances
20
+ # are launched in the default security group. Instances within the same security group have
21
+ # unrestricted network access to one another. Instances will reject network access attempts from other
22
+ # instances in a different security group. As the owner of instances you may grant or revoke specific
23
+ # permissions using the AuthorizeSecurityGroupIngress and RevokeSecurityGroupIngress operations.
24
+ #
25
+ #Required Arguments:
26
+ #
27
+ # :group_name => String (default : "")
28
+ # :group_description => String (default : "")
29
+ #
30
+ #Optional Arguments:
31
+ #
32
+ # none
33
+ #
34
+ def create_security_group( options = {} )
35
+
36
+ options = {:group_name => "",
37
+ :group_description => ""
38
+ }.merge(options)
39
+
40
+ raise ArgumentError, "No :group_name provided" if options[:group_name].nil? || options[:group_name].empty?
41
+ raise ArgumentError, "No :group_description provided" if options[:group_description].nil? || options[:group_description].empty?
42
+
43
+ params = {
44
+ "GroupName" => options[:group_name],
45
+ "GroupDescription" => options[:group_description]
46
+ }
47
+
48
+ return response_generator(:action => "CreateSecurityGroup", :params => params)
49
+
50
+ end
51
+
52
+
53
+ #Amazon Developer Guide Docs:
54
+ #
55
+ # The DescribeSecurityGroups operation returns information about security groups owned by the
56
+ # user making the request.
57
+ #
58
+ # An optional list of security group names may be provided to request information for those security
59
+ # groups only. If no security group names are provided, information of all security groups will be
60
+ # returned. If a group is specified that does not exist a fault is returned.
61
+ #
62
+ #Required Arguments:
63
+ #
64
+ # none
65
+ #
66
+ #Optional Arguments:
67
+ #
68
+ # :group_name => Array (default : [])
69
+ #
70
+ def describe_security_groups( options = {} )
71
+
72
+ options = { :group_name => [] }.merge(options)
73
+
74
+ params = pathlist("GroupName", options[:group_name] )
75
+
76
+ return response_generator(:action => "DescribeSecurityGroups", :params => params)
77
+
78
+ end
79
+
80
+
81
+ #Amazon Developer Guide Docs:
82
+ #
83
+ # The DeleteSecurityGroup operation deletes a security group.
84
+ #
85
+ # If an attempt is made to delete a security group and any instances exist that are members of that group a
86
+ # fault is returned.
87
+ #
88
+ #Required Arguments:
89
+ #
90
+ # :group_name => String (default : "")
91
+ #
92
+ #Optional Arguments:
93
+ #
94
+ # none
95
+ #
96
+ def delete_security_group( options = {} )
97
+
98
+ options = { :group_name => "" }.merge(options)
99
+
100
+ raise ArgumentError, "No :group_name provided" if options[:group_name].nil? || options[:group_name].empty?
101
+
102
+ params = { "GroupName" => options[:group_name] }
103
+
104
+ return response_generator(:action => "DeleteSecurityGroup", :params => params)
105
+
106
+ end
107
+
108
+
109
+ #Amazon Developer Guide Docs:
110
+ #
111
+ # The AuthorizeSecurityGroupIngress operation adds permissions to a security group.
112
+ #
113
+ # Permissions are specified in terms of the IP protocol (TCP, UDP or ICMP), the source of the request (by
114
+ # IP range or an Amazon EC2 user-group pair), source and destination port ranges (for TCP and UDP),
115
+ # and ICMP codes and types (for ICMP). When authorizing ICMP, -1 may be used as a wildcard in the
116
+ # type and code fields.
117
+ #
118
+ # Permission changes are propagated to instances within the security group being modified as quickly as
119
+ # possible. However, a small delay is likely, depending on the number of instances that are members of
120
+ # the indicated group.
121
+ #
122
+ # When authorizing a user/group pair permission, GroupName, SourceSecurityGroupName and
123
+ # SourceSecurityGroupOwnerId must be specified. When authorizing a CIDR IP permission,
124
+ # GroupName, IpProtocol, FromPort, ToPort and CidrIp must be specified. Mixing these two types
125
+ # of parameters is not allowed.
126
+ #
127
+ #Required Arguments:
128
+ #
129
+ # :group_name => String (default : "")
130
+ #
131
+ #Optional Arguments:
132
+ #
133
+ # :ip_protocol => String (default : nil) : Required when authorizing CIDR IP permission
134
+ # :from_port => Integer (default : nil) : Required when authorizing CIDR IP permission
135
+ # :to_port => Integer (default : nil) : Required when authorizing CIDR IP permission
136
+ # :cidr_ip => String (default : nil): Required when authorizing CIDR IP permission
137
+ # :source_security_group_name => String (default : nil) : Required when authorizing user group pair permissions
138
+ # :source_security_group_owner_id => String (default : nil) : Required when authorizing user group pair permissions
139
+ #
140
+ def authorize_security_group_ingress( options = {} )
141
+
142
+ # defaults
143
+ options = { :group_name => nil,
144
+ :ip_protocol => nil,
145
+ :from_port => nil,
146
+ :to_port => nil,
147
+ :cidr_ip => nil,
148
+ :source_security_group_name => nil,
149
+ :source_security_group_owner_id => nil }.merge(options)
150
+
151
+ # lets not validate the rest of the possible permutations of required params and instead let
152
+ # EC2 sort it out on the server side. We'll only require :group_name as that is always needed.
153
+ raise ArgumentError, "No :group_name provided" if options[:group_name].nil? || options[:group_name].empty?
154
+
155
+ params = { "GroupName" => options[:group_name],
156
+ "IpProtocol" => options[:ip_protocol],
157
+ "FromPort" => options[:from_port].to_s,
158
+ "ToPort" => options[:to_port].to_s,
159
+ "CidrIp" => options[:cidr_ip],
160
+ "SourceSecurityGroupName" => options[:source_security_group_name],
161
+ "SourceSecurityGroupOwnerId" => options[:source_security_group_owner_id]
162
+ }
163
+
164
+ return response_generator(:action => "AuthorizeSecurityGroupIngress", :params => params)
165
+
166
+ end
167
+
168
+
169
+ #Amazon Developer Guide Docs:
170
+ #
171
+ # The RevokeSecurityGroupIngress operation revokes existing permissions that were previously
172
+ # granted to a security group. The permissions to revoke must be specified using the same values
173
+ # originally used to grant the permission.
174
+ #
175
+ # Permissions are specified in terms of the IP protocol (TCP, UDP or ICMP), the source of the request (by
176
+ # IP range or an Amazon EC2 user-group pair), source and destination port ranges (for TCP and UDP),
177
+ # and ICMP codes and types (for ICMP). When authorizing ICMP, -1 may be used as a wildcard in the
178
+ # type and code fields.
179
+ #
180
+ # Permission changes are propagated to instances within the security group being modified as quickly as
181
+ # possible. However, a small delay is likely, depending on the number of instances that are members of
182
+ # the indicated group.
183
+ #
184
+ # When revoking a user/group pair permission, GroupName, SourceSecurityGroupName and
185
+ # SourceSecurityGroupOwnerId must be specified. When authorizing a CIDR IP permission,
186
+ # GroupName, IpProtocol, FromPort, ToPort and CidrIp must be specified. Mixing these two types
187
+ # of parameters is not allowed.
188
+ #
189
+ #Required Arguments:
190
+ #
191
+ # :group_name => String (default : "")
192
+ #
193
+ #Optional Arguments:
194
+ #
195
+ # :ip_protocol => String (default : nil) : Required when revoking CIDR IP permission
196
+ # :from_port => Integer (default : nil) : Required when revoking CIDR IP permission
197
+ # :to_port => Integer (default : nil) : Required when revoking CIDR IP permission
198
+ # :cidr_ip => String (default : nil): Required when revoking CIDR IP permission
199
+ # :source_security_group_name => String (default : nil) : Required when revoking user group pair permissions
200
+ # :source_security_group_owner_id => String (default : nil) : Required when revoking user group pair permissions
201
+ #
202
+ def revoke_security_group_ingress( options = {} )
203
+
204
+ # defaults
205
+ options = { :group_name => nil,
206
+ :ip_protocol => nil,
207
+ :from_port => nil,
208
+ :to_port => nil,
209
+ :cidr_ip => nil,
210
+ :source_security_group_name => nil,
211
+ :source_security_group_owner_id => nil }.merge(options)
212
+
213
+ # lets not validate the rest of the possible permutations of required params and instead let
214
+ # EC2 sort it out on the server side. We'll only require :group_name as that is always needed.
215
+ raise ArgumentError, "No :group_name provided" if options[:group_name].nil? || options[:group_name].empty?
216
+
217
+ params = { "GroupName" => options[:group_name],
218
+ "IpProtocol" => options[:ip_protocol],
219
+ "FromPort" => options[:from_port].to_s,
220
+ "ToPort" => options[:to_port].to_s,
221
+ "CidrIp" => options[:cidr_ip],
222
+ "SourceSecurityGroupName" => options[:source_security_group_name],
223
+ "SourceSecurityGroupOwnerId" => options[:source_security_group_owner_id]
224
+ }
225
+
226
+ return response_generator(:action => "RevokeSecurityGroupIngress", :params => params)
227
+
228
+ end
229
+
230
+ end
231
+
232
+ end
@@ -0,0 +1,30 @@
1
+ module EC2
2
+
3
+ class Base
4
+ def create_snapshot( options = {} )
5
+ options = { :volume_id => '' }.merge(options)
6
+ raise ArgumentError, "No ':volume_id' provided" if options[:volume_id].nil? || options[:volume_id].empty?
7
+
8
+ params = { "VolumeId" => options[:volume_id] }
9
+ return response_generator(:action => "CreateSnapshot", :params => params)
10
+ end
11
+
12
+ def describe_snapshots( options = {} )
13
+ options = { :snapshot_id => [] }.merge(options)
14
+ params = pathlist("SnapshotId", options[:snapshot_id])
15
+
16
+ return response_generator(:action => "DescribeSnapshots", :params => params)
17
+ end
18
+
19
+ def delete_snapshot( options = {} )
20
+ options = { :snapshot_id => '' }.merge(options)
21
+ raise ArgumentError, "No ':snapshot_id' provided" if options[:snapshot_id].nil? || options[:snapshot_id].empty?
22
+
23
+ params = { "SnapshotId" => options[:snapshot_id] }
24
+ return response_generator(:action => "DeleteSnapshot", :params => params)
25
+ end
26
+
27
+
28
+ end
29
+
30
+ end
@@ -0,0 +1,39 @@
1
+ module EC2
2
+
3
+ class Base
4
+
5
+ def describe_volumes( options = {} )
6
+ options = { :volume_id => [] }.merge(options)
7
+ params = pathlist("VolumeId", options[:volume_id])
8
+
9
+ return response_generator(:action => "DescribeVolumes", :params => params)
10
+ end
11
+
12
+ def attach_volumes( options = {} )
13
+ options = { :volume_id => '', :instance_id => '' }.merge(options)
14
+ raise ArgumentError, "No ':volume_id' provided" if options[:volume_id].nil? || options[:volume_id].empty?
15
+ raise ArgumentError, "No ':instance_id' provided" if options[:instance_id].nil? || options[:instance_id].empty?
16
+
17
+ params = { "VolumeId" => options[:volume_id], "InstanceId" => options[:instance_id] }
18
+ return response_generator(:action => "AttachVolume", :params => params)
19
+ end
20
+
21
+ def delete_volume( options = {} )
22
+ options = { :volume_id => '' }.merge(options)
23
+ raise ArgumentError, "No ':volume_id' provided" if options[:volume_id].nil? || options[:v].empty?
24
+
25
+ params = { "VolumeId" => options[:volume_id] }
26
+ return response_generator(:action => "DeleteVolume", :params => params)
27
+ end
28
+
29
+ def detach_volumes( options = {} )
30
+ options = { :volume_id => '', :instance_id => '', :device => '', :force => false }.merge(options)
31
+ raise ArgumentError, "No ':volume_id' provided" if options[:volume_id].nil? || options[:volume_id].empty?
32
+
33
+ params = { "VolumeId" => options[:volume_id], "InstanceId" => options[:instance_id], 'Device' => options[:device], 'Force' => options[:force] }
34
+ return response_generator(:action => "DetachVolume", :params => params)
35
+ end
36
+
37
+ end
38
+
39
+ end