Skip to content

Commit

Permalink
refs #8642, IAM: AWS Identity and Access Management support, ELB: API…
Browse files Browse the repository at this point in the history
… 2010-07-01 support (SSL + listeners creation/removal)
  • Loading branch information
konstantin committed Jan 18, 2011
1 parent e0d31f5 commit 84440ae
Show file tree
Hide file tree
Showing 25 changed files with 1,030 additions and 48 deletions.
2 changes: 2 additions & 0 deletions History.txt
Expand Up @@ -294,6 +294,8 @@ the source key.
- Tags Suport
- ClientToken support added on instance launch
- RDS: API "2010-07-28"
- ELB: API '2010-07-01' (SSL support)
- IAM: API '2010-05-08' (AWS Identity and Access Management interface)
- 301 Redirect support added
- Removed:
- ActiveSupport dependency
Expand Down
5 changes: 5 additions & 0 deletions Manifest.txt
Expand Up @@ -33,6 +33,11 @@ lib/acf/right_acf_interface.rb
lib/acf/right_acf_streaming_interface.rb
lib/acf/right_acf_origin_access_identities.rb
lib/rds/right_rds_interface.rb
lib/iam/right_iam_interface.rb
lib/iam/right_iam_groups.rb
lib/iam/right_iam_users.rb
lib/iam/right_iam_access_keys.rb
lib/iam/right_iam_mfa_devices.rb
test/ec2/test_helper.rb
test/ec2/test_right_ec2.rb
test/http_connection.rb
Expand Down
4 changes: 0 additions & 4 deletions README.txt
Expand Up @@ -68,10 +68,6 @@ concurrent requests to AWS. The way this plays out in practice is:
Note that due to limitations in the I/O of the Ruby interpreter you
may not get the degree of parallelism you may expect with the multi-threaded setting.

By default, EC2/S3/SQS/SDB/ACF interface instances are created in single-threaded mode. Set
"params[:multi_thread]" to "true" in the initialization arguments to use
multithreaded mode.

== GETTING STARTED:

* For EC2 read RightAws::Ec2 and consult the Amazon EC2 API documentation at
Expand Down
1 change: 0 additions & 1 deletion lib/acf/right_acf_interface.rb
Expand Up @@ -96,7 +96,6 @@ def self.bench_service
# * <tt>:server</tt>: CloudFront service host, default: DEFAULT_HOST
# * <tt>:port</tt>: CloudFront service port, default: DEFAULT_PORT
# * <tt>:protocol</tt>: 'http' or 'https', default: DEFAULT_PROTOCOL
# * <tt>:multi_thread</tt>: true=HTTP connection per thread, false=per process
# * <tt>:logger</tt>: for log messages, default: RAILS_DEFAULT_LOGGER else STDOUT
#
# acf = RightAws::AcfInterface.new('1E3GDYEOGFJPIT7XXXXXX','hgTHt68JY07JKUY08ftHYtERkjgtfERn57XXXXXX',
Expand Down
1 change: 0 additions & 1 deletion lib/acw/right_acw_interface.rb
Expand Up @@ -54,7 +54,6 @@ def self.bench_service
# * <tt>:server</tt>: ACW service host, default: DEFAULT_HOST
# * <tt>:port</tt>: ACW service port, default: DEFAULT_PORT
# * <tt>:protocol</tt>: 'http' or 'https', default: DEFAULT_PROTOCOL
# * <tt>:multi_thread</tt>: true=HTTP connection per thread, false=per process
# * <tt>:logger</tt>: for log messages, default: RAILS_DEFAULT_LOGGER else STDOUT
# * <tt>:signature_version</tt>: The signature version : '0','1' or '2'(default)
# * <tt>:cache</tt>: true/false(default): list_metrics
Expand Down
1 change: 0 additions & 1 deletion lib/as/right_as_interface.rb
Expand Up @@ -95,7 +95,6 @@ def self.bench_service
# * <tt>:server</tt>: AS service host, default: DEFAULT_HOST
# * <tt>:port</tt>: AS service port, default: DEFAULT_PORT
# * <tt>:protocol</tt>: 'http' or 'https', default: DEFAULT_PROTOCOL
# * <tt>:multi_thread</tt>: true=HTTP connection per thread, false=per process
# * <tt>:logger</tt>: for log messages, default: RAILS_DEFAULT_LOGGER else STDOUT
# * <tt>:signature_version</tt>: The signature version : '0','1' or '2'(default)
# * <tt>:cache</tt>: true/false(default): describe_auto_scaling_groups
Expand Down
21 changes: 14 additions & 7 deletions lib/awsbase/right_awsbase.rb
Expand Up @@ -23,7 +23,6 @@

# Test
module RightAws
# require 'md5'
require 'digest/md5'
require 'pp'

Expand Down Expand Up @@ -288,7 +287,6 @@ def init(service_info, aws_access_key_id, aws_secret_access_key, params={}) #:no
# a set of options to be passed to RightHttpConnection object
@params[:connection_options] = {} unless @params[:connection_options].is_a?(Hash)
@with_connection_options = {}
# @params[:multi_thread] ||= defined?(AWS_DAEMON)
@params[:connections] ||= :shared # || :dedicated
@params[:max_connections] ||= 10
@params[:connection_lifetime] ||= 20*60
Expand Down Expand Up @@ -360,11 +358,6 @@ def on_exception(options={:raise=>true, :log=>true}) # :nodoc:
AwsError::on_aws_exception(self, options)
end

# # Return +true+ if this instance works in multi_thread mode and +false+ otherwise.
# def multi_thread
# @params[:multi_thread]
# end

# ACF, AMS, EC2, LBS and SDB uses this guy
# SQS and S3 use their own methods
def generate_request_impl(verb, action, options={}) #:nodoc:
Expand Down Expand Up @@ -535,6 +528,20 @@ def last_request_id
@last_response && @last_response.body.to_s[%r{<requestId>(.+?)</requestId>}i] && $1
end

# Incrementally lists something.
def incrementally_list_items(action, parser_class, params={}, &block) # :nodoc:
params = params.dup
params['MaxItems'] = params.delete(:max_items) if params[:max_items]
params['Marker'] = params.delete(:marker) if params[:marker]
last_response = nil
loop do
last_response = request_info( generate_request(action, params), parser_class.new(:logger => @logger))
params['Marker'] = last_response[:marker]
break unless block && block.call(last_response) && !last_response[:marker].right_blank?
end
last_response
end

# Format array of items into Amazons handy hash ('?' is a place holder):
# Options:
# :default => "something" : Set a value to "something" when it is nil
Expand Down
1 change: 0 additions & 1 deletion lib/ec2/right_ec2.rb
Expand Up @@ -107,7 +107,6 @@ def self.api
# * <tt>:region</tt>: EC2 region (North America by default)
# * <tt>:port</tt>: EC2 service port, default: DEFAULT_PORT
# * <tt>:protocol</tt>: 'http' or 'https', default: DEFAULT_PROTOCOL
# * <tt>:multi_thread</tt>: true=HTTP connection per thread, false=per process
# * <tt>:logger</tt>: for log messages, default: RAILS_DEFAULT_LOGGER else STDOUT
# * <tt>:signature_version</tt>: The signature version : '0','1' or '2'(default)
# * <tt>:cache</tt>: true/false: caching for: ec2_describe_images, describe_instances,
Expand Down
88 changes: 74 additions & 14 deletions lib/elb/right_elb_interface.rb
Expand Up @@ -62,12 +62,14 @@ class ElbInterface < RightAwsBase
include RightAwsBaseInterface

# Amazon ELB API version being used
API_VERSION = "2009-11-25"
API_VERSION = "2010-07-01"
DEFAULT_HOST = "elasticloadbalancing.amazonaws.com"
DEFAULT_PATH = '/'
DEFAULT_PROTOCOL = 'https'
DEFAULT_PORT = 443

LISTENER_PROTOCOLS = [ 'HTTP', 'HTTPS', 'TCP', 'SSL' ]

@@bench = AwsBenchmarkingBlock.new
def self.bench_xml
@@bench.xml
Expand All @@ -83,7 +85,6 @@ def self.bench_service
# * <tt>:server</tt>: ELB service host, default: DEFAULT_HOST
# * <tt>:port</tt>: ELB service port, default: DEFAULT_PORT
# * <tt>:protocol</tt>: 'http' or 'https', default: DEFAULT_PROTOCOL
# * <tt>:multi_thread</tt>: true=HTTP connection per thread, false=per process
# * <tt>:logger</tt>: for log messages, default: RAILS_DEFAULT_LOGGER else STDOUT
# * <tt>:signature_version</tt>: The signature version : '0','1' or '2'(default)
# * <tt>:cache</tt>: true/false(default): caching works for: describe_load_balancers
Expand Down Expand Up @@ -172,11 +173,15 @@ def describe_load_balancers(*load_balancers)
# Create new load balancer.
# Returns a new load balancer DNS name.
#
# lb = elb.create_load_balancer( 'test-kd1',
# ['us-east-1a', 'us-east-1b'],
# [ { :protocol => :http, :load_balancer_port => 80, :instance_port => 80 },
# { :protocol => :tcp, :load_balancer_port => 443, :instance_port => 443 } ])
# puts lb #=> "test-kd1-1519253964.us-east-1.elb.amazonaws.com"
# Listener options: :protocol, :load_balancer_port, :instance_port and :ssl_certificate_id
# Protocols: :tcp, :http, :https or :ssl
#
# elb.create_load_balancer( 'test-kd1',
# ['us-east-1a', 'us-east-1b'],
# [ { :protocol => :http, :load_balancer_port => 80, :instance_port => 80 },
# { :protocol => :https, :load_balancer_port => 443, :instance_port => 443,
# :ssl_certificate_id => 'arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/Bob' } ])
# #=> "test-kd1-1519253964.us-east-1.elb.amazonaws.com"
#
def create_load_balancer(load_balancer_name, availability_zones=[], listeners=[])
request_hash = { 'LoadBalancerName' => load_balancer_name }
Expand All @@ -188,13 +193,7 @@ def create_load_balancer(load_balancer_name, availability_zones=[], listeners=[]
:load_balancer_port => 80,
:instance_port => 80 }
end
listeners = [listeners] unless listeners.is_a?(Array)
request_hash.merge!( amazonize_list( ['Listeners.member.?.Protocol',
'Listeners.member.?.LoadBalancerPort',
'Listeners.member.?.InstancePort'],
listeners.map{|i| [ (i[:protocol] || 'HTTP').to_s.upcase,
(i[:load_balancer_port] || 80),
(i[:instance_port] || 80) ] } ) )
request_hash = merge_listeners_into_request_hash(request_hash, listeners)
link = generate_request("CreateLoadBalancer", request_hash)
request_info(link, CreateLoadBalancerParser.new(:logger => @logger))
end
Expand All @@ -212,6 +211,37 @@ def delete_load_balancer(load_balancer_name)
request_info(link, DeleteLoadBalancerParser.new(:logger => @logger))
end

# Creates one or more new listeners on a LoadBalancer for the specified port. If a listener with the given
# port does not already exist, it will be created; otherwise, the properties of the new listener must match
# the the properties of the existing listener.
#
# Listener options: :protocol, :load_balancer_port, :instance_port and :ssl_certificate_id
# Protocols: :tcp, :http, :https or :ssl
#
# elb.create_load_balancer_listeners( 'test-kd1',
# [ { :protocol => :http, :load_balancer_port => 80, :instance_port => 80 },
# { :protocol => :https, :load_balancer_port => 443, :instance_port => 443,
# :ssl_certificate_id => 'arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/Bob' } ]) #=> true
#
def create_load_balancer_listeners(load_balancer_name, listeners)
request_hash = { 'LoadBalancerName' => load_balancer_name }
request_hash = merge_listeners_into_request_hash(request_hash, listeners)
link = generate_request("CreateLoadBalancerListeners", request_hash)
request_info(link, RightHttp2xxParser.new(:logger => @logger))
end

# Removes listeners from the load balancer for the specified port number.
#
# elb.delete_load_balancer_listeners( 'kd_test', 80, 443) #=> true
#
def delete_load_balancer_listeners(load_balancer_name, *load_balancer_ports)
load_balancer_ports.flatten!
request_hash = { 'LoadBalancerName' => load_balancer_name }
request_hash.merge!( amazonize_list("LoadBalancerPorts.member", load_balancer_ports ) )
link = generate_request("DeleteLoadBalancerListeners", request_hash )
request_info(link, DeleteLoadBalancerParser.new(:logger => @logger))
end

# Add one or more zones to a load balancer.
# Returns a list of updated availability zones for the load balancer.
#
Expand Down Expand Up @@ -368,6 +398,35 @@ def delete_load_balancer_policy(load_balancer_name, policy_name)
request_info(link, RightHttp2xxParser.new(:logger => @logger))
end

def set_load_balancer_listener_ssl_certificate(load_balancer_name, load_balancer_port, ssl_sertificate_id)
request_hash = { 'LoadBalancerName' => load_balancer_name,
'LoadBalancerPort' => load_balancer_port,
'SSLCertificateId' => ssl_sertificate_id }
link = generate_request("SetLoadBalancerListenerSSLCertificate", request_hash)
request_info(link, RightHttp2xxParser.new(:logger => @logger))
end

#-----------------------------------------------------------------
# Helpers
#-----------------------------------------------------------------

def merge_listeners_into_request_hash(request_hash, listeners) # :nodoc:
listeners = [listeners] unless listeners.is_a?(Array)
request_hash.merge(amazonize_list( ['Listeners.member.?.Protocol',
'Listeners.member.?.LoadBalancerPort',
'Listeners.member.?.InstancePort',
'Listeners.member.?.SSLCertificateId'],
listeners.map{ |i|
[ (i[:protocol] || 'HTTP').to_s.upcase,
i[:load_balancer_port] || 80,
i[:instance_port] || 80,
i[:ssl_certificate_id]]
},
:default => :skip_nils
)
)
end

#-----------------------------------------------------------------
# PARSERS: Load Balancers
#-----------------------------------------------------------------
Expand Down Expand Up @@ -400,6 +459,7 @@ def tagend(name)
when 'Protocol' then @listener[:protocol] = @text
when 'LoadBalancerPort' then @listener[:load_balancer_port] = @text
when 'InstancePort' then @listener[:instance_port] = @text
when 'SSLCertificateId' then @listener[:ssl_certificate_id] = @text
end
case full_tag_name
when %r{AvailabilityZones/member$} then @item[:availability_zones] << @text
Expand Down
71 changes: 71 additions & 0 deletions lib/iam/right_iam_access_keys.rb
@@ -0,0 +1,71 @@
module RightAws

class IamInterface < RightAwsBase

#-----------------------------------------------------------------
# Access Keys
#-----------------------------------------------------------------

# Returns information about the Access Key IDs associated with the specified User.
#
# Options: :user_name, :max_items, :marker
#
# iam.list_access_keys #=>
# [{:create_date=>"2007-01-09T06:16:30Z",
# :status=>"Active",
# :access_key_id=>"00000000000000000000"}]
#
def list_access_keys(options={}, &block)
incrementally_list_iam_resources('ListAccessKeys', options, &block)
end

# Creates a new AWS Secret Access Key and corresponding AWS Access Key ID for the specified User.
#
# Options: :user_name
#
# iam.create_access_key(:user_name => 'kd1') #=>
# {:access_key_id=>"AK0000000000000000ZQ",
# :status=>"Active",
# :secret_access_key=>"QXN0000000000000000000000000000000000Ioj",
# :create_date=>"2010-10-29T07:16:32.210Z",
# :user_name=>"kd1"}
#
def create_access_key(options={})
request_hash = {}
request_hash['UserName'] = options[:user_name] unless options[:user_name].right_blank?
link = generate_request("CreateAccessKey", request_hash)
request_info(link, CreateAccessKeyParser.new(:logger => @logger))
end

# Deletes the access key associated with the specified User.
#
# Options: :user_name
#
# iam.delete_access_key('AK00000000000000006A', :user_name => 'kd1') #=> true
#
def delete_access_key(access_key_id, options={})
request_hash = { 'AccessKeyId' => access_key_id }
request_hash['UserName'] = options[:user_name] unless options[:user_name].right_blank?
link = generate_request("DeleteAccessKey", request_hash)
request_info(link, RightHttp2xxParser.new(:logger => @logger))
end

#-----------------------------------------------------------------
# PARSERS
#-----------------------------------------------------------------

class ListAccessKeysParser < BasicIamListParser #:nodoc:
def reset
@expected_tags = %w{ AccessKeyId CreateDate Status UserName }
end
end

class CreateAccessKeyParser < BasicIamParser #:nodoc:
def reset
@expected_tags = %w{ AccessKeyId CreateDate SecretAccessKey Status UserName }
end
end

end

end

0 comments on commit 84440ae

Please sign in to comment.