modulator 0.2.2 → 0.3.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/.gitignore +6 -0
- data/CHANGELOG.md +19 -0
- data/Gemfile +0 -4
- data/Gemfile.lock +26 -22
- data/README.md +243 -7
- data/lib/modulator.rb +82 -46
- data/lib/modulator/gateway/gateway.rb +4 -6
- data/lib/modulator/gateway/routes/console.rb +32 -34
- data/lib/modulator/gateway_event.json +60 -0
- data/lib/modulator/{lambda/aws_lambda_handler.rb → lambda_handler.rb} +2 -15
- data/lib/modulator/stack/builder.rb +256 -0
- data/lib/modulator/stack/policies.rb +99 -0
- data/lib/modulator/{lambda/aws_stack_uploader.rb → stack/uploader.rb} +59 -38
- data/lib/modulator/version.rb +1 -1
- data/lib/utils.rb +7 -1
- data/modulator.gemspec +1 -4
- metadata +9 -20
- data/lib/modulator/lambda/aws_stack_builder.rb +0 -225
@@ -12,7 +12,7 @@ class Gateway < Roda
|
|
12
12
|
|
13
13
|
my_dir = Pathname.new(__FILE__).dirname
|
14
14
|
my_dir.glob('routes/*.rb').each{|file| require_relative file}
|
15
|
-
DUMMY_AWS_EVENT = Utils.load_json my_dir.parent.join('
|
15
|
+
DUMMY_AWS_EVENT = Utils.load_json my_dir.parent.join('gateway_event.json')
|
16
16
|
|
17
17
|
before do
|
18
18
|
@time = Time.now
|
@@ -32,7 +32,7 @@ class Gateway < Roda
|
|
32
32
|
after do |res|
|
33
33
|
puts "Matched path: #{request.matched_path}"
|
34
34
|
puts "Status: #{response.status}"
|
35
|
-
puts
|
35
|
+
puts "Took: #{Time.now - @time} seconds"
|
36
36
|
end
|
37
37
|
|
38
38
|
plugin :error_handler do |e|
|
@@ -51,11 +51,9 @@ class Gateway < Roda
|
|
51
51
|
|
52
52
|
# process lambda configs
|
53
53
|
Modulator::LAMBDAS.each do |lambda_name, lambda_config|
|
54
|
-
# puts "* Registering #{lambda_name}"
|
55
|
-
# pp lambda_config
|
56
54
|
|
57
|
-
#
|
58
|
-
Modulator.
|
55
|
+
# copy config to env
|
56
|
+
Modulator.set_env_values lambda_config
|
59
57
|
|
60
58
|
# build route
|
61
59
|
@path_params = {}
|
@@ -1,11 +1,5 @@
|
|
1
|
-
require 'aws-sdk-cloudformation'
|
2
|
-
|
3
|
-
# console API
|
4
1
|
Gateway.route('console') do |r|
|
5
2
|
|
6
|
-
client = Aws::CloudFormation::Client.new
|
7
|
-
app_name = (opts[:app_dir] || Pathname.getwd.basename.to_s).camelize
|
8
|
-
|
9
3
|
# helpers
|
10
4
|
def capture_output
|
11
5
|
previous_stdout, $stdout = $stdout, StringIO.new
|
@@ -18,18 +12,29 @@ Gateway.route('console') do |r|
|
|
18
12
|
$stderr = previous_stderr
|
19
13
|
end
|
20
14
|
|
21
|
-
|
22
|
-
|
23
|
-
|
15
|
+
# cf call return value or its capture from stdout
|
16
|
+
def render_cf_call_output(cf_call_result, cf_call_output, cf_call_name = 'aws cf sdk call')
|
17
|
+
if cf_call_result
|
18
|
+
cf_call_result.to_hash
|
24
19
|
else
|
25
|
-
{
|
20
|
+
{cf_call_name => cf_call_output.split("\n").first}
|
26
21
|
end
|
27
22
|
end
|
28
23
|
|
24
|
+
# list registered lambdas
|
25
|
+
r.on 'lambdas' do
|
26
|
+
r.get 'list' do
|
27
|
+
Modulator::LAMBDAS
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# stack operations
|
29
32
|
r.on 'stack' do
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
+
client = Aws::CloudFormation::Client.new
|
34
|
+
app_name = (opts[:app_dir] || Pathname.getwd.basename.to_s).camelize
|
35
|
+
s3_bucket = opts[:s3_bucket] || ENV['MODULATOR_S3_BUCKET'] || 'modulator-apps'
|
36
|
+
payload = request.params.symbolize_keys
|
37
|
+
cf_call_result = nil
|
33
38
|
|
34
39
|
r.get 'events' do
|
35
40
|
resp = client.describe_stack_events(stack_name: app_name, next_token: @headers['X-Next-Token'])
|
@@ -37,6 +42,7 @@ Gateway.route('console') do |r|
|
|
37
42
|
resp.stack_events.map(&:to_hash)
|
38
43
|
end
|
39
44
|
|
45
|
+
# initialize stack
|
40
46
|
r.on 'init' do
|
41
47
|
serializer = :yaml
|
42
48
|
content_type = 'text/html'
|
@@ -47,42 +53,34 @@ Gateway.route('console') do |r|
|
|
47
53
|
r.pass
|
48
54
|
end
|
49
55
|
|
50
|
-
# init stack
|
51
56
|
stack = Modulator.init_stack(
|
52
|
-
|
53
|
-
bucket: bucket_name,
|
57
|
+
s3_bucket: s3_bucket,
|
54
58
|
timeout: 15
|
55
59
|
)
|
56
60
|
|
57
|
-
#
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
type: param[:type],
|
62
|
-
value: param[:value]
|
63
|
-
)
|
64
|
-
end
|
65
|
-
|
66
|
-
r.post 'valid' do
|
67
|
-
command_output = capture_output do
|
68
|
-
command_result = stack.valid?
|
61
|
+
# validate stack
|
62
|
+
r.post 'validate' do
|
63
|
+
cf_call_output = capture_output do
|
64
|
+
cf_call_result = stack.valid?
|
69
65
|
end
|
70
|
-
|
66
|
+
render_cf_call_output(cf_call_result, cf_call_output, 'stack validation call')
|
71
67
|
end
|
72
68
|
|
69
|
+
# deploy stack
|
73
70
|
r.post 'deploy' do
|
74
|
-
|
75
|
-
|
76
|
-
parameters:
|
71
|
+
cf_call_output = capture_output do
|
72
|
+
cf_call_result = stack.deploy(
|
73
|
+
parameters: s3_bucket[:parameters]&.map{|param| {parameter_key: param[:key], parameter_value: param[:value]}},
|
77
74
|
capabilities: ['CAPABILITY_IAM']
|
78
75
|
)
|
79
76
|
end
|
80
|
-
|
77
|
+
render_cf_call_output(cf_call_result, cf_call_output)
|
81
78
|
end
|
82
79
|
|
80
|
+
# print template
|
83
81
|
r.post do
|
84
82
|
response['Content-Type'] = content_type
|
85
|
-
|
83
|
+
stack.to_cf(serializer)
|
86
84
|
end
|
87
85
|
end
|
88
86
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
{
|
2
|
+
"body": "{\"x\": 123}",
|
3
|
+
"isBase64Encoded": false,
|
4
|
+
|
5
|
+
"resource": "/calc/{proxy+}",
|
6
|
+
"path": "/calc/1/add/2",
|
7
|
+
"httpMethod": "POST",
|
8
|
+
|
9
|
+
"multiValueHeaders": {
|
10
|
+
"x-custom": [
|
11
|
+
"abc"
|
12
|
+
]
|
13
|
+
},
|
14
|
+
"queryStringParameters": {
|
15
|
+
"aa": "11",
|
16
|
+
"bb": "22"
|
17
|
+
},
|
18
|
+
"multiValueQueryStringParameters": {
|
19
|
+
"aa": [
|
20
|
+
"11"
|
21
|
+
],
|
22
|
+
"bb": [
|
23
|
+
"22"
|
24
|
+
]
|
25
|
+
},
|
26
|
+
"pathParameters": {
|
27
|
+
"id": "1",
|
28
|
+
"other_id": "2"
|
29
|
+
},
|
30
|
+
"stageVariables": null,
|
31
|
+
|
32
|
+
"headers": {
|
33
|
+
"Host": "1234567890.execute-api.us-east-1.amazonaws.com",
|
34
|
+
"User-Agent": "Custom User Agent String",
|
35
|
+
"X-Forwarded-For": "127.0.0.1, 127.0.0.2",
|
36
|
+
"X-Forwarded-Port": "443",
|
37
|
+
"X-Forwarded-Proto": "https"
|
38
|
+
},
|
39
|
+
"requestContext": {
|
40
|
+
"accountId": "123456789012",
|
41
|
+
"resourceId": "123456",
|
42
|
+
"stage": "prod",
|
43
|
+
"requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
|
44
|
+
"requestTime": "09/Apr/2015:12:34:56 +0000",
|
45
|
+
"requestTimeEpoch": 1428582896000,
|
46
|
+
"identity": {
|
47
|
+
"cognitoIdentityPoolId": null,
|
48
|
+
"accountId": null,
|
49
|
+
"cognitoIdentityId": null,
|
50
|
+
"caller": null,
|
51
|
+
"accessKey": null,
|
52
|
+
"sourceIp": "127.0.0.1",
|
53
|
+
"cognitoAuthenticationType": null,
|
54
|
+
"cognitoAuthenticationProvider": null,
|
55
|
+
"userArn": null,
|
56
|
+
"userAgent": "Custom User Agent String",
|
57
|
+
"user": null
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'pathname'
|
2
2
|
|
3
|
+
# NOTE: aws has LambdaHandler already defined as a class so we need an aws prefix here
|
3
4
|
module AwsLambdaHandler
|
4
5
|
module_function
|
5
6
|
|
@@ -8,20 +9,6 @@ module AwsLambdaHandler
|
|
8
9
|
# TODO: implement handlers for other event types based on some event key, like AwsS3EventHandler
|
9
10
|
AwsApiGatewayEventHandler.call(event: event, context: context)
|
10
11
|
end
|
11
|
-
|
12
|
-
# helpers
|
13
|
-
def symbolize_keys(obj)
|
14
|
-
case obj
|
15
|
-
when Hash
|
16
|
-
hash = {}
|
17
|
-
obj.each {|k, v| hash[k.to_sym] = symbolize_keys(v)}
|
18
|
-
hash
|
19
|
-
when Array
|
20
|
-
obj.map {|x| symbolize_keys(x)}
|
21
|
-
else
|
22
|
-
obj
|
23
|
-
end
|
24
|
-
end
|
25
12
|
end
|
26
13
|
|
27
14
|
module AwsApiGatewayEventHandler
|
@@ -96,7 +83,7 @@ module AwsApiGatewayEventHandler
|
|
96
83
|
mod.send(mod_method, *path_params.values)
|
97
84
|
|
98
85
|
elsif verb == 'POST'
|
99
|
-
payload =
|
86
|
+
payload = JSON.parse(event['body'], symbolize_names: true)
|
100
87
|
method_signature.each do |arg_type, arg_name| # [[:req, :id], [:key, :pet]]
|
101
88
|
payload = {arg_name => payload} if arg_type == :key # scope payload to first named argument
|
102
89
|
end
|
@@ -0,0 +1,256 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'humidifier'
|
3
|
+
require_relative 'uploader'
|
4
|
+
require_relative 'policies'
|
5
|
+
|
6
|
+
module StackBuilder
|
7
|
+
module_function
|
8
|
+
|
9
|
+
RUBY_VERSION = 'ruby2.5'
|
10
|
+
GEM_PATH_RUBY_VERSION = '2.5.0'
|
11
|
+
GEM_PATH = "/opt/ruby/#{GEM_PATH_RUBY_VERSION}"
|
12
|
+
LAMBDA_HANDLER_FILE_NAME = 'modulator-lambda-handler'
|
13
|
+
|
14
|
+
class << self
|
15
|
+
attr_accessor :stack, :stack_opts, :app_name, :app_path, :app_dir
|
16
|
+
attr_accessor :hidden_dir, :s3_bucket, :lambda_handler_s3_object_version
|
17
|
+
attr_accessor :api_gateway_deployment, :api_gateway_id, :lambda_policies
|
18
|
+
attr_accessor :lambda_handlers, :lambda_handler_s3_key
|
19
|
+
end
|
20
|
+
|
21
|
+
def init(app_name:, s3_bucket:, **stack_opts)
|
22
|
+
puts 'Initializing stack'
|
23
|
+
@app_name = app_name.camelize
|
24
|
+
@s3_bucket = s3_bucket
|
25
|
+
@app_path = Pathname.getwd
|
26
|
+
@app_dir = app_path.basename.to_s
|
27
|
+
@hidden_dir = '.modulator'
|
28
|
+
@stack_opts = stack_opts
|
29
|
+
@lambda_handlers = stack_opts[:lambda_handlers] || []
|
30
|
+
@lambda_policies = Array(stack_opts[:lambda_policies]) << :cloudwatch
|
31
|
+
|
32
|
+
# create hidden dir for build artifacts
|
33
|
+
app_path.join(hidden_dir).mkpath
|
34
|
+
|
35
|
+
# init stack instance
|
36
|
+
self.stack = Humidifier::Stack.new(name: app_name, aws_template_format_version: '2010-09-09')
|
37
|
+
|
38
|
+
# app environment - test, development, production ...
|
39
|
+
app_envs = stack_opts[:app_envs] || ['development']
|
40
|
+
stack.add_parameter('AppEnvironment', description: 'Application environment', type: 'String', allowed_values: app_envs, constraint_description: "Must be one of #{app_envs.join(', ')}")
|
41
|
+
|
42
|
+
if lambda_handlers.empty?
|
43
|
+
# api stage
|
44
|
+
stack.add_parameter('ApiGatewayStageName', description: 'Gateway deployment stage', type: 'String', default: 'v1')
|
45
|
+
|
46
|
+
# add gateway
|
47
|
+
stack.add_api_gateway
|
48
|
+
stack.add_api_gateway_deployment
|
49
|
+
end
|
50
|
+
|
51
|
+
# add role
|
52
|
+
stack.add_lambda_iam_role
|
53
|
+
|
54
|
+
# add policies to role
|
55
|
+
stack.lambda_policies.each do |policy|
|
56
|
+
stack.add_policy(policy) if policy.is_a?(Symbol)
|
57
|
+
stack.add_policy(policy[:name], **policy) if policy.is_a?(Hash)
|
58
|
+
end
|
59
|
+
|
60
|
+
# simple lambda app
|
61
|
+
if lambda_handlers.any?
|
62
|
+
stack.upload_lambda_files
|
63
|
+
lambda_handlers.each do |handler|
|
64
|
+
stack.add_lambda(handler: handler, env: stack_opts[:env] || {}, settings: stack_opts[:settings] || {})
|
65
|
+
end
|
66
|
+
else
|
67
|
+
# upload handlers and layers
|
68
|
+
stack.upload_files
|
69
|
+
end
|
70
|
+
|
71
|
+
# return humidifier instance
|
72
|
+
stack
|
73
|
+
end
|
74
|
+
|
75
|
+
def upload_files
|
76
|
+
if stack_opts[:skip_upload]
|
77
|
+
puts 'Skipping upload'
|
78
|
+
return
|
79
|
+
end
|
80
|
+
stack.upload_generic_lambda_handler
|
81
|
+
puts 'Generating layers'
|
82
|
+
stack.upload_gems_layer
|
83
|
+
stack.upload_app_layer
|
84
|
+
end
|
85
|
+
|
86
|
+
def add_lambda_endpoint(**opts) # gateway:, mod:, wrapper: {}, env: {}, settings: {}
|
87
|
+
# add api resources and its lambda
|
88
|
+
stack.add_api_gateway_resources(gateway: opts[:gateway], lambda: stack.add_generic_lambda(opts))
|
89
|
+
end
|
90
|
+
|
91
|
+
# gateway
|
92
|
+
def add_api_gateway
|
93
|
+
self.api_gateway_id = 'ApiGateway'
|
94
|
+
stack.add(api_gateway_id, Humidifier::ApiGateway::RestApi.new(name: app_name, description: app_name + ' API'))
|
95
|
+
end
|
96
|
+
|
97
|
+
# gateway deployment
|
98
|
+
def add_api_gateway_deployment
|
99
|
+
self.api_gateway_deployment = Humidifier::ApiGateway::Deployment.new(
|
100
|
+
rest_api_id: Humidifier.ref(api_gateway_id),
|
101
|
+
stage_name: Humidifier.ref("ApiGatewayStageName")
|
102
|
+
)
|
103
|
+
stack.add('ApiGatewayDeployment', api_gateway_deployment)
|
104
|
+
stack.add_output('ApiGatewayInvokeURL',
|
105
|
+
value: Humidifier.fn.sub("https://${#{api_gateway_id}}.execute-api.${AWS::Region}.amazonaws.com/${ApiGatewayStageName}"),
|
106
|
+
description: 'API root url',
|
107
|
+
export_name: app_name + 'RootUrl'
|
108
|
+
)
|
109
|
+
api_gateway_deployment.depends_on = []
|
110
|
+
end
|
111
|
+
|
112
|
+
# custom lambda function
|
113
|
+
def add_lambda(handler:, env: {}, settings: {})
|
114
|
+
lambda_resource = generate_lambda_resource(
|
115
|
+
description: "Lambda for #{handler}",
|
116
|
+
function_name: ([app_name] << handler.split('.')).flatten.join('-').dasherize,
|
117
|
+
handler: handler,
|
118
|
+
s3_key: lambda_handler_s3_key,
|
119
|
+
env_vars: env.merge('app_env' => Humidifier.ref('AppEnvironment')),
|
120
|
+
role: Humidifier.fn.get_att(['LambdaRole', 'Arn']),
|
121
|
+
settings: settings
|
122
|
+
)
|
123
|
+
stack.add(handler.gsub('.', '_').camelize, lambda_resource)
|
124
|
+
end
|
125
|
+
|
126
|
+
# generic lambda function for gateway
|
127
|
+
def add_generic_lambda(gateway: {}, mod: {}, wrapper: {}, env: {}, settings: {})
|
128
|
+
lambda_config = {}
|
129
|
+
name_parts = mod[:name].split('::')
|
130
|
+
{gateway: gateway, module: mod, wrapper: wrapper}.each do |env_group_prefix, env_group|
|
131
|
+
env_group.each{|env_key, env_value| lambda_config["#{env_group_prefix}_#{env_key}"] = env_value}
|
132
|
+
end
|
133
|
+
env_vars = env
|
134
|
+
.reduce({}){|env_as_string, (k, v)| env_as_string.update(k.to_s => v.to_s)}
|
135
|
+
.merge(lambda_config)
|
136
|
+
.merge(
|
137
|
+
'GEM_PATH' => GEM_PATH,
|
138
|
+
'app_dir' => app_dir,
|
139
|
+
'app_env' => Humidifier.ref('AppEnvironment')
|
140
|
+
)
|
141
|
+
|
142
|
+
lambda_resource = generate_lambda_resource(
|
143
|
+
description: "Lambda for #{mod[:name]}.#{mod[:method]}",
|
144
|
+
function_name: [app_name, name_parts, mod[:method]].flatten.join('-').dasherize,
|
145
|
+
handler: "#{LAMBDA_HANDLER_FILE_NAME}.AwsLambdaHandler.call",
|
146
|
+
s3_key: LAMBDA_HANDLER_FILE_NAME + '.rb.zip',
|
147
|
+
env_vars: env_vars,
|
148
|
+
role: Humidifier.fn.get_att(['LambdaRole', 'Arn']),
|
149
|
+
settings: settings,
|
150
|
+
layers: [Humidifier.ref(app_name + 'Layer'), Humidifier.ref(app_name + 'GemsLayer')]
|
151
|
+
)
|
152
|
+
|
153
|
+
# add to stack
|
154
|
+
['Lambda', name_parts, mod[:method].capitalize].join.tap do |id|
|
155
|
+
stack.add(id, lambda_resource)
|
156
|
+
stack.add_lambda_invoke_permission(id: id, gateway: gateway)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def generate_lambda_resource(description:, function_name:, handler:, s3_key:, env_vars:, role:, settings:, layers: [])
|
161
|
+
lambda_function = Humidifier::Lambda::Function.new(
|
162
|
+
description: description,
|
163
|
+
function_name: function_name,
|
164
|
+
handler: handler,
|
165
|
+
environment: {variables: env_vars},
|
166
|
+
role: role,
|
167
|
+
timeout: settings[:timeout] || stack_opts[:timeout] || 15,
|
168
|
+
memory_size: settings[:memory_size] || stack_opts[:memory_size] || 128,
|
169
|
+
runtime: RUBY_VERSION,
|
170
|
+
code: {
|
171
|
+
s3_bucket: s3_bucket,
|
172
|
+
s3_key: s3_key,
|
173
|
+
s3_object_version: lambda_handler_s3_object_version
|
174
|
+
},
|
175
|
+
layers: layers
|
176
|
+
)
|
177
|
+
end
|
178
|
+
|
179
|
+
# invoke permission
|
180
|
+
def add_lambda_invoke_permission(id:, gateway:)
|
181
|
+
arn_path_matcher = gateway[:path].split('/').each_with_object([]) do |fragment, matcher|
|
182
|
+
fragment = '*' if fragment.start_with?(':')
|
183
|
+
matcher << fragment
|
184
|
+
end.join('/')
|
185
|
+
stack.add(id + 'InvokePermission' , Humidifier::Lambda::Permission.new(
|
186
|
+
action: "lambda:InvokeFunction",
|
187
|
+
function_name: Humidifier.fn.get_att([id, 'Arn']),
|
188
|
+
principal: "apigateway.amazonaws.com",
|
189
|
+
source_arn: Humidifier.fn.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${#{api_gateway_id}}/*/#{gateway[:verb]}/#{arn_path_matcher}")
|
190
|
+
)
|
191
|
+
)
|
192
|
+
end
|
193
|
+
|
194
|
+
# gateway method
|
195
|
+
def add_api_gateway_resources(gateway:, lambda:)
|
196
|
+
|
197
|
+
# example: calculator/algebra/:x/:y/sum -> module name, args, method name
|
198
|
+
path = gateway[:path].split('/')
|
199
|
+
|
200
|
+
# root resource
|
201
|
+
root_resource = path.shift
|
202
|
+
stack.add(root_resource.camelize, Humidifier::ApiGateway::Resource.new(
|
203
|
+
rest_api_id: Humidifier.ref(api_gateway_id),
|
204
|
+
parent_id: Humidifier.fn.get_att(["ApiGateway", "RootResourceId"]),
|
205
|
+
path_part: root_resource
|
206
|
+
)
|
207
|
+
)
|
208
|
+
|
209
|
+
# args and method name are nested resources
|
210
|
+
parent_resource = root_resource.camelize
|
211
|
+
path.each do |fragment|
|
212
|
+
if fragment.start_with?(':')
|
213
|
+
fragment = fragment[1..-1]
|
214
|
+
dynamic_fragment = "{#{fragment}}"
|
215
|
+
end
|
216
|
+
stack.add(parent_resource + fragment.camelize, Humidifier::ApiGateway::Resource.new(
|
217
|
+
rest_api_id: Humidifier.ref(api_gateway_id),
|
218
|
+
parent_id: Humidifier.ref(parent_resource),
|
219
|
+
path_part: dynamic_fragment || fragment
|
220
|
+
)
|
221
|
+
)
|
222
|
+
parent_resource = parent_resource + fragment.camelize
|
223
|
+
end
|
224
|
+
|
225
|
+
# attach lambda to last resource
|
226
|
+
id = 'EndpointFor' + (gateway[:path].gsub(':', '').gsub('/', '_')).camelize
|
227
|
+
stack.add(id, Humidifier::ApiGateway::Method.new(
|
228
|
+
authorization_type: 'NONE',
|
229
|
+
http_method: gateway[:verb].to_s.upcase,
|
230
|
+
integration: {
|
231
|
+
integration_http_method: 'POST',
|
232
|
+
type: "AWS_PROXY",
|
233
|
+
uri: Humidifier.fn.sub([
|
234
|
+
"arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations",
|
235
|
+
'lambdaArn' => Humidifier.fn.get_att([lambda, 'Arn'])
|
236
|
+
])
|
237
|
+
},
|
238
|
+
rest_api_id: Humidifier.ref(api_gateway_id),
|
239
|
+
resource_id: Humidifier.ref(parent_resource) # last evaluated resource
|
240
|
+
)
|
241
|
+
)
|
242
|
+
|
243
|
+
# deployment depends on each endpoint
|
244
|
+
api_gateway_deployment.depends_on << id
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
# delegate from stack instance to our module
|
249
|
+
module Humidifier
|
250
|
+
class Stack
|
251
|
+
extend Forwardable
|
252
|
+
[StackBuilder, StackBuilder::LambdaPolicy].each do |mod|
|
253
|
+
def_delegators mod.to_s.to_sym, *mod.singleton_methods
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|