elastic-mapreduce 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +51 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +16 -0
- data/LICENSE.txt +393 -0
- data/NOTICE.txt +26 -0
- data/README +1007 -0
- data/Rakefile +35 -0
- data/VERSION +1 -0
- data/bin/elastic-mapreduce +27 -0
- data/cacert.pem +280 -0
- data/elastic-mapreduce.gemspec +104 -0
- data/lib/amazon/aws/exceptions.rb +211 -0
- data/lib/amazon/coral/awsquery.rb +128 -0
- data/lib/amazon/coral/awsquerychainhelper.rb +92 -0
- data/lib/amazon/coral/awsqueryhandler.rb +170 -0
- data/lib/amazon/coral/awsqueryurihandler.rb +34 -0
- data/lib/amazon/coral/call.rb +68 -0
- data/lib/amazon/coral/dispatcher.rb +33 -0
- data/lib/amazon/coral/ec2client.rb +91 -0
- data/lib/amazon/coral/elasticmapreduceclient.rb +198 -0
- data/lib/amazon/coral/handler.rb +20 -0
- data/lib/amazon/coral/httpdelegationhelper.rb +27 -0
- data/lib/amazon/coral/httpdestinationhandler.rb +36 -0
- data/lib/amazon/coral/httphandler.rb +124 -0
- data/lib/amazon/coral/identityhandler.rb +32 -0
- data/lib/amazon/coral/job.rb +25 -0
- data/lib/amazon/coral/logfactory.rb +35 -0
- data/lib/amazon/coral/option.rb +70 -0
- data/lib/amazon/coral/orchestrator.rb +49 -0
- data/lib/amazon/coral/querystringmap.rb +93 -0
- data/lib/amazon/coral/service.rb +130 -0
- data/lib/amazon/coral/simplelog.rb +98 -0
- data/lib/amazon/coral/urlencoding.rb +19 -0
- data/lib/amazon/coral/v0signaturehandler.rb +33 -0
- data/lib/amazon/coral/v0signaturehelper.rb +83 -0
- data/lib/amazon/coral/v1signaturehandler.rb +32 -0
- data/lib/amazon/coral/v1signaturehelper.rb +58 -0
- data/lib/amazon/coral/v2signaturehandler.rb +46 -0
- data/lib/amazon/coral/v2signaturehelper.rb +76 -0
- data/lib/amazon/retry_delegator.rb +66 -0
- data/lib/amazon/stderr_logger.rb +23 -0
- data/lib/client.rb +117 -0
- data/lib/commands.rb +1690 -0
- data/lib/credentials.rb +86 -0
- data/lib/ec2_client_wrapper.rb +73 -0
- data/lib/json/lexer.rb +294 -0
- data/lib/json/objects.rb +200 -0
- data/lib/json.rb +58 -0
- data/lib/simple_executor.rb +11 -0
- data/lib/simple_logger.rb +38 -0
- data/lib/uuidtools/version.rb +32 -0
- data/lib/uuidtools.rb +655 -0
- data/run_tests.rb +8 -0
- data/samples/freebase/code/freebase_jobflow.json +44 -0
- data/samples/similarity/lastfm_jobflow.json +78 -0
- data/samples/wordSplitter.py +18 -0
- data/tests/commands_test.rb +587 -0
- data/tests/credentials.json +7 -0
- data/tests/example.json +14 -0
- metadata +154 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2008-2010 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
|
|
4
|
+
require 'uri'
|
|
5
|
+
require 'amazon/coral/identityhandler'
|
|
6
|
+
require 'amazon/coral/httpdestinationhandler'
|
|
7
|
+
require 'amazon/coral/awsqueryhandler'
|
|
8
|
+
require 'amazon/coral/v0signaturehandler'
|
|
9
|
+
require 'amazon/coral/v1signaturehandler'
|
|
10
|
+
require 'amazon/coral/v2signaturehandler'
|
|
11
|
+
require 'amazon/coral/awsqueryurihandler'
|
|
12
|
+
require 'amazon/coral/httphandler'
|
|
13
|
+
require 'amazon/coral/orchestrator'
|
|
14
|
+
|
|
15
|
+
module Amazon
|
|
16
|
+
module Coral
|
|
17
|
+
|
|
18
|
+
class AwsQuery
|
|
19
|
+
|
|
20
|
+
@@identity_arg_keys = [:aws_access_key, :aws_secret_key, :http_authorization, :http_client_x509_cert, :http_client_x509_key]
|
|
21
|
+
@@recognized_arg_keys = [:endpoint, :uri, :signature_algorithm, :ca_file, :verbose,
|
|
22
|
+
:aws_access_key, :aws_secret_key, :http_authorization, :http_client_x509_cert, :http_client_x509_key,
|
|
23
|
+
:timeout, :connect_timeout]
|
|
24
|
+
|
|
25
|
+
# Creates an Orchestrator capable of processing AWS/QUERY requests. Possible arguments include:
|
|
26
|
+
# [:endpoint]
|
|
27
|
+
# The HTTP URL at which the service is located.
|
|
28
|
+
# [:signature_algorithm]
|
|
29
|
+
# The AWS signature version to be used to sign outgoing requests. Current choices are:
|
|
30
|
+
# :V0 :V1 :V2
|
|
31
|
+
# By default, the version 2 signing algorithm is used.
|
|
32
|
+
# All signing may be disabled by passing the value 'nil' as the signature algorithm.
|
|
33
|
+
# [:aws_access_key]
|
|
34
|
+
# An AWS access key to associate with every outgoing request.
|
|
35
|
+
# This parameter is optional and may be specified on a per-request basis as well.
|
|
36
|
+
# [:aws_secret_key]
|
|
37
|
+
# An AWS secret key to associate with every outgoing request.
|
|
38
|
+
# This parameter is optional and may be specified on a per-request basis as well.
|
|
39
|
+
# [:http_client_x509_cert]
|
|
40
|
+
# A base64-encoded X509 certificate to sign outgoing requests.
|
|
41
|
+
# Requires that the x509 key also be specified.
|
|
42
|
+
# [:http_client_x509_key]
|
|
43
|
+
# A base64-encoded private key for an X509 certificate to sign outgoing requests.
|
|
44
|
+
# Requires that the x509 certificate also be specified.
|
|
45
|
+
# [:http_authorization]
|
|
46
|
+
# The content of an http-authorization header to send with the request.
|
|
47
|
+
# Used for services which require HTTP basic authentication.
|
|
48
|
+
# [:ca_file]
|
|
49
|
+
# A Certificate Authority file to pass to the HttpHandler.
|
|
50
|
+
# [:timeout]
|
|
51
|
+
# The socket read timeout to use during service calls (see HttpHandler for details)
|
|
52
|
+
# [:connect_timeout]
|
|
53
|
+
# A timeout to use for establishing a connection to the service (see HttpHandler for details)
|
|
54
|
+
# [:verbose]
|
|
55
|
+
# A verbosity flag to pass to the HttpHandler.
|
|
56
|
+
#
|
|
57
|
+
# Example usage:
|
|
58
|
+
# orchestrator = AwsQuery.new_orchestrator(:endpoint => "http://localhost:8000", :signature_algorithm => :V2)
|
|
59
|
+
# client = ExampleClient.new(orchestrator)
|
|
60
|
+
def AwsQuery.new_orchestrator(args)
|
|
61
|
+
check_args(args)
|
|
62
|
+
return Orchestrator.new(new_chain(args))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
def AwsQuery.new_chain(args)
|
|
67
|
+
# remap args, add defaults where necessary:
|
|
68
|
+
|
|
69
|
+
# support deprecated :uri mechanism of specifying service endpoint
|
|
70
|
+
args[:endpoint] = args[:uri] if args[:endpoint].nil?
|
|
71
|
+
|
|
72
|
+
# default to V2 if no algorithm is specified
|
|
73
|
+
args[:signature_algorithm] = :V2 if args[:signature_algorithm].nil?
|
|
74
|
+
|
|
75
|
+
# support the deprecated mechanism for specifying AWS account information
|
|
76
|
+
args[:aws_access_key] = args[:access_key] if !args.has_key?(:aws_access_key) && args.has_key?(:access_key)
|
|
77
|
+
args[:aws_secret_key] = args[:secret_key] if !args.has_key?(:aws_secret_key) && args.has_key?(:secret_key)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# build up the chain:
|
|
82
|
+
chain = []
|
|
83
|
+
|
|
84
|
+
# allow user to preload identity attributes to be used on all requests
|
|
85
|
+
identity_args = {}
|
|
86
|
+
@@identity_arg_keys.each {|k|
|
|
87
|
+
identity_args[k] = args[k] if args.has_key?(k)
|
|
88
|
+
}
|
|
89
|
+
chain << IdentityHandler.new(identity_args) unless identity_args.empty?
|
|
90
|
+
|
|
91
|
+
# set the remote endpoint
|
|
92
|
+
chain << HttpDestinationHandler.new(args[:endpoint])
|
|
93
|
+
|
|
94
|
+
# use the AwsQuery protocol
|
|
95
|
+
chain << AwsQueryHandler.new({:api_version => args[:api_version], :content_type => args[:content_type]})
|
|
96
|
+
|
|
97
|
+
# select a signing algorithm
|
|
98
|
+
case args[:signature_algorithm].to_sym
|
|
99
|
+
when :V0
|
|
100
|
+
chain << V0SignatureHandler.new
|
|
101
|
+
when :V1
|
|
102
|
+
chain << V1SignatureHandler.new
|
|
103
|
+
when :V2
|
|
104
|
+
chain << V2SignatureHandler.new
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# collect the query string and update the destination URL
|
|
108
|
+
chain << AwsQueryUriHandler.new
|
|
109
|
+
|
|
110
|
+
# make connection over HTTP
|
|
111
|
+
chain << HttpHandler.new( {:ca_file => args[:ca_file], :verbose => args[:verbose],
|
|
112
|
+
:timeout => args[:timeout], :connect_timeout => args[:connect_timeout]} )
|
|
113
|
+
|
|
114
|
+
return chain
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def AwsQuery.check_args(args)
|
|
118
|
+
log = LogFactory.getLog('Amazon::Coral::AwsQuery')
|
|
119
|
+
|
|
120
|
+
args.each_key do |key|
|
|
121
|
+
log.info("Unknown argument: #{key}") unless @@recognized_arg_keys.include?(key)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
end
|
|
128
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2008-2010 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
|
|
4
|
+
require 'uri'
|
|
5
|
+
require 'amazon/coral/identityhandler'
|
|
6
|
+
require 'amazon/coral/httpdestinationhandler'
|
|
7
|
+
require 'amazon/coral/awsqueryhandler'
|
|
8
|
+
require 'amazon/coral/v0signaturehandler'
|
|
9
|
+
require 'amazon/coral/v1signaturehandler'
|
|
10
|
+
require 'amazon/coral/v2signaturehandler'
|
|
11
|
+
require 'amazon/coral/awsqueryurihandler'
|
|
12
|
+
require 'amazon/coral/httphandler'
|
|
13
|
+
|
|
14
|
+
module Amazon
|
|
15
|
+
module Coral
|
|
16
|
+
|
|
17
|
+
# Constructs a handler chain appropriate for issuing requests using the AWS/QUERY protocol.
|
|
18
|
+
# This class is deprecated in favor of the use of the AwsQuery class. Clients generated with
|
|
19
|
+
# up-to-date versions of the generator will no longer depend on this class.
|
|
20
|
+
class AwsQueryChainHelper < Array
|
|
21
|
+
|
|
22
|
+
@@identity_arg_keys = [:aws_access_key, :aws_secret_key, :http_authorization, :http_client_x509_cert, :http_client_x509_key]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Creates a chain. Possible arguments are:
|
|
26
|
+
# [:endpoint]
|
|
27
|
+
# The HTTP URL at which the service is located.
|
|
28
|
+
# [:signature_algorithm]
|
|
29
|
+
# The AWS signature version to be used to sign outgoing requests. Current choices are:
|
|
30
|
+
# :V0 :V1 :V2
|
|
31
|
+
# [:aws_access_key]
|
|
32
|
+
# An AWS access key to associate with every outgoing request.
|
|
33
|
+
# This parameter is optional and may be specified on a per-request basis as well.
|
|
34
|
+
# [:aws_secret_key]
|
|
35
|
+
# An AWS secret key to associate with every outgoing request.
|
|
36
|
+
# This parameter is optional and may be specified on a per-request basis as well.
|
|
37
|
+
# [:ca_file]
|
|
38
|
+
# A Certificate Authority file to pass to the HttpHandler.
|
|
39
|
+
# [:verbose]
|
|
40
|
+
# A verbosity flag to pass to the HttpHandler.
|
|
41
|
+
def initialize(args)
|
|
42
|
+
|
|
43
|
+
# remap args, add defaults where necessary:
|
|
44
|
+
|
|
45
|
+
# support deprecated :uri mechanism of specifying service endpoint
|
|
46
|
+
args[:endpoint] = args[:uri] if args[:endpoint].nil?
|
|
47
|
+
|
|
48
|
+
# default to V2 if no algorithm is specified
|
|
49
|
+
args[:signature_algorithm] = :V2 if args[:signature_algorithm].nil?
|
|
50
|
+
|
|
51
|
+
# support the deprecated mechanism for specifying AWS account information
|
|
52
|
+
args[:aws_access_key] = args[:access_key] if !args.has_key?(:aws_access_key) && args.has_key?(:access_key)
|
|
53
|
+
args[:aws_secret_key] = args[:secret_key] if !args.has_key?(:aws_secret_key) && args.has_key?(:secret_key)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# build up the chain:
|
|
58
|
+
|
|
59
|
+
# allow user to preload identity attributes to be used on all requests
|
|
60
|
+
identity_args = {}
|
|
61
|
+
@@identity_arg_keys.each {|k|
|
|
62
|
+
identity_args[k] = args[k] if args.has_key?(k)
|
|
63
|
+
}
|
|
64
|
+
self << IdentityHandler.new(identity_args) unless identity_args.empty?
|
|
65
|
+
|
|
66
|
+
# set the remote endpoint
|
|
67
|
+
self << HttpDestinationHandler.new(args[:endpoint])
|
|
68
|
+
|
|
69
|
+
# use the AwsQuery protocol
|
|
70
|
+
self << AwsQueryHandler.new
|
|
71
|
+
|
|
72
|
+
# select a signing algorithm
|
|
73
|
+
case args[:signature_algorithm].to_sym
|
|
74
|
+
when :V0
|
|
75
|
+
self << V0SignatureHandler.new
|
|
76
|
+
when :V1
|
|
77
|
+
self << V1SignatureHandler.new
|
|
78
|
+
when :V2
|
|
79
|
+
self << V2SignatureHandler.new
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# collect the query string and update the destination URL
|
|
83
|
+
self << AwsQueryUriHandler.new
|
|
84
|
+
|
|
85
|
+
# make connection over HTTP
|
|
86
|
+
self << HttpHandler.new( {:ca_file => args[:ca_file], :verbose => args[:verbose]} )
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2008-2010 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
|
|
4
|
+
require 'json/lexer'
|
|
5
|
+
require 'json/objects'
|
|
6
|
+
require 'rexml/document'
|
|
7
|
+
require 'amazon/coral/handler'
|
|
8
|
+
require 'amazon/coral/querystringmap'
|
|
9
|
+
require 'amazon/coral/logfactory'
|
|
10
|
+
require 'amazon/aws/exceptions'
|
|
11
|
+
|
|
12
|
+
module Amazon
|
|
13
|
+
module Coral
|
|
14
|
+
|
|
15
|
+
class AwsQueryHandler < Handler
|
|
16
|
+
|
|
17
|
+
def initialize(args = {})
|
|
18
|
+
@api_version = args[:api_version]
|
|
19
|
+
@content_type = args[:content_type]
|
|
20
|
+
|
|
21
|
+
@log = LogFactory.getLog('Amazon::Coral::AwsQueryHandler')
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def before(job)
|
|
25
|
+
request = job.request
|
|
26
|
+
|
|
27
|
+
operation_name = request[:operation_name]
|
|
28
|
+
|
|
29
|
+
query_string_map = QueryStringMap.new(request[:value])
|
|
30
|
+
query_string_map['Action'] = operation_name.to_s
|
|
31
|
+
if @content_type then
|
|
32
|
+
query_string_map['ContentType'] = @content_type
|
|
33
|
+
end
|
|
34
|
+
if @api_version then
|
|
35
|
+
query_string_map['Version'] = @api_version
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
request[:query_string_map] = query_string_map
|
|
39
|
+
request[:http_verb] = 'POST'
|
|
40
|
+
|
|
41
|
+
@log.info "Making request to operation #{operation_name} with parameters #{query_string_map}"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def after(job)
|
|
45
|
+
operation_name = job.request[:operation_name]
|
|
46
|
+
|
|
47
|
+
reply = job.reply
|
|
48
|
+
|
|
49
|
+
@log.info "Received response body: #{reply[:value]}"
|
|
50
|
+
|
|
51
|
+
json_result = nil
|
|
52
|
+
begin
|
|
53
|
+
if @content_type == 'JSON' then
|
|
54
|
+
json_result = JSON::Lexer.new(reply[:value]).nextvalue
|
|
55
|
+
reply[:value] = get_value(operation_name, json_result)
|
|
56
|
+
else
|
|
57
|
+
reply[:value] = convert_to_json(reply[:value])
|
|
58
|
+
end
|
|
59
|
+
rescue
|
|
60
|
+
code = reply[:http_status_code]
|
|
61
|
+
message = reply[:http_status_message]
|
|
62
|
+
|
|
63
|
+
raise "#{code} : #{message}" unless code.to_i == 200
|
|
64
|
+
raise "Failed parsing response: #{$!}\n"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
aws_error?(reply[:response], reply[:value]) if @content_type != 'JSON'
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
def get_value(operation_name, json_result)
|
|
72
|
+
# If there was an error, unwrap it and return
|
|
73
|
+
return {"Error" => json_result["Error"]} if json_result["Error"]
|
|
74
|
+
|
|
75
|
+
# Otherwise unwrap the valid response
|
|
76
|
+
json_result = json_result["#{operation_name}Response"]
|
|
77
|
+
json_result = json_result["#{operation_name}Result"]
|
|
78
|
+
return json_result
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
def convert_to_json(document)
|
|
83
|
+
doc = REXML::Document.new(document)
|
|
84
|
+
array = []
|
|
85
|
+
doc.elements.each do |elem|
|
|
86
|
+
array << xml_to_json(elem) if elem.kind_of?(REXML::Element)
|
|
87
|
+
end
|
|
88
|
+
raise "Failed parsing response: #{$!}\n" if array.length > 1
|
|
89
|
+
|
|
90
|
+
return array.first
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
def xml_to_json(parent)
|
|
95
|
+
array = []
|
|
96
|
+
struct = {}
|
|
97
|
+
parent.children.each do |elem|
|
|
98
|
+
if elem.kind_of?(REXML::Element) then
|
|
99
|
+
if elem.name == "item" then
|
|
100
|
+
array << xml_to_json(elem)
|
|
101
|
+
else
|
|
102
|
+
if struct[elem.name] != nil then
|
|
103
|
+
if ! struct[elem.name].is_a?(Array) then
|
|
104
|
+
struct[elem.name] = [ struct[elem.name] ]
|
|
105
|
+
end
|
|
106
|
+
struct[elem.name] << xml_to_json(elem)
|
|
107
|
+
else
|
|
108
|
+
struct[elem.name] = xml_to_json(elem)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
if array.size > 0 then
|
|
114
|
+
return array
|
|
115
|
+
elsif struct.keys.size > 0 then
|
|
116
|
+
return struct
|
|
117
|
+
else
|
|
118
|
+
return parent.text
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
private
|
|
123
|
+
def aws_error?(response, body)
|
|
124
|
+
# This method has been copied and adapted from:
|
|
125
|
+
#--
|
|
126
|
+
# Amazon Web Services EC2 + ELB API Ruby library
|
|
127
|
+
#
|
|
128
|
+
# Ruby Gem Name:: amazon-ec2
|
|
129
|
+
# Author:: Glenn Rempe (mailto:glenn@rempe.us)
|
|
130
|
+
# Copyright:: Copyright (c) 2007-2009 Glenn Rempe
|
|
131
|
+
# License:: Distributes under the same terms as Ruby
|
|
132
|
+
# Home:: http://github.com/grempe/amazon-ec2/tree/master
|
|
133
|
+
#++
|
|
134
|
+
|
|
135
|
+
# return false if we got a HTTP 200 code,
|
|
136
|
+
# otherwise there is some type of error (40x,50x) and
|
|
137
|
+
# we should try to raise an appropriate exception
|
|
138
|
+
# from one of our exception classes defined in
|
|
139
|
+
# exceptions.rb
|
|
140
|
+
return false if response.is_a?(Net::HTTPSuccess)
|
|
141
|
+
|
|
142
|
+
raise RuntimeError, "Unexpected server error. response.body is: #{body}" if response.is_a?(Net::HTTPServerError)
|
|
143
|
+
|
|
144
|
+
# Check that the Error element is in the place we would expect.
|
|
145
|
+
# and if not raise a generic error exception
|
|
146
|
+
unless body['Errors']['Error'].length >= 2
|
|
147
|
+
raise RuntimeError, "Unexpected error format. response.body is: #{body}"
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# An valid error response looks like this:
|
|
151
|
+
# <?xml version="1.0"?><Response><Errors><Error><Code>InvalidParameterCombination</Code><Message>Unknown parameter: foo</Message></Error></ Errors><RequestID>291cef62-3e86-414b-900e-17246eccfae8</RequestID></Response>
|
|
152
|
+
# AWS throws some exception codes that look like Error.SubError. Since we can't name classes this way
|
|
153
|
+
# we need to strip out the '.' in the error 'Code' and we name the error exceptions with this
|
|
154
|
+
# non '.' name as well.
|
|
155
|
+
error_code = body['Errors']['Error']['Code']
|
|
156
|
+
error_message = body['Errors']['Error']['Message']
|
|
157
|
+
|
|
158
|
+
# Raise one of our specific error classes if it exists.
|
|
159
|
+
# otherwise, throw a generic EC2 Error with a few details.
|
|
160
|
+
if AWS.const_defined?(error_code)
|
|
161
|
+
raise AWS.const_get(error_code), error_message
|
|
162
|
+
else
|
|
163
|
+
raise Error, error_message
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
end
|
|
170
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2008-2010 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
|
|
4
|
+
require 'uri'
|
|
5
|
+
require 'amazon/coral/handler'
|
|
6
|
+
require 'amazon/coral/logfactory'
|
|
7
|
+
|
|
8
|
+
module Amazon
|
|
9
|
+
module Coral
|
|
10
|
+
|
|
11
|
+
# Compiles the request URL from AwsQueryHandler and any intervening
|
|
12
|
+
# signature handler.
|
|
13
|
+
class AwsQueryUriHandler < Handler
|
|
14
|
+
def initialize
|
|
15
|
+
@log = LogFactory.getLog('Amazon::Coral::AwsQueryUriHandler')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def before(job)
|
|
19
|
+
http_verb = job.request[:http_verb]
|
|
20
|
+
|
|
21
|
+
if http_verb.nil?
|
|
22
|
+
raise "http_verb must be defined"
|
|
23
|
+
elsif http_verb == 'GET' || http_verb == 'HEAD'
|
|
24
|
+
job.request[:http_uri].query = job.request[:query_string_map].to_s
|
|
25
|
+
else
|
|
26
|
+
job.request[:http_query_map] = job.request[:query_string_map]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
@log.debug "Final request URI: #{job.request[:http_uri]}"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2008-2010 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
|
|
4
|
+
require 'uuidtools'
|
|
5
|
+
|
|
6
|
+
module Amazon
|
|
7
|
+
module Coral
|
|
8
|
+
|
|
9
|
+
class Call
|
|
10
|
+
|
|
11
|
+
# Create a new Call object tied to a specific Dispatcher.
|
|
12
|
+
def initialize(dispatcher)
|
|
13
|
+
@dispatcher = dispatcher
|
|
14
|
+
@identity = {}
|
|
15
|
+
@request_id = nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Specify a hash containing identity information for the outgoing request.
|
|
19
|
+
# This is protocol specific but typically contains account names, certificates or other credentials.
|
|
20
|
+
def identity=(i)
|
|
21
|
+
@identity = i.to_hash
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Retrieve the hash of identity information for the outgoing request.
|
|
25
|
+
# The returned hash is mutable such that callers may add or remove identity information from it.
|
|
26
|
+
def identity
|
|
27
|
+
@identity
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Specify the request ID to attach to the outgoing request. (Internal only)
|
|
31
|
+
def request_id=(r)
|
|
32
|
+
@request_id = r
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Retrieve the request ID returned by the remote service.
|
|
36
|
+
def request_id
|
|
37
|
+
@request_id
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Invoke the remote service and return the result.
|
|
41
|
+
def call(input = {})
|
|
42
|
+
begin
|
|
43
|
+
@request_id = UUID.random_create if @request_id.nil?
|
|
44
|
+
|
|
45
|
+
return @dispatcher.dispatch(self, input)
|
|
46
|
+
rescue Timeout::Error => timeout
|
|
47
|
+
return {
|
|
48
|
+
"Error" => {
|
|
49
|
+
"Type" => "Receiver",
|
|
50
|
+
"Code" => "Timeout",
|
|
51
|
+
"Details" => timeout
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
rescue Exception => e
|
|
55
|
+
return {
|
|
56
|
+
"Error" => {
|
|
57
|
+
"Type" => "Sender",
|
|
58
|
+
"Code" => "InternalFailure",
|
|
59
|
+
"Details" => e
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2008-2010 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
|
|
4
|
+
module Amazon
|
|
5
|
+
module Coral
|
|
6
|
+
|
|
7
|
+
# Dispatches requests to a particular remote service operation.
|
|
8
|
+
class Dispatcher
|
|
9
|
+
|
|
10
|
+
# Instantiates a Dispatcher with the specified Orchestrator and
|
|
11
|
+
# strings declaring the service and operation to which requests
|
|
12
|
+
# will be directed.
|
|
13
|
+
def initialize(orchestrator, service_name, operation_name)
|
|
14
|
+
@orchestrator = orchestrator
|
|
15
|
+
@service_name = service_name
|
|
16
|
+
@operation_name = operation_name
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Invoke the remote service and produce a result for the
|
|
20
|
+
# provided Call object and input hash.
|
|
21
|
+
def dispatch(call, input)
|
|
22
|
+
request = {
|
|
23
|
+
:operation_name => @operation_name, :service_name => @service_name,
|
|
24
|
+
:identity => call.identity, :id => call.request_id, :value => input
|
|
25
|
+
}
|
|
26
|
+
reply = @orchestrator.orchestrate(request)
|
|
27
|
+
|
|
28
|
+
return reply[:value]
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2008-2011 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
|
|
4
|
+
require 'amazon/coral/dispatcher'
|
|
5
|
+
require 'amazon/coral/call'
|
|
6
|
+
require 'amazon/coral/service'
|
|
7
|
+
|
|
8
|
+
module Amazon
|
|
9
|
+
module Coral
|
|
10
|
+
|
|
11
|
+
# Client interface for calling Ec2.
|
|
12
|
+
#
|
|
13
|
+
# The client supports two mechanisms to invoke each remote service call: a simple approach
|
|
14
|
+
# which directly calls the remote service, or a Call based mechanism that allows you to
|
|
15
|
+
# control aspects of the outgoing request such as request-id and identity attributes.
|
|
16
|
+
#
|
|
17
|
+
# Each instance of a client interface is backed by an Orchestrator object which manages
|
|
18
|
+
# the processing of each request to the remote service.
|
|
19
|
+
# Clients can be instantiated with a custom orchestrator or with presets corresponding to
|
|
20
|
+
# particular protocols. Inputs and return values to the direct service-call methods and
|
|
21
|
+
# the Call.call methods are hashes.
|
|
22
|
+
class Ec2Client
|
|
23
|
+
# Construct a new client. Takes an orchestrator through which to process requests.
|
|
24
|
+
# See additional constructors below to use pre-configured orchestrators for specific protocols.
|
|
25
|
+
#
|
|
26
|
+
# [orchestrator]
|
|
27
|
+
# The Orchestrator is responsible for actually making the remote service call. Clients
|
|
28
|
+
# construct requests, hand them off to the orchestrator, and receive responses in return.
|
|
29
|
+
def initialize(orchestrator)
|
|
30
|
+
@allocateAddressDispatcher = Dispatcher.new(orchestrator, 'Ec2', 'AllocateAddress')
|
|
31
|
+
@associateAddressDispatcher = Dispatcher.new(orchestrator, 'Ec2', 'AssociateAddress')
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# Instantiates a call object to invoke the AllocateAddress operation:
|
|
36
|
+
#
|
|
37
|
+
# Example usage:
|
|
38
|
+
# my_call = my_client.newAllocateAddressCall
|
|
39
|
+
# # set identity information if needed
|
|
40
|
+
# my_call.identity[:aws_access_key] = my_access_key
|
|
41
|
+
# my_call.identity[:aws_secret_key] = my_secret_key
|
|
42
|
+
# # make the remote call
|
|
43
|
+
# my_call.call(my_input)
|
|
44
|
+
# # retrieve the request-id returned by the server
|
|
45
|
+
# my_request_id = my_call.request_id
|
|
46
|
+
def newAllocateAddressCall
|
|
47
|
+
Call.new(@allocateAddressDispatcher)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def newAssociateAddressCall
|
|
51
|
+
Call.new(@associateAddressDispatcher)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# Shorthand method to invoke the AllocateAddress operation:
|
|
56
|
+
#
|
|
57
|
+
# Example usage:
|
|
58
|
+
# my_client.AllocateAddress(my_input)
|
|
59
|
+
def AllocateAddress(input = {})
|
|
60
|
+
newAllocateAddressCall.call(input)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Shorthand method to invoke the AssociateAddress operation:
|
|
64
|
+
#
|
|
65
|
+
# Example usage:
|
|
66
|
+
# my_client.AssociateAddress(my_input)
|
|
67
|
+
def AssociateAddress(input = {})
|
|
68
|
+
newAssociateAddressCall.call(input)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
#TODO: Add stubs for all other Ec2 WS operations here, see http://s3.amazonaws.com/ec2-downloads/2010-11-15.ec2.wsdl
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# Instantiates the client with an orchestrator configured for use with AWS/QUERY.
|
|
75
|
+
# Use of this constructor is deprecated in favor of using the AwsQuery class:
|
|
76
|
+
# client = Ec2Client.new(AwsQuery.new_orchestrator(args))
|
|
77
|
+
def Ec2Client.new_aws_query(args)
|
|
78
|
+
require 'amazon/coral/awsquery'
|
|
79
|
+
Ec2Client.new(AwsQuery.new_orchestrator(args))
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# allow running from the command line
|
|
85
|
+
Service.new(:service => 'Ec2', :operations => [
|
|
86
|
+
'AllocateAddress',
|
|
87
|
+
'AssociateAddress'
|
|
88
|
+
]).main if caller.empty?
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|