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
81 changes: 60 additions & 21 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,36 +1,75 @@
# This is a basic workflow to help you get started with Actions
name: quick-actions-aws-lambda-template-ci

name: CI

# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the "main" branch
push:
branches: [main]
pull_request:
branches: [main]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
code-quality:
name: Code Quality
runs-on: ubuntu-latest

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v3

# Runs a single command using the runners shell
- name: Run a one-line script
run: echo Hello, world!
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install Python dependencies
run: pip install ruff ruff-lsp

- name: Lint Python with Ruff
run: ruff check python/

- name: Check Python formatting with Ruff Format
run: ruff format python/ --check

- name: Set up Terraform
uses: hashicorp/setup-terraform@v3

- name: Check Terraform formatting
run: terraform fmt terraform/ -check

- name: Install yamllint and toml
run: pip install yamllint toml

# Runs a set of commands using the runners shell
- name: Run a multi-line script
- name: Lint TOML files
run: |
echo Add other actions to build,
echo test, and deploy your project.
for file in $(find . -name "*.toml"); do
python -c "import toml; toml.load(open('$file'))" || exit 1
done

- name: Lint YAML files
run: yamllint . -c=./config/.yamllint.yaml

- name: Format YAML files (check only)
run: echo "No standard YAML formatter in check mode; skipping."

- name: Format Markdown files (check only)
run: |
pip install mdformat
mdformat --check .

# terraform:
# name: Terraform
# runs-on: ubuntu-latest
# needs: code-quality
# steps:
# - uses: actions/checkout@v3

# - name: Set up Terraform
# uses: hashicorp/setup-terraform@v3

# - name: Terraform Init
# run: terraform -chdir=terraform/ init

# - name: Terraform Plan
# run: terraform -chdir=terraform/ plan

# - name: Terraform Apply
# if: github.ref == 'refs/heads/main'
# run: terraform -chdir=terraform/ apply -auto-approve
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
node_modules
/.nova
.DS_Store
package-lock.json
.venv
.pytest_cache
.ruff_cache
.vscode
# Ignore Python bytecode files
__pycache__/
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"python.testing.pytestArgs": [
"python"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}
157 changes: 157 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,158 @@
# quick-actions-aws-lambda-template

A template project for deploying AWS Lambda functions with best practices, infrastructure-as-code (Terraform), and automated code quality checks using GitHub Actions.

______________________________________________________________________

## Features

- **AWS Lambda Function**: Python 3.12 Lambda with event source mapping (SQS trigger).
- **Infrastructure as Code**: All AWS resources (Lambda, IAM, SQS, CloudWatch Logs) managed via Terraform.
- **CI/CD**: GitHub Actions pipeline for linting, formatting, and Terraform plan/apply.
- **Code Quality**: Python linting and formatting (ruff), TOML and YAML linting, Markdown formatting.
- **Best Practices**: Environment variables, tagging, log retention, and least-privilege IAM.

______________________________________________________________________

## Project Structure

```
.
├── python/
│ └── src/
│ └── base_lambda.py # Lambda function source code
├── terraform/
│ └── lambda.tf # Terraform for Lambda, IAM, SQS, etc.
├── .github/
│ └── workflows/
│ └── ci.yml # GitHub Actions pipeline
├── README.md
```

______________________________________________________________________

## Lambda Function

The Lambda function (`base_lambda.py`) provides utility actions via AWS APIs:

- Delete another Lambda function
- Redrive messages from an SQS DLQ
- Get ECR login and repository URI

The handler expects an event with a key indicating the action to perform.

______________________________________________________________________

## Infrastructure

Terraform provisions:

- **Lambda Function** (`example_lambda`)
- **IAM Role** for Lambda execution
- **CloudWatch Log Group** for Lambda logs
- **SQS Queue** as event source
- **Event Source Mapping** between SQS and Lambda

All resources are tagged for project and environment tracking.

______________________________________________________________________

## CI/CD Pipeline

GitHub Actions workflow (`ci.yml`) includes:

### Code Quality Stage

- Lint Python with Ruff
- Check Python formatting with Ruff Format
- Check Terraform formatting
- Lint TOML files
- Lint YAML files
- Check Markdown formatting

### Terraform Stage

- Terraform init, plan, and apply (on main branch)

______________________________________________________________________

## Getting Started

### Prerequisites

- [Python 3.12+](https://www.python.org/)
- [Terraform](https://www.terraform.io/)
- [AWS CLI](https://aws.amazon.com/cli/)
- Docker (for packaging Lambda, if needed)

### Setup

1. **Clone the repository**

```sh
git clone https://github.com/your-org/quick-actions-aws-lambda-template.git
cd quick-actions-aws-lambda-template
```

1. **Install Python dependencies**

```sh
pip install -r requirements.txt
```

1. **Build Lambda deployment package**

```sh
mkdir -p build
cd python/src
zip -r ../../build/example_lambda.zip .
cd ../../
```

1. **Initialize and apply Terraform**

```sh
cd terraform
terraform init
terraform apply
```

______________________________________________________________________

## Usage

The Lambda function expects an event with a key indicating the action, for example:

```json
{
"body": "{\"event\": \"delete_lambda_function\", \"function_name\": \"target_lambda\"}"
}
```

Supported events:

- `delete_lambda_function`
- `redrive_sqs_dlq`
- `get_ecr_login_and_repo_uri`

Update the Lambda code to handle your specific use cases.

______________________________________________________________________

## Customization

- **Add more Lambda actions** in `base_lambda.py`
- **Adjust Terraform** for additional AWS resources or permissions
- **Modify CI pipeline** in `.github/workflows/ci.yml` for your team's standards

______________________________________________________________________

## License

MIT License

______________________________________________________________________

## Authors

- [Riyan Imam](https://github.com/riyanimam)
2 changes: 1 addition & 1 deletion config/.yamllint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ rules:
line-length:
max: 500
level: warning
new-lines: disable
new-lines: disable
45 changes: 44 additions & 1 deletion python/src/base_lambda.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from aws_lambda_powertools.shared.types import JSONType
from aws_lambda_powertools.utilities.typing import LambdaContext
import json
import boto3

from botocore.config import Config

Expand All @@ -10,5 +12,46 @@
)


def delete_lambda_function(function_name: str):
client = boto3.client("lambda", config=aws_client_config)
response = client.delete_function(FunctionName=function_name)
return response


def redrive_sqs_dlq(source_queue_url: str, dlq_url: str, max_messages: int = 10):
sqs = boto3.client("sqs", config=aws_client_config)
messages = sqs.receive_message(
QueueUrl=dlq_url, MaxNumberOfMessages=max_messages, WaitTimeSeconds=2
).get("Messages", [])

for msg in messages:
sqs.send_message(QueueUrl=source_queue_url, MessageBody=msg["Body"])
sqs.delete_message(QueueUrl=dlq_url, ReceiptHandle=msg["ReceiptHandle"])
return {"redriven": len(messages)}


def get_ecr_login_and_repo_uri(repository_name: str):
ecr = boto3.client("ecr", config=aws_client_config)
auth = ecr.get_authorization_token()
repo = ecr.describe_repositories(repositoryNames=[repository_name])
repo_uri = repo["repositories"][0]["repositoryUri"]
token = auth["authorizationData"][0]["authorizationToken"]
proxy_endpoint = auth["authorizationData"][0]["proxyEndpoint"]
return {
"repository_uri": repo_uri,
"auth_token": token,
"proxy_endpoint": proxy_endpoint,
}


def lambda_handler(payload: JSONType, context: LambdaContext):
return
event = json.loads(payload["body"])

if event == "delete_lambda_function":
delete_lambda_function("function_name_here")
elif event == "redrive_sqs_dlq":
redrive_sqs_dlq("source_queue_url_here", "dlq_url_here")
elif event == "get_ecr_login_and_repo_uri":
get_ecr_login_and_repo_uri("repository_name_here")
else:
return "Invalid or no event received"
2 changes: 2 additions & 0 deletions python/src/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
boto3
json
Binary file not shown.
1 change: 1 addition & 0 deletions python/test/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ aws-xray-sdk
boto3
boto3-stubs
dataclasses_json
json
mdformat
mdformat-gfm
mdformat-black
Expand Down
Loading