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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 53e5c13a8cdab463ca2f7e696ce8f6be7a28e6b7
4
- data.tar.gz: 7c0b522b66731d66b8374cf1cf8d8c8cba679d57
3
+ metadata.gz: 04b74ccb392ce39559dbdd053081d2e304b52957
4
+ data.tar.gz: c5010f4e017481193b8f0e84c17b54a2bb3edc6f
5
5
  SHA512:
6
- metadata.gz: 5c93b6c6b2d5013370a4277bd28002c5b357af8d28846f21c1c44147a1ec4773e15c4ab047795ee5fd718755b66ad153db597be569cbe33e043c930e599e9f01
7
- data.tar.gz: 174a539d140553b296d6ef4beb68f792f6f02a67ca3c17a7d25a76c7d1038aade3807ec7efb7be7e1bb0c479c010ad5e790a9e396bd7fec7895d73de4c620c9e
6
+ metadata.gz: f24cc2d407182a671b21b832ccfbc45fda04f794ac5f6fcb8a117925a86f9df1c82af39d1021d412cf8ca190b98c461807cdeea74322beaaec7af9aafaf33bfa
7
+ data.tar.gz: e6f134e032e570cc657deec822c02621e27e9a7e891adf3967ddb85b2c0fd48883be9fe33de1578d6349226f8279ae8a5563119cf9894f15e96adc781ddc0183
@@ -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'
@@ -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
- for key in params.keys.sort
154
- unless (value = params[key]).nil?
155
- body << "#{key}=#{escape(value.to_s)}&"
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 => {}, :path => options[:path]}, date)
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
@@ -2,11 +2,32 @@ module Fog
2
2
  module AWS
3
3
  module Errors
4
4
  def self.match_error(error)
5
- matcher = lambda {|s| s.match(/(?:.*<Code>(.*)<\/Code>)(?:.*<Message>(.*)<\/Message>)/m)}
6
- [error.message, error.response.body].each(&Proc.new {|s|
7
- match = matcher.call(s)
8
- return {:code => match[1].split('.').last, :message => match[2]} if match
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