fog-aws 0.5.0 → 0.6.0
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.
- 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
|