/
lambda.rb
184 lines (152 loc) · 6.74 KB
/
lambda.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
require 'dpl/helper/zip'
module Dpl
module Providers
class Lambda < Provider
status :alpha
full_name 'AWS Lambda'
description sq(<<-str)
tbd
str
gem 'aws-sdk-lambda', '~> 1.0'
gem 'rubyzip', '~> 1.2.2', require: 'zip'
env :aws
config '~/.aws/credentials', '~/.aws/config', prefix: 'aws'
opt '--access_key_id ID', 'AWS access key id', required: true, secret: true
opt '--secret_access_key KEY', 'AWS secret key', required: true, secret: true
opt '--region REGION', 'AWS region the Lambda function is running in', default: 'us-east-1'
opt '--function_name FUNC', 'Name of the Lambda being created or updated', required: true
opt '--role ROLE', 'ARN of the IAM role to assign to the Lambda function', note: 'required for creating a new function'
opt '--handler_name NAME', 'Function the Lambda calls to begin execution.', note: 'required for creating a new function'
opt '--module_name NAME', 'Name of the module that exports the handler', default: 'index', requires: :handler_name
opt '--description DESCR', 'Description of the Lambda being created or updated'
opt '--timeout SECS', 'Function execution time (in seconds) at which Lambda should terminate the function', default: 3
opt '--memory_size MB', 'Amount of memory in MB to allocate to this Lambda', default: 128
opt '--subnet_ids IDS', 'List of subnet IDs to be added to the function', type: :array, note: 'Needs the ec2:DescribeSubnets and ec2:DescribeVpcs permission for the user of the access/secret key to work'
opt '--security_group_ids IDS', 'List of security group IDs to be added to the function', type: :array, note: 'Needs the ec2:DescribeSecurityGroups and ec2:DescribeVpcs permission for the user of the access/secret key to work'
opt '--environment VARS', 'List of Environment Variables to add to the function', type: :array, format: /[\w\-]+=.+/, note: 'Can be encrypted for added security', alias: :environment_variables
opt '--runtime NAME', 'Lambda runtime to use', default: 'nodejs8.10', enum: %w(java8 nodejs8.10 nodejs10.x python2.7 python3.6 python3.7 dotnetcore2.1 go1.x ruby2.5)
opt '--dead_letter_arn ARN', 'ARN to an SNS or SQS resource used for the dead letter queue.'
opt '--kms_key_arn ARN', 'KMS key ARN to use to encrypt environment_variables.'
opt '--tracing_mode MODE', 'Tracing mode', default: 'PassThrough', enum: %w(Active PassThrough), note: 'Needs xray:PutTraceSegments xray:PutTelemetryRecords on the role'
opt '--layers LAYERS', 'Function layer arns', type: :array
opt '--function_tags TAGS', 'List of tags to add to the function', type: :array, format: /[\w\-]+=.+/, note: 'Can be encrypted for added security'
opt '--publish', 'Create a new version of the code instead of replacing the existing one.'
opt '--zip PATH', 'Path to a packaged Lambda, a directory to package, or a single file to package', default: '.'
opt '--dot_match', 'Include hidden .* files to the zipped archive'
msgs login: 'Using Access Key: %{access_key_id}',
create_function: 'Creating function %{function_name}.',
update_config: 'Updating existing function %{function_name}.',
update_tags: 'Updating tags.',
update_code: 'Updating code.',
description: 'Deploy build %{build_number} to AWS Lambda via Travis CI'
def login
info :login
end
def deploy
exists? ? update : create
rescue Aws::Errors::ServiceError => e
error e.message
end
private
def exists?
!!client.get_function(function_name: function_name)
rescue ::Aws::Lambda::Errors::ResourceNotFoundException
false
end
def create
info :create_function
config = function_config
config = config.merge(code: { zip_file: function_zip })
config = config.merge(tags: function_tags) if function_tags?
client.create_function(config)
end
def update
arn = update_config
update_tags(arn) if function_tags?
update_code
end
def update_config
info :update_config
response = client.update_function_configuration(function_config)
response.function_arn
end
def update_tags(arn)
info :update_tags
client.tag_resource(tag_resource(arn))
end
def update_code
info :update_code
client.update_function_code(function_code)
end
def function_config
compact(
function_name: function_name,
role: role,
handler: handler,
description: description,
timeout: timeout,
memory_size: memory_size,
vpc_config: vpc_config,
environment: environment,
runtime: runtime,
dead_letter_config: dead_letter_arn,
kms_key_arn: kms_key_arn,
tracing_config: tracing_config,
layers: layers
)
end
def tag_resource(arn)
{
resource: arn,
tags: function_tags
}
end
def function_code
{
function_name: function_name,
zip_file: function_zip,
publish: publish?
}
end
def handler
[module_name, java? ? '::' : '.', handler_name].join if handler_name?
end
def java?
runtime =~ /java/
end
def function_zip
Zip.new(zip, tmp_filename, opts).zip
end
def vpc_config
compact(subnet_ids: subnet_ids, security_group_ids: security_group_ids)
end
def environment
{ variables: split_vars(super) } if environment?
end
def dead_letter_arn
{ target_arn: super } if dead_letter_arn?
end
def tracing_config
{ mode: tracing_mode } if tracing_mode?
end
def function_tags
split_vars(super) if function_tags?
end
def description
super || interpolate(msg(:description))
end
def client
@client ||= Aws::Lambda::Client.new(region: region, credentials: credentials)
end
def credentials
Aws::Credentials.new(access_key_id, secret_access_key)
end
def split_vars(vars)
vars.map { |var| var.split('=', 2) }.to_h
end
def tmp_filename
@tmp_filename ||= "#{tmp_dir}/#{repo_name}.zip"
end
end
end
end