fog-aws 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/fog-aws.gemspec +1 -0
- data/lib/fog/aws.rb +18 -6
- data/lib/fog/aws/errors.rb +26 -5
- data/lib/fog/aws/lambda.rb +195 -0
- data/lib/fog/aws/parsers/lambda/base.rb +39 -0
- data/lib/fog/aws/requests/lambda/add_permission.rb +100 -0
- data/lib/fog/aws/requests/lambda/create_event_source_mapping.rb +94 -0
- data/lib/fog/aws/requests/lambda/create_function.rb +146 -0
- data/lib/fog/aws/requests/lambda/delete_event_source_mapping.rb +46 -0
- data/lib/fog/aws/requests/lambda/delete_function.rb +43 -0
- data/lib/fog/aws/requests/lambda/get_event_source_mapping.rb +54 -0
- data/lib/fog/aws/requests/lambda/get_function.rb +74 -0
- data/lib/fog/aws/requests/lambda/get_function_configuration.rb +44 -0
- data/lib/fog/aws/requests/lambda/get_policy.rb +52 -0
- data/lib/fog/aws/requests/lambda/invoke.rb +85 -0
- data/lib/fog/aws/requests/lambda/list_event_source_mappings.rb +69 -0
- data/lib/fog/aws/requests/lambda/list_functions.rb +39 -0
- data/lib/fog/aws/requests/lambda/remove_permission.rb +56 -0
- data/lib/fog/aws/requests/lambda/update_event_source_mapping.rb +86 -0
- data/lib/fog/aws/requests/lambda/update_function_code.rb +75 -0
- data/lib/fog/aws/requests/lambda/update_function_configuration.rb +84 -0
- data/lib/fog/aws/version.rb +1 -1
- data/tests/requests/lambda/function_sample_1.js +9 -0
- data/tests/requests/lambda/function_sample_2.js +9 -0
- data/tests/requests/lambda/function_tests.rb +460 -0
- data/tests/requests/lambda/helper.rb +81 -0
- metadata +38 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04b74ccb392ce39559dbdd053081d2e304b52957
|
4
|
+
data.tar.gz: c5010f4e017481193b8f0e84c17b54a2bb3edc6f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f24cc2d407182a671b21b832ccfbc45fda04f794ac5f6fcb8a117925a86f9df1c82af39d1021d412cf8ca190b98c461807cdeea74322beaaec7af9aafaf33bfa
|
7
|
+
data.tar.gz: e6f134e032e570cc657deec822c02621e27e9a7e891adf3967ddb85b2c0fd48883be9fe33de1578d6349226f8279ae8a5563119cf9894f15e96adc781ddc0183
|
data/fog-aws.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
23
23
|
spec.add_development_dependency 'rake', '~> 10.0'
|
24
24
|
spec.add_development_dependency 'shindo', '~> 0.3'
|
25
|
+
spec.add_development_dependency 'rubyzip', '~> 0.9.9'
|
25
26
|
|
26
27
|
spec.add_dependency 'fog-core', '~> 1.27'
|
27
28
|
spec.add_dependency 'fog-json', '~> 1.0'
|
data/lib/fog/aws.rb
CHANGED
@@ -45,6 +45,7 @@ module Fog
|
|
45
45
|
autoload :Glacier, File.expand_path('../aws/glacier', __FILE__)
|
46
46
|
autoload :IAM, File.expand_path('../aws/iam', __FILE__)
|
47
47
|
autoload :KMS, File.expand_path('../aws/kms', __FILE__)
|
48
|
+
autoload :Lambda, File.expand_path('../aws/lambda', __FILE__)
|
48
49
|
autoload :RDS, File.expand_path('../aws/rds', __FILE__)
|
49
50
|
autoload :Redshift, File.expand_path('../aws/redshift', __FILE__)
|
50
51
|
autoload :SES, File.expand_path('../aws/ses', __FILE__)
|
@@ -70,6 +71,7 @@ module Fog
|
|
70
71
|
service(:glacier, 'Glacier')
|
71
72
|
service(:iam, 'IAM')
|
72
73
|
service(:kms, 'KMS')
|
74
|
+
service(:lambda, 'Lambda')
|
73
75
|
service(:rds, 'RDS')
|
74
76
|
service(:redshift, 'Redshift')
|
75
77
|
service(:ses, 'SES')
|
@@ -148,16 +150,21 @@ module Fog
|
|
148
150
|
|
149
151
|
headers = headers.merge('Host' => options[:host], 'x-amz-date' => date.to_iso8601_basic)
|
150
152
|
headers['x-amz-security-token'] = options[:aws_session_token] if options[:aws_session_token]
|
153
|
+
query = options[:query] || {}
|
151
154
|
|
152
|
-
body
|
153
|
-
|
154
|
-
|
155
|
-
|
155
|
+
if !options[:body]
|
156
|
+
body = ''
|
157
|
+
for key in params.keys.sort
|
158
|
+
unless (value = params[key]).nil?
|
159
|
+
body << "#{key}=#{escape(value.to_s)}&"
|
160
|
+
end
|
156
161
|
end
|
162
|
+
body.chop!
|
163
|
+
else
|
164
|
+
body = options[:body]
|
157
165
|
end
|
158
|
-
body.chop!
|
159
166
|
|
160
|
-
headers['Authorization'] = options[:signer].sign({:method => options[:method], :headers => headers, :body => body, :query =>
|
167
|
+
headers['Authorization'] = options[:signer].sign({:method => options[:method], :headers => headers, :body => body, :query => query, :path => options[:path]}, date)
|
161
168
|
|
162
169
|
return body, headers
|
163
170
|
end
|
@@ -209,5 +216,10 @@ module Fog
|
|
209
216
|
end
|
210
217
|
options
|
211
218
|
end
|
219
|
+
|
220
|
+
def self.json_response?(response)
|
221
|
+
return false unless response && response.headers
|
222
|
+
response.get_header('Content-Type') =~ %r{application/json}i ? true : false
|
223
|
+
end
|
212
224
|
end
|
213
225
|
end
|
data/lib/fog/aws/errors.rb
CHANGED
@@ -2,11 +2,32 @@ module Fog
|
|
2
2
|
module AWS
|
3
3
|
module Errors
|
4
4
|
def self.match_error(error)
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
if !Fog::AWS.json_response?(error.response)
|
6
|
+
matchers = [
|
7
|
+
lambda {|s| s.match(/(?:.*<Code>(.*)<\/Code>)(?:.*<Message>(.*)<\/Message>)/m)},
|
8
|
+
lambda {|s| s.match(/.*<(.+Exception)>(?:.*<Message>(.*)<\/Message>)/m)}
|
9
|
+
]
|
10
|
+
[error.message, error.response.body].each(&Proc.new {|s|
|
11
|
+
matchers.each do |matcher|
|
12
|
+
match = matcher.call(s)
|
13
|
+
return {:code => match[1].split('.').last, :message => match[2]} if match
|
14
|
+
end
|
15
|
+
})
|
16
|
+
else
|
17
|
+
begin
|
18
|
+
full_msg_error = Fog::JSON.decode(error.response.body)
|
19
|
+
if (full_msg_error.has_key?('Message') || full_msg_error.has_key?('message')) &&
|
20
|
+
error.response.headers.has_key?('x-amzn-ErrorType')
|
21
|
+
matched_error = {
|
22
|
+
:code => error.response.headers['x-amzn-ErrorType'].split(':').first,
|
23
|
+
:message => full_msg_error['Message'] || full_msg_error['message']
|
24
|
+
}
|
25
|
+
return matched_error
|
26
|
+
end
|
27
|
+
rescue Fog::JSON::DecodeError => e
|
28
|
+
Fog::Logger.warning("Error parsing response json - #{e}")
|
29
|
+
end
|
30
|
+
end
|
10
31
|
{} # we did not match the message or response body
|
11
32
|
end
|
12
33
|
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
module Fog
|
2
|
+
module AWS
|
3
|
+
class Lambda < Fog::Service
|
4
|
+
extend Fog::AWS::CredentialFetcher::ServiceMethods
|
5
|
+
|
6
|
+
requires :aws_access_key_id, :aws_secret_access_key
|
7
|
+
recognizes :host, :path, :port, :scheme, :persistent, :region, :use_iam_profile, :aws_session_token, :aws_credentials_expire_at, :version, :instrumentor, :instrumentor_name
|
8
|
+
|
9
|
+
request_path 'fog/aws/requests/lambda'
|
10
|
+
request :create_function
|
11
|
+
request :delete_function
|
12
|
+
request :get_function
|
13
|
+
request :get_function_configuration
|
14
|
+
request :invoke
|
15
|
+
request :list_functions
|
16
|
+
request :update_function_code
|
17
|
+
request :update_function_configuration
|
18
|
+
|
19
|
+
request :get_policy
|
20
|
+
request :add_permission
|
21
|
+
request :remove_permission
|
22
|
+
|
23
|
+
request :create_event_source_mapping
|
24
|
+
request :delete_event_source_mapping
|
25
|
+
request :get_event_source_mapping
|
26
|
+
request :list_event_source_mappings
|
27
|
+
request :update_event_source_mapping
|
28
|
+
|
29
|
+
class Mock
|
30
|
+
def self.data
|
31
|
+
@data ||= Hash.new do |hash, region|
|
32
|
+
hash[region] = Hash.new do |region_hash, key|
|
33
|
+
region_hash[key] = {
|
34
|
+
:functions => {},
|
35
|
+
:permissions => {},
|
36
|
+
:event_source_mappings => {}
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
attr_reader :region
|
43
|
+
attr_reader :account_id
|
44
|
+
attr_reader :aws_access_key_id
|
45
|
+
|
46
|
+
def initialize(options={})
|
47
|
+
@region = options[:region] || 'us-east-1'
|
48
|
+
@aws_access_key_id = options[:aws_access_key_id]
|
49
|
+
@account_id = Fog::AWS::Mock.owner_id
|
50
|
+
@module = "lambda"
|
51
|
+
|
52
|
+
unless ['ap-northeast-1', 'ap-southeast-1', 'ap-southeast-2', 'eu-central-1', 'eu-west-1', 'us-east-1', 'us-west-1', 'us-west-2', 'sa-east-1'].include?(@region)
|
53
|
+
raise ArgumentError, "Unknown region: #{@region.inspect}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def data
|
58
|
+
self.class.data[@region][@aws_access_key_id]
|
59
|
+
end
|
60
|
+
|
61
|
+
def reset_data
|
62
|
+
self.class.data[@region].delete(@aws_access_key_id)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class Real
|
67
|
+
include Fog::AWS::CredentialFetcher::ConnectionMethods
|
68
|
+
# Initialize connection to Lambda
|
69
|
+
#
|
70
|
+
# ==== Notes
|
71
|
+
# options parameter must include values for :aws_access_key_id and
|
72
|
+
# :aws_secret_access_key in order to create a connection
|
73
|
+
#
|
74
|
+
# ==== Examples
|
75
|
+
# lambda = Lambda.new(
|
76
|
+
# :aws_access_key_id => your_aws_access_key_id,
|
77
|
+
# :aws_secret_access_key => your_aws_secret_access_key
|
78
|
+
# )
|
79
|
+
#
|
80
|
+
# ==== Parameters
|
81
|
+
# * options<~Hash> - config arguments for connection. Defaults to {}.
|
82
|
+
#
|
83
|
+
# ==== Returns
|
84
|
+
# * Lambda object with connection to AWS.
|
85
|
+
def initialize(options={})
|
86
|
+
@use_iam_profile = options[:use_iam_profile]
|
87
|
+
@connection_options = options[:connection_options] || {}
|
88
|
+
@instrumentor = options[:instrumentor]
|
89
|
+
@instrumentor_name = options[:instrumentor_name] || 'fog.aws.lambda'
|
90
|
+
|
91
|
+
options[:region] ||= 'us-east-1'
|
92
|
+
@region = options[:region]
|
93
|
+
@host = options[:host] || "lambda.#{options[:region]}.amazonaws.com"
|
94
|
+
|
95
|
+
@path = options[:path] || '/'
|
96
|
+
@persistent = options[:persistent] || false
|
97
|
+
@port = options[:port] || 443
|
98
|
+
@scheme = options[:scheme] || 'https'
|
99
|
+
@version = options[:version] || '2015-03-31'
|
100
|
+
@connection = Fog::Core::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", @persistent, @connection_options)
|
101
|
+
|
102
|
+
setup_credentials(options)
|
103
|
+
end
|
104
|
+
|
105
|
+
attr_reader :region
|
106
|
+
|
107
|
+
def reload
|
108
|
+
@connection.reset
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def setup_credentials(options)
|
114
|
+
@aws_access_key_id = options[:aws_access_key_id]
|
115
|
+
@aws_secret_access_key = options[:aws_secret_access_key]
|
116
|
+
@aws_session_token = options[:aws_session_token]
|
117
|
+
@aws_credentials_expire_at = options[:aws_credentials_expire_at]
|
118
|
+
|
119
|
+
@signer = Fog::AWS::SignatureV4.new( @aws_access_key_id, @aws_secret_access_key, @region, 'lambda')
|
120
|
+
end
|
121
|
+
|
122
|
+
def request(params)
|
123
|
+
refresh_credentials_if_expired
|
124
|
+
|
125
|
+
idempotent = params.delete(:idempotent)
|
126
|
+
parser = params.delete(:parser)
|
127
|
+
request_path = "/#{@version}#{params.delete(:path)}"
|
128
|
+
query = params.delete(:query) || {}
|
129
|
+
method = params.delete(:method) || 'POST'
|
130
|
+
expects = params.delete(:expects) || 200
|
131
|
+
headers = { 'Content-Type' => 'application/json' }
|
132
|
+
|
133
|
+
headers.merge!(params[:headers] || {})
|
134
|
+
|
135
|
+
body, headers = AWS.signed_params_v4(
|
136
|
+
params,
|
137
|
+
headers,
|
138
|
+
{
|
139
|
+
:method => method,
|
140
|
+
:aws_session_token => @aws_session_token,
|
141
|
+
:signer => @signer,
|
142
|
+
:host => @host,
|
143
|
+
:path => request_path,
|
144
|
+
:port => @port,
|
145
|
+
:query => query,
|
146
|
+
:body => params[:body]
|
147
|
+
}
|
148
|
+
)
|
149
|
+
|
150
|
+
if @instrumentor
|
151
|
+
@instrumentor.instrument("#{@instrumentor_name}.request", params) do
|
152
|
+
_request(method, request_path, query, body, headers, expects, idempotent, parser)
|
153
|
+
end
|
154
|
+
else
|
155
|
+
_request(method, request_path, query, body, headers, expects, idempotent, parser)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def _request(method, path, query, body, headers, expects, idempotent, parser=nil)
|
160
|
+
response = process_response(@connection.request({
|
161
|
+
:path => path,
|
162
|
+
:query => query,
|
163
|
+
:body => body,
|
164
|
+
:expects => expects,
|
165
|
+
:idempotent => idempotent,
|
166
|
+
:headers => headers,
|
167
|
+
:method => method
|
168
|
+
}), parser)
|
169
|
+
rescue Excon::Errors::HTTPStatusError => error
|
170
|
+
match = Fog::AWS::Errors.match_error(error)
|
171
|
+
raise if match.empty?
|
172
|
+
raise Fog::AWS::Lambda::Error.slurp(error,
|
173
|
+
"#{match[:code]} => #{match[:message]}")
|
174
|
+
end
|
175
|
+
|
176
|
+
def process_response(response, parser)
|
177
|
+
if response &&
|
178
|
+
response.body &&
|
179
|
+
response.body.is_a?(String) &&
|
180
|
+
!response.body.strip.empty? &&
|
181
|
+
Fog::AWS.json_response?(response)
|
182
|
+
begin
|
183
|
+
response.body = Fog::JSON.decode(response.body)
|
184
|
+
response.body = parser.process(response.body) if parser
|
185
|
+
rescue Fog::JSON::DecodeError => e
|
186
|
+
Fog::Logger.warning("Error parsing response json - #{e}")
|
187
|
+
response.body = {}
|
188
|
+
end
|
189
|
+
end
|
190
|
+
response
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Fog
|
2
|
+
module AWS
|
3
|
+
module Parsers
|
4
|
+
module Lambda
|
5
|
+
class Base
|
6
|
+
def process(body)
|
7
|
+
body.inject({}) { |h, (k, v)| h[k] = rules(k, v); h }
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def rules(key, value)
|
13
|
+
case value
|
14
|
+
when Hash
|
15
|
+
process(value)
|
16
|
+
when Array
|
17
|
+
value.map { |i| process(i) }
|
18
|
+
else
|
19
|
+
case key
|
20
|
+
when 'LastModified'
|
21
|
+
Time.parse(value)
|
22
|
+
when 'Policy', 'Statement'
|
23
|
+
begin
|
24
|
+
Fog::JSON.decode(value)
|
25
|
+
rescue Fog::JSON::DecodeError => e
|
26
|
+
Fog::Logger.warning("Error parsing response json - #{e}")
|
27
|
+
{}
|
28
|
+
end
|
29
|
+
else
|
30
|
+
value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Fog
|
2
|
+
module AWS
|
3
|
+
class Lambda
|
4
|
+
class Real
|
5
|
+
require 'fog/aws/parsers/lambda/base'
|
6
|
+
|
7
|
+
# Adds a permission to the access policy associated with the specified AWS Lambda function.
|
8
|
+
# http://docs.aws.amazon.com/lambda/latest/dg/API_AddPermission.html
|
9
|
+
# ==== Parameters
|
10
|
+
# * FunctionName <~String> - Name of the Lambda function whose access policy you are updating by adding a new permission.
|
11
|
+
# * Action <~String> - AWS Lambda action you want to allow in this statement.
|
12
|
+
# * Principal <~String> - principal who is getting this permission.
|
13
|
+
# * SourceAccount <~String> - AWS account ID (without a hyphen) of the source owner.
|
14
|
+
# * SourceArn <~String> - Amazon Resource Name (ARN) of the source resource to assign permissions.
|
15
|
+
# * StatemendId. <~String> - unique statement identifier.
|
16
|
+
# ==== Returns
|
17
|
+
# * response<~Excon::Response>:
|
18
|
+
# * body<~Hash>:
|
19
|
+
# * 'Statement' <~Hash> - permission statement you specified in the request.
|
20
|
+
def add_permission(params={})
|
21
|
+
function_name = params.delete('FunctionName')
|
22
|
+
action = params.delete('Action')
|
23
|
+
principal = params.delete('Principal')
|
24
|
+
source_account = params.delete('SourceAccount')
|
25
|
+
source_arn = params.delete('SourceArn')
|
26
|
+
sid = params.delete('StatementId')
|
27
|
+
|
28
|
+
permission = {
|
29
|
+
'Action' => action,
|
30
|
+
'Principal' => principal,
|
31
|
+
'StatementId' => sid
|
32
|
+
}
|
33
|
+
permission['SourceAccount'] = source_account if source_account
|
34
|
+
permission['SourceArn'] = source_arn if source_arn
|
35
|
+
|
36
|
+
request({
|
37
|
+
:method => 'POST',
|
38
|
+
:path => "/functions/#{function_name}/versions/HEAD/policy",
|
39
|
+
:expects => 201,
|
40
|
+
:body => Fog::JSON.encode(permission),
|
41
|
+
:parser => Fog::AWS::Parsers::Lambda::Base.new
|
42
|
+
}.merge(params))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Mock
|
47
|
+
def add_permission(params={})
|
48
|
+
function_id = params.delete('FunctionName')
|
49
|
+
function = self.get_function_configuration(
|
50
|
+
'FunctionName' => function_id
|
51
|
+
).body
|
52
|
+
function_arn = function['FunctionArn']
|
53
|
+
|
54
|
+
action = params.delete('Action')
|
55
|
+
principal = params.delete('Principal')
|
56
|
+
source_account = params.delete('SourceAccount')
|
57
|
+
source_arn = params.delete('SourceArn')
|
58
|
+
sid = params.delete('StatementId')
|
59
|
+
|
60
|
+
if action.nil? || action.empty?
|
61
|
+
message = 'Action cannot be blank'
|
62
|
+
raise Fog::AWS::Lambda::Error, message
|
63
|
+
end
|
64
|
+
|
65
|
+
if principal.nil? || principal.empty?
|
66
|
+
message = 'Principal cannot be blank'
|
67
|
+
raise Fog::AWS::Lambda::Error, message
|
68
|
+
end
|
69
|
+
|
70
|
+
if sid.nil? || sid.empty?
|
71
|
+
message = 'Sid cannot be blank'
|
72
|
+
raise Fog::AWS::Lambda::Error, message
|
73
|
+
end
|
74
|
+
|
75
|
+
statement = {
|
76
|
+
'Action' => [action],
|
77
|
+
'Principal' => { 'Service' => principal },
|
78
|
+
'Sid' => sid,
|
79
|
+
'Resource' => function_arn,
|
80
|
+
'Effect' => 'Allow'
|
81
|
+
}
|
82
|
+
if source_arn
|
83
|
+
statement['Condition'] = {}
|
84
|
+
statement['Condition']['ArnLike'] = {
|
85
|
+
'AWS:SourceArn' => source_arn
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
self.data[:permissions][function_arn] ||= []
|
90
|
+
self.data[:permissions][function_arn] << statement
|
91
|
+
|
92
|
+
response = Excon::Response.new
|
93
|
+
response.status = 201
|
94
|
+
response.body = { 'Statement' => statement }
|
95
|
+
response
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|