aws-sdk-v1-1.66.0/0000755000004100000410000000000012604445426013540 5ustar www-datawww-dataaws-sdk-v1-1.66.0/bin/0000755000004100000410000000000012604445426014310 5ustar www-datawww-dataaws-sdk-v1-1.66.0/bin/aws-rb0000755000004100000410000001025712604445426015436 0ustar www-datawww-data#!/usr/bin/env ruby # Copyright 2011-2013 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. $:.unshift(File.join(File.dirname(File.dirname(__FILE__)), 'lib')) require 'rubygems' require 'optparse' require 'logger' def env_bool key, default if ENV.key?(key) !['0', 'false', 'no', 'off'].include?(ENV[key].downcase) else default end end # setup default options, check ENV for most options = { :repl => env_bool('AWSRB', nil), :log => env_bool('AWSRB_LOG', true), :color => env_bool('AWSRB_COLOR', true), :debug => env_bool('AWSRB_DEBUG', false), :load_paths => [], :require => [], :execute => [], } OptionParser.new do |opts| opts.banner = "Usage: aws-rb [options]" opts.on("--repl REPL", "specify the repl environment, pry or irb") do |value| options[:repl] = value end opts.on("-e 'command'", "one line of script. Several -e's allowed.") do |value| options[:execute] << value options[:log] = false unless options[:log_set] options[:debug] = false unless options[:debug_set] end opts.on("-l", "--[no-]log", "log client requets, on by default") do |value| options[:log] = value options[:log_set] = true end opts.on("-c", "--[no-]color", "colorize request logging, on by default") do |value| options[:color] = value end opts.on("--profile PROFILE", "Use a specific profile from your credential file.") do |value| options[:profile] = value end opts.on("-d", "--[no-]debug", "log HTTP wire traces, off by default") do |value| options[:debug] = value options[:debug_set] = true end opts.on("-Idirectory", Array, "specify $LOAD_PATH directory (may be used more than once)") do |values| options[:load_paths] += values end opts.on("-rlibrary", Array, "require the library") do |values| options[:require] += values end opts.on("-v", "--verbose", "enable client logging and HTTP wire tracing") do |value| options[:log] = true options[:log_set] = true options[:debug] = true options[:debug_set] = true end opts.on("-q", "--quiet", "disable client logging and HTTP wire tracing") do |value| options[:log] = false options[:log_set] = true options[:debug] = false options[:debug_set] = true end opts.on("-h", "--help") do puts opts exit end end.parse! # amend the $LOAD_PATH options[:load_paths].each do |path| $LOAD_PATH.unshift(path) end require 'aws-sdk-v1' # configure the aws-sdk gem cfg = {} if options[:profile] provider = AWS::Core::CredentialProviders::SharedCredentialFileProvider.new( :profile_name => options[:profile] ) cfg[:credential_provider] = provider end if options[:log] logger = Logger.new($stdout) logger.formatter = proc {|severity, datetime, progname, msg| msg } cfg[:logger] = logger end if options[:color] cfg[:log_formatter] = AWS::Core::LogFormatter.colored end if options[:debug] cfg[:http_wire_trace] = true end AWS.config(cfg) options[:require].each do |library| require(library) end unless options[:execute].empty? eval(options[:execute].join("\n")) exit end unless options[:repl] == 'irb' # these dependencies are normally autoloaded by the aws-sdk, however # we require them up front to squelch warnings from pry require 'nokogiri' require 'json' end class PryNotAvailable < StandardError; end def run_with_pry begin require 'pry' rescue LoadError raise PryNotAvailable end Pry.config.prompt = [proc { "AWS> " }, proc { "AWS| " }] AWS.pry end def run_with_irb require 'irb' IRB.start end case options[:repl] when 'pry' then run_with_pry when 'irb' then run_with_irb else begin run_with_pry rescue PryNotAvailable warn("Pry not available, falling back to irb") run_with_irb end end aws-sdk-v1-1.66.0/LICENSE.txt0000644000004100000410000000104512604445426015363 0ustar www-datawww-dataCopyright 2011-2015 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. aws-sdk-v1-1.66.0/lib/0000755000004100000410000000000012604445426014306 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws.rb0000644000004100000410000000112012604445426015417 0ustar www-datawww-data# Copyright 2011-2013 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 'aws-sdk-v1' aws-sdk-v1-1.66.0/lib/aws/0000755000004100000410000000000012604445426015100 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/sts/0000755000004100000410000000000012604445426015711 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/sts/errors.rb0000644000004100000410000000123412604445426017552 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class STS module Errors extend Core::LazyErrorClasses end end end aws-sdk-v1-1.66.0/lib/aws/sts/federated_session.rb0000644000004100000410000000352112604445426021725 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class STS # Represents a federated session using temporary AWS credentials. # Use {STS#new_federated_session} to get an instance of this # class. class FederatedSession < Session # The string identifying the federated user associated with the # session, similar to the UserId of an IAM user. # # @return [String] attr_reader :user_id # The ARN specifying the federated user associated with the # session. For more information about ARNs and how to use them # in policies, see # {http://docs.aws.amazon.com/IAM/latest/UserGuide/index.html?Using_Identifiers.html # Identifiers for IAM Entities} in Using AWS Identity and # Access Management. # # @return [String] attr_reader :user_arn # A percentage value indicating the size of the policy in packed # form. Policies for which the packed size is greater than 100% # of the allowed value are rejected by the service. # # @return [Integer] attr_reader :packed_policy_size # @api private def initialize(opts = {}) @user_id = opts[:user_id] @user_arn = opts[:user_arn] @packed_policy_size = opts[:packed_policy_size] super end end end end aws-sdk-v1-1.66.0/lib/aws/sts/policy.rb0000644000004100000410000000141512604445426017536 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class STS # (see Core::Policy) class Policy < Core::Policy # (see Core::Policy#to_h) def to_h h = super h.delete("Id") h end end end end aws-sdk-v1-1.66.0/lib/aws/sts/client.rb0000644000004100000410000000307012604445426017514 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class STS # Client class for AWS Security Token Service (STS). class Client < Core::QueryClient API_VERSION = '2011-06-15' signature_version :Version4, 'sts' REGION_US_E1 = 'sts.amazonaws.com' # @api private CACHEABLE_REQUESTS = Set[] def initialize *args super unless config.use_ssl? msg = 'AWS Security Token Service (STS) requires ssl but the ' + ':use_ssl option is set to false. Try passing :use_ssl => true' raise ArgumentError, msg end end # Two STS operations are un-signed alias do_sign_request sign_request def sign_request(req) action = req.params.find { |param| param.name == 'Action' }.value unsigned = %w( AssumeRoleWithWebIdentity AssumeRoleWithSAML ) do_sign_request(req) unless unsigned.include?(action) req end end class Client::V20110615 < Client define_client_methods('2011-06-15') end end end aws-sdk-v1-1.66.0/lib/aws/sts/config.rb0000644000004100000410000000121312604445426017500 0ustar www-datawww-data# Copyright 2011-2013 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. AWS::Core::Configuration.module_eval do add_service 'STS', 'sts', 'sts' end aws-sdk-v1-1.66.0/lib/aws/sts/session.rb0000644000004100000410000000267612604445426017734 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class STS # Represents a session using temporary AWS credentials. Use # {STS#new_session} or {STS#new_federated_session} to get a new # set of temporary credentials. class Session # A hash containing the following keys: # # * `:access_key_id` # * `:secret_access_key` # * `:session_token` # # This hash may be passed as-is to {AWS.config} or to the # constructor of any service interface that supports temporary # security credentials from the AWS Security Token Service. # # @return [Hash] attr_reader :credentials # The date on which these credentials expire. # # @return [Time] attr_reader :expires_at # @api private def initialize(opts = {}) @credentials = opts[:credentials] @expires_at = opts[:expires_at] end end end end aws-sdk-v1-1.66.0/lib/aws/sqs/0000755000004100000410000000000012604445426015706 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/sqs/errors.rb0000644000004100000410000000733712604445426017561 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class SQS module Errors extend Core::LazyErrorClasses # @api private def self.error_class(code) super(code.sub(/^AWS\.SimpleQueueService\./, '')) end # Raised when one or more messages fail to delete during a # batch delete operation. # # See {#failures} for a complete list of failures. # class BatchDeleteError < StandardError def initialize failures @failures = failures super("Failed to delete #{failures.size} messages") end # @return [Array] Returns a list of hashes. Each hash # contains information about one message that failed to delete. # Hash keys include: # # * `:error_code` # * `:error_message` # * `:sender_fault` # * `:receipt_handle` # attr_reader :failures end # Raised from a batch change message visibility call when one or more # of the updates fail. # # See {#failures} for a complete list of failures. # class BatchChangeVisibilityError < StandardError def initialize failures @failures = failures super("Failed to change visibility for #{failures.size} messages") end # @return [Array] Returns a list of hashes. Each hash # contains information about one message that failed to change # visibility. Hash keys include: # # * `:error_code` # * `:error_message` # * `:sender_fault` # * `:receipt_handle` # attr_reader :failures end class BatchSendError < StandardError def initialize sent, failures @sent = sent @failures = failures super("Failed to send #{failures.size} messages") end # @return [Array] Returns a list of # {Queue::SentMessage} objects. attr_reader :sent # @return [Array] Returns a list of hashes. Each hash # contains information about one message that was not sent. # # * `:error_code` - identifies the type of failure # * `:error_message` - human readable description of the failure # * `:sender_fault` - whether the failure was caused by a server fault # * `:message_body` - the message body as passed to `:batch_send` # * `:batch_index` - the index in the list of messages passed # to `batch_send` of the failed message. # attr_reader :failures end class ChecksumError < StandardError def initialize failures # failures can also be a single failure, always generate an array @failures = failures.is_a?(Array) ? failures : [failures] super("#{@failures.size} messages failed checksum verification") end attr_reader :failures end class BatchSendMultiError < StandardError def initialize *error_set @errors = [] error_set.each do |error| @errors << error end end attr_reader :errors end end end end aws-sdk-v1-1.66.0/lib/aws/sqs/policy.rb0000644000004100000410000000300312604445426017526 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class SQS # (see Core::Policy) class Policy < Core::Policy class Statement < Core::Policy::Statement ACTION_MAPPING = { :add_permission => 'sqs:AddPermission', :change_message_visibility => 'sqs:ChangeMessageVisibility', :create_queue => 'sqs:CreateQueue', :delete_message => 'sqs:DeleteMessage', :delete_queue => 'sqs:DeleteQueue', :get_queue_attributes => 'sqs:GetQueueAttributes', :list_queues => 'sqs:ListQueues', :receive_message => 'sqs:ReceiveMessage', :remove_permission => 'sqs:RemovePermission', :send_message => 'sqs:SendMessage', :set_queue_attributes => 'sqs:SetQueueAttributes', } protected def resource_arn resource case resource when Queue then URI.parse(resource.url).path else resource.to_s end end end end end end aws-sdk-v1-1.66.0/lib/aws/sqs/client.rb0000644000004100000410000000270212604445426017512 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class SQS # Client class for Amazon Simple Queue Service (SQS). class Client < Core::QueryClient API_VERSION = '2012-11-05' signature_version :Version4, 'sqs' # @api private CACHEABLE_REQUESTS = Set[] private def build_request *args request = super(*args) if url_param = request.params.find { |p| p.name == "QueueUrl" } url = URI.parse(url_param.value) if url.class == URI::Generic raise ArgumentError, "invalid queue url `#{url_param.value}'" end request.host = url.host request.uri = url.request_uri if matches = request.host.match(/^sqs\.(.+?)\./) request.region = matches[1] end end request end end class Client::V20121105 < Client define_client_methods('2012-11-05') end end end aws-sdk-v1-1.66.0/lib/aws/sqs/received_message.rb0000644000004100000410000001551212604445426021531 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class SQS # Represents a message received from an Amazon SQS Queue. class ReceivedMessage include Core::Model # @return [Queue] The queue from which this message was # received. attr_reader :queue # @return [String] The ID of the message. attr_reader :id # @return [String] A string associated with this specific # instance of receiving the message. attr_reader :handle # @return [String] The message's contents. attr_reader :body # @return [String] An MD5 digest of the message body. attr_reader :md5 # @return [String] The request ID. attr_reader :request_id # @api private attr_reader :attributes # @return [String] The message attributes attached to the message. attr_reader :message_attributes # @api private ATTRIBUTE_ALIASES = { :sent_at => :sent_timestamp, :receive_count => :approximate_receive_count, :first_received_at => :approximate_first_receive_timestamp } # @api private def initialize(queue, id, handle, opts = {}) @queue = queue @id = id @handle = handle @body = opts[:body] @md5 = opts[:md5] @request_id = opts[:request_id] @attributes = opts[:attributes] || {} @message_attributes = opts[:message_attributes] || {} super end # When SNS publishes messages to SQS queues the message body is # formatted as a json message and then base 64 encoded. # # @example # # sns_msg = message.as_sns_message # # sns_msg.topic # #=> # # sns_msg.to_h.inspect # #=> { :body => '...', :topic_arn => ... } # # @return [ReceivedSNSMessage] def as_sns_message ReceivedSNSMessage.new(body, :config => config) end # Deletes the message from the queue. Even if the message is # locked by another reader due to the visibility timeout # setting, it is still deleted from the queue. If you leave a # message in the queue for more than 4 days, SQS automatically # deletes it. # # If you use {Queue#poll} or {Queue#receive_message} in block # form, the messages you receive will be deleted automatically # unless an exception occurs while you are processing them. # You can still use this method if you want to delete a # message early and then continue processing it. # # @note It is possible you will receive a message even after # you have deleted it. This might happen on rare occasions # if one of the servers storing a copy of the message is # unavailable when you request to delete the message. The # copy remains on the server and might be returned to you # again on a subsequent receive request. You should create # your system to be idempotent so that receiving a # particular message more than once is not a problem. # # @return [nil] def delete client.delete_message( :queue_url => queue.url, :receipt_handle => handle) nil end # Changes the visibility timeout of a specified message in a # queue to a new value. The maximum allowed timeout value you # can set the value to is 12 hours. This means you can't # extend the timeout of a message in an existing queue to more # than a total visibility timeout of 12 hours. (For more # information visibility timeout, see # [Visibility Timeout](http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/IntroductionArticle.html#AboutVT) # in the Amazon SQS Developer Guide.) # # For example, let's say the timeout for the queue is 30 # seconds, and you receive a message. Once you're 20 seconds # into the timeout for that message (i.e., you have 10 seconds # left), you extend it by 60 seconds by calling this method # with `timeout` set to 60 seconds. You have then changed the # remaining visibility timeout from 10 seconds to 60 seconds. # # @note If you attempt to set the timeout to an amount more # than the maximum time left, Amazon SQS returns an # error. It will not automatically recalculate and increase # the timeout to the maximum time remaining. # # @note Unlike with a queue, when you change the visibility # timeout for a specific message, that timeout value is # applied immediately but is not saved in memory for that # message. If you don't delete a message after it is # received, the visibility timeout for the message the next # time it is received reverts to the original timeout value, # not the value you set with this method. # # @return Returns the timeout argument as passed. # def visibility_timeout=(timeout) client.change_message_visibility( :queue_url => queue.url, :receipt_handle => handle, :visibility_timeout => timeout ) timeout end # @return [String] The AWS account number (or the IP address, # if anonymous access is allowed) of the sender. def sender_id attributes["SenderId"] end # @return [Time] The time when the message was sent. def sent_timestamp @sent_at ||= (timestamp = attributes["SentTimestamp"] and Time.at(timestamp.to_i / 1000.0)) || nil rescue RangeError => e p [timestamp, timestamp.to_i] end alias_method :sent_at, :sent_timestamp # @return [Integer] The number of times a message has been # received but not deleted. def approximate_receive_count (count = attributes["ApproximateReceiveCount"] and count.to_i) or nil end alias_method :receive_count, :approximate_receive_count # @return [Time] The time when the message was first received. def approximate_first_receive_timestamp @received_at ||= (timestamp = attributes["ApproximateFirstReceiveTimestamp"] and Time.at(timestamp.to_i / 1000.0)) || nil end alias_method :first_received_at, :approximate_first_receive_timestamp end end end aws-sdk-v1-1.66.0/lib/aws/sqs/received_sns_message.rb0000644000004100000410000000643212604445426022415 0ustar www-datawww-data# Copyright 2011-2013 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 'time' require 'base64' module AWS class SQS # Represents message published from an {SNS::Topic} to an {SQS::Queue}. class ReceivedSNSMessage include Core::Model # @param [String] body The SQS message body # from a message published by SNS. # @param [Hash] options def initialize body, options = {} @body = body super end # @return [String] Returns the JSON hash (as a string) as was # published by SNS. See {#body} to get the decoded message # or {#to_h} to get the decoded JSON hash as a ruby hash. def raw_message @body end # @return[String] Returns the decoded message as was published. def body to_h[:body] end # @return [String] Returns the ARN for the topic that published this # message. def topic_arn to_h[:topic_arn] end # @return [SNS::Topic] Returns the topic that published this message. def topic SNS::Topic.new(topic_arn, :config => config) end # @return [String] Returns the message type. def message_type to_h[:message_type] end # @return [String] Returns the calculated signature for the message. def signature to_h[:signature] end # @return [String] Returns the signature version. def signature_version to_h[:signature_version] end # @return [Time] Returns the time the message was published at by SNS. # by SNS. def published_at to_h[:published_at] end # @return [String] Returns the unique id of the SNS message. def message_id to_h[:message_id] end # @return [String] Returns the url for the signing cert. def signing_cert_url to_h[:signing_cert_url] end # @return [String] Returns the url you can request to unsubscribe message # from this queue. def unsubscribe_url to_h[:unsubscribe_url] end # @return [Hash] Returns the decoded message as a hash. def to_h data = JSON.parse(@body) { :body => data['Message'], :topic_arn => data['TopicArn'], :message_type => data['Type'], :signature => data['Signature'], :signature_version => data['SignatureVersion'], :published_at => Time.parse(data['Timestamp']), :message_id => data['MessageId'], :signing_cert_url => data['SigningCertURL'], :unsubscribe_url => data['UnsubscribeURL'], } end # @return [Hash] Returns the decoded message body as a hash. def body_message_as_h @body_message_as_h ||= JSON.parse(to_h[:body]) end end end end aws-sdk-v1-1.66.0/lib/aws/sqs/config.rb0000644000004100000410000000130712604445426017501 0ustar www-datawww-data# Copyright 2011-2013 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. AWS::Core::Configuration.module_eval do add_service 'SQS', 'sqs', 'sqs' add_option :sqs_verify_checksums, true, :boolean => true end aws-sdk-v1-1.66.0/lib/aws/sqs/queue_collection.rb0000644000004100000410000001405712604445426021601 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class SQS # Represents all the {Queue} objects in your account. # # If you have permission to access a queue created by another # account, you can also use this collection to access that queue # by URL. # # @example Printing the URLs of all queues # # pp sqs.queues.map(&:url) # # @example Filtering queues by queue name prefix # # pp sqs.queues.with_prefix("production_").map(&:url) # # @example Accessing a queue by URL # # url = "http://sqs.us-west-2.amazonaws.com/123456789012/myqueue" # sqs.queues[url].send_message("HELLO") # # @example Accessing a queue in your account by name # # sqs.queues.named("myqueue").send_message("HELLO") # class QueueCollection include Core::Collection::Simple # @api private def initialize(opts = {}) @prefix = opts[:prefix] super end # @return [String] The queue name prefix by which this # collection is filtered. attr_reader :prefix # Creates a new queue. # # @note If you delete a queue, you must wait at least 60 # seconds before creating a queue with the same name. # # @param [String] name The name to use for the queue created. # Constraints: Maximum 80 characters; alphanumeric # characters, hyphens (-), and underscores (_) are allowed. # # The name of the queue should be unique within your account. If # you provide the name of an existing queue with the same options # it was created with then no error is raised and the existing # queue will be returned. # # @param [Hash] options # # @option options [Integer] :visibility_timeout (30) The number of # seconds a message received from a queue will be invisible to # others when they ask to receive messages. # # @option options [Policy] :policy A policy object or policy desription # (a json string). # # @option options [Integer] :maximum_message_size (65536) The maximum # number of bytes a message can contain before Amazon SQS rejects # it. # # @option options [Integer] :delay_seconds The time in seconds that # the delivery of all messages in the queue will be delayed. # This can be overriden when sending a message to the queue. # # @option options [Integer] :message_retention_period The number of # seconds from 60 (1 minute) to 1209600 (14 days). The default # is 345600 (4 days). # # @return [Queue] The newly created queue. # def create name, options = {} # SQS removed the default prefix to the visibility timeout option # in the 2011-10-01 update -- this allows us to not break existing # customers. if options[:default_visibility_timeout] options[:visibility_timeout] = options.delete(:default_visibility_timeout) end if policy = options[:policy] options[:policy] = policy.to_json unless policy.is_a?(String) end client_opts = {} client_opts[:queue_name] = name unless options.empty? client_opts[:attributes] = options.inject({}) do |attributes,(k,v)| attributes.merge(Core::Inflection.class_name(k.to_s) => v.to_s) end end response = client.create_queue(client_opts) Queue.new(response[:queue_url], :config => config) end # @param [String] prefix The queue name prefix. # @return [QueueCollection] A new collection representing only # the queues whose names start with the given prefix. def with_prefix(prefix) self.class.new(:prefix => prefix, :config => config) end # @return [Queue] The queue with the given URL. def [] url Queue.new(url, :config => config) end # Returns the queue with the given name. This requires making # a request to SQS to get the queue url. If you know the url, # you should use {#[]} instead. # # @example # # queue = AWS::SQS.new.queues.named('my-queue') # # @param (see #url_for) # @option (see #url_for) # @return [Queue] Returns the queue with the given name. def named queue_name, options = {} self[url_for(queue_name, options = {})] end # Returns the url for the given queue. # # @example # # sqs.queues.url_for('my-queue') # #=> "https://sqs.us-east-1.amazonaws.com/123456789012/my-queue" # # @param [String] queue_name The name of the queue you need a URL for. # # @param [Hash] options # # @option options [String] :queue_owner_aws_account_id The AWS account # ID of the account that created the queue. You can only get the # url for queues in other accounts when the account owner has # granted you permission. # def url_for queue_name, options = {} client_opts = {} client_opts[:queue_name] = queue_name client.get_queue_url(client_opts.merge(options))[:queue_url] end protected # @yieldparam [Queue] queue Each {Queue} object in the collection. def _each_item options, &block options[:queue_name_prefix] = prefix if prefix resp = client.list_queues(options) resp.data[:queue_urls].each do |url| queue = self[url] yield(queue) end end end end end aws-sdk-v1-1.66.0/lib/aws/sqs/queue.rb0000644000004100000410000007161712604445426017373 0ustar www-datawww-data# Copyright 2011-2013 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 'openssl' module AWS class SQS # Represents an Amazon SQS Queue. # # @example Sending a message # # msg = queue.send_message("HELLO") # puts "Sent message: #{msg.id}" # # @example Polling for messages indefinitely # # queue.poll do |msg| # puts "Got message: #{msg.body}" # end # class Queue # The default number of seconds to wait between polling requests for # new messages. # @deprecated No longer used by {#poll} DEFAULT_POLL_INTERVAL = 1 # The default number of seconds to pass in as the SQS long polling # value (`:wait_time_seconds`) in {#receive_message}. # # @since 1.8.0 DEFAULT_WAIT_TIME_SECONDS = 15 include Core::Model # @return [String] The queue URL. attr_reader :url # @api private def initialize(url, opts = {}) @url = url super end # Deletes the queue, regardless of whether it is empty. # # When you delete a queue, the deletion process takes up to 60 # seconds. Requests you send involving that queue during the # 60 seconds might succeed. For example, calling # {#send_message} might succeed, but after the 60 seconds, the # queue and that message you sent no longer exist. # # Also, when you delete a queue, you must wait at least 60 seconds # before creating a queue with the same name. # @return [nil] def delete client.delete_queue(:queue_url => url) nil end # Represents a message sent using {Queue#send_message}. class SentMessage # @return [String] Returns the message ID. attr_accessor :message_id alias_method :id, :message_id # @return [String] Returns the request ID. attr_accessor :request_id # @return [String] Returns an MD5 digest of the message body # string. You can use this to verify that SQS received your # message correctly. attr_accessor :md5 end # Delivers a message to this queue. # # @param [String] body The message to send. The maximum # allowed message size is 64 KB. The message may only # contain Unicode characters from the following list, # according to the W3C XML specification (for more # information, go to # http://www.w3.org/TR/REC-xml/#charsets). If you send any # characters not included in the list, your request will be # rejected. # # * `#x9` # * `#xA` # * `#xD` # * `#x20` to `#xD7FF` # * `#xE000` to `#xFFFD` # * `#x10000` to `#x10FFFF` # # @param [Hash] options # # @option options [Integer] :delay_seconds The number of seconds to # delay the message. The message will become available for # processing after the delay time has passed. # If you don't specify a value, the default value for the # queue applies. Should be from 0 to 900 (15 mins). # # @return [SentMessage] An object containing information about # the message that was sent. # def send_message body, options = {} client_opts = options.dup client_opts[:queue_url] = url client_opts[:message_body] = body response = client.send_message(client_opts) msg = SentMessage.new msg.message_id = response[:message_id] msg.request_id = (response[:response_metadata] || {})[:request_id] msg.md5 = response[:md5_of_message_body] verify_send_message_checksum body, msg.md5 msg end # Retrieves one or more messages. When a block is given, each # message is yielded to the block and then deleted as long as # the block exits normally. When no block is given, you must # delete the message yourself using {ReceivedMessage#delete}. # # @note Due to the distributed nature of the queue, a weighted # random set of machines is sampled on a ReceiveMessage # call. That means only the messages on the sampled machines # are returned. If the number of messages in the queue is # small (less than 1000), it is likely you will get fewer # messages than you requested per call to # {#receive_message}. If the number of messages in the queue # is extremely small, you might not receive any messages. # To poll continually for messages, use the {#poll} method, # which automatically retries the request after a # configurable delay. # # @param [Hash] opts Options for receiving messages. # # @option opts [Integer] :limit The maximum number of messages # to receive. By default this is 1, and the return value is # a single message object. If this options is specified and # is not 1, the return value is an array of message objects; # however, the array may contain fewer objects than you # requested. Valid values: integers from 1 to 10. # # Not necessarily all the messages in the queue are returned # (for more information, see the preceding note about # machine sampling). # # @option opts [Integer] :wait_time_seconds The number of seconds # the service should wait for a response when requesting a new message. # Defaults to the {#wait_time_seconds} attribute defined on the queue. # See {#wait_time_seconds} to set the global long poll setting # on the queue. # # @option opts [Integer] :visibility_timeout The duration (in # seconds) that the received messages are hidden from # subsequent retrieve requests. Valid values: integer from # 0 to 43200 (maximum 12 hours) # # @option opts [Array] :attributes The # attributes to populate in each received message. Valid values: # # * `:all` (to populate all attributes) # * `:sender_id` # * `:sent_at` # * `:receive_count` # * `:first_received_at` # # See {ReceivedMessage} for documentation on each # attribute's meaning. # # @option opts [Array] :message_attribute_names A list of # message attribute names to receive. These will be available on # the {ReceivedMessage} as `#message_attributes`. # # @yieldparam [ReceivedMessage] message Each message that was received. # # @return [ReceivedMessage] Returns the received message (or messages) # only if a block is not given to this method. # def receive_message(opts = {}, &block) resp = client.receive_message(receive_opts(opts)) failed = verify_receive_message_checksum resp raise Errors::ChecksumError.new(failed) unless failed.empty? messages = resp[:messages].map do |m| ReceivedMessage.new(self, m[:message_id], m[:receipt_handle], :body => m[:body], :md5 => m[:md5_of_body], :request_id => (resp[:response_metadata] || {})[:request_id], :attributes => m[:attributes], :message_attributes => m[:message_attributes]) end if block call_message_block(messages, block) elsif opts[:limit] && opts[:limit] != 1 messages else messages.first end end alias_method :receive_messages, :receive_message # Polls continually for messages. For example, you can use # this to poll indefinitely: # # queue.poll { |msg| puts msg.body } # # Or, to poll indefinitely for the first message and then # continue polling until no message is received for a period # of at least ten seconds: # # queue.poll(:initial_timeout => false, # :idle_timeout => 10) { |msg| puts msg.body } # # As with the block form of {#receive_message}, this method # automatically deletes the message then the block exits # normally. # # @yieldparam [ReceivedMessage] message Each message that was received. # # @param [Hash] opts Options for polling. # # @option opts [Integer] :wait_time_seconds The number of seconds # the service should wait for a response when requesting a new message. # Defaults to {DEFAULT_WAIT_TIME_SECONDS}. Use `nil` to # use the queue's global long polling wait time setting. # See {#wait_time_seconds} to set the global long poll setting # on the queue. # # @option opts [Integer] :idle_timeout The maximum number of # seconds to spend polling while no messages are being # returned. By default this method polls indefinitely # whether messages are received or not. # # @option opts [Integer] :initial_timeout The maximum number # of seconds to spend polling before the first message is # received. This option defaults to the value of # `:idle_timeout`. You can specify `false` to poll # indefinitely for the first message when `:idle_timeout` is # set. # # @option opts [Integer] :batch_size The maximum number of # messages to retrieve in a single request. By default # messages are received one at a time. Valid values: # integers from 1 to 10. # # @option opts [Integer] :visibility_timeout The duration (in # seconds) that the received messages are hidden from # subsequent retrieve requests. Valid values: integer from # 0 to 43200 (maximum 12 hours) # # @option opts [Array] :attributes The # attributes to populate in each received message. Valid values: # # * `:all` (to populate all attributes) # * `:sender_id` # * `:sent_at` # * `:receive_count` # * `:first_received_at` # # See {ReceivedMessage} for documentation on each # attribute's meaning. # # @option opts [Float, Integer] :poll_interval As of # v1.7.2, this option is no longer used. See the # `:wait_time_seconds` option for long polling instead. # # @return [nil] def poll(opts = {}, &block) opts[:limit] = opts.delete(:batch_size) if opts.key?(:batch_size) opts[:wait_time_seconds] = DEFAULT_WAIT_TIME_SECONDS unless opts.has_key?(:wait_time_seconds) last_message_at = Time.now got_first = false loop do got_msg = false receive_messages(opts) do |message| got_msg = got_first = true last_message_at = Time.now yield(message) end unless got_msg return if hit_timeout?(got_first, last_message_at, opts) end end nil end # @return [Integer] The approximate number of visible messages # in a queue. For more information, see # [Resources Required to Process Messages](http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/IntroductionArticle.html#ApproximateNumber) # in the Amazon SQS Developer Guide. def approximate_number_of_messages get_attribute("ApproximateNumberOfMessages").to_i end alias_method :visible_messages, :approximate_number_of_messages # @return [Integer] The approximate number of messages that # are not timed-out and not deleted. For more information, # see [Resources Required to Process Messages](http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/IntroductionArticle.html#ApproximateNumber) # in the Amazon SQS Developer Guide. def approximate_number_of_messages_not_visible get_attribute("ApproximateNumberOfMessagesNotVisible").to_i end alias_method :invisible_messages, :approximate_number_of_messages_not_visible # @return [Integer] Returns the visibility timeout for the # queue. For more information about visibility timeout, see # [Visibility Timeout](http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/IntroductionArticle.html#AboutVT) # in the Amazon SQS Developer Guide. def visibility_timeout get_attribute("VisibilityTimeout").to_i end # Sets the visibility timeout for the queue. # # @param [Integer] timeout The length of time (in seconds) # that a message received from a queue will be invisible to # other receiving components when they ask to receive # messages. Valid values: integers from 0 to 43200 (12 # hours). # # @return Returns the value passed as a timeout. def visibility_timeout=(timeout) set_attribute("VisibilityTimeout", timeout.to_s) timeout end # @return [Time] The time when the queue was created. def created_timestamp Time.at(get_attribute("CreatedTimestamp").to_i) end # @return [Time] The time when the queue was last changed. def last_modified_timestamp Time.at(get_attribute("LastModifiedTimestamp").to_i) end # @return [Integer] The limit of how many bytes a message can # contain before Amazon SQS rejects it. def maximum_message_size get_attribute("MaximumMessageSize").to_i end # Sets the maximum message size for the queue. # # @param [Integer] size The limit of how many bytes a message # can contain before Amazon SQS rejects it. This must be an # integer from 1024 bytes (1KB) up to 65536 bytes # (64KB). The default for this attribute is 8192 (8KB). # @return Retuns the passed size argument. def maximum_message_size=(size) set_attribute("MaximumMessageSize", size.to_s) end # @return [Integer] The number of seconds Amazon SQS retains a # message. def message_retention_period get_attribute("MessageRetentionPeriod").to_i end # Sets the message retention period for the queue # # @param [Integer] period The number of seconds Amazon SQS # retains a message. Must be an integer from 3600 (1 hour) # to 1209600 (14 days). The default for this attribute is # 345600 (4 days). # @return Returns the passed period argument. def message_retention_period=(period) set_attribute("MessageRetentionPeriod", period.to_s) period end # @return [Integer] Gets the current default delay for messages sent # to the queue. def delay_seconds get_attribute("DelaySeconds").to_i end # Sets the default delay for messages sent to the queue. # @param [Integer] seconds How many seconds a message will be delayed. def delay_seconds= seconds set_attribute("DelaySeconds", seconds.to_s) end # @return [Integer] Gets the number of seconds the service will wait # for a response when requesting a new message # @since 1.8.0 def wait_time_seconds get_attribute("ReceiveMessageWaitTimeSeconds").to_i end # Sets the number of seconds that the service should wait for a response # when requesting a new message # @param [Integer] seconds How many seconds to wait for a response # @since 1.8.0 def wait_time_seconds= seconds set_attribute("ReceiveMessageWaitTimeSeconds", seconds.to_s) end # @return [Integer] Returns an approximate count of messages delayed. def approximate_number_of_messages_delayed get_attribute("ApproximateNumberOfMessagesDelayed").to_i end # @return [String] The queue's Amazon resource name (ARN). def arn @arn ||= get_attribute("QueueArn") end # @return [Boolean] True if the queue exists. # # @note This may raise an exception if you don't have # permission to access the queue attributes. Also, it may # return true for up to 60 seconds after a queue has been # deleted. def exists? client.get_queue_attributes(:queue_url => url, :attribute_names => ["QueueArn"]) rescue Errors::NonExistentQueue, Errors::InvalidAddress false else true end # @api private module PolicyProxy attr_accessor :queue def change yield(self) queue.policy = self end def delete queue.client.send(:set_attribute, 'Policy', '') end end # @return [Policy] Returns the current queue policy if there is one. # Returns `nil` otherwise. def policy if policy_json = get_attribute('Policy') policy = SQS::Policy.from_json(policy_json) policy.extend(PolicyProxy) policy.queue = self policy else nil end end # Set the policy on this queue. # # If you pass nil or an empty string then it will have the same # effect as deleting the policy. # # @param policy The policy to set. This policy can be a {Policy} object, # a json policy string, or any other object that responds with a policy # string when it received #to_json. # # @return [nil] # def policy= policy policy_string = case policy when nil, '' then '' when String then policy else policy.to_json end set_attribute('Policy', policy_string) nil end # Sends a batch of up to 10 messages in a single request. # # queue.send_messages('message-1', 'message-2') # # You can also set an optional delay for all of the messages: # # # delay all messages 15 minutes # queue.batch_send(msg1, msg2, :delay_seconds => 900) # # If you need to set a custom delay for each message you can pass # hashes: # # messages = [] # messages << { :message_body => 'msg1', :delay_seconds => 60 } # messages << { :message_body => 'msg2', :delay_seconds => 30 } # # queue.batch_send(messages) # # @param [String,Hash] messages A list of messages. Each message # should be a string, or a hash with a `:message_body`, # and optionally `:delay_seconds`. # # @raise [Errors::BatchSendError] Raises this error when one or more # of the messages failed to send, but others did not. On the raised # object you can access a list of the messages that failed, and # a list of messages that succeeded. # # @return [Array] Returns an array of sent message objects. # Each object responds to #message_id and #md5_of_message_body. # The message id is generated by Amazon SQS. # def batch_send *messages entries = messages.flatten unless entries.first.is_a?(Hash) options = entries.last.is_a?(Hash) ? entries.pop : {} entries = entries.collect{|msg| { :message_body => msg } } if delay = options[:delay_seconds] entries.each {|entry| entry[:delay_seconds] = delay } end end entries.each_with_index {|entry,n| entry[:id] = n.to_s } client_opts = {} client_opts[:queue_url] = url client_opts[:entries] = entries response = client.send_message_batch(client_opts) failed = batch_failures(entries, response, true) checksum_failed = verify_send_message_batch_checksum entries, response sent = response[:successful].collect do |sent| msg = SentMessage.new msg.message_id = sent[:message_id] msg.md5 = sent[:md5_of_message_body] msg end if !failed.empty? && !checksum_failed.empty? send_error = Errors::BatchSendError.new(sent, failed) checksum_error = Errors::ChecksumError.new(checksum_failed) raise Errors::BatchSendMultiError.new send_error, checksum_error elsif !failed.empty? raise Errors::BatchSendError.new(sent, failed) unless failed.empty? elsif !checksum_failed.empty? raise Errors::ChecksumError.new(checksum_failed) end sent end # @param [ReceivedMessage,String] messages A list of up to 10 messages # to delete. Each message should be a {ReceivedMessage} object # or a received message handle (string). # # @raise [Errors::BatchDeleteSend] Raised when one or more of the # messages failed to delete. The raised error has a list # of the failures. # # @return [nil] # def batch_delete *messages entries = [] messages.flatten.each_with_index do |msg,n| handle = msg.is_a?(ReceivedMessage) ? msg.handle : msg entries << { :id => n.to_s, :receipt_handle => handle } end response = client.delete_message_batch( :queue_url => url, :entries => entries) failures = batch_failures(entries, response) raise Errors::BatchDeleteError.new(failures) unless failures.empty? nil end # @overload batch_change_visibility(visibility_timeout, *messages) # # Accepts a single `:visibility_timeout` value and a list of # messages ({ReceivedMessage} objects or receipt handle strings). # This form of the method is useful when you want to set the same # timeout value for each message. # # queue.batch_change_visibility(10, messages) # # @param [Integer] visibility_timeout The new value for the message's # visibility timeout (in seconds). # # @param [ReceivedMessage,String] message A list of up to 10 messages # to change the visibility timeout for. # # @raise [BatchChangeVisibilityError] Raises this error when one # or more of the messages failed the visibility update. # # @return [nil] # # @overload batch_change_visibility(*messages_with_timeouts) # # Accepts a list of hashes. Each hash should provide the visibility # timeout and message (a {ReceivedMessage} object or the recipt handle # string). # # Use this form when each message needs a different visiblity timeout. # # messages = [] # messages << { :message => 'handle1', :visibility_timeout => 5 } # messages << { :message => 'handle2', :visibility_timeout => 10 } # # queue.batch_change_visibility(*messages) # # @param [Hash] message A list hashes, each with a `:visibility_timeout` # and a `:message`. # # @raise [BatchChangeVisibilityError] Raises this error when one # or more of the messages failed the visibility update. # # @return [nil] # def batch_change_visibility *args args = args.flatten if args.first.is_a?(Integer) timeout = args.shift messages = args.collect{|m| [m, timeout] } else messages = args.collect{|m| [m[:message], m[:visibility_timeout]] } end entries = [] messages.each do |msg,timeout| handle = msg.is_a?(ReceivedMessage) ? msg.handle : msg entries << { :id => entries.size.to_s, :receipt_handle => handle, :visibility_timeout => timeout, } end response = client.change_message_visibility_batch( :queue_url => url, :entries => entries) failures = batch_failures(entries, response) raise Errors::BatchChangeVisibilityError.new(failures) unless failures.empty? nil end # @return [Boolean] Returns true if the other queue has the same # url. def ==(other) other.kind_of?(Queue) and other.url == url end alias_method :eql?, :== # @api private def inspect "<#{self.class}:#{url}>" end protected def batch_failures entries, response, include_batch_index=false response[:failed].inject([]) do |failures, failure| entry = entries.find{|e| e[:id] == failure[:id] } details = { :error_code => failure[:code], :error_message => failure[:message], :sender_fault => failure[:sender_fault], } if include_batch_index details[:batch_index] = failure[:id].to_i end if message_body = entry[:message_body] details[:message_body] = message_body end if handle = entry[:receipt_handle] details[:receipt_handle] = handle end failures << details end end # @api private protected def hit_timeout?(got_first, last_message_at, opts) initial_timeout = opts[:initial_timeout] idle_timeout = opts[:idle_timeout] timeout = (got_first || # if initial_timeout is false (as opposed # to nil) then we skip the branch and poll # indefinitely until the first message # comes (!initial_timeout && initial_timeout != false) ? idle_timeout : initial_timeout) and Time.now - last_message_at > timeout end # @api private protected def receive_opts(opts) receive_opts = { :queue_url => url } receive_opts[:visibility_timeout] = opts[:visibility_timeout] if opts[:visibility_timeout] receive_opts[:max_number_of_messages] = opts[:limit] if opts[:limit] receive_opts[:wait_time_seconds] = opts[:wait_time_seconds] if opts[:wait_time_seconds] receive_opts[:message_attribute_names] = opts[:message_attribute_names] if opts[:message_attribute_names] if names = opts[:attributes] receive_opts[:attribute_names] = names.map do |name| name = ReceivedMessage::ATTRIBUTE_ALIASES[name.to_sym] if ReceivedMessage::ATTRIBUTE_ALIASES.key?(name.to_sym) name = Core::Inflection.class_name(name.to_s) if name.kind_of?(Symbol) name end end receive_opts end # @api private protected def call_message_block(messages, block) result = nil messages.each do |message| begin result = block.call(message) rescue Exception => e raise else message.delete end end result end # @api private protected def get_attribute(name) resp = client.get_queue_attributes(:queue_url => url, :attribute_names => [name, "QueueArn"].uniq) @arn ||= resp.attributes["QueueArn"] resp.attributes[name] end # @api private protected def set_attribute(name, value) client.set_queue_attributes({ :queue_url => url, :attributes => { name => value }, }) end # @api private protected def is_checksum_valid checksum, data if config.sqs_verify_checksums? calculate_checksum(data) == checksum else true end end # @api private protected def calculate_checksum data OpenSSL::Digest::MD5.hexdigest data end # @api private protected def verify_send_message_checksum body, md5 unless is_checksum_valid md5, body raise Errors::ChecksumError.new "Invalid MD5 #{md5} for message body #{body}" end end # @api private protected def verify_send_message_batch_checksum entries, response failed = [] response[:successful].each do |msg| entry = entries.find{ |e| e[:id] == msg[:id] } failed << msg unless is_checksum_valid msg[:md5_of_message_body], entry[:message_body] end failed end # @api private protected def verify_receive_message_checksum response return [] if response[:messages].nil? invalid_msgs = [] response[:messages].each do |msg| md5 = msg[:md5_of_body] body = msg[:body] invalid_msgs << msg unless is_checksum_valid md5, body end invalid_msgs end end end end aws-sdk-v1-1.66.0/lib/aws/emr/0000755000004100000410000000000012604445426015663 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/emr/errors.rb0000644000004100000410000000123412604445426017524 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class EMR module Errors extend Core::LazyErrorClasses end end end aws-sdk-v1-1.66.0/lib/aws/emr/instance_group_collection.rb0000644000004100000410000000521212604445426023443 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class EMR class InstanceGroupCollection include Core::Collection::Simple # @param [JobFlow] job_flow # @api private def initialize job_flow, options = {} @job_flow = job_flow super end # @return [JobFlow] attr_reader :job_flow # @param [String] instance_group_id # @return [InstanceGroup] Returns an instance group with the given ID. def [] instance_group_id InstanceGroup.new(job_flow, instance_group_id) end # Adds an instance group to the job flow. # @param [String] role The role of the instance group in the cluster. # @param [String] instance_type The Amazon EC2 instance type to use. # @param [Integer] instance_count Target size of instances for the group. # @param [Hash] options # @option options [String] :name Friendly name given to the group. # @option options [String] :market Market type of the Amazon EC2 # instances used to create a cluster node. # @option opitons [Float,String] :bid_price Bid price for each Amazon # EC2 instance in the instance group when launching nodes as # spot instances, expressed in USD. # @return [InstanceGroup] def create role, instance_type, instance_count, options = {} options[:instance_role] = role options[:instance_type] = instance_type options[:instance_count] = instance_count options[:bid_price] = options[:bid_price].to_s if options[:bid_price] client_opts = {} client_opts[:job_flow_id] = job_flow.job_flow_id client_opts[:instance_groups] = [options] resp = client.add_instance_groups(client_opts) self[resp.data[:instance_group_ids].first] end alias_method :add, :create protected def _each_item options = {} job_flow.instance_group_details.each do |details| group = InstanceGroup.new_from( :describe_job_flows, details, job_flow, details[:instance_group_id]) yield(group) end end end end end aws-sdk-v1-1.66.0/lib/aws/emr/job_flow_collection.rb0000644000004100000410000001217712604445426022234 0ustar www-datawww-data# Copyright 2011-2013 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 'date' require 'time' module AWS class EMR # # Creating a Job Flow # # Call {#create} to run a new job flow. # # emr = AWS::EMR.new # # job_flow = emr.job_flows.create('name', # :instances => { # :instance_count => 2, # :master_instance_type => 'm1.small', # :slave_instance_type => 'm1.small', # } # ) # # # Getting a Job Flow # # You can get a job flow by its ID. # # job_flow = emr.job_flows['j-123456678'] # makes no request # job_flow.exists? #=> true/false # # # Enumerating Job Flows # # You can enumerate all job flows, or filter them. # # # all job flows # job_flows.each {|job_flow| ... } # # # only job flows with a particular state # job_flows.with_state('ENDED').each {|job_flow| ... } # # The filtering methods include: # # * {#with_id} # * {#with_state} # * {#created_before} # * {#created_after} # class JobFlowCollection include Core::Collection::Simple # @api private def initialize options = {} @filters = options[:filters] || {} super end # @param [String] job_flow_id # @return [JobFlow] Returns a {JobFlow} with the given ID. def [] job_flow_id JobFlow.new(job_flow_id, :config => config) end # Runs a job flow. # # job_flow = emr.job_flows.create('name', # :instances => { # :instance_count => 2, # :master_instance_type => 'm1.small', # :slave_instance_type => 'm1.small', # } # ) # # See {Client#run_job_flow} for documentation on the complete # list of accepted options. # @param [String] name # @param [Hash] options # @see (Client#run_job_flow) # @return [JobFlow] def create name, options = {} options[:name] = name options[:ami_version] ||= 'latest' options[:instances] ||= {} resp = client.run_job_flow(options) self[resp.data[:job_flow_id]] end alias_method :run, :create # Returns a new collection that will only enumerate job flows that have # one of the given ids. # # emr.job_flows.with_id('id1', 'id2', 'id3').each do |job_flow| # # ... # end # # @param [String] ids One or more job flow ids to use as a filter. # @return [JobFlowCollection] def with_id *ids filter(:job_flow_ids, ids.flatten) end # Returns a new collection that will only enumerate job flows that have # one of the given job flow states. # # emr.job_flows.with_state('SHUTTING_DOWN', 'TERMINATED').each do |job| # # ... # end # # @param [String] states One or more job flow states to use as a filter. # @return [JobFlowCollection] def with_state *states filter(:job_flow_states, states.flatten) end # Returns a new collection that will only enumerate job flows that # were created before the given time. # # # enumerate jobs that are more than an hour old # emr.job_flows.created_before(Time.now - 3600).each{|job| ... } # # @param [Time,DateTime,Date,Integer] time # @return [JobFlowCollection] def created_before time filter(:created_before, time.to_i) end # Returns a new collection that will only enumerate job flows that # were created after the given time. # # # enumerate jobs that are at most 1 hour old # emr.job_flows.created_after(Time.now - 3600).each{|job| ... } # # @param [Time,DateTime,Date,Integer] time # @return [JobFlowCollection] def created_after time filter(:created_after, time.to_i) end # @param [String,Symbol] name # @param [Mixed] value # @return [JobFlowCollection] def filter name, value options = {} options[:filters] = @filters.merge(name.to_s.to_sym => value) options[:config] = config JobFlowCollection.new(options) end protected def _each_item options = {}, &block resp = client.describe_job_flows(@filters.merge(options)) resp.data[:job_flows].each do |details| job_flow = JobFlow.new_from( :describe_job_flows, details, details[:job_flow_id], :config => config) yield(job_flow) end end end end end aws-sdk-v1-1.66.0/lib/aws/emr/client.rb0000644000004100000410000000164412604445426017473 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class EMR # Client class for Elastic MapReduce (EMR). class Client < Core::JSONClient API_VERSION = '2009-03-31' signature_version :Version4, 'elasticmapreduce' # @api private CACHEABLE_REQUESTS = Set[] end class Client::V20090331 < Client define_client_methods('2009-03-31') end end end aws-sdk-v1-1.66.0/lib/aws/emr/config.rb0000644000004100000410000000123012604445426017451 0ustar www-datawww-data# Copyright 2011-2013 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. AWS::Core::Configuration.module_eval do add_service 'EMR', 'emr', 'elasticmapreduce' end aws-sdk-v1-1.66.0/lib/aws/emr/instance_group.rb0000644000004100000410000000713312604445426021234 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class EMR # @attr_reader [String] market # # @attr_reader [String] instance_role # # @attr_reader [String,nil] bid_price # # @attr_reader [String] instance_type # # @attr_reader [String] instance_request_count # # @attr_reader [String] instance_running_count # # @attr_reader [String] state # # @attr_reader [String] last_state_change_reason # # @attr_reader [Time] created_at # # @attr_reader [Time] started_at # # @attr_reader [Time] ready_at # # @attr_reader [Time] ended_at # class InstanceGroup < Core::Resource # @api private def initialize job_flow, instance_group_id, options = {} @job_flow = job_flow @instance_group_id = instance_group_id super end # @return [JobFlow] attr_reader :job_flow # @return [String] attr_reader :instance_group_id alias_method :id, :instance_group_id # @attr_reader [String] name attribute :name, :static => true attribute :market, :static => true attribute :instance_role, :static => true attribute :bid_price, :static => true attribute :instance_type, :static => true attribute :instance_request_count attribute :instance_running_count attribute :state attribute :last_state_change_reason attribute :creation_date_time, :static => true, :alias => :created_at attribute :start_date_time, :alias => :started_at attribute :ready_date_time, :alias => :ready_at attribute :end_date_time, :alias => :ended_at populates_from(:describe_job_flows) do |resp| find_in_response(resp) end # Modifies the target size of this instance group. # @param [Integer] count # @return (see #modify) def set_instance_count count modify(:instance_count => count) end # @param [Hash] options # @option options [Integer] :count The new target size for the # instance group. # @return [nil] def modify options = {} options[:instance_group_id] = instance_group_id options[:instance_count] = options.delete(:count) if options[:count] client.modify_instance_groups(:instance_groups => [options]) nil end # @return [Boolean] Returns `true` if the instance group exists. def exists? !!find_in_response(get_resource) end protected def resource_identifiers [[:job_flow_id, job_flow.id], [:instance_group_id, id]] end def get_resource attr = nil client.describe_job_flows(:job_flow_ids => [job_flow.id]) end def find_in_response resp data = nil resp.data[:job_flows].each do |job| if job[:job_flow_id] == job_flow.job_flow_id job[:instances][:instance_groups].each do |ig| if ig[:instance_group_id] == instance_group_id data = ig end end end end data end end end end aws-sdk-v1-1.66.0/lib/aws/emr/job_flow.rb0000644000004100000410000002267612604445426020026 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class EMR # # @attr_reader [String] name # The name of the job flow. # # @attr_reader [String] ami_version # The version of the AMI used to initialize Amazon EC2 instances in # the job flow. # # @attr_reader [String,nil] log_uri # The location in Amazon S3 where log files for the job are stored. # # @attr_reader [Array] supported_products # A list of strings set by third party software when the job flow is # launched. If you are not using third party software to manage the # job flow this value is empty. # # @attr_reader [Array] bootstrap_actions # # @attr_reader [String] state # # @attr_reader [Time] created_at # # @attr_reader [Time] started_at # # @attr_reader [Time] ready_at # # @attr_reader [Time] ended_at # # @attr_reader [String] last_state_change_reason # # @attr_reader [String] master_instance_type # # @attr_reader [String] master_public_dns_name # # @attr_reader [String] master_instance_id # # @attr_reader [String] slave_instance_id # # @attr_reader [Integer] instance_count # # @attr_reader [Integer] normalized_instance_hours # # @attr_reader [String] ec2_key_name # # @attr_reader [String] ec2_subnet_id # # @attr_reader [String] availability_zone_name # # @attr_reader [Boolean] keep_job_flow_alive_when_no_steps # # @attr_reader [Boolean] termination_protected # # @attr_reader [String] hadoop_version # # @attr_reader [Array] instance_group_details # # @attr_reader [Array] step_details # class JobFlow < Core::Resource # @param [String] job_flow_id # @param [Hash] options # @api private def initialize job_flow_id, options = {} @job_flow_id = job_flow_id super end # @return [String] attr_reader :job_flow_id alias_method :id, :job_flow_id attribute :name, :static => true attribute :ami_version, :static => true attribute :log_uri, :static => true attribute :supported_products, :static => true # attributes from :execution_status_detail attribute :state, :from => [:execution_status_detail, :state] attribute :creation_date_time, :from => [:execution_status_detail, :creation_date_time], :static => true, :alias => :created_at attribute :start_date_time, :from => [:execution_status_detail, :start_date_time], :alias => :started_at attribute :ready_date_time, :from => [:execution_status_detail, :ready_date_time], :alias => :ready_at attribute :end_date_time, :from => [:execution_status_detail, :end_date_time], :alias => :ended_at attribute :last_state_change_reason, :from => [:execution_status_detail, :last_state_change_reason] # attributes from :instances attribute :master_instance_type, :from => [:instances, :master_instance_type] attribute :master_public_dns_name, :from => [:instances, :master_public_dns_name] attribute :master_instance_id, :from => [:instances, :master_instance_id] attribute :slave_instance_type, :from => [:instances, :slave_instance_type] attribute :instance_count, :from => [:instances, :instance_count] attribute :normalized_instance_hours, :from => [:instances, :normalized_instance_hours] attribute :ec2_key_name, :from => [:instances, :ec2_key_name] attribute :ec2_subnet_id, :from => [:instances, :ec2_subnet_id] attribute :availability_zone_name, :from => [:instances, :placement, :availability_zone] attribute :keep_job_flow_alive_when_no_steps, :from => [:instances, :keep_job_flow_alive_when_no_steps], :alias => :keep_job_flow_alive_when_no_steps? attribute :termination_protected, :from => [:instances, :termination_protected], :alias => :termination_protected? attribute :hadoop_version, :from => [:instances, :hadoop_version] attribute :instance_group_details, :from => [:instances, :instance_groups] attribute :step_details, :from => :steps attribute :bootstrap_actions populates_from(:describe_job_flows) do |resp| resp.data[:job_flows].find{|j| j[:job_flow_id] == job_flow_id } end # @return [EC2::Instance,nil] def master_instance if instance_id = master_instance_id AWS::EC2.new(:config => config).instances[instance_id] end end # @return [EC2::Instance,nil] def slave_instance if instance_id = slave_instance_id AWS::EC2.new(:config => config).instances[instance_id] end end # @return [EC2::AvailabilityZone,nil] def availability_zone if name = availability_zone_name AWS::EC2.new(:config => config).availability_zones[name] end end # Adds one (or more) steps to the current job flow. # # emr.job_flows['job-flow-id'].add_steps([{ # :name => 'step-name', # :action_on_failure => 'TERMINATE_JOB_FLOW', # :hadoop_jar_step => { # :jar => 'path/to/a/jar/file', # :main_class => 'MainClassName', # :args => %w(arg1 arg2 arg3)], # :properties => [ # { :key => 'property-1-name', :value => 'property-1-value' } # { :key => 'property-2-name', :value => 'property-2-value' } # ], # } # }]) # emr.job_flows['job-flow-id'].add_steps([{ # # @param [Array] steps A list of one or more steps to add. # Each step should be a hash with the following structure: # * `:name` - *required* - (String) The name of the job flow step. # * `:action_on_failure` - (String) Specifies the action to take if the # job flow step fails. # * `:hadoop_jar_step` - *required* - (Hash) Specifies the JAR file # used for the job flow step. # * `:properties` - (Array) A list of Java properties that are # set when the step runs. You can use these properties to pass key # value pairs to your main function. # * `:key` - (String) The unique identifier of a key value pair. # * `:value` - (String) The value part of the identified key. # * `:jar` - *required* - (String) A path to a JAR file run during # the step. # * `:main_class` - (String) The name of the main class in the # specified Java file. If not specified, the JAR file should # specify a Main-Class in its manifest file. # * `:args` - (Array) A list of command line arguments passed # to the JAR file's main function when executed. # # @return [nil] # def add_steps *steps options = {} options[:job_flow_id] = job_flow_id options[:steps] = steps.flatten client.add_job_flow_steps(options) nil end # @return [InstanceGroupCollection] def instance_groups InstanceGroupCollection.new(self) end # Locks this job flow so the Amazon EC2 instances in the cluster # cannot be terminated by user intervention, an API call, or in the # event of a job-flow error. # @return [nil] def enable_termination_protection set_termination_protection(true) end # Removes a lock on this job flow so the Amazon EC2 instances in the # cluster may be terminated. # @return [nil] def disable_termination_protection set_termination_protection(false) end # @param [Boolean] state # @return [nil] def set_termination_protection state options = {} options[:termination_protected] = state options[:job_flow_ids] = [job_flow_id] client.set_termination_protection(options) nil end # @param [Boolean] state # @return [nil] def set_visible_to_all_users state options = {} options[:visible_to_all_users] = state options[:job_flow_ids] = [job_flow_id] client.set_visible_to_all_users(options) nil end # Terminates the current job flow. # @return [nil] def terminate client.terminate_job_flows(:job_flow_ids => [job_flow_id]) nil end alias_method :delete, :terminate # @return [Boolean] Returns `true` if the job flow exists. def exists? !get_resource.data[:job_flows].empty? end protected def resource_identifiers [[:job_flow_id, job_flow_id]] end def get_resource attr = nil client.describe_job_flows(:job_flow_ids => [job_flow_id]) end end end end aws-sdk-v1-1.66.0/lib/aws/elasticache.rb0000644000004100000410000000266112604445426017677 0ustar www-datawww-data# Copyright 2011-2013 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 'aws/core' require 'aws/elasticache/config' module AWS # Provides an expressive, object-oriented interface to Amazon ElastiCache. # # ## Credentials # # You can setup default credentials for all AWS services via # AWS.config: # # AWS.config( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # Or you can set them directly on the ElastiCache interface: # # ec = AWS::ElastiCache.new( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # @!attribute [r] client # @return [Client] the low-level ElastiCache client object class ElastiCache autoload :Client, 'aws/elasticache/client' autoload :Errors, 'aws/elasticache/errors' include Core::ServiceInterface endpoint_prefix 'elasticache' end end aws-sdk-v1-1.66.0/lib/aws/simple_db.rb0000644000004100000410000001536312604445426017373 0ustar www-datawww-data# Copyright 2011-2013 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 'aws/core' require 'aws/simple_db/config' module AWS # This class is the starting point for working with Amazon SimpleDB. # # To use Amazon SimpleDB you must first # [sign up here](http://aws.amazon.com/simpledb/). # # For more information about Amazon SimpleDB: # # * [Amazon SimpleDB](http://aws.amazon.com/simpledb/) # * [Amazon SimpleDB Documentation](http://aws.amazon.com/documentation/simpledb/) # # # Credentials # # You can setup default credentials for all AWS services via # AWS.config: # # AWS.config( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # Or you can set them directly on the SimpleDB interface: # # sdb = AWS::SimpleDB.new( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # # Understanding the SimpleDB Interface # # SimpleDB stores data in a hierarchy of: # # Domains > Items > Attributes # # These are modeled with the following classes: # # * {DomainCollection} # * {Domain} # * {ItemCollection} # * {Item} # * {AttributeCollection} # * {Attribute} # # The collection classes listed above make it easy to enumerate, # the objects they represent. They also make it easy to perform # bulk operations on all objects in that collection. # # # Domains # # Domains are like database tables. A domain must exist before you can # write to it. To create a domain: # # sdb = SimpleDB.new # domain = sdb.domains.create('mydomain') # # For more information about working with domains see {DomainCollection} # and {Domain}. # # # Items & Attributes # # Items exist in SimpleDB when they have attributes. You can delete an # item by removing all of its attributes. You create an item by adding # an attribute to it. # # The following example illustrates how you can reference an item that # does not exist yet: # # sdb = SimpleDB.new # # # this domain is empty, it has no items # domain = sdb.domains.create('newdomain') # domain.items.collect(&:name) # #=> [] # # # this item doesn't exist yet, so it has no attributes # item = domain.items['newitem'] # item.attributes.collect(&:name) # #=> [] # # # the item has no attributes # tags = item.attributes['tags'] # tags.values # #=> [] # # To create the item in SimpleDB you just need to add an attribute. # # tags.add %w(first new) # # domain.items.collect(&:name) # #=> ['newitem'] # # item.attributes.collect(&:name) # #=> ['tags'] # # tags.values # #=> ['first', 'new'] # # For more information about working with items and attributes, see: # # * {ItemCollection} # * {Item} # * {AttributeCollection} # * {Attribute} # # # Lazy Execution # # Requests are not made until necessary. This means you can drill down # all the way to an attribute, by name, without making any requests # to SimpleDB. # # # makes no request to SimpleDB # sdb = SimpleDB.new # colors = sdb.domains['mydomain'].items['car'].attributes['colors'] # # # one request to get the values for 'colors' # puts colors.values # # # one request to add blue and green # colors.add 'blue', 'green' # # # one request to delete the colors attribute # colors.delete # # @!attribute [r] client # @return [Client] the low-level SimpleDB client object class SimpleDB autoload :Attribute, 'aws/simple_db/attribute' autoload :AttributeCollection, 'aws/simple_db/attribute_collection' autoload :Client, 'aws/simple_db/client' autoload :ConsistentReadOption, 'aws/simple_db/consistent_read_option' autoload :DeleteAttributes, 'aws/simple_db/delete_attributes' autoload :Domain, 'aws/simple_db/domain' autoload :DomainCollection, 'aws/simple_db/domain_collection' autoload :DomainMetadata, 'aws/simple_db/domain_metadata' autoload :Errors, 'aws/simple_db/errors' autoload :ExpectConditionOption, 'aws/simple_db/expect_condition_option' autoload :Item, 'aws/simple_db/item' autoload :ItemCollection, 'aws/simple_db/item_collection' autoload :ItemData, 'aws/simple_db/item_data' autoload :PutAttributes, 'aws/simple_db/put_attributes' include Core::ServiceInterface endpoint_prefix 'sdb' # Returns a collection object that represents the domains in your # account. # # @return [DomainCollection] Returns a collection representing all your # domains. def domains DomainCollection.new(:config => config) end # Call this method with a block. Code executed inside the block # make consistent reads until the block ends. # # AWS::SimpleDB.consistent_reads do # # ... # end # # ### Other Modes # # You can also use this same function to disable consistent reads inside # a block. This is useful if you have consistent reads enabled by # default: # # AWS::SimpleDB.consistent_reads(false) do # # ... # end # # @param [Boolean] state (true) When true, all SimpleDB read operations # will be consistent reads inside the block. When false, all # reads operations will not be consistent reads. The previous state # will be restored after the block executes. # @return Returns the final block value. def self.consistent_reads state = true, &block begin prev_state = Thread.current['_simple_db_consistent_reads_'] Thread.current['_simple_db_consistent_reads_'] = state yield ensure Thread.current['_simple_db_consistent_reads_'] = prev_state end end # @return [Boolean] Returns true if we are inside an AWS::SimpleDB # #consistent_reads method block. # @api private def self.in_consistent_reads_block? !Thread.current['_simple_db_consistent_reads_'].nil? end # @return [Boolean] Returns true if the consistent_reads block has # a true state, false otherwise. # @api private def self.consistent_reads_state Thread.current['_simple_db_consistent_reads_'] end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/0000755000004100000410000000000012604445426017550 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/auto_scaling/scaling_policy.rb0000644000004100000410000000765012604445426023104 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class AutoScaling # # @attr_reader [String] arn # # @attr_reader [String] adjustment_type # # @attr_reader [Integer] scaling_adjustment # # @attr_reader [Hash] alarms Returns a hash of alarms names (keys) # to alarm ARNs (values). # # @attr_reader [Integer] cooldown # # @attr_reader [Integer] min_adjustment_step # class ScalingPolicy < Core::Resource include ScalingPolicyOptions # @api private def initialize auto_scaling_group, policy_name, options = {} @group = auto_scaling_group @name = policy_name super end # @return [Group] attr_reader :group alias_method :auto_scaling_group, :group # @return [String] attr_reader :name attribute :arn, :from => :policy_arn, :static => true attribute :adjustment_type attribute :scaling_adjustment attribute :alarms do translates_output do |alarms| alarms.inject({}) do |hash,alarm| hash.merge(alarm.alarm_name => alarm.alarm_arn) end end end attribute :cooldown attribute :min_adjustment_step populates_from(:describe_policies) do |resp| resp.scaling_policies.find do |p| p.policy_name == name and p.auto_scaling_group_name == group.name end end # Updates this scaling policy. # @param (see ScalingPolicyOptions#scaling_policy_options) # @option (see ScalingPolicyOptions#scaling_policy_options) # @return [nil] def update options = {} client_opts = scaling_policy_options(group, name, options) resp = client.put_scaling_policy(client_opts) static_attributes[:arn] = resp.policy_arn nil end alias_method :put, :update # Runs this policy against it's Auto Scaling group. # # @param [Hash] options # # @option options [Boolean] :honor_cooldown (false) Set to true if you # want Auto Scaling to reject this request when the Auto Scaling # group is in cooldown. # # @raise [Errors::ScalingActivityInProgress] # # @return [nil] # def execute options = {} client_opts = {} client_opts[:auto_scaling_group_name] = group.name client_opts[:policy_name] = name client_opts[:honor_cooldown] = options[:honor_cooldown] == true client.execute_policy(client_opts) nil end # Deletes this scaling policy. # @return [nil] def delete client_opts = {} client_opts[:auto_scaling_group_name] = group.name client_opts[:policy_name] = name client.delete_policy(client_opts) nil end # @return [Boolean] Returns true if the policy exists. def exists? client_opts = {} client_opts[:auto_scaling_group_name] = group.name client_opts[:policy_names] = [name] resp = client.describe_policies(client_opts) !resp.scaling_policies.empty? end protected def get_resource attr_name = nil client_opts = {} client_opts[:auto_scaling_group_name] = group.name client_opts[:policy_names] = [name] client.describe_policies(client_opts) end def resource_identifiers [[:group, group], [:name, name]] end end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/errors.rb0000644000004100000410000000124412604445426021412 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class AutoScaling module Errors extend Core::LazyErrorClasses end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/scheduled_action.rb0000644000004100000410000000705412604445426023400 0ustar www-datawww-data# Copyright 2011-2013 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 'time' module AWS class AutoScaling # @attr_reader [Integer] desired_capacity # # @attr_reader [String] recurrence # # @attr_reader [Time] start_time # # @attr_reader [Time] end_time # # @attr_reader [Integer] min_size # # @attr_reader [Integer] max_size # # @attr_reader [String] arn # class ScheduledAction < Core::Resource # @api private def initialize group, name, options = {} @group = group @name = name super end # @return [String] attr_reader :name attr_reader :group # @return [String] def auto_scaling_group_name group.name end attribute :arn, :from => :scheduled_action_arn attribute :desired_capacity attribute :recurrence attribute :start_time attribute :end_time attribute :max_size attribute :min_size populates_from(:describe_scheduled_actions) do |resp| resp.scheduled_update_group_actions.find do |action| action.scheduled_action_name == name end end # Updates the scheduled action. If you omit an option, # the corresponding value remains unchanged in the Auto # Scaling group. # # @param [Hash] options # # @option options [Integer] :desired_capacity # # @option options [String] :recurrence # # @option options [Time,String] :start_time # # @option options [Time,String] :end_time # # @option options [Integer] :min_size # # @option options [Integer] :max_size # # @return [nil] # def update options = {} options.update(resource_options) # convert times to formatted strings [:start_time, :end_time].each do |opt| if options[opt].is_a?(Time) options[opt] = options[opt].iso8601 end end client.put_scheduled_update_group_action(options) nil end alias_method :put, :update # @return [Boolean] def exists? client_opts = {} client_opts[:scheduled_action_names] = [name] client_opts[:auto_scaling_group_name] = auto_scaling_group_name resp = client.describe_scheduled_actions(client_opts) !resp.scheduled_update_group_actions.empty? rescue Errors::ValidationError false end # Deletes the current scheduled action. # @return [nil] def delete client.delete_scheduled_action(resource_options) nil end protected def resource_identifiers [ [:auto_scaling_group_name, auto_scaling_group_name], [:scheduled_action_name, name], ] end def get_resource attr_name = nil client_opts = {} client_opts[:scheduled_action_names] = [name] client_opts[:auto_scaling_group_name] = auto_scaling_group_name client.describe_scheduled_actions(client_opts) end end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/activity_collection.rb0000644000004100000410000000423512604445426024150 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class AutoScaling # Allows you to enumerate Auto Scaling activities # # Enumerating ALL activities: # # auto_scaling = AWS::AutoScaling.new # auto_scaling.activities.each do |activity| # # ... # end # # Enumerating activities for a single Auto Scaling group: # # group = auto_scaling.groups['group-name'] # group.activities.each do |activity| # # ... # end # # If you know the id of an activity you can get a reference to it: # # activity = auto_scaling.activities['activity-id'] class ActivityCollection include Core::Collection::WithLimitAndNextToken # @api private def initialize options = {} @group = options[:group] if @group super(@group, options) else super end end # @param [String] activity_id # @return [Activity] def [] activity_id Activity.new(activity_id, :config => config) end protected def _each_item next_token, limit, options = {}, &block options[:next_token] = next_token if next_token options[:max_records] = limit if limit options[:auto_scaling_group_name] = @group.name if @group resp = client.describe_scaling_activities(options) resp.activities.each do |details| activity = Activity.new_from( :describe_scaling_activities, details, details.activity_id, :config => config) yield(activity) end resp.data[:next_token] end end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/activity.rb0000644000004100000410000000476512604445426021745 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class AutoScaling # @attr_reader [String] auto_scaling_group_name # # @attr_reader [String] cause # # @attr_reader [nil,String] description # # @attr_reader [String] details # # @attr_reader [Time] start_time # # @attr_reader [nil,Time] end_time # # @attr_reader [Integer] progress # # @attr_reader [nil,String] status_code # # @attr_reader [nil,String] status_message # class Activity < Core::Resource # @api private def initialize activity_id, options = {} @activity_id = activity_id super end # @return [String] attr_reader :activity_id alias_method :id, :activity_id attribute :auto_scaling_group_name, :static => true attribute :cause, :static => true attribute :description, :static => true attribute :details attribute :start_time, :static => true attribute :end_time attribute :progress attribute :status_code attribute :status_message populates_from(:describe_scaling_activities) do |resp| resp.activities.find {|a| a.activity_id == activity_id } end populates_from(:terminate_instance_in_auto_scaling_group) do |resp| resp.activity if resp.activity.activity_id == activity_id end # @return [Group] def group Group.new(auto_scaling_group_name, :config => config) end # @return [Boolean] def exists? client_opts = {} client_opts[:activity_ids] = [activity_id] resp = client.describe_scaling_activities(client_opts) !resp.activities.empty? end protected def get_resource attr_name = nil client_opts = {} client_opts[:activity_ids] = [activity_id] client.describe_scaling_activities(client_opts) end def resource_identifiers [[:activity_id, activity_id]] end end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/instance_collection.rb0000644000004100000410000000352312604445426024117 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class AutoScaling # Allows you to enumerate Auto Scaling instances. # # auto_scaling = AWS::AutoScaling.new # auto_scaling.instances.each do |instance| # # ... # end # # You can also get an Auto Scaling instance by its EC2 instance id. # # auto_scaling_instance = auto_scaling.instances['i-12345678'] # auto_scaling_instance.class #=> AWS::AutoScaling::Instance # class InstanceCollection include Core::Collection::WithLimitAndNextToken # @param [String] instance_id An {EC2::Instance} id string. # @return [AutoScaling::Instance] def [] instance_id Instance.new(instance_id, :config => config) end protected def _each_item next_token, limit, options = {}, &block options[:next_token] = next_token if next_token options[:max_records] = limit if limit resp = client.describe_auto_scaling_instances(options) resp.auto_scaling_instances.each do |details| instance = Instance.new_from( :describe_auto_scaling_instances, details, details.instance_id, :config => config) yield(instance) end resp.data[:next_token] end end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/notification_configuration_collection.rb0000644000004100000410000001405012604445426027725 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class AutoScaling # Allows you to enumerate and create notification configurations.# # # ## Enumerating Notification Configurations # # You can enumerated *ALL* configurations from the AWS::AutoScaling class. # # auto_scaling = AWS::AutoScaling.new # auto_scaling.notification_configurations.each do |config| # # ... # end # # You can also limit them to a single Auto Scaling group: # # group = auto_scaling.groups['group-name'] # group.notification_configurations.each do |config| # # ... # end # # ## Creating Notification Configurations # # You can create a notification configuration like so: # # auto_scaling.notification_configurations.create( # :group => 'auto-scaling-group-name', # :topic => 'sns-topic-arn') # # Just like with enumeration, you can create them from the Auto # Scaling group: # # group.notification_configurations.create(:topic => 'sns-topic-arn') class NotificationConfigurationCollection include Core::Collection::WithLimitAndNextToken # @api private def initialize options = {} @group = options[:group] if @group super(@group, options) else super(options) end end # @return [Group,nil] If this collection was initialized with # an Auto Scaling group, then that group is returned, nil otherwise. attr_reader :group alias_method :auto_scaling_group, :group # Creates a new notification configuration. To create a notification # configuration you need an {SNS::Topic} and an Auto Scaling {Group}. # # auto_scaling.notification_configurations.create( # :group => 'auto-scaling-group-name', # :topic => 'sns-topic-arn') # # You can also create notification configurations from an Auto Scaling # group and omit the `:group` option. # # auto_scaling_group.notification_configurations.create( # :topic => 'sns-topic-arn') # # You may also pass a list of notification types to publish to the # topic. If you omit this option, then all notification types # will be configured. # # # publish only these two specific notification types # auto_scaling_group.notification_configurations.create( # :topic => 'sns-topic-arn', # :types => [ # 'autoscaling:EC2_INSTANCE_LAUNCH', # 'autoscaling:EC2_INSTANCE_TERMINATE', # ] # ) # # @param [Hash] options # # @option options [required,SNS::Topic,String] :topic An {SNS::Topic} # object or a topic arn string. Notifications will be published # to this topic. # # @option options [Group,String] :group An Auto Scaling {Group} object # or the name of an Auto Scaling group. This is required if you # this collection is not scoped by a {Group}. # # @option options [Array] :types A list of notification # types that should publish messages to the given topic. # # @return [NotificationConfiguration] # def create options = {} topic_arn = options[:topic].is_a?(SNS::Topic) ? options[:topic].arn : options[:topic] unless group = @group if group = options[:group] group = Group.new(group) unless group.is_a?(Group) else raise ArgumentError, 'missing required :group option' end end unless types = options[:types] types = AutoScaling.new(:config => config).notification_types end notification_config = NotificationConfiguration.new(group, topic_arn) notification_config.notification_types = types notification_config end alias_method :put, :create # @yield [notification_config] # @yieldparam [NotificationConfiguration] notification_config def each &block # # We can't use the standard pageable collection mixin here. # When you provide :max_records it returns each notification # type as an individual record, instead of notification configurations # with grouped types. This makes it very possible to # get a part of a configuration in one page of results with the # rest in the next page. # # So instead we will request and group them all before yielding. # next_token = nil groups = {} begin client_opts = {} client_opts[:next_token] = next_token if next_token client_opts[:auto_scaling_group_names] = [@group.name] if @group resp = client.describe_notification_configurations(client_opts) resp.notification_configurations.each do |c| group_name = c.auto_scaling_group_name groups[group_name] ||= {} groups[group_name][c.topic_arn] ||= [] groups[group_name][c.topic_arn] << c.notification_type end next_token = resp.data[:next_token] end while next_token groups.each_pair do |group_name, topics| topics.each_pair do |topic_arn, types| notification_config = NotificationConfiguration.new( Group.new(group_name, :config => config), topic_arn, types) yield(notification_config) end end end end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/client.rb0000644000004100000410000000256612604445426021364 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class AutoScaling # Client class for Auto Scaling. class Client < Core::QueryClient API_VERSION= '2011-01-01' signature_version :Version4, 'autoscaling' # @api private CACHEABLE_REQUESTS = Set[ :describe_adjustment_types, :describe_auto_scaling_groups, :describe_auto_scaling_instances, :describe_auto_scaling_notification_types, :describe_launch_configurations, :describe_metric_collection_types, :describe_notification_configurations, :describe_policies, :describe_scaling_activities, :describe_scaling_process_types, :describe_scheduled_actions, :describe_tags, ] end class Client::V20110101 < Client define_client_methods('2011-01-01') end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/group_collection.rb0000644000004100000410000000540112604445426023444 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class AutoScaling class GroupCollection include GroupOptions include Core::Collection::WithLimitAndNextToken # Creates an Auto Scaling Group. # # group = auto_scaling.groups.create('group-name', # :launch_configuration => 'launch-config-name', # :availability_zones => %(us-west-2a us-west-2b), # :min_size => 1, # :max_size => 4) # # @param [String] name The name of the Auto Scaling group. # Must be unique within the scope of your AWS account. # # @param [Hash] options # # @option (see GroupOptions#group_options) # # @option options [Array,Array] :load_balancers # A list of load balancers to use. This can be an array of # {ELB::LoadBalancer} objects or an array of load balancer names. # # @return [Group] # def create name, options = {} unless options[:launch_configuration] raise ArgumentError, 'missing required option :launch_configuration' end group_opts = group_options(options) group_opts[:auto_scaling_group_name] = name if balancers = options[:load_balancers] group_opts[:load_balancer_names] = balancers.collect do |balancer| balancer.is_a?(ELB::LoadBalancer) ? balancer.name : balancer end end client.create_auto_scaling_group(group_opts) self[name] end # @param [String] name The name of the Auto Scaling group. # @return [Group] def [] name Group.new(name, :config => config) end protected def _each_item next_token, limit, options = {}, &block options[:next_token] = next_token if next_token options[:max_records] = limit if limit resp = client.describe_auto_scaling_groups(options) resp.auto_scaling_groups.each do |details| group = Group.new_from( :describe_auto_scaling_groups, details, details.auto_scaling_group_name, :config => config) yield(group) end resp.data[:next_token] end end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/scaling_policy_options.rb0000644000004100000410000000433112604445426024650 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class AutoScaling # Provides a helper method for parsing scaling policy options. # @api private module ScalingPolicyOptions protected # @param [Hash] options # # @option options [required,String] :adjustment_type Specifies whether # the adjustment is an absolute number or a percentage of the current # capacity. Valid values are: # # * 'ChangeInCapacity' # * 'ExactCapacity' # * 'PercentChangeInCapacity' # # @option options [required,Integer] :scaling_adjustment The number of # instances by which to scale. `:adjustment_type` determines the # interpretation of this umber (e.g., as an absolute number or as a # percentage of the existing Auto Scaling group size). A positive # increment adds to the current capacity and a negative value # removes from the current capacity. # # @option options [Integer] :cooldown The amount of time, in seconds, # after a scaling activity completes before any further # trigger-related scaling activities can start. # # @option options [Integer] :min_adjustment_step # # @return [Hash] # def scaling_policy_options auto_scaling_group, policy_name, options opts = {} opts[:auto_scaling_group_name] = auto_scaling_group.name opts[:policy_name] = policy_name [ :cooldown, :adjustment_type, :scaling_adjustment, :min_adjustment_step, ].each do |opt| opts[opt] = options[opt] if options.key?(opt) end opts end end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/tag_collection.rb0000644000004100000410000000667112604445426023075 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class AutoScaling # Provides an interface for enumerating tags defined in Auto Scaling. # # auto_scaling = AWS::AutoScaling.new # auto_scaling.tags.each do |tag| # puts "#{tag.key}:#{tag.value}" # end # # ## Filters # # You can filter the tags returned using {#filter}: # # # returns tags with the key "role" # auto_scaling.filter(:key, 'role').to_a # # # returns tags with the key "role" and value "webserver" # auto_scaling.filter(:key, 'role').filter(:value, 'webserver')to_a # # # returns tags with the Auto Scaling group name "group1" # auto_scaling.filter(:auto_scaling_group, 'group1').to_a # # # returns all tags that propagate at launch # auto_scaling.filter(:propagate_at_launch, true).to_a # # ## Creating Tags # # You can create Auto Scaling tags when you: # # * [create]{GroupCollection#create} an Auto Scaling group # * [update]{Group#update} an Auto Scaling group # # Both of these methods accept a `:tags` option. # # tags = [ # { :key => 'auto-scaling-instance' }, # tag name only # { :key => 'role', :value => 'webserver' }, # tag name and value # ] # # # creating a group with tags # group = auto_scaling.groups.create('group-name', :tags => tags, ...) # # # updating a group's tags # group.update(:tags => tags) # class TagCollection include Core::Collection::WithLimitAndNextToken # @api private def initialize options = {} @filters = options.delete(:filters) || [] super end # Filters the tags by the given filter name and value(s). # # `` # # return tags with the key "role" and the value "webserver" # auto_scaling.tags.filter(:key, 'role').filer(:value, 'webserver') # `` # # @param [Symbol] name Valid filter names include: # # * :key # * :value # * :propagate_at_launch # * :auto_scaling_group # # @param [Array] values # # @return [TagCollection] # def filter name, *values name = name.to_s.gsub(/_/, '-') values = values.flatten.map(&:to_s) filter = { :name => name, :values => values } TagCollection.new(:filters => @filters + [filter], :config => config) end protected def _each_item next_token, limit, options = {}, &block options[:next_token] = next_token if next_token options[:max_records] = limit if limit options[:filters] = @filters unless @filters.empty? resp = client.describe_tags(options) resp.tags.each do |tag| yield(Tag.new(tag.to_hash.merge(:config => config))) end resp.data[:next_token] end end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/config.rb0000644000004100000410000000124412604445426021343 0ustar www-datawww-data# Copyright 2011-2013 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. AWS::Core::Configuration.module_eval do add_service 'AutoScaling', 'auto_scaling', 'autoscaling' end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/notification_configuration.rb0000644000004100000410000000465212604445426025521 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class AutoScaling class NotificationConfiguration # @api private def initialize auto_scaling_group, topic_arn, notification_types = [] @group = auto_scaling_group @topic_arn = topic_arn @notification_types = notification_types end # @return [Group] attr_reader :group alias_method :auto_scaling_group, :group # @return [String] attr_reader :topic_arn # @return [Arra] attr_reader :notification_types # @return [SNS::Topic] def topic SNS::Topic.new(topic_arn, :config => group.config) end # Updates the notification configuration with a new list of types: # # config = auto_scaling_group.notification_configurations.first # config.notification_types = %w(autoscaling:EC2_INSTANCE_LAUNCH) # # @return [nil] # def notification_types= *notification_types client_opts = {} client_opts[:topic_arn] = topic_arn client_opts[:notification_types] = notification_types.flatten client_opts[:auto_scaling_group_name] = group.name group.client.put_notification_configuration(client_opts) @notification_types = notification_types.flatten nil end # Deletes this Auto Scaling notification configuration. # @return [nil] def delete client_opts = {} client_opts[:auto_scaling_group_name] = group.name client_opts[:topic_arn] = topic_arn group.client.delete_notification_configuration(client_opts) nil end # @api private def eql? other other.is_a?(NotificationConfiguration) and other.group == group and other.topic_arn == topic_arn and other.notification_types == notification_types end alias_method :==, :eql? end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/tag.rb0000644000004100000410000000300712604445426020650 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class AutoScaling # Auto Scaling tags are hashes with two helper methods: # # * {#resource} # * {#delete} # class Tag < Hash # @api private def initialize options = {} super() @resource = case options[:resource_type] when 'auto-scaling-group' group_name = options[:resource_id] config = options.delete(:config) Group.new(group_name, :config => config) else msg = "unhandled resource type: #{options[:resource_type]}" raise ArgumentError, msg end merge!(options) end # @return [Group] Returns the tagged resource. Currently this is # always an Auto Scaling group. def resource @resource end # Deletes the tag from the resource. # @return [nil] def delete resource.delete_tags([self]) nil end end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/scheduled_action_collection.rb0000644000004100000410000001357412604445426025617 0ustar www-datawww-data# Copyright 2011-2013 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 'time' module AWS class AutoScaling class ScheduledActionCollection include Core::Collection::WithLimitAndNextToken # @api private def initialize options = {} @filters = options[:filters] || {} super end # Creates a scheduled scaling action for an Auto Scaling group. # If you leave a parameter unspecified, the corresponding attribute # remains unchanged in the group. # # You must specify an Auto Scaling group. This can be implicit # or explicit: # # # given explicitly # auto_scaling.scheduled_actions.create('action-name', :group => 'group-name') # # # implied by the group # group = auto_scaling.groups.first # group.scheduled_actions.create('action-name') # # @param [String] name # # @param [Hash] options # # @option options [Group,String] :group # # @option options [Integer] :desired_capacity # # @option options [Integer] :max_size # # @option options [Integer] :min_size # # @option options [String] :recurrence # # @option options [Time] :start_time # # @option options [Time] :end_time # # @return [ScheduledAction] # def create name, options = {} group = auto_scaling_group(options) scheduled_action = ScheduledAction.new(group, name, :auto_scaling_group_name => group.name, :config => config) scheduled_action.update(options) scheduled_action end alias_method :put, :create # @param [String] name The name of the scheduled action. # @return [ScheduledAction] def [] name if group_name = @filters[:auto_scaling_group_name] group = Group.new(group_name, :config => config) ScheduledAction.new(group, name) else msg = 'uou must filter this collection by a group to get a ' + 'scheduled action by name' raise msg end end # Returns a new {ScheduledActionCollection} filtered # by the given options. # # auto_scaling.scheduled_actions.filter(:end_time => Time.now).each do |a| # # ... # end # # You can chain filter calls: # # actions = auto_scaling.scheduled_actions. # filter(:group => 'auto-scaling-group-name'). # filter(:start_time => Time.now - 3600). # filter(:end_time => Time.now) # # actions.each {|scheduled_action| ... } # # @param [Hash] filters # # @option filters [Group,String] :group # # @option filters [Array] :scheduled_actions # A list of scheduled actions to be described. If this list is # omitted, all scheduled actions are described. The list of # requested scheduled actions cannot contain more than 50 items. # If an Auto Scaling group name is provided, # the results are limited to that group. If unknown scheduled # actions are requested, they are ignored with no error. # # @option options [Time,String] :start_time The earliest scheduled # start time to return. If `:scheduled_actions` is provided, # this field will be ignored. Should be a Time object or # an iso8601 string. # # @option filters [Time,String] :end_time # # @return [ScheduledActionCollection] Returns a scheduled action # collection that will filter the actions returned by the # given criteria. # def filter filters = {} init_opts = {} init_opts[:config] = config init_opts[:filters] = @filters init_opts[:filters].merge!(filter_opts(filters)) ScheduledActionCollection.new(init_opts) end protected def auto_scaling_group(options) group = options.delete(:group) group ||= @filters[:auto_scaling_group_name] group = Group.new(group, :config => config) if group.is_a?(String) unless group raise ArgumentError, 'missing required option :group' end group end def filter_opts options opts = {} if g = options[:group] opts[:auto_scaling_group_name] = g.is_a?(Group) ? g.name : g end if actions = options[:scheduled_actions] opts[:scheduled_action_names] = actions end [:end_time, :start_time].each do |opt| if options[opt].is_a?(Time) opts[opt] = options[opt].iso8601 end end opts end def _each_item next_token, limit, options = {}, &block options[:next_token] = next_token if next_token options[:max_records] = limit if limit resp = client.describe_scheduled_actions(options.merge(@filters)) resp.scheduled_update_group_actions.each do |details| group = Group.new(details[:auto_scaling_group_name], :config => config) scheduled_action = ScheduledAction.new_from( :describe_scheduled_actions, details, group, details.scheduled_action_name, :config => config) yield(scheduled_action) end resp.data[:next_token] end end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/group.rb0000644000004100000410000003011712604445426021233 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class AutoScaling # @attr_reader [String] arn # # @attr_reader [Array] availability_zone_names # # @attr_reader [Time] created_time # # @attr_reader [Integer] default_cooldown # # @attr_reader [Integer] desired_capacity # # @attr_reader [Array] enabled_metrics Returns a hash of enabled # metric names (keys) and granularities (values). # # @attr_reader [Integer] health_check_grace_period # # @attr_reader [Symbol] health_check_type Returns :ec2 or :vpc. # # @attr_reader [String] launch_configuration_name # # @attr_reader [Array] load_balancer_names # # @attr_reader [Integer] min_size # # @attr_reader [Integer] max_size # # @attr_reader [String,nil] placement_group # # @attr_reader [Hash] suspended_processes A hash of suspended process # names (keys) and reasons (values). # class Group < Core::Resource include GroupOptions def initialize name, options = {} @name = name super end # @return [String] attr_reader :name attribute :auto_scaling_group_arn, :static => true alias_method :arn, :auto_scaling_group_arn attribute :availability_zone_names, :from => :availability_zones attribute :created_time, :static => true attribute :default_cooldown attribute :desired_capacity attribute :enabled_metrics do translates_output do |metrics| metrics.inject({}) do |hash,metric| hash.merge(metric.metric => metric.granularity) end end end attribute :health_check_grace_period attribute :health_check_type, :to_sym => true attribute :instances protected :instances attribute :launch_configuration_name attribute :load_balancer_names, :static => true attribute :min_size attribute :max_size attribute :placement_group attribute :termination_policies attribute :suspended_processes do translates_output do |processes| processes.inject({}) do |hash,process| hash.merge(process.process_name => process.suspension_reason) end end end attribute :tag_details, :from => :tags protected :tag_details attribute :vpc_zone_identifier protected :vpc_zone_identifier populates_from(:describe_auto_scaling_groups) do |resp| resp.auto_scaling_groups.find{|g| g.auto_scaling_group_name == name } end # @return [ScalingPolicyCollection] def scaling_policies ScalingPolicyCollection.new(self) end # @return [NotificationConfigurationCollection] def notification_configurations NotificationConfigurationCollection.new(:group => self) end # @return [ScheduledActionCollection] def scheduled_actions actions = ScheduledActionCollection.new(:config => config) actions.filter(:group => self) end # @return [Tag] def tags tag_details.collect do |tag| Tag.new(tag.to_hash.merge(:config => config)) end end # @return [LaunchConfiguration] def launch_configuration LaunchConfiguration.new(launch_configuration_name, :config => config) end # @return [ActivityCollection] def activities ActivityCollection.new(:group => self) end # @return [Array] def auto_scaling_instances instances.collect do |details| Instance.new_from( :describe_auto_scaling_groups, details, details.instance_id, :auto_scaling_group_name => name, # not provided by the response :config => config) end end # Returns a collection that represents the instances belonging to this # Auto Scaling group. You can use this collection to further refine # the instances you are interested in: # # group.ec2_instances.filter('availability-zone', 'us-west-2a').each do |i| # puts instance.id # end # # @return [EC2::InstanceCollection] Returns an instance collection # (without making a request) that represents the instances # belonging to this Auto Scaling group. # def ec2_instances instances = EC2::InstanceCollection.new(:config => config) instances.filter('tag:aws:autoscaling:groupName', name) end # @return [Array] def subnets vpc_zone_identifier.to_s.split(/,/).collect do |subnet_id| EC2::Subnet.new(subnet_id, :config => config) end end # @return [Array] def availability_zones availability_zone_names.collect do |az_name| EC2::AvailabilityZone.new(az_name, :config => config) end end # @return [Array,] def load_balancers load_balancer_names.collect do |name| ELB::LoadBalancer.new(name, :config => config) end end # Adjusts the desired size of the Auto Scaling group by initiating # scaling activities. When reducing the size of the group, it is # not possible to define which Amazon EC2 instances will be # terminated. This applies to any Auto Scaling decisions that might # result in terminating instances. # # @param [Integer] capacity The new capacity setting for this Auto # Scaling group. # # @param [Hash] options # # @option options [Boolean] :honor_cooldown (false) # # @return [nil] # def set_desired_capacity capacity, options = {} client_opts = {} client_opts[:auto_scaling_group_name] = name client_opts[:desired_capacity] = capacity client_opts[:honor_cooldown] = options[:honor_cooldown] == true client.set_desired_capacity(client_opts) nil end # Suspends processes for this Auto Scaling group. # # # suspend two processes by name # auto_scaling_group.suspend_processes 'Launch', 'AZRebalance' # # @param [Array] processes A list of process to suspend. # # @return [nil] # def suspend_processes *processes client_opts = {} client_opts[:auto_scaling_group_name] = name client_opts[:scaling_processes] = processes.flatten client.suspend_processes(client_opts) nil end # Suspends all processes for this Auto Scaling group. # @return [nil] def suspend_all_processes suspend_processes end # Resumes processes for this Auto Scaling group. # # # resume two processes by name # auto_scaling_group.suspend_processes 'Launch', 'AZRebalance' # # @param [Array] processes A list of process to resume. # # @return [nil] # def resume_processes *processes client_opts = {} client_opts[:auto_scaling_group_name] = name client_opts[:scaling_processes] = processes.flatten client.resume_processes(client_opts) nil end # Resumes all processes for this Auto Scaling group. # @return [nil] def resume_all_processes resume_processes end # @param [Array] metrics A list of metrics to collect. # @return [nil] def enable_metrics_collection *metrics client_opts = {} client_opts[:auto_scaling_group_name] = name client_opts[:granularity] = '1Minute' client_opts[:metrics] = metrics.flatten client.enable_metrics_collection(client_opts) nil end # Enables all metrics collection for the Auto Scaling group. # @return [nil] def enable_all_metrics_collection enable_metrics_collection end # @param [Array] metrics A list of metrics to collect. # @return [nil] def disable_metrics_collection *metrics client_opts = {} client_opts[:auto_scaling_group_name] = name client_opts[:metrics] = metrics.flatten client.disable_metrics_collection(client_opts) nil end # Disables all metrics collection for the Auto Scaling group. # @return [nil] def disable_all_metrics_collection disable_metrics_collection end # Update one or more attributes on the Auto Scaling group. # # @param (see GroupOptions#group_options) # # @option (see GroupOptions#group_options) # # @return [nil] # def update options = {} group_opts = group_options(options) # tags must be updated using a separate request from the # other attributes, *sigh* if tags = group_opts.delete(:tags) tags.map(&:to_hash).each do |tag| tag[:resource_type] = 'auto-scaling-group' tag[:resource_id] = name end client.create_or_update_tags(:tags => tags) end unless group_opts.empty? client_opts = group_opts.merge(:auto_scaling_group_name => name) client.update_auto_scaling_group(client_opts) end nil end # Deletes specific tags from this Auto Scaling group. # # group.delete_tags([ # { :key => 'role', :value => 'webserver' }, # ]) # # You may also pass {Tag} objects. # # @param [Array] tags An array of {Tag} objects or # tag hashes to remove. If you pass hashes they should have # the following keys: # * `:key` # * `:value` # * `:propagate_at_launch` # # @return [nil] # def delete_tags *tags tags = tags.flatten.collect do |tag| tag.to_hash.merge( :resource_type => 'auto-scaling-group', :resource_id => name) end client.delete_tags(:tags => tags) nil end # Removes all tags from this Auto Scaling group. # @return [nil] def delete_all_tags delete_tags(self.tags) nil end # Deletes the Auto Scaling group. If you pass `:force` as true # then all the instances associated with this group will also # be terminated. # # @see #delete! # # @param [Hash] options # # @option options [Boolean] :force (false) When true, the Auto Scaling # group will be deleted along with all instances associated with # the group, without waiting for all instances to be terminated. # # @return [nil] # def delete options = {} client_opts = {} client_opts[:force_delete] = options[:force] == true client_opts[:auto_scaling_group_name] = name client.delete_auto_scaling_group(client_opts) nil end # Deletes the Auto Scaling group along with all instances # associated with the group, without waiting for all instances # to be terminated. # @return [nil] def delete! delete(:force => true) nil end # @return [Boolean] def exists? client_opts = {} client_opts[:auto_scaling_group_names] = [name] resp = client.describe_auto_scaling_groups(client_opts) !resp.auto_scaling_groups.empty? end protected def resource_identifiers [[:name, name]] end def get_resource attr_name = nil client.describe_auto_scaling_groups(:auto_scaling_group_names => [name]) end end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/group_options.rb0000644000004100000410000001321212604445426023003 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class AutoScaling # This mixin provides a method for parsing Auto Scaling group options # (for create and update methods). # @api private module GroupOptions protected # @param [Hash] options # # @option options [required,Integer] :min_size # The maximum size of the Auto Scaling group. # # @option options [required,Integer] :max_size # The minimum size of the Auto Scaling group. # # @option options [required,LaunchConfiguration,String] :launch_configuration # The launch configuration to use with the Auto Scaling group. # This may be a {LaunchConfiguration} object or a launch configuration # name string. # # @option options [required,Array] :availability_zones # A list of Availability Zones for the Auto Scaling group. # This can be {EC2::AvailabilityZone} objects or availability # zone names. # # @option options [Integer] :default_cooldown # The amount of time, in seconds, after a scaling activity completes # before any further trigger-related scaling activities can start. # # @option options [Integer] :desired_capacity # The number of Amazon EC2 instances that should be running in # the group. # # @option options [Integer] :health_check_grace_period # Length of time in seconds after a new Amazon EC2 instance comes # into service that Auto Scaling starts checking its health. # # @option options [Symbol] :health_check_type # The service you want the health status from, # Amazon EC2 or Elastic Load Balancer. Valid values are # `:ec2` or `:elb`. # # @option options [String] :placement_group # Physical location of your cluster placement group created in # Amazon EC2. For more information about cluster placement group, see # [Using Cluster Instances](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using_cluster_computing.html). # # @option options [Array] :termination_policies # A standalone termination policy or a list of termination policies used # to select the instance to terminate. The policies are executed in the # order they are listed. For more information on creating a termination # policy for your Auto Scaling group, go to # [Instance Termination Policy for Your Auto Scaling Group](http://docs.aws.amazon.com/AutoScaling/latest/DeveloperGuide/us-termination-policy.html) # in the Auto Scaling Developer Guide. # # @option options [Array] :tags A list of tags to apply launched # instances. Each tag hash may have the following keys: # # * `:key` - (required,String) The tag name. # * `:value` - (String) The optional tag value. # * `:propagate_at_launch` - (Boolean) Whether or not to propagate # to instances, defaults to true. # # @option options [Array,Array] :subnets # A list of subnet identifiers of Amazon Virtual Private Clouds # (Amazon VPCs). Ensure the subnets' Availability Zones match the # Availability Zones specified. # # @return [Hash] # def group_options options group_opts = {} group_opts[:launch_configuration_name] = launch_config_opt(options) if options.key?(:launch_configuration) group_opts[:availability_zones] = az_opt(options) if options.key?(:availability_zones) group_opts[:vpc_zone_identifier] = subnets_opt(options) if options.key?(:subnets) group_opts[:health_check_type] = health_check_type_opt(options) if options.key?(:health_check_type) group_opts[:tags] = tags_opt(options) if options.key?(:tags) [ :min_size, :max_size, :default_cooldown, :desired_capacity, :health_check_grace_period, :placement_group, :termination_policies, ].each do |opt| group_opts[opt] = options[opt] if options.key?(opt) end group_opts end def launch_config_opt options lc = options[:launch_configuration] lc.is_a?(LaunchConfiguration) ? lc.name : lc end def az_opt options zones = options[:availability_zones] zones.map {|zone| zone.is_a?(EC2::AvailabilityZone) ? zone.name : zone } end def load_balancers_opt options options[:load_balancers].collect do |lb| lb.is_a?(ELB::LoadBalancer) ? lb.name : lb end end def subnets_opt options options[:subnets].collect do |subnet| subnet.is_a?(EC2::Subnet) ? subnet.id : subnet end.join(',') end def health_check_type_opt options options[:health_check_type].to_s.upcase end def tags_opt options options[:tags].map(&:to_hash).each do |tag| tag[:propagate_at_launch] = true unless tag.key?(:propagate_at_launch) end end end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/launch_configuration_collection.rb0000644000004100000410000001454612604445426026523 0ustar www-datawww-data# Copyright 2011-2013 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 'base64' module AWS class AutoScaling class LaunchConfigurationCollection include Core::Collection::WithLimitAndNextToken # Creates an Auto Scaling launch configuration. # # auto_scaling.launch_configurations.create('name', 'ami-12345', 'm1.small') # # @param [String] name The name of the launch configuration to create. # # @param [EC2::Image,String] image An {EC2::Image} or image id string. # # @param [String] instance_type The type of instance (e.g. # 't1.micro', 'm1.small', 'm2.4xlarge', etc). # # @param [Hash] options # # @option options [Array] :block_device_mappings # # @option options [Boolean] :detailed_instance_monitoring (true) # When enabled, CloudWatch will generate metrics every minute # and your account will be charged a fee. When you disable # detailed monitoring, by specifying False, Cloudwatch will # generate metrics every 5 minutes. # # @option options [String] :kernel_id The ID of the kernel to # launch the instances with. # # @option options [KeyPair,String] :key_pair The keypair to launch # instances with. This may be an {EC2::KeyPair} object or # or key pair name string. # # @option options [String] :ramdisk_id The ID of the ramdisk to # launch the instances with. # # @option options [Array,Array] :security_groups # A list of security groups to associate with the instances. # For both EC2 Classic and VPC, this option can be an array of {EC2::SecurityGroup} objects # or security group ids. For EC2 Classic, this option can also be an array of # security group names. # Note: The VPC is derived from the security groups. # # @option options [String] :user_data The user data available to # the launched Amazon EC2 instances. # # @option options [String] :iam_instance_profile # # @option options [String] :spot_price # # @option options [Boolean] :associate_public_ip_address # Used for Auto Scaling groups that launch instances into an # Amazon Virtual Private Cloud (Amazon VPC). Specifies whether # to assign a public IP address to each instance launched in a Amazon VPC. # # @option options [String] :placement_tenancy # # @option options [String] :classic_link_vpc_id # The ID of a ClassicLink-enabled VPC to link EC2 Classic instances to. # # @option options [Array,Array] :classic_link_vpc_security_groups # The list of security groups for the specified VPC to associate # with the instances. This may be an array of {EC2::SecurityGroup} # objects or security group ids. VPC security groups cannot be # referenced by name. # # @return [LaunchConfiguration] # def create name, image, instance_type, options = {} client_opts = {} client_opts[:launch_configuration_name] = name client_opts[:image_id] = image_id_opt(image) client_opts[:instance_type] = instance_type client_opts[:instance_monitoring] = instance_monitoring_opt(options) if options.key?(:detailed_instance_monitoring) client_opts[:key_name] = key_name_opt(options) if options[:key_pair] client_opts[:security_groups] = security_groups_opt(options[:security_groups]) if options.key?(:security_groups) client_opts[:classic_link_vpc_security_groups] = security_groups_opt(options[:classic_link_vpc_security_groups]) if options.key?(:classic_link_vpc_security_groups) client_opts[:user_data] = user_data_opt(options) if options[:user_data] [ :classic_link_vpc_id, :iam_instance_profile, :spot_price, :kernel_id, :ramdisk_id, :block_device_mappings, :associate_public_ip_address, :placement_tenancy, ].each do |opt| client_opts[opt] = options[opt] if options.key?(opt) end client.create_launch_configuration(client_opts) LaunchConfiguration.new(name, :image_id => client_opts[:image_id], :instance_type => client_opts[:instance_type], :config => config) end # @param [String] name The name of a launch configuration. # @return [LaunchConfiguration] def [] name LaunchConfiguration.new(name, :config => config) end protected def _each_item next_token, limit, options = {}, &block options[:next_token] = next_token if next_token options[:max_records] = limit if limit resp = client.describe_launch_configurations(options) resp.launch_configurations.each do |details| launch_configuration = LaunchConfiguration.new_from( :describe_launch_configurations, details, details.launch_configuration_name, :config => config) yield(launch_configuration) end resp.data[:next_token] end def image_id_opt image image.is_a?(EC2::Image) ? image.image_id : image end def instance_monitoring_opt options options[:detailed_instance_monitoring] == true ? { :enabled => true } : { :enabled => false } end def key_name_opt options key_pair = options[:key_pair] key_pair.is_a?(EC2::KeyPair) ? key_pair.name : key_pair end def security_groups_opt security_groups security_groups.collect do |sg| sg.is_a?(EC2::SecurityGroup) ? sg.id : sg end end def user_data_opt options Base64.encode64(options[:user_data]) end end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/instance.rb0000644000004100000410000001345612604445426021712 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class AutoScaling # A small wrapper around an {EC2::Instance}. # # ## Getting Auto Scaling Instances # # If you know the EC2 instance id, you can use {InstanceCollection#[]} # to get the Auto Scaling instance. # # instance = auto_scaling.instances['i-1234578'] # instance.health_statue #=> :healthy # instance.ec2_instance #=> # # ## Enumerating Auto Scaling Instances # # You can enumerate *ALL* instances like so: # # auto_scaling = AWS::AutoScaling.new # auto_scaling.instances.each do |auto_scaling_instance| # # ... # end # # If you want the instances for a single auto scaling group: # # group = auto_scaling.groups['group-name'] # group.auto_scaling_instances.each do |instance| # # ... # end # # If you prefer {EC2::Instance} objects you should use # {Group#ec2_instances} instead. # # @attr_reader [String] auto_scaling_group_name # # @attr_reader [String] launch_configuration_name # # @attr_reader [String] health_status Returns the instance health status # (e.g. 'Healthly' or 'Unhealthly'). # # @attr_reader [String] availability_zone_name # # @attr_reader [String] lifecycle_state # class Instance < Core::Resource # @api private def initialize instance_id, options = {} @instance_id = instance_id super end # @return [String] instance_id Returns the EC2 id instance. attr_reader :instance_id alias_method :id, :instance_id attribute :auto_scaling_group_name, :static => true attribute :availability_zone_name, :from => :availability_zone, :static => true attribute :health_status attribute :launch_configuration_name, :static => true attribute :lifecycle_state populates_from(:describe_auto_scaling_instances) do |resp| resp.auto_scaling_instances.find do |i| i.instance_id == instance_id end end # describe auto scaling groups returns ALL attributes # except :auto_scaling_group_name provider(:describe_auto_scaling_groups) do |provider| provider.find do |resp| instance = nil resp.auto_scaling_groups.each do |group| group.instances.each do |i| instance = i if i.instance_id == instance_id end end instance end provider.provides(*(attributes.keys - [:auto_scaling_group_name])) end # @return [EC2::Instance] def ec2_instance EC2::Instance.new(instance_id, :config => config) end # @return [AutoScaling::Group] def auto_scaling_group Group.new(auto_scaling_group_name, :config => config) end alias_method :group, :auto_scaling_group # @return [EC2::AvailabilityZone] def availability_zone EC2::AvailabilityZone.new(availability_zone_name, :config => config) end # @return [LaunchConfiguration] def launch_configuration LaunchConfiguration.new(launch_configuration_name, :config => config) end # @param [String] status Sets the health status of an instance. # Valid values inculde 'Healthy' and 'Unhealthy' # # @param [Hash] options # # @option options [Boolean] :respect_grace_period (false) If true, # this call should respect the grace period associated with # this instance's Auto Scaling group. # # @return [nil] # def set_health status, options = {} client_opts = {} client_opts[:instance_id] = instance_id client_opts[:health_status] = status client_opts[:should_respect_grace_period] = options[:respect_grace_period] == true client.set_instance_health(client_opts) end # @return [Boolean] Returns true if there exists an Auto Scaling # instance with this instance id. def exists? !get_resource.auto_scaling_instances.empty? end # Terminates the current Auto Scaling instance. # # @param [Boolean] decrement_desired_capacity Specifies whether or not # terminating this instance should also decrement the size of # the AutoScalingGroup. # # @return [Activity] Returns an activity that represents the # termination of the instance. # def terminate decrement_desired_capacity client_opts = {} client_opts[:instance_id] = instance_id client_opts[:should_decrement_desired_capacity] = decrement_desired_capacity resp = client.terminate_instance_in_auto_scaling_group(client_opts) Activity.new_from( :terminate_instance_in_auto_scaling_group, resp.activity, resp.activity.activity_id, :config => config) end alias_method :delete, :terminate protected def resource_identifiers [[:instance_id, instance_id]] end def get_resource attr_name = nil client_opts = {} client_opts[:instance_ids] = [instance_id] client.describe_auto_scaling_instances(client_opts) end end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/scaling_policy_collection.rb0000644000004100000410000000404512604445426025312 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class AutoScaling class ScalingPolicyCollection include Core::Collection::WithLimitAndNextToken include ScalingPolicyOptions def initialize auto_scaling_group, options = {} @group = auto_scaling_group super end # @return [Group] attr_reader :group alias_method :auto_scaling_group, :group # @param [String] name The name of the policy you want to create or update. # @param (see ScalingPolicyOptions#scaling_policy_options) # @option (see ScalingPolicyOptions#scaling_policy_options) # @return [ScalingPolicy] def create name, options = {} scaling_policy = self[name] scaling_policy.put(options) scaling_policy end alias_method :put, :create # @param [String] policy_name # @return [ScalingPolicy] def [] policy_name ScalingPolicy.new(group, policy_name) end protected def _each_item next_token, limit, options = {}, &block options[:next_token] = next_token if next_token options[:max_records] = limit if limit options[:auto_scaling_group_name] = group.name resp = client.describe_policies(options) resp.scaling_policies.each do |details| scaling_policy = ScalingPolicy.new_from( :describe_policies, details, group, details.policy_name) yield(scaling_policy) end resp.data[:next_token] end end end end aws-sdk-v1-1.66.0/lib/aws/auto_scaling/launch_configuration.rb0000644000004100000410000001151412604445426024300 0ustar www-datawww-data# Copyright 2011-2013 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 'base64' module AWS class AutoScaling # @attr_reader [String] name # # @attr_reader [Time] created_time # # @attr_reader [String] image_id # # @attr_reader [Boolean] detailed_instance_monitoring # # @attr_reader [String] instance_type # # @attr_reader [String,nil] kernel_id # # @attr_reader [String,nil] key_name # # @attr_reader [String] arn # # @attr_reader [String,nil] ramdisk_id # # @attr_reader [String,nil] user_data # # @attr_reader [Array] block_device_mappings # # @attr_reader [String] iam_instance_profile # # @attr_reader [String] spot_price # # @attr_reader [Boolean] associate_public_ip_address # # @attr_reader [String] classic_link_vpc_id class LaunchConfiguration < Core::Resource # @api private def initialize name, options = {} super(options.merge(:name => name)) end attribute :name, :from => :launch_configuration_name, :static => true attribute :created_time, :static => true alias_method :created_at, :created_time attribute :image_id, :static => true attribute :detailed_instance_monitoring, :from => :instance_monitoring, :static => true do translates_output {|value| value[:enabled] } end alias_method :detailed_instance_monitoring?, :detailed_instance_monitoring attribute :instance_type, :static => true attribute :kernel_id, :static => true attribute :key_name, :static => true attribute :arn, :from => :launch_configuration_arn, :static => true attribute :ramdisk_id, :static => true attribute :iam_instance_profile, :static => true attribute :spot_price, :static => true attribute :user_data, :static => true do translates_output{|v| Base64.decode64(v) } end attribute :block_device_mappings, :static => true do translates_output{|mappings| mappings.map(&:to_hash) } end attribute :security_group_details, :from => :security_groups, :static => true protected :security_group_details attribute :classic_link_vpc_security_group_details, :from => :classic_link_vpc_security_groups, :static => true protected :classic_link_vpc_security_group_details attribute :classic_link_vpc_id, :static => true attribute :associate_public_ip_address, :static => true populates_from(:describe_launch_configurations) do |resp| resp.launch_configurations.find do |lc| lc.launch_configuration_name == name end end # @return [EC2::Image] def image EC2::Image.new(image_id, :config => config) end # @return [KeyPair,nil] def key_pair if key_name EC2::KeyPair.new(key_name, :config => config) end end # @return [Array] def security_groups get_security_groups(security_group_details) end # @return [Array] def classic_link_vpc_security_groups get_security_groups(classic_link_vpc_security_group_details) end # @return [Boolean] Returns true if this launch configuration exists. def exists? !!get_resource.launch_configurations.first end # Deletes the current launch configuration. # @return [nil] def delete client.delete_launch_configuration(resource_options) nil end protected def get_security_groups(names_or_ids) if names_or_ids.all?{|str| str.match(/^sg-[0-9a-f]{8}$/) } names_or_ids.collect do |security_group_id| EC2::SecurityGroup.new(security_group_id, :config => config) end else begin ec2 = EC2.new(:config => config) ec2.security_groups.filter('group-name', *names_or_ids).to_a rescue names_or_ids end end end def resource_identifiers [[:launch_configuration_name, name]] end def get_resource attr_name = nil client_opts = {} client_opts[:launch_configuration_names] = [name] client.describe_launch_configurations(client_opts) end end end end aws-sdk-v1-1.66.0/lib/aws/record/0000755000004100000410000000000012604445426016356 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/record/hash_model/0000755000004100000410000000000012604445426020461 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/record/hash_model/finder_methods.rb0000644000004100000410000001325012604445426024001 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record class HashModel class << self # @param [String] id The id of the record to load. # @param [Hash] options # @option options [String] :shard Specifies what shard (i.e. table) # should be searched. # @raise [RecordNotFound] Raises a record not found exception if there # was no data found for the given id. # @return [Record::HashModel] Returns the record with the given id. def find_by_id id, options = {} table = dynamo_db_table(options[:shard]) data = table.items[id].attributes.to_h raise RecordNotFound, "no data found for id: #{id}" if data.empty? obj = self.new(:shard => table) obj.send(:hydrate, id, data) obj end alias_method :[], :find_by_id # Finds records in Amazon DynamoDB and returns them as objects of # the current class. # # Finding `:all` returns an enumerable scope object # # People.find(:all, :limit => 10).each do |person| # puts person.name # end # # Finding `:first` returns a single record (or nil) # # boss = People.find(:first) # # Find accepts a hash of find modifiers (`:shard` and `:limit`). # You can also choose to omit these modifiers and # chain them on the scope object returned. In the following # example only one request is made to SimpleDB (when #each is # called) # # people = People.find(:all, :limit => 10) # # people = people.limit(10).find(:all) # # @overload find(id) # @param id The record to find, raises an exception if the record is # not found. # # @overload find(mode, options = {}) # @param [:all,:first] mode (:all) When finding `:all` matching records # and array is returned of records. When finding `:first` then # `nil` or a single record will be returned. # @param [Hash] options # @option options [Integer] :shard The shard name of the Amazon # DynamoDB table to search. # @option options [Integer] :limit The max number of records to fetch. def find *args new_scope.find(*args) end # Returns a chainable scope object that restricts further scopes to a # particular table. # # Book.shard('books-2').each do |book| # # ... # end # # @param [String] shard_name # @return [Scope] Returns a scope for restricting the table searched. def shard shard_name new_scope.shard(shard_name) end alias_method :domain, :shard # backwards compat # Returns an enumerable scope object represents all records. # # Book.all.each do |book| # # ... # end # # This method is equivalent to `find(:all)`, and therefore you can also # pass aditional options. # # Book.all(:where => { :author' => 'me' }).each do |my_book| # # ... # end # # @return [Scope] Returns an enumerable scope object. # def all options = {} new_scope.find(:all, options) end # Yields once for each record. def each &block all.each(&block) end # Counts records Amazon DynamoDB. # # class Product < AWS::Record::HashModel # end # # # returns the count of records in the 'Product' table # Product.count # # You can specify the table via #shard # # # returns the count of records in the 'products-1' table # Product.shard('products-1').count # # You can also specify the shard as an option to #count. # # Product.count(:shard => 'table-name') # # Chaining #count with #limit has no effect on the count. # # Product.limit(10).count # same as Product.count, limit ignored # # @param [Hash] options # # @option [String] :shard Which shard to count records in. # # @return [Integer] The count of records in the table. # def count options = {} new_scope.count(options) end alias_method :size, :count # @return [Object,nil] Returns the first record found. If there were # no records found, nil is returned. def first options = {} new_scope.first(options) end # The maximum number of records to return. By default, all records # matching the where conditions will be returned from a find. # # People.limit(10).each {|person| ... } # # Limit can be chained with other scope modifiers: # # People.where(:age => 40).limit(10).each {|person| ... } # def limit limit new_scope.limit(limit) end end end end end aws-sdk-v1-1.66.0/lib/aws/record/hash_model/attributes.rb0000644000004100000410000001410712604445426023177 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record class HashModel class << self # Adds a string attribute to this class. # # @example A standard string attribute # # class Recipe < AWS::Record::HashModel # string_attr :name # end # # recipe = Recipe.new(:name => "Buttermilk Pancakes") # recipe.name #=> 'Buttermilk Pancakes' # # @example A string attribute with `:set` set to true # # class Recipe < AWS::Record::HashModel # string_attr :tags, :set => true # end # # recipe = Recipe.new(:tags => %w(popular dessert)) # recipe.tags #=> # # # @param [Symbol] name The name of the attribute. # @param [Hash] options # @option options [Boolean] :set (false) When true this attribute # can have multiple values. def string_attr name, options = {} add_attribute(Attributes::StringAttr.new(name, options)) end # Adds an integer attribute to this class. # # class Recipe < AWS::Record::HashModel # integer_attr :servings # end # # recipe = Recipe.new(:servings => '10') # recipe.servings #=> 10 # # @param [Symbol] name The name of the attribute. # @param [Hash] options # @option options [Boolean] :set (false) When true this attribute # can have multiple values. def integer_attr name, options = {} add_attribute(Attributes::IntegerAttr.new(name, options)) end # Adds a float attribute to this class. # # class Listing < AWS::Record::HashModel # float_attr :score # end # # listing = Listing.new(:score => '123.456') # listing.score # => 123.456 # # @param [Symbol] name The name of the attribute. # @param [Hash] options # @option options [Boolean] :set (false) When true this attribute # can have multiple values. def float_attr name, options = {} add_attribute(Attributes::FloatAttr.new(name, options)) end # Adds a boolean attribute to this class. # # @example # # class Book < AWS::Record::HashModel # boolean_attr :read # end # # b = Book.new # b.read? # => false # b.read = true # b.read? # => true # # listing = Listing.new(:score => '123.456' # listing.score # => 123.456 # # @param [Symbol] name The name of the attribute. def boolean_attr name, options = {} attr = add_attribute(Attributes::BooleanAttr.new(name, options)) # add the boolean question mark method define_method("#{attr.name}?") do !!__send__(attr.name) end end # Adds a datetime attribute to this class. # # @example A standard datetime attribute # # class Recipe < AWS::Record::HashModel # datetime_attr :invented # end # # recipe = Recipe.new(:invented => Time.now) # recipe.invented #=> # # If you add a datetime_attr for `:created_at` and/or `:updated_at` those # will be automanaged. # # @param [Symbol] name The name of the attribute. # # @param [Hash] options # # @option options [Boolean] :set (false) When true this attribute # can have multiple date times. # def datetime_attr name, options = {} add_attribute(Attributes::DateTimeAttr.new(name, options)) end # Adds a date attribute to this class. # # @example A standard date attribute # # class Person < AWS::Record::HashModel # date_attr :birthdate # end # # baby = Person.new # baby.birthdate = Time.now # baby.birthdate #=> # # @param [Symbol] name The name of the attribute. # # @param [Hash] options # # @option options [Boolean] :set (false) When true this attribute # can have multiple dates. # def date_attr name, options = {} add_attribute(Attributes::DateAttr.new(name, options)) end # Adds a DynamoDB binary attribute to this class. A binary # attribute acts the same as a string attribute, except # # @param [Symbol] name The name of the attribute. # # @param [Hash] options # # @option options [Boolean] :set (false) When true this attribute # can have multiple values. # # @note This should not be used for large objects. # def binary_attr name, options = {} end # A convenience method for adding the standard two datetime attributes # `:created_at` and `:updated_at`. # # @example # # class Recipe < AWS::Record::HashModel # timestamps # end # # recipe = Recipe.new # recipe.save # recipe.created_at #=> # recipe.updated_at #=> # def timestamps c = datetime_attr :created_at u = datetime_attr :updated_at [c, u] end end end end end aws-sdk-v1-1.66.0/lib/aws/record/hash_model/scope.rb0000644000004100000410000000635612604445426022131 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record class HashModel # The primary interface for finding records with {AWS::Record::HashModel}. # # ## Getting a Scope Object # # You should normally never need to construct a Scope object directly. # Scope objects are returned from the AWS::Record::HashModel finder # methods # (e.g. `shard` and `limit`). # # books = Book.limit(100) # books.class #=> AWS::Record::HashModel::Scope # # Scopes are also returned from methods defined with the `scope` method. # # class Book < AWS::Record::HashModel # scope :sampling, limit(10) # end # # Book.sampling #=> returns a scope that limits to 10 # # ## Chaining Scopes # # Scope objects represent a request, but do not actualy make a request # until required. This allows you to chain requests # # # no request made by the following 2 statements # books = Book.shard('books-1') # what table to search # books = books.limit(10) # how many records to fetch # # books.each do |book| # # yields up to 10 books from the table 'books-1' # end # # The following methods returns a scope that can be chained. # # * {#shard} # * {#limit} # # ## Terminating Scopes # # To terminate a scope you can enumerate it or call #first. # # # terminate a scope by enumerating # Book.limit(10).each {|book| ... } # # # terminate a scope by getting the first record # Book.shard('books-1').first # class Scope < Record::Scope private def _each_object &block items = _item_collection items.select(:limit => @options[:limit]).each do |item_data| obj = base_class.new(:shard => _shard) obj.send(:hydrate, item_data.attributes['id'], item_data.attributes) yield(obj) end end private def _merge_scope scope merged = self scope.instance_variable_get('@options').each_pair do |opt_name,opt_value| unless [nil, []].include?(opt_value) merged = merged.send(opt_name, *opt_value) end end merged end private def _handle_options options scope = self options.each_pair do |method, args| scope = scope.send(method, *args) end scope end private def _item_collection base_class.dynamo_db_table(_shard).items end end end end end aws-sdk-v1-1.66.0/lib/aws/record/model.rb0000644000004100000410000003231112604445426020003 0ustar www-datawww-data# Copyright 2011-2013 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. # todo move these to included modules (like validations and naming) module AWS module Record # An ActiveRecord-like interface built ontop of Amazon SimpleDB. # # class Book < AWS::Record::Model # # string_attr :title # string_attr :author # integer_attr :number_of_pages # # timestamps # adds a :created_at and :updated_at pair of timestamps # # end # # b = Book.new(:title => 'My Book', :author => 'Me', :pages => 1) # b.save # # # Attribute Macros # # When extending AWS::Record::Model you should first consider what # attributes your class should have. Unlike ActiveRecord, AWS::Record # models are not backed by a database table/schema. You must choose what # attributes (and what types) you need. # # * `string_attr` # * `boolean_attr` # * `integer_attr` # * `float_attr` # * `datetime_attr` # * `date_attr` # # ### Usage # # Normally you just call these methods inside your model class definition: # # class Book < AWS::Record::Model # string_attr :title # boolean_attr :has_been_read # integer_attr :number_of_pages # float_attr :weight_in_pounds # datetime_attr :published_at # end # # For each attribute macro a pair of setter/getter methods are added # # to your class (and a few other useful methods). # # b = Book.new # b.title = "My Book" # b.has_been_read = true # b.number_of_pages = 1000 # b.weight_in_pounds = 1.1 # b.published_at = Time.now # b.save # # b.id #=> "0aa894ca-8223-4d34-831e-e5134b2bb71c" # b.attributes # #=> { 'title' => 'My Book', 'has_been_read' => true, ... } # # ### Default Values # # All attribute macros accept the `:default_value` option. This sets # a value that is populated onto all new instnaces of the class. # # class Book < AWS::Record::Model # string_attr :author, :default_value => 'Me' # end # # Book.new.author #=> 'Me' # # ### Multi-Valued (Set) Attributes # # AWS::Record permits storing multiple values with a single attribute. # # class Book < AWS::Record::Model # string_attr :tags, :set => true # end # # b = Book.new # b.tags #=> # # # b.tags = ['fiction', 'fantasy'] # b.tags #=> # # # These multi-valued attributes are treated as sets, not arrays. This # means: # # * values are unordered # * duplicate values are automatically omitted # # Please consider these limitations when you choose to use the `:set` # option with the attribute macros. # # # Validations # # It's important to validate models before there are persisted to keep # your data clean. AWS::Record supports most of the ActiveRecord style # validators. # # class Book < AWS::Record::Model # string_attr :title # validates_presence_of :title # end # # b = Book.new # b.valid? #=> false # b.errors.full_messages #=> ['Title may not be blank'] # # Validations are checked before saving a record. If any of the validators # adds an error, the the save will fail. # # For more information about the available validation methods see # {Validations}. # # # Finder Methods # # You can find records by their ID. Each record gets a UUID when it # is saved for the first time. You can use this ID to fetch the record # at a latter time: # # b = Book["0aa894ca-8223-4d34-831e-e5134b2bb71c"] # # b = Book.find("0aa894ca-8223-4d34-831e-e5134b2bb71c") # # If you try to find a record by ID that has no data an error will # be raised. # # ### All # # You can enumerate all of your records using `all`. # # Book.all.each do |book| # puts book.id # end # # Book.find(:all) do |book| # puts book.id # end # # Be careful when enumerating all. Depending on the number of records # and number of attributes each record has, this can take a while, # causing quite a few requests. # # ### First # # If you only want a single record, you should use `first`. # # b = Book.first # # ### Modifiers # # Frequently you do not want ALL records or the very first record. You # can pass options to `find`, `all` and `first`. # # my_books = Book.find(:all, :where => 'owner = "Me"') # # book = Book.first(:where => { :has_been_read => false }) # # You can pass as find options: # # * `:where` - Conditions that must be met to be returned # * `:order` - The order to sort matched records by # * `:limit` - The maximum number of records to return # # # Scopes # # More useful than writing query fragments all over the place is to # name your most common conditions for reuse. # # class Book < AWS::Record::Model # # scope :mine, where(:owner => 'Me') # # scope :unread, where(:has_been_read => false) # # scope :by_popularity, order(:score, :desc) # # scope :top_10, by_popularity.limit(10) # # end # # # The following expression returns 10 books that belong # # to me, that are unread sorted by popularity. # next_good_reads = Book.mine.unread.top_10 # # There are 3 standard scope methods: # # * `where` # * `order` # * `limit` # # ### Conditions (where) # # Where accepts aruments in a number of forms: # # 1. As an sql-like fragment. If you need to escape values this form is # not suggested. # # Book.where('title = "My Book"') # # 2. An sql-like fragment, with placeholders. This escapes quoted # arguments properly to avoid injection. # # Book.where('title = ?', 'My Book') # # 3. A hash of key-value pairs. This is the simplest form, but also the # least flexible. You can not use this form if you need more complex # expressions that use or. # # Book.where(:title => 'My Book') # # ### Order # # This orders the records as returned by AWS. Default ordering is ascending. # Pass the value :desc as a second argument to sort in reverse ordering. # # Book.order(:title) # alphabetical ordering # Book.order(:title, :desc) # reverse alphabetical ordering # # You may only order by a single attribute. If you call order twice in the # chain, the last call gets presedence: # # Book.order(:title).order(:price) # # In this example the books will be ordered by :price and the order(:title) # is lost. # # ### Limit # # Just call `limit` with an integer argument. This sets the maximum # number of records to retrieve: # # Book.limit(2) # # ### Delayed Execution # # It should be noted that all finds are lazy (except `first`). This # means the value returned is not an array of records, rather a handle # to a {Scope} object that will return records when you enumerate over them. # # This allows you to build an expression without making unecessary requests. # In the following example no request is made until the call to # each_with_index. # # all_books = Books.all # ten_books = all_books.limit(10) # # ten_books.each_with_index do |book,n| # puts "#{n + 1} : #{book.title}" # end # class Model require 'aws/record/model/attributes' require 'aws/record/model/finder_methods' require 'aws/record/model/scope' extend AbstractBase # The id for each record is auto-generated. The default strategy # generates uuid strings. # @return [String] Returns the id string (uuid) for this record. Retuns # nil if this is a new record that has not been persisted yet. def id @_id end # @return [Hash] A hash with attribute names as hash keys (strings) and # attribute values (of mixed types) as hash values. def attributes attributes = super attributes['id'] = id if persisted? attributes end class << self # Creates the SimpleDB domain that is configured for this class. # # class Product < AWS::Record::Model # end # # Product.create_table #=> 'Product' # # If you share a single AWS account with multiple applications, you # can provide a domain prefix for your model classes. # # AWS::Record.domain_prefix = 'myapp-' # # Product.create_table #=> 'myapp-Product' # # If you have set a model shard name, this is used in place of the # class name. # # AWS::Record.domain_prefix = 'prod-' # class Product < AWS::Record::Model # set_shard_name 'products' # end # # Product.create_table #=> 'prod-products' # # If you shard you data across multiple domains, you can specify the # shard name: # # # create two domains, with the given names # Product.create_domain 'products-1' # Product.create_domain 'products-2' # # @param [optional,String] shard_name Defaults to the class name. # # @return [SimpleDB::Domain] # def create_domain shard_name = nil sdb.domains.create(sdb_domain_name(shard_name)) end # @return [AWS::SimpleDB::Domain] # @api private def sdb_domain shard_name = nil sdb.domains[sdb_domain_name(shard_name)] end protected def sdb_domain_name shard_name = nil "#{AWS::Record.domain_prefix}#{self.shard_name(shard_name)}" end protected def sdb AWS::SimpleDB.new end end # @return [SimpleDB::Item] Returns a reference to the item as stored in # simple db. # @api private private def sdb_item sdb_domain.items[id] end # @return [SimpleDB::Domain] Returns the domain this record is # persisted to or will be persisted to. private def sdb_domain self.class.sdb_domain(shard) end # This function accepts a hash of item data (as returned from # AttributeCollection#to_h or ItemData#attributes) and returns only # the key/value pairs that are configured attribues for this class. # @api private private def deserialize_item_data item_data marked_for_deletion = item_data['_delete_'] || [] data = {} item_data.each_pair do |attr_name,values| attribute = self.class.attributes[attr_name] next unless attribute next if marked_for_deletion.include?(attr_name) if attribute.set? data[attr_name] = values.map{|v| attribute.deserialize(v) } else data[attr_name] = attribute.deserialize(values.first) end end data end def hydrate(id, data) @_id = id super end # @api private def populate_id @_id = SecureRandom.uuid end # @api private protected def create_storage to_add = serialize_attributes sdb_item.attributes.add(to_add.merge(opt_lock_conditions)) end # @api private private def update_storage to_update = {} to_delete = [] # serialized_attributes will raise error if the entire record is blank attribute_values = serialize_attributes changed.each do |attr_name| if values = attribute_values[attr_name] to_update[attr_name] = values else to_delete << attr_name end end to_update.merge!(opt_lock_conditions) if to_delete.empty? sdb_item.attributes.replace(to_update) else sdb_item.attributes.replace(to_update.merge('_delete_' => to_delete)) sdb_item.attributes.delete(to_delete + ['_delete_']) end end # @return [true] # @api private private def delete_storage sdb_item.delete(opt_lock_conditions) @_deleted = true end end # for backwards compatability with the old AWS::Record::Base Base = Model end end aws-sdk-v1-1.66.0/lib/aws/record/model/0000755000004100000410000000000012604445426017456 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/record/model/finder_methods.rb0000644000004100000410000002004712604445426023000 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record class Model class << self # @param [String] id The id of the record to load. # @param [Hash] options # @option options [String] :shard Specifies what shard (i.e. domain) # should be searched. # @raise [RecordNotFound] Raises a record not found exception if there # was no data found for the given id. # @return [Record::HashModel] Returns the record with the given id. def find_by_id id, options = {} domain = sdb_domain(options[:shard] || options[:domain]) data = domain.items[id].data.attributes raise RecordNotFound, "no data found for id: #{id}" if data.empty? obj = self.new(:shard => domain) obj.send(:hydrate, id, data) obj end alias_method :[], :find_by_id # Finds records in SimpleDB and returns them as objects of the # current class. # # Finding `:all` returns an enumerable scope object # # People.find(:all, :order => [:age, :desc], :limit => 10).each do |person| # puts person.name # end # # Finding `:first` returns a single record (or nil) # # boss = People.find(:first, :where => { :boss => true }) # # Find accepts a hash of find modifiers (`:where`, `:order` and # `:limit`). You can also choose to omit these modifiers and # chain them on the scope object returned. In the following # example only one request is made to SimpleDB (when #each is # called) # # people = People.find(:all) # # johns = people.where(:name => 'John Doe') # # johns.order(:age, :desc).limit(10).each do |suspects| # # ... # end # # See also {where}, {order} and {limit} for more # information and options. # # @overload find(id) # @param id The record to find, raises an exception if the record is # not found. # # @overload find(mode, options = {}) # @param [:all,:first] mode (:all) When finding `:all` matching records # and array is returned of records. When finding `:first` then # `nil` or a single record will be returned. # @param [Hash] options # @option options [Mixed] :where Conditions that determine what # records are returned. # @option options [String,Array] :sort The order records should be # returned in. # @option options [Integer] :limit The max number of records to fetch. def find *args new_scope.find(*args) end # Returns a chainable scope object that restricts further scopes to a # particular domain. # # Book.domain('books-2').each do |book| # # ... # end # # @param [String] shard_name # @return [Scope] Returns a scope for restricting the domain of subsequent def shard shard_name new_scope.shard(shard_name) end alias_method :domain, :shard # Returns an enumerable scope object represents all records. # # Book.all.each do |book| # # ... # end # # This method is equivalent to `find(:all)`, and therefore you can also # pass aditional options. See {.find} for more information on what # options you can pass. # # Book.all(:where => { :author' => 'me' }).each do |my_book| # # ... # end # # @return [Scope] Returns an enumerable scope object. def all options = {} new_scope.find(:all, options) end # Yields once for each record. def each &block all.each(&block) end # Counts records in SimpleDB. # # With no arguments, counts all records: # # People.count # # Accepts query options to count a subset of records: # # People.count(:where => { :boss => true }) # # You can also count records on a scope object: # # People.find(:all).where(:boss => true).count # # See {find} and {Scope#count} for more details. # # @param [Hash] options ({}) Options for counting # records. # # @option options [Mixed] :where Conditions that determine what # records are counted. # @option options [Integer] :limit The max number of records to count. def count(options = {}) new_scope.count(options) end alias_method :size, :count # @return [Object,nil] Returns the first record found. If there were # no records found, nil is returned. def first options = {} new_scope.first(options) end # Limits which records are retried from SimpleDB when performing a find. # # Simple string condition # # Car.where('color = "red" or color = "blue"').each {|car| ... } # # String with placeholders for quoting params # # Car.where('color = ?', 'red') # # Car.where('color = ? OR style = ?', 'red', 'compact') # # # produces a condition using in, like: WHERE color IN ('red', 'blue') # Car.where('color IN ?', ['red','blue']) # # Hash arguments # # # WHERE age = '40' AND gender = 'male' # People.where(:age => 40, :gender => 'male').each {|person| ... } # # # WHERE name IN ('John', 'Jane') # People.where(:name => ['John', 'Jane']).each{|person| ... } # # Chaining where with other scope modifiers # # # 10 most expensive red cars # Car.where(:color => 'red').order(:price, :desc).limit(10) # # @overload where(conditions_hash) # @param [Hash] conditions_hash A hash of attributes to values. Each # key/value pair from the hash becomes a find condition. All # conditions are joined by AND. # # @overload where(sql_fragment[, quote_params, ...]) # def where *args new_scope.where(*args) end # Defines the order in which records are returned when performing a find. # SimpleDB only allows sorting by one attribute per request. # # # oldest to youngest # People.order(:age, :desc).each {|person| ... } # # You can chain order with the other scope modifiers: # # Pepole.order(:age, :desc).limit(10).each {|person| ... } # # @overload order(attribute, direction = :asc) # @param [String,Symbol] attribute The attribute to sort by. # @param [:asc,:desc] direction (:asc) The direction to sort. def order *args new_scope.order(*args) end # The maximum number of records to return. By default, all records # matching the where conditions will be returned from a find. # # People.limit(10).each {|person| ... } # # Limit can be chained with other scope modifiers: # # People.where(:age => 40).limit(10).each {|person| ... } # def limit limit new_scope.limit(limit) end end end end end aws-sdk-v1-1.66.0/lib/aws/record/model/attributes.rb0000644000004100000410000003164612604445426022203 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record class Model module Attributes class BooleanAttr < Record::Attributes::BooleanAttr def self.serialize boolean, options = {} super.to_s end end class IntegerAttr < Record::Attributes::IntegerAttr def self.serialize integer, options = {} super.to_s end end class FloatAttr < Record::Attributes::FloatAttr def self.serialize float, options = {} super.to_s end end class SortableIntegerAttr < IntegerAttr def initialize name, options = {} range = options[:range] raise ArgumentError, "missing required option :range" unless range raise ArgumentError, ":range should be a integer range" unless range.is_a?(Range) and range.first.is_a?(Integer) super(name, options) end # Returns a serialized representation of the integer value suitable for # storing in SimpleDB. # # attribute.serialize(123) # #=> '123' # # # padded to the correct number of digits # attribute.serialize('123', :range => (0..10_000) # #=> '00123' # # # offset applied to make all values positive # attribute.serialize('-55', :range => (-100..10_000) # #=> '00045' # # @param [Integer] integer The number to serialize. # @param [Hash] options # @option options [required,Range] :range A range that represents the # minimum and maximum values this integer can be. # The returned value will have an offset applied (if min is # less than 0) and will be zero padded. # @return [String] A serialized representation of the integer. def self.serialize integer, options = {} expect(Integer, integer) do check_range(integer, options) offset_and_precision(options) do |offset,precision| "%0#{precision}d" % (integer.to_i + offset) end end end def self.deserialize string_value, options = {} offset_and_precision(options) do |offset,precision| string_value.to_i - offset end end protected def self.offset_and_precision options, &block min = options[:range].first max = options[:range].last offset = min < 0 ? min * -1 : 0 precision = (max + offset).to_s.length yield(offset, precision) end def self.check_range number, options unless options[:range].include?(number) msg = "unable to serialize `#{number}`, falls outside " + "the range #{options[:range]}" raise msg end end end class SortableFloatAttr < FloatAttr def initialize name, options = {} range = options[:range] raise ArgumentError, "missing required option :range" unless range raise ArgumentError, ":range should be an integer range" unless range.is_a?(Range) and range.first.is_a?(Integer) super(name, options) end def self.serialize float, options = {} expect(Float, float) do left, right = float.to_s.split('.') left = SortableIntegerAttr.serialize(left.to_i, options) SortableIntegerAttr.check_range(float, options) "#{left}.#{right}" end end def self.deserialize string_value, options = {} expect(String, string_value) do left, right = string_value.split('.') left = SortableIntegerAttr.deserialize(left, options) "#{left}.#{right}".to_f end end end end class << self # Adds a string attribute to this class. # # @example A standard string attribute # # class Recipe < AWS::Record::Model # string_attr :name # end # # recipe = Recipe.new(:name => "Buttermilk Pancakes") # recipe.name #=> 'Buttermilk Pancakes' # # @example A string attribute with `:set` set to true # # class Recipe < AWS::Record::Model # string_attr :tags, :set => true # end # # recipe = Recipe.new(:tags => %w(popular dessert)) # recipe.tags #=> # # # @param [Symbol] name The name of the attribute. # @param [Hash] options # @option options [Boolean] :set (false) When true this attribute # can have multiple values. def string_attr name, options = {} add_attribute(Record::Attributes::StringAttr.new(name, options)) end # Adds an integer attribute to this class. # # class Recipe < AWS::Record::Model # integer_attr :servings # end # # recipe = Recipe.new(:servings => '10') # recipe.servings #=> 10 # # @param [Symbol] name The name of the attribute. # @param [Hash] options # @option options [Boolean] :set (false) When true this attribute # can have multiple values. def integer_attr name, options = {} add_attribute(Attributes::IntegerAttr.new(name, options)) end # Adds a sortable integer attribute to this class. # # class Person < AWS::Record::Model # sortable_integer_attr :age, :range => 0..150 # end # # person = Person.new(:age => 10) # person.age #=> 10 # # ### Validations # # It is recomended to apply a validates_numericality_of with # minimum and maximum value constraints. If a value is assigned # to a sortable integer that falls outside of the +:range: it will # raise a runtime error when the record is saved. # # ### Difference Between Sortable an Regular Integer Attributes # # Because SimpleDB does not support numeric types, all values must # be converted to strings. This complicates sorting by numeric values. # To accomplish sorting numeric attributes the values must be # zero padded and have an offset applied to eliminate negative values. # # @param [Symbol] name The name of the attribute. # @param [Hash] options # @option options [Range] :range A numeric range the represents the # minimum and maximum values this attribute should accept. # @option options [Boolean] :set (false) When true this attribute # can have multiple values. def sortable_integer_attr name, options = {} add_attribute(Attributes::SortableIntegerAttr.new(name, options)) end # Adds a float attribute to this class. # # class Listing < AWS::Record::Model # float_attr :score # end # # listing = Listing.new(:score => '123.456') # listing.score # => 123.456 # # @param [Symbol] name The name of the attribute. # @param [Hash] options # @option options [Boolean] :set (false) When true this attribute # can have multiple values. def float_attr name, options = {} add_attribute(Attributes::FloatAttr.new(name, options)) end # Adds sortable float attribute to this class. # # Persisted values are stored (and sorted) as strings. This makes it # more difficult to sort numbers because they don't sort # lexicographically unless they have been offset to be positive and # then zero padded. # # ### Postive Floats # # To store floats in a sort-friendly manor: # # sortable_float_attr :score, :range => (0..10) # # This will cause values like 5.5 to persist as a string like '05.5' so # that they can be sorted lexicographically. # # ### Negative Floats # # If you need to store negative sortable floats, increase your `:range` # to include a negative value. # # sortable_float_attr :position, :range => (-10..10) # # AWS::Record will add 10 to all values and zero pad them # (e.g. -10.0 will be represented as '00.0' and 10 will be represented as # '20.0'). This will allow the values to be compared lexicographically. # # @note If you change the `:range` after some values have been persisted # you must also manually migrate all of the old values to have the # correct padding & offset or they will be interpreted differently. # # @param [Symbol] name The name of the attribute. # @param [Hash] options # @option options [Range] :range The range of numbers this attribute # should represent. The min and max values of this range will determine # how many digits of precision are required and how much of an offset # is required to make the numbers sort lexicographically. # @option options [Boolean] :set (false) When true this attribute # can have multiple values. def sortable_float_attr name, options = {} add_attribute(Attributes::SortableFloatAttr.new(name, options)) end # Adds a boolean attribute to this class. # # @example # # class Book < AWS::Record::Model # boolean_attr :read # end # # b = Book.new # b.read? # => false # b.read = true # b.read? # => true # # listing = Listing.new(:score => '123.456' # listing.score # => 123.456 # # @param [Symbol] name The name of the attribute. def boolean_attr name, options = {} attr = add_attribute(Attributes::BooleanAttr.new(name, options)) # add the boolean question mark method define_method("#{attr.name}?") do !!__send__(attr.name) end end # Adds a datetime attribute to this class. # # @example A standard datetime attribute # # class Recipe < AWS::Record::Model # datetime_attr :invented # end # # recipe = Recipe.new(:invented => Time.now) # recipe.invented #=> # # If you add a datetime_attr for `:created_at` and/or `:updated_at` those # will be automanaged. # # @param [Symbol] name The name of the attribute. # # @param [Hash] options # # @option options [Boolean] :set (false) When true this attribute # can have multiple date times. # def datetime_attr name, options = {} add_attribute(Record::Attributes::DateTimeAttr.new(name, options)) end # Adds a date attribute to this class. # # @example A standard date attribute # # class Person < AWS::Record::Model # date_attr :birthdate # end # # baby = Person.new # baby.birthdate = Time.now # baby.birthdate #=> # # @param [Symbol] name The name of the attribute. # # @param [Hash] options # # @option options [Boolean] :set (false) When true this attribute # can have multiple dates. # def date_attr name, options = {} add_attribute(Record::Attributes::DateAttr.new(name, options)) end # A convenience method for adding the standard two datetime attributes # `:created_at` and `:updated_at`. # # @example # # class Recipe < AWS::Record::Model # timestamps # end # # recipe = Recipe.new # recipe.save # recipe.created_at #=> # recipe.updated_at #=> # def timestamps c = datetime_attr :created_at u = datetime_attr :updated_at [c, u] end end end end end aws-sdk-v1-1.66.0/lib/aws/record/model/scope.rb0000644000004100000410000001641212604445426021120 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record class Model # The primary interface for finding records with {AWS::Record::Model}. # # ## Getting a Scope Object # # You should normally never need to construct a Scope object directly. # Scope objects are returned from the AWS::Record::Model finder methods # (e.g. `shard`, `where`, `order`, `limit`, etc). # # books = Book.where(:author => 'John Doe') # books.class #=> AWS::Record::Scope, not Array # # Scopes are also returned from methods defined with the `scope` method. # # ## Chaining Scopes # # Scope objects represent a request, but do not actualy make a request # until required. This allows you to chain requests # # # no request made by the following 2 statements # books = Book.where(:author => 'John Doe') # books = books.limit(10) # # books.each do |book| # # yields up to 10 books # end # # Each of the following methods returns a scope that can be chained. # # * {#shard} # * {#where} # * {#order} # * {#limit} # # ## Terminating Scopes # # To terminate a scope you can enumerate it or call #first. # # # terminate a scope by enumerating # Book.limit(10).each {|book| ... } # # # terminate a scope by getting the first value # Book.where('author' => 'John Doe').first # class Scope < Record::Scope # @api private def initialize base_class, options = {} super @options[:where] ||= [] end def new attributes = {} attributes = attributes.dup @options[:where].each do |conditions| if conditions.size == 1 and conditions.first.is_a?(Hash) attributes.merge!(conditions.first) end end super(attributes) end # Applies conditions to the scope that limit which records are returned. # Only those matching all given conditions will be returned. # # @overload where(conditions_hash) # Specify a hash of conditions to query with. Multiple conditions # are joined together with AND. # # Book.where(:author => 'John Doe', :softcover => true) # # where `author` = `John Doe` AND `softcover` = `1` # # @param [Hash] conditions # # @overload where(conditions_string, *values) # A sql-like query fragment with optional placeholders and values. # Placeholders are replaced with properly quoted values. # # Book.where('author = ?', 'John Doe') # # @param [String] conditions_string A sql-like where string with # question mark placeholders. For each placeholder there should # be a value that will be quoted into that position. # @param [String] *values A value that should be quoted into the # corresponding (by position) placeholder. # # @return [Scope] Returns a new scope with the passed conditions applied. def where *conditions if conditions.empty? raise ArgumentError, 'missing required condition' end _with(:where => @options[:where] + [conditions]) end # Specifies how to sort records returned. # # # enumerate books, starting with the most recently published ones # Book.order(:published_at, :desc).each do |book| # # ... # end # # Only one order may be applied. If order is specified more than # once the last one in the chain takes precedence: # # # books returned by this scope will be ordered by :published_at # # and not :author. # Book.where(:read => false).order(:author).order(:published_at) # # @param [String,Symbol] attribute_name The attribute to sort by. # @param [:asc, :desc] order (:asc) The direct to sort. def order attribute_name, order = :asc _with(:order => [attribute_name, order]) end # @api private private def _each_object &block items = _item_collection items.select.each do |item_data| obj = base_class.new(:shard => _shard) obj.send(:hydrate, item_data.name, item_data.attributes) yield(obj) end end # Merges another scope with this scope. Conditions are added together # and the limit and order parts replace those in this scope (if set). # @param [Scope] scope A scope to merge with this one. # @return [Scope] Returns a new scope with merged conditions and # overriden order and limit. # @api private private def _merge_scope scope merged = self scope.instance_variable_get('@options').each_pair do |opt_name,opt_value| unless [nil, []].include?(opt_value) if opt_name == :where opt_value.each do |condition| merged = merged.where(*condition) end else merged = merged.send(opt_name, *opt_value) end end end merged end # Consumes a hash of options (e.g. `:where`, `:order` and `:limit`) and # builds them onto the current scope, returning a new one. # @param [Hash] options # @option options :where # @option options :order # @option options [Integer] :limit # @return [Scope] Returns a new scope with the hash of scope # options applied. # @api private private def _handle_options options scope = self options.each_pair do |method, args| if method == :where and args.is_a?(Hash) # splatting a hash turns it into an array, bad juju scope = scope.send(method, args) else scope = scope.send(method, *args) end end scope end # Converts this scope object into an AWS::SimpleDB::ItemCollection # @return [SimpleDB::ItemCollection] # @api private private def _item_collection items = base_class.sdb_domain(_shard).items items = items.order(*@options[:order]) if @options[:order] items = items.limit(*@options[:limit]) if @options[:limit] @options[:where].each do |where_condition| items = items.where(*where_condition) end items end end end end end aws-sdk-v1-1.66.0/lib/aws/record/errors.rb0000644000004100000410000001120312604445426020214 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record class Errors < Core::IndifferentHash include Enumerable # Returns the errors for the atttibute in an array. # # errors.add(:name, 'may not be blank') # errors.add(:name, 'must be less than 30 characters') # errors[:name] # #=> ['may not be blank', 'must be less than 30 characters'] # # @param [String,Symbol] attribute_name The name of the attribute to retnr # errors for. You can pass the string or symbol version. # @return [Array] Returns the error messages for the given # `attribute_name`. If there are no errors on the attribute then # an empty array is returned. def [] attribute_name super(attribute_name) || [] end alias_method :on, :[] # Adds an error message to the named attribute. # # errors.add(:name, 'may not be blank') # errors.on(:name) # #=> ['may not be blank'] # # If you want to add a general error message, then pass `:base` # for `attribute_name`, or call {#add_to_base}. # @param [String,Symbol] attribute_name The name of the attribute # that you are adding an error to. # @param [String] message ('is invalid') The error message (should # not contain the attribute name). # @return [String] Returns the message. def []= attribute_name, message = 'is invalid' if has_key?(attribute_name) self[attribute_name] << message else super(attribute_name, [message]) end self[attribute_name] end alias_method :add, :[]= # Adds a general error message (not associated with any particular # attribute). # @param [String] message ('is invalid') The error message (should # not contain the attribute name). # @return [String] Returns the message. def add_to_base message add(:base, message) end # @return [Integer] Returns the number of error messages. def count values.flatten.length end alias_method :size, :count # Yields once for each error message added. # # An attribute_name may yield more than once if there are more than # one errors associated with that attirbute. # # @yield [attribute_name, error_message] # @yieldparam [String] attribute_name The name of the attribute # @yieldparam [String] error_message The error message associated the # the named attribute. def each &block super do |attribute_name, error_messages| error_messages.each do |error_message| yield(attribute_name, error_message) end end end # Returns the errors prefixed by a humanized version of the attribute # name. # # errors.add(:name, 'may not be blank') # errors.full_messages # #=> ['Name may not be blank'] # # @return [Array of Strings] Returns an array of error messages. def full_messages messages = [] each do |attr_name, error_message| messages << case attr_name when 'base' then error_message.dup else "#{attr_name.capitalize.gsub(/_/, ' ')} #{error_message}" end end messages end alias_method :to_a, :full_messages # Returns a hash of of errors messages. Keys are attribute names # and values are arrays of error messages. # # errors.add(:name, 'may not be blank') # errors.to_hash # #=> { 'name' => ['may not be blank'] } # # Please note that the hash values are always arrays, even if there # is only one error message for the attribute. def to_hash hash = {} each do |attr_name, message| hash[attr_name] ||= [] hash[attr_name] << message.dup end hash end # Removes all error messages. # @return [nil] def clear! keys.each do |key| delete(key) end nil end end end end aws-sdk-v1-1.66.0/lib/aws/record/dirty_tracking.rb0000644000004100000410000002122012604445426021715 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # Provides a way to track changes in your records. # # my_book = Book['bookid'] # # my_book.changed? #=> false # my_book.title #=> "My Book" # my_book.title = "My Awesome Book" # my_book.changed? #=> true # # my_book = Book['bookid'] # # You can inspect further and get a list of changed attributes # # my_book.changed #=> ['title'] # # Or you can get a more detailed description of the changes. {#changes} # returns a hash of changed attributes (keys) with their old and new # values. # # my_book.changes # #=> { 'title' => ['My Book', 'My Awesome Book'] # # For every configured attribute you also get a handful of methods # for inspecting changes on that attribute. Given the following # attribute: # # string_attr :title # # You can now call any of the following methods: # # * title_changed? # * title_change # * title_was # * reset_title! # * title_will_change! # # Given the title change from above: # # my_book.title_changed? #=> true # my_book.title_change #=> ['My Book', 'My Awesome Book'] # my_book.title_was #=> ['My Book'] # # my_book.reset_title! # my_book.title #=> 'My Book' # # ## In-Place Editing # # Dirty tracking works by comparing incoming attribute values upon # assignment against the value that was there previously. If you # use functions against the value that modify it (like gsub!) # you must notify your record about the coming change. # # my_book.title #=> 'My Book' # my_book.title_will_change! # my_book.title.gsub!(/My/, 'Your') # my_book.title_change #=> ['My Book', 'Your Book'] # # ## Partial Updates # # Dirty tracking makes it possible to only persist those attributes # that have changed since they were loaded. This speeds up requests # against AWS when saving data. # module DirtyTracking # Returns true if this model has unsaved changes. # # b = Book.new(:title => 'My Book') # b.changed? # #=> true # # New objects and objects freshly loaded should not have any changes: # # b = Book.new # b.changed? #=> false # # b = Book.first # b.changed? #=> false # # @return [Boolean] Returns true if any of the attributes have # unsaved changes. def changed? !orig_values.empty? end # Returns an array of attribute names that have changes. # # book.changed #=> [] # person.title = 'New Title' # book.changed #=> ['title'] # # @return [Array] Returns an array of attribute names that have # unsaved changes. def changed orig_values.keys end # Returns the changed attributes in a hash. Keys are attribute names, # values are two value arrays. The first value is the previous # attribute value, the second is the current attribute value. # # book.title = 'New Title' # book.changes # #=> { 'title' => ['Old Title', 'New Title'] } # # @return [Hash] Returns a hash of attribute changes. def changes changed.inject({}) do |changes, attr_name| changes[attr_name] = attribute_change(attr_name) changes end end # Returns true if the named attribute has unsaved changes. # # This is an attribute method. The following two expressions # are equivilent: # # book.title_changed? # book.attribute_changed?(:title) # # @param [String] attribute_name Name of the attribute to check # for changes. # # @return [Boolean] Returns true if the named attribute # has unsaved changes. # @api private private def attribute_changed? attribute_name orig_values.keys.include?(attribute_name) end # Returns an array of the old value and the new value for # attributes that have unsaved changes, returns nil otherwise. # # This is an attribute method. The following two expressions # are equivilent: # # book.title_change # book.attribute_change(:title) # # @example Asking for changes on an unchanged attribute # # book = Book.new # book.title_change #=> nil # # @example Getting changed attributes on a new object # # book = Book.new(:title => 'My Book') # book.title_change #=> [nil, 'My Book'] # # @example Getting changed attributes on a loaded object # # book = Book.first # book.title = 'New Title' # book.title_change #=> ['Old Title', 'New Title'] # # @param [String] attribute_name Name of the attribute to fetch # a change for. # @return [Boolean] Returns true if the named attribute # has unsaved changes. # @api private private def attribute_change attribute_name self.class.attribute_for(attribute_name) do |attribute| if orig_values.has_key?(attribute.name) [orig_values[attribute.name], __send__(attribute.name)] else nil end end end # Returns the previous value for changed attributes, or the current # value for unchanged attributes. # # This is an attribute method. The following two expressions # are equivilent: # # book.title_was # book.attribute_was(:title) # # @example Returns the previous value for changed attributes: # # book = Book.where(:title => 'My Book').first # book.title = 'New Title' # book.title_was #=> 'My Book' # # @example Returns the current value for unchanged attributes: # # book = Book.where(:title => 'My Book').first # book.title_was #=> 'My Book' # # @return Returns the previous value for changed attributes # or the current value for unchanged attributes. # @api private private def attribute_was attribute_name self.class.attribute_for(attribute_name) do |attribute| name = attribute.name orig_values.has_key?(name) ? orig_values[name] : __send__(name) end end # Reverts any changes to the attribute, restoring its original value. # @param [String] attribute_name Name of the attribute to reset. # @return [nil] # @api private private def reset_attribute! attribute_name __send__("#{attribute_name}=", attribute_was(attribute_name)) nil end # Indicate to the record that you are about to edit an attribute # in place. # @param [String] attribute_name Name of the attribute that will # be changed. # @return [nil] # @api private private def attribute_will_change! attribute_name self.class.attribute_for(attribute_name) do |attribute| name = attribute.name unless orig_values.has_key?(name) was = __send__(name) begin # booleans, nil, etc all #respond_to?(:clone), but they raise # a TypeError when you attempt to dup them. orig_values[name] = was.clone rescue TypeError orig_values[name] = was end end end nil end private def orig_values @_orig_values ||= {} end private def clear_change! attribute_name orig_values.delete(attribute_name) end private def ignore_changes &block begin @_ignore_changes = true yield ensure @_ignore_changes = false end end private def if_tracking_changes &block yield unless @_ignore_changes end private def clear_changes! orig_values.clear end end end end aws-sdk-v1-1.66.0/lib/aws/record/conversion.rb0000644000004100000410000000160412604445426021071 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # @api private module Conversion # @api private def to_model self end # @api private def to_key persisted? ? [id] : nil end # @api private def to_param persisted? ? to_key.join('-') : nil end end end end aws-sdk-v1-1.66.0/lib/aws/record/abstract_base.rb0000644000004100000410000005205512604445426021507 0ustar www-datawww-data# Copyright 2011-2013 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' module AWS module Record module AbstractBase def self.extended base base.send(:extend, ClassMethods) base.send(:include, InstanceMethods) base.send(:include, DirtyTracking) base.send(:extend, Validations) # these 3 modules are for rails 3+ active model compatability base.send(:extend, Naming) base.send(:include, Naming) base.send(:include, Conversion) end module InstanceMethods # Constructs a new record. # # @param [Hash] attributes Attributes that should be bulk assigned # to this record. You can also specify the shard (i.e. domain # or table) this record should persist to via `:shard`). # # @option attributes [String] :shard The domain/table this record # should persist to. If this is omitted, it will persist to the # class default shard (which defaults to the class name). # # @return [Model,HashModel] Returns a new (non-persisted) record. # Call {#save} to persist changes to AWS. # def initialize attributes = {} attributes = attributes.dup # supporting :domain for backwards compatability, :shard is prefered @_shard = attributes.delete(:domain) @_shard ||= attributes.delete('domain') @_shard ||= attributes.delete(:shard) @_shard ||= attributes.delete('shard') @_shard = self.class.shard_name(@_shard) @_data = {} assign_default_values bulk_assign(attributes) end # @return [String] Returns the name of the shard this record # is persisted to or will be persisted to. Defaults to the # domain/table named after this record class. def shard @_shard end alias_method :domain, :shard # for backwards compatability # @return [Hash] A hash with attribute names as hash keys (strings) and # attribute values (of mixed types) as hash values. def attributes attributes = Core::IndifferentHash.new self.class.attributes.keys.inject(attributes) do |hash,attr_name| hash.merge(attr_name => __send__(attr_name)) end end # Acts like {#update} but does not call {#save}. # # record.attributes = { :name => 'abc', :age => 20 } # # @param [Hash] attributes A hash of attributes to set on this record # without calling save. # # @return [Hash] Returns the attribute hash that was passed in. # def attributes= attributes bulk_assign(attributes) end # Persistence indicates if the record has been saved previously or not. # # @example # @recipe = Recipe.new(:name => 'Buttermilk Pancackes') # @recipe.persisted? #=> false # @recipe.save! # @recipe.persisted? #=> true # # @return [Boolean] Returns true if this record has been persisted. def persisted? !!@_persisted end # @return [Boolean] Returns true if this record has not been persisted # to SimpleDB. def new_record? !persisted? end # @param [Hash] opts Pass :validate => false to skip validations # @return [Boolean] Returns true if this record has no validation errors. def valid? opts = {} opts = {} if opts.nil? opts = {:validate => true}.merge(opts) run_validations if opts[:validate] errors.empty? end def errors @errors ||= Errors.new end # Creates new records, updates existing records. # @param [Hash] opts Pass :validate => false to skip validations # @return [Boolean] Returns true if the record saved without errors, # false otherwise. def save opts = {} if valid?(opts) persisted? ? update : create clear_changes! true else false end end # Creates new records, updates exsting records. If there is a validation # error then an exception is raised. # @raise [InvalidRecordError] Raised when the record has validation # errors and can not be saved. # @return [true] Returns true after a successful save. def save! raise InvalidRecordError.new(self) unless save true end # Bulk assigns the attributes and then saves the record. # @param [Hash] attribute_hash A hash of attribute names (keys) and # attribute values to assign to this record. # @return (see #save) def update_attributes attribute_hash bulk_assign(attribute_hash) save end # Bulk assigns the attributes and then saves the record. Raises # an exception (AWS::Record::InvalidRecordError) if the record is not # valid. # @param (see #update_attributes) # @return [true] def update_attributes! attribute_hash if update_attributes(attribute_hash) true else raise InvalidRecordError.new(self) end end # Deletes the record. # @return [true] def delete if persisted? if deleted? raise 'unable to delete, this object has already been deleted' else delete_storage @_deleted = true end else raise 'unable to delete, this object has not been saved yet' end end alias_method :destroy, :delete # @return [Boolean] Returns true if this instance object has been deleted. def deleted? persisted? ? !!@_deleted : false end # If you define a custom setter, you use #[]= to set the value # on the record. # # class Book < AWS::Record::Model # # string_attr :name # # # replace the default #author= method # def author= name # self['author'] = name.blank? ? 'Anonymous' : name # end # # end # # @param [String,Symbol] The attribute name to set a value for # @param attribute_value The value to assign. protected def []= attribute_name, new_value self.class.attribute_for(attribute_name) do |attribute| if_tracking_changes do original_value = type_cast(attribute, attribute_was(attribute.name)) incoming_value = type_cast(attribute, new_value) if original_value == incoming_value clear_change!(attribute.name) else attribute_will_change!(attribute.name) end end @_data[attribute.name] = new_value end end # Returns the typecasted value for the named attribute. # # book = Book.new(:title => 'My Book') # book['title'] #=> 'My Book' # book.title #=> 'My Book' # # ### Intended Use # # This method's primary use is for getting/setting the value for # an attribute inside a custom method: # # class Book < AWS::Record::Model # # string_attr :title # # def title # self['title'] ? self['title'].upcase : nil # end # # end # # book = Book.new(:title => 'My Book') # book.title #=> 'MY BOOK' # # @param [String,Symbol] attribute_name The name of the attribute to fetch # a value for. # @return The current type-casted value for the named attribute. protected def [] attribute_name self.class.attribute_for(attribute_name) do |attribute| type_cast(attribute, @_data[attribute.name]) end end protected def create populate_id touch_timestamps('created_at', 'updated_at') increment_optimistic_lock_value create_storage @_persisted = true end private def update return unless changed? touch_timestamps('updated_at') increment_optimistic_lock_value update_storage end protected def touch_timestamps *attributes now = Time.now attributes.each do |attr_name| if self.class.attributes[attr_name] and !attribute_changed?(attr_name) # don't touch timestamps the user modified then __send__("#{attr_name}=", now) end end end protected def increment_optimistic_lock_value if_locks_optimistically do |lock_attr| if value = self[lock_attr.name] self[lock_attr.name] = value + 1 else self[lock_attr.name] = 1 end end end protected def if_locks_optimistically &block if opt_lock_attr = self.class.optimistic_locking_attr yield(opt_lock_attr) end end protected def opt_lock_conditions conditions = {} if_locks_optimistically do |lock_attr| if was = attribute_was(lock_attr.name) conditions[:if] = { lock_attr.name => lock_attr.serialize(was) } else conditions[:unless_exists] = lock_attr.name end end conditions end private def assign_default_values # populate default attribute values ignore_changes do self.class.attributes.values.each do |attribute| default = attribute.default_value begin # copy default values down so methods like #gsub! don't # modify the default values for other objects @_data[attribute.name] = default.clone rescue TypeError @_data[attribute.name] = default end end end end private def bulk_assign hash flatten_date_parts(hash).each_pair do |attr_name, attr_value| __send__("#{attr_name}=", attr_value) end end private # Rails date and time select helpers split date and time # attributes into multiple values for form submission. # These attributes get named things like 'created_at(1i)' # and represent year/month/day/hour/min/sec parts of # the date/time. # # This method converts these attributes back into a single # value and converts them to Date and DateTime objects. def flatten_date_parts attributes multi_attributes = Set.new hash = attributes.inject({}) do |hash,(key,value)| # collects attribuets like "created_at(1i)" into an array of parts if key =~ /\(/ key, index = key.to_s.split(/\(|i\)/) hash[key] ||= [] hash[key][index.to_i - 1] = value.to_i multi_attributes << key else hash[key] = value end hash end # convert multiattribute values into date/time objects multi_attributes.each do |key| values = hash[key] hash[key] = case values.size when 0 then nil when 2 now = Time.now Time.local(now.year, now.month, now.day, values[0], values[1], 0, 0) when 3 then Date.new(*values) else DateTime.new(*values) end end hash end private def type_cast attribute, raw if attribute.set? values = Record.as_array(raw).inject([]) do |values,value| values << attribute.type_cast(value) values end Set.new(values.compact) else attribute.type_cast(raw) end end private def serialize_attributes hash = {} self.class.attributes.each_pair do |attribute_name,attribute| value = serialize_attribute(attribute, @_data[attribute_name]) unless [nil, []].include?(value) hash[attribute_name] = value end end # simple db does not support persisting items without attribute values raise EmptyRecordError.new(self) if hash.empty? hash end private def serialize_attribute attribute, raw_value type_casted_value = type_cast(attribute, raw_value) case type_casted_value when nil then nil when Set then type_casted_value.map{|v| attribute.serialize(v) } else attribute.serialize(type_casted_value) end end # @api private protected def hydrate id, data # New objects are populated with default values, but we don't # want these values to hang around when hydrating persisted values # (those values may have been blanked out before save). self.class.attributes.values.each do |attribute| @_data[attribute.name] = nil end ignore_changes do bulk_assign(deserialize_item_data(data)) end @_persisted = true end protected def create_storage raise NotImplementedError end protected def update_storage raise NotImplementedError end protected def delete_storage raise NotImplementedError end end module ClassMethods # Allows you to override the default shard name for this class. # The shard name defaults to the class name. # @param [String] name def set_shard_name name @_shard_name = name end alias_method :set_domain_name, :set_shard_name alias_method :shard_name=, :set_shard_name # Returns the name of the shard this class will persist records # into by default. # # @param [String] name Defaults to the name of this class. # @return [String] Returns the full prefixed domain name for this class. def shard_name name = nil case name when nil @_shard_name || self.name when AWS::DynamoDB::Table name.name.gsub(/^#{Record::table_prefix}/, '') when AWS::SimpleDB::Domain name.name.gsub(/^#{Record::domain_prefix}/, '') else name end end alias_method :domain_name, :shard_name # Adds a scoped finder to this class. # # class Book < AWS::Record::Model # scope :top_10, order(:popularity, :desc).limit(10) # end # # Book.top_10.to_a # #=> [#, #] # # Book.top_10.first # #=> # # # You can also provide a block that accepts params for the scoped # finder. This block should return a scope. # # class Book < AWS::Record::Model # scope :by_author, lambda {|name| where(:author => name) } # end # # # top 10 books by the author 'John Doe' # Book.by_author('John Doe').top_10 # # @param [Symbol] name The name of the scope. Scope names should be # method-safe and should not conflict with any other class methods. # # @param [Scope] scope # def scope name, scope = nil, &block method_definition = scope ? lambda { scope } : block extend(Module.new { define_method(name, &method_definition) }) end # Creates an object (or multiple if you pass an array of attributes). # The {#save} method is called on the object(s) after construction. # The object(s) are returned wether or not the object(s) are valid. # # class Book < AWS::Record::Model # string_attr :title # end # # book = Book.create(:title => "The big book of tests") # book.persisted? # #=> true # # books = Book.create([{:title => 'abc'}, {:title => 'xyz'}]) # books.each(&:persisted?) # #=> [true, true] # def create attributes = {} create_impl(attributes, :create, :save) end # Creates an object (or multiple if you pass an array of attributes). # The {#save!} method is called on the object(s) after construction. # If the object(s) are not valid, then an error is raised. # # class Book < AWS::Record::Model # string_attr :title # validates_presence_of :title # end # # book = Book.create!(:title => "The big book of tests") # book.persisted? # #=> true # # book = Book.create!() # #=> raises AWS::Record::InvalidRecordError # def create! attributes = {} create_impl(attributes, :create!, :save!) end # @api private def new_scope self::Scope.new(self) end def optimistic_locking attribute_name = :version_id attribute = integer_attr(attribute_name) @optimistic_locking_attr = attribute end # @return [Boolean] Returns true if this class is configured to # perform optimistic locking. def optimistic_locking? !!@optimistic_locking_attr end # @private def optimistic_locking_attr @optimistic_locking_attr end # @return [Hash] Returns a hash of all of the # configured attributes for this class. def attributes @attributes ||= {} end # @api private def attribute_for attribute_name, &block unless attribute = attributes[attribute_name.to_s] raise UndefinedAttributeError.new(attribute_name.to_s) end block_given? ? yield(attribute) : attribute end # @api private def add_attribute attribute attr_name = attribute.name attributes[attr_name] = attribute # setter define_method("#{attr_name}=") do |value| self[attr_name] = value end # getter define_method(attr_name) do self[attr_name] end # before type-cast getter define_method("#{attr_name}_before_type_cast") do @_data[attr_name] end # dirty tracking methods define_method("#{attr_name}_changed?") do attribute_changed?(attr_name) end define_method("#{attr_name}_change") do attribute_change(attr_name) end define_method("#{attr_name}_was") do attribute_was(attr_name) end define_method("#{attr_name}_will_change!") do attribute_will_change!(attr_name) end define_method("reset_#{attr_name}!") do reset_attribute!(attr_name) end attribute end # @api private def remove_attribute(attribute) send(:remove_method, attribute.name) send(:remove_method, "#{attribute.name}=") send(:remove_method, "#{attribute.name}_before_type_cast") send(:remove_method, "#{attribute.name}_changed?") send(:remove_method, "#{attribute.name}_change") send(:remove_method, "#{attribute.name}_was") send(:remove_method, "#{attribute.name}_will_change!") send(:remove_method, "reset_#{attribute.name}!") validators.each do |validator| validator.attribute_names.delete(attribute.name) end attributes.delete(attribute.name) end private def create_impl attributes = {}, create_method = :create, save_method = :save if attributes.is_a?(Array) attributes.map {|attr| send(create_method, attr) } else obj = new(attributes) obj.send(save_method) obj end end end end end end aws-sdk-v1-1.66.0/lib/aws/record/naming.rb0000644000004100000410000000174212604445426020160 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # @api private module Naming # This method should only ever get called in a Rails 3+ context # where active model and active support have been loaded. Rails 2 # does not call model name on object. # @api private def model_name @_model_name ||= ActiveModel::Name.new(self.kind_of?(Class) ? self : self.class) end end end end aws-sdk-v1-1.66.0/lib/aws/record/hash_model.rb0000644000004100000410000001366012604445426021014 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record class HashModel require 'aws/record/hash_model/attributes' require 'aws/record/hash_model/finder_methods' require 'aws/record/hash_model/scope' extend AbstractBase def self.inherited(sub_class) sub_class.string_attr :id, :hash_key => true, :default_hash_key_attribute => true end # @return [String,nil] def hash_key self[self.class.hash_key] end class << self # Creates the DynamoDB table that is configured for this class. # # class Product < AWS::Record::HashModel # end # # # create the table 'Product' with 10 read/write capacity units # Product.create_table 10, 10 # # If you shard you data across multiple tables, you can specify the # shard name: # # # create two tables, with the given names # Product.create_table 500, 10, :shard_name => 'products-1' # Product.create_table 500, 10, :shard_name => 'products-2' # # If you share a single AWS account with multiple applications, you # can provide a table prefix to group tables and to avoid name # collisions: # # AWS::Record.table_prefix = 'myapp-' # # # creates the table 'myapp-Product' # Product.create_table 250, 50 # # # creates the table 'myapp-products-1' # Product.create_table 250, 50, :shard_name => 'products-1' # # @param [Integer] read_capacity_units # See {DynamoDB::TableCollection#create} for more information. # # @param [Integer] write_capacity_units # See {DynamoDB::TableCollection#create} for more information. # # @param [Hash] options # # @option options [String] :shard_name Defaults to the class name. The # shard name will be prefixed with {AWS::Record.table_prefix}, # and that becomes the table name. # # @return [DynamoDB::Table] # def create_table read_capacity_units, write_capacity_units, options = {} table_name = dynamo_db_table_name(options[:shard_name]) create_opts = {} create_opts[:hash_key] = { hash_key => :string } dynamo_db.tables.create( table_name, read_capacity_units, write_capacity_units, create_opts) end # @return [DynamoDB::Table] # @api private def dynamo_db_table shard_name = nil table = dynamo_db.tables[dynamo_db_table_name(shard_name)] table.hash_key = [hash_key, :string] table end # @api private def hash_key hash_key_attribute.name end # @api private def hash_key_attribute @hash_key_attribute end private def set_hash_key_attribute(attribute) if hash_key_attribute and hash_key_attribute.options[:default_hash_key_attribute] then remove_attribute(hash_key_attribute) end @hash_key_attribute = attribute end def dynamo_db_table_name shard_name = nil "#{Record.table_prefix}#{self.shard_name(shard_name)}" end def dynamo_db AWS::DynamoDB.new end def add_attribute(attribute) set_hash_key_attribute(attribute) if attribute.options[:hash_key] super(attribute) end end private def populate_id hash_key = self.class.hash_key_attribute if hash_key.options[:default_hash_key_attribute] self[hash_key.name] = SecureRandom.uuid end end # @return [DynamoDB::Item] Returns a reference to the item as stored in # simple db. # @api private private def dynamo_db_item dynamo_db_table.items[hash_key] end # @return [SimpleDB::Domain] Returns the domain this record is # persisted to or will be persisted to. private def dynamo_db_table self.class.dynamo_db_table(shard) end private def create_storage dynamo_db_table.items.create(serialize_attributes, opt_lock_conditions) end private def update_storage # Only enumerating dirty (i.e. changed) attributes. Empty # (nil and empty set) values are deleted, the others are replaced. dynamo_db_item.attributes.update(opt_lock_conditions) do |u| changed.each do |attr_name| attribute = self.class.attribute_for(attr_name) value = serialize_attribute(attribute, @_data[attr_name]) if value.nil? or value == [] u.delete(attr_name) else u.set(attr_name => value) end end end end private def delete_storage dynamo_db_item.delete(opt_lock_conditions) end private def deserialize_item_data data data.inject({}) do |hash,(attr_name,value)| if attribute = self.class.attributes[attr_name] hash[attr_name] = value.is_a?(Set) ? value.map{|v| attribute.deserialize(v) } : attribute.deserialize(value) end hash end end end end end aws-sdk-v1-1.66.0/lib/aws/record/validator.rb0000644000004100000410000001533112604445426020673 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # Base class for all validators # @api private class Validator # these should be defined in subclasses ACCEPTED_OPTIONS = [] def initialize record_class, *attribute_names, &block @options = attribute_names.last.is_a?(Hash) ? attribute_names.pop : {} @attribute_names = attribute_names.map(&:to_s) reject_unknown_options ensure_type([Symbol, Proc], :if, :unless) ensure_is([:save, :create, :update], :on) setup(record_class) end # @return [String] Returns the name of the attribute this validator # will check on the record during validation. attr_reader :attribute_names # @return [Hash] Returns the hash of options for this validator. attr_reader :options def validate record if passes_on_condition?(record) and passes_if_condition?(record) and passes_unless_condition?(record) then validate_attributes(record) end end # @api private protected def setup klass end # @api private protected def each_value value, &block case value when Array, Set then value.each{|v| yield(v) } else yield(value) end end # @api private protected def add_accessors klass, *accessors methods = klass.instance_methods.collect{|m| m.to_s } accessors.each do |attr| setter = "#{attr}=" getter = attr.to_s unless methods.include?(getter) klass.send(:attr_reader, attr) klass.send(:public, getter) end unless methods.include?(setter) klass.send(:attr_writer, attr) klass.send(:public, setter) end end end # @api private protected def validate_attributes record attribute_names.each do |attribute_name| value = read_attribute_for_validation(record, attribute_name) next if (value.nil? && options[:allow_nil]) || (blank?(value) && options[:allow_blank]) validate_attribute(record, attribute_name, value) end end def blank? value case value when nil then true when String then value !~ /\S/ else !value end end # @api private protected def read_attribute_for_validation(record, attribute_name) record.send(attribute_name) end # @api private def reject_unknown_options invalid_keys = options.keys - self.class::ACCEPTED_OPTIONS if invalid_keys.length == 1 raise ArgumentError, "unknown option :#{invalid_keys.first}" elsif invalid_keys.length > 1 bad = invalid_keys.collect{|k| ":#{k}" }.join(', ') raise ArgumentError, "unknown options #{bad}" end end # @api private private def passes_if_condition? record case options[:if] when nil then true when Proc then options[:if].call(record) when String, Symbol then record.send(options[:if]) else raise 'invalid :if option, must be nil, a method name or a Proc' end end # @api private private def passes_unless_condition? record case options[:unless] when nil then true when Proc then !options[:unless].call(record) when String, Symbol then !record.send(options[:unless]) else raise 'invalid :unless option, must be nil, a method name or a Proc' end end # @api private private def passes_on_condition? record case options[:on] when nil then true when :save then true when :create then record.new_record? when :update then record.persisted? else raise 'invalid :on option, must be nil, :save, :create or :update' end end # @api private protected def ensure_type type_or_types, *keys types = Array(type_or_types) keys.each do |key| next unless options.has_key?(key) next unless types.none?{|type| options[key].is_a?(type) } expected = types.map{|type| type.to_s } if expected.count == 1 raise ArgumentError, "expected option :#{key} to be a #{expected}" else msg = "expected :#{key} to be one of #{expected.join(', ')}" raise ArgumentError, msg end end end def ensure_is value_or_values, *keys values = Array(value_or_values) keys.each do |key| next unless options.has_key?(key) unless values.include?(options[key]) valid = values.map{|v| v.is_a?(Symbol) ? ":#{v}" : v.to_s }.join(', ') raise ArgumentError, "expected :#{key} to be one of #{valid}" end end end # @api private protected def ensure_exclusive *key_groups key_groups.each do |key_group| others = key_groups - [key_group] Array(key_group).each do |key| next unless options.has_key?(key) conflicts = others.flatten.select{|other| options.has_key?(other) } unless conflicts.empty? msg = ":#{key} may not be used with :#{conflicts.first}" raise ArgumentError, msg end end end end # @api private protected def ensure_present *keys keys.each do |k| unless options.has_key?(k) raise ArgumentError, "missing required option :#{k}" end end end # @api private protected def ensure_at_least_one *keys found = keys.select{|k| options.has_key?(k) } unless found.count >= 1 opts = keys.collect{|k| ":#{k}" }.join(', ') msg = "must provide at least one of the following options: #{opts}" raise ArgumentError, msg end end protected def set_default key, value options[key] = value unless options.has_key?(key) end end end end aws-sdk-v1-1.66.0/lib/aws/record/attributes.rb0000644000004100000410000002746712604445426021111 0ustar www-datawww-data# Copyright 2011-2013 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 'date' module AWS module Record module Attributes # Base class for all of the AWS::Record attributes. class BaseAttr # @param [Symbol] name Name of this attribute. It should be a name that # is safe to use as a method. # @param [Hash] options # @option options [String] :persist_as Defaults to the name of the # attribute. You can pass a string to specify what the attribute # will be named in the backend storage. # @option options [Boolean] :set (false) When true this attribute can # accept multiple unique values. def initialize name, options = {} @name = name.to_s @options = options.dup if options[:set] and !self.class.allow_set? raise ArgumentError, "invalid option :set for #{self.class}" end end # @return [String] The name of this attribute attr_reader :name # @return [Hash] Attribute options passed to the constructor. attr_reader :options # @return [Boolean] Returns true if this attribute can have # multiple values. def set? options[:set] ? true : false end # @return Returns the default value for this attribute. def default_value if options[:default_value].is_a?(Proc) options[:default_value].call else options[:default_value] end end # @return [String] Returns the name this attribute will use # in the storage backend. def persist_as (options[:persist_as] || @name).to_s end # @param [Mixed] raw_value A single value to type cast. # @return [Mixed] Returns the type casted value. def type_cast raw_value self.class.type_cast(raw_value, options) end # @param [String] serialized_value The serialized string value. # @return [Mixed] Returns a deserialized type-casted value. def deserialize serialized_value self.class.deserialize(serialized_value, options) end # Takes the type casted value and serializes it # @param [Mixed] type_casted_value A single value to serialize. # @return [Mixed] Returns the serialized value. def serialize type_casted_value self.class.serialize(type_casted_value, options) end # @param [String] serialized_value The raw value returned from AWS. # @return [Mixed] Returns the type-casted deserialized value. def self.deserialize serialized_value, options = {} self.type_cast(serialized_value, options) end # @return [Boolean] Returns true if this attribute type can be used # with the `:set => true` option. Certain attirbutes can not # be represented with multiple values (like BooleanAttr). def self.allow_set? raise NotImplementedError end # @api private protected def self.expect klass, value, &block unless value.is_a?(klass) raise ArgumentError, "expected a #{klass}, got #{value.class}" end yield if block_given? end end class StringAttr < BaseAttr # Returns the value cast to a string. Empty strings are returned as # nil by default. Type casting is done by calling #to_s on the value. # # string_attr.type_cast(123) # # => '123' # # string_attr.type_cast('') # # => nil # # string_attr.type_cast('', :preserve_empty_strings => true) # # => '' # # @param [Mixed] raw_value # @param [Hash] options # @option options [Boolean] :preserve_empty_strings (false) When true, # empty strings are preserved and not cast to nil. # @return [String,nil] The type casted value. def self.type_cast raw_value, options = {} case raw_value when nil then nil when '' then options[:preserve_empty_strings] ? '' : nil when String then raw_value else raw_value.to_s end end # Returns a serialized representation of the string value suitable for # storing in SimpleDB. # @param [String] string # @param [Hash] options # @return [String] The serialized string. def self.serialize string, options = {} unless string.is_a?(String) msg = "expected a String value, got #{string.class}" raise ArgumentError, msg end string end # @api private def self.allow_set? true end end class BooleanAttr < BaseAttr def self.type_cast raw_value, options = {} case raw_value when nil then nil when '' then nil when false, 'false', '0', 0 then false else true end end def self.serialize boolean, options = {} case boolean when false then 0 when true then 1 else msg = "expected a boolean value, got #{boolean.class}" raise ArgumentError, msg end end # @api private def self.allow_set? false end end class IntegerAttr < BaseAttr # Returns value cast to an integer. Empty strings are cast to # nil by default. Type casting is done by calling #to_i on the value. # # int_attribute.type_cast('123') # #=> 123 # # int_attribute.type_cast('') # #=> nil # # @param [Mixed] raw_value The value to type cast to an integer. # @return [Integer,nil] Returns the type casted integer or nil def self.type_cast raw_value, options = {} case raw_value when nil then nil when '' then nil when Integer then raw_value else raw_value.respond_to?(:to_i) ? raw_value.to_i : raw_value.to_s.to_i end end # Returns a serialized representation of the integer value suitable for # storing in SimpleDB. # # attribute.serialize(123) # #=> '123' # # @param [Integer] integer The number to serialize. # @param [Hash] options # @return [String] A serialized representation of the integer. def self.serialize integer, options = {} expect(Integer, integer) { integer } end # @api private def self.allow_set? true end end class FloatAttr < BaseAttr def self.type_cast raw_value, options = {} case raw_value when nil then nil when '' then nil when Float then raw_value else raw_value.respond_to?(:to_f) ? raw_value.to_f : raw_value.to_s.to_f end end def self.serialize float, options = {} expect(Float, float) { float } end # @api private def self.allow_set? true end end class DateAttr < BaseAttr # Returns value cast to a Date object. Empty strings are cast to # nil. Values are cast first to strings and then passed to # Date.parse. Integers are treated as timestamps. # # date_attribute.type_cast('2000-01-02T10:11:12Z') # #=> # # # date_attribute.type_cast(1306170146) # # # # date_attribute.type_cast('') # #=> nil # # date_attribute.type_cast(nil) # #=> nil # # @param [Mixed] raw_value The value to cast to a Date object. # @param [Hash] options # @return [Date,nil] def self.type_cast raw_value, options = {} case raw_value when nil then nil when '' then nil when Date then raw_value when Integer then begin Date.parse(Time.at(raw_value).to_s) # assumed timestamp rescue nil end else begin Date.parse(raw_value.to_s) # Time, DateTime or String rescue nil end end end # Returns a Date object encoded as a string (suitable for sorting). # # attribute.serialize(DateTime.parse('2001-01-01')) # #=> '2001-01-01' # # @param [Date] date The date to serialize. # # @param [Hash] options # # @return [String] Returns the date object serialized to a string # ('YYYY-MM-DD'). # def self.serialize date, options = {} unless date.is_a?(Date) raise ArgumentError, "expected a Date value, got #{date.class}" end date.strftime('%Y-%m-%d') end # @api private def self.allow_set? true end end class DateTimeAttr < BaseAttr # Returns value cast to a DateTime object. Empty strings are cast to # nil. Values are cast first to strings and then passed to # DateTime.parse. Integers are treated as timestamps. # # datetime_attribute.type_cast('2000-01-02') # #=> # # # datetime_attribute.type_cast(1306170146) # # # # datetime_attribute.type_cast('') # #=> nil # # datetime_attribute.type_cast(nil) # #=> nil # # @param [Mixed] raw_value The value to cast to a DateTime object. # @param [Hash] options # @return [DateTime,nil] def self.type_cast raw_value, options = {} case raw_value when nil then nil when '' then nil when DateTime then raw_value when Integer then begin DateTime.parse(Time.at(raw_value).to_s) # timestamp rescue nil end else begin DateTime.parse(raw_value.to_s) # Time, Date or String rescue nil end end end # Returns a DateTime object encoded as a string (suitable for sorting). # # attribute.serialize(DateTime.parse('2001-01-01')) # #=> '2001-01-01T00:00:00:Z) # # @param [DateTime] datetime The datetime object to serialize. # @param [Hash] options # @return [String] Returns the datetime object serialized to a string # in ISO8601 format (e.g. '2011-01-02T10:11:12Z') def self.serialize datetime, options = {} unless datetime.is_a?(DateTime) msg = "expected a DateTime value, got #{datetime.class}" raise ArgumentError, msg end datetime.strftime('%Y-%m-%dT%H:%M:%S%Z') end # @api private def self.allow_set? true end end end end end aws-sdk-v1-1.66.0/lib/aws/record/validators/0000755000004100000410000000000012604445426020526 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/record/validators/confirmation.rb0000644000004100000410000000232412604445426023544 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # @api private class ConfirmationValidator < Validator ACCEPTED_OPTIONS = [:message, :on, :if, :unless] def setup record_class accessors = attribute_names.collect{|m| "#{m}_confirmation" } add_accessors(record_class, *accessors) end def validate_attribute record, attribute_name, value confirmation_value = record.send("#{attribute_name}_confirmation") unless value == confirmation_value record.errors.add(attribute_name, message) end end def message options[:message] || "doesn't match confirmation" end end end end aws-sdk-v1-1.66.0/lib/aws/record/validators/acceptance.rb0000644000004100000410000000245712604445426023151 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # @api private class AcceptanceValidator < Validator ACCEPTED_OPTIONS = [:accept, :message, :allow_nil, :allow_blank, :on, :if, :unless] def setup record_class set_default(:allow_nil, true) add_accessors(record_class, *attribute_names) end def validate_attribute record, attribute_name, value accepted = case value when '1' then true when true then true else options.has_key?(:accept) ? value == options[:accept] : false end record.errors.add(attribute_name, message) unless accepted end def message options[:message] || 'must be accepted' end end end end aws-sdk-v1-1.66.0/lib/aws/record/validators/count.rb0000644000004100000410000000600112604445426022200 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # @api private class CountValidator < Validator ACCEPTED_OPTIONS = [ :exactly, :within, :minimum, :maximum, :too_many, :too_few, :wrong_number, :on, :if, :unless, ] def setup record_class ensure_at_least_one(:within, :exactly, :minimum, :maximum) ensure_exclusive(:within, :exactly, [:minimum, :maximum]) ensure_type(Range, :within) ensure_type(Integer, :exactly, :minimum, :maximum) ensure_type(String, :too_many, :too_few, :wrong_number) end def validate_attribute record, attribute_name, value count = case value when nil then 0 when String then 1 when Enumerable then value.count else 1 end if exact = options[:exactly] unless count == exact record.errors.add(attribute_name, wrong_number(exact, count)) end end if within = options[:within] if count < within.first record.errors.add(attribute_name, too_few(within.first, count)) end if count > within.last record.errors.add(attribute_name, too_many(within.last, count)) end end if min = options[:minimum] if count < min record.errors.add(attribute_name, too_few(min, count)) end end if max = options[:maximum] if count > max record.errors.add(attribute_name, too_many(max, count)) end end end # @api private protected def wrong_number exactly, got msg = options[:wrong_number] || "has the wrong number of values (should have %{exactly})" interpolate(msg, :exactly => exactly, :count => got) end # @api private protected def too_few min, got msg = options[:too_few] || "has too few values (minimum is %{minimum})" interpolate(msg, :minimum => min, :count => got) end # @api private protected def too_many max, got msg = options[:too_many] || "has too many values (maximum is %{maximum})" interpolate(msg, :maximum => max, :count => got) end protected def interpolate message_with_placeholders, values msg = message_with_placeholders.dup values.each_pair do |key,value| msg.gsub!(/%\{#{key}\}/, value.to_s) end msg end end end end aws-sdk-v1-1.66.0/lib/aws/record/validators/block.rb0000644000004100000410000000172712604445426022154 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # @api private class BlockValidator < Validator ACCEPTED_OPTIONS = [:allow_nil, :allow_blank, :on, :if, :unless] def initialize *args, &block @block = block super(*args) end attr_reader :block def validate_attribute record, attribute_name, value block.call(record, attribute_name, value) end end end end aws-sdk-v1-1.66.0/lib/aws/record/validators/exclusion.rb0000644000004100000410000000226012604445426023064 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # @api private class ExclusionValidator < InclusionValidator ACCEPTED_OPTIONS = [:in, :message, :allow_nil, :allow_blank, :on, :if, :unless] def setup record_class ensure_present(:in) ensure_type(Enumerable, :in) end def validate_attribute record, attribute_name, value_or_values each_value(value_or_values) do |value| included = value_included?(value) record.errors.add(attribute_name, message) if included end end def message options[:message] || 'is reserved' end end end end aws-sdk-v1-1.66.0/lib/aws/record/validators/inclusion.rb0000644000004100000410000000272712604445426023066 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # @api private class InclusionValidator < Validator ACCEPTED_OPTIONS = [:in, :message, :allow_nil, :allow_blank, :on, :if, :unless] def setup record_class ensure_present(:in) ensure_type(Enumerable, :in) end def validate_attribute record, attribute_name, value_or_values each_value(value_or_values) do |value| included = if value.is_a?(Enumerable) value.all?{|v| value_included?(v) } else value_included?(value) end record.errors.add(attribute_name, message) unless included end end def value_included? value options[:in].respond_to?(:cover?) ? options[:in].cover?(value) : options[:in].include?(value) end def message options[:message] || 'is not included in the list' end end end end aws-sdk-v1-1.66.0/lib/aws/record/validators/presence.rb0000644000004100000410000000245712604445426022667 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # @api private class PresenceValidator < Validator ACCEPTED_OPTIONS = [:message, :allow_nil, :allow_blank, :on, :if, :unless] def validate_attribute record, attribute_name, value blank = case when value.nil? then true when value.is_a?(String) then value !~ /\S/ when value == false then false # defeat false.blank? == true when value.respond_to?(:empty?) then value.empty? when value.respond_to?(:blank?) then value.blank? else false end record.errors.add(attribute_name, message) if blank end def message options[:message] || 'may not be blank' end end end end aws-sdk-v1-1.66.0/lib/aws/record/validators/numericality.rb0000644000004100000410000000753712604445426023574 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # @api private class NumericalityValidator < Validator ACCEPTED_OPTIONS = [ :greater_than, :greater_than_or_equal_to, :less_than, :less_than_or_equal_to, :equal_to, :only_integer, :odd, :even, :message, :allow_nil, :allow_blank, :on, :if, :unless, ] COMPARISONS = { :equal_to => :==, :greater_than => :>, :greater_than_or_equal_to => :>=, :less_than => :<, :less_than_or_equal_to => :<=, :even => lambda{|value| value.to_i % 2 == 0 }, :odd => lambda{|value| value.to_i % 2 == 1 }, } def setup record_class ensure_exclusive(:odd, :even) ensure_exclusive(:equal_to, [:greater_than, :greater_than_or_equal_to, :less_than, :less_than_or_equal_to]) ensure_type([TrueClass, FalseClass], :only_integer) ensure_type(TrueClass, :odd, :even) ensure_type([Numeric, Symbol, Proc], :greater_than, :greater_than_or_equal_to, :less_than, :less_than_or_equal_to, :equal_to) end def read_attribute_for_validation(record, attribute_name) if record.respond_to?("#{attribute_name}_before_type_cast") record.send("#{attribute_name}_before_type_cast") else record.send(attribute_name) end end def validate_attribute record, attribute_name, raw each_value(raw) do |raw_value| if options[:only_integer] or options[:odd] or options[:even] value = as_integer(raw_value) error_type = :not_an_integer else value = as_number(raw_value) error_type = :not_a_number end unless value record.errors.add(attribute_name, message_for(error_type)) return end COMPARISONS.each do |option,method| next unless options.has_key?(option) requirement = case options[option] when Symbol then record.send(options[option]) when Proc then options[option].call(record) else options[option] end valid = case method when Symbol then value.send(method, requirement) else method.call(value) end unless valid message = message_for(option, requirement) record.errors.add(attribute_name, message) end end end end def message_for error_type, requirement = nil return options[:message] if options[:message] case error_type when :not_a_number then 'is not a number' when :not_an_integer then 'must be an integer' when :even then 'must be an even number' when :odd then 'must be an odd number' when :equal_to then "should equal #{requirement}" else "must be #{error_type.to_s.gsub(/_/, ' ')} #{requirement}" end end def as_number value begin Kernel.Float(value) rescue ArgumentError, TypeError nil end end def as_integer value begin Kernel.Integer(value) rescue ArgumentError, TypeError nil end end end end end aws-sdk-v1-1.66.0/lib/aws/record/validators/method.rb0000644000004100000410000000165312604445426022340 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # Uses the base validator class to call user-defined validation methods. # @api private class MethodValidator < Validator ACCEPTED_OPTIONS = [:on, :if, :unless] def validate_attributes record attribute_names.each do |method_name| record.send(method_name) end end end end end aws-sdk-v1-1.66.0/lib/aws/record/validators/format.rb0000644000004100000410000000270312604445426022345 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # @api private class FormatValidator < Validator ACCEPTED_OPTIONS = [ :with, :without, :message, :allow_nil, :allow_blank, :on, :if, :unless, ] def setup record_class ensure_type(Regexp, :with, :without) ensure_at_least_one(:with, :without) end def validate_attribute record, attribute_name, value_or_values each_value(value_or_values) do |value| if options[:with] unless value.to_s =~ options[:with] record.errors.add(attribute_name, message) end end if options[:without] unless value.to_s !~ options[:without] record.errors.add(attribute_name, message) end end end end def message options[:message] || 'is invalid' end end end end aws-sdk-v1-1.66.0/lib/aws/record/validators/length.rb0000644000004100000410000000620112604445426022333 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # @api private class LengthValidator < Validator ACCEPTED_OPTIONS = [ :exactly, :within, :minimum, :maximum, :too_long, :too_short, :wrong_length, :allow_nil, :allow_blank, :on, :if, :unless, ] def setup record_class ensure_at_least_one(:within, :exactly, :minimum, :maximum) ensure_exclusive(:within, :exactly, [:minimum, :maximum]) ensure_type(Range, :within) ensure_type(Integer, :exactly, :minimum, :maximum) ensure_type(String, :too_long, :too_short, :wrong_length) end def validate_attribute record, attribute_name, value_or_values each_value(value_or_values) do |value| length = value.respond_to?(:length) ? value.length : value.to_s.length if exact = options[:exactly] unless length == exact record.errors.add(attribute_name, wrong_length(exact, length)) end end if within = options[:within] if length < within.first record.errors.add(attribute_name, too_short(within.first, length)) end if length > within.last record.errors.add(attribute_name, too_long(within.last, length)) end end if min = options[:minimum] if length < min record.errors.add(attribute_name, too_short(min, length)) end end if max = options[:maximum] if length > max record.errors.add(attribute_name, too_long(max, length)) end end end end # @api private protected def wrong_length exactly, got msg = options[:wrong_length] || "is the wrong length (should be %{exactly} characters)" interpolate(msg, :exactly => exactly, :length => got) end # @api private protected def too_short min, got msg = options[:too_short] || "is too short (minimum is %{minimum} characters)" interpolate(msg, :minimum => min, :length => got) end # @api private protected def too_long max, got msg = options[:too_long] || "is too long (maximum is %{maximum} characters)" interpolate(msg, :maximum => max, :length => got) end protected def interpolate message_with_placeholders, values msg = message_with_placeholders.dup values.each_pair do |key,value| msg.gsub!(/%\{#{key}\}/, value.to_s) end msg end end end end aws-sdk-v1-1.66.0/lib/aws/record/validations.rb0000644000004100000410000007327412604445426021235 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # Validation methods to be used with subclasses of AWS::Record::Model. # # # General Usage # # All standard validation methods follow the same basic usage. # Call the validation method followed by one more attribute names # and then an optional hash of modifiers. # # class Book < AWS::Record::Model # # # ... # # validates_presence_of :title, :author # # validates_length_of :summary, # :max => 500, # :allow_nil => true, # :allow_blank => true # # end # # # Conditional Validations # # Sometimes you only want to validate an attribute under certain # conditions. To make this simple, all validation methods accept the # following 3 options: # # * `:on` # * `:if` # * `:unless` # # You may mix and match all 3 of the above options. # # ### Validate on :create or :update # # By default validations are run on create and update, but you can # specify them to run for only create (initial save) or updates. # # validates_presence_of :created_at, :on => :create # # validates_presence_of :updated_at, :on => :update # # ### Validate :if or :unless # # Sometimes you have more complex requirements to determine if/when a # validation should run. `:if` and `:unless`: both accept either # a method name or proc. # # class Person # # # ... # # validates_presence_of :job_title, :if => :employee? # # validates_presence_of :nickname, :if => lambda {|person| # person.is_family? or person.is_friend? } # # end # # # Validating Virtual (Non-persisted) Attributes # # All of the validators can be used with configured attributes, but they # can also be used with any attribute that has a setter and a getter. # # Class Book < AWS::Record::Model # attr_accessor :title # validates_presence_of :title # end # module Validations def self.extended base base.send(:define_method, :run_validations) do errors.clear! self.class.send(:validators).each do |validator| validator.validate(self) end end base.send(:private, :run_validations) end # Registers a validation method. # # validate :ensure_age_is_greater_than_shoe_size # # def ensure_age_is_greater_than_shoe_size # unless age > shoe_size # errors.add(:age, 'should be greater than your shoe size') # end # end # # You can also pass a list of method names that should be called during # validation. # # validate :some_complex_validation, :some_other_validation # # As with most other validation methods you can also pass a hash of # options that affect when the named validation methods get called. # # validate :my_custom_validation, :unless => :new_record? # # @overload validate(*method_names, options = {}) # @param [Array] method_names A list of methods to call # during validation. # @param [Hash] options # @option options [Symbol] :on (:save) When this validation is run. # Valid values include: # # * `:save` # * `:create` # * `:update` # @option options [Symbol,String,Proc] :if Specifies a method or proc # to call. The validation will only be run if the return value is # of the method/proc is true (e.g. `:if => :name_changed?` or # `:if => lambda{|book| book.in_stock? }`). # @option options [Symbol,String,Proc] :unless Specifies a method or # proc to call. The validation will *not* be run if the return value # is of the method/proc is false. def validate *args validators << MethodValidator.new(self, *args) end # This validation method is primariliy intended for ensuring a form # checkbox (like an EULA agreement or terms of service acknowledgement) # is checked. # # class User < AWS::Record::Model # boolean_attr :terms_of_service # validates_acceptance_of :terms_of_service # end # # ### Virtual Attributes # # If you choose to validate the acceptance of a non-existant attribute # then a setter and a getter will be added automtically for you. # # class User < AWS::Record::Model # validates_acceptance_of :terms_of_service # end # # user = User.new # user.respond_to?(:terms_of_service) #=> true # user.respond_to?(:terms_of_service=) #=> true # # ### Accepted Values # # The default behavior for `validates_acceptance_of` is to add # an error when the value is '1' or `true`. Also note, this validation # method defaults `:allow_nil` to true. # # * `nil` implies the field was omitted from the form and therefore # should not be validated # # class User < AWS::Record::Model # validates_acceptance_of :terms_of_service # end # # u = User.new # u.terms_of_service #=> nil # u.valid? #=> true # # * '1' is the default value for most checkbox form helpers, and # # therefore indicates an accepted value. # # * `true` is how boolean attributes typecast '1'. This is helpful # when you have your checkbox post its value to a `:boolean_attr`. # # ### Multi-Valued Attributes # # This validator works only with single-valued attributes. If you need # to validate that all of the values in a set are true, then use # {#validates_inclusion_of}. # # @note Most validators default :allow_nil to false, this one defaults to true # @note This validator should not be used with multi-valued attributes # # @overload validates_acceptance_of(*attributes, options = {}, &block) # @param attributes A list of attribute names to validate. # @param [Hash] options # @option options [mixed] :accpet Specify an additional accepted value. # # validates_acceptance_of :agree, :accept => 'yes' # # @option options [String] :message A custom error message. The default # `:message` is "must be accepted". # @option options [Boolean] :allow_nil (true) Skip validation if the # attribute value is `nil`. # @option options [Boolean] :allow_blank (true) Skip validation if the # attribute value is `blank`. # @option options [Symbol] :on (:save) When this validation is run. # Valid values include: # # * `:save` # * `:create` # * `:update` # @option options [Symbol,String,Proc] :if Specifies a method or proc # to call. The validation will only be run if the return value is # of the method/proc is true (e.g. `:if => :name_changed?` or # `:if => lambda{|book| book.in_stock? }`). # @option options [Symbol,String,Proc] :unless Specifies a method or # proc to call. The validation will *not* be run if the return value # is of the method/proc is false. def validates_acceptance_of *args validators << AcceptanceValidator.new(self, *args) end # Intended primarily for validating a form field was entered correctly # by requiring it twice: # # Model: # class User < AWS::Record::Model # validates_confirmation_of :password, :if => :password_changed? # end # # View: # <%= password_field "user", "password" %> # <%= password_field "user", "password_confirmation" %> # # ### Confirmation Value Accessors # # If your model does not have accessors for the confirmation value # then they will be automatically added. In the example above # the user class would have an `attr_accessor` for # `:password_confirmation`. # # ### Conditional Validation # # Mostly commonly you only need to validate confirmation of an # attribute when it has changed. It is therefore suggested to # pass an `:if` condition reflecting this: # # validates_confirmation_of :password, :if => :password_changed? # # ### Multi-Valued Attributes # # This validator works only with single-valued attributes. # It should not be used on attributes that have array or set values. # # @note This validation method does not accept the `:allow_nil` or the # `:allow_blank` options. # # @overload validates_confirmation_of(*attributes, options = {}, &block) # @param attributes A list of attribute names to validate. # @param [Hash] options # @option options [String] :message A custom error message. The default # `:message` is "doesn't match confirmation". # @option options [Symbol] :on (:save) When this validation is run. # Valid values include: # # * `:save` # * `:create` # * `:update` # @option options [Symbol,String,Proc] :if Specifies a method or proc # to call. The validation will only be run if the return value is # of the method/proc is true (e.g. `:if => :name_changed?` or # `:if => lambda{|book| book.in_stock? }`). # @option options [Symbol,String,Proc] :unless Specifies a method or # proc to call. The validation will *not* be run if the return value # is of the method/proc is false. def validates_confirmation_of *args validators << ConfirmationValidator.new(self, *args) end # Validates the number of values for a given attribute. # # ### Length vs Count # # `validates_count_of` validates the number of attribute values, # whereas +validates_length_of: validates the length of each # attribute value instead. # # If you need to ensure each attribute value is a given length see # {#validates_length_of} instead. # # ### Examples # # You can validate there are a certain number of values: # # validates_count_of :parents, :exactly => 2 # # You can also specify a range: # # validates_count_of :tags, :within => (2..10) # # You can also specify min and max value seperately: # # validates_count_of :tags, :minimum => 2, :maximum => 10 # # ### `nil` Values # # If you are validating an array or set that contains `nil` values, # the `nil` values are counted normally as 1 each. # # If you are validating a non-enuemrable attribute that only # contains a single nil or other scalar value, then nil is # counted as 0. # # ### Singular Attributes # # This validator is intended to for validating attributes that have # an array or set of values. If used on an attribute that # returns a scalar value (like `nil` or a string), the count will # always be 0 (for `nil`) or 1 (for everything else). # # It is therefore recomended to use `:validates_presence_of` in # place of `:validates_count_of` when working with single-valued # attributes. # # @overload validates_count_of(*attributes, options = {}, &block) # @param attributes A list of attribute names to validate. # @param [Hash] options # @option options [Integer] :exactly The exact number of values the # attribute should have. If this validation option fails the # error message specified by `:wrong_number` will be added. # @option options [Range] :within An range of number of values to # accept. If the attribute has a number of values outside this range # then the `:too_many` or `:too_few` error message will be added. # @option options [Integer] :minimum The minimum number of values # the attribute should have. If it has fewer, the `:too_few` error # message will be added. # @option options [Integer] :maximum The maximum number of values # the attribute should have. If it has more, the `:too_many` error # message will be added. # @option options [String] :too_many An error message added # when the attribute has too many values. Defaults to # "has too many values (maximum is %{maximum})" # @option options [String] :too_few An error message added # when the attribute has too few values. Defaults to # "has too few values (minimum is %{minimum})" # @option options [String] :wrong_number An error message # added when the number of attribute values does not match # the `:exactly` option. Defaults to "has the wrong # number of values (should have exactly %{exactly}" # @option options [Symbol] :on (:save) When this validation is run. # Valid values include: # * `:save` # * `:create` # * `:update` # @option options [Symbol,String,Proc] :if Specifies a method or proc # to call. The validation will only be run if the return value is # of the method/proc is true (e.g. `:if => :name_changed?` or # `:if => lambda{|book| book.in_stock? }`). # @option options [Symbol,String,Proc] :unless Specifies a method or # proc to call. The validation will *not* be run if the return value # is of the method/proc is false. def validates_count_of *args validators << CountValidator.new(self, *args) end # Adds a block validator that is called during record validation. # # class ExampleClass < AWS::Record::Model # # string_attr :name # # validates_each(:name) do |record, attribute_name, value| # if value == 'John Doe' # record.errors.add(attr_name, 'may not be an alias') # end # end # # end # # @overload validates_each(*attributes, options = {}, &block) # @param attributes A list of attribute names to validate. # @param [Hash] options # @option options [Boolean] :allow_nil (false) Skip validation if the # attribute value is `nil`. # @option options [Boolean] :allow_blank (false) Skip validation if the # attribute value is `blank`. # @option options [Symbol] :on (:save) When this validation is run. # Valid values include: # * `:save` # * `:create` # * `:update` # @option options [Symbol,String,Proc] :if Specifies a method or proc # to call. The validation will only be run if the return value is # of the method/proc is true (e.g. `:if => :name_changed?` or # `:if => lambda{|book| book.in_stock? }`). # @option options [Symbol,String,Proc] :unless Specifies a method or # proc to call. The validation will *not* be run if the return value # is of the method/proc is false. def validates_each *attributes, &block unless block_given? raise ArgumentError, 'missing required block for validates_each' end validators << BlockValidator.new(self, *attributes, &block) end # Validates that the attribute value is not included in the given # enumerable. # # validates_exlusion_of :username, :in => %w(admin administrator) # # ### Multi-Valued Attributes # # You may use this with multi-valued attributes the same way you use it # with single-valued attributes: # # class Product < AWS::Record::Model # string_attr :tags, :set => true # validates_exlusion_of :tags, :in => four_letter_words # end # # @overload validates_exclusion_of(*attributes, options = {}, &block) # @param attributes A list of attribute names to validate. # @param [Hash] options # @option options [required, Enumerable] :in An enumerable object to # ensure the value is not in. # @option options [String] :message A custom error message. The default # `:message` is "is reserved". # @option options [Boolean] :allow_nil (false) Skip validation if the # attribute value is `nil`. # @option options [Boolean] :allow_blank (false) Skip validation if the # attribute value is `blank`. # @option options [Symbol] :on (:save) When this validation is run. # Valid values include: # * `:save` # * `:create` # * `:update` # @option options [Symbol,String,Proc] :if Specifies a method or proc # to call. The validation will only be run if the return value is # of the method/proc is true (e.g. `:if => :name_changed?` or # `:if => lambda{|book| book.in_stock? }`). # @option options [Symbol,String,Proc] :unless Specifies a method or # proc to call. The validation will *not* be run if the return value # is of the method/proc is false. def validates_exclusion_of *args validators << ExclusionValidator.new(self, *args) end # Validates the attribute's value matches the given regular exression. # # validates_format_of :year, :with => /^\d{4}$/ # # You can also perform a not-match using `:without` instead of `:with`. # # validates_format_of :username, :without => /\d/ # # ### Multi-Valued Attributes # # You may use this with multi-valued attributes the same way you use it # with single-valued attributes: # # class Product < AWS::Record::Model # string_attr :tags, :set => true # validates_format_of :tags, :with => /^\w{2,10}$/ # end # # @overload validates_format_of(*attributes, options = {}, &block) # @param attributes A list of attribute names to validate. # @param [Hash] options # @option options [Regexp] :with If the value matches the given # regex, an error will not be added. # @option options [Regexp] :without If the value matches the given # regex, an error will be added. # must match, or an error is added. # @option options [String] :message A custom error message. The default # `:message` is "is reserved". # @option options [Boolean] :allow_nil (false) Skip validation if the # attribute value is `nil`. # @option options [Boolean] :allow_blank (false) Skip validation if the # attribute value is `blank`. # @option options [Symbol] :on (:save) When this validation is run. # Valid values include: # * `:save` # * `:create` # * `:update` # @option options [Symbol,String,Proc] :if Specifies a method or proc # to call. The validation will only be run if the return value is # of the method/proc is true (e.g. `:if => :name_changed?` or # `:if => lambda{|book| book.in_stock? }`). # @option options [Symbol,String,Proc] :unless Specifies a method or # proc to call. The validation will *not* be run if the return value # is of the method/proc is false. def validates_format_of *args validators << FormatValidator.new(self, *args) end # Validates that the attribute value is included in the given enumerable # object. # # class MultipleChoiceAnswer < AWS::Record::Model # validates_inclusion_of :letter, :in => %w(a b c d e) # end # # ### Multi-Valued Attributes # # You may use this with multi-valued attributes the same way you use it # with single-valued attributes. # # @overload validates_inclusion_of(*attributes, options = {}, &block) # @param attributes A list of attribute names to validate. # @param [Hash] options # @option options [required, Enumerable] :in An enumerable object to # check for the value in. # @option options [String] :message A custom error message. The default # `:message` is "is not included in the list". # @option options [Boolean] :allow_nil (false) Skip validation if the # attribute value is `nil`. # @option options [Boolean] :allow_blank (false) Skip validation if the # attribute value is `blank`. # @option options [Symbol] :on (:save) When this validation is run. # Valid values include: # * `:save` # * `:create` # * `:update` # @option options [Symbol,String,Proc] :if Specifies a method or proc # to call. The validation will only be run if the return value is # of the method/proc is true (e.g. `:if => :name_changed?` or # `:if => lambda{|book| book.in_stock? }`). # @option options [Symbol,String,Proc] :unless Specifies a method or # proc to call. The validation will *not* be run if the return value # is of the method/proc is false. def validates_inclusion_of *attributes validators << InclusionValidator.new(self, *attributes) end # Validates the attribute values are of a specified length. # # validates_lenth_of :username, :within => 3..25 # # ### Length vs Count # # `validates_length_of` validates the length of individual attribute # values, whereas +validates_count_of: validates the number of # attribute values. # # If you need to ensure there are certain number of values see # {#validates_count_of} instead. # # @overload validates_length_of(*attributes, options = {}, &block) # @param attributes A list of attribute names to validate. # @param [Hash] options # @option options [Enumerable] :within An enumerable object to # ensure the length of the value falls within. # @option options [Integer] :exactly The exact length a value must be. # If this validation fails the error message specified by # `:wrong_length` will be added. # @option options [Range] :within An enumerable object which must # include the length of the attribute, or an error will be added. # If the attribute has a length outside the range then the # `:too_long` or `:too_short` error message will be added. # @option options [Integer] :minimum The minimum length an attribute # value should be. If it is shorter, the `:too_short` error # message will be added. # @option options [Integer] :maximum The maximum length an attribute # value should be. If it is longer, the `:too_long` error # message will be added. # @option options [String] :too_long An error message added # when the attribute value is too long. Defaults to # "is too long (maximum is %{maximum} # characters)" # @option options [String] :too_short An error message added # when the attribute value is too short. Defaults to # "is too short (minimum is %{minimum} # characters)" # @option options [String] :wrong_length An error message # added when the attribute has the incorrect length (as # specified by `:exactly`). Defaults to "is the wrong # length (should be %{exactly} characters" # @option options [Boolean] :allow_nil (false) Skip validation if the # attribute value is `nil`. # @option options [Boolean] :allow_blank (false) Skip validation if the # attribute value is `blank`. # @option options [Symbol] :on (:save) When this validation is run. # Valid values include: # * `:save` # * `:create` # * `:update` # @option options [Symbol,String,Proc] :if Specifies a method or proc # to call. The validation will only be run if the return value is # of the method/proc is true (e.g. `:if => :name_changed?` or # `:if => lambda{|book| book.in_stock? }`). # @option options [Symbol,String,Proc] :unless Specifies a method or # proc to call. The validation will *not* be run if the return value # is of the method/proc is false. def validates_length_of *args validators << LengthValidator.new(self, *args) end # Validates the attribute has a numeric value. # # validates_numericality_of :age, :only_integer => true # # ### Multi-Valued Attributes # # You can validate multi-valued attributes using this the same way you # validate single-valued attributes. Each value will be validated # individually. # # @overload validates_numericality_of(*attributes, options = {}, &block) # @param attributes A list of attribute names to validate. # @param [Hash] options # @option options [Boolean] :only_integer (false) Adds an error # when valiating and the value is numeric, but it not a whole number. # @option options [Integer] :equal_to When set the value must equal # the given value exactly. May not be used with the greater/less # options. # @option options [Numeric] :greater_than Ensures the attribute # is greater than the given number. # @option options [Integer] :greater_than_or_equal_to Ensures the # attribute is greater than or equal to the given number. # @option options [Numeric] :less_than Ensures the attribute is less # than the given value. # @option options [Integer] :less_than_or_equal_to Ensures the value is # less than or equal to the given number. # @option options [Numeric] :even If true, the value may only be # an even integer. This forces the `:only_integer` to `true`. # @option options [Numeric] :odd If true, the value may only be # an odd integer. This forces the `:only_integer` to `true`. # @option options [String] :message A custom error message. The default # `:message` is "is not a number". # @option options [Boolean] :allow_nil (false) Skip validation if the # attribute value is `nil`. # @option options [Boolean] :allow_blank (false) Skip validation if the # attribute value is `blank`. # @option options [Symbol] :on (:save) When this validation is run. # Valid values include: # * `:save` # * `:create` # * `:update` # @option options [Symbol,String,Proc] :if Specifies a method or proc # to call. The validation will only be run if the return value is # of the method/proc is true (e.g. `:if => :name_changed?` or # `:if => lambda{|book| book.in_stock? }`). # @option options [Symbol,String,Proc] :unless Specifies a method or # proc to call. The validation will *not* be run if the return value # is of the method/proc is false. def validates_numericality_of *args validators << NumericalityValidator.new(self, *args) end # Validates the named attributes are not blank. For validation # purposes, blank values include: # # * `nil` # * empty string # * anything that responds to #empty? with true # * anything that responds to #blank? with true # # @overload validates_presence_of(*attributes, options = {}, &block) # @param attributes A list of attribute names to validate. # @param [Hash] options # @option options [String] :message A custom error message. The default # `:message` is "may not be blank". # @option options [Symbol] :on (:save) When this validation is run. # Valid values include: # * `:save` # * `:create` # * `:update` # @option options [Boolean] :allow_nil (false) Skip validation if the # attribute value is `nil`. # @option options [Boolean] :allow_blank (false) Skip validation if the # attribute value is `blank`. # @option options [Symbol,String,Proc] :if Specifies a method or proc # to call. The validation will only be run if the return value is # of the method/proc is true (e.g. `:if => :name_changed?` or # `:if => lambda{|book| book.in_stock? }`). # @option options [Symbol,String,Proc] :unless Specifies a method or # proc to call. The validation will *not* be run if the return value # is of the method/proc is false. def validates_presence_of *args validators << PresenceValidator.new(self, *args) end # @api private private def validators @validators ||= [] end end end end aws-sdk-v1-1.66.0/lib/aws/record/exceptions.rb0000644000004100000410000000301612604445426021064 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # @api private class RecordNotFound < StandardError; end # Raised when trying to access an attribute that does not exist. # @api private class UndefinedAttributeError < StandardError def initalize attribute_name super("undefined attribute `#{attribute_name}`") end end # Raised when calling #save!, #create! or #update_attributes! on a record that # has validation errors. # @api private class InvalidRecordError < StandardError def initialize record @record = record super(record.errors.full_messages.join(', ')) end attr_reader :record end # Raised when trying to persist a record that has no attribute values # to persist. # @api private class EmptyRecordError < StandardError def initialize record @record = record super('unable persist empty records') end attr_reader :record end end end aws-sdk-v1-1.66.0/lib/aws/record/scope.rb0000644000004100000410000001342412604445426020020 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Record # Base class for {AWS::Record::Model::Scope} and # {AWS::Record::HashModel::Scope}. class Scope include Enumerable # @param base_class A class that extends {AWS::Record::AbstractBase}. # @param [Hash] options # @option options : # @api private def initialize base_class, options = {} @base_class = base_class @options = options.dup # backwards compat @options[:shard] = @options.delete(:domain) if @options[:domain] end # @return [Class] Returns the AWS::Record::Model extending class that # this scope will find records for. attr_reader :base_class def new attributes = {} attributes = attributes.dup attributes[:shard] ||= attributes.delete(:shard) attributes[:shard] ||= attributes.delete('shard') # for backwards compatability, domain is accepted attributes[:shard] ||= attributes.delete('domain') attributes[:shard] ||= attributes.delete(:domain) attributes[:shard] ||= _shard base_class.new(attributes) end alias_method :build, :new # @param [String] shard_name # @return [Scope] Returns a scope that specifies which shard # (i.e. SimpleDB domain) should be used. def shard shard_name _with(:shard => shard_name) end alias_method :domain, :shard # @overload find(id) # Finds and returns a single record by id. If no record is found # with the given `id`, then a RecordNotFound error will be raised. # @param [String] id ID of the record to find. # @return Returns the record. # # @overload find(:first, options = {}) # Returns the first record found. If no records were matched then # nil will be returned (raises no exceptions). # @param [Symbol] mode (:first) # @return [Object,nil] Returns the first record or nil if no # records matched the conditions. # # @overload find(:all, options = {}) # Returns an enumerable Scope object that represents all matching # records. No request is made to AWS until the scope is enumerated. # # Book.find(:all, :limit => 100).each do |book| # # ... # end # # @param [Symbol] mode (:all) # @return [Scope] Returns an enumerable scope object. # def find id_or_mode, options = {} scope = _handle_options(options) case when id_or_mode == :all then scope when id_or_mode == :first then scope.limit(1).to_a.first else base_class.find_by_id(id_or_mode, :shard => scope._shard) end end # @return [Integer] Returns the number of records that match the # current scoped finder. def count options = {} if scope = _handle_options(options) and scope != self scope.count else _item_collection.count end end alias_method :size, :count # @return Returns the first record found, returns # nil if the domain/table is empty. def first options = {} _handle_options(options).find(:first) end # Limits the maximum number of total records to return when finding # or counting. Returns a scope, does not make a request. # # @example # # books = Book.limit(100) # # @param [Integer] limit The maximum number of records to return. # @return [Scope] Returns a new scope that has the applied limit. def limit limit _with(:limit => limit) end # Yields once for each record matching the request made by this scope. # # @example # # books = Book.where(:author => 'me').order(:price, :asc).limit(10) # # books.each do |book| # puts book.attributes.to_yaml # end # # @yieldparam [Object] record def each &block if block_given? _each_object(&block) else to_enum(:"_each_object") end end protected def _shard @options[:shard] || base_class.shard_name end alias_method :domain, :shard # @api private private def _each_object &block raise NotImplementedError end # @api private private def _with options self.class.new(base_class, @options.merge(options)) end # @api private private def method_missing scope_name, *args # @todo only proxy named scope methods _merge_scope(base_class.send(scope_name, *args)) end # Merges the one scope with the current scope, returning a 3rd. # @param [Scope] scope # @return [Scope] # @api private private def _merge_scope scope raise NotImplementedError end # Consumes a hash of options (e.g. `:shard`, +:limit) and returns # a new scope with those applied. # @return [Scope] # @api private private def _handle_options options raise NotImplementedError end # @api private private def _item_collection raise NotImplementedError end end end end aws-sdk-v1-1.66.0/lib/aws/cloud_formation.rb0000644000004100000410000002004412604445426020611 0ustar www-datawww-data# Copyright 2011-2013 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 'aws/core' require 'aws/cloud_formation/config' module AWS # # AWS::CloudFormation # # Provides an expressive, object-oriented interface to AWS CloudFormation. # # ## Credentials # # You can setup default credentials for all AWS services via # AWS.config: # # AWS.config( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # Or you can set them directly on the CloudFormation interface: # # cf = AWS::CloudFormation.new( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # # Stacks # # This is the starting point for working with CloudFormation. # # ## Creating a Stack # # You can create a CloudFormation stack with a name and a template. # # template = <<-TEMPLATE # { # "AWSTemplateFormatVersion" : "2010-09-09", # "Description": "A simple template", # "Resources": { # "web": { # "Type": "AWS::EC2::Instance", # "Properties": { # "ImageId": "ami-41814f28" # } # } # } # } # TEMPLATE # # cfm = AWS::CloudFormation.new # stack = cfm.stacks.create('stack-name', template) # # See {StackCollection#create} for more information on creating templates # with capabilities and parameters. # # ## Getting a Stack # # Given a name, you can fetch a {Stack}. # # stack = cfm.stacks['stack-name'] # # ## Enumerating Stacks # # You can enumerate stacks in two ways. You can enumerate {Stack} # objects or stack summaries (simple hashes). You can filter the stack # summary collection by a status. # # # enumerating all stack objects # cfm.stacks.each do |stack| # # ... # end # # # enumerating stack summaries (hashes) # cfm.stack_summaries.each do |stack_summary| # # ... # end # # # filtering stack summaries by status # cfm.stack_summaries.with_status(:create_failed).each do |summary| # puts summary.to_yaml # end # # ## Template # # You can fetch the template body for a stack as a JSON string. # # cfm.stacks['stack-name'].template # #=> "{...}" # # You can update the template for a {Stack} with the {Stack#update} method: # # cfm.stacks['stack-name'].update(:template => new_template) # # ## Stack Events # # You can enumerate events for a stack. # # stack.events.each do |event| # puts "#{event.physical_resource_id}: #{event.resource_status}" # end # # See {StackEvent} for a complete list of event attributes. # # ## Stack Resources # # You can enumerate stack resources or request a stack resource by its # logical resource id. # # # enumerating stack resources # stack.resources.each do |resource| # # ... # end # # # getting a resource by its logical id # res = stack.resources['logical-resource-id'] # puts res.physical_resource_id # # If you need a stack resource, but only have its physical resource # id, then you can call {CloudFormation#stack_resource}. # # stack_resource = cfm.stack_resource('physical-resource-id') # # ## Stack Resource Summaries # # As an alternative to stack resources, you can enumerate stack # resource summaries (hashes). # # # enumerate all resources, this collection can not be filtered # stack.resource_summaries.each do |summary| # # ... # end # # @!attribute [r] client # @return [Client] the low-level CloudFormation client object class CloudFormation autoload :Client, 'aws/cloud_formation/client' autoload :Errors, 'aws/cloud_formation/errors' autoload :Stack, 'aws/cloud_formation/stack' autoload :StackCollection, 'aws/cloud_formation/stack_collection' autoload :StackEvent, 'aws/cloud_formation/stack_event' autoload :StackEventCollection, 'aws/cloud_formation/stack_event_collection' autoload :StackOptions, 'aws/cloud_formation/stack_options' autoload :StackOutput, 'aws/cloud_formation/stack_output' autoload :StackSummaryCollection, 'aws/cloud_formation/stack_summary_collection' autoload :StackResource, 'aws/cloud_formation/stack_resource' autoload :StackResourceCollection, 'aws/cloud_formation/stack_resource_collection' autoload :StackResourceSummaryCollection, 'aws/cloud_formation/stack_resource_summary_collection' include Core::ServiceInterface include StackOptions endpoint_prefix 'cloudformation' # @return [StackCollection] def stacks StackCollection.new(:config => config) end # @return [StackSummaryCollection] def stack_summaries StackSummaryCollection.new(:config => config) end # Returns a stack resource with the given physical resource # id. # # resource = cfm.stack_resource('i-123456789') # # Alternatively, you may pass a stack name and logical resource id: # # resource = cfm.stack_resource('stack-name', 'logical-resource-id') # # @overload stack_resource(physical_resource_id) # @param [String] physical_resource_id The physical resource id # of the stack resource you want returned. # # @overload stack_resource(stack_name, logical_resource_id) # @param [String] stack_name # @param [String] logical_resource_id # # @return [StackResource] Returns the stack resource with the # given physical resource id. # def stack_resource *args client_opts = {} if args.size == 1 client_opts[:physical_resource_id] = args.first else client_opts[:stack_name] = args[0] client_opts[:logical_resource_id] = args[1] end response = client.describe_stack_resources(client_opts) details = response.stack_resources.first StackResource.new_from( :describe_stack_resource, details, Stack.new(details.stack_name, :config => config), details.logical_resource_id) end # Validates the template and returns a hash. If the template is valid, # the returned hash may/will contain the following keys (actual # key list depends on the template). # # * `:description` # * `:capabilities` # * `:capabilities_reason` # * `:parameters` # # If the template is not parseable, then a hash will the following # keys will be returned: # # * `:code` # * `:message` # # @return [Hash] # def validate_template template begin client_opts = {} client_opts[:template] = template apply_template(client_opts) client.validate_template(client_opts).data rescue CloudFormation::Errors::ValidationError => e results = {} results[:code] = e.code results[:message] = e.message results end end # @param (see Stack#template=) # # @param [Hash] parameters A hash that specifies the input # parameters for the template. # # @return [String] Returns a URL to the AWS Simple Monthly Calculator # with a query string that describes the resources required to run # the template. # def estimate_template_cost template, parameters = {} client_opts = {} client_opts[:template] = template client_opts[:parameters] = parameters apply_template(client_opts) apply_parameters(client_opts) client.estimate_template_cost(client_opts).url end end end aws-sdk-v1-1.66.0/lib/aws/s3/0000755000004100000410000000000012604445426015425 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/s3/bucket_collection.rb0000644000004100000410000001201612604445426021442 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # Represents a collection of buckets. # # You can use this to create a bucket: # # s3.buckets.create("mybucket") # # You can get a handle for a specific bucket with indifferent # access: # # bucket = s3.buckets[:mybucket] # bucket = s3.buckets['mybucket'] # # You can also use it to find out which buckets are in your account: # # s3.buckets.collect(&:name) # #=> ['bucket1', 'bucket2', ...] # class BucketCollection include Core::Model include Enumerable # Creates and returns a new Bucket. For example: # # @note If your bucket name contains one or more periods and it # is hosted in a non-US region, you should make requests # against the bucket using the S3 endpoint specific to the # region in which your bucket resides. For example: # # s3 = AWS::S3.new(:region => "eu-west-1") # bucket = s3.buckets.create("my.eu.bucket") # # For a full list of endpoints and regions, see # {http://docs.aws.amazon.com/general/latest/gr/index.html?rande.html # Regions and Endpoints} in the Amazon Web Services General # Reference. # # @example # # bucket = s3.buckets.create('my-bucket') # bucket.name #=> "my-bucket" # bucket.exists? #=> true # # @param [String] bucket_name # # @param [Hash] options # # @option options [String] :location_constraint (nil) The # location where the bucket should be created. Defaults to # the classic US region; however, if you configure a regional # endpoint for Amazon S3 this option will default to the # appropriate location constraint for the endpoint. For # example: # # s3 = AWS::S3.new(:region => "us-west-1") # bucket = s3.buckets.create("my-us-west-bucket") # bucket.location_constraint # => "us-west-1" # # @option options [Symbol,String] :acl (:private) Sets the ACL of the # bucket you are creating. Valid Values include: # * `:private` # * `:public_read` # * `:public_read_write` # * `:authenticated_read` # * `:log_delivery_write` # # @option options [String] :grant_read # @option options [String] :grant_write # @option options [String] :grant_read_acp # @option options [String] :grant_write_acp # @option options [String] :grant_full_control # # @return [Bucket] # def create bucket_name, options = {} # convert the symbolized-canned acl into the string version if acl = options[:acl] options[:acl] = acl.to_s.tr('_', '-') end # auto set the location constraint for the user if it is not # passed in and the endpoint is not the us-standard region. don't # override the location constraint though, even it is wrong, unless config.s3_endpoint == 's3.amazonaws.com' or options[:location_constraint] then constraint = guess_constraint options[:location_constraint] = constraint if constraint end client.create_bucket(options.merge(:bucket_name => bucket_name)) bucket_named(bucket_name) end # Returns the Bucket with the given name. # # Makes no requests. The returned bucket object can # be used to make requets for the bucket and its objects. # # @example # # bucket = s3.buckets[:mybucket], # bucket = s3.buckets['mybucket'], # # @param [String] bucket_name # @return [Bucket] def [] bucket_name bucket_named(bucket_name) end # Iterates the buckets in this collection. # # @example # # s3.buckets.each do |bucket| # puts bucket.name # end # # @return [nil] def each &block response = client.list_buckets response.buckets.each do |b| yield(bucket_named(b.name, response.owner)) end nil end private def bucket_named name, owner = nil S3::Bucket.new(name.to_s, :owner => owner, :config => config) end def guess_constraint case config.s3_endpoint when 's3-eu-west-1.amazonaws.com' then 'EU' when /^s3[.-](.*)\.amazonaws\.com/ then $1 end end end end end aws-sdk-v1-1.66.0/lib/aws/s3/presign_v4.rb0000644000004100000410000001005312604445426020031 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # Utility class for building pre-signed URLs for Amazon S3 objects using # signature version 4. class PresignV4 # @param [S3Object] object def initialize(object) @object = object @client = object.client @signer = object.client.send(:v4_signer) end # @return [S3Object] attr_reader :object # @return [Client] attr_reader :client # @return [Core::Signers::Version4] attr_reader :signer # @param (see S3Object#url_for) # @option (see S3Object#url_for) # @return (see S3Object#url_for) def presign(method, options = {}) now = Time.now.utc one_week = 60 * 60 * 24 * 7 if options[:expires] - now.to_i > one_week msg = "presigned URLs using sigv4 may not expire more than one week out" raise ArgumentError, msg end now = now.strftime("%Y%m%dT%H%M%SZ") request = build_request(method, options) request.headers.clear request.headers['host'] = request.host signed_headers = 'Host' if options[:acl] request.add_param("x-amz-acl", options[:acl].to_s.gsub(/_/, '-')) end # must be sent along with the PUT request headers if options[:content_md5] request.headers['Content-MD5'] = options[:content_md5] signed_headers << ';Content-MD5' end request_params = Core::Signers::S3::QUERY_PARAMS.map do |p| param = p.tr("-","_").to_sym if options.key?(param) request.add_param(p, options[param]) end end token = client.credential_provider.session_token request.add_param("X-Amz-Algorithm", "AWS4-HMAC-SHA256") request.add_param("X-Amz-Date", now) request.add_param("X-Amz-SignedHeaders", signed_headers) request.add_param("X-Amz-Expires", seconds_away(options[:expires])) request.add_param('X-Amz-Security-Token', token) if token request.add_param("X-Amz-Credential", signer.credential(now)) request.add_param("X-Amz-Signature", signature(request, now)) build_uri(request, options) end private def build_request(method, options) path_style = object.config.s3_force_path_style params = options.merge( :bucket_name => object.bucket.name, :key => object.key, :data => '' ) req = client.send(:build_request, operation_name(method), params) req.force_path_style = options.fetch(:force_path_style, path_style) req end def operation_name(method) case method when :get, :read then :get_object when :put, :write then :put_object when :delete then :delete_object when :head then :head_object else msg = "invalid method, expected :get, :put or :delete, got " msg << method.inspect raise ArgumentError msg end end def signature(request, datetime) key = signer.derive_key(datetime) signer.signature(request, key, datetime, 'UNSIGNED-PAYLOAD') end def build_uri(request, options) uri_class = options[:secure] ? URI::HTTPS : URI::HTTP uri_class.build( :host => request.host, :port => request.port, :path => request.path, :query => request.querystring ) end def seconds_away(expires) expires - Time.now.to_i end end end end aws-sdk-v1-1.66.0/lib/aws/s3/object_upload_collection.rb0000644000004100000410000000441512604445426023003 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # Represents uploads in progress for a single object. # # @example Cancel all uploads for an object # object.multipart_uploads.each(&:abort) # # @example Get an upload by ID # object.multipart_uploads[id] class ObjectUploadCollection include Enumerable include Core::Model # @return [S3Object] The object to which the uploads belong. attr_reader :object # @api private def initialize(object, opts = {}) @all_uploads = MultipartUploadCollection.new(object.bucket). with_prefix(object.key) @object = object super end # Creates a new multipart upload. It is usually more # convenient to use {S3Object#multipart_upload}. def create(options = {}) options[:storage_class] = :reduced_redundancy if options.delete(:reduced_redundancy) initiate_opts = { :bucket_name => object.bucket.name, :key => object.key }.merge(options) id = client.initiate_multipart_upload(initiate_opts).upload_id MultipartUpload.new(object, id) end # Iterates the uploads in the collection. # # @yieldparam [MultipartUpload] upload An upload in the # collection. # @return [nil] def each(options = {}, &block) @all_uploads.each(options) do |upload| yield(upload) if upload.object.key == @object.key end nil end # @return [MultipartUpload] An object representing the upload # with the given ID. # # @param [String] id The ID of an upload to get. def [] id MultipartUpload.new(object, id) end end end end aws-sdk-v1-1.66.0/lib/aws/s3/errors.rb0000644000004100000410000000556212604445426017276 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # This module contains exception classes for each of the error # types that S3 can return. You can use these classes to rescue # specific errors, for example: # # begin # S3.new.buckets.mybucket. # objects.myobj.write("HELLO") # rescue S3::Errors::NoSuchBucket => e # S3.new.buckets.create("mybucket") # retry # end # # All errors raised as a result of error responses from the # service are instances of either {ClientError} or {ServerError}. module Errors # @api private GRAMMAR = Core::XML::Grammar.customize extend Core::LazyErrorClasses class BatchDeleteError < StandardError def initialize error_counts @error_counts = error_counts total = error_counts.values.inject(0) {|sum,count| sum + count } super("Failed to delete #{total} objects") end # @return [Hash] Returns a hash of error codes and how many # objects failed with that code. attr_reader :error_counts end # This error is special, because S3 does not (and must not # according to RFC 2616) return a body with the HTTP response. # The interface is the same as for any other client error. class NotModified < AWS::Errors::Base include AWS::Errors::ClientError def initialize(req, resp) super(req, resp, "NotModified", "Not Modified") end end # This error is special, because S3 does not return a body with # the HTTP response. The interface is the same as for any other # client error. class NoSuchKey < AWS::Errors::Base include AWS::Errors::ClientError def initialize(req, resp, code = nil, message = nil) super(req, resp, "NoSuchKey", "No Such Key") end end # This error is special, because S3 must first retrieve the client # side encryption key in it's encrypted form before finding if the # key is incorrect. class IncorrectClientSideEncryptionKey < AWS::Errors::Base include AWS::Errors::ClientError def initialize(msg) super("", "", "IncorrectClientSideEncryptionKey", msg) end end end end end aws-sdk-v1-1.66.0/lib/aws/s3/bucket_version_collection.rb0000644000004100000410000000427612604445426023220 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # A collection of versioned objects for the entire bucket. # # @see PrefixedCollection class BucketVersionCollection include PrefixAndDelimiterCollection # @param [Bucket] bucket def initialize bucket, options = {} @bucket = bucket super end # @return [Bucket] The bucket this collection belongs to. attr_reader :bucket # @return [ObjectVersion] Returns the most recently created object # version in the entire bucket. def latest first #self.find{|version| true } end # Yields once for each version in the bucket. # # @yield [object_version] # # @yieldparam [ObjectVersion] object_version # # @return nil # def each options = {}, █ super; end # @api private protected def each_member_in_page(page, &block) super page.versions.each do |version| object_version = ObjectVersion.new(bucket.objects[version.key], version.version_id, :delete_marker => version.delete_marker?, :last_modified => version.last_modified) yield(object_version) end end # @api private protected def list_request(options) client.list_object_versions(options) end # @api private protected def limit_param; :max_keys; end # @api private protected def pagination_markers; super + [:version_id_marker]; end end end end aws-sdk-v1-1.66.0/lib/aws/s3/tree/0000755000004100000410000000000012604445426016364 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/s3/tree/child_collection.rb0000644000004100000410000000624112604445426022212 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 class Tree class ChildCollection include Core::Model include Enumerable # @api private def initialize parent, collection, options = {} options = { :prefix => nil, :delimiter => '/', :append => true, }.merge(options) @parent = parent @collection = collection @prefix = options[:prefix] @delimiter = options[:delimiter] @append = options[:append] super end # @return [Tree, BranchNode] The parent node in the tree. attr_reader :parent # @return [ObjectCollection, ObjectVersionCollection, # MultipartUploadCollection] Returns the collection this # tree is based on. attr_reader :collection # A tree may have a prefix of where in the bucket to be based from. # @return [String,nil] attr_reader :prefix # When looking at S3 keys as a tree, the delimiter defines what # string pattern seperates each level of the tree. The delimiter # defaults to '/' (like in a file system). # @return [String] attr_reader :delimiter # @return [Boolean] Returns true if the tree is set to auto-append # the delimiter to the prefix when the prefix does not end with # the delimiter. def append? @append end # Yields up branches and leaves. # # A branch node represents a common prefix (like a directory) # and a leaf node represents a key (S3 object). # # @yield [tree_node] Yields up a mixture of branches and leafs. # @yieldparam [BranchNode,LeafNode] tree_node A branch or a leaf. # @return [nil] def each &block collection = self.collection if prefix = prefix_with_delim collection = collection.with_prefix(prefix) end collection.each(:delimiter => delimiter) do |member| case when member.respond_to?(:key) yield LeafNode.new(parent, member) when member.respond_to?(:prefix) yield BranchNode.new(parent, member, :delimiter => delimiter, :append => append?) end end nil end protected def prefix_with_delim return prefix unless append? return nil if prefix.nil? prefix =~ /#{delimiter}$/ ? prefix : "#{prefix}#{delimiter}" end end end end end aws-sdk-v1-1.66.0/lib/aws/s3/tree/leaf_node.rb0000644000004100000410000000466012604445426020633 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 class Tree # Represents a leaf in an {S3::Tree}. # # When enumerating nodes in an S3 tree, keys are yielded # as leaf nodes (they have no children beneath them). # # @see Tree # @note Generally you do not need to create leaf nodes class LeafNode < Node # @api private def initialize parent, member @parent = parent @member = member super() end # @return [Tree, BranchNode] The parent node in the tree. attr_reader :parent # @return [mixed] Returns the object this leaf node represents. # @see #object # @see #version # @see #upload attr_reader :member # @return [String] the key this leaf node represents. def key @member.key end # @return [false] def branch? false end # @return [true] def leaf? true end # @return [S3Object] The object this leaf node represents. def object if @member.kind_of?(S3Object) @member else @member.object end end # @return [ObjectVersion] Returns the object version this leaf # node represents. def version if @member.kind_of?(ObjectVersion) @member else raise "This leaf does not represent a version" end end # @return [MultipartUpload] Returns the object version this leaf # node represents. def upload if @member.kind_of?(MultipartUpload) @member else raise "This leaf does not represent an upload" end end def inspect "<#{self.class}:#{@member.bucket.name}:#{key}>" end end end end end aws-sdk-v1-1.66.0/lib/aws/s3/tree/branch_node.rb0000644000004100000410000000375412604445426021164 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 class Tree # Represents a branch in an {S3::Tree}. From a branch node you # can descend deeper into the tree using {Parent#children} or go # back to the parent node using {#parent}. # # When enumerating nodes in an S3 tree keys grouped by a common # prefix are represented as a branch node. # # Branch nodes are often treated like directories. # # @see Tree # @note Generally you do not need to create branch nodes. class BranchNode < Node include Parent # @api private def initialize parent, collection, options = {} @parent = parent super(collection, options.merge(:prefix => collection.prefix)) end # @return [Tree, BranchNode] The parent node in the tree. attr_reader :parent # @return [true] def branch? true end # @return [false] def leaf? false end # Returns a new Tree object that starts at this branch node. # The returned tree will have the same prefix, delimiter and # append mode as the tree the branch belongs to. # # @return [Tree] def as_tree Tree.new(collection, :prefix => prefix, :delimiter => delimiter, :append => append?) end end end end end aws-sdk-v1-1.66.0/lib/aws/s3/tree/parent.rb0000644000004100000410000000521012604445426020200 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 class Tree # Common methods for tree nodes that are parents to other nodes # ({Tree} and {BranchNode}). module Parent include Core::Model # @api private def initialize collection, options = {} options = { :prefix => nil, :delimiter => '/', :append => true, }.merge(options) @collection = collection @prefix = options[:prefix] @delimiter = options[:delimiter] @append = options[:append] super end # @return [ObjectCollection, BucketVersionCollection, # MultipartUploadCollection] The collection whose members # will be explored using the tree. attr_reader :collection # A tree may have a prefix of where in the bucket to be based # from. A value of `nil` means that the tree will include all # objects in the collection. # # @return [String,nil] attr_reader :prefix # When looking at S3 keys as a tree, the delimiter defines what # string pattern seperates each level of the tree. The delimiter # defaults to '/' (like in a file system). # # @return [String] attr_reader :delimiter # @return [Boolean] Returns true if the tree is set to auto-append # the delimiter to the prefix when the prefix does not end with # the delimiter. def append? @append end # @return [Tree::ChildCollection] A collection representing all # the child nodes of this node. These may be either # {Tree::BranchNode} objects or {Tree::LeafNode} objects. def children Tree::ChildCollection.new(self, collection, :delimiter => delimiter, :prefix => prefix, :append => append?) end def inspect "<#{self.class}:#{collection.bucket.name}:#{prefix}>" end end end end end aws-sdk-v1-1.66.0/lib/aws/s3/tree/node.rb0000644000004100000410000000124212604445426017635 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 class Tree # @api private class Node end end end end aws-sdk-v1-1.66.0/lib/aws/s3/uploaded_part.rb0000644000004100000410000000456412604445426020606 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # Represents a part of a multipart upload that has been uploaded # to S3. # # @example Get the total size of the uploaded parts # upload.parts.inject(0) { |sum, part| sum + part.size } class UploadedPart include Core::Model # @return [MultipartUpload] The upload to which this belongs. attr_reader :upload # @return [Integer] The part number. attr_reader :part_number # @api private def initialize(upload, part_number, opts = {}) @upload = upload @part_number = part_number @etag = opts[:etag] super end def ==(other) other.kind_of?(UploadedPart) and other.upload == upload and other.part_number == part_number end alias_method :eql?, :== # @return [Integer] The size of the part as it currently # exists in S3. def size get_attribute(:size) end # @return [DateTime] The time at which the part was last # modified. def last_modified get_attribute(:last_modified) end # @return [String] The ETag of the part. def etag @etag ||= get_attribute(:etag) @etag end # @api private private def get_attribute(name) (resp = client.list_parts(:bucket_name => upload.object.bucket.name, :key => upload.object.key, :upload_id => upload.id, :part_number_marker => part_number-1, :max_parts => 1) and part = resp.parts.first and part.part_number == part_number and part.send(name)) or raise "part #{part_number} of upload #{upload.id} does not exist" end end end end aws-sdk-v1-1.66.0/lib/aws/s3/bucket_region_cache.rb0000644000004100000410000000157112604445426021721 0ustar www-datawww-datarequire 'thread' module AWS class S3 class BucketRegionCache def initialize @regions = {} @mutex = Mutex.new end def [](bucket_name) @mutex.synchronize do @regions[bucket_name] end end def []=(bucket_name, region_name) @mutex.synchronize do @regions[bucket_name] = region_name end end def delete(bucket_name) @mutex.synchronize do @regions[bucket_name] = region_name end end def update!(bucket_regions) @mutex.synchronize do @regions.update!(bucket_regions) end end def clear @mutex.synchronize do @regions = {} end end def to_hash @mutex.synchronize do @regions.dup end end alias to_h to_hash end end end aws-sdk-v1-1.66.0/lib/aws/s3/data_options.rb0000644000004100000410000001307112604445426020440 0ustar www-datawww-data# Copyright 2011-2013 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 'pathname' module AWS class S3 # Used by S3#S3Object and S3::Client to accept options with # data that should be uploaded (streamed). # @api private module DataOptions protected # @return [Hash] Returns a hash of options with a :data option that # responds to #read and #eof?. def compute_write_options *args, &block options = convert_args_to_options_hash(*args) validate_data!(options, &block) rename_file_to_data(options) convert_data_to_io_obj(options, &block) try_to_determine_content_length(options) options end # Converts an argument list into a single hash of options. Treats # non-hash arguments in the first position as a data option. def convert_args_to_options_hash *args case args.count when 0 then {} when 1 then args[0].is_a?(Hash) ? args[0] : { :data => args[0] } when 2 then args[1].merge(:data => args[0]) else msg = "expected 0, 1 or 2 arguments, got #{args.count}" raise ArgumentError, msg end end # Moves options[:file] to options[:data]. If this option is a string # then it is treated as a file path and is converted to an open file. def rename_file_to_data options if file = options.delete(:file) options[:data] = file.is_a?(String) ? open_file(file) : file end end # Converts the :data option to an IO-like object. This allows us # to always perform streaming uploads. def convert_data_to_io_obj options, &block data = options.delete(:data) if block_given? options[:data] = IOProxy.new(block) elsif data.is_a?(String) data = data.dup if data.frozen? data.force_encoding("BINARY") if data.respond_to?(:force_encoding) options[:data] = StringIO.new(data) elsif data.is_a?(Pathname) options[:data] = open_file(data.to_s) elsif io_like?(data) options[:data] = data else msg = "invalid :data option, expected a String, Pathname or " msg << "an object that responds to #read and #eof?" raise ArgumentError, msg end end # Attempts to determine the content length of the :data option. # This is only done when a content length is not already provided. def try_to_determine_content_length options unless options[:content_length] data = options[:data] length = case when data.respond_to?(:path) && data.path then File.size(data.path) when data.respond_to?(:bytesize) then data.bytesize when data.respond_to?(:size) then data.size when data.respond_to?(:length) then data.length else nil end options[:content_length] = length if length end end def validate_data! options, &block data = options[:data] file = options[:file] raise ArgumentError, 'Object data passed multiple ways.' if [data, file, block].compact.count > 1 data = file if file return if block_given? return if data.kind_of?(String) return if data.kind_of?(Pathname) return if io_like?(data) msg = ":data must be provided as a String, Pathname, File, or " msg << "an object that responds to #read and #eof?" raise ArgumentError, msg end # @return [Boolean] Returns `true` if the object responds to # `#read` and `#eof?`. def io_like? io io.respond_to?(:read) and io.respond_to?(:eof?) end # @param [String] path Path to a file on disk. # @return [File] Given a path string, returns an open File. def open_file path Core::ManagedFile.open(path) end # A utility class that turns a block (with 2 args) into an # IO object that responds to #read and #eof. # @api private class IOProxy def initialize write_block unless write_block.arity == 2 msg = "a write block must accept 2 yield params: a buffer and " msg << "a number of bytes to write" raise ArgumentError, msg end @write_block = write_block @eof = false end def read bytes = nil, output_buffer = nil data = if bytes (@eof) ? nil : read_chunk(bytes) else (@eof) ? "" : read_all end output_buffer ? output_buffer.replace(data || '') : data end def eof? @eof end protected def read_chunk bytes buffer = StringIO.new @write_block.call(buffer, bytes) buffer.rewind @eof = true if buffer.size < bytes buffer.read end def read_all buffer = StringIO.new buffer << read_chunk(1024 * 1024 * 5) until @eof buffer.rewind buffer.read end end end end end aws-sdk-v1-1.66.0/lib/aws/s3/object_version_collection.rb0000644000004100000410000000544212604445426023205 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # For S3 buckets with versioning enabled, objects will store versions # each time you write to them. # # object = bucket.objects['myobj'] # object.write('1') # object.write('2') # object.write('3') # # object.versions.collect(&:read) # #=> ['1', '2', '3'] # # To see all the version id for a particular object, access the any particular version, # and see the latest version: # # object.versions.each do |version| puts version.version_id end # #=> T2TwAiZ3SmNr7tOfe0QBa4RZnSb3GSLq # #=> kAEHC_ysT65bT4P3zyYOP1ELA6ajar_6 # #=> itHPX6m8na_sog0cAtkgP3QITEE8v5ij # # object.versions['itHPX6m8na_sog0cAtkgP3QITEE8v5ij'] # #=> >:myobj:itHPX6m8na_sog0cAtkgP3QITEE8v5ij> # # object.versions.latest # #=> >:myobj:T2TwAiZ3SmNr7tOfe0QBa4RZnSb3GSLq> # # If you know the id of a particular version you can get that object. # # bucket.objects['myobj'].version[version_id].delete # class ObjectVersionCollection include Core::Model include Enumerable # @return [S3Object] The object this collection belongs to. attr_reader :object # @param [S3Object] object def initialize object, options = {} @object = object super(options) end # Returns an object that represents a single version of the {#object}. # @param [String] version_id # @return [ObjectVersion] def [] version_id ObjectVersion.new(object, version_id) end # @note Generally you will just want to grab the object key its key. # @return [ObjectVersion] Returns the latest version of this object. def latest self.find{|version| true } end # Yields once for each version of the {#object}. # # @yield [object_version] # @yieldparam [ObectVersion] object_version # @return [nil] def each &block object.bucket.versions.with_prefix(object.key).each do |version| if version.key == object.key yield(version) end end nil end end end end aws-sdk-v1-1.66.0/lib/aws/s3/tree.rb0000644000004100000410000001033212604445426016710 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # A utility class that supports exploring an S3 {Bucket} like a # tree. # # Frequently objects stored in S3 have keys that look like a filesystem # directory structure. # # Given you have a bucket with the following keys: # # README.txt # videos/wedding.mpg # videos/family_reunion.mpg # photos/2010/house.jpg # photos/2011/fall/leaves.jpg # photos/2011/summer/vacation.jpg # photos/2011/summer/family.jpg # # You might like to explore the contents of this bucket as a tree: # # tree = bucket.as_tree # # directories = tree.children.select(&:branch?).collect(&:prefix) # #=> ['photos', 'videos'] # # files = tree.children.select(&:leaf?).collect(&:key) # #=> ['README.txt'] # # If you want to start further down, pass a prefix to {Bucket#as_tree}: # # tree = bucket.as_tree(:prefix => 'photos/2011') # # directories = tree.children.select(&:branch?).collect(&:prefix) # #=> ['photos/2011/fall', 'photos/2011/summer'] # # files = tree.children.select(&:leaf?).collect(&:key) # #=> [] # # All non-leaf nodes ({Tree} and {Tree::BranchNode} instances) # have a {Tree::Parent#children} method that provides access to # the next level of the tree, and all nodes ({Tree}, # {Tree::BranchNode}, and {Tree::LeafNode}) have a {#parent} # method that returns the parent node. In our examples above, the # non-leaf nodes are common prefixes to multiple keys # (directories) and leaf nodes are object keys. # # You can continue crawling the tree using the `children` # collection on each branch node, which will contain the branch # nodes and leaf nodes below it. # # You can construct a Tree object using the `as_tree` method of # any of the following classes: # # * {Bucket} or {ObjectCollection} (for {S3Object} leaf nodes) # # * {BucketVersionCollection} (for {ObjectVersion} leaf nodes) # # * {MultipartUploadCollection} (for {MultipartUpload} leaf nodes) # # The methods to explore the tree are the same for each kind of # leaf node, but {Tree::LeafNode#member} will return a different # type of object depending on which kind of collection the tree is # using. class Tree autoload :BranchNode, 'aws/s3/tree/branch_node' autoload :ChildCollection, 'aws/s3/tree/child_collection' autoload :LeafNode, 'aws/s3/tree/leaf_node' autoload :Node, 'aws/s3/tree/node' autoload :Parent, 'aws/s3/tree/parent' include Parent # @param [ObjectCollection, BucketVersionCollection, # MultipartUploadCollection] collection The collection whose # members will be explored using the tree. # # @param [Hash] options Additional options for constructing the # tree. # # @option options [String] :prefix (nil) Set prefix to choose # where the top of the tree will be. A value of `nil` means # that the tree will include all objects in the collection. # # @option options [String] :delimiter ('/') The string that # separates each level of the tree. This is usually a # directory separator. # # @option options [Boolean] :append (true) If true, the delimiter is # appended to the prefix when the prefix does not already end # with the delimiter. def initialize collection, options = {} super end # @return The parent node in the tree. In the case of a Tree, # the parent is always nil. def parent; nil; end end end end aws-sdk-v1-1.66.0/lib/aws/s3/policy.rb0000644000004100000410000000541712604445426017260 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # (see Core::Policy) class Policy < Core::Policy class Statement < Core::Policy::Statement ACTION_MAPPING = { :list_buckets => "s3:ListAllMyBuckets", :create_bucket => "s3:CreateBucket", :delete_bucket => "s3:DeleteBucket", :list_objects => "s3:ListBucket", :list_object_versions => "s3:ListBucketVersions", :list_multipart_uploads => "s3:ListBucketMultipartUploads", :get_object => "s3:GetObject", :get_object_version => "s3:GetObjectVersion", :put_object => "s3:PutObject", :get_object_acl => "s3:GetObjectAcl", :get_object_version_acl => "s3:GetObjectVersionAcl", :set_object_acl => "s3:PutObjectAcl", :set_object_acl_version => "s3:PutObjectAclVersion", :delete_object => "s3:DeleteObject", :delete_object_version => "s3:DeleteObjectVersion", :list_multipart_upload_parts => "s3:ListMultipartUploadParts", :abort_multipart_upload => "s3:AbortMultipartUpload", :get_bucket_acl => "s3:GetBucketAcl", :set_bucket_acl => "s3:PutBucketAcl", :get_bucket_versioning => "s3:GetBucketVersioning", :set_bucket_versioning => "s3:PutBucketVersioning", :get_bucket_requester_pays => "s3:GetBucketRequesterPays", :set_bucket_requester_pays => "s3:PutBucketRequesterPays", :get_bucket_location => "s3:GetBucketLocation", :get_bucket_policy => "s3:GetBucketPolicy", :set_bucket_policy => "s3:PutBucketPolicy", :get_bucket_notification => "s3:GetBucketNotification", :set_bucket_notification => "s3:PutBucketNotification" } protected def resource_arn resource prefix = 'arn:aws:s3:::' case resource when Bucket "#{prefix}#{resource.name}" when S3Object "#{prefix}#{resource.bucket.name}/#{resource.key}" when ObjectCollection "#{prefix}#{resource.bucket.name}/#{resource.prefix}*" when /^arn:/ resource else "arn:aws:s3:::#{resource}" end end end end end end aws-sdk-v1-1.66.0/lib/aws/s3/paginated_collection.rb0000644000004100000410000000350512604445426022124 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # @api private module PaginatedCollection include Core::Collection::WithLimitAndNextToken protected def _each_item markers, limit, options = {}, &block options = list_options(options) options.merge!(markers) unless markers.nil? or markers.empty? options[limit_param] = limit || 1000 response = list_request(options) each_member_in_page(response, &block) response.data[:truncated] ? next_markers(response) : nil end protected def each_member_in_page(page, &block); end protected def list_request(options) raise NotImplementedError end protected def list_options options opts = {} opts[:bucket_name] = bucket.name if respond_to?(:bucket) opts end protected def limit_param raise NotImplementedError end protected def pagination_markers [:key_marker] end protected def next_markers page pagination_markers.inject({}) do |markers, marker_name| if marker = page.data[:"next_#{marker_name}"] markers[marker_name] = marker if marker end markers end end end end end aws-sdk-v1-1.66.0/lib/aws/s3/presigned_post.rb0000644000004100000410000004442712604445426021012 0ustar www-datawww-data# Copyright 2011-2013 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 'uri' require 'time' module AWS class S3 # Helper to generate form fields for presigned POST requests to # a bucket. You can use this to create a form that can be used # from a web browser to upload objects to S3 while specifying # conditions on what can be uploaded and how it is processed and # stored. # # @example Form fields for uploading by file name # # form = bucket.presigned_post(:key => "photos/${filename}") # form.url.to_s # => "https://mybucket.s3.amazonaws.com/" # form.fields # => { "AWSAccessKeyId" => "...", ... } # # @example Generating a minimal HTML form # # form = bucket.objects.myobj.presigned_post # hidden_inputs = form.fields.map do |(name, value)| # %() # end # <<-END #
# #{hidden_inputs} # #
# END # # @example Restricting the size of the uploaded object # # bucket.presigned_post(:content_length => 1..(10*1024)) # # @example Restricting the key prefix # # bucket.presigned_post.where(:key).starts_with("photos/") # class PresignedPost include Core::Model # @return [Bucket] The bucket to which data can be uploaded # using the form fields attr_reader :bucket # @return [String] The key of the object that will be # uploaded. If this is nil, then the object can be uploaded # with any key that satisfies the conditions specified for # the upload (see {#where}). attr_reader :key # @return [Hash] A hash of the metadata fields included in the # signed fields. Additional metadata fields may be provided # with the upload as long as they satisfy the conditions # specified for the upload (see {#where}). attr_reader :metadata # @return [Range] The range of acceptable object sizes for the # upload. By default any size object may be uploaded. attr_reader :content_length # @api private attr_reader :conditions # @return [Array] Additional fields which may be sent # with the upload. These will be included in the policy so # that they can be sent with any value. S3 will ignore # them. attr_reader :ignored_fields # @return The expiration time for the signature. By default # the signature will expire an hour after it is generated. attr_reader :expires # @api private SPECIAL_FIELDS = [:key, :policy, :signature, :expires, :metadata, :content_length, :conditions, :ignore, :secure] # Creates a new presigned post object. # # @param [Bucket] bucket The bucket to which data can be uploaded # using the form fields. # # @param [Hash] opts Additional options for the upload. Aside # from `:secure`, `:expires`, `:content_length` and `:ignore` # the values provided here will be stored in the hash returned # from the {#fields} method, and the policy in that hash will # restrict their values to the values provided. If you # instead want to only restrict the values and not provide # them -- for example, if your application generates separate # form fields for those values -- you should use the {#where} # method on the returned object instead of providing the # values here. # # @option opts [String] :key The key of the object that will # be uploaded. If this is nil, then the object can be # uploaded with any key that satisfies the conditions # specified for the upload (see {#where}). # # @option opts [Boolean] :secure By setting this to false, you # can cause {#url} to return an HTTP URL. By default it # returns an HTTPS URL. # # @option opts [Time, DateTime, Integer, String] :expires The # time at which the signature will expire. By default the # signature will expire one hour after it is generated # (e.g. when {#fields} is called). # # When the value is a Time or DateTime, the signature # expires at the specified time. When it is an integer, the # signature expires the specified number of seconds after it # is generated. When it is a string, the string is parsed # as a time (using Time.parse) and the signature expires at # that time. # # @option opts [String] :cache_control Sets the Cache-Control # header stored with the object. # # @option opts [String] :content_type Sets the Content-Type # header stored with the object. # # @option opts [String] :content_disposition Sets the # Content-Disposition header stored with the object. # # @option opts [String] :expires_header Sets the Expires # header stored with the object. # # @option options [Symbol] :acl A canned access control # policy. Valid values are: # * `:private` # * `:public_read` # * `:public_read_write` # * `:authenticated_read` # * `:bucket_owner_read` # * `:bucket_owner_full_control` # # @option options [Symbol] :server_side_encryption (nil) If this # option is set, the object will be stored using server side # encryption. The only valid value is `:aes256`, which # specifies that the object should be stored using the AES # encryption algorithm with 256 bit keys. By default, this # option uses the value of the `:s3_server_side_encryption` # option in the current configuration; for more information, # see {AWS.config}. # # @option opts [String] :success_action_redirect The URL to # which the client is redirected upon successful upload. # # @option opts [Integer] :success_action_status The status # code returned to the client upon successful upload if # `:success_action_redirect` is not specified. Accepts the # values 200, 201, or 204 (default). # # If the value is set to 200 or 204, Amazon S3 returns an # empty document with a 200 or 204 status code. # # If the value is set to 201, Amazon S3 returns an XML # document with a 201 status code. For information on the # content of the XML document, see # [POST Object](http://docs.aws.amazon.com/AmazonS3/2006-03-01/API/index.html?RESTObjectPOST.html). # # @option opts [Hash] :metadata A hash of the metadata fields # included in the signed fields. Additional metadata fields # may be provided with the upload as long as they satisfy # the conditions specified for the upload (see {#where}). # # @option opts [Integer, Range] :content_length The range of # acceptable object sizes for the upload. By default any # size object may be uploaded. # # @option opts [Array] :ignore Additional fields which # may be sent with the upload. These will be included in # the policy so that they can be sent with any value. S3 # will ignore them. def initialize(bucket, opts = {}) @bucket = bucket @key = opts[:key] @secure = (opts[:secure] != false) @fields = {} # TODO normalize all values to @fields opts.each do |opt_key, opt_val| @fields[opt_key] = opt_val unless SPECIAL_FIELDS.include? opt_key end @metadata = opts[:metadata] || {} @content_length = range_value(opts[:content_length]) @conditions = opts[:conditions] || {} @ignored_fields = [opts[:ignore]].flatten.compact @expires = opts[:expires] || Time.now.utc + 60*60 super @fields[:server_side_encryption] = config.s3_server_side_encryption unless @fields.key?(:server_side_encryption) @fields.delete(:server_side_encryption) if @fields[:server_side_encryption].nil? end # @return [Boolean] True if {#url} generates an HTTPS url. def secure? @secure end # @return [URI::HTTP, URI::HTTPS] The URL to which the form # fields should be POSTed. If you are using the fields in # an HTML form, this is the URL to put in the `action` # attribute of the form tag. def url req = Request.new req.bucket = bucket.name req.host = config.s3_endpoint build_uri(req) end # Lets you specify conditions on a field. See # {PresignedPost#where} for usage examples. class ConditionBuilder # @api private def initialize(post, field) @post = post @field = field end # Specifies that the value of the field must equal the # provided value. def is(value) if @field == :content_length self.in(value) else @post.with_equality_condition(@field, value) end end # Specifies that the value of the field must begin with the # provided value. If you are specifying a condition on the # "key" field, note that this check takes place after the # `${filename}` variable is expanded. This is only valid # for the following fields: # # * `:key` # * `:cache_control` # * `:content_type` # * `:content_disposition` # * `:content_encoding` # * `:expires_header` # * `:acl` # * `:success_action_redirect` # * metadata fields (see {#where_metadata}) def starts_with(prefix) @post.with_prefix_condition(@field, prefix) end # Specifies that the value of the field must be in the given # range. This may only be used to constrain the # `:content_length` field, # e.g. `presigned_post.with(:conent_length).in(1..4)`. def in(range) @post.refine(:content_length => range) end end # Adds a condition to the policy for the POST. Use # {#where_metadata} to add metadata conditions. # # @example Restricting the ACL to "bucket-owner" ACLs # presigned_post.where(:acl).starts_with("bucket-owner") # # @param [Symbol] field The field for which a condition should # be added. In addition to any arbitrary values you have set, # the following values are also permitted: # # * `:key` # * `:content_length` # * `:cache_control` # * `:content_type` # * `:content_disposition` # * `:content_encoding` # * `:expires_header` # * `:acl` # * `:success_action_redirect` # * `:success_action_status` # # @return [ConditionBuilder] An object that allows you to # specify a condition on the field. def where(field) ConditionBuilder.new(self, field) end # Adds a condition to the policy for the POST to constrain the # values of metadata fields uploaded with the object. If a # metadata field does not have a condition associated with it # and is not specified in the constructor (see {#metadata}) # then S3 will reject it. # # @param [Symbol, String] field The name of the metadata # attribute. For example, `:color` corresponds to the # "x-amz-meta-color" field in the POST body. # # @return [ConditionBuilder] An object that allows you to # specify a condition on the metadata attribute. def where_metadata(field) where("x-amz-meta-#{field}") end # @return [String] The Base64-encoded JSON policy document. def policy json = { "expiration" => format_expiration, "conditions" => generate_conditions }.to_json Base64.encode64(json).tr("\n","") end # @return [Hash] A collection of form fields (including a # signature and a policy) that can be used to POST data to # S3. Additional form fields may be added after the fact as # long as they are described by a policy condition (see # {#where}). def fields secret = config.credential_provider.secret_access_key signature = Core::Signers::Base.sign(secret, policy, 'sha1') fields = { "AWSAccessKeyId" => config.credential_provider.access_key_id, "key" => key, "policy" => policy, "signature" => signature }.merge(optional_fields) if token = config.credential_provider.session_token fields["x-amz-security-token"] = token end fields.merge(optional_fields) end # @api private def with_equality_condition(option_name, value) field_name = field_name(option_name) with_condition(option_name, Hash[[[field_name, value]]]) end # @api private def with_prefix_condition(option_name, prefix) field_name = field_name(option_name) with_condition(option_name, ["starts-with", "$#{field_name}", prefix]) end # @api private def refine(opts) self.class.new(bucket, { :conditions => conditions, :key => key, :metadata => metadata, :secure => secure?, :content_length => content_length, :expires => expires, :ignore => ignored_fields }.merge(@fields). merge(opts)) end # @api private private def with_condition(field, condition) conditions = self.conditions.dup (conditions[field] ||= []) << condition refine(:conditions => conditions) end # @api private private def format_expiration time = case expires when Time expires when DateTime Time.parse(expires.to_s) when Integer (Time.now + expires) when String Time.parse(expires) end time.utc.iso8601 end # @api private private def range_value(range) case range when Integer range..range when Range range end end # @api private private def split_range(range) range = range_value(range) [range.begin, (range.exclude_end? ? range.end-1 : range.end)] end # @api private private def optional_fields fields = @fields.keys.inject({}) do |fields, option_name| fields[field_name(option_name)] = field_value(option_name) fields end @metadata.each do |key, value| fields["x-amz-meta-#{key}"] = value.to_s end fields end # @api private private def field_name(option_name) case option_name when :expires_header "Expires" when :server_side_encryption "x-amz-server-side-encryption" when :key, "Key", :policy, "Policy" option_name.to_s.downcase when :acl, :success_action_redirect, :success_action_status option_name.to_s else # e.g. Cache-Control from cache_control field_name = option_name.to_s.tr("_", "-"). gsub(/-(.)/) { |m| m.upcase } field_name[0,1] = field_name[0,1].upcase field_name end end # @api private private def field_value(option_name) case option_name when :acl @fields[:acl].to_s.tr("_", "-") when :server_side_encryption value = @fields[:server_side_encryption] if value.kind_of?(Symbol) value.to_s.upcase else value.to_s end else @fields[option_name].to_s end end # @api private private def generate_conditions conditions = self.conditions.inject([]) do |list, (field, field_conds)| list + field_conds end conditions << { "bucket" => bucket.name } conditions += key_conditions conditions += optional_fields.map { |(n, v)| Hash[[[n, v]]] } conditions += range_conditions conditions += ignored_conditions if token = config.credential_provider.session_token conditions << { "x-amz-security-token" => token } end conditions end # @api private private def ignored_conditions ignored_fields.map do |field| ["starts-with", "$#{field}", ""] end end # @api private private def range_conditions if content_length [["content-length-range", *split_range(content_length)]] else [] end end # @api private private def key_conditions [if key && key.include?("${filename}") ["starts-with", "$key", key[/^(.*)\$\{filename\}/, 1]] elsif key { "key" => key } else ["starts-with", "$key", ""] end] end # @api private private def build_uri(request) uri_class = secure? ? URI::HTTPS : URI::HTTP uri_class.build(:host => request.host, :path => request.path, :query => request.querystring) end end end end aws-sdk-v1-1.66.0/lib/aws/s3/client.rb0000644000004100000410000023653512604445426017246 0ustar www-datawww-data# -*- coding: utf-8 -*- # Copyright 2011-2014 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 'rexml/document' require 'pathname' require 'stringio' require 'json' require 'digest/md5' require 'base64' require 'nokogiri' require 'set' module AWS class S3 # Client class for Amazon Simple Storage Service (S3). class Client < Core::Client include RegionDetection def initialize(options = {}) super(options.merge(:http_continue_threshold => 0)) end signature_version :S3 API_VERSION = '2006-03-01' XMLNS = "http://s3.amazonaws.com/doc/#{API_VERSION}/" HTTP_200_ERROR_OPERATIONS = Set.new([ :complete_multipart_upload, :copy_object, :copy_part, ]) autoload :XML, 'aws/s3/client/xml' # @api private EMPTY_BODY_ERRORS = { 304 => Errors::NotModified, 403 => Errors::Forbidden, 400 => Errors::BadRequest, 404 => Errors::NoSuchKey, } # @api private CACHEABLE_REQUESTS = Set[] include DataOptions include Core::UriEscape # @param [Core::Http::Request] request # @api private def sign_request request case @config.s3_signature_version.to_sym when :v4 then v4_signer.sign_request(request) when :v3 then v3_signer.sign_request(request) else raise "invalid signature version #{@config.s3_signature_version.inspect}" end end protected # @return [Core::Signers::S3] def v3_signer @v3_signer ||= Core::Signers::S3.new(credential_provider) end # @return [Core::Signers::Version4] def v4_signer @v4_signer ||= begin Core::Signers::Version4.new(credential_provider, 's3', @region) end end # @param [Http::Request] req # @return [Boolean] def chunk_sign? req req.http_method == 'PUT' && req.headers['content-length'].to_i > 2 * 1024 * 1024 # 2MB end def self.bucket_method(method_name, verb, *args, &block) method_options = (args.pop if args.last.kind_of?(Hash)) || {} xml_grammar = (args.pop if args.last.respond_to?(:rules)) verb = verb.to_s.upcase subresource = args.first add_client_request_method(method_name) do configure_request do |req, options| require_bucket_name!(options[:bucket_name]) req.http_method = verb req.bucket = options[:bucket_name] req.add_param(subresource) if subresource if header_options = method_options[:header_options] header_options.each do |(opt, header)| if value = options[opt] # for backwards compatability we translate canned acls # header values from symbols to strings (e.g. # :public_read translates to 'public-read') value = (opt == :acl ? value.to_s.tr('_', '-') : value) req.headers[header] = value end end end end instance_eval(&block) if block if xml_grammar parser = Core::XML::Parser.new(xml_grammar.rules) process_response do |resp| resp.data = parser.parse(resp.http_response.body) super(resp) end simulate_response do |resp| resp.data = parser.simulate super(resp) end end end end protected def set_metadata request, options if metadata = options[:metadata] Array(metadata).each do |name, value| request.headers["x-amz-meta-#{name}"] = value end end end def set_storage_class request, options storage_class = options[:storage_class] if storage_class.kind_of?(Symbol) request.headers["x-amz-storage-class"] = storage_class.to_s.upcase elsif storage_class request.headers["x-amz-storage-class"] = storage_class end end def set_server_side_encryption request, options sse = options[:server_side_encryption] if sse.is_a?(Symbol) request.headers['x-amz-server-side-encryption'] = sse.to_s.upcase elsif sse request.headers['x-amz-server-side-encryption'] = sse end end def extract_error_details response if ( response.http_response.status >= 300 || HTTP_200_ERROR_OPERATIONS.include?(response.request_type) ) and body = response.http_response.body and error = Core::XML::Parser.parse(body) and error[:code] then [error[:code], error[:message]] end end def empty_response_body? response_body response_body.nil? or response_body == '' end # There are a few of s3 requests that can generate empty bodies and # yet still be errors. These return empty bodies to comply with the # HTTP spec. We have to detect these errors specially. def populate_error resp code = resp.http_response.status if EMPTY_BODY_ERRORS.include?(code) and empty_response_body?(resp.http_response.body) error_class = EMPTY_BODY_ERRORS[code] resp.error = error_class.new(resp.http_request, resp.http_response) else super end end def retryable_error? response super || http_200_error?(response) || response.error.is_a?(Errors::RequestTimeout) end # S3 may return with a 200 status code in the response, but still # embed an error in the body for the following operations: # # * `#complete_multipart_upload` # * `#copy_object` # * `#copy_part` # # To ensure the response is not in error, we have to parse # it before the normal parser. def http_200_error? response HTTP_200_ERROR_OPERATIONS.include?(response.request_type) && extract_error_details(response) end def new_request req = S3::Request.new req.force_path_style = config.s3_force_path_style? req end # Previously the access control policy could be specified via :acl # as a string or an object that responds to #to_xml. The prefered # method now is to pass :access_control_policy an xml document. def move_access_control_policy options if acl = options[:acl] if acl.is_a?(String) and is_xml?(acl) options[:access_control_policy] = options.delete(:acl) elsif acl.respond_to?(:to_xml) options[:access_control_policy] = options.delete(:acl).to_xml end end end # @param [String] possible_xml # @return [Boolean] Returns `true` if the given string is a valid xml # document. def is_xml? possible_xml begin REXML::Document.new(possible_xml).has_elements? rescue false end end def md5 str Base64.encode64(OpenSSL::Digest::MD5.digest(str)).strip end def parse_copy_part_response resp doc = REXML::Document.new(resp.http_response.body) resp[:etag] = doc.root.elements["ETag"].text resp[:last_modified] = doc.root.elements["LastModified"].text if header = resp.http_response.headers['x-amzn-requestid'] data[:request_id] = [header].flatten.first end end def extract_object_headers resp meta = {} resp.http_response.headers.each_pair do |name,value| if name =~ /^x-amz-meta-(.+)$/i meta[$1] = [value].flatten.join end end resp.data[:meta] = meta if expiry = resp.http_response.headers['x-amz-expiration'] expiry.first =~ /^expiry-date="(.+)", rule-id="(.+)"$/ exp_date = DateTime.parse($1) exp_rule_id = $2 else exp_date = nil exp_rule_id = nil end resp.data[:expiration_date] = exp_date if exp_date resp.data[:expiration_rule_id] = exp_rule_id if exp_rule_id restoring = false restore_date = nil if restore = resp.http_response.headers['x-amz-restore'] if restore.first =~ /ongoing-request="(.+?)", expiry-date="(.+?)"/ restoring = $1 == "true" restore_date = $2 && DateTime.parse($2) elsif restore.first =~ /ongoing-request="(.+?)"/ restoring = $1 == "true" end end resp.data[:restore_in_progress] = restoring resp.data[:restore_expiration_date] = restore_date if restore_date { 'x-amz-version-id' => :version_id, 'content-type' => :content_type, 'content-encoding' => :content_encoding, 'cache-control' => :cache_control, 'expires' => :expires, 'etag' => :etag, 'x-amz-website-redirect-location' => :website_redirect_location, 'accept-ranges' => :accept_ranges, 'x-amz-server-side-encryption-customer-algorithm' => :sse_customer_algorithm, 'x-amz-server-side-encryption-customer-key-MD5' => :sse_customer_key_md5 }.each_pair do |header,method| if value = resp.http_response.header(header) resp.data[method] = value end end if time = resp.http_response.header('Last-Modified') resp.data[:last_modified] = Time.parse(time) end if length = resp.http_response.header('content-length') resp.data[:content_length] = length.to_i end if sse = resp.http_response.header('x-amz-server-side-encryption') resp.data[:server_side_encryption] = sse.downcase.to_sym end end module Validators # @return [Boolean] Returns true if the given bucket name is valid. def valid_bucket_name?(bucket_name) validate_bucket_name!(bucket_name) rescue false end # Returns true if the given `bucket_name` is DNS compatible. # # DNS compatible bucket names may be accessed like: # # http://dns.compat.bucket.name.s3.amazonaws.com/ # # Whereas non-dns compatible bucket names must place the bucket # name in the url path, like: # # http://s3.amazonaws.com/dns_incompat_bucket_name/ # # @return [Boolean] Returns true if the given bucket name may be # is dns compatible. # this bucket n # def dns_compatible_bucket_name?(bucket_name) return false if !valid_bucket_name?(bucket_name) or # Bucket names should be between 3 and 63 characters long bucket_name.size > 63 or # Bucket names must only contain lowercase letters, numbers, dots, and dashes # and must start and end with a lowercase letter or a number bucket_name !~ /^[a-z0-9][a-z0-9.-]+[a-z0-9]$/ or # Bucket names should not be formatted like an IP address (e.g., 192.168.5.4) bucket_name =~ /(\d+\.){3}\d+/ or # Bucket names cannot contain two, adjacent periods bucket_name['..'] or # Bucket names cannot contain dashes next to periods # (e.g., "my-.bucket.com" and "my.-bucket" are invalid) (bucket_name['-.'] || bucket_name['.-']) true end # Returns true if the bucket name must be used in the request # path instead of as a sub-domain when making requests against # S3. # # This can be an issue if the bucket name is DNS compatible but # contains '.' (periods). These cause the SSL certificate to # become invalid when making authenticated requets over SSL to the # bucket name. The solution is to send this as a path argument # instead. # # @return [Boolean] Returns true if the bucket name should be used # as a path segement instead of dns prefix when making requests # against s3. # def path_style_bucket_name? bucket_name if dns_compatible_bucket_name?(bucket_name) bucket_name =~ /\./ ? true : false else true end end def validate! name, value, &block if error_msg = yield raise ArgumentError, "#{name} #{error_msg}" end value end def validate_key!(key) validate!('key', key) do case when key.nil? || key == '' 'may not be blank' end end end def require_bucket_name! bucket_name if [nil, ''].include?(bucket_name) raise ArgumentError, "bucket_name may not be blank" end end # Returns true if the given bucket name is valid. If the name # is invalid, an ArgumentError is raised. def validate_bucket_name!(bucket_name) validate!('bucket_name', bucket_name) do case when bucket_name.nil? || bucket_name == '' 'may not be blank' when bucket_name !~ /^[A-Za-z0-9._\-]+$/ 'may only contain uppercase letters, lowercase letters, numbers, periods (.), ' + 'underscores (_), and dashes (-)' when !(3..255).include?(bucket_name.size) 'must be between 3 and 255 characters long' when bucket_name =~ /\n/ 'must not contain a newline character' end end end def require_policy!(policy) validate!('policy', policy) do case when policy.nil? || policy == '' 'may not be blank' else json_validation_message(policy) end end end def require_acl! options acl_options = [ :acl, :grant_read, :grant_write, :grant_read_acp, :grant_write_acp, :grant_full_control, :access_control_policy, ] unless options.keys.any?{|opt| acl_options.include?(opt) } msg = "missing a required ACL option, must provide an ACL " + "via :acl, :grant_* or :access_control_policy" raise ArgumentError, msg end end def set_body_stream_and_content_length request, options unless options[:content_length] msg = "S3 requires a content-length header, unable to determine " msg << "the content length of the data provided, please set " msg << ":content_length" raise ArgumentError, msg end request.headers['content-length'] = options[:content_length] request.body_stream = options[:data] end def require_upload_id!(upload_id) validate!("upload_id", upload_id) do "must not be blank" if upload_id.to_s.empty? end end def require_part_number! part_number validate!("part_number", part_number) do "must not be blank" if part_number.to_s.empty? end end def validate_parts!(parts) validate!("parts", parts) do if !parts.kind_of?(Array) "must not be blank" elsif parts.empty? "must contain at least one entry" elsif !parts.all? { |p| p.kind_of?(Hash) } "must be an array of hashes" elsif !parts.all? { |p| p[:part_number] } "must contain part_number for each part" elsif !parts.all? { |p| p[:etag] } "must contain etag for each part" elsif parts.any? { |p| p[:part_number].to_i < 1 } "must not have part numbers less than 1" end end end def json_validation_message(obj) if obj.respond_to?(:to_str) obj = obj.to_str elsif obj.respond_to?(:to_json) obj = obj.to_json end error = nil begin JSON.parse(obj) rescue => e error = e end "contains invalid JSON: #{error}" if error end def require_allowed_methods!(allowed_methods) validate!("allowed_methods", allowed_methods) do if !allowed_methods.kind_of?(Array) "must be an array" elsif !allowed_methods.all? { |x| x.kind_of?(String) } "must be an array of strings" end end end def require_allowed_origins!(allowed_origins) validate!("allowed_origins", allowed_origins) do if !allowed_origins.kind_of?(Array) "must be an array" elsif !allowed_origins.all? { |x| x.kind_of?(String) } "must be an array of strings" end end end end include Validators extend Validators end class Client::V20060301 < Client def self.object_method(method_name, verb, *args, &block) bucket_method(method_name, verb, *args) do configure_request do |req, options| validate_key!(options[:key]) super(req, options) req.key = options[:key] end instance_eval(&block) if block end end public # Creates a bucket. # @overload create_bucket(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [String] :acl A canned ACL (e.g. 'private', # 'public-read', etc). See the S3 API documentation for # a complete list of valid values. # @option options [String] :grant_read # @option options [String] :grant_write # @option options [String] :grant_read_acp # @option options [String] :grant_write_acp # @option options [String] :grant_full_control # @return [Core::Response] bucket_method(:create_bucket, :put, :header_options => { :acl => 'x-amz-acl', :grant_read => 'x-amz-grant-read', :grant_write => 'x-amz-grant-write', :grant_read_acp => 'x-amz-grant-read-acp', :grant_write_acp => 'x-amz-grant-write-acp', :grant_full_control => 'x-amz-grant-full-control', }) do configure_request do |req, options| validate_bucket_name!(options[:bucket_name]) if location = options[:location_constraint] xmlns = "http://s3.amazonaws.com/doc/#{API_VERSION}/" req.body = <<-XML #{location} XML end super(req, options) end end alias_method :put_bucket, :create_bucket # @!method put_bucket_website(options = {}) # @param [Hash] options # @option (see WebsiteConfiguration#initialize) # @option options [required,String] :bucket_name # @return [Core::Response] bucket_method(:put_bucket_website, :put, 'website') do configure_request do |req, options| req.body = Nokogiri::XML::Builder.new do |xml| xml.WebsiteConfiguration(:xmlns => XMLNS) do if redirect = options[:redirect_all_requests_to] xml.RedirectAllRequestsTo do xml.HostName(redirect[:host_name]) xml.Protocol(redirect[:protocol]) if redirect[:protocol] end end if indx = options[:index_document] xml.IndexDocument do xml.Suffix(indx[:suffix]) end end if err = options[:error_document] xml.ErrorDocument do xml.Key(err[:key]) end end rules = options[:routing_rules] if rules.is_a?(Array) && !rules.empty? xml.RoutingRules do rules.each do |rule| xml.RoutingRule do redirect = rule[:redirect] xml.Redirect do xml.Protocol(redirect[:protocol]) if redirect[:protocol] xml.HostName(redirect[:host_name]) if redirect[:host_name] xml.ReplaceKeyPrefixWith(redirect[:replace_key_prefix_with]) if redirect[:replace_key_prefix_with] xml.ReplaceKeyWith(redirect[:replace_key_with]) if redirect[:replace_key_with] xml.HttpRedirectCode(redirect[:http_redirect_code]) if redirect[:http_redirect_code] end if condition = rule[:condition] xml.Condition do xml.KeyPrefixEquals(condition[:key_prefix_equals]) if condition[:key_prefix_equals] xml.HttpErrorCodeReturnedEquals(condition[:http_error_code_returned_equals]) if condition[:http_error_code_returned_equals] end end end end end end end end.doc.root.to_xml super(req, options) end end # @overload get_bucket_website(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @return [Core::Response] # * `:index_document` - (Hash) # * `:suffix` - (String) # * `:error_document` - (Hash) # * `:key` - (String) bucket_method(:get_bucket_website, :get, 'website', XML::GetBucketWebsite) # @overload delete_bucket_website(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @return [Core::Response] bucket_method(:delete_bucket_website, :delete, 'website') # Deletes an empty bucket. # @overload delete_bucket(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @return [Core::Response] bucket_method(:delete_bucket, :delete) # @overload set_bucket_lifecycle_configuration(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,String] :lifecycle_configuration # @return [Core::Response] bucket_method(:set_bucket_lifecycle_configuration, :put) do configure_request do |req, options| xml = options[:lifecycle_configuration] req.add_param('lifecycle') req.body = xml req.headers['content-md5'] = md5(xml) super(req, options) end end # @overload get_bucket_lifecycle_configuration(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @return [Core::Response] bucket_method(:get_bucket_lifecycle_configuration, :get) do configure_request do |req, options| req.add_param('lifecycle') super(req, options) end process_response do |resp| xml = resp.http_response.body resp.data = XML::GetBucketLifecycleConfiguration.parse(xml) end end # @overload delete_bucket_lifecycle_configuration(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @return [Core::Response] bucket_method(:delete_bucket_lifecycle_configuration, :delete) do configure_request do |req, options| req.add_param('lifecycle') super(req, options) end end # @overload put_bucket_cors(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,Array] :rules An array of rule hashes. # * `:id` - (String) A unique identifier for the rule. The ID # value can be up to 255 characters long. The IDs help you find # a rule in the configuration. # * `:allowed_methods` - (required,Array) A list of HTTP # methods that you want to allow the origin to execute. # Each rule must identify at least one method. # * `:allowed_origins` - (required,Array) A list of origins # you want to allow cross-domain requests from. This can # contain at most one * wild character. # * `:allowed_headers` - (Array) A list of headers allowed # in a pre-flight OPTIONS request via the # Access-Control-Request-Headers header. Each header name # specified in the Access-Control-Request-Headers header must # have a corresponding entry in the rule. # Amazon S3 will send only the allowed headers in a response # that were requested. This can contain at most one * wild # character. # * `:max_age_seconds` - (Integer) The time in seconds that your # browser is to cache the preflight response for the specified # resource. # * `:expose_headers` - (Array) One or more headers in # the response that you want customers to be able to access # from their applications (for example, from a JavaScript # XMLHttpRequest object). # @return [Core::Response] bucket_method(:put_bucket_cors, :put) do configure_request do |req, options| req.add_param('cors') options[:rules].each do |rule| require_allowed_methods!(rule[:allowed_methods]) require_allowed_origins!(rule[:allowed_origins]) end xml = Nokogiri::XML::Builder.new do |xml| xml.CORSConfiguration do options[:rules].each do |rule| xml.CORSRule do xml.ID(rule[:id]) if rule[:id] (rule[:allowed_methods] || []).each do |method| xml.AllowedMethod(method) end (rule[:allowed_origins] || []).each do |origin| xml.AllowedOrigin(origin) end (rule[:allowed_headers] || []).each do |header| xml.AllowedHeader(header) end xml.MaxAgeSeconds(rule[:max_age_seconds]) if rule[:max_age_seconds] (rule[:expose_headers] || []).each do |header| xml.ExposeHeader(header) end end end end end.doc.root.to_xml req.body = xml req.headers['content-md5'] = md5(xml) super(req, options) end end # @overload get_bucket_cors(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @return [Core::Response] bucket_method(:get_bucket_cors, :get) do configure_request do |req, options| req.add_param('cors') super(req, options) end process_response do |resp| resp.data = XML::GetBucketCors.parse(resp.http_response.body) end end # @overload delete_bucket_cors(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @return [Core::Response] bucket_method(:delete_bucket_cors, :delete) do configure_request do |req, options| req.add_param('cors') super(req, options) end end # @overload put_bucket_tagging(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [Hash] :tags # @return [Core::Response] bucket_method(:put_bucket_tagging, :put) do configure_request do |req, options| req.add_param('tagging') xml = Nokogiri::XML::Builder.new xml.Tagging do |xml| xml.TagSet do options[:tags].each_pair do |key,value| xml.Tag do xml.Key(key) xml.Value(value) end end end end xml = xml.doc.root.to_xml req.body = xml req.headers['content-md5'] = md5(xml) super(req, options) end end # @overload get_bucket_tagging(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @return [Core::Response] bucket_method(:get_bucket_tagging, :get) do configure_request do |req, options| req.add_param('tagging') super(req, options) end process_response do |resp| resp.data = XML::GetBucketTagging.parse(resp.http_response.body) end end # @overload delete_bucket_tagging(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @return [Core::Response] bucket_method(:delete_bucket_tagging, :delete) do configure_request do |req, options| req.add_param('tagging') super(req, options) end end # @overload list_buckets(options = {}) # @param [Hash] options # @return [Core::Response] add_client_request_method(:list_buckets) do configure_request do |req, options| req.http_method = "GET" end process_response do |resp| resp.data = XML::ListBuckets.parse(resp.http_response.body) end simulate_response do |resp| resp.data = Core::XML::Parser.new(XML::ListBuckets.rules).simulate end end # Sets the access policy for a bucket. # @overload set_bucket_policy(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,String] :policy This can be a String # or any object that responds to `#to_json`. # @return [Core::Response] bucket_method(:set_bucket_policy, :put, 'policy') do configure_request do |req, options| require_policy!(options[:policy]) super(req, options) policy = options[:policy] policy = policy.to_json unless policy.respond_to?(:to_str) req.body = policy end end # Gets the access policy for a bucket. # @overload get_bucket_policy(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @return [Core::Response] bucket_method(:get_bucket_policy, :get, 'policy') do process_response do |resp| resp.data[:policy] = resp.http_response.body end end # Deletes the access policy for a bucket. # @overload delete_bucket_policy(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @return [Core::Response] bucket_method(:delete_bucket_policy, :delete, 'policy') # @overload set_bucket_versioning(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,String] :state # @option options [String] :mfa_delete # @option options [String] :mfa # @return [Core::Response] bucket_method(:set_bucket_versioning, :put, 'versioning', :header_options => { :mfa => "x-amz-mfa" }) do configure_request do |req, options| state = options[:state].to_s.downcase.capitalize unless state =~ /^(Enabled|Suspended)$/ raise ArgumentError, "invalid versioning state `#{state}`" end # Leave validation of MFA options to S3 mfa_delete = options[:mfa_delete].to_s.downcase.capitalize if options[:mfa_delete] # Generate XML request for versioning req.body = Nokogiri::XML::Builder.new do |xml| xml.VersioningConfiguration('xmlns' => XMLNS) do xml.Status(state) xml.MfaDelete(mfa_delete) if mfa_delete end end.doc.root.to_xml super(req, options) end end # Gets the bucket's location constraint. # @overload get_bucket_location(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @return [Core::Response] bucket_method(:get_bucket_location, :get, 'location') do process_response do |response| regex = />(.*)<\/LocationConstraint>/ matches = response.http_response.body.to_s.match(regex) response.data[:location_constraint] = matches ? matches[1] : nil end end # @overload put_bucket_logging(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [Boolean] :logging_enabled Set to true if turning on # bucket logging. If not set or false, all of the following options # will be ignored. # @option options [String] :target_bucket The name of the bucket in # which you want Amazon S3 to store server access logs. You can push # logs to any bucket you own, including the bucket being logged. # @option options [String] :target_prefix Allows you to specify a prefix # for the keys that the log files will be stored under. Recommended # if you will be writing logs from multiple buckets to the same target # bucket. # @option options [Array] :grants An array of hashes specifying # permission grantees. For each hash, specify ONLY ONE of :id, :uri, # or :email_address. # * `:email_address` - (String) E-mail address of the person being # granted logging permissions. # * `:id` - (String) The canonical user ID of the grantee. # * `:uri` - (String) URI of the grantee group. # * `:permission` - (String) Logging permissions given to the Grantee # for the bucket. The bucket owner is automatically granted FULL_CONTROL # to all logs delivered to the bucket. This optional element enables # you grant access to others. Valid Values: FULL_CONTROL | READ | WRITE # @return [Core::Response] bucket_method(:put_bucket_logging, :put) do configure_request do |req, options| req.add_param('logging') xml = Nokogiri::XML::Builder.new xml.BucketLoggingStatus('xmlns' => XMLNS) do |xml| if options[:logging_enabled] == true xml.LoggingEnabled do xml.TargetBucket(options[:target_bucket]) xml.TargetPrefix(options[:target_prefix]) unless options[:grants].nil? xml.TargetGrants do options[:grants].each do |grant| xml.Grant do if !grant[:email_address].nil? xml.Grantee('xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:type' => 'AmazonCustomerByEmail') do xml.EmailAddress(grant[:email_address]) end elsif !grant[:uri].nil? xml.Grantee('xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:type' => 'Group') do xml.URI(grant[:uri]) end elsif !grant[:id].nil? xml.Grantee('xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:type' => 'CanonicalUser') do xml.ID(grant[:id]) end end xml.Permission(grant[:permission]) end end end end end end end xml = xml.doc.root.to_xml req.body = xml req.headers['content-md5'] = md5(xml) super(req, options) end end # Gets the bucket's logging status. # @overload get_bucket_logging(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @return [Core::Response] bucket_method(:get_bucket_logging, :get, 'logging', XML::GetBucketLogging) # @overload get_bucket_versioning(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @return [Core::Response] bucket_method(:get_bucket_versioning, :get, 'versioning', XML::GetBucketVersioning) # @overload list_object_versions(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [String] :prefix # @option options [String] :delimiter # @option options [String] :max_keys # @option options [String] :key_marker # @option options [String] :version_id_marker # @return [Core::Response] bucket_method(:list_object_versions, :get, 'versions', XML::ListObjectVersions) do configure_request do |req, options| super(req, options) params = %w(delimiter key_marker max_keys prefix version_id_marker) params.each do |param| if options[param.to_sym] req.add_param(param.gsub(/_/, '-'), options[param.to_sym]) end end end end # Sets the access control list for a bucket. You must specify an ACL # via one of the following methods: # # * as a canned ACL (via `:acl`) # * as a list of grants (via the `:grant_*` options) # * as an access control policy document (via `:access_control_policy`) # # @example Using a canned acl # s3_client.put_bucket_acl( # :bucket_name => 'bucket-name', # :acl => 'public-read') # # @example Using grants # s3_client.put_bucket_acl( # :bucket_name => 'bucket-name', # :grant_read => 'uri="http://acs.amazonaws.com/groups/global/AllUsers"', # :grant_full_control => 'emailAddress="xyz@amazon.com", id="8a9...fa7"') # # @example Using an access control policy document # policy_xml = <<-XML # # # 852b113e7a2f25102679df27bb0ae12b3f85be6BucketOwnerCanonicalUserID # OwnerDisplayName # # # # # BucketOwnerCanonicalUserID # OwnerDisplayName # # FULL_CONTROL # # # # http://acs.amazonaws.com/groups/global/AllUsers # # READ # # # # # XML # s3_client.put_bucket_acl( # :bucket_name => 'bucket-name', # :access_control_policy => policy_xml) # # @overload put_bucket_acl(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [String] :access_control_policy An access control # policy description as a string of XML. See the S3 API # documentation for a description. # @option options [String] :acl A canned ACL (e.g. 'private', # 'public-read', etc). See the S3 API documentation for # a complete list of valid values. # @option options [String] :grant_read # @option options [String] :grant_write # @option options [String] :grant_read_acp # @option options [String] :grant_write_acp # @option options [String] :grant_full_control # @return [Core::Response] bucket_method(:put_bucket_acl, :put, 'acl', :header_options => { :acl => 'x-amz-acl', :grant_read => 'x-amz-grant-read', :grant_write => 'x-amz-grant-write', :grant_read_acp => 'x-amz-grant-read-acp', :grant_write_acp => 'x-amz-grant-write-acp', :grant_full_control => 'x-amz-grant-full-control', }) do configure_request do |req, options| move_access_control_policy(options) require_acl!(options) super(req, options) req.body = options[:access_control_policy] if options[:access_control_policy] end end alias_method :set_bucket_acl, :put_bucket_acl # Gets the access control list for a bucket. # @overload get_bucket_acl(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @return [Core::Response] bucket_method(:get_bucket_acl, :get, 'acl', XML::GetBucketAcl) # Sets the access control list for an object. You must specify an ACL # via one of the following methods: # # * as a canned ACL (via `:acl`) # * as a list of grants (via the `:grant_*` options) # * as an access control policy document (via `:access_control_policy`) # # @example Using a canned acl # s3_client.put_object_acl( # :bucket_name => 'bucket-name', # :key => 'object-key', # :acl => 'public-read') # # @example Using grants # s3_client.put_bucket_acl( # :bucket_name => 'bucket-name', # :key => 'object-key', # :grant_read => 'uri="http://acs.amazonaws.com/groups/global/AllUsers"', # :grant_full_control => 'emailAddress="xyz@amazon.com", id="8a9...fa7"') # # @example Using an access control policy document # policy_xml = <<-XML # # # 852b113e7a2f25102679df27bb0ae12b3f85be6BucketOwnerCanonicalUserID # OwnerDisplayName # # # # # BucketOwnerCanonicalUserID # OwnerDisplayName # # FULL_CONTROL # # # # http://acs.amazonaws.com/groups/global/AllUsers # # READ # # # # # XML # s3_client.put_bucket_acl( # :bucket_name => 'bucket-name', # :key => 'object-key', # :access_control_policy => policy_xml) # # @overload put_object_acl(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,String] :key # @option options [String] :access_control_policy An access control # policy description as a string of XML. See the S3 API # documentation for a description. # @option options [String] :acl A canned ACL (e.g. 'private', # 'public-read', etc). See the S3 API documentation for # a complete list of valid values. # @option options [String] :grant_read # @option options [String] :grant_write # @option options [String] :grant_read_acp # @option options [String] :grant_write_acp # @option options [String] :grant_full_control # @return [Core::Response] object_method(:put_object_acl, :put, 'acl', :header_options => { :acl => 'x-amz-acl', :grant_read => 'x-amz-grant-read', :grant_write => 'x-amz-grant-write', :grant_read_acp => 'x-amz-grant-read-acp', :grant_write_acp => 'x-amz-grant-write-acp', :grant_full_control => 'x-amz-grant-full-control', }) do configure_request do |req, options| move_access_control_policy(options) require_acl!(options) super(req, options) req.body = options[:access_control_policy] if options[:access_control_policy] end end alias_method :set_object_acl, :put_object_acl # Gets the access control list for an object. # @overload get_object_acl(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,String] :key # @return [Core::Response] object_method(:get_object_acl, :get, 'acl', XML::GetBucketAcl) # Puts data into an object, replacing the current contents. # # s3_client.put_object({ # :bucket_name => 'bucket-name', # :key => 'readme.txt', # :data => 'This is the readme for ...', # }) # # @overload put_object(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,String] :key # @option options [required,String,Pathname,File,IO] :data # The data to upload. This can be provided as a string, # a Pathname object, or any object that responds to # `#read` and `#eof?` (e.g. IO, File, Tempfile, StringIO, etc). # @option options [Integer] :content_length # Required if you are using block form to write data or if it is # not possible to determine the size of `:data`. A best effort # is made to determine the content length of strings, files, # tempfiles, io objects, and any object that responds # to `#length` or `#size`. # @option options [String] :website_redirect_location If the bucket is # configured as a website, redirects requests for this object to # another object in the same bucket or to an external URL. # @option options [Hash] :metadata # A hash of metadata to be included with the # object. These will be sent to S3 as headers prefixed with # `x-amz-meta`. # @option options [Symbol] :acl (:private) A canned access # control policy. Accepted values include: # * `:private` # * `:public_read` # * ... # @option options [String] :storage_class+ ('STANDARD') # Controls whether Reduced Redundancy Storage is enabled for # the object. Valid values are 'STANDARD' and # 'REDUCED_REDUNDANCY'. # @option options [Symbol,String] :server_side_encryption (nil) The # algorithm used to encrypt the object on the server side # (e.g. :aes256). # object on the server side, e.g. `:aes256`) # @option options [String] :cache_control # Can be used to specify caching behavior. # @option options [String] :content_disposition # Specifies presentational information. # @option options [String] :content_encoding # Specifies the content encoding. # @option options [String] :content_md5 # The base64 encoded content md5 of the `:data`. # @option options [String] :content_type # Specifies the content type. # @option options [String] :expires The date and time at which the # object is no longer cacheable. # @option options [String] :acl A canned ACL (e.g. 'private', # 'public-read', etc). See the S3 API documentation for # a complete list of valid values. # @option options [String] :grant_read # @option options [String] :grant_write # @option options [String] :grant_read_acp # @option options [String] :grant_write_acp # @option options [String] :grant_full_control # @option options [String] :sse_customer_algorithm Specifies the # algorithm to use to when encrypting the object (e.g., AES256). # @option options [String] :sse_customer_key Specifies the # customer-provided encryption key for Amazon S3 to use in encrypting # data. This value is used to store the object and then it is # discarded; Amazon does not store the encryption key. The key must be # appropriate for use with the algorithm specified in the # `:sse_customer_algorithm` header. # @option options [String] :sse_customer_key_md5 Specifies the 128-bit # MD5 digest of the encryption key according to RFC 1321. Amazon S3 # uses this header for a message integrity check to ensure the # encryption key was transmitted without error. # @return [Core::Response] # object_method(:put_object, :put, :header_options => { :website_redirect_location => 'x-amz-website-redirect-location', :acl => 'x-amz-acl', :grant_read => 'x-amz-grant-read', :grant_write => 'x-amz-grant-write', :grant_read_acp => 'x-amz-grant-read-acp', :grant_write_acp => 'x-amz-grant-write-acp', :grant_full_control => 'x-amz-grant-full-control', :content_md5 => 'Content-MD5', :cache_control => 'Cache-Control', :content_disposition => 'Content-Disposition', :content_encoding => 'Content-Encoding', :content_type => 'Content-Type', :expires => 'Expires', :sse_customer_algorithm => 'x-amz-server-side-encryption-customer-algorithm', :sse_customer_key => 'x-amz-server-side-encryption-customer-key', :sse_customer_key_md5 => 'x-amz-server-side-encryption-customer-key-MD5', }) do configure_request do |request, options| options = compute_write_options(options) set_body_stream_and_content_length(request, options) set_metadata(request, options) set_storage_class(request, options) set_server_side_encryption(request, options) super(request, options) end process_response do |resp| extract_object_headers(resp) end simulate_response do |response| response.data[:etag] = 'abc123' response.data[:version_id] = nil end end # Gets the data for a key. # @overload get_object(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,String] :key # @option options [String] :request_payer If specified, the request # will contain the specified String value in the x-amz-request-payer # header. This is required for Requester Pays enabled buckets. # @option options [Time] :if_modified_since If specified, the # response will contain an additional `:modified` value that # returns true if the object was modified after the given # time. If `:modified` is false, then the response # `:data` value will be `nil`. # @option options [Time] :if_unmodified_since If specified, the # response will contain an additional `:unmodified` value # that is true if the object was not modified after the # given time. If `:unmodified` returns false, the `:data` # value will be `nil`. # @option options [String] :if_match If specified, the response # will contain an additional `:matches` value that is true # if the object ETag matches the value for this option. If # `:matches` is false, the `:data` value of the # response will be `nil`. # @option options [String] :if_none_match If specified, the # response will contain an additional `:matches` value that # is true if and only if the object ETag matches the value for # this option. If `:matches` is true, the `:data` value # of the response will be `nil`. # @option options [String] :sse_customer_algorithm Specifies the # algorithm to use to when encrypting the object (e.g., AES256). # @option options [String] :sse_customer_key Specifies the # customer-provided encryption key for Amazon S3 to use in encrypting # data. This value is used to store the object and then it is # discarded; Amazon does not store the encryption key. The key must be # appropriate for use with the algorithm specified in the # `:sse_customer_algorithm` header. # @option options [String] :sse_customer_key_md5 Specifies the 128-bit # MD5 digest of the encryption key according to RFC 1321. Amazon S3 # uses this header for a message integrity check to ensure the # encryption key was transmitted without error. # @option options [Range] :range A byte range of data to request. # @return [Core::Response] # object_method(:get_object, :get, :header_options => { :request_payer => "x-amz-request-payer", :if_modified_since => "If-Modified-Since", :if_unmodified_since => "If-Unmodified-Since", :if_match => "If-Match", :if_none_match => "If-None-Match", :sse_customer_algorithm => 'x-amz-server-side-encryption-customer-algorithm', :sse_customer_key => 'x-amz-server-side-encryption-customer-key', :sse_customer_key_md5 => 'x-amz-server-side-encryption-customer-key-MD5', }) do configure_request do |req, options| super(req, options) if options[:version_id] req.add_param('versionId', options[:version_id]) end ["If-Modified-Since", "If-Unmodified-Since"].each do |date_header| case value = req.headers[date_header] when DateTime req.headers[date_header] = Time.parse(value.to_s).rfc2822 when Time req.headers[date_header] = value.rfc2822 end end if options[:range] range = options[:range] if range.is_a?(Range) offset = range.exclude_end? ? -1 : 0 range = "bytes=#{range.first}-#{range.last + offset}" end req.headers['Range'] = range end end process_response do |resp| extract_object_headers(resp) resp.data[:data] = resp.http_response.body end end # Gets the torrent for a key. # @overload get_object_torrent(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,String] :key # @return [Core::Response] # object_method(:get_object_torrent, :get, 'torrent') do process_response do |resp| extract_object_headers(resp) resp.data[:data] = resp.http_response.body end end # @overload head_object(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,String] :key # @option options [String] :version_id # @option options [Time] :if_modified_since If specified, the # response will contain an additional `:modified` value that # returns true if the object was modified after the given # time. If `:modified` is false, then the response # `:data` value will be `nil`. # @option options [Time] :if_unmodified_since If specified, the # response will contain an additional `:unmodified` value # that is true if the object was not modified after the # given time. If `:unmodified` returns false, the `:data` # value will be `nil`. # @option options [String] :if_match If specified, the response # will contain an additional `:matches` value that is true # if the object ETag matches the value for this option. If # `:matches` is false, the `:data` value of the # response will be `nil`. # @option options [String] :if_none_match If specified, the # response will contain an additional `:matches` value that # is true if and only if the object ETag matches the value for # this option. If `:matches` is true, the `:data` value # of the response will be `nil`. # @option options [String] :sse_customer_algorithm Specifies the # algorithm to use to when encrypting the object (e.g., AES256). # @option options [String] :sse_customer_key Specifies the # customer-provided encryption key for Amazon S3 to use in encrypting # data. This value is used to store the object and then it is # discarded; Amazon does not store the encryption key. The key must be # appropriate for use with the algorithm specified in the # `:sse_customer_algorithm` header. # @option options [String] :sse_customer_key_md5 Specifies the 128-bit # MD5 digest of the encryption key according to RFC 1321. Amazon S3 # uses this header for a message integrity check to ensure the # encryption key was transmitted without error. # @option options [Range] :range A byte range of data to request. # @return [Core::Response] object_method(:head_object, :head, :header_options => { :if_modified_since => "If-Modified-Since", :if_unmodified_since => "If-Unmodified-Since", :if_match => "If-Match", :if_none_match => "If-None-Match", :sse_customer_algorithm => 'x-amz-server-side-encryption-customer-algorithm', :sse_customer_key => 'x-amz-server-side-encryption-customer-key', :sse_customer_key_md5 => 'x-amz-server-side-encryption-customer-key-MD5', }) do configure_request do |req, options| super(req, options) if options[:version_id] req.add_param('versionId', options[:version_id]) end ["If-Modified-Since", "If-Unmodified-Since"].each do |date_header| case value = req.headers[date_header] when DateTime req.headers[date_header] = Time.parse(value.to_s).rfc2822 when Time req.headers[date_header] = value.rfc2822 end end if options[:range] range = options[:range] if range.is_a?(Range) offset = range.exclude_end? ? -1 : 0 range = "bytes=#{range.first}-#{range.last + offset}" end req.headers['Range'] = range end end process_response do |resp| extract_object_headers(resp) end end # @overload delete_object(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,String] :key # @option options [String] :version_id # @option options [String] :mfa # @return [Core::Response] object_method(:delete_object, :delete, :header_options => { :mfa => "x-amz-mfa" }) do configure_request do |req, options| super(req, options) if options[:version_id] req.add_param('versionId', options[:version_id]) end end process_response do |resp| resp.data[:version_id] = resp.http_response.header('x-amz-version-id') end end # @overload restore_object(options = {}) # Restores a temporary copy of an archived object. # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,String] :key # @option options [required,Integer] :days the number of days to keep # the restored object. # @return [Core::Response] # @since 1.7.2 object_method(:restore_object, :post, 'restore', :header_options => { :content_md5 => 'Content-MD5' }) do configure_request do |req, options| super(req, options) validate!(:days, options[:days]) do "must be greater or equal to 1" if options[:days].to_i <= 0 end xml = Nokogiri::XML::Builder.new do |xml| xml.RestoreRequest('xmlns' => XMLNS) do xml.Days(options[:days].to_i) if options[:days] end end.doc.root.to_xml req.body = xml req.headers['content-type'] = 'application/xml' req.headers['content-md5'] = md5(xml) end end # @overload list_objects(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [String] :delimiter # @option options [String] :marker # @option options [String] :max_keys # @option options [String] :prefix # @return [Core::Response] bucket_method(:list_objects, :get, XML::ListObjects) do configure_request do |req, options| super(req, options) params = %w(delimiter marker max_keys prefix) params.each do |param| if options[param.to_sym] req.add_param(param.gsub(/_/, '-'), options[param.to_sym]) end end end end alias_method :get_bucket, :list_objects # @overload initiate_multipart_upload(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,String] :key # @option options [String] :website_redirect_location If the bucket is # configured as a website, redirects requests for this object to # another object in the same bucket or to an external URL. # @option options [Hash] :metadata # @option options [Symbol] :acl # @option options [String] :cache_control # @option options [String] :content_disposition # @option options [String] :content_encoding # @option options [String] :content_type # @option options [String] :storage_class+ ('STANDARD') # Controls whether Reduced Redundancy Storage is enabled for # the object. Valid values are 'STANDARD' and # 'REDUCED_REDUNDANCY'. # @option options [Symbol,String] :server_side_encryption (nil) The # algorithm used to encrypt the object on the server side # (e.g. :aes256). # @option options [String] :expires The date and time at which the # object is no longer cacheable. # @option options [String] :acl A canned ACL (e.g. 'private', # 'public-read', etc). See the S3 API documentation for # a complete list of valid values. # @option options [String] :grant_read # @option options [String] :grant_write # @option options [String] :grant_read_acp # @option options [String] :grant_write_acp # @option options [String] :grant_full_control # @option options [String] :sse_customer_algorithm Specifies the # algorithm to use to when encrypting the object (e.g., AES256). # @option options [String] :sse_customer_key Specifies the # customer-provided encryption key for Amazon S3 to use in encrypting # data. This value is used to store the object and then it is # discarded; Amazon does not store the encryption key. The key must be # appropriate for use with the algorithm specified in the # `:sse_customer_algorithm` header. # @option options [String] :sse_customer_key_md5 Specifies the 128-bit # MD5 digest of the encryption key according to RFC 1321. Amazon S3 # uses this header for a message integrity check to ensure the # encryption key was transmitted without error. # @return [Core::Response] object_method(:initiate_multipart_upload, :post, 'uploads', XML::InitiateMultipartUpload, :header_options => { :website_redirect_location => 'x-amz-website-redirect-location', :acl => 'x-amz-acl', :grant_read => 'x-amz-grant-read', :grant_write => 'x-amz-grant-write', :grant_read_acp => 'x-amz-grant-read-acp', :grant_write_acp => 'x-amz-grant-write-acp', :grant_full_control => 'x-amz-grant-full-control', :cache_control => 'Cache-Control', :content_disposition => 'Content-Disposition', :content_encoding => 'Content-Encoding', :content_type => 'Content-Type', :expires => 'Expires', :sse_customer_algorithm => 'x-amz-server-side-encryption-customer-algorithm', :sse_customer_key => 'x-amz-server-side-encryption-customer-key', :sse_customer_key_md5 => 'x-amz-server-side-encryption-customer-key-MD5', }) do configure_request do |req, options| set_metadata(req, options) set_storage_class(req, options) set_server_side_encryption(req, options) super(req, options) end process_response do |resp| extract_object_headers(resp) end end # @overload list_multipart_uploads(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [String] :delimiter # @option options [String] :key_marker # @option options [String] :max_keys # @option options [String] :upload_id_marker # @option options [String] :max_uploads # @option options [String] :prefix # @return [Core::Response] bucket_method(:list_multipart_uploads, :get, 'uploads', XML::ListMultipartUploads) do configure_request do |req, options| super(req, options) params = %w(delimiter key_marker max_keys) + %w(upload_id_marker max_uploads prefix) params.each do |param| if options[param.to_sym] req.add_param(param.gsub(/_/, '-'), options[param.to_sym]) end end end end # @overload delete_objects(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,Array] :objects Each entry should be # a hash with the following keys: # * `:key` - *required* # * `:version_id` # @option options [Boolean] :quiet (true) # @option options [String] :mfa # @return [Core::Response] bucket_method(:delete_objects, :post, 'delete', XML::DeleteObjects, :header_options => { :mfa => "x-amz-mfa" } ) do configure_request do |req, options| super(req, options) req.body = Nokogiri::XML::Builder.new do |xml| xml.Delete do xml.Quiet(options.key?(:quiet) ? options[:quiet] : true) (options[:objects] || options[:keys]).each do |obj| xml.Object do xml.Key(obj[:key]) xml.VersionId(obj[:version_id]) if obj[:version_id] end end end end.doc.root.to_xml req.headers['content-md5'] = md5(req.body) end end # @overload upload_part(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,String] :key # @option options [required,String] :upload_id # @option options [required,Integer] :part_number # @option options [required,String,Pathname,File,IO] :data # The data to upload. This can be provided as a string, # a Pathname object, or any object that responds to # `#read` and `#eof?` (e.g. IO, File, Tempfile, StringIO, etc). # @return [Core::Response] object_method(:upload_part, :put, :header_options => { :content_md5 => 'Content-MD5', :sse_customer_algorithm => 'x-amz-server-side-encryption-customer-algorithm', :sse_customer_key => 'x-amz-server-side-encryption-customer-key', :sse_customer_key_md5 => 'x-amz-server-side-encryption-customer-key-MD5', }) do configure_request do |request, options| options = compute_write_options(options) set_body_stream_and_content_length(request, options) require_upload_id!(options[:upload_id]) request.add_param('uploadId', options[:upload_id]) require_part_number!(options[:part_number]) request.add_param('partNumber', options[:part_number]) super(request, options) end process_response do |resp| extract_object_headers(resp) end simulate_response do |response| response.data[:etag] = 'abc123' end end # @overload complete_multipart_upload(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,String] :key # @option options [required,String] :upload_id # @option options [required,Array] :parts An array of hashes # with the following keys: # * `:part_number` [Integer] - *required* # * `:etag` [String] - *required* # @return [Core::Response] object_method(:complete_multipart_upload, :post, XML::CompleteMultipartUpload) do configure_request do |req, options| require_upload_id!(options[:upload_id]) validate_parts!(options[:parts]) super(req, options) req.add_param('uploadId', options[:upload_id]) req.body = Nokogiri::XML::Builder.new do |xml| xml.CompleteMultipartUpload do options[:parts].each do |part| xml.Part do xml.PartNumber(part[:part_number]) xml.ETag(part[:etag]) end end end end.doc.root.to_xml end process_response do |resp| extract_object_headers(resp) end simulate_response do |response| response.data = {} end end # @overload abort_multipart_upload(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,String] :key # @option options [required,String] :upload_id # @return [Core::Response] object_method(:abort_multipart_upload, :delete) do configure_request do |req, options| require_upload_id!(options[:upload_id]) super(req, options) req.add_param('uploadId', options[:upload_id]) end end # @overload list_parts(options = {}) # @param [Hash] options # @option options [required,String] :bucket_name # @option options [required,String] :key # @option options [required,String] :upload_id # @option options [Integer] :max_parts # @option options [Integer] :part_number_marker # @return [Core::Response] object_method(:list_parts, :get, XML::ListParts) do configure_request do |req, options| require_upload_id!(options[:upload_id]) super(req, options) req.add_param('uploadId', options[:upload_id]) req.add_param('max-parts', options[:max_parts]) req.add_param('part-number-marker', options[:part_number_marker]) end end # Copies an object from one key to another. # @overload copy_object(options = {}) # @param [Hash] options # @option options [required, String] :bucket_name Name of the bucket # to copy a object into. # @option options [required, String] :key Where (object key) in the # bucket the object should be copied to. # @option options [String] :website_redirect_location If the bucket is # configured as a website, redirects requests for this object to # another object in the same bucket or to an external URL. # @option options [required, String] :copy_source The source # bucket name and key, joined by a forward slash ('/'). # This string must be URL-encoded. Additionally, you must # have read access to the source object. # @option options [String] :acl A canned ACL (e.g. 'private', # 'public-read', etc). See the S3 API documentation for # a complete list of valid values. # @option options [Symbol,String] :server_side_encryption (nil) The # algorithm used to encrypt the object on the server side # (e.g. :aes256). # @option options [String] :storage_class+ ('STANDARD') # Controls whether Reduced Redundancy Storage is enabled for # the object. Valid values are 'STANDARD' and # 'REDUCED_REDUNDANCY'. # @option options [String] :metadata_directive ('COPY') Specify 'COPY' or # 'REPLACE'. # @option options [String] :content_type # @option options [String] :content_encoding # @option options [String] :content_disposition # @option options [String] :cache_control # @option options [String] :expires The date and time at which the # object is no longer cacheable. # @option options [String] :grant_read # @option options [String] :grant_write # @option options [String] :grant_read_acp # @option options [String] :grant_write_acp # @option options [String] :grant_full_control # @option options [String] :sse_customer_algorithm Specifies the # algorithm to use to when encrypting the object (e.g., AES256). # @option options [String] :sse_customer_key Specifies the # customer-provided encryption key for Amazon S3 to use in encrypting # data. This value is used to store the object and then it is # discarded; Amazon does not store the encryption key. The key must be # appropriate for use with the algorithm specified in the # `:sse_customer_algorithm` header. # @option options [String] :sse_customer_key_md5 Specifies the 128-bit # MD5 digest of the encryption key according to RFC 1321. Amazon S3 # uses this header for a message integrity check to ensure the # encryption key was transmitted without error. # @option options [String] :copy_source_sse_customer_algorithm Specifies # the algorithm to use when decrypting the source object (e.g., # AES256). # @option options [String] :copy_source_sse_customer_key Specifies the # customer-provided encryption key for Amazon S3 to use to decrypt the # source object. The encryption key provided in this header must be # one that was used when the source object was created. # @option options [String] :copy_source_sse_customer_key_md5 Specifies # the 128-bit MD5 digest of the encryption key according to RFC 1321. # Amazon S3 uses this header for a message integrity check to ensure # the encryption key was transmitted without error. # @return [Core::Response] object_method(:copy_object, :put, :header_options => { :website_redirect_location => 'x-amz-website-redirect-location', :acl => 'x-amz-acl', :grant_read => 'x-amz-grant-read', :grant_write => 'x-amz-grant-write', :grant_read_acp => 'x-amz-grant-read-acp', :grant_write_acp => 'x-amz-grant-write-acp', :grant_full_control => 'x-amz-grant-full-control', :copy_source => 'x-amz-copy-source', :cache_control => 'Cache-Control', :metadata_directive => 'x-amz-metadata-directive', :content_type => 'Content-Type', :content_encoding => 'Content-Encoding', :content_disposition => 'Content-Disposition', :expires => 'Expires', :sse_customer_algorithm => 'x-amz-server-side-encryption-customer-algorithm', :sse_customer_key => 'x-amz-server-side-encryption-customer-key', :sse_customer_key_md5 => 'x-amz-server-side-encryption-customer-key-MD5', :copy_source_sse_customer_algorithm => 'x-amz-copy-source-server-side-encryption-customer-algorithm', :copy_source_sse_customer_key => 'x-amz-copy-source-server-side-encryption-customer-key', :copy_source_sse_customer_key_md5 => 'x-amz-copy-source-server-side-encryption-customer-key-MD5', }) do configure_request do |req, options| validate!(:copy_source, options[:copy_source]) do "may not be blank" if options[:copy_source].to_s.empty? end options = options.merge(:copy_source => escape_path(options[:copy_source])) super(req, options) set_metadata(req, options) set_storage_class(req, options) set_server_side_encryption(req, options) if options[:version_id] req.headers['x-amz-copy-source'] += "?versionId=#{options[:version_id]}" end end process_response do |resp| extract_object_headers(resp) end end object_method(:copy_part, :put, XML::CopyPart, :header_options => { :copy_source => 'x-amz-copy-source', :copy_source_range => 'x-amz-copy-source-range', }) do configure_request do |request, options| validate!(:copy_source, options[:copy_source]) do "may not be blank" if options[:copy_source].to_s.empty? end validate!(:copy_source_range, options[:copy_source_range]) do "must start with bytes=" if options[:copy_source_range] && !options[:copy_source_range].start_with?("bytes=") end options = options.merge(:copy_source => escape_path(options[:copy_source])) require_upload_id!(options[:upload_id]) request.add_param('uploadId', options[:upload_id]) require_part_number!(options[:part_number]) request.add_param('partNumber', options[:part_number]) super(request, options) if options[:version_id] req.headers['x-amz-copy-source'] += "?versionId=#{options[:version_id]}" end end end end end end aws-sdk-v1-1.66.0/lib/aws/s3/cipher_io.rb0000644000004100000410000000654512604445426017725 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # @api private class CipherIO def initialize cipher, stream, stream_size = nil @stream = stream @stream_size = stream_size @orig_cipher = cipher.clone reset_cipher # add a #rewind method if the original stream can be rewound if @stream.respond_to?(:rewind) Core::MetaUtils.extend_method(self, :rewind) do reset_cipher @stream.rewind end end # add a #size method if the stream size is known if stream_size Core::MetaUtils.extend_method(self, :size) do EncryptionUtils.get_encrypted_size(@stream_size) end end end # @return [String] Returns the requested number of bytes. If no byte # amount is given, it will return the entire body of encrypted data def read bytes = nil, output_buffer = nil data = if bytes (@eof) ? nil : read_chunk(bytes) else (@eof) ? "" : read_all end output_buffer ? output_buffer.replace(data || '') : data end # @return [Boolean] Returns `true` when the entire stream has been read. def eof? @eof end private attr_reader :cipher # Sets the CipherIO in a reset state without having to know anything # about the cipher def reset_cipher @cipher = @orig_cipher.clone @eof = false @final = nil end # @return [String] Returns an encrytped chunk def read_chunk bytes unless @final # If given a number of bytes, read it out and work out encryption # issues chunk = @stream.read(bytes) # If there is nothing, finish the encryption if chunk and chunk.length > 0 handle_finish(bytes, cipher.update(chunk)) else @eof = true cipher.final end # Read as much as possible if not given a byte size else @eof = true @final end end # @return [String] Returns the entire encrypted data def read_all @eof = true body = @stream.read() data = (body and body.length > 0) ? cipher.update(body) : "" data << cipher.final end # Figures out how much of the final block goes into the current chunk # and adds it. # @return [String] Returns the encrypted chunk with possible padding. def handle_finish(bytes, chunk) free_space = bytes - chunk.size if free_space > 0 @final = cipher.final chunk << @final[0..free_space-1] @final = @final[free_space..@final.size-1] @eof = true unless @final and @final.size > 0 end chunk end end end end aws-sdk-v1-1.66.0/lib/aws/s3/request.rb0000644000004100000410000000267212604445426017451 0ustar www-datawww-data# Copyright 2011-2013 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 'uri' require 'time' module AWS class S3 # @api private class Request < Core::Http::Request include Core::UriEscape # @return [bucket] S3 bucket name attr_accessor :bucket # @return [String] S3 object key attr_accessor :key # @api private attr_accessor :force_path_style def host path_style? ? @host : "#{bucket}.#{@host}" end def path_style? if force_path_style true else Client.path_style_bucket_name?(bucket) end end def uri parts = [] parts << bucket if bucket and path_style? parts << escape_path(key) if key path = '/' + parts.join('/') querystring = url_encoded_params uri = '' uri << path uri << "?#{querystring}" if querystring uri end end end end aws-sdk-v1-1.66.0/lib/aws/s3/s3_object.rb0000644000004100000410000017751712604445426017647 0ustar www-datawww-data# Copyright 2011-2013 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 'uri' require 'base64' module AWS class S3 # Represents an object in S3. Objects live in a bucket and have # unique keys. # # # Getting Objects # # You can get an object by its key. # # s3 = AWS::S3.new # obj = s3.buckets['my-bucket'].objects['key'] # no request made # # You can also get objects by enumerating a objects in a bucket. # # bucket.objects.each do |obj| # puts obj.key # end # # See {ObjectCollection} for more information on finding objects. # # # Creating Objects # # You create an object by writing to it. The following two # expressions are equivalent. # # obj = bucket.objects.create('key', 'data') # obj = bucket.objects['key'].write('data') # # # Writing Objects # # To upload data to S3, you simply need to call {#write} on an object. # # obj.write('Hello World!') # obj.read # #=> 'Hello World!' # # ## Uploading Files # # You can upload a file to S3 in a variety of ways. Given a path # to a file (as a string) you can do any of the following: # # # specify the data as a path to a file # obj.write(Pathname.new(path_to_file)) # # # also works this way # obj.write(:file => path_to_file) # # # Also accepts an open file object # file = File.open(path_to_file, 'rb') # obj.write(file) # # All three examples above produce the same result. The file # will be streamed to S3 in chunks. It will not be loaded # entirely into memory. # # ## Streaming Uploads # # When you call {#write} with an IO-like object, it will be streamed # to S3 in chunks. # # While it is possible to determine the size of many IO objects, you may # have to specify the :content_length of your IO object. # If the exact size can not be known, you may provide an # `:estimated_content_length`. Depending on the size (actual or # estimated) of your data, it will be uploaded in a single request or # in multiple requests via {#multipart_upload}. # # You may also stream uploads to S3 using a block: # # obj.write do |buffer, bytes| # # writing fewer than the requested number of bytes to the buffer # # will cause write to stop yielding to the block # end # # # Reading Objects # # You can read an object directly using {#read}. Be warned, this will # load the entire object into memory and is not recommended for large # objects. # # obj.write('abc') # puts obj.read # #=> abc # # ## Streaming Downloads # # If you want to stream an object from S3, you can pass a block # to {#read}. # # File.open('output', 'wb') do |file| # large_object.read do |chunk| # file.write(chunk) # end # end # # # Encryption # # Amazon S3 can encrypt objects for you service-side. You can also # use client-side encryption. # # ## Server Side Encryption # # You can specify to use server side encryption when writing an object. # # obj.write('data', :server_side_encryption => :aes256) # # You can also make this the default behavior. # # AWS.config(:s3_server_side_encryption => :aes256) # # s3 = AWS::S3.new # s3.buckets['name'].objects['key'].write('abc') # will be encrypted # # ## Client Side Encryption # # Client side encryption utilizes envelope encryption, so that your keys are # never sent to S3. You can use a symetric key or an asymmetric # key pair. # # ### Symmetric Key Encryption # # An AES key is used for symmetric encryption. The key can be 128, 192, # and 256 bit sizes. Start by generating key or read a previously # generated key. # # # generate a new random key # my_key = OpenSSL::Cipher.new("AES-256-ECB").random_key # # # read an existing key from disk # my_key = File.read("my_key.der") # # Now you can encrypt locally and upload the encrypted data to S3. # To do this, you need to provide your key. # # obj = bucket.objects["my-text-object"] # # # encrypt then upload data # obj.write("MY TEXT", :encryption_key => my_key) # # # try read the object without decrypting, oops # obj.read # #=> '.....' # # Lastly, you can download and decrypt by providing the same key. # # obj.read(:encryption_key => my_key) # #=> "MY TEXT" # # ### Asymmetric Key Pair # # A RSA key pair is used for asymmetric encryption. The public key is used # for encryption and the private key is used for decryption. Start # by generating a key. # # my_key = OpenSSL::PKey::RSA.new(1024) # # Provide your key to #write and the data will be encrypted before it # is uploaded. Pass the same key to #read to decrypt the data # when you download it. # # obj = bucket.objects["my-text-object"] # # # encrypt and upload the data # obj.write("MY TEXT", :encryption_key => my_key) # # # download and decrypt the data # obj.read(:encryption_key => my_key) # #=> "MY TEXT" # # ### Configuring storage locations # # By default, encryption materials are stored in the object metadata. # If you prefer, you can store the encryption materials in a separate # object in S3. This object will have the same key + '.instruction'. # # # new object, does not exist yet # obj = bucket.objects["my-text-object"] # # # no instruction file present # bucket.objects['my-text-object.instruction'].exists? # #=> false # # # store the encryption materials in the instruction file # # instead of obj#metadata # obj.write("MY TEXT", # :encryption_key => MY_KEY, # :encryption_materials_location => :instruction_file) # # bucket.objects['my-text-object.instruction'].exists? # #=> true # # If you store the encryption materials in an instruction file, you # must tell #read this or it will fail to find your encryption materials. # # # reading an encrypted file whos materials are stored in an # # instruction file, and not metadata # obj.read(:encryption_key => MY_KEY, # :encryption_materials_location => :instruction_file) # # ### Configuring default behaviors # # You can configure the default key such that it will automatically # encrypt and decrypt for you. You can do this globally or for a # single S3 interface # # # all objects uploaded/downloaded with this s3 object will be # # encrypted/decrypted # s3 = AWS::S3.new(:s3_encryption_key => "MY_KEY") # # # set the key to always encrypt/decrypt # AWS.config(:s3_encryption_key => "MY_KEY") # # You can also configure the default storage location for the encryption # materials. # # AWS.config(:s3_encryption_materials_location => :instruction_file) # class S3Object include Core::Model include DataOptions include ACLOptions include AWS::S3::EncryptionUtils # @param [Bucket] bucket The bucket this object belongs to. # @param [String] key The object's key. def initialize(bucket, key, opts = {}) @content_length = opts.delete(:content_length) @etag = opts.delete(:etag) @last_modified = opts.delete(:last_modified) super @key = key @bucket = bucket end # @return [String] The objects unique key attr_reader :key # @return [Bucket] The bucket this object is in. attr_reader :bucket # @api private def inspect "<#{self.class}:#{bucket.name}/#{key}>" end # @return [Boolean] Returns true if the other object belongs to the # same bucket and has the same key. def == other other.kind_of?(S3Object) and other.bucket == bucket and other.key == key end alias_method :eql?, :== # @return [Boolean] Returns `true` if the object exists in S3. def exists? head rescue Errors::NoSuchKey => e false else true end # Performs a HEAD request against this object and returns an object # with useful information about the object, including: # # * metadata (hash of user-supplied key-value pairs) # * content_length (integer, number of bytes) # * content_type (as sent to S3 when uploading the object) # * etag (typically the object's MD5) # * server_side_encryption (the algorithm used to encrypt the # object on the server side, e.g. `:aes256`) # # @param [Hash] options # @option options [String] :version_id Which version of this object # to make a HEAD request against. # @return A head object response with metadata, # content_length, content_type, etag and server_side_encryption. def head options = {} client.head_object(options.merge( :bucket_name => bucket.name, :key => key)) end # Returns the object's ETag. # # Generally the ETAG is the MD5 of the object. If the object was # uploaded using multipart upload then this is the MD5 all of the # upload-part-md5s. # # @return [String] Returns the object's ETag def etag @etag = config.s3_cache_object_attributes && @etag || head[:etag] end # Returns the object's last modified time. # # @return [Time] Returns the object's last modified time. def last_modified @last_modified = config.s3_cache_object_attributes && @last_modified || head[:last_modified] end # @return [Integer] Size of the object in bytes. def content_length @content_length = config.s3_cache_object_attributes && @content_length || head[:content_length] end # @note S3 does not compute content-type. It reports the content-type # as was reported during the file upload. # @return [String] Returns the content type as reported by S3, # defaults to an empty string when not provided during upload. def content_type head[:content_type] end # @return [DateTime,nil] def expiration_date head[:expiration_date] end # @return [String,nil] def expiration_rule_id head[:expiration_rule_id] end # @return [Symbol, nil] Returns the algorithm used to encrypt # the object on the server side, or `nil` if SSE was not used # when storing the object. def server_side_encryption head[:server_side_encryption] end # @return [true, false] Returns true if the object was stored # using server side encryption. def server_side_encryption? !server_side_encryption.nil? end # @return [Boolean] whether a {#restore} operation on the # object is currently being performed on the object. # @see #restore_expiration_date # @since 1.7.2 def restore_in_progress? head[:restore_in_progress] end # @return [DateTime] the time when the temporarily restored object # will be removed from S3. Note that the original object will remain # available in Glacier. # @return [nil] if the object was not restored from an archived # copy # @since 1.7.2 def restore_expiration_date head[:restore_expiration_date] end # @return [Boolean] whether the object is a temporary copy of an # archived object in the Glacier storage class. # @since 1.7.2 def restored_object? !!head[:restore_expiration_date] end # Deletes the object from its S3 bucket. # # @param [Hash] options # # @option [String] :version_id (nil) If present the specified version # of this object will be deleted. Only works for buckets that have # had versioning enabled. # # @option [Boolean] :delete_instruction_file (false) Set this to `true` # if you use client-side encryption and the encryption materials # were stored in a separate object in S3 (key.instruction). # # @option [String] :mfa The serial number and current token code of # the Multi-Factor Authentication (MFA) device for the user. Format # is "SERIAL TOKEN" - with a space between the serial and token. # # @return [nil] def delete options = {} client.delete_object(options.merge( :bucket_name => bucket.name, :key => key)) if options[:delete_instruction_file] client.delete_object( :bucket_name => bucket.name, :key => key + '.instruction') end nil end # Restores a temporary copy of an archived object from the # Glacier storage tier. After the specified `days`, Amazon # S3 deletes the temporary copy. Note that the object # remains archived; Amazon S3 deletes only the restored copy. # # Restoring an object does not occur immediately. Use # {#restore_in_progress?} to check the status of the operation. # # @option [Integer] :days (1) the number of days to keep the object # @return [Boolean] `true` if a restore can be initiated. # @since 1.7.2 def restore options = {} options[:days] ||= 1 client.restore_object(options.merge({ :bucket_name => bucket.name, :key => key, })) true end # @option [String] :version_id (nil) If present the metadata object # will be for the specified version. # @return [ObjectMetadata] Returns an instance of ObjectMetadata # representing the metadata for this object. def metadata options = {} options[:config] = config ObjectMetadata.new(self, options) end # Returns a collection representing all the object versions # for this object. # # @example # # bucket.versioning_enabled? # => true # version = bucket.objects["mykey"].versions.latest # # @return [ObjectVersionCollection] def versions ObjectVersionCollection.new(self) end # Uploads data to the object in S3. # # obj = s3.buckets['bucket-name'].objects['key'] # # # strings # obj.write("HELLO") # # # files (by path) # obj.write(Pathname.new('path/to/file.txt')) # # # file objects # obj.write(File.open('path/to/file.txt', 'rb')) # # # IO objects (must respond to #read and #eof?) # obj.write(io) # # ### Multipart Uploads vs Single Uploads # # This method will intelligently choose between uploading the # file in a signal request and using {#multipart_upload}. # You can control this behavior by configuring the thresholds # and you can disable the multipart feature as well. # # # always send the file in a single request # obj.write(file, :single_request => true) # # # upload the file in parts if the total file size exceeds 100MB # obj.write(file, :multipart_threshold => 100 * 1024 * 1024) # # @overload write(data, options = {}) # # @param [String,Pathname,File,IO] data The data to upload. # This may be a: # * String # * Pathname # * File # * IO # * Any object that responds to `#read` and `#eof?`. # # @param options [Hash] Additional upload options. # # @option options [Integer] :content_length If provided, this # option must match the total number of bytes written to S3. # This options is *required* when it is not possible to # automatically determine the size of `data`. # # @option options [Integer] :estimated_content_length When uploading # data of unknown content length, you may specify this option to # hint what mode of upload should take place. When # `:estimated_content_length` exceeds the `:multipart_threshold`, # then the data will be uploaded in parts, otherwise it will # be read into memory and uploaded via {Client#put_object}. # # @option options [Boolean] :single_request (false) When `true`, # this method will always upload the data in a single request # (via {Client#put_object}). When `false`, this method will # choose between {Client#put_object} and {#multipart_upload}. # # @option options [Integer] :multipart_threshold (16777216) Specifies # the maximum size (in bytes) of a single-request upload. If the # data exceeds this threshold, it will be uploaded via # {#multipart_upload}. The default threshold is 16MB and can # be configured via AWS.config(:s3_multipart_threshold => ...). # # @option options [Integer] :multipart_min_part_size (5242880) The # minimum size of a part to upload to S3 when using # {#multipart_upload}. S3 will reject parts smaller than 5MB # (except the final part). The default is 5MB and can be # configured via AWS.config(:s3_multipart_min_part_size => ...). # # @option options [Hash] :metadata A hash of metadata to be # included with the object. These will be sent to S3 as # headers prefixed with `x-amz-meta`. Each name, value pair # must conform to US-ASCII. # # @option options [Symbol,String] :acl (:private) A canned access # control policy. Valid values are: # # * `:private` # * `:public_read` # * `:public_read_write` # * `:authenticated_read` # * `:bucket_owner_read` # * `:bucket_owner_full_control` # # @option options [String] :grant_read # # @option options [String] :grant_write # # @option options [String] :grant_read_acp # # @option options [String] :grant_write_acp # # @option options [String] :grant_full_control # # @option options [Boolean] :reduced_redundancy (false) When `true`, # this object will be stored with Reduced Redundancy Storage. # # @option options :cache_control [String] Can be used to specify # caching behavior. See # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 # # @option options :content_disposition [String] Specifies # presentational information for the object. See # http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1 # # @option options :content_encoding [String] Specifies what # content encodings have been applied to the object and thus # what decoding mechanisms must be applied to obtain the # media-type referenced by the `Content-Type` header field. # See # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11 # # @option options [String] :content_md5 # The base64 encoded content md5 of the data. # # @option options :content_type A standard MIME type # describing the format of the object data. # # @option options [Symbol] :server_side_encryption (nil) If this # option is set, the object will be stored using server side # encryption. The only valid value is `:aes256`, which # specifies that the object should be stored using the AES # encryption algorithm with 256 bit keys. By default, this # option uses the value of the `:s3_server_side_encryption` # option in the current configuration; for more information, # see {AWS.config}. # # @option options [OpenSSL::PKey::RSA, String] :encryption_key # Set this to encrypt the data client-side using envelope # encryption. The key must be an OpenSSL asymmetric key # or a symmetric key string (16, 24 or 32 bytes in length). # # @option options [Symbol] :encryption_materials_location (:metadata) # Set this to `:instruction_file` if you prefer to store the # client-side encryption materials in a separate object in S3 # instead of in the object metadata. # # @option options [String] :expires The date and time at which the # object is no longer cacheable. # # @option options [String] :website_redirect_location # # @return [S3Object, ObjectVersion] If the bucket has versioning # enabled, this methods returns an {ObjectVersion}, otherwise # this method returns `self`. # def write *args, &block options = compute_write_options(*args, &block) add_storage_class_option(options) add_sse_options(options) add_cse_options(options) if use_multipart?(options) write_with_multipart(options) else write_with_put_object(options) end end # Performs a multipart upload. Use this if you have specific # needs for how the upload is split into parts, or if you want # to have more control over how the failure of an individual # part upload is handled. Otherwise, {#write} is much simpler # to use. # # Note: After you initiate multipart upload and upload one or # more parts, you must either complete or abort multipart # upload in order to stop getting charged for storage of the # uploaded parts. Only after you either complete or abort # multipart upload, Amazon S3 frees up the parts storage and # stops charging you for the parts storage. # # @example Uploading an object in two parts # # bucket.objects.myobject.multipart_upload do |upload| # upload.add_part("a" * 5242880) # upload.add_part("b" * 2097152) # end # # @example Uploading parts out of order # # bucket.objects.myobject.multipart_upload do |upload| # upload.add_part("b" * 2097152, :part_number => 2) # upload.add_part("a" * 5242880, :part_number => 1) # end # # @example Aborting an upload after parts have been added # # bucket.objects.myobject.multipart_upload do |upload| # upload.add_part("b" * 2097152, :part_number => 2) # upload.abort # end # # @example Starting an upload and completing it later by ID # # upload = bucket.objects.myobject.multipart_upload # upload.add_part("a" * 5242880) # upload.add_part("b" * 2097152) # id = upload.id # # # later or in a different process # upload = bucket.objects.myobject.multipart_uploads[id] # upload.complete(:remote_parts) # # @yieldparam [MultipartUpload] upload A handle to the upload. # {MultipartUpload#close} is called in an `ensure` clause so # that the upload will always be either completed or # aborted. # # @param [Hash] options Options for the upload. # # @option options [Hash] :metadata A hash of metadata to be # included with the object. These will be sent to S3 as # headers prefixed with `x-amz-meta`. Each name, value pair # must conform to US-ASCII. # # @option options [Symbol] :acl (private) A canned access # control policy. Valid values are: # # * `:private` # * `:public_read` # * `:public_read_write` # * `:authenticated_read` # * `:bucket_owner_read` # * `:bucket_owner_full_control` # # @option options [Boolean] :reduced_redundancy (false) If true, # Reduced Redundancy Storage will be enabled for the uploaded # object. # # @option options :cache_control [String] Can be used to specify # caching behavior. See # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 # # @option options :content_disposition [String] Specifies # presentational information for the object. See # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec19.5.1 # # @option options :content_encoding [String] Specifies what # content encodings have been applied to the object and thus # what decoding mechanisms must be applied to obtain the # media-type referenced by the `Content-Type` header field. # See # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11 # # @option options :content_type A standard MIME type # describing the format of the object data. # # @option options [Symbol] :server_side_encryption (nil) If this # option is set, the object will be stored using server side # encryption. The only valid value is `:aes256`, which # specifies that the object should be stored using the AES # encryption algorithm with 256 bit keys. By default, this # option uses the value of the `:s3_server_side_encryption` # option in the current configuration; for more information, # see {AWS.config}. # # @return [S3Object, ObjectVersion] If the bucket has versioning # enabled, returns the {ObjectVersion} representing the # version that was uploaded. If versioning is disabled, # returns self. # def multipart_upload(options = {}) options = options.dup add_sse_options(options) upload = multipart_uploads.create(options) if block_given? begin yield(upload) upload.close rescue => e upload.abort raise e end else upload end end # @example Abort any in-progress uploads for the object: # # object.multipart_uploads.each(&:abort) # # @return [ObjectUploadCollection] Returns an object representing the # collection of uploads that are in progress for this object. def multipart_uploads ObjectUploadCollection.new(self) end # Moves an object to a new key. # # This works by copying the object to a new key and then # deleting the old object. This function returns the # new object once this is done. # # bucket = s3.buckets['old-bucket'] # old_obj = bucket.objects['old-key'] # # # renaming an object returns a new object # new_obj = old_obj.move_to('new-key') # # old_obj.key #=> 'old-key' # old_obj.exists? #=> false # # new_obj.key #=> 'new-key' # new_obj.exists? #=> true # # If you need to move an object to a different bucket, pass # `:bucket` or `:bucket_name`. # # obj = s3.buckets['old-bucket'].objects['old-key'] # obj.move_to('new-key', :bucket_name => 'new_bucket') # # If the copy succeeds, but the then the delete fails, an error # will be raised. # # @param [String] target The key to move this object to. # # @param [Hash] options # # @option (see #copy_to) # # @return [S3Object] Returns a new object with the new key. # def move_to target, options = {} copy = copy_to(target, options) delete copy end alias_method :rename_to, :move_to # Copies data from one S3 object to another. # # S3 handles the copy so the clients does not need to fetch the data # and upload it again. You can also change the storage class and # metadata of the object when copying. # # @note This operation does not copy the ACL, storage class # (standard vs. reduced redundancy) or server side encryption # setting from the source object. If you don't specify any of # these options when copying, the object will have the default # values as described below. # # @param [Mixed] source # # @param [Hash] options # # @option options [String] :bucket_name The slash-prefixed name of # the bucket the source object can be found in. Defaults to the # current object's bucket. # # @option options [Bucket] :bucket The bucket the source object # can be found in. Defaults to the current object's bucket. # # @option options [Hash] :metadata A hash of metadata to save # with the copied object. Each name, value pair must conform # to US-ASCII. When blank, the sources metadata is copied. # If you set this value, you must set ALL metadata values for # the object as we do not preserve existing values. # # @option options [String] :content_type The content type of # the copied object. Defaults to the source object's content # type. # # @option options [String] :content_disposition The presentational # information for the object. Defaults to the source object's # content disposition. # # @option options [Boolean] :reduced_redundancy (false) If true the # object is stored with reduced redundancy in S3 for a lower cost. # # @option options [String] :version_id (nil) Causes the copy to # read a specific version of the source object. # # @option options [Symbol] :acl (private) A canned access # control policy. Valid values are: # # * `:private` # * `:public_read` # * `:public_read_write` # * `:authenticated_read` # * `:bucket_owner_read` # * `:bucket_owner_full_control` # # @option options [Symbol] :server_side_encryption (nil) If this # option is set, the object will be stored using server side # encryption. The only valid value is `:aes256`, which # specifies that the object should be stored using the AES # encryption algorithm with 256 bit keys. By default, this # option uses the value of the `:s3_server_side_encryption` # option in the current configuration; for more information, # see {AWS.config}. # # @option options [Boolean] :client_side_encrypted (false) Set to true # when the object being copied was client-side encrypted. This # is important so the encryption metadata will be copied. # # @option options [Boolean] :use_multipart_copy (false) Set this to # `true` if you need to copy an object that is larger than 5GB. # # @option options :cache_control [String] Can be used to specify # caching behavior. See # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 # # @option options [String] :expires The date and time at which the # object is no longer cacheable. # # @return [nil] def copy_from source, options = {} options = options.dup options[:copy_source] = case source when S3Object "/#{source.bucket.name}/#{source.key}" when ObjectVersion options[:version_id] = source.version_id "/#{source.object.bucket.name}/#{source.object.key}" else if options[:bucket] "/#{options.delete(:bucket).name}/#{source}" elsif options[:bucket_name] # oops, this should be slash-prefixed, but unable to change # this without breaking users that already work-around this # bug by sending :bucket_name => "/bucket-name" "#{options.delete(:bucket_name)}/#{source}" else "/#{self.bucket.name}/#{source}" end end if [:metadata, :content_disposition, :content_type, :cache_control, ].any? {|opt| options.key?(opt) } then options[:metadata_directive] = 'REPLACE' else options[:metadata_directive] ||= 'COPY' end # copies client-side encryption materials (from the metadata or # instruction file) if options.delete(:client_side_encrypted) copy_cse_materials(source, options) end add_sse_options(options) options[:storage_class] = options.delete(:reduced_redundancy) ? 'REDUCED_REDUNDANCY' : 'STANDARD' options[:bucket_name] = bucket.name options[:key] = key if use_multipart_copy?(options) multipart_copy(options) else resp = client.copy_object(options) end nil end # Copies data from the current object to another object in S3. # # S3 handles the copy so the client does not need to fetch the data # and upload it again. You can also change the storage class and # metadata of the object when copying. # # @note This operation does not copy the ACL, storage class # (standard vs. reduced redundancy) or server side encryption # setting from this object to the new object. If you don't # specify any of these options when copying, the new object # will have the default values as described below. # # @param [S3Object,String] target An S3Object, or a string key of # and object to copy to. # # @param [Hash] options # # @option options [String] :bucket_name The slash-prefixed name of the # bucket the object should be copied into. Defaults to the current # object's bucket. # # @option options [Bucket] :bucket The bucket the target object # should be copied into. Defaults to the current object's bucket. # # @option options [Hash] :metadata A hash of metadata to save # with the copied object. Each name, value pair must conform # to US-ASCII. When blank, the sources metadata is copied. # # @option options [Boolean] :reduced_redundancy (false) If true # the object is stored with reduced redundancy in S3 for a # lower cost. # # @option options [Symbol] :acl (private) A canned access # control policy. Valid values are: # # * `:private` # * `:public_read` # * `:public_read_write` # * `:authenticated_read` # * `:bucket_owner_read` # * `:bucket_owner_full_control` # # @option options [Symbol] :server_side_encryption (nil) If this # option is set, the object will be stored using server side # encryption. The only valid value is `:aes256`, which # specifies that the object should be stored using the AES # encryption algorithm with 256 bit keys. By default, this # option uses the value of the `:s3_server_side_encryption` # option in the current configuration; for more information, # see {AWS.config}. # # @option options [Boolean] :client_side_encrypted (false) When `true`, # the client-side encryption materials will be copied. Without this # option, the key and iv are not guaranteed to be transferred to # the new object. # # @option options [String] :expires The date and time at which the # object is no longer cacheable. # # @return [S3Object] Returns the copy (target) object. # def copy_to target, options = {} unless target.is_a?(S3Object) bucket = case when options[:bucket] then options[:bucket] when options[:bucket_name] Bucket.new(options[:bucket_name], :config => config) else self.bucket end target = S3Object.new(bucket, target) end copy_opts = options.dup copy_opts.delete(:bucket) copy_opts.delete(:bucket_name) target.copy_from(self, copy_opts) target end # Fetches the object data from S3. If you pass a block to this # method, the data will be yielded to the block in chunks as it # is read off the HTTP response. # # ### Read an object from S3 in chunks # # When downloading large objects it is recommended to pass a block # to #read. Data will be yielded to the block as it is read off # the HTTP response. # # # read an object from S3 to a file # File.open('output.txt', 'wb') do |file| # bucket.objects['key'].read do |chunk| # file.write(chunk) # end # end # # ### Reading an object without a block # # When you omit the block argument to #read, then the entire # HTTP response and read and the object data is loaded into # memory. # # bucket.objects['key'].read # #=> 'object-contents-here' # # @param [Hash] options # # @option options [String] :version_id Reads data from a # specific version of this object. # # @option options [Time] :if_unmodified_since If specified, the # method will raise # `AWS::S3::Errors::PreconditionFailed` unless the # object has not been modified since the given time. # # @option options [Time] :if_modified_since If specified, the # method will raise `AWS::S3::Errors::NotModified` if # the object has not been modified since the given time. # # @option options [String] :if_match If specified, the method # will raise `AWS::S3::Errors::PreconditionFailed` # unless the object ETag matches the provided value. # # @option options [String] :if_none_match If specified, the # method will raise `AWS::S3::Errors::NotModified` if # the object ETag matches the provided value. # # @option options [Range] :range A byte range to read data from # # @option options [OpenSSL::PKey::RSA, String] :encryption_key # (nil) If this option is set, the object will be decrypted using # envelope encryption. The valid values are OpenSSL asymmetric keys # `OpenSSL::Pkey::RSA` or strings representing symmetric keys # of an AES-128/192/256-ECB cipher as a `String`. # This value defaults to the value in `s3_encryption_key`; # for more information, see {AWS.config}. # # Symmetric Keys: # # cipher = OpenSSL::Cipher.new('AES-256-ECB') # key = cipher.random_key # # Asymmetric keys can also be generated as so: # key = OpenSSL::PKey::RSA.new(KEY_SIZE) # # @option options [Symbol] :encryption_materials_location (:metadata) # Set this to `:instruction_file` if the encryption materials # are not stored in the object metadata # # @note `:range` option cannot be used with client-side encryption # # @note All decryption reads incur at least an extra HEAD operation. # def read options = {}, &read_block options[:bucket_name] = bucket.name options[:key] = key if should_decrypt?(options) get_encrypted_object(options, &read_block) else resp_data = get_object(options, &read_block) block_given? ? resp_data : resp_data[:data] end end # @api private module ACLProxy attr_accessor :object def change yield(self) object.acl = self end end # Returns the object's access control list. This will be an # instance of AccessControlList, plus an additional `change` # method: # # object.acl.change do |acl| # # remove any grants to someone other than the bucket owner # owner_id = object.bucket.owner.id # acl.grants.reject! do |g| # g.grantee.canonical_user_id != owner_id # end # end # # Note that changing the ACL is not an atomic operation; it # fetches the current ACL, yields it to the block, and then # sets it again. Therefore, it's possible that you may # overwrite a concurrent update to the ACL using this # method. # # @return [AccessControlList] # def acl resp = client.get_object_acl(:bucket_name => bucket.name, :key => key) acl = AccessControlList.new(resp.data) acl.extend ACLProxy acl.object = self acl end # Sets the objects's ACL (access control list). You can provide an ACL # in a number of different formats. # @param (see ACLOptions#acl_options) # @return [nil] def acl=(acl) client_opts = {} client_opts[:bucket_name] = bucket.name client_opts[:key] = key client.put_object_acl(acl_options(acl).merge(client_opts)) nil end # @api private REQUEST_PARAMETERS = Core::Signers::S3::QUERY_PARAMS.map do |p| p.tr("-","_").to_sym end # Generates a presigned URL for an operation on this object. # This URL can be used by a regular HTTP client to perform the # desired operation without credentials and without changing # the permissions of the object. # # @example Generate a url to read an object # # bucket.objects.myobject.url_for(:read) # # @example Generate a url to delete an object # # bucket.objects.myobject.url_for(:delete) # # @example Override response headers for reading an object # # object = bucket.objects.myobject # url = object.url_for(:read, # :response_content_type => "application/json") # # @example Generate a url that expires in 10 minutes # # bucket.objects.myobject.url_for(:read, :expires => 10*60) # # @param [Symbol, String] method The HTTP verb or object # method for which the returned URL will be valid. Valid # values: # # * `:get` or `:read` # * `:put` or `:write` # * `:delete` # * `:head` # # @param [Hash] options Additional options for generating the URL. # # @option options :expires Sets the expiration time of the # URL; after this time S3 will return an error if the URL is # used. This can be an integer (to specify the number of # seconds after the current time), a string (which is parsed # as a date using Time#parse), a Time, or a DateTime object. # This option defaults to one hour after the current time. # # @option options [Boolean] :secure (true) Whether to generate a # secure (HTTPS) URL or a plain HTTP url. # # @option options [String] :content_type Object content type for # HTTP PUT. When provided, has to be also added to the request # header as a 'content-type' field # # @option options [String] :content_md5 Object MD5 hash for HTTP PUT. # When provided, has to be also added to the request header as a # 'content-md5' field # # @option options [String] :endpoint Sets the hostname of the # endpoint. # # @option options [Integer] :port Sets the port of the # endpoint (overrides config.s3_port). # # @option options [Boolean] :force_path_style (false) Indicates # whether the generated URL should place the bucket name in # the path (true) or as a subdomain (false). # # @option options [String] :response_content_type Sets the # Content-Type header of the response when performing an # HTTP GET on the returned URL. # # @option options [String] :response_content_language Sets the # Content-Language header of the response when performing an # HTTP GET on the returned URL. # # @option options [String] :response_expires Sets the Expires # header of the response when performing an HTTP GET on the # returned URL. # # @option options [String] :response_cache_control Sets the # Cache-Control header of the response when performing an # HTTP GET on the returned URL. # # @option options [String] :response_content_disposition Sets # the Content-Disposition header of the response when # performing an HTTP GET on the returned URL. # # @option options [String] :acl The value to use for the # x-amz-acl. # # @option options [String] :response_content_encoding Sets the # Content-Encoding header of the response when performing an # HTTP GET on the returned URL. # # @option options [:v3, :v4] :signature_version (:v3) # # @return [URI::HTTP, URI::HTTPS] def url_for(method, options = {}) options = options.dup options[:expires] = expiration_timestamp(options[:expires]) options[:secure] = config.use_ssl? unless options.key?(:secure) options[:signature_version] ||= config.s3_signature_version case options[:signature_version] when :v3 then presign_v3(method, options) when :v4 then presign_v4(method, options) else msg = "invalid signature version, expected :v3 or :v4, got " msg << options[:signature_version].inspect raise ArgumentError, msg end end # Generates a public (not authenticated) URL for the object. # # @param [Hash] options Options for generating the URL. # # @option options [Boolean] :secure Whether to generate a # secure (HTTPS) URL or a plain HTTP url. # # @return [URI::HTTP, URI::HTTPS] # def public_url(options = {}) options[:secure] = config.use_ssl? unless options.key?(:secure) build_uri(request_for_signing(options), options) end # Generates fields for a presigned POST to this object. This # method adds a constraint that the key must match the key of # this object. All options are sent to the PresignedPost # constructor. # # @see PresignedPost # @return [PresignedPost] def presigned_post(options = {}) PresignedPost.new(bucket, options.merge(:key => key)) end # @note Changing the storage class of an object incurs a COPY # operation. # # Changes the storage class of the object to enable or disable # Reduced Redundancy Storage (RRS). # # @param [true,false] value If this is true, the object will be # copied in place and stored with reduced redundancy at a # lower cost. Otherwise, the object will be copied and stored # with the standard storage class. # # @return [true,false] The `value` parameter. def reduced_redundancy= value copy_from(key, :reduced_redundancy => value) value end private def presign_v4(method, options) PresignV4.new(self).presign(method, options) end def presign_v3(method, options) options[:acl] = options[:acl].to_s.sub('_', '-') if options[:acl] req = request_for_signing(options) req.http_method = http_method(method) req.add_param("AWSAccessKeyId", config.credential_provider.access_key_id) req.add_param("versionId", options[:version_id]) if options[:version_id] req.add_param("Signature", signature(req, options)) req.add_param("Expires", options[:expires]) req.add_param("x-amz-acl", options[:acl]) if options[:acl] if config.credential_provider.session_token req.add_param( "x-amz-security-token", config.credential_provider.session_token ) end build_uri(req, options) end # Used to determine if the data needs to be copied in parts def use_multipart_copy? options options[:use_multipart_copy] end def multipart_copy options unless options[:content_length] msg = "unknown content length, must set :content_length " + "to use multi-part copy" raise ArgumentError, msg end part_size = compute_part_size(options) clean_up_options(options) source_length = options.delete(:content_length) multipart_upload(options) do |upload| pos = 0 # We copy in part_size chunks until we read the until pos >= source_length last_byte = (pos + part_size >= source_length) ? source_length - 1 : pos + part_size - 1 upload.copy_part(options[:copy_source], options.merge({:copy_source_range => "bytes=#{pos}-#{last_byte}"})) pos += part_size end end end # @return [Boolean] def should_decrypt? options options[:encryption_key] or config.s3_encryption_key end # A small wrapper around client#get_object def get_object options, &read_block client.get_object(options, &read_block).data end # A wrapper around get_object that decrypts def get_encrypted_object options, &read_block decryption_cipher(options) do |cipher| if block_given? resp = get_object(options) do |chunk| yield(cipher.update(chunk)) end yield(cipher.final) resp else cipher.update(get_object(options)[:data]) + cipher.final end end end # @return [Boolean] Returns `true` if the :data option is large or # guessed to be larger than a configured threshold. def use_multipart? options estimated_content_length(options) > multipart_threshold(options) and !options[:single_request] end # @return [Integer] Returns the number of bytes where a multipart # upload is used instead of #put_object. def multipart_threshold options threshold = options[:multipart_threshold] || config.s3_multipart_threshold end # @return [Integer] Returns the size of each multipart chunk. def compute_part_size options max_parts = options[:multipart_max_parts] || config.s3_multipart_max_parts min_size = options[:multipart_min_part_size] || config.s3_multipart_min_part_size estimated_size = estimated_content_length(options) part_size = [(estimated_size.to_f / max_parts).ceil, min_size].max.to_i part_size += 16 - (part_size % 16) part_size end # @return [Integer] Returns the size of the data or an estimated # size as provided by the user (useful for IO streams). def estimated_content_length options estimate = options[:content_length] || options[:estimated_content_length] unless estimate msg = "unknown content length, must set :content_length or " + ":estimated_content_length" raise ArgumentError, msg end estimate end def build_uri(request, options) uri_class = options[:secure] ? URI::HTTPS : URI::HTTP uri_class.build(:host => request.host, :port => request.port, :path => request.path, :query => request.querystring) end def signature request, options parts = [] parts << request.http_method parts << options[:content_md5].to_s parts << options[:content_type].to_s parts << options[:expires] parts << "x-amz-acl:#{options[:acl]}" if options[:acl] if token = config.credential_provider.session_token parts << "x-amz-security-token:#{token}" end parts << Core::Signers::S3.canonicalized_resource(request) string_to_sign = parts.join("\n") secret = config.credential_provider.secret_access_key Core::Signers::Base.sign(secret, string_to_sign, 'sha1') end def expiration_timestamp(input) input = input.to_int if input.respond_to?(:to_int) case input when Time then input.to_i when DateTime then Time.parse(input.to_s).to_i when Integer then (Time.now + input).to_i when String then Time.parse(input).to_i else (Time.now + 60*60).to_i end end def http_method(input) symbol = case input when :read then :get when :write then :put else input end symbol.to_s.upcase end def request_for_signing(options) port = [443, 80].include?(config.s3_port) ? (options[:secure] ? 443 : 80) : config.s3_port req = Request.new req.key = key req.host = options.fetch(:endpoint, config.s3_endpoint) if req.host.nil? && options.include?(:endpoint) && options[:endpoint].nil? req.host = bucket.name else req.bucket = bucket.name end req.port = options.fetch(:port, port) req.force_path_style = options.fetch(:force_path_style, config.s3_force_path_style) REQUEST_PARAMETERS.each do |param| req.add_param(param.to_s.tr("_","-"), options[param]) if options.key?(param) end req end def add_sse_options(options) unless options.key?(:server_side_encryption) options[:server_side_encryption] = config.s3_server_side_encryption end options.delete(:server_side_encryption) if options[:server_side_encryption].nil? end # Adds client-side encryption metadata headers and encrypts key def add_cse_options(options) encryption_key_for(options) do |encryption_key| check_encryption_materials(:encrypt, encryption_key) cipher = get_aes_cipher(:encrypt, :CBC) generate_aes_key(cipher) do |envelope_key, envelope_iv| envelope_key, envelope_iv = encode_envelope_key(encryption_key, envelope_key, envelope_iv) build_cse_metadata(options, envelope_key, envelope_iv) do |headers, encryption_materials| store_encryption_materials(options, headers, encryption_materials) end end # Wrap current stream in encryption options[:data] = CipherIO.new(cipher, options[:data], options[:content_length]) # Update content_length options[:content_length] = get_encrypted_size(options[:content_length]) if options[:content_length] end remove_cse_options(options) end # @yield [String, String] Yields an encrypted encoded key and iv pair def encode_envelope_key encryption_key, envelope_key, envelope_iv, &block envelope_key = encrypt(envelope_key, encryption_key) [encode64(envelope_key), encode64(envelope_iv)] end # @yield [Hash, Hash] Yields headers and encryption materials that are # to be stored in the metadata and/or instruction file def build_cse_metadata options, enc_envelope_key, enc_envelope_iv, &block # Ensure metadata exists options[:metadata] = {} unless options[:metadata] matdesc = options[:encryption_matdesc] || config.s3_encryption_matdesc encryption_materials = {'x-amz-key' => enc_envelope_key, 'x-amz-iv' => enc_envelope_iv, 'x-amz-matdesc' => matdesc} orig_headers = {} # Save the unencrypted content length if options[:content_length] orig_headers['x-amz-unencrypted-content-length'] = options[:content_length] end # Save the unencrypted content MD5 if options[:content_md5] orig_headers['x-amz-unencrypted-content-md5'] = options[:content_md5] options.delete(:content_md5) end options[:metadata].merge!(orig_headers) yield([orig_headers, encryption_materials]) end # Stores the headers and encryption materials needed to decrypt the data # and to know unencrypted information about the object def store_encryption_materials options, orig_headers, encryption_materials # Get the storage location cse_location = options[:encryption_materials_location] || config.s3_encryption_materials_location # Encryption type specific metadata case cse_location when :metadata options[:metadata].merge!(encryption_materials) when :instruction_file json_string = JSON.generate(encryption_materials) inst_headers = {'x-amz-crypto-instr-file' => ""}.merge(orig_headers) bucket.objects["#{key}.instruction"].write(json_string, :metadata => inst_headers) else msg = "invalid :encryption_materials_location, expected " msg << ":metadata or :instruction_file, got: #{cse_location.inspect}" raise ArgumentError, msg end nil end # Removes any extra headers client-side encryption uses. def remove_cse_options options options.delete(:encryption_key) options.delete(:encryption_materials_location) options.delete(:encryption_matdesc) end # Yields a decryption cipher for the given client-side encryption key # or raises an error. def decryption_cipher options, &block encryption_key_for(options) do |encryption_key| check_encryption_materials(:decrypt, encryption_key) location = options[:encryption_materials_location] || config.s3_encryption_materials_location cipher = decryption_materials(location, options) do |envelope_key, envelope_iv| envelope_key, envelope_iv = decode_envelope_key(envelope_key, envelope_iv, encryption_key) get_aes_cipher(:decrypt, :CBC, envelope_key, envelope_iv) end remove_cse_options(options) yield(cipher) end end # Decodes the envelope key for decryption def decode_envelope_key envelope_key, envelope_iv, encryption_key decrypted_key = begin decrypt(decode64(envelope_key), encryption_key) rescue RuntimeError msg = "Master key used to decrypt data key is not correct." raise AWS::S3::Errors::IncorrectClientSideEncryptionKey, msg end [decrypted_key, decode64(envelope_iv)] end # @yield [String, String, String] Yields encryption materials for # decryption def decryption_materials location, options = {}, &block materials = case location when :metadata then get_metadata_materials(options) when :instruction_file then get_inst_file_materials else msg = "invalid :encryption_materials_location option, expected " msg << ":metadata or :instruction_file, got: #{location.inspect}" raise ArgumentError, msg end envelope_key, envelope_iv = materials unless envelope_key and envelope_iv raise 'no encryption materials found, unable to decrypt' end yield(envelope_key, envelope_iv) end # @return [String, String, String] Returns the data key, envelope_iv, and the # material description for decryption from the metadata. def get_metadata_materials(options) opts = {} opts[:version_id] = options[:version_id] if options[:version_id] metadata(opts).to_h.values_at(*%w(x-amz-key x-amz-iv)) end # @return [String, String, String] Returns the data key, envelope_iv, and the # material description for decryption from the instruction file. def get_inst_file_materials obj = bucket.objects["#{key}.instruction"] JSON.parse(obj.read).values_at(*%w(x-amz-key x-amz-iv)) end # @yield [Hash] Yields the metadata to be saved for client-side encryption def copy_cse_materials source, options cse_materials = {} meta = source.metadata.to_h cse_materials['x-amz-key'] = meta['x-amz-key'] if meta['x-amz-key'] cse_materials['x-amz-iv'] = meta['x-amz-iv'] if meta['x-amz-iv'] cse_materials['x-amz-matdesc'] = meta['x-amz-matdesc'] if meta['x-amz-matdesc'] cse_materials['x-amz-unencrypted-content-length'] = meta['x-amz-unencrypted-content-length'] if meta['x-amz-unencrypted-content-length'] cse_materials['x-amz-unencrypted-content-md5'] = meta['x-amz-unencrypted-content-md5'] if meta['x-amz-unencrypted-content-md5'] if cse_materials['x-amz-key'] and cse_materials['x-amz-iv'] and cse_materials['x-amz-matdesc'] then options[:metadata] = (options[:metadata] || {}).merge(cse_materials) else # Handling instruction file source_inst = "#{source.key}.instruction" dest_inst = "#{key}.instruction" self.bucket.objects[dest_inst].copy_from( source.bucket.objects[source_inst]) end end # Removes unwanted options that should not be passed to the client. def clean_up_options(options) options.delete(:estimated_content_length) options.delete(:single_request) options.delete(:multipart_threshold) end # Performs a write using a multipart upload def write_with_multipart options part_size = compute_part_size(options) clean_up_options(options) options.delete(:content_length) multipart_upload(options) do |upload| upload.add_part(options[:data].read(part_size)) until options[:data].eof? end end # Performs a write using a single request def write_with_put_object options # its possible we don't know the content length of the data # option, but the :estimated_content_length was sufficiently # small that we will read the entire stream into memory # so we can tell s3 the content length (this is required). unless options[:content_length] data = StringIO.new while (chunk = options[:data].read(4 * 1024)) data << chunk end options[:content_length] = data.size data.rewind options[:data] = data end clean_up_options(options) options[:bucket_name] = bucket.name options[:key] = key resp = client.put_object(options) resp.data[:version_id] ? ObjectVersion.new(self, resp.data[:version_id]) : self end def encryption_key_for options, &block if key = options[:encryption_key] || config.s3_encryption_key yield(key) end end def add_storage_class_option options if options[:reduced_redundancy] == true options[:storage_class] = 'REDUCED_REDUNDANCY' end end # @return [String] Encodes a `String` in base 64 regardless of version of # Ruby for http headers (removes newlines). def encode64 input Base64.encode64(input).split("\n") * "" end # @return [String] Decodes a `String` in base 64. def decode64 input Base64.decode64(input) end end end end aws-sdk-v1-1.66.0/lib/aws/s3/bucket.rb0000644000004100000410000005562212604445426017241 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # Represents a bucket in S3. # # # Creating Buckets # # You create a bucket by name. Bucket names must be globally unique # and must be DNS compatible. # # s3 = AWS::S3.new # bucket = s3.buckets.create('dns-compat-bucket-name') # # # Getting a Bucket # # You can create a reference to a bucket, given its name. # # bucket = s3.buckets['bucket-name'] # makes no request # bucket.exists? #=> returns true/false # # # Enumerating Buckets # # The {BucketCollection} class is enumerable. # # s3.buckets.each do |bucket| # puts bucket.name # end # # # Deleting a Bucket # # You can delete an empty bucket you own. # # bucket = s3.buckets.create('my-temp-bucket') # bucket.objects['abc'].write('xyz') # # bucket.clear! # deletes all object versions in batches # bucket.delete # # You can alternatively call {#delete!} which will clear # the bucket for your first. # # bucket.delete! # # # Objects # # Given a bucket you can access its objects, either by key or by # enumeration. # # bucket.objects['key'] #=> makes no request, returns an S3Object # # bucket.objects.each do |obj| # puts obj.key # end # # See {ObjectCollection} and {S3Object} for more information on working # with objects. # # # Website Configuration # # It is easy to enable website hosting for a bucket. # # bucket.configure_website # # You can specify the index and error documents by passing a block. # If your bucket is already configured as a website, the current # configuration will be yielded. If you bucket it not currently # configured as a website, a new configuration will be yielded # with default values. # # bucket.configure_website do |cfg| # cfg.index_document_suffix = 'index.html' # cfg.error_document_key = 'error.html' # end # # You can disable website hosting two ways: # # bucket.remove_website_configuration # bucket.website_configuration = nil # # You can use {#website_configuration=} to copy a website configuration # from one bucket to another. # # bucket.website_configuration = other_bucket.website_configuration # # # Bucket Policies and ACLs # # You can control access to your bucket and its contents a number # of ways. You can specify a bucket ACL (access control list) # or a bucket policy. # # ## ACLs # # ACLs control access to your bucket and its contents via a list of # grants and grantees. # # ### Canned ACLs # # The simplest way to specify an ACL is to use one of Amazon's "canned" # ACLs. Amazon accepts the following canned ACLs: # # * `:private` # * `:public_read` # * `:public_read_write` # * `:authenticated_read` # * `:bucket_owner_read` # * `:bucket_owner_full_control` # # You can specify a the ACL at bucket creation or later update a bucket. # # # at create time, defaults to :private when not specified # bucket = s3.buckets.create('name', :acl => :public_read) # # # replacing an existing bucket ACL # bucket.acl = :private # # ### Grants # # Alternatively you can specify a hash of grants. Each entry in the # `:grant` hash has a grant (key) and a list of grantees (values). # Valid grant keys are: # # * `:grant_read` # * `:grant_write` # * `:grant_read_acp` # * `:grant_write_acp` # * `:grant_full_control` # # Each grantee can be a String, Hash or array of strings or hashes. # The following example uses grants to provide public read # to everyone while providing full control to a user by email address # and to another by their account id (cannonical user id). # # bucket = s3.buckets.create('name', :grants => { # :grant_read => [ # { :uri => "http://acs.amazonaws.com/groups/global/AllUsers" }, # ], # :grant_full_control => [ # { :id => 'abc...mno' } # cannonical user id # { :email_address => 'foo@bar.com' }, # email address # ] # }) # # ### ACL Object # # Lastly, you can build an ACL object and use a Ruby DSL to specify grants # and grantees. See {ACLObject} for more information. # # # updating an existing bucket acl using ACLObject # bucket.acl.change do |acl| # acl.grants.reject! do |g| # g.grantee.canonical_user_id != bucket.owner.id # end # end # # ## Policies # # You can also work with bucket policies. # # policy = AWS::S3::Policy.new # policy.allow( # :actions => [:put_object, :get_object] # :resources => [bucket] # :principals => :any) # # bucket.policy = policy # # See {Core::Policy} and {S3::Policy} for more information on build # policy objects. # # # Versioned Buckets # # You can enable versioning on a bucket you control. When versioning # is enabled, S3 will keep track of each version of each object you # write to the bucket (even deletions). # # bucket.versioning_enabled? #=> false # bucket.enable_versioning # # there is also a #suspend_versioning method # # obj = bucket.objects['my-obj'] # obj.write('a') # obj.write('b') # obj.delete # obj.write('c') # # obj.versions.each do |obj_version| # if obj_version.delete_marker? # puts obj_version.read # else # puts "- DELETE MARKER" # end # end # # Alternatively you can enumerate all versions of all objects in your # bucket. # # bucket.versions.each do |obj_version| # puts obj_version.key ` " : " ` obj_version.version_id # end # # See {BucketVersionCollection}, {ObjectVersionCollection} and # {ObjectVersion} for more information on working with objects in # a versioned bucket. Also see the S3 documentation for information # on object versioning. # class Bucket include Core::Model include ACLOptions # @param [String] name # @param [Hash] options # @option options [String] :owner (nil) The owner id of this bucket. def initialize(name, options = {}) # the S3 docs disagree with what the service allows, # so it's not safe to toss out invalid bucket names # S3::Client.validate_bucket_name!(name) @name = name @owner = options[:owner] super end # @return [String] The bucket name attr_reader :name # Returns the url for this bucket. # @return [String] url to the bucket def url(options = {}) protocol = options.fetch(:secure, false) ? "https://" : "http://" if client.dns_compatible_bucket_name?(name) "#{protocol}#{name}.s3.amazonaws.com/" else "#{protocol}s3.amazonaws.com/#{name}/" end end # @return [Boolean] Returns true if the bucket has no objects # (this includes versioned objects that are delete markers). def empty? versions.first ? false : true end # @return [String,nil] Returns the location constraint for a bucket # (if it has one), nil otherwise. def location_constraint client.get_bucket_location(:bucket_name => name).location_constraint end # Configure the current bucket as a website. # # bucket.configure_website # # If you pass a block, the website configuration object # will be yielded. You can modify it before it is saved. # # bucket.configure_website do |cfg| # cfg.index_document_suffix = 'index.html' # cfg.error_document_key = 'error.html' # end # # If the bucket already has a website configuration, it will be loaded # and yielded. This makes it possible to modify an existing # configuration. # # # only rename the error document # bucket.configure_website do |cfg| # cfg.error_document_key = 'oops.html' # end # # @yieldparam [WebsiteConfiguration] website_config # @return [WebsiteConfiguration] # @see #website_configuration # @see #website_configuration= # @see #remove_website_configuration # @see #website? def configure_website &block website_config = self.website_configuration website_config ||= WebsiteConfiguration.new yield(website_config) if block_given? self.website_configuration = website_config end # Returns the bucket website configuration. Returns `nil` if the bucket # is not configured as a website. # @return [WebsiteConfiguration,nil] # @see #configure_website # @see #website_configuration= # @see #remove_website_configuration # @see #website? def website_configuration resp = client.get_bucket_website(:bucket_name => name) WebsiteConfiguration.new(resp.data) rescue Errors::NoSuchWebsiteConfiguration nil end # Sets the website configuration. Deletes the configuration if # `nil` is passed. # @param [WebsiteConfiguration,nil] website_configuration # @see #configure_website # @see #website_configuration # @see #remove_website_configuration # @see #website? def website_configuration= website_configuration if website_configuration client_opts = website_configuration.to_hash client_opts[:bucket_name] = name client.put_bucket_website(client_opts) else remove_website_configuration end end # @return [nil] Deletes the bucket website configuration. # @see #configure_website # @see #website_configuration # @see #website_configuration= # @see #website? def remove_website_configuration client.delete_bucket_website(:bucket_name => name) @website_configuration = false nil end # @return [Boolean] Returns `true` if this bucket is configured as # a website. # @see #configure_website # @see #website_configuration # @see #website_configuration= # @see #remove_website_configuration def website? !!website_configuration end # Returns the tags for this bucket. # # tags = bucket.tags # #=> # # # adds a tag to the bucket # tags['foo'] = 'abc' # # # replaces all tags # tags.set('new' => 'tags') # # # removes all tags from the bucket # tags.clear # # # returns tags as a hash # tags.to_h # # @return [BucketTagCollection] Returns a collection that represents # the tags for this bucket. # def tags BucketTagCollection.new(self) end # Sets the tags for this bucket. # # bucket.tags = { 'contents' => 'photots' } # # You can remove all tags for the bucket by passing an empty # hash or `nil`. # # bucket.tags = nil # {} also deletes all tags # bucket.tags # #=> {} # # @param [Hash,nil] tags The tags to set on this bucket. # def tags= tags self.tags.set(tags) end # @return [CORSRuleCollection] Returns a collection that can be # used to manage (add, edit and delete) CORS rules for this bucket. def cors CORSRuleCollection.new(self) end # Sets the bucket CORS rules. # @param (see CORSRuleCollection#set) # @see CORSRuleCollection#set def cors= *rules self.cors.set(*rules) end # Enables versioning on this bucket. # # @option opts [String] :mfa_delete Set to 'Enabled' or 'Disabled' # to control the state of MFA delete on the bucket versioning. # Setting this option requires the :mfa option to also be set. # # @option opts [String] :mfa The serial number and current token code of # the Multi-Factor Authentication (MFA) device for the user. Format # is "SERIAL TOKEN" - with a space between the serial and token. # # @return [nil] def enable_versioning(opts = {}) client.set_bucket_versioning( :bucket_name => @name, :state => :enabled, :mfa_delete => opts[:mfa_delete], :mfa => opts[:mfa]) nil end # Suspends versioning on this bucket. # # @option opts [String] :mfa_delete Set to 'Enabled' or 'Disabled' # to control the state of MFA delete on the bucket versioning. # Setting this option requires the :mfa option to also be set. # # @option opts [String] :mfa The serial number and current token code of # the Multi-Factor Authentication (MFA) device for the user. Format # is "SERIAL TOKEN" - with a space between the serial and token. # # @return [nil] def suspend_versioning(opts = {}) client.set_bucket_versioning( :bucket_name => @name, :state => :suspended, :mfa_delete => opts[:mfa_delete], :mfa => opts[:mfa]) nil end # @return [Boolean] returns `true` if version is enabled on this bucket. def versioning_enabled? versioning_state == :enabled end alias_method :versioned?, :versioning_enabled? # Returns the versioning status for this bucket. States include: # # * `:enabled` - currently enabled # * `:suspended` - currently suspended # * `:unversioned` - versioning has never been enabled # # @return [Symbol] the versioning state def versioning_state client.get_bucket_versioning(:bucket_name => @name).status end # Deletes all objects from this bucket. # @return [nil] def clear! versions.each_batch do |versions| objects.delete(versions) end end # Deletes the current bucket. An error will be raised if the # bucket is not empty. # @return [nil] def delete client.delete_bucket(:bucket_name => @name) nil end # Deletes all objects in a bucket and then deletes the bucket. # @return [nil] def delete! clear! delete end # @return [String] bucket owner id def owner @owner || client.list_buckets.owner end # @api private def inspect "#" end # @return [Boolean] Returns true if the two buckets have the same name. def ==(other) other.kind_of?(Bucket) && other.name == name end # @return [Boolean] Returns true if the two buckets have the same name def eql?(other_bucket) self == other_bucket end # @note This method only indicates if there is a bucket in S3, not # if you have permissions to work with the bucket or not. # @return [Boolean] Returns true if the bucket exists in S3. def exists? begin versioned? # makes a get bucket request without listing contents # raises a client error if the bucket doesn't exist or # if you don't have permission to get the bucket # versioning status. true rescue Errors::NoSuchBucket => e false # bucket does not exist rescue Errors::AccessDenied => e true # bucket exists end end # @return [ObjectCollection] Represents all objects(keys) in # this bucket. def objects ObjectCollection.new(self) end # @return [BucketVersionCollection] Represents all of the versioned # objects stored in this bucket. def versions BucketVersionCollection.new(self) end # @return [MultipartUploadCollection] Represents all of the # multipart uploads that are in progress for this bucket. def multipart_uploads MultipartUploadCollection.new(self) end # @api private module ACLProxy attr_accessor :bucket def change yield(self) bucket.acl = self end end # Returns the bucket's access control list. This will be an # instance of AccessControlList, plus an additional `change` # method: # # bucket.acl.change do |acl| # acl.grants.reject! do |g| # g.grantee.canonical_user_id != bucket.owner.id # end # end # # @return [AccessControlList] def acl resp = client.get_bucket_acl(:bucket_name => name) acl = AccessControlList.new(resp.data) acl.extend ACLProxy acl.bucket = self acl end # Sets the bucket's ACL (access control list). You can provide an ACL # in a number of different formats. # @param (see ACLOptions#acl_options) # @return [nil] def acl= acl client.set_bucket_acl(acl_options(acl).merge(:bucket_name => name)) nil end # @api private module PolicyProxy attr_accessor :bucket def change yield(self) bucket.policy = self end def delete bucket.client.delete_bucket_policy(:bucket_name => bucket.name) end end # Returns the bucket policy. This will be an instance of # Policy. The returned policy will also have the methods of # PolicyProxy mixed in, so you can use it to change the # current policy or delete it, for example: # # if policy = bucket.policy # # add a statement # policy.change do |p| # p.allow(...) # end # # # delete the policy # policy.delete # end # # Note that changing the policy is not an atomic operation; it # fetches the current policy, yields it to the block, and then # sets it again. Therefore, it's possible that you may # overwrite a concurrent update to the policy using this # method. # # @return [Policy,nil] Returns the bucket policy (if it has one), # or it returns `nil` otherwise. def policy resp = client.get_bucket_policy(:bucket_name => name) policy = Policy.from_json(resp.data[:policy]) policy.extend(PolicyProxy) policy.bucket = self policy rescue Errors::NoSuchBucketPolicy => e nil end # Sets the bucket's policy. # # @param policy The new policy. This can be a string (which # is assumed to contain a valid policy expressed in JSON), a # Policy object or any object that responds to `to_json`. # @see Policy # @return [nil] def policy=(policy) client.set_bucket_policy(:bucket_name => name, :policy => policy) nil end # The primary interface for editing the lifecycle configuration. # See {BucketLifecycleConfiguration} for more information. # # @example Adding rules to a bucket's lifecycle configuration # # bucket.lifecycle_configuration.update do # add_rule 'cache-1/', 30 # add_rule 'cache-2/', 30 # end # # @example Deleting the lifecycle configuration # # bucket.lifecycle_configuration.clear # # @return [BucketLifecycleConfiguration] # def lifecycle_configuration @lifecycle_cfg ||= BucketLifecycleConfiguration.new(self) end # You can call this method if you prefer to build your own # lifecycle configuration. # # bucket.lifecycle_configuration = <<-XML # # ... # # XML # # You can also use this method to copy a lifecycle configuration # from another bucket. # # bucket.lifecycle_configuration = other_bucket.lifecycle_configuration # # If you call this method, passing nil, the lifecycle configuration # for this bucket will be deleted. # # @param [String,Object] config You can pass an xml string or any # other object that responds to #to_xml (e.g. # BucketLifecycleConfiguration). # # @return [nil] # def lifecycle_configuration= config if config.nil? client_opts = {} client_opts[:bucket_name] = name client.delete_bucket_lifecycle_configuration(client_opts) @lifecycle_cfg = BucketLifecycleConfiguration.new(self, :empty => true) else xml = config.is_a?(String) ? config : config.to_xml client_opts = {} client_opts[:bucket_name] = name client_opts[:lifecycle_configuration] = xml client.set_bucket_lifecycle_configuration(client_opts) @lifecycle_cfg = BucketLifecycleConfiguration.new(self, :xml => xml) end nil end # Returns a tree that allows you to expose the bucket contents # like a directory structure. # # @see Tree # @param [Hash] options # @option options [String] :prefix (nil) Set prefix to choose where # the top of the tree will be. A value of `nil` means # that the tree will include all objects in the collection. # # @option options [String] :delimiter ('/') The string that separates # each level of the tree. This is usually a directory separator. # # @option options [Boolean] :append (true) If true, the delimiter is # appended to the prefix when the prefix does not already end # with the delimiter. # # @return [Tree] def as_tree options = {} objects.as_tree(options) end # Generates fields for a presigned POST to this object. All # options are sent to the PresignedPost constructor. # # @see PresignedPost def presigned_post(options = {}) PresignedPost.new(self, options) end end end end aws-sdk-v1-1.66.0/lib/aws/s3/client/0000755000004100000410000000000012604445426016703 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/s3/client/xml.rb0000644000004100000410000001714712604445426020042 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 class Client < Core::Client # @api private module XML BaseGrammar = Core::XML::Grammar.new({}, :inflect_rename => true) ListBuckets = BaseGrammar.customize do element "Buckets" do list "Bucket" end end GetBucketAcl = GetObjectAcl = BaseGrammar.customize do element "AccessControlList" do ignore element "Grant" do rename :grants list element "Grantee" do element "ID" do rename :canonical_user_id end end element "Permission" do symbol_value end end end end ListObjects = BaseGrammar.customize do element("Name") { rename :bucket_name } element("MaxKeys") { integer_value } element("IsTruncated") { rename :truncated; boolean_value } element("Delimiter") { force } element("Contents") do list element("Owner") do element("ID") { } element("DisplayName") { } end element("Key") { } element("Size") { } element("StorageClass") { } element("ETag") { rename :etag } element("LastModified") { time_value } end element "CommonPrefixes" do collect_values end end GetBucketLogging = BaseGrammar.customize do element("LoggingEnabled") do element("TargetBucket") { } element("TargetPrefix") { } element("TargetGrants") do list "Grant" element("Grant") do element("Grantee") do element("EmailAddress") { } element("ID") { } element("URI") { } end element("Permission") { } end end end end GetBucketVersioning = BaseGrammar.customize do default_value :status, :unversioned element("Status") do symbol_value end end ListObjectVersions = BaseGrammar.customize do element("MaxKeys") { integer_value } element("IsTruncated") { rename :truncated; boolean_value } element("NextKeyMarker") { force } element("NextVersionIdMarker") { force } %w(DeleteMarker Version).each do |element_name| element(element_name) do collect_values rename(:versions) element("IsLatest") { rename :latest; boolean_value } element("LastModified") { datetime_value } element("ETag") { rename :etag } element("Size") { integer_value } element("StorageClass") { symbol_value } end end element "DeleteMarker" do default_value(:delete_marker, true) default_value(:version, false) end element "Version" do default_value(:delete_marker, false) default_value(:version, true) end element "CommonPrefixes" do collect_values end end InitiateMultipartUpload = BaseGrammar.customize do element("UploadId") { force } end ListMultipartUploads = BaseGrammar.customize do element("IsTruncated") { rename :truncated; boolean_value } element("MaxUploads") { integer_value } element("NextKeyMarker") { force } element("NextUploadIdMarker") { force } element("Upload") do collect_values rename :uploads element("StorageClass") { symbol_value } element("Initiated") { datetime_value } end element "CommonPrefixes" do collect_values end end DeleteObjects = BaseGrammar.customize do element("Deleted") do element("DeleteMarker") { boolean_value } list end element("Error") { list; rename(:errors) } end CompleteMultipartUpload = BaseGrammar.customize ListParts = BaseGrammar.customize do element("StorageClass") { symbol_value } element("IsTruncated") { rename :truncated; boolean_value } element("MaxParts") { integer_value } element("PartNumberMarker") { integer_value } element("NextPartNumberMarker") { integer_value } element("Part") do collect_values rename :parts element("PartNumber") { integer_value } element("LastModified") { datetime_value } element("Size") { integer_value } end end GetBucketLifecycleConfiguration = BaseGrammar.customize do element("Rule") do list rename(:rules) element("Expiration") do element("Days") { integer_value } element("Date") { datetime_value } end element("Transition") do element("StorageClass") { } element("Days") { integer_value } element("Date") { datetime_value } end element("NoncurrentVersionTransition") do element("NoncurrentDays") { integer_value } element("StorageClass") { string_value } end element("NoncurrentVersionDays") do element("NoncurrentDays") { integer_value } end end end GetBucketCors = BaseGrammar.customize do element "CORSRule" do list rename :rules element "AllowedMethod" do list rename :allowed_methods end element "AllowedOrigin" do list rename :allowed_origins end element "AllowedHeader" do list rename :allowed_headers end element "MaxAgeSeconds" do integer end element "ExposeHeader" do list rename :expose_headers end end end GetBucketTagging = BaseGrammar.customize do element "TagSet" do ignore element "Tag" do map_entry("Key", "Value") rename :tags end end end GetBucketWebsite = BaseGrammar.customize do element "IndexDocument" do element "Suffix" end element "ErrorDocument" do element "Key" end element "RoutingRules" do list("RoutingRule") end end CopyPart = BaseGrammar.customize do element "ETag" do rename :etag end element "LastModified" do datetime_value rename :last_modified end end end end end end aws-sdk-v1-1.66.0/lib/aws/s3/cors_rule_collection.rb0000644000004100000410000001330612604445426022165 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # Manages the CORS rules for a single bucket. # # ## Getting Rules # # To get the CORS rules for a bucket, use the {Bucket#cors} method. This # returns a CORSRuleCollection for the bucket. The collection is # enumerable. # # # enumerating all rules for a buck # bucket.cors.each do |rule| # # rule is a CORSRule object # end # # ## Setting Rules # # You can set the rules for a bucket (replacing all existing rules) using # the {#set} method. # # # accepts a list of one or more rules # bucket.rules.set(rule1, rule2) # # # rules can be an array of rules # bucket.rules.set(rules) # # # passing an empty list or array removes all rules # bucket.rules.set([]) # bucket.rules.clear # does the same thing # # Each rule can be a Hash, a {CORSRule} or another {CORSRuleCollection}. # See {Client#put_bucket_cors} for a list of keys for a rule hash. # # ## Adding Rules # # Adding rules is the same as setting rules. Rules you add will be # appended to the end of the existing list of rules. # # # add one or more rules # bucket.rules.add(rules) # # ## Deleting Rules # # To remove a rule, use the {#delete_if} method. # # # delete rules that allow access from any domain # bucket.cors.delete_if{|rule| rule.allowed_origins.include?('*') class CORSRuleCollection include Core::Collection::Simple # @param [Bucket] bucket # @param [Hash] options def initialize bucket, options = {} @bucket = bucket super end # @return [Bucket] attr_reader :bucket # Replaces the CORS rules attached to this bucket. You can pass # one or more rules as an array or a list. # # # replace all exisitng rules with a single rule # bucket.cors.set( # :allowed_methods => %w(GET), # :allowed_origins => %w(http://*.mydomain.com), # :max_age_seconds => 3600) # # If you pass an empty array, all of the rules will be removed from # the bucket. # # # these two lines are equivilent # bucket.cors.clear # bucket.cors.set([]) # # @param [Hash,CORSRule,CORSRuleCollection] rules A list or array # of one or more rules to set. Each rule may be a Hash, a CORSRule # or a CORSRuleCollection. # # @return [nil] # def set *rules raise ArgumentError, 'expected one or more rules' if rules.empty? if rules == [[]] self.clear else rules = rule_hashes(rules) client.put_bucket_cors(:bucket_name => bucket.name, :rules => rules) end nil end # Add one or more CORS rules to this bucket. # # # adding a single rule as a hash # bucket.cors.add( # :allowed_methods => %w(GET HEAD), # :allowed_origins => %w(*), # :max_age_seconds => 3600) # # You can add multiple rules in a single call: # # # each rule may be a hash, CORSRule or a CORSRuleCollection, # bucket.cors.add(rules) # # # alternatively you can pass a list of rules # bucket.cors.add(rule1, rule2, ...) # # @param (see #set) # @return (see #set) def add *rules self.set(self, *rules) end alias_method :create, :add # Deletes every rule for which the block evaluates to `true`. # # @example Remove all rules that are open to the 'world' # # bucket.cors.delete_if{|rule| rule.allowed_origins.include?('*') } # # @yield [rule] # @yieldparam [CORSRule] rule # @yieldreturn [Boolean] Return `true` for each rule you want to delete. # @return (see #set) def delete_if &block rules = [] self.each do |rule| rules << rule unless yield(rule) end self.set(rules) end # Removes all CORS rules attached to this bucket. # # @example # # bucket.cors.count #=> 3 # bucket.cors.clear # bucket.cors.count #=> 0 # # @return [nil] def clear client.delete_bucket_cors(:bucket_name => bucket.name) nil end protected def _each_item options resp = client.get_bucket_cors(options.merge(:bucket_name => bucket.name)) resp.data[:rules].each do |rule| yield(CORSRule.new(rule)) end rescue AWS::S3::Errors::NoSuchCORSConfiguration # no cors rules exist for this bucket, nothing to yield end def rule_hashes rule case rule when Hash then rule when CORSRule then rule.to_h when CORSRuleCollection then rule.map(&:to_h) when Array then rule.map{|r| rule_hashes(r) }.flatten else msg = "Expected one or more CORSRule, CORSRuleCollection or hash" msg << ", got #{rule.class.name}" raise ArgumentError, msg end end end end end aws-sdk-v1-1.66.0/lib/aws/s3/config.rb0000644000004100000410000000311712604445426017221 0ustar www-datawww-data# Copyright 2011-2013 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. AWS::Core::Configuration.module_eval do add_service 'S3', 's3', 's3' add_option :s3_force_path_style, false, :boolean => true add_option :s3_multipart_threshold, 16 * 1024 * 1024 add_option :s3_multipart_min_part_size, 5 * 1024 * 1024 add_option :s3_multipart_max_parts, 10000 add_option :s3_server_side_encryption, nil add_option :s3_encryption_key, nil add_option :s3_encryption_materials_location, :metadata add_option :s3_encryption_matdesc, '{}' add_option :s3_storage_class, 'STANDARD' add_option :s3_cache_object_attributes, false, :boolean => true add_option :s3_signature_version do |config, value| v3_regions = %w( us-east-1 us-west-1 us-west-2 ap-northeast-1 ap-southeast-1 ap-southeast-2 sa-east-1 eu-west-1 us-gov-west-1 ) if value value elsif config.s3 && config.s3[:signature_version] config.s3[:signature_version] elsif v3_regions.include?(config.s3_region) :v3 else :v4 end end end aws-sdk-v1-1.66.0/lib/aws/s3/bucket_lifecycle_configuration.rb0000644000004100000410000003711312604445426024202 0ustar www-datawww-data# Copyright 2011-2013 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 'nokogiri' module AWS class S3 # A lifecycle configuration specify {Rule rules} that manage the way # Amazon S3 stores objects. The rules apply to objects whose keys match # the rule's prefix. # # ## Rules # # A rule is comprised primarily of an id, prefix and set of # configuration options. Configuration options on the rules can specify: # # * When to expire an object # * When to transition an object to Glacier # * Whether the rule is enabled or disabled # # See {Rule} for more information on all of the attributes and methods # available for rules. # # ## Expiring Objects # # You can add a rule to a bucket lifecycle configuration using {#add_rule} # inside of an {#update} block that will expire an object after a given # number of days: # # # delete backups after they are 1 year old # bucket.lifecycle_configuration.update do # add_rule('backups/', :expiration_time => 365) # end # # You can also define the rule to expire objects at a specific date: # # # delete backups on January 1st of next year # bucket.lifecycle_configuration.update do # date = Date.new(Time.now.year + 1, 01, 01) # add_rule('backups/', :expiration_time => date) # end # # ## Transitioning Objects to Glacier # # You can add a rule to a bucket lifecycle configuration using {#add_rule} # inside of an {#update} block that will transition objects to Glacier # after a given number of days: # # # move backups to Glacier after 3 days # bucket.lifecycle_configuration.update do # add_rule('backups/', :glacier_transition_time => 3) # end # # You can also define the rule to transition objects at a specific date: # # # transition all backups on January 1st of next year # bucket.lifecycle_configuration.update do # date = Date.new(Time.now.year + 1, 01, 01) # add_rule('backups/', :glacier_transition_time => date) # end # # ## Replacing Rules # # If you prefer to completely replace a lifecycle configuration, call # {#add_rule} inside a {#replace} block instead of an `#update` block: # # # replace all existing rules with the following # bucket.lifecycle_configuration.replace do # add_rule('backups/', :glacier_transition_time => 10) # add_rule('temp/', :expiration_time => 30) # end # # ## Removing Rules # # You can delete specific rules with {#remove_rule}. # # # delete all disabled rules # bucket.lifecycle_configuration.update do # rules.each do |rule| # remove_rule(rule) if rule.disabled? # end # end # # You can also remove all rules in a single call with {#clear}: # # # remove all rules from this lifecycle configuration # bucket.lifecycle_configuration.clear # # ## Editing Existing Rules # # You can also make changes to existing rules. # # # change the expiration days to 10 for EVERY rule # bucket.lifecycle_configuration.update do # rules.each do |rule| # rule.expiration_time = 10 # end # end # # Please be aware, if you add, remove or edit rules outside of an # {#update} or {#replace} block, then you must call `#update` yourself # or the changes will not be persisted. # class BucketLifecycleConfiguration # @api private def initialize bucket, options = {} @bucket = bucket @rules = parse_xml(options[:xml]) if options[:xml] @rules = [] if options[:empty] == true end # @return [Bucket] Returns the bucket this lifecycle configuration # belongs to. attr_reader :bucket # @return [Array] Returns an array of rules. def rules @rules ||= begin begin opts = { :bucket_name => bucket.name } response = bucket.client.get_bucket_lifecycle_configuration(opts) parse_xml(response.http_response.body) rescue Errors::NoSuchLifecycleConfiguration [] end end end # @overload add_rule(prefix, options = {}) # @param [String] prefix objects whose keys begin with this prefix # will be affected by the rule. # # @option options [String] :id A unique ID for this rule. If an ID # is not provided, one will be generated. # # @option options [Boolean] :disabled (false) By default, all rules # will have the status of enabled. You can override this default # by passing `:disabled` => true. # # @option options [Date, Integer] :expiration_time (nil) Indicates # the lifetime for objects matching the given prefix. # # @option options [Date, Integer] :glacier_transition_time (nil) # Indicates the time before objects matching the given prefix will # be transitioned into the Amazon Glacier storage tier. # # @return [Rule] Returns the rule that was added, as a {Rule} object. def add_rule prefix, expiration_time = nil, options = {} if Hash === expiration_time options = expiration_time else options[:expiration_time] = expiration_time end id = options[:id] || SecureRandom.uuid opts = { :status => options[:disabled] == true ? 'Disabled' : 'Enabled', :expiration_time => options[:expiration_time], :glacier_transition_time => options[:glacier_transition_time], :noncurrent_version_transition_days => options[:noncurrent_version_transition_days], :noncurrent_version_expiration_days => options[:noncurrent_version_expiration_days] } rule = Rule.new(self, id, prefix, opts) self.rules << rule rule end # Removes a single rule. You can pass a rule id or a {Rule} # object. # # # remove a single rule by its ID # bucket.lifecycle_configuration.update do # remove_rule('rule-id') # end # # # remove all disabled rules # bucket.lifecycle_configuration.update do # rules.each do |rule| # remove_rule(rule) if rule.disabled? # end # end # # If you call #remove_rule outside an update block # you need to call #update to save the changes. # # @param [Rule,String] rule_or_rule_id # # @return [nil] # def remove_rule rule_or_rule_id rule_id = rule_or_rule_id if rule_id.nil? raise ArgumentError, "expected a rule or rule id, got nil" end rule_id = rule_id.id unless rule_id.is_a?(String) @rules = rules.select{|r| r.id != rule_id } nil end # Saves changes made to this lifecycle configuration. # # # set the number of days before expiration for all rules to 10 # config = bucket.lifecycle_configuration # config.rules.each do |rule| # rule.expiration_time = 10 # end # config.update # # You can call #update with a block. Changes are persisted at the # end of the block. # # # shorter version of the example above # bucket.lifecycle_configuration.update do # rules.each {|rule| rule.expiration_time = 10 } # end # # A block method for updating a BucketLifecycleConfiguration. # All modifications made inside the block are persisted at the end of # the block. # # # 1 request # bucket.lifecycle_configuration.update do # add_rule 'prefix/a', 10 # add_rule 'prefix/b', 5 # end # # # 2 requests # bucket.lifecycle_configuration.add_rule 'prefix/a', 10 # bucket.lifecycle_configuration.add_rule 'prefix/b', 5 # # @return [nil] # def update arg = {}, &block begin @batching = true instance_exec(arg, &block) if block_given? persist(true) ensure @batching = false end nil end # Yields to the given block. Before yielding, the current # rules will be blanked out. This allows you to provide all # new rules. # # When the block is complete, a single call will be made to save # the new rules. # # bucket.lifecycle_configuration.rules.size #=> 3 # # # replace the existing 3 rules with a single rule # bucket.lifecycle_configuration.replace # add_rule 'temp/', 10 # end # # bucket.lifecycle_configuration.rules.size #=> 1 def replace &block @rules = [] update(&block) end def clear @rules = [] bucket.lifecycle_configuration = nil end alias_method :remove, :clear # @return [String] Returns an xml string representation of this # bucket lifecycle configuration. def to_xml Nokogiri::XML::Builder.new do |xml| xml.LifecycleConfiguration do rules.each do |rule| xml.Rule do xml.ID rule.id xml.Prefix rule.prefix xml.Status rule.status xml.Expiration do if Integer === rule.expiration_time xml.Days rule.expiration_time else date = rule.expiration_time.to_s xml.Date "#{date}T00:00:00Z" end end if rule.expiration_time xml.Transition do xml.StorageClass 'GLACIER' if Integer === rule.glacier_transition_time xml.Days rule.glacier_transition_time else date = rule.glacier_transition_time.to_s xml.Date "#{date}T00:00:00Z" end end if rule.glacier_transition_time xml.NoncurrentVersionTransition do xml.StorageClass 'GLACIER' xml.NoncurrentDays rule.noncurrent_version_transition_days end if rule.noncurrent_version_transition_days xml.NoncurrentVersionExpiration do xml.NoncurrentDays rule.noncurrent_version_expiration_days end if rule.noncurrent_version_expiration_days end end end end.doc.root.to_xml end protected def persist force = false unless @batching and force == false if rules.empty? bucket.lifecycle_configuration = nil else bucket.lifecycle_configuration = self end end end # Represents a single rule from an Amazon S3 bucket lifecycle # configuration. # # # delete all objects with the prefix 'temporary/' after 10 days # bucket.lifecycle_configuration.add_rule 'temporary/', 10 # # # remove the rule created above # bucket.lifecycle_configuration.remove_rule 'temporary/' # # class Rule # @api private def initialize configuration, id, prefix, expiration_time = nil, status = nil @configuration = configuration @id = id @prefix = prefix if Hash === expiration_time options = expiration_time options.each do |key, value| send("#{key}=", value) if respond_to?("#{key}=") end else self.expiration_time = expiration_time self.status = status end end # @return [BucketLifecycleConfiguration] attr_reader :configuration # @return [String] attr_reader :id # @return [String] attr_accessor :prefix # @return [Date] the date the objects will expire # @return [Integer] if the value is an integer, returns the number # of days before the object will expire. attr_reader :expiration_time # Converts any time values to Date objects def expiration_time=(value) @expiration_time = convert_time_value(value) end alias expiration_days expiration_time alias expiration_days= expiration_time= # @return [Date] the date the objects will be # transitioned into the Amazon Glacier storage tier. # @return [Integer] if the value is an integer, returns the number # of days before the object is transitioned into the Amazon Glacier # storage tier. attr_reader :glacier_transition_time # Converts any time values to Date objects def glacier_transition_time=(value) @glacier_transition_time = convert_time_value(value) end # @return [Integer] attr_accessor :noncurrent_version_transition_days # @return [Integer] attr_accessor :noncurrent_version_expiration_days # @return [String] Returns the rule status, 'Enabled' or 'Disabled' attr_accessor :status def enabled? status == 'Enabled' end def enable! self.status = 'Enabled' end def disabled? status == 'Disabled' end def disabled! self.status = 'Disabled' end # @api private def eql? other other.is_a?(Rule) and other.configuration.bucket == configuration.bucket and other.id == id and other.prefix == prefix and other.expiration_time == expiration_time and other.glacier_transition_time == glacier_transition_time and other.status == status and other.noncurrent_version_transition_days == noncurrent_version_transition_days and other.noncurrent_version_expiration_days == noncurrent_version_expiration_days end alias_method :==, :eql? private # If an integer, returns the integer as days, otherwise # converts any time-like values into Date objects # @return [Integer] if the value is an integer # @return [Date] if the value is a time-like object # @return [nil] if the value is nil def convert_time_value(value) return nil if value.nil? return value if value.is_a?(Integer) Date.parse(value.to_s) end end protected def parse_xml xml Client::XML::GetBucketLifecycleConfiguration.parse(xml).rules.map do |r| opts = { :status => r[:status] } if r[:expiration] opts[:expiration_time] = r[:expiration][:days] || r[:expiration][:date] end if r[:transition] opts[:glacier_transition_time] = r[:transition][:days] || r[:transition][:date] end Rule.new(self, r[:id], r[:prefix], opts) end end end end end aws-sdk-v1-1.66.0/lib/aws/s3/prefixed_collection.rb0000644000004100000410000000524312604445426021777 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 module PrefixedCollection include PaginatedCollection # @api private def initialize *args options = args.last.is_a?(Hash) ? args.pop : {} @prefix = options[:prefix] args.push(options) super(*args) end # @return [String,nil] The prefix of this collection. attr_reader :prefix # Returns a new collection with a different prefix # # @example # # objects = collection.with_prefix('photos') # objects.prefix #=> 'photos' # # @example Chaining with_prefix replaces previous prefix # # objects = collection.with_prefix('photos').with_prefix('videos') # objects.prefix #=> 'videos' # # @example Chaining with_prefix with :append # # objects = collection.with_prefix('a/').with_prefix('b/', :append) # objects.prefix #=> 'a/b/' # # @example Chaining with_prefix with :prepend # # objects = collection.with_prefix('a/').with_prefix('b/', :prepend) # objects.prefix #=> 'b/a/' # # @param [String] prefix The prefix condition that limits what objects # are returned by this collection. # @param [Symbol] mode (:replace) If you chain calls to #with_prefix # the `mode` affects if the prefix prepends, appends, or replaces. # Valid modes are: # * `:replace` # * `:append` # * `:prepend` # @return [Collection] Returns a new collection with a modified prefix. def with_prefix prefix, mode = :replace new_prefix = case mode when :replace then prefix when :append then "#{@prefix}#{prefix}" when :prepend then "#{prefix}#{@prefix}" else raise ArgumentError, "invalid prefix mode `#{mode}`, it must be " + ":replace, :append or :prepend" end self.class.new(bucket, :prefix => new_prefix) end # @api private protected def list_options(options) opts = super opts[:prefix] = prefix if prefix opts end end end end aws-sdk-v1-1.66.0/lib/aws/s3/bucket_tag_collection.rb0000644000004100000410000000521212604445426022275 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # Manages tags for a single S3 {Bucket}. # # @example Setting a tag. # # bucket.tags['key'] = 'value' # # @example Getting a tag. # # bucket.tags['key'] # #=> 'value' # # @example Getting all tags # # bucket.tags.to_h # #=> { 'key' => 'value', ... } # # @example Removing all tags # # bucket.tags.clear # class BucketTagCollection include Core::Model # @param [Bucket] bucket # @param [Hash] options def initialize bucket, options = {} @bucket = bucket super end # @return [Bucket] attr_reader :bucket # @param [String] key # @return [String,nil] Returns the tag for the given key. If there # Returns `nil` if the key does not exist. def [] key self.to_h[key] end # @param [String] key # @param [String] value def []= key, value self.set(self.to_h.merge(key => value)) end # @param [Hash] tags A hash of tag keys and values. # @return [nil] def set tags if tags.nil? or tags.empty? self.clear else client.put_bucket_tagging(:bucket_name => bucket.name, :tags => tags) end nil end # Removes all tags from the bucket. # # @example # # bucket.tags.clear # bucket.tags.to_h #=> {} # # @return [nil] def clear client.delete_bucket_tagging(:bucket_name => bucket.name) nil end # @return [Hash] def to_h client.get_bucket_tagging(:bucket_name => bucket.name).data[:tags] rescue AWS::S3::Errors::NoSuchTagSet {} end alias_method :to_hash, :to_h # @param [Hash] other # @return [Boolean] Returns `true` if the tags for this bucket match # the passed hash. def eql? other self.to_h == other end alias_method :==, :eql? # @api private def inspect self.to_h.inspect end end end end aws-sdk-v1-1.66.0/lib/aws/s3/encryption_utils.rb0000644000004100000410000001166112604445426021371 0ustar www-datawww-data# Copyright 2011-2013 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 'openssl' module AWS class S3 # @api private module EncryptionUtils protected UNSAFE_MSG = "Unsafe encryption, data is longer than key length" # @param [OpenSSL::PKey::RSA, String] key Key used to encrypt. # # @param [String] data Data to be encrypted. # # @note Use check_encryption_materials before this method to check # formatting of keys. # @note This should not be used for data longer than the key length as # it will not be cryptographically safe. # # @return [String] Returns the data encrypted with the key given. def encrypt data, key rsa = OpenSSL::PKey::RSA data_cipher_size = get_cipher_size(data.length) # Encrypting data key case key when rsa # Asymmetric encryption warn UNSAFE_MSG if key.public_key.n.num_bits < data_cipher_size key.public_encrypt(data) when String # Symmetric encryption warn UNSAFE_MSG if get_cipher_size(key.length) < data_cipher_size cipher = get_aes_cipher(:encrypt, :ECB, key) cipher.update(data) + cipher.final end end # @param [OpenSSL::PKey::RSA, String] key Key used to encrypt. # # @param [String] data Data to be encrypted. # # @note Use check_encryption_materials before this method to check # formatting of keys # # @return [String] Returns the data decrypted with the key given. def decrypt data, key rsa = OpenSSL::PKey::RSA begin case key when rsa # Asymmetric Decryption key.private_decrypt(data) when String # Symmetric Decryption cipher = get_aes_cipher(:decrypt, :ECB, key) cipher.update(data) + cipher.final end rescue OpenSSL::Cipher::CipherError raise RuntimeError, "decryption failed, incorrect key?" end end # Checks for any formatting problems for keys and initialization vectors # supported with EncryptionUtils. def check_encryption_materials mode, key rsa = OpenSSL::PKey::RSA case key when rsa unless key.private? or mode == :encrypt msg = "invalid key, #{rsa} requires a private key" raise ArgumentError, msg end when String # no problem else msg = "invalid key, must be an #{rsa} or a cipher key string" raise ArgumentError, msg end end # @param [OpenSSL::Cipher] cipher The cipher with configured key and iv. # # @yield [String, String] key_iv_pair A randomly generated key, iv pair # for use with the given cipher. Sets the key and iv on the cipher. def generate_aes_key cipher, &block key_iv_pair = [cipher.random_key, cipher.random_iv] yield(key_iv_pair) if block_given? end # @param [Symbol] mode The encryption/decryption mode. Valid inputs are # :encrypt or :decrypt # # @param [String] key Key for the cipher. # # @param [String] iv IV for the cipher. # # @return [OpenSSL::Cipher] Will return a configured `OpenSSL::Cipher`. def get_aes_cipher mode, block_mode, key = nil, iv = nil # If no key given, default to 256 bit cipher_size = (key) ? get_cipher_size(key.length) : 256 cipher = OpenSSL::Cipher.new("AES-#{cipher_size}-#{block_mode}") (mode == :encrypt) ? cipher.encrypt : cipher.decrypt cipher.key = key if key cipher.iv = iv if iv cipher end # @param [Integer] size Size of data given. # @return [Integer] Returns the AES encrypted size based on a given size. def get_encrypted_size size # The next multiple of 16 ((size / 16) + 1) * 16 end module_function :get_encrypted_size private # @param [Fixnum] key_length Length of the key given. # @return [Fixnum] Returns the cipher size based on the key length. def get_cipher_size(key_length) case key_length when 32 then 256 when 24 then 192 when 16 then 128 else msg = "invalid key, symmetric key required to be 16, 24, or 32 bytes " msg << "in length, saw length #{key_length}" raise ArgumentError, msg end end end end end aws-sdk-v1-1.66.0/lib/aws/s3/region_detection.rb0000644000004100000410000000451712604445426021302 0ustar www-datawww-datarequire 'cgi' module AWS class S3 # @api private module RegionDetection private def retry_server_errors(&block) response = super if requires_sigv4?(response) detect_region_and_retry(response, &block) else response end end def requires_sigv4?(resp) resp.http_response.status == 400 && resp.http_response.body && resp.http_response.body.include?('Please use AWS4-HMAC-SHA256') end def detect_region_and_retry(response, &retry_block) updgrade_to_v4(response, 'us-east-1') yield return if response.http_response.status == 200 actual_region = region_from_location_header(response) updgrade_to_v4(response, actual_region) log_region_warning(response, actual_region) yield end def updgrade_to_v4(response, region) bucket = response.request_options[:bucket_name] if response.http_request.body_stream.respond_to?(:rewind) response.http_request.body_stream.rewind end response.http_request.headers.delete('authorization') response.http_request.headers.delete('x-amz-security-token') response.http_request.host = new_hostname(response, region) new_v4_signer(region).sign_request(response.http_request) end def region_from_location_header(response) location = response.http_response.headers['location'].first location.match(/s3\.(.+?)\.amazonaws\.com/)[1] end def new_v4_signer(region) Core::Signers::Version4.new(credential_provider, 's3', region) end def new_hostname(response, region) bucket = response.request_options[:bucket_name] if region == 'us-east-1' 's3-external-1.amazonaws.com' else "s3.#{region}.amazonaws.com" end end def log_region_warning(response, actual_region) bucket_name = response.request_options[:bucket_name] S3::BUCKET_REGIONS[bucket_name] = actual_region log_warning("S3 client configured for #{@region.inspect} " + "but the bucket #{bucket_name.inspect} is in" + "#{actual_region.inspect}; Please configure the proper region " + "to avoid multiple unecessary redirects and signing attempts\n") end end end end aws-sdk-v1-1.66.0/lib/aws/s3/object_metadata.rb0000644000004100000410000000655312604445426021071 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # Returns an object that represents the metadata for an S3 object. class ObjectMetadata include Core::Model # @param [S3Object] object # @param [Hash] options # @option options [String] :version_id A specific version of the object # to get metadata for def initialize object, options = {} @object = object @version_id = options[:version_id] super end # @return [S3Object] attr_reader :object # Returns the value for the given name stored in the S3Object's # metadata: # # bucket.objects['myobject'].metadata['purpose'] # # returns nil if the given metadata key has not been set # # @param [String,Symbol] name The name of the metadata field to # get. # # @return [String,nil] Returns the metadata for the given name. def [] name to_h[name.to_s] end # Changes the value of the given name stored in the S3Object's # metadata: # # object = bucket.object['myobject'] # object.metadata['purpose'] = 'research' # object.metadata['purpose'] # => 'research' # # @deprecated In order to safely update an S3 object's metadata, you # should use {S3Object#copy_from}. This operation does not preserve # the ACL, storage class (standard vs. reduced redundancy) or server # side encryption settings. Using this method on anything other than # vanilla S3 objects risks clobbering other metadata values set on the # object. # # @note The name and value of each metadata field must conform # to US-ASCII. # # @param [String,Symbol] name The name of the metadata field to # set. # # @param [String] value The new value of the metadata field. # # @return [String,nil] Returns the value that was set. def []= name, value raise "cannot change the metadata of an object version; "+ "use S3Object#write to create a new version with different metadata" if @version_id metadata = to_h.dup metadata[name.to_s] = value object.copy_from(object.key, :metadata => metadata) value end # Proxies the method to {#[]}. # @return (see #[]) def method_missing name, *args, &blk return super if !args.empty? || blk self[name] end # @return [Hash] Returns the user-generated metadata stored with # this S3 Object. def to_h options = {} options[:bucket_name] = object.bucket.name options[:key] = object.key options[:version_id] = @version_id if @version_id client.head_object(options).meta end end end end aws-sdk-v1-1.66.0/lib/aws/s3/access_control_list.rb0000644000004100000410000002046512604445426022015 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # Represents an access control list for S3 objects and buckets. For example: # # acl = AccessControlList.new # acl.grant(:full_control). # to(:canonical_user_id => "8a6925ce4adf588a4f21c32aa379004fef") # acl.to_xml # => '...' # # You can also construct an AccessControlList from a hash: # # AccessControlList.new( # :owner => { :id => "8a6925ce4adf588a4f21c32aa379004fef" }, # :grants => [{ # :grantee => { :canonical_user_id => "8a6925ce4adf588a4f21c32aa379004fef" }, # :permission => :full_control, # }] # ) # # @see ACLObject # # @attr [AccessControlList::Owner] owner The owner of the access # control list. You can set this as a hash, for example: # acl.owner = { :id => '8a6925ce4adf588a4f21c32aa379004fef' } # This attribute is required when setting an ACL. # # @attr [list of AccessControlList::Grant] grants The list of # grants. You can set this as a list of hashes, for example: # # acl.grants = [{ # :grantee => { :canonical_user_id => "8a6925ce4adf588a4f21c32aa379004fef" }, # :permission => :full_control, # }] class AccessControlList # Represents an ACL owner. In the default ACL, this is the # bucket owner. # # @attr [String] id The canonical user ID of the ACL owner. # This attribute is required when setting an ACL. # # @attr [String] display_name The display name of the ACL # owner. This value is ignored when setting an ACL. class Owner include ACLObject string_attr "ID", :required => true string_attr "DisplayName" end # Represents a user who is granted some kind of permission # through a Grant. There are three ways to specify a grantee: # # * You can specify the canonical user ID, for example. When # you read an ACL from S3, all grantees will be identified # this way, and the display_name attribute will also be provided. # # Grantee.new(:canonical_user_id => "8a6925ce4adf588a4f21c32aa379004fef") # # * You can specify the e-mail address of an AWS customer, for example: # # Grantee.new(:amazon_customer_email => 'foo@example.com') # # * You can specify a group URI, for example: # # Grantee.new(:group_uri => 'http://acs.amazonaws.com/groups/global/AllUsers') # # For more details about group URIs, see: # http://docs.aws.amazon.com/AmazonS3/latest/dev/ACLOverview.html # # When constructing a grantee, you must provide a value for # exactly one of the following attributes: # # * `amazon_customer_email` # * `canonical_user_id` # * `group_uri` # # @attr [String] amazon_customer_email The e-mail address of # an AWS customer. # # @attr [String] canonical_user_id The canonical user ID of an # AWS customer. # # @attr [String] group_uri A URI that identifies a particular # group of users. # # @attr [String] display_name The display name associated with # the grantee. This is provided by S3 when reading an ACL. class Grantee include ACLObject SIGNAL_ATTRIBUTES = [ :amazon_customer_email, :canonical_user_id, :group_uri, :uri, ] string_attr "EmailAddress", :method_name => "amazon_customer_email" string_attr "ID", :method_name => "canonical_user_id" string_attr "URI", :method_name => "group_uri" string_attr "URI", :method_name => "uri" string_attr "DisplayName" # (see ACLObject#validate!) def validate! attr = signal_attribute raise "missing amazon_customer_email, canonical_user_id, "+ "or group_uri" unless attr raise "display_name is invalid with #{attr}" if attr != :canonical_user_id and display_name end # @api private def stag if attr = signal_attribute super + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" + " xsi:type=\"#{type_for_attr(attr)}\"" else super end end # @api private def signal_attribute SIGNAL_ATTRIBUTES.find { |att| send(att) } end # @api private def type_for_attr(attr) { :amazon_customer_email => "AmazonCustomerByEmail", :canonical_user_id => "CanonicalUser", :group_uri => "Group", :uri => "Group", }[attr] end end # Represents the permission being granted in a Grant object. # Typically you will not need to construct an instance of this # class directly. # @see Grant#permission class Permission include ACLObject # The permission expressed as a symbol following Ruby # conventions. For example, S3's FULL_CONTROL permission # will be returned as `:full_control`. attr_reader :name # @api private def initialize(name) raise "expected string or symbol" unless name.respond_to?(:to_str) or name.respond_to?(:to_sym) @name = name.to_sym end def body_xml name.to_s.upcase end end # Represents a single grant in an ACL. Both `grantee` and # `permission` are required for each grant when setting an # ACL. # # See # http://docs.aws.amazon.com/AmazonS3/latest/dev/ACLOverview.html # for more information on how grantees and permissions are # interpreted by S3. # # @attr [Grantee] grantee The user or users who are granted # access according to this grant. You can specify this as a # hash: # # grant.grantee = { :amazon_customer_email => "foo@example.com" } # # @attr [Permission or Symbol] permission The type of # permission that is granted by this grant. Valid values are: # * `:read` # * `:write` # * `:read_acp` # * `:write_acp` # * `:full_control` class Grant include ACLObject object_attr Grantee, :required => true object_attr Permission, :required => true, :cast => Symbol end include ACLObject # @api private def stag super()+" xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"" end # @api private def element_name "AccessControlPolicy" end class GrantBuilder # @api private def initialize(acl, grant) @acl = acl @grant = grant end # Specifies the grantee. # # @param [Grantee or Hash] grantee A Grantee object or hash; # for example: # # acl.grant(:full_control).to(:amazon_customer_email => "foo@example.com") def to(grantee) @grant.grantee = grantee @acl.grants << @grant end end # Convenience method for constructing a new grant and adding # it to the ACL. # # @example # # acl.grants.size # => 0 # acl.grant(:full_control).to(:canonical_user_id => "8a6925ce4adf588a4f21c32aa379004fef") # acl.grants.size # => 1 # # @return [GrantBuilder] def grant(permission) GrantBuilder.new(self, Grant.new(:permission => permission)) end object_attr Owner, :required => true object_list_attr("AccessControlList", Grant, :required => true, :method_name => :grants) end end end aws-sdk-v1-1.66.0/lib/aws/s3/prefix_and_delimiter_collection.rb0000644000004100000410000000231312604445426024341 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # @api private module PrefixAndDelimiterCollection include PrefixedCollection # @see Bucket#as_tree def as_tree options = {} Tree.new(self, { :prefix => prefix }.merge(options)) end # @api private protected def each_member_in_page(page, &block) super page.common_prefixes.each do |p| yield(with_prefix(p[:prefix])) end end # @api private protected def list_options(options) opts = super opts[:delimiter] = options[:delimiter] if options.key?(:delimiter) opts end end end end aws-sdk-v1-1.66.0/lib/aws/s3/website_configuration.rb0000644000004100000410000000712612604445426022351 0ustar www-datawww-data# Copyright 2011-2013 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 'uri' require 'base64' module AWS class S3 class WebsiteConfiguration # @option options [Hash] :redirect_all_requests_to # Describes the redirect behavior for every request to this # bucket's website endpoint. If this element is present, no # other options are are allowed. # * `:host_name` - (*required*, String) # Name of the host where requests will be redirected. # * `:protocol` - (String) # Protocol to use (http, https) when redirecting requests. The # default is the protocol that is used in the original request. # @option options [Hash] :index_document # * `:suffix` - (*required*, String) - A suffix that is appended to # a request that is for a directory on the website endpoint # (e.g. if the suffix is index.html and you make a request to # samplebucket/images/ the data that is returned will be for # the object with the key name images/index.html). # The suffix must not be empty and must not include a # slash character. # @option options [Hash] :error_document # * `:key` - (*required*, String) - The object key name to use # when a 4XX class error occurs. # @option options [Array] :routing_rules # * `:redirect` - (*required*, Hash) # * `:host_name` - (String) # * `:protocol` - (String) # * `:replace_key_prefix_with` - (String) # * `:replace_key_with` - (String) # * `:http_redirect_code` - (String) # * `:condition` - (Hash) # * `:key_prefix_equals` - (String) # * `:http_error_code_returned_equals` - (String) def initialize options = {} @options = deep_copy(options) if @options.empty? @options[:index_document] = { :suffix => 'index.html' } @options[:error_document] = { :key => 'error.html' } end end # @return [Hash] attr_reader :options alias_method :to_hash, :options # This method exists for backwards compatability. # @return [String,nil] # @api private def index_document_suffix (@options[:index_document] || {})[:suffix] end # This method exists for backwards compatability. # @api private def index_document_suffix= suffix @options.delete(:redirect_all_requests_to) @options[:index_document] ||= {} @options[:index_document][:suffix] = suffix end # This method exists for backwards compatability. # @return [String,nil] # @api private def error_document_key (@options[:error_document] || {})[:key] end # This method exists for backwards compatability. # @api private def error_document_key= key @options.delete(:redirect_all_requests_to) @options[:error_document] ||= {} @options[:error_document][:key] = key end private def deep_copy hash Marshal.load(Marshal.dump(hash)) end end end end aws-sdk-v1-1.66.0/lib/aws/s3/multipart_upload_collection.rb0000644000004100000410000000437712604445426023565 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # Represents the uploads in progress for a bucket. # # Note: After you initiate multipart upload and upload one or more # parts, you must either complete or abort multipart upload in order # to stop getting charged for storage of the uploaded parts. Only # after you either complete or abort multipart upload, Amazon S3 frees # up the parts storage and stops charging you for the parts storage. # # @example Finding uploads by prefix # # bucket.multipart_uploads.with_prefix("photos/"). # map { |upload| upload.object.key } # # => ["photos/1.jpg", "photos/2.jpg", ...] # # @example Browsing with a tree interface # # bucket.multipart_uploads.with_prefix("photos").as_tree. # children.select(&:branch?).map(&:prefix) # # => ["photos/2010", "photos/2011", ...] # # @see Tree class MultipartUploadCollection include Enumerable include Core::Model include PrefixAndDelimiterCollection # @return [Bucket] The bucket in which the uploads are taking # place. attr_reader :bucket # @api private def initialize(bucket, opts = {}) @bucket = bucket super end protected def each_member_in_page(page, &block) super page.uploads.each do |u| object = S3Object.new(bucket, u.key) upload = MultipartUpload.new(object, u.upload_id) yield(upload) end end def list_request(options) client.list_multipart_uploads(options) end def limit_param; :max_uploads; end def pagination_markers; super + [:upload_id_marker]; end end end end aws-sdk-v1-1.66.0/lib/aws/s3/object_version.rb0000644000004100000410000001116612604445426020772 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # Represents a single version of an S3Object. # # When you enable versioning on a S3 bucket, writing to an object # will create an object version instead of replacing the existing # object. class ObjectVersion include Core::Model # @param [S3Object] object The object this is a version of. # @param [String] version_id The unique id for this version. # @param [Hash] options # @option options [Boolean] :delete_marker Is this version a # delete marker? # @option options [DateTime] :last_modified Date and time the # object was last modified. def initialize(object, version_id, options = {}) @object = object @version_id = version_id @delete_marker = options[:delete_marker] @last_modified = options[:last_modified] super end # @return [S3Object] the object this is a version of. attr_reader :object # @return [DateTime] timestamp of this version attr_reader :last_modified def bucket object.bucket end # @return [String] The unique version identifier. attr_reader :version_id # @return (see S3Object#key) def key object.key end # (see S3Object#url_for) def url_for method, options = {} object.url_for(method, options.merge(:version_id => version_id)) end # @see S3Object#head # @return (see S3Object#head) def head object.head(:version_id => @version_id) end # @see S3Object#etag # @return (see S3Object#etag) def etag head.etag end # @return (see S3Object#content_length) def content_length head.content_length end # @note (see S3Object#content_type) # @see S3Object#content_type # @return (see S3Object#content_type) def content_type head.content_type end # @see S3Object#metadata # @return (see S3Object#metadata) def metadata object.metadata(:version_id => @version_id) end # Reads the data from this object version. # @see S3Object#read # @options (see S3Object#read) # @return (see S3Object#read) def read options = {}, &block object.read(options.merge(:version_id => @version_id), &block) end # Deletes this object version from S3. # @option options [String] :mfa The serial number and current token code of # the Multi-Factor Authentication (MFA) device for the user. Format # is "SERIAL TOKEN" - with a space between the serial and token. # @return (see S3Object#delete) def delete(options = {}) object.delete(:version_id => @version_id, :mfa => options[:mfa] ) end # @return [Boolean] Returns this if this is the latest version of # the object, false if the object has been written to since # this version was created. def latest? object.versions.latest.version_id == self.version_id end # If you delete an object in a versioned bucket, a delete marker # is created. # @return [Boolean] Returns true if this version is a delete marker. def delete_marker? if @delete_marker.nil? begin # S3 responds with a 405 (method not allowed) when you try # to HEAD an s3 object version that is a delete marker metadata['foo'] @delete_marker = false rescue Errors::MethodNotAllowed => error @delete_marker = true end end @delete_marker end # @return [Boolean] Returns true if the other object version has # the same s3 object key and version id. def ==(other) other.kind_of?(ObjectVersion) and other.object == object and other.version_id == version_id end alias_method :eql?, :== # @api private def inspect "<#{self.class}:#{object.bucket.name}:#{object.key}:#{version_id}>" end end end end aws-sdk-v1-1.66.0/lib/aws/s3/cors_rule.rb0000644000004100000410000001002012604445426017740 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # Represents a single CORS rule for an S3 {Bucket}. # # @example # # rule = bucket.cors.first # rule.allowed_methods #=> ['GET', 'HEAD'] # rule.allowed_origins #=> ['*'] # # @see CORSRuleCollection class CORSRule # @param [Hash] options A hash of the rule details. # # @option options [String] :id A unique identifier for the rule. The ID # value can be up to 255 characters long. The IDs help you find # a rule in the configuration. # # @option options [required,Array] :allowed_methods A list of HTTP # methods that you want to allow the origin to execute. # Each rule must identify at least one method. # # @option options [required,Array] :allowed_origins A list of # origins you want to allow cross-domain requests from. This can # contain at most one * wild character. # # @option options [Array] :allowed_headers A list of headers # allowed in a pre-flight OPTIONS request via the # Access-Control-Request-Headers header. Each header name # specified in the Access-Control-Request-Headers header must # have a corresponding entry in the rule. # # Amazon S3 will send only the allowed headers in a response # that were requested. This can contain at most one '*' wild # character. # # @option options [Array] :max_age_seconds The time in # seconds that your browser is to cache the pre-flight response for # the specified resource. # # @option options [Array] :expose_headers One or more headers in # the response that you want customers to be able to access # from their applications (for example, from a JavaScript # XMLHttpRequest object). # def initialize options = {} @id = options[:id] @allowed_methods = options[:allowed_methods] || [] @allowed_origins = options[:allowed_origins] || [] @allowed_headers = options[:allowed_headers] || [] @max_age_seconds = options[:max_age_seconds] @expose_headers = options[:expose_headers] || [] end # @return [String,nil] A user supplied unique identifier for this role. # Set this when you set or add roles via {CORSRuleCollection}. attr_reader :id # @return [Array] A list of HTTP methods (GET, POST, etc) this # role authorizes. attr_reader :allowed_methods # @return [Array] The list of origins allowed to make # cross-domain requests to the bucket. attr_reader :allowed_origins # @return [Array] A list of headers allowed in the pre-flight # OPTIONS request. attr_reader :allowed_headers # @return [Integer,nil] The time in seconds the browser may cache the # pre-flight response. attr_reader :max_age_seconds # @return [Array] The headers that may be accessed cross-domain. attr_reader :expose_headers # @return [Hash] def to_h h = {} h[:id] = id if id h[:allowed_methods] = allowed_methods h[:allowed_origins] = allowed_origins h[:allowed_headers] = allowed_headers unless allowed_headers.empty? h[:max_age_seconds] = max_age_seconds if max_age_seconds h[:expose_headers] = expose_headers unless expose_headers.empty? h end end end end aws-sdk-v1-1.66.0/lib/aws/s3/uploaded_part_collection.rb0000644000004100000410000000437712604445426023023 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # Represents the collection of parts that have been uploaded for # a given multipart upload. You can get an instance of this # class by calling {MultipartUpload#parts}. # # @example Get the total size of the uploaded parts # upload.parts.inject(0) { |sum, part| sum + part.size } class UploadedPartCollection include Enumerable include Core::Model include PaginatedCollection # @return [MultipartUpload] The upload to which the parts belong. attr_reader :upload # @api private def initialize(upload, opts = {}) @upload = upload super end # @return [UploadedPart] An object representing the part with # the given part number. # # @param [Integer] number The part number. def [](number) UploadedPart.new(upload, number) end # @api private protected def each_member_in_page(page, &block) page.parts.each do |part_info| part = UploadedPart.new(upload, part_info.part_number, :etag => part_info.etag) yield(part) end end # @api private protected def list_options(options) opts = super opts.merge!(:bucket_name => upload.object.bucket.name, :key => upload.object.key, :upload_id => upload.id) opts end # @api private protected def limit_param; :max_parts; end # @api private protected def list_request(options) client.list_parts(options) end # @api private protected def pagination_markers [:part_number_marker] end end end end aws-sdk-v1-1.66.0/lib/aws/s3/acl_object.rb0000644000004100000410000002053212604445426020041 0ustar www-datawww-data# Copyright 2011-2013 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 'rexml/text' module AWS class S3 # Common methods for AccessControlList and related objects. module ACLObject # @api private def initialize(opts = {}); end # @api private def body_xml; ""; end # @api private def stag element_name end # @api private def element_name self.class.name[/::([^:]*)$/, 1] end # Returns the XML representation of the object. Generally # you'll want to call this on an AccessControlList object, # which will yield an XML representation of the ACL that you # can send to S3. def to_s if body_xml.empty? "<#{stag}/>" else "<#{stag}>#{body_xml}" end end # (see #to_s) def to_xml to_s end # Returns true if and only if this object is valid according # to S3's published ACL schema. In particular, this will # check that all required attributes are provided and that # they are of the correct type. def valid? validate! rescue => e false else true end # Raises an exception unless this object is valid according to # S3's published ACL schema. # @see #valid? def validate!; end # @api private def validate_input(name, value, context = nil) send("validate_#{name}_input!", value, context) end # @api private module ClassMethods def string_attr(element_name, options = {}) method_name = options[:method_name] || Core::Inflection.ruby_name(element_name) attr_accessor(method_name) setter_option(method_name) string_input_validator(method_name) validate_string(method_name) if options[:required] body_xml_string_content(element_name, method_name) end def object_attr(klass, options = {}) base_name = klass.name[/::([^:]*)$/, 1] method_name = Core::Inflection.ruby_name(base_name) cast = options[:cast] || Hash attr_reader(method_name) setter_option(method_name) object_setter(klass, method_name, cast) object_input_validator(klass, base_name, method_name, cast) validate_object(method_name) if options[:required] body_xml_content(method_name) end def object_list_attr(list_element, klass, options = {}) base_name = klass.name[/::([^:]*)$/, 1] method_name = Core::Inflection.ruby_name(options[:method_name].to_s || list_element) default_value = nil default_value = [] if options[:required] attr_reader(method_name) setter_option(method_name) { [] if options[:required] } object_list_setter(klass, method_name) object_list_input_validator(klass, base_name, method_name) validate_list(method_name) body_xml_list_content(list_element, method_name) end def setter_option(method_name) Core::MetaUtils.class_extend_method(self, :initialize) do |*args| opts = args.last || {} instance_variable_set("@#{method_name}", yield) if block_given? key = method_name.to_sym if opts.has_key?(key) value = opts[key] validate_input(method_name, value, "for #{method_name} option") self.send("#{method_name}=", value) end super(opts) end end def string_input_validator(method_name) input_validator(method_name) do |value, context| raise ArgumentError.new("expected string"+context) unless value.respond_to?(:to_str) end end def object_input_validator(klass, base_name, method_name, cast) input_validator(method_name) do |value, context| if value.kind_of?(cast) klass.new(value).validate! else raise ArgumentError.new("expected #{base_name} object or hash"+context) unless value.nil? or value.kind_of? klass end end end def object_list_input_validator(klass, base_name, method_name) input_validator(method_name) do |value, context| raise ArgumentError.new("expected array"+context) unless value.kind_of?(Array) value.each do |member| if member.kind_of?(Hash) klass.new(member).validate! else raise ArgumentError.new("expected array#{context} "+ "to contain #{base_name} objects "+ "or hashes") unless member.kind_of? klass end end end end def input_validator(method_name, &blk) validator = "__validator__#{blk.object_id}" Core::MetaUtils.class_extend_method(self, validator, &blk) Core::MetaUtils.class_extend_method(self, "validate_#{method_name}_input!") do |*args| (value, context) = args context = " "+context if context context ||= "" send(validator, value, context) end end def object_setter(klass, method_name, cast) define_method("#{method_name}=") do |value| validate_input(method_name, value) if value.kind_of?(cast) value = klass.new(value) end instance_variable_set("@#{method_name}", value) end end def object_list_setter(klass, method_name) define_method("#{method_name}=") do |value| validate_input(method_name, value) list = value.map do |member| if member.kind_of?(Hash) klass.new(member) else member end end instance_variable_set("@#{method_name}", list) end end def validate_string(method_name) Core::MetaUtils.class_extend_method(self, :validate!) do super() raise "missing #{method_name}" unless send(method_name) end end def validate_object(method_name) Core::MetaUtils.class_extend_method(self, :validate!) do super() raise "missing #{method_name}" unless send(method_name) send(method_name).validate! end end def validate_list(method_name) Core::MetaUtils.class_extend_method(self, :validate!) do super() raise "missing #{method_name}" unless send(method_name) send(method_name).each { |member| member.validate! } end end def body_xml_string_content(element_name, method_name) add_xml_child(method_name) do |value| normalized = REXML::Text.normalize(value.to_s) "<#{element_name}>#{normalized}" end end def body_xml_content(method_name) add_xml_child(method_name) { |value| value.to_s } end def body_xml_list_content(list_element, method_name) add_xml_child(method_name) do |list| list_content = list.map { |member| member.to_s }.join if list_content.empty? "<#{list_element}/>" else "<#{list_element}>#{list_content}" end end end def add_xml_child(method_name) Core::MetaUtils.class_extend_method(self, :body_xml) do xml = super() value = send(method_name) xml += yield(value) if value xml end end end def self.included(m) m.extend(ClassMethods) end end end end aws-sdk-v1-1.66.0/lib/aws/s3/object_collection.rb0000644000004100000410000002412312604445426021435 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class S3 # Represents a collection of S3 objects. # # ## Getting an S3Object by Key # # If you know the key of the object you want, you can reference it this way: # # # this will not make any requests against S3 # object = bucket.objects['foo.jpg'] # object.key #=> 'foo.jpg' # # ## Finding objects with a Prefix # # Given a bucket with the following keys: # # photos/sunset.jpg # photos/sunrise.jpg # photos/winter.jpg # videos/comedy.mpg # videos/dancing.mpg # # You can list objects that share a prefix: # # bucket.objects.with_prefix('videos').collect(&:key) # #=> ['videos/comedy.mpg', 'videos/dancing.mpg'] # # ## Exploring Objects with a Tree Interface # # Given a bucket with the following keys: # # README.txt # videos/wedding.mpg # videos/family_reunion.mpg # photos/2010/house.jpg # photos/2011/fall/leaves.jpg # photos/2011/summer/vacation.jpg # photos/2011/summer/family.jpg # # tree = bucket.objects.with_prefix('photos').as_tree # # directories = tree.children.select(&:branch?).collect(&:prefix) # #=> ['photos/2010', 'photos/2011'] # class ObjectCollection include Core::Model include Enumerable include PrefixAndDelimiterCollection # @param [Bucket] bucket The S3 bucket this object collection belongs to. # @param [Hash] options def initialize(bucket, options = {}) @bucket = bucket super end # @return [Bucket] The bucket this collection belongs to. attr_reader :bucket # Writes a new object to S3. # # The first param is the key you want to write this object to. # All other params/options are documented in {S3Object#write}. # # @see S3Object#write # # @param [String] key Where in S3 to write the object. # @return (see S3Object#write) def create key, *args, &block self[key].write(*args, &block) end # Returns an S3Object given its name. For example: # # @example # # object = bucket.objects['file.txt'] # object.class #=> S3Object # # @param [String] key The object key. # @return [S3Object] def [] key S3Object.new(bucket, key.to_s) end # (see PrefixedCollection#with_prefix) def with_prefix prefix, mode = :replace super(prefix, mode) end # Deletes the objects provided in as few requests as possible. # # # delete 2 objects (by key) in a single request # bucket.objects.delete('abc', 'xyz') # # You can delete objects also by passing their S3Object representation: # # to_delete = [] # to_delete << buckets.objects['foo'] # to_delete << buckets.objects['bar'] # # bucket.objects.delete(to_delete) # # @overload delete(objects) # @param [Mixed] objects One or more objects to delete. Each object # can be one of the following: # # * An object key (string) # * A hash with :key and :version_id (for versioned objects) # * An {S3Object} instance # * An {ObjectVersion} instance # # @overload delete(objects, options) # Deletes multiple objects, with additional options. The array can # contain any of the types of objects the first method invocation style # accepts. # @param [Array] objects One or more objects to delete. # @param [Hash] options Optional headers to pass on. # # @raise [BatchDeleteError] If any of the objects failed to delete, # a BatchDeleteError will be raised with a summary of the errors. # # @return [nil] # def delete *objects # Detect and retrieve options from the end of the splat. if objects.size == 2 and objects[0].is_a?(Array) and objects[1].is_a?(Hash) then client_opts = objects.pop else client_opts = {} end objects = objects.flatten.collect do |obj| case obj when String then { :key => obj } when Hash then obj when S3Object then { :key => obj.key } when ObjectVersion then { :key => obj.key, :version_id => obj.version_id } else msg = "objects must be keys (strings or hashes with :key and " + ":version_id), S3Objects or ObjectVersions, got " + obj.class.name raise ArgumentError, msg end end batch_helper = BatchHelper.new(1000) do |batch| client_opts[:bucket_name] = bucket.name client_opts[:quiet] = true client_opts[:objects] = batch client.delete_objects(client_opts) end error_counts = {} batch_helper.after_batch do |response| response.errors.each do |error| error_counts[error.code] ||= 0 error_counts[error.code] += 1 end end objects.each do |object| batch_helper.add(object) end batch_helper.complete! raise Errors::BatchDeleteError.new(error_counts) unless error_counts.empty? nil end # Deletes each object in the collection that returns a true value # from block passed to this method. Deletes are batched for efficiency. # # # delete text files in the 2009 "folder" # bucket.objects.with_prefix('2009/').delete_if {|o| o.key =~ /\.txt$/ } # # @yieldparam [S3Object] object # # @raise [BatchDeleteError] If any of the objects failed to delete, # a BatchDeleteError will be raised with a summary of the errors. # def delete_if &block error_counts = {} batch_helper = BatchHelper.new(1000) do |objects| begin delete(objects) rescue Errors::BatchDeleteError => error error.error_counts.each_pair do |code,count| error_counts[code] ||= 0 error_counts[code] += count end end end each do |object| batch_helper.add(object) if yield(object) end batch_helper.complete! raise Errors::BatchDeleteError.new(error_counts) unless error_counts.empty? nil end # Deletes all objects represented by this collection. # # @example Delete all objects from a bucket # # bucket.objects.delete_all # # @example Delete objects with a given prefix # # bucket.objects.with_prefix('2009/').delete_all # # @raise [BatchDeleteError] If any of the objects failed to delete, # a BatchDeleteError will be raised with a summary of the errors. # # @return [Array] Returns an array of results # def delete_all error_counts = {} each_batch do |objects| begin delete(objects) rescue Errors::BatchDeleteError => error error.error_counts.each_pair do |code,count| error_counts[code] ||= 0 error_counts[code] += count end end end raise Errors::BatchDeleteError.new(error_counts) unless error_counts.empty? nil end # Iterates the collection, yielding instances of S3Object. # # Use break or raise an exception to terminate the enumeration. # # @param [Hash] options # @option options [Integer] :limit (nil) The maximum number of # objects to yield. # @option options [Integer] :batch_size (1000) The number of objects to # fetch each request to S3. Maximum is 1000 keys at time. # @return [nil] def each options = {}, &block super end private def each_member_in_page(page, &block) super page.contents.each do |content| content_length = content[:size].to_i if content[:size] etag = content[:etag] last_modified = content[:last_modified] yield(S3Object.new(bucket, content.key, { :content_length => content_length, :etag => etag, :last_modified => last_modified})) end end def list_request options client.list_objects(options) end def limit_param :max_keys end def next_markers page if page[:next_marker] marker = page[:next_marker] elsif page[:contents].size > 0 marker = page[:contents].last[:key] else raise 'Unable to find marker in S3 list objects response' end { :marker => marker } end # processes items in batches of 1k items # @api private class BatchHelper def initialize batch_size, &block @batch_size = batch_size @block = block @batch = [] end def after_batch &block @after_batch = block end def add item @batch << item if @batch.size == @batch_size process_batch @batch = [] end item end def complete! process_batch unless @batch.empty? end private def process_batch response = @block.call(@batch) @after_batch.call(response) if @after_batch end end end end end aws-sdk-v1-1.66.0/lib/aws/s3/multipart_upload.rb0000644000004100000410000002625112604445426021345 0ustar www-datawww-data# Copyright 2011-2013 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 'thread' module AWS class S3 # Represents a multipart upload to an S3 object. See # {S3Object#multipart_upload} for a convenient way to initiate a # multipart upload. # # Note: After you initiate multipart upload and upload one or more # parts, you must either complete or abort multipart upload in order # to stop getting charged for storage of the uploaded parts. Only # after you either complete or abort multipart upload, Amazon S3 # frees up the parts storage and stops charging you for the parts # storage. class MultipartUpload include Core::Model class EmptyUploadError < StandardError; end # @api private def initialize(object, id, options = {}) @id = id @object = object super @completed_parts = {} @increment_mutex = Mutex.new @completed_mutex = Mutex.new @last_part = 0 end def bucket object.bucket end def inspect "<#{self.class}:#{object.bucket.name}/#{object.key}:#{id}>" end # @return [String] Returns the upload id. attr_reader :id alias_method :upload_id, :id # @return [S3Object] Returns the object this upload is intended for. attr_reader :object # @return [Boolean] Returns true if both multipart uploads # represent the same object and upload. def ==(other) other.kind_of?(MultipartUpload) and other.object == object and other.id == id end alias_method :eql?, :== # @return [Boolean] True if the upload exists. def exists? client.list_parts(base_opts) rescue Errors::NoSuchUpload => e false else true end # @return The upload initiator. This object will have `:id` # and `:display_name` methods; if the initiator is an IAM # user, the `:id` method will return the ARN of the user, and # if the initiator is an AWS account, this method will return # the same data as {#owner}. def initiator client.list_parts(base_opts).initiator end # @return The upload owner. This object will have `:id` # and `:display_name` methods. def owner client.list_parts(base_opts).owner end # @return [Symbol] The class of storage used to store the # uploaded object. Possible values: # # * `:standard` # * `:reduced_redundancy?` def storage_class client.list_parts(base_opts).storage_class.downcase.to_sym end # @return [Boolean] True if the uploaded object will be stored # with reduced redundancy. def reduced_redundancy? storage_class == :reduced_redundancy end # Aborts the upload. After a multipart upload is aborted, no # additional parts can be uploaded using that upload ID. The # storage consumed by any previously uploaded parts will be # freed. However, if any part uploads are currently in # progress, those part uploads might or might not succeed. As # a result, it might be necessary to abort a given multipart # upload multiple times in order to completely free all # storage consumed by all parts. # @return [nil] def abort unless aborted? client.abort_multipart_upload(base_opts) @aborted = true end nil end alias_method :delete, :abort alias_method :cancel, :abort # @return [Boolean] True if the upload has been aborted. # @see #abort def aborted? @aborted end # Uploads a part. # # @overload add_part(data, options = {}) # # @param data The data to upload. # Valid values include: # # * A string # * A Pathname object # * Any object responding to `read` and `eof?`; the object # must support the following access methods: # # read # all at once # read(length) until eof? # in chunks # # If you specify data this way, you must also include # the `:content_length` option. # # @param [Hash] options Additional options for the upload. # # @option options [Integer] :content_length If provided, # this option must match the total number of bytes written # to S3 during the operation. This option is required if # `:data` is an IO-like object without a `size` method. # # @overload add_part(options) # # @param [Hash] options Options for the upload. Either # `:data` or `:file` is required. # # @option options :data The data to upload. Valid values # include: # # * A string # * A Pathname object # * Any object responding to `read` and `eof?`; the object # must support the following access methods: # # read # all at once # read(length) until eof? # in chunks # # If you specify data this way, you must also include # the `:content_length` option. # # @option options [String] :file Can be specified instead of # `:data`; its value specifies the path of a file to # upload. # # @option options [Integer] :content_length If provided, # this option must match the total number of bytes written # to S3 during the operation. This option is required if # `:data` is an IO-like object without a `size` method. # # @option options [Integer] :part_number The part number. def add_part(data_or_options, options = {}) if data_or_options.kind_of?(Hash) part_options = base_opts.merge(data_or_options) else part_options = base_opts.merge(:data => data_or_options) end part_options.merge!(options) unless part_options[:part_number] @increment_mutex.synchronize do part_options[:part_number] = (@last_part += 1) end end part_number = part_options[:part_number] resp = client.upload_part(part_options) @completed_mutex.synchronize do @completed_parts[part_number] = { :part_number => part_number, :etag => resp[:etag] } end UploadedPart.new(self, part_number, :etag => resp[:etag]) end # Copies a part. # # @param [string] copy_source Full S3 name of source, ie bucket/key # # @param [Hash] options Additional options for the copy. # # @option options [Integer] :part_number The part number. # # @option options [Integer] :copy_source_range Range of bytes to copy, ie bytes=0-45687 def copy_part(copy_source, options = {}) part_options = base_opts.merge(options) part_options.merge!(:copy_source => copy_source) unless part_options[:part_number] @increment_mutex.synchronize do part_options[:part_number] = (@last_part += 1) end end part_number = part_options[:part_number] resp = client.copy_part(part_options) @completed_mutex.synchronize do @completed_parts[part_number] = { :part_number => part_number, :etag => resp[:etag] } end UploadedPart.new(self, part_number, :etag => resp[:etag]) end # Completes the upload by assembling previously uploaded # parts. # # @return [S3Object, ObjectVersion] If the bucket has versioning # enabled, returns the {ObjectVersion} representing the # version that was uploaded. If versioning is disabled, # returns the object. def complete(*parts) parts = parts.flatten case parts.first when :remote_parts complete_opts = get_complete_opts when :local_parts, nil complete_opts = base_opts.merge(:parts => completed_parts) else part_numbers = parts.map do |part| case part when Integer part when UploadedPart raise ArgumentError.new("cannot complete an upload with parts "+ "from a different upload") unless part.upload == self part.part_number else raise ArgumentError.new("expected number or UploadedPart") end end complete_opts = get_complete_opts(part_numbers) end raise EmptyUploadError.new("Unable to complete an empty upload.") if complete_opts[:parts].empty? resp = client.complete_multipart_upload(complete_opts) if resp.data[:version_id] ObjectVersion.new(object, resp.data[:version_id]) else object end end # Completes the upload or aborts it if no parts have been # uploaded yet. Does nothing if the upload has already been # aborted. # # @return [S3Object, ObjectVersion] If the bucket has versioning # enabled, returns the {ObjectVersion} representing the # version that was uploaded. If versioning is disabled, # returns the object. If no upload was attempted (e.g. if it # was aborted or if no parts were uploaded), returns `nil`. def close if aborted? nil elsif completed_parts.empty? abort else complete end end # @return [UploadedPartCollection] A collection representing # the parts that have been uploaded to S3 for this upload. def parts UploadedPartCollection.new(self) end # @api private def completed_parts @completed_parts.values. sort { |a, b| a[:part_number] <=> b[:part_number] } end # @api private def inspect "<#{self.class}:#{object.bucket.name}/#{object.key}:#{id}>" end private def get_complete_opts(part_numbers = nil) parts = [] self.parts.each do |part| parts << { :part_number => part.part_number, :etag => part.etag } end if part_numbers parts.reject! do |part| !part_numbers.include?(part[:part_number]) end end base_opts.merge(:parts => parts) end def base_opts opts = { :bucket_name => object.bucket.name, :key => object.key } opts[:upload_id] = upload_id if upload_id opts end end end end aws-sdk-v1-1.66.0/lib/aws/s3/acl_options.rb0000644000004100000410000001544412604445426020274 0ustar www-datawww-data# Copyright 2011-2013 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 'rexml/document' module AWS class S3 # Provides a method to {Bucket} and {S3Object} that parses a wide # range of ACL options. # @api private module ACLOptions protected # @param [Symbol,String,Hash,AccessControlList] acl Accepts an ACL # description in one of the following formats: # # ==== Canned ACL # # S3 supports a number of canned ACLs for buckets and # objects. These include: # # * `:private` # * `:public_read` # * `:public_read_write` # * `:authenticated_read` # * `:bucket_owner_read` (object-only) # * `:bucket_owner_full_control` (object-only) # * `:log_delivery_write` (bucket-only) # # Here is an example of providing a canned ACL to a bucket: # # s3.buckets['bucket-name'].acl = :public_read # # ==== ACL Grant Hash # # You can provide a hash of grants. The hash is composed of grants (keys) # and grantees (values). Accepted grant keys are: # # * `:grant_read` # * `:grant_write` # * `:grant_read_acp` # * `:grant_write_acp` # * `:grant_full_control` # # Grantee strings (values) should be formatted like some of the # following examples: # # id="8a6925ce4adf588a4532142d3f74dd8c71fa124b1ddee97f21c32aa379004fef" # uri="http://acs.amazonaws.com/groups/global/AllUsers" # emailAddress="xyz@amazon.com" # # You can provide a comma delimited list of multiple grantees in a single # string. Please note the use of quotes inside the grantee string. # Here is a simple example: # # { :grant_full_control => "emailAddress=\"foo@bar.com\", id=\"abc..mno\"" } # # See the S3 API documentation for more information on formatting # grants. # # ==== AcessControlList Object # # You can build an ACL using the {AccessControlList} class and # pass this object. # # acl = AWS::S3::AccessControlList.new # acl.grant(:full_control).to(:canonical_user_id => "8a6...fef") # acl #=> this is acceptible # # ==== ACL XML String # # Lastly you can build your own ACL XML document and pass it as a string. # # <<-XML # # # 8a6...fef # owner-display-name # # # # # 8a6...fef # owner-display-name # # FULL_CONTROL # # # # XML # # @return [Hash] Returns a hash of options suitable for # passing to {Client#put_bucket_acl} and {Client#put_object_acl} # with a mixture of ACL options. # def acl_options acl case acl when Symbol { :acl => acl.to_s.tr('_', '-') } when String # Strings are either access control policies (xml strings) # or they are canned acls xml?(acl) ? { :access_control_policy => acl } : { :acl => acl } when AccessControlList { :access_control_policy => acl.to_xml } when Hash # Hashes are either grant hashes or constructor args for an # access control list (deprecated) grant_hash?(acl) ? format_grants(acl) : { :access_control_policy => AccessControlList.new(acl).to_xml } else # failed to parse the acl option msg = "expected a canned ACL, AccessControlList object, ACL " "XML string or a grants hash" raise ArgumentError, msg end end # @param [Hash] acl_hash # @return [Boolean] Retursn `true` if this hash is a hash of grants. def grant_hash? acl_hash grant_keys = [ :grant_read, :grant_write, :grant_read_acp, :grant_write_acp, :grant_full_control, ] acl_hash.keys.all?{|key| grant_keys.include?(key) } end # @param [String] acl_string # @return [Boolean] Returns `true` if this string is an xml document. def xml? acl_string begin REXML::Document.new(acl_string).has_elements? rescue false end end # @param [Hash] acl_hash # @return [Hash] Returns a hash of grant options suitable for # passing to the various S3 client methods that accept ACL grants. def format_grants acl_hash grants = {} acl_hash.each_pair do |grant,grantees| grantees = [grantees] unless grantees.is_a?(Array) grants[grant] = grantees.map{|g| format_grantee(g) }.join(', ') end grants end def format_grantee grantee case grantee when String then grantee when Hash if grantee.keys.count != 1 msg = "grantee hashes must have exactly 1 key" raise ArgumentError, msg end # A granee hash looks like: # # { :id => 'abc...fec' } # { :uri => 'http://abc.com/foo' } # { :email_address => 'xyz@amazon.com } # # It needs to look like # # 'id="abc...fec"' # 'uri="http://abc.com/foo"' # 'emailAddress="xyz@amazon.com"' type, token = grantee.to_a.flatten type = type.to_s.split('_').map{|part| ucfirst(part) }.join "#{type[0,1].downcase}#{type[1..-1]}=\"#{token}\"" else raise ArgumentError, "grantees must be a string or a hash" end end def ucfirst str str[0,1].upcase + str[1..-1] end end end end aws-sdk-v1-1.66.0/lib/aws/emr.rb0000644000004100000410000000515712604445426016220 0ustar www-datawww-data# Copyright 2011-2013 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 'aws/core' require 'aws/emr/config' require 'time' module AWS # Provides an expressive, object-oriented interface to Amazon Elastic # MapReduce. # # To use Amazon Elastic MapReduce you must first # [sign up here](http://aws.amazon.com/elasticmapreduce/) # # For more information about Amazon Elastic MapReduce, see: # # * [Amazon Elastic MapReduce](http://aws.amazon.com/elasticmapreduce/) # * [Amazon Elastic MapReduce Documentation](http://aws.amazon.com/documentation/elasticmapreduce/) # # ## Credentials # # You can setup default credentials for all AWS services via # AWS.config: # # AWS.config( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # Or you can set them directly on the EMR interface: # # emr = AWS::EMR.new( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # # Job Flows # # The {#job_flows} method returns a collection you use to interact # with your job flows. # # emr = AWS::EMR.new # # # creating a job flow # job_flow = emr.job_flows.create(...) # # # enumerating job flows # emr.job_flows.each do |job_flow| # puts job_flow.id # end # # See {JobFlowCollection} and {JobFlow} for more information on working # with job flows. # # @!attribute [r] client # @return [Client] the low-level EMR client object class EMR autoload :Client, 'aws/emr/client' autoload :Errors, 'aws/emr/errors' autoload :InstanceGroup, 'aws/emr/instance_group' autoload :InstanceGroupCollection, 'aws/emr/instance_group_collection' autoload :JobFlow, 'aws/emr/job_flow' autoload :JobFlowCollection, 'aws/emr/job_flow_collection' include Core::ServiceInterface endpoint_prefix 'elasticmapreduce' # @return [JobFlowCollection] Returns a collection that represents all # job flows. def job_flows JobFlowCollection.new(:config => config) end alias_method :jobs, :job_flows end end aws-sdk-v1-1.66.0/lib/aws/core/0000755000004100000410000000000012604445426016030 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/core/endpoints.rb0000644000004100000410000000213712604445426020363 0ustar www-datawww-data# Copyright 2011-2013 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 'json' module AWS module Core # Provides a read-only interface to the bundled endpoints.json file. module Endpoints def hostname(region, endpoint_prefix) region = endpoints["regions"][region] || {} endpoint = region[endpoint_prefix] || {} endpoint["hostname"] end module_function :hostname def endpoints @endpoints ||= begin JSON.parse(File.read(File.join(AWS::ROOT, 'endpoints.json'))) end end module_function :endpoints end end end aws-sdk-v1-1.66.0/lib/aws/core/meta_utils.rb0000644000004100000410000000225612604445426020530 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # @api private module MetaUtils def extend_method(object, name, &block) object.extend( Module.new do define_method(name, &block) end ) end module_function :extend_method def class_extend_method(klass, name, &block) klass.send(:include, Module.new do define_method(name, &block) end ) end module_function :class_extend_method def extend(object, &block) object.extend(Module.new(&block)) end module_function :extend end end end aws-sdk-v1-1.66.0/lib/aws/core/query_request_builder.rb0000644000004100000410000000257212604445426023006 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # @api private class QueryRequestBuilder def initialize api_version, operation @api_version = api_version @operation_name = operation[:name] @grammar = OptionGrammar.customize(operation[:inputs]) end def populate_request request, options now = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ') request.headers['Content-Type'] = "application/x-www-form-urlencoded; charset=utf-8" request.add_param 'Timestamp', now request.add_param 'Version', @api_version request.add_param 'Action', @operation_name @grammar.request_params(options).each do |param| request.add_param(param) end request.body = request.url_encoded_params end end end end aws-sdk-v1-1.66.0/lib/aws/core/rest_error_parser.rb0000644000004100000410000000123012604445426022113 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # @api private module RESTErrorParser end end end aws-sdk-v1-1.66.0/lib/aws/core/log_formatter.rb0000644000004100000410000003325012604445426021224 0ustar www-datawww-data# Copyright 2011-2013 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 'pathname' module AWS module Core # # Log Formatters # # Log formatters receive a {AWS::Core::Response} object and return # a log message. When you construct a {LogFormatter}, you provide # a pattern string with substitutions. # # pattern = '[AWS :http_response_status] :service :operation :duration' # formatter = AWS::Core::LogFormatter.new(pattern) # formatter.format(response) # #=> '[AWS 200] EC2 get_bucket 0.0352' # # # AWS Configuration # # AWS.config provides a {LogFormatter.default} log formatter. You can # repace this formatter by building your own and then passing it # to {AWS.config}. # # pattern = '[AWS :http_response_status] :service :operation :duration' # AWS.config(:log_formatter => AWS::Core::LogFormatter.new(pattern) # # ## Canned Formatters # # Instead of providing your own pattern, you can choose a canned log # formatter. # # AWS.config(:log_formatter => AWS::Core::LogFormatter.colored) # # Here is the list of canned formatters. # # * {LogFormatter.default} # * {LogFormatter.short} # * {LogFormatter.debug} # * {LogFormatter.colored} # # # Pattern Substitutions # # You can put any of these placeholders into you pattern. # # * `:service` - The AWS service name (e.g. 'S3', 'EC2', 'SimpleDB', etc) # * `:region` - The AWS region name (e.g. 'us-west-1', 'us-west-2', etc) # * `:operation` - The name of the client request method. This maps to # the name of the serivce API operation (e.g. :describe_instances). # * `:options` - The hash of options passed to the client request method. # Long strings are truncated/summarized if they excede the log # formatters {#max_string_size}. Other objects are inspected. # * `:retry_count` - The number of times a client request was retried. # Throttlings and service errors trigger the automatic retry logic. # This value indicates how many extra attempts were made before # getting a successful response or giving up. # * `:duration` - The time it took to generate a response, expressed # in decimal seconds. This time includes everything from # calling the client request method, until that method returns # a value (event retries and retry delays). # * `:error_class` - The class name of the error returned by the # service. If no error was returned, this will be replcaed by # an empty string. # * `:error_message` - The message of the error returned. If # no error was returned by the service, this will be an empty # string. # * `:http_request_method` - The HTTP request verb (e.g. 'POST', # 'PUT', 'GET', etc). # * `:http_request_protocol` - This is replaced by 'http' or 'https'. # * `:http_request_host` - The host name of the http request # endpoint (e.g. 's3.amazon.com'). # * `:http_request_port` - The port number (e.g. '443' or '80'). # * `:http_request_uri` - The http request uri folling the host (e.g. # '/bucket_name/objects/key?versions'). # * `:http_request_body` - The http request payload. # * `:http_request_headers` - The http request headers, inspected. # * `:http_request_proxy_uri` - The proxy uri used, or an empty string. # * `:http_response_status` - The http response status # code (e.g. '200', '404', '500', etc). # * `:http_response_headers` - The http response headers, inspected. # * `:http_response_body` - The http response body contents. # class LogFormatter # @param [String] pattern The log format pattern should be a string # and may contain any of the following placeholders: # # * `:service` # * `:region` # * `:operation` # * `:options` # * `:retry_count` # * `:duration` # * `:error_class` # * `:error_message` # * `:http_request_method` # * `:http_request_protocol` # * `:http_request_host` # * `:http_request_port` # * `:http_request_uri` # * `:http_request_body` # * `:http_request_headers` # * `:http_request_proxy_uri` # * `:http_response_status` # * `:http_response_headers` # * `:http_response_body` # # @param [Hash] options # # @option options [Integer] :max_string_size (1000) # def initialize pattern, options = {} @pattern = pattern @max_string_size = options[:max_string_size] || 1000 end # @return [String] attr_reader :pattern # @return [Integer] attr_reader :max_string_size # @param [Response] response # @return [String] def format response pattern.gsub(/:(\w+)/) {|sym| send("_#{sym[1..-1]}", response) } end # @api private def eql? other other.is_a?(self.class) and other.pattern == self.pattern end alias_method :==, :eql? protected def method_missing method_name, *args if method_name.to_s.chars.first == '_' ":#{method_name.to_s[1..-1]}" else super end end def _service response response.http_request.service end def _region response response.http_request.region end def _operation response response.request_type end def _options response summarize_hash(response.request_options) if response.request_options end def _retry_count response response.retry_count end def _duration response ("%.06f" % response.duration).sub(/0+$/, '') end def _error_class response response.error.class.name if response.error end def _error_message response response.error.message if response.error end def _http_request_method response response.http_request.http_method end def _http_request_protocol response response.http_request.use_ssl? ? 'https' : 'http' end def _http_request_host response response.http_request.host end def _http_request_port response response.http_request.port end def _http_request_uri response response.http_request.uri end def _http_request_headers response response.http_request.headers.inspect end def _http_request_body response response.http_request.body end def _http_request_proxy_uri response response.config.proxy_uri end def _http_response_status response response.http_response.status end def _http_response_headers response response.http_response.headers.inspect end def _http_response_body response response.http_response.body end # The following methods are for summarizing request options that have # symbolized keys and a mix of values. The summarizing is important # because large request options (e.g. s3 data) can cause memory usage # to spike if it is inspected. # @param [Hash] hash # @return [String] def summarize_hash hash hash.map do |key,v| "#{key.inspect}=>#{summarize_value(v)}" end.sort.join(",") end # @param [Object] value # @return [String] def summarize_value value case value when String then summarize_string(value) when Hash then '{' + summarize_hash(value) + '}' when Array then summarize_array(value) when File then summarize_file(value.path) when Pathname then summarize_file(value) else value.inspect end end # @param [String] str # @return [String] def summarize_string str max = max_string_size if str.size > max "#" else str.inspect end end # Given the path to a file on disk, this method returns a summarized # inspecton string that includes the file size. # @param [String] path # @return [String] def summarize_file path "#" end # @param [Array] array # @return [String] def summarize_array array "[" + array.map{|v| summarize_value(v) }.join(",") + "]" end class << self # The default log format. # # @example A sample of the default format. # # [AWS SimpleEmailService 200 0.580066 0 retries] list_verified_email_addresses() # # @return [LogFormatter] # def default pattern = [] pattern << "[AWS" pattern << ":service" pattern << ":http_response_status" pattern << ":duration" pattern << ":retry_count retries]" pattern << ":operation(:options)" pattern << ":error_class" pattern << ":error_message" LogFormatter.new(pattern.join(' ') + "\n") end # The short log format. Similar to default, but it does not # inspect the request params or report on retries. # # @example A sample of the short format # # [AWS SimpleEmailService 200 0.494532] list_verified_email_addresses # # @return [LogFormatter] # def short pattern = [] pattern << "[AWS" pattern << ":service" pattern << ":http_response_status" pattern << ":duration]" pattern << ":operation" pattern << ":error_class" LogFormatter.new(pattern.join(' ') + "\n") end # A debug format that dumps most of the http request and response # data. # # @example A truncated sample of the debug format. # # +------------------------------------------------------------------------------- # | AWS us-east-1 SimpleEmailService list_verified_email_addresses 0.429189 0 retries # +------------------------------------------------------------------------------- # | REQUEST # +------------------------------------------------------------------------------- # | METHOD: POST # | URL: https://email.us-east-1.amazonaws.com::443:/ # | HEADERS: {"content-type"=>"application/x-www-form-urlencoded" ... # | BODY: Action=ListVerifiedEmailAddresses&Timestamp= ... # +------------------------------------------------------------------------------- # | RESPONSE # +------------------------------------------------------------------------------- # | STATUS: 200 # | HEADERS: {"x-amzn-requestid"=>["..."], ... # | BODY: normalize_value(v, child_rules)) end end def normalize_value value, rules case rules[:type] when :hash then normalize_keys(value, rules[:members]) when :array then value.map{|v| normalize_value(v, rules[:members]) } when :map value.inject({}) do |h,(k,v)| h.merge(k => normalize_value(v, rules[:members])) end when :blob then Base64.encode64(value.read).strip else value end end end end end end aws-sdk-v1-1.66.0/lib/aws/core/options/xml_serializer.rb0000644000004100000410000000714712604445426023112 0ustar www-datawww-data# Copyright 2011-2013 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 'nokogiri' module AWS module Core module Options # Given a hash of serialization rules, an XMLSerializer can convert # a hash of request options into XML. The request options are # validated before returning XML. class XMLSerializer # @param [String] namespace # @param [String] operation_name # @param [Hash] operation def initialize namespace, operation_name, operation @namespace = namespace @operation_name = operation_name @rules = operation[:inputs] @http = operation[:http] @validator = Validator.new(rules) end # @return [String] Returns the name of the API operation. attr_reader :operation_name # @return [String] attr_reader :namespace # @return [Hash] attr_reader :rules # @return [Hash,nil] attr_reader :http # @return [Validator] attr_reader :validator # @overload serialize!(request_options) # @param [Hash] request_options A hash of already validated # request options with normalized values. # @return [String] Returns an string of the request parameters # serialized into XML. def serialize request_options if http && http[:request_payload] payload = http[:request_payload] root_node_name = rules[payload][:name] params = request_options[payload] rules = self.rules[payload][:members] else root_node_name = "#{operation_name}Request" params = request_options rules = self.rules end xml = Nokogiri::XML::Builder.new xml.send(root_node_name, :xmlns => namespace) do |xml| hash_members_xml(params, rules, xml) end xml.doc.root.to_xml end protected def to_xml builder, opt_name, rules, value xml_name = rules[:name] xml_name ||= opt_name.is_a?(String) ? opt_name : Inflection.class_name(opt_name.to_s) case value when Hash builder.send(xml_name) do |builder| hash_members_xml(value, rules[:members], builder) end when Array builder.send(xml_name) do value.each do |member_value| to_xml(builder, 'member', rules[:members], member_value) end end else builder.send(xml_name, value) end end def hash_members_xml hash, rules, builder xml_ordered_members(rules).each do |member_name| if hash.key?(member_name) value = hash[member_name] to_xml(builder, member_name, rules[member_name], value) end end end def xml_ordered_members members members.inject([]) do |list,(member_name, member)| list << [member[:position] || 0, member_name] end.sort_by(&:first).map(&:last) end end end end end aws-sdk-v1-1.66.0/lib/aws/core/options/validator.rb0000644000004100000410000001210612604445426022035 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core module Options # Given a hash of validation rules, a validator validate request # options. Validations support: # # * rejecting unknown options # * ensuring presence of required options # * validating expected option types (e.g. hash, array, string, # integer, etc). # # After validating, a hash of request options is returned with # with normalized values (with converted types). class Validator # @param [Hash] rules A hash of option rules to validate against. def initialize rules @rules = rules end # @return [Hash] attr_reader :rules # @overload validate!(request_options) # @param [Hash] request_options The hash of options to validate. # @raise [ArgumentError] Raised when the options do not validate. # @return [Hash] def validate! request_options, rules = @rules # Verify all required options are present. rules.each_pair do |opt_name, opt_rules| if opt_rules[:required] unless request_options.key?(opt_name) raise ArgumentError, "missing required option #{opt_name.inspect}" end end end request_options.inject({}) do |options, (opt_name, value)| # Ensure this is a valid/accepted option unless rules.key?(opt_name) raise ArgumentError, "unexpected option #{opt_name.inspect}" end # Validate and convert the value valid_value = validate_value(rules[opt_name], value, opt_name) options.merge(opt_name => valid_value) end end protected # Proxies calls to the correct validation method based on the # rules[:type]. def validate_value *args send("validate_#{args.first[:type]}", *args) end # Ensures the value is a hash and validates the hash context. def validate_hash rules, value, opt_name, context = nil unless value.respond_to?(:to_hash) format_error('hash value', opt_name, context) end validate!(value.to_hash, rules[:members]) end def validate_map rules, value, opt_name, context = nil unless value.respond_to?(:to_hash) format_error('hash value', opt_name, context) end value.inject({}) do |values,(k,v)| context = "member #{k.inspect} of :#{opt_name}" values[k] = validate_value(rules[:members], v, opt_name, context) values end end # Ensures the value is an array (or at least enumerable) and # that the yielded values are valid. def validate_array rules, value, opt_name, context = nil unless value.respond_to?(:each) format_error('enumerable value', opt_name, context) end values = [] value.each do |v| context = "member #{values.size} of :#{opt_name}" values << validate_value(rules[:members], v, opt_name, context) end values end # Ensures the value is a string. def validate_string rules, value, opt_name, context = nil unless value.respond_to?(:to_str) format_error('string value', opt_name, context) end rules[:lstrip] ? value.to_str.sub(/^#{rules[:lstrip]}/, '') : value.to_str end # Ensures the value is a boolean. def validate_boolean rules, value, opt_name, context = nil unless [true, false].include?(value) format_error('true or false', opt_name, context) end value end # Ensures the value is an integer. def validate_integer rules, value, opt_name, context = nil unless value.respond_to?(:to_int) format_error('integer value', opt_name, context) end value.to_int end # Ensures the value is a timestamp. def validate_timestamp rules, value, opt_name, context = nil # TODO : add validation to timestamps values value.to_s end def validate_blob rules, value, opt_name, context = nil value end def format_error description, opt_name, context context = context || "option :#{opt_name}" raise ArgumentError, "expected #{description} for #{context}" end end end end end aws-sdk-v1-1.66.0/lib/aws/core/model.rb0000644000004100000410000000350712604445426017462 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # @api private module Model # @api private def initialize(*args) options = args.last.kind_of?(Hash) ? args.last : {} @config = case when options[:config] then options[:config] when args.first.respond_to?(:config) then args.first.config else AWS.config end end # @return [Configuration] Returns the configuration for this object. attr_reader :config # Each class including this module has its own client class. # Generally it is the service namespace suffixed by client: # # * s3_client # * simple_db_client # # @return Retruns the proper client class for the given model. def client @config.send("#{config_prefix}_client") end # @return [String] The short name of the service as used in coniguration. # (e.g. SimpleDB::Client.config_prefix #=> 'simple_db') def config_prefix Inflection.ruby_name(self.class.to_s.split(/::/)[1]) end # @return [String] A sensible default inspect string. def inspect "<#{self.class}>" end # @api private def to_yaml_properties instance_variables.map(&:to_s) - %w(@config) end end end end aws-sdk-v1-1.66.0/lib/aws/core/configuration.rb0000644000004100000410000004374712604445426021243 0ustar www-datawww-data# Copyright 2011-2013 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 Credentials # # In order to do anything with AWS you will need to assign credentials. # The simplest method is to assign 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_retries => 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 (nil) # AWS access key id credential. # # @attr_reader [String,nil] secret_access_key (nil) # AWS secret access key credential. # # @attr_reader [String,nil] session_token (nil) AWS secret token credential. # # @attr_reader [String] region # The AWS region used for requests. The default is `us-east-1`. # # @attr_reader [Boolean] dynamo_db_big_decimals (true) When `true`, # {DynamoDB} will convert number values returned by {DynamoDB::Client} # from strings to BigDecimal objects. If you set this to `false`, # they will be converted from strings into floats (with a potential # loss of precision). # # @attr_reader [Boolean] dynamo_db_retry_throughput_errors (true) When # true, AWS::DynamoDB::Errors::ProvisionedThroughputExceededException # errors will be retried. # # @attr_reader [Object] http_handler The http handler that sends requests # to AWS. Defaults to an HTTP handler built on net/http. # # @attr_reader [Integer] http_idle_timeout The number of seconds a # persistent connection is allowed to sit idle before it should no # longer be used. # # @attr_reader [Integer] http_open_timeout The number of seconds before # the `http_handler` should timeout while trying to open a new HTTP # session. # # @attr_reader [Integer] http_read_timeout The number of seconds before # the `http_handler` should timeout while waiting for a HTTP # response. # # @attr_reader [Boolean] http_wire_trace When `true`, the http handler # will log all wire traces to the `:logger`. If a `:logger` is not # configured, then wire traces will be sent to standard out. # # @attr_reader [Logger,nil] logger (nil) The logging interface. # # @attr_reader [Symbol] log_level (:info) The log level to use when # logging every API call. Does not set the `:logger`'s log_level. # # @attr_reader [LogFormatter] log_formatter The log message formatter. # # @attr_reader [Integer] max_retries (3) The maximum number of times # service errors (500) and throttling errors should be retried. There is # an exponential backoff in between retries, so the more retries the # longer it can take to fail. # # @attr_reader [URI,nil] proxy_uri (nil) The URI of the proxy # to send service requests through. # # @attr_reader [Boolean] s3_force_path_style (false) When # `true`, requests will always use path style. This can be useful # for testing environments. # # @attr_reader [Integer] s3_multipart_max_parts (10000) # The maximum number of parts to split a file into when uploading # in parts to S3. # # @attr_reader [Integer] s3_multipart_threshold (16777216) When uploading # data to S3, if the number of bytes to send exceeds # `: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 (5242880) # 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 [OpenSSL::PKey::RSA, String] s3_encryption_key # If this is set, AWS::S3::S3Object #read and #write methods will always # perform client-side encryption with this key. The key can be overridden # at runtime by using the :encryption_key option. A value of nil # means that client-side encryption will not be used. # # @attr_reader [Symbol] s3_encryption_materials_location # When set to `:instruction_file`, AWS::S3::S3Object will store # encryption materials in a separate object, instead of the object # metadata. # # @attr_reader [Boolean] simple_db_consistent_reads (false) Determines # if all SimpleDB read requests should be done consistently. # Consistent reads are slower, but reflect all changes to SDB. # # @attr_reader [Boolean] sqs_verify_checksums (true) # When `true` all SQS operations will check body content against # MD5 checksums, raising an exception if there is a mismatch. # # @attr_reader [CredentialProvider::Provider] credential_provider # Returns the object that is responsible for loading credentials. # # @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 [String] ssl_ca_path (nil) # The path the a CA cert directory. # # @attr_reader [String] ssl_cert_store (nil) # # @attr_reader [Boolean] ssl_verify_peer (true) When `true` # the HTTP handler validate server certificates for HTTPS requests. # # 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 (false) When `true` requests are not # sent to AWS, instead empty responses are generated and returned to # each service request. # # @attr_reader [Boolean] use_ssl (true) When `true`, all requests # to AWS are sent using HTTPS instead vanilla HTTP. # # @attr_reader [String] user_agent_prefix (nil) A string prefix to # append to all requests against AWS services. This should be set # for clients and applications built on top of the aws-sdk gem. # # @attr_reader [Boolean] verify_response_body_content_length (true) # When `true` all HTTP handlers will perform a check to ensure # that response bodies match the content-length specified in the # response header, if present. Note that some HTTP handlers will # always do this whether or not this value is true. # class Configuration # Creates a new Configuration object. # @param options (see AWS.config) # @option options (see AWS.config) def initialize options = {} @created = options.delete(:__created__) || {} # :signer is now a deprecated option, this ensures it will still # work, but its now preferred to set :credential_provider instead. # Credential providers don't have to provide a #sign method. if signer = options.delete(:signer) options[:credential_provider] = signer end options.each_pair do |opt_name, value| opt_name = opt_name.to_sym if self.class.accepted_options.include?(opt_name) #if opt_name.to_s =~ /_endpoint$/ # warning = ":#{opt_name} is a deprecated AWS configuration option, " # warning << "use :region instead" # warn(warning) #end supplied[opt_name] = value end end end # @return [Hash] Returns a hash with your configured credentials. def credentials credentials = {} [:access_key_id, :secret_access_key, :session_token].each do |opt| if value = credential_provider.send(opt) credentials[opt] = value end end credentials 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.merge(k => send(k)) end end alias_method :to_hash, :to_h # @return [Boolean] Returns true if the two configuration objects have # the same values. def eql? other other.is_a?(self.class) and self.supplied == other.supplied end alias_method :==, :eql? # @api private def inspect "<#{self.class.name}>" end # @api private def endpoint_region(svc) (supplied[svc.method_name] || {})[:region] or supplied[:"#{svc.old_name}_region"] or region end protected def supplied @supplied ||= {} end class << self # @api private def accepted_options @options ||= Set.new end # @api 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(self, value) : value end alias_method("#{name}?", name) if options[:boolean] end # Configuration options that have dependencies are re-recreated # anytime one of their dependent configuration values are # changed. # @api 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.inject({}) {|h,need| h.merge(need => send(need)) } unless @created.key?(name) and @created[name][:needed] == needed created = {} created[:object] = create_block.call(self,needed) created[:needed] = needed @created[name] = created end @created[name][:object] end end def add_service name, ruby_name, endpoint_prefix svc = SERVICES[name] svc_opt = svc.method_name ruby_name = svc.old_name add_option(svc_opt, {}) add_option :"#{ruby_name}_endpoint" do |config,value| region = config.endpoint_region(svc) endpoint = value endpoint ||= config.send(svc_opt)[:endpoint] endpoint ||= Endpoints.hostname(region, endpoint_prefix) endpoint ||= "#{endpoint_prefix}.#{region}.amazonaws.com" endpoint end add_option(:"#{ruby_name}_port") do |config,value| if value value elsif port = config.send(svc_opt)[:port] port else config.use_ssl? ? 443 : 80 end end # users only need to specify service regions when they use # a test endpoint with a sigv4 service add_option(:"#{ruby_name}_region") do |config,value| if value value elsif region = config.send(svc_opt)[:region] region else endpoint = config.send("#{ruby_name}_endpoint") if endpoint =~ /us-gov/ if matches = endpoint.match(/(us-gov-west-\d+)/) matches[1] else 'us-gov-west-1' # e.g. iam.us-gov.amazonaws.com end elsif matches = endpoint.match(/^.+?[.-](.+)\.amazonaws.com/) matches[1] else AWS.const_get(name).global_endpoint? ? 'us-east-1' : config.region end end end needs = [ :"#{svc_opt}", :"#{ruby_name}_endpoint", :"#{ruby_name}_port", :"#{ruby_name}_region", :credential_provider, :http_handler, :http_read_timeout, :http_continue_timeout, :http_continue_threshold, :log_formatter, :log_level, :logger, :proxy_uri, :max_retries, :stub_requests?, :ssl_verify_peer?, :ssl_ca_file, :ssl_ca_path, :ssl_cert_store, :use_ssl?, :user_agent_prefix, ] create_block = lambda do |config,client_options| options = client_options[:"#{svc_opt}"] AWS.const_get(name)::Client.new(options.merge(:config => config)) end add_option_with_needs :"#{ruby_name}_client", needs, &create_block end end add_option :access_key_id add_option :secret_access_key add_option :session_token add_option :region do |cfg,region| region || ENV['AWS_REGION'] || ENV['AMAZON_REGION'] || ENV['AWS_DEFAULT_REGION'] || 'us-east-1' end add_option_with_needs :credential_provider, [:access_key_id, :secret_access_key, :session_token] do |cfg,static_creds| CredentialProviders::DefaultProvider.new(static_creds) end add_option :http_open_timeout, 15 add_option :http_read_timeout, 60 add_option :http_continue_timeout, 1 add_option :http_continue_threshold, false add_option :http_idle_timeout, 5 add_option :http_wire_trace, false, :boolean => true add_option_with_needs(:http_handler, AWS::Core::Http::ConnectionPool::OPTIONS + [:verify_response_body_content_length] ) do |config,options| AWS::Core::Http::NetHttpHandler.new(options) end add_option :logger add_option :log_level, :info add_option :log_formatter, LogFormatter.default add_option :max_retries, 3 add_option :proxy_uri do |config,uri| uri ? URI.parse(uri.to_s) : nil 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 :ssl_ca_path add_option :ssl_cert_store add_option :stub_requests, false, :boolean => true add_option :use_ssl, true, :boolean => true add_option :user_agent_prefix add_option :verify_response_body_content_length, true, :boolean => true end end end aws-sdk-v1-1.66.0/lib/aws/core/page_result.rb0000644000004100000410000000533512604445426020675 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core class PageResult < Array # @return [Collection] Returns the collection that was used to # populated this page of results. attr_reader :collection # @return [Integer] Returns the maximum number of results per page. # The final page in a collection may return fewer than `:per_page` # items (e.g. `:per_page` is 10 and there are only 7 items). attr_reader :per_page # @return [String] An opaque token that can be passed the #page method # of the collection that returned this page of results. This next # token behaves as a pseudo offset. If `next_token` is `nil` then # there are no more results for the collection. attr_reader :next_token # @param [Collection] collection The collection that was used to # request this page of results. The collection should respond to # #page and accept a :next_token option. # # @param [Array] items An array of result items that represent a # page of results. # # @param [Integer] per_page The number of requested items for this # page of results. If the count of items is smaller than `per_page` # then this is the last page of results. # # @param [String] next_token (nil) A token that can be passed to the # def initialize collection, items, per_page, next_token @collection = collection @per_page = per_page @next_token = next_token super(items) end # @return [PageResult] # @raise [RuntimeError] Raises a runtime error when called against # a collection that has no more results (i.e. #last_page? == true). def next_page if last_page? raise 'unable to get the next page, already at the last page' end collection.page(:per_page => per_page, :next_token => next_token) end # @return [Boolean] Returns `true` if this is the last page of results. def last_page? next_token.nil? end # @return [Boolean] Returns `true` if there are more pages of results. def more? !!next_token end end end end aws-sdk-v1-1.66.0/lib/aws/core/service_interface.rb0000644000004100000410000000451612604445426022043 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core module ServiceInterface def self.included base base.send(:attr_reader, :config) base.send(:attr_reader, :client) base.module_eval('module Errors; end') unless base::Errors.include?(Errors) base::Errors.module_eval { include Errors } end AWS::Core::MetaUtils.extend(base) do # @api private def endpoint_prefix prefix = nil, options = {} if prefix @endpoint_prefix = prefix @global_endpoint = !!options[:global] end @endpoint_prefix end # @api private def global_endpoint? @global_endpoint end def regions RegionCollection.new(:service => self) end end end # Returns a new interface object for this service. You can override # any of the global configuration parameters by passing them in as # hash options. They are merged with AWS.config or merged # with the provided `:config` object. # # @ec2 = AWS::EC2.new(:max_retries => 2) # # @see AWS::Cofiguration # # @param [Hash] options # # @option options [Configuration] :config An AWS::Configuration # object to initialize this service interface object with. Defaults # to AWS.config when not provided. # def initialize options = {} options = options.dup @config = (options.delete(:config) || AWS.config) @config = @config.with(options) @client = @config.send(Inflection.ruby_name(self.class.name.split('::').last) + '_client') end # @return [String] def inspect "<#{self.class}>" end end end end aws-sdk-v1-1.66.0/lib/aws/core/json_response_parser.rb0000644000004100000410000000412012604445426022615 0ustar www-datawww-data# Copyright 2011-2013 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 'json' require 'time' require 'bigdecimal' require 'base64' module AWS module Core # @api private class JSONResponseParser def initialize rules @rules = rules end def extract_data response body = response.http_response.body body = "{}" if [nil, ''].include?(body) translate(JSON.load(body)) end def simulate {} end protected # @param [Hash] values # @param [Hash] rules # @return [Hash] def translate values, rules = @rules rules.inject({}) do |data,(key,rule)| if values.key?(key) data.merge(rule[:sym] || key => translate_value(values[key], rule)) else data end end end def translate_hash values, rules translate(values, rules[:members]) end def translate_map values, rules values.inject({}) do |data,(key,value)| data.merge(key => translate_value(value, rules[:members])) end end def translate_value value, rule case when value.is_a?(Array) then value.map{|v| translate_value(v, rule) } when rule[:type] == :hash then translate_hash(value, rule) when rule[:type] == :map then translate_map(value, rule) when rule[:type] == :blob then Base64.decode64(value) when rule[:type] == :time then Time.at(value) when rule[:type] == :big_decimal then BigDecimal.new(value) else value end end end end end aws-sdk-v1-1.66.0/lib/aws/core/rest_request_builder.rb0000644000004100000410000001050412604445426022610 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # Given a hash of request options, a REST::RequestHandler can # populate a Core::Http::Request object. class RESTRequestBuilder # @api private def initialize operation, options = {} @http = operation[:http] @rules = operation[:inputs] @validator = Options::Validator.new(@rules) @serializer = case options[:format] when :xml namespace = options[:xmlnamespace] name = operation[:name] Options::XMLSerializer.new(namespace, name, operation) when :json Options::JSONSerializer.new(@rules, @http[:request_payload]) else raise ArgumentError, "unhandled format: #{options[:format]}" end end # Populates a Http::Request with the following: # # * HTTP method # * URI # * headers # * body # # @param [Http::Request] request # # @param [Hash] params The hash of request options provided # to the client request method. This will be used to populate # the headers, uri and body. # # @raise [ArgumentError] Raises ArgumentError when any of the # request options are invalid (wrong type, missing, unknown, etc). # def populate_request request, params params = @validator.validate!(params) populate_method(request) populate_uri(request, params) populate_headers(request, params) populate_body(request, params) end private def populate_method request request.http_method = @http[:verb] end def populate_uri request, params request.uri = extract_uri(params) end def populate_headers request, params extract_headers(params).each_pair do |header_name, header_value| request.headers[header_name] = header_value end end # @param [Hash] params # @return [String] def extract_uri params path, querystring = @http[:uri].split(/\?/) uri = path.gsub(/:\w+/) do |param_name| if param = params.delete(param_name.sub(/^:/, '').to_sym) UriEscape.escape(param) else raise ArgumentError, "missing required option #{param_name}" end end querystring_parts = [] querystring.to_s.split(/&|;/).each do |part| param_name = part.match(/:(\w+)/)[1] if param = params.delete(param_name.to_sym) param = UriEscape.escape(param) querystring_parts << part.sub(/:#{param_name}/, param) end end unless querystring_parts.empty? uri << "?#{querystring_parts.join('&')}" end uri end # @param [Hash] params # @return [Hash] def extract_headers params headers = {} (@http[:request_headers] || {}).each_pair do |param,header| headers[header] = params[param] if params.key?(param) end headers end # @param [Hash] params # @return [String,nil] def populate_body request, params if params.empty? request.body = nil elsif payload = streaming_param # streaming request request.body_stream = params[payload] request.headers['Content-Length'] = size(params[payload]) else request.body = @serializer.serialize(params) end end def size(payload) if payload.respond_to?(:path) && payload.path File.size(payload.path) else payload.size end end def streaming_param if payload = @http[:request_payload] @rules[payload][:type] == :blob ? payload : nil end end end end end aws-sdk-v1-1.66.0/lib/aws/core/collection/0000755000004100000410000000000012604445426020163 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/core/collection/simple.rb0000644000004100000410000000414412604445426022004 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core module Collection # AWS::Core::Collection::Simple is used by collections that always # recieve every matching items in a single response. # # This means: # # * Paging methods are simulated # # * Next tokens are artificial (guessable numeric offsets) # # AWS services generally return all items only for requests with a # small maximum number of results. # # See {AWS::Core::Collection} for documentation on the available # collection methods. module Simple include Model include Enumerable include Collection protected def _each_batch options = {}, &block limit = _extract_limit(options) next_token = _extract_next_token(options) offset = next_token ? next_token.to_i - 1 : 0 total = 0 skipped = 0 simulated_next_token = nil batch = [] _each_item(options.dup) do |item| total += 1 # skip until we reach our offset (derived from the "next token") if skipped < offset skipped += 1 next end if limit if batch.size < limit batch << item else simulated_next_token = total break end else batch << item end end yield(batch) simulated_next_token end end end end end aws-sdk-v1-1.66.0/lib/aws/core/collection/with_limit_and_next_token.rb0000644000004100000410000000355712604445426025753 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core module Collection # # Collection::WithLimitAndNextToken # # This module is used by collections where the service may truncate # responses but that also accept a upper limit of results to # return in a single request. # # See {AWS::Core::Collection} for documentation on the available # methods. # module WithLimitAndNextToken include Model include Collection include Enumerable protected def _each_batch options = {}, &block limit = _extract_limit(options) batch_size = _extract_batch_size(options) next_token = _extract_next_token(options) total = 0 # count of items yeilded across all batches begin max = nil if limit or batch_size max = [] max << (limit - total) if limit max << batch_size if batch_size max = max.min end batch = [] next_token = _each_item(next_token, max, options.dup) do |item| total += 1 batch << item end yield(batch) end until next_token.nil? or (limit and limit == total) next_token end end end end end aws-sdk-v1-1.66.0/lib/aws/core/collection/with_next_token.rb0000644000004100000410000000514512604445426023726 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core module Collection # # Collection::WithNextToken # # When making a request to list elements from one of these # collections, the response may return a next token. This indicates # there are more results than were returned. You can not control # the number of elements returned with each response. # # See {AWS::Core::Collection} for documentation on the available # collection methods. # module WithNextToken include Model include Enumerable include Collection protected def _each_batch options = {}, &block limit = _extract_limit(options) next_token, skip_count = _extract_next_token(options) skipped = 0 collected = 0 begin offset = 0 batch = [] next_token = _each_item(next_token, options.dup) do |item| if skipped < skip_count skipped += 1 next end if limit if collected < limit batch << item collected += 1 else yield(batch) simulated_next_token = {} simulated_next_token[:token] = next_token if next_token simulated_next_token[:offset] = offset + skipped return simulated_next_token end else batch << item collected += 1 end offset += 1 end # _each_item yield(batch) end until next_token.nil? or (limit and limit == collected) next_token.nil? ? nil : { :token => next_token } end def _extract_next_token options next_token = super case next_token when nil then [nil, 0] when Hash then [next_token[:token], next_token[:offset] || 0] else [next_token, 0] end end end end end end aws-sdk-v1-1.66.0/lib/aws/core/deprecations.rb0000644000004100000410000000461112604445426021037 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # A utility module that provides a class method that wraps # a method such that it generates a deprecation warning when called. # Given the following class: # # class Example # # def do_something # end # # end # # If you want to deprecate the `#do_something` method, you can extend # this module and then call `deprecated` on the method (after it # has been defined). # # class Example # # extend AWS::Core::Deprecations # # def do_something # end # # def do_something_else # end # # deprecated :do_something # # end # # The `#do_something` method will continue to function, but will # generate a deprecation warning when called. # # @api private module Deprecations # @param [Symbol] method The name of the deprecated method. # # @option options [String] :message The warning message to issue # when the deprecated method is called. # # @option options [Symbol] :use The name of an use # method that should be used. # def deprecated method, options = {} deprecation_msg = options[:message] || begin msg = "DEPRECATION WARNING: called deprecated method `#{method}' " msg << "of #{self.name}" msg << ", try calling #{options[:use]} instead" if options[:use] msg end alias_method(:"deprecated_#{method}", method) warned = false # we only want to issue this warning once define_method(method) do |*args,&block| unless warned warn(deprecation_msg) warned = true end send("deprecated_#{method}", *args, &block) end end end end end aws-sdk-v1-1.66.0/lib/aws/core/response.rb0000644000004100000410000001531012604445426020213 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # # Response # # Each Service has a Client class. There is one method per service # operation defined on the client. These methods all return a {Response} # object. # # In addition to the response data, these responses provide metadata # about the HTTP request made and the HTTP response received. # # ## Response Data # # You can access the response data for a client request using the {#data} # method or the {#[]} method. Response data is a hash and {#[]} is # a shortcut for accessing this hash. # # # make a request to describe one instance # ec2 = AWS::EC2.new # response = ec2.client.describe_instances(:instance_ids => ['i-12345678']) # # # find the instance in the response data (2 ways to get the data) # instance = response[:reservation_set].first[:instance_set].first # instance = response.data[:reservation_set].first[:instance_set].first # # instance[:status] #=> 'running' # # ## Response Metadata # # In addition to the response data, there is additional information # available with the response, including: # # * {#request_type} - the name of the client request method # * {#request_options} - the hash of options passed to the client method # * {#http_request} - The HTTP request made # * {#http_response} - the HTTP response received # # Given the example and response object from above: # # response.request_type #=> :describe_instances # response.request_options #=> { :instance_ids => ['i-12345678'] } # response.http_request #=> # # response.http_response #=> # # class Response include AsyncHandle # @return [Hash] Returns the response data as a hash. attr_accessor :data # @api private attr_accessor :config # @return [Symbol] The name of the client request method that # returned this response. attr_accessor :request_type # @return [String] The API version of the request/client. attr_accessor :api_version # @return [Hash] Returns the hash of options passed to the client # request method that generated this response. attr_accessor :request_options # @return [Core::Http::Request] attr_accessor :http_request # @return [Core::Http::Response] attr_accessor :http_response # @return [Boolean] true if the response was generated from a # another cached response. attr_accessor :cached alias_method :cached?, :cached # @return [AWS::Error,nil] Returns nil unless the request failed. # Normally this will be nil unless you are using the Asynchronous # interface. attr_accessor :error # @return [Integer] Returns the number of times the request # was retried. attr_accessor :retry_count # @return [Float] The total number of seconds taken to make the # request and return the response. attr_accessor :duration # @param [Http::Request] http_request # @param [Http::Response] http_response def initialize http_request = nil, http_response = nil, &block @http_request = http_request @http_response = http_response @request_builder = block @data = {} @retry_count = 0 @duration = 0 build_request if @request_builder && !http_request end # Provides access to the response data. This is a short-cut # for calling `response.data[key]`. # # @param [Symbol,String] key # @return [Hash,nil] def [] key data[key] end # @return [Boolean] Returns true if there is no response error. def successful? error.nil? end # @return [Boolean] Returns `true` if the http request failed due to # a networking issue. def network_error? http_response.network_error? end # @return [String] # @api private def inspect data.inspect end # @return [String] # @api private def cache_key [ api_version, http_request.access_key_id, http_request.host, request_type, serialized_options ].join(":") end # Rebuilds the HTTP request using the block passed to the initializer. # This is primarily used by the client when a request must be retried # (throttling, server errors, socket errors, etc). # @api private def rebuild_request @http_request.body_stream.rewind if @http_request.body_stream build_request end # @return [Boolean] Returns `false` if it is not safe to retry a # request. This happens when the http request body is an IO # object that can not be rewound and re-streamed. def safe_to_retry? @http_request.body_stream.nil? or @http_request.body_stream.respond_to?(:rewind) end protected def build_request @http_request = @request_builder.call end # @note The prefered method to get as response data is to use {#[]}. # # This provides a backwards-compat layer to the old response objects # where each response value had a method extended onto this object. # Now all response data is accessible as a hash. # # @see #[] # @see #data # def method_missing *args, &block Core::Data.new(data).send(*args, &block) end def serialized_options serialize_options_hash(request_options) end def serialize_options_hash(hash) "(" + hash.keys.sort_by(&:to_s).map do |key| "#{key}=#{serialize_options_value(hash[key])}" end.join(" ") + ")" end def serialize_options_value(value) case value when Hash then serialize_options_hash(value) when Array then serialize_options_array(value) else value.inspect end end def serialize_options_array array "[" + array.map{|v| serialize_options_value(v) }.join(" ") + "]" end end end end aws-sdk-v1-1.66.0/lib/aws/core/inflection.rb0000644000004100000410000000333212604445426020510 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # @api private module Inflection def ruby_name aws_name inflector = Hash.new do |hash,key| key. sub(/^.*:/, ''). # strip namespace gsub(/([A-Z0-9]+)([A-Z][a-z])/, '\1_\2'). # split acronyms scan(/[a-z]+|\d+|[A-Z0-9]+[a-z]*/). # split words join('_').downcase # join parts end # add a few irregular inflections inflector['ETag'] = 'etag' inflector['s3Bucket'] = 's3_bucket' inflector['s3Key'] = 's3_key' inflector['Ec2KeyName'] = 'ec2_key_name' inflector['Ec2SubnetId'] = 'ec2_subnet_id' inflector['Ec2VolumeId'] = 'ec2_volume_id' inflector['Ec2InstanceId'] = 'ec2_instance_id' inflector['ElastiCache'] = 'elasticache' inflector['NotificationARNs'] = 'notification_arns' inflector[aws_name] end module_function :ruby_name def class_name(name) name.sub(/^(.)/) { |m| m.upcase }. gsub(/[-_]([a-z])/i) { |m| m[1,1].upcase } end module_function :class_name end end end aws-sdk-v1-1.66.0/lib/aws/core/ini_parser.rb0000644000004100000410000000240012604445426020504 0ustar www-datawww-data# Copyright 2011-2014 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. module AWS module Core # @api private module IniParser def self.parse(ini) current_section = {} map = {} ini.split(/\r?\n/).each do |line| line = line.split(/^|\s;/).first # remove comments section = line.match(/^\s*\[([^\[\]]+)\]\s*$/) unless line.nil? if section current_section = section[1] elsif current_section item = line.match(/^\s*(.+?)\s*=\s*(.+)\s*$/) unless line.nil? if item map[current_section] = map[current_section] || {} map[current_section][item[1]] = item[2] end end end map end end end end aws-sdk-v1-1.66.0/lib/aws/core/async_handle.rb0000644000004100000410000000544612604445426021016 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # Mixin that provides a generic callback facility for asynchronous # tasks that can either succeed or fail. module AsyncHandle # Called to signal success and fire off the success and complete callbacks. def signal_success __send_signal(:success) end # Called to signal failure and fire off the failure and complete callbacks. def signal_failure __send_signal(:failure) end # Registers a callback to be called on successful completion of # the task. # # handle.on_success { puts "It worked!" } # # If this is called when the task has already completed # successfully, it will call the callback immediately. def on_success(&block) if @_async_status == :success block.call else (@_async_callbacks ||= []) << { :success => block } end end # Registers a callback to be called when the task fails. # # handle.on_failure { puts "It didn't work!" } # # If this is called when the task has already failed, it will # call the callback immediately. def on_failure(&block) if @_async_status == :failure block.call else (@_async_callbacks ||= []) << { :failure => block } end end # Registers a callback to be called when the task is complete, # regardless of its status. Yields the status to the block. # # handle.on_complete do |status| # puts "It #{status == :success ? 'did' : 'did not'} work!" # end # # If this is called when the task has already completed, it will # call the callback immediately. def on_complete(&block) if !@_async_status.nil? block.call(@_async_status) else (@_async_callbacks ||= []) << { :failure => lambda { block.call(:failure) }, :success => lambda { block.call(:success) } } end end private def __send_signal(kind) @_async_status = kind @_async_callbacks.map do |cb| cb[kind] end.compact.each {|block| block.call } if @_async_callbacks end end end end aws-sdk-v1-1.66.0/lib/aws/core/managed_file.rb0000644000004100000410000000223012604445426020745 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # This trival wrapper around File provides an easy way for the client to know when # the file that it just streamed over HTTP should be closed after receiving the # response. This should only be used internally to track files that we opened. # Open files passed into upload methods should be closed by the user. # @api private class ManagedFile < File def self.open path file_opts = ['rb'] file_opts << { :encoding => "BINARY" } if Object.const_defined?(:Encoding) super(path.to_s, *file_opts) end end end end aws-sdk-v1-1.66.0/lib/aws/core/query_client.rb0000644000004100000410000000232512604445426021062 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core class QueryClient < Core::Client protected def self.request_builder_for api_config, operation QueryRequestBuilder.new(api_config[:api_version], operation) end def self.response_parser_for api_config, operation QueryResponseParser.new(operation[:outputs]) end def extract_error_details response if response.http_response.status >= 300 and body = response.http_response.body and error = errors_module::GRAMMAR.parse(body) and error[:code] then [error[:code], error[:message]] end end end end end aws-sdk-v1-1.66.0/lib/aws/core/option_grammar.rb0000644000004100000410000005042212604445426021376 0ustar www-datawww-data# Copyright 2011-2013 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 'bigdecimal' require 'json' module AWS module Core # @api private class OptionGrammar # @api private class DefaultOption; end # @api private class FormatError < ArgumentError attr_accessor :expectation attr_accessor :context_description def initialize(expectation, context) @expectation = expectation @context_description = context end def to_s "expected #{expectation} for #{context_description}" end end # @api private module Descriptors # @api private module NoArgs def apply(option) option.extend self end end module Timestamp extend NoArgs def validate(value, context = nil) true # raise format_error("timestamp value", context) unless # case value # when String # value =~ /^\d+$/ or value =~ /^\d{4}-\d{2}-d{2}T\d{2}:\d{2}:\d{2}Z$/ # when String then value =~ /^2009-12-04T20:56:05.000Z\d+$/ # when Integer then true # when DateTime then true # when Timestamp then true # when Date then true # else false # end # end # value.respond_to? :to_str end def encode_value(value) value.to_s # value.to_s # case value # when Integer # when # case value # when nil, '' then nil # when DateTime then raw # when Integer then DateTime.parse(Time.at(raw).to_s) # timestamp # else DateTime.parse(raw.to_s) # work with Time, Date and String objects # end end end # @api private module String extend NoArgs def validate(value, context = nil) raise format_error("string value", context) unless value.respond_to? :to_str end def encode_value(value) value.to_s end end # @api private module Blob extend NoArgs def validate(value, context = nil) raise format_error("string value", context) unless value.respond_to? :to_str end def encode_value(value) [value.to_s].pack("m0").gsub("\n", '') end def hash_format(value) [value.to_s].pack("m0").gsub("\n", '') end end # @api private module Integer extend NoArgs def validate(value, context = nil) raise format_error("integer value", context) unless value.respond_to? :to_int end def encode_value(value) value.to_s end end Long = Integer # @api private module Boolean extend NoArgs def validate(value, context = nil) raise format_error("boolean value", context) unless value == true || value == false end def encode_value(value) value.to_s end end # @api private module Required extend NoArgs def required?; true; end end module Position def self.apply *args; end end # @api private module Float extend NoArgs def validate(value, context = nil) raise format_error("float value", context) unless value.kind_of?(Numeric) or value.respond_to? :to_f end def encode_value(value) value.to_f.to_s end end Double = Float # @api private module Rename def self.apply(option, new_name) new_name = Inflection.ruby_name(new_name) MetaUtils.extend_method(option, :ruby_name) { new_name } end end # @api private module Pattern # def validate value, context = nil # unless value =~ regex # raise format_error("value to match #{regex}", context) # end # end # # def self.apply option, regex # option.extend(self) # MetaUtils.extend_method(option, :regex) { regex } # end def self.apply *args end end # @api private module ListMethods module ClassMethods def apply(option, member_descriptors) super(option) member_option = option.member_option if option.respond_to?(:member_option) # ignoring member name descriptors for lists, only useful for rest descriptors = [] member_descriptors.each do |descriptor| unless descriptor.is_a?(Hash) and descriptor[:member_name] descriptors << descriptor end end member_option ||= ListMember.new member_option = member_option.extend_with_config(*descriptors) MetaUtils.extend_method(option, :member_option) { member_option } end end module InstanceMethods def validate(value, context = nil) raise format_error("enumerable value", context) unless value.respond_to? :each i = 0 value.each do |member| i += 1 member_option.validate(member, "member #{i} of #{context_description(context)}") end end def request_params(value, prefix = nil) params = [] value.each do |v| name = prefixed_name(prefix) + join + (params.size + 1).to_s params << member_option.request_params(v, name) end return [Http::Request::Param.new(prefixed_name(prefix), "")] if params.empty? params end def hash_format(value) value.map do |v| member_option.hash_format(v) end end def join '.' end end end module List extend NoArgs extend ListMethods::ClassMethods include ListMethods::InstanceMethods end module MemberedList extend NoArgs extend ListMethods::ClassMethods include ListMethods::InstanceMethods def join '.member.' end end class ListMember < DefaultOption def initialize options = {} super("##list-member##") @prefix = options[:prefix] || '' end def prefixed_name(prefix) "#{prefix}#{@prefix}" end end # @api private module Structure extend NoArgs def self.apply(option, members) options = {} options = option.member_options.inject({}) do |memo, member_option| memo[member_option.name] = member_option memo end if option.respond_to?(:member_options) super(option) members.each do |(name, descriptors)| member_option = options[name] || DefaultOption.new(name) member_option = member_option.extend_with_config(*descriptors) options[name] = member_option end MetaUtils.extend_method(option, :member_options) { options.values } by_ruby_name = options.values.inject({}) do |memo, member_option| memo[member_option.ruby_name] = member_option memo[member_option.name] = member_option memo end MetaUtils.extend_method(option, :member_option) { |n| by_ruby_name[n] } end def validate(value, context = nil) raise format_error("hash value", context) unless value.respond_to?(:to_hash) context = context_description(context) value.each do |name, v| name = name.to_s raise ArgumentError.new("unexpected key #{name} for #{context}") unless member_option(name) member_option(name).validate(v, "key #{name} of #{context}") end member_options.each do |option| raise ArgumentError.new("missing required key #{option.ruby_name} for #{context}") if option.required? and !value.has_key?(option.ruby_name) and !value.has_key?(option.ruby_name.to_sym) and !value.has_key?(option.name) end end def request_params(values, prefix = nil) values.map do |name, value| name = name.to_s member_option(name).request_params(value, prefixed_name(prefix)) end.flatten end def hash_format(hash) hash.inject({}) do |hash, (name, value)| option = member_option(name.to_s) hash[option.name] = option.hash_format(value) hash end end end module Map def self.apply option, members = {} option.extend self key_option = option.key_option(members) if key_descriptors = members[:key] key_option = key_option.extend_with_config(*key_descriptors) MetaUtils.extend_method(option, :key_option) { key_option } end value_option = option.value_option(members) if value_descriptors = members[:value] value_option = value_option.extend_with_config(*value_descriptors) MetaUtils.extend_method(option, :value_option) { value_option } end key_option.param_name = members[:key_param] if members[:key_param] value_option.param_name = members[:value_param] if members[:value_param] separator = members[:flattened] ? '.' : '.entry.' MetaUtils.extend_method(option, :separator) { separator } end def validate(value, context = nil) raise format_error("hash value", context) unless value.respond_to?(:to_hash) context = context_description(context) value.each do |key, value| key_option.validate(key, "key of #{context}") value_option.validate(value, "value at key #{key} of #{context}") end end def request_params values, prefix = nil index = 0 values.inject([]) do |params, (key,value)| index += 1 common_prefix = "#{prefixed_name(prefix)}#{separator}#{index}" key_name = common_prefix + key_option.param_name value_name = common_prefix + value_option.param_name params += key_option.request_params(key, common_prefix) params += value_option.request_params(value, common_prefix) end end def hash_format(value) value.inject({}) do |hash, (key, value)| hash[key_option.hash_format(key)] = value_option.hash_format(value) hash end end def key_option(options) @_key_option ||= MapOption.new(options[:key_param] || "key") end def value_option(options) @_value_option ||= MapOption.new(options[:value_param] || "value") end end module Bigdecimal extend NoArgs def validate(value, context = nil) raise format_error("decimal value", context) unless value.kind_of?(Numeric) or value.respond_to?(:to_int) end def hash_format(value) BigDecimal(value.to_s) end end # @api private module Boolean extend NoArgs end end class DefaultOption attr_reader :name def initialize(name) @name = name end def ruby_name Inflection.ruby_name(name) end def request_params(value, prefix = nil) [Http::Request::Param.new(prefixed_name(prefix), encode_value(value))] end def hash_format(value) value end def prefixed_name(prefix) return "#{prefix}.#{name}" if prefix name end def encode_value(value) value end def required? false end def format_error(expected, context = nil) context = context_description(context) FormatError.new(expected, context) end def context_description(context) context or "option #{ruby_name}" end def extend_with_config(*descriptors) option = clone descriptors.each do |desc| if desc.kind_of?(Hash) (name, arg) = desc.to_a.first next if name == :documentation else name = desc arg = nil end class_name = Inflection.class_name(name.to_s) mod = Descriptors::const_get(class_name) if arg mod.apply(option, arg) else mod.apply(option) end end option end include Descriptors::String end # @api private module ModuleMethods include Inflection def customize(config = []) m = Class.new(self) supported_options = m.supported_options.inject({}) do |memo, opt| memo[opt.name] = opt memo end config.each do |option_config| if config.kind_of?(Hash) (name, value_desc) = option_config else (name, value_desc) = parse_option(option_config) end option = supported_options[name] || DefaultOption.new(name) option = option.extend_with_config(*value_desc) supported_options[option.name] = option end supported_ary = supported_options.values MetaUtils.extend_method(m, :supported_options) { supported_ary } supported_ruby_names = supported_ary.inject({}) do |memo, opt| memo[opt.ruby_name] = opt memo end MetaUtils.extend_method(m, :option) { |n| supported_ruby_names[n] } supported_ary.each do |opt| MetaUtils.extend_method(m, "validate_#{opt.ruby_name}") do |value| opt.validate(value) end end m end def option(name) nil end def supported_options [] end def validate(options) options.each do |name, value| name = name.to_s raise ArgumentError.new("unexpected option #{name}") unless option(name) option(name).validate(value) end supported_options.each do |option| raise ArgumentError.new("missing required option #{option.ruby_name}") unless !option.required? || options.has_key?(option.ruby_name) || options.has_key?(option.ruby_name.to_sym) end end # Returns the options in AWS/Query format def request_params(options) validate(options) options.map do |(name, value)| name = name.to_s option(name).request_params(value) end.flatten end # Returns the options as a hash (which is used to generate JSON # in to_json). def to_h(options) validate(options) options.inject({}) do |hash, (name, value)| option = self.option(name.to_s) hash[option.name] = option.hash_format(value) hash end end # Returns the options in JSON format def to_json(options) to_h(options).to_json end def included(m) m.extend(self::ModuleMethods) end protected def parse_option(option) value_desc = nil if option.kind_of? Hash raise ArgumentError.new("passed empty hash where an option was expected") if option.empty? raise ArgumentError.new("too many entries in option description") if option.size > 1 (name, value_desc) = option.to_a.first name = name.to_s raise ArgumentError.new("expected an array for "+ "value description of option #{name},"+ "got #{value_desc.inspect}") unless value_desc.nil? or value_desc.kind_of?(Array) else name = option end value_desc ||= [] [name, value_desc] end protected def apply_required_descriptor(m, name) name = ruby_name(name) MetaUtils.extend_method(m, :validate) do |opts| raise ArgumentError.new("missing required option #{name}") unless opts.key? name or opts.key? name.to_sym end end protected def apply_integer_descriptor(m, name) MetaUtils.extend_method(m, "validate_#{ruby_name(name)}") do |value| raise ArgumentError.new("expected integer value for option #{ruby_name(name)}") unless value.respond_to? :to_int end end protected def apply_string_descriptor(m, name) MetaUtils.extend_method(m, "validate_#{ruby_name(name)}") do |value| raise ArgumentError.new("expected string value for option #{ruby_name(name)}") unless value.respond_to? :to_str end end protected def apply_list_descriptor(m, name, arg) MetaUtils.extend_method(m, "validate_#{ruby_name(name)}") do |value| raise ArgumentError.new("expected value for option #{ruby_name(name)} "+ "to respond to #each") unless value.respond_to? :each end MetaUtils.extend_method(m, "params_for_#{ruby_name(name)}") do |value| i = 0 values = [] value.each do |member| i += 1 values << Http::Request::Param.new(name+"."+i.to_s, member.to_s) end if i > 0 values else Http::Request::Param.new(name, "") end end end protected def apply_rename_descriptor(m, name, new_name) name = ruby_name(name) MetaUtils.extend_method(m, :validate) do |opts| raise ArgumentError.new("unexpected option foo") if opts.key?(name) or opts.key?(name.to_sym) opts = opts.dup opts[name] = opts[new_name] if opts.key?(new_name) opts[name.to_sym] = opts[new_name.to_sym] if opts.key?(new_name.to_sym) opts.delete(new_name) opts.delete(new_name.to_sym) super(opts) end # couldn't find a better way to alias a class method method = m.method("params_for_#{name}") MetaUtils.extend_method(m, "params_for_#{new_name}") do |value| method.call(value) end end end class MapOption < DefaultOption def param_name @param_name || name end def param_name= name @param_name = name end end extend ModuleMethods end end end aws-sdk-v1-1.66.0/lib/aws/core/rest_xml_client.rb0000644000004100000410000000256012604445426021553 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # @since 1.8.0 class RESTXMLClient < Core::Client protected def self.request_builder_for api_config, operation RESTRequestBuilder.new(operation, :format => :xml, :xmlnamespace => api_config[:namespace]) end def self.response_parser_for api_config, operation RESTResponseParser.new(operation, :format => :xml) end def extract_error_details response if response.http_response.status >= 300 and body = response.http_response.body and error = errors_module::GRAMMAR.parse(body) and error[:code] then [error[:code], error[:message]] end end end # @deprecated Use RESTXMLClient instead. RESTClient = RESTXMLClient end end aws-sdk-v1-1.66.0/lib/aws/core/uri_escape.rb0000644000004100000410000000253612604445426020502 0ustar www-datawww-data# Copyright 2011-2013 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 'cgi' module AWS module Core # Provides helper methods for URI escaping values and paths. module UriEscape # @param [String] value # @return [String] Returns a URI escaped string. def escape value value = value.encode("UTF-8") if value.respond_to?(:encode) CGI::escape(value.to_s).gsub('+', '%20').gsub('%7E', '~') end module_function :escape # @param [String] value # @return [String] Returns a URI-escaped path without escaping the # separators. def escape_path value escaped = "" value.scan(%r{(/*)([^/]*)(/*)}) do |(leading, part, trailing)| escaped << leading + escape(part) + trailing end escaped end module_function :escape_path end end end aws-sdk-v1-1.66.0/lib/aws/core/policy.rb0000644000004100000410000007147512604445426017672 0ustar www-datawww-data# Copyright 2011-2013 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 'date' require 'json' module AWS module Core # Represents an access policy for AWS operations and resources. For example: # # policy = Policy.new # policy.allow( # :actions => ['s3:PutObject'], # :resources => "arn:aws:s3:::mybucket/mykey/*", # :principals => :any # ).where(:acl).is("public-read") # # policy.to_json # => '{ "Version":"2008-10-17", ...' # # @see #initialize More ways to construct a policy. # @see http://docs.aws.amazon.com/AmazonS3/latest/dev/AccessPolicyLanguage_UseCases_s3_a.html Example policies (in JSON). class Policy # @see Statement # @return [Array] An array of policy statements. attr_reader :statements # @return [String] The version of the policy language used in this # policy object. attr_reader :version # @return [String] A unique ID for the policy. attr_reader :id class Statement; end # Constructs a policy. There are a few different ways to # build a policy: # # * With hash arguments: # # Policy.new(:statements => [ # { # :effect => :allow, # :actions => :all, # :principals => ["abc123"], # :resources => "mybucket/mykey" # } # ]) # # * From a JSON policy document: # # Policy.from_json(policy_json_string) # # * With a block: # # Policy.new do |policy| # policy.allow( # :actions => ['s3:PutObject'], # :resources => "arn:aws:s3:::mybucket/mykey/*", # :principals => :any # ).where(:acl).is("public-read") # end # def initialize(opts = {}) @statements = opts.values_at(:statements, "Statement").select do |a| a.kind_of?(Array) end.flatten.map do |stmt| self.class::Statement.new(stmt) end if opts.has_key?(:id) or opts.has_key?("Id") @id = opts[:id] || opts["Id"] else @id = SecureRandom.uuid.tr('-','') end if opts.has_key?(:version) or opts.has_key?("Version") @version = opts[:version] || opts["Version"] else @version = "2008-10-17" end yield(self) if block_given? end # @return [Boolean] Returns true if the two policies are the same. def ==(other) if other.kind_of?(Core::Policy) self.hash_without_ids == other.hash_without_ids else false end end alias_method :eql?, :== # Removes the ids from the policy and its statements for the purpose # of comparing two policies for equivilence. # @return [Hash] Returns the policy as a hash with no ids # @api private def hash_without_ids hash = self.to_h hash.delete('Id') hash['Statement'].each do |statement| statement.delete('Sid') end hash end protected :hash_without_ids # Returns a hash representation of the policy. The following # statements are equivalent: # # policy.to_h.to_json # policy.to_json # # @return [Hash] def to_h { "Version" => version, "Id" => id, "Statement" => statements.map { |st| st.to_h } } end # @return [String] a JSON representation of the policy. def to_json to_h.to_json end # Constructs a policy from a JSON representation. # @see #initialize # @return [Policy] Returns a Policy object constructed by parsing # the passed JSON policy. def self.from_json(json) new(JSON.parse(json)) end # Convenient syntax for expressing operators in statement # condition blocks. For example, the following: # # policy.allow.where(:s3_prefix).not("forbidden"). # where(:current_time).lte(Date.today+1) # # is equivalent to: # # conditions = Policy::ConditionBlock.new # conditions.add(:not, :s3_prefix, "forbidden") # conditions.add(:lte, :current_time, Date.today+1) # policy.allow(:conditions => conditions) # # @see ConditionBlock#add class OperatorBuilder # @api private def initialize(condition_builder, key) @condition_builder = condition_builder @key = key end def method_missing(m, *values) @condition_builder.conditions.add(m, @key, *values) @condition_builder end end # Convenient syntax for adding conditions to a statement. # @see Policy#allow # @see Policy#deny class ConditionBuilder # @return [Array] Returns an array of policy conditions. attr_reader :conditions # @api private def initialize(conditions) @conditions = conditions end # Adds a condition for the given key. For example: # # policy.allow(...).where(:current_time).lte(Date.today + 1) # # @return [OperatorBuilder] def where(key, operator = nil, *values) if operator @conditions.add(operator, key, *values) self else OperatorBuilder.new(self, key) end end end # Convenience method for constructing a new statement with the # "Allow" effect and adding it to the policy. For example: # # policy.allow( # :actions => [:put_object], # :principals => :any, # :resources => "mybucket/mykey/*"). # where(:acl).is("public-read") # # @option (see Statement#initialize) # @see Statement#initialize # @return [ConditionBuilder] def allow(opts = {}) stmt = self.class::Statement.new(opts.merge(:effect => :allow)) statements << stmt ConditionBuilder.new(stmt.conditions) end # Convenience method for constructing a new statement with the # "Deny" effect and adding it to the policy. For example: # # policy.deny( # :actions => [:put_object], # :principals => :any, # :resources => "mybucket/mykey/*" # ).where(:acl).is("public-read") # # @param (see Statement#initialize) # @see Statement#initialize # @return [ConditionBuilder] def deny(opts = {}) stmt = self.class::Statement.new(opts.merge(:effect => :deny)) statements << stmt ConditionBuilder.new(stmt.conditions) end # Represents the condition block of a policy. In JSON, # condition blocks look like this: # # { "StringLike": { "s3:prefix": ["photos/*", "photos.html"] } } # # ConditionBlock lets you specify conditions like the above # example using the add method, for example: # # conditions.add(:like, :s3_prefix, "photos/*", "photos.html") # # See the add method documentation for more details about how # to specify keys and operators. # # This class also provides a convenient way to query a # condition block to see what operators, keys, and values it # has. For example, consider the following condition block # (in JSON): # # { # "StringEquals": { # "s3:prefix": "photos/index.html" # }, # "DateEquals": { # "aws:CurrentTime": ["2010-10-12", "2011-01-02"] # }, # "NumericEquals": { # "s3:max-keys": 10 # } # } # # You can get access to the condition data using #[], #keys, # #operators, and #values -- for example: # # conditions["DateEquals"]["aws:CurrentTime"].values # # => ["2010-10-12", "2011-01-02"] # # You can also perform more sophisticated queries, like this # one: # # conditions[:is].each do |equality_conditions| # equality_conditions.keys.each do |key| # puts("#{key} may be any of: " + # equality_conditions[key].values.join(" ") # end # end # # This would print the following lines: # # s3:prefix may be any of: photos/index.html # aws:CurrentTime may be any of: 2010-10-12 2011-01-02 # s3:max-keys may be any of: 10 # class ConditionBlock # @api private def initialize(conditions = {}) # filter makes a copy @conditions = filter_conditions(conditions) end # Adds a condition to the block. This method defines a # convenient set of abbreviations for operators based on the # type of value passed in. For example: # # conditions.add(:is, :secure_transport, true) # # Maps to: # # { "Bool": { "aws:SecureTransport": true } } # # While: # # conditions.add(:is, :s3_prefix, "photos/") # # Maps to: # # { "StringEquals": { "s3:prefix": "photos/" } } # # The following list shows which operators are accepted as # symbols and how they are represented in the JSON policy: # # * `:is` (StringEquals, NumericEquals, DateEquals, or Bool) # * `:like` (StringLike) # * `:not_like` (StringNotLike) # * `:not` (StringNotEquals, NumericNotEquals, or DateNotEquals) # * `:greater_than`, `:gt` (NumericGreaterThan or DateGreaterThan) # * `:greater_than_equals`, `:gte` # (NumericGreaterThanEquals or DateGreaterThanEquals) # * `:less_than`, `:lt` (NumericLessThan or DateLessThan) # * `:less_than_equals`, `:lte` # (NumericLessThanEquals or DateLessThanEquals) # * `:is_ip_address` (IpAddress) # * `:not_ip_address` (NotIpAddress) # * `:is_arn` (ArnEquals) # * `:not_arn` (ArnNotEquals) # * `:is_arn_like` (ArnLike) # * `:not_arn_like` (ArnNotLike) # # @param [Symbol or String] operator The operator used to # compare the key with the value. See above for valid # values and their interpretations. # # @param [Symbol or String] key The key to compare. Symbol # keys are inflected to match AWS conventions. By # default, the key is assumed to be in the "aws" # namespace, but if you prefix the symbol name with "s3_" # it will be sent in the "s3" namespace. For example, # `:s3_prefix` is sent as "s3:prefix" while # `:secure_transport` is sent as "aws:SecureTransport". # See # http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingResOpsConditions.html # for a list of the available keys for each action in S3. # # @param [Mixed] values The value to compare against. # This can be: # * a String # * a number # * a Date, DateTime, or Time # * a boolean value # This method does not attempt to validate that the values # are valid for the operators or keys they are used with. # def add(operator, key, *values) if operator.kind_of?(Symbol) converted_values = values.map { |v| convert_value(v) } else converted_values = values end operator = translate_operator(operator, values.first) op = (@conditions[operator] ||= {}) raise "duplicate #{operator} conditions for #{key}" if op[key] op[translate_key(key)] = converted_values end # @api private def to_h @conditions end # Filters the conditions described in the block, returning a # new ConditionBlock that contains only the matching # conditions. Each argument is matched against either the # keys or the operators in the block, and you can specify # the key or operator in any way that's valid for the #add # method. Some examples: # # # all conditions using the StringLike operator # conditions["StringLike"] # # # all conditions using StringEquals, DateEquals, NumericEquals, or Bool # conditions[:is] # # # all conditions on the s3:prefix key # conditions["s3:prefix"] # # # all conditions on the aws:CurrentTime key # conditions[:current_time] # # Multiple conditions are ANDed together, so the following # are equivalent: # # conditions[:s3_prefix][:is] # conditions[:is][:s3_prefix] # conditions[:s3_prefix, :is] # # @see #add # @return [ConditionBlock] A new set of conditions filtered by the # given conditions. def [](*args) filtered = @conditions args.each do |filter| type = valid_operator?(filter) ? nil : :key filtered = filter_conditions(filtered) do |op, key, value| (match, type) = match_triple(filter, type, op, key, value) match end end self.class.new(filtered) end # @return [Array] Returns an array of operators used in this block. def operators @conditions.keys end # @return [Array] Returns an array of unique keys used in the block. def keys @conditions.values.map do |keys| keys.keys if keys end.compact.flatten.uniq end # Returns all values used in the block. Note that the # values may not all be from the same condition; for example: # # conditions.add(:like, :user_agent, "mozilla", "explorer") # conditions.add(:lt, :s3_max_keys, 12) # conditions.values # => ["mozilla", "explorer", 12] # # @return [Array] Returns an array of values used in this condition block. def values @conditions.values.map do |keys| keys.values end.compact.flatten end # @api private protected def match_triple(filter, type, op, key, value) value = [value].flatten.first if type target = (type == :operator ? op : key) match = send("match_#{type}", filter, target, value) else if match_operator(filter, op, value) match = true type = :operator elsif match_key(filter, key) match = true type = :key else match = false end end [match, type] end # @api private protected def match_operator(filter, op, value) # dates are the only values that don't come back as native types in JSON # but where we use the type as a cue to the operator translation value = Date.today if op =~ /^Date/ translate_operator(filter, value) == op end # @api private protected def match_key(filter, key, value = nil) translate_key(filter) == key end # @api private protected def filter_conditions(conditions = @conditions) conditions.inject({}) do |m, (op, keys)| m[op] = keys.inject({}) do |m2, (key, value)| m2[key] = value if !block_given? or yield(op, key, value) m2 end m.delete(op) if m[op].empty? m end end # @api private protected def translate_key(key) if key.kind_of?(Symbol) if key.to_s =~ /^s3_(.*)$/ s3_name = $1 if s3_name == "version_id" or s3_name == "location_constraint" s3_name = Inflection.class_name(s3_name) else s3_name.tr!('_', '-') end "s3:#{s3_name}" else "aws:#{Inflection.class_name(key.to_s)}" end else key end end # @api private MODIFIERS = { /_ignoring_case$/ => "IgnoreCase", /_equals$/ => "Equals" } # @api private protected def valid_operator?(operator) translate_operator(operator, "") true rescue ArgumentError => e false end # @api private protected def translate_operator(operator, example_value) return operator if operator.kind_of?(String) original_operator = operator (operator, opts) = strip_modifiers(operator) raise ArgumentError.new("unrecognized operator #{original_operator}") unless respond_to?("translate_#{operator}", true) send("translate_#{operator}", example_value, opts) end # @api private protected def translate_is(example, opts) return "Bool" if type_notation(example) == "Bool" base_translate(example, "Equals", opts[:ignore_case]) end # @api private protected def translate_not(example, opts) base_translate(example, "NotEquals", opts[:ignore_case]) end # @api private protected def translate_like(example, opts) base_translate(example, "Like") end # @api private protected def translate_not_like(example, opts) base_translate(example, "NotLike") end # @api private protected def translate_less_than(example, opts) base_translate(example, "LessThan", opts[:equals]) end alias_method :translate_lt, :translate_less_than # @api private protected def translate_lte(example, opts) translate_less_than(example, { :equals => "Equals" }) end # @api private protected def translate_greater_than(example, opts) base_translate(example, "GreaterThan", opts[:equals]) end alias_method :translate_gt, :translate_greater_than # @api private protected def translate_gte(example, opts) translate_greater_than(example, { :equals => "Equals" }) end # @api private protected def translate_is_ip_address(example, opts) "IpAddress" end # @api private protected def translate_not_ip_address(example, opts) "NotIpAddress" end # @api private protected def translate_is_arn(example, opts) "ArnEquals" end # @api private protected def translate_not_arn(example, opts) "ArnNotEquals" end # @api private protected def translate_is_arn_like(example, opts) "ArnLike" end # @api private protected def translate_not_arn_like(example, opts) "ArnNotLike" end # @api private protected def base_translate(example, base_operator, *modifiers) "#{type_notation(example)}#{base_operator}#{modifiers.join}" end # @api private protected def type_notation(example) case example when String "String" when Numeric "Numeric" when Time, Date "Date" when true, false "Bool" end end # @api private protected def convert_value(value) case value when DateTime, Time Time.parse(value.to_s).iso8601 when Date value.strftime("%Y-%m-%d") else value end end # @api private protected def strip_modifiers(operator) opts = {} MODIFIERS.each do |(regex, mod)| ruby_name = Inflection.ruby_name(mod).to_sym opts[ruby_name] = "" if operator.to_s =~ regex opts[ruby_name] = mod operator = operator.to_s.sub(regex, '').to_sym end end [operator, opts] end end # Represents a statement in a policy. # # @see Policy#allow # @see Policy#deny class Statement # @return [String] Returns the statement id attr_accessor :sid # @return [String] Returns the statement effect, either "Allow" or # "Deny" attr_accessor :effect # @return [Array] Returns an array of principals. attr_accessor :principals # @return [Array] Returns an array of statement actions included # by this policy statement. attr_accessor :actions # @return [Array] Returns an array of actions excluded by this # policy statement. attr_accessor :excluded_actions # @return [Array] Returns an array of resources affected by this # policy statement. attr_accessor :resources # @return [Array] Returns an array of conditions for this policy. attr_accessor :conditions attr_accessor :excluded_resources # Constructs a new statement. # # @option opts [String] :sid The statement ID. This is optional; if # omitted, a UUID will be generated for the statement. # @option opts [String] :effect The statement effect, which must be either # "Allow" or "Deny". # @see Policy#allow # @see Policy#deny # @option opts [String or array of strings] :principals The account(s) # affected by the statement. These should be AWS account IDs. # @option opts :actions The action or actions affected by # the statement. These can be symbols or strings. If # they are strings, you can use wildcard character "*" # to match zero or more characters in the action name. # Symbols are expected to match methods of S3::Client. # @option opts :excluded_actions Action or actions which are # explicitly not affected by this statement. As with # `:actions`, these may be symbols or strings. # @option opts [String or array of strings] :resources The # resource(s) affected by the statement. These can be # expressed as ARNs (e.g. `arn:aws:s3:::mybucket/mykey`) # or you may omit the `arn:aws:s3:::` prefix and just give # the path as `bucket_name/key`. You may use the wildcard # character "*" to match zero or more characters in the # resource name. # @option opts [ConditionBlock or Hash] :conditions # Additional conditions that narrow the effect of the # statement. It's typically more convenient to use the # ConditionBuilder instance returned from Policy#allow or # Policy#deny to add conditions to a statement. # @see S3::Client def initialize(opts = {}) self.sid = SecureRandom.uuid.tr('-','') self.conditions = ConditionBlock.new parse_options(opts) yield(self) if block_given? end # Convenience method to add to the list of actions affected # by this statement. def include_actions(*actions) self.actions ||= [] self.actions.push(*actions) end alias_method :include_action, :include_actions # Convenience method to add to the list of actions # explicitly not affected by this statement. def exclude_actions(*actions) self.excluded_actions ||= [] self.excluded_actions.push(*actions) end alias_method :exclude_action, :exclude_actions # @api private def to_h stmt = { "Sid" => sid, "Effect" => Inflection.class_name(effect.to_s), "Principal" => principals_hash, "Resource" => (resource_arns if resource_arns), "NotResource" => (excluded_resource_arns if excluded_resource_arns), "Condition" => (conditions.to_h if conditions) } stmt.delete("Condition") if !conditions || conditions.to_h.empty? stmt.delete("Principal") unless principals_hash stmt.delete("Resource") unless resource_arns stmt.delete("NotResource") unless excluded_resource_arns if !translated_actions || translated_actions.empty? stmt["NotAction"] = translated_excluded_actions else stmt["Action"] = translated_actions end stmt end protected def parse_options(options) options.each do |name, value| name = Inflection.ruby_name(name.to_s) name.sub!(/s$/,'') send("parse_#{name}_option", value) if respond_to?("parse_#{name}_option", true) end end protected def parse_effect_option(value) self.effect = value end protected def parse_sid_option(value) self.sid = value end protected def parse_action_option(value) coerce_array_option(:actions, value) end protected def parse_not_action_option(value) coerce_array_option(:excluded_actions, value) end alias_method :parse_excluded_action_option, :parse_not_action_option protected def parse_principal_option(value) if value and value.kind_of?(Hash) value = value["AWS"] || [] end coerce_array_option(:principals, value) end protected def parse_resource_option(value) coerce_array_option(:resources, value) end def parse_not_resource_option(value) coerce_array_option(:excluded_resources, value) end alias_method :parse_excluded_resource_option, :parse_not_resource_option protected def parse_condition_option(value) self.conditions = ConditionBlock.new(value) end protected def coerce_array_option(attr, value) if value.kind_of?(Array) send("#{attr}=", value) else send("#{attr}=", [value]) end end protected def principals_hash return nil unless principals { "AWS" => principals.map do |principal| principal == :any ? "*" : principal end } end protected def translate_action(action) case action when String then action when :any then '*' when Symbol if self.class == Core::Policy::Statement msg = 'symbolized action names are only accepted by service ' + 'specific policies (e.g. AWS::S3::Policy)' raise ArgumentError, msg end unless self.class::ACTION_MAPPING.has_key?(action) raise ArgumentError, "unrecognized action: #{action}" end self.class::ACTION_MAPPING[action] end end protected def translated_actions return nil unless actions actions.map do |action| translate_action(action) end end protected def translated_excluded_actions return nil unless excluded_actions excluded_actions.map { |a| translate_action(a) } end protected def resource_arns return nil unless resources resources.map do |resource| case resource when :any then "*" else resource_arn(resource) end end end protected def resource_arn resource resource.to_s end protected def excluded_resource_arns return nil unless excluded_resources excluded_resources.map do |excluded_resource| case excluded_resource when :any then "*" else excluded_resource_arn(excluded_resource) end end end protected def excluded_resource_arn excluded_resource excluded_resource.to_s end end end end end aws-sdk-v1-1.66.0/lib/aws/core/json_client.rb0000644000004100000410000000263512604445426020672 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core class JSONClient < Core::Client protected def self.request_builder_for api_config, operation JSONRequestBuilder.new(api_config, operation) end def self.response_parser_for api_config, operation JSONResponseParser.new(operation[:outputs]) end def extract_error_details response if response.http_response.status >= 300 and body = response.http_response.body and json = (::JSON.load(body) rescue nil) and type = json["__type"] then code = type.split('#').last if code == 'RequestEntityTooLarge' message = 'Request body must be less than 1 MB' else message = json['message'] || json['Message'] end [code, message] end end end end end aws-sdk-v1-1.66.0/lib/aws/core/client.rb0000644000004100000410000005761612604445426017652 0ustar www-datawww-data# Copyright 2011-2013 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 'json' require 'set' require 'yaml' require 'uri' module AWS module Core # Base client class for all of the Amazon AWS service clients. class Client extend Deprecations # Raised when a request failed due to a networking issue (e.g. # EOFError, IOError, Errno::ECONNRESET, Errno::EPIPE, # Timeout::Error, etc) class NetworkError < StandardError; end extend Naming # @api private CACHEABLE_REQUESTS = Set[] # Creates a new low-level client. # @param [Hash] options # @option options [Core::Configuration] :config (AWS.config) # The base configuration object to use. All other options # are merged with this. Defaults to the AWS.config. # @option (see AWS.config) def initialize options = {} options = options.dup # so we don't modify the options passed in @service_ruby_name = self.class.service_ruby_name # translate these into service specific configuration options, # e.g. :endpoint into :s3_endpoint [:endpoint, :region, :port, :signature_version].each do |opt| if options[opt] options[:"#{service_ruby_name}_#{opt}"] = options.delete(opt) end end @config = (options.delete(:config) || AWS.config) @config = @config.with(options) @region = @config.send(:"#{service_ruby_name}_region") @credential_provider = @config.credential_provider @http_handler = @config.http_handler @endpoint = config.send(:"#{service_ruby_name}_endpoint") @port = config.send(:"#{service_ruby_name}_port") # deprecated attributes @http_read_timeout = @config.http_read_timeout end # @return [Configuration] This clients configuration. attr_reader :config # @return [CredentialProviders::Provider] Returns the credential # provider for this client. # @api private attr_reader :credential_provider # @return [String] The snake-cased ruby name for the service # (e.g. 's3', 'iam', 'dynamo_db', etc). # @api private attr_reader :service_ruby_name # @return [Integer] What port this client makes requests via. # @api private attr_reader :port # @return [Integer] The number of seconds before requests made by # this client should timeout if they have not received a response. # @api private attr_reader :http_read_timeout deprecated :http_read_timeout, :use => 'config.http_read_timeout' # @return [String] Returns the service endpoint (hostname) this client # makes requests against. # @api private attr_reader :endpoint # @return (see Client.operations) def operations self.class.operations end # Returns a copy of the client with a different HTTP handler. # You can pass an object like BuiltinHttpHandler or you can # use a block; for example: # # s3_with_logging = s3.with_http_handler do |request, response| # $stderr.puts request.inspect # super(request, response) # $stderr.puts response.inspect # end # # The block executes in the context of an HttpHandler # instance, and `super` delegates to the HTTP handler used by # this client. This provides an easy way to spy on requests # and responses. See HttpHandler, HttpRequest, and # HttpResponse for more details on how to implement a fully # functional HTTP handler using a different HTTP library than # the one that ships with Ruby. # @param handler (nil) A new http handler. Leave blank and pass a # block to wrap the current handler with the block. # @return [Core::Client] Returns a new instance of the client class with # the modified or wrapped http handler. def with_http_handler(handler = nil, &blk) handler ||= Http::Handler.new(@http_handler, &blk) with_options(:http_handler => handler) end # Returns a new client with the passed configuration options # merged with the current configuration options. # # no_retry_client = client.with_options(:max_retries => 0) # # @param [Hash] options # @option (see AWS.config) # @return [Client] def with_options options with_config(config.with(options)) end # @param [Configuration] config The configuration object to use. # @return [Core::Client] Returns a new client object with the given # configuration. # @api private def with_config config self.class.new(:config => config) end # The stub returned is memoized. # @see new_stub_for # @api private def stub_for method_name @stubs ||= {} @stubs[method_name] ||= new_stub_for(method_name) end # Primarily used for testing, this method returns an empty pseudo # service response without making a request. Its used primarily for # testing the lighter level service interfaces. # @api private def new_stub_for method_name response = Response.new(Http::Request.new, Http::Response.new) response.request_type = method_name response.request_options = {} send("simulate_#{method_name}_response", response) response.signal_success response end # Logs the warning to the configured logger, otherwise to stderr. # @param [String] warning # @return [nil] def log_warning warning message = '[aws-sdk-gem-warning] ' + warning if config.logger config.logger.warn(message) else $stderr.puts(message) end nil end # @api private def inspect "#<#{self.class.name}>" end # @api private def to_yaml_properties skip = %w(@config @credential_provider @http_handler) instance_variables.map(&:to_s) - skip end protected # @api private def new_request Http::Request.new end def new_response(*args, &block) resp = Response.new(*args, &block) resp.config = config resp.api_version = self.class::API_VERSION resp end def make_async_request response pauses = async_request_with_retries(response, response.http_request) response end def async_request_with_retries response, http_request, retry_delays = nil response.http_response = Http::Response.new handle = Object.new handle.extend AsyncHandle handle.on_complete do |status| case status when :failure response.error = StandardError.new("failed to contact the service") response.signal_failure when :success populate_error(response) retry_delays ||= sleep_durations(response) if should_retry?(response) and !retry_delays.empty? rebuild_http_request(response) @http_handler.sleep_with_callback(retry_delays.shift) do async_request_with_retries(response, response.http_request, retry_delays) end else response.error ? response.signal_failure : response.signal_success end end end @http_handler.handle_async(http_request, response.http_response, handle) end def make_sync_request response, &read_block retry_server_errors do response.http_response = Http::Response.new @http_handler.handle( response.http_request, response.http_response, &read_block) if block_given? and response.http_response.status < 300 and response.http_response.body then msg = ":http_handler read the entire http response body into " msg << "memory, it should have instead yielded chunks" log_warning(msg) # go ahead and yield the body on behalf of the handler yield(response.http_response.body) end populate_error(response) response.signal_success unless response.error response end end def retry_server_errors &block response = yield sleeps = sleep_durations(response) while should_retry?(response) break if sleeps.empty? Kernel.sleep(sleeps.shift) rebuild_http_request(response) response = yield end response end def rebuild_http_request response credential_provider.refresh if expired_credentials?(response) response.rebuild_request if redirected?(response) loc = URI.parse(response.http_response.headers['location'].first) AWS::Core::MetaUtils.extend_method(response.http_request, :host) do loc.host end response.http_request.host = loc.host response.http_request.port = loc.port response.http_request.uri = loc.path end response.retry_count += 1 end def sleep_durations response if expired_credentials?(response) [0] else factor = scaling_factor(response) Array.new(config.max_retries) {|n| (2 ** n) * factor } end end def scaling_factor response throttled?(response) ? (0.5 + Kernel.rand * 0.1) : 0.3 end def should_retry? response if retryable_error?(response) response.safe_to_retry? else false end end def retryable_error? response expired_credentials?(response) or response.network_error? or throttled?(response) or redirected?(response) or response.error.kind_of?(Errors::ServerError) end # @return [Boolean] Returns `true` if the response contains an # error message that indicates credentials have expired. def expired_credentials? response response.error and response.error.respond_to?(:code) and ( response.error.code.to_s.match(/expired/i) or # session credentials response.error.code == 'InvalidClientTokenId' or # query services response.error.code == 'UnrecognizedClientException' or # json services response.error.code == 'InvalidAccessKeyId' or # s3 response.error.code == 'AuthFailure' # ec2 ) end def throttled? response response.error and response.error.respond_to?(:code) and ( response.error.code.to_s.match(/throttl/i) or #response.error.code == 'Throttling' or # most query services #response.error.code == 'ThrottlingException' or # json services #response.error.code == 'RequestThrottled' or # sqs response.error.code == 'ProvisionedThroughputExceededException' or # ddb response.error.code == 'RequestLimitExceeded' or # ec2 response.error.code == 'BandwidthLimitExceeded' # cloud search ) end def redirected? response response.http_response.status == 307 end def return_or_raise options, &block response = yield unless options[:async] raise response.error if response.error end response end # Yields to the given block (which should be making a # request and returning a {Response} object). The results of the # request/response are logged. # # @param [Hash] options # @option options [Boolean] :async # @return [Response] def log_client_request options, &block # time the request, retries and all start = Time.now response = yield response.duration = Time.now - start if options[:async] response.on_complete { log_response(response) } else log_response(response) end response end # Logs the response to the configured logger. # @param [Response] response # @return [nil] def log_response response if config.logger message = config.log_formatter.format(response) config.logger.send(config.log_level, message) end nil end def populate_error response status = response.http_response.status error_code, error_message = extract_error_details(response) error_args = [ response.http_request, response.http_response, error_code, error_message ] response.error = case when response.network_error? then response.http_response.network_error when error_code then error_class(error_code).new(*error_args) when status >= 500 then Errors::ServerError.new(*error_args) when status >= 300 then Errors::ClientError.new(*error_args) else nil # no error end end # Extracts the error code and error message from a response # if it contains an error. Returns nil otherwise. Should be defined # in sub-classes (e.g. QueryClient, RESTClient, etc). # @param [Response] response # @return [Array,nil] Should return an array with an # error code and message, or `nil`. def extract_error_details response raise NotImplementedError end # Given an error code string, this method will return an error class. # # AWS::EC2::Client.new.send(:error_code, 'InvalidInstanceId') # #=> AWS::EC2::Errors::InvalidInstanceId # # @param [String] error_code The error code string as returned by # the service. If this class contains periods, they will be # converted into namespaces (e.g. 'Foo.Bar' becomes Errors::Foo::Bar). # # @return [Class] # def error_class error_code errors_module.error_class(error_code) end # Returns the ::Errors module for the current client. # # AWS::S3::Client.new.errors_module # #=> AWS::S3::Errors # # @return [Module] # def errors_module AWS.const_get(self.class.to_s[/(\w+)::Client/, 1])::Errors end def client_request name, options, &read_block return_or_raise(options) do log_client_request(options) do if config.stub_requests? response = stub_for(name) response.http_request = build_request(name, options) response.request_options = options response else client = self response = new_response do req = client.send(:build_request, name, options) client.send(:sign_request, req) req end response.request_type = name response.request_options = options if cacheable_request?(name, options) and cache = AWS.response_cache and cached_response = cache.cached(response) then cached_response.cached = true cached_response else # process the http request options[:async] ? make_async_request(response, &read_block) : make_sync_request(response, &read_block) # process the http response response.on_success do send("process_#{name}_response", response) if cache = AWS.response_cache cache.add(response) end end # close files we opened response.on_complete do if response.http_request.body_stream.is_a?(ManagedFile) response.http_request.body_stream.close end end response end end end end end def cacheable_request? name, options self.class::CACHEABLE_REQUESTS.include?(name) end def build_request name, options # we dont want to pass the async option to the configure block opts = options.dup opts.delete(:async) http_request = new_request http_request.access_key_id = credential_provider.access_key_id http_request.service = self.class.name.split('::')[1] # configure the http request http_request.service_ruby_name = service_ruby_name http_request.host = endpoint http_request.port = port http_request.region = @region http_request.use_ssl = config.use_ssl? http_request.read_timeout = config.http_read_timeout send("configure_#{name}_request", http_request, opts) http_request.headers["user-agent"] = user_agent_string if @config.http_continue_threshold and http_request.headers['content-length'] and http_request.headers['content-length'].to_i > @config.http_continue_threshold then http_request.headers["expect"] = "100-continue" http_request.continue_timeout = @config.http_continue_timeout else http_request.continue_timeout = nil end http_request end # @param [Http::Request] req # @return [Http::Request] # @api private def sign_request req req end def user_agent_string engine = (RUBY_ENGINE rescue nil or "ruby") user_agent = "%s aws-sdk-ruby/#{VERSION} %s/%s %s" % [config.user_agent_prefix, engine, RUBY_VERSION, RUBY_PLATFORM] user_agent.strip! if AWS.memoizing? user_agent << " memoizing" end user_agent end class << self # @return [Array] Returns a list of service operations as # method names supported by this client. # @api private def operations(options = {}) if name.match(/V\d{8}$/) @operations ||= [] else client_class(options).operations end end # @api private def request_builders @request_builders ||= {} end # @api private def response_parsers @response_parsers ||= {} end # @api private def new(*args, &block) options = args.last.is_a?(Hash) ? args.last : {} client = client_class(options).allocate client.send(:initialize, *args, &block) client end private def client_class(options) if name =~ /Client::V\d+$/ self else const_get("V#{client_api_version(options).gsub(/-/, '')}") end end def client_api_version(options) api_version = options[:api_version] api_version ||= configured_version(options[:config]) if options[:config] api_version ||= configured_version(AWS.config) api_version || const_get(:API_VERSION) end def configured_version(config = AWS.config) svc_opt = AWS::SERVICES[name.split('::')[1]].method_name config.send(svc_opt)[:api_version] end protected # Define this in sub-classes (e.g. QueryClient, RESTClient, etc) def request_builder_for api_config, operation raise NotImplementedError end # Define this in sub-classes (e.g. QueryClient, RESTClient, etc) def response_parser_for api_config, operation raise NotImplementedError end # Adds a single method to the current client class. This method # yields a request method builder that allows you to specify how: # # * the request is built # * the response is processed # * the response is stubbed for testing # def add_client_request_method method_name, options = {}, &block operations << method_name ClientRequestMethodBuilder.new(self, method_name, &block) method_def = <<-METHOD def #{method_name}(*args, &block) options = args.first ? args.first : {} client_request(#{method_name.inspect}, options, &block) end METHOD module_eval(method_def) end # Loads the API configuration for the given API version. # @param [String] api_version The API version date string # (e.g. '2012-01-05'). # @return [Hash] def load_api_config api_version lib = File.dirname(File.dirname(__FILE__)) path = "#{lib}/api_config/#{service_name}-#{api_version}.yml" YAML.load(File.read(path)) end # @param [Symbol] version # @param [String,nil] service_signing_name Required for `:Version4` # @api private def signature_version version, service_signing_name = nil define_method(:sign_request) do |req| @signer ||= begin signer_class = AWS::Core::Signers.const_get(version) signer_args = (version == :Version4) ? [credential_provider, service_signing_name, req.region] : [credential_provider] signer_class.new(*signer_args) end @signer.sign_request(req) req end end # Defines one method for each service operation described in # the API configuration. # @param [String] api_version def define_client_methods api_version const_set(:API_VERSION, api_version) api_config = load_api_config(api_version) api_config[:operations].each do |operation| builder = request_builder_for(api_config, operation) parser = response_parser_for(api_config, operation) define_client_method(operation[:method], builder, parser) end end def define_client_method method_name, builder, parser request_builders[method_name] = builder response_parsers[method_name] = parser add_client_request_method(method_name) do configure_request do |request, request_options| builder.populate_request(request, request_options) end process_response do |response| response.data = parser.extract_data(response) end simulate_response do |response| response.data = parser.simulate end end end end # @api private class ClientRequestMethodBuilder def initialize client_class, method_name, &block @client_class = client_class @method_name = method_name configure_request {|request, options|} process_response {|response|} simulate_response {|response|} instance_eval(&block) end def configure_request options = {}, &block name = "configure_#{@method_name}_request" MetaUtils.class_extend_method(@client_class, name, &block) end def process_response &block name = "process_#{@method_name}_response" MetaUtils.class_extend_method(@client_class, name, &block) end def simulate_response &block name = "simulate_#{@method_name}_response" MetaUtils.class_extend_method(@client_class, name, &block) end end end end end aws-sdk-v1-1.66.0/lib/aws/core/credential_providers.rb0000644000004100000410000005033312604445426022570 0ustar www-datawww-data# Copyright 2011-2013 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 'net/http' require 'timeout' require 'thread' require 'time' require 'json' module AWS module Core module CredentialProviders # This module is mixed into the various credential provider # classes. It provides a unified interface for getting # credentials and refreshing them. module Provider # The list of possible keys in the hash returned by {#credentials}. KEYS = Set[:access_key_id, :secret_access_key, :session_token] # @return [Hash] Returns a hash of credentials containg at least # the `:access_key_id` and `:secret_access_key`. The hash may # also contain a `:session_token`. # # @raise [Errors::MissingCredentialsError] Raised when the # `:access_key_id` or the `:secret_access_key` can not be found. # def credentials raise Errors::MissingCredentialsError unless set? @cached_credentials.dup end # @return [Boolean] Returns true if has credentials and it contains # at least the `:access_key_id` and `:secret_access_key`. # def set? @cache_mutex ||= Mutex.new unless @cached_credentials @cache_mutex.synchronize do @cached_credentials ||= get_credentials end end !!(@cached_credentials[:access_key_id] && @cached_credentials[:secret_access_key]) end # @return [String] Returns the AWS access key id. # @raise (see #credentials) def access_key_id credentials[:access_key_id] end # @return [String] Returns the AWS secret access key. # @raise (see #credentials) def secret_access_key credentials[:secret_access_key] end # @return [String,nil] Returns the AWS session token or nil if these # are not session credentials. # @raise (see #credentials) def session_token credentials[:session_token] end # Clears out cached/memoized credentials. Causes the provider # to refetch credentials from the source. # @return [nil] def refresh @cached_credentials = nil end protected # This method is called on a credential provider to fetch # credentials. The credentials hash returned from this # method will be cached until the client calls {#refresh}. # @return [Hash] def get_credentials # should be defined in provider classes. raise NotImplementedError end end # The default credential provider makes a best effort to # locate your AWS credentials. It checks a variety of locations # in the following order: # # * Static credentials from AWS.config (e.g. AWS.config.access_key_id, # AWS.config.secret_access_key) # # * The environment (e.g. ENV['AWS_ACCESS_KEY_ID'] or # ENV['AMAZON_ACCESS_KEY_ID']) # # * EC2 metadata service (checks for credentials provided by # roles for instances). # class DefaultProvider include Provider # (see StaticProvider#new) def initialize static_credentials = {} @providers = [] @providers << StaticProvider.new(static_credentials) @providers << ENVProvider.new('AWS') @providers << ENVProvider.new('AWS', :access_key_id => 'ACCESS_KEY', :secret_access_key => 'SECRET_KEY', :session_token => 'SESSION_TOKEN') @providers << ENVProvider.new('AMAZON') begin if Dir.home @providers << SharedCredentialFileProvider.new end rescue ArgumentError, NoMethodError end @providers << EC2Provider.new end # @return [Array] attr_reader :providers def credentials providers.each do |provider| if provider.set? return provider.credentials end end raise Errors::MissingCredentialsError end def set? providers.any?(&:set?) end def refresh providers.each do |provider| provider.refresh end end end # Static credentials are provided directly to config via # `:access_key_id` and `:secret_access_key` (and optionally # `:session_token`). # @api private class StaticProvider include Provider # @param [Hash] static_credentials # @option static_credentials [required,String] :access_key_id # @option static_credentials [required,String] :secret_access_key # @option static_credentials [String] :session_token def initialize static_credentials = {} static_credentials.keys.each do |opt_name| unless KEYS.include?(opt_name) raise ArgumentError, "invalid option #{opt_name.inspect}" end end @static_credentials = {} KEYS.each do |opt_name| if opt_value = static_credentials[opt_name] @static_credentials[opt_name] = opt_value end end end # (see Provider#get_credentials) def get_credentials @static_credentials end end # Fetches credentials from the environment (ENV). You construct # an ENV provider with a prefix. Given the prefix "AWS" # ENV will be checked for the following keys: # # * AWS_ACCESS_KEY_ID # * AWS_SECRET_ACCESS_KEY # * AWS_SESSION_TOKEN (optional) # class ENVProvider include Provider # @param [String] prefix The prefix to apply to the ENV variable. def initialize(prefix, suffixes=Hash[KEYS.map{|key| [key, key.to_s.upcase]}]) @prefix = prefix @suffixes = suffixes end # @return [String] attr_reader :prefix # (see Provider#get_credentials) def get_credentials credentials = {} KEYS.each do |key| if value = ENV["#{@prefix}_#{@suffixes[key]}"] credentials[key] = value end end # Merge in CredentialFileProvider credentials if # a #{@prefix}_CREDENTIAL_FILE environment(ENV) variable is set if ENV["#{@prefix}_CREDENTIAL_FILE"] credentials.merge! CredentialFileProvider.new(ENV["#{@prefix}_CREDENTIAL_FILE"]).get_credentials end credentials end end # This credential provider gets credentials from a credential file # with the following format: # # AWSAccessKeyId=your_key # AWSSecretKey=your_secret # class CredentialFileProvider include Provider # Map of AWS credential file key names to accepted provider key names CREDENTIAL_FILE_KEY_MAP = { "AWSAccessKeyId" => :access_key_id, "AWSSecretKey" => :secret_access_key } attr_reader :credential_file # @param [String] credential_file The file path of a credential file def initialize(credential_file) @credential_file = credential_file end # (see Provider#get_credentials) def get_credentials credentials = {} if File.exist?(credential_file) && File.readable?(credential_file) File.open(credential_file, 'r') do |fh| fh.each_line do |line| key, val = line.strip.split(%r(\s*=\s*)) if key && val && CREDENTIAL_FILE_KEY_MAP[key] && KEYS.include?(CREDENTIAL_FILE_KEY_MAP[key]) credentials[CREDENTIAL_FILE_KEY_MAP[key]] = val end end fh.close end end credentials end end class SharedCredentialFileProvider include Provider def shared_credential_file_path if RUBY_VERSION < '1.9' msg = "Must specify the :path to your shared credential file when using" msg << " Ruby #{RUBY_VERSION}" raise ArgumentError, msg else File.join(Dir.home, '.aws', 'credentials') end end # @api private KEY_MAP = { "aws_access_key_id" => :access_key_id, "aws_secret_access_key" => :secret_access_key, "aws_session_token" => :session_token, } # @option [String] :path # @option [String] :profile_name def initialize(options = {}) @path = options[:path] || shared_credential_file_path @profile_name = options[:profile_name] @profile_name ||= ENV['AWS_PROFILE'] @profile_name ||= 'default' end # @return [String] attr_reader :path # @return [String] attr_reader :profile_name # (see Provider#get_credentials) def get_credentials if File.exist?(path) && File.readable?(path) load_from_path else {} end end private def load_from_path profile = load_profile KEY_MAP.inject({}) do |credentials, (source, target)| credentials[target] = profile[source] if profile.key?(source) credentials end end def load_profile ini = IniParser.parse(File.read(path)) ini[profile_name] || {} end end # This credential provider tries to get credentials from the EC2 # metadata service. class EC2Provider # Raised when an http response is recieved with a non 200 # http status code. # @api private class FailedRequestError < StandardError; end # These are the errors we trap when attempting to talk to the # instance metadata service. Any of these imply the service # is not present, no responding or some other non-recoverable # error. # @api private FAILURES = [ FailedRequestError, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, SocketError, Timeout::Error, ] include Provider # @param [Hash] options # @option options [String] :ip_address ('169.254.169.254') # @option options [Integer] :port (80) # @option options [Integer] :retries (0) Number of times to # retry retrieving credentials. # @option options [Float] :http_open_timeout (1) # @option options [Float] :http_read_timeout (1) # @option options [Object] :http_debug_output (nil) HTTP wire # traces are sent to this object. You can specify something # like $stdout. def initialize options = {} @ip_address = options[:ip_address] || '169.254.169.254' @port = options[:port] || 80 @retries = options[:retries] || 0 @http_open_timeout = options[:http_open_timeout] || 1 @http_read_timeout = options[:http_read_timeout] || 1 @http_debug_output = options[:http_debug_output] end # @return [String] Defaults to '169.254.169.254'. attr_accessor :ip_address # @return [Integer] Defaults to port 80. attr_accessor :port # @return [Integer] Defaults to 0 attr_accessor :retries # @return [Float] attr_accessor :http_open_timeout # @return [Float] attr_accessor :http_read_timeout # @return [Object,nil] attr_accessor :http_debug_output # @return [Time,nil] attr_accessor :credentials_expiration # Refresh provider if existing credentials will be expired in 15 min # @return [Hash] Returns a hash of credentials containg at least # the `:access_key_id` and `:secret_access_key`. The hash may # also contain a `:session_token`. # # @raise [Errors::MissingCredentialsError] Raised when the # `:access_key_id` or the `:secret_access_key` can not be found. # def credentials refresh if near_expiration? super end protected def near_expiration? if @credentials_expiration.nil? true elsif @credentials_expiration.utc <= (Time.now.utc + (15 * 60)) true else false end end # (see Provider#get_credentials) def get_credentials retries_left = retries begin http = Net::HTTP.new(ip_address, port, nil) http.open_timeout = http_open_timeout http.read_timeout = http_read_timeout http.set_debug_output(http_debug_output) if http_debug_output http.start # get the first/default instance profile name path = '/latest/meta-data/iam/security-credentials/' profile_name = get(http, path).lines.map(&:strip).first # get the session details from the instance profile name path << profile_name session = JSON.parse(get(http, path)) http.finish credentials = {} credentials[:access_key_id] = session['AccessKeyId'] credentials[:secret_access_key] = session['SecretAccessKey'] credentials[:session_token] = session['Token'] @credentials_expiration = Time.parse(session['Expiration']) credentials rescue *FAILURES => e if retries_left > 0 sleep_time = 2 ** (retries - retries_left) Kernel.sleep(sleep_time) retries_left -= 1 retry else {} end end end # Makes an HTTP Get request with the given path. If a non-200 # response is received, then a FailedRequestError is raised. # a {FailedRequestError} is raised. # @param [Net::HTTPSession] session # @param [String] path # @raise [FailedRequestError] # @return [String] Returns the http response body. def get session, path response = session.request(Net::HTTP::Get.new(path)) if response.code.to_i == 200 response.body else raise FailedRequestError end end end # # Session Credential Provider # # The session provider consumes long term credentials (`:access_key_id` # and `:secret_access_key`) and requests a session from STS. # It then returns the short term credential set from STS. # # Calling {#refresh} causes the session provider to request a new # set of credentials. # # This session provider is currently only used for DynamoDB which # requires session credentials. class SessionProvider include Provider @create_mutex = Mutex.new class << self # @param [Hash] long_term_credentials A hash of credentials with # `:access_key_id` and `:secret_access_key` (but not # `:session_token`). def for long_term_credentials @create_mutex.synchronize do @session_providers ||= {} @session_providers[long_term_credentials[:access_key_id]] = self.new(long_term_credentials) end end # Creation of SessionProviders *must* happen behind the mutex and # we want to reuse session providers for the same access key id. protected :new end # @param [Hash] long_term_credentials A hash of credentials with # `:access_key_id` and `:secret_access_key` (but not # `:session_token`). def initialize long_term_credentials @static = StaticProvider.new(long_term_credentials) if @static.session_token raise ArgumentError, 'invalid option :session_token' end @session_mutex = Mutex.new end # Aliasing the refresh method so we can call it from the refresh # method defined in this class. alias_method :orig_refresh, :refresh protected :orig_refresh # (see Provider#refresh) def refresh refresh_session orig_refresh end protected # (see Provider#get_credentials) def get_credentials session = cached_session if session.nil? refresh_session session = cached_session end session.credentials end # Replaces the cached STS session with a new one. # @return [nil] def refresh_session sts = AWS::STS.new(@static.credentials.merge(:use_ssl => true)) @session_mutex.synchronize do @session = sts.new_session end nil end # @return [nil,STS::Session] Returns nil if a session has not # already been started. def cached_session local_session = nil @session_mutex.synchronize do local_session = @session end local_session end end # An auto-refreshing credential provider that works by assuming # a role via {AWS::STS#assume_role}. # # provider = AWS::Core::CredentialProviders::AssumeRoleProvider.new( # sts: AWS::STS.new(access_key_id:'AKID', secret_access_key:'SECRET'), # # assume role options: # role_arn: "linked::account::arn", # role_session_name: "session-name" # ) # # ec2 = AWS::EC2.new(credential_provider:provider) # # If you omit the `:sts` option, a new {STS} service object will be # constructed and it will use the default credential provider # from {Aws.config}. # class AssumeRoleProvider include Provider # @option options [AWS::STS] :sts (STS.new) An instance of {AWS::STS}. # This is used to make the API call to assume role. # @option options [required, String] :role_arn # @option options [required, String] :role_session_name # @option options [String] :policy # @option options [Integer] :duration_seconds # @option options [String] :external_id def initialize(options = {}) @options = options.dup @sts = @options.delete(:sts) || STS.new end def credentials refresh if near_expiration? super end private def near_expiration? @expiration && @expiration.utc <= Time.now.utc + 5 * 60 end def get_credentials role = @sts.assume_role(@options) @expiration = role[:credentials][:expiration] role[:credentials] end end # Returns a set of fake credentials, should only be used for testing. class FakeProvider < StaticProvider # @param [Hash] options # @option options [Boolean] :with_session_token (false) When `true` a # fake session token will also be provided. def initialize options = {} options[:access_key_id] ||= fake_access_key_id options[:secret_access_key] ||= fake_secret_access_key if options.delete(:with_session_token) options[:session_token] ||= fake_session_token end super end protected def fake_access_key_id "AKIA" + random_chars(16).upcase end def fake_secret_access_key random_chars(40) end def fake_session_token random_chars(260) end def random_chars count chars = ('0'..'9').to_a + ('a'..'z').to_a + ('A'..'Z').to_a (1..count).map{ chars[rand(chars.size)] }.join end end end end end aws-sdk-v1-1.66.0/lib/aws/core/indifferent_hash.rb0000644000004100000410000000441312604445426021657 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # A utility class to provide indifferent access to hash data. # # Inspired by ActiveSupport's HashWithIndifferentAccess, this class # has a few notable differences: # # * ALL keys are converted to strings (via #to_s) # * It does not deep merge/convert hashes indifferently, good for fla # * It will not perserve default value behaviours # # These features were omitted because our primary use for this class is to # wrap a 1-level hash as a return value, but we want the user to access # the values with string or symbol keys. # # @api private class IndifferentHash < Hash def initialize *args if args.first.is_a?(Hash) super() merge!(*args) else super(*args) end end alias_method :_getter, :[] alias_method :_setter, :[]= def []=(key, value) _setter(_convert_key(key), value) end alias_method :store, :[]= def [] key _getter(_convert_key(key)) end def merge! hash hash.each_pair do |key,value| self[key] = value end self end alias_method :update, :merge! def merge hash self.dup.merge!(hash) end def has_key? key super(_convert_key(key)) end alias_method :key?, :has_key? alias_method :member?, :has_key? alias_method :include?, :has_key? def fetch key, *extras, &block super(_convert_key(key), *extras, &block) end def delete key super(_convert_key(key)) end private def _convert_key key key.is_a?(String) ? key : key.to_s end end end end aws-sdk-v1-1.66.0/lib/aws/core/resource_cache.rb0000644000004100000410000000211312604445426021324 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # @api private class ResourceCache def initialize @cache = {} end def store(key, attributes) (@cache[key] ||= {}).merge!(attributes) end def cached?(key, attribute) attributes = @cache[key] and attributes.has_key?(attribute) end def get(key, attribute) raise "No cached value for attribute :#{attribute} of #{key}" unless cached?(key, attribute) @cache[key][attribute] end end end end aws-sdk-v1-1.66.0/lib/aws/core/region_collection.rb0000644000004100000410000000460412604445426022057 0ustar www-datawww-data# Copyright 2011-2013 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 'uri' require 'net/http' require 'json' module AWS module Core # Provides a mechnasim to discover available regions. This can useful if # you want to perform an operation for a service in every region. # # # call the EC2 DescribeInstances operation in each region # AWS.regions.each do |region| # resp = region.ec2.client.describe_instances # end # # You can also use this collection as a shortcut for creating # a service interface with a given region. # # s3 = AWS.regions['us-west-1'].s3 # # This collection enumerates and returns {Region} objects. # # @see Region class RegionCollection include Enumerable # @option options [Configuration] :config (AWS.config) # @option options [ServiceInterface] :service (nil) # @api private def initialize options = {} @config = options[:config] || AWS.config @service = options[:service] end # @return [Configuration] attr_reader :config # @param [String] name # @return [Region] Returns a {Region} with the given name. def [] name Region.new(name, :config => config) end # Enumerates public regions (non US Gov regions). # @yieldparam [region] Region def each &block public_regions.each do |region_name| yield(self[region_name]) end end private # @return [Array] Returns an array of non-gov-cloud region names. def public_regions return ['us-east-1'] if @service and @service.global_endpoint? data = Endpoints.endpoints regions = @service ? data['services'][@service.endpoint_prefix] : data['regions'].keys regions.reject{ |r| r =~ /us-gov/ }.reject{ |r| r =~ /^cn-/ } end end end end aws-sdk-v1-1.66.0/lib/aws/core/signers/0000755000004100000410000000000012604445426017502 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/core/signers/version_3_https.rb0000644000004100000410000000332312604445426023161 0ustar www-datawww-data# Copyright 2011-2013 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 'time' module AWS module Core module Signers # @api private class Version3Https include Base # @param [CredentialProviders::Provider] credentials def initialize credentials @credentials = credentials end # @return [CredentialProviders::Provider] attr_reader :credentials # @param [Http::Request] req # @return [Http::Request] def sign_request req parts = [] parts << "AWS3-HTTPS AWSAccessKeyId=#{credentials.access_key_id}" parts << "Algorithm=HmacSHA256" parts << "Signature=#{signature(req)}" req.headers['x-amzn-authorization'] = parts.join(',') req.headers['x-amz-security-token'] = credentials.session_token if credentials.session_token req end private # @param [Http::Request] req def signature req sign(credentials.secret_access_key, string_to_sign(req)) end # @param [Http::Request] req def string_to_sign req req.headers['date'] ||= Time.now.httpdate end end end end end aws-sdk-v1-1.66.0/lib/aws/core/signers/version_4.rb0000644000004100000410000001660112604445426021743 0ustar www-datawww-data# Copyright 2011-2013 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 'time' require 'openssl' require 'digest' module AWS module Core module Signers # @api private class Version4 autoload :ChunkSignedStream, 'aws/core/signers/version_4/chunk_signed_stream' # @api private # SHA256 hex digest of the empty string EMPTY_DIGEST = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' # @api private STREAMING_CHECKSUM = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD" # @param [CredentialProviders::Provider] credentials # @param [String] service_name # @param [String] region def initialize credentials, service_name, region @credentials = credentials @service_name = service_name @region = region end # @return [CredentialProviders::Provider] attr_reader :credentials # @return [String] attr_reader :service_name # @return [String] attr_reader :region # @param [Http::Request] req # @option options [Boolean] :chunk_signing (false) When +true+, the # request body will be signed in chunk. # @option options [DateTime String] :datetime # @return [Http::Request] def sign_request req, options = {} datetime = options[:datetime] || Time.now.utc.strftime("%Y%m%dT%H%M%SZ") key = derive_key(datetime) token = credentials.session_token chunk_signing = !!options[:chunk_signing] content_sha256 = req.headers['x-amz-content-sha256'] || body_digest(req, chunk_signing) req.headers['host'] = req.host req.headers['x-amz-date'] = datetime req.headers['x-amz-security-token'] = token if token req.headers['x-amz-content-sha256'] = content_sha256 if chunk_signing orig_size = req.headers['content-length'].to_i signed_size = ChunkSignedStream.signed_size(orig_size.to_i) req.headers['content-length'] = signed_size.to_s req.headers['x-amz-decoded-content-length'] = orig_size.to_s end req.headers['authorization'] = authorization(req, key, datetime, content_sha256) req.body_stream = chunk_signed_stream(req, key) if chunk_signing req end def signature(request, key, datetime, content_sha256) string = string_to_sign(request, datetime, content_sha256) hexhmac(key, string) end def credential(datetime) "#{credentials.access_key_id}/#{key_path(datetime)}" end def derive_key(datetime) k_secret = credentials.secret_access_key k_date = hmac("AWS4" + k_secret, datetime[0,8]) k_region = hmac(k_date, region) k_service = hmac(k_region, service_name) k_credentials = hmac(k_service, 'aws4_request') end private # Wraps the req body stream with another stream. The wrapper signs # the original body as it is read, injecting signatures of indiviaul # chunks into the resultant stream. # @param [Http::Request] req # @param [String] key # @param [String] datetime def chunk_signed_stream req, key args = [] args << req.body_stream args << req.headers['x-amz-decoded-content-length'].to_i args << key args << key_path(req.headers['x-amz-date']) args << req.headers['x-amz-date'] args << req.headers['authorization'].split('Signature=')[1] ChunkSignedStream.new(*args) end def authorization req, key, datetime, content_sha256 parts = [] parts << "AWS4-HMAC-SHA256 Credential=#{credential(datetime)}" parts << "SignedHeaders=#{signed_headers(req)}" parts << "Signature=#{signature(req, key, datetime, content_sha256)}" parts.join(', ') end def string_to_sign req, datetime, content_sha256 parts = [] parts << 'AWS4-HMAC-SHA256' parts << datetime parts << key_path(datetime) parts << hexdigest(canonical_request(req, content_sha256)) parts.join("\n") end # @param [String] datetime # @return [String] the signature scope. def key_path datetime parts = [] parts << datetime[0,8] parts << region parts << service_name parts << 'aws4_request' parts.join("/") end # @param [Http::Request] req def canonical_request req, content_sha256 parts = [] parts << req.http_method parts << req.path parts << req.querystring parts << canonical_headers(req) + "\n" parts << signed_headers(req) parts << content_sha256 parts.join("\n") end # @param [Http::Request] req def signed_headers req to_sign = req.headers.keys.map{|k| k.to_s.downcase } to_sign.delete('authorization') to_sign.sort.join(";") end # @param [Http::Request] req def canonical_headers req headers = [] req.headers.each_pair do |k,v| headers << [k,v] unless k == 'authorization' end headers = headers.sort_by(&:first) headers.map{|k,v| "#{k}:#{canonical_header_values(v)}" }.join("\n") end # @param [String,Array] values def canonical_header_values values values = [values] unless values.is_a?(Array) values.map(&:to_s).join(',').gsub(/\s+/, ' ').strip end # @param [Http::Request] req # @param [Boolean] chunk_signing # @return [String] def body_digest req, chunk_signing case when chunk_signing then STREAMING_CHECKSUM when ['', nil].include?(req.body) then EMPTY_DIGEST else hexdigest(req.body) end end # @param [String] value # @return [String] def hexdigest value digest = OpenSSL::Digest::SHA256.new if value.respond_to?(:read) chunk = nil chunk_size = 1024 * 1024 # 1 megabyte digest.update(chunk) while chunk = value.read(chunk_size) value.rewind else digest.update(value) end digest.hexdigest end # @param [String] key # @param [String] value # @return [String] def hmac key, value OpenSSL::HMAC.digest(sha256_digest, key, value) end # @param [String] key # @param [String] value # @return [String] def hexhmac key, value OpenSSL::HMAC.hexdigest(sha256_digest, key, value) end def sha256_digest OpenSSL::Digest.new('sha256') end end end end end aws-sdk-v1-1.66.0/lib/aws/core/signers/s3.rb0000644000004100000410000001215412604445426020357 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core module Signers # @api private class S3 SUB_RESOURCES = %w( acl location logging notification partNumber policy requestPayment torrent uploadId uploads versionId versioning versions restore delete lifecycle tagging cors website ) QUERY_PARAMS = %w( response-content-type response-content-language response-expires response-cache-control response-content-disposition response-content-encoding ) # @param [CredentialProviders::Provider] credentials def initialize credentials @credentials = credentials end # @return [CredentialProviders::Provider] attr_reader :credentials # @param [Http::Request] req # @return [Http::Request] def sign_request req if token = credentials.session_token req.headers["x-amz-security-token"] = token end req.headers["authorization"] = authorization(req) end private def authorization req "AWS #{credentials.access_key_id}:#{signature(req)}" end def signature req secret = credentials.secret_access_key signature = self.class.string_to_sign(req) signature = Base.sign(credentials.secret_access_key, signature, 'sha1') URI.escape(signature) end class << self # From the S3 developer guide: # # StringToSign = # HTTP-Verb ` "\n" ` # content-md5 ` "\n" ` # content-type ` "\n" ` # date ` "\n" ` # CanonicalizedAmzHeaders + CanonicalizedResource; # def string_to_sign req [ req.http_method, req.headers.values_at('content-md5', 'content-type').join("\n"), signing_string_date(req), canonicalized_headers(req), canonicalized_resource(req), ].flatten.compact.join("\n") end def signing_string_date req # if a date is provided via x-amz-date then we should omit the # Date header from the signing string (should appear as a blank line) if req.headers.detect{|k,v| k.to_s =~ /^x-amz-date$/i } '' else req.headers['date'] ||= Time.now.httpdate end end # CanonicalizedAmzHeaders # # See the developer guide for more information on how this element # is generated. # def canonicalized_headers req x_amz = req.headers.select{|k, v| k.to_s =~ /^x-amz-/i } x_amz = x_amz.collect{|k, v| [k.downcase, v] } x_amz = x_amz.sort_by{|k, v| k } x_amz = x_amz.collect{|k, v| "#{k}:#{v.to_s.strip}" }.join("\n") x_amz == '' ? nil : x_amz end # From the S3 developer guide # # CanonicalizedResource = # [ "/" ` Bucket ] ` # + # [ sub-resource, if present. e.g. "?acl", "?location", # "?logging", or "?torrent"]; # # @api private def canonicalized_resource req parts = [] # virtual hosted-style requests require the hostname to appear # in the canonicalized resource prefixed by a forward slash. if AWS::S3::Client.dns_compatible_bucket_name?(req.bucket) and !req.path_style? then parts << "/#{req.bucket}" end # all requests require the portion of the un-decoded uri up to # but not including the query string parts << req.path # lastly any sub resource querystring params need to be appened # in lexigraphical ordered joined by '&' and prefixed by '?' params = sub_resource_params(req) + query_parameters_for_signature(req) unless params.empty? parts << '?' parts << params.sort.collect{|p| p.to_s }.join('&') end parts.join end def sub_resource_params req req.params.select{|p| SUB_RESOURCES.include?(p.name) } end def query_parameters_for_signature req req.params.select { |p| QUERY_PARAMS.include?(p.name) } end end end end end end aws-sdk-v1-1.66.0/lib/aws/core/signers/cloud_front.rb0000644000004100000410000000306012604445426022344 0ustar www-datawww-data# Copyright 2011-2013 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 'time' module AWS module Core module Signers class CloudFront include Base # @param [CredentialProviders::Provider] credentials def initialize credentials @credentials = credentials end # @return [CredentialProviders::Provider] attr_reader :credentials # @param [Http::Request] req # @return [Http::Request] def sign_request req req.headers['x-amz-security-token'] = credentials.session_token if credentials.session_token req.headers['authorization'] = "AWS #{credentials.access_key_id}:#{signature(req)}" req end private # @param [Http::Request] req def signature req sign(credentials.secret_access_key, string_to_sign(req), 'sha1') end # @param [Http::Request] req def string_to_sign req req.headers['date'] ||= Time.now.httpdate end end end end end aws-sdk-v1-1.66.0/lib/aws/core/signers/version_4/0000755000004100000410000000000012604445426021412 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/core/signers/version_4/chunk_signed_stream.rb0000644000004100000410000001347712604445426025767 0ustar www-datawww-data# Copyright 2011-2013 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 'stringio' module AWS module Core module Signers class Version4 class ChunkSignedStream # @api private DEFAULT_CHUNK_SIZE = 128 * 1024 # @api private MAX_BUFFER_SIZE = 256 * 1024 # @api private CHUNK_SIGNATURE_HEADER = ";chunk-signature=" # @api private CHUNK_STRING_TO_SIGN_PREFIX = "AWS4-HMAC-SHA256-PAYLOAD" # @api private SIGNATURE_LENGTH = 64 # @api private CLRF = "\r\n" # @param [IO] stream The original http request body stream. # @param [Integer] stream_size Size of the original stream in bytes. # This must be greater than 0. # @param [String] key The derived sigv4 signing key. # @param [String] key_path The scope of the derived key. # @param [String] datetime The iso8601 formatted datetime. # @param [String] signature The computed signature of the request headers. # @return [IO] Returns an IO-like object. def initialize stream, stream_size, key, key_path, datetime, signature @stream = stream || StringIO.new('') @size = self.class.signed_size(stream_size) @key = key @key_path = key_path @datetime = datetime @prev_chunk_signature = signature reset end # @return [Integer] the size of the final (signed) stream attr_reader :size # @param [Integer] bytes (nil) # @param [String] output_buffer (nil) # @return [String,nil] def read bytes = nil, output_buffer = nil data = read_bytes(bytes || @size) if output_buffer output_buffer.replace(data || '') else (data.nil? and bytes.nil?) ? '' : data end end # @return [Integer] def rewind @stream.rewind reset end private def reset @buffer = '' @more_chunks = true end # @param [Integer] num_bytes The maximum number of bytes to return. # @return [String,nil] `nil` once the complete stream has been read def read_bytes num_bytes fill_buffer(num_bytes) bytes = @buffer[0,num_bytes] @buffer = @buffer[num_bytes..-1] || '' # flatten the buffer bytes == '' ? nil : bytes end # Fills the internal buffer at least +num_bytes+ of data. # @param [Integer] num_bytes def fill_buffer num_bytes while @buffer.bytesize < num_bytes && more_chunks? @buffer << next_chunk end end def more_chunks? @more_chunks end def next_chunk chunk = @stream.read(DEFAULT_CHUNK_SIZE) if chunk.nil? chunk = '' @more_chunks = false end sign_chunk(chunk) end # Given a chunk of the original stream, this method returns a signed # chunk with the prefixed header. # @param [String] chunk # @return [String] def sign_chunk chunk [ chunk.bytesize.to_s(16), CHUNK_SIGNATURE_HEADER, next_chunk_signature(chunk), CLRF, chunk, CLRF, ].join end # @param [String] chunk # @return [String] def next_chunk_signature chunk string_to_sign = [ "AWS4-HMAC-SHA256-PAYLOAD", @datetime, @key_path, @prev_chunk_signature, hash(''), hash(chunk), ].join("\n") signature = sign(string_to_sign) @prev_chunk_signature = signature signature end def sign value @digest ||= OpenSSL::Digest.new('sha256') OpenSSL::HMAC.hexdigest(@digest, @key, value) end def hash value OpenSSL::Digest::SHA256.new.update(value).hexdigest end class << self # Computes the final size of a chunked signed stream. # @param [Integer] size Size of the original, unsigned stream. # @return [Integer] def signed_size size full_sized_chunks = size / DEFAULT_CHUNK_SIZE trailing_bytes = size % DEFAULT_CHUNK_SIZE length = 0 length += full_sized_chunks * header_length(DEFAULT_CHUNK_SIZE) length += trailing_bytes > 0 ? header_length(trailing_bytes) : 0 length += header_length(0) length end private # Computes the size of a header that prefixes a chunk. The size # appears in the header as a string. # @param [Integer] size # @return [Integer] def header_length size size.to_s(16).length + CHUNK_SIGNATURE_HEADER.length + SIGNATURE_LENGTH + CLRF.length + size + CLRF.length end end end end end end end aws-sdk-v1-1.66.0/lib/aws/core/signers/base.rb0000644000004100000410000000307712604445426020750 0ustar www-datawww-data# Copyright 2011-2013 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 'base64' module AWS module Core module Signers # @api private module Base # Signs a string using the credentials stored in memory. # @param [String] secret Usually an AWS secret access key. # @param [String] string_to_sign The string to sign. # @param [String] digest_method The digest method to use when # computing the HMAC digest. # @return [String] Returns the computed signature. def sign secret, string_to_sign, digest_method = 'sha256' Base64.encode64(hmac(secret, string_to_sign, digest_method)).strip end module_function :sign # Computes an HMAC digest of the passed string. # @param [String] key # @param [String] value # @param [String] digest ('sha256') # @return [String] def hmac key, value, digest = 'sha256' OpenSSL::HMAC.digest(OpenSSL::Digest.new(digest), key, value) end module_function :hmac end end end end aws-sdk-v1-1.66.0/lib/aws/core/signers/version_2.rb0000644000004100000410000000370312604445426021740 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core module Signers # @api private class Version2 include Base # @param [CredentialProviders::Provider] credentials def initialize credentials @credentials = credentials end # @return [CredentialProviders::Provider] attr_reader :credentials # @param [Http::Request] req # @return [Http::Request] def sign_request req req.add_param('AWSAccessKeyId', credentials.access_key_id) if token = credentials.session_token req.add_param("SecurityToken", token) end req.add_param('SignatureVersion', '2') req.add_param('SignatureMethod', 'HmacSHA256') req.add_param('Signature', signature(req)) req.body = req.url_encoded_params req end private # @param [Http::Request] req def signature req sign(credentials.secret_access_key, string_to_sign(req)) end # @param [Http::Request] req def string_to_sign req host = case req.port when 80, 443 then req.host else "#{req.host}:#{req.port}" end [ req.http_method, host.to_s.downcase, req.path, req.url_encoded_params, ].join("\n") end end end end end aws-sdk-v1-1.66.0/lib/aws/core/signers/version_3.rb0000644000004100000410000000477212604445426021750 0ustar www-datawww-data# Copyright 2011-2013 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 'openssl' require 'time' module AWS module Core module Signers # @api private class Version3 include Base # @param [CredentialProviders::Provider] credentials def initialize credentials @credentials = credentials end # @return [CredentialProviders::Provider] attr_reader :credentials # @param [Http::Request] req # @return [Http::Request] def sign_request req req.headers["x-amz-date"] ||= (req.headers["date"] ||= Time.now.httpdate) req.headers["host"] ||= req.host req.headers["x-amz-security-token"] = credentials.session_token if credentials.session_token req.headers["x-amzn-authorization"] = "AWS3 "+ "AWSAccessKeyId=#{credentials.access_key_id},"+ "Algorithm=HmacSHA256,"+ "SignedHeaders=#{headers_to_sign(req).join(';')},"+ "Signature=#{signature(req)}" end private # @param [Http::Request] req def signature req, service_signing_name = nil sign(credentials.secret_access_key, string_to_sign(req)) end # @param [Http::Request] req def string_to_sign req OpenSSL::Digest::SHA256.digest([ req.http_method, "/", "", canonical_headers(req), req.body ].join("\n")) end # @param [Http::Request] req def canonical_headers req headers_to_sign(req).map do |name| value = req.headers[name] "#{name.downcase.strip}:#{value.strip}\n" end.sort.join end # @param [Http::Request] req def headers_to_sign req req.headers.keys.select do |header| header == "host" || header == "content-encoding" || header =~ /^x-amz/ end end end end end end aws-sdk-v1-1.66.0/lib/aws/core/naming.rb0000644000004100000410000000147112604445426017631 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # @api private module Naming def service_name self.name.split(/::/)[1] end def service_ruby_name @service_ruby_name ||= Inflection.ruby_name(service_name) end end end end aws-sdk-v1-1.66.0/lib/aws/core/query_response_parser.rb0000644000004100000410000000161612604445426023020 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # @api private class QueryResponseParser def initialize parsing_rules @parser = XML::Parser.new(parsing_rules) end def extract_data response @parser.parse(response.http_response.body) end def simulate @parser.simulate end end end end aws-sdk-v1-1.66.0/lib/aws/core/xml/0000755000004100000410000000000012604445426016630 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/core/xml/grammar.rb0000644000004100000410000002146612604445426020614 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core module XML # A class that simplifies building XML {Parser} rules. This is also # a compatability layer between the old and new formats of the api # config. class Grammar def initialize rules = {}, options = {} @rules = rules @context = @rules @element_name = 'xml' @inflect_rename = options.key?(:inflect_rename) ? options[:inflect_rename] : true end # Parses the XML with the rules provided by the current grammar. # This method is meant to provide backwards compatability with # the old XmlGrammar class that handled rules and parsing. # @param [String] xml # @return [Data] Returns a hash-like parsed response. def parse xml Data.new(Parser.parse(xml, rules)) end # @return [Hash] Returns a hash of rules defined by this grammar. attr_reader :rules # Returns a new grammar (leaving the current one un-modified) with # the given customizations applied. Customizations can be given in # a hash-form or in a block form. # # @example Block-form customizations # # grammar.customize do # element "EnumElement" do # symbol_value # list # end # end # # @example Hash-form customizations # # grammar.customize "EnumElement" => [:symbol_value, :list] # # @return [Grammar] Returns a grammar with the given customizations # applied. # def customize customizations = nil, &block opts = { :inflect_rename => @inflect_rename } self.class.customize(customizations, @rules, opts, &block) end # Applies customizations to the current grammar, not returning # a new grammar. def customize! customizations = nil, &block apply_customizations(customizations) if customizations instance_eval(&block) if block_given? self end def self.customize customizations = nil, rules = {}, opts = {}, &block grammar = self.new(deep_copy(rules), opts) grammar.send(:apply_customizations, customizations) if customizations grammar.instance_eval(&block) if block_given? grammar end def self.parse xml self.new.parse(xml) end protected # Performs a deep copy of the rules hash so that it can be # customized without chaning the parent grammar. def self.deep_copy rules rules.inject({}) do |copy,(key,value)| copy[key] = value.is_a?(Hash) ? deep_copy(value) : value copy end end def apply_customizations customizations customizations.each do |item| (type, identifier, args) = parse_customization_item(item) case type when :method validate_config_method(identifier) validate_args(identifier, args) send(identifier, *args) when :element element(identifier) do apply_customizations(args) end end end end def parse_customization_item item case item when Symbol [:method, item, []] when Hash (method, arg) = item.to_a.first if method.kind_of?(Symbol) [:method, method, [arg].flatten] else [:element, method, arg] end end end def validate_config_method(method) allow_methods = %w( rename attribute_name boolean integer long float list force string ignore collect_values symbol_value timestamp map_entry map blob enum position ) unless allow_methods.include?(method.to_s) raise "#{method} cannot be used in configuration" end end def validate_args(identifier, args) arity = method(identifier).arity if args.length > 0 raise "#{identifier} does not accept an argument" if arity == 0 else raise "#{identifier} requires an argument" unless arity == 0 || arity == -1 end end def inflect value Inflection.ruby_name(value.to_s).to_sym end # customization methods def element element_name, &block parent_context = @context parent_element_name = @element_name @context = context_for_child(element_name) @element_name = element_name begin if block_given? block.arity == 1 ? yield(parent_element_name) : yield end ensure @context = parent_context @element_name = parent_element_name end end def ignore @context[:ignore] = true end def rename new_name if @inflect_rename @context[:rename] = inflect(new_name) else @context[:rename] = new_name end end def force @context[:force] = true end def collect_values @context[:list] = true end def index index_name, options = {} @context[:index] = options.merge(:name => index_name) end def default_value name, value @context[:defaults] ||= {} @context[:defaults][name] = value end def list child_element_name = nil, &block if child_element_name ignore element(child_element_name) do |parent_element_name| rename(parent_element_name) collect_values yield if block_given? end else collect_values end end def map_entry key_element_name, value_element_name @context[:map] = [key_element_name, value_element_name] end def map map_element_name, key_element_name, value_element_name ignore element(map_element_name) do |parent_element_name| rename(parent_element_name) map_entry(key_element_name, value_element_name) end end def wrapper method_name, options = {}, &block options[:for].each do |child| context_for_child(child)[:wrap] = method_name end end def construct_value &block raise 'remove the need for this' end def boolean_value @context[:type] = :boolean end alias_method :boolean, :boolean_value def blob_value @context[:type] = :blob end alias_method :blob, :blob_value def datetime_value @context[:type] = :datetime end alias_method :datetime, :datetime_value def time_value @context[:type] = :time end alias_method :timestamp, :time_value alias_method :time, :time_value def string_value @context[:type] = :string end alias_method :string, :string_value def integer_value @context[:type] = :integer end alias_method :integer, :integer_value alias_method :long, :integer_value def float_value @context[:type] = :float end alias_method :float, :float_value def symbol_value @context[:type] = :symbol end alias_method :symbol, :symbol_value def eql? other other.is_a?(Grammar) and self.rules == other.rules end alias_method :==, :eql? public :== def enum *args; end def position *args; end def http_trait *args; end alias_method :http_header, :http_trait alias_method :http_uri_label, :http_trait alias_method :http_payload, :http_trait alias_method :http_status, :http_trait protected def context_for_child child_element_name @context[:children] ||= {} @context[:children][child_element_name] ||= {} @context[:children][child_element_name] end end end end end aws-sdk-v1-1.66.0/lib/aws/core/xml/parser.rb0000644000004100000410000000437712604445426020464 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core module XML class Parser # @param [Hash] rules A has of xml parsing rules. Generally # rules will come from an xml grammar. def initialize rules = {} @rules = rules end # @return [Hash] Returns the rules for this xml parser that define # how it should transform the XMl into Ruby. attr_reader :rules # @param [String] xml An XML document string to parse. # @return [Hash] Returns a hash of parsed xml data. def parse xml xml = '' if xml.nil? or xml.empty? sax_handler.parse(xml) end # @return [Hash] Returns a hash of mostly empty placeholder data. def simulate XML::Stub.simulate(rules) end # @param [String] xml An XML document string to parse. # @param [Hash] rules A has of xml parsing rules. Generally # rules will come from an xml grammar. # @return [Hash] Returns a hash of parsed xml data. def self.parse xml, rules = {} self.new(rules).parse(xml) end protected # There are three handlers, nokogiri is the fastest, followed # by libxml-ruby. Lastly (by a long shot) is REXML. REXML # is the only library that does not rely on a native # extension. # # Currently you can not choose your xml sax handler, and the only # we express a gem dependency on is nokogiri. # def sax_handler begin SaxHandlers::Nokogiri.new(rules) rescue NameError, LoadError SaxHandlers::REXML.new(rules) end end end end end end aws-sdk-v1-1.66.0/lib/aws/core/xml/stub.rb0000644000004100000410000000665512604445426020146 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core module XML # This class takes the rules from an XML parser and then # returns a stubbed reponse. This response has placeholder # values based on the grammar, e.g. # # * Lists are stubbed with empty arrays # * Indexes become empty hashes # * Numeric types are returned as 0 # * etc # # This is used primarily to help with the AWS.stub! utility. # class Stub # @param [Hash] rules def initialize rules @rules = rules end # @return [Hash] attr_reader :rules # Returns a hash with stubbed values as if it had parsed # an empty xml document. # @return [Hash] def simulate if rules[:children] data = stub_data_for(rules) apply_empty_indexes(rules, data) data else {} end end # Returns a hash with stubbed values as if it had parsed # an empty xml document. # @param [Hash] rules An XML::Parser rule set. # @return [Hash] def self.simulate rules stub = Stub.new(rules) stub.simulate end protected def stub_data_for rules, data = {} rules[:children].each_pair do |name,child_rules| # skip ignored elements if child_rules[:ignore] stub_data_for(child_rules, data) if child_rules[:children] next end orig_data = data if wrapper = child_rules[:wrap] data[wrapper] ||= {} data = data[wrapper] end ruby_name = child_rules[:rename] || Inflection.ruby_name(name.to_s).to_sym if child_rules[:list] data[ruby_name] = [] elsif child_rules[:map] data[ruby_name] = {} elsif child_rules[:children] and !child_rules[:children].empty? data[ruby_name] = stub_data_for(child_rules) else data[ruby_name] = case child_rules[:type] when :integer then 0 when :float then 0.0 when :time then Time.now when :datetime then Date.parse(Time.now.to_s) when :boolean then false else nil end end # restore data incase it was redirected for wrapping data = orig_data end data end protected def apply_empty_indexes rules, data return unless rules[:children] rules[:children].each_pair do |name,child_rules| if index = child_rules[:index] data[index[:name]] = {} end apply_empty_indexes(child_rules, data) end end end end end end aws-sdk-v1-1.66.0/lib/aws/core/xml/sax_handlers/0000755000004100000410000000000012604445426021303 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/core/xml/sax_handlers/libxml.rb0000644000004100000410000000235512604445426023124 0ustar www-datawww-data# Copyright 2011-2013 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 'libxml' module AWS module Core module XML module SaxHandlers class LibXML include FrameStack include ::LibXML::XML::SaxParser::Callbacks def sax_parse xml sax_parser = ::LibXML::XML::SaxParser.string(xml) sax_parser.callbacks = self sax_parser.parse end def on_start_element_ns element_name, attributes, *ignore start_element(element_name, attributes) end def on_end_element_ns *ignore end_element end def on_characters chars text(chars) end end end end end end aws-sdk-v1-1.66.0/lib/aws/core/xml/sax_handlers/ox.rb0000644000004100000410000000177212604445426022265 0ustar www-datawww-data# Copyright 2011-2013 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 'stringio' require 'ox' module AWS module Core module XML module SaxHandlers class Ox include FrameStack def sax_parse xml ::Ox.sax_parse(self, StringIO.new(xml)) end def start_element name super(name.to_s) end def attr name, value attributes(name.to_s => value) end end end end end end aws-sdk-v1-1.66.0/lib/aws/core/xml/sax_handlers/rexml.rb0000644000004100000410000000226712604445426022766 0ustar www-datawww-data# Copyright 2011-2013 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 'rexml/document' require 'rexml/streamlistener' module AWS module Core module XML module SaxHandlers class REXML include FrameStack include ::REXML::StreamListener def sax_parse xml source = ::REXML::Source.new(xml) ::REXML::Parsers::StreamParser.new(source, self).parse end def tag_start name, attrs start_element(name, attrs) end def tag_end name end_element end def text(chars) set_text(chars) end end end end end end aws-sdk-v1-1.66.0/lib/aws/core/xml/sax_handlers/nokogiri.rb0000644000004100000410000000266712604445426023464 0ustar www-datawww-data# Copyright 2011-2013 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 'nokogiri' module AWS module Core module XML module SaxHandlers class Nokogiri include FrameStack def sax_parse xml ::Nokogiri::XML::SAX::Parser.new(self).parse(xml) end def xmldecl(*args); end def start_document; end def end_document; end def error(*args); end def comment(*args); end def start_element_namespace element_name, attributes = [], *ignore attributes = attributes.map.inject({}) do |hash,attr| hash.merge(attr.localname => attr.value) end start_element(element_name, attributes) end def end_element_namespace *ignore end_element end def characters chars set_text(chars) end end end end end end aws-sdk-v1-1.66.0/lib/aws/core/xml/frame_stack.rb0000644000004100000410000000522012604445426021433 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core module XML # @api private module FrameStack # @param [Hash] rules A hash of parser rules. These # rules are typically generated by an {XML::Grammar}. def initialize rules @frame = RootFrame.new(rules) end def sax_parse xml raise NotImplementedError end protected :sax_parse # Parses the xml string and returns a hash with the resutls. # @param [String] xml # @return [Hash] def parse xml sax_parse(xml) @frame.value end # Increase the frame stack level by one. # @param [String] element_name The name of the xml opening tag. # @param [Hash] attributes A hash of xml element attributes. # @return [nil] def start_element element_name, attributes = {} @frame = @frame.build_child_frame(element_name) self.attributes(attributes) nil end # Increase the frame stack level by one by treating # xml element attributes as nested elements. # @param [Hash] attributes A hash of attributes names to values. # @return [nil] def attributes attributes attributes.each_pair do |attr_name, attr_value| attr_frame = @frame.build_child_frame(attr_name) attr_frame.add_text(attr_value) @frame.consume_child_frame(attr_frame) end nil end # Pops the top frame off the stack. When closing frames # their final value is computed. # @overload end_element # @return [nil] def end_element *ignored parent = @frame.parent_frame child = @frame parent.consume_child_frame(child) @frame = @frame.parent_frame nil end # Adds text to the current frame. Frames that only contain # text and no child elements are leaf nodes and have # raw string values. def set_text text @frame.add_text(text) if @frame end end end end end aws-sdk-v1-1.66.0/lib/aws/core/xml/frame.rb0000644000004100000410000001567412604445426020264 0ustar www-datawww-data# Copyright 2011-2013 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 'base64' require 'date' require 'time' module AWS module Core module XML class Frame TRANSLATE_DIGITS = ['0123456789'.freeze, ('X'*10).freeze] EASY_FORMAT = "XXXX-XX-XXTXX:XX:XX.XXXZ".freeze DATE_PUNCTUATION = ['-:.TZ'.freeze, (' '*5).freeze] def initialize root_frame, parent_frame, element_name, rules @root_frame = root_frame @parent_frame = parent_frame @element_name = element_name @rules = rules @rules[:children] ||= {} @data = {}.merge(rules[:defaults] || {}) @text = nil # initialize values for child frames of special types (e.g. # lists, maps, and forced elements) known_child_frames.each do |child_frame| context = data_context_for(child_frame) if child_frame.list? context[child_frame.ruby_name] = [] elsif child_frame.map? context[child_frame.ruby_name] = {} elsif child_frame.forced? context[child_frame.ruby_name] = child_frame.value end end end attr_reader :root_frame attr_reader :parent_frame attr_reader :element_name attr_reader :rules def data ignored? ? parent_frame.data : @data end def ruby_name rules[:rename] || root_frame.inflect(element_name) end def rules_for child_element_name rules[:children][child_element_name] || {} end # The list of child frames that have customizations (rules), all # other children will be parsed using standard rules def known_child_frames rules[:children].keys.map {|name| build_child_frame(name) } end def build_child_frame element_name # if element_name should be wrapped # build a frame for the wrapper # build a child frame from the wrapper # else Frame.new(root_frame, self, element_name, rules_for(element_name)) end def consume_child_frame child_frame child_frame.close return if child_frame.ignored? ruby_name = child_frame.ruby_name value = child_frame.value context = data_context_for(child_frame) if child_frame.list? context[ruby_name] << value elsif map = child_frame.map? context[ruby_name][child_frame.map_key] = child_frame.map_value else context[ruby_name] = value end end def close # some xml elements should be indexed at the root level # The :index rule determines the name of this index # and what keys the data should be indexed as (one element # can be indexed under multiple keys). The index value # is always the element itself. if index = @rules[:index] index_keys_for(index) do |key| root_frame.add_to_index(index[:name], key, data) end end end def index_keys_for index_opts, &block # simple (single) key if key = index_opts[:key] yield(data[key]) return end # composite key, joined by ":" if parts = index_opts[:keys] composite_key = parts.map{|part| data[part] }.join(":") yield(composite_key) return end # multiple keys, collected from the given path if path = index_opts[:key_path] keys_from_path(data, path.dup, &block) return end raise "missing require index rule option, :key, :keys or :key_path" end def keys_from_path data, path, &block step = path.shift value = data[step] if path.empty? yield(value) return end if value.is_a?(Array) value.each do |v| keys_from_path(v, path.dup, &block) end else keys_from_path(value, path.dup, &block) end end def add_text chars @text ||= '' @text << chars end def value if !data.empty? data[:encoding] == 'base64' ? Base64.decode64(@text.strip) : data elsif @text.nil? rules[:type] == :boolean ? false : nil else case rules[:type] when nil, :string then @text when :datetime then datetime_like_value(DateTime, :civil) when :time then datetime_like_value(Time, :utc) when :integer then @text.to_i when :float then @text.to_f when :boolean then @text == 'true' when :blob then Base64.decode64(@text) when :symbol then Core::Inflection.ruby_name(@text).to_sym else raise "unhandled type" end end end def ignored? @rules[:ignore] end def forced? @rules[:force] end def list? @rules[:list] end def map? @rules[:map] end def wrapped? @rules[:wrap] end alias_method :wrapper, :wrapped? protected def map_key data[root_frame.inflect(@rules[:map].first)] end def map_value data[root_frame.inflect(@rules[:map].last)] end def data_context_for child_frame if child_frame.wrapped? data[child_frame.wrapper] ||= {} data[child_frame.wrapper] else data end end def datetime_like_value klass, parts_constructor # it's way faster to parse this specific format manually # vs. DateTime#parse, and this happens to be the format # that AWS uses almost (??) everywhere. if @text.tr(*TRANSLATE_DIGITS) == EASY_FORMAT parts = @text.tr(*DATE_PUNCTUATION).chop.split.map {|p| p.to_i } milliseconds = parts.pop parts[-1] = parts[-1] + Rational(milliseconds, 1000) #Ruby 1.8.7 compatibility klass.send(parts_constructor, *parts) else # fallback in case we have to handle another date format klass.parse(@text) end end end end end end aws-sdk-v1-1.66.0/lib/aws/core/xml/root_frame.rb0000644000004100000410000000356012604445426021316 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core module XML class RootFrame < Frame def initialize rules @inflected = {} @indexes = {} setup_indexes(rules) super(self, nil, 'XML', rules) end def build_child_frame element_name Frame.new(self, self, element_name, rules) end def value value = @data.values.find{|v| v.is_a?(Hash) } value ||= {} value.merge(@indexes) end def add_to_index index_name, key, value @indexes[index_name] ||= {} @indexes[index_name][key] = value end # The root frame maintains a cache of inflected element names. def inflect element_name @inflected[element_name] ||= Inflection.ruby_name(element_name).to_sym end protected # recursively crawls the parser rules and looks for elements # that index values. Adds an empty index for each of these. def setup_indexes rules if rules[:children] rules[:children].each_pair do |child_name,child_rules| if index = child_rules[:index] @indexes[index[:name]] = {} end setup_indexes(child_rules) end end end end end end end aws-sdk-v1-1.66.0/lib/aws/core/response_cache.rb0000644000004100000410000000252612604445426021343 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # @api private class ResponseCache attr_reader :cached_responses attr_reader :resource_cache def initialize @cached_responses = [] @indexed_responses = {} @resource_cache = ResourceCache.new end def add(resp) cached_responses.unshift(resp) @indexed_responses[resp.cache_key] = resp if resp.respond_to?(:cache_key) @resource_cache = ResourceCache.new end def select(*types, &block) cached_responses.select do |resp| types.map{|t| t.to_s }.include?(resp.request_type.to_s) and (block.nil? || block.call(resp)) end end def cached(resp) @indexed_responses[resp.cache_key] end end end end aws-sdk-v1-1.66.0/lib/aws/core/resource.rb0000644000004100000410000002643012604445426020211 0ustar www-datawww-data # Copyright 2011-2013 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. module AWS module Core # @api private class Resource include Model include Cacheable # @api private class NotFound < StandardError; end # @api private def initialize *args super # cache static attributes passed into options options = args.last.is_a?(Hash) ? args.last : {} options.each_pair do |opt_name,opt_value| if self.class.attributes.has_key?(opt_name) and self.class.attributes[opt_name].static? then static_attributes[opt_name] = opt_value end end end # @return [String] Returns a simple string representation of this resource. def inspect identifiers = [] resource_identifiers.each do |key, value| if attr = self.class.attributes.values.find{|a| a.from == key } identifiers << "#{attr.name}:#{value}" else identifiers << "#{key}:#{value}" end end "<#{self::class} #{identifiers.join(' ')}>" end # @return [Boolean] Returns true if the objects references the same # AWS resource. def eql? other other.kind_of?(self.class) and other.resource_identifiers == resource_identifiers end alias_method :==, :eql? # @api private protected def get_resource attr_name raise NotImplementedError end # @api private protected def update_resource attr, value raise NotImplementedError end # Overide this method is subclasses of Resource. This method should # return an array of identifying key/value pairs. # # # @api private # protected # def resource_identifiers # [[:user_name, name]] # end # # @api private protected def resource_identifiers raise NotImplementedError end # @protected protected def resource_options(additional = {}) Hash[resource_identifiers].merge(additional) end # @api private protected def local_cache_key resource_identifiers.collect{|name,value| value.to_s }.join(":") end # @api private protected def static_attributes @static_attributes ||= {} end # @api private protected def ruby_name @ruby_name ||= Inflection.ruby_name(self.class.name) end # @api private public def attributes_from_response resp # check each provider for this request type to see if it # can find the resource and some of its attributes attributes = [] self.class.attribute_providers_for(resp.request_type).each do |provider| attributes << provider.attributes_from_response(self, resp) end # drop out those that returned no attributesj attributes.compact! # stop here if nothing was found for this resource return nil if attributes.empty? # merge the attributes together into a single hash attributes = attributes.inject({}) {|hash,attribs| hash.merge(attribs) } # cache static attributes attributes.each_pair do |attr_name,value| if self.class.attributes[attr_name].static? static_attributes[attr_name] = value end end attributes end # @api private protected def cache_static_attributes request_type, resp_obj self.class.attribute_providers_for(request_type).each do |provider| attributes = provider.attributes_from_response_object(resp_obj) attributes.each_pair do |attr_name,value| if self.class.attributes[attr_name].static? static_attributes[attr_name] = value end end end end class << self # @api private def define_attribute_type type_name class_eval <<-METHODS def self.#{type_name}_attributes @#{type_name}_attributes ||= {} end def self.#{type_name}_attribute name, options = {}, &block attr = attribute(name, options, &block) #{type_name}_attributes[attr.name] = attr end METHODS end # @api private def new_from request_type, resp_obj, *args resource = new(*args) resource.send(:cache_static_attributes, request_type, resp_obj) resource end # @api private def attributes @attributes ||= Hash.new do |hash,attr_name| raise "uknown attribute #{attr_name}" end end # @api private def attribute_providers @attribute_providers ||= [] end # @api private def attribute_providers_for request_type attribute_providers.select do |provider| provider.request_types.include?(request_type) end end # @api private protected def attribute name, options = {}, &block attr = Attribute.new(name, options) attr.instance_eval(&block) if block_given? define_attribute_getter(attr) define_attribute_setter(attr) if attr.mutable? alias_method(options[:alias], name) if options[:alias] attributes[attr.name] = attr end # @api private protected def mutable_attribute name, options = {}, &block attribute(name, options.merge(:mutable => true), &block) end # @api private protected def define_attribute_getter attribute define_method(attribute.name) do return static_attributes[attribute.name] if static_attributes.has_key?(attribute.name) begin retrieve_attribute(attribute) { get_resource(attribute) } rescue Cacheable::NoData => e name = ruby_name.tr("_", " ") raise NotFound, "unable to find the #{name}" end end end # @api private protected def define_attribute_setter attribute setter = attribute.name.to_s.sub(/\?/, '') + '=' define_method(setter) do |value| translated_value = attribute.translate_input_value(value) update_resource(attribute, translated_value) if attribute.static? static_attributes[attribute.name] = translated_value end value end end # @api private protected def populates_from *request_types, &block provider = provider(*request_types) provider.find(&block) provider.provides(*attributes.keys) provider end # @api private protected def provider *request_types, &block provider = AttributeProvider.new(self, request_types) if block_given? yield(provider) end attribute_providers << provider provider end end # @api private class Attribute def initialize name, options = {} @name = name @options = options @request_types = [] end attr_reader :name attr_reader :request_types def from @from ||= (@options[:from] || name) end def set_as @set_as ||= (@options[:set_as] || @options[:from] || name) end def mutable? @options[:mutable] == true end def static? @options[:static] == true end def translates_input &block @input_translator = block end def translates_output options = {}, &block @translates_nil = options[:nil] @output_translator = block end def translate_input_value value @input_translator ? @input_translator.call(value) : value end def translate_output_value value # by default nil values are not translated return nil if value.nil? and @translates_nil != true case when @options[:to_sym] then value.tr('-','_').downcase.to_sym when @options[:timestamp] then Time.at(value.to_i) when @output_translator then @output_translator.call(value) else value end end end # @api private class AttributeProvider def initialize klass, request_types @klass = klass @id = klass.attribute_providers.length @request_types = request_types @provides = {} end attr_reader :request_types def find &block @klass.send(:define_method, finder_method, &block) end def finder_method "_find_in_#{request_types.join('_or_')}_response_#{@id}" end # Indicates that all of the the named attributes can be retrieved # from an appropriate response object. # # @overload provides(*attr_names, options = {}) # @param [Symbol] attr_names A list of attributes provided # @param [Hash] options # @option options [Boolean] :value_wrapped (false) If true, then # the value returned by the response object will also receive # the message :value before it is translated and returned. # @option options [Symbol] :from Defaults to the method named # by the attribute. This is useful when you have two providers # for the same attribute but their response object name # them differently. def provides *attr_names options = attr_names.last.is_a?(Hash) ? attr_names.pop : {} attr_names.each do |attr_name| attr = @klass.attributes[attr_name] attr.request_types.push(*request_types) @provides[attr_name] = options end end def attributes_from_response resource, response if response_object = resource.send(finder_method, response) attributes_from_response_object(response_object) else nil end end def attributes_from_response_object resp_obj @provides.inject({}) do |attributes,(attr_name,options)| attr = @klass.attributes[attr_name] methods = [options[:from] || attr.from].flatten v = resp_obj methods.each do |method| v = v.key?(method) ? v[method] : v[method.to_s] break if v.nil? end v = v[:value] if v and options[:value_wrapped] v = attr.translate_output_value(v) attributes.merge(attr_name => v) end end end end end end aws-sdk-v1-1.66.0/lib/aws/core/json_parser.rb0000644000004100000410000000403012604445426020677 0ustar www-datawww-data# Copyright 2011-2013 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 'json' require 'time' require 'bigdecimal' require 'base64' module AWS module Core # @api private class JSONParser def initialize rules @rules = rules end attr_reader :rules def parse body body = "{}" if [nil, ''].include?(body) translate(JSON.load(body)) end protected # @param [Hash] values # @param [Hash] rules # @return [Hash] def translate values, rules = @rules rules.inject({}) do |data,(key,rule)| if values.key?(key) && !values[key].nil? data.merge(rule[:sym] || key => translate_value(values[key], rule)) else data end end end def translate_hash values, rules translate(values, rules[:members]) end def translate_map values, rules values.inject({}) do |data,(key,value)| data.merge(key => translate_value(value, rules[:members])) end end def translate_value value, rule case when value.is_a?(Array) then value.map{|v| translate_value(v, rule) } when rule[:type] == :hash then translate_hash(value, rule) when rule[:type] == :map then translate_map(value, rule) when rule[:type] == :blob then Base64.decode64(value) when rule[:type] == :time then Time.at(value) when rule[:type] == :big_decimal then BigDecimal.new(value) else value end end end end end aws-sdk-v1-1.66.0/lib/aws/core/rest_response_parser.rb0000644000004100000410000000367712604445426022641 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # Given a hash of request options, a REST::RequestHandler can # populate a Core::Http::Request object. class RESTResponseParser # @api private def initialize operation, options @http = operation[:http] @parser = case options[:format] when :xml then XML::Parser.new(operation[:outputs]) when :json then Core::JSONParser.new(operation[:outputs]) else raise "unhandled format: #{options[:format].inspect}" end end # Given a response object, this method extract and returns a # hash of response data. # @param [Response] response # @return [Hash] def extract_data response if payload = @http[:response_payload] data = { payload => response.http_response.body } else data = @parser.parse(response.http_response.body) end if header = response.http_response.headers['x-amzn-requestid'] data[:request_id] = [header].flatten.first end # extract headers and insert into response (@http[:response_headers] || {}).each_pair do |name,header_name| if header = response.http_response.headers[header_name.downcase] data[name] = [header].flatten.first end end data end def simulate {} end end end end aws-sdk-v1-1.66.0/lib/aws/core/region.rb0000644000004100000410000000550412604445426017644 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # Represents an AWS region. A region has a name and provides access # to service interface objects. # # aws = AWS.regions['us-west-1'] # # aws.dynamo_db.tables.map(&:name) # aws.ec2.instances.map(&:id) # # Regions provide helper methods for each service. # # @attr_reader [AutoScaling] auto_scaling # @attr_reader [CloudFormation] cloud_formation # @attr_reader [CloudFront] cloud_front # @attr_reader [CloudSearch] cloud_search # @attr_reader [CloudTrail] cloud_trail # @attr_reader [CloudWatch] cloud_watch # @attr_reader [DataPipeline] data_pipeline # @attr_reader [DirectConnect] direct_connect # @attr_reader [DynamoDB] dynamo_db # @attr_reader [EC2] ec2 # @attr_reader [ElasticBeanstalk] elastic_beanstalk # @attr_reader [ElasticTranscoder] elastic_transcoder # @attr_reader [ElastiCache] elasticache # @attr_reader [ELB] elb # @attr_reader [EMR] emr # @attr_reader [Glacier] glacier # @attr_reader [IAM] iam # @attr_reader [ImportExport] import_export # @attr_reader [Kinesis] kinesis # @attr_reader [OpsWorks] ops_works # @attr_reader [RDS] rds # @attr_reader [Redshift] redshift # @attr_reader [Route53] route_53 # @attr_reader [S3] s3 # @attr_reader [SimpleEmailService] ses # @attr_reader [SimpleDB] simple_db # @attr_reader [SNS] sns # @attr_reader [SQS] sqs # @attr_reader [StorageGateway] storage_gateway # @attr_reader [STS] sts # @attr_reader [Support] support # @attr_reader [SimpleWorkflow] swf # class Region # @param [String] name # @option options [Configuration] :config (AWS.config) def initialize name, options = {} @name = name @config = options[:config] || AWS.config @config = @config.with(:region => name) end # @return [String] The name of this region (e.g. 'us-west-1'). attr_reader :name # @return [Configuration] attr_reader :config AWS::SERVICES.values.each do |svc| define_method(svc.method_name) do AWS.const_get(svc.class_name).new(:config => config) end alias_method(svc.method_alias, svc.method_name) if svc.method_alias end end end end aws-sdk-v1-1.66.0/lib/aws/core/collection.rb0000644000004100000410000002066312604445426020517 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # Provides useful methods for enumerating items in a collection. module Collection autoload :Simple, 'aws/core/collection/simple' autoload :WithNextToken, 'aws/core/collection/with_next_token' autoload :WithLimitAndNextToken, 'aws/core/collection/with_limit_and_next_token' include Enumerable # Yields once for every item in this collection. # # collection.each {|item| ... } # # @note If you want fewer than all items, it is generally better # to call {#page} than {#each} with a `:limit`. # # @param [Hash] options # # @option options [Integer] :limit (nil) The maximum number of # items to enumerate from this collection. # # @option options [next_token] :next_token (nil) # Acts as an offset. `:next_token` may be returned by {#each} and # {#each_batch} when a `:limit` is provided. # # @return [nil_or_next_token] Returns nil if all items were enumerated. # If some items were excluded because of a `:limit` option then # a `next_token` is returned. Calling an enumerable method on # the same collection with the `next_token` acts like an offset. # def each options = {}, &block each_batch(options) do |batch| batch.each(&block) end end # Yields items from this collection in batches. # # collection.each_batch do |batch| # batch.each do |item| # # ... # end # end # # ## Variable Batch Sizes # # Each AWS service has its own rules on how it returns results. # Because of this batch size may very based on: # # * Service limits (e.g. S3 limits keys to 1000 per response) # # * The size of response objects (SimpleDB limits responses to 1MB) # # * Time to process the request # # Because of these variables, batch sizes may not be consistent for # a single collection. Each batch represents all of the items returned # in a single resopnse. # # @note If you require fixed batch sizes, see {#in_groups_of}. # @param (see #each) # @option (see #each) # @return (see #each) def each_batch options = {}, &block _each_batch(options.dup, &block) end # Use this method when you want to call a method provided by # Enumerable, but you need to pass options: # # # raises an error because collect does not accept arguments # collection.collect(:limit => 10) {|i| i.name } # # # not an issue with the enum method # collection.enum(:limit => 10).collect(&:name) # # @param (see #each) # @option (see #each) # @return [Enumerable::Enumerator] Returns an enumerator for this # collection. # def enum options = {} to_enum(:each, options) end alias_method :enumerator, :enum # Returns the first item from this collection. # # @return [item_or_nil] Returns the first item from this collection or # nil if the collection is empty. # def first options = {} enum(options.merge(:limit => 1)).first end # Yields items from this collection in groups of an exact # size (except for perhaps the last group). # # collection.in_groups_of (10, :limit => 30) do |group| # # # each group should be exactly 10 items unless # # fewer than 30 items are returned by the service # group.each do |item| # #... # end # # end # # @param [Integer] size Size each each group of objects # should be yielded in. # @param [Hash] options # @option (see #each) # @return (see #each) def in_groups_of size, options = {}, &block group = [] nil_or_next_token = each_batch(options) do |batch| batch.each do |item| group << item if group.size == size yield(group) group = [] end end end yield(group) unless group.empty? nil_or_next_token end # Returns a single page of results in a kind-of array ({PageResult}). # # items = collection.page(:per_page => 10) # defaults to 10 items # items.is_a?(Array) # => true # items.size # => 8 # items.per_page # => 10 # items.last_page? # => true # # If you need to display a "next page" link in a web view you can # use the #more? method. Just make sure the generated link # contains the `next_token`. # # <% if items.more? %> # <%= link_to('Next Page', params.merge(:next_token => items.next_token) %> # <% end %> # # Then in your controller you can find the next page of results: # # items = collection.page(:next_token => params[:next_token]) # # Given a {PageResult} you can also get more results directly: # # more_items = items.next_page # # @note This method does not accept a `:page` option, which means you # can only start at the begining of the collection and request # the next page of results. You can not choose an offset # or know how many pages of results there will be. # # @param [Hash] options A hash of options that modifies the # items returned in the page of results. # # @option options [Integer] :per_page (10) The number of results # to return for each page. # # @option options [String] :next_token (nil) A token that indicates # an offset to use when paging items. Next tokens are returned # by {PageResult#next_token}. # # Next tokens should only be consumed by the same collection that # created them. # def page options = {} each_opts = options.dup per_page = each_opts.delete(:per_page) per_page = [nil,''].include?(per_page) ? 10 : per_page.to_i each_opts[:limit] = per_page items = [] next_token = each(each_opts) do |item| items << item end Core::PageResult.new(self, items, per_page, next_token) end protected def _each_batch options, &block # should be defined in the collection modules raise NotImplementedError end def _each_item next_token, options = {}, &block # should be defined in classes included the collection modules raise NotImplementedError end def _extract_next_token options next_token = options.delete(:next_token) next_token = nil if next_token == '' next_token end def _extract_batch_size options batch_size = options.delete(:batch_size) batch_size = nil if batch_size == '' batch_size = batch_size.to_i if batch_size batch_size end def _extract_limit options limit = options.delete(:limit) || _limit limit = nil if limit == '' limit = limit.to_i if limit limit end # Override this method in collection classes that provide # an alternative way to provide the limit than passinging # it to the enumerable method as :limit. # # An example of when this would be useful: # # collection.limit(10).each {|item| ... } # # The collection class including this module should define _limit # and return the cached limit value (of 10 from this example). # This value may still be overridden by a locally passed # `:limit` option: # # # limit 5 wins out # collection.limit(10).each(:limit => 5) {|item| ... } # def _limit nil end end end end aws-sdk-v1-1.66.0/lib/aws/core/rest_json_client.rb0000644000004100000410000000230212604445426021716 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core class RESTJSONClient < Core::Client protected def self.request_builder_for api_config, operation Core::RESTRequestBuilder.new(operation, :format => :json) end def self.response_parser_for api_config, operation Core::RESTResponseParser.new(operation, :format => :json) end def extract_error_details response if response.http_response.status >= 300 and body = response.http_response.body and json = (::JSON.load(body) rescue nil) then [json['code'], json['message']] end end end end end aws-sdk-v1-1.66.0/lib/aws/core/cacheable.rb0000644000004100000410000000414112604445426020244 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # @api private module Cacheable # @api private class NoData < StandardError; end def self.included base base.extend Naming unless base.respond_to?(:service_ruby_name) end # @api private protected def local_cache_key raise NotImplementedError end # @api private protected def cache_key @cache_key ||= begin config.credential_provider.access_key_id + ":" + config.region + ":" + self.class.name + ":" + local_cache_key end end # @api private public def retrieve_attribute attr, &block if cache = AWS.response_cache if cache.resource_cache.cached?(cache_key, attr.name) return cache.resource_cache.get(cache_key, attr.name) end cache.select(*attr.request_types).each do |response| if attributes = attributes_from_response(response) cache.resource_cache.store(cache_key, attributes) return attributes[attr.name] if attributes.key?(attr.name) end end end response = yield if attributes = attributes_from_response(response) if cache = AWS.response_cache cache.resource_cache.store(cache_key, attributes) end attributes[attr.name] if attributes.key?(attr.name) else raise NoData.new("no data in #{response.request_type} response") end end end end end aws-sdk-v1-1.66.0/lib/aws/core/json_request_builder.rb0000644000004100000410000000215412604445426022606 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # @api private class JSONRequestBuilder def initialize api, operation @x_amz_target = api[:target_prefix] + operation[:name] @content_type = "application/x-amz-json-#{api[:json_version] || 1.0}" @grammar = OptionGrammar.customize(operation[:inputs]) end def populate_request request, options request.headers["content-type"] = @content_type request.headers["x-amz-target"] = @x_amz_target request.body = @grammar.to_json(options) end end end end aws-sdk-v1-1.66.0/lib/aws/core/data.rb0000644000004100000410000001435112604445426017272 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core # Data is a light wrapper around a Ruby hash that provides # method missing access to the hash contents. # # ## Method Missing Access # # You can access hash content with methods if their keys # are symbols. # # data = AWS::Core::Data.new({ :a => 1, :b => 2, :c => true }) # data.a #=> 1 # data.b #=> 2 # data.c #=> true # data.d #=> raises NoMethodError # # ## Boolean Methods # # Given the structure above you can also use question-mark methods. # # data.c? #=> true # data.d? #=> raises NoMethodError # # ## Nested Hashes # # If the data contains nested hashes you can chain methods into # the structure. # # data = AWS::Core::Data.new(:a => { :b => { :c => 'abc' }}) # data.a.b.c #=> 'abc' # # ## Nested Arrays # # Arrays are wrapped in {Data::List} objects. They ensure any # data returned is correctly wrapped so you can continue using # method-missing access. # # data = AWS::Core::Data.new( # :people => [ # {:name => 'john'}, # {:name => 'jane'}, # ]}) # # data.people[0].name #=> 'john' # data.people[1].name #=> 'jane' # # data.people.map(&:name) #=> ['john','jane'] # class Data module MethodMissingProxy # @api private def id self[:id] || self.id end def [] index_or_key Data.cast(@data[index_or_key]) end # @return [Boolean] Returns true if the passed object equals # the wrapped array. def eql? other if other.is_a?(MethodMissingProxy) @data == other._data else @data == other end end alias_method :==, :eql? def dup Data.cast(@data.dup) end alias_method :clone, :dup protected def method_missing *args, &block if block_given? return_value = @data.send(*args) do |*values| yield(*values.flatten.map{|v| Data.cast(v) }) end Data.cast(return_value) else Data.cast(@data.send(*args)) end end def _data @data end end include MethodMissingProxy def method_missing method_name, *args, &block if args.empty? and !block_given? and key = _remove_question_mark(method_name) and @data.has_key?(key) then Data.cast(@data[key]) else super end end # @param [Hash] data The ruby hash of data you need wrapped. def initialize data @data = data end # @return [Hash] Returns contents of this Data object as a raw hash. def to_hash @data end alias_method :to_h, :to_hash # @return [Array] def to_a @data.to_a end alias_method :to_ary, :to_a # @param [String,Symbol] method_name # @return [Boolean] Returns true if this data object will # respond to the given method name. def respond_to? method_name @data.key?(_remove_question_mark(method_name)) or @data.respond_to?(method_name) end # Returns an inspection string from the wrapped data. # # data = AWS::Core::Data.new({ :a => 1, :b => 2, :c => true }) # data.inspect #=> '{:a=>1, :b=>2, :c=>true}' # # @return [String] # def inspect @data.inspect end # @api private def kind_of? klass if klass == Hash true else super end end alias_method :is_a?, :kind_of? protected def _remove_question_mark method_name case method_name when Symbol then method_name.to_s.sub(/\?$/, '').to_sym when String then method_name.sub(/\?$/, '') else method_name end end class << self # Given a hash, this method returns a {Data} object. Given # an Array, this method returns a {Data::List} object. Everything # else is returned as is. # # @param [Object] value The value to conditionally wrap. # # @return [Data,Data::List,Object] Wraps hashes and lists with # Data and List objects, all other objects are returned as # is. # def cast value case value when Hash then Data.new(value) when Array then Data::List.new(value) else value end end end class List include MethodMissingProxy # @param [Array] array def initialize array @data = array end # @return [String] Returns the inspection string for the # wrapped array. def inspect @data.inspect end # @return [Array] Returns the contents of this Data::List as # a raw array. def to_ary @data end alias_method :to_a, :to_ary # #inject works on Core::Data::List in in 1.8.7 and 1.9.3, but not # in 1.9.2 unless we define it like so. # @api private def inject *args, &block @data.inject(*args) do |obj,value| yield(Data.cast(obj),Data.cast(value)) end end # @api private def kind_of? klass if klass == Array true else super end end alias_method :is_a?, :kind_of? # @api private def empty? @data.empty? end end end end end aws-sdk-v1-1.66.0/lib/aws/core/http/0000755000004100000410000000000012604445426017007 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/core/http/response.rb0000644000004100000410000000533312604445426021176 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core module Http # Represents the http response from a service request. # # Responses have: # # * status (200, 404, 500, etc) # * headers (hash of response headers) # * body (the response body) class Response # @return [Integer] Returns the http response status code. attr_accessor :status # @return [Hash] ({}) Returns the HTTP response headers. attr_accessor :headers # @return [String,nil] Returns the HTTP response body. attr_accessor :body # @return [Exception,nil] attr_accessor :network_error # @return [Boolean] Returns `true` if the request could not be made # because of a networking issue (including timeouts). def network_error? @network_error ? true : false end # The #network_error attribute was previously #timeout, aliasing # for backwards compatability alias_method :timeout=, :network_error= # @param [Hash] options # @option options [Integer] :status (200) HTTP status code # @option options [Hash] :headers ({}) HTTP response headers # @option options [String] :body ('') HTTP response body def initialize options = {}, &block @status = options[:status] || 200 @headers = options[:headers] || {} @body = options[:body] yield(self) if block_given? self end # Returns the header value with the given name. # # The value is matched case-insensitively so if the headers hash # contains a key like 'Date' and you request the value for # 'date' the 'Date' value will be returned. # # @param [String,Symbol] name The name of the header to fetch a value for. # @return [String,nil] The value of the given header def header name headers.each_pair do |header_name, header_value| if header_name.downcase == name.to_s.downcase return header_value.is_a?(Array) ? header_value.first : header_value end end nil end end end end end aws-sdk-v1-1.66.0/lib/aws/core/http/net_http_handler.rb0000644000004100000410000001172012604445426022657 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core module Http # # NetHttpHandler # # This is the default HTTP handler for the aws-sdk gem. It uses # Ruby's Net::HTTP to make requests. It uses persistent connections # and a connection pool. # class NetHttpHandler class TruncatedBodyError < IOError; end # @api private NETWORK_ERRORS = [ SocketError, EOFError, IOError, Timeout::Error, Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE, Errno::EINVAL, Errno::ETIMEDOUT, Errno::EHOSTUNREACH, OpenSSL::SSL::SSLError ] # (see ConnectionPool.new) def initialize options = {} @pool = options[:connection_pool] || ConnectionPool.new(options) @verify_content_length = options[:verify_response_body_content_length] end # @return [ConnectionPool] attr_reader :pool # Given a populated request object and an empty response object, # this method will make the request and them populate the # response. # @param [Request] request # @param [Response] response # @return [nil] def handle request, response, &read_block retry_possible = true begin @pool.session_for(request.endpoint) do |http| http.read_timeout = request.read_timeout http.continue_timeout = request.continue_timeout if http.respond_to?(:continue_timeout=) exp_length = nil act_length = 0 http.request(build_net_http_request(request)) do |net_http_resp| response.status = net_http_resp.code.to_i response.headers = net_http_resp.to_hash exp_length = determine_expected_content_length(response) if block_given? and response.status < 300 net_http_resp.read_body do |data| begin act_length += data.bytesize yield data unless data.empty? ensure retry_possible = false end end else response.body = net_http_resp.read_body act_length += response.body.bytesize unless response.body.nil? end end run_check = exp_length && request.http_method != "HEAD" && @verify_content_length if run_check && act_length != exp_length raise TruncatedBodyError, 'content-length does not match' end end rescue *NETWORK_ERRORS => error raise error unless retry_possible response.network_error = error end nil end protected def determine_expected_content_length response if header = response.headers['content-length'] if header.is_a?(Array) header.first.to_i end end end # Given an AWS::Core::HttpRequest, this method translates # it into a Net::HTTPRequest (Get, Put, Post, Head or Delete). # @param [Request] request # @return [Net::HTTPRequest] def build_net_http_request request # Net::HTTP adds a content-type (1.8.7+) and accept-encoding (2.0.0+) # to the request if these headers are not set. Setting a default # empty value defeats this. # # Removing these are necessary for most services to no break request # signatures as well as dynamodb crc32 checks (these fail if the # response is gzipped). headers = { 'content-type' => '', 'accept-encoding' => '' } request.headers.each_pair do |key,value| headers[key] = value.to_s end request_class = case request.http_method when 'GET' then Net::HTTP::Get when 'PUT' then Net::HTTP::Put when 'POST' then Net::HTTP::Post when 'HEAD' then Net::HTTP::Head when 'DELETE' then Net::HTTP::Delete else msg = "unsupported http method: #{request.http_method}" raise ArgumentError, msg end net_http_req = request_class.new(request.uri, headers) net_http_req.body_stream = request.body_stream net_http_req end end end end end aws-sdk-v1-1.66.0/lib/aws/core/http/request.rb0000644000004100000410000001730112604445426021026 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core module Http # Base class for all service reqeusts. This class describes # a basic HTTP request, but will not make one. It is consumed # by a HTTP handler class that sends the actual request # and parses the actual response. class Request extend Deprecations # Returns a new empty http request object. def initialize @http_method = 'POST' @use_ssl = true @headers = CaseInsensitiveHash.new @uri = '/' @params = [] @read_timeout = 60 end # @return [String] hostname of the request attr_accessor :host # @return [Integer] Returns the port number this request will be # made via (usually 443 or 80). attr_accessor :port # @return [String] Returns the HTTP request method (e.g. 'GET', 'PUT', # 'POST', 'HEAD' or 'DELETE'). Defaults to 'POST'. attr_accessor :http_method # @return [CaseInsensitiveHash] request headers attr_accessor :headers # @return [String] Returns the request URI (path + querystring). attr_accessor :uri # @return [String] The region name this request is for. Only needs # to be populated for requests against signature v4 endpoints. attr_accessor :region # @api private attr_accessor :service # @return [String] Returns the AWS access key ID used to authorize the # request. # @api private attr_accessor :access_key_id # @return [Array] Returns an array of request params. Requests # that use signature version 2 add params to the request and then # sign those before building the {#body}. Normally the {#body} # should be set directly with the HTTP payload. # @api private attr_accessor :params # @return [String] The name of the service for Signature v4 signing. # This does not always match the ruby name (e.g. # simple_email_service and ses do not match). attr_accessor :service_ruby_name # @return [Integer] The number of seconds the service has to respond # before a timeout error is raised on the request. attr_accessor :read_timeout alias_method :default_read_timeout, :read_timeout deprecated :default_read_timeout, :use => :read_timeout # @return [Boolean] Returns `true` if this request should be made # with SSL enabled. attr_accessor :use_ssl alias_method :use_ssl?, :use_ssl # @return [Float] timeout The number of seconds to wait for a # 100-continue response before sending the HTTP request body. # @api private attr_accessor :continue_timeout # @api private def endpoint scheme = use_ssl ? 'https' : 'http' port = case scheme when 'https' then self.port == 443 ? '' : ":#{self.port}" when 'http' then self.port == 80 ? '' : ":#{self.port}" end "#{scheme}://#{host}#{port}" end # @return [Integer] Returns the port the request will be made over. # Defaults to 443 for SSL requests and 80 for non-SSL requests. def port @port || (use_ssl? ? 443 : 80) end # @return [String] Returns the HTTP request path. def path uri.split(/\?/)[0] end # @return [String] Returns the HTTP request querystring. def querystring uri.split(/\?/)[1] end # Adds a request param. # # @overload add_param(param_name, param_value = nil) # Add a param (name/value) # @param [String] param_name # @param [String] param_value Leave blank for sub resources # # @overload add_param(param_obj) # Add a param (object) # @param [Param] param_obj # # @api private def add_param name_or_param, value = nil if name_or_param.kind_of?(Param) @params << name_or_param else @params << Param.new(name_or_param, value) end end # @api private def remove_param(name) if param = @params.find { |p| p.name == name } @params.delete(param) end end # @api private # @return [String,nil] Returns the url encoded request params. If there # are no params, then nil is returned. def url_encoded_params params.empty? ? nil : params.sort.collect(&:encoded).join('&') end # @param [String] body def body= body @body = body if body headers['content-length'] = body.bytesize if body else headers.delete('content-length') end end # @note Calling #body on a request with a #body_stream # will cause the entire stream to be read into memory. # @return [String,nil] Returns the request body. def body if @body @body elsif @body_stream @body = @body_stream.read if @body_stream.respond_to?(:rewind) @body_stream.rewind else @body_stream = StringIO.new(@body) end @body else nil end end # Sets the request body as an IO object that will be streamed. # @note You must also set the #headers['content-length'] # @param [IO] stream An object that responds to #read and #eof. def body_stream= stream @body_stream = stream end # @return [IO,nil] def body_stream if @body_stream @body_stream elsif @body StringIO.new(@body) else nil end end # @api private class CaseInsensitiveHash < Hash def []= key, value super(key.to_s.downcase, value) end def [] key super(key.to_s.downcase) end def has_key?(key) super(key.to_s.downcase) end alias_method :key?, :has_key? alias_method :include?, :has_key? alias_method :member?, :has_key? end # Represents a single request paramater. Some services accept this # in a form encoded body string, others as query parameters. # It is up to each service's Request class to determine how to # consume these params. # @api private class Param include UriEscape attr_accessor :name, :value def initialize name, value = nil @name = name @value = value end def <=> other name <=> other.name end def to_s value ? "#{name}=#{value}" : name end def ==(other) other.kind_of?(Param) and to_s == other.to_s end def encoded value ? "#{escape(name)}=#{escape(value)}" : "#{escape(name)}=" end end end end end end aws-sdk-v1-1.66.0/lib/aws/core/http/handler.rb0000644000004100000410000000476512604445426020765 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS module Core module Http # @api private class Handler attr_reader :base def initialize(base, &block) @base = base if base.respond_to?(:handle) unless [2,3].include?(block.arity) raise ArgumentError, 'passed block must accept 2 or 3 arguments' end MetaUtils.extend_method(self, :handle, &block) if block.arity == 3 m = Module.new do eval(<<-DEF) def handle req, resp, &read_block super(req, resp, read_block) end DEF end self.extend(m) end elsif base.respond_to?(:handle_async) unless block.arity == 3 raise ArgumentError, 'passed block must accept 3 arguments' end MetaUtils.extend_method(self, :handle_async) do |req, resp, handle| @base.handle_async(req, resp, handle) end MetaUtils.extend(self) do define_method(:handle) do |req, resp| raise "attempted to call #handle on an async handler" end define_method(:handle_async, &block) end else raise ArgumentError, 'base must respond to #handle or #handle_async' end end def handle(request, http_response, &read_block) @base.handle(request, http_response, &read_block) end def handle_async(request, http_response, handle) Thread.new do begin self.handle(request, http_response) rescue => e handle.signal_failure else handle.signal_success end end end def sleep_with_callback seconds, &block Kernel.sleep(seconds) yield end end end end end aws-sdk-v1-1.66.0/lib/aws/core/http/connection_pool.rb0000644000004100000410000003112212604445426022523 0ustar www-datawww-data# Copyright 2011-2013 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 'net/http' require 'net/https' require 'thread' require 'logger' module AWS module Core module Http # @attr_reader [URI::HTTP,nil] proxy_uri Returns the configured proxy uri. # @attr_reader [Float,nil] http_continue_timeout # @attr_reader [Integer,Float] http_idle_timeout # @attr_reader [Integer,Float] http_open_timeout # @attr_reader [Integer,Float] http_read_timeout # @attr_reader [Boolean] http_wire_trace # @attr_reader [Logger,nil] logger # @attr_reader [Boolean] ssl_verify_peer # @attr_reader [String,nil] ssl_ca_file # @attr_reader [String,nil] ssl_ca_path # @attr_reader [String,nil] ssl_cert_store # @api private class ConnectionPool @pools_mutex = Mutex.new @pools = {} # @api private OPTIONS = [ :proxy_uri, :http_continue_timeout, :http_idle_timeout, :http_open_timeout, :http_read_timeout, :http_wire_trace, :logger, :ssl_verify_peer, :ssl_ca_file, :ssl_ca_path, :ssl_cert_store, ] OPTIONS.each do |attr_name| attr_reader(attr_name) end alias_method :http_wire_trace?, :http_wire_trace alias_method :ssl_verify_peer?, :ssl_verify_peer # @api private def initialize options = {} # user supplied options are filtered by the class .for method options.each_pair do |opt_name, opt_value| instance_variable_set("@#{opt_name}", opt_value) end # connection pool @pool_mutex = Mutex.new @pool = Hash.new do |pool,endpoint| pool[endpoint] = [] pool[endpoint] end end # @return [Hash] a read-only hash of options for this pool. def options OPTIONS.inject({}) do |options, opt_name| options[opt_name] = send(opt_name) options end.freeze end # Makes an HTTP request, yielding a Net::HTTPResponse object. # # pool.request('http://google.com', Net::HTTP::Get.new('/')) do |resp| # puts resp.code # status code # puts resp.to_h.inspect # dump the headers # puts resp.body # end # # @param [URI::HTTP,URI::HTTPS,String] endpoint The HTTP(S) endpoint to # connect to (e.g. 'https://domain.com'). # # @param [Net::HTTPRequest] request The request to make. This can be # any request object from Net::HTTP (e.g. Net::HTTP::Get, # Net::HTTP::POST, etc). # # @yieldparam [Net::HTTPResponse] net_http_response # # @return (see #session_for def request endpoint, request, &block session_for(endpoint) do |http| yield(http.request(request)) end end # @param [URI::HTTP,URI::HTTPS,String] endpoint The HTTP(S) endpoint to # connect to (e.g. 'https://domain.com'). # # @yieldparam [Net::HTTPSession] session # # @return [nil] def session_for endpoint, &block endpoint = endpoint.to_s session = nil # attempt to recycle an already open session @pool_mutex.synchronize do _clean session = @pool[endpoint].shift end begin session ||= start_session(endpoint) session.read_timeout = http_read_timeout session.continue_timeout = http_continue_timeout if session.respond_to?(:continue_timeout=) yield(session) rescue Exception => error session.finish if session raise error else # No error raised? Good, check the session into the pool. @pool_mutex.synchronize { @pool[endpoint] << session } end nil end # @return [Integer] Returns the count of sessions currently in the pool, # not counting those currently in use. def size @pool_mutex.synchronize do size = 0 @pool.each_pair do |endpoint,sessions| size += sessions.size end size end end # Removes stale http sessions from the pool (that have exceeded # the idle timeout). # @return [nil] def clean! @pool_mutex.synchronize { _clean } nil end # Closes and removes removes all sessions from the pool. # If empty! is called while there are outstanding requests they may # get checked back into the pool, leaving the pool in a non-empty state. # @return [nil] def empty! @pool_mutex.synchronize do @pool.each_pair do |endpoint,sessions| sessions.each(&:finish) end @pool.clear end nil end class << self # Returns a connection pool constructed from the given options. # Calling this method twice with the same options will return # the same pool. # # @option options [URI::HTTP,String] :proxy_uri A proxy to send # requests through. Formatted like 'http://proxy.com:123'. # # @option options [Float] :http_continue_timeout (nil) The number of # seconds to wait for a 100-continue response before sending the # request body. This option has no effect unless the request has # "Expect" header set to "100-continue". Defaults to `nil` which # disables this behaviour. This value can safely be set per-request # on the session yeidled by {#session_for}. # # @option options [Float] :http_idle_timeout (15) The number of # seconds a connection is allowed to sit idble before it is # considered stale. Stale connections are closed and removed # from the pool before making a request. # # @option options [Float] :http_open_timeout (15) The number of # seconds to wait when opening a HTTP session before rasing a # `Timeout::Error`. # # @option options [Integer] :http_read_timeout (60) The default # number of seconds to wait for response data. This value can # safely be set # per-request on the session yeidled by {#session_for}. # # @option options [Boolean] :http_wire_trace (false) When `true`, HTTP # debug output will be sent to the `:logger`. # # @option options [Logger] :logger Where debug output is sent. # Defaults to `nil` when `:http_wire_trace` is `false`. # Defaults to `Logger.new($stdout)` when `:http_wire_trace` is # `true`. # # @option options [Boolean] :ssl_verify_peer (true) When `true`, SSL # peer certificates are verified when establishing a connection. # # @option options [String] :ssl_ca_file Full path to the SSL # certificate authority bundle file that should be used when # verifying peer certificates. If you do not pass # `:ssl_ca_file` or `:ssl_ca_path` the the system default will be # used if available. # # @option options [String] :ssl_ca_path Full path of the directory # that contains the unbundled SSL certificate authority files# # for verifying peer certificates. If you do not pass # `:ssl_ca_file` or `:ssl_ca_path` the the system default will # be used if available. # # @option options [String] :ssl_cert_store # # @return [ConnectionPool] def new options = {} options = pool_options(options) @pools_mutex.synchronize do @pools[options] ||= build(options) end end # Constructs and returns a new connection pool. This pool is never # shared. # @option (see new) # @return [ConnectionPool] def build(options = {}) pool = allocate pool.send(:initialize, pool_options(options)) pool end # @return [Array] Returns a list of of the constructed # connection pools. def pools @pools.values end private # Filters an option hash, merging in default values. # @return [Hash] def pool_options options wire_trace = !!options[:http_wire_trace] logger = options[:logger] || Logger.new($stdout) if wire_trace verify_peer = options.key?(:ssl_verify_peer) ? !!options[:ssl_verify_peer] : true { :proxy_uri => URI.parse(options[:proxy_uri].to_s), :http_continue_timeout => options[:http_continue_timeout], :http_open_timeout => options[:http_open_timeout] || 15, :http_idle_timeout => options[:http_idle_timeout] || 15, :http_read_timeout => options[:http_read_timeout] || 60, :http_wire_trace => wire_trace, :logger => logger, :ssl_verify_peer => verify_peer, :ssl_ca_file => options[:ssl_ca_file], :ssl_ca_path => options[:ssl_ca_path], :ssl_cert_store => options[:ssl_cert_store], } end end private # Starts and returns a new HTTP(S) session. # @param [String] endpoint # @return [Net::HTTPSession] def start_session endpoint endpoint = URI.parse(endpoint) args = [] args << endpoint.host args << endpoint.port args << proxy_uri.host args << proxy_uri.port if proxy_uri.user args << URI::decode(proxy_uri.user) else args << nil end if proxy_uri.password args << URI::decode(proxy_uri.password) else args << nil end http = Net::HTTP.new(*args.compact) http.extend(SessionExtensions) http.set_debug_output(logger) if http_wire_trace? http.open_timeout = http_open_timeout if endpoint.scheme == 'https' http.use_ssl = true if ssl_verify_peer? http.verify_mode = OpenSSL::SSL::VERIFY_PEER http.ca_file = ssl_ca_file if ssl_ca_file http.ca_path = ssl_ca_path if ssl_ca_path http.cert_store = ssl_cert_store if ssl_cert_store else http.verify_mode = OpenSSL::SSL::VERIFY_NONE end else http.use_ssl = false end http.start http end # Removes stale sessions from the pool. This method *must* be called # @note **Must** be called behind a `@pool_mutex` synchronize block. def _clean now = Time.now @pool.each_pair do |endpoint,sessions| sessions.delete_if do |session| if session.last_used.nil? or now - session.last_used > http_idle_timeout then session.finish true end end end end # Helper methods extended onto Net::HTTPSession objects opend by the # connection pool. # @api private module SessionExtensions # Sends the request and tracks that this session has been used. def request *args, &block @last_used = Time.now super(*args, &block) end # @return [Time,nil] def last_used @last_used end # Attempts to close/finish the session without raising an error. def finish super rescue IOError nil end end end end end end aws-sdk-v1-1.66.0/lib/aws/core/http/patch.rb0000644000004100000410000000630012604445426020432 0ustar www-datawww-datarequire 'net/http' module AWS module Core module Http # @api private module Patches def self.apply! if RUBY_VERSION >= '2.0' Net::HTTP.send(:include, Ruby_2) elsif RUBY_VERSION >= '1.9.3' Net::HTTP.send(:include, Ruby_1_9_3) end if RUBY_VERSION >= '1.9.3' Net::HTTP.send(:alias_method, :old_transport_request, :transport_request) Net::HTTP.send(:alias_method, :transport_request, :new_transport_request) end end module Ruby_2 def new_transport_request(req) count = 0 begin begin_transport req res = catch(:response) { req.exec @socket, @curr_http_version, edit_path(req.path) begin res = Net::HTTPResponse.read_new(@socket) res.decode_content = req.decode_content end while res.kind_of?(Net::HTTPContinue) res.uri = req.uri res } res.reading_body(@socket, req.response_body_permitted?) { yield res if block_given? } rescue Net::OpenTimeout raise rescue Net::ReadTimeout, IOError, EOFError, Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE, # avoid a dependency on OpenSSL defined?(OpenSSL::SSL) ? OpenSSL::SSL::SSLError : IOError, Timeout::Error => exception if count == 0 && Net::HTTP::IDEMPOTENT_METHODS_.include?(req.method) count += 1 @socket.close if @socket and not @socket.closed? D "Conn close because of error #{exception}, and retry" if req.body_stream if req.body_stream.respond_to?(:rewind) req.body_stream.rewind else raise end end retry end D "Conn close because of error #{exception}" @socket.close if @socket and not @socket.closed? raise end end_transport req, res res rescue => exception D "Conn close because of error #{exception}" @socket.close if @socket and not @socket.closed? raise exception end end module Ruby_1_9_3 def new_transport_request(req) begin_transport req res = catch(:response) { req.exec @socket, @curr_http_version, edit_path(req.path) begin res = Net::HTTPResponse.read_new(@socket) end while res.kind_of?(Net::HTTPContinue) res } res.reading_body(@socket, req.response_body_permitted?) { yield res if block_given? } end_transport req, res res rescue => exception D "Conn close because of error #{exception}" @socket.close if @socket and not @socket.closed? raise exception end end end end end end aws-sdk-v1-1.66.0/lib/aws/core/http/curb_handler.rb0000644000004100000410000001042612604445426021767 0ustar www-datawww-data# Copyright 2011-2013 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 'thread' module AWS module Core module Http # @api private class CurbHandler class NetworkError < StandardError; end def initialize @q = [] @sem = Mutex.new @multi = Curl::Multi.new start_processor end def handle request, response, &read_block raise "unsupport http reqest method: #{request.http_method}" unless ['GET', 'HEAD', 'PUT', 'POST', 'DELETE'].include? request.http_method @sem.synchronize do @q << [request, response, read_block, Thread.current] begin @processor.wakeup rescue ThreadError start_processor end end Thread.stop nil end # fills the Curl::Multi handle with the given array of queue # items, calling make_easy_handle on each one first private def fill_multi(items) items.each do |item| c = make_easy_handle(*item) @multi.add(c) end end # starts a background thread that waits for new items and # sends them through the Curl::Multi handle private def start_processor @processor = Thread.new do loop do items = nil @sem.synchronize do items = @q.slice!(0..-1) end unless items.empty? fill_multi(items) @multi.perform do # curl is idle, so process more items if we can get them # without blocking if !@q.empty? && @sem.try_lock begin fill_multi(@q.slice!(0..-1)) ensure @sem.unlock end end end end # wait for a new item to show up before continuing Thread.stop if @q.empty? end end end private def make_easy_handle request, response, read_block, thread = nil protocol = request.use_ssl? ? 'https' : 'http' url = "#{protocol}://#{request.host}:#{request.port}#{request.uri}" curl = Curl::Easy.new(url) # curl.verbose = true request.headers.each {|k, v| curl.headers[k] = v} curl.on_header {|header_data| if header_data =~ /:\s+/ name, value = header_data.strip.split(/:\s+/, 2) response.headers[name] = value end header_data.length } case request.http_method when 'GET' # .... when 'HEAD' curl.head = true when 'PUT' curl.put_data = request.body || '' when 'POST' curl.headers['Content-Type'] = curl.headers['Content-Type'] || '' curl.post_body = request.body || '' when 'DELETE' curl.delete = true end buffer = [] if read_block curl.on_body do |chunk| read_block.call(chunk) chunk.size end else curl.on_body do |chunk| buffer << chunk chunk.size end end curl.on_complete do response.status = curl.response_code unless curl.response_code > 0 response.network_error = NetworkError.new('Empty response. Assume network error.') end unless read_block response.body = buffer.join("") end thread.run if thread end curl end end end end end aws-sdk-v1-1.66.0/lib/aws/core/lazy_error_classes.rb0000644000004100000410000000654712604445426022276 0ustar www-datawww-data# Copyright 2011-2013 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 'thread' module AWS module Core # Provides lazy creation of error classes via {#const_missing}. # # Extend this module provides 3 benefits to another module: # # * A method that accepts strings and returns error classes. # * Thread-safe dynamic error class creation via {#const_missing} # * An error grammar for parsing AWS xml errors # # Here is an example of how it works: # # Class Foo # module Errors # extend AWS::Core::LazyErrorClasses # end # end # # Foo::Errors.error_class('NoSuchKey') # #=> Foo::Errors::NoSuckKey # # Foo::Errors.error_class('Nested.Error.Klasses') # #=> Foo::Errors::Nested::Error::Klasses # # The errors returned from {#error_class} are subclasses # of {AWS::Errors::Base}. # module LazyErrorClasses # This grammar parses the defualt AWS XML error format BASE_ERROR_GRAMMAR = XML::Grammar.customize do element("Error") do ignore end end # @api private def self.extended base unless base.const_defined?(:GRAMMAR) base.const_set(:GRAMMAR, BASE_ERROR_GRAMMAR) end mutex = Mutex.new MetaUtils.extend_method(base, :const_missing_mutex) { mutex } end # Defines a new error class. # @param [String,Symbol] constant # @return [nil] def const_missing constant const_missing_mutex.synchronize do # It's possible the constant was defined by another thread while # this thread was waiting on the mutex, check before setting. if error_const_set?(constant) const_get(constant) else const_set(constant, Class.new(Errors::Base) { extend LazyErrorClasses }) end end end # Converts the error code into an error class constant. # # AWS::EC2::Errors.error_class('Non.Existent.Error') # #=> AWS::EC2::Errors::Non::Existent::Error # # @param [String] code An AWS error code. # # @return [Class] Returns the error class defiend by the error code. # def error_class code module_eval("#{self}::#{code.gsub('.Range','Range').gsub(".","::")}") end private # @return [Boolean] Returns true if the constant is defined in the # current module. def error_const_set?(constant) # Not using #const_defined? because in Ruby 1.9+, it returns true for # constants not defined directly on the current module. constant = constant.to_sym # In Ruby 1.8, #constants returns an array of strings, # in Ruby 1.9+, #constants returns an array of symbols. constants.any? { |c| c.to_sym == constant } end end end end aws-sdk-v1-1.66.0/lib/aws/sns.rb0000644000004100000410000000463312604445426016236 0ustar www-datawww-data# Copyright 2011-2013 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 'aws/core' require 'aws/sns/config' require 'aws/sns/message' module AWS # This class is the starting point for working with Amazon Simple # Notification Service (SNS). # # To use Amazon SNS you must first [sign up here](http://aws.amazon.com/sns/). # # For more information about Amazon SNS: # # * [Amazon SNS](http://aws.amazon.com/sns/) # * [Amazon SNS Documentation](http://aws.amazon.com/documentation/sns/) # # # Credentials # # You can setup default credentials for all AWS services via # AWS.config: # # AWS.config( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # Or you can set them directly on the SNS interface: # # sns = AWS::SNS.new( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # @!attribute [r] client # @return [Client] the low-level SNS client object class SNS autoload :Client, 'aws/sns/client' autoload :Errors, 'aws/sns/errors' autoload :Policy, 'aws/sns/policy' autoload :HasDeliveryPolicy, 'aws/sns/has_delivery_policy' autoload :Subscription, 'aws/sns/subscription' autoload :SubscriptionCollection, 'aws/sns/subscription_collection' autoload :Topic, 'aws/sns/topic' autoload :TopicCollection, 'aws/sns/topic_collection' autoload :TopicSubscriptionCollection, 'aws/sns/topic_subscription_collection' include Core::ServiceInterface endpoint_prefix 'sns' # @return [TopicCollection] Returns a topic collection for managing # SNS topics. def topics TopicCollection.new(:config => config) end # @return [SubscriptionCollection] Returns a subscription # collection for managing SNS subscriptions. def subscriptions SubscriptionCollection.new(:config => config) end end end aws-sdk-v1-1.66.0/lib/aws/iam.rb0000644000004100000410000003324012604445426016175 0ustar www-datawww-data# Copyright 2011-2013 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 'aws/core' require 'aws/iam/config' module AWS # This class is the starting point for working with # AWS Identity and Access Management (IAM). # # For more information about IAM: # # * [AWS Identity and Access Management](http://aws.amazon.com/iam/) # * [AWS Identity and Access Management Documentation](http://aws.amazon.com/documentation/iam/) # # # Credentials # # You can setup default credentials for all AWS services via # AWS.config: # # AWS.config( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # Or you can set them directly on the IAM interface: # # iam = AWS::IAM.new( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # # Account Summary # # You can get account level information about entity usage and IAM quotas # directly from an IAM interface object. # # summary = iam.account_summary # # puts "Num users: #{summary[:users]}" # puts "Num user quota: #{summary[:users_quota]}" # # For a complete list of summary attributes see the {#account_summary} method. # # # Account Aliases # # Currently IAM only supports a single account alias for each AWS account. # You can set the account alias on the IAM interface. # # iam.account_alias = 'myaccountalias' # iam.account_alias # #=> 'myaccountalias' # # You can also remove your account alias: # # iam.remove_account_alias # iam.account_alias # #=> nil # # # Access Keys # # You can create up to 2 access for your account and 2 for each user. # This makes it easy to rotate keys if you need to. You can also # deactivate/activate access keys. # # # get your current access key # old_access_key = iam.access_keys.first # # # create a new access key # new_access_key = iam.access_keys.create # new_access_key.credentials # #=> { :access_key_id => 'ID', :secret_access_key => 'SECRET' } # # # go rotate your keys/credentials ... # # # now disable the old access key # old_access_key.deactivate! # # # go make sure everything still works ... # # # all done, lets clean up # old_access_key.delete # # Users can also have access keys: # # u = iam.users['someuser'] # access_key = u.access_keys.create # access_key.credentials # #=> { :access_key_id => 'ID', :secret_access_key => 'SECRET' } # # See {AccessKeyCollection} and {AccessKey} for more information about # working with access keys. # # # Users & Groups # # Each AWS account can have multiple users. Users can be used to easily # manage permissions. Users can also be organized into groups. # # user = iam.users.create('JohnDoe') # group = iam.groups.create('Developers') # # # add a user to a group # user.groups.add(group) # # # remove a user from a group # user.groups.remove(group) # # # add a user to a group # group.users.add(user) # # # remove a user from a group # group.users.remove(user) # # See {User}, {UserCollection}, {Group} and {GroupCollection} for more # information on how to work with users and groups. # # # Other Interfaces # # Other useful IAM interfaces: # * User Login Profiles ({LoginProfile}) # * Policies ({Policy}) # * Server Certificates ({ServerCertificateCollection}, {ServerCertificate}) # * Signing Certificates ({SigningCertificateCollection}, {SigningCertificate}) # * Multifactor Authentication Devices ({MFADeviceCollection}, {MFADevice}) # # @!attribute [r] client # @return [Client] the low-level IAM client object class IAM autoload :AccessKey, 'aws/iam/access_key' autoload :AccessKeyCollection, 'aws/iam/access_key_collection' autoload :AccountAliasCollection, 'aws/iam/account_alias_collection' autoload :Client, 'aws/iam/client' autoload :Collection, 'aws/iam/collection' autoload :Errors, 'aws/iam/errors' autoload :Group, 'aws/iam/group' autoload :GroupCollection, 'aws/iam/group_collection' autoload :GroupPolicyCollection, 'aws/iam/group_policy_collection' autoload :GroupUserCollection, 'aws/iam/group_user_collection' autoload :LoginProfile, 'aws/iam/login_profile' autoload :MFADevice, 'aws/iam/mfa_device' autoload :MFADeviceCollection, 'aws/iam/mfa_device_collection' autoload :Policy, 'aws/iam/policy' autoload :PolicyCollection, 'aws/iam/policy_collection' autoload :Resource, 'aws/iam/resource' autoload :ServerCertificate, 'aws/iam/server_certificate' autoload :ServerCertificateCollection, 'aws/iam/server_certificate_collection' autoload :SigningCertificate, 'aws/iam/signing_certificate' autoload :SigningCertificateCollection, 'aws/iam/signing_certificate_collection' autoload :User, 'aws/iam/user' autoload :UserCollection, 'aws/iam/user_collection' autoload :UserGroupCollection, 'aws/iam/user_group_collection' autoload :UserPolicy, 'aws/iam/user_policy' autoload :UserPolicyCollection, 'aws/iam/user_policy_collection' autoload :VirtualMfaDeviceCollection, 'aws/iam/virtual_mfa_device_collection' autoload :VirtualMfaDevice, 'aws/iam/virtual_mfa_device' include Core::ServiceInterface endpoint_prefix 'iam', :global => true # Returns a collection that represents all AWS users for this account: # # @example Getting a user by name # # user = iam.users['username'] # # @example Enumerating users # # iam.users.each do |user| # puts user.name # end # # @return [UserCollection] Returns a collection that represents all of # the IAM users for this AWS account. def users UserCollection.new(:config => config) end # Returns a collection that represents all AWS groups for this account: # # @example Getting a group by name # # group = iam.groups['groupname'] # # @example Enumerating groups # # iam.groups.each do |group| # puts group.name # end # # @return [GroupCollection] Returns a collection that represents all of # the IAM groups for this AWS account. def groups GroupCollection.new(:config => config) end # Returns a collection that represents the access keys for this # AWS account. # # iam = AWS::IAM.new # iam.access_keys.each do |access_key| # puts access_key.id # end # # @return [AccessKeyCollection] Returns a collection that represents all # access keys for this AWS account. def access_keys AccessKeyCollection.new(:config => config) end # Returns a collection that represents the signing certificates # for this AWS account. # # iam = AWS::IAM.new # iam.signing_certificates.each do |cert| # # ... # end # # If you need to access the signing certificates of a specific user, # see {User#signing_certificates}. # # @return [SigningCertificateCollection] Returns a collection that # represents signing certificates for this AWS account. def signing_certificates SigningCertificateCollection.new(:config => config) end # @note Currently, Amazon Elastic Load Balancing is the only # service to support the use of server certificates with # IAM. Using server certificates with Amazon Elastic Load # Balancing is described in the # {http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/US_SettingUpLoadBalancerHTTPSIntegrated.html # Amazon Elastic Load Balancing} Developer Guide. # # Returns a collection that represents the server certificates # for this AWS account. # # iam = AWS::IAM.new # iam.server_certificates.each do |cert| # # ... # end # # @return [ServerCertificateCollection] Returns a collection that # represents server certificates for this AWS account. def server_certificates ServerCertificateCollection.new(:config => config) end # Returns a collection that represents the virtual MFA devices # that are not assigned to an IAM user. # # iam = AWS::IAM.new # iam.virtual_mfa_devices.each do |cert| # # ... # end # # @return [VirtualMfaDeviceCollection] Returns a collection that # represents the virtual MFA devices that are not assigned to an # IAM user. def virtual_mfa_devices VirtualMfaDeviceCollection.new(:config => config) end # Sets the account alias for this AWS account. # @param [String] account_alias # @return [String] Returns the account alias passed. def account_alias= account_alias account_alias.nil? ? remove_account_alias : account_aliases.create(account_alias) end # @return [String,nil] Returns the account alias. If this account has # no alias, then `nil` is returned. def account_alias account_aliases.first end # Deletes the account alias (if one exists). # @return [nil] def remove_account_alias account_aliases.each do |account_alias| account_aliases.delete(account_alias) end nil end # @api private def account_aliases AccountAliasCollection.new(:config => config) end # Retrieves account level information about account entity usage # and IAM quotas. The returned hash contains the following keys: # # * `:users` - Number of users for the AWS account # * `:users_quota` - Maximum users allowed for the AWS account # * `:groups` - Number of Groups for the AWS account # * `:groups_quota` - Maximum Groups allowed for the AWS account # * `:server_certificates` - Number of Server Certificates for the # AWS account # * `:server_certificates_quota` - Maximum Server Certificates # allowed for the AWS account # * `:user_policy_size_quota` - Maximum allowed size for user policy # documents (in kilobytes) # * `:group_policy_size_quota` - Maximum allowed size for Group # policy documents (in kilobyes) # * `:groups_per_user_quota` - Maximum number of groups a user can # belong to # * `:signing_certificates_per_user_quota` - Maximum number of X509 # certificates allowed # for a user # * `:access_keys_per_user_quota` - Maximum number of access keys # that can be created per user # @return [Hash] def account_summary client.get_account_summary.data[:summary_map].inject({}) do |h,(k,v)| h.merge(Core::Inflection.ruby_name(k).to_sym => v) end end # Changes the web password associated with the current IAM user. # In order to change your password you must configure the sdk # to use your IAM user credentials. # # # To change a user password, you must be using credentials from the # user you want to change: # # # pass in a key pair generated for the user you want to change # # the password for # iam = AWS::IAM.new(:access_key_id => '...', :secret_access_key => '...) # iam.change_password('old-password', 'new-password') # # @param [String] old_password # # @param [String] new_password # # @return [nil] # def change_password old_password, new_password client_opts = {} client_opts[:old_password] = old_password client_opts[:new_password] = new_password client.change_password(client_opts) nil end # Updates the account password policy for all IAM accounts. # @param [Hash] options # @option options [Integer] :minimum_password_length # @option options [Boolean] :require_symbols # @option options [Boolean] :require_numbers # @option options [Boolean] :require_uppercase_characters # @option options [Boolean] :require_lowercase_characters # @return [nil] def update_account_password_policy options = {} client.update_account_password_policy(options) nil end # Removes the account password policy. # @return [nil] def delete_account_password_policy client.delete_account_password_policy nil end # Returns the account password policy details as a hash. This method # returns nil if no password policy has been set for this account. # # # set the policy # iam.update_account_password_policy :minimum_password_length => 8 # # iam.account_password_policy # #=> {:require_symbols=>false, :require_numbers=>false, :require_uppercase_characters=>false, :require_lowercase_characters=>false, :minimum_password_length=>8} # # @return [Hash,nil] def account_password_policy begin policy = client.get_account_password_policy.password_policy [ :minimum_password_length, :require_symbols?, :require_numbers?, :require_uppercase_characters?, :require_lowercase_characters?, ].inject({}) do |hash,method| key = method.to_s.sub(/\?/, '').to_sym hash.merge(key => policy.send(method)) end rescue Errors::NoSuchEntity nil end end end end aws-sdk-v1-1.66.0/lib/aws/storage_gateway.rb0000644000004100000410000000445312604445426020620 0ustar www-datawww-data# Copyright 2011-2013 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 'aws/core' require 'aws/storage_gateway/config' module AWS # This class is the starting point for working with AWS Storage Gateway. # # To use AWS Storage Gateway you must first # [sign up here](http://aws.amazon.com/storagegateway/). # # For more information about AWS Storage Gateway: # # * [AWS Storage Gateway](http://aws.amazon.com/storagegateway/) # * [AWS Storage Gateway Documentation](http://aws.amazon.com/documentation/storagegateway/) # # # Credentials # # You can setup default credentials for all AWS services via # AWS.config: # # AWS.config( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # Or you can set them directly on the AWS::StorageGateway interface: # # sg = AWS::StorageGateway.new( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # # Using the Client # # AWS::StorageGateway does not provide higher level abstractions for Route 53 at # this time. You can still access all of the API methods using # {AWS::StorageGateway::Client}. Here is how you access the client and make # a simple request: # # sg = AWS::StorageGateway.new # # resp = sg.client.list_gateways # resp[:gateways].each do |gateway| # puts gateway[:gateway_arn] # end # # See {Client} for documentation on all of the supported operations. # # @!attribute [r] client # @return [Client] the low-level StorageGateway client object class StorageGateway autoload :Client, 'aws/storage_gateway/client' autoload :Errors, 'aws/storage_gateway/errors' include Core::ServiceInterface endpoint_prefix 'storagegateway' end end aws-sdk-v1-1.66.0/lib/aws/simple_workflow.rb0000644000004100000410000002121612604445426020652 0ustar www-datawww-data# Copyright 2011-2013 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 'aws/core' require 'aws/simple_workflow/config' module AWS # This is the starting point for working with Amazon Simple Workflow Service. # # # Domains # # To get started, you need to first create a domain. Domains are used to # organize related tasks and activities. # # swf = AWS::SimpleWorkflow.new # # # name the domain and specify the retention period (in days) # domain = swf.domains.create('my-domain', 10) # # You can reference existing domains as well. # # domain = swf.domains['my-domain'] # # # Workflow and Activity Types # # Once you have a domain you can create a workflow and # activity types. Both types (workflow and activity) are templates that # can be used to start workflow executions or schedule activity tasks. # # Workflow and Activity types both have a number of default values # (e.g. default task list, timeouts, etc). If you do not specify these # optional default values when creating the type, you *MUST* specify # the actual values when starting a workflow execution or scheduling # an activity task. # # ## Sample Workflow type and activity type # # # register an workflow type with the version id '1' # workflow_type = domain.workflow_types.create('my-long-processes', '1', # :default_task_list => 'my-task-list', # :default_child_policy => :request_cancel, # :default_task_start_to_close_timeout => 3600, # :default_execution_start_to_close_timeout => 24 * 3600) # # # register an activity type, with the version id '1' # activity_type = domain.activity_types.create('do-something', '1', # :default_task_list => 'my-task-list', # :default_task_heartbeat_timeout => 900, # :default_task_schedule_to_start_timeout => 60, # :default_task_schedule_to_close_timeout => 3660, # :default_task_start_to_close_timeout => 3600) # # # Starting a Workflow Execution # # Once you have a domain and at least one workflow type you can # start a workflow execution. You may provide a workflow id, or a # random one will be generated. You may also provide optional # input and override any of the defaults registered with the # workflow type. # # workflow_execution = workflow_type.start_execution :input => '...' # # workflow_execution.workflow_id #=> "5abbdd75-70c7-4af3-a324-742cd29267c2" # workflow_execution.run_id #=> "325a8c34-d133-479e-9ecf-5a61286d165f" # # # Decision Tasks # # Once a workflow execution has been started, it will start to generate # decision tasks. You poll for decision tasks from a task list. # Yielded decision tasks provide access to the history of events # for the workflow execution. You can also enumerate only new # events since the last decision. # # To make decisions you call methods from the list below. You can call # any number of decision methods any number of times. # # * schedule_activity_task # * request_cancel_activity_task # * complete_workflow_execution # * fail_workflow_execution # * cancel_workflow_execution # * continue_as_new_workflow_execution # * record_marker # * start_timer # * cancel_timer # * signal_external_workflow_execution # * request_cancel_external_workflow_execution workflow_execution, options = {} # * start_child_workflow_execution workflow_type, options = {} # # This sample gets a decision task and responds based on the events # by scheduling an activity task or completing the workflow execution. # # # poll for decision tasks from 'my-task-list' # domain.decision_tasks.poll('my-task-list') do |task| # # # investigate new events and make decisions # task.new_events.each do |event| # case event.event_type # when 'WorkflowExecutionStarted' # task.schedule_activity_task 'do-something', :input => 'abc xyz' # when 'ActivityTaskCompleted' # task.complete_workflow_execution :result => event.attributes.result # end # end # # end # decision task is completed here # # When you are done calling decision methods, you need to complete the # decision task. This is done by default if you pass a block to # `poll` or `poll_for_single_task`. # # # Activity Tasks # # The only way to spawn activity tasks is to call `schedule_activity_task` # on a decision task. Scheduled activity tasks are returned when you # poll for activity tasks. # # # poll 'my-task-list' for activities # domain.activity_tasks.poll('my-task-list') do |activity_task| # # case activity_task.activity_type.name # when 'do-something' # # ... # else # activity_task.fail! :reason => 'unknown activity task type' # end # # end # # ## Activity Task Heartbeats # # When you receive an activity task, you need to update the service # with status messages. This is called recording a heartbeat.# # To record a heartbeat, just call {ActivityTask#record_heartbeat!}. # When you call `record_heartbeat` you should rescue # {ActivityTask::CancelRequestedError}. These are thrown when a task # should be canceled. You can cleanup the task and then call # `cancel!` when you are finished. # # # poll 'my-task-list' for activities # domain.activity_tasks.poll('my-task-list') do |activity_task| # begin # # # do stuff ... # # activity_task.record_heartbeat! :details => '25%' # # # do more stuff ... # # activity_task.record_heartbeat! :details => '50%' # # # do more stuff ... # # activity_task.record_heartbeat! :details => '75%' # # # do more stuff ... # # rescue ActivityTask::CancelRequestedError # # cleanup after ourselves # activity_task.cancel! # end # end # # Like decision tasks, activity tasks are auto-completed at the # end of a poll block. # # # History Events # # You might want to view the event history for a running workflow # execution. You can get a workflow execution by its workflow # id (you may optionally provide the run id as well). # # execution = domain.workflow_executions['workflow-id', 'run-id'] # execution.events.each do |event| # puts event.attributes.to_h.inspect # end # # See {HistoryEvent} and {HistoryEvent::Attributes} for more information. # # @!attribute [r] client # @return [Client] the low-level SimpleWorkflow client object class SimpleWorkflow autoload :ActivityType, 'aws/simple_workflow/activity_type' autoload :ActivityTypeCollection, 'aws/simple_workflow/activity_type_collection' autoload :ActivityTask, 'aws/simple_workflow/activity_task' autoload :ActivityTaskCollection, 'aws/simple_workflow/activity_task_collection' autoload :Client, 'aws/simple_workflow/client' autoload :Count, 'aws/simple_workflow/count' autoload :DecisionTask, 'aws/simple_workflow/decision_task' autoload :DecisionTaskCollection, 'aws/simple_workflow/decision_task_collection' autoload :Domain, 'aws/simple_workflow/domain' autoload :DomainCollection, 'aws/simple_workflow/domain_collection' autoload :Errors, 'aws/simple_workflow/errors' autoload :HistoryEvent, 'aws/simple_workflow/history_event' autoload :HistoryEventCollection, 'aws/simple_workflow/history_event_collection' autoload :OptionFormatters, 'aws/simple_workflow/option_formatters' autoload :Resource, 'aws/simple_workflow/resource' autoload :Type, 'aws/simple_workflow/type' autoload :TypeCollection, 'aws/simple_workflow/type_collection' autoload :WorkflowExecution, 'aws/simple_workflow/workflow_execution' autoload :WorkflowExecutionCollection, 'aws/simple_workflow/workflow_execution_collection' autoload :WorkflowType, 'aws/simple_workflow/workflow_type' autoload :WorkflowTypeCollection, 'aws/simple_workflow/workflow_type_collection' include Core::ServiceInterface endpoint_prefix 'swf' # @return [DomainCollection] def domains DomainCollection.new(:config => config) end end end aws-sdk-v1-1.66.0/lib/aws/elastic_beanstalk.rb0000644000004100000410000000274612604445426021106 0ustar www-datawww-data# Copyright 2011-2013 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 'aws/core' require 'aws/elastic_beanstalk/config' module AWS # Provides an expressive, object-oriented interface to AWS Elastic Beanstalk. # # ## Credentials # # You can setup default credentials for all AWS services via # AWS.config: # # AWS.config( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # Or you can set them directly on the ElasticBeanstalk interface: # # beanstalk = AWS::ElasticBeanstalk.new( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # @!attribute [r] client # @return [Client] the low-level ElasticBeanstalk client object class ElasticBeanstalk autoload :Client, 'aws/elastic_beanstalk/client' autoload :Errors, 'aws/elastic_beanstalk/errors' include Core::ServiceInterface endpoint_prefix 'elasticbeanstalk' end end aws-sdk-v1-1.66.0/lib/aws/redshift/0000755000004100000410000000000012604445426016710 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/redshift/errors.rb0000644000004100000410000000124112604445426020547 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class Redshift module Errors extend Core::LazyErrorClasses end end end aws-sdk-v1-1.66.0/lib/aws/redshift/client.rb0000644000004100000410000000163212604445426020515 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class Redshift # Client class for Amazon Redshift. class Client < Core::QueryClient API_VERSION = '2012-12-01' signature_version :Version4, 'redshift' # @api private CACHEABLE_REQUESTS = Set[] end class Client::V20121201 < Client define_client_methods('2012-12-01') end end end aws-sdk-v1-1.66.0/lib/aws/redshift/config.rb0000644000004100000410000000123212604445426020500 0ustar www-datawww-data# Copyright 2011-2013 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. AWS::Core::Configuration.module_eval do add_service 'Redshift', 'redshift', 'redshift' end aws-sdk-v1-1.66.0/lib/aws/elastic_beanstalk/0000755000004100000410000000000012604445426020550 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/elastic_beanstalk/errors.rb0000644000004100000410000000125112604445426022410 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class ElasticBeanstalk module Errors extend Core::LazyErrorClasses end end end aws-sdk-v1-1.66.0/lib/aws/elastic_beanstalk/client.rb0000644000004100000410000000166112604445426022357 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class ElasticBeanstalk # Client class for AWS Elastic Beanstalk. class Client < Core::QueryClient API_VERSION = '2010-12-01' signature_version :Version4, 'elasticbeanstalk' # @api private CACHEABLE_REQUESTS = Set[] end class Client::V20101201 < Client define_client_methods('2010-12-01') end end end aws-sdk-v1-1.66.0/lib/aws/elastic_beanstalk/config.rb0000644000004100000410000000126312604445426022344 0ustar www-datawww-data# Copyright 2011-2013 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. AWS::Core::Configuration.module_eval do add_service 'ElasticBeanstalk', 'elastic_beanstalk', 'elasticbeanstalk' end aws-sdk-v1-1.66.0/lib/aws/errors.rb0000644000004100000410000001147612604445426016752 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS # # Errors # # There are two basic types of errors: # # * {ClientError} # * {ServerError} # # ## Client Errors # # Errors in the three and four hundreds are client errors ({ClientError}). # A client error should not be resent without changes. The body of the # http response (the error #message) should give more information about # the nature of the problem. # # ## Server Errors # # A 500 level error typically indicates the service is having an issue. # # Requests that generate service errors are automatically retried with # an exponential backoff. If the service still fails to respond with # a 200 after 3 retries the error is raised. # module Errors # Base class for all errors returned by the service. class Base < StandardError # @overload new(error_message) # @param [String] error_message The body of the error message # # @overload new(http_request, http_response, code = nil, message = nil) # @param [Http::Request] http_request # @param [Http::Response] http_response # @param [String] code (nil) # @param [String] message (nil) # def initialize req = nil, resp = nil, code = nil, message = nil if req.is_a?(String) or req.nil? super(req) else @http_request = req @http_response = resp @code = code include_error_type super(message || http_response.body) end end # @return [String] The response code given by the service. attr_reader :code # @return [Http::Request] The low level http request that caused the # error to be raised. attr_reader :http_request # @return [Http::Response] The low level http response from the service # that wrapped the service error. attr_reader :http_response protected # Extends the error object with {ServerError} or {ClientError}. # This indicates if the request should be retried (server errors) # or not (client errors). def include_error_type if http_response.status >= 500 extend ServerError else extend ClientError end end end # Provides the ability to instantiate instances of {ServerError} and # {ClientError}. # @api private module ExceptionMixinClassMethods def new(*args) e = Base.new(*args) e.extend(self) e end end # Raised when an error occurs as a result of bad client # behavior, most commonly when the parameters passed to a method # are somehow invalid. Other common cases: # # * Throttling errors # * Bad credentials # * No permission to do the requested operation # * Limits exceeded (e.g. too many buckets) # module ClientError extend ExceptionMixinClassMethods end # Raised when an AWS service is unable to handle the request. These # are automatically retired. If after 3 retries the request is still # failing, then the error is raised. module ServerError extend ExceptionMixinClassMethods end # Raised when AWS credentials could not be found. class MissingCredentialsError < StandardError def initialize msg = nil msg ||= <<-MSG Missing Credentials. Unable to find AWS credentials. You can configure your AWS credentials a few different ways: * Call AWS.config with :access_key_id and :secret_access_key * Export AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to ENV * On EC2 you can run instances with an IAM instance profile and credentials will be auto loaded from the instance metadata service on those instances. * Call AWS.config with :credential_provider. A credential provider should either include AWS::Core::CredentialProviders::Provider or respond to the same public methods. = Ruby on Rails In a Ruby on Rails application you may also specify your credentials in the following ways: * Via a config initializer script using any of the methods mentioned above (e.g. RAILS_ROOT/config/initializers/aws-sdk.rb). * Via a yaml configuration file located at RAILS_ROOT/config/aws.yml. This file should be formated like the default RAILS_ROOT/config/database.yml file. MSG super(msg) end end end end aws-sdk-v1-1.66.0/lib/aws/route_53/0000755000004100000410000000000012604445426016545 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/route_53/change_batch.rb0000644000004100000410000001202512604445426021460 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class Route53 # # Modify resource record sets with ChangeBatch # # batch = AWS::Route53::ChangeBatch.new(hosted_zone_id) # batch << AWS::Route53::CreateRequest.new('foo.example.com.', 'A', :resource_records => [{:value => '192.168.0.1'}]) # batch << AWS::Route53::DeleteRequest.new('bar.example.com.', 'CNAME') # batch << AWS::Route53::DeleteRequest.new('baz.example.com.', 'AAAA') # batch << AWS::Route53::CreateRequest.new('baz.example.com.', 'AAAA', :resource_records => [{:value => '192.168.0.3'}]) # # batch.call # class ChangeBatch include Enumerable include Core::Model # @api private def initialize hosted_zone_id, options = {} super(options) @hosted_zone_id = hosted_zone_id @comment = options[:comment] @changes = [] end # @return [String] attr_reader :hosted_zone_id # @return [Array] attr_reader :changes # @return [String] attr_reader :comment # @param [ChangeRequest] change # @return [Array] def push change @changes.push(change) end alias_method :<<, :push # Calls change batch request. # @option (see Client#change_resource_record_sets) # @return [ChangeInfo] def call options={} resp = client.change_resource_record_sets(options.merge(self.to_hash)) if resp[:change_info][:id] ChangeInfo.new_from(:change_resource_record_sets, resp[:change_info], resp[:change_info][:id], :config => config) end end # Enumerates over changes. def each(&block) @changes.each(&block) end # Returns length of changes. # @return [Integer] def length @changes.length end alias_method :size, :length # Build query from change batch. # @return [Hash] def to_hash q = {} q[:hosted_zone_id] = hosted_zone_id q[:change_batch] = {} q[:change_batch][:comment] = comment if comment q[:change_batch][:changes] = [] self.each { |change| q[:change_batch][:changes] << change.to_hash } q end end class ChangeRequest # @api private def initialize(action, name, type, options={}) @action = action @name = name @type = type @change_options = options end # @return [String] attr_reader :action # @return [String] attr_reader :name # @return [String] attr_reader :type # Build query for change request. # @return [Hash] def to_hash q = {} q[:action] = action q[:resource_record_set] = {} q[:resource_record_set][:name] = name q[:resource_record_set][:type] = type q[:resource_record_set][:set_identifier] = @change_options[:set_identifier] if @change_options[:set_identifier] q[:resource_record_set][:weight] = @change_options[:weight] if @change_options[:weight] q[:resource_record_set][:region] = @change_options[:region] if @change_options[:region] q[:resource_record_set][:ttl] = @change_options[:ttl] if @change_options[:ttl] q[:resource_record_set][:resource_records] = @change_options[:resource_records] if @change_options[:resource_records] q[:resource_record_set][:alias_target] = @change_options[:alias_target] if @change_options[:alias_target] q[:resource_record_set][:geo_location] = @change_options[:geo_location] if @change_options[:geo_location] q[:resource_record_set][:failover] = @change_options[:failover] if @change_options[:failover] q[:resource_record_set][:health_check_id] = @change_options[:health_check_id] if @change_options[:health_check_id] q end end # A change request to create a resource record set. class CreateRequest < ChangeRequest # @param [String] name # @param [String] type # @param [Hash] options def initialize name, type, options = {} super('CREATE', name, type, options) end end # A change request to delete a resource record set. class DeleteRequest < ChangeRequest # @param [String] name # @param [String] type # @param [Hash] options def initialize name, type, options = {} super('DELETE', name, type, options) end end end end aws-sdk-v1-1.66.0/lib/aws/route_53/resource_record_set.rb0000644000004100000410000001671412604445426023143 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class Route53 # # Modify resource record set # # rrsets = AWS::Route53::HostedZone.new(hosted_zone_id).rrsets # rrset = rrsets['foo.example.com.', 'A'] # rrset.ttl = 3600 # rrset.update # # # Delete existing resource record set # # rrsets = AWS::Route53::HostedZone.new(hosted_zone_id).rrsets # rrset = rrsets['foo.example.com.', 'A'] # rrset.delete # # @attr_reader [Hash] alias_target # # @attr_reader [Integer] weight # # @attr_reader [String] region # # @attr_reader [Integer] ttl # # @attr_reader [Array] resource_records # class ResourceRecordSet < Core::Resource # @api private def initialize name, type, options = {} @name = name @type = type @set_identifier = options[:set_identifier] @hosted_zone_id = options[:hosted_zone_id] @change_info = options[:change_info] @create_options = {} super end # @return [String] The hosted zone ID. attr_reader :hosted_zone_id # @return [ChangeInfo] attr_reader :change_info # @return [String] name attr_reader :name # @param [String] new_name # @return [String] def name= new_name @create_options[:name] = new_name end # @return [String] attr_reader :type # @param [String] new_type # @return [String] def type= new_type @create_options[:type] = new_type end # @return [String] attr_reader :set_identifier alias_method :identifier, :set_identifier # @param [String] new_identifier # @return [String] def set_identifier= new_identifier @create_options[:set_identifier] = new_identifier end alias_method :identifier=, :set_identifier= attribute :alias_target # @param [Hash] new_target # @return [Hash] def alias_target= new_target @create_options[:alias_target] = new_target end attribute :weight # @param [Integer] new_weight # @return [Integer] def weight= new_weight @create_options[:weight] = new_weight end attribute :region # @param [String] new_region # @return [String] def region= new_region @create_options[:region] = new_region end attribute :ttl # @param [Integer] new_ttl # @return [Integer] def ttl= new_ttl @create_options[:ttl] = new_ttl end attribute :geo_location def geo_location= new_geo_location @create_options[:geo_location] = new_geo_location end attribute :failover def failover= new_failover @create_options[:failover] = new_failover end attribute :health_check_id def health_check_id= new_health_check_id @create_options[:health_check_id] = new_health_check_id end attribute :resource_records # @param [Array] new_rrs # @return [Array] def resource_records= new_rrs @create_options[:resource_records] = new_rrs end populates_from :list_resource_record_sets do |resp| resp[:resource_record_sets].find { |details| if set_identifier details[:name] == name and details[:type] == type and details[:set_identifier] == set_identifier else details[:name] == name and details[:type] == type end } end # @return [Boolean] Returns `true` if this rrset exists. def exists? !get_resource.data[:resource_record_sets].find { |details| if set_identifier details[:name] == name and details[:type] == type and details[:set_identifier] == set_identifier else details[:name] == name and details[:type] == type end }.nil? end # Update values of resource record set. # @param [Hash] options Options for change batch. # @return [ResourceRecordSet] New resource record set with current value. def update options = {} batch = new_change_batch(options) AWS.memoize do batch << new_delete_request batch << new_create_request end @change_info = batch.call() @name = @create_options[:name] || @name @type = @create_options[:type] || @type @set_identifier = @create_options[:set_identifier] || @set_identifier @create_options = {} self end # Delete resource record set. # @param [Hash] options Options for change batch. # @return [ChangeInfo] def delete options = {} batch = new_change_batch(options) batch << new_delete_request change_info = batch.call() end # Return a new change batch for this hosted zone. # @param [Hash] options Options for change batch. # @return [ChangeBatch] def new_change_batch options = {} ChangeBatch.new(hosted_zone_id, options.merge(:config => config)) end # Return the create request that #update would include in its change # batch. Note that #update also includes a delete request. # @return [CreateRequest] def new_create_request create_options = delete_options.merge(@create_options) CreateRequest.new(create_options[:name], create_options[:type], create_options) end # Return a delete request that would delete this resource record set. # @return [DeleteRequest] def new_delete_request options = delete_options DeleteRequest.new(options[:name], options[:type], options) end protected def resource_identifiers [[:name, name], [:type, type], [:set_identifier, set_identifier]] end def get_resource attr_name = nil options = {} options[:start_record_name] = name options[:start_record_type] = type options[:start_record_identifier] = set_identifier if set_identifier options[:hosted_zone_id] = hosted_zone_id client.list_resource_record_sets(options) end private # Format a hash of options that can be used to initialize a change # request. # @return [Hash] def delete_options options = {:name => name, :type => type} AWS.memoize do options[:set_identifier] = set_identifier if set_identifier options[:alias_target] = alias_target if alias_target options[:weight] = weight if weight options[:region] = region if region options[:ttl] = ttl if ttl options[:resource_records] = resource_records if resource_records && !resource_records.empty? options[:geo_location] = geo_location if geo_location options[:failover] = failover if failover options[:health_check_id] = health_check_id if health_check_id end options end end end end aws-sdk-v1-1.66.0/lib/aws/route_53/errors.rb0000644000004100000410000000124012604445426020403 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class Route53 module Errors extend Core::LazyErrorClasses end end end aws-sdk-v1-1.66.0/lib/aws/route_53/change_info.rb0000644000004100000410000000344312604445426021336 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class Route53 # # @attr_reader [String] id # change id. # # @attr_reader [String] status # status of the change. # # @attr_reader [Time] submitted_at # class ChangeInfo < Core::Resource # @api private def initialize id, options = {} @id = id super end attr_reader :id attribute :status attribute :submitted_at, :static => true populates_from :change_resource_record_sets do |resp| resp[:change_info] if resp[:change_info][:id] == id end populates_from :create_hosted_zone do |resp| resp[:change_info] if resp[:change_info][:id] == id end populates_from :delete_hosted_zone do |resp| resp[:change_info] if resp[:change_info][:id] == id end populates_from :get_change do |resp| resp[:change_info] if resp[:change_info][:id] == id end # @return [Boolean] Returns true if this change exists. def exists? get_resource.data[:change_info][:id] == id end protected def resource_identifiers [[:id, id]] end def get_resource attr_name = nil client.get_change(:id => id) end end end end aws-sdk-v1-1.66.0/lib/aws/route_53/resource_record_set_collection.rb0000644000004100000410000000741212604445426025351 0ustar www-datawww-data# Copyright 2011-2013 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 'time' module AWS class Route53 # # Create new resource record set # # rrsets = AWS::Route53::HostedZone.new(hosted_zone_id).rrsets # rrset = rrsets.create('foo.example.com.', 'A', :ttl => 300, :resource_records => [{:value => '127.0.0.1'}]) # # # Find existing resource record set # # rrsets = AWS::Route53::HostedZone.new(hosted_zone_id).rrsets # rrset = rrsets['foo.example.com.', 'A'] # class ResourceRecordSetCollection include Core::Collection::WithLimitAndNextToken # @api private def initialize hosted_zone_id, options = {} @hosted_zone_id = hosted_zone_id @filters = options[:filters] || {} super end # @return [String] attr_reader :hosted_zone_id # Find resource record set by its name, type and identifier. # @param [String] name # @param [String] type # @param [String] set_identifier # @return [ResourceRecordSet] def [] name, type, set_identifier = nil ResourceRecordSet.new(name, type, :set_identifier => set_identifier, :hosted_zone_id => hosted_zone_id, :config => config) end # Create new resource record set. # @param [String] name # @param [String] type # @param [Hash] options # @return [ResourceRecordSet] def create name, type, options = {} batch = ChangeBatch.new(hosted_zone_id, :comment => options[:comment], :config => config) batch << CreateRequest.new(name, type, options) change_info = batch.call() if change_info ResourceRecordSet.new(name, type, :set_identifier => options[:set_identifier], :change_info => change_info, :hosted_zone_id => hosted_zone_id, :config => config) end end private def _each_item next_token, limit, options = {}, &block options = @filters.merge(options) options[:start_record_name] = next_token[:next_record_name] if next_token and next_token[:next_record_name] options[:start_record_type] = next_token[:next_record_type] if next_token and next_token[:next_record_type] options[:start_record_identifier] = next_token[:next_record_identifier] if next_token and next_token[:next_record_identifier] options[:maxitems] = limit if limit options[:hosted_zone_id] = hosted_zone_id resp = client.list_resource_record_sets(options) resp.data[:resource_record_sets].each do |details| rrset = ResourceRecordSet.new_from( :list_resource_record_sets, details, details[:name], details[:type], :set_identifier => details[:set_identifier], :hosted_zone_id => hosted_zone_id, :config => config) yield(rrset) end if resp.data[:is_truncated] { :next_record_name => resp.data[:next_record_name], :next_record_type => resp.data[:next_record_type], :next_record_identifier => resp.data[:next_record_identifier], } end end end end end aws-sdk-v1-1.66.0/lib/aws/route_53/client.rb0000644000004100000410000000174312604445426020355 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class Route53 # Client class for Route53. class Client < Core::RESTXMLClient API_VERSION = '2013-04-01' signature_version :Version3Https # @api private CACHEABLE_REQUESTS = Set[] end class Client::V20121212 < Client define_client_methods('2012-12-12') end class Client::V20130401 < Client define_client_methods('2013-04-01') end end end aws-sdk-v1-1.66.0/lib/aws/route_53/hosted_zone.rb0000644000004100000410000001133412604445426021415 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class Route53 # # Delete existing hosted zone # # hosted_zone = AWS::Route53::HostedZone.new(hosted_zone_id) # hosted_zone.delete # # @attr_reader [String] name The hosted zone name. # # @attr_reader [Integer] resource_record_set_count # The resource record set count. # # @attr_reader [Array] delegation_set # class HostedZone < Core::Resource S3_HOSTED_ZONE_IDS = { 'us-east-1' => 'Z3AQBSTGFYJSTF', 'us-west-2' => 'Z3BJ6K6RIION7M', 'us-west-1' => 'Z2F56UZL2M1ACD', 'eu-west-1' => 'Z1BKCTXD74EZPE', 'ap-southeast-1' => 'Z3O0J2DXBE1FTB', 'ap-southeast-2' => 'Z1WCIGYICN2BYD', 'ap-northeast-1' => 'Z2M4EHUR26P7ZW', 'sa-east-1' => 'Z7KQH4QJS55SO', 'us-gov-west-1' => 'Z31GFT0UA1I2HV' } # @api private def initialize id, options = {} @id = id.sub(%r!^/hostedzone/!, '') @change_info = options[:change_info] super end # @return [String] The hosted zone ID. attr_reader :id # @return [ChangeInfo] Change info for the newly created HostedZone # instance. attr_reader :change_info # The Hosted zone path. # @return [String] def path "/hostedzone/#{id}" end define_attribute_type :list define_attribute_type :get list_attribute :name, :static => true list_attribute :configuration, :from => :config, :static => true list_attribute :resource_record_set_count get_attribute :delegation_set, :static => true get_attribute :vpcs provider(:list_hosted_zones) do |provider| provider.find do |resp| resp.data[:hosted_zones].find do |detail| detail[:hosted_zone][:id] == path end end provider.provides *list_attributes.keys end provider(:create_hosted_zone, :get_hosted_zone) do |provider| provider.find do |resp| if resp[:hosted_zone][:id] == path resp[:hosted_zone][:delegation_set] = resp[:delegation_set] resp[:hosted_zone][:vpcs] = resp[:vpcs] resp[:hosted_zone] end end provider.provides *list_attributes.keys provider.provides *get_attributes.keys end # Deletes the hosted zone. # @return [ChangeInfo] def delete resp = client.delete_hosted_zone(:id => id) if resp[:change_info][:id] ChangeInfo.new_from(:delete_hosted_zone, resp[:change_info], resp[:change_info][:id], :config => config) end end # @return [Boolean] Returns `true` if this hosted zone exists. def exists? get_resource true rescue Errors::NoSuchHostedZone false end # Returns resource record sets. # @return [ResourceRecordSetCollection] def resource_record_sets ResourceRecordSetCollection.new(id, :config => config) end alias_method :rrsets, :resource_record_sets # Associates an additional VPC with a private hosted zone. # @return [ChangeInfo] def associate_vpc vpc resp = client.associate_vpc_with_hosted_zone(:hosted_zone_id => id, :vpc => vpc) if resp[:change_info][:id] ChangeInfo.new_from(:associate_vpc_with_hosted_zone, resp[:change_info], resp[:change_info][:id]) end end # Disassociates an VPC from an private hosted zone. # @return [ChangeInfo] def disassociate_vpc vpc resp = client.disassociate_vpc_from_hosted_zone(:hosted_zone_id => id, :vpc => vpc) if resp[:change_info][:id] ChangeInfo.new_from(:disassociate_vpc_from_hosted_zone, resp[:change_info], resp[:change_info][:id]) end end protected def resource_identifiers [[:id, id], [:name, name]] end def get_resource attr_name = nil client.get_hosted_zone(:id => id) end end end end aws-sdk-v1-1.66.0/lib/aws/route_53/config.rb0000644000004100000410000000123012604445426020333 0ustar www-datawww-data# Copyright 2011-2013 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. AWS::Core::Configuration.module_eval do add_service 'Route53', 'route_53', 'route53' end aws-sdk-v1-1.66.0/lib/aws/route_53/hosted_zone_collection.rb0000644000004100000410000000544612604445426023637 0ustar www-datawww-data# Copyright 2011-2013 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 'time' module AWS class Route53 # # Create new hosted zone # # r53 = AWS::Route53.new # hosted_zone = r53.hosted_zones.create('example.com.') # # # Find existing hosted zone # # r53 = AWS::Route53.new # # to lookup a route53 hosted zone, you need to use the zone id (i.e hosted_zone.id) # hosted_zone = r53.hosted_zones['Zabcdefghijklm'] # class HostedZoneCollection include Core::Collection::WithLimitAndNextToken # @api private def initialize options = {} @filters = options[:filters] || {} super end # Find hosted zone by id. # @param [String] hosted_zone_id # @return [HostedZone] def [] hosted_zone_id HostedZone.new(hosted_zone_id, :config => config) end # @param [String] name # @option options [String] :comment # @option options [String] :caller_reference # @return [HostedZone] def create name, options = {} options[:name] = name unless options[:caller_reference] options[:caller_reference] = "CreateHostedZone, #{name}, #{Time.now.httpdate}" end if options[:comment] options[:hosted_zone_config] ||= {} options[:hosted_zone_config][:comment] = options.delete(:comment) end resp = client.create_hosted_zone(options) change_info = ChangeInfo.new_from(:create_hosted_zone, resp, resp[:change_info][:id], :config => config) HostedZone.new_from(:create_hosted_zone, resp, resp[:hosted_zone][:id], :change_info => change_info, :config => config) end protected def _each_item next_token, limit, options = {}, &block options = @filters.merge(options) options[:marker] = next_token if next_token options[:max_items] = limit if limit resp = client.list_hosted_zones(options) resp.data[:hosted_zones].each do |details| hosted_zone = HostedZone.new_from( :list_hosted_zones, details, details[:id], :config => config) yield(hosted_zone) end resp.data[:next_marker] end end end end aws-sdk-v1-1.66.0/lib/aws/direct_connect.rb0000644000004100000410000000441612604445426020415 0ustar www-datawww-data# Copyright 2011-2013 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 'aws/core' require 'aws/direct_connect/config' module AWS # This class is the starting point for working with AWS Import/Export. # # To use AWS Direct Connect you must first # [sign up here](http://aws.amazon.com/directconnect/). # # For more information about AWS AWS Direct Connect: # # * [AWS Direct Connect](http://aws.amazon.com/directconnect/) # * [AWS Direct Connect Documentation](http://aws.amazon.com/documentation/directconnect/) # # # Credentials # # You can setup default credentials for all AWS services via # AWS.config: # # AWS.config( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # Or you can set them directly on the AWS::DirectConnect interface: # # dc = AWS::DirectConnect.new( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # # Using the Client # # AWS::DirectConnect does not provide higher level abstractions for at # this time. You can still access all of the API methods using # {AWS::DirectConnect::Client}. Here is how you access the client and make # a simple request: # # dc = AWS::DirectConnect.new # # resp = dc.client.describe_connections # resp[:connections].each do |connection| # # ... # end # # See {Client} for documentation on all of the supported operations. # # @!attribute [r] client # @return [Client] the low-level DirectConnect client object # class DirectConnect autoload :Client, 'aws/direct_connect/client' autoload :Errors, 'aws/direct_connect/errors' include Core::ServiceInterface endpoint_prefix 'directconnect' end end aws-sdk-v1-1.66.0/lib/aws/cloud_search.rb0000644000004100000410000000441112604445426020060 0ustar www-datawww-data# Copyright 2011-2013 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 'aws/core' require 'aws/cloud_search/config' module AWS # This class is the starting point for working with Amazon CloudSearch. # # To use Amazon CloudSearch you must first # [sign up here](http://aws.amazon.com/cloudsearch/). # # For more information about Amazon CloudSearch: # # * [Amazon CloudSearch](http://aws.amazon.com/cloudsearch/) # * [Amazon CloudSearch Documentation](http://aws.amazon.com/documentation/cloudsearch/) # # # Credentials # # You can setup default credentials for all AWS services via # AWS.config: # # AWS.config( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # Or you can set them directly on the AWS::CloudSearch interface: # # cs = AWS::CloudSearch.new( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # # Using the Client # # AWS::CloudSearch does not provide higher level abstractions for CloudSearch at # this time. You can still access all of the API methods using # {AWS::CloudSearch::Client}. Here is how you access the client and make # a simple request: # # cs = AWS::CloudSearch.new # # resp = cs.client.describe_domains # resp[:domain_status_list].each do |domain| # puts domain[:domain_id] # end # # See {Client} for documentation on all of the supported operations. # # @!attribute [r] client # @return [Client] the low-level CloudSearch client object class CloudSearch autoload :Client, 'aws/cloud_search/client' autoload :Errors, 'aws/cloud_search/errors' include Core::ServiceInterface endpoint_prefix 'cloudsearch' end end aws-sdk-v1-1.66.0/lib/aws/cloud_watch/0000755000004100000410000000000012604445426017374 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/cloud_watch/metric_statistics.rb0000644000004100000410000000335112604445426023460 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class CloudWatch # Statistics for a metric. # # This class is an enumerable collection of data points. # # ## Enumerating Statistics # # metric = CloudWatch::Metric.new('my/namepace', 'metric-name') # # stats = metric.statistics( # :start_time => Time.now - 3600, # :end_time => Time.now, # :statistics => ['Average']) # # stats.label #=> 'some-label' # stats.each do |datapoint| # # datapoint is a hash # end # # @see Core::Collection # class MetricStatistics include Core::Collection::Simple # @param [Metric] metric # @param [String] label # @param [Array] datapoints def initialize metric, label, datapoints @metric = metric @label = label @datapoints = datapoints end # @return [Metric] attr_reader :metric # @return [String] attr_reader :label # @return [Array] attr_reader :datapoints protected def _each_item options = {} datapoints.each do |point| yield(point) end end end end end aws-sdk-v1-1.66.0/lib/aws/cloud_watch/errors.rb0000644000004100000410000000124312604445426021235 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class CloudWatch module Errors extend Core::LazyErrorClasses end end end aws-sdk-v1-1.66.0/lib/aws/cloud_watch/alarm_history_item_collection.rb0000644000004100000410000000446412604445426026037 0ustar www-datawww-data# Copyright 2011-2013 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 'date' require 'time' module AWS class CloudWatch class AlarmHistoryItemCollection include Core::Collection::WithLimitAndNextToken # @api private def initialize options = {} @filters = options[:filters] || {} super end # @param [String,Symbol] name # @param [String] value # @return [AlarmHistoryItemCollection] def filter name, value filters = @filters.merge(name.to_s.to_sym => value) AlarmHistoryItemCollection.new(:filters => filters, :config => config) end # @param [String] name # @return [AlarmHistoryItemCollection] def with_alarm_name name filter(:alarm_name, name) end # @param [Time,DateTime,String] date # @return [AlarmHistoryItemCollection] def with_start_date date date = date.iso8601 if date.respond_to?(:iso8601) filter(:start_date, date) end # @param [Time,DateTime,String] date # @return [AlarmHistoryItemCollection] def with_end_date date date = date.iso8601 if date.respond_to?(:iso8601) filter(:end_date, date) end # @param [String] type # @return [AlarmHistoryItemCollection] def with_type type filter(:history_item_type, type) end protected def _each_item next_token, limit, options = {}, &block options = @filters.merge(options) options[:max_records] = limit if limit options[:next_token] = next_token if next_token resp = client.describe_alarm_history(options) resp.data[:alarm_history_items].each do |details| yield(AlarmHistoryItem.new(details)) end resp.data[:next_token] end end end end aws-sdk-v1-1.66.0/lib/aws/cloud_watch/client.rb0000644000004100000410000000202712604445426021200 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class CloudWatch # Client class for Cloud Watch class Client < Core::QueryClient API_VERSION = '2010-08-01' signature_version :Version4, 'monitoring' # @api private CACHEABLE_REQUESTS = Set[ :describe_alarm_history, :describe_alarms, :describe_alarms_for_metric, :list_metrics, ] end class Client::V20100801 < Client define_client_methods('2010-08-01') end end end aws-sdk-v1-1.66.0/lib/aws/cloud_watch/metric.rb0000644000004100000410000000763312604445426021215 0ustar www-datawww-data# Copyright 2011-2013 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 'date' require 'time' module AWS class CloudWatch # # Metric # # Represents a single metric. # class Metric < Core::Resource # @param [String] namespace The metric namespace. # @param [String] metric_name The metric name. # @param [Hash] options # @option options [Array] :dimensions An array of dimensions. # Each hash must have a `:name` and a `value` key (with string values). def initialize namespace, metric_name, options = {} @namespace = namespace @metric_name = metric_name @dimensions = options[:dimensions] || [] super end # @return [String] attr_reader :namespace # @return [String] attr_reader :metric_name alias_method :name, :metric_name # @return [Array] attr_reader :dimensions # @return [MetricAlarmCollection] def alarms MetricAlarmCollection.new(self, :config => config) end # Publishes metric data points to Amazon CloudWatch. # @param [Array] metric_data An array of hashes. Each hash # must pass `:value` (number) or `:statistic_values` (hash). # @return [nil] def put_data *metric_data metric_opts = {} metric_opts[:metric_name] = metric_name metric_opts[:dimensions] = dimensions unless dimensions.empty? options = {} options[:namespace] = namespace options[:metric_data] = metric_data.flatten.map do |data| data.merge(metric_opts) end client.put_metric_data(options) nil end # Gets statistics for this metric. # # metric = CloudWatch::Metric.new('my/namepace', 'metric-name') # # stats = metric.statistics( # :start_time => Time.now - 3600, # :end_time => Time.now, # :statistics => ['Average']) # # stats.label #=> 'some-label' # stats.each do |datapoint| # # datapoint is a hash # end # # @param [Hash] options # @option options [Time,required] :start_time # @option options [Time,required] :end_time # @option options [Array,required] :statistics # @option options [String] :unit # @option options [Integer] :period (60) # @return [MetricStatistics] def statistics options = {} start = options.delete(:start_time) stop = options.delete(:end_time) options[:namespace] = namespace options[:metric_name] = metric_name options[:dimensions] = dimensions unless dimensions.empty? options[:start_time] = start.respond_to?(:iso8601) ? start.iso8601 : start options[:end_time] = stop.respond_to?(:iso8601) ? stop.iso8601 : stop options[:period] ||= 60 resp = client.get_metric_statistics(options) MetricStatistics.new(self, resp[:label], resp[:datapoints]) end # @return [Boolean] Returns `true` if this metric exists. def exists? !get_resource.data[:metrics].empty? end protected def resource_identifiers [ [:namespace, namespace], [:metric_name, metric_name], [:dimensions, dimensions], ] end def get_resource attr_name = nil client.list_metrics(resource_options) end end end end aws-sdk-v1-1.66.0/lib/aws/cloud_watch/config.rb0000644000004100000410000000124112604445426021164 0ustar www-datawww-data# Copyright 2011-2013 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. AWS::Core::Configuration.module_eval do add_service 'CloudWatch', 'cloud_watch', 'monitoring' end aws-sdk-v1-1.66.0/lib/aws/cloud_watch/metric_collection.rb0000644000004100000410000000754112604445426023426 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class CloudWatch class MetricCollection include Core::Collection::WithNextToken # @api private def initialize options = {} @filters = options[:filters] || {} super end # Returns a new collection that will filter results when enumerated. # # @example Filtering by a namespace # # traffic_metrics = metrics.filter('namespace', 'traffic') # # @example Filtering by a metric name # # my_metric = metrics.filter('metric_name', 'my-metric').first # # @example Filtering by one or more dimensions # # metrics = metrics.filter('dimensions', [ # { :name => 'n1', :value => 'v1' }, # { :name => 'n2', :value => 'v2' }, # { :name => 'n3', :value => 'v3' }, # ]) # # @param [String,Symbol] name # @param [String,Array] value # @return [MetricCollection] def filter name, value filters = @filters.merge(name.to_s.to_sym => value) MetricCollection.new(:filters => filters, :config => config) end # @param [String] namespace # @return [MetricCollection] def with_namespace namespace filter(:namespace, namespace) end # @param [String] name # @return [MetricCollection] def with_metric_name name filter(:metric_name, name) end # Returns a collection filtered by the given dimension: # # metric = metrics.with_dimension('name', 'value').first # # You can chain calls to #with_dimension. Additional dimensions are # added. # # metrics = metrics. # with_dimension('d1', 'v1'). # with_dimension('d2', 'v2'). # with_dimension('d3', 'v3') # # metrics.each{|metric|} # filtered by all three dimensions # # @param [String] name # @param [String] value # @return [MetricCollection] def with_dimension name, value with_dimensions([{ :name => name, :value => value }]) end # Returns a collection filtered by the given dimensions. # # metrics.with_dimensions([ # { :name => 'd1', :value => 'v1' }, # { :name => 'd2', :value => 'v2' }, # { :name => 'd3', :value => 'v3' }, # ]).each do |metric| # # ... # end # # Multiple calls to #with_dimensions will add to previous dimensions. # @param [Array] dimensions An array of dimensions. Each dimension # should be a Hash with a `:name` and `:value`. # @return [MetricCollection] def with_dimensions *dimensions filter(:dimensions, (@filters[:dimensions] || []) + dimensions.flatten ) end protected def _each_item next_token, options = {}, &block options = @filters.merge(options) options[:next_token] = next_token if next_token resp = client.list_metrics(options) resp.data[:metrics].each do |details| metric = Metric.new_from( :list_metrics, details, details[:namespace], details[:metric_name], details.merge(:config => config)) yield(metric) end resp.data[:next_token] end end end end aws-sdk-v1-1.66.0/lib/aws/cloud_watch/alarm_history_item.rb0000644000004100000410000000306212604445426023615 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class CloudWatch class AlarmHistoryItem # @api private def initialize options @alarm_name = options[:alarm_name] @history_data = options[:history_data] @history_item_type = options[:history_item_type] @history_summary = options[:history_summary] @timestamp = options[:timestamp] end # @return [String] The descriptive name for the alarm. attr_reader :alarm_name # @return [String] Machine-readable data about the alarm in JSON format. attr_reader :history_data alias_method :data, :history_data # @return [String] The type of alarm history item. attr_reader :history_item_type alias_method :type, :history_item_type # @return [String] A human-readable summary of the alarm history. attr_reader :history_summary alias_method :summary, :history_summary # @return [Time] The time stamp for the alarm history item. attr_reader :timestamp end end end aws-sdk-v1-1.66.0/lib/aws/cloud_watch/alarm_collection.rb0000644000004100000410000001062012604445426023227 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class CloudWatch # # AlarmCollection # # Represents alarms for an AWS account. # # ## Getting an alarm by name # # If you know the name of the alarm, you can get a reference using # the {#[]} method. # # cw = AWS::CloudWatch.new # alarm = cw.alarms['alarm-name'] # # ## Enumerating Alarms # # You can enumerate all alarms using each (or any of the # methods defined in {Core::Collection}). # # cw.alarms.each do |alarm| # puts alarm.name # end # # ## Filtering Alarms # # Use one of the filtering methods to reduce the number of alarms # returned. # # cw.alarms.with_name_prefix('some-prefix-').each {|alarm| ... } # class AlarmCollection include Core::Collection::WithLimitAndNextToken def initialize options = {} @filters = options[:filters] || {} super end # @param [String] alarm_name # @return [Alarm] def [] alarm_name Alarm.new(alarm_name, :config => config) end # Creates an alarm and associates it with the specified metric. # # @param [String] alarm_name The descriptive name for the alarm. # This name must be unique within the user's AWS account. # @param [Hash] options # @option options [String,required] :namespace The namespace for the # alarm's associated metric. # @option options [String,required] :metric_name The name for the # alarm's associated metric. # @option options [Array] :dimensions The dimensions for the # alarm's associated metric. Each dimension must specify a # `:name` and a `:value`. # @option (see Alarm#update) # @return [Alarm] def create alarm_name, options = {} options[:alarm_name] = alarm_name client.put_metric_alarm(options) self[alarm_name] end # Delete one or more alarms by name. # # cloud_watch.alarms.delete('alarm1', 'alarm2') # # @param [String,Array] alarm_names # @return [nil] def delete *alarm_names client.delete_alarms(:alarm_names => alarm_names.flatten) nil end # Returns a new collection with the given filter. # @param [String,Symbol] name # @param [String,Integer] value # @return [Alarm] def filter name, value filters = @filters.merge(name.to_s.to_sym => value) AlarmCollection.new(:filters => filters, :config => config) end # @param [String] prefix # @return [MetricAlarmCollection] def with_action_prefix prefix filter(:action_prefix, prefix) end # @param [String] prefix The alarm name prefix. # @return [MetricAlarmCollection] def with_name_prefix prefix filter(:alarm_name_prefix, prefix) end # @param [String,Array] names A list of alarm names to # retrieve information for. # @return [MetricAlarmCollection] def with_name *names filter(:alarm_names, names.flatten) end # @param [String] state The state value to be used in matching alarms. # @return [MetricAlarmCollection] def with_state_value state filter(:state_value, state) end protected def _each_item next_token, limit, options = {}, &block options = @filters.merge(options) options[:next_token] = next_token if next_token options[:max_records] = limit if limit resp = client.describe_alarms(options) resp.data[:metric_alarms].each do |details| alarm = Alarm.new_from( :describe_alarms, details, details[:alarm_name], :config => config) yield(alarm) end resp.data[:next_token] end end end end aws-sdk-v1-1.66.0/lib/aws/cloud_watch/metric_alarm_collection.rb0000644000004100000410000001106012604445426024571 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class CloudWatch # # MetricAlarmCollection # # Represents all alarms for a single metric. # # ## Getting an alarm by name # # If you know the name of the alarm, you can get a reference using # the {#[]} method. # # metric.alarms['alarm-name'] # # ## Enumerating Alarms # # You can enumerate all alarms for a metric using each (or any of the # methods defined in {Core::Collection}). # # metric.alarms.each do |alarm| # puts alarm.name # end # # ## Filtering Alarms # # Use one of the filtering methods to reduce the number of alarms # returned. # # metric.alarms.with_unit('Seconds').each {|alarm| ... } # class MetricAlarmCollection < AlarmCollection include Core::Collection::Simple # @api private def initialize metric, options = {} @metric = metric super(options.merge(:config => metric.config)) end # @return [Metric] attr_reader :metric # @param [String] alarm_name # @return [Alarm] def [] alarm_name options = {} options[:namespace] = metric.namespace options[:metric_name] = metric.name options[:dimensions] = metric.dimensions unless metric.dimensions.empty? options[:config] = config Alarm.new(alarm_name, options) end # Creates an alarm for this metric. # @param (see AlarmCollection#create) # @option (see MetricAlarm#update) # @return (see AlarmCollection#create) def create alarm_name, options = {} options[:namespace] = metric.namespace options[:metric_name] = metric.metric_name options[:dimensions] = metric.dimensions unless metric.dimensions.empty? super(alarm_name, options) end # Returns a new collection that will filter results when enumerated. # # @example Filtering by a 1 hour period # # metric.alarms.filter('period', 3600) # # @example Filtering by statistic # # my_metric = metrics.filter('statistic', 'maximum') # # @example Filtering by a unit # # metrics = metrics.filter('unit', 'Megabits') # # @param [String,Symbol] name # @param [String,Integer] value # @return [MetricAlarmCollection] def filter name, value filters = @filters.merge(name.to_s.to_sym => value) MetricAlarmCollection.new(metric, :filters => filters) end # Returns a new collection that filters alarms by a period. # # metric.alarms.with_period(3600).each {|alarm| ... } # # @param [Integer] period # @return [MetricAlarmCollection] def with_period period filter(:period, period) end # Returns a new collection that filters alarms by a statistic. # # metric.alarms.with_statistic('Average').each {|alarm| ... } # # @param [String] statistic # @return [MetricAlarmCollection] def with_statistic statistic filter(:statistic, statistic) end # Returns a new collection that filters alarms by a unit. # # metric.alarms.with_unit('Percent').each {|alarm| ... } # # @param [String] unit # @return [MetricAlarmCollection] def with_unit unit filter(:unit, unit) end protected def _each_item options = {}, &block options = @filters.merge(options) options[:namespace] = metric.namespace options[:metric_name] = metric.metric_name options[:dimensions] = metric.dimensions unless metric.dimensions.empty? resp = client.describe_alarms_for_metric(options) resp.data[:metric_alarms].each do |details| alarm = Alarm.new_from( :describe_alarms_for_metric, details, details[:alarm_name], :config => config) yield(alarm) end resp.data[:next_token] end end end end aws-sdk-v1-1.66.0/lib/aws/cloud_watch/alarm.rb0000644000004100000410000002252212604445426021020 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class CloudWatch # @attr_reader [String] metric_name # # @attr_reader [String] namespace # # @attr_reader [Array] dimensions # # @attr_reader [Boolean] enabled Indicates whether actions # should be executed during any changes to the alarm's state. # # @attr_reader [Array] alarm_actions The list of actions to execute # when this alarm transitions into an ALARM state from any other # state. # # @attr_reader [String] arn The Amazon Resource Name (ARN) of the alarm. # # @attr_reader [Time] configuration_updated_timestamp # The time stamp of the last update to the alarm configuration. # # @attr_reader [String] description The description for the alarm. # # @attr_reader [String] comparison_operator The arithmetic operation to # use when comparing the specified Statistic and Threshold. The # specified Statistic value is used as the first operand. # # @attr_reader [Integer] evaluation_periods The number of periods over # which data is compared to the specified threshold. # # @attr_reader [Array] insufficient_data_actions The list of # actions to execute when this alarm transitions into an # INSUFFICIENT_DATA state # # @attr_reader [Array] ok_actions The list of actions to execute # when this alarm transitions into an OK state. # # @attr_reader [Integer] period The period in seconds over which the # statistic is applied. # # @attr_reader [String] state_reason A human-readable explanation for # the alarm's state. # # @attr_reader [String] state_reason_data An explanation for the alarm's # state in machine-readable JSON format. # # @attr_reader [Time] state_updated_timestamp When the alarm's state # last updated. # # @attr_reader [String] state_value The state value for the alarm. # # @attr_reader [Float] threshold The value against which the specified # statistic is compared. # # @attr_reader [String] unit The unit of the alarm's associated metric. # class Alarm < Core::Resource # @api private def initialize alarm_name, options = {} @alarm_name = alarm_name super end # @return [String] attr_reader :alarm_name alias_method :name, :alarm_name attribute :namespace, :static => true attribute :metric_name, :static => true attribute :dimensions, :static => true attribute :actions_enabled alias_method :enabled, :actions_enabled alias_method :enabled?, :enabled attribute :alarm_actions alias_method :actions, :alarm_actions attribute :alarm_arn, :static => true alias_method :arn, :alarm_arn attribute :alarm_configuration_updated_timestamp alias_method :configuration_updated_timestamp, :alarm_configuration_updated_timestamp attribute :alarm_description alias_method :description, :alarm_description attribute :comparison_operator attribute :evaluation_periods attribute :insufficient_data_actions attribute :ok_actions attribute :period attribute :state_reason attribute :state_reason_data attribute :state_updated_timestamp attribute :state_value attribute :statistic attribute :threshold attribute :unit populates_from :describe_alarms do |resp| resp.data[:metric_alarms].find{|a| a[:alarm_name] == alarm_name } end populates_from :describe_alarms_for_metric do |resp| resp.data[:metric_alarms].find{|a| a[:alarm_name] == alarm_name } end # @return [Metric] def metric options = {} options[:dimensions] = dimensions unless dimensions.empty? options[:config] = config Metric.new(namespace, metric_name, options) end # Updates the metric alarm. # # @option options [String,required] :comparison_operator The arithmetic # operation to use when comparing the specified Statistic and # Threshold. The specified Statistic value is used as the first # operand. Valid values include: # # * 'GreaterThanOrEqualToThreshold' # * 'GreaterThanThreshold' # * 'LessThanThreshold' # * 'LessThanOrEqualToThreshold' # # @option options [String,required] :namespace The namespace for the # alarm's associated metric. # # @option options [Integer,required] :evaluation_periods The number # of periods over which data is compared to the specified threshold. # # @option options [Integer,required] :period The period in seconds # over which the specified statistic is applied. # # @option options [String,required] :statistic The statistic to apply # to the alarm's associated metric. Valid values include: # # * 'SampleCount' # * 'Average' # * 'Sum' # * 'Minimum' # * 'Maximum' # # @option options [Number,required] :threshold The value against which # the specified statistic is compared. # # @option options [Array] :insufficient_data_actions # The list of actions to execute when this alarm transitions into an # INSUFFICIENT_DATA state from any other state. Each action is # specified as an Amazon Resource Number (ARN). Currently the only # action supported is publishing to an Amazon SNS topic or an # Amazon Auto Scaling policy. # # @option options [Array] :ok_actions The list of actions to # execute when this alarm transitions into an OK state from any # other state. Each action is specified as an Amazon Resource # Number (ARN). Currently the only action supported is publishing to # an Amazon SNS topic or an Amazon Auto Scaling policy. # # @option options [Boolean] :actions_enabled Indicates whether or not # actions should be executed during any changes to the alarm's # state. # # @option options [Array] :alarm_actions The list of actions # to execute when this alarm transitions into an ALARM state from # any other state. Each action is specified as an Amazon Resource # Number (ARN). Currently the only action supported is publishing # to an Amazon SNS topic or an Amazon Auto Scaling policy. # Maximum of 5 alarm actions. # # @option options [String] :alarm_description The description for # the alarm. # # @option options [String] :unit The unit for the alarm's associated # metric. # # @return [nil] def update options = {} options[:alarm_name] = alarm_name client.put_metric_alarm(options) nil end # Deletes the current alarm. # @return [nil] def delete client.delete_alarms(:alarm_names => [ alarm_name ]) nil end # Disable the current alarm actions. # @return [nil] def disable client.disable_alarm_actions(:alarm_names => [ alarm_name ]) nil end # Enable the current alarm actions. # @return [nil] def enable client.enable_alarm_actions(:alarm_names => [ alarm_name ]) nil end # @return [Boolean] Returns true if this alarm exists. def exists? !get_resource.data[:metric_alarms].empty? end # Returns a collection of the history items for current alarm. # @return [AlarmHistoryItemCollection] def history_items options = {} AlarmHistoryItemCollection.new(:config => config).with_alarm_name(name) end alias_method :history, :history_items alias_method :histories, :history_items # Temporarily sets the state of current alarm. # @param [String] reason The reason that this alarm is set to this # specific state (in human-readable text format). # # @param [String] value Valid values include: # # * 'OK' # * 'ALARM' # * 'INSUFFICIENT_DATA' # # @param [Hash] options # @option options [String] :state_reason_data The reason that this # # alarm is set to this specific state (in machine-readable JSON # format) # # @return [nil] def set_state reason, value, options = {} options[:alarm_name] = alarm_name options[:state_reason] = reason options[:state_value] = value client.set_alarm_state(options) nil end protected def resource_identifiers [[:alarm_name, alarm_name]] end def get_resource attr_name = nil client.describe_alarms(:alarm_names => [ alarm_name ]) end end end end aws-sdk-v1-1.66.0/lib/aws/direct_connect/0000755000004100000410000000000012604445426020063 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/direct_connect/errors.rb0000644000004100000410000000127012604445426021724 0ustar www-datawww-data # Copyright 2011-2013 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. module AWS class DirectConnect # @api private module Errors extend Core::LazyErrorClasses end end end aws-sdk-v1-1.66.0/lib/aws/direct_connect/client.rb0000644000004100000410000000164712604445426021676 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class DirectConnect # Client class for AWS Direct Connect. class Client < Core::JSONClient API_VERSION = '2012-10-25' signature_version :Version4, 'directconnect' # @api private CACHEABLE_REQUESTS = Set[] end class Client::V20121025 < Client define_client_methods('2012-10-25') end end end aws-sdk-v1-1.66.0/lib/aws/direct_connect/config.rb0000644000004100000410000000125212604445426021655 0ustar www-datawww-data# Copyright 2011-2013 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. AWS::Core::Configuration.module_eval do add_service 'DirectConnect', 'direct_connect', 'directconnect' end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/0000755000004100000410000000000012604445426017034 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/dynamo_db/expectations.rb0000644000004100000410000000215612604445426022073 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class DynamoDB module Expectations private def expect_conditions(options) expected = {} options[:if].each do |name, value| context = "expected value for attribute #{name}" expected[name.to_s] = { :value => format_attribute_value(value, context) } end if options[:if] [options[:unless_exists]].flatten.each do |name| expected[name.to_s] = { :exists => false } end if options[:unless_exists] expected end end end end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/binary.rb0000644000004100000410000000227012604445426020646 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class DynamoDB # Use this class to wrap strings that you want Amazon DynamoDB # to store as a binary attribute. This can reduce the size # of larger attributes to save on storage costs. # # table = AWS::DynamoDB.new.tables['data-table'] # table.hash_key = { 'id' => :string } # table.range_key = { 'position' => :number } # # # put an item with a binary data attribute # table.items.create( # 'id' => 'abc', # 'position' => 5, # 'data' => AWS::DynamoDB::Binary.new('abc') # ) # class Binary < String; end end end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/client_v2.rb0000644000004100000410000000264012604445426021250 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class DynamoDB # ClientV2 is now deprecated. To use the lastest Amazon DynamoDB # api version, pass the :api_version option to AWS::DynamoDB::Client.new # # AWS::DynamoDB::Client.new(:api_version => '2012-08-10') # #=> # # # # defaults to the oldest api version # AWS::DynamoDB::Client.new # #=> # # # @deprecated class ClientV2 DEPRECATION_MSG = "DEPRECATION WARNING: AWS::DynamoDB::ClientV2 is deprecated, use AWS::DynamoDB::Client.new(:api_version => '2012-08-10')" class << self extend Core::Deprecations def new(options = {}) Client.new(options.merge(:api_version => '2012-08-10')) end deprecated :new, :message => DEPRECATION_MSG end end end end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/errors.rb0000644000004100000410000000123712604445426020700 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class DynamoDB module Errors extend Core::LazyErrorClasses end end end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/item.rb0000644000004100000410000001050512604445426020320 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class DynamoDB # Represents a DynamoDB item. An item is identified by simple or # complex primary key (according to the table schema) and consists # of a collection of attributes. Attributes are name/value pairs # where the value may be a string, number, string set, or number # set. # # Getting an item by hash key value: # # item = table.items['hash-key-value'] # # Getting an item from a table with both hash and range keys: # # item = table.items['hash-key','range-key'] # class Item < Core::Resource extend Types include Keys include Expectations # @return [Table] The table in which the item is stored. attr_reader :table # @return [String, Numeric] The hash key value of the item. attr_reader :hash_value # @return [String, Numeric, nil] The range key value of the # item, or `nil` if the table has a simple primary key. attr_reader :range_value # @api private def initialize(table, *args) opts = args.pop if args.last.kind_of?(Hash) (@hash_value, @range_value) = args @table = table super(table, opts) end # Deletes the item. # # @param [Hash] options Options for deleting the item. # # @option options [Hash] :if Designates a conditional delete. # The operation will fail unless the item exists and has the # attributes in the value for this option. For example: # # # throws DynamoDB::Errors::ConditionalCheckFailedException # # unless the item has "color" set to "red" # item.delete(:if => { :color => "red" }) # # @option options [String, Symbol, Array] :unless_exists A name # or collection of attribute names; if the item has a value # for any of these attributes, this method will raise # `DynamoDB::Errors::ConditionalCheckFailedException`. For # example: # # item.delete(:unless_exists => "version") def delete(options = {}) client_opts = item_key_options(self) expected = expect_conditions(options) client_opts[:expected] = expected unless expected.empty? client_opts[:return_values] = options[:return].to_s.upcase if options[:return] resp = client.delete_item(client_opts) values_from_response_hash(resp.data["Attributes"]) if options[:return] and resp.data["Attributes"] end # @return [Boolean] True if the item exists. def exists?(options = {}) client_opts = item_key_options(self, options) client_opts[:attributes_to_get] = [table.hash_key.name] resp = client.get_item(client_opts) resp.data.key?("Item") end # @return [AttributeCollection] An object representing the # attributes of the item. def attributes AttributeCollection.new(self) end # @api private def self.new_from(op, response_object, table, *args) config = args.last.is_a?(Hash) ? args.last : AWS.config table.assert_schema! hash_value = value_from_response(response_object[table.hash_key.name]) range_value = value_from_response(response_object[table.range_key.name]) if table.range_key raise "missing hash key value in put_item response" unless hash_value raise "missing range key value in put_item response" unless range_value || !table.range_key super(op, response_object, table, hash_value, range_value, *args) end protected def resource_identifiers [[:table_name, table.name], [:hash_value, hash_value], [:range_value, range_value]] end end end end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/types.rb0000644000004100000410000000573012604445426020532 0ustar www-datawww-data# Copyright 2011-2013 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 'bigdecimal' require 'set' require 'base64' module AWS class DynamoDB # @api private module Types def value_from_response(hash, options = {}) (type, value) = hash.to_a.first case type when "S", :s value when "SS", :ss Set[*value] when "N", :n cast_number(value, options) when "NS", :ns Set[*value.map {|v| cast_number(v, options) }] when "B", :b cast_binary(value) when "BS", :bs Set[*value.map{|v| cast_binary(v) }] end end def values_from_response_hash(hash, options = {}) hash.inject({}) do |h, (key, value_hash)| h.update(key => value_from_response(value_hash)) end end def format_attribute_value(value, context = nil) indicator = type_indicator(value, context) value = case when value == :empty_number_set then [] when indicator == :n then value.to_s when indicator == :ns then value.map(&:to_s) else value end { indicator => value } end protected def cast_number number, options = {} cfg = self.respond_to?(:config) ? self.config : (options[:config] || AWS.config) cfg.dynamo_db_big_decimals ? BigDecimal.new(number.to_s) : number.to_f end def cast_binary data DynamoDB::Binary.new(data) end def type_indicator(value, context) case when value.kind_of?(DynamoDB::Binary) then :b when value.respond_to?(:to_str) then :s when value.kind_of?(Numeric) then :n when value.respond_to?(:each) indicator = nil value.each do |v| member_indicator = type_indicator(v, context) raise_error("nested collections", context) if member_indicator.to_s.size > 1 raise_error("mixed types", context) if indicator and member_indicator != indicator indicator = member_indicator end indicator ||= :s :"#{indicator}s" when value == :empty_number_set :ns else raise_error("unsupported attribute type #{value.class}", context) end end def raise_error(msg, context) msg = "#{msg} in #{context}" if context raise ArgumentError, msg end end end end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/table.rb0000644000004100000410000004033612604445426020456 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class DynamoDB # Represents a DynamoDB table. # # ## Working with Tables # # Dynamo DB allows you to organize data into tables. Tables have a # unique name and a key schema. A key schema is comprised of a # hash key and an optional range key. # # Dynamo DB automatically partitions the data contained in a table # across multiple nodes so that the data throughput is not constrained # by the scale of a single box. You can reserve the required throughput # by specifying a number of reads and writes per second to support. # # ## Creating a Table # # To get started you can create a table by supplying a name # and the read/write capacity. A default schema with a hash_key # of :id => :string will be provided. # # dynamo_db = AWS::DynamoDB.new # dynamo_db.tables.create('mytable', 10, 5) # # You can provide your own hash key and optional range key. # # dynamo_db.tables.create('comments', 10, 5, # :hash_key => { :blog_post_id => :number }, # :range_key => { :comment_id => :number } # ) # # ## Provisioning Throughput # # You must specify the desired read and write capacity when # creating a table. After a table is created you can see what has # been provisioned. # # table.read_capacity_units #=> 10 # table.write_capacity_units #=> 5 # # To change these values, call {#provision_throughput}: # # table.provision_throughput :read_capacity_units => 100, :write_capacity_units => 100 # # ## Table Status # # When you create or update a table the changes can take some time to # apply. You can query the status of your table at any time: # # # creating a table can be a *very* slow operation # table = dynamo_db.tables.create('mytable') # sleep 1 while table.status == :creating # table.status #=> :active # # @attr_reader [Time] created_at When the table was first creatd. # # @attr_reader [Symbol] status # # @attr [Integer] read_capacity_units # # @attr [Integer] write_capacity_units # # @attr [Time] throughput_last_increased_at # # @attr [Time] throughput_last_decreased_at # # @attr [Integer] size_bytes # # @attr [Integer] item_count # # @attr [PrimaryKeyElement] hash_key Returns the hash key element # for this table. # # @attr [PrimaryKeyElement,nil] range_key Returns the range key # element for this table, or nil if the table does not have a range # key. # class Table < Resource # @api private def initialize name, options = {} @name = name super end # @return [String] The name of this table. attr_reader :name attribute :creation_date_time, :static => true alias_method :created_at, :creation_date_time attribute :status, :from => 'TableStatus', :to_sym => true attribute :throughput_last_increased_at, :from => 'LastIncreaseDateTime' attribute :throughput_last_decreased_at, :from => 'LastDecreaseDateTime' attribute :read_capacity_units attribute :write_capacity_units attribute :item_count attribute :size_bytes, :from => 'TableSizeBytes' attribute :hash_key, :from => "HashKeyElement", :static => true do translates_output {|v| PrimaryKeyElement.new(v) } end attribute :range_key, :from => "RangeKeyElement", :static => true do translates_output {|v| PrimaryKeyElement.new(v) } end alias_method :range_key_without_schema_override, :range_key populates_from :describe_table do |resp| desc = resp.data['Table'] if desc['TableName'] == name desc. merge(desc['ProvisionedThroughput']). merge(desc['KeySchema'] || {}) end end populates_from :create_table, :delete_table do |resp| desc = resp.data['TableDescription'] if desc['TableName'] == name desc. merge(desc['ProvisionedThroughput']). merge(desc['KeySchema'] || {}) end end # @return [PrimaryKeyElement] def range_key if schema_loaded? static_attributes[:range_key] else range_key_without_schema_override end end # Updates the provisioned throughput for this table. # @param [Hash] options # @option options [Integer] :read_capacity_units The desired read capacity units. # @option options [Integer] :write_capacity_units The desired write capacity units. # @return [Hash] Returns the given `options` hash. def provision_throughput options = {} options[:read_capacity_units] ||= read_capacity_units options[:write_capacity_units] ||= write_capacity_units client_opts = {} client_opts[:table_name] = name client_opts[:provisioned_throughput] = options client.update_table(client_opts) options end # @param [Integer] read_capacity_units def read_capacity_units= read_capacity_units provision_throughput(:read_capacity_units => read_capacity_units) end # @param [Integer] write_capacity_units def write_capacity_units= write_capacity_units provision_throughput(:write_capacity_units => write_capacity_units) end # @return [Boolean] Returns true if the table has a hash key and no # range key. def simple_key? range_key.nil? end # @return [Boolean] Returns true if the table has both a hash key and # a range key. def composite_key? !simple_key? end alias_method :has_range_key?, :composite_key? # @return [Boolean] True if the table's schema information is # loaded into memory. # # @note You must load the the table schema using {#load_schema}, # {#hash_key} or {#range_key} or configure it using # {#hash_key=} and optionally {#range_key=} in order to work # with DynamoDB items. # def schema_loaded? static_attributes.include?(:hash_key) end # Raises an exception unless the table schema is loaded. # # @return [nil] # def assert_schema! raise "table schema not loaded" unless schema_loaded? end # Loads the table's schema information into memory. This method # should not be used in a high-volume code path, and is intended # only as a convenience for exploring the API. In general you # should configure a schema with {#hash_key=} and {#range_key=} # before using the table. # # @note You must load the the table schema using {#load_schema}, # {#hash_key} or {#range_key} or configure it using # {#hash_key=} and optionally {#range_key=} in order to work # with DynamoDB items. # # @return self def load_schema hash_key self end # Configures the hash key element of the table's key schema. # This is the preferred way to load the table schema so that it # can be used to work with DynamoDB items. # # # these are equivalent: # table.hash_key = [:id, :string] # table.hash_key = { :id => :string } # # @note For tables with composite primary keys, you must call # this method first followed by {#range_key=} to configure the # table schema. # # @param description A description of the hash key element. If # this is a hash, it may contain a single mapping; the key is # the name of the hash key attribute and the value is the type # (`:string`, `:number` or `:binary`). If it is an array, the first # element is the name and the second element is the type. # def hash_key= description static_attributes[:hash_key] = PrimaryKeyElement.from_description(description) end # Configures the range key element of the table's key schema. # This is the preferred way to load the table schema so that it # can be used to work with DynamoDB items. This method is only # valid if the table has a composite key schema, and it may only # be called after {#hash_key=} has been used to configure the # hash key element. # # # these are equivalent: # table.range_key = [:id, :string] # table.range_key = { :id => :string } # # @param description A description of the range key element. If # this is a hash, it may contain a single mapping; the key is # the name of the hash key attribute and the value is the type # (`:string`, `:number` or `:binary`). If it is an array, the first # element is the name and the second element is the type. # def range_key= description raise "attempted to set a range key without configuring a hash key first" unless schema_loaded? static_attributes[:range_key] = PrimaryKeyElement.from_description(description) end # Deletes a table and all of its items. The table must be in an # `:active` state (see {#status}). # # @return [nil] # def delete client.delete_table(:table_name => name) nil end # @return [ItemCollection] Returns an object representing all the # items in the table. def items ItemCollection.new(self) end # @return [Boolean] Returns true if the table exists. Note that a table # exists even when it is in a `:deleting` state; this method # only returns false when DynamoDB no longer returns any # information about the table. def exists? get_resource true rescue Errors::ResourceNotFoundException false end # Requets a list of attributes for a list of items in the same table. # # If you want to request a list of attributes for items that span # multiple tables, see {DynamoDB#batch_get}. # # You can call this method in two forms: # # # block form # table.batch_get(:all, items) do |attributes| # # yeilds one hash of attribute names/values for each item # puts attributes.to_yaml # end # # # enumerable return value # attribute_hashes = table.batch_get(:all, items) # attribute_hashes.each do |attributes| # # ... # end # # @note This method does not require the table schema to be loaded. # # ## Attributes # # You can specify the list of attributes to request in 3 ways: # # * The symbol `:all` (to recieve all attributes) # * A single attribute name (e.g. 'size') # * An array of attribute names (e.g. ['size', 'color']) # # A few exmaples: # # # get all attributes # table.batch_get(:all, items) # # # only get the 'color' attribute # table.batch_get('color', items) # # # get 'color' and 'size' attributes # table.batch_get(['color', size'], items) # # ## Items # # You must specify an array of items to fetch attributes for. # The `items` param should always be an array with: # # * String hash key values # * Arrays of string hash key and range key values # * Item objects # # Here are a few examples: # # # items as a list of hash key values # items = %w(hashkey1 hashkey2 hashkey3) # table.batch_get(:all, items) # # # items as a list of hash and range key values # items = [['hashkey1', 'rangekey2'], ['hashkey1', 'rangekey2']] # table.batch_get(:all, items) # # # items as a list of Item objects # items = [] # items << Item.new(table, 'hashkey1') # items << Item.new(table, 'hashkey2') # table.batch_get(:all, items) # # Please note that you must provide both hash and range keys for tables # that include a range key in the schema. # # @param [:all, String, Array] attributes The list of # attributes you want to fetch for each item. `attributes` may be: # # * the symbol `:all` # * a single attribute name string # * an array of attribute name strings # # @param [Mixed] items A list of 2 or more items to fetch attributes # for. You may provide `items` as: # # * an array of hash key value strings # * an array of hash and range key value pairs (nested arrays) # * an array of {Item} objects # # @param [Hash] options # # @option options [Boolean] :consistent_read (false) When `true`, items # are read from this table with consistent reads. When `false`, reads # are eventually consistent. # # @yield [Hash] Yields a hash of attributes for each item. # # @return [Enumerable] Returns an enumerable object that yields # hashes of attributes. # def batch_get attributes, items, options = {}, &block batch = BatchGet.new(:config => config) batch.table(name, attributes, items, options) enum = batch.to_enum(:each_attributes) block_given? ? enum.each(&block) : enum end # Batch puts up to 25 items to this table. # # table.batch_put([ # { :id => 'id1', :color => 'red' }, # { :id => 'id2', :color => 'blue' }, # { :id => 'id3', :color => 'green' }, # ]) # # @param [Array] items A list of item attributes to put. # The hash must contain the table hash key element and range key # element (if one is defined). # # @return (see BatchWrite#process!) # def batch_put items batch = BatchWrite.new(:config => config) batch.put(self, items) batch.process! end # Batch writes up to 25 items to this table. A batch may contain # a mix of items to put and items to delete. # # table.batch_write( # :put => [ # { :id => 'id1', :color => 'red' }, # { :id => 'id2', :color => 'blue' }, # { :id => 'id3', :color => 'green' }, # ], # :delete => ['id4', 'id5'] # ) # # @param [Hash] options # # @option options (BatchWrite#write) # # @return (see BatchWrite#process!) # def batch_write options = {} batch = BatchWrite.new(:config => config) batch.write(self, options) batch.process! end # Delete up to 25 items in a single batch. # # table.batch_delete(%w(id1 id2 id3 id4 id5)) # # @param [Array,Array] items A list of item keys to # delete. For tables without a range key, items should be an array # of hash key strings. # # batch.delete('table-name', ['hk1', 'hk2', 'hk3']) # # For tables with a range key, items should be an array of # hash key and range key pairs. # # batch.delete('table-name', [['hk1', 'rk1'], ['hk1', 'rk2']]) # # @return (see BatchWrite#process!) # def batch_delete items batch = BatchWrite.new(:config => config) batch.delete(self, items) batch.process! end protected def get_resource attribute_name = nil client.describe_table(resource_options) end protected def resource_identifiers [[:table_name, name]] end end end end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/client.rb0000644000004100000410000000744612604445426020652 0ustar www-datawww-data# Copyright 2011-2013 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 'zlib' module AWS class DynamoDB # Builds a client for Amazon DynamoDB. # # ddb = AWS::DynamoDB::Client.new # # ## API Versions # # Amazon DynamoDB has multiple API versions. It is important to know # which API you are using. Each API version accepts different parameters # and returns data in a different format. # # By default, the oldest API version is used. This ensures customers # who started using DynamoDB early would not get broken by API updates. # You can construct a client of a specific version by passing the # `:api_version` option to the {#initialize constructor}. # # # defaults to the 2011-12-05 API version # ddb = AWS::DynamoDB::Client.new # # # specify the API version # ddb = AWS::DynamoDB::Client.new(:api_version => '2011-12-05') # ddb = AWS::DynamoDB::Client.new(:api_version => '2012-08-10') # # You can specify a global default API version using AWS.config: # # AWS.config(:dynamo_db => { :api_version => '2012-08-10' }) # # AWS::DynamoDB::Client.new # #=> AWS::DynamoDB::Client::V20120810 # # @see V20111205 # @see V20120810 # class Client < Core::JSONClient autoload :V20111205, 'aws/dynamo_db/client/v20111205' autoload :V20120810, 'aws/dynamo_db/client/v20120810' API_VERSION = '2011-12-05' signature_version :Version4, 'dynamodb' # @private REGION_US_E1 = 'dynamodb.us-east-1.amazonaws.com' # @private CACHEABLE_REQUESTS = Set[:list_tables, :describe_table] protected def extract_error_details response if response.http_response.status == 413 ['RequestEntityTooLarge', 'Request entity too large'] elsif crc32_is_valid?(response) == false ['CRC32CheckFailed', 'CRC32 integrity check failed'] else super end end def retryable_error? response case response.error when Errors::ProvisionedThroughputExceededException config.dynamo_db_retry_throughput_errors? when Errors::CRC32CheckFailed true else super end end def sleep_durations response retry_count = if expired_credentials?(response) config.max_retries == 0 ? 0 : 1 else config.max_retries { 10 } end # given a retry_count of 10, the sleep durations will look like: # 0, 50, 100, 200, 400, 800, 1600, 3200, 6400, 12800 (milliseconds) (0...retry_count).map do |n| if n == 0 0 else 50 * (2 ** (n - 1)) / 1000.0 end end end private # @return [Boolean] whether the CRC32 response header matches the body. # @return [nil] if no CRC32 header is present or we are not verifying CRC32 def crc32_is_valid? response return nil unless config.dynamo_db_crc32 if crcs = response.http_response.headers['x-amz-crc32'] crcs[0].to_i == calculate_crc32(response) else nil end end def calculate_crc32 response Zlib.crc32(response.http_response.body) end end end end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/client/0000755000004100000410000000000012604445426020312 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/dynamo_db/client/v20120810.rb0000644000004100000410000023251712604445426021734 0ustar www-datawww-data# Copyright 2011-2013 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. class AWS::DynamoDB::Client::V20120810 < AWS::DynamoDB::Client # client methods # # @!method batch_get_item(options = {}) # Calls the BatchGetItem API operation. # @param [Hash] options # # * `:request_items` - *required* - (Hash) A map of one or # more table names and, for each table, the corresponding primary # keys for the items to retrieve. Each table name can be invoked only # once. Each element in the map consists of the following: Keys - An # array of primary key attribute values that define specific items in # the table. AttributesToGet - One or more attributes to be retrieved # from the table or index. By default, all attributes are returned. # If a specified attribute is not found, it does not appear in the # result. ConsistentRead - If `true` , a strongly consistent read is # used; if `false` (the default), an eventually consistent read is # used. # * `:keys` - *required* - (Array>) Represents the # primary key attribute values that define the items and the # attributes associated with the items. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:attributes_to_get` - (Array) Represents one or more # attributes to retrieve from the table or index. If no attribute # names are specified then all attributes will be returned. If any # of the specified attributes are not found, they will not appear # in the result. # * `:consistent_read` - (Boolean) Represents the consistency of a # read operation. If set to `true` , then a strongly consistent # read is used; otherwise, an eventually consistent read is used. # * `:return_consumed_capacity` - (String) Valid values include: # * `TOTAL` # * `NONE` # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `:responses` - (Hash) # * `:member` - (Hash) # * `:s` - (String) # * `:n` - (String) # * `:b` - (String) # * `:ss` - (Array) # * `:ns` - (Array) # * `:bs` - (Array) # * `:unprocessed_keys` - (Hash) # * `:member` - (Hash) # * `:s` - (String) # * `:n` - (String) # * `:b` - (String) # * `:ss` - (Array) # * `:ns` - (Array) # * `:bs` - (Array) # * `:attributes_to_get` - (Array) # * `:consistent_read` - (Boolean) # * `:consumed_capacity` - (Array) # * `:table_name` - (String) # * `:capacity_units` - (Numeric) # @!method batch_write_item(options = {}) # Calls the BatchWriteItem API operation. # @param [Hash] options # # * `:request_items` - *required* - (Hash>) A map of # one or more table names and, for each table, a list of operations # to be performed (DeleteRequest or PutRequest). Each element in the # map consists of the following: DeleteRequest - Perform a DeleteItem # operation on the specified item. The item to be deleted is # identified by a Key subelement: Key - A map of primary key # attribute values that uniquely identify the item. Each entry in # this map consists of an attribute name and an attribute value. # PutRequest - Perform a PutItem operation on the specified item. The # item to be put is identified by an Item subelement: Item - A map of # attributes and their values. Each entry in this map consists of an # attribute name and an attribute value. Attribute values must not be # null; string and binary type attributes must have lengths greater # than zero; and set type attributes must not be empty. Requests that # contain empty values will be rejected with a ValidationException. # If you specify any attributes that are part of an index key, then # the data types for those attributes must match those of the schema # in the table's attribute definition. # * `:put_request` - (Hash) Represents a request to perform a # DeleteItem operation. # * `:item` - *required* - (Hash) A map of attribute # name to attribute values, representing the primary key of an # item to be processed by PutItem. All of the table's primary key # attributes must be specified, and their data types must match # those of the table's key schema. If any attributes are present # in the item which are part of an index key schema for the # table, their types must match the index key schema. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:delete_request` - (Hash) Represents a request to perform a # PutItem operation. # * `:key` - *required* - (Hash) A map of attribute # name to attribute values, representing the primary key of the # item to delete. All of the table's primary key attributes must # be specified, and their data types must match those of the # table's key schema. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:return_consumed_capacity` - (String) Valid values include: # * `TOTAL` # * `NONE` # * `:return_item_collection_metrics` - (String) Valid values include: # * `SIZE` # * `NONE` # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `:unprocessed_items` - (Hash) # * `:value` - (Array) # * `:put_request` - (Hash) # * `:item` - (Hash) # * `:s` - (String) # * `:n` - (String) # * `:b` - (String) # * `:ss` - (Array) # * `:ns` - (Array) # * `:bs` - (Array) # * `:delete_request` - (Hash) # * `:key` - (Hash) # * `:s` - (String) # * `:n` - (String) # * `:b` - (String) # * `:ss` - (Array) # * `:ns` - (Array) # * `:bs` - (Array) # * `:item_collection_metrics` - (Hash) # * `:value` - (Array) # * `:item_collection_key` - (Hash) # * `:s` - (String) # * `:n` - (String) # * `:b` - (String) # * `:ss` - (Array) # * `:ns` - (Array) # * `:bs` - (Array) # * `:size_estimate_range_gb` - (Array) # * `:consumed_capacity` - (Array) # * `:table_name` - (String) # * `:capacity_units` - (Numeric) # @!method create_table(options = {}) # Calls the CreateTable API operation. # @param [Hash] options # # * `:attribute_definitions` - *required* - (Array) An array of # attributes that describe the key schema for the table and indexes. # * `:attribute_name` - *required* - (String) A name for the # attribute. # * `:attribute_type` - *required* - (String) The data type for the # attribute. Valid values include: # * `S` # * `N` # * `B` # * `:table_name` - *required* - (String) The name of the table to # create. # * `:key_schema` - *required* - (Array) Specifies the attributes # that make up the primary key for the table. The attributes in # KeySchema must also be defined in the AttributeDefinitions array. # For more information, see Data Model . Each KeySchemaElement in the # array is composed of: AttributeName - The name of this key # attribute. KeyType - Determines whether the key attribute is HASH # or RANGE. For a primary key that consists of a hash attribute, you # must specify exactly one element with a KeyType of HASH. For a # primary key that consists of hash and range attributes, you must # specify exactly two elements, in this order: The first element must # have a KeyType of HASH, and the second element must have a KeyType # of RANGE. For more information, see Specifying the Primary Key . # * `:attribute_name` - *required* - (String) Represents the name of # a key attribute. # * `:key_type` - *required* - (String) Represents the attribute # data, consisting of the data type and the attribute value itself. # Valid values include: # * `HASH` # * `RANGE` # * `:local_secondary_indexes` - (Array) One or more secondary # indexes (the maximum is five) to be created on the table. Each # index is scoped to a given hash key value. There is a 10 gigabyte # size limit per hash key; otherwise, the size of a local secondary # index is unconstrained. Each secondary index in the array includes # the following: IndexName - The name of the secondary index. Must be # unique only for this table. KeySchema - Specifies the key schema # for the index. The key schema must begin with the same hash key # attribute as the table. # * `:index_name` - *required* - (String) Represents the name of the # secondary index. The name must be unique among all other indexes # on this table. # * `:key_schema` - *required* - (Array) Represents the # complete index key schema, which consists of one or more pairs of # attribute names and key types (HASH or RANGE). # * `:attribute_name` - *required* - (String) Represents the name # of a key attribute. # * `:key_type` - *required* - (String) Represents the attribute # data, consisting of the data type and the attribute value # itself. Valid values include: # * `HASH` # * `RANGE` # * `:projection` - *required* - (Hash) # * `:projection_type` - (String) Represents the set of attributes # that are projected into the index: KEYS_ONLY - Only the index # and primary keys are projected into the index. INCLUDE - Only # the specified table attributes are projected into the index. # The list of projected attributes are in NonKeyAttributes. ALL - # All of the table attributes are projected into the index. Valid # values include: # * `ALL` # * `KEYS_ONLY` # * `INCLUDE` # * `:non_key_attributes` - (Array) Represents the non-key # attribute names which will be projected into the index. The # total count of attributes specified in NonKeyAttributes, summed # across all of the local secondary indexes, must not exceed 20. # If you project the same attribute into two different indexes, # this counts as two distinct attributes when determining the # total. # * `:provisioned_throughput` - *required* - (Hash) # * `:read_capacity_units` - *required* - (Integer) The maximum # number of strongly consistent reads consumed per second before # returns a ThrottlingException. For more information, see # Specifying Read and Write Requirements . # * `:write_capacity_units` - *required* - (Integer) The maximum # number of writes consumed per second before returns a # ThrottlingException. For more information, see Specifying Read # and Write Requirements . # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `:table_description` - (Hash) # * `:attribute_definitions` - (Array) # * `:attribute_name` - (String) # * `:attribute_type` - (String) # * `:table_name` - (String) # * `:key_schema` - (Array) # * `:attribute_name` - (String) # * `:key_type` - (String) # * `:table_status` - (String) # * `:creation_date_time` - (Time) # * `:provisioned_throughput` - (Hash) # * `:last_increase_date_time` - (Time) # * `:last_decrease_date_time` - (Time) # * `:number_of_decreases_today` - (Integer) # * `:read_capacity_units` - (Integer) # * `:write_capacity_units` - (Integer) # * `:table_size_bytes` - (Integer) # * `:item_count` - (Integer) # * `:local_secondary_indexes` - (Array) # * `:index_name` - (String) # * `:key_schema` - (Array) # * `:attribute_name` - (String) # * `:key_type` - (String) # * `:projection` - (Hash) # * `:projection_type` - (String) # * `:non_key_attributes` - (Array) # * `:index_size_bytes` - (Integer) # * `:item_count` - (Integer) # @!method delete_item(options = {}) # Calls the DeleteItem API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table from # which to delete the item. # * `:key` - *required* - (Hash) A map of attribute names # to AttributeValue objects, representing the primary key of the item # to delete. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:expected` - (Hash) A map of attribute/condition # pairs. This is the conditional block for the DeleteItemoperation. # All the conditions must be met for the operation to succeed. # * `:value` - (Hash) Specify whether or not a value already exists # and has a specific content for the attribute name-value pair. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:exists` - (Boolean) Causes to evaluate the value before # attempting a conditional operation: If Exists is `true` , will # check to see if that attribute value already exists in the table. # If it is found, then the operation succeeds. If it is not found, # the operation fails with a ConditionalCheckFailedException. If # Exists is `false` , assumes that the attribute value does not # exist in the table. If in fact the value does not exist, then the # assumption is valid and the operation succeeds. If the value is # found, despite the assumption that it does not exist, the # operation fails with a ConditionalCheckFailedException. The # default setting for Exists is `true` . If you supply a Value all # by itself, assumes the attribute exists: You don't have to set # Exists to `true` , because it is implied. returns a # ValidationException if: Exists is `true` but there is no Value to # check. (You expect a value to exist, but don't specify what that # value is.) Exists is `false` but you also specify a Value. (You # cannot expect an attribute to have a value, while also expecting # it not to exist.) If you specify more than one condition for # Exists, then all of the conditions must evaluate to `true` . (In # other words, the conditions are ANDed together.) Otherwise, the # conditional operation will fail. # * `:return_values` - (String) Use ReturnValues if you want to get the # item attributes as they appeared before they were deleted. For # DeleteItem, the valid values are: NONE - If ReturnValues is not # specified, or if its value is NONE, then nothing is returned. (This # is the default for ReturnValues.) ALL_OLD - The content of the old # item is returned. Valid values include: # * `NONE` # * `ALL_OLD` # * `UPDATED_OLD` # * `ALL_NEW` # * `UPDATED_NEW` # * `:return_consumed_capacity` - (String) Valid values include: # * `TOTAL` # * `NONE` # * `:return_item_collection_metrics` - (String) Valid values include: # * `SIZE` # * `NONE` # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `:attributes` - (Hash) # * `:s` - (String) # * `:n` - (String) # * `:b` - (String) # * `:ss` - (Array) # * `:ns` - (Array) # * `:bs` - (Array) # * `:consumed_capacity` - (Hash) # * `:table_name` - (String) # * `:capacity_units` - (Numeric) # * `:item_collection_metrics` - (Hash) # * `:item_collection_key` - (Hash) # * `:s` - (String) # * `:n` - (String) # * `:b` - (String) # * `:ss` - (Array) # * `:ns` - (Array) # * `:bs` - (Array) # * `:size_estimate_range_gb` - (Array) # @!method delete_table(options = {}) # Calls the DeleteTable API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table to # delete. # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `:table_description` - (Hash) # * `:attribute_definitions` - (Array) # * `:attribute_name` - (String) # * `:attribute_type` - (String) # * `:table_name` - (String) # * `:key_schema` - (Array) # * `:attribute_name` - (String) # * `:key_type` - (String) # * `:table_status` - (String) # * `:creation_date_time` - (Time) # * `:provisioned_throughput` - (Hash) # * `:last_increase_date_time` - (Time) # * `:last_decrease_date_time` - (Time) # * `:number_of_decreases_today` - (Integer) # * `:read_capacity_units` - (Integer) # * `:write_capacity_units` - (Integer) # * `:table_size_bytes` - (Integer) # * `:item_count` - (Integer) # * `:local_secondary_indexes` - (Array) # * `:index_name` - (String) # * `:key_schema` - (Array) # * `:attribute_name` - (String) # * `:key_type` - (String) # * `:projection` - (Hash) # * `:projection_type` - (String) # * `:non_key_attributes` - (Array) # * `:index_size_bytes` - (Integer) # * `:item_count` - (Integer) # @!method describe_table(options = {}) # Calls the DescribeTable API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table to # describe. # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `:table` - (Hash) # * `:attribute_definitions` - (Array) # * `:attribute_name` - (String) # * `:attribute_type` - (String) # * `:table_name` - (String) # * `:key_schema` - (Array) # * `:attribute_name` - (String) # * `:key_type` - (String) # * `:table_status` - (String) # * `:creation_date_time` - (Time) # * `:provisioned_throughput` - (Hash) # * `:last_increase_date_time` - (Time) # * `:last_decrease_date_time` - (Time) # * `:number_of_decreases_today` - (Integer) # * `:read_capacity_units` - (Integer) # * `:write_capacity_units` - (Integer) # * `:table_size_bytes` - (Integer) # * `:item_count` - (Integer) # * `:local_secondary_indexes` - (Array) # * `:index_name` - (String) # * `:key_schema` - (Array) # * `:attribute_name` - (String) # * `:key_type` - (String) # * `:projection` - (Hash) # * `:projection_type` - (String) # * `:non_key_attributes` - (Array) # * `:index_size_bytes` - (Integer) # * `:item_count` - (Integer) # @!method get_item(options = {}) # Calls the GetItem API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table # containing the requested item. # * `:key` - *required* - (Hash) A map of attribute names # to AttributeValue objects, representing the primary key of the item # to retrieve. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:attributes_to_get` - (Array) # * `:consistent_read` - (Boolean) # * `:return_consumed_capacity` - (String) Valid values include: # * `TOTAL` # * `NONE` # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `:item` - (Hash) # * `:s` - (String) # * `:n` - (String) # * `:b` - (String) # * `:ss` - (Array) # * `:ns` - (Array) # * `:bs` - (Array) # * `:consumed_capacity` - (Hash) # * `:table_name` - (String) # * `:capacity_units` - (Numeric) # @!method list_tables(options = {}) # Calls the ListTables API operation. # @param [Hash] options # # * `:exclusive_start_table_name` - (String) The name of the table that # starts the list. If you already ran a ListTables operation and # received a LastEvaluatedTableName value in the response, use that # value here to continue the list. # * `:limit` - (Integer) A maximum number of table names to return. # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `:table_names` - (Array) # * `:last_evaluated_table_name` - (String) # @!method put_item(options = {}) # Calls the PutItem API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table to # contain the item. # * `:item` - *required* - (Hash) A map of attribute # name/value pairs, one for each attribute. Only the primary key # attributes are required; you can optionally provide other attribute # name-value pairs for the item. If you specify any attributes that # are part of an index key, then the data types for those attributes # must match those of the schema in the table's attribute definition. # For more information about primary keys, see Primary Key . Each # element in the Item map is an AttributeValue object. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:expected` - (Hash) A map of attribute/condition # pairs. This is the conditional block for the PutItem operation. All # the conditions must be met for the operation to succeed. # * `:value` - (Hash) Specify whether or not a value already exists # and has a specific content for the attribute name-value pair. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:exists` - (Boolean) Causes to evaluate the value before # attempting a conditional operation: If Exists is `true` , will # check to see if that attribute value already exists in the table. # If it is found, then the operation succeeds. If it is not found, # the operation fails with a ConditionalCheckFailedException. If # Exists is `false` , assumes that the attribute value does not # exist in the table. If in fact the value does not exist, then the # assumption is valid and the operation succeeds. If the value is # found, despite the assumption that it does not exist, the # operation fails with a ConditionalCheckFailedException. The # default setting for Exists is `true` . If you supply a Value all # by itself, assumes the attribute exists: You don't have to set # Exists to `true` , because it is implied. returns a # ValidationException if: Exists is `true` but there is no Value to # check. (You expect a value to exist, but don't specify what that # value is.) Exists is `false` but you also specify a Value. (You # cannot expect an attribute to have a value, while also expecting # it not to exist.) If you specify more than one condition for # Exists, then all of the conditions must evaluate to `true` . (In # other words, the conditions are ANDed together.) Otherwise, the # conditional operation will fail. # * `:return_values` - (String) Use ReturnValues if you want to get the # item attributes as they appeared before they were updated with the # PutItem request. For PutItem, the valid values are: NONE - If # ReturnValues is not specified, or if its value is NONE, then # nothing is returned. (This is the default for ReturnValues.) # ALL_OLD - If PutItem overwrote an attribute name-value pair, then # the content of the old item is returned. Valid values include: # * `NONE` # * `ALL_OLD` # * `UPDATED_OLD` # * `ALL_NEW` # * `UPDATED_NEW` # * `:return_consumed_capacity` - (String) Valid values include: # * `TOTAL` # * `NONE` # * `:return_item_collection_metrics` - (String) Valid values include: # * `SIZE` # * `NONE` # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `:attributes` - (Hash) # * `:s` - (String) # * `:n` - (String) # * `:b` - (String) # * `:ss` - (Array) # * `:ns` - (Array) # * `:bs` - (Array) # * `:consumed_capacity` - (Hash) # * `:table_name` - (String) # * `:capacity_units` - (Numeric) # * `:item_collection_metrics` - (Hash) # * `:item_collection_key` - (Hash) # * `:s` - (String) # * `:n` - (String) # * `:b` - (String) # * `:ss` - (Array) # * `:ns` - (Array) # * `:bs` - (Array) # * `:size_estimate_range_gb` - (Array) # @!method query(options = {}) # Calls the Query API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table # containing the requested items. # * `:index_name` - (String) The name of an index on the table to # query. # * `:select` - (String) The attributes to be returned in the result. # You can retrieve all item attributes, specific item attributes, the # count of matching items, or in the case of an index, some or all of # the attributes projected into the index. ALL_ATTRIBUTES: Returns # all of the item attributes. For a table, this is the default. For # an index, this mode causes to fetch the full item from the table # for each matching item in the index. If the index is configured to # project all item attributes, the matching items will not be fetched # from the table. Fetching items from the table incurs additional # throughput cost and latency. ALL_PROJECTED_ATTRIBUTES: Allowed only # when querying an index. Retrieves all attributes which have been # projected into the index. If the index is configured to project all # attributes, this is equivalent to specifying ALL_ATTRIBUTES. COUNT: # Returns the number of matching items, rather than the matching # items themselves. SPECIFIC_ATTRIBUTES : Returns only the attributes # listed in AttributesToGet. This is equivalent to specifying # AttributesToGet without specifying any value for Select. When # neither Select nor AttributesToGet are specified, defaults to # ALL_ATTRIBUTES when accessing a table, and ALL_PROJECTED_ATTRIBUTES # when accessing an index. You cannot use both Select and # AttributesToGet together in a single request, unless the value for # Select is SPECIFIC_ATTRIBUTES. (This usage is equivalent to # specifying AttributesToGet without any value for Select.) Valid # values include: # * `ALL_ATTRIBUTES` # * `ALL_PROJECTED_ATTRIBUTES` # * `SPECIFIC_ATTRIBUTES` # * `COUNT` # * `:attributes_to_get` - (Array) You cannot use both # AttributesToGet and Select together in a Query request, unless the # value for Select is SPECIFIC_ATTRIBUTES. (This usage is equivalent # to specifying AttributesToGet without any value for Select.) # * `:limit` - (Integer) # * `:consistent_read` - (Boolean) # * `:key_conditions` - (Hash) The selection criteria for # the query. For a query on a table, you can only have conditions on # the table primary key attributes. you must specify the hash key # attribute name and value as an EQ condition. You can optionally # specify a second condition, referring to the range key attribute. # For a query on a secondary index, you can only have conditions on # the index key attributes. You must specify the index hash attribute # name and value as an EQ condition. You can optionally specify a # second condition, referring to the index key range attribute. # Multiple conditions are evaluated using "AND"; in other words, all # of the conditions must be met in order for an item to appear in the # results results. Each KeyConditions element consists of an # attribute name to compare, along with the following: # AttributeValueList - One or more values to evaluate against the # supplied attribute. This list contains exactly one value, except # for a BETWEEN or IN comparison, in which case the list contains two # values. For type Number, value comparisons are numeric. String # value comparisons for greater than, equals, or less than are based # on ASCII character code values. For example, a is greater than A, # and aa is greater than B. For a list of code values, see # http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters. For # Binary, treats each byte of the binary data as unsigned when it # compares binary values, for example when evaluating query # expressions. ComparisonOperator - A comparator for evaluating # attributes. For example, equals, greater than, less than, etc. For # information on specifying data types in JSON, see JSON Data Format # . The following are descriptions of each comparison operator. EQ : # Equal. AttributeValueList can contain only one AttributeValue of # type String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does not # equal {"N":"6"}. Also, {"N":"6"} does not equal {"NS":["6", "2", # "1"]}. LE : Less than or equal. AttributeValueList can contain only # one AttributeValue of type String, Number, or Binary (not a set). # If an item contains an AttributeValue of a different type than the # one specified in the request, the value does not match. For # example, {"S":"6"} does not equal {"N":"6"}. Also, {"N":"6"} does # not compare to {"NS":["6", "2", "1"]}. LT : Less than. # AttributeValueList can contain only one AttributeValue of type # String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does not # equal {"N":"6"}. Also, {"N":"6"} does not compare to {"NS":["6", # "2", "1"]}. GE : Greater than or equal. AttributeValueList can # contain only one AttributeValue of type String, Number, or Binary # (not a set). If an item contains an AttributeValue of a different # type than the one specified in the request, the value does not # match. For example, {"S":"6"} does not equal {"N":"6"}. Also, # {"N":"6"} does not compare to {"NS":["6", "2", "1"]}. GT : Greater # than. AttributeValueList can contain only one AttributeValue of # type String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does not # equal {"N":"6"}. Also, {"N":"6"} does not compare to {"NS":["6", # "2", "1"]}. BEGINS_WITH : checks for a prefix. AttributeValueList # can contain only one AttributeValue of type String or Binary (not a # Number or a set). The target attribute of the comparison must be a # String or Binary (not a Number or a set). BETWEEN : Greater than or # equal to the first value, and less than or equal to the second # value. AttributeValueList must contain two AttributeValue elements # of the same type, either String, Number, or Binary (not a set). A # target attribute matches if the target value is greater than, or # equal to, the first element and less than, or equal to, the second # element. If an item contains an AttributeValue of a different type # than the one specified in the request, the value does not match. # For example, {"S":"6"} does not compare to {"N":"6"}. Also, # {"N":"6"} does not compare to {"NS":["6", "2", "1"]} # * `:attribute_value_list` - (Array) Represents one or more # values to evaluate against the supplied attribute. This list # contains exactly one value, except for a BETWEEN or IN # comparison, in which case the list contains two values. For type # Number, value comparisons are numeric. String value comparisons # for greater than, equals, or less than are based on ASCII # character code values. For example, a is greater than A, and aa # is greater than B. For a list of code values, see # http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters. # For Binary, treats each byte of the binary data as unsigned when # it compares binary values, for example when evaluating query # expressions. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:comparison_operator` - *required* - (String) Represents a # comparator for evaluating attributes. For example, equals, # greater than, less than, etc. For information on specifying data # types in JSON, see JSON Data Format . The following are # descriptions of each comparison operator. EQ : Equal. # AttributeValueList can contain only one AttributeValue of type # String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does # not equal {"N":"6"}. Also, {"N":"6"} does not equal {"NS":["6", # "2", "1"]}. NE : Not equal. AttributeValueList can contain only # one AttributeValue of type String, Number, or Binary (not a set). # If an item contains an AttributeValue of a different type than # the one specified in the request, the value does not match. For # example, {"S":"6"} does not equal {"N":"6"}. Also, {"N":"6"} does # not equal {"NS":["6", "2", "1"]}. LE : Less than or equal. # AttributeValueList can contain only one AttributeValue of type # String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does # not equal {"N":"6"}. Also, {"N":"6"} does not compare to # {"NS":["6", "2", "1"]}. LT : Less than. AttributeValueList can # contain only one AttributeValue of type String, Number, or Binary # (not a set). If an item contains an AttributeValue of a different # type than the one specified in the request, the value does not # match. For example, {"S":"6"} does not equal {"N":"6"}. Also, # {"N":"6"} does not compare to {"NS":["6", "2", "1"]}. GE : # Greater than or equal. AttributeValueList can contain only one # AttributeValue of type String, Number, or Binary (not a set). If # an item contains an AttributeValue of a different type than the # one specified in the request, the value does not match. For # example, {"S":"6"} does not equal {"N":"6"}. Also, {"N":"6"} does # not compare to {"NS":["6", "2", "1"]}. GT : Greater than. # AttributeValueList can contain only one AttributeValue of type # String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does # not equal {"N":"6"}. Also, {"N":"6"} does not compare to # {"NS":["6", "2", "1"]}. NOT_NULL : The attribute exists. NULL : # The attribute does not exist. CONTAINS : checks for a # subsequence, or value in a set. AttributeValueList can contain # only one AttributeValue of type String, Number, or Binary (not a # set). If the target attribute of the comparison is a String, then # the operation checks for a substring match. If the target # attribute of the comparison is Binary, then the operation looks # for a subsequence of the target that matches the input. If the # target attribute of the comparison is a set ("SS", "NS", or # "BS"), then the operation checks for a member of the set (not as # a substring). NOT_CONTAINS : checks for absence of a subsequence, # or absence of a value in a set. AttributeValueList can contain # only one AttributeValue of type String, Number, or Binary (not a # set). If the target attribute of the comparison is a String, then # the operation checks for the absence of a substring match. If the # target attribute of the comparison is Binary, then the operation # checks for the absence of a subsequence of the target that # matches the input. If the target attribute of the comparison is a # set ("SS", "NS", or "BS"), then the operation checks for the # absence of a member of the set (not as a substring). BEGINS_WITH # : checks for a prefix. AttributeValueList can contain only one # AttributeValue of type String or Binary (not a Number or a set). # The target attribute of the comparison must be a String or Binary # (not a Number or a set). IN : checks for exact matches. # AttributeValueList can contain more than one AttributeValue of # type String, Number, or Binary (not a set). The target attribute # of the comparison must be of the same type and exact value to # match. A String never matches a String set. BETWEEN : Greater # than or equal to the first value, and less than or equal to the # second value. AttributeValueList must contain two AttributeValue # elements of the same type, either String, Number, or Binary (not # a set). A target attribute matches if the target value is greater # than, or equal to, the first element and less than, or equal to, # the second element. If an item contains an AttributeValue of a # different type than the one specified in the request, the value # does not match. For example, {"S":"6"} does not compare to # {"N":"6"}. Also, {"N":"6"} does not compare to {"NS":["6", "2", # "1"]} Valid values include: # * `EQ` # * `NE` # * `IN` # * `LE` # * `LT` # * `GE` # * `GT` # * `BETWEEN` # * `NOT_NULL` # * `NULL` # * `CONTAINS` # * `NOT_CONTAINS` # * `BEGINS_WITH` # * `:scan_index_forward` - (Boolean) Specifies ascending ( `true` ) or # descending ( `false` ) traversal of the index. returns results # reflecting the requested order determined by the range key. If the # data type is Number, the results are returned in numeric order. For # String, the results are returned in order of ASCII character code # values. For Binary, Amazon DynamoDB treats each byte of the binary # data as unsigned when it compares binary values. If # ScanIndexForward is not specified, the results are returned in # ascending order. # * `:exclusive_start_key` - (Hash) # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:return_consumed_capacity` - (String) Valid values include: # * `TOTAL` # * `NONE` # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `:member` - (Hash) # * `:s` - (String) # * `:n` - (String) # * `:b` - (String) # * `:ss` - (Array) # * `:ns` - (Array) # * `:bs` - (Array) # * `:count` - (Integer) # * `:last_evaluated_key` - (Hash) # * `:s` - (String) # * `:n` - (String) # * `:b` - (String) # * `:ss` - (Array) # * `:ns` - (Array) # * `:bs` - (Array) # * `:consumed_capacity` - (Hash) # * `:table_name` - (String) # * `:capacity_units` - (Numeric) # @!method scan(options = {}) # Calls the Scan API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table # containing the requested items. # * `:attributes_to_get` - (Array) # * `:limit` - (Integer) # * `:select` - (String) The attributes to be returned in the result. # You can retrieve all item attributes, specific item attributes, the # count of matching items, or in the case of an index, some or all of # the attributes projected into the index. ALL_ATTRIBUTES: Returns # all of the item attributes. For a table, this is the default. For # an index, this mode causes to fetch the full item from the table # for each matching item in the index. If the index is configured to # project all item attributes, the matching items will not be fetched # from the table. Fetching items from the table incurs additional # throughput cost and latency. ALL_PROJECTED_ATTRIBUTES: Retrieves # all attributes which have been projected into the index. If the # index is configured to project all attributes, this is equivalent # to specifying ALL_ATTRIBUTES. COUNT: Returns the number of matching # items, rather than the matching items themselves. # SPECIFIC_ATTRIBUTES : Returns only the attributes listed in # AttributesToGet. This is equivalent to specifying AttributesToGet # without specifying any value for Select. When neither Select nor # AttributesToGet are specified, defaults to ALL_ATTRIBUTES when # accessing a table, and ALL_PROJECTED_ATTRIBUTES when accessing an # index. You cannot use both Select and AttributesToGet together in a # single request, unless the value for Select is SPECIFIC_ATTRIBUTES. # (This usage is equivalent to specifying AttributesToGet without any # value for Select.) Valid values include: # * `ALL_ATTRIBUTES` # * `ALL_PROJECTED_ATTRIBUTES` # * `SPECIFIC_ATTRIBUTES` # * `COUNT` # * `:scan_filter` - (Hash) Evaluates the scan results and # returns only the desired values. Multiple conditions are treated as # "AND" operations: all conditions must be met to be included in the # results. Each ScanConditions element consists of an attribute name # to compare, along with the following: AttributeValueList - One or # more values to evaluate against the supplied attribute. This list # contains exactly one value, except for a BETWEEN or IN comparison, # in which case the list contains two values. For type Number, value # comparisons are numeric. String value comparisons for greater than, # equals, or less than are based on ASCII character code values. For # example, a is greater than A, and aa is greater than B. For a list # of code values, see # http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters. For # Binary, treats each byte of the binary data as unsigned when it # compares binary values, for example when evaluating query # expressions. ComparisonOperator - A comparator for evaluating # attributes. For example, equals, greater than, less than, etc. For # information on specifying data types in JSON, see JSON Data Format # . The following are descriptions of each comparison operator. EQ : # Equal. AttributeValueList can contain only one AttributeValue of # type String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does not # equal {"N":"6"}. Also, {"N":"6"} does not equal {"NS":["6", "2", # "1"]}. NE : Not equal. AttributeValueList can contain only one # AttributeValue of type String, Number, or Binary (not a set). If an # item contains an AttributeValue of a different type than the one # specified in the request, the value does not match. For example, # {"S":"6"} does not equal {"N":"6"}. Also, {"N":"6"} does not equal # {"NS":["6", "2", "1"]}. LE : Less than or equal. AttributeValueList # can contain only one AttributeValue of type String, Number, or # Binary (not a set). If an item contains an AttributeValue of a # different type than the one specified in the request, the value # does not match. For example, {"S":"6"} does not equal {"N":"6"}. # Also, {"N":"6"} does not compare to {"NS":["6", "2", "1"]}. LT : # Less than. AttributeValueList can contain only one AttributeValue # of type String, Number, or Binary (not a set). If an item contains # an AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does not # equal {"N":"6"}. Also, {"N":"6"} does not compare to {"NS":["6", # "2", "1"]}. GE : Greater than or equal. AttributeValueList can # contain only one AttributeValue of type String, Number, or Binary # (not a set). If an item contains an AttributeValue of a different # type than the one specified in the request, the value does not # match. For example, {"S":"6"} does not equal {"N":"6"}. Also, # {"N":"6"} does not compare to {"NS":["6", "2", "1"]}. GT : Greater # than. AttributeValueList can contain only one AttributeValue of # type String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does not # equal {"N":"6"}. Also, {"N":"6"} does not compare to {"NS":["6", # "2", "1"]}. NOT_NULL : The attribute exists. NULL : The attribute # does not exist. CONTAINS : checks for a subsequence, or value in a # set. AttributeValueList can contain only one AttributeValue of type # String, Number, or Binary (not a set). If the target attribute of # the comparison is a String, then the operation checks for a # substring match. If the target attribute of the comparison is # Binary, then the operation looks for a subsequence of the target # that matches the input. If the target attribute of the comparison # is a set ("SS", "NS", or "BS"), then the operation checks for a # member of the set (not as a substring). NOT_CONTAINS : checks for # absence of a subsequence, or absence of a value in a set. # AttributeValueList can contain only one AttributeValue of type # String, Number, or Binary (not a set). If the target attribute of # the comparison is a String, then the operation checks for the # absence of a substring match. If the target attribute of the # comparison is Binary, then the operation checks for the absence of # a subsequence of the target that matches the input. If the target # attribute of the comparison is a set ("SS", "NS", or "BS"), then # the operation checks for the absence of a member of the set (not as # a substring). BEGINS_WITH : checks for a prefix. AttributeValueList # can contain only one AttributeValue of type String or Binary (not a # Number or a set). The target attribute of the comparison must be a # String or Binary (not a Number or a set). IN : checks for exact # matches. AttributeValueList can contain more than one # AttributeValue of type String, Number, or Binary (not a set). The # target attribute of the comparison must be of the same type and # exact value to match. A String never matches a String set. BETWEEN # : Greater than or equal to the first value, and less than or equal # to the second value. AttributeValueList must contain two # AttributeValue elements of the same type, either String, Number, or # Binary (not a set). A target attribute matches if the target value # is greater than, or equal to, the first element and less than, or # equal to, the second element. If an item contains an AttributeValue # of a different type than the one specified in the request, the # value does not match. For example, {"S":"6"} does not compare to # {"N":"6"}. Also, {"N":"6"} does not compare to {"NS":["6", "2", # "1"]} # * `:attribute_value_list` - (Array) Represents one or more # values to evaluate against the supplied attribute. This list # contains exactly one value, except for a BETWEEN or IN # comparison, in which case the list contains two values. For type # Number, value comparisons are numeric. String value comparisons # for greater than, equals, or less than are based on ASCII # character code values. For example, a is greater than A, and aa # is greater than B. For a list of code values, see # http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters. # For Binary, treats each byte of the binary data as unsigned when # it compares binary values, for example when evaluating query # expressions. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:comparison_operator` - *required* - (String) Represents a # comparator for evaluating attributes. For example, equals, # greater than, less than, etc. For information on specifying data # types in JSON, see JSON Data Format . The following are # descriptions of each comparison operator. EQ : Equal. # AttributeValueList can contain only one AttributeValue of type # String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does # not equal {"N":"6"}. Also, {"N":"6"} does not equal {"NS":["6", # "2", "1"]}. NE : Not equal. AttributeValueList can contain only # one AttributeValue of type String, Number, or Binary (not a set). # If an item contains an AttributeValue of a different type than # the one specified in the request, the value does not match. For # example, {"S":"6"} does not equal {"N":"6"}. Also, {"N":"6"} does # not equal {"NS":["6", "2", "1"]}. LE : Less than or equal. # AttributeValueList can contain only one AttributeValue of type # String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does # not equal {"N":"6"}. Also, {"N":"6"} does not compare to # {"NS":["6", "2", "1"]}. LT : Less than. AttributeValueList can # contain only one AttributeValue of type String, Number, or Binary # (not a set). If an item contains an AttributeValue of a different # type than the one specified in the request, the value does not # match. For example, {"S":"6"} does not equal {"N":"6"}. Also, # {"N":"6"} does not compare to {"NS":["6", "2", "1"]}. GE : # Greater than or equal. AttributeValueList can contain only one # AttributeValue of type String, Number, or Binary (not a set). If # an item contains an AttributeValue of a different type than the # one specified in the request, the value does not match. For # example, {"S":"6"} does not equal {"N":"6"}. Also, {"N":"6"} does # not compare to {"NS":["6", "2", "1"]}. GT : Greater than. # AttributeValueList can contain only one AttributeValue of type # String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does # not equal {"N":"6"}. Also, {"N":"6"} does not compare to # {"NS":["6", "2", "1"]}. NOT_NULL : The attribute exists. NULL : # The attribute does not exist. CONTAINS : checks for a # subsequence, or value in a set. AttributeValueList can contain # only one AttributeValue of type String, Number, or Binary (not a # set). If the target attribute of the comparison is a String, then # the operation checks for a substring match. If the target # attribute of the comparison is Binary, then the operation looks # for a subsequence of the target that matches the input. If the # target attribute of the comparison is a set ("SS", "NS", or # "BS"), then the operation checks for a member of the set (not as # a substring). NOT_CONTAINS : checks for absence of a subsequence, # or absence of a value in a set. AttributeValueList can contain # only one AttributeValue of type String, Number, or Binary (not a # set). If the target attribute of the comparison is a String, then # the operation checks for the absence of a substring match. If the # target attribute of the comparison is Binary, then the operation # checks for the absence of a subsequence of the target that # matches the input. If the target attribute of the comparison is a # set ("SS", "NS", or "BS"), then the operation checks for the # absence of a member of the set (not as a substring). BEGINS_WITH # : checks for a prefix. AttributeValueList can contain only one # AttributeValue of type String or Binary (not a Number or a set). # The target attribute of the comparison must be a String or Binary # (not a Number or a set). IN : checks for exact matches. # AttributeValueList can contain more than one AttributeValue of # type String, Number, or Binary (not a set). The target attribute # of the comparison must be of the same type and exact value to # match. A String never matches a String set. BETWEEN : Greater # than or equal to the first value, and less than or equal to the # second value. AttributeValueList must contain two AttributeValue # elements of the same type, either String, Number, or Binary (not # a set). A target attribute matches if the target value is greater # than, or equal to, the first element and less than, or equal to, # the second element. If an item contains an AttributeValue of a # different type than the one specified in the request, the value # does not match. For example, {"S":"6"} does not compare to # {"N":"6"}. Also, {"N":"6"} does not compare to {"NS":["6", "2", # "1"]} Valid values include: # * `EQ` # * `NE` # * `IN` # * `LE` # * `LT` # * `GE` # * `GT` # * `BETWEEN` # * `NOT_NULL` # * `NULL` # * `CONTAINS` # * `NOT_CONTAINS` # * `BEGINS_WITH` # * `:exclusive_start_key` - (Hash) In a parallel scan, a # Scan request that includes ExclusiveStartKey must specify the same # segment whose previous Scan returned the corresponding value of # LastEvaluatedKey. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:return_consumed_capacity` - (String) Valid values include: # * `TOTAL` # * `NONE` # * `:total_segments` - (Integer) For a parallel Scan request, # TotalSegments represents the total number of segments into which # the Scan operation will be divided. The value of TotalSegments # corresponds to the number of application workers that will perform # the parallel scan. For example, if you want to scan a table using # four application threads, you would specify a TotalSegments value # of 4. The value for TotalSegments must be greater than or equal to # 1, and less than or equal to 4096. If you specify a TotalSegments # value of 1, the Scan will be sequential rather than parallel. If # you specify TotalSegments, you must also specify Segment. # * `:segment` - (Integer) For a parallel Scan request, Segment # identifies an individual segment to be scanned by an application # worker. Segment IDs are zero-based, so the first segment is always # 0. For example, if you want to scan a table using four application # threads, the first thread would specify a Segment value of 0, the # second thread would specify 1, and so on. The value of # LastEvaluatedKey returned from a parallel Scan request must be used # as ExclusiveStartKey with the same Segment ID in a subsequent Scan # operation. The value for Segment must be greater than or equal to # 0, and less than the value provided for TotalSegments. If you # specify Segment, you must also specify TotalSegments. # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `:member` - (Hash) # * `:s` - (String) # * `:n` - (String) # * `:b` - (String) # * `:ss` - (Array) # * `:ns` - (Array) # * `:bs` - (Array) # * `:count` - (Integer) # * `:scanned_count` - (Integer) # * `:last_evaluated_key` - (Hash) # * `:s` - (String) # * `:n` - (String) # * `:b` - (String) # * `:ss` - (Array) # * `:ns` - (Array) # * `:bs` - (Array) # * `:consumed_capacity` - (Hash) # * `:table_name` - (String) # * `:capacity_units` - (Numeric) # @!method update_item(options = {}) # Calls the UpdateItem API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table # containing the item to update. # * `:key` - *required* - (Hash) The primary key that # defines the item. Each element consists of an attribute name and a # value for that attribute. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:attribute_updates` - (Hash) The names of attributes # to be modified, the action to perform on each, and the new value # for each. If you are updating an attribute that is an index key # attribute for any indexes on that table, the attribute type must # match the index key type defined in the AttributesDefinition of the # table description. You can use UpdateItem to update any non-key # attributes. Attribute values cannot be null. String and binary type # attributes must have lengths greater than zero. Set type attributes # must not be empty. Requests with empty values will be rejected with # a ValidationException. Each AttributeUpdates element consists of an # attribute name to modify, along with the following: Value - The new # value, if applicable, for this attribute. Action - Specifies how to # perform the update. Valid values for Action are PUT, DELETE, and # ADD. The behavior depends on whether the specified primary key # already exists in the table. If an item with the specified Key is # found in the table: PUT - Adds the specified attribute to the item. # If the attribute already exists, it is replaced by the new value. # DELETE - If no value is specified, the attribute and its value are # removed from the item. The data type of the specified value must # match the existing value's data type. If a set of values is # specified, then those values are subtracted from the old set. For # example, if the attribute value was the set [a,b,c] and the DELETE # action specified [a,c], then the final attribute value would be # [b]. Specifying an empty set is an error. ADD - If the attribute # does not already exist, then the attribute and its values are added # to the item. If the attribute does exist, then the behavior of ADD # depends on the data type of the attribute: If the existing # attribute is a number, and if Value is also a number, then the # Value is mathematically added to the existing attribute. If Value # is a negative number, then it is subtracted from the existing # attribute. If you use ADD to increment or decrement a number value # for an item that doesn't exist before the update, uses 0 as the # initial value. In addition, if you use ADD to update an existing # item, and intend to increment or decrement an attribute value which # does not yet exist, uses 0 as the initial value. For example, # suppose that the item you want to update does not yet have an # attribute named itemcount, but you decide to ADD the number 3 to # this attribute anyway, even though it currently does not exist. # will create the itemcount attribute, set its initial value to 0, # and finally add 3 to it. The result will be a new itemcount # attribute in the item, with a value of 3. If the existing data type # is a set, and if the Value is also a set, then the Value is added # to the existing set. (This is a set operation, not mathematical # addition.) For example, if the attribute value was the set [1,2], # and the ADD action specified [3], then the final attribute value # would be [1,2,3]. An error occurs if an Add action is specified for # a set attribute and the attribute type specified does not match the # existing set type. Both sets must have the same primitive data # type. For example, if the existing data type is a set of strings, # the Value must also be a set of strings. The same holds `true` for # number sets and binary sets. This action is only valid for an # existing attribute whose data type is number or is a set. Do not # use ADD for any other data types. If no item with the specified Key # is found: PUT - creates a new item with the specified primary key, # and then adds the attribute. DELETE - Nothing happens; there is no # attribute to delete. ADD - creates an item with the supplied # primary key and number (or set of numbers) for the attribute value. # The only data types allowed are number and number set; no other # data types can be specified. If you specify any attributes that are # part of an index key, then the data types for those attributes must # match those of the schema in the table's attribute definition. # * `:value` - (Hash) # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:action` - (String) Specifies how to perform the update. Valid # values are PUT, DELETE, and ADD. The behavior depends on whether # the specified primary key already exists in the table. If an item # with the specified Key is found in the table: PUT - Adds the # specified attribute to the item. If the attribute already exists, # it is replaced by the new value. DELETE - If no value is # specified, the attribute and its value are removed from the item. # The data type of the specified value must match the existing # value's data type. If a set of values is specified, then those # values are subtracted from the old set. For example, if the # attribute value was the set [a,b,c] and the DELETE action # specified [a,c], then the final attribute value would be [b]. # Specifying an empty set is an error. ADD - If the attribute does # not already exist, then the attribute and its values are added to # the item. If the attribute does exist, then the behavior of ADD # depends on the data type of the attribute: If the existing # attribute is a number, and if Value is also a number, then the # Value is mathematically added to the existing attribute. If Value # is a negative number, then it is subtracted from the existing # attribute. If you use ADD to increment or decrement a number # value for an item that doesn't exist before the update, uses 0 as # the initial value. In addition, if you use ADD to update an # existing item, and intend to increment or decrement an attribute # value which does not yet exist, uses 0 as the initial value. For # example, suppose that the item you want to update does not yet # have an attribute named itemcount, but you decide to ADD the # number 3 to this attribute anyway, even though it currently does # not exist. will create the itemcount attribute, set its initial # value to 0, and finally add 3 to it. The result will be a new # itemcount attribute in the item, with a value of 3. If the # existing data type is a set, and if the Value is also a set, then # the Value is added to the existing set. (This is a set operation, # not mathematical addition.) For example, if the attribute value # was the set [1,2], and the ADD action specified [3], then the # final attribute value would be [1,2,3]. An error occurs if an Add # action is specified for a set attribute and the attribute type # specified does not match the existing set type. Both sets must # have the same primitive data type. For example, if the existing # data type is a set of strings, the Value must also be a set of # strings. The same holds `true` for number sets and binary sets. # This action is only valid for an existing attribute whose data # type is number or is a set. Do not use ADD for any other data # types. If no item with the specified Key is found: PUT - creates # a new item with the specified primary key, and then adds the # attribute. DELETE - Nothing happens; there is no attribute to # delete. ADD - creates an item with the supplied primary key and # number (or set of numbers) for the attribute value. The only data # types allowed are number and number set; no other data types can # be specified. Valid values include: # * `ADD` # * `PUT` # * `DELETE` # * `:expected` - (Hash) A map of attribute/condition # pairs. This is the conditional block for the UpdateItem operation. # All the conditions must be met for the operation to succeed. # * `:value` - (Hash) Specify whether or not a value already exists # and has a specific content for the attribute name-value pair. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:exists` - (Boolean) Causes to evaluate the value before # attempting a conditional operation: If Exists is `true` , will # check to see if that attribute value already exists in the table. # If it is found, then the operation succeeds. If it is not found, # the operation fails with a ConditionalCheckFailedException. If # Exists is `false` , assumes that the attribute value does not # exist in the table. If in fact the value does not exist, then the # assumption is valid and the operation succeeds. If the value is # found, despite the assumption that it does not exist, the # operation fails with a ConditionalCheckFailedException. The # default setting for Exists is `true` . If you supply a Value all # by itself, assumes the attribute exists: You don't have to set # Exists to `true` , because it is implied. returns a # ValidationException if: Exists is `true` but there is no Value to # check. (You expect a value to exist, but don't specify what that # value is.) Exists is `false` but you also specify a Value. (You # cannot expect an attribute to have a value, while also expecting # it not to exist.) If you specify more than one condition for # Exists, then all of the conditions must evaluate to `true` . (In # other words, the conditions are ANDed together.) Otherwise, the # conditional operation will fail. # * `:return_values` - (String) Use ReturnValues if you want to get the # item attributes as they appeared either before or after they were # updated. For UpdateItem, the valid values are: NONE - If # ReturnValues is not specified, or if its value is NONE, then # nothing is returned. (This is the default for ReturnValues.) # ALL_OLD - If UpdateItem overwrote an attribute name-value pair, # then the content of the old item is returned. UPDATED_OLD - The old # versions of only the updated attributes are returned. ALL_NEW - All # of the attributes of the new version of the item are returned. # UPDATED_NEW - The new versions of only the updated attributes are # returned. Valid values include: # * `NONE` # * `ALL_OLD` # * `UPDATED_OLD` # * `ALL_NEW` # * `UPDATED_NEW` # * `:return_consumed_capacity` - (String) Valid values include: # * `TOTAL` # * `NONE` # * `:return_item_collection_metrics` - (String) Valid values include: # * `SIZE` # * `NONE` # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `:attributes` - (Hash) # * `:s` - (String) # * `:n` - (String) # * `:b` - (String) # * `:ss` - (Array) # * `:ns` - (Array) # * `:bs` - (Array) # * `:consumed_capacity` - (Hash) # * `:table_name` - (String) # * `:capacity_units` - (Numeric) # * `:item_collection_metrics` - (Hash) # * `:item_collection_key` - (Hash) # * `:s` - (String) # * `:n` - (String) # * `:b` - (String) # * `:ss` - (Array) # * `:ns` - (Array) # * `:bs` - (Array) # * `:size_estimate_range_gb` - (Array) # @!method update_table(options = {}) # Calls the UpdateTable API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table to be # updated. # * `:provisioned_throughput` - *required* - (Hash) # * `:read_capacity_units` - *required* - (Integer) The maximum # number of strongly consistent reads consumed per second before # returns a ThrottlingException. For more information, see # Specifying Read and Write Requirements . # * `:write_capacity_units` - *required* - (Integer) The maximum # number of writes consumed per second before returns a # ThrottlingException. For more information, see Specifying Read # and Write Requirements . # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `:table_description` - (Hash) # * `:attribute_definitions` - (Array) # * `:attribute_name` - (String) # * `:attribute_type` - (String) # * `:table_name` - (String) # * `:key_schema` - (Array) # * `:attribute_name` - (String) # * `:key_type` - (String) # * `:table_status` - (String) # * `:creation_date_time` - (Time) # * `:provisioned_throughput` - (Hash) # * `:last_increase_date_time` - (Time) # * `:last_decrease_date_time` - (Time) # * `:number_of_decreases_today` - (Integer) # * `:read_capacity_units` - (Integer) # * `:write_capacity_units` - (Integer) # * `:table_size_bytes` - (Integer) # * `:item_count` - (Integer) # * `:local_secondary_indexes` - (Array) # * `:index_name` - (String) # * `:key_schema` - (Array) # * `:attribute_name` - (String) # * `:key_type` - (String) # * `:projection` - (Hash) # * `:projection_type` - (String) # * `:non_key_attributes` - (Array) # * `:index_size_bytes` - (Integer) # * `:item_count` - (Integer) # end client methods # define_client_methods('2012-08-10') end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/client/v20111205.rb0000644000004100000410000021347212604445426021731 0ustar www-datawww-data# Copyright 2011-2013 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. class AWS::DynamoDB::Client::V20111205 < AWS::DynamoDB::Client # client methods # # @!method batch_get_item(options = {}) # Calls the BatchGetItem API operation. # @param [Hash] options # # * `:request_items` - *required* - (Hash) A map of one or # more table names and, for each table, the corresponding primary # keys for the items to retrieve. Each table name can be invoked only # once. Each element in the map consists of the following: Keys - An # array of primary key attribute values that define specific items in # the table. AttributesToGet - One or more attributes to be retrieved # from the table or index. By default, all attributes are returned. # If a specified attribute is not found, it does not appear in the # result. ConsistentRead - If `true` , a strongly consistent read is # used; if `false` (the default), an eventually consistent read is # used. # * `:keys` - *required* - (Array) Represents the primary key # attribute values that define the items and the attributes # associated with the items. # * `:hash_key_element` - *required* - (Hash) A hash key element is # treated as the primary key, and can be a string or a number. # Single attribute primary keys have one index value. The value # can be String, Number, StringSet, NumberSet. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:range_key_element` - (Hash) A range key element is treated as # a secondary key (used in conjunction with the primary key), and # can be a string or a number, and is only used for # hash-and-range primary keys. The value can be String, Number, # StringSet, NumberSet. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:attributes_to_get` - (Array) Represents one or more # attributes to retrieve from the table or index. If no attribute # names are specified then all attributes will be returned. If any # of the specified attributes are not found, they will not appear # in the result. # * `:consistent_read` - (Boolean) Represents the consistency of a # read operation. If set to `true` , then a strongly consistent # read is used; otherwise, an eventually consistent read is used. # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `Responses` - (Hash) # * `member` - (Hash) # * `S` - (String) # * `N` - (String) # * `B` - (String) # * `SS` - (Array) # * `NS` - (Array) # * `BS` - (Array) # * `ConsumedCapacityUnits` - (Numeric) # * `UnprocessedKeys` - (Hash) # * `Keys` - (Array) # * `HashKeyElement` - (Hash) # * `S` - (String) # * `N` - (String) # * `B` - (String) # * `SS` - (Array) # * `NS` - (Array) # * `BS` - (Array) # * `RangeKeyElement` - (Hash) # * `S` - (String) # * `N` - (String) # * `B` - (String) # * `SS` - (Array) # * `NS` - (Array) # * `BS` - (Array) # * `AttributesToGet` - (Array) # * `ConsistentRead` - (Boolean) # @!method batch_write_item(options = {}) # Calls the BatchWriteItem API operation. # @param [Hash] options # # * `:request_items` - *required* - (Hash>) A map of # one or more table names and, for each table, a list of operations # to be performed (DeleteRequest or PutRequest). Each element in the # map consists of the following: DeleteRequest - Perform a DeleteItem # operation on the specified item. The item to be deleted is # identified by a Key subelement: Key - A map of primary key # attribute values that uniquely identify the item. Each entry in # this map consists of an attribute name and an attribute value. # PutRequest - Perform a PutItem operation on the specified item. The # item to be put is identified by an Item subelement: Item - A map of # attributes and their values. Each entry in this map consists of an # attribute name and an attribute value. Attribute values must not be # null; string and binary type attributes must have lengths greater # than zero; and set type attributes must not be empty. Requests that # contain empty values will be rejected with a ValidationException. # If you specify any attributes that are part of an index key, then # the data types for those attributes must match those of the schema # in the table's attribute definition. # * `:put_request` - (Hash) Represents a request to perform a # DeleteItem operation. # * `:item` - *required* - (Hash) A map of attribute # name to attribute values, representing the primary key of an # item to be processed by PutItem. All of the table's primary key # attributes must be specified, and their data types must match # those of the table's key schema. If any attributes are present # in the item which are part of an index key schema for the # table, their types must match the index key schema. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:delete_request` - (Hash) Represents a request to perform a # PutItem operation. # * `:key` - *required* - (Hash) A map of attribute name to # attribute values, representing the primary key of the item to # delete. All of the table's primary key attributes must be # specified, and their data types must match those of the table's # key schema. # * `:hash_key_element` - *required* - (Hash) A hash key element # is treated as the primary key, and can be a string or a # number. Single attribute primary keys have one index value. # The value can be String, Number, StringSet, NumberSet. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:range_key_element` - (Hash) A range key element is treated # as a secondary key (used in conjunction with the primary # key), and can be a string or a number, and is only used for # hash-and-range primary keys. The value can be String, Number, # StringSet, NumberSet. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `Responses` - (Hash) # * `ConsumedCapacityUnits` - (Numeric) # * `UnprocessedItems` - (Hash) # * `value` - (Array) # * `PutRequest` - (Hash) # * `Item` - (Hash) # * `S` - (String) # * `N` - (String) # * `B` - (String) # * `SS` - (Array) # * `NS` - (Array) # * `BS` - (Array) # * `DeleteRequest` - (Hash) # * `Key` - (Hash) # * `HashKeyElement` - (Hash) # * `S` - (String) # * `N` - (String) # * `B` - (String) # * `SS` - (Array) # * `NS` - (Array) # * `BS` - (Array) # * `RangeKeyElement` - (Hash) # * `S` - (String) # * `N` - (String) # * `B` - (String) # * `SS` - (Array) # * `NS` - (Array) # * `BS` - (Array) # @!method create_table(options = {}) # Calls the CreateTable API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table to # create. # * `:key_schema` - *required* - (Hash) Specifies the attributes that # make up the primary key for the table. The attributes in KeySchema # must also be defined in the AttributeDefinitions array. For more # information, see Data Model . Each KeySchemaElement in the array is # composed of: AttributeName - The name of this key attribute. # KeyType - Determines whether the key attribute is HASH or RANGE. # For a primary key that consists of a hash attribute, you must # specify exactly one element with a KeyType of HASH. For a primary # key that consists of hash and range attributes, you must specify # exactly two elements, in this order: The first element must have a # KeyType of HASH, and the second element must have a KeyType of # RANGE. For more information, see Specifying the Primary Key . # * `:hash_key_element` - *required* - (Hash) A hash key element is # treated as the primary key, and can be a string or a number. # Single attribute primary keys have one index value. The value can # be String, Number, StringSet, NumberSet. # * `:attribute_name` - *required* - (String) Represents the name # of a key attribute. # * `:attribute_type` - *required* - (String) The AttributeType of # the KeySchemaElement which can be a String or a Number. Valid # values include: # * `S` # * `N` # * `B` # * `:range_key_element` - (Hash) A range key element is treated as a # secondary key (used in conjunction with the primary key), and can # be a string or a number, and is only used for hash-and-range # primary keys. The value can be String, Number, StringSet, # NumberSet. # * `:attribute_name` - *required* - (String) Represents the name # of a key attribute. # * `:attribute_type` - *required* - (String) The AttributeType of # the KeySchemaElement which can be a String or a Number. Valid # values include: # * `S` # * `N` # * `B` # * `:provisioned_throughput` - *required* - (Hash) # * `:read_capacity_units` - *required* - (Integer) The maximum # number of strongly consistent reads consumed per second before # returns a ThrottlingException. For more information, see # Specifying Read and Write Requirements . # * `:write_capacity_units` - *required* - (Integer) The maximum # number of writes consumed per second before returns a # ThrottlingException. For more information, see Specifying Read # and Write Requirements . # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `TableDescription` - (Hash) # * `TableName` - (String) # * `KeySchema` - (Hash) # * `HashKeyElement` - (Hash) # * `AttributeName` - (String) # * `AttributeType` - (String) # * `RangeKeyElement` - (Hash) # * `AttributeName` - (String) # * `AttributeType` - (String) # * `TableStatus` - (String) # * `CreationDateTime` - (Time) # * `ProvisionedThroughput` - (Hash) # * `LastIncreaseDateTime` - (Time) # * `LastDecreaseDateTime` - (Time) # * `NumberOfDecreasesToday` - (Integer) # * `ReadCapacityUnits` - (Integer) # * `WriteCapacityUnits` - (Integer) # * `TableSizeBytes` - (Integer) # * `ItemCount` - (Integer) # @!method delete_item(options = {}) # Calls the DeleteItem API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table from # which to delete the item. # * `:key` - *required* - (Hash) A map of attribute names to # AttributeValue objects, representing the primary key of the item to # delete. # * `:hash_key_element` - *required* - (Hash) A hash key element is # treated as the primary key, and can be a string or a number. # Single attribute primary keys have one index value. The value can # be String, Number, StringSet, NumberSet. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:range_key_element` - (Hash) A range key element is treated as a # secondary key (used in conjunction with the primary key), and can # be a string or a number, and is only used for hash-and-range # primary keys. The value can be String, Number, StringSet, # NumberSet. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:expected` - (Hash) A map of attribute/condition # pairs. This is the conditional block for the DeleteItemoperation. # All the conditions must be met for the operation to succeed. # * `:value` - (Hash) Specify whether or not a value already exists # and has a specific content for the attribute name-value pair. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:exists` - (Boolean) Causes to evaluate the value before # attempting a conditional operation: If Exists is `true` , will # check to see if that attribute value already exists in the table. # If it is found, then the operation succeeds. If it is not found, # the operation fails with a ConditionalCheckFailedException. If # Exists is `false` , assumes that the attribute value does not # exist in the table. If in fact the value does not exist, then the # assumption is valid and the operation succeeds. If the value is # found, despite the assumption that it does not exist, the # operation fails with a ConditionalCheckFailedException. The # default setting for Exists is `true` . If you supply a Value all # by itself, assumes the attribute exists: You don't have to set # Exists to `true` , because it is implied. returns a # ValidationException if: Exists is `true` but there is no Value to # check. (You expect a value to exist, but don't specify what that # value is.) Exists is `false` but you also specify a Value. (You # cannot expect an attribute to have a value, while also expecting # it not to exist.) If you specify more than one condition for # Exists, then all of the conditions must evaluate to `true` . (In # other words, the conditions are ANDed together.) Otherwise, the # conditional operation will fail. # * `:return_values` - (String) Use ReturnValues if you want to get the # item attributes as they appeared before they were deleted. For # DeleteItem, the valid values are: NONE - If ReturnValues is not # specified, or if its value is NONE, then nothing is returned. (This # is the default for ReturnValues.) ALL_OLD - The content of the old # item is returned. Valid values include: # * `NONE` # * `ALL_OLD` # * `UPDATED_OLD` # * `ALL_NEW` # * `UPDATED_NEW` # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `Attributes` - (Hash) # * `S` - (String) # * `N` - (String) # * `B` - (String) # * `SS` - (Array) # * `NS` - (Array) # * `BS` - (Array) # * `ConsumedCapacityUnits` - (Numeric) # @!method delete_table(options = {}) # Calls the DeleteTable API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table to # delete. # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `TableDescription` - (Hash) # * `TableName` - (String) # * `KeySchema` - (Hash) # * `HashKeyElement` - (Hash) # * `AttributeName` - (String) # * `AttributeType` - (String) # * `RangeKeyElement` - (Hash) # * `AttributeName` - (String) # * `AttributeType` - (String) # * `TableStatus` - (String) # * `CreationDateTime` - (Time) # * `ProvisionedThroughput` - (Hash) # * `LastIncreaseDateTime` - (Time) # * `LastDecreaseDateTime` - (Time) # * `NumberOfDecreasesToday` - (Integer) # * `ReadCapacityUnits` - (Integer) # * `WriteCapacityUnits` - (Integer) # * `TableSizeBytes` - (Integer) # * `ItemCount` - (Integer) # @!method describe_table(options = {}) # Calls the DescribeTable API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table to # describe. # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `Table` - (Hash) # * `TableName` - (String) # * `KeySchema` - (Hash) # * `HashKeyElement` - (Hash) # * `AttributeName` - (String) # * `AttributeType` - (String) # * `RangeKeyElement` - (Hash) # * `AttributeName` - (String) # * `AttributeType` - (String) # * `TableStatus` - (String) # * `CreationDateTime` - (Time) # * `ProvisionedThroughput` - (Hash) # * `LastIncreaseDateTime` - (Time) # * `LastDecreaseDateTime` - (Time) # * `NumberOfDecreasesToday` - (Integer) # * `ReadCapacityUnits` - (Integer) # * `WriteCapacityUnits` - (Integer) # * `TableSizeBytes` - (Integer) # * `ItemCount` - (Integer) # @!method get_item(options = {}) # Calls the GetItem API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table # containing the requested item. # * `:key` - *required* - (Hash) A map of attribute names to # AttributeValue objects, representing the primary key of the item to # retrieve. # * `:hash_key_element` - *required* - (Hash) A hash key element is # treated as the primary key, and can be a string or a number. # Single attribute primary keys have one index value. The value can # be String, Number, StringSet, NumberSet. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:range_key_element` - (Hash) A range key element is treated as a # secondary key (used in conjunction with the primary key), and can # be a string or a number, and is only used for hash-and-range # primary keys. The value can be String, Number, StringSet, # NumberSet. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:attributes_to_get` - (Array) # * `:consistent_read` - (Boolean) # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `Item` - (Hash) # * `S` - (String) # * `N` - (String) # * `B` - (String) # * `SS` - (Array) # * `NS` - (Array) # * `BS` - (Array) # * `ConsumedCapacityUnits` - (Numeric) # @!method list_tables(options = {}) # Calls the ListTables API operation. # @param [Hash] options # # * `:exclusive_start_table_name` - (String) The name of the table that # starts the list. If you already ran a ListTables operation and # received a LastEvaluatedTableName value in the response, use that # value here to continue the list. # * `:limit` - (Integer) A maximum number of table names to return. # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `TableNames` - (Array) # * `LastEvaluatedTableName` - (String) # @!method put_item(options = {}) # Calls the PutItem API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table to # contain the item. # * `:item` - *required* - (Hash) A map of attribute # name/value pairs, one for each attribute. Only the primary key # attributes are required; you can optionally provide other attribute # name-value pairs for the item. If you specify any attributes that # are part of an index key, then the data types for those attributes # must match those of the schema in the table's attribute definition. # For more information about primary keys, see Primary Key . Each # element in the Item map is an AttributeValue object. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:expected` - (Hash) A map of attribute/condition # pairs. This is the conditional block for the PutItem operation. All # the conditions must be met for the operation to succeed. # * `:value` - (Hash) Specify whether or not a value already exists # and has a specific content for the attribute name-value pair. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:exists` - (Boolean) Causes to evaluate the value before # attempting a conditional operation: If Exists is `true` , will # check to see if that attribute value already exists in the table. # If it is found, then the operation succeeds. If it is not found, # the operation fails with a ConditionalCheckFailedException. If # Exists is `false` , assumes that the attribute value does not # exist in the table. If in fact the value does not exist, then the # assumption is valid and the operation succeeds. If the value is # found, despite the assumption that it does not exist, the # operation fails with a ConditionalCheckFailedException. The # default setting for Exists is `true` . If you supply a Value all # by itself, assumes the attribute exists: You don't have to set # Exists to `true` , because it is implied. returns a # ValidationException if: Exists is `true` but there is no Value to # check. (You expect a value to exist, but don't specify what that # value is.) Exists is `false` but you also specify a Value. (You # cannot expect an attribute to have a value, while also expecting # it not to exist.) If you specify more than one condition for # Exists, then all of the conditions must evaluate to `true` . (In # other words, the conditions are ANDed together.) Otherwise, the # conditional operation will fail. # * `:return_values` - (String) Use ReturnValues if you want to get the # item attributes as they appeared before they were updated with the # PutItem request. For PutItem, the valid values are: NONE - If # ReturnValues is not specified, or if its value is NONE, then # nothing is returned. (This is the default for ReturnValues.) # ALL_OLD - If PutItem overwrote an attribute name-value pair, then # the content of the old item is returned. Valid values include: # * `NONE` # * `ALL_OLD` # * `UPDATED_OLD` # * `ALL_NEW` # * `UPDATED_NEW` # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `Attributes` - (Hash) # * `S` - (String) # * `N` - (String) # * `B` - (String) # * `SS` - (Array) # * `NS` - (Array) # * `BS` - (Array) # * `ConsumedCapacityUnits` - (Numeric) # @!method query(options = {}) # Calls the Query API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table # containing the requested items. # * `:attributes_to_get` - (Array) You cannot use both # AttributesToGet and Select together in a Query request, unless the # value for Select is SPECIFIC_ATTRIBUTES. (This usage is equivalent # to specifying AttributesToGet without any value for Select.) # * `:limit` - (Integer) # * `:consistent_read` - (Boolean) # * `:count` - (Boolean) If set to `true` , Amazon DynamoDB returns a # total number of items that match the query parameters, instead of a # list of the matching items and their attributes. Do not set Count # to `true` while providing a list of AttributesToGet, otherwise # Amazon DynamoDB returns a validation error. # * `:hash_key_value` - *required* - (Hash) Attribute value of the hash # component of the composite primary key. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:range_key_condition` - (Hash) A container for the attribute # values and comparison operators to use for the query. # * `:attribute_value_list` - (Array) Represents one or more # values to evaluate against the supplied attribute. This list # contains exactly one value, except for a BETWEEN or IN # comparison, in which case the list contains two values. For type # Number, value comparisons are numeric. String value comparisons # for greater than, equals, or less than are based on ASCII # character code values. For example, a is greater than A, and aa # is greater than B. For a list of code values, see # http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters. # For Binary, treats each byte of the binary data as unsigned when # it compares binary values, for example when evaluating query # expressions. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:comparison_operator` - *required* - (String) Represents a # comparator for evaluating attributes. For example, equals, # greater than, less than, etc. For information on specifying data # types in JSON, see JSON Data Format . The following are # descriptions of each comparison operator. EQ : Equal. # AttributeValueList can contain only one AttributeValue of type # String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does # not equal {"N":"6"}. Also, {"N":"6"} does not equal {"NS":["6", # "2", "1"]}. NE : Not equal. AttributeValueList can contain only # one AttributeValue of type String, Number, or Binary (not a set). # If an item contains an AttributeValue of a different type than # the one specified in the request, the value does not match. For # example, {"S":"6"} does not equal {"N":"6"}. Also, {"N":"6"} does # not equal {"NS":["6", "2", "1"]}. LE : Less than or equal. # AttributeValueList can contain only one AttributeValue of type # String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does # not equal {"N":"6"}. Also, {"N":"6"} does not compare to # {"NS":["6", "2", "1"]}. LT : Less than. AttributeValueList can # contain only one AttributeValue of type String, Number, or Binary # (not a set). If an item contains an AttributeValue of a different # type than the one specified in the request, the value does not # match. For example, {"S":"6"} does not equal {"N":"6"}. Also, # {"N":"6"} does not compare to {"NS":["6", "2", "1"]}. GE : # Greater than or equal. AttributeValueList can contain only one # AttributeValue of type String, Number, or Binary (not a set). If # an item contains an AttributeValue of a different type than the # one specified in the request, the value does not match. For # example, {"S":"6"} does not equal {"N":"6"}. Also, {"N":"6"} does # not compare to {"NS":["6", "2", "1"]}. GT : Greater than. # AttributeValueList can contain only one AttributeValue of type # String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does # not equal {"N":"6"}. Also, {"N":"6"} does not compare to # {"NS":["6", "2", "1"]}. NOT_NULL : The attribute exists. NULL : # The attribute does not exist. CONTAINS : checks for a # subsequence, or value in a set. AttributeValueList can contain # only one AttributeValue of type String, Number, or Binary (not a # set). If the target attribute of the comparison is a String, then # the operation checks for a substring match. If the target # attribute of the comparison is Binary, then the operation looks # for a subsequence of the target that matches the input. If the # target attribute of the comparison is a set ("SS", "NS", or # "BS"), then the operation checks for a member of the set (not as # a substring). NOT_CONTAINS : checks for absence of a subsequence, # or absence of a value in a set. AttributeValueList can contain # only one AttributeValue of type String, Number, or Binary (not a # set). If the target attribute of the comparison is a String, then # the operation checks for the absence of a substring match. If the # target attribute of the comparison is Binary, then the operation # checks for the absence of a subsequence of the target that # matches the input. If the target attribute of the comparison is a # set ("SS", "NS", or "BS"), then the operation checks for the # absence of a member of the set (not as a substring). BEGINS_WITH # : checks for a prefix. AttributeValueList can contain only one # AttributeValue of type String or Binary (not a Number or a set). # The target attribute of the comparison must be a String or Binary # (not a Number or a set). IN : checks for exact matches. # AttributeValueList can contain more than one AttributeValue of # type String, Number, or Binary (not a set). The target attribute # of the comparison must be of the same type and exact value to # match. A String never matches a String set. BETWEEN : Greater # than or equal to the first value, and less than or equal to the # second value. AttributeValueList must contain two AttributeValue # elements of the same type, either String, Number, or Binary (not # a set). A target attribute matches if the target value is greater # than, or equal to, the first element and less than, or equal to, # the second element. If an item contains an AttributeValue of a # different type than the one specified in the request, the value # does not match. For example, {"S":"6"} does not compare to # {"N":"6"}. Also, {"N":"6"} does not compare to {"NS":["6", "2", # "1"]} Valid values include: # * `EQ` # * `NE` # * `IN` # * `LE` # * `LT` # * `GE` # * `GT` # * `BETWEEN` # * `NOT_NULL` # * `NULL` # * `CONTAINS` # * `NOT_CONTAINS` # * `BEGINS_WITH` # * `:scan_index_forward` - (Boolean) Specifies ascending ( `true` ) or # descending ( `false` ) traversal of the index. returns results # reflecting the requested order determined by the range key. If the # data type is Number, the results are returned in numeric order. For # String, the results are returned in order of ASCII character code # values. For Binary, Amazon DynamoDB treats each byte of the binary # data as unsigned when it compares binary values. If # ScanIndexForward is not specified, the results are returned in # ascending order. # * `:exclusive_start_key` - (Hash) # * `:hash_key_element` - *required* - (Hash) A hash key element is # treated as the primary key, and can be a string or a number. # Single attribute primary keys have one index value. The value can # be String, Number, StringSet, NumberSet. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:range_key_element` - (Hash) A range key element is treated as a # secondary key (used in conjunction with the primary key), and can # be a string or a number, and is only used for hash-and-range # primary keys. The value can be String, Number, StringSet, # NumberSet. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `member` - (Hash) # * `S` - (String) # * `N` - (String) # * `B` - (String) # * `SS` - (Array) # * `NS` - (Array) # * `BS` - (Array) # * `Count` - (Integer) # * `LastEvaluatedKey` - (Hash) # * `HashKeyElement` - (Hash) # * `S` - (String) # * `N` - (String) # * `B` - (String) # * `SS` - (Array) # * `NS` - (Array) # * `BS` - (Array) # * `RangeKeyElement` - (Hash) # * `S` - (String) # * `N` - (String) # * `B` - (String) # * `SS` - (Array) # * `NS` - (Array) # * `BS` - (Array) # * `ConsumedCapacityUnits` - (Numeric) # @!method scan(options = {}) # Calls the Scan API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table # containing the requested items. # * `:attributes_to_get` - (Array) # * `:limit` - (Integer) # * `:count` - (Boolean) If set to `true` , Amazon DynamoDB returns a # total number of items for the Scan operation, even if the operation # has no matching items for the assigned filter. Do not set Count to # `true` while providing a list of AttributesToGet, otherwise Amazon # DynamoDB returns a validation error. # * `:scan_filter` - (Hash) Evaluates the scan results and # returns only the desired values. Multiple conditions are treated as # "AND" operations: all conditions must be met to be included in the # results. Each ScanConditions element consists of an attribute name # to compare, along with the following: AttributeValueList - One or # more values to evaluate against the supplied attribute. This list # contains exactly one value, except for a BETWEEN or IN comparison, # in which case the list contains two values. For type Number, value # comparisons are numeric. String value comparisons for greater than, # equals, or less than are based on ASCII character code values. For # example, a is greater than A, and aa is greater than B. For a list # of code values, see # http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters. For # Binary, treats each byte of the binary data as unsigned when it # compares binary values, for example when evaluating query # expressions. ComparisonOperator - A comparator for evaluating # attributes. For example, equals, greater than, less than, etc. For # information on specifying data types in JSON, see JSON Data Format # . The following are descriptions of each comparison operator. EQ : # Equal. AttributeValueList can contain only one AttributeValue of # type String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does not # equal {"N":"6"}. Also, {"N":"6"} does not equal {"NS":["6", "2", # "1"]}. NE : Not equal. AttributeValueList can contain only one # AttributeValue of type String, Number, or Binary (not a set). If an # item contains an AttributeValue of a different type than the one # specified in the request, the value does not match. For example, # {"S":"6"} does not equal {"N":"6"}. Also, {"N":"6"} does not equal # {"NS":["6", "2", "1"]}. LE : Less than or equal. AttributeValueList # can contain only one AttributeValue of type String, Number, or # Binary (not a set). If an item contains an AttributeValue of a # different type than the one specified in the request, the value # does not match. For example, {"S":"6"} does not equal {"N":"6"}. # Also, {"N":"6"} does not compare to {"NS":["6", "2", "1"]}. LT : # Less than. AttributeValueList can contain only one AttributeValue # of type String, Number, or Binary (not a set). If an item contains # an AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does not # equal {"N":"6"}. Also, {"N":"6"} does not compare to {"NS":["6", # "2", "1"]}. GE : Greater than or equal. AttributeValueList can # contain only one AttributeValue of type String, Number, or Binary # (not a set). If an item contains an AttributeValue of a different # type than the one specified in the request, the value does not # match. For example, {"S":"6"} does not equal {"N":"6"}. Also, # {"N":"6"} does not compare to {"NS":["6", "2", "1"]}. GT : Greater # than. AttributeValueList can contain only one AttributeValue of # type String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does not # equal {"N":"6"}. Also, {"N":"6"} does not compare to {"NS":["6", # "2", "1"]}. NOT_NULL : The attribute exists. NULL : The attribute # does not exist. CONTAINS : checks for a subsequence, or value in a # set. AttributeValueList can contain only one AttributeValue of type # String, Number, or Binary (not a set). If the target attribute of # the comparison is a String, then the operation checks for a # substring match. If the target attribute of the comparison is # Binary, then the operation looks for a subsequence of the target # that matches the input. If the target attribute of the comparison # is a set ("SS", "NS", or "BS"), then the operation checks for a # member of the set (not as a substring). NOT_CONTAINS : checks for # absence of a subsequence, or absence of a value in a set. # AttributeValueList can contain only one AttributeValue of type # String, Number, or Binary (not a set). If the target attribute of # the comparison is a String, then the operation checks for the # absence of a substring match. If the target attribute of the # comparison is Binary, then the operation checks for the absence of # a subsequence of the target that matches the input. If the target # attribute of the comparison is a set ("SS", "NS", or "BS"), then # the operation checks for the absence of a member of the set (not as # a substring). BEGINS_WITH : checks for a prefix. AttributeValueList # can contain only one AttributeValue of type String or Binary (not a # Number or a set). The target attribute of the comparison must be a # String or Binary (not a Number or a set). IN : checks for exact # matches. AttributeValueList can contain more than one # AttributeValue of type String, Number, or Binary (not a set). The # target attribute of the comparison must be of the same type and # exact value to match. A String never matches a String set. BETWEEN # : Greater than or equal to the first value, and less than or equal # to the second value. AttributeValueList must contain two # AttributeValue elements of the same type, either String, Number, or # Binary (not a set). A target attribute matches if the target value # is greater than, or equal to, the first element and less than, or # equal to, the second element. If an item contains an AttributeValue # of a different type than the one specified in the request, the # value does not match. For example, {"S":"6"} does not compare to # {"N":"6"}. Also, {"N":"6"} does not compare to {"NS":["6", "2", # "1"]} # * `:attribute_value_list` - (Array) Represents one or more # values to evaluate against the supplied attribute. This list # contains exactly one value, except for a BETWEEN or IN # comparison, in which case the list contains two values. For type # Number, value comparisons are numeric. String value comparisons # for greater than, equals, or less than are based on ASCII # character code values. For example, a is greater than A, and aa # is greater than B. For a list of code values, see # http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters. # For Binary, treats each byte of the binary data as unsigned when # it compares binary values, for example when evaluating query # expressions. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:comparison_operator` - *required* - (String) Represents a # comparator for evaluating attributes. For example, equals, # greater than, less than, etc. For information on specifying data # types in JSON, see JSON Data Format . The following are # descriptions of each comparison operator. EQ : Equal. # AttributeValueList can contain only one AttributeValue of type # String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does # not equal {"N":"6"}. Also, {"N":"6"} does not equal {"NS":["6", # "2", "1"]}. NE : Not equal. AttributeValueList can contain only # one AttributeValue of type String, Number, or Binary (not a set). # If an item contains an AttributeValue of a different type than # the one specified in the request, the value does not match. For # example, {"S":"6"} does not equal {"N":"6"}. Also, {"N":"6"} does # not equal {"NS":["6", "2", "1"]}. LE : Less than or equal. # AttributeValueList can contain only one AttributeValue of type # String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does # not equal {"N":"6"}. Also, {"N":"6"} does not compare to # {"NS":["6", "2", "1"]}. LT : Less than. AttributeValueList can # contain only one AttributeValue of type String, Number, or Binary # (not a set). If an item contains an AttributeValue of a different # type than the one specified in the request, the value does not # match. For example, {"S":"6"} does not equal {"N":"6"}. Also, # {"N":"6"} does not compare to {"NS":["6", "2", "1"]}. GE : # Greater than or equal. AttributeValueList can contain only one # AttributeValue of type String, Number, or Binary (not a set). If # an item contains an AttributeValue of a different type than the # one specified in the request, the value does not match. For # example, {"S":"6"} does not equal {"N":"6"}. Also, {"N":"6"} does # not compare to {"NS":["6", "2", "1"]}. GT : Greater than. # AttributeValueList can contain only one AttributeValue of type # String, Number, or Binary (not a set). If an item contains an # AttributeValue of a different type than the one specified in the # request, the value does not match. For example, {"S":"6"} does # not equal {"N":"6"}. Also, {"N":"6"} does not compare to # {"NS":["6", "2", "1"]}. NOT_NULL : The attribute exists. NULL : # The attribute does not exist. CONTAINS : checks for a # subsequence, or value in a set. AttributeValueList can contain # only one AttributeValue of type String, Number, or Binary (not a # set). If the target attribute of the comparison is a String, then # the operation checks for a substring match. If the target # attribute of the comparison is Binary, then the operation looks # for a subsequence of the target that matches the input. If the # target attribute of the comparison is a set ("SS", "NS", or # "BS"), then the operation checks for a member of the set (not as # a substring). NOT_CONTAINS : checks for absence of a subsequence, # or absence of a value in a set. AttributeValueList can contain # only one AttributeValue of type String, Number, or Binary (not a # set). If the target attribute of the comparison is a String, then # the operation checks for the absence of a substring match. If the # target attribute of the comparison is Binary, then the operation # checks for the absence of a subsequence of the target that # matches the input. If the target attribute of the comparison is a # set ("SS", "NS", or "BS"), then the operation checks for the # absence of a member of the set (not as a substring). BEGINS_WITH # : checks for a prefix. AttributeValueList can contain only one # AttributeValue of type String or Binary (not a Number or a set). # The target attribute of the comparison must be a String or Binary # (not a Number or a set). IN : checks for exact matches. # AttributeValueList can contain more than one AttributeValue of # type String, Number, or Binary (not a set). The target attribute # of the comparison must be of the same type and exact value to # match. A String never matches a String set. BETWEEN : Greater # than or equal to the first value, and less than or equal to the # second value. AttributeValueList must contain two AttributeValue # elements of the same type, either String, Number, or Binary (not # a set). A target attribute matches if the target value is greater # than, or equal to, the first element and less than, or equal to, # the second element. If an item contains an AttributeValue of a # different type than the one specified in the request, the value # does not match. For example, {"S":"6"} does not compare to # {"N":"6"}. Also, {"N":"6"} does not compare to {"NS":["6", "2", # "1"]} Valid values include: # * `EQ` # * `NE` # * `IN` # * `LE` # * `LT` # * `GE` # * `GT` # * `BETWEEN` # * `NOT_NULL` # * `NULL` # * `CONTAINS` # * `NOT_CONTAINS` # * `BEGINS_WITH` # * `:exclusive_start_key` - (Hash) In a parallel scan, a Scan request # that includes ExclusiveStartKey must specify the same segment whose # previous Scan returned the corresponding value of LastEvaluatedKey. # * `:hash_key_element` - *required* - (Hash) A hash key element is # treated as the primary key, and can be a string or a number. # Single attribute primary keys have one index value. The value can # be String, Number, StringSet, NumberSet. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:range_key_element` - (Hash) A range key element is treated as a # secondary key (used in conjunction with the primary key), and can # be a string or a number, and is only used for hash-and-range # primary keys. The value can be String, Number, StringSet, # NumberSet. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `member` - (Hash) # * `S` - (String) # * `N` - (String) # * `B` - (String) # * `SS` - (Array) # * `NS` - (Array) # * `BS` - (Array) # * `Count` - (Integer) # * `ScannedCount` - (Integer) # * `LastEvaluatedKey` - (Hash) # * `HashKeyElement` - (Hash) # * `S` - (String) # * `N` - (String) # * `B` - (String) # * `SS` - (Array) # * `NS` - (Array) # * `BS` - (Array) # * `RangeKeyElement` - (Hash) # * `S` - (String) # * `N` - (String) # * `B` - (String) # * `SS` - (Array) # * `NS` - (Array) # * `BS` - (Array) # * `ConsumedCapacityUnits` - (Numeric) # @!method update_item(options = {}) # Calls the UpdateItem API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table # containing the item to update. # * `:key` - *required* - (Hash) The primary key that defines the item. # Each element consists of an attribute name and a value for that # attribute. # * `:hash_key_element` - *required* - (Hash) A hash key element is # treated as the primary key, and can be a string or a number. # Single attribute primary keys have one index value. The value can # be String, Number, StringSet, NumberSet. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:range_key_element` - (Hash) A range key element is treated as a # secondary key (used in conjunction with the primary key), and can # be a string or a number, and is only used for hash-and-range # primary keys. The value can be String, Number, StringSet, # NumberSet. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:attribute_updates` - *required* - (Hash) The names # of attributes to be modified, the action to perform on each, and # the new value for each. If you are updating an attribute that is an # index key attribute for any indexes on that table, the attribute # type must match the index key type defined in the # AttributesDefinition of the table description. You can use # UpdateItem to update any non-key attributes. Attribute values # cannot be null. String and binary type attributes must have lengths # greater than zero. Set type attributes must not be empty. Requests # with empty values will be rejected with a ValidationException. Each # AttributeUpdates element consists of an attribute name to modify, # along with the following: Value - The new value, if applicable, for # this attribute. Action - Specifies how to perform the update. Valid # values for Action are PUT, DELETE, and ADD. The behavior depends on # whether the specified primary key already exists in the table. If # an item with the specified Key is found in the table: PUT - Adds # the specified attribute to the item. If the attribute already # exists, it is replaced by the new value. DELETE - If no value is # specified, the attribute and its value are removed from the item. # The data type of the specified value must match the existing # value's data type. If a set of values is specified, then those # values are subtracted from the old set. For example, if the # attribute value was the set [a,b,c] and the DELETE action specified # [a,c], then the final attribute value would be [b]. Specifying an # empty set is an error. ADD - If the attribute does not already # exist, then the attribute and its values are added to the item. If # the attribute does exist, then the behavior of ADD depends on the # data type of the attribute: If the existing attribute is a number, # and if Value is also a number, then the Value is mathematically # added to the existing attribute. If Value is a negative number, # then it is subtracted from the existing attribute. If you use ADD # to increment or decrement a number value for an item that doesn't # exist before the update, uses 0 as the initial value. In addition, # if you use ADD to update an existing item, and intend to increment # or decrement an attribute value which does not yet exist, uses 0 as # the initial value. For example, suppose that the item you want to # update does not yet have an attribute named itemcount, but you # decide to ADD the number 3 to this attribute anyway, even though it # currently does not exist. will create the itemcount attribute, set # its initial value to 0, and finally add 3 to it. The result will be # a new itemcount attribute in the item, with a value of 3. If the # existing data type is a set, and if the Value is also a set, then # the Value is added to the existing set. (This is a set operation, # not mathematical addition.) For example, if the attribute value was # the set [1,2], and the ADD action specified [3], then the final # attribute value would be [1,2,3]. An error occurs if an Add action # is specified for a set attribute and the attribute type specified # does not match the existing set type. Both sets must have the same # primitive data type. For example, if the existing data type is a # set of strings, the Value must also be a set of strings. The same # holds `true` for number sets and binary sets. This action is only # valid for an existing attribute whose data type is number or is a # set. Do not use ADD for any other data types. If no item with the # specified Key is found: PUT - creates a new item with the specified # primary key, and then adds the attribute. DELETE - Nothing happens; # there is no attribute to delete. ADD - creates an item with the # supplied primary key and number (or set of numbers) for the # attribute value. The only data types allowed are number and number # set; no other data types can be specified. If you specify any # attributes that are part of an index key, then the data types for # those attributes must match those of the schema in the table's # attribute definition. # * `:value` - (Hash) # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:action` - (String) Specifies how to perform the update. Valid # values are PUT, DELETE, and ADD. The behavior depends on whether # the specified primary key already exists in the table. If an item # with the specified Key is found in the table: PUT - Adds the # specified attribute to the item. If the attribute already exists, # it is replaced by the new value. DELETE - If no value is # specified, the attribute and its value are removed from the item. # The data type of the specified value must match the existing # value's data type. If a set of values is specified, then those # values are subtracted from the old set. For example, if the # attribute value was the set [a,b,c] and the DELETE action # specified [a,c], then the final attribute value would be [b]. # Specifying an empty set is an error. ADD - If the attribute does # not already exist, then the attribute and its values are added to # the item. If the attribute does exist, then the behavior of ADD # depends on the data type of the attribute: If the existing # attribute is a number, and if Value is also a number, then the # Value is mathematically added to the existing attribute. If Value # is a negative number, then it is subtracted from the existing # attribute. If you use ADD to increment or decrement a number # value for an item that doesn't exist before the update, uses 0 as # the initial value. In addition, if you use ADD to update an # existing item, and intend to increment or decrement an attribute # value which does not yet exist, uses 0 as the initial value. For # example, suppose that the item you want to update does not yet # have an attribute named itemcount, but you decide to ADD the # number 3 to this attribute anyway, even though it currently does # not exist. will create the itemcount attribute, set its initial # value to 0, and finally add 3 to it. The result will be a new # itemcount attribute in the item, with a value of 3. If the # existing data type is a set, and if the Value is also a set, then # the Value is added to the existing set. (This is a set operation, # not mathematical addition.) For example, if the attribute value # was the set [1,2], and the ADD action specified [3], then the # final attribute value would be [1,2,3]. An error occurs if an Add # action is specified for a set attribute and the attribute type # specified does not match the existing set type. Both sets must # have the same primitive data type. For example, if the existing # data type is a set of strings, the Value must also be a set of # strings. The same holds `true` for number sets and binary sets. # This action is only valid for an existing attribute whose data # type is number or is a set. Do not use ADD for any other data # types. If no item with the specified Key is found: PUT - creates # a new item with the specified primary key, and then adds the # attribute. DELETE - Nothing happens; there is no attribute to # delete. ADD - creates an item with the supplied primary key and # number (or set of numbers) for the attribute value. The only data # types allowed are number and number set; no other data types can # be specified. Valid values include: # * `ADD` # * `PUT` # * `DELETE` # * `:expected` - (Hash) A map of attribute/condition # pairs. This is the conditional block for the UpdateItem operation. # All the conditions must be met for the operation to succeed. # * `:value` - (Hash) Specify whether or not a value already exists # and has a specific content for the attribute name-value pair. # * `:s` - (String) Represents a String data type # * `:n` - (String) Represents a Number data type # * `:b` - (String) Represents a Binary data type # * `:ss` - (Array) Represents a String set data type # * `:ns` - (Array) Represents a Number set data type # * `:bs` - (Array) Represents a Binary set data type # * `:exists` - (Boolean) Causes to evaluate the value before # attempting a conditional operation: If Exists is `true` , will # check to see if that attribute value already exists in the table. # If it is found, then the operation succeeds. If it is not found, # the operation fails with a ConditionalCheckFailedException. If # Exists is `false` , assumes that the attribute value does not # exist in the table. If in fact the value does not exist, then the # assumption is valid and the operation succeeds. If the value is # found, despite the assumption that it does not exist, the # operation fails with a ConditionalCheckFailedException. The # default setting for Exists is `true` . If you supply a Value all # by itself, assumes the attribute exists: You don't have to set # Exists to `true` , because it is implied. returns a # ValidationException if: Exists is `true` but there is no Value to # check. (You expect a value to exist, but don't specify what that # value is.) Exists is `false` but you also specify a Value. (You # cannot expect an attribute to have a value, while also expecting # it not to exist.) If you specify more than one condition for # Exists, then all of the conditions must evaluate to `true` . (In # other words, the conditions are ANDed together.) Otherwise, the # conditional operation will fail. # * `:return_values` - (String) Use ReturnValues if you want to get the # item attributes as they appeared either before or after they were # updated. For UpdateItem, the valid values are: NONE - If # ReturnValues is not specified, or if its value is NONE, then # nothing is returned. (This is the default for ReturnValues.) # ALL_OLD - If UpdateItem overwrote an attribute name-value pair, # then the content of the old item is returned. UPDATED_OLD - The old # versions of only the updated attributes are returned. ALL_NEW - All # of the attributes of the new version of the item are returned. # UPDATED_NEW - The new versions of only the updated attributes are # returned. Valid values include: # * `NONE` # * `ALL_OLD` # * `UPDATED_OLD` # * `ALL_NEW` # * `UPDATED_NEW` # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `Attributes` - (Hash) # * `S` - (String) # * `N` - (String) # * `B` - (String) # * `SS` - (Array) # * `NS` - (Array) # * `BS` - (Array) # * `ConsumedCapacityUnits` - (Numeric) # @!method update_table(options = {}) # Calls the UpdateTable API operation. # @param [Hash] options # # * `:table_name` - *required* - (String) The name of the table to be # updated. # * `:provisioned_throughput` - *required* - (Hash) # * `:read_capacity_units` - *required* - (Integer) The maximum # number of strongly consistent reads consumed per second before # returns a ThrottlingException. For more information, see # Specifying Read and Write Requirements . # * `:write_capacity_units` - *required* - (Integer) The maximum # number of writes consumed per second before returns a # ThrottlingException. For more information, see Specifying Read # and Write Requirements . # @return [Core::Response] # The #data method of the response object returns # a hash with the following structure: # # * `TableDescription` - (Hash) # * `TableName` - (String) # * `KeySchema` - (Hash) # * `HashKeyElement` - (Hash) # * `AttributeName` - (String) # * `AttributeType` - (String) # * `RangeKeyElement` - (Hash) # * `AttributeName` - (String) # * `AttributeType` - (String) # * `TableStatus` - (String) # * `CreationDateTime` - (Time) # * `ProvisionedThroughput` - (Hash) # * `LastIncreaseDateTime` - (Time) # * `LastDecreaseDateTime` - (Time) # * `NumberOfDecreasesToday` - (Integer) # * `ReadCapacityUnits` - (Integer) # * `WriteCapacityUnits` - (Integer) # * `TableSizeBytes` - (Integer) # * `ItemCount` - (Integer) # end client methods # define_client_methods('2011-12-05') end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/config.rb0000644000004100000410000000153112604445426020626 0ustar www-datawww-data# Copyright 2011-2013 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. AWS::Core::Configuration.module_eval do add_service 'DynamoDB', 'dynamo_db', 'dynamodb' add_option :dynamo_db_retry_throughput_errors, true, :boolean => true add_option :dynamo_db_big_decimals, true, :boolean => true add_option :dynamo_db_crc32, true, :boolean => true end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/attribute_collection.rb0000644000004100000410000004062012604445426023601 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class DynamoDB # Represents the attributes of a DynamoDB item. An attribute is a # name-value pair. The name must be a string, but the value can be # a string, number, string set, or number set. Attribute values # cannot be null or empty. # # @note The SDK always returns numbers as BigDecimal objects and # sets as Set objects; however, on input it accepts any numeric # type for number attributes and either Arrays or Sets for set # attributes. # # @example Retrieving specific attributes of an item # (title, description) = # item.attributes.values_at(:title, :description) # # @example Retrieving all attributes in hash form # item.attributes.to_hash # # @example Replacing the value of an attribute # item.attributes[:title] = "Automobiles" # # @example Doing a mixed update of item attributes in a single operation # item.attributes.update do |u| # # # add 12 to the (numeric) value of "views" # u.add(:views => 12) # # # delete attributes # u.delete(:foo, :bar) # # # delete values out of a set attribute # u.delete(:colors => ["red", "blue"]) # # # replace values # u.set(:title => "More Automobiles") # end # # @example Returning overwritten values # item.attributes.to_hash # => { "foo" => "bar", # "name" => "fred" } # item.attributes.set( # { "foo" => "baz" }, # :return => :updated_old # ) # => { "foo" => "bar" } # # @example Performing a conditional update # item.set({ :version => 3 }, :if => { :version => 2 }) class AttributeCollection include Core::Model include Enumerable include Types include Keys include Expectations # @return [Item] The item to which these attributes belong. attr_reader :item # @api private def initialize(item, opts = {}) @item = item super end # Behaves like Hash#each; yields each attribute as a name/value # pair. # # attributes.each { |(name, value)| puts "#{name} = #{value}" } # # attributes.each { |name, value| puts "#{name} = #{value}" } # # @param (see #to_hash) # # @option options (see #to_hash) def each(options = {}, &block) to_hash(options).each(&block) end # @yieldparam [String] name Each attribute name. def each_key(options = {}) each(options) { |k, v| yield(k) if block_given? } end # @yieldparam value Each attribute value belonging to the item. # Values will be of type String, BigDecimal, Set or # Set. def each_value(options = {}) each(options) { |k, v| yield(v) if block_given? } end # Retrieves the value of a single attribute. # # @param [String, Symbol] attribute The name of the attribute to # get. # # @return The value of the specified attribute, which may be a # String, BigDecimal, Set or Set. def [] attribute attribute = attribute.to_s response_attributes = get_item(:attributes_to_get => [attribute]) value_from_response(response_attributes[attribute]) end # Replaces the value of a single attribute. # # @param [String, Symbol] attribute The name of the attribute to # replace. # # @param value The new value to set. This may be a String, # Numeric, Set or Array of String objects, or Set or Array of # Numeric objects. Mixed types are not allowed in sets, and # neither String values nor set values may be empty. Setting # an attribute to nil is the same as deleting the attribute. # # @return The new value of the attribute. def []= attribute, value set(attribute => value) value end # Replaces the values of one or more attributes. # # @param [Hash] attributes The attributes to replace. The keys # of the hash may be strings or symbols. The values may be of # type String, Numeric, Set or Array of String objects, or Set # or Array of Numeric objects. Mixed types are not allowed in # sets, and neither String values nor set values may be empty. # Setting an attribute to nil is the same as deleting the # attribute. # # @param [Hash] options Options for updating the item. # # @option options (see #update) def set attributes, options = {} update(options) { |u| u.set(attributes) } end alias_method :merge!, :set alias_method :put, :set # Adds to the values of one or more attributes. Each attribute # must be a set or number in the original item, and each input # value must have the same type as the value in the original # item. For example, it is invalid to add a single number to a # set of numbers, but it is valid to add a set containing a # single number to another set of numbers. # # When the original attribute is a set, the values provided to # this method are added to that set. When the original # attribute is a number, the original value is incremented by # the numeric value provided to this method. For example: # # item = table.items.put( # :id => "abc123", # :colors => ["red", "white"], # :age => 3 # ) # item.attributes.add( # { :colors => ["muave"], # :age => 1 }, # :return => :updated_new # ) # => { "colors" => Set["red", "white", "mauve"], "age" => 4 } # # @param [Hash] attributes The attribute values to add. The # keys of the hash may be strings or symbols. The values may # be of type Numeric, Set or Array of String objects, or Set # or Array of Numeric objects. Mixed types are not allowed in # sets, and neither String values nor set values may be empty. # Single string values are not allowed for this method, since # DynamoDB does not currently support adding a string to # another string. # # @param [Hash] options Options for updating the item. # # @option options (see #update) def add attributes, options = {} update(options) { |u| u.add(attributes) } end # @overload delete *attributes # # Deletes attributes from the item. Each argument must be a # string or symbol specifying the name of the attribute to # delete. The last argument may be a hash containing options # for the update. See {#update} for more information about # what options are accepted. # # @overload delete attributes, options = {} # # Deletes specific values from one or more attributes, whose # original values must be sets. # # @param [Hash] attributes The attribute values to delete. # The keys of the hash may be strings or symbols. The # values must be arrays or Sets of numbers or strings. # Mixed types are not allowed in sets. The type of each # member in a set must match the type of the members in the # original attribute value. # # @param [Hash] options Options for updating the item. # # @option options (see #update) def delete *args if args.first.kind_of?(Hash) delete_args = [args.shift] else delete_args = args end options = args.pop if args.last.kind_of?(Hash) update(options || {}) { |u| u.delete(*delete_args) } end # Used to build a batch of updates to an item's attributes. See # {AttributeCollection#update} for more information. class UpdateBuilder # @api private attr_reader :updates include Types # @api private def initialize @updates = {} end # Replaces the values of one or more attributes. See # {AttributeCollection#set} for more information. def set attributes to_delete = [] attributes = attributes.inject({}) do |attributes, (name, value)| if value == nil to_delete << name else attributes[name] = value end attributes end attribute_updates("PUT", attributes) delete(*to_delete) end alias_method :put, :set alias_method :merge!, :set # Adds to the values of one or more attributes. See # {AttributeCollection#add} for more information. def add attributes attribute_updates("ADD", attributes) end # Deletes one or more attributes or attribute values. See # {AttributeCollection#delete} for more information. def delete *args if args.first.kind_of?(Hash) attribute_updates("DELETE", args.shift, :setify => true) else add_updates(args.inject({}) do |u, name| u.update(name.to_s => { :action => "DELETE" }) end) end end private def attribute_updates(action, attributes, our_opts = {}) new_updates = attributes.inject({}) do |new_updates, (name, value)| name = name.to_s context = "in value for attribute #{name}" value = [value].flatten if our_opts[:setify] new_updates.update(name => { :action => action, :value => format_attribute_value(value, context) }) end add_updates(new_updates) end private def add_updates(new_updates) updates.merge!(new_updates) do |name, old, new| raise ArgumentError, "conflicting updates for attribute #{name}" end end end # Updates multiple attributes in a single operation. This is # more efficient than performing each type of update in # sequence, and it also allows you to group different kinds of # updates into an atomic operation. # # item.attributes.update do |u| # # # add 12 to the (numeric) value of "views" # u.add(:views => 12) # # # delete attributes # u.delete(:foo, :bar) # # # delete values out of a set attribute # u.delete(:colors => ["red", "blue"]) # # # replace values # u.set(:title => "More Automobiles") # end # # @param [Hash] options Options for updating the item. # # @option options [Hash] :if Designates a conditional update. # The operation will fail unless the item exists and has the # attributes in the value for this option. For example: # # # throws DynamoDB::Errors::ConditionalCheckFailedException # # unless the item has "color" set to "red" # item.attributes.update(:if => { :color => "red" }) do |u| # # ... # end # # @option options [String, Symbol, Array] :unless_exists A name # or collection of attribute names; if the item already exists # and has a value for any of these attributes, this method # will raise # `DynamoDB::Errors::ConditionalCheckFailedException`. For example: # # item.attributes.update(:unless_exists => :color) do |u| # # ... # end # # @option options [Symbol] :return (`:none`) Changes the return # value of the method. Valid values: # # * `:none` - Return `nil` # * `:all_old` - Returns a hash containing all of the original # values of the attributes before the update, or # `nil` if the item did not exist at the time of # the update. # * `:updated_old` - Returns a hash containing the original # values of the attributes that were modified # as part of this operation. This includes # attributes that were deleted, and # set-valued attributes whose member values # were deleted. # * `:updated_new` - Returns a hash containing the new values of # the attributes that were modified as part # of this operation. This includes # set-valued attributes whose member values # were deleted. # * `:all_new` - Returns a hash containing the new values of all # of the attributes. # # @yieldparam [UpdateBuilder] builder A handle for describing # the update. # # @note DnamoDB allows only one update per attribute in a # single operation. This method will raise an ArgumentError # if multiple updates are described for a single attribute. # # @return [nil] See the documentation for the `:return` option # above. def update(options = {}) builder = UpdateBuilder.new yield(builder) do_updates({ :attribute_updates => builder.updates }, options) end # Retrieves the values of the specified attributes. # # @param [Array] attributes The names of the # attributes to retrieve. The last argument may be a hash of # options for retrieving attributes from the item. Currently # the only supported option is `:consistent_read`; If set to # true, then a consistent read is issued, otherwise an # eventually consistent read is used. # # @return [Array] An array in which each member contains the # value of the attribute at that index in the argument list. # Values may be Strings, BigDecimals, Sets of Strings or Sets # or BigDecimals. If a requested attribute does not exist, # the corresponding member of the output array will be `nil`. def values_at(*attributes) options = {} options = attributes.pop if attributes.last.kind_of?(Hash) return [] if attributes.empty? attributes.map! { |a| a.to_s } response_attributes = get_item(options, :attributes_to_get => attributes) values_from_response_hash(response_attributes). values_at(*attributes) end # @param [Hash] options Options for retrieving attributes from # the item. # # @option options [Boolean] :consistent_read If set to true, # then a consistent read is issued, otherwise an eventually # consistent read is used. def to_hash options = {} values_from_response_hash(get_item(options)) end alias_method :to_h, :to_hash private def item_key_options(options = {}) super(item, options) end private def get_item(their_options, our_options = {}) options = their_options.merge(our_options) resp = client.get_item(item_key_options(options)) resp.data['Item'] || {} end private def do_updates(client_opts, options) return nil if client_opts[:attribute_updates].empty? client_opts[:return_values] = options[:return].to_s.upcase if options[:return] expected = expect_conditions(options) client_opts[:expected] = expected unless expected.empty? resp = client.update_item(item_key_options(client_opts)) values_from_response_hash(resp.data["Attributes"]) if options[:return] and resp.data["Attributes"] end end end end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/keys.rb0000644000004100000410000000236312604445426020340 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class DynamoDB # @api private module Keys include Types # @return [Hash] Client options for identifying an item. def item_key_options(item, extra = {}) key = item_key_hash(item) extra.merge({ :table_name => item.table.name, :key => key }) end # @return [Hash] Returns just the hash key element and range key element def item_key_hash item item.table.assert_schema! key = {} key[:hash_key_element] = format_attribute_value(item.hash_value) key[:range_key_element] = format_attribute_value(item.range_value) if item.table.composite_key? key end end end end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/batch_get.rb0000644000004100000410000001531512604445426021306 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class DynamoDB # A utility class for configuring a list of tables, attributes and # items to request information for. # # @see DynamoDB#batch_get # @see Table#batch_get # class BatchGet include Keys include Enumerable include Core::Model def initialize options = {} super(options) @request_items = {} end # Add a list of items to fetch in this batch. # # @param [Table,String] table The name of the table to fetch attributes # from. # # @param [Symbol, String, Array] attributes The list of attributes # to fetch. If you want to load *ALL* attributes for the named items, # then pass the symbol `:all`. # # # get all attributes # batch_get.table('mytable', :all, items) # # # get one attribute for each item # batch_get.table('mytable', ['name'], items) # # # get a list of attributes for each item # batch_get.table('mytable', ['name', 'size'], items) # # @param [Array] items One or more items to fetch attributes # for. Each attribute should be one of the following: # # * an {Item} object # * a hash key value # * a hash key value and a range key value # # You must provide both the hash key and range key values if the table # schema has both. # # batch_get.table('mytable', :all, [%w(hk1 rk1), %w(hk1 rk2), ...]) # # @param [Hash] options # # @option options [Boolean] :consistent_read (false) When `true`, items # are read from this table with consistent reads. When `false`, reads # are eventually consistent. # # @return [nil] # def table table, attributes, items, options = {} table = table.is_a?(Table) ? table.name : table.to_s attributes = attributes == :all ? nil : [attributes].flatten keys = items.collect do |item| case item when Item then item_key_hash(item) when Array { :hash_key_element => format_attribute_value(item[0]), :range_key_element => format_attribute_value(item[1]), } else { :hash_key_element => format_attribute_value(item) } end end # ensure we don't receive 2 different lists of attributes for # the same table if @request_items.has_key?(table) and @request_items[table][:attributes_to_get] != attributes then msg = "When batch getting attributes, you may only provide " + "1 list of attributes per table, but the `#{table}` table " + "has received reqeusts for 2 different sets of attributes" raise ArgumentError, msg end # merge attributes and items with the request items @request_items[table] ||= { :keys => [] } @request_items[table][:attributes_to_get] = attributes if attributes @request_items[table][:keys] += keys @request_items[table].merge!(options) nil end # Specify a list of {Item} objects to batch fetch attributes for. # The table name is retrieved from the items objects, this means # the items do not need to belong to the same table. # # @param [Symbol, String, Array] attributes The list of attributes # to fetch. If you want to load *ALL* attributes for the named items, # then pass the symbol `:all`. # # # get all attributes # batch_get.table('mytable', :all, items) # # # get one attribute for each item # batch_get.table('mytable', ['name'], items) # # # get a list of attributes for each item # batch_get.table('mytable', ['name', 'size'], items) # # @param [Item] items One or more {Item} objects to fetch attributes # for. These items may come from any number of different tables. # def items attributes, *items [items].flatten.each do |item| self.table(item.table, attributes, [item]) end end # @return [nil] def each &block options = { :request_items => @request_items } begin response = client.batch_get_item(options) response.data['Responses'].each_pair do |table_name,details| details['Items'].each do |hash_data| attributes = values_from_response_hash(hash_data) yield(table_name, attributes) end end options[:request_items] = convert_unprocessed_keys(response) end while options[:request_items] nil end # Yields only attribute hashes. This removes the outer hash that # normally provides the :table_name and :attributes keys. This is # useful when your batch get requested items from a single table. def each_attributes each do |table_name, attributes| yield(attributes) end end protected def convert_unprocessed_keys response return nil if response.data['UnprocessedKeys'].empty? # convert the json response keys into symbolized keys str2sym = lambda do |key_desc| type, value = key_desc.to_a.flatten case type when "S" then { :s => value } when "N" then { :n => value } else raise "unhandled key type: #{type}" end end request_items = {} response.data['UnprocessedKeys'].each_pair do |table,keys| request_items[table] = {} request_items[table][:attributes_to_get] = keys['AttributesToGet'] if keys['AttributesToGet'] request_items[table][:keys] = keys['Keys'].collect do |desc| key = {} key[:hash_key_element] = str2sym.call(desc['HashKeyElement']) key[:range_key_element] = str2sym.call(desc['RangeKeyElement']) if desc['RangeKeyElement'] key end end request_items end end end end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/resource.rb0000644000004100000410000000176312604445426021217 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class DynamoDB class Resource < Core::Resource # @api private def self.attribute name, options = {} # DynamoDB attributes are all returned in UpperCamelCase, this # converts the :snake_case name into the correct format. unless options[:from] options[:from] = name.to_s.split(/_/).map(&:capitalize).join end super(name, options) end end end end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/table_collection.rb0000644000004100000410000001214612604445426022667 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class DynamoDB # Represents the tables in your account. Each table is # represented by an instance of the {Table} class. # # ## Schemas # # Before you can operate on items in a table you must specify the schema. # You do this by calling #hash_key= (and optionally #range_key=) on # a table. # # table = dynamo_db.tables['mytable'] # table.hash_key = [:id, :string] # # @example Creating a Table # table = dynamo_db.tables.create('mytable', 10, 10, :hash_key => { :id => :string }) # # @example Enumerating Tables # dynamo_db.tables.each {|table| puts table.name } # # @example Getting a Table by Name # table = dynamo_db.tables['mytable'] # class TableCollection include Core::Collection::WithLimitAndNextToken # Creates a new table. # # table = dynamo_db.tables.create('mytable', 25, 25, # :hash_key => { :id => :string }) # # @note Creating a table is an eventualy consistent operation. You # can not interact with the table until its status # ({Table#status}) is `:active`. # # @param [String] name The name of the table. # # @param [Integer] read_capacity_units Sets the minimum # number of reads supported before read requests are throttled. # # @param [Integer] write_capacity_units Sets the minimum # number of writes supported before writes requests are throttled. # # @param [Hash] options # # @option options [Hash] :hash_key A hash key is a combination # of an attribute name and type. If you want to have the # hash key on the string attribute username you would call #create # with: # # :hash_key => { :username => :string } # # The other supported types are `:number` and `:binary`. If you # wanted to set the hash key on a numeric (integer) attribute then you # could call #create with: # # :hash_key => { :id => :number } # # All tables require a hash key. If `:hash_key` is not provided # then a default hash key will be provided. The default hash # key is: # # :hash_key => { :id => :string } # # @option options [String] :range_key You can setup a table to use # composite keys by providing a `:range_key`. Range keys are # configured the same way as hash keys. They are useful # for ordering items that share the same hash key. # # @return [Table] The newly created table. # def create name, read_capacity_units, write_capacity_units, options = {} client_opts = { :table_name => name.to_s, :key_schema => key_schema(options), :provisioned_throughput => { :read_capacity_units => read_capacity_units, :write_capacity_units => write_capacity_units, }, } response = client.create_table(client_opts) Table.new(name, :config => config) end # References a table by name. # # dynamo_db.tables["MyTable"] # # @param [String] name # @return [Table] Returns the table with the given name. def [] name Table.new(name, :config => config) end # @api private protected def _each_item next_token, limit, options = {}, &block options[:limit] = limit if limit options[:exclusive_start_table_name] = next_token if next_token response = client.list_tables(options) response.data['TableNames'].each do |name| yield Table.new(name, :config => config) end response.data['LastEvaluatedTableName'] end private def key_schema options hash_key, range_key = options.values_at(:hash_key, :range_key) # default options for :hash_key hash_key ||= { :id => :string } schema = {} schema[:hash_key_element] = schema_element(hash_key, "hash") if range_key schema[:range_key_element] = schema_element(range_key, "range") end schema end private def schema_element desc, key_type (name, type) = desc.to_a.first unless [:string, :number, :binary].include?(type) msg = "invalid #{key_type} key type, expected :string, :number or :binary" raise ArgumentError, msg end { :attribute_name => name.to_s, :attribute_type => type.to_s[0,1].upcase } end end end end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/batch_write.rb0000644000004100000410000001606712604445426021666 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class DynamoDB class BatchWrite include Types include Core::Model def initialize options = {} super(options) @request_items = {} end # Adds one or more items to the batch write operation. # # # adding one item at a time to the batch # batch = AWS::DynamoDB::BatchWrite.new # batch.put('table-name', :id => 'id1', :color => 'red') # batch.put('table-name', :id => 'id2', :color => 'blue') # batch.process! # # # adding multiple items to a batch # batch = AWS::DynamoDB::BatchWrite.new # batch.put('table-name', [ # { :id => 'id1', :color => 'red' }, # { :id => 'id2', :color => 'blue' }, # { :id => 'id3', :color => 'green' }, # ]) # batch.process! # # @param [Table,String] table A {Table} object or table name string. # # @param [Array] items A list of item attributes to put. # The hash must contain the table hash key element and range key # element (if one is defined). # # @return [nil] # def put table, items write(table, :put => items.flatten) nil end # Adds one or more items to the batch to delete. # # # for a table w/out a range key # batch = AWS::DynamoDB::BatchWrite.new # batch.delete('table-name', %w(hk1 hk2)) # batch.process! # # # for a table with a range key # batch = AWS::DynamoDB::BatchWrite.new # batch.delete('table-name', [['hk1', 'rk2'], ['hk1', 'rk2']]]) # batch.process! # # @param [Table,String] table A {Table} object or table name string. # # @param [Array,Array] items A list of item keys to # delete. For tables without a range key, items should be an array # of hash key strings. # # batch.delete('table-name', ['hk1', 'hk2', 'hk3']) # # For tables with a range key, items should be an array of # hash key and range key pairs. # # batch.delete('table-name', [['hk1', 'rk1'], ['hk1', 'rk2']]) # # @return [nil] # def delete table, items write(table, :delete => items) nil end # Add items to the batch. Accepts both item to put and and items # to delete. # # @param [Table,String] table A {Table} object or table name string. # # @param [Hash] options # # @option options [Array] :put An array of items to put. Each item # should be an array of attribute hashes. # # # add 3 items to the batch # batch.write(table, :put => [ # { :id => 'abc', :color => 'red', :count => 2 }, # { :id => 'mno', :color => 'blue', :count => 3 }, # { :id => 'xyz', :color => 'green', :count => 5 }, # ]) # # @option options [Array,Array] :delete A list of item keys # to delete. For tables without a range key, items should be an array # of hash key strings. # # batch.write('table-name', :delete => ['hk1', 'hk2', 'hk3']) # # For tables with a range key, items should be an array of # hash key and range key pairs. # # batch.write('table-name', :delete => [['hk1', 'rk1'], ['hk1', 'rk2']]) # def write table, options = {} items = table_items(table) if put = options[:put] put.each do |attributes| items << { :put_request => { :item => format_put(attributes) }} end end if del = options[:delete] del.each do |keys| items << { :delete_request => { :key => format_delete(keys) }} end end end # Proccesses pending request items. # @return [nil] def process! return if @request_items.empty? opts = { :request_items => @request_items } begin response = client.batch_write_item(opts) unprocessed = response.data['UnprocessedItems'] opts[:request_items] = convert_unprocessed_items(unprocessed) end while opts[:request_items] @request_items = {} nil end protected def table_name table table.is_a?(Table) ? table.name : table.to_s end def table_items table @request_items[table_name(table)] ||= [] end def format_put attributes attributes.inject({}) do |hash, (key, value)| context = "value for attribute #{key}" hash.merge(key.to_s => format_attribute_value(value, context)) end end def format_delete keys keys = [keys] unless keys.is_a?(Array) item = {} item[:hash_key_element] = format_attribute_value(keys.first) item[:range_key_element] = format_attribute_value(keys.last) if keys.count > 1 item end def convert_unprocessed_items items return nil if items.empty? request_items = {} items.each_pair do |table,requests| request_items[table] ||= [] requests.each do |request| item = request.values.first request_items[table] << case request.keys.first when 'PutRequest' then convert_put_item(item['Item']) when 'DeleteRequest' then convert_delete_item(item['Key']) end end end request_items end def convert_put_item item attributes = {} item.each_pair do |name,value| attributes[name] = str2sym(value) end { :put_request => { :item => attributes }} end def convert_delete_item item key = {} key[:hash_key_element] = str2sym(item['HashKeyElement']) key[:range_key_element] = str2sym(item['RangeKeyElement']) if item['RangeKeyElement'] { :delete_request => { :key => key}} end def str2sym key_desc type = key_desc.keys.first value = key_desc[type] case type when "S" then { :s => value } when "N" then { :n => value } when "B" then { :b => value } when "SS" then { :ss => value } when "NS" then { :ns => value } when "BS" then { :bs => value } else raise "unhandled key type: #{type.inspect}" end end end end end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/item_collection.rb0000644000004100000410000007414012604445426022540 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class DynamoDB # Represents a collection of DynamoDB items. # # You can use an item collection to: # # * Create an {Item} # * Get an {Item} # * Enumerate {Item} or {ItemData} objects # # ## Creating an Item # # To create an item, just call {#create} with a hash of attributes. # # table = dynamo_db.tables['my-table'] # table.hash_key = [:id, :string] # # table.items.create('id' => 'abc', 'count' => 5, 'colors' => %w(red blue)) # # Attribute names can be symbols/strings and values can be strings or # numbers or arrays/sets of strings/numbers. The attributes must contain # the hash key name/value for the item and the value must be of the # correct type (e.g. string or number). # # ## Getting an Item # # To get an item, you provide the hash key # # # gets a reference to the item, no request is made # item = table.items['hash-key-value'] # # You call methods against the item returned to get, add, update or delete # attributes. See {Item} for more information. # # ## Enumerating Items # # You can enumerate items 2 ways: # # * Enuemrate {Item} objects # * Enumerate {ItemData} objects # # {Item} objects do not have any attribute data populated. Think of # them as just references to the item in Amazon DynamoDB. They only # konw the objects hash key (and optional range key). # # {ItemData} objects are wrappers around the actual item attributes. # # To enumerate {Item} objects just call each on the item collection. # # table.items.each do |item| # puts item.hash_value # end # # To enumerate {ItemData} objects you need to specify what attributes # you are interested in. This will cause #each to yield {ItemData} # objects. Call {ItemData#attributes} to get the hash of attribute # names/values. # # table.items.select('id', 'category').each do |item_data| # item_data.attributes #=> { 'id' => 'abc', 'category' => 'foo' } # end # # If you want item data objects with all attributes just call select # without a list of attributes (#select still accepts options). # # # request a maximum of 10 items from Amazon DynamoDB # table.items.select(:limit => 10).each do |item_data| # item_data.attributes #=> { 'id' => 'abc', 'category' => 'foo', ... } # end # # Please note that enumerating objects is done via the scan operation. # Refer to the Amazon DynamoDB documentation for more information # about scanning. # class ItemCollection include Core::Collection::WithLimitAndNextToken include Types include Expectations # @api private def initialize(table, opts = {}) @table = table @scan_filters = opts[:scan_filters] || {} super end # @return [Table] The table to which the items in the collection # belong. attr_reader :table # @api private attr_reader :scan_filters # Creates a new item, or replaces an old item with a new item # (including all the attributes). If an item already exists in # the specified table with the same primary key, the new item # completely replaces the existing item. You can perform a # conditional put (insert a new item if one with the specified # primary key doesn't exist), or replace an existing item if it # has certain attribute values. # # items.put(:id => "abc123", :colors => ["red", "white"]) # # @param [Hash] attributes The attributes to store with the # item. These must include the primary key attributes for the # table (see {Table#hash_key} and {Table#range_key}. # Attribute names may be symbols or UTF-8 strings, and # attribute values may be any of these types: # # * String # * Array or Set # * Numeric # * Array or Set # # Empty sets, arrays, and strings are invalid. # # @param [Hash] options ({}) Additional options for # storing the item. # # @option options [Hash] :if Designates a conditional put. The # operation will fail unless the item exists and has the # attributes in the value for this option. For example: # # # throws DynamoDB::Errors::ConditionalCheckFailedException # # unless the item has "color" set to "red" # items.put( # { :foo => "Bar" }, # :if => { :color => "red" } # ) # # @option options [String, Symbol, Array] :unless_exists A name # or collection of attribute names; if the item already exists # and has a value for any of these attributes, this method # will raise # `DynamoDB::Errors::ConditionalCheckFailedException`. For example: # # items.put({ :id => "abc123" }, :unless_exists => "id") # # @option options [Symbol] :return If set to `:all_old`, this # method will return a hash containing the previous values of # all attributes for the item that was overwritten. If this # option is set to `:none`, or if it is set to `:all_old` and # no item currently exists with the same primary key values, # the method will return `nil`. # # @return [Item] An object representing the item that was # stored. Note that the SDK retains only the item's primary # key values in memory; if you access the attributes of the # item using the returned object, the SDK will contact the # service to retrieve those attributes. The `:return` option # may be used to change the return value of this method. def create attributes, options = {} table.assert_schema! attributes = attributes.inject({}) do |hash, (key, value)| context = "value for attribute #{key}" hash.update(key.to_s => format_attribute_value(value, context)) end client_opts = { :table_name => table.name, :item => attributes } expected = expect_conditions(options) client_opts[:expected] = expected unless expected.empty? client_opts[:return_values] = options[:return].to_s.upcase if options[:return] resp = client.put_item(client_opts) item = Item.new_from(:put_item, attributes, table) if options[:return] values_from_response_hash(resp.data["Attributes"]) else item end end alias_method :put, :create # Returns an object representing an item in the table, # identified by its hash key value. This method will raise an # exception unless the table has a schema loaded or configured, # or if the table has a composite primary key. # # table.hash_key = [:id, :string] # item = table.items["abc123"] # # @param [String, Numeric] hash_value The hash key value for the # item. The type of this parameter must match the type in the # table's schema, but currently the SDK makes no attempt to # validate the key. # # @return [Item] def [] hash_value table.assert_schema! raise(ArgumentError, "table has a range key; use #at instead of #[]") unless table.simple_key? Item.new(table, hash_value) end # Returns an object representing an item in the table, # identified by its hash key value and conditionally its range # key value. This method will raise an exception unless the # table has a schema loaded or configured. The type of each # parameter must match the type in the table's schema, but # currently the SDK makes no attempt to validate the key # elements. # # table.hash_key = [:id, :string] # table.range_key = [:range, :number] # item = table.items.at("abc123", 12) # # @param [String, Numeric] hash_value The hash key value for the # item. # # @param [String, Numeric] range_value The range key value for # the item. This parameter is required when the table has a # composite primary key, and it may not be specified when the # table has a simple primary key. # # @return [Item] def at hash_value, range_value = nil table.assert_schema! if table.composite_key? and !range_value raise ArgumentError, "a range key value is required for this table" end Item.new(table, hash_value, range_value) end alias_method :[], :at # Provides a convenient syntax for expressing scan filters. # # table.items.where(:path).begins_with("users/") # class FilterBuilder include Types attr_reader :items attr_reader :attribute # @api private def initialize(items, attribute) @items = items @attribute = attribute end # Filters the collection to include only those items where the # value of this attribute is equal to the argument. # # @param [String, Numeric] value The value to compare against. # # @return [ItemCollection] A new item collection filtered by # this condition. def equals value @items.with_filter(attribute, "EQ", value) end # Filters the collection to include only those items where the # value of this attribute is not equal to the argument. # # @param [String, Numeric] value The value to compare against. # # @return [ItemCollection] A new item collection filtered by # this condition. def not_equal_to value @items.with_filter(attribute, "NE", value) end # Filters the collection to include only those items where the # value of this attribute is less than the argument. # # @param [String, Numeric] value The value to compare against. # # @return [ItemCollection] A new item collection filtered by # this condition. def less_than value @items.with_filter(attribute, "LT", value) end # Filters the collection to include only those items where the # value of this attribute is greater than the argument. # # @param [String, Numeric] value The value to compare against. # # @return [ItemCollection] A new item collection filtered by # this condition. def greater_than value @items.with_filter(attribute, "GT", value) end # Filters the collection to include only those items where the # value of this attribute is less than or equal to the # argument. # # @param [String, Numeric] value The value to compare against. # # @return [ItemCollection] A new item collection filtered by # this condition. def lte value @items.with_filter(attribute, "LE", value) end # Filters the collection to include only those items where the # value of this attribute is greater than or equal to the # argument. # # @param [String, Numeric] value The value to compare against. # # @return [ItemCollection] A new item collection filtered by # this condition. def gte value @items.with_filter(attribute, "GE", value) end # Filters the collection to include only those items where # this attribute does not exist. # # @return [ItemCollection] A new item collection filtered by # this condition. def is_null @items.with_filter(attribute, "NULL") end # Filters the collection to include only those items where # this attribute exists. # # @return [ItemCollection] A new item collection filtered by # this condition. def not_null @items.with_filter(attribute, "NOT_NULL") end # Filters the collection to include only those items where # this attribute contains the argument. If the attribute # value is a set, this filter matches items where the argument # is one of the values in the set. If the attribute value is # a string, this filter matches items where the argument # (which must be a string) is a substring of the attribute # value. # # @param [String, Numeric] value The value to compare against. # # @return [ItemCollection] A new item collection filtered by # this condition. def contains value @items.with_filter(attribute, "CONTAINS", value) end # Filters the collection to include only those items where # this attribute does not contain the argument. If the # attribute value is a set, this filter matches items where # the argument is not present in the set. If the attribute # value is a string, this filter matches items where the # argument (which must be a string) is not a substring of the # attribute value. # # @param [String, Numeric] value The value to compare against. # # @return [ItemCollection] A new item collection filtered by # this condition. def does_not_contain value @items.with_filter(attribute, "NOT_CONTAINS", value) end # Filters the collection to include only those items where # this attribute begins with the argument. # # @param [String] value The value to compare against. # # @return [ItemCollection] A new item collection filtered by # this condition. def begins_with value @items.with_filter(attribute, "BEGINS_WITH", value) end # Filters the collection to include only those items where # this attribute equals one of the arguments. # # @param [Array] values The values to compare # against. # # @return [ItemCollection] A new item collection filtered by # this condition. def in *values @items.with_filter(attribute, "IN", *values) end # Filters the collection to include only those items where # this attribute is between the two arguments. # # @param [String, Numeric] min The minimum value. # # @param [String, Numeric] max The maximum value. # # @return [ItemCollection] A new item collection filtered by # this condition. def between min, max @items.with_filter(attribute, "BETWEEN", min, max) end end # @overload where(attributes) # # table.items.where(:name => "Fred") # # @param [Hash] attributes The returned collection will be # filtered such that each item contains the attributes and # values in this map. # # @return [ItemCollection] A collection where all the items # have the provided attributes and values. # # @overload where(attribute_name) # # table.items.where(:name).equals("Fred") # # @return [FilterBuilder] An object that allows you to specify # a filter on the provided attribute name. def where(filter) case filter when Hash filter.inject(self) do |items, (name, value)| case value when nil items.with_filter(name.to_s, "NULL") when Range items.with_filter(name.to_s, "BETWEEN", value.begin, value.end) else items.with_filter(name.to_s, "EQ", value) end end when String, Symbol FilterBuilder.new(self, filter.to_s) end end alias_method :and, :where # Iterates over all the items in the collection using a scan # operation. A scan operation scans the entire table. You can # specify filters to apply to the results to refine the values # returned to you, after the complete scan. Amazon DynamoDB puts # a 1MB limit on the scan (the limit applies before the results # are filtered). A scan can result in no table data meeting the # filter criteria. # # For more information about filtering the collection # see the {#where} method. # # @param [Hash] options Options for iterating the collection. # # @yieldparam [Item] item Each item in the collection. # # @option options [Integer] :limit The maximum number of items to yield. # # @option options [Integer] :batch_size The maximum number of items # to retrieve with each service request. def each(options = {}, &block) if conditions = options.delete(:where) return where(conditions).each(options, &block) end table.assert_schema! options = options.merge(:table_name => table.name) options[:scan_filter] = scan_filters unless scan_filters.empty? unless options[:count] or options[:item_data] options[:attributes_to_get] = [table.hash_key.name] options[:attributes_to_get] << table.range_key.name if table.composite_key? end super(options, &block) end def first(options = {}) each(options) do |item| return item end end # Retrieves data about the items in the collection. This method # works like {#each}, except that it returns or yields # {ItemData} instances instead of {Item} instances. This is # useful if you want to use the attributes of the item in a loop # or retain them in memory. Also, unlike {#each} which always # requests only the primary key attributes of the items, this # method allows you to specify which attributes to retrieve from # DynamoDB. # # # fetch all attributes for a collection of items # items.select { |data| p data.attributes } # # # fetch only the "color" attribute of each item # items.select(:color) { |data| p data.attributes["color"] } # # # use client-side filtering to delete a subset of the items # items.select do |data| # data.item.delete if data.attributes.size % 2 == 0 # end # # @overload select(*attributes, options = {}) # # @param [Array] attributes Specifies which # attributes to retrieve from the service. By default all # attributes are retrieved. If the last argument is a hash, # it may contain options for iterating the items in the # collection. See the {#each} method for more information # about these options. # # @param [Hash] options # # @option options [Integer] :limit The maximum number of records to # select (scan). If more records are requested than can # be returned in a single response, multiple requests # will be made. # # @yieldparam [ItemData] data The data for each item in the # collection. The attributes of each item will be populated # in the ItemData object; however, {ItemData#item} will not be # populated unless the requested attributes include all # elements of the table's primary key. For example, if a # table has a composite primary key, this method will only # populate {ItemData#item} if the list of requested attributes # includes both the hash key and range key attributes. # # @return [Enumerator, nil] If a block is given, this method # returns nil. Otherwise, it returns an enumerator for the # values that would have been yielded to the block. # def select *attributes, &block options = {} options = attributes.pop if attributes.last.kind_of?(Hash) options = options.merge(:item_data => true) options[:attributes_to_get] = attributes.map { |att| att.to_s } unless attributes.empty? if block_given? each(options, &block) else enumerator(options) end end # Counts the items in the collection using a table scan. The # count applies to the items that match all the filters on the # collection. For example: # # # count the blue items # items.where(:color => "blue").count # # @param [Hash] options Options for counting the items. # # @option options [Integer] :max_requests The maximum number of # requests to make. # # @option options [Integer] :limit The maximum count; the return # value will be less than or equal to the value of this # option. # # @option options [Integer] :batch_size DynamoDB will scan up to # 1MB of data on each request; you can use this option to # further limit the number of items scanned on each request. # # @return [Integer] def count options = {} options = options.merge(:count => true) # since each with :count yields the per-page counts, each with # :limit and :count effectively limits the number of requests, # not the number of items limit = options.delete(:limit) options[:limit] = options.delete(:max_requests) if options.key?(:max_requests) # it usually doesn't make sense to ask for more items than you # care about counting options[:batch_size] ||= limit if limit enumerator(options).inject(0) do |sum, n| return limit if limit && sum + n >= limit sum + n end end RANGE_KEY_OPTIONS = { :range_less_than => "LT", :range_greater_than => "GT", :range_lte => "LE", :range_gte => "GE", :range_begins_with => "BEGINS_WITH" } # Queries the items in the table by primary key values. This # operation is generally more efficient than the scan operation, # which always scans the whole table. A Query operation # searches for a specific range of keys satisfying a given set # of key conditions and does not have the added step of # filtering out results. # # # find all items with a given hash key value # items.query(:hash_value => "abc123") # # # get only the colors attribute of each item # items.query( # :hash_value => "abc123", # :select => [:colors]) # # # find only the items where the range key is between two values # items.query( # :hash_value => "abc123", # :range_value => 1..100 # ) # # @note This method is only valid for tables with a composite # primary key. # # @param [Hash] options Options for the query. `:hash_value` is # required. Only one of the following options may be set: # # * `:range_value` # * `:range_greater_than` # * `:range_less_than` # * `:range_gte` # * `:range_lte` # * `:range_begins_with` # # @option [Boolean] :scan_index_forward (true) Specifies which # order records will be returned. Defaults to returning them # in ascending range key order. Pass false to reverse this. # # @option :select (nil) By default {#query} yields {Item} # objects without any attribute data. If you want to select # specific attributes, pass a list of them to :select. # # :select => [:id, :category, :size] # # If you want to select ALL attributes, pass the symbol `:all` # # :select => :all # # @option options [String, Numeric] :hash_value Attribute value # of the hash component of the composite primary key. # # @option options [Array, String, Symbol] :select # Attribute name or names to retrieve. When this option is # set, the returned or yielded items will be instances of # {ItemData} instead of {Item}. The special value `:all` # indicates that all attributes should be retrieved and # returned in ItemData instances. # # @option options [String, Numeric, Range] :range_value # Specifies which range key values to find in the table. If # this is a Range, the query will return items with range key # values between the beginning and end of the range # (inclusive). If it is a string or number, the query will # return only the item with that range key value. # # @option options [String, Numeric] :range_greater_than Matches # items where the range key value is greater than this value. # # @option options [String, Numeric] :range_less_than Matches # items where the range key value is less than this value. # # @option options [String, Numeric] :range_gte Matches items # where the range key value is greater than or equal to this # value. # # @option options [String, Numeric] :range_lte Matches items # where the range key value is less than or equal to this # value. # # @option options [String, Numeric] :range_begins_with Matches # items where the range key value begins with this value. # This option is only valid if the range key is a string. # def query(options = {}, &block) options = options.merge(:query => true) raise ArgumentError, "a hash key value is required" unless options[:hash_value] options[:hash_key_value] = format_attribute_value(options.delete(:hash_value)) range = options.delete(:range_value) range_op = nil value_list = [] if range and range.kind_of?(Range) value_list = [format_attribute_value(range.begin), format_attribute_value(range.end)] range_op = "BETWEEN" elsif range value_list = [format_attribute_value(range)] range_op = "EQ" end RANGE_KEY_OPTIONS.each do |name, op| if value = options.delete(name) raise(ArgumentError, "only one range key condition is supported") if range_op range_op = op value_list = [format_attribute_value(value)] end end options[:range_key_condition] = { :attribute_value_list => value_list, :comparison_operator => range_op } if range_op if select = options.delete(:select) || options.delete(:attributes_to_get) options[:item_data] = true options[:attributes_to_get] = select.map(&:to_s) unless select == :all end if block each(options, &block) else enumerator(options) end end # @api private def with_filter attribute, op, *values values = values.map {|value| format_attribute_value(value) } filter = { :attribute_value_list => values, :comparison_operator => op } if scan_filters.key?(attribute) raise(ArgumentError, "conflicting filters for attribute #{attribute}") end refine(:scan_filters => scan_filters.merge(attribute => filter)) end # @api private def refine(opts) opts = { :scan_filters => scan_filters }.merge(opts) self.class.new(table, opts) end protected def _each_item next_token, limit, options = {}, &block options[:exclusive_start_key] = next_token if next_token options[:limit] = limit if limit method = options.delete(:query) ? :query : :scan mode = case when options.delete(:item_data) then :item_data when options[:count] then :count else :item end response = client.send(method, options) _yield_items(mode, response, &block) response.data["LastEvaluatedKey"] end protected def _yield_items mode, response, &block case mode # yield the count of items matching when :count yield(response.data["Count"]) # yeild item data objects when :item_data table.assert_schema! #construct_items = # (true if request_includes_key?(response.request_options)) construct_items = request_includes_key?(response.request_options) response.data["Items"].each do |i| attributes = values_from_response_hash(i) item = nil item = Item.new_from(:put_item, i, table) if construct_items item_data = ItemData.new(:item => item, :attributes => attributes) yield(item_data) end # yield item objects when :item response.data["Items"].each do |i| item = Item.new_from(:put_item, i, table) yield(item) end end end protected def request_includes_key?(options) requested_atts = options[:attributes_to_get] requested_atts.nil? or (table.simple_key? && requested_atts.include?(table.hash_key.name)) or (table.composite_key? && requested_atts.include?(table.hash_key.name) && requested_atts.include?(table.range_key.name)) end end end end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/item_data.rb0000644000004100000410000000144612604445426021315 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class DynamoDB class ItemData attr_reader :item attr_reader :attributes def initialize(opts = {}) @item = opts[:item] @attributes = opts[:attributes] end end end end aws-sdk-v1-1.66.0/lib/aws/dynamo_db/primary_key_element.rb0000644000004100000410000000254012604445426023426 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class DynamoDB class PrimaryKeyElement attr_reader :name attr_reader :type ATTRIBUTE_TYPES = { "S" => :string, "N" => :number, "B" => :binary, } def initialize(hash) @name = hash[:name] || hash["AttributeName"] @type = hash[:type] || ATTRIBUTE_TYPES[hash["AttributeType"]] end def self.from_description(description) (name, type, *extra) = description.to_a.flatten raise(ArgumentError, "key element may contain only one name/type pair") unless extra.empty? raise ArgumentError, "unsupported type #{type.inspect}" unless ATTRIBUTE_TYPES.values.include?(type.to_sym) new(:name => name.to_s, :type => type) end end end end aws-sdk-v1-1.66.0/lib/aws/redshift.rb0000644000004100000410000000300412604445426017232 0ustar www-datawww-data# Copyright 2011-2013 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 'aws/core' require 'aws/redshift/config' module AWS # This class is the starting point for working with Amazon Redshift. # # For more information about Redshift: # # * [Amazon Redshift](http://aws.amazon.com/redshift/) # * [Amazon Redshift Documentation](http://aws.amazon.com/documentation/redshift/) # # # Credentials # # You can setup default credentials for all AWS services via # AWS.config: # # AWS.config( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # # Or you can set them directly on the AWS::Redshift interface: # # redshift = AWS::Redshift.new( # :access_key_id => 'YOUR_ACCESS_KEY_ID', # :secret_access_key => 'YOUR_SECRET_ACCESS_KEY') # class Redshift autoload :Client, 'aws/redshift/client' autoload :Errors, 'aws/redshift/errors' include Core::ServiceInterface endpoint_prefix 'redshift' end end aws-sdk-v1-1.66.0/lib/aws/glacier/0000755000004100000410000000000012604445426016506 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/glacier/archive_collection.rb0000644000004100000410000000767312604445426022704 0ustar www-datawww-data# Copyright 2011-2013 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 'openssl' module AWS class Glacier class ArchiveCollection include Core::Model # @param [Vault] vault # @param [Hash] options # @option options [String] :account_id def initialize vault, options = {} @vault = vault @account_id = options[:account_id] || '-' super end # @return [Vault] attr_reader :vault # @return [String] attr_reader :account_id # Creates an archive by uploading a file to a vault. # @param [File,Pathname,IO,String] data The data to upload. # If `data` is a string, this is treated as a path to a file # on disk. # @param [Hash] options # @option options [String] description # @return [Archive] def create data, options = {} data = convert_to_io(data) hash, tree_hash = compute_checksums(data) upload_options = {} upload_options[:vault_name] = vault.name upload_options[:account_id] = account_id upload_options[:body] = data upload_options[:checksum] = tree_hash upload_options[:content_sha256] = hash upload_options[:archive_description] = options[:description] if options[:description] resp = client.upload_archive(upload_options) self[resp[:archive_id]] end # @param [String] archive_id # @return [Archive] def [] archive_id Archive.new(vault, archive_id, :config => config, :account_id => account_id) end protected def convert_to_io data return Core::ManagedFile.open(data) if data.is_a?(Pathname) or data.is_a?(String) return data if io_like?(data) msg = "expected data to be IO-like or a file path (String/Pathanme)." raise ArgumentError, msg end # @return [Boolean] Returns `tue` if data acts like a file. def io_like? data data.respond_to?(:read) and data.respond_to?(:eof?) and data.respond_to?(:rewind) and data.respond_to?(:size) end # Computes two checksums in a single pass of the data: # * a hash of the entire payload # * a tree hash of the entire payload # # The tree hash is required by the streaming operations, # the simple hash is required for generating the signature # (via sigv4). # # The sigv4 module will compute the hash of the payload for us, # but that requires reading the data a 2nd time. :( def compute_checksums data digest = OpenSSL::Digest.new('sha256') tree_digest = OpenSSL::Digest.new('sha256') tree_parts = [] until data.eof? chunk = data.read(1024 * 1024) # read 1MB tree_parts << tree_digest.update(chunk).digest tree_digest.reset digest.update(chunk) end data.rewind [digest.to_s, compute_tree_hash(tree_parts)] end def compute_tree_hash hashes digest = OpenSSL::Digest.new('sha256') until hashes.count == 1 hashes = hashes.each_slice(2).map do |h1,h2| digest.reset if h2 digest.update(h1) digest.update(h2) digest.digest else h1 end end end hashes.first.bytes.map{|x| x.to_i.to_s(16).rjust(2,'0')}.join('') end end end end aws-sdk-v1-1.66.0/lib/aws/glacier/errors.rb0000644000004100000410000000124012604445426020344 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class Glacier module Errors extend Core::LazyErrorClasses end end end aws-sdk-v1-1.66.0/lib/aws/glacier/vault_collection.rb0000644000004100000410000000353312604445426022405 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class Glacier class VaultCollection include Core::Collection::WithLimitAndNextToken # @param [Hash] options # @option options [String] :account_id def initialize options = {} @account_id = options[:account_id] || '-' super end # @return [String] attr_reader :account_id # @param [String] name def create name options = {} options[:vault_name] = name options[:account_id] = account_id client.create_vault(options) self[name] end # @param [String] name The name of the vault. # @return [Vault] Returns a vault with the given name. def [] name Vault.new(name, :config => config, :account_id => account_id) end protected def _each_item next_token, limit, options, &block options[:limit] = limit if limit options[:marker] = next_token if next_token options[:account_id] = account_id resp = client.list_vaults(options) resp[:vault_list].each do |v| vault = Vault.new_from(:list_vaults, v, v[:vault_name], :config => config, :account_id => account_id) yield(vault) end resp[:marker] end end end end aws-sdk-v1-1.66.0/lib/aws/glacier/client.rb0000644000004100000410000000247012604445426020314 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class Glacier # All operations with Amazon Glacier require your AWS account ID. # You can specify the special value of '-' to specify your # AWS account ID. # # glacier = AWS::Glacier.new # resp = glacier.client.list_vaults(:account_id => '-') # class Client < Core::RESTJSONClient API_VERSION = '2012-06-01' signature_version :Version4, 'glacier' # @api private CACHEABLE_REQUESTS = Set[] private def build_request *args request = super(*args) request.headers['x-amz-glacier-version'] = self.class.const_get(:API_VERSION) request end end class Client::V20120601 < Client define_client_methods('2012-06-01') end end end aws-sdk-v1-1.66.0/lib/aws/glacier/archive.rb0000644000004100000410000000257012604445426020460 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class Glacier class Archive < Resource # @param [Vault] vault # @param [String] archive_id # @param [Hash] options # @option options [String] :account_id def initialize vault, archive_id, options = {} @vault = vault @archive_id = archive_id super end # @return [Vault] attr_reader :vault # @return [String] attr_reader :archive_id alias_method :id, :archive_id # Deletes the current archive. # @return [nil] def delete client.delete_archive(resource_options) nil end protected def resource_identifiers [ [:vault_name, vault.name], [:archive_id, archive_id], [:account_id, account_id], ] end end end end aws-sdk-v1-1.66.0/lib/aws/glacier/config.rb0000644000004100000410000000123012604445426020274 0ustar www-datawww-data # Copyright 2011-2013 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. AWS::Core::Configuration.module_eval do add_service 'Glacier', 'glacier', 'glacier' end aws-sdk-v1-1.66.0/lib/aws/glacier/resource.rb0000644000004100000410000000160512604445426020664 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class Glacier class Resource < Core::Resource # @api private def initialize *args options = args.last.is_a?(Hash) ? args.last : {} @account_id = options[:account_id] || '-' super end # @return [String] :account_id attr_reader :account_id end end end aws-sdk-v1-1.66.0/lib/aws/glacier/vault_notification_configuration.rb0000644000004100000410000000170312604445426025664 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class Glacier class VaultNotificationConfiguration # @return [SNS::Topic] The SNS topic Glacier will publish events to. attr_accessor :sns_topic alias_method :topic, :sns_topic # @return [Array] events An array of one or more events for # which Amazon Glacier will send notifications. attr_accessor :events end end end aws-sdk-v1-1.66.0/lib/aws/glacier/vault.rb0000644000004100000410000001031112604445426020162 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class Glacier # # @attr_reader [String] arn # # @attr_reader [Integer] size_in_bytes # # @attr_reader [Integer] number_of_archives # # @attr_reader [Time] creation_date # # @attr_reader [Time] last_inventory_date # class Vault < Resource # @param [String] name # @param [Hash] options # @option options [String] :account_id def initialize name, options = {} @name = name super end # @return [String] attr_reader :name attribute :arn, :from => :vault_arn, :static => true attribute :size_in_bytes attribute :number_of_archives attribute :creation_date, :static => true attribute :last_inventory_date populates_from(:list_vaults) do |resp| resp.request_options[:account_id] == account_id and resp[:vault_list].find {|vault| vault[:vault_name] == name } end populates_from(:describe_vault) do |resp| if resp.request_options[:account_id] == account_id and resp[:vault_name] == name resp end end # @return [Boolean] Returns `true` if the vault exists. def exists? client.describe_vault(:vault_name => name, :account_id => account_id) true rescue Errors::ResourceNotFoundException false end # @return [ArchiveCollection] def archives ArchiveCollection.new(self, :account_id => account_id) end # @param [String,SNS::Topic] topic The SNS topic ARN string or an # SNS::Topic object to send event notifications to. # @param [Array] events An array of one or more events for # which you want Amazon Glacier to send notifications. # Valid values include: # * 'ArchiveRetrievalCompleted' # * 'InventoryRetrievalCompleted' # @return [VaultNotificationConfiguration] def configure_notifications topic, events topic_arn = topic.is_a?(String) ? topic : topic.arn cfg = VaultNotificationConfiguration.new cfg.sns_topic = SNS::Topic.new(topic_arn, :config => config) cfg.events = events cfg self.notification_configuration = cfg end # @return [VaultNotificationConfiguration,nil] def notification_configuration resp = client.get_vault_notifications(resource_options) cfg = VaultNotificationConfiguration.new cfg.sns_topic = SNS::Topic.new(resp[:sns_topic], :config => config) cfg.events = resp[:events] cfg rescue Errors::ResourceNotFoundException nil end # Sets the notification configuration for this vault. If you pass # a `nil` value, the notification configuration will be deleted # @param [VaultNotificationConfiguration] cfg def notification_configuration= cfg if cfg opts = {} opts.merge!(resource_options) opts[:vault_notification_config] = {} opts[:vault_notification_config][:sns_topic] = cfg.sns_topic.arn opts[:vault_notification_config][:events] = cfg.events client.set_vault_notifications(opts) else client.delete_vault_notifications(resource_options) end end # Deletes the current vault. You can only delete an empty vault. # @return [nil] def delete client.delete_vault(resource_options) nil end protected def get_resource attr = nil client.describe_vault(resource_options) end def resource_identifiers [ [:vault_name, name], [:account_id, account_id], ] end end end end aws-sdk-v1-1.66.0/lib/aws/simple_workflow/0000755000004100000410000000000012604445426020323 5ustar www-datawww-dataaws-sdk-v1-1.66.0/lib/aws/simple_workflow/activity_type_collection.rb0000644000004100000410000001011312604445426025754 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class SimpleWorkflow class ActivityTypeCollection < TypeCollection # Registers a new activity type along with its configuration settings # in the current domain. # # @param [String] name The name of the activity type. # # @param [String] version The version of the activity type. # The activity type consists of the name and version, the # combination of which must be unique within the domain. # # @param [Hash] options # # @option options [Integer,:none] :default_task_heartbeat_timeout (nil) # The default maximum time before which a worker processing a task # of this type must report progress. If the timeout is exceeded, # the activity task is automatically timed out. If the worker # subsequently attempts to record a heartbeat or returns a # result, it will be ignored. This default can be overridden when # scheduling an activity task. # # The value should be a number of seconds (integer) or the symbol # `:none` (implying no timeout). # # @option options [String] :default_task_list (nil) The default task # list to use for scheduling tasks of this activity type. # This default task list is used if a task list is not provided # when a task is scheduled. # # @option options [Integer] :default_task_priority (nil) Specifies # the default task priority to use for scheduling tasks for this # activity type. This default is used only if a task priority is # not provided when a task is scheduled. # # @option options [Integer,:none] :default_task_schedule_to_close_timeout (nil) # The value should be a number of seconds (integer) or the symbol # `:none` (implying no timeout). # # @option options [Integer,:none] :default_task_schedule_to_start_timeout (nil) # The default maximum duration that a task of this activity type # can wait before being assigned to a worker. This default can be # overridden when scheduling an activity task. # # The value should be a number of seconds (integer) or the symbol # `:none` (implying no timeout). # # @option options [Integer,:none] :default_task_start_to_close_timeout (nil) # The default maximum duration that a worker can take to process # tasks of this activity type (in the ISO 8601 format). This default # can be overridden when scheduling an activity task. # # The value should be a number of seconds (integer) or the symbol # `:none` (implying no timeout). # # @option options [String] :description (nil) A textual description # of the activity type. # def register name, version, options = {} options[:domain] = domain.name options[:name] = name options[:version] = version duration_opts(options, :default_task_heartbeat_timeout, :default_task_schedule_to_close_timeout, :default_task_schedule_to_start_timeout, :default_task_start_to_close_timeout) if priority = options[:default_task_priority] options[:default_task_priority] = priority.to_s end if task_list = options[:default_task_list] options[:default_task_list] = { :name => task_list.to_s } end client.register_activity_type(options) self[name, version] end alias_method :create, :register end end end aws-sdk-v1-1.66.0/lib/aws/simple_workflow/workflow_execution.rb0000644000004100000410000003405512604445426024614 0ustar www-datawww-data# Copyright 2011-2013 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. module AWS class SimpleWorkflow # @attr_reader [Symbol] child_policy The policy to use for the child # workflow executions if this workflow execution is terminated. # The return value will be one of the following values: # # * `:terminate` - the child executions will be terminated. # * `:request_cancel` - a request to cancel will be attempted for each # child execution by recording a WorkflowExecutionCancelRequested # event in its history. It is up to the decider to take appropriate # actions when it receives an execution history with this event. # * `:abandon` - no action will be taken. The child executions will # continue to run. # # @attr_reader [String] start_to_close_timeout The total allowed # duration for this workflow execution. # # The return value will be formatted as an ISO 8601 duration (e.g. # 'PnYnMnDTnHnMnS'). # # @attr_reader [String] task_list The task list used for the decision # tasks generated for this workflow execution. # # @attr_reader [String] task_priority The task priority used for the decision # tasks generated for this workflow execution. # # @attr_reader [String] task_start_to_close_timeout The maximum duration # allowed for decision tasks for this workflow execution. # # The return value will be formatted as an ISO 8601 duration (e.g. # 'PnYnMnDTnHnMnS'). # # @attr_reader [Time,nil] closed_at The time when the workflow execution # was closed. Returns nil if this execution is not closed. # # @attr_reader [Time] started_at The time when the execution was started. # # @attr_reader [Time,nil] latest_activity_task_scheduled_at The time # when the last activity task was scheduled for this workflow execution. # You can use this information to determine if the workflow has not # made progress for an unusually long period of time and might # require a corrective action. # # @attr_reader [String,nil] latest_execution_context The latest execution # context provided by the decider for this workflow execution. A decider # can provide an execution context, which is a free form string, when # closing a decision task. # # @attr_reader [Hash] open_counts Returns a hash of counts, including: # `:open_timers`, `:open_child_workflow_executions`, `:open_decision_tasks`, # and `:open_activity_tasks`. # class WorkflowExecution < Resource def initialize domain, workflow_id, run_id, options = {} @domain = domain @workflow_id = workflow_id @run_id = run_id super end # @return [Domain] The domain this workflow execution was started in. attr_reader :domain # @return [String] The workflow id of this execution. attr_reader :workflow_id # @return [String] The run id of this execution. attr_reader :run_id config_attribute :child_policy, :to_sym => true config_attribute :execution_start_to_close_timeout, :duration => true config_attribute :task_list do translates_output{|v| v['name'] } end config_attribute :task_priority do translates_output{|v| v.to_i } end config_attribute :task_start_to_close_timeout, :duration => true info_attribute :cancel_requested info_attribute :close_status, :to_sym => true protected :close_status info_attribute :closed_at, :from => 'closeTimestamp', :timestamp => true info_attribute :execution_status, :to_sym => true protected :execution_status info_attribute :parent_details, :from => 'parent', :static => true protected :parent_details info_attribute :started_at, :from => 'startTimestamp', :timestamp => true, :static => true info_attribute :tag_list, :static => true protected :tag_list info_attribute :type_details, :from => 'workflowType', :static => true protected :type_details attribute :latest_activity_task_scheduled_at, :from => 'latestActivityTaskTimestamp', :timestamp => true attribute :latest_execution_context attribute :open_counts do translates_output do |hash| hash.inject({}) do |h,(k,v)| h[Core::Inflection.ruby_name(k).to_sym] = v; h end end end # list_workflow_executions provides ONLY type attributes provider( :list_open_workflow_executions, :list_closed_workflow_executions ) do |provider| provider.provides *info_attributes.keys provider.find do |resp| execution = { 'workflowId' => workflow_id, 'runId' => run_id } resp.data['executionInfos'].find do |desc| desc['execution'] == execution end end end # describe_workflow_execution provides ALL attributes provider(:describe_workflow_execution) do |provider| provider.provides *attributes.keys provider.find do |resp| execution = { 'workflowId' => workflow_id, 'runId' => run_id } d = resp.data if d['executionInfo']['execution'] == execution d.merge(d['executionInfo']).merge(d['executionConfiguration']) else nil end end end # @return [Symbol] Returns the status of this execution. Possible # return values are: # # * `:open` - The execution is still running. # * `:completed` - The execution was successfully completed. # * `:canceled` - The execution was canceled, cancellation allows # the implementation to gracefully clean up before the execution # is closed. # * `:failed` - The execution failed to complete. # and was automatically timed out. # * `:continued_as_new` - The execution is logically continued. This # means the current execution was completed and a new execution # was started to carry on the workflow. # * `:terminated` - The execution was force terminated. # * `:timed_out` - The execution did not complete in the allotted # time and was automatically timed out. # def status AWS.memoize do execution_status == :open ? :open : (close_status || :closed) end end # @return [Boolean] Returns true if a request was made to cancel # this workflow execution. def cancel_requested? cancel_requested end # @return [Boolean] Returns true if the workflow execution is still open. def open? status == :open end # @return [Boolean] Returns true if the workflow execution is closed. def closed? !open? end # @return [Boolean] Returns true if this workflow execution has an # open decision task. def open_child_workflow_execution_count open_counts[:open_child_workflow_executions] end # @return [Integer] Returns the number of open activity tasks. def open_activity_task_count open_counts[:open_activity_tasks] end # @return [Integer] Returns the number of open timers. def open_timer_count open_counts[:open_timers] end # @return [Integer] Returns the number of closed activity tasks. def open_decision_task_count open_counts[:open_decision_tasks] end # @return [Array] Returns an array of tags assigned to this # execution. def tags tag_list || [] end # @return [HistoryEventCollection] Returns a collection that enumerates # history events for this workflow execution. def history_events HistoryEventCollection.new(self) end alias_method :events, :history_events # @return [WorkflowType] Returns the type of this workflow execution. def workflow_type type = self.type_details WorkflowType.new(domain, type['name'], type['version']) end # @return [WorkflowExecution,nil] Returns the parent workflow execution # (if there is one). def parent if parent = self.parent_details domain.workflow_executions[parent['workflowId'],parent['runId']] else nil end end # Records a WorkflowExecutionSignaled event in the workflow execution # history and creates a decision task for the workflow execution. # # workflow_execution.signal('signal_name', :input => '...') # # @param [String] signal_name The name of the signal. This name must be # meaningful to the target workflow. # # @param [Hash] options # # @option options [String] :input (nil) Data to attach to the # WorkflowExecutionSignaled event in the target workflow # execution's history. # # @return [nil] # def signal signal_name, options = {} options[:run_id] = run_id domain.workflow_executions.signal(workflow_id, signal_name, options) end # Records a WorkflowExecutionCancelRequested event in the currently # running workflow execution. This logically requests the cancellation # of the workflow execution as a whole. It is up to the decider to # take appropriate actions when it receives an execution history # with this event. # # @note Because this action allows the workflow to properly clean up # and gracefully close, it should be used instead of {#terminate} # when possible. # # @return [nil] # def request_cancel options = { :run_id => run_id } domain.workflow_executions.request_cancel(workflow_id, options) end # Records a WorkflowExecutionTerminated event and forces closure of # the workflow execution. The child policy, registered with the # workflow type or specified when starting this execution, is applied # to any open child workflow executions of this workflow execution. # # @note If the workflow execution was in progress, it is terminated # immediately. # # @note You should consider canceling the workflow execution # instead because it allows the workflow to gracefully close # while terminate does not. # # @param [Hash] options # # @option options [Symbol] :child_policy (nil) # If set, specifies the policy to use for the child workflow # executions of the workflow execution being terminated. This # policy overrides the default child policy. Valid policies include: # # * `:terminate` - the child executions will be terminated. # # * `:request_cancel` - a request to cancel will be attempted for each # child execution by recording a WorkflowExecutionCancelRequested # event in its history. It is up to the decider to take appropriate # actions when it receives an execution history with this event. # # * `:abandon` - no action will be taken. The child executions will # continue to run. # # @option options [String] :details (nil) Optional details for # terminating the workflow execution. # # @option options [String] :reason (nil) An optional descriptive # reason for terminating the workflow execution. # # @return [nil] # def terminate options = {} options[:run_id] = run_id domain.workflow_executions.terminate(workflow_id, options) end # Counts the number of executions that share the same workflow id. # # @note See {WorkflowExecutionCollection#count} for a broader count. # # @note This operation is eventually consistent. The results are best # effort and may not exactly reflect recent updates and changes. # # @param [Hash] options # # @option options [Symbol] :status (:open) Specifies that # status of the workflow executions to count. Defaults to # open workflows. # # * `:open` # * `:closed` # # @option options [Array