2020-07-09 17:27:30 -07:00
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""
Purpose
2022-04-08 15:42:13 -07:00
Shows how to use the AWS SDK for Python (Boto3) to manage and invoke AWS Lambda
functions.
2020-07-09 17:27:30 -07:00
"""
import io
import json
import logging
import zipfile
from botocore . exceptions import ClientError
logger = logging . getLogger ( __name__ )
2022-04-08 15:42:13 -07:00
# snippet-start:[python.example_code.python.LambdaWrapper.full]
# snippet-start:[python.example_code.python.LambdaWrapper.decl]
class LambdaWrapper :
def __init__ ( self , lambda_client , iam_resource ) :
self . lambda_client = lambda_client
self . iam_resource = iam_resource
2023-10-18 10:35:05 -07:00
# snippet-end:[python.example_code.python.LambdaWrapper.decl]
2022-04-08 15:42:13 -07:00
@staticmethod
def create_deployment_package ( source_file , destination_file ) :
"""
2022-04-12 12:01:44 -07:00
Creates a Lambda deployment package in .zip format in an in-memory buffer. This
2022-04-08 15:42:13 -07:00
buffer can be passed directly to Lambda when creating the function.
:param source_file: The name of the file that contains the Lambda handler
function.
:param destination_file: The name to give the file when it ' s deployed to Lambda.
:return: The deployment package.
"""
buffer = io . BytesIO ( )
2023-10-18 10:35:05 -07:00
with zipfile . ZipFile ( buffer , " w " ) as zipped :
2022-04-08 15:42:13 -07:00
zipped . write ( source_file , destination_file )
buffer . seek ( 0 )
return buffer . read ( )
def get_iam_role ( self , iam_role_name ) :
"""
Get an AWS Identity and Access Management (IAM) role.
:param iam_role_name: The name of the role to retrieve.
:return: The IAM role.
"""
role = None
2020-07-09 17:27:30 -07:00
try :
2022-04-08 15:42:13 -07:00
temp_role = self . iam_resource . Role ( iam_role_name )
temp_role . load ( )
role = temp_role
logger . info ( " Got IAM role %s " , role . name )
except ClientError as err :
2023-10-18 10:35:05 -07:00
if err . response [ " Error " ] [ " Code " ] == " NoSuchEntity " :
2022-04-08 15:42:13 -07:00
logger . info ( " IAM role %s does not exist. " , iam_role_name )
else :
logger . error (
2023-10-18 10:35:05 -07:00
" Couldn ' t get IAM role %s . Here ' s why: %s : %s " ,
iam_role_name ,
err . response [ " Error " ] [ " Code " ] ,
err . response [ " Error " ] [ " Message " ] ,
)
2022-04-08 15:42:13 -07:00
raise
return role
def create_iam_role_for_lambda ( self , iam_role_name ) :
"""
Creates an IAM role that grants the Lambda function basic permissions. If a
role with the specified name already exists, it is used for the demo.
:param iam_role_name: The name of the role to create.
:return: The role and a value that indicates whether the role is newly created.
"""
role = self . get_iam_role ( iam_role_name )
if role is not None :
return role , False
lambda_assume_role_policy = {
2023-10-18 10:35:05 -07:00
" Version " : " 2012-10-17 " ,
" Statement " : [
2022-04-08 15:42:13 -07:00
{
2023-10-18 10:35:05 -07:00
" Effect " : " Allow " ,
" Principal " : { " Service " : " lambda.amazonaws.com " } ,
" Action " : " sts:AssumeRole " ,
2022-04-08 15:42:13 -07:00
}
2023-10-18 10:35:05 -07:00
] ,
2022-04-08 15:42:13 -07:00
}
2023-10-18 10:35:05 -07:00
policy_arn = " arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole "
2022-04-08 15:42:13 -07:00
try :
role = self . iam_resource . create_role (
RoleName = iam_role_name ,
2023-10-18 10:35:05 -07:00
AssumeRolePolicyDocument = json . dumps ( lambda_assume_role_policy ) ,
)
2022-04-08 15:42:13 -07:00
logger . info ( " Created role %s . " , role . name )
role . attach_policy ( PolicyArn = policy_arn )
logger . info ( " Attached basic execution policy to role %s . " , role . name )
2020-07-09 17:27:30 -07:00
except ClientError as error :
2023-10-18 10:35:05 -07:00
if error . response [ " Error " ] [ " Code " ] == " EntityAlreadyExists " :
2022-04-08 15:42:13 -07:00
role = self . iam_resource . Role ( iam_role_name )
logger . warning ( " The role %s already exists. Using it. " , iam_role_name )
2020-07-09 17:27:30 -07:00
else :
2022-04-08 15:42:13 -07:00
logger . exception (
" Couldn ' t create role %s or attach policy %s . " ,
2023-10-18 10:35:05 -07:00
iam_role_name ,
policy_arn ,
)
2020-07-09 17:27:30 -07:00
raise
2022-04-08 15:42:13 -07:00
return role , True
# snippet-start:[python.example_code.lambda.GetFunction]
def get_function ( self , function_name ) :
"""
Gets data about a Lambda function.
:param function_name: The name of the function.
:return: The function data.
"""
response = None
try :
response = self . lambda_client . get_function ( FunctionName = function_name )
except ClientError as err :
2023-10-18 10:35:05 -07:00
if err . response [ " Error " ] [ " Code " ] == " ResourceNotFoundException " :
2022-04-08 15:42:13 -07:00
logger . info ( " Function %s does not exist. " , function_name )
else :
logger . error (
2023-10-18 10:35:05 -07:00
" Couldn ' t get function %s . Here ' s why: %s : %s " ,
function_name ,
err . response [ " Error " ] [ " Code " ] ,
err . response [ " Error " ] [ " Message " ] ,
)
2022-04-08 15:42:13 -07:00
raise
return response
2023-10-18 10:35:05 -07:00
2022-04-08 15:42:13 -07:00
# snippet-end:[python.example_code.lambda.GetFunction]
# snippet-start:[python.example_code.lambda.CreateFunction]
2023-10-18 10:35:05 -07:00
def create_function (
self , function_name , handler_name , iam_role , deployment_package
) :
2022-04-08 15:42:13 -07:00
"""
Deploys a Lambda function.
:param function_name: The name of the Lambda function.
:param handler_name: The fully qualified name of the handler function. This
must include the file name and the function name.
:param iam_role: The IAM role to use for the function.
:param deployment_package: The deployment package that contains the function
2022-04-12 12:01:44 -07:00
code in .zip format.
2022-04-08 15:42:13 -07:00
:return: The Amazon Resource Name (ARN) of the newly created function.
"""
try :
response = self . lambda_client . create_function (
FunctionName = function_name ,
Description = " AWS Lambda doc example " ,
2024-10-22 16:22:44 -04:00
Runtime = " python3.9 " ,
2022-04-08 15:42:13 -07:00
Role = iam_role . arn ,
Handler = handler_name ,
2023-10-18 10:35:05 -07:00
Code = { " ZipFile " : deployment_package } ,
Publish = True ,
)
function_arn = response [ " FunctionArn " ]
waiter = self . lambda_client . get_waiter ( " function_active_v2 " )
2022-04-08 15:42:13 -07:00
waiter . wait ( FunctionName = function_name )
2023-10-18 10:35:05 -07:00
logger . info (
" Created function ' %s ' with ARN: ' %s ' . " ,
function_name ,
response [ " FunctionArn " ] ,
)
2022-04-08 15:42:13 -07:00
except ClientError :
logger . error ( " Couldn ' t create function %s . " , function_name )
2020-07-09 17:27:30 -07:00
raise
2022-04-08 15:42:13 -07:00
else :
return function_arn
2023-10-18 10:35:05 -07:00
2022-04-08 15:42:13 -07:00
# snippet-end:[python.example_code.lambda.CreateFunction]
2020-07-09 17:27:30 -07:00
2022-04-08 15:42:13 -07:00
# snippet-start:[python.example_code.lambda.DeleteFunction]
def delete_function ( self , function_name ) :
"""
Deletes a Lambda function.
:param function_name: The name of the function to delete.
"""
try :
self . lambda_client . delete_function ( FunctionName = function_name )
except ClientError :
logger . exception ( " Couldn ' t delete function %s . " , function_name )
raise
2023-10-18 10:35:05 -07:00
2022-04-08 15:42:13 -07:00
# snippet-end:[python.example_code.lambda.DeleteFunction]
# snippet-start:[python.example_code.lambda.Invoke]
def invoke_function ( self , function_name , function_params , get_log = False ) :
"""
Invokes a Lambda function.
:param function_name: The name of the function to invoke.
:param function_params: The parameters of the function as a dict. This dict
is serialized to JSON before it is sent to Lambda.
2022-04-12 12:01:44 -07:00
:param get_log: When true, the last 4 KB of the execution log are included in
2022-04-08 15:42:13 -07:00
the response.
:return: The response from the function invocation.
"""
try :
response = self . lambda_client . invoke (
FunctionName = function_name ,
Payload = json . dumps ( function_params ) ,
2023-10-18 10:35:05 -07:00
LogType = " Tail " if get_log else " None " ,
)
2022-04-08 15:42:13 -07:00
logger . info ( " Invoked function %s . " , function_name )
except ClientError :
logger . exception ( " Couldn ' t invoke function %s . " , function_name )
raise
return response
2023-10-18 10:35:05 -07:00
2022-04-08 15:42:13 -07:00
# snippet-end:[python.example_code.lambda.Invoke]
# snippet-start:[python.example_code.lambda.UpdateFunctionCode]
def update_function_code ( self , function_name , deployment_package ) :
"""
2022-04-12 12:01:44 -07:00
Updates the code for a Lambda function by submitting a .zip archive that contains
2022-04-08 15:42:13 -07:00
the code for the function.
:param function_name: The name of the function to update.
:param deployment_package: The function code to update, packaged as bytes in
2022-04-12 12:01:44 -07:00
.zip format.
2022-04-08 15:42:13 -07:00
:return: Data about the update, including the status.
"""
try :
response = self . lambda_client . update_function_code (
2023-10-18 10:35:05 -07:00
FunctionName = function_name , ZipFile = deployment_package
)
2022-04-08 15:42:13 -07:00
except ClientError as err :
logger . error (
2023-10-18 10:35:05 -07:00
" Couldn ' t update function %s . Here ' s why: %s : %s " ,
function_name ,
err . response [ " Error " ] [ " Code " ] ,
err . response [ " Error " ] [ " Message " ] ,
)
2022-04-08 15:42:13 -07:00
raise
else :
return response
2023-10-18 10:35:05 -07:00
2022-04-08 15:42:13 -07:00
# snippet-end:[python.example_code.lambda.UpdateFunctionCode]
# snippet-start:[python.example_code.lambda.UpdateFunctionConfiguration]
def update_function_configuration ( self , function_name , env_vars ) :
"""
Updates the environment variables for a Lambda function.
:param function_name: The name of the function to update.
:param env_vars: A dict of environment variables to update.
:return: Data about the update, including the status.
"""
try :
response = self . lambda_client . update_function_configuration (
2023-10-18 10:35:05 -07:00
FunctionName = function_name , Environment = { " Variables " : env_vars }
)
2022-04-08 15:42:13 -07:00
except ClientError as err :
logger . error (
2023-10-18 10:35:05 -07:00
" Couldn ' t update function configuration %s . Here ' s why: %s : %s " ,
function_name ,
err . response [ " Error " ] [ " Code " ] ,
err . response [ " Error " ] [ " Message " ] ,
)
2022-04-08 15:42:13 -07:00
raise
else :
return response
2023-10-18 10:35:05 -07:00
2022-04-08 15:42:13 -07:00
# snippet-end:[python.example_code.lambda.UpdateFunctionConfiguration]
# snippet-start:[python.example_code.lambda.ListFunctions]
def list_functions ( self ) :
"""
Lists the Lambda functions for the current account.
"""
try :
2023-10-18 10:35:05 -07:00
func_paginator = self . lambda_client . get_paginator ( " list_functions " )
2022-04-08 15:42:13 -07:00
for func_page in func_paginator . paginate ( ) :
2023-10-18 10:35:05 -07:00
for func in func_page [ " Functions " ] :
print ( func [ " FunctionName " ] )
desc = func . get ( " Description " )
2022-04-08 15:42:13 -07:00
if desc :
print ( f " \t { desc } " )
print ( f " \t { func [ ' Runtime ' ] } : { func [ ' Handler ' ] } " )
except ClientError as err :
logger . error (
" Couldn ' t list functions. Here ' s why: %s : %s " ,
2023-10-18 10:35:05 -07:00
err . response [ " Error " ] [ " Code " ] ,
err . response [ " Error " ] [ " Message " ] ,
)
2022-04-08 15:42:13 -07:00
raise
2023-10-18 10:35:05 -07:00
2022-04-08 15:42:13 -07:00
# snippet-end:[python.example_code.lambda.ListFunctions]
2023-10-18 10:35:05 -07:00
2022-04-08 15:42:13 -07:00
# snippet-end:[python.example_code.python.LambdaWrapper.full]