Skip to content

Commit b8f084f

Browse files
authored
Merge pull request nficano#63 from slapula/master
Adding function to upload zip file to S3
2 parents f23d9ba + 9ebf9e7 commit b8f084f

File tree

5 files changed

+78
-3
lines changed

5 files changed

+78
-3
lines changed

README.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,16 @@ value for the environment variable at the time of deployment (instead of hard co
165165
166166
This would create environment variables in the lambda instance upon deploy. If your functions don't need environment variables, simply leave this section out of your config.
167167

168+
Uploading to S3
169+
===============
170+
You may find that you do not need the toolkit to fully deploy your Lambda or that your code bundle is too large to upload via the API. You can use the `upload` command to send the bundle to an S3 bucket of your choosing.
171+
Before doing this, you will need to set the following variables in `config.yaml`:
172+
```
173+
role: basic_s3_upload
174+
bucket_name: 'example-bucket'
175+
s3_key_prefix: 'path/to/file/'
176+
```
177+
Your role must have `s3:PutObject` permission on the bucket/key that you specify for the upload to work properly. Once you have that set, you can execute `lambda upload` to initiate the transfer.
168178

169179
Development
170180
===========

aws_lambda/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
__email__ = 'nficano@gmail.com'
55
__version__ = '1.0.1'
66

7-
from .aws_lambda import deploy, invoke, init, build, cleanup_old_versions
7+
from .aws_lambda import deploy, invoke, init, build, upload, cleanup_old_versions
88

99
# Set default logging handler to avoid "No handler found" warnings.
1010
import logging

aws_lambda/aws_lambda.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import botocore
1616
import pip
1717
import yaml
18+
import hashlib
1819

1920
from .helpers import archive
2021
from .helpers import mkdir
@@ -94,6 +95,27 @@ def deploy(src, requirements=False, local_package=None):
9495
else:
9596
create_function(cfg, path_to_zip_file)
9697

98+
def upload(src, requirements=False, local_package=None):
99+
"""Uploads a new function to AWS S3.
100+
101+
:param str src:
102+
The path to your Lambda ready project (folder must contain a valid
103+
config.yaml and handler module (e.g.: service.py).
104+
:param str local_package:
105+
The path to a local package with should be included in the deploy as
106+
well (and/or is not available on PyPi)
107+
"""
108+
# Load and parse the config file.
109+
path_to_config_file = os.path.join(src, 'config.yaml')
110+
cfg = read(path_to_config_file, loader=yaml.load)
111+
112+
# Copy all the pip dependencies required to run your code into a temporary
113+
# folder then add the handler file in the root of this directory.
114+
# Zip the contents of this folder into a single file and output to the dist
115+
# directory.
116+
path_to_zip_file = build(src, requirements, local_package)
117+
118+
upload_s3(cfg, path_to_zip_file)
97119

98120
def invoke(src, alt_event=None, verbose=False):
99121
"""Simulates a call to your function.
@@ -437,6 +459,39 @@ def update_function(cfg, path_to_zip_file):
437459

438460
client.update_function_configuration(**kwargs)
439461

462+
def upload_s3(cfg, path_to_zip_file):
463+
"""Upload a function to AWS S3."""
464+
465+
print('Uploading your new Lambda function')
466+
aws_access_key_id = cfg.get('aws_access_key_id')
467+
aws_secret_access_key = cfg.get('aws_secret_access_key')
468+
account_id = get_account_id(aws_access_key_id, aws_secret_access_key)
469+
client = get_client('s3', aws_access_key_id, aws_secret_access_key,
470+
cfg.get('region'))
471+
role = get_role_name(account_id, cfg.get('role', 'basic_s3_upload'))
472+
byte_stream = b''
473+
with open(path_to_zip_file, mode='rb') as fh:
474+
byte_stream = fh.read()
475+
s3_key_prefix = cfg.get('s3_key_prefix', '/dist')
476+
checksum = hashlib.new('md5', byte_stream).hexdigest()
477+
timestamp = str(time.time())
478+
filename = '{prefix}{checksum}-{ts}.zip'.format(prefix=s3_key_prefix, checksum=checksum, ts=timestamp)
479+
480+
# Do we prefer development variable over config?
481+
buck_name = (
482+
os.environ.get('S3_BUCKET_NAME') or cfg.get('bucket_name')
483+
)
484+
func_name = (
485+
os.environ.get('LAMBDA_FUNCTION_NAME') or cfg.get('function_name')
486+
)
487+
kwargs = {
488+
'Bucket': '{}'.format(buck_name),
489+
'Key': '{}'.format(filename),
490+
'Body': byte_stream
491+
}
492+
493+
client.put_object(**kwargs)
494+
print('Finished uploading {} to S3 bucket {}'.format(func_name, buck_name))
440495

441496
def function_exists(cfg, function_name):
442497
"""Check whether a function exists or not"""

aws_lambda/project_templates/config.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@ region: us-east-1
22

33
function_name: my_lambda_function
44
handler: service.handler
5-
# role: lambda_basic_execution
65
description: My first lambda function
76
runtime: python2.7
7+
# role: lambda_basic_execution
8+
9+
# S3 upload requires appropriate role with s3:PutObject permission
10+
# (ex. basic_s3_upload), a destination bucket, and the key prefix
11+
# bucket_name: 'example-bucket'
12+
# s3_key_prefix: 'path/to/file/'
813

914
# if access key and secret are left blank, boto will use the credentials
1015
# defined in the [default] section of ~/.aws/credentials.

scripts/lambda

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ def invoke(event_file, verbose):
4646
def deploy(use_requirements, local_package):
4747
aws_lambda.deploy(CURRENT_DIR, use_requirements, local_package)
4848

49-
49+
@click.command(help="Upload your lambda to S3.")
50+
@click.option('--use-requirements', default=False, is_flag=True, help='Install all packages defined in requirements.txt')
51+
@click.option('--local-package', default=None, help='Install local package as well.', type=click.Path(), multiple=True)
52+
def upload(use_requirements, local_package):
53+
aws_lambda.upload(CURRENT_DIR, use_requirements, local_package)
5054

5155
@click.command(help="Delete old versions of your functions")
5256
@click.option("--keep-last", type=int, prompt="Please enter the number of recent versions to keep")
@@ -57,6 +61,7 @@ if __name__ == '__main__':
5761
cli.add_command(init)
5862
cli.add_command(invoke)
5963
cli.add_command(deploy)
64+
cli.add_command(upload)
6065
cli.add_command(build)
6166
cli.add_command(cleanup)
6267
cli()

0 commit comments

Comments
 (0)