lambda_deployment 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3c703c23c73564ef0a8f7bd9124ad25f4c3c7abe
4
+ data.tar.gz: 72a2a8888964fa26bad41af062a81411e708bf9e
5
+ SHA512:
6
+ metadata.gz: 64b21dc6b85d9a9ac17fba736cadc6c39998b3e760425245c9155509766054ed96ad5cbdad5ddba987b784df7712fd5472c977016f75abc1f572fbf1e0a5d7b6
7
+ data.tar.gz: 555176f4ddff69b6435aa286234746eabbad8c79dfe8bef09eea60d34e980217aef964dd534118e24d52271795bb47603fabdb5058f97211448c66b2668c7f0f
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # lambda_deployment
2
+ Ruby gem for deploying lambda functions in AWS with Samson or another tool.
3
+ **This gem is used to update the function code only** - the resources must
4
+ already be provisioned using another tool (or manually).
5
+
6
+ [![Build Status](https://travis-ci.org/zendesk/lambda_deployment.svg?branch=master)](https://travis-ci.org/zendesk/lambda_deployment)
7
+
8
+ ## Usage
9
+ This gem provides a binary called `lambda_deploy` which will deploy a zip or
10
+ jar file to lambda, version it, and promote it to production (release).
11
+ Usage:
12
+ ```
13
+ lambda_deploy [-c path/to/configuration.yml] deploy|release
14
+ ```
15
+
16
+ ### Deploy action
17
+ The deploy action will upload the function to S3, and update the function to
18
+ use the new code. If the environmental variable `TAG` is set it will also
19
+ create a version and link that version to an alias named `TAG`.
20
+
21
+ ### Release action
22
+ The release action will link the `production` alias to the version referenced
23
+ by the `TAG` alias. **If `TAG` is not set this action is only required if the
24
+ `production` alias is not already pointing to `$LATEST`.**
25
+
26
+ ## Environmental variables
27
+ The configuration file is intentionally small with the option to override
28
+ environmental variables. The default action is to fetch values from the
29
+ environment to ensure consistency within a given environment. These variables
30
+ should be set within the deploy tool or using the configuration file.
31
+
32
+ ### AWS_REGION (required)
33
+ Region in AWS where resources are located.
34
+
35
+ ### LAMBDA_ASSUME_ROLE (optional)
36
+ STS assume role to use if resources are in another account.
37
+
38
+ ### LAMBDA_S3_BUCKET (required)
39
+ Name of S3 bucket to upload function to. Buckets can be provisioned per project
40
+ or per environment.
41
+
42
+ ### LAMBDA_S3_SSE (optional)
43
+ Type of encryption to use with S3.
44
+
45
+ ### TAG (optional)
46
+ Version of the function being uploaded (e.g. git tag).
47
+
48
+ ## Quickstart Guide
49
+ See the `examples/lambda` directory for a sample project layout.
50
+
51
+ ### Add the gem to your project
52
+ Add the following line to your `Gemfile` and run `bundle install`:
53
+ ```
54
+ gem 'lambda_deployment'
55
+ ```
56
+
57
+ ### Create a lambda_deploy.yml configuration file
58
+ The only required fields are the project name (the function name in AWS), and
59
+ the zip or jar file to upload (containing at least the script named after the
60
+ lambda_function).
61
+
62
+ Here is an example:
63
+ ```
64
+ file_name: lambda/foobar.zip # required: zip or jar of lambda function and dependencies
65
+ project: my-dev-lambda-name # required: name of lambda function
66
+ region: us-east-1 # optional: specify AWS region (will override $AWS_REGION)
67
+ s3_bucket: my-test-bucket # optional: specify s3 bucket (will override $LAMBDA_S3_BUCKET)
68
+ s3_sse: AES256 # optional: set server side encryption on s3 objects (will override $LAMBDA_S3_SSE)
69
+ ```
70
+
71
+ * *file_name* is a path relative to the configuration file
72
+ * *project* must match the function name in the AWS console (the last value in
73
+ the following example):
74
+ ```
75
+ arn:aws:lambda:<region>:<account_id>:function:<project>
76
+ ```
77
+
78
+ ### Create lambda function and s3 bucket
79
+ The lambda function and s3 buckets must already exist to use this gem. If you
80
+ are creating actions for your lambda make sure they execute the `production`
81
+ alias (see below). To do this append `:production` to the end of the ARN
82
+ associated with your lambda function.
83
+
84
+ ### Create `production` alias for lambda function
85
+ In the lambda console chose *Create alias* from the *Actions* drop down. The
86
+ name should be `production` and version should point to `$LATEST`.
data/bin/lambda_deploy ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'lambda_deployment/cli'
4
+
5
+ LambdaDeployment::CLI.new.run(ARGV)
@@ -0,0 +1,42 @@
1
+ require 'lambda_deployment'
2
+
3
+ module LambdaDeployment
4
+ class CLI
5
+ def run(args)
6
+ parse_args(args)
7
+ case @action
8
+ when 'deploy'
9
+ deploy
10
+ when 'release'
11
+ release
12
+ else
13
+ raise 'Action must be either deploy or release'
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def config
20
+ @config ||= LambdaDeployment::Configuration.new
21
+ end
22
+
23
+ def deploy
24
+ LambdaDeployment::Lambda::Deploy.new(config).run
25
+ end
26
+
27
+ def release
28
+ LambdaDeployment::Lambda::Release.new(config).run
29
+ end
30
+
31
+ def parse_args(args)
32
+ config_file = 'lambda_deploy.yml'
33
+ OptionParser.new do |opts|
34
+ opts.banner = 'Usage: lambda_deploy [-c FILE] deploy|release'
35
+ opts.version = LambdaDeployment::VERSION
36
+ opts.on('-c', '--config [FILE]', 'Use specified config file') { |c| config_file = c }
37
+ end.parse!(args)
38
+ @action = args.shift
39
+ config.load_config(config_file)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,32 @@
1
+ module LambdaDeployment
2
+ class Client
3
+ def initialize(region)
4
+ @region = region
5
+ end
6
+
7
+ def lambda_client
8
+ @lambda_client ||= Aws::Lambda::Client.new(config)
9
+ end
10
+
11
+ def s3_client
12
+ @s3_client ||= Aws::S3::Client.new(config)
13
+ end
14
+
15
+ private
16
+
17
+ def config
18
+ config = { region: @region }
19
+ if role_arn
20
+ config[:credentials] = Aws::AssumeRoleCredentials.new(
21
+ role_arn: role_arn,
22
+ role_session_name: SecureRandom.hex(10)
23
+ )
24
+ end
25
+ config
26
+ end
27
+
28
+ def role_arn
29
+ ENV.fetch('LAMBDA_ASSUME_ROLE', false)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ module LambdaDeployment
2
+ class Configuration
3
+ attr_reader :file_path, :project, :region, :s3_bucket, :s3_key, :s3_sse
4
+
5
+ def load_config(config_file)
6
+ config = YAML.load_file(config_file)
7
+ @project = config.fetch('project')
8
+ @region = config.fetch('region', ENV.fetch('AWS_REGION', nil))
9
+ @file_path = File.expand_path(config.fetch('file_name'), File.dirname(config_file))
10
+ raise "File not found: #{@file_path}" unless File.exist?(@file_path)
11
+
12
+ @s3_bucket = config.fetch('s3_bucket', ENV.fetch('LAMBDA_S3_BUCKET', nil))
13
+ @s3_key = s3_key_name(config.fetch('file_name'))
14
+ @s3_sse = config.fetch('s3_sse', ENV.fetch('LAMBDA_S3_SSE', nil))
15
+ end
16
+
17
+ def alias_name
18
+ ENV.fetch('TAG', nil)
19
+ end
20
+
21
+ private
22
+
23
+ def s3_key_name(file_name)
24
+ basename = File.basename(file_name, '.*')
25
+ extension = File.extname(file_name)
26
+ "#{basename}-#{ENV.fetch('TAG', 'latest')}#{extension}"
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,63 @@
1
+ module LambdaDeployment
2
+ module Lambda
3
+ class Deploy
4
+ def initialize(config)
5
+ @config = config
6
+ @client = LambdaDeployment::Client.new(config.region)
7
+ end
8
+
9
+ def run
10
+ upload_to_s3
11
+ update_function_code
12
+ return unless @config.alias_name
13
+ version = publish_version
14
+ begin
15
+ create_alias(version)
16
+ rescue Aws::Lambda::Errors::ResourceConflictException
17
+ update_alias(version)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def upload_to_s3
24
+ @client.s3_client.put_object(
25
+ body: File.read(@config.file_path),
26
+ bucket: @config.s3_bucket,
27
+ key: @config.s3_key,
28
+ server_side_encryption: @config.s3_sse
29
+ )
30
+ end
31
+
32
+ def update_function_code
33
+ @client.lambda_client.update_function_code(
34
+ function_name: @config.project,
35
+ s3_bucket: @config.s3_bucket,
36
+ s3_key: @config.s3_key
37
+ )
38
+ end
39
+
40
+ def publish_version
41
+ @client.lambda_client.publish_version(
42
+ function_name: @config.project
43
+ ).version
44
+ end
45
+
46
+ def create_alias(version)
47
+ @client.lambda_client.create_alias(alias_params(version))
48
+ end
49
+
50
+ def update_alias(version)
51
+ @client.lambda_client.update_alias(alias_params(version))
52
+ end
53
+
54
+ def alias_params(version)
55
+ {
56
+ function_name: @config.project,
57
+ name: @config.alias_name,
58
+ function_version: version
59
+ }
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,36 @@
1
+ module LambdaDeployment
2
+ module Lambda
3
+ class Release
4
+ def initialize(config)
5
+ @config = config
6
+ @client = LambdaDeployment::Client.new(config.region)
7
+ end
8
+
9
+ def run
10
+ version = version_for_tag
11
+ update_production_alias(version)
12
+ end
13
+
14
+ private
15
+
16
+ def version_for_tag
17
+ if @config.alias_name
18
+ @client.lambda_client.get_alias(
19
+ function_name: @config.project,
20
+ name: @config.alias_name
21
+ ).function_version
22
+ else
23
+ '$LATEST'
24
+ end
25
+ end
26
+
27
+ def update_production_alias(version)
28
+ @client.lambda_client.update_alias(
29
+ function_name: @config.project,
30
+ function_version: version,
31
+ name: 'production'
32
+ )
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ module LambdaDeployment
2
+ VERSION = '0.1.0'.freeze
3
+ end
@@ -0,0 +1,10 @@
1
+ require 'aws-sdk-core'
2
+ require 'optparse'
3
+ require 'securerandom'
4
+ require 'yaml'
5
+ require 'lambda_deployment/cli'
6
+ require 'lambda_deployment/client'
7
+ require 'lambda_deployment/configuration'
8
+ require 'lambda_deployment/lambda/deploy'
9
+ require 'lambda_deployment/lambda/release'
10
+ require 'lambda_deployment/version'
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lambda_deployment
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Zendesk CloudOps
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-08-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: single_cov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description:
70
+ email:
71
+ executables:
72
+ - lambda_deploy
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - README.md
77
+ - bin/lambda_deploy
78
+ - lib/lambda_deployment.rb
79
+ - lib/lambda_deployment/cli.rb
80
+ - lib/lambda_deployment/client.rb
81
+ - lib/lambda_deployment/configuration.rb
82
+ - lib/lambda_deployment/lambda/deploy.rb
83
+ - lib/lambda_deployment/lambda/release.rb
84
+ - lib/lambda_deployment/version.rb
85
+ homepage: https://github.com/zendesk/lambda_deployment
86
+ licenses: []
87
+ metadata: {}
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 2.6.8
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Lambda Deployment Library
108
+ test_files: []