amazon-ec2 0.9.15 → 0.9.17

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.
data/bin/ec2sh CHANGED
@@ -4,59 +4,17 @@
4
4
  #
5
5
  # Ruby Gem Name:: amazon-ec2
6
6
  # Author:: Glenn Rempe (mailto:glenn@rempe.us)
7
- # Copyright:: Copyright (c) 2007-2008 Glenn Rempe
7
+ # Copyright:: Copyright (c) 2007-2010 Glenn Rempe
8
8
  # License:: Distributes under the same terms as Ruby
9
9
  # Home:: http://github.com/grempe/amazon-ec2/tree/master
10
10
  #++
11
11
 
12
- # CREDITS : Credit for this bit of shameful ripoff coolness
13
- # goes to Marcel Molina and his AWS::S3 gem. Thanks!
12
+ message = <<-MESSAGE
14
13
 
15
- # Usage : running this starts up an irb session and
16
- # sets up the connection to EC2 as a class variable called
17
- # '@ec2'. So just do something like the following on the
18
- # shell command line:
14
+ DEPRECATION WARNING:
19
15
 
20
- # macbook-pro:~ glenn$ ec2sh
21
- # >> @ec2.describe_images
22
- # => [#<AWS::EC2::Item image_location...
16
+ This script has been renamed to 'awshell'. Please run that command instead.
23
17
 
24
- aws_lib = File.dirname(__FILE__) + '/../lib/AWS'
25
- setup = File.dirname(__FILE__) + '/setup'
26
- irb_name = RUBY_PLATFORM =~ /mswin32/ ? 'irb.bat' : 'irb'
18
+ MESSAGE
27
19
 
28
- if ( ENV['AMAZON_ACCESS_KEY_ID'] && ENV['AMAZON_SECRET_ACCESS_KEY'] )
29
-
30
- welcome_message = <<-MESSAGE
31
-
32
- 'ec2sh' usage :
33
- This is an interactive 'irb' command shell that allows you to use all
34
- commands available to the amazon-ec2 gem. You'll find this to be a
35
- great tool to help you debug issues and practice running commands
36
- against the live EC2 servers prior to putting them in your code.
37
-
38
- The EC2 connection is wired to the class instance '@ec2'. Make method calls
39
- on this to execute commands on EC2. Adding a #to_s
40
- at the end of any command should give you a full String representation of the
41
- response.
42
-
43
- Examples to try:
44
-
45
- returns : all ec2 public methods
46
- >> @ec2.methods.sort
47
-
48
- returns : a string representation of ALL images
49
- >> @ec2.describe_images.to_s
50
-
51
- returns : an Array of AWS::Response objects, each an EC2 image and its data
52
- >> @ec2.describe_images.imagesSet.item
53
- >> @ec2.describe_images.imagesSet.item[0] (a hash representing a single item in that array)
54
- >> @ec2.describe_images.imagesSet.item[0].to_s (a String representation of that item)
55
-
56
- MESSAGE
57
-
58
- puts welcome_message
59
- exec "#{irb_name} -rubygems -r #{aws_lib} -r #{setup} --simple-prompt"
60
- else
61
- puts "You must define AMAZON_ACCESS_KEY_ID and AMAZON_SECRET_ACCESS_KEY as shell environment variables before running #{$0}!"
62
- end
20
+ puts message
@@ -4,26 +4,75 @@
4
4
  #
5
5
  # Ruby Gem Name:: amazon-ec2
6
6
  # Author:: Glenn Rempe (mailto:glenn@rempe.us)
7
- # Copyright:: Copyright (c) 2007-2008 Glenn Rempe
7
+ # Copyright:: Copyright (c) 2007-2010 Glenn Rempe
8
8
  # License:: Distributes under the same terms as Ruby
9
9
  # Home:: http://github.com/grempe/amazon-ec2/tree/master
10
10
  #++
11
11
 
12
12
  if ENV['AMAZON_ACCESS_KEY_ID'] && ENV['AMAZON_SECRET_ACCESS_KEY']
13
+
13
14
  opts = {
14
15
  :access_key_id => ENV['AMAZON_ACCESS_KEY_ID'],
15
16
  :secret_access_key => ENV['AMAZON_SECRET_ACCESS_KEY']
16
17
  }
18
+
17
19
  if ENV['EC2_URL']
18
- opts[:server] = URI.parse(ENV['EC2_URL']).host
20
+ ec2uri = URI.parse(ENV['EC2_URL'])
21
+ opts[:server] = ec2uri.host
22
+ if ec2uri.path.downcase.include?("eucalyptus")
23
+ opts[:path] = ec2uri.path
24
+ opts[:port] = ec2uri.port
25
+ if ec2uri.class == URI::HTTPS
26
+ opts[:use_ssl] = true
27
+ else
28
+ opts[:use_ssl] = false
29
+ end
30
+ end
31
+ @ec2 = AWS::EC2::Base.new(opts)
32
+ else
33
+ @ec2 = AWS::EC2::Base.new(opts)
34
+ end
35
+
36
+ if ENV['ELB_URL']
37
+ opts[:server] = URI.parse(ENV['ELB_URL']).host
38
+ @elb = AWS::ELB::Base.new(opts)
39
+ else
40
+ @elb = AWS::ELB::Base.new(opts)
41
+ end
42
+
43
+ if ENV['AS_URL']
44
+ opts[:server] = URI.parse(ENV['AS_URL']).host
45
+ @as = AWS::Autoscaling::Base.new(opts)
46
+ else
47
+ @as = AWS::Autoscaling::Base.new(opts)
19
48
  end
20
- @ec2 = AWS::EC2::Base.new(opts)
21
- @elb = AWS::ELB::Base.new(opts)
22
- @as = AWS::Autoscaling::Base.new(opts)
23
- @rds = AWS::RDS::Base.new(opts)
24
- end
25
49
 
26
- puts "EC2 Server: #{opts[:server]}"
50
+ if ENV['RDS_URL']
51
+ opts[:server] = URI.parse(ENV['RDS_URL']).host
52
+ @rds = AWS::RDS::Base.new(opts)
53
+ else
54
+ @rds = AWS::RDS::Base.new(opts)
55
+ end
56
+
57
+ if ENV['AWS_CLOUDWATCH_URL']
58
+ opts[:server] = URI.parse(ENV['AWS_CLOUDWATCH_URL']).host
59
+ @cw = AWS::Cloudwatch::Base.new(opts)
60
+ else
61
+ @cw = AWS::Cloudwatch::Base.new(opts)
62
+ end
63
+
64
+ puts ""
65
+ puts "Server Endpoints Configured"
66
+ puts "--"
67
+ puts "@ec2.default_host (Elastic Compute Cloud) : #{@ec2.default_host}"
68
+ puts "@elb.default_host (Elastic Load Balancer) : #{@elb.default_host}"
69
+ puts "@as.default_host (Autoscaling) : #{@as.default_host}"
70
+ puts "@rds.default_host (Relational DB Service) : #{@rds.default_host}"
71
+ puts "@cw.default_host (Cloudwatch) : #{@cw.default_host}"
72
+ puts ""
73
+
74
+ end
27
75
 
76
+ require 'pp'
28
77
  include AWS
29
78
 
data/lib/AWS.rb CHANGED
@@ -93,7 +93,7 @@ module AWS
93
93
  # @param [Boolean] urlencode whether or not to url encode the result., true or false
94
94
  # @return [String] the signed and encoded string.
95
95
  def AWS.encode(secret_access_key, str, urlencode=true)
96
- digest = OpenSSL::Digest::Digest.new('sha1')
96
+ digest = OpenSSL::Digest::Digest.new('sha256')
97
97
  b64_hmac =
98
98
  Base64.encode64(
99
99
  OpenSSL::HMAC.digest(digest, secret_access_key, str)).gsub("\n","")
@@ -126,12 +126,14 @@ module AWS
126
126
  :secret_access_key => "",
127
127
  :use_ssl => true,
128
128
  :server => default_host,
129
+ :path => "/",
129
130
  :proxy_server => nil
130
131
  }.merge(options)
131
132
 
132
133
  @server = options[:server]
133
134
  @proxy_server = options[:proxy_server]
134
135
  @use_ssl = options[:use_ssl]
136
+ @path = options[:path]
135
137
 
136
138
  raise ArgumentError, "No :access_key_id provided" if options[:access_key_id].nil? || options[:access_key_id].empty?
137
139
  raise ArgumentError, "No :secret_access_key provided" if options[:secret_access_key].nil? || options[:secret_access_key].empty?
@@ -219,7 +221,46 @@ module AWS
219
221
  params = {}
220
222
  arr_of_hashes.each_with_index do |hash, i|
221
223
  hash.each do |attribute, value|
222
- params["#{key}.#{i+1}.#{mappings[attribute]}"] = value.to_s
224
+ if value.is_a? Array
225
+ params["#{key}.#{i+1}.Name"] = mappings[attribute]
226
+ value.each_with_index do |item, j|
227
+ params["#{key}.#{i+1}.Value.#{j+1}"] = item.to_s
228
+ end
229
+ else
230
+ params["#{key}.#{i+1}.#{mappings[attribute]}"] = value.to_s
231
+ end
232
+ end
233
+ end
234
+ params
235
+ end
236
+
237
+ # Same as _pathhashlist_ except it generates explicit <prefix>.Key= and <prefix>.Value or <prefix>.Value.1, <prefix>.Value.2
238
+ # depending on whether the value is a scalar or an array.
239
+ #
240
+ # So if you pass in args
241
+ # ("People", [{:name=>'jon'}, {:names=>['chris', 'bob']} with key_name = 'Key' and value_name = 'Value',
242
+ # you should get
243
+ # {"People.1.Key"=>"name", "People.1.Value"=>'jon', "People.2.Key"=>'names', 'People.2.Value.1'=>'chris', 'People.2.Value.2'=>'bob'}
244
+ def pathkvlist(key, arr_of_hashes, key_name, value_name, mappings)
245
+ raise ArgumentError, "expected a key that is a String" unless key.is_a? String
246
+ raise ArgumentError, "expected a arr_of_hashes that is an Array" unless arr_of_hashes.is_a? Array
247
+ arr_of_hashes.each{|h| raise ArgumentError, "expected each element of arr_of_hashes to be a Hash" unless h.is_a?(Hash)}
248
+ raise ArgumentError, "expected a key_nam that is a String" unless key_name.is_a? String
249
+ raise ArgumentError, "expected a value_name that is a String" unless value_name.is_a? String
250
+ raise ArgumentError, "expected a mappings that is an Hash" unless mappings.is_a? Hash
251
+ params = {}
252
+ arr_of_hashes.each_with_index do |hash, i|
253
+ hash.each do |attribute, value|
254
+ params["#{key}.#{i+1}.#{key_name}"] = mappings.fetch(attribute, attribute)
255
+ if !value.nil?
256
+ if value.is_a? Array
257
+ value.each_with_index do |item, j|
258
+ params["#{key}.#{i+1}.#{value_name}.#{j+1}"] = item.to_s
259
+ end
260
+ else
261
+ params["#{key}.#{i+1}.#{value_name}"] = value.to_s
262
+ end
263
+ end
223
264
  end
224
265
  end
225
266
  params
@@ -237,7 +278,7 @@ module AWS
237
278
 
238
279
  params.merge!( {"Action" => action,
239
280
  "SignatureVersion" => "2",
240
- "SignatureMethod" => 'HmacSHA1',
281
+ "SignatureMethod" => 'HmacSHA256',
241
282
  "AWSAccessKeyId" => @access_key_id,
242
283
  "Version" => api_version,
243
284
  "Timestamp"=>Time.now.getutc.iso8601} )
@@ -248,7 +289,7 @@ module AWS
248
289
  CGI::escape(param[0]) + "=" + CGI::escape(param[1])
249
290
  end.join("&") + "&Signature=" + sig
250
291
 
251
- req = Net::HTTP::Post.new("/")
292
+ req = Net::HTTP::Post.new(@path)
252
293
  req.content_type = 'application/x-www-form-urlencoded'
253
294
  req['User-Agent'] = "github-amazon-ec2-ruby-gem"
254
295
 
@@ -265,7 +306,7 @@ module AWS
265
306
 
266
307
  # Set the Authorization header using AWS signed header authentication
267
308
  def get_aws_auth_param(params, secret_access_key, server)
268
- canonical_string = AWS.canonical_string(params, server)
309
+ canonical_string = AWS.canonical_string(params, server,"POST", @path)
269
310
  encoded_canonical = AWS.encode(secret_access_key, canonical_string)
270
311
  end
271
312
 
@@ -282,6 +323,7 @@ module AWS
282
323
 
283
324
  http_response = make_request(options[:action], options[:params])
284
325
  http_xml = http_response.body
326
+
285
327
  return Response.parse(:xml => http_xml)
286
328
  end
287
329
 
@@ -296,6 +338,8 @@ module AWS
296
338
  # exceptions.rb
297
339
  return false if response.is_a?(Net::HTTPSuccess)
298
340
 
341
+ raise AWS::Error, "Unexpected server error. response.body is: #{response.body}" if response.is_a?(Net::HTTPServerError)
342
+
299
343
  # parse the XML document so we can walk through it
300
344
  doc = REXML::Document.new(response.body)
301
345
 
@@ -7,8 +7,6 @@ module AWS
7
7
  # export AS_URL='http://autoscaling.amazonaws.com'
8
8
  if ENV['AS_URL']
9
9
  AS_URL = ENV['AS_URL']
10
- VALID_HOSTS = ['http://autoscaling.amazonaws.com']
11
- raise ArgumentError, "Invalid AS_URL environment variable : #{AS_URL}" unless VALID_HOSTS.include?(AS_URL)
12
10
  DEFAULT_HOST = URI.parse(AS_URL).host
13
11
  else
14
12
  # Default US API endpoint
@@ -8,8 +8,6 @@ module AWS
8
8
  # export AWS_CLOUDWATCH_URL='https://montoring.amazonaws.com'
9
9
  if ENV['AWS_CLOUDWATCH_URL']
10
10
  AWS_CLOUDWATCH_URL = ENV['AWS_CLOUDWATCH_URL']
11
- VALID_HOSTS = ['monitoring.amazonaws.com']
12
- raise ArgumentError, "Invalid AWS_CLOUDWATCH_URL environment variable : #{AWS_CLOUDWATCH_URL}" unless VALID_HOSTS.include?(AWS_CLOUDWATCH_URL)
13
11
  DEFAULT_HOST = URI.parse(AWS_CLOUDWATCH_URL).host
14
12
  else
15
13
  # Default US API endpoint
@@ -7,9 +7,7 @@ module AWS
7
7
  # call get_metric_statistics.
8
8
  #
9
9
  # there are no options available to this method.
10
-
11
10
  def list_metrics
12
- raise ArgumentError, "Server must be monitoring.amazonaws.com" if server != 'monitoring.amazonaws.com'
13
11
  return response_generator(:action => 'ListMetrics', :params => {})
14
12
  end
15
13
 
@@ -34,8 +32,6 @@ module AWS
34
32
  # @option options [String] :statistics (nil) The statistics to be returned for your metric. See the developer guide for valid options. Required.
35
33
  # @option options [Time] :start_time (Time.now() - 86400) Inner bound of the date range you want to view. Defaults to 24 hours ago
36
34
  # @option options [String] :unit (nil) Standard unit for a given Measure. See the developer guide for valid options.
37
-
38
-
39
35
  def get_metric_statistics ( options ={} )
40
36
  options = { :custom_unit => nil,
41
37
  :dimensions => nil,
@@ -51,23 +47,42 @@ module AWS
51
47
  raise ArgumentError, ":end_time must be a Time object" if options[:end_time].class != Time
52
48
  raise ArgumentError, ":start_time must be provided" if options[:start_time].nil?
53
49
  raise ArgumentError, ":start_time must be a Time object" if options[:start_time].class != Time
54
- raise ArgumentError, "Server must be monitoring.amazonaws.com" if server != 'monitoring.amazonaws.com'
55
50
  raise ArgumentError, ":start_time must be before :end_time" if options[:start_time] > options[:end_time]
56
51
  raise ArgumentError, ":measure_name must be provided" if options[:measure_name].nil? || options[:measure_name].empty?
57
52
  raise ArgumentError, ":statistics must be provided" if options[:statistics].nil? || options[:statistics].empty?
58
53
 
59
54
  params = {
60
55
  "CustomUnit" => options[:custom_unit],
61
- "Dimensions" => options[:dimensions],
62
56
  "EndTime" => options[:end_time].iso8601,
63
57
  "MeasureName" => options[:measure_name],
64
58
  "Namespace" => options[:namespace],
65
59
  "Period" => options[:period].to_s,
66
- "Statistics.member.1" => options[:statistics],
67
60
  "StartTime" => options[:start_time].iso8601,
68
61
  "Unit" => options[:unit]
69
62
  }
70
63
 
64
+ # FDT: Fix statistics and dimensions values
65
+ if !(options[:statistics].nil? || options[:statistics].empty?)
66
+ stats_params = {}
67
+ i = 1
68
+ options[:statistics].split(',').each{ |stat|
69
+ stats_params.merge!( "Statistics.member.#{i}" => "#{stat}" )
70
+ i += 1
71
+ }
72
+ params.merge!( stats_params )
73
+ end
74
+
75
+ if !(options[:dimensions].nil? || options[:dimensions].empty?)
76
+ dims_params = {}
77
+ i = 1
78
+ options[:dimensions].split(',').each{ |dimension|
79
+ dimension_var = dimension.split('=')
80
+ dims_params = dims_params.merge!( "Dimensions.member.#{i}.Name" => "#{dimension_var[0]}", "Dimensions.member.#{i}.Value" => "#{dimension_var[1]}" )
81
+ i += 1
82
+ }
83
+ params.merge!( dims_params )
84
+ end
85
+
71
86
  return response_generator(:action => 'GetMetricStatistics', :params => params)
72
87
 
73
88
  end
@@ -14,7 +14,7 @@ module AWS
14
14
  DEFAULT_HOST = 'ec2.amazonaws.com'
15
15
  end
16
16
 
17
- API_VERSION = '2009-11-30'
17
+ API_VERSION = '2010-08-31'
18
18
 
19
19
  class Base < AWS::Base
20
20
  def api_version
@@ -36,7 +36,7 @@ module AWS
36
36
  raise ArgumentError, ":image_id must be provided" if options[:image_id].nil? || options[:image_id].empty?
37
37
  raise ArgumentError, ":min_count is not valid" unless options[:min_count].to_i > 0
38
38
  raise ArgumentError, ":max_count is not valid or must be >= :min_count" unless options[:max_count].to_i > 0 && options[:max_count].to_i >= options[:min_count].to_i
39
- raise ArgumentError, ":instance_type must specify a valid instance type" unless options[:instance_type].nil? || ["m1.small", "m1.large", "m1.xlarge", "m2.xlarge", "c1.medium", "c1.xlarge", "m2.2xlarge", "m2.4xlarge"].include?(options[:instance_type])
39
+ raise ArgumentError, ":instance_type must specify a valid instance type" unless options[:instance_type].nil? || ["t1.micro", "m1.small", "m1.large", "m1.xlarge", "m2.xlarge", "c1.medium", "c1.xlarge", "m2.2xlarge", "m2.4xlarge", "cc1.4xlarge"].include?(options[:instance_type])
40
40
  raise ArgumentError, ":monitoring_enabled must be 'true' or 'false'" unless options[:monitoring_enabled].nil? || [true, false].include?(options[:monitoring_enabled])
41
41
  raise ArgumentError, ":disable_api_termination must be 'true' or 'false'" unless options[:disable_api_termination].nil? || [true, false].include?(options[:disable_api_termination])
42
42
  raise ArgumentError, ":instance_initiated_shutdown_behavior must be 'stop' or 'terminate'" unless options[:instance_initiated_shutdown_behavior].nil? || ["stop", "terminate"].include?(options[:instance_initiated_shutdown_behavior])
@@ -92,30 +92,57 @@ module AWS
92
92
  end
93
93
 
94
94
 
95
- # Not yet implemented
95
+ # Returns information about an attribute of an instance.
96
96
  #
97
- # @todo Implement this method
97
+ # @option options [String] :instance_id (nil) ID of the instance on which the attribute will be queried.
98
+ # @option options [String] :attribute (nil) Specifies the attribute to query..
98
99
  #
99
100
  def describe_instance_attribute( options = {} )
100
- raise "Not yet implemented"
101
+ raise ArgumentError, "No :instance_id provided" if options[:instance_id].nil? || options[:instance_id].empty?
102
+ raise ArgumentError, "No :attribute provided" if options[:attribute].nil? || options[:attribute].empty?
103
+ valid_attributes = %w(instanceType kernel ramdisk userData disableApiTermination instanceInitiatedShutdownBehavior rootDevice blockDeviceMapping)
104
+ raise ArgumentError, "Invalid :attribute provided" unless valid_attributes.include?(options[:attribute].to_s)
105
+ params = {}
106
+ params["InstanceId"] = options[:instance_id]
107
+ params["Attribute"] = options[:attribute]
108
+ return response_generator(:action => "DescribeInstanceAttribute", :params => params)
101
109
  end
102
110
 
103
111
 
104
- # Not yet implemented
112
+ # Modifies an attribute of an instance.
105
113
  #
106
- # @todo Implement this method
114
+ # @option options [String] :instance_id (nil) ID of the instance on which the attribute will be modified.
115
+ # @option options [String] :attribute (nil) Specifies the attribute to modify.
116
+ # @option options [String] :value (nil) The value of the attribute being modified.
107
117
  #
108
118
  def modify_instance_attribute( options = {} )
109
- raise "Not yet implemented"
119
+ raise ArgumentError, "No :instance_id provided" if options[:instance_id].nil? || options[:instance_id].empty?
120
+ raise ArgumentError, "No :attribute provided" if options[:attribute].nil? || options[:attribute].empty?
121
+ raise ArgumentError, "No :value provided" if options[:value].nil?
122
+ valid_attributes = %w(instanceType kernel ramdisk userData disableApiTermination instanceInitiatedShutdownBehavior rootDevice blockDeviceMapping)
123
+ raise ArgumentError, "Invalid :attribute provided" unless valid_attributes.include?(options[:attribute].to_s)
124
+ params = {}
125
+ params["InstanceId"] = options[:instance_id]
126
+ params["Attribute"] = options[:attribute]
127
+ params["Value"] = options[:value].to_s
128
+ return response_generator(:action => "ModifyInstanceAttribute", :params => params)
110
129
  end
111
130
 
112
131
 
113
- # Not yet implemented
132
+ # Resets an attribute of an instance to its default value.
114
133
  #
115
- # @todo Implement this method
134
+ # @option options [String] :instance_id (nil) ID of the instance on which the attribute will be reset.
135
+ # @option options [String] :attribute (nil) The instance attribute to reset to the default value.
116
136
  #
117
137
  def reset_instance_attribute( options = {} )
118
- raise "Not yet implemented"
138
+ raise ArgumentError, "No :instance_id provided" if options[:instance_id].nil? || options[:instance_id].empty?
139
+ raise ArgumentError, "No :attribute provided" if options[:attribute].nil? || options[:attribute].empty?
140
+ valid_attributes = %w(kernel ramdisk)
141
+ raise ArgumentError, "Invalid :attribute provided" unless valid_attributes.include?(options[:attribute].to_s)
142
+ params = {}
143
+ params["InstanceId"] = options[:instance_id]
144
+ params["Attribute"] = options[:attribute]
145
+ return response_generator(:action => "ResetInstanceAttribute", :params => params)
119
146
  end
120
147
 
121
148
 
@@ -238,7 +265,7 @@ module AWS
238
265
  # Example Class Method Usage :
239
266
  # instance_id = AWS::EC2::Instance.local_instance_id
240
267
  #
241
- module Instance
268
+ class Instance
242
269
 
243
270
  EC2_META_URL_BASE = 'http://169.254.169.254/latest/meta-data/'
244
271
 
@@ -0,0 +1,20 @@
1
+ module AWS
2
+ module EC2
3
+ class Base < AWS::Base
4
+
5
+
6
+ # The GetPasswordData operation retrieves the encrypted administrator password for the instances running Window.
7
+ #
8
+ # @option options [String] :instance_id ("") an Instance ID
9
+ #
10
+ def get_password_data( options = {} )
11
+ options = {:instance_id => ""}.merge(options)
12
+ raise ArgumentError, "No instance ID provided" if options[:instance_id].nil? || options[:instance_id].empty?
13
+ params = { "InstanceId" => options[:instance_id] }
14
+ return response_generator(:action => "GetPasswordData", :params => params)
15
+ end
16
+
17
+
18
+ end
19
+ end
20
+ end