# Copyright 2011-2012 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). You # may not use this file except in compliance with the License. A copy of # the License is located at # # http://aws.amazon.com/apache2.0/ # # or in the "license" file accompanying this file. This file is # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. require 'set' require 'uri' module AWS module Core # A configuration object for AWS interfaces and clients. # # == Configuring Credential # # In order to do anything with AWS you will need to assign credentials. # The simplest method is to assing your credentials into the default # configuration: # # AWS.config(:access_key_id => 'KEY', :secret_access_key => 'SECRET') # # You can also export them into your environment and they will be picked up # automatically: # # export AWS_ACCESS_KEY_ID='YOUR_KEY_ID_HERE' # export AWS_SECRET_ACCESS_KEY='YOUR_SECRET_KEY_HERE' # # For compatability with other AWS gems, the credentials can also be # exported like: # # export AMAZON_ACCESS_KEY_ID='YOUR_KEY_ID_HERE' # export AMAZON_SECRET_ACCESS_KEY='YOUR_SECRET_KEY_HERE' # # == Modifying a Configuration # # Configuration objects are read-only. If you need a different set of # configuration values, call {#with}, passing in the updates # and a new configuration object will be returned. # # config = Configuration.new(:max_retires => 3) # new_config = config.with(:max_retries => 2) # # config.max_retries #=> 3 # new_config.max_retries #=> 2 # # == Global Configuration # # The global default configuration can be found at {AWS.config} # # @attr_reader [String,nil] access_key_id AWS access key id credential. # Defaults to +nil+. # # @attr_reader [String] ec2_endpoint The service endpoint for Amazon EC2. # Defaults to 'ec2.amazonaws.com'. # # @attr_reader [Object] http_handler The http handler that sends requests # to AWS. Defaults to an HTTP handler built on net/http. # # @attr_reader [String] iam_endpoint The service endpoint for AWS Idenity # Access Management (IAM). Defaults to 'iam.amazonaws.com'. # # @attr_reader [Object,nil] logger A logger instance that # should receive log messages generated by service requets. # A logger needs to respond to #log and must accept a # severity (e.g. :info, :error, etc) and a string message. # Defaults to +nil+. # # @attr_reader [Integer] max_retries The maximum number of times # service errors (500) should be retried. There is an exponential # backoff in between service request retries, so the more retries the # longer it can take to fail. Defautls to 3. # # @attr_reader [String, URI, nil] proxy_uri The URI of the proxy # to send service requests through. You can pass a URI object or a # URI string. Defautls to +nil+. # # AWS.config(:proxy_uri => 'https://user:pass@my.proxy:443') # # @attr_reader [String] s3_endpoint The service endpoint for Amazon S3. # Defaults to 's3.amazonaws.com'. # # @attr_reader [Integer] s3_multipart_max_parts The maximum number of # parts to split a file into when uploading in parts to S3. # Defaults to 1000. # # @attr_reader [Integer] s3_multipart_threshold (16777216) When uploading # data to S3, if the number of bytes to send exceedes # +:s3_multipart_threshold+ then a multi part session is automatically # started and the data is sent up in chunks. The size of each part # is specified by +:s3_multipart_min_part_size+. Defaults to # 16777216 (16MB). # # @attr_reader [Integer] s3_multipart_min_part_size The absolute minimum # size (in bytes) each S3 multipart segment should be. # Defaults to 5242880 (5MB). # # @attr_reader [Symbol] s3_server_side_encryption The algorithm to # use when encrypting object data on the server side. The only # valid value is +:aes256+, which specifies that the object # should be stored using the AES encryption algorithm with 256 # bit keys. Defaults to +nil+, meaning server side encryption # is not used unless specified on each individual call to upload # an object. This option controls the default behavior for the # following method: # # * {S3::S3Object#write} # * {S3::S3Object#multipart_upload} # * {S3::S3Object#copy_from} and {S3::S3Object#copy_to} # * {S3::S3Object#presigned_post} # * {S3::Bucket#presigned_post} # # You can construct an interface to Amazon S3 which always # stores data using server side encryption as follows: # # s3 = AWS::S3.new(:s3_server_side_encryption => :aes256) # # @attr_reader [String,nil] secret_access_key AWS secret access key # credential. Defaults to +nil+. # # @attr_reader [String,nil] session_token AWS secret token credential. # Defaults to +nil+. # # @attr_reader [String] simple_db_endpoint The service endpoint for Amazon # SimpleDB. Defaults to 'sdb.amazonaws.com'. # # @attr_reader [Boolean] simple_db_consistent_reads Determines # if all SimpleDB read requests should be done consistently. # Consistent reads are slower, but reflect all changes to SDB. # Defaults to +false+. # # @attr_reader [String] simple_email_service_endpoint The service endpoint # for Amazon Simple Email Service. Defaults to # 'email.us-east-1.amazonaws.com'. # # @attr_reader [Object] signer The request signer. Defaults to # a default request signer implementation. # # @attr_reader [String] ssl_ca_file The path to a CA cert bundle in # PEM format. # # If +ssl_verify_peer+ is true (the default) this bundle will be # used to validate the server certificate in each HTTPS request. # The AWS SDK for Ruby ships with a CA cert bundle, which is the # default value for this option. # # @attr_reader [Boolean] ssl_verify_peer When +true+ # the HTTP handler validate server certificates for HTTPS requests. # Defaults to +true+. # # This option should only be disabled for diagnostic purposes; # leaving this option set to +false+ exposes your application to # man-in-the-middle attacks and can pose a serious security # risk. # # @attr_reader [Boolean] stub_requests When +true+ requests are not # sent to AWS, instead empty reponses are generated and returned to # each service request. # # @attr_reader [String] sns_endpoint The service endpoint for Amazon SNS. # Defaults to 'sns.us-east-1.amazonaws.com'. # # @attr_reader [String] sqs_endpoint The service endpoint for Amazon SQS. # Defaults to 'sqs.us-east-1.amazonaws.com'. # # @attr_reader [String] sts_endpoint The service endpoint for AWS # Security Token Service. Defaults to 'sts.amazonaws.com'. # # @attr_reader [Boolean] use_ssl When +true+, all requests # to AWS are sent using HTTPS instead vanilla HTTP. # Defaults to +true+. # # @attr_reader [String] user_agent_prefix A string prefix to # append to all requets against AWS services. This should be set # for clients and applications built ontop of the aws-sdk gem. # Defaults to +nil+. # class Configuration # Creates a new Configuration object. # @param options (see AWS.config) # @option options (see AWS.config) def initialize options = {} @created = options.delete(:__created__) || {} options.each_pair do |opt_name, value| opt_name = opt_name.to_sym if self.class.accepted_options.include?(opt_name) supplied[opt_name] = value end end end # Used to create a new Configuration object with the given modifications. # The current configuration object is not modified. # # AWS.config(:max_retries => 2) # # no_retries_config = AWS.config.with(:max_retries => 0) # # AWS.config.max_retries #=> 2 # no_retries_config.max_retries #=> 0 # # You can use these configuration objects returned by #with to create # AWS objects: # # AWS::S3.new(:config => no_retries_config) # AWS::SQS.new(:config => no_retries_config) # # @param options (see AWS.config) # @option options (see AWS.config) # @return [Configuration] Copies the current configuration and returns # a new one with modifications as provided in +:options+. def with options = {} # symbolize option keys options = options.inject({}) {|h,kv| h[kv.first.to_sym] = kv.last; h } values = supplied.merge(options) if supplied == values self # nothing changed else self.class.new(values.merge(:__created__ => @created.dup)) end end # @return [Hash] Returns a hash of all configuration values. def to_h self.class.accepted_options.inject({}) do |h,k| h[k] = send(k) h end end # @return [Boolean] Returns true if the two configuration objects have # the same values. def == other other.is_a?(self.class) and self.supplied == other.supplied end alias_method :eql, :== # @private def inspect "<#{self.class.name}>" end protected def supplied @supplied ||= {} end class << self # @private def accepted_options @options ||= Set.new end # @private def add_option name, default_value = nil, options = {}, &transform accepted_options << name define_method(name) do |&default_override| value = if supplied.has_key?(name) supplied[name] elsif default_override default_override.call else default_value end transform ? transform.call(value) : value end alias_method("#{name}?", name) if options[:boolean] end # Configuration options that have dependencies are re-recreated # anytime one of their dependendent configuration values are # changed. # @private def add_option_with_needs name, needs, &create_block accepted_options << name define_method(name) do return supplied[name] if supplied.has_key?(name) needed = needs.collect{|need| send(need) } unless @created.key?(name) and @created[name][:needed] == needed @created[name] = {} @created[name][:object] = create_block.call(self) @created[name][:needed] = needed end @created[name][:object] end end def add_service name, ruby_name, default_endpoint create_block = lambda do |config| AWS.const_get(name)::Client.new(:config => config) end needs = [ :signer, :http_handler, :"#{ruby_name}_endpoint", :max_retries, :stub_requests?, :proxy_uri, :use_ssl?, :ssl_verify_peer?, :ssl_ca_file, :user_agent_prefix, :logger, :logger_truncate_strings_at, ] add_option :"#{ruby_name}_endpoint", default_endpoint add_option_with_needs :"#{ruby_name}_client", needs, &create_block end end add_option :access_key_id, ENV['AWS_ACCESS_KEY_ID'] || ENV['AMAZON_ACCESS_KEY_ID'] add_option :http_handler, Core::Http::NetHttpHandler.new add_option :logger add_option :logger_truncate_strings_at, 1000 add_option :max_retries, 3 add_option :proxy_uri do |uri| uri ? URI.parse(uri.to_s) : nil end add_option :secret_access_key, ENV['AWS_SECRET_ACCESS_KEY'] || ENV['AMAZON_SECRET_ACCESS_KEY'] add_option :session_token add_option_with_needs :signer, [:access_key_id, :secret_access_key, :session_token] do |config| DefaultSigner.new( config.access_key_id, config.secret_access_key, config.session_token) end add_option :ssl_verify_peer, true, :boolean => true add_option :ssl_ca_file, File.expand_path(File.dirname(__FILE__) + "/../../../ca-bundle.crt") add_option :stub_requests, false, :boolean => true add_option :use_ssl, true, :boolean => true add_option :user_agent_prefix end end end