Skip to content

Instantly share code, notes, and snippets.

@steinwaywhw
Last active March 8, 2022 10:40
Show Gist options
  • Save steinwaywhw/9d64db15518099c1f26f254ee35c4217 to your computer and use it in GitHub Desktop.
Save steinwaywhw/9d64db15518099c1f26f254ee35c4217 to your computer and use it in GitHub Desktop.
An extremely simple AWS Lambda example in Python 3.

Preface

In general, AWS services can be accessed using

  1. AWS web interface,
  2. API libraries in a programming language, such as boto3 for Python 3,
  3. AWS command-line interface, i.e. awscli.

I opted for the API library since it is

  1. formally defined,
  2. programmable by definition,
  3. can be version controlled.

A Simple Example

Assuming that awscli is installed and properly configured with access keys and secrets, we can run a very simple lambda function in hello.py using scripts in the main.py file. The main.py script is extremely minimal, and the source code demos how to interact with AWS Lambda services.

For instance, let's start up an ipython in the shell, and perform the followings.

In [1]: import main
   ...: main.setup_roles()
   ...: main.create_function()
   ...: main.invoke_function('Jeff', 'Bezos')
Out[1]: ...

To see the logs generated from the lambda function, we can do

In [2]: main.get_logs()
Out[2]: ...

If we changed the contents of hello.py, we should update it on AWS Lambda by using

In [3]: main.update_function()
Out[3]: ...

If we changed the contents of our script main.py, we can reload it.

In [4]: from importlib import reload
   ...: reload(main)
Out[4]:

Appendix

To setup AWS accounts using IAM in general, follow Set Up an AWS Account - AWS Lambda. Alternatively, in ipython,

In [1]: import boto3
   ...: iam = boto3.client('iam')
   ...: iam.create_user(UserName='user')
Out[1]: ...

To give it full permissions (not recommended),

In [2]: iam.attach_user_policy(UserName='user', PolicyArn='arn:aws:iam::aws:policy/AdministratorAccess')
Out[2]: ...

To create an access key,

In [3]: iam.create_access_key(UserName='user')
Out[3]: ...

We can now use the access key and secret to configure AWS command-line interface. To install and configure AWS command-line interface, follow these links,

TL;DR, in the shell, e.g. bash,

pip3 install --upgrade awscli
aws configure 

After properly configuring AWS CLI, the boto3 library can properly use AWS services in Python 3.

def handler(event, context):
message = f'Hello {event["first_name"]} {event["last_name"]}!'
return {'message': message, 'event': event}
import json, boto3, yaml
config = yaml.load("""
role: BasicLambdaRole
name: HelloWorld
zip: HelloWorld.zip
path: ./hello.py
handler: hello.handler
""")
def setup_roles():
""" Sets up AWS IAM roles for executing this lambda function. """
# https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html
# https://docs.aws.amazon.com/lambda/latest/dg/policy-templates.html
# https://docs.aws.amazon.com/lambda/latest/dg/intro-permission-model.html#lambda-intro-execution-role
basic_role = """
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
"""
iam = boto3.client('iam')
# lambda.awazonaws.com can assume this role.
iam.create_role(RoleName=config['role'],
AssumeRolePolicyDocument=json.dumps(yaml.load(basic_role)))
# This role has the AWSLambdaBasicExecutionRole managed policy.
iam.attach_role_policy(RoleName=config['role'],
PolicyArn='arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole')
def get_logs():
""" Returns all logs related to the invocations of this lambda function. """
log = boto3.client('logs')
return log.filter_log_events(logGroupName=f'/aws/lambda/{config["name"]}')
def create_function():
""" Creates and uploads the lambda function. """
lam = boto3.client('lambda')
iam = boto3.client('iam')
# Creates a zip file containing our handler code.
import zipfile
with zipfile.ZipFile(config['zip'], 'w') as z:
z.write(config['path'])
# Loads the zip file as binary code.
with open(config['zip'], 'rb') as f:
code = f.read()
role = iam.get_role(RoleName=config['role'])
return lam.create_function(
FunctionName=config['name'],
Runtime='python3.6',
Role=role['Role']['Arn'],
Handler=config['handler'],
Code={'ZipFile':code})
def update_function():
""" Updates the function. """
lam = boto3.client('lambda')
# Creates a zip file containing our handler code.
import zipfile
with zipfile.ZipFile(config['zip'], 'w') as z:
z.write(config['path'])
# Loads the zip file as binary code.
with open(config['zip'], 'rb') as f:
code = f.read()
return lam.update_function_code(
FunctionName=config['name'],
ZipFile=code)
def invoke_function(first, last):
""" Invokes the function. """
lam = boto3.client('lambda')
resp = lam.invoke(
FunctionName=config['name'],
InvocationType='RequestResponse',
LogType='Tail',
Payload=json.dumps({'first_name': first, 'last_name': last}))
print(resp['Payload'].read())
return resp
@apatrushev
Copy link

Just to note: you can simplify your code by using

package = io.BytesIO()
with zipfile.ZipFile(package) as z:
    [skipped]
package = package.getvalue()

... and avoid temp files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment