Repository navigation
Give every sample its own name prefix, and exit with an error when a step fails - #148
Conversation
run-samples.sh runs the samples one after another on one emulator, and after each sample it deletes every resource group with --no-wait. 60 of its 81 entries then reuse the previous entry's group (local-rg, local-aca-rg), so they write into a group that may still be being deleted: Azure refuses that with 409 ResourceGroupBeingDeleted, the emulator will too (SMF-998), and today the emulator accepts it and leaves the new resources behind once the group is gone (18 Terraform entries already fail on azurerm's existence check because of that).
The runner now exports its own PREFIX for every entry: the letter l and four random lowercase letters, never the previous entry's, so every group and resource name differs from the previous sample's and nothing waits for a delete. The prefix has the length and characters of the default "local", so no name changes length.
Every sample builds its names from PREFIX: the 27 scripts that hardcoded PREFIX='local' now read PREFIX="${PREFIX:-local}" like the other 89, and the five deploy scripts whose template took the prefix from its parameter file or variable default (url-shortener and eventhubs Bicep, eventhubs-eventgrid Bicep, eventhubs and eventhubs-eventgrid Terraform) pass it explicitly. Running a sample by hand still uses local.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FvNuJJpEr2yMWrV5cbJi2Z
The samples runner and the samples CI trust each entry's exit status, but several scripts could end with status 0 after a failed step: - 146 failure branches in 39 scripts ended with a bare exit, which returns the status of the echo before it, 0. They now exit 1. - web-app-cosmosdb-nosql-api (Python and .NET) checked none of its writes after the resource group, and its two export VAR=$(az ...) lines hid any failure of the command. Every az call, the zip and the deploy now stop the script with a message naming the failed step. - container-apps-blob-storage (Terraform and Bicep) did not check the registry create, its login server and admin credentials, the image tag or the docker login; the Terraform deploy also ignored the resource group create, terraform init, terraform plan and its outputs, and swallowed every failure of the resource group import with || true. Each now stops the script with a message; the import is skipped when the group is already in the state (a re-run), which is the only failure the || true meant to tolerate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FvNuJJpEr2yMWrV5cbJi2Z
There was a problem hiding this comment.
🟡 Changes recommended
Prefix handling can trigger destructive Terraform replacements and mix credentials between deployments, while some sample tests can fail or target the wrong resources.
5 open issues
What changed in this PR
This PR improves reliability when running Azure samples sequentially on a shared emulator by varying resource-name prefixes and making deployment failures return nonzero exit codes.
Changes:
- Generates a five-letter prefix per runner entry and propagates it through deployment, validation, and cleanup scripts.
- Replaces bare failure exits with
exit 1across sample deployments. - Adds explicit failure checks to Cosmos DB NoSQL and Container Apps deployment steps.
| File | Description |
|---|---|
samples/web-app-sql-database/python/scripts/deploy.sh |
Returns failure on SQL server creation errors. |
samples/web-app-sql-database/python/bicep/deploy.sh |
Returns failure on setup and validation errors. |
samples/web-app-sql-database/dotnet/scripts/deploy.sh |
Returns failure on SQL server creation errors. |
samples/web-app-sql-database/dotnet/bicep/deploy.sh |
Returns failure on setup and validation errors. |
samples/web-app-postgresql-flexible-server/python/scripts/deploy.sh |
Returns failure on networking setup errors. |
samples/web-app-postgresql-flexible-server/python/bicep/deploy.sh |
Returns failure on setup and validation errors. |
samples/web-app-postgresql-flexible-server/dotnet/scripts/deploy.sh |
Returns failure on networking setup errors. |
samples/web-app-postgresql-flexible-server/dotnet/bicep/deploy.sh |
Returns failure on setup and validation errors. |
samples/web-app-mysql-flexible-server/python/scripts/deploy.sh |
Returns failure on networking setup errors. |
samples/web-app-mysql-flexible-server/python/bicep/deploy.sh |
Returns failure on setup and validation errors. |
samples/web-app-mysql-flexible-server/dotnet/scripts/deploy.sh |
Returns failure on networking setup errors. |
samples/web-app-mysql-flexible-server/dotnet/bicep/deploy.sh |
Returns failure on setup and validation errors. |
samples/web-app-managed-identity/python/scripts/user-assigned.sh |
Returns failure on group and role-assignment errors. |
samples/web-app-managed-identity/python/scripts/system-assigned.sh |
Returns failure on group and role-assignment errors. |
samples/web-app-managed-identity/python/scripts/cli.sh |
Returns failure on resource-group creation errors. |
samples/web-app-managed-identity/python/scripts/api.sh |
Returns failure on resource-group creation errors. |
samples/web-app-managed-identity/python/bicep/deploy.sh |
Returns failure on setup and validation errors. |
samples/web-app-managed-identity/dotnet/scripts/user-assigned.sh |
Returns failure on group and role-assignment errors. |
samples/web-app-managed-identity/dotnet/scripts/system-assigned.sh |
Returns failure on group and role-assignment errors. |
samples/web-app-managed-identity/dotnet/scripts/cli.sh |
Returns failure on resource-group creation errors. |
samples/web-app-managed-identity/dotnet/scripts/api.sh |
Returns failure on resource-group creation errors. |
samples/web-app-managed-identity/dotnet/bicep/deploy.sh |
Returns failure on setup and validation errors. |
samples/web-app-custom-image/python/scripts/deploy.sh |
Returns failure on private-network setup errors. |
samples/web-app-custom-image/python/bicep/deploy.sh |
Returns failure on group and template-validation errors. |
samples/web-app-custom-image/dotnet/scripts/deploy.sh |
Returns failure on private-network setup errors. |
samples/web-app-custom-image/dotnet/bicep/deploy.sh |
Returns failure on group and template-validation errors. |
samples/web-app-cosmosdb-nosql-api/python/scripts/deploy.sh |
Checks provisioning, configuration, packaging, and deployment failures. |
samples/web-app-cosmosdb-nosql-api/dotnet/scripts/deploy.sh |
Checks provisioning, configuration, packaging, and deployment failures. |
samples/web-app-cosmosdb-mongodb-api/python/scripts/deploy.sh |
Returns failure on networking setup errors. |
samples/web-app-cosmosdb-mongodb-api/python/bicep/deploy.sh |
Returns failure on setup and validation errors. |
samples/web-app-cosmosdb-mongodb-api/dotnet/scripts/deploy.sh |
Returns failure on networking setup errors. |
samples/web-app-cosmosdb-mongodb-api/dotnet/bicep/deploy.sh |
Returns failure on setup and validation errors. |
samples/url-shortener/python/terraform/deploy.sh |
Honors the supplied prefix. |
samples/url-shortener/python/scripts/validate.sh |
Uses the supplied prefix for validation. |
samples/url-shortener/python/scripts/deploy.sh |
Honors the supplied prefix. |
samples/url-shortener/python/scripts/call-web-app.sh |
Targets the supplied prefix's web app. |
samples/url-shortener/python/bicep/deploy.sh |
Passes the prefix to validation and deployment. |
samples/servicebus/java/terraform/deploy.sh |
Honors the supplied prefix. |
samples/servicebus/java/scripts/validate.sh |
Uses the supplied prefix for validation. |
samples/servicebus/java/scripts/deploy.sh |
Honors the supplied prefix. |
samples/servicebus/java/bicep/deploy.sh |
Honors the prefix and returns failure on errors. |
samples/function-app-storage-http/dotnet/bicep/deploy.sh |
Returns failure on setup and validation errors. |
samples/function-app-service-bus/dotnet/scripts/deploy.sh |
Returns failure on provisioning and permission errors. |
samples/function-app-service-bus/dotnet/bicep/deploy.sh |
Returns failure on setup and validation errors. |
samples/function-app-managed-identity/python/scripts/user-managed-identity.sh |
Returns failure on group and role-assignment errors. |
samples/function-app-managed-identity/python/scripts/system-managed-identity.sh |
Returns failure on group and role-assignment errors. |
samples/function-app-managed-identity/python/bicep/deploy.sh |
Returns failure on setup and validation errors. |
samples/eventhubs/python/terraform/deploy.sh |
Passes the prefix to plans and re-apply. |
samples/eventhubs/python/scripts/validate.sh |
Uses the supplied prefix for validation. |
samples/eventhubs/python/scripts/deploy.sh |
Honors the supplied prefix. |
samples/eventhubs/python/scripts/cleanup.sh |
Uses the supplied prefix for cleanup. |
samples/eventhubs/python/bicep/deploy.sh |
Passes the prefix to validation and deployment. |
samples/eventhubs-eventgrid/python/terraform/deploy.sh |
Passes the prefix to plans and re-apply. |
samples/eventhubs-eventgrid/python/scripts/validate.sh |
Uses the supplied prefix for validation. |
samples/eventhubs-eventgrid/python/scripts/deploy.sh |
Honors the supplied prefix. |
samples/eventhubs-eventgrid/python/scripts/cleanup.sh |
Uses the supplied prefix for cleanup. |
samples/eventhubs-eventgrid/python/bicep/deploy.sh |
Passes the prefix to validation and deployment. |
samples/container-apps-blob-storage/python/terraform/deploy.sh |
Honors the prefix; checks registry, image, and Terraform operations. |
samples/container-apps-blob-storage/python/scripts/validate.sh |
Uses the supplied prefix for validation. |
samples/container-apps-blob-storage/python/scripts/deploy.sh |
Honors the supplied prefix. |
samples/container-apps-blob-storage/python/scripts/cleanup.sh |
Uses the supplied prefix for cleanup. |
samples/container-apps-blob-storage/python/bicep/deploy.sh |
Honors the prefix and checks registry and image operations. |
samples/aci-blob-storage/python/terraform/deploy.sh |
Honors the supplied prefix. |
samples/aci-blob-storage/python/scripts/validate.sh |
Uses the supplied prefix for validation. |
samples/aci-blob-storage/python/scripts/deploy.sh |
Honors the supplied prefix. |
samples/aci-blob-storage/python/scripts/cleanup.sh |
Uses the supplied prefix for cleanup. |
samples/aci-blob-storage/python/bicep/deploy.sh |
Honors the prefix and returns failure on errors. |
run-samples.sh |
Exports a random prefix different from the previous entry's. |
Review effort: Balanced
The checks added to the Cosmos DB NoSQL and Container Apps scripts used a pattern these scripts do not use (if ! cmd). They now follow the samples' own: the command, then if [[ $? == 0 ]] with a success message, else a "Failed to ..." message naming the resource in brackets and exit 1; a captured value is tested with if [[ -n $VAR ]], and a Docker or Terraform step with if [[ $? != 0 ]] as the same file already tests its build and apply. The Terraform outputs are read as before: the apply that produces them is checked, and principal_id is empty by design without a managed identity. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FvNuJJpEr2yMWrV5cbJi2Z
…script samples/function-app-storage-http/dotnet/scripts/validate.sh wrote local-rg, local-func-test and localstoragetest out literally, so with the runner's per-sample prefix it checked resources that do not exist (the CI run of this PR failed there). It now builds them from PREFIX and SUFFIX as deploy.sh does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FvNuJJpEr2yMWrV5cbJi2Z
…IX is set
The runner gives every sample its own prefix and deletes the groups of the sample before without waiting, so the only web or function app in the subscription can be two for a while. With PREFIX set, the call scripts now count and pick the apps of ${PREFIX}-rg, the group every one of these samples deploys into; without it they look in the whole subscription, as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FvNuJJpEr2yMWrV5cbJi2Z
…n PREFIX is set Defaulting PREFIX to local and always passing -var prefix overrode a prefix set in terraform.tfvars or TF_VAR_prefix, so a rerun could replace a customized deployment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FvNuJJpEr2yMWrV5cbJi2Z
Deployments under different prefixes shared scripts/.last_deploy.env, so a rerun of one could read another's PostgreSQL password and host. The CLI, Bicep and Terraform deploy scripts and the validation script now use scripts/.last_deploy.<prefix>.env. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FvNuJJpEr2yMWrV5cbJi2Z
… group Run under another PREFIX next to the state of a previous run, the apply would replace that run's resource group and delete its resources. The two scripts that pre-create the group for the image push now stop first, naming the group the state tracks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FvNuJJpEr2yMWrV5cbJi2Z
The check ran before RESOURCE_GROUP_NAME was assigned, so any state left by a previous run, under the same PREFIX too, stopped the deployment. It now runs right after the names are set, before anything is created. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FvNuJJpEr2yMWrV5cbJi2Z
paolosalvatori
left a comment
There was a problem hiding this comment.
1. Rules applied
localstack-pro-azure/CLAUDE.md.claude/rules/azure/common/:coding-style.md,hooks.md,patterns.md,security.md,testing.md.claude/rules/azure/python/:cloud-pipeline.md,coding-style.md,hooks.md,patterns.md,security.md,testing.md.claude/rules/azure/scripts/:coding-style.md,hooks.md,patterns.md,security.md,testing.md. These are path-scoped tolocalstack-pro-azure/**/*.shand*.bats, so they do not bind this repository. Its scripts follow their own style: the command, a blank line, thenif [[ $? == 0 ]]with a success message, or a failure message andexit 1, and noset -e.- No Bicep, Terraform or emulator rule applies: the PR changes no
.bicep,.tfor emulator code.
2. Existing comments
Copilot's five findings were all answered and resolved in this round: the Terraform state of another run, the Terraform prefix override, the URL shortener's shared state file, the call scripts' subscription-wide app lookup, and the function-app validation names.
3. Findings
samples/container-apps-blob-storage/python/terraform/deploy.sh, samples/aci-blob-storage/python/terraform/deploy.sh
HIGH | state check before the names | Any existing Terraform state stopped the deployment
Description: The check that stops a deployment whose state tracks another run's resource group ran before RESOURCE_GROUP_NAME was assigned. It compared the state's group with an empty name, so a manual rerun under the same PREFIX stopped too. CI never hit it, because the runner deletes the Terraform state before every entry. Fixed in 3d7c253, which moves the check after the name assignments, before anything is created. Run from the scripts' own first lines with a stubbed terraform, it now goes on for the same group, stops for another run's group, and goes on with no state. The previous version stopped for the same group.
Rules applied: General best practice (a check must read the value it compares after it is set).
Before:
# Stop if the Terraform state of a previous run tracks another resource group ...
STATE_RESOURCE_GROUP_NAME=$(terraform state show ...)
if [[ -n $STATE_RESOURCE_GROUP_NAME && $STATE_RESOURCE_GROUP_NAME != "$RESOURCE_GROUP_NAME" ]]; then ...
# Create resource group and ACR first so we can push the image
RESOURCE_GROUP_NAME="${PREFIX}-aca-rg"After:
# Create resource group and ACR first so we can push the image
RESOURCE_GROUP_NAME="${PREFIX}-aca-rg"
ACR_NAME="${PREFIX}acaacr${SUFFIX}"
# Stop if the Terraform state of a previous run tracks another resource group ...
STATE_RESOURCE_GROUP_NAME=$(terraform state show ...)
if [[ -n $STATE_RESOURCE_GROUP_NAME && $STATE_RESOURCE_GROUP_NAME != "$RESOURCE_GROUP_NAME" ]]; then ...4. Clean files
The other 83 scripts and the 4 README files have no material findings. What was checked:
bash -non all 85 changed scripts: no syntax errors.- ShellCheck at warning level on every changed line, without SC2181 and SC2086, which are this repository's own style: no warnings.
- All 183 new
exit 1lines sit in failure branches. The two without an error message are the deliberate stop of the state check. set_sample_name_prefixinrun-samples.shbuildslplus four random lowercase letters: five lowercase letters likelocal, so every name keeps its length and leading letter, and never the previous entry's prefix.- The three Bicep scripts name their own resources from
PREFIXand pass the same value to the template, so script and template always agree. - No file still reads the old
scripts/.last_deploy.env.
5. Verdict
Approve. The only HIGH finding is fixed in 3d7c253. Posted as a comment, because GitHub does not accept an approval on your own pull request.
|
Review round summary:
|


Motivation
run-samples.shruns the samples one after another on one emulator, and after each sample it deletes every resource group with--no-waitand sleeps 2 seconds. 60 of its 81 entries then reuse the previous entry's group (local-rg,local-aca-rg), so they write into a group that may still be being deleted.Azure refuses such writes with 409
ResourceGroupBeingDeleted, the emulator is about to do the same (SMF-998), and today the emulator accepts them and leaves the new resources behind once the group is gone: 18 Terraform entries already fail on azurerm's existence check in a full local run because of it.CI is not affected (each job runs one entry on a fresh emulator), but full local runs are.
While checking those entries, it turned out that several scripts can end with status 0 after a failed step, so the runner and CI report success for a sample that did not deploy.
Changes
run-samples.shexports its ownPREFIXfor every entry: the letterland four random lowercase letters, never the previous entry's. Every group and resource name then differs from the previous sample's, so nothing waits for a delete and neither CI nor a local run gets slower. The prefix has the length and the characters of the defaultlocal, so no Azure name changes length. Running a sample by hand still useslocal.PREFIX='local'now readPREFIX="${PREFIX:-local}", like the other 89.localfrom its parameter file or variable default:url-shortener,eventhubsandeventhubs-eventgridBicep, andeventhubsandeventhubs-eventgridTerraform. They now pass it, on every plan and apply for Terraform, where it goes out only whenPREFIXis set so a prefix fromterraform.tfvarsorTF_VAR_prefixstill applies otherwise.PREFIXset, the 16 call scripts the runner uses without an app name look for the only app in${PREFIX}-rginstead of the whole subscription, where the previous entry's group can still be being deleted.scripts/.last_deploy.<prefix>.env, one file per prefix.container-apps-blob-storageandaci-blob-storageTerraform scripts stop before creating anything when the Terraform state of a previous run tracks another resource group, which the apply would otherwise replace. (api-management-function-appBicep already reads it withreadEnvironmentVariable('PREFIX', 'local').)exit, which returns the status of theechobefore it, 0. They nowexit 1.if [[ $? == 0 ]]with a success message, else a "Failed to ..." message naming the resource in brackets andexit 1; captured values are tested withif [[ -n $VAR ]].web-app-cosmosdb-nosql-api(Python and .NET) checked none of its writes after the resource group, andexport VAR=$(az ...)hid any failure of the command. Everyazcall, the zip and the deploy now stop the script with a message naming the failed step.container-apps-blob-storage(Terraform and Bicep) did not check the registry create, its login server and admin credentials, the image tag or thedocker login. The Terraform deploy also ignored the resource group create,terraform initandterraform plan, and swallowed every failure of the group import with|| true. Each now stops the script with a message; the import is skipped when the group is already in the state (a re-run), the only failure the|| truemeant to tolerate.Tests
bash -non all 68 changed scripts: no errors.PREFIXin the environment rather than a literal, as in the 89 scripts that already read it that way.set -euo pipefail: every value matches^l[a-z]{4}$, no two in a row are equal, and the value reaches child processes.run-samples.sh --list, which the CI uses to build its matrix: identical tomain.Related
Fixes SMF-999
Fixes SMF-1000
🤖 Generated with Claude Code
https://claude.ai/code/session_01FvNuJJpEr2yMWrV5cbJi2Z