View a markdown version of this page

Lambda examples using AWS CLI with Bash script - AWS Command Line Interface

Lambda examples using AWS CLI with Bash script

The following code examples show you how to perform actions and implement common scenarios by using the AWS Command Line Interface with Bash script with Lambda.

Scenarios are code examples that show you how to accomplish specific tasks by calling multiple functions within a service or combined with other AWS services.

Each example includes a link to the complete source code, where you can find instructions on how to set up and run the code in context.

Topics

Scenarios

The following code example shows how to:

  • Create an IAM role for Lambda execution

  • Create and deploy a Lambda function

  • Create a REST API

  • Configure Lambda proxy integration

  • Deploy and test the API

  • Clean up resources

AWS CLI with Bash script
Note

There's more on GitHub. Find the complete example and learn how to set up and run in the Sample developer tutorials repository.

#!/bin/bash # Simple API Gateway Lambda Integration Script # This script creates a REST API with Lambda proxy integration # Generate random identifiers FUNCTION_NAME="GetStartedLambdaProxyIntegration-$(openssl rand -hex 4)" ROLE_NAME="GetStartedLambdaBasicExecutionRole-$(openssl rand -hex 4)" API_NAME="LambdaProxyAPI-$(openssl rand -hex 4)" # Get AWS account info ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) REGION=$(aws configure get region || echo "us-east-1") echo "Creating Lambda function code..." # Create Lambda function code cat > lambda_function.py << 'EOF' import json def lambda_handler(event, context): print(event) greeter = 'World' try: if (event['queryStringParameters']) and (event['queryStringParameters']['greeter']) and ( event['queryStringParameters']['greeter'] is not None): greeter = event['queryStringParameters']['greeter'] except KeyError: print('No greeter') try: if (event['multiValueHeaders']) and (event['multiValueHeaders']['greeter']) and ( event['multiValueHeaders']['greeter'] is not None): greeter = " and ".join(event['multiValueHeaders']['greeter']) except KeyError: print('No greeter') try: if (event['headers']) and (event['headers']['greeter']) and ( event['headers']['greeter'] is not None): greeter = event['headers']['greeter'] except KeyError: print('No greeter') if (event['body']) and (event['body'] is not None): body = json.loads(event['body']) try: if (body['greeter']) and (body['greeter'] is not None): greeter = body['greeter'] except KeyError: print('No greeter') res = { "statusCode": 200, "headers": { "Content-Type": "*/*" }, "body": "Hello, " + greeter + "!" } return res EOF # Create deployment package zip function.zip lambda_function.py echo "Creating IAM role..." # Create IAM trust policy cat > trust-policy.json << 'EOF' { "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF # Create IAM role aws iam create-role \ --role-name "$ROLE_NAME" \ --assume-role-policy-document file://trust-policy.json # Attach execution policy aws iam attach-role-policy \ --role-name "$ROLE_NAME" \ --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" # Wait for role propagation sleep 15 echo "Creating Lambda function..." # Create Lambda function aws lambda create-function \ --function-name "$FUNCTION_NAME" \ --runtime python3.9 \ --role "arn:aws:iam::$ACCOUNT_ID:role/$ROLE_NAME" \ --handler lambda_function.lambda_handler \ --zip-file fileb://function.zip echo "Creating API Gateway..." # Create REST API aws apigateway create-rest-api \ --name "$API_NAME" \ --endpoint-configuration types=REGIONAL # Get API ID API_ID=$(aws apigateway get-rest-apis --query "items[?name=='$API_NAME'].id" --output text) # Get root resource ID ROOT_RESOURCE_ID=$(aws apigateway get-resources --rest-api-id "$API_ID" --query 'items[?path==`/`].id' --output text) # Create helloworld resource aws apigateway create-resource \ --rest-api-id "$API_ID" \ --parent-id "$ROOT_RESOURCE_ID" \ --path-part helloworld # Get resource ID RESOURCE_ID=$(aws apigateway get-resources --rest-api-id "$API_ID" --query "items[?pathPart=='helloworld'].id" --output text) # Create ANY method aws apigateway put-method \ --rest-api-id "$API_ID" \ --resource-id "$RESOURCE_ID" \ --http-method ANY \ --authorization-type NONE # Set up Lambda proxy integration LAMBDA_URI="arn:aws:apigateway:$REGION:lambda:path/2015-03-31/functions/arn:aws:lambda:$REGION:$ACCOUNT_ID:function:$FUNCTION_NAME/invocations" aws apigateway put-integration \ --rest-api-id "$API_ID" \ --resource-id "$RESOURCE_ID" \ --http-method ANY \ --type AWS_PROXY \ --integration-http-method POST \ --uri "$LAMBDA_URI" # Grant API Gateway permission to invoke Lambda SOURCE_ARN="arn:aws:execute-api:$REGION:$ACCOUNT_ID:$API_ID/*/*" aws lambda add-permission \ --function-name "$FUNCTION_NAME" \ --statement-id "apigateway-invoke-$(openssl rand -hex 4)" \ --action lambda:InvokeFunction \ --principal apigateway.amazonaws.com \ --source-arn "$SOURCE_ARN" # Deploy API aws apigateway create-deployment \ --rest-api-id "$API_ID" \ --stage-name test echo "Testing API..." # Test the API INVOKE_URL="https://$API_ID.execute-api.$REGION.amazonaws.com/test/helloworld" echo "API URL: $INVOKE_URL" # Test with query parameter echo "Testing with query parameter:" curl -X GET "$INVOKE_URL?greeter=John" echo "" # Test with header echo "Testing with header:" curl -X GET "$INVOKE_URL" \ -H 'content-type: application/json' \ -H 'greeter: John' echo "" # Test with body echo "Testing with POST body:" curl -X POST "$INVOKE_URL" \ -H 'content-type: application/json' \ -d '{ "greeter": "John" }' echo "" echo "Tutorial completed! API is available at: $INVOKE_URL" # Cleanup echo "Cleaning up resources..." # Delete API aws apigateway delete-rest-api --rest-api-id "$API_ID" # Delete Lambda function aws lambda delete-function --function-name "$FUNCTION_NAME" # Detach policy and delete role aws iam detach-role-policy \ --role-name "$ROLE_NAME" \ --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" aws iam delete-role --role-name "$ROLE_NAME" # Clean up local files rm -f lambda_function.py function.zip trust-policy.json echo "Cleanup completed!"

The following code example shows how to:

  • Create a CloudWatch dashboard

  • Add Lambda metrics widgets with a function name variable

  • Verify the dashboard

  • Clean up resources

AWS CLI with Bash script
Note

There's more on GitHub. Find the complete example and learn how to set up and run in the Sample developer tutorials repository.

#!/bin/bash # Script to create a CloudWatch dashboard with Lambda function name as a variable # This script creates a CloudWatch dashboard that allows you to switch between different Lambda functions # Set up logging LOG_FILE="cloudwatch-dashboard-script.log" exec > >(tee -a "$LOG_FILE") 2>&1 echo "$(date): Starting CloudWatch dashboard creation script" # Function to handle errors handle_error() { echo "ERROR: $1" echo "Resources created:" echo "- CloudWatch Dashboard: LambdaMetricsDashboard" echo "" echo "===========================================" echo "CLEANUP CONFIRMATION" echo "===========================================" echo "An error occurred. Do you want to clean up the created resources? (y/n): " read -r CLEANUP_CHOICE if [[ "${CLEANUP_CHOICE,,}" == "y" ]]; then echo "Cleaning up resources..." aws cloudwatch delete-dashboards --dashboard-names LambdaMetricsDashboard echo "Cleanup complete." else echo "Resources were not cleaned up. You can manually delete them later." fi exit 1 } # Check if AWS CLI is installed and configured echo "Checking AWS CLI configuration..." aws sts get-caller-identity > /dev/null 2>&1 if [ $? -ne 0 ]; then handle_error "AWS CLI is not properly configured. Please configure it with 'aws configure' and try again." fi # Get the current region REGION=$(aws configure get region) if [ -z "$REGION" ]; then REGION="us-east-1" echo "No region found in AWS config, defaulting to $REGION" fi echo "Using region: $REGION" # Check if there are any Lambda functions in the account echo "Checking for Lambda functions..." LAMBDA_FUNCTIONS=$(aws lambda list-functions --query "Functions[*].FunctionName" --output text) if [ -z "$LAMBDA_FUNCTIONS" ]; then echo "No Lambda functions found in your account. Creating a simple test function..." # Create a temporary directory for Lambda function code TEMP_DIR=$(mktemp -d) # Create a simple Lambda function cat > "$TEMP_DIR/index.js" << EOF exports.handler = async (event) => { console.log('Event:', JSON.stringify(event, null, 2)); return { statusCode: 200, body: JSON.stringify('Hello from Lambda!'), }; }; EOF # Zip the function code cd "$TEMP_DIR" || handle_error "Failed to change to temporary directory" zip -q function.zip index.js # Create a role for the Lambda function ROLE_NAME="LambdaDashboardTestRole" ROLE_ARN=$(aws iam create-role \ --role-name "$ROLE_NAME" \ --assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"},"Action":"sts:AssumeRole"}]}' \ --query "Role.Arn" \ --output text) if [ $? -ne 0 ]; then handle_error "Failed to create IAM role for Lambda function" fi echo "Waiting for role to be available..." sleep 10 # Attach basic Lambda execution policy aws iam attach-role-policy \ --role-name "$ROLE_NAME" \ --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" if [ $? -ne 0 ]; then aws iam delete-role --role-name "$ROLE_NAME" handle_error "Failed to attach policy to IAM role" fi # Create the Lambda function FUNCTION_NAME="DashboardTestFunction" aws lambda create-function \ --function-name "$FUNCTION_NAME" \ --runtime nodejs18.x \ --role "$ROLE_ARN" \ --handler index.handler \ --zip-file fileb://function.zip if [ $? -ne 0 ]; then aws iam detach-role-policy \ --role-name "$ROLE_NAME" \ --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" aws iam delete-role --role-name "$ROLE_NAME" handle_error "Failed to create Lambda function" fi # Invoke the function to generate some metrics echo "Invoking Lambda function to generate metrics..." for i in {1..5}; do aws lambda invoke --function-name "$FUNCTION_NAME" --payload '{}' /dev/null > /dev/null sleep 1 done # Clean up temporary directory cd - > /dev/null rm -rf "$TEMP_DIR" # Set the function name for the dashboard DEFAULT_FUNCTION="$FUNCTION_NAME" else # Use the first Lambda function as default DEFAULT_FUNCTION=$(echo "$LAMBDA_FUNCTIONS" | awk '{print $1}') echo "Found Lambda functions. Using $DEFAULT_FUNCTION as default." fi # Create a dashboard with Lambda metrics and a function name variable echo "Creating CloudWatch dashboard with Lambda function name variable..." # Create a JSON file for the dashboard body cat > dashboard-body.json << EOF { "widgets": [ { "type": "metric", "x": 0, "y": 0, "width": 12, "height": 6, "properties": { "metrics": [ [ "AWS/Lambda", "Invocations", "FunctionName", "\${FunctionName}" ], [ ".", "Errors", ".", "." ], [ ".", "Throttles", ".", "." ] ], "view": "timeSeries", "stacked": false, "region": "$REGION", "title": "Lambda Function Metrics for \${FunctionName}", "period": 300 } }, { "type": "metric", "x": 0, "y": 6, "width": 12, "height": 6, "properties": { "metrics": [ [ "AWS/Lambda", "Duration", "FunctionName", "\${FunctionName}", { "stat": "Average" } ] ], "view": "timeSeries", "stacked": false, "region": "$REGION", "title": "Duration for \${FunctionName}", "period": 300 } }, { "type": "metric", "x": 12, "y": 0, "width": 12, "height": 6, "properties": { "metrics": [ [ "AWS/Lambda", "ConcurrentExecutions", "FunctionName", "\${FunctionName}" ] ], "view": "timeSeries", "stacked": false, "region": "$REGION", "title": "Concurrent Executions for \${FunctionName}", "period": 300 } } ], "periodOverride": "auto", "variables": [ { "type": "property", "id": "FunctionName", "property": "FunctionName", "label": "Lambda Function", "inputType": "select", "values": [ { "value": "$DEFAULT_FUNCTION", "label": "$DEFAULT_FUNCTION" } ] } ] } EOF # Create the dashboard using the JSON file DASHBOARD_RESULT=$(aws cloudwatch put-dashboard --dashboard-name LambdaMetricsDashboard --dashboard-body file://dashboard-body.json) DASHBOARD_EXIT_CODE=$? # Check if there was a fatal error if [ $DASHBOARD_EXIT_CODE -ne 0 ]; then # If we created resources, clean them up if [ -n "${FUNCTION_NAME:-}" ]; then aws lambda delete-function --function-name "$FUNCTION_NAME" aws iam detach-role-policy \ --role-name "$ROLE_NAME" \ --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" aws iam delete-role --role-name "$ROLE_NAME" fi handle_error "Failed to create CloudWatch dashboard." fi # Display any validation messages but continue if [[ "$DASHBOARD_RESULT" == *"DashboardValidationMessages"* ]]; then echo "Dashboard created with validation messages:" echo "$DASHBOARD_RESULT" echo "These validation messages are warnings and the dashboard should still function." else echo "Dashboard created successfully!" fi # Verify the dashboard was created echo "Verifying dashboard creation..." DASHBOARD_INFO=$(aws cloudwatch get-dashboard --dashboard-name LambdaMetricsDashboard) DASHBOARD_INFO_EXIT_CODE=$? if [ $DASHBOARD_INFO_EXIT_CODE -ne 0 ]; then # If we created resources, clean them up if [ -n "${FUNCTION_NAME:-}" ]; then aws lambda delete-function --function-name "$FUNCTION_NAME" aws iam detach-role-policy \ --role-name "$ROLE_NAME" \ --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" aws iam delete-role --role-name "$ROLE_NAME" fi handle_error "Failed to verify dashboard creation." fi echo "Dashboard verification successful!" echo "Dashboard details:" echo "$DASHBOARD_INFO" # List all dashboards to confirm echo "Listing all dashboards:" DASHBOARDS=$(aws cloudwatch list-dashboards) DASHBOARDS_EXIT_CODE=$? if [ $DASHBOARDS_EXIT_CODE -ne 0 ]; then # If we created resources, clean them up if [ -n "${FUNCTION_NAME:-}" ]; then aws lambda delete-function --function-name "$FUNCTION_NAME" aws iam detach-role-policy \ --role-name "$ROLE_NAME" \ --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" aws iam delete-role --role-name "$ROLE_NAME" fi handle_error "Failed to list dashboards." fi echo "$DASHBOARDS" # Show instructions for accessing the dashboard echo "" echo "Dashboard created successfully! To access it:" echo "1. Open the CloudWatch console at https://console.aws.amazon.com/cloudwatch/" echo "2. In the navigation pane, choose Dashboards" echo "3. Select LambdaMetricsDashboard" echo "4. You should see a dropdown menu labeled 'Lambda Function' at the top of the dashboard" echo "5. Use this dropdown to select different Lambda functions and see their metrics" echo "" # Create a list of resources for cleanup RESOURCES=("- CloudWatch Dashboard: LambdaMetricsDashboard") if [ -n "${FUNCTION_NAME:-}" ]; then RESOURCES+=("- Lambda Function: $FUNCTION_NAME") RESOURCES+=("- IAM Role: $ROLE_NAME") fi # Prompt for cleanup echo "===========================================" echo "CLEANUP CONFIRMATION" echo "===========================================" echo "Resources created:" for resource in "${RESOURCES[@]}"; do echo "$resource" done echo "" echo "Do you want to clean up all created resources? (y/n): " read -r CLEANUP_CHOICE if [[ "${CLEANUP_CHOICE,,}" == "y" ]]; then echo "Cleaning up resources..." # Delete the dashboard aws cloudwatch delete-dashboards --dashboard-names LambdaMetricsDashboard if [ $? -ne 0 ]; then echo "WARNING: Failed to delete dashboard. You may need to delete it manually." else echo "Dashboard deleted successfully." fi # If we created a Lambda function, delete it and its role if [ -n "${FUNCTION_NAME:-}" ]; then echo "Deleting Lambda function..." aws lambda delete-function --function-name "$FUNCTION_NAME" if [ $? -ne 0 ]; then echo "WARNING: Failed to delete Lambda function. You may need to delete it manually." else echo "Lambda function deleted successfully." fi echo "Detaching role policy..." aws iam detach-role-policy \ --role-name "$ROLE_NAME" \ --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" if [ $? -ne 0 ]; then echo "WARNING: Failed to detach role policy. You may need to detach it manually." else echo "Role policy detached successfully." fi echo "Deleting IAM role..." aws iam delete-role --role-name "$ROLE_NAME" if [ $? -ne 0 ]; then echo "WARNING: Failed to delete IAM role. You may need to delete it manually." else echo "IAM role deleted successfully." fi fi # Clean up the JSON file rm -f dashboard-body.json echo "Cleanup complete." else echo "Resources were not cleaned up. You can manually delete them later with:" echo "aws cloudwatch delete-dashboards --dashboard-names LambdaMetricsDashboard" if [ -n "${FUNCTION_NAME:-}" ]; then echo "aws lambda delete-function --function-name $FUNCTION_NAME" echo "aws iam detach-role-policy --role-name $ROLE_NAME --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" echo "aws iam delete-role --role-name $ROLE_NAME" fi fi echo "Script completed successfully!"

The following code example shows how to:

  • Create an IAM role for Lambda

  • Create function code

  • Create a Lambda function

  • Test your Lambda function

  • Clean up resources

AWS CLI with Bash script
Note

There's more on GitHub. Find the complete example and learn how to set up and run in the Sample developer tutorials repository.

#!/bin/bash # AWS Lambda - Create Your First Function # This script creates a Lambda function, invokes it with a test event, # views CloudWatch logs, and cleans up all resources. # # Source: https://docs.aws.amazon.com/lambda/latest/dg/getting-started.html # # Resources created: # - IAM role (Lambda execution role with basic logging permissions) # - Lambda function (Python 3.13 or Node.js 22.x runtime) # - CloudWatch log group (created automatically by Lambda on invocation) set -eE ############################################################################### # Setup ############################################################################### UNIQUE_ID=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 8 | head -n 1) FUNCTION_NAME="my-lambda-function-${UNIQUE_ID}" ROLE_NAME="lambda-execution-role-${UNIQUE_ID}" LOG_GROUP_NAME="/aws/lambda/${FUNCTION_NAME}" TEMP_DIR=$(mktemp -d) LOG_FILE="${TEMP_DIR}/lambda-gettingstarted.log" exec > >(tee -a "$LOG_FILE") 2>&1 declare -a CREATED_RESOURCES ############################################################################### # Helper functions ############################################################################### cleanup_resources() { # Disable error trap to prevent recursion during cleanup trap - ERR set +eE echo "" echo "Cleaning up resources..." echo "" for ((i=${#CREATED_RESOURCES[@]}-1; i>=0; i--)); do local RESOURCE="${CREATED_RESOURCES[$i]}" local TYPE="${RESOURCE%%:*}" local NAME="${RESOURCE#*:}" case "$TYPE" in log-group) echo "Deleting CloudWatch log group: ${NAME}" aws logs delete-log-group \ --log-group-name "$NAME" 2>&1 || echo " WARNING: Could not delete log group ${NAME}." ;; lambda-function) echo "Deleting Lambda function: ${NAME}" aws lambda delete-function \ --function-name "$NAME" 2>&1 || echo " WARNING: Could not delete Lambda function ${NAME}." echo " Waiting for function deletion to complete..." local DELETE_WAIT=0 while aws lambda get-function --function-name "$NAME" > /dev/null 2>&1; do sleep 2 DELETE_WAIT=$((DELETE_WAIT + 2)) if [ "$DELETE_WAIT" -ge 60 ]; then echo " WARNING: Timed out waiting for function deletion." break fi done ;; iam-role-policy) local ROLE_PART="${NAME%%|*}" local POLICY_PART="${NAME#*|}" echo "Detaching policy from role: ${ROLE_PART}" aws iam detach-role-policy \ --role-name "$ROLE_PART" \ --policy-arn "$POLICY_PART" 2>&1 || echo " WARNING: Could not detach policy from role ${ROLE_PART}." ;; iam-role) echo "Deleting IAM role: ${NAME}" aws iam delete-role \ --role-name "$NAME" 2>&1 || echo " WARNING: Could not delete IAM role ${NAME}." ;; esac done if [ -d "$TEMP_DIR" ]; then rm -rf "$TEMP_DIR" fi echo "" echo "Cleanup complete." } handle_error() { echo "" echo "===========================================" echo "ERROR: Script failed at $1" echo "===========================================" echo "" if [ ${#CREATED_RESOURCES[@]} -gt 0 ]; then echo "Attempting to clean up ${#CREATED_RESOURCES[@]} resource(s)..." cleanup_resources fi exit 1 } trap 'handle_error "line $LINENO"' ERR wait_for_resource() { local DESCRIPTION="$1" local COMMAND="$2" local TARGET_VALUE="$3" local TIMEOUT=300 local ELAPSED=0 local INTERVAL=5 echo "Waiting for ${DESCRIPTION}..." while true; do local RESULT RESULT=$(eval "$COMMAND" 2>&1) || true if echo "$RESULT" | grep -q "$TARGET_VALUE"; then echo " ${DESCRIPTION} is ready." return 0 fi if [ "$ELAPSED" -ge "$TIMEOUT" ]; then echo "ERROR: Timed out waiting for ${DESCRIPTION} after ${TIMEOUT} seconds." return 1 fi sleep "$INTERVAL" ELAPSED=$((ELAPSED + INTERVAL)) done } ############################################################################### # Region pre-check ############################################################################### CONFIGURED_REGION=$(aws configure get region 2>/dev/null || true) if [ -z "$CONFIGURED_REGION" ] && [ -z "$AWS_DEFAULT_REGION" ] && [ -z "$AWS_REGION" ]; then echo "ERROR: No AWS region configured." echo "Run 'aws configure set region <region>' or export AWS_DEFAULT_REGION." exit 1 fi ############################################################################### # Runtime selection ############################################################################### echo "" echo "===========================================" echo "AWS Lambda - Create Your First Function" echo "===========================================" echo "" echo "Select a runtime for your Lambda function:" echo " 1) Python 3.13" echo " 2) Node.js 22.x" echo "" echo "Enter your choice (1 or 2): " read -r RUNTIME_CHOICE case "$RUNTIME_CHOICE" in 1) RUNTIME="python3.13" HANDLER="lambda_function.lambda_handler" CODE_FILE="lambda_function.py" cat > "${TEMP_DIR}/${CODE_FILE}" << 'PYTHON_EOF' import json import logging logger = logging.getLogger() logger.setLevel(logging.INFO) def lambda_handler(event, context): length = event['length'] width = event['width'] area = calculate_area(length, width) print(f'The area is {area}') logger.info(f'CloudWatch logs group: {context.log_group_name}') return json.dumps({'area': area}) def calculate_area(length, width): return length * width PYTHON_EOF echo "Selected runtime: Python 3.13" ;; 2) RUNTIME="nodejs22.x" HANDLER="index.handler" CODE_FILE="index.mjs" cat > "${TEMP_DIR}/${CODE_FILE}" << 'NODEJS_EOF' export const handler = async (event, context) => { const area = event.length * event.width; console.log(`The area is ${area}`); console.log('CloudWatch log group: ', context.logGroupName); return JSON.stringify({area}); }; NODEJS_EOF echo "Selected runtime: Node.js 22.x" ;; *) echo "ERROR: Invalid choice. Please enter 1 or 2." exit 1 ;; esac ############################################################################### # Step 1: Create IAM execution role ############################################################################### echo "" echo "===========================================" echo "Step 1: Create IAM execution role" echo "===========================================" echo "" TRUST_POLICY='{ "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }' echo "Creating IAM role: ${ROLE_NAME}" ROLE_OUTPUT=$(aws iam create-role \ --role-name "$ROLE_NAME" \ --assume-role-policy-document "$TRUST_POLICY" \ --query 'Role.Arn' \ --output text 2>&1) echo "$ROLE_OUTPUT" ROLE_ARN="$ROLE_OUTPUT" CREATED_RESOURCES+=("iam-role:${ROLE_NAME}") echo "Role ARN: ${ROLE_ARN}" echo "" echo "Attaching AWSLambdaBasicExecutionRole policy..." aws iam attach-role-policy \ --role-name "$ROLE_NAME" \ --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" 2>&1 CREATED_RESOURCES+=("iam-role-policy:${ROLE_NAME}|arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole") echo "Policy attached." # IAM roles can take a few seconds to propagate echo "Waiting for IAM role to propagate..." sleep 10 ############################################################################### # Step 2: Create Lambda function ############################################################################### echo "" echo "===========================================" echo "Step 2: Create Lambda function" echo "===========================================" echo "" echo "Creating deployment package..." ORIGINAL_DIR=$(pwd) cd "$TEMP_DIR" zip -j function.zip "$CODE_FILE" > /dev/null 2>&1 cd "$ORIGINAL_DIR" echo "Creating Lambda function: ${FUNCTION_NAME}" echo " Runtime: ${RUNTIME}" echo " Handler: ${HANDLER}" echo "" CREATE_OUTPUT=$(aws lambda create-function \ --function-name "$FUNCTION_NAME" \ --runtime "$RUNTIME" \ --role "$ROLE_ARN" \ --handler "$HANDLER" \ --architectures x86_64 \ --zip-file "fileb://${TEMP_DIR}/function.zip" \ --query '[FunctionName, FunctionArn, Runtime, State]' \ --output text 2>&1) echo "$CREATE_OUTPUT" CREATED_RESOURCES+=("lambda-function:${FUNCTION_NAME}") wait_for_resource "Lambda function to become Active" \ "aws lambda get-function-configuration --function-name ${FUNCTION_NAME} --query State --output text" \ "Active" ############################################################################### # Step 3: Invoke the function ############################################################################### echo "" echo "===========================================" echo "Step 3: Invoke the function" echo "===========================================" echo "" TEST_EVENT='{"length": 6, "width": 7}' echo "Invoking function with test event: ${TEST_EVENT}" echo "" echo "$TEST_EVENT" > "${TEMP_DIR}/test-event.json" INVOKE_OUTPUT=$(aws lambda invoke \ --function-name "$FUNCTION_NAME" \ --payload "fileb://${TEMP_DIR}/test-event.json" \ --cli-read-timeout 30 \ "${TEMP_DIR}/response.json" 2>&1) echo "$INVOKE_OUTPUT" RESPONSE=$(cat "${TEMP_DIR}/response.json") echo "" echo "Function response: ${RESPONSE}" echo "" if echo "$INVOKE_OUTPUT" | grep -qi "functionerror"; then echo "WARNING: Function returned an error." fi ############################################################################### # Step 4: View CloudWatch logs ############################################################################### echo "" echo "===========================================" echo "Step 4: View CloudWatch Logs" echo "===========================================" echo "" echo "Log group: ${LOG_GROUP_NAME}" echo "" echo "Waiting for CloudWatch logs to be available..." LOG_STREAMS="" for i in $(seq 1 6); do LOG_STREAMS=$(aws logs describe-log-streams \ --log-group-name "$LOG_GROUP_NAME" \ --order-by LastEventTime \ --descending \ --query 'logStreams[0].logStreamName' \ --output text 2>/dev/null) || true if [ -n "$LOG_STREAMS" ] && [ "$LOG_STREAMS" != "None" ]; then break fi LOG_STREAMS="" sleep 5 done if [ -n "$LOG_STREAMS" ] && [ "$LOG_STREAMS" != "None" ]; then echo "Latest log stream: ${LOG_STREAMS}" echo "" echo "--- Log events ---" LOG_EVENTS=$(aws logs get-log-events \ --log-group-name "$LOG_GROUP_NAME" \ --log-stream-name "$LOG_STREAMS" \ --query 'events[].message' \ --output text 2>&1) || true echo "$LOG_EVENTS" echo "--- End of log events ---" else echo "No log streams found yet. Logs may take a moment to appear." echo "You can view them in the CloudWatch console:" echo " Log group: ${LOG_GROUP_NAME}" fi CREATED_RESOURCES+=("log-group:${LOG_GROUP_NAME}") ############################################################################### # Summary and cleanup ############################################################################### echo "" echo "===========================================" echo "SUMMARY" echo "===========================================" echo "" echo "Resources created:" echo " IAM role: ${ROLE_NAME}" echo " Lambda function: ${FUNCTION_NAME}" echo " CloudWatch logs: ${LOG_GROUP_NAME}" echo "" echo "===========================================" echo "CLEANUP CONFIRMATION" echo "===========================================" echo "" echo "Do you want to clean up all created resources? (y/n): " read -r CLEANUP_CHOICE if [[ "$CLEANUP_CHOICE" =~ ^[Yy]$ ]]; then cleanup_resources else echo "" echo "Resources were NOT deleted. To clean up manually, run:" echo "" echo " # Delete the Lambda function" echo " aws lambda delete-function --function-name ${FUNCTION_NAME}" echo "" echo " # Delete the CloudWatch log group" echo " aws logs delete-log-group --log-group-name ${LOG_GROUP_NAME}" echo "" echo " # Detach the policy and delete the IAM role" echo " aws iam detach-role-policy --role-name ${ROLE_NAME} --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" echo " aws iam delete-role --role-name ${ROLE_NAME}" echo "" if [ -d "$TEMP_DIR" ]; then rm -rf "$TEMP_DIR" fi fi echo "" echo "Done."

The following code example shows how to:

  • Create Lambda functions for monitoring

  • Create a CloudWatch dashboard

  • Add a property variable to the dashboard

  • Clean up resources

AWS CLI with Bash script
Note

There's more on GitHub. Find the complete example and learn how to set up and run in the Sample developer tutorials repository.

#!/bin/bash # CloudWatch Dashboard with Lambda Function Variable Script # This script creates a CloudWatch dashboard with a property variable for Lambda function names # Set up logging LOG_FILE="cloudwatch-dashboard-script-v4.log" echo "Starting script execution at $(date)" > "$LOG_FILE" # Function to log commands and their output log_cmd() { echo "$(date): Running command: $1" >> "$LOG_FILE" eval "$1" 2>&1 | tee -a "$LOG_FILE" return ${PIPESTATUS[0]} } # Function to check for errors in command output check_error() { local cmd_output="$1" local cmd_status="$2" local error_msg="$3" if [ $cmd_status -ne 0 ] || echo "$cmd_output" | grep -i "error" > /dev/null; then echo "ERROR: $error_msg" | tee -a "$LOG_FILE" echo "Command output: $cmd_output" | tee -a "$LOG_FILE" cleanup_resources exit 1 fi } # Function to clean up resources cleanup_resources() { echo "" | tee -a "$LOG_FILE" echo "==========================================" | tee -a "$LOG_FILE" echo "CLEANUP PROCESS" | tee -a "$LOG_FILE" echo "==========================================" | tee -a "$LOG_FILE" if [ -n "$DASHBOARD_NAME" ]; then echo "Deleting CloudWatch dashboard: $DASHBOARD_NAME" | tee -a "$LOG_FILE" log_cmd "aws cloudwatch delete-dashboards --dashboard-names \"$DASHBOARD_NAME\"" fi if [ -n "$LAMBDA_FUNCTION1" ]; then echo "Deleting Lambda function: $LAMBDA_FUNCTION1" | tee -a "$LOG_FILE" log_cmd "aws lambda delete-function --function-name \"$LAMBDA_FUNCTION1\"" fi if [ -n "$LAMBDA_FUNCTION2" ]; then echo "Deleting Lambda function: $LAMBDA_FUNCTION2" | tee -a "$LOG_FILE" log_cmd "aws lambda delete-function --function-name \"$LAMBDA_FUNCTION2\"" fi if [ -n "$ROLE_NAME" ]; then echo "Detaching policy from role: $ROLE_NAME" | tee -a "$LOG_FILE" log_cmd "aws iam detach-role-policy --role-name \"$ROLE_NAME\" --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" echo "Deleting IAM role: $ROLE_NAME" | tee -a "$LOG_FILE" log_cmd "aws iam delete-role --role-name \"$ROLE_NAME\"" fi echo "Cleanup completed." | tee -a "$LOG_FILE" } # Function to prompt for cleanup confirmation confirm_cleanup() { echo "" | tee -a "$LOG_FILE" echo "==========================================" | tee -a "$LOG_FILE" echo "CLEANUP CONFIRMATION" | tee -a "$LOG_FILE" echo "==========================================" | tee -a "$LOG_FILE" echo "The following resources were created:" | tee -a "$LOG_FILE" echo "- CloudWatch Dashboard: $DASHBOARD_NAME" | tee -a "$LOG_FILE" if [ -n "$LAMBDA_FUNCTION1" ]; then echo "- Lambda Function: $LAMBDA_FUNCTION1" | tee -a "$LOG_FILE" fi if [ -n "$LAMBDA_FUNCTION2" ]; then echo "- Lambda Function: $LAMBDA_FUNCTION2" | tee -a "$LOG_FILE" fi if [ -n "$ROLE_NAME" ]; then echo "- IAM Role: $ROLE_NAME" | tee -a "$LOG_FILE" fi echo "" | tee -a "$LOG_FILE" echo "Do you want to clean up all created resources? (y/n): " | tee -a "$LOG_FILE" read -r CLEANUP_CHOICE if [[ "$CLEANUP_CHOICE" =~ ^[Yy]$ ]]; then cleanup_resources else echo "Resources were not cleaned up. You can manually delete them later." | tee -a "$LOG_FILE" fi } # Get AWS region AWS_REGION=$(aws configure get region) if [ -z "$AWS_REGION" ]; then AWS_REGION="us-east-1" echo "No region found in AWS config, defaulting to $AWS_REGION" | tee -a "$LOG_FILE" else echo "Using AWS region: $AWS_REGION" | tee -a "$LOG_FILE" fi # Generate unique identifiers RANDOM_ID=$(openssl rand -hex 6) DASHBOARD_NAME="LambdaMetricsDashboard-${RANDOM_ID}" LAMBDA_FUNCTION1="TestFunction1-${RANDOM_ID}" LAMBDA_FUNCTION2="TestFunction2-${RANDOM_ID}" ROLE_NAME="LambdaExecutionRole-${RANDOM_ID}" echo "Using random identifier: $RANDOM_ID" | tee -a "$LOG_FILE" echo "Dashboard name: $DASHBOARD_NAME" | tee -a "$LOG_FILE" echo "Lambda function names: $LAMBDA_FUNCTION1, $LAMBDA_FUNCTION2" | tee -a "$LOG_FILE" echo "IAM role name: $ROLE_NAME" | tee -a "$LOG_FILE" # Create IAM role for Lambda functions echo "Creating IAM role for Lambda..." | tee -a "$LOG_FILE" TRUST_POLICY='{ "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }' echo "$TRUST_POLICY" > trust-policy.json ROLE_OUTPUT=$(log_cmd "aws iam create-role --role-name \"$ROLE_NAME\" --assume-role-policy-document file://trust-policy.json --output json") check_error "$ROLE_OUTPUT" $? "Failed to create IAM role" ROLE_ARN=$(echo "$ROLE_OUTPUT" | grep -o '"Arn": "[^"]*' | cut -d'"' -f4) echo "Role ARN: $ROLE_ARN" | tee -a "$LOG_FILE" # Attach Lambda basic execution policy to the role echo "Attaching Lambda execution policy to role..." | tee -a "$LOG_FILE" POLICY_OUTPUT=$(log_cmd "aws iam attach-role-policy --role-name \"$ROLE_NAME\" --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole") check_error "$POLICY_OUTPUT" $? "Failed to attach policy to role" # Wait for role to propagate echo "Waiting for IAM role to propagate..." | tee -a "$LOG_FILE" sleep 10 # Create simple Python Lambda function code echo "Creating Lambda function code..." | tee -a "$LOG_FILE" cat > lambda_function.py << 'EOF' def handler(event, context): print("Lambda function executed successfully") return { 'statusCode': 200, 'body': 'Success' } EOF # Zip the Lambda function code log_cmd "zip -j lambda_function.zip lambda_function.py" # Create first Lambda function echo "Creating first Lambda function: $LAMBDA_FUNCTION1..." | tee -a "$LOG_FILE" LAMBDA1_OUTPUT=$(log_cmd "aws lambda create-function --function-name \"$LAMBDA_FUNCTION1\" --runtime python3.9 --role \"$ROLE_ARN\" --handler lambda_function.handler --zip-file fileb://lambda_function.zip") check_error "$LAMBDA1_OUTPUT" $? "Failed to create first Lambda function" # Create second Lambda function echo "Creating second Lambda function: $LAMBDA_FUNCTION2..." | tee -a "$LOG_FILE" LAMBDA2_OUTPUT=$(log_cmd "aws lambda create-function --function-name \"$LAMBDA_FUNCTION2\" --runtime python3.9 --role \"$ROLE_ARN\" --handler lambda_function.handler --zip-file fileb://lambda_function.zip") check_error "$LAMBDA2_OUTPUT" $? "Failed to create second Lambda function" # Invoke Lambda functions to generate some metrics echo "Invoking Lambda functions to generate metrics..." | tee -a "$LOG_FILE" log_cmd "aws lambda invoke --function-name \"$LAMBDA_FUNCTION1\" --payload '{}' /dev/null" log_cmd "aws lambda invoke --function-name \"$LAMBDA_FUNCTION2\" --payload '{}' /dev/null" # Create CloudWatch dashboard with property variable echo "Creating CloudWatch dashboard with property variable..." | tee -a "$LOG_FILE" # Create a simpler dashboard with a property variable # This approach uses a more basic dashboard structure that's known to work with the CloudWatch API DASHBOARD_BODY=$(cat <<EOF { "widgets": [ { "type": "metric", "x": 0, "y": 0, "width": 12, "height": 6, "properties": { "metrics": [ [ "AWS/Lambda", "Invocations", "FunctionName", "$LAMBDA_FUNCTION1" ] ], "view": "timeSeries", "stacked": false, "region": "$AWS_REGION", "title": "Lambda Invocations", "period": 300, "stat": "Sum" } } ] } EOF ) # First create a basic dashboard without variables echo "Creating initial dashboard without variables..." | tee -a "$LOG_FILE" DASHBOARD_OUTPUT=$(log_cmd "aws cloudwatch put-dashboard --dashboard-name \"$DASHBOARD_NAME\" --dashboard-body '$DASHBOARD_BODY'") check_error "$DASHBOARD_OUTPUT" $? "Failed to create initial CloudWatch dashboard" # Now let's try to add a property variable using the console instructions echo "To complete the tutorial, please follow these steps in the CloudWatch console:" | tee -a "$LOG_FILE" echo "1. Open the CloudWatch console at https://console.aws.amazon.com/cloudwatch/" | tee -a "$LOG_FILE" echo "2. Navigate to Dashboards and select your dashboard: $DASHBOARD_NAME" | tee -a "$LOG_FILE" echo "3. Choose Actions > Variables > Create a variable" | tee -a "$LOG_FILE" echo "4. Choose Property variable" | tee -a "$LOG_FILE" echo "5. For Property that the variable changes, choose FunctionName" | tee -a "$LOG_FILE" echo "6. For Input type, choose Select menu (dropdown)" | tee -a "$LOG_FILE" echo "7. Choose Use the results of a metric search" | tee -a "$LOG_FILE" echo "8. Choose Pre-built queries > Lambda > Errors" | tee -a "$LOG_FILE" echo "9. Choose By Function Name and then choose Search" | tee -a "$LOG_FILE" echo "10. (Optional) Configure any secondary settings as desired" | tee -a "$LOG_FILE" echo "11. Choose Add variable" | tee -a "$LOG_FILE" echo "" | tee -a "$LOG_FILE" echo "The dashboard has been created and can be accessed at:" | tee -a "$LOG_FILE" echo "https://console.aws.amazon.com/cloudwatch/home#dashboards:name=$DASHBOARD_NAME" | tee -a "$LOG_FILE" # Verify dashboard creation echo "Verifying dashboard creation..." | tee -a "$LOG_FILE" VERIFY_OUTPUT=$(log_cmd "aws cloudwatch get-dashboard --dashboard-name \"$DASHBOARD_NAME\"") check_error "$VERIFY_OUTPUT" $? "Failed to verify dashboard creation" echo "" | tee -a "$LOG_FILE" echo "==========================================" | tee -a "$LOG_FILE" echo "DASHBOARD CREATED SUCCESSFULLY" | tee -a "$LOG_FILE" echo "==========================================" | tee -a "$LOG_FILE" echo "Dashboard Name: $DASHBOARD_NAME" | tee -a "$LOG_FILE" echo "Lambda Functions: $LAMBDA_FUNCTION1, $LAMBDA_FUNCTION2" | tee -a "$LOG_FILE" echo "" | tee -a "$LOG_FILE" echo "You can view your dashboard in the CloudWatch console:" | tee -a "$LOG_FILE" echo "https://console.aws.amazon.com/cloudwatch/home#dashboards:name=$DASHBOARD_NAME" | tee -a "$LOG_FILE" echo "" | tee -a "$LOG_FILE" # Prompt for cleanup confirm_cleanup echo "Script completed successfully." | tee -a "$LOG_FILE" exit 0