Skip to content

Commit 08aa7ab

Browse files
viw-test1wangzlei
andauthored
feat: Add region-build-release workflow for region-specific Lambda la… (#721)
…yer deployments *Issue #, if available:* N/A *Description of changes:* Add a standalone region-build-release.yml workflow for deploying the Lambda layer to specific AWS regions without triggering a full SDK release (no PyPI publish, no ECR image push, no GitHub release). By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. Co-authored-by: Lei Wang <66336933+wangzlei@users.noreply.github.com>
1 parent 921b9f8 commit 08aa7ab

1 file changed

Lines changed: 287 additions & 0 deletions

File tree

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
name: Region Build Release
2+
on:
3+
workflow_dispatch:
4+
inputs:
5+
version:
6+
description: The version to tag the release with, e.g., 1.2.0
7+
required: true
8+
aws_region:
9+
description: 'Deploy lambda layer to aws regions'
10+
required: true
11+
default: ''
12+
13+
env:
14+
AWS_DEFAULT_REGION: us-east-1
15+
VERSION: ${{ github.event.inputs.version }}
16+
AWS_REGIONS: ${{ github.event.inputs.aws_region }}
17+
LEGACY_COMMERCIAL_REGIONS: us-east-1, us-east-2, us-west-1, us-west-2, ap-south-1, ap-northeast-3, ap-northeast-2, ap-southeast-1, ap-southeast-2, ap-northeast-1, ca-central-1, eu-central-1, eu-west-1, eu-west-2, eu-west-3, eu-north-1, sa-east-1
18+
LAYER_NAME: AWSOpenTelemetryDistroPython
19+
LAYER_ARTIFACT_NAME: aws-opentelemetry-python-layer.zip
20+
21+
permissions:
22+
id-token: write
23+
contents: write
24+
25+
jobs:
26+
download-artifacts:
27+
environment: Release
28+
runs-on: ubuntu-latest
29+
outputs:
30+
aws_regions_json: ${{ steps.set-matrix.outputs.aws_regions_json }}
31+
steps:
32+
- name: Checkout Repo @ SHA - ${{ github.sha }}
33+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #v5.0.0
34+
35+
- name: Get main build run ID and download artifacts
36+
env:
37+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
38+
run: |
39+
WORKFLOW_ID=$(gh api repos/${{ github.repository }}/actions/workflows --jq '.workflows[] | select(.name=="Python Instrumentation Main Build") | .id')
40+
LATEST_RUN=$(gh api repos/${{ github.repository }}/actions/workflows/$WORKFLOW_ID/runs --jq '[.workflow_runs[] | select(.head_branch=="${{ github.ref_name }}")] | sort_by(.created_at) | .[-1]')
41+
STATUS=$(echo "$LATEST_RUN" | jq -r '.status')
42+
CONCLUSION=$(echo "$LATEST_RUN" | jq -r '.conclusion')
43+
RUN_ID=$(echo "$LATEST_RUN" | jq -r '.id')
44+
45+
if [ "$STATUS" = "in_progress" ] || [ "$STATUS" = "queued" ]; then
46+
echo "Main build is still running (status: $STATUS). Cannot proceed with release."
47+
exit 1
48+
elif [ "$CONCLUSION" != "success" ]; then
49+
echo "Latest main build on branch ${{ github.ref_name }} conclusion: $CONCLUSION"
50+
exit 1
51+
fi
52+
echo "Main build succeeded (run ID: $RUN_ID), downloading artifacts..."
53+
54+
gh run download $RUN_ID -n layer.zip -D layer
55+
56+
- name: Upload layer artifact
57+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 #v4.6.2
58+
with:
59+
name: layer.zip
60+
path: layer/${{ env.LAYER_ARTIFACT_NAME }}
61+
62+
- name: Set up regions matrix
63+
id: set-matrix
64+
run: |
65+
IFS=',' read -ra REGIONS <<< "${{ env.AWS_REGIONS }}"
66+
MATRIX="["
67+
for region in "${REGIONS[@]}"; do
68+
trimmed_region=$(echo "$region" | xargs)
69+
MATRIX+="\"$trimmed_region\","
70+
done
71+
MATRIX="${MATRIX%,}]"
72+
echo ${MATRIX}
73+
echo "aws_regions_json=${MATRIX}" >> $GITHUB_OUTPUT
74+
75+
publish-layer-prod:
76+
runs-on: ubuntu-latest
77+
needs: [download-artifacts]
78+
strategy:
79+
matrix:
80+
aws_region: ${{ fromJson(needs.download-artifacts.outputs.aws_regions_json) }}
81+
steps:
82+
- name: role arn
83+
env:
84+
LEGACY_COMMERCIAL_REGIONS: ${{ env.LEGACY_COMMERCIAL_REGIONS }}
85+
run: |
86+
LEGACY_COMMERCIAL_REGIONS_ARRAY=(${LEGACY_COMMERCIAL_REGIONS//,/ })
87+
FOUND=false
88+
for REGION in "${LEGACY_COMMERCIAL_REGIONS_ARRAY[@]}"; do
89+
if [[ "$REGION" == "${{ matrix.aws_region }}" ]]; then
90+
FOUND=true
91+
break
92+
fi
93+
done
94+
if [ "$FOUND" = true ]; then
95+
echo "Found ${{ matrix.aws_region }} in LEGACY_COMMERCIAL_REGIONS"
96+
SECRET_KEY="LAMBDA_LAYER_RELEASE"
97+
else
98+
echo "Not found ${{ matrix.aws_region }} in LEGACY_COMMERCIAL_REGIONS"
99+
SECRET_KEY="${{ matrix.aws_region }}_LAMBDA_LAYER_RELEASE"
100+
fi
101+
SECRET_KEY=${SECRET_KEY//-/_}
102+
echo "SECRET_KEY=${SECRET_KEY}" >> $GITHUB_ENV
103+
- uses: aws-actions/configure-aws-credentials@a03048d87541d1d9fcf2ecf528a4a65ba9bd7838 #v5.0.0
104+
with:
105+
role-to-assume: ${{ secrets[env.SECRET_KEY] }}
106+
role-duration-seconds: 1200
107+
aws-region: ${{ matrix.aws_region }}
108+
- name: Get s3 bucket name for release
109+
run: |
110+
echo BUCKET_NAME=python-lambda-layer-${{ github.run_id }}-${{ matrix.aws_region }} | tee --append $GITHUB_ENV
111+
- name: download layer.zip
112+
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 #v5.0.0
113+
with:
114+
name: layer.zip
115+
116+
- name: Upload to S3 and Sign
117+
continue-on-error: true
118+
run: |
119+
aws s3 mb s3://${{ env.BUCKET_NAME }}
120+
aws s3 cp ${{ env.LAYER_ARTIFACT_NAME }} s3://${{ env.BUCKET_NAME }}
121+
122+
# Sign the layer
123+
echo "Checking for signing profile..."
124+
PROFILE=$(aws signer list-signing-profiles --query "profiles[?profileName=='ADOTLambdaLayerSigningProfile'].arn" --output text 2>/dev/null)
125+
[ -z "$PROFILE" ] && echo "No signing profile found, skipping" && exit 0
126+
127+
echo "PROFILE is: $PROFILE"
128+
129+
echo "Starting signing job..."
130+
# Capture both stdout and stderr to properly handle errors
131+
SIGNING_OUTPUT=$(aws signer start-signing-job \
132+
--source "s3={bucketName=${{ env.BUCKET_NAME }},key=${{ env.LAYER_ARTIFACT_NAME }},version=null}" \
133+
--destination "s3={bucketName=${{ env.BUCKET_NAME }},prefix=signed-}" \
134+
--profile-name ADOTLambdaLayerSigningProfile \
135+
--query 'jobId' --output text 2>&1)
136+
SIGNING_EXIT_CODE=$?
137+
138+
if [ $SIGNING_EXIT_CODE -ne 0 ]; then
139+
echo "Signing job failed with exit code $SIGNING_EXIT_CODE"
140+
echo "Error output: $SIGNING_OUTPUT"
141+
exit 0 # Continue workflow but log the failure
142+
fi
143+
144+
JOB_ID="$SIGNING_OUTPUT"
145+
[ -z "$JOB_ID" ] && echo "No job ID returned" && exit 0
146+
echo "Job ID: $JOB_ID"
147+
148+
echo "Waiting for signing job to complete..."
149+
if ! aws signer wait successful-signing-job --job-id "$JOB_ID" 2>&1; then
150+
echo "Warning: Signing job wait failed or timed out"
151+
exit 0
152+
fi
153+
echo "Signing completed"
154+
155+
echo "Moving signed layer..."
156+
SIGNED=$(aws signer describe-signing-job --job-id "$JOB_ID" --query 'signedObject.s3.key' --output text 2>&1)
157+
DESCRIBE_EXIT_CODE=$?
158+
159+
if [ $DESCRIBE_EXIT_CODE -ne 0 ]; then
160+
echo "Warning: Failed to describe signing job"
161+
echo "Error: $SIGNED"
162+
exit 0
163+
fi
164+
165+
echo "SIGNED value: '$SIGNED'"
166+
if [ -n "$SIGNED" ]; then
167+
# Delete the original unsigned file first
168+
aws s3 rm "s3://${{ env.BUCKET_NAME }}/${{ env.LAYER_ARTIFACT_NAME }}"
169+
# Move the signed file to replace it
170+
aws s3 mv "s3://${{ env.BUCKET_NAME }}/$SIGNED" "s3://${{ env.BUCKET_NAME }}/${{ env.LAYER_ARTIFACT_NAME }}"
171+
echo "Signed layer moved successfully"
172+
else
173+
echo "No SIGNED value returned, skipping move"
174+
fi
175+
176+
- name: Publish Layer Version
177+
run: |
178+
layerARN=$(
179+
aws lambda publish-layer-version \
180+
--layer-name ${{ env.LAYER_NAME }} \
181+
--content S3Bucket=${{ env.BUCKET_NAME }},S3Key=${{ env.LAYER_ARTIFACT_NAME }} \
182+
--compatible-runtimes python3.10 python3.11 python3.12 python3.13 \
183+
--compatible-architectures "arm64" "x86_64" \
184+
--license-info "Apache-2.0" \
185+
--description "AWS Distro of OpenTelemetry Lambda Layer for Python Runtime" \
186+
--query 'LayerVersionArn' \
187+
--output text
188+
)
189+
echo $layerARN
190+
echo "LAYER_ARN=${layerARN}" >> $GITHUB_ENV
191+
mkdir ${{ env.LAYER_NAME }}
192+
echo $layerARN > ${{ env.LAYER_NAME }}/${{ matrix.aws_region }}
193+
cat ${{ env.LAYER_NAME }}/${{ matrix.aws_region }}
194+
195+
# Output SigningProfileVersionArn
196+
aws lambda get-layer-version-by-arn \
197+
--arn $layerARN \
198+
--output json | jq -r '.Content.SigningProfileVersionArn'
199+
- name: public layer
200+
run: |
201+
layerVersion=$(
202+
aws lambda list-layer-versions \
203+
--layer-name ${{ env.LAYER_NAME }} \
204+
--query 'max_by(LayerVersions, &Version).Version'
205+
)
206+
aws lambda add-layer-version-permission \
207+
--layer-name ${{ env.LAYER_NAME }} \
208+
--version-number $layerVersion \
209+
--principal "*" \
210+
--statement-id publish \
211+
--action lambda:GetLayerVersion
212+
- name: upload layer arn artifact
213+
if: ${{ success() }}
214+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 #v4.6.2
215+
with:
216+
name: ${{ env.LAYER_NAME }}-${{ matrix.aws_region }}
217+
path: ${{ env.LAYER_NAME }}/${{ matrix.aws_region }}
218+
- name: clean s3
219+
if: always()
220+
run: |
221+
aws s3 rb --force s3://${{ env.BUCKET_NAME }}
222+
223+
generate-lambda-release-note:
224+
runs-on: ubuntu-latest
225+
needs: publish-layer-prod
226+
outputs:
227+
layer-note: ${{ steps.layer-note.outputs.layer-note }}
228+
steps:
229+
- name: Checkout Repo @ SHA - ${{ github.sha }}
230+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #v5.0.0
231+
- uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd #v3.1.2
232+
- name: download layerARNs
233+
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 #v5.0.0
234+
with:
235+
pattern: ${{ env.LAYER_NAME }}-*
236+
path: ${{ env.LAYER_NAME }}
237+
merge-multiple: true
238+
- name: show layerARNs
239+
run: |
240+
for file in ${{ env.LAYER_NAME }}/*
241+
do
242+
echo $file
243+
cat $file
244+
done
245+
- name: generate layer-note
246+
id: layer-note
247+
working-directory: ${{ env.LAYER_NAME }}
248+
run: |
249+
echo "| Region | Layer ARN |" >> ../layer-note
250+
echo "| ---- | ---- |" >> ../layer-note
251+
for file in *
252+
do
253+
read arn < $file
254+
echo "| " $file " | " $arn " |" >> ../layer-note
255+
done
256+
cd ..
257+
{
258+
echo "layer-note<<EOF"
259+
cat layer-note
260+
echo "EOF"
261+
} >> $GITHUB_OUTPUT
262+
cat layer-note
263+
- name: generate tf layer
264+
working-directory: ${{ env.LAYER_NAME }}
265+
run: |
266+
echo "locals {" >> ../layer_arns.tf
267+
echo " sdk_layer_arns = {" >> ../layer_arns.tf
268+
for file in *
269+
do
270+
read arn < $file
271+
echo " \""$file"\" = \""$arn"\"" >> ../layer_arns.tf
272+
done
273+
cd ..
274+
echo " }" >> layer_arns.tf
275+
echo "}" >> layer_arns.tf
276+
terraform fmt layer_arns.tf
277+
cat layer_arns.tf
278+
- name: generate layer ARN constants for CDK
279+
working-directory: ${{ env.LAYER_NAME }}
280+
run: |
281+
echo "{" > ../layer_cdk
282+
for file in *; do
283+
read arn < "$file"
284+
echo " \"$file\": \"$arn\"," >> ../layer_cdk
285+
done
286+
echo "}" >> ../layer_cdk
287+
cat ../layer_cdk

0 commit comments

Comments
 (0)