aws-sdk-v1-1.67.0/ 0000755 0000041 0000041 00000000000 13136075146 013540 5 ustar www-data www-data aws-sdk-v1-1.67.0/bin/ 0000755 0000041 0000041 00000000000 13136075146 014310 5 ustar www-data www-data aws-sdk-v1-1.67.0/bin/aws-rb 0000755 0000041 0000041 00000010257 13136075146 015436 0 ustar www-data www-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.67.0/LICENSE.txt 0000644 0000041 0000041 00000001045 13136075146 015363 0 ustar www-data www-data Copyright 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.67.0/lib/ 0000755 0000041 0000041 00000000000 13136075146 014306 5 ustar www-data www-data aws-sdk-v1-1.67.0/lib/aws.rb 0000644 0000041 0000041 00000001120 13136075146 015417 0 ustar www-data www-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.67.0/lib/aws/ 0000755 0000041 0000041 00000000000 13136075146 015100 5 ustar www-data www-data aws-sdk-v1-1.67.0/lib/aws/sts/ 0000755 0000041 0000041 00000000000 13136075146 015711 5 ustar www-data www-data aws-sdk-v1-1.67.0/lib/aws/sts/errors.rb 0000644 0000041 0000041 00000001234 13136075146 017552 0 ustar www-data www-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.67.0/lib/aws/sts/federated_session.rb 0000644 0000041 0000041 00000003521 13136075146 021725 0 ustar www-data www-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.67.0/lib/aws/sts/policy.rb 0000644 0000041 0000041 00000001415 13136075146 017536 0 ustar www-data www-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.67.0/lib/aws/sts/client.rb 0000644 0000041 0000041 00000003070 13136075146 017514 0 ustar www-data www-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.67.0/lib/aws/sts/config.rb 0000644 0000041 0000041 00000001213 13136075146 017500 0 ustar www-data www-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.67.0/lib/aws/sts/session.rb 0000644 0000041 0000041 00000002676 13136075146 017734 0 ustar www-data www-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.67.0/lib/aws/sqs/ 0000755 0000041 0000041 00000000000 13136075146 015706 5 ustar www-data www-data aws-sdk-v1-1.67.0/lib/aws/sqs/errors.rb 0000644 0000041 0000041 00000007337 13136075146 017561 0 ustar www-data www-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.67.0/lib/aws/sqs/policy.rb 0000644 0000041 0000041 00000003003 13136075146 017526 0 ustar www-data www-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.67.0/lib/aws/sqs/client.rb 0000644 0000041 0000041 00000002702 13136075146 017512 0 ustar www-data www-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.67.0/lib/aws/sqs/received_message.rb 0000644 0000041 0000041 00000015512 13136075146 021531 0 ustar www-data www-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.67.0/lib/aws/sqs/received_sns_message.rb 0000644 0000041 0000041 00000006432 13136075146 022415 0 ustar www-data www-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.67.0/lib/aws/sqs/config.rb 0000644 0000041 0000041 00000001307 13136075146 017501 0 ustar www-data www-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.67.0/lib/aws/sqs/queue_collection.rb 0000644 0000041 0000041 00000014057 13136075146 021601 0 ustar www-data www-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.67.0/lib/aws/sqs/queue.rb 0000644 0000041 0000041 00000071617 13136075146 017373 0 ustar www-data www-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.67.0/lib/aws/emr/ 0000755 0000041 0000041 00000000000 13136075146 015663 5 ustar www-data www-data aws-sdk-v1-1.67.0/lib/aws/emr/errors.rb 0000644 0000041 0000041 00000001234 13136075146 017524 0 ustar www-data www-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.67.0/lib/aws/emr/instance_group_collection.rb 0000644 0000041 0000041 00000005212 13136075146 023443 0 ustar www-data www-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.67.0/lib/aws/emr/job_flow_collection.rb 0000644 0000041 0000041 00000012177 13136075146 022234 0 ustar www-data www-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.67.0/lib/aws/emr/client.rb 0000644 0000041 0000041 00000001644 13136075146 017473 0 ustar www-data www-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.67.0/lib/aws/emr/config.rb 0000644 0000041 0000041 00000001230 13136075146 017451 0 ustar www-data www-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.67.0/lib/aws/emr/instance_group.rb 0000644 0000041 0000041 00000007133 13136075146 021234 0 ustar www-data www-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.67.0/lib/aws/emr/job_flow.rb 0000644 0000041 0000041 00000022676 13136075146 020026 0 ustar www-data www-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.67.0/lib/aws/elasticache.rb 0000644 0000041 0000041 00000002661 13136075146 017677 0 ustar www-data www-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.67.0/lib/aws/simple_db.rb 0000644 0000041 0000041 00000015363 13136075146 017373 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/ 0000755 0000041 0000041 00000000000 13136075146 017550 5 ustar www-data www-data aws-sdk-v1-1.67.0/lib/aws/auto_scaling/scaling_policy.rb 0000644 0000041 0000041 00000007650 13136075146 023104 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/errors.rb 0000644 0000041 0000041 00000001244 13136075146 021412 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/scheduled_action.rb 0000644 0000041 0000041 00000007054 13136075146 023400 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/activity_collection.rb 0000644 0000041 0000041 00000004235 13136075146 024150 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/activity.rb 0000644 0000041 0000041 00000004765 13136075146 021745 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/instance_collection.rb 0000644 0000041 0000041 00000003523 13136075146 024117 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/notification_configuration_collection.rb 0000644 0000041 0000041 00000014050 13136075146 027725 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/client.rb 0000644 0000041 0000041 00000002566 13136075146 021364 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/group_collection.rb 0000644 0000041 0000041 00000005401 13136075146 023444 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/scaling_policy_options.rb 0000644 0000041 0000041 00000004331 13136075146 024650 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/tag_collection.rb 0000644 0000041 0000041 00000006671 13136075146 023075 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/config.rb 0000644 0000041 0000041 00000001244 13136075146 021343 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/notification_configuration.rb 0000644 0000041 0000041 00000004652 13136075146 025521 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/tag.rb 0000644 0000041 0000041 00000003007 13136075146 020650 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/scheduled_action_collection.rb 0000644 0000041 0000041 00000013574 13136075146 025617 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/group.rb 0000644 0000041 0000041 00000030117 13136075146 021233 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/group_options.rb 0000644 0000041 0000041 00000013212 13136075146 023003 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/launch_configuration_collection.rb 0000644 0000041 0000041 00000014546 13136075146 026523 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/instance.rb 0000644 0000041 0000041 00000013456 13136075146 021712 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/scaling_policy_collection.rb 0000644 0000041 0000041 00000004045 13136075146 025312 0 ustar www-data www-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.67.0/lib/aws/auto_scaling/launch_configuration.rb 0000644 0000041 0000041 00000011514 13136075146 024300 0 ustar www-data www-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.67.0/lib/aws/record/ 0000755 0000041 0000041 00000000000 13136075146 016356 5 ustar www-data www-data aws-sdk-v1-1.67.0/lib/aws/record/hash_model/ 0000755 0000041 0000041 00000000000 13136075146 020461 5 ustar www-data www-data aws-sdk-v1-1.67.0/lib/aws/record/hash_model/finder_methods.rb 0000644 0000041 0000041 00000013250 13136075146 024001 0 ustar www-data www-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.67.0/lib/aws/record/hash_model/attributes.rb 0000644 0000041 0000041 00000014107 13136075146 023177 0 ustar www-data www-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.67.0/lib/aws/record/hash_model/scope.rb 0000644 0000041 0000041 00000006356 13136075146 022131 0 ustar www-data www-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.67.0/lib/aws/record/model.rb 0000644 0000041 0000041 00000032311 13136075146 020003 0 ustar www-data www-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.67.0/lib/aws/record/model/ 0000755 0000041 0000041 00000000000 13136075146 017456 5 ustar www-data www-data aws-sdk-v1-1.67.0/lib/aws/record/model/finder_methods.rb 0000644 0000041 0000041 00000020047 13136075146 023000 0 ustar www-data www-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.67.0/lib/aws/record/model/attributes.rb 0000644 0000041 0000041 00000031646 13136075146 022203 0 ustar www-data www-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.67.0/lib/aws/record/model/scope.rb 0000644 0000041 0000041 00000016412 13136075146 021120 0 ustar www-data www-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.67.0/lib/aws/record/errors.rb 0000644 0000041 0000041 00000011203 13136075146 020214 0 ustar www-data www-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.67.0/lib/aws/record/dirty_tracking.rb 0000644 0000041 0000041 00000021220 13136075146 021715 0 ustar www-data www-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.67.0/lib/aws/record/conversion.rb 0000644 0000041 0000041 00000001604 13136075146 021071 0 ustar www-data www-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.67.0/lib/aws/record/abstract_base.rb 0000644 0000041 0000041 00000052055 13136075146 021507 0 ustar www-data www-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.67.0/lib/aws/record/naming.rb 0000644 0000041 0000041 00000001742 13136075146 020160 0 ustar www-data www-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.67.0/lib/aws/record/hash_model.rb 0000644 0000041 0000041 00000013660 13136075146 021014 0 ustar www-data www-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.67.0/lib/aws/record/validator.rb 0000644 0000041 0000041 00000015331 13136075146 020673 0 ustar www-data www-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.67.0/lib/aws/record/attributes.rb 0000644 0000041 0000041 00000027467 13136075146 021111 0 ustar www-data www-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.67.0/lib/aws/record/validators/ 0000755 0000041 0000041 00000000000 13136075146 020526 5 ustar www-data www-data aws-sdk-v1-1.67.0/lib/aws/record/validators/confirmation.rb 0000644 0000041 0000041 00000002324 13136075146 023544 0 ustar www-data www-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.67.0/lib/aws/record/validators/acceptance.rb 0000644 0000041 0000041 00000002457 13136075146 023151 0 ustar www-data www-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.67.0/lib/aws/record/validators/count.rb 0000644 0000041 0000041 00000006001 13136075146 022200 0 ustar www-data www-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.67.0/lib/aws/record/validators/block.rb 0000644 0000041 0000041 00000001727 13136075146 022154 0 ustar www-data www-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.67.0/lib/aws/record/validators/exclusion.rb 0000644 0000041 0000041 00000002260 13136075146 023064 0 ustar www-data www-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.67.0/lib/aws/record/validators/inclusion.rb 0000644 0000041 0000041 00000002727 13136075146 023066 0 ustar www-data www-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.67.0/lib/aws/record/validators/presence.rb 0000644 0000041 0000041 00000002457 13136075146 022667 0 ustar www-data www-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.67.0/lib/aws/record/validators/numericality.rb 0000644 0000041 0000041 00000007537 13136075146 023574 0 ustar www-data www-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.67.0/lib/aws/record/validators/method.rb 0000644 0000041 0000041 00000001653 13136075146 022340 0 ustar www-data www-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.67.0/lib/aws/record/validators/format.rb 0000644 0000041 0000041 00000002703 13136075146 022345 0 ustar www-data www-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.67.0/lib/aws/record/validators/length.rb 0000644 0000041 0000041 00000006201 13136075146 022333 0 ustar www-data www-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.67.0/lib/aws/record/validations.rb 0000644 0000041 0000041 00000073274 13136075146 021235 0 ustar www-data www-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.67.0/lib/aws/record/exceptions.rb 0000644 0000041 0000041 00000003016 13136075146 021064 0 ustar www-data www-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.67.0/lib/aws/record/scope.rb 0000644 0000041 0000041 00000013424 13136075146 020020 0 ustar www-data www-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.67.0/lib/aws/cloud_formation.rb 0000644 0000041 0000041 00000020044 13136075146 020611 0 ustar www-data www-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.67.0/lib/aws/s3/ 0000755 0000041 0000041 00000000000 13136075146 015425 5 ustar www-data www-data aws-sdk-v1-1.67.0/lib/aws/s3/bucket_collection.rb 0000644 0000041 0000041 00000012016 13136075146 021442 0 ustar www-data www-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.67.0/lib/aws/s3/presign_v4.rb 0000644 0000041 0000041 00000010053 13136075146 020031 0 ustar www-data www-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.67.0/lib/aws/s3/object_upload_collection.rb 0000644 0000041 0000041 00000004415 13136075146 023003 0 ustar www-data www-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.67.0/lib/aws/s3/errors.rb 0000644 0000041 0000041 00000005562 13136075146 017276 0 ustar www-data www-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.67.0/lib/aws/s3/bucket_version_collection.rb 0000644 0000041 0000041 00000004276 13136075146 023220 0 ustar www-data www-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.67.0/lib/aws/s3/tree/ 0000755 0000041 0000041 00000000000 13136075146 016364 5 ustar www-data www-data aws-sdk-v1-1.67.0/lib/aws/s3/tree/child_collection.rb 0000644 0000041 0000041 00000006241 13136075146 022212 0 ustar www-data www-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.67.0/lib/aws/s3/tree/leaf_node.rb 0000644 0000041 0000041 00000004660 13136075146 020633 0 ustar www-data www-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.67.0/lib/aws/s3/tree/branch_node.rb 0000644 0000041 0000041 00000003754 13136075146 021164 0 ustar www-data www-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.67.0/lib/aws/s3/tree/parent.rb 0000644 0000041 0000041 00000005210 13136075146 020200 0 ustar www-data www-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.67.0/lib/aws/s3/tree/node.rb 0000644 0000041 0000041 00000001242 13136075146 017635 0 ustar www-data www-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.67.0/lib/aws/s3/uploaded_part.rb 0000644 0000041 0000041 00000004564 13136075146 020606 0 ustar www-data www-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.67.0/lib/aws/s3/bucket_region_cache.rb 0000644 0000041 0000041 00000001571 13136075146 021721 0 ustar www-data www-data require '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.67.0/lib/aws/s3/data_options.rb 0000644 0000041 0000041 00000013071 13136075146 020440 0 ustar www-data www-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.67.0/lib/aws/s3/object_version_collection.rb 0000644 0000041 0000041 00000005442 13136075146 023205 0 ustar www-data www-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.67.0/lib/aws/s3/tree.rb 0000644 0000041 0000041 00000010332 13136075146 016710 0 ustar www-data www-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.67.0/lib/aws/s3/policy.rb 0000644 0000041 0000041 00000005417 13136075146 017260 0 ustar www-data www-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.67.0/lib/aws/s3/paginated_collection.rb 0000644 0000041 0000041 00000003505 13136075146 022124 0 ustar www-data www-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.67.0/lib/aws/s3/presigned_post.rb 0000644 0000041 0000041 00000044427 13136075146 021012 0 ustar www-data www-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
#
# 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.67.0/lib/aws/s3/client.rb 0000644 0000041 0000041 00000236535 13136075146 017246 0 ustar www-data www-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.67.0/lib/aws/s3/cipher_io.rb 0000644 0000041 0000041 00000006545 13136075146 017725 0 ustar www-data www-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.67.0/lib/aws/s3/request.rb 0000644 0000041 0000041 00000002672 13136075146 017451 0 ustar www-data www-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.67.0/lib/aws/s3/s3_object.rb 0000644 0000041 0000041 00000177517 13136075146 017647 0 ustar www-data www-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.67.0/lib/aws/s3/bucket.rb 0000644 0000041 0000041 00000055622 13136075146 017241 0 ustar www-data www-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.67.0/lib/aws/s3/client/ 0000755 0000041 0000041 00000000000 13136075146 016703 5 ustar www-data www-data aws-sdk-v1-1.67.0/lib/aws/s3/client/xml.rb 0000644 0000041 0000041 00000017147 13136075146 020042 0 ustar www-data www-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.67.0/lib/aws/s3/cors_rule_collection.rb 0000644 0000041 0000041 00000013306 13136075146 022165 0 ustar www-data www-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.67.0/lib/aws/s3/config.rb 0000644 0000041 0000041 00000003117 13136075146 017221 0 ustar www-data www-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.67.0/lib/aws/s3/bucket_lifecycle_configuration.rb 0000644 0000041 0000041 00000037113 13136075146 024202 0 ustar www-data www-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.67.0/lib/aws/s3/prefixed_collection.rb 0000644 0000041 0000041 00000005243 13136075146 021777 0 ustar www-data www-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.67.0/lib/aws/s3/bucket_tag_collection.rb 0000644 0000041 0000041 00000005212 13136075146 022275 0 ustar www-data www-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.67.0/lib/aws/s3/encryption_utils.rb 0000644 0000041 0000041 00000011661 13136075146 021371 0 ustar www-data www-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.67.0/lib/aws/s3/region_detection.rb 0000644 0000041 0000041 00000004517 13136075146 021302 0 ustar www-data www-data require '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.67.0/lib/aws/s3/object_metadata.rb 0000644 0000041 0000041 00000006553 13136075146 021071 0 ustar www-data www-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.67.0/lib/aws/s3/access_control_list.rb 0000644 0000041 0000041 00000020465 13136075146 022015 0 ustar www-data www-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.67.0/lib/aws/s3/prefix_and_delimiter_collection.rb 0000644 0000041 0000041 00000002313 13136075146 024341 0 ustar www-data www-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.67.0/lib/aws/s3/website_configuration.rb 0000644 0000041 0000041 00000007126 13136075146 022351 0 ustar www-data www-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.67.0/lib/aws/s3/multipart_upload_collection.rb 0000644 0000041 0000041 00000004377 13136075146 023565 0 ustar www-data www-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.67.0/lib/aws/s3/object_version.rb 0000644 0000041 0000041 00000011166 13136075146 020772 0 ustar www-data www-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.67.0/lib/aws/s3/cors_rule.rb 0000644 0000041 0000041 00000010020 13136075146 017740 0 ustar www-data www-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.67.0/lib/aws/s3/uploaded_part_collection.rb 0000644 0000041 0000041 00000004377 13136075146 023023 0 ustar www-data www-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.67.0/lib/aws/s3/acl_object.rb 0000644 0000041 0000041 00000020532 13136075146 020041 0 ustar www-data www-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}#{element_name}>"
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}#{element_name}>"
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}#{list_element}>"
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.67.0/lib/aws/s3/object_collection.rb 0000644 0000041 0000041 00000024123 13136075146 021435 0 ustar www-data www-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.67.0/lib/aws/s3/multipart_upload.rb 0000644 0000041 0000041 00000026251 13136075146 021345 0 ustar www-data www-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.67.0/lib/aws/s3/acl_options.rb 0000644 0000041 0000041 00000015444 13136075146 020274 0 ustar www-data www-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.67.0/lib/aws/emr.rb 0000644 0000041 0000041 00000005157 13136075146 016220 0 ustar www-data www-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.67.0/lib/aws/core/ 0000755 0000041 0000041 00000000000 13136075146 016030 5 ustar www-data www-data aws-sdk-v1-1.67.0/lib/aws/core/endpoints.rb 0000644 0000041 0000041 00000002137 13136075146 020363 0 ustar www-data www-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.67.0/lib/aws/core/meta_utils.rb 0000644 0000041 0000041 00000002256 13136075146 020530 0 ustar www-data www-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.67.0/lib/aws/core/query_request_builder.rb 0000644 0000041 0000041 00000002572 13136075146 023006 0 ustar www-data www-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.67.0/lib/aws/core/rest_error_parser.rb 0000644 0000041 0000041 00000001230 13136075146 022113 0 ustar www-data www-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.67.0/lib/aws/core/log_formatter.rb 0000644 0000041 0000041 00000033250 13136075146 021224 0 ustar www-data www-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: