Skip to content

Commit f954602

Browse files
committed
Merge branch 'master' of github.com:nficano/python-lambda
* 'master' of github.com:nficano/python-lambda: updating README and changing md5 to hashlib removing print statement adding various changes based on review feedback Update README.rst include subdirectories when building for deploy making reference to bucket_name consistent forgot to add refs to upload func adding function to upload to s3 Push environment variables from the config file into the actual environment when calling invoke
2 parents 51782e9 + b8f084f commit f954602

File tree

5 files changed

+100
-13
lines changed

5 files changed

+100
-13
lines changed

README.rst

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,22 @@ 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
===========
171181

172-
Development of this happens on GitHub, patches including tests, documentation are very welcome, as well as bug reports and feature contributions are welcome! Also please open an issue if this tool does not function as you'd expect.
182+
Development of "python-lambda" is facilitated exclusively on GitHub. Contributions in the form of patches, tests and feature creation and/or requests are very welcome and highly encouraged. Please open an issue if this tool does not function as you'd expect.
183+
173184

174185
How to release updates
175186
----------------------
@@ -180,10 +191,16 @@ Once complete, execute the following commands:
180191

181192
.. code:: bash
182193
183-
$ git checkout master
184-
$ bumpversion [major|minor|patch]
185-
$
186-
$ python setup.py sdist bdist_wheel upload
187-
$
188-
$ bumpversion --no-tag patch
189-
$ git push origin master --tags
194+
git checkout master
195+
196+
# Increment the version number and tag the release.
197+
bumpversion [major|minor|patch]
198+
199+
# Upload the distribution to PyPi
200+
python setup.py sdist bdist_wheel upload
201+
202+
# Since master often contains work-in-progress changes, increment the version
203+
# to a patch release to prevent inaccurate attribution.
204+
bumpversion --no-tag patch
205+
206+
git push origin master --tags

aws_lambda/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
__email__ = '[email protected]'
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: 62 additions & 2 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.
@@ -110,6 +132,10 @@ def invoke(src, alt_event=None, verbose=False):
110132
path_to_config_file = os.path.join(src, 'config.yaml')
111133
cfg = read(path_to_config_file, loader=yaml.load)
112134

135+
# Load environment variables from the config file into the actual environment.
136+
for key, value in cfg.get('environment_variables').items():
137+
os.environ[key] = value
138+
113139
# Load and parse event file.
114140
if alt_event:
115141
path_to_event_file = os.path.join(src, alt_event)
@@ -211,8 +237,9 @@ def build(src, requirements=False, local_package=None):
211237
continue
212238
if filename == 'config.yaml':
213239
continue
214-
print('Bundling: %r' % filename)
215-
files.append(os.path.join(src, filename))
240+
# TODO: Check subdirectories for '.DS_Store' files
241+
print('Bundling: %r' % filename)
242+
files.append(os.path.join(src, filename))
216243

217244
# "cd" into `temp_path` directory.
218245
os.chdir(path_to_temp)
@@ -432,6 +459,39 @@ def update_function(cfg, path_to_zip_file):
432459

433460
client.update_function_configuration(**kwargs)
434461

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))
435495

436496
def function_exists(cfg, function_name):
437497
"""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)