Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,16 @@ value for the environment variable at the time of deployment (instead of hard co

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.

Uploading to S3
===============
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.
Before doing this, you will need to set the following variables in `config.yaml`:
```
role: basic_s3_upload
bucket_name: 'example-bucket'
s3_key_prefix: 'path/to/file/'
```
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.

Development
===========
Expand Down
2 changes: 1 addition & 1 deletion aws_lambda/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
__email__ = 'nficano@gmail.com'
__version__ = '1.0.1'

from .aws_lambda import deploy, invoke, init, build, cleanup_old_versions
from .aws_lambda import deploy, invoke, init, build, upload, cleanup_old_versions

# Set default logging handler to avoid "No handler found" warnings.
import logging
Expand Down
55 changes: 55 additions & 0 deletions aws_lambda/aws_lambda.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import botocore
import pip
import yaml
import hashlib

from .helpers import archive
from .helpers import mkdir
Expand Down Expand Up @@ -94,6 +95,27 @@ def deploy(src, requirements=False, local_package=None):
else:
create_function(cfg, path_to_zip_file)

def upload(src, requirements=False, local_package=None):
"""Uploads a new function to AWS S3.

:param str src:
The path to your Lambda ready project (folder must contain a valid
config.yaml and handler module (e.g.: service.py).
:param str local_package:
The path to a local package with should be included in the deploy as
well (and/or is not available on PyPi)
"""
# Load and parse the config file.
path_to_config_file = os.path.join(src, 'config.yaml')
cfg = read(path_to_config_file, loader=yaml.load)

# Copy all the pip dependencies required to run your code into a temporary
# folder then add the handler file in the root of this directory.
# Zip the contents of this folder into a single file and output to the dist
# directory.
path_to_zip_file = build(src, requirements, local_package)

upload_s3(cfg, path_to_zip_file)

def invoke(src, alt_event=None, verbose=False):
"""Simulates a call to your function.
Expand Down Expand Up @@ -432,6 +454,39 @@ def update_function(cfg, path_to_zip_file):

client.update_function_configuration(**kwargs)

def upload_s3(cfg, path_to_zip_file):
"""Upload a function to AWS S3."""

print('Uploading your new Lambda function')
aws_access_key_id = cfg.get('aws_access_key_id')
aws_secret_access_key = cfg.get('aws_secret_access_key')
account_id = get_account_id(aws_access_key_id, aws_secret_access_key)
client = get_client('s3', aws_access_key_id, aws_secret_access_key,
cfg.get('region'))
role = get_role_name(account_id, cfg.get('role', 'basic_s3_upload'))
byte_stream = b''
with open(path_to_zip_file, mode='rb') as fh:
byte_stream = fh.read()
s3_key_prefix = cfg.get('s3_key_prefix', '/dist')
checksum = hashlib.new('md5', byte_stream).hexdigest()
timestamp = str(time.time())
filename = '{prefix}{checksum}-{ts}.zip'.format(prefix=s3_key_prefix, checksum=checksum, ts=timestamp)

# Do we prefer development variable over config?
buck_name = (
os.environ.get('S3_BUCKET_NAME') or cfg.get('bucket_name')
)
func_name = (
os.environ.get('LAMBDA_FUNCTION_NAME') or cfg.get('function_name')
)
kwargs = {
'Bucket': '{}'.format(buck_name),
'Key': '{}'.format(filename),
'Body': byte_stream
}

client.put_object(**kwargs)
print('Finished uploading {} to S3 bucket {}'.format(func_name, buck_name))

def function_exists(cfg, function_name):
"""Check whether a function exists or not"""
Expand Down
7 changes: 6 additions & 1 deletion aws_lambda/project_templates/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ region: us-east-1

function_name: my_lambda_function
handler: service.handler
# role: lambda_basic_execution
description: My first lambda function
runtime: python2.7
# role: lambda_basic_execution

# S3 upload requires appropriate role with s3:PutObject permission
# (ex. basic_s3_upload), a destination bucket, and the key prefix
# bucket_name: 'example-bucket'
# s3_key_prefix: 'path/to/file/'

# if access key and secret are left blank, boto will use the credentials
# defined in the [default] section of ~/.aws/credentials.
Expand Down
7 changes: 6 additions & 1 deletion scripts/lambda
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ def invoke(event_file, verbose):
def deploy(use_requirements, local_package):
aws_lambda.deploy(CURRENT_DIR, use_requirements, local_package)


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

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