Skip to content

Commit 08446aa

Browse files
committed
Add Python examples deployment infrastructure
- Add examples catalog with hello_world function - Add build script to copy SDK dependencies from hatch environment - Add deployment script with AWS Lambda integration - Add SAM template for local testing - Add GitHub workflow for automated deployment - Add hatch examples environment with build/deploy/clean commands
1 parent f32bfb6 commit 08446aa

File tree

12 files changed

+459
-6
lines changed

12 files changed

+459
-6
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
name: Deploy Python Examples
2+
3+
on:
4+
push:
5+
branches: [ "main", "development" ]
6+
paths:
7+
- 'src/aws_durable_execution_sdk_python_testing/**'
8+
- 'examples/**'
9+
- '.github/workflows/deploy-examples.yml'
10+
pull_request:
11+
branches: [ "main", "development"]
12+
paths:
13+
- 'src/aws_durable_execution_sdk_python_testing/**'
14+
- 'examples/**'
15+
- '.github/workflows/deploy-examples.yml'
16+
workflow_dispatch:
17+
18+
env:
19+
AWS_REGION: us-west-2
20+
21+
permissions:
22+
id-token: write
23+
contents: read
24+
25+
jobs:
26+
deploy:
27+
runs-on: ubuntu-latest
28+
outputs:
29+
function-name-map: ${{ steps.deploy-functions.outputs.function-name-map }}
30+
steps:
31+
- uses: actions/checkout@v4
32+
33+
- name: Setup Python
34+
uses: actions/setup-python@v4
35+
with:
36+
python-version: '3.13'
37+
38+
- name: Configure AWS credentials
39+
if: github.event_name != 'workflow_dispatch' || github.actor != 'nektos/act'
40+
uses: aws-actions/configure-aws-credentials@v4
41+
with:
42+
role-to-assume: "${{ secrets.ACTIONS_INTEGRATION_ROLE_NAME }}"
43+
role-session-name: githubIntegrationTest
44+
aws-region: ${{ env.AWS_REGION }}
45+
46+
- name: Install Hatch
47+
run: pip install hatch
48+
49+
- name: Build examples
50+
run: hatch run examples:build
51+
52+
- name: Deploy functions
53+
id: deploy-functions
54+
env:
55+
AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }}
56+
LAMBDA_ENDPOINT: ${{ secrets.LAMBDA_ENDPOINT }}
57+
INVOKE_ACCOUNT_ID: ${{ secrets.INVOKE_ACCOUNT_ID }}
58+
KMS_KEY_ARN: ${{ secrets.KMS_KEY_ARN }}
59+
GITHUB_EVENT_NAME: ${{ github.event_name }}
60+
GITHUB_EVENT_NUMBER: ${{ github.event.number }}
61+
run: |
62+
# Read examples catalog and deploy each function
63+
FUNCTION_NAME_MAP="{}"
64+
65+
for example in $(jq -r '.examples[] | select(.integration == true) | .handler' examples/examples-catalog.json); do
66+
EXAMPLE_NAME=$(echo $example | sed 's/\.handler$//')
67+
68+
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
69+
FUNCTION_NAME="${EXAMPLE_NAME}-Python-PR-$GITHUB_EVENT_NUMBER"
70+
else
71+
FUNCTION_NAME="${EXAMPLE_NAME}-Python"
72+
fi
73+
74+
echo "Deploying $EXAMPLE_NAME as $FUNCTION_NAME"
75+
hatch run examples:deploy "$EXAMPLE_NAME" "$FUNCTION_NAME"
76+
77+
# Add to function name map
78+
FUNCTION_NAME_MAP=$(echo $FUNCTION_NAME_MAP | jq --arg key "$EXAMPLE_NAME" --arg value "$FUNCTION_NAME" '. + {($key): $value}')
79+
done
80+
81+
echo "function-name-map=$FUNCTION_NAME_MAP" >> $GITHUB_OUTPUT
82+
echo "Function name map: $FUNCTION_NAME_MAP"
83+
84+
cleanup:
85+
needs: [deploy]
86+
runs-on: ubuntu-latest
87+
if: always()
88+
89+
steps:
90+
- uses: actions/checkout@v4
91+
92+
- name: Setup Python
93+
uses: actions/setup-python@v4
94+
with:
95+
python-version: '3.13'
96+
97+
- name: Configure AWS credentials
98+
if: github.event_name != 'workflow_dispatch' || github.actor != 'nektos/act'
99+
uses: aws-actions/configure-aws-credentials@v4
100+
with:
101+
role-to-assume: "${{ secrets.ACTIONS_INTEGRATION_ROLE_NAME }}"
102+
role-session-name: githubIntegrationTest
103+
aws-region: ${{ env.AWS_REGION }}
104+
105+
- name: Install Hatch
106+
run: pip install hatch
107+
108+
- name: Cleanup Lambda functions
109+
env:
110+
LAMBDA_ENDPOINT: ${{ secrets.LAMBDA_ENDPOINT }}
111+
FUNCTION_NAME_MAP: ${{ needs.deploy.outputs.function-name-map }}
112+
run: |
113+
# Delete deployed functions
114+
echo "Cleaning up functions: $FUNCTION_NAME_MAP"
115+
116+
for function_name in $(echo $FUNCTION_NAME_MAP | jq -r '.[]'); do
117+
echo "Deleting function: $function_name"
118+
aws lambda delete-function --function-name "$function_name" --endpoint-url "$LAMBDA_ENDPOINT" --region "$AWS_REGION" || true
119+
done

examples/.env.template

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# AWS Configuration for Lambda Deployment
2+
AWS_REGION=us-west-2
3+
AWS_ACCOUNT_ID=123456789012
4+
LAMBDA_ENDPOINT=https://lambda.us-west-2.amazonaws.com
5+
INVOKE_ACCOUNT_ID=123456789012
6+
KMS_KEY_ARN=arn:aws:kms:us-west-2:123456789012:key/12345678-1234-1234-1234-123456789012

examples/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
build/
2+
*.zip
3+
.env
4+
.aws-sam/

examples/README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Python Durable Functions Examples
2+
3+
## Local Testing with SAM
4+
5+
Test functions locally:
6+
```bash
7+
sam local invoke HelloWorldFunction
8+
```
9+
10+
Test with custom event:
11+
```bash
12+
sam local invoke HelloWorldFunction -e event.json
13+
```
14+
15+
## Deploy Functions
16+
17+
Deploy with Python script:
18+
```bash
19+
python3 deploy.py hello_world
20+
```
21+
22+
Deploy with SAM:
23+
```bash
24+
sam build
25+
sam deploy --guided
26+
```
27+
28+
## Environment Variables
29+
30+
- `AWS_ACCOUNT_ID`: Your AWS account ID
31+
- `LAMBDA_ENDPOINT`: Your Lambda service endpoint
32+
- `INVOKE_ACCOUNT_ID`: Account ID allowed to invoke functions
33+
- `AWS_REGION`: AWS region (default: us-west-2)
34+
- `KMS_KEY_ARN`: KMS key for encryption (optional)
35+
36+
## Available Examples
37+
38+
- **hello_world**: Simple hello world function
39+
40+
## Adding New Examples
41+
42+
1. Add your Python function to `src/`
43+
2. Update `examples-catalog.json` and `template.yaml`
44+
3. Deploy using either script above

examples/build.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env python3
2+
3+
import shutil
4+
import site
5+
from pathlib import Path
6+
7+
8+
def build():
9+
"""Build examples with SDK dependencies from current environment."""
10+
examples_dir = Path(__file__).parent
11+
build_dir = examples_dir / "build"
12+
13+
# Clean build directory
14+
if build_dir.exists():
15+
shutil.rmtree(build_dir)
16+
build_dir.mkdir()
17+
18+
print("Copying SDK from current environment...")
19+
20+
# Copy the SDK from current environment (hatch installs it)
21+
for site_dir in site.getsitepackages():
22+
sdk_path = Path(site_dir) / "aws_durable_execution_sdk_python"
23+
if sdk_path.exists():
24+
shutil.copytree(sdk_path, build_dir / "aws_durable_execution_sdk_python")
25+
print(f"Copied SDK from {sdk_path}")
26+
break
27+
else:
28+
print("SDK not found in site-packages")
29+
30+
print("Copying testing SDK source...")
31+
32+
# Copy testing SDK source
33+
sdk_src = examples_dir.parent / "src" / "aws_durable_execution_sdk_python_testing"
34+
if sdk_src.exists():
35+
shutil.copytree(sdk_src, build_dir / "aws_durable_execution_sdk_python_testing")
36+
37+
print("Copying example functions...")
38+
39+
# Copy example source files
40+
src_dir = examples_dir / "src"
41+
for py_file in src_dir.glob("*.py"):
42+
if py_file.name != "__init__.py":
43+
shutil.copy2(py_file, build_dir)
44+
45+
print(f"Build complete: {build_dir}")
46+
47+
48+
if __name__ == "__main__":
49+
build()

0 commit comments

Comments
 (0)