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
72 changes: 72 additions & 0 deletions .github/scripts/publish-layer-parameter.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env bash
#
# Publishes the version-named SSM pointer after CloudFormation has deployed a layer.
# The parameter deliberately lives outside the stack: retaining a
# parameter whose Name contains the package version made CloudFormation collide with
# the retained resource whenever a version was re-used.
#
# The PipelineExecutionRole's ssm:PutParameter grant for these names lives in
# LambdaWebAdapterInfrastructureCDK (lib/infra-template.yaml,
# PipelineExecutionRolePermissions), which also denies the `latest` pointer that
# CloudFormation owns.
#
# Usage:
# publish-layer-parameter.sh <stack-name> <x86_64|arm64> <version> <region>
set -euo pipefail
export AWS_PAGER=""

STACK_NAME="${1:?stack name required}"
ARCHITECTURE="${2:?architecture required}"
VERSION="${3:?version required}"
REGION="${4:?region required}"

# A version containing a slash would write outside the path the grant covers — and, worse,
# could name a `latest` pointer. Fail before the API call rather than on an opaque
# AccessDenied.
if [[ "$VERSION" != "${VERSION//\//}" || -z "$VERSION" ]]; then
echo "Refusing to publish a parameter for version '$VERSION'" >&2
exit 2
fi

case "$ARCHITECTURE" in
x86_64)
OUTPUT_KEY="LambdaAdapterLayerX86Arn"
DESCRIPTION_ARCH="X86_64"
;;
arm64)
OUTPUT_KEY="LambdaAdapterLayerArm64Arn"
DESCRIPTION_ARCH="Arm64"
;;
*)
echo "Unsupported architecture: $ARCHITECTURE" >&2
exit 2
;;
esac

LAYER_ARN="$(
aws cloudformation describe-stacks \
--stack-name "$STACK_NAME" \
--region "$REGION" \
--query "Stacks[0].Outputs[?OutputKey=='${OUTPUT_KEY}'].OutputValue | [0]" \
--output text
)"

if [[ -z "$LAYER_ARN" || "$LAYER_ARN" == "None" ]]; then
echo "Stack $STACK_NAME has no $OUTPUT_KEY output in $REGION" >&2
exit 1
fi

PARAMETER_NAME="/lambda-web-adapter/layer/${ARCHITECTURE}/${VERSION}"
PARAMETER_VERSION="$(
aws ssm put-parameter \
--name "$PARAMETER_NAME" \
--description "Layer ARN for the Lambda Web Adapter ${DESCRIPTION_ARCH} Layer: ${VERSION}" \
--type String \
--value "$LAYER_ARN" \
--overwrite \
--region "$REGION" \
--query Version \
--output text
)"

echo "Published $PARAMETER_NAME -> $LAYER_ARN (parameter version $PARAMETER_VERSION)"
27 changes: 25 additions & 2 deletions .github/workflows/merge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -228,13 +228,19 @@ jobs:
run: |
echo "CARGO_PKG_VERSION=$(cargo metadata --no-deps --format-version=1 | jq -r '.packages[0].version')" >> $GITHUB_ENV

- name: Resolve the layer stack names
run: |
# Once, from BETA_STACK_NAME, so the deploy and the publish below cannot drift.
echo "X86_STACK=${BETA_STACK_NAME}-x86" >> $GITHUB_ENV
echo "ARM64_STACK=${BETA_STACK_NAME}-arm64" >> $GITHUB_ENV

- uses: actions/download-artifact@v4
with:
name: packaged-beta-x86_64.yaml

- name: Deploy x86_64 layer to beta account
run: |
sam deploy --stack-name ${BETA_STACK_NAME}-x86 \
sam deploy --stack-name ${X86_STACK} \
--template packaged-beta-x86_64.yaml \
--parameter-overrides CargoPkgVersion=${CARGO_PKG_VERSION} \
--capabilities CAPABILITY_IAM \
Expand All @@ -250,7 +256,7 @@ jobs:

- name: Deploy arm64 layer to beta account
run: |
sam deploy --stack-name ${BETA_STACK_NAME}-arm64 \
sam deploy --stack-name ${ARM64_STACK} \
--template packaged-beta-arm64.yaml \
--parameter-overrides CargoPkgVersion=${CARGO_PKG_VERSION} \
--capabilities CAPABILITY_IAM \
Expand All @@ -260,6 +266,23 @@ jobs:
--no-fail-on-empty-changeset \
--role-arn ${BETA_CLOUDFORMATION_EXECUTION_ROLE}

# Both deploys complete before either pointer is written, deliberately. These steps
# need ssm:PutParameter, granted to the PipelineExecutionRole by
# LambdaWebAdapterInfrastructureCDK (lib/infra-template.yaml,
# PipelineExecutionRolePermissions) — so a region whose pipeline-resources stack has
# not been updated with that grant fails here with AccessDenied. Ordered this way,
# that failure leaves both layers published and the version pointers stale; ordered
# between the deploys, it left the region with a new x86 layer and no arm64 one.
- name: Publish versioned x86_64 layer parameter
run: |
.github/scripts/publish-layer-parameter.sh \
"$X86_STACK" x86_64 "${CARGO_PKG_VERSION}" "${BETA_REGION}"

- name: Publish versioned arm64 layer parameter
run: |
.github/scripts/publish-layer-parameter.sh \
"$ARM64_STACK" arm64 "${CARGO_PKG_VERSION}" "${BETA_REGION}"

e2e-test-zip:
needs: [deploy-beta]
runs-on: ubuntu-24.04
Expand Down
99 changes: 91 additions & 8 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,11 @@ jobs:
runs-on: ubuntu-24.04
strategy:
matrix: ${{fromJSON(needs.load-matrices.outputs.gamma)}}
env:
# One definition each, used by the deploy and by the publish step
# below, so the two cannot drift apart in a copy-paste.
X86_STACK: lambda-adapter-gamma-x86-${{ matrix.region }}
ARM64_STACK: lambda-adapter-gamma-arm64-${{ matrix.region }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
Expand Down Expand Up @@ -464,7 +469,7 @@ jobs:

- name: Deploy x86_64 Layer to all regions in gamma account
run: |
sam deploy --stack-name lambda-adapter-gamma-x86-${{ matrix.region }} \
sam deploy --stack-name ${X86_STACK} \
--template packaged-gamma-x86_64-${{ matrix.region }}.yaml \
--parameter-overrides CargoPkgVersion=${CARGO_PKG_VERSION} \
--capabilities CAPABILITY_IAM \
Expand All @@ -474,14 +479,15 @@ jobs:
--no-fail-on-empty-changeset \
--role-arn ${{ matrix.cloudformation_execution_role }}


- uses: actions/download-artifact@v4
with:
name: packaged-gamma-arm64-${{ matrix.region }}.yaml

- name: Deploy arm64 Layer to supported regions in gamma account
if: ${{ matrix.arm64_supported }}
run: |
sam deploy --stack-name lambda-adapter-gamma-arm64-${{ matrix.region }} \
sam deploy --stack-name ${ARM64_STACK} \
--template packaged-gamma-arm64-${{ matrix.region }}.yaml \
--parameter-overrides CargoPkgVersion=${CARGO_PKG_VERSION} \
--capabilities CAPABILITY_IAM \
Expand All @@ -491,12 +497,37 @@ jobs:
--no-fail-on-empty-changeset \
--role-arn ${{ matrix.cloudformation_execution_role }}

# Both deploys complete before either pointer is written, deliberately. These steps
# need ssm:PutParameter, granted to the PipelineExecutionRole by
# LambdaWebAdapterInfrastructureCDK (lib/infra-template.yaml,
# PipelineExecutionRolePermissions) — so a region whose pipeline-resources stack has
# not been updated with that grant fails here with AccessDenied. Ordered this way,
# that failure leaves both layers published and the version pointers stale; ordered
# between the deploys, it left the region with a new x86 layer and no arm64 one.
- name: Publish versioned x86_64 layer parameter
run: |
.github/scripts/publish-layer-parameter.sh \
"$X86_STACK" \
x86_64 "${CARGO_PKG_VERSION}" "${{ matrix.region }}"

- name: Publish versioned arm64 layer parameter
if: ${{ matrix.arm64_supported }}
run: |
.github/scripts/publish-layer-parameter.sh \
"$ARM64_STACK" \
arm64 "${CARGO_PKG_VERSION}" "${{ matrix.region }}"

deploy-prod:
needs: [load-matrices, deploy-gamma, package-prod]
runs-on: ubuntu-24.04
environment: prod
strategy:
matrix: ${{fromJSON(needs.load-matrices.outputs.prod)}}
env:
# One definition each, used by the deploy and by the publish step
# below, so the two cannot drift apart in a copy-paste.
X86_STACK: lambda-adapter-prod-x86-${{ matrix.region }}
ARM64_STACK: lambda-adapter-prod-arm64-${{ matrix.region }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
Expand Down Expand Up @@ -533,7 +564,7 @@ jobs:

- name: Deploy x86_64 Layer to all regions in prod account
run: |
sam deploy --stack-name lambda-adapter-prod-x86-${{ matrix.region }} \
sam deploy --stack-name ${X86_STACK} \
--template packaged-prod-x86_64-${{ matrix.region }}.yaml \
--parameter-overrides CargoPkgVersion=${CARGO_PKG_VERSION} \
--capabilities CAPABILITY_IAM \
Expand All @@ -543,14 +574,15 @@ jobs:
--no-fail-on-empty-changeset \
--role-arn ${{ matrix.cloudformation_execution_role }}


- uses: actions/download-artifact@v4
with:
name: packaged-prod-arm64-${{ matrix.region }}.yaml

- name: Deploy arm64 Layer to supported regions in prod account
if: ${{ matrix.arm64_supported }}
run: |
sam deploy --stack-name lambda-adapter-prod-arm64-${{ matrix.region }} \
sam deploy --stack-name ${ARM64_STACK} \
--template packaged-prod-arm64-${{ matrix.region }}.yaml \
--parameter-overrides CargoPkgVersion=${CARGO_PKG_VERSION} \
--capabilities CAPABILITY_IAM \
Expand All @@ -560,11 +592,29 @@ jobs:
--no-fail-on-empty-changeset \
--role-arn ${{ matrix.cloudformation_execution_role }}

- name: Publish versioned x86_64 layer parameter
run: |
.github/scripts/publish-layer-parameter.sh \
"$X86_STACK" \
x86_64 "${CARGO_PKG_VERSION}" "${{ matrix.region }}"

- name: Publish versioned arm64 layer parameter
if: ${{ matrix.arm64_supported }}
run: |
.github/scripts/publish-layer-parameter.sh \
"$ARM64_STACK" \
arm64 "${CARGO_PKG_VERSION}" "${{ matrix.region }}"

deploy-china-gamma:
needs: [load-matrices, package-china-gamma]
runs-on: ubuntu-24.04
strategy:
matrix: ${{fromJSON(needs.load-matrices.outputs.china-gamma)}}
env:
# One definition each, used by the deploy and by the publish step
# below, so the two cannot drift apart in a copy-paste.
X86_STACK: lambda-adapter-gamma-x86-${{ matrix.region }}
ARM64_STACK: lambda-adapter-gamma-arm64-${{ matrix.region }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
Expand Down Expand Up @@ -603,7 +653,7 @@ jobs:

- name: Deploy x86_64 Layer to all regions in china
run: |
sam deploy --stack-name lambda-adapter-gamma-x86-${{ matrix.region }} \
sam deploy --stack-name ${X86_STACK} \
--template packaged-china-gamma-x86_64-${{ matrix.region }}.yaml \
--parameter-overrides CargoPkgVersion=${CARGO_PKG_VERSION} \
--capabilities CAPABILITY_IAM \
Expand All @@ -613,14 +663,15 @@ jobs:
--no-fail-on-empty-changeset \
--role-arn ${{ matrix.cloudformation_execution_role }}


- uses: actions/download-artifact@v4
with:
name: packaged-china-gamma-arm64-${{ matrix.region }}.yaml

- name: Deploy arm64 Layer to supported china regions
if: ${{ matrix.arm64_supported }}
run: |
sam deploy --stack-name lambda-adapter-gamma-arm64-${{ matrix.region }} \
sam deploy --stack-name ${ARM64_STACK} \
--template packaged-china-gamma-arm64-${{ matrix.region }}.yaml \
--parameter-overrides CargoPkgVersion=${CARGO_PKG_VERSION} \
--capabilities CAPABILITY_IAM \
Expand All @@ -630,12 +681,30 @@ jobs:
--no-fail-on-empty-changeset \
--role-arn ${{ matrix.cloudformation_execution_role }}

- name: Publish versioned x86_64 layer parameter
run: |
.github/scripts/publish-layer-parameter.sh \
"$X86_STACK" \
x86_64 "${CARGO_PKG_VERSION}" "${{ matrix.region }}"

- name: Publish versioned arm64 layer parameter
if: ${{ matrix.arm64_supported }}
run: |
.github/scripts/publish-layer-parameter.sh \
"$ARM64_STACK" \
arm64 "${CARGO_PKG_VERSION}" "${{ matrix.region }}"

deploy-china-prod:
needs: [load-matrices, deploy-china-gamma, package-china-prod]
runs-on: ubuntu-24.04
environment: prod
strategy:
matrix: ${{fromJSON(needs.load-matrices.outputs.china-prod)}}
env:
# One definition each, used by the deploy and by the publish step
# below, so the two cannot drift apart in a copy-paste.
X86_STACK: lambda-adapter-prod-x86-${{ matrix.region }}
ARM64_STACK: lambda-adapter-prod-arm64-${{ matrix.region }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
Expand Down Expand Up @@ -674,7 +743,7 @@ jobs:

- name: Deploy x86_64 Layer to all regions in china
run: |
sam deploy --stack-name lambda-adapter-prod-x86-${{ matrix.region }} \
sam deploy --stack-name ${X86_STACK} \
--template packaged-china-prod-x86_64-${{ matrix.region }}.yaml \
--parameter-overrides CargoPkgVersion=${CARGO_PKG_VERSION} \
--capabilities CAPABILITY_IAM \
Expand All @@ -684,14 +753,15 @@ jobs:
--no-fail-on-empty-changeset \
--role-arn ${{ matrix.cloudformation_execution_role }}


- uses: actions/download-artifact@v4
with:
name: packaged-china-prod-arm64-${{ matrix.region }}.yaml

- name: Deploy arm64 Layer to supported china regions
if: ${{ matrix.arm64_supported }}
run: |
sam deploy --stack-name lambda-adapter-prod-arm64-${{ matrix.region }} \
sam deploy --stack-name ${ARM64_STACK} \
--template packaged-china-prod-arm64-${{ matrix.region }}.yaml \
--parameter-overrides CargoPkgVersion=${CARGO_PKG_VERSION} \
--capabilities CAPABILITY_IAM \
Expand All @@ -701,6 +771,19 @@ jobs:
--no-fail-on-empty-changeset \
--role-arn ${{ matrix.cloudformation_execution_role }}

- name: Publish versioned x86_64 layer parameter
run: |
.github/scripts/publish-layer-parameter.sh \
"$X86_STACK" \
x86_64 "${CARGO_PKG_VERSION}" "${{ matrix.region }}"

- name: Publish versioned arm64 layer parameter
if: ${{ matrix.arm64_supported }}
run: |
.github/scripts/publish-layer-parameter.sh \
"$ARM64_STACK" \
arm64 "${CARGO_PKG_VERSION}" "${{ matrix.region }}"

publish-to-public-ecr:
needs: [deploy-prod]
runs-on: ubuntu-24.04
Expand Down
7 changes: 3 additions & 4 deletions template-arm64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,9 @@ Resources:
Type: String
Value: !Ref LambdaAdapterLayerArm64

# A per-version parameter (/lambda-web-adapter/layer/arm64/<CargoPkgVersion>) used to
# live here. See the matching comment in template-x86_64.yaml for why it was removed:
# a Name change replaces the parameter, and UpdateReplacePolicy: Retain orphaned the
# old name, so re-deploying an already-used version failed with AlreadyExists.
# The version-named parameter (/lambda-web-adapter/layer/arm64/<CargoPkgVersion>)
# is published after deployment with `aws ssm put-parameter --overwrite`. See the
# matching comment in template-x86_64.yaml for why it cannot live in this stack.

Outputs:
LambdaAdapterLayerArm64Arn:
Expand Down
12 changes: 4 additions & 8 deletions template-x86_64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,10 @@ Resources:
Type: String
Value: !Ref LambdaAdapterLayerX86

# A per-version parameter (/lambda-web-adapter/layer/x86_64/<CargoPkgVersion>) used
# to live here. It was removed: because CloudFormation replaces a parameter when its
# Name changes, and UpdateReplacePolicy was Retain, every version bump orphaned the
# previous name. Deploying a version whose name had already been orphaned — after the
# v1.1.0 revert, or on any re-release — then failed with AlreadyExists and wedged
# every merge to main. Existing per-version parameters are retained, and the layer's
# Description still records the version, so `aws lambda list-layer-versions` maps a
# version to its layer ARN.
# The version-named parameter (/lambda-web-adapter/layer/x86_64/<CargoPkgVersion>)
# is published after deployment with `aws ssm put-parameter --overwrite`. It cannot
# live in this stack: a Name change replaces the resource, while retaining old
# versions leaves names that CloudFormation collides with when a version is re-used.

Outputs:
LambdaAdapterLayerX86Arn:
Expand Down
Loading