Skip to content

Commit bcd79a4

Browse files
authored
ci: fix the deploy-beta SSM parameter collision and retry tool downloads (#843)
* ci: drop the version-named SSM layer parameter Every merge to main has failed at deploy-beta since the v1.1.0 revert (2026-07-10) with: Resource of type 'AWS::SSM::Parameter' with identifier '/lambda-web-adapter/layer/x86_64/1.0.1' already exists. (AlreadyExists) The parameter's Name embedded ${CargoPkgVersion}, so a version change forces CloudFormation to replace the resource, and UpdateReplacePolicy: Retain left the old name behind un-managed. Releasing 1.1.0 orphaned /x86_64/1.0.1; reverting to 1.0.1 then tried to create that exact name and hit the orphan. Rollback restores the 1.1.0 name, so the next deploy repeats it — a permanent wedge, not a flake. It also took e2e-test-zip and e2e-test-oci down with it (both `needs: deploy-beta`), so main had no e2e coverage for two months. Removing the resource is the fix rather than dropping UpdateReplacePolicy: with only the current version ever tracked, the per-version parameter holds the same value as the /latest parameter beside it, so it earns nothing. The alternative — writing it with `aws ssm put-parameter --overwrite` from the workflow — needs ssm:PutParameter added to the PipelineExecutionRole in every beta, gamma, prod, and China account, which today grants only ssm:GetParameters on /lambda-web-adapter/e2e/*. Nothing reads a per-version parameter: the only consumer of either parameter is tests/e2e_tests/fixtures/go-httpbin-zip/template.yaml, which reads /lambda-web-adapter/layer/x86_64/latest. That one keeps its static name, so it updates in place and can never collide. No parameter is deleted by this change. DeletionPolicy: Retain applies when a resource is removed from the template, so the currently-tracked names are kept as the historical pointers, and the layer Description still records the version for `aws lambda list-layer-versions`. * ci: retry tool downloads instead of piping curl into tar e2e-test-zip failed on the first green deploy-beta in two months, six steps before it ran anything: curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ... curl: (35) Recv failure: Connection reset by peer tar: Error is not recoverable: exiting now Two problems. There was no retry, so one reset from get.nexte.st failed the job. And piping into tar discarded curl's exit status — the default shell for `run` is `bash -e`, without pipefail — so the diagnosis surfaced as a tar error rather than the network failure it was. Both downloads now retry and land in a file before extraction: cargo-nextest in all five places it is installed (merge test, merge e2e-test-zip, merge e2e-test-oci, pr, release) and mdBook in the docs workflow, which has the same pattern and would have been the next one to flake. * ci: fail the mdBook download on an HTTP error The mdBook step kept `-sSL` while the cargo-nextest steps use `-LsSf`, so it still had the failure mode this branch set out to remove. Without `--fail`, curl treats an HTTP error as a successful transfer: it writes the error page to /tmp/mdbook.tar.gz and exits 0, and `tar` then fails with "not in gzip format" instead of reporting the 403 or 404 that actually happened. `--retry` cannot help either, because curl never classifies the response as an error to retry. Reproduced against a non-existent release asset: without -f, curl exits 0 having written a 9-byte "Not Found" body and tar exits 2 with no usable message; with -f, curl exits 22 and says "The requested URL returned error: 404". The real asset still downloads and extracts (mdbook v0.4.40). Reported by aws-sam-tooling-bot on #843.
1 parent 4c38d8f commit bcd79a4

6 files changed

Lines changed: 55 additions & 24 deletions

File tree

.github/workflows/docs.yaml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,14 @@ jobs:
2626
- name: Install mdBook
2727
run: |
2828
mkdir -p $HOME/bin
29-
curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.40/mdbook-v0.4.40-x86_64-unknown-linux-gnu.tar.gz | tar -xz -C $HOME/bin
29+
# -f so an HTTP error is an error: without it curl writes the error page to
30+
# the output file and exits 0, and tar then fails with "not in gzip format"
31+
# — the same misleading failure this commit set out to remove. It is also
32+
# what lets --retry see a 5xx as retryable at all.
33+
curl --retry 5 --retry-all-errors --retry-delay 5 -sSLf \
34+
https://github.com/rust-lang/mdBook/releases/download/v0.4.40/mdbook-v0.4.40-x86_64-unknown-linux-gnu.tar.gz \
35+
-o /tmp/mdbook.tar.gz
36+
tar -xz -C $HOME/bin -f /tmp/mdbook.tar.gz
3037
echo "$HOME/bin" >> $GITHUB_PATH
3138
3239
- name: Build book

.github/workflows/merge.yaml

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,13 @@ jobs:
3636
uses: Swatinem/rust-cache@v2
3737

3838
- name: Install cargo-nextest
39-
run: curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin
39+
# Retried, and downloaded to a file rather than piped into tar: the default
40+
# shell has no pipefail, so curl's exit status was discarded and a transient
41+
# connection reset surfaced as an unrecoverable tar error.
42+
run: |
43+
curl --retry 5 --retry-all-errors --retry-delay 5 -LsSf \
44+
https://get.nexte.st/latest/linux -o /tmp/cargo-nextest.tar.gz
45+
tar zxf /tmp/cargo-nextest.tar.gz -C "${CARGO_HOME:-$HOME/.cargo}/bin"
4046
4147
- name: linting
4248
run: |
@@ -271,7 +277,13 @@ jobs:
271277
uses: Swatinem/rust-cache@v2
272278

273279
- name: Install cargo-nextest
274-
run: curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin
280+
# Retried, and downloaded to a file rather than piped into tar: the default
281+
# shell has no pipefail, so curl's exit status was discarded and a transient
282+
# connection reset surfaced as an unrecoverable tar error.
283+
run: |
284+
curl --retry 5 --retry-all-errors --retry-delay 5 -LsSf \
285+
https://get.nexte.st/latest/linux -o /tmp/cargo-nextest.tar.gz
286+
tar zxf /tmp/cargo-nextest.tar.gz -C "${CARGO_HOME:-$HOME/.cargo}/bin"
275287
276288
- uses: actions/setup-python@v4
277289
with:
@@ -334,7 +346,13 @@ jobs:
334346
uses: Swatinem/rust-cache@v2
335347

336348
- name: Install cargo-nextest
337-
run: curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin
349+
# Retried, and downloaded to a file rather than piped into tar: the default
350+
# shell has no pipefail, so curl's exit status was discarded and a transient
351+
# connection reset surfaced as an unrecoverable tar error.
352+
run: |
353+
curl --retry 5 --retry-all-errors --retry-delay 5 -LsSf \
354+
https://get.nexte.st/latest/linux -o /tmp/cargo-nextest.tar.gz
355+
tar zxf /tmp/cargo-nextest.tar.gz -C "${CARGO_HOME:-$HOME/.cargo}/bin"
338356
339357
- uses: actions/setup-python@v4
340358
with:

.github/workflows/pr.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,13 @@ jobs:
2828
uses: Swatinem/rust-cache@v2
2929

3030
- name: Install cargo-nextest
31-
run: curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin
31+
# Retried, and downloaded to a file rather than piped into tar: the default
32+
# shell has no pipefail, so curl's exit status was discarded and a transient
33+
# connection reset surfaced as an unrecoverable tar error.
34+
run: |
35+
curl --retry 5 --retry-all-errors --retry-delay 5 -LsSf \
36+
https://get.nexte.st/latest/linux -o /tmp/cargo-nextest.tar.gz
37+
tar zxf /tmp/cargo-nextest.tar.gz -C "${CARGO_HOME:-$HOME/.cargo}/bin"
3238
3339
- name: linting
3440
run: |

.github/workflows/release.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,13 @@ jobs:
3232
uses: Swatinem/rust-cache@v2
3333

3434
- name: Install cargo-nextest
35-
run: curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin
35+
# Retried, and downloaded to a file rather than piped into tar: the default
36+
# shell has no pipefail, so curl's exit status was discarded and a transient
37+
# connection reset surfaced as an unrecoverable tar error.
38+
run: |
39+
curl --retry 5 --retry-all-errors --retry-delay 5 -LsSf \
40+
https://get.nexte.st/latest/linux -o /tmp/cargo-nextest.tar.gz
41+
tar zxf /tmp/cargo-nextest.tar.gz -C "${CARGO_HOME:-$HOME/.cargo}/bin"
3642
3743
- name: linting
3844
run: |

template-arm64.yaml

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,10 @@ Resources:
3939
Type: String
4040
Value: !Ref LambdaAdapterLayerArm64
4141

42-
LambdaAdapterLayerArm64VersionParameter:
43-
Type: AWS::SSM::Parameter
44-
DeletionPolicy: Retain
45-
UpdateReplacePolicy: Retain
46-
Properties:
47-
Name: !Sub '/lambda-web-adapter/layer/arm64/${CargoPkgVersion}'
48-
Description: !Sub 'Layer ARN for the latest Lambda Web Adapter Arm64 Layer: ${CargoPkgVersion}'
49-
Type: String
50-
Value: !Ref LambdaAdapterLayerArm64
42+
# A per-version parameter (/lambda-web-adapter/layer/arm64/<CargoPkgVersion>) used to
43+
# live here. See the matching comment in template-x86_64.yaml for why it was removed:
44+
# a Name change replaces the parameter, and UpdateReplacePolicy: Retain orphaned the
45+
# old name, so re-deploying an already-used version failed with AlreadyExists.
5146

5247
Outputs:
5348
LambdaAdapterLayerArm64Arn:

template-x86_64.yaml

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,14 @@ Resources:
3939
Type: String
4040
Value: !Ref LambdaAdapterLayerX86
4141

42-
LambdaAdapterLayerArm64VersionParameter:
43-
Type: AWS::SSM::Parameter
44-
DeletionPolicy: Retain
45-
UpdateReplacePolicy: Retain
46-
Properties:
47-
Name: !Sub '/lambda-web-adapter/layer/x86_64/${CargoPkgVersion}'
48-
Description: !Sub 'Layer ARN for the latest Lambda Web Adapter X86_64 Layer: ${CargoPkgVersion}'
49-
Type: String
50-
Value: !Ref LambdaAdapterLayerX86
42+
# A per-version parameter (/lambda-web-adapter/layer/x86_64/<CargoPkgVersion>) used
43+
# to live here. It was removed: because CloudFormation replaces a parameter when its
44+
# Name changes, and UpdateReplacePolicy was Retain, every version bump orphaned the
45+
# previous name. Deploying a version whose name had already been orphaned — after the
46+
# v1.1.0 revert, or on any re-release — then failed with AlreadyExists and wedged
47+
# every merge to main. Existing per-version parameters are retained, and the layer's
48+
# Description still records the version, so `aws lambda list-layer-versions` maps a
49+
# version to its layer ARN.
5150

5251
Outputs:
5352
LambdaAdapterLayerX86Arn:

0 commit comments

Comments
 (0)