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,198 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2008-2010 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 ElasticMapReduce.
|
|
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 ElasticMapReduceClient
|
|
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
|
+
@addJobFlowStepsDispatcher = Dispatcher.new(orchestrator, 'ElasticMapReduce', 'AddJobFlowSteps')
|
|
31
|
+
@addInstanceGroupsDispatcher = Dispatcher.new(orchestrator, 'ElasticMapReduce', 'AddInstanceGroups')
|
|
32
|
+
@terminateJobFlowsDispatcher = Dispatcher.new(orchestrator, 'ElasticMapReduce', 'TerminateJobFlows')
|
|
33
|
+
@setTerminationProtectionDispatcher = Dispatcher.new(orchestrator, 'ElasticMapReduce', 'SetTerminationProtection')
|
|
34
|
+
@describeJobFlowsDispatcher = Dispatcher.new(orchestrator, 'ElasticMapReduce', 'DescribeJobFlows')
|
|
35
|
+
@runJobFlowDispatcher = Dispatcher.new(orchestrator, 'ElasticMapReduce', 'RunJobFlow')
|
|
36
|
+
@modifyInstanceGroupsDispatcher = Dispatcher.new(orchestrator, 'ElasticMapReduce', 'ModifyInstanceGroups')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# Instantiates a call object to invoke the AddJobFlowSteps operation:
|
|
41
|
+
#
|
|
42
|
+
# Example usage:
|
|
43
|
+
# my_call = my_client.newAddJobFlowStepsCall
|
|
44
|
+
# # set identity information if needed
|
|
45
|
+
# my_call.identity[:aws_access_key] = my_access_key
|
|
46
|
+
# my_call.identity[:aws_secret_key] = my_secret_key
|
|
47
|
+
# # make the remote call
|
|
48
|
+
# my_call.call(my_input)
|
|
49
|
+
# # retrieve the request-id returned by the server
|
|
50
|
+
# my_request_id = my_call.request_id
|
|
51
|
+
def newAddJobFlowStepsCall
|
|
52
|
+
Call.new(@addJobFlowStepsDispatcher)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Instantiates a call object to invoke the AddInstanceGroups operation:
|
|
56
|
+
#
|
|
57
|
+
# Example usage:
|
|
58
|
+
# my_call = my_client.newAddInstanceGroupsCall
|
|
59
|
+
# # set identity information if needed
|
|
60
|
+
# my_call.identity[:aws_access_key] = my_access_key
|
|
61
|
+
# my_call.identity[:aws_secret_key] = my_secret_key
|
|
62
|
+
# # make the remote call
|
|
63
|
+
# my_call.call(my_input)
|
|
64
|
+
# # retrieve the request-id returned by the server
|
|
65
|
+
# my_request_id = my_call.request_id
|
|
66
|
+
def newAddInstanceGroupsCall
|
|
67
|
+
Call.new(@addInstanceGroupsDispatcher)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Instantiates a call object to invoke the TerminateJobFlows operation:
|
|
71
|
+
#
|
|
72
|
+
# Example usage:
|
|
73
|
+
# my_call = my_client.newTerminateJobFlowsCall
|
|
74
|
+
# # set identity information if needed
|
|
75
|
+
# my_call.identity[:aws_access_key] = my_access_key
|
|
76
|
+
# my_call.identity[:aws_secret_key] = my_secret_key
|
|
77
|
+
# # make the remote call
|
|
78
|
+
# my_call.call(my_input)
|
|
79
|
+
# # retrieve the request-id returned by the server
|
|
80
|
+
# my_request_id = my_call.request_id
|
|
81
|
+
def newTerminateJobFlowsCall
|
|
82
|
+
Call.new(@terminateJobFlowsDispatcher)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Instantiates a call object to invoke the SetTerminationProtection operation:
|
|
86
|
+
def newSetTerminationProtectionCall
|
|
87
|
+
Call.new(@setTerminationProtectionDispatcher)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Instantiates a call object to invoke the DescribeJobFlows operation:
|
|
91
|
+
#
|
|
92
|
+
# Example usage:
|
|
93
|
+
# my_call = my_client.newDescribeJobFlowsCall
|
|
94
|
+
# # set identity information if needed
|
|
95
|
+
# my_call.identity[:aws_access_key] = my_access_key
|
|
96
|
+
# my_call.identity[:aws_secret_key] = my_secret_key
|
|
97
|
+
# # make the remote call
|
|
98
|
+
# my_output = my_call.call(my_input)
|
|
99
|
+
# # retrieve the request-id returned by the server
|
|
100
|
+
# my_request_id = my_call.request_id
|
|
101
|
+
def newDescribeJobFlowsCall
|
|
102
|
+
Call.new(@describeJobFlowsDispatcher)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Instantiates a call object to invoke the RunJobFlow operation:
|
|
106
|
+
#
|
|
107
|
+
# Example usage:
|
|
108
|
+
# my_call = my_client.newRunJobFlowCall
|
|
109
|
+
# # set identity information if needed
|
|
110
|
+
# my_call.identity[:aws_access_key] = my_access_key
|
|
111
|
+
# my_call.identity[:aws_secret_key] = my_secret_key
|
|
112
|
+
# # make the remote call
|
|
113
|
+
# my_output = my_call.call(my_input)
|
|
114
|
+
# # retrieve the request-id returned by the server
|
|
115
|
+
# my_request_id = my_call.request_id
|
|
116
|
+
def newRunJobFlowCall
|
|
117
|
+
Call.new(@runJobFlowDispatcher)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def newModifyInstanceGroupsCall
|
|
121
|
+
Call.new(@modifyInstanceGroupsDispatcher)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# Shorthand method to invoke the AddJobFlowSteps operation:
|
|
126
|
+
#
|
|
127
|
+
# Example usage:
|
|
128
|
+
# my_client.AddJobFlowSteps(my_input)
|
|
129
|
+
def AddJobFlowSteps(input = {})
|
|
130
|
+
newAddJobFlowStepsCall.call(input)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Shorthand method to invoke the AddInstanceGroups operation:
|
|
134
|
+
#
|
|
135
|
+
# Example usage:
|
|
136
|
+
# my_client.AddInstanceGroups(my_input)
|
|
137
|
+
def AddInstanceGroups(input = {})
|
|
138
|
+
newAddInstanceGroupsCall.call(input)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Shorthand method to invoke the TerminateJobFlows operation:
|
|
142
|
+
#
|
|
143
|
+
# Example usage:
|
|
144
|
+
# my_client.TerminateJobFlows(my_input)
|
|
145
|
+
def TerminateJobFlows(input = {})
|
|
146
|
+
newTerminateJobFlowsCall.call(input)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Shorthand method to invoke the SetTerminationProtection operation:
|
|
150
|
+
def SetTerminationProtection(input = {})
|
|
151
|
+
newSetTerminationProtectionCall.call(input)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Shorthand method to invoke the DescribeJobFlows operation:
|
|
155
|
+
#
|
|
156
|
+
# Example usage:
|
|
157
|
+
# my_output = my_client.DescribeJobFlows(my_input)
|
|
158
|
+
def DescribeJobFlows(input = {})
|
|
159
|
+
newDescribeJobFlowsCall.call(input)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Shorthand method to invoke the RunJobFlow operation:
|
|
163
|
+
#
|
|
164
|
+
# Example usage:
|
|
165
|
+
# my_output = my_client.RunJobFlow(my_input)
|
|
166
|
+
def RunJobFlow(input = {})
|
|
167
|
+
newRunJobFlowCall.call(input)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def ModifyInstanceGroups(input = {})
|
|
172
|
+
newModifyInstanceGroupsCall.call(input)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
# Instantiates the client with an orchestrator configured for use with AWS/QUERY.
|
|
177
|
+
# Use of this constructor is deprecated in favor of using the AwsQuery class:
|
|
178
|
+
# client = ElasticMapReduceClient.new(AwsQuery.new_orchestrator(args))
|
|
179
|
+
def ElasticMapReduceClient.new_aws_query(args)
|
|
180
|
+
require 'amazon/coral/awsquery'
|
|
181
|
+
ElasticMapReduceClient.new(AwsQuery.new_orchestrator(args))
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# allow running from the command line
|
|
187
|
+
Service.new(:service => 'ElasticMapReduce', :operations => [
|
|
188
|
+
'AddJobFlowSteps',
|
|
189
|
+
'AddInstanceGroups',
|
|
190
|
+
'TerminateJobFlows',
|
|
191
|
+
'SetTerminationProtection',
|
|
192
|
+
'DescribeJobFlows',
|
|
193
|
+
'RunJobFlow',
|
|
194
|
+
'ModifyInstanceGroups'
|
|
195
|
+
]).main if caller.empty?
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2008-2010 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
|
|
4
|
+
module Amazon
|
|
5
|
+
module Coral
|
|
6
|
+
|
|
7
|
+
class Handler
|
|
8
|
+
|
|
9
|
+
# Operate on the specified Job on the "outbound" side of the execution
|
|
10
|
+
def before(job)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Operation on the specified Job on the "inbound" side of the execution
|
|
14
|
+
def after(job)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2008-2010 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
|
|
4
|
+
module Amazon
|
|
5
|
+
module Coral
|
|
6
|
+
|
|
7
|
+
class HttpDelegationHelper
|
|
8
|
+
def self.add_delegation_token(delegate_identity, request_identity)
|
|
9
|
+
token = ""
|
|
10
|
+
first = true
|
|
11
|
+
|
|
12
|
+
delegate_identity.each do |k,v|
|
|
13
|
+
if(first)
|
|
14
|
+
first = false
|
|
15
|
+
else
|
|
16
|
+
token << ';'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
token << "#{k}=#{v}"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
request_identity[:http_delegation] = token if(token.length > 0)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Copyright 2008-2010 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
|
|
3
|
+
require 'uri'
|
|
4
|
+
require 'amazon/coral/handler'
|
|
5
|
+
require 'amazon/coral/logfactory'
|
|
6
|
+
|
|
7
|
+
module Amazon
|
|
8
|
+
module Coral
|
|
9
|
+
|
|
10
|
+
# Attaches the specified endpoint URI to the outgoing request.
|
|
11
|
+
class HttpDestinationHandler < Handler
|
|
12
|
+
|
|
13
|
+
# Initialize an HttpDestinationHandler with the specified endpoint
|
|
14
|
+
# URI.
|
|
15
|
+
def initialize(endpoint)
|
|
16
|
+
@log = LogFactory.getLog('Amazon::Coral::HttpDestinationHandler')
|
|
17
|
+
|
|
18
|
+
@uri = case endpoint
|
|
19
|
+
when URI
|
|
20
|
+
endpoint
|
|
21
|
+
else
|
|
22
|
+
URI.parse(endpoint)
|
|
23
|
+
end
|
|
24
|
+
@uri.path = '/' if @uri.path.nil? || @uri.path.empty?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def before(job)
|
|
28
|
+
job.request[:http_verb] = 'GET'
|
|
29
|
+
job.request[:http_uri] = @uri.clone
|
|
30
|
+
|
|
31
|
+
@log.debug "Initial request URI #{@uri}"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2008-2010 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
|
|
4
|
+
require 'uri'
|
|
5
|
+
require 'net/http'
|
|
6
|
+
require 'net/https'
|
|
7
|
+
require 'amazon/coral/handler'
|
|
8
|
+
require 'amazon/coral/logfactory'
|
|
9
|
+
|
|
10
|
+
module Amazon
|
|
11
|
+
module Coral
|
|
12
|
+
|
|
13
|
+
# Executes HTTP requests via the Net::HTTP library. Supports HTTP,
|
|
14
|
+
# HTTPS and client X509 certificates.
|
|
15
|
+
class HttpHandler < Handler
|
|
16
|
+
|
|
17
|
+
# Instantiate a new HttpHandler with the specified arguments. Possible arguments include:
|
|
18
|
+
# [:verbose]
|
|
19
|
+
# If true, the handler will output the URI it is requesting to STDOUT.
|
|
20
|
+
# This may be useful for debugging purposes.
|
|
21
|
+
# [:ca_file]
|
|
22
|
+
# This parameter's value points to a valid .pem certificate file to enable the
|
|
23
|
+
# client to validate server certificates when using SSL.
|
|
24
|
+
# If this parameter is not specified, the client operates in insecure mode and does not
|
|
25
|
+
# validate that server certificates come from a trusted source.
|
|
26
|
+
# [:timeout]
|
|
27
|
+
# This value (in seconds) will be used for every socket operation during the request.
|
|
28
|
+
# Note that since a request can involve many socket operations, calls that timeout may
|
|
29
|
+
# actually take more time than this value. If unspecified, defaults to 5.0 seconds.
|
|
30
|
+
# A value of zero will result in an infinite timeout.
|
|
31
|
+
# [:connect_timeout]
|
|
32
|
+
# This value (in seconds) will be used as the timeout for opening a connection to the
|
|
33
|
+
# service. If unspecified, defaults to 5.0 seconds. A value of zero will result in
|
|
34
|
+
# an infinite timeout.
|
|
35
|
+
def initialize(args = {})
|
|
36
|
+
@log = LogFactory.getLog('Amazon::Coral::HttpHandler')
|
|
37
|
+
|
|
38
|
+
@verbose = args[:verbose]
|
|
39
|
+
@ca_file = args[:ca_file]
|
|
40
|
+
@connect_timeout = args[:connect_timeout]
|
|
41
|
+
@timeout = args[:timeout]
|
|
42
|
+
|
|
43
|
+
@connect_timeout = 5.0 if @connect_timeout.nil?
|
|
44
|
+
@timeout = 5.0 if @timeout.nil?
|
|
45
|
+
|
|
46
|
+
raise ArgumentError, "connect_timeout must be non-negative" if @connect_timeout < 0
|
|
47
|
+
raise ArgumentError, "timeout must be non-negative" if @timeout < 0
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def before(job)
|
|
51
|
+
identity = job.request[:identity]
|
|
52
|
+
request_id = job.request[:id]
|
|
53
|
+
uri = job.request[:http_uri]
|
|
54
|
+
verb = job.request[:http_verb]
|
|
55
|
+
query_map = job.request[:http_query_map]
|
|
56
|
+
|
|
57
|
+
verb = 'GET' if verb.nil?
|
|
58
|
+
|
|
59
|
+
headers = {}
|
|
60
|
+
headers['x-amzn-RequestId'] = "#{request_id}"
|
|
61
|
+
headers['x-amzn-Delegation'] = identity[:http_delegation] unless identity[:http_delegation].nil?
|
|
62
|
+
headers['Authorization'] = identity[:http_authorization] unless identity[:http_authorization].nil?
|
|
63
|
+
headers['Host'] = job.request[:http_host] unless job.request[:http_host].nil?
|
|
64
|
+
headers['User-Agent'] = 'ruby-client'
|
|
65
|
+
|
|
66
|
+
result = http_request(uri, headers, verb, query_map, identity[:http_client_x509], identity[:http_client_x509_key])
|
|
67
|
+
|
|
68
|
+
@log.info "Response code: #{result.code}"
|
|
69
|
+
|
|
70
|
+
job.reply[:response] = result
|
|
71
|
+
job.reply[:value] = result.body
|
|
72
|
+
job.reply[:http_status_code] = result.code
|
|
73
|
+
job.reply[:http_status_message] = result.message
|
|
74
|
+
job.reply[:http_content] = nil # TODO: get content-type header
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
def http_request(uri, headers, verb, query_map = nil, cert = nil, key = nil)
|
|
79
|
+
if @verbose then
|
|
80
|
+
puts "Requesting URL:\n#{uri}\nQuery string:\n#{query_map}\nHeaders:\n#{headers}\n"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
84
|
+
http.read_timeout = @timeout;
|
|
85
|
+
http.open_timeout = @connect_timeout;
|
|
86
|
+
|
|
87
|
+
if(uri.scheme == 'https')
|
|
88
|
+
# enable SSL
|
|
89
|
+
http.use_ssl = true
|
|
90
|
+
|
|
91
|
+
# if we haven't been given CA certificates to check, disable certificate verification (otherwise we'll get repeated warnings to STDOUT)
|
|
92
|
+
if @ca_file.nil?
|
|
93
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
94
|
+
else
|
|
95
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
96
|
+
http.ca_file = @ca_file
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# negotiate with the client certificate, if one is present
|
|
100
|
+
unless(cert.nil? || key.nil?)
|
|
101
|
+
http.cert = OpenSSL::X509::Certificate.new(cert)
|
|
102
|
+
http.key = OpenSSL::PKey::RSA.new(key)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
if verb == 'GET'
|
|
107
|
+
request = Net::HTTP::Get.new("#{uri.path}?#{uri.query}", headers)
|
|
108
|
+
elsif verb == 'POST'
|
|
109
|
+
request = Net::HTTP::Post.new("#{uri.path}?#{uri.query}", headers)
|
|
110
|
+
request.set_form_data(query_map)
|
|
111
|
+
else
|
|
112
|
+
raise "Unrecognized http_verb: #{http_verb}"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
http.start { |http|
|
|
116
|
+
http.request(request)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2008-2010 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
|
|
4
|
+
require 'amazon/coral/handler'
|
|
5
|
+
|
|
6
|
+
module Amazon
|
|
7
|
+
module Coral
|
|
8
|
+
|
|
9
|
+
# Preloads identity information into request objects. Useful if all
|
|
10
|
+
# requests through a client will utilize the same identity.
|
|
11
|
+
class IdentityHandler < Handler
|
|
12
|
+
|
|
13
|
+
# Instantiates an IdentityHandler with a hash of identity attributes
|
|
14
|
+
# to be contributed to the request's identity. Attributes specified
|
|
15
|
+
# here will not override those explicitly associated with a request.
|
|
16
|
+
def initialize(attributes)
|
|
17
|
+
@attributes = attributes.to_hash
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def before(job)
|
|
21
|
+
identity = job.request[:identity]
|
|
22
|
+
|
|
23
|
+
# for each shared identity attribute, set it on the request's
|
|
24
|
+
# identity IFF no attribute with that key is already present
|
|
25
|
+
@attributes.each { |k,v|
|
|
26
|
+
identity[k] = v unless identity.has_key?(k)
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2008-2010 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
|
|
4
|
+
module Amazon
|
|
5
|
+
module Coral
|
|
6
|
+
|
|
7
|
+
class Job
|
|
8
|
+
def initialize(request)
|
|
9
|
+
@request = request
|
|
10
|
+
@reply = {}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Returns the hash of request attributes
|
|
14
|
+
def request
|
|
15
|
+
@request
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Returns the hash of reply attributes
|
|
19
|
+
def reply
|
|
20
|
+
@reply
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2008-2010 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
|
|
4
|
+
require 'logger'
|
|
5
|
+
|
|
6
|
+
module Amazon
|
|
7
|
+
module Coral
|
|
8
|
+
|
|
9
|
+
# A simple log retrieval interface to allow injection of common logging frameworks.
|
|
10
|
+
class LogFactory
|
|
11
|
+
|
|
12
|
+
@@instance = LogFactory.new
|
|
13
|
+
|
|
14
|
+
# Invokes the singleton LogFactory instance to retrieve a logger for a given key.
|
|
15
|
+
def LogFactory.getLog(key)
|
|
16
|
+
return @@instance.getLog(key)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Specifies a LogFactory instance which will handle log requests.
|
|
20
|
+
# Call this method early in execution prior to instantiating handlers to replace the default no-op log.
|
|
21
|
+
def LogFactory.setInstance(instance)
|
|
22
|
+
@@instance = instance
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Default logging implementation which returns a null logger.
|
|
26
|
+
def getLog(key)
|
|
27
|
+
log = Logger.new(nil)
|
|
28
|
+
log.level = Logger::FATAL
|
|
29
|
+
return log
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Copyright 2008-2010 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
|
|
3
|
+
module Amazon
|
|
4
|
+
module Coral
|
|
5
|
+
|
|
6
|
+
# A simple library for processing command line arguments.
|
|
7
|
+
class Option
|
|
8
|
+
def initialize(args)
|
|
9
|
+
@long = args[:long]
|
|
10
|
+
@short = args[:short]
|
|
11
|
+
@num_parameters = args[:parameters]
|
|
12
|
+
@description = args[:description]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Returns the long form of this option's name
|
|
16
|
+
def long
|
|
17
|
+
@long
|
|
18
|
+
end
|
|
19
|
+
# Returns the short form of this option's name
|
|
20
|
+
def short
|
|
21
|
+
@short
|
|
22
|
+
end
|
|
23
|
+
# Returns a text description of this option, if present
|
|
24
|
+
def description
|
|
25
|
+
@description
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Consume the arguments of this option from the argument vector and store them in the provided hash
|
|
29
|
+
# Returns the incremented counter of current position within the argument vector.
|
|
30
|
+
def consume(argv, i, hash)
|
|
31
|
+
i = i + 1
|
|
32
|
+
hash[@long] = []
|
|
33
|
+
unless @num_parameters.nil?
|
|
34
|
+
@num_parameters.times do
|
|
35
|
+
raise "Option #{@long} requires #{@num_parameters} parameter(s)" if argv.length <= i
|
|
36
|
+
hash[@long] << argv[i]
|
|
37
|
+
i = i + 1
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
return i
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Using the provided list of arguments (defined as Option objects), parse the given argument vector.
|
|
45
|
+
def Option.parse(arguments, argv)
|
|
46
|
+
long_map = {}
|
|
47
|
+
short_map = {}
|
|
48
|
+
arguments.each { |p|
|
|
49
|
+
long_map["--#{p.long}"] = p unless p.long.nil?
|
|
50
|
+
short_map["-#{p.short}"] = p unless p.short.nil?
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
h = {}
|
|
55
|
+
i = 0
|
|
56
|
+
while i < argv.length
|
|
57
|
+
arg = argv[i]
|
|
58
|
+
a = long_map[arg]
|
|
59
|
+
a = short_map[arg] if a.nil?
|
|
60
|
+
raise "Unrecognized argument '#{arg}'" if a.nil?
|
|
61
|
+
|
|
62
|
+
i = a.consume(argv, i, h)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
return h
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2008-2010 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
|
|
4
|
+
require 'amazon/coral/job'
|
|
5
|
+
require 'amazon/coral/logfactory'
|
|
6
|
+
|
|
7
|
+
module Amazon
|
|
8
|
+
module Coral
|
|
9
|
+
|
|
10
|
+
# Directs a Job through a Handler chain for processing.
|
|
11
|
+
class Orchestrator
|
|
12
|
+
|
|
13
|
+
# Instantiate an orchestrator with the given list of Handlers.
|
|
14
|
+
def initialize(handlers)
|
|
15
|
+
@log = LogFactory.getLog('Amazon::Coral::Orchestrator')
|
|
16
|
+
@handlers = handlers
|
|
17
|
+
|
|
18
|
+
@log.info "Initialized with handlers: #{handlers}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Direct the specified request down the Handler chain, invoking first each before method,
|
|
22
|
+
# then in reverse order each after method. If any exceptions are thrown along the way, orchestration
|
|
23
|
+
# will stop immediately.
|
|
24
|
+
def orchestrate(request)
|
|
25
|
+
@log.debug "Processing request #{request}"
|
|
26
|
+
|
|
27
|
+
job = Job.new(request)
|
|
28
|
+
|
|
29
|
+
stack = []
|
|
30
|
+
|
|
31
|
+
@handlers.each { |handler|
|
|
32
|
+
stack << handler
|
|
33
|
+
|
|
34
|
+
@log.debug "Invoking #{handler}.before()"
|
|
35
|
+
handler.before(job)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
stack.reverse.each { |handler|
|
|
39
|
+
@log.debug "Invoking #{handler}.after()"
|
|
40
|
+
handler.after(job)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return job.reply
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
end
|