Add a .NET 10 version of every AKS Vacation Planner sample - #30
Conversation
Each samples/web-app-<store>/ now holds its Python implementation under python/ (README, images, scripts, src) to make room for a .NET twin under dotnet/. Relative links that reached outside a sample gained one level, the root README table points at python/README.md, every Python README links to its upcoming .NET sibling, .gitignore learns the .NET build outputs and the files sample scripts drop into scripts/, and a .gitattributes pins LF line endings for scripts, manifests and .NET sources. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Every Python Vacation Planner gains a GET /health route that answers
{"status": "ok"} when its backing store is reachable (container exists,
directory writable, MongoDB ping, Cosmos container read, SELECT 1) and
503 {"status": "unavailable"} otherwise. The liveness and readiness
probes of all nine Deployments call it instead of rendering the full
page on every probe. Verified locally with the file-storage image: 200
on a writable mount, 503 on a missing one.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ASP.NET Core Razor Pages port of the Vacation Planner backed by Azure Blob Storage, under samples/web-app-blob-storage/dotnet, with the same environment variables, Kubernetes names, flash wording and blob naming as the Python version and a -dotnet image name. Deletes are keyed by blob name, the Data Protection key ring is derived from SECRET_KEY so the three replicas validate each other's antiforgery tokens and flash cookies, GET /health probes the container, and the client honours the connection string's explicit BlobEndpoint, which the .NET parser otherwise rejects when the LocalStack EndpointSuffix carries a port. Verified on the emulator's AKS: rollout, port-forward and in-cluster smoke tests, then the Python image rolled over the same Deployment. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Same ASP.NET Core Vacation Planner as web-app-blob-storage, authenticating to Blob Storage with Microsoft Entra Workload ID through DefaultAzureCredential: the pod's service account carries the federated identity, and the emulator's webhook injects the token file, the authority host and the trust bundle (SSL_CERT_FILE), so the app needs no identity-specific code. Verified on the emulator's AKS: rollout, port-forward and in-cluster smoke tests, then the Python image rolled over the same Deployment. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ASP.NET Core Vacation Planner storing one text file per activity on an Azure Files share mounted by the CSI driver, with no Azure SDK, under samples/web-app-file-storage/dotnet. It keeps the Python behaviour: files named yyyy-MM-dd-HH-mm-ss-activity.txt, listed by name, deletes posted by file name with the same path-traversal guard, failure flashes when the share rejects a write, the serving pod shown in the header, and the app user pinned to uid/gid 1000 (the runtime image's default ubuntu account, which owns 1000, is dropped first). Verified on the emulator's AKS with a static SMB share: seeded activities listed, rollout, port-forward and in-cluster smoke tests, then the Python image rolled over the same Deployment. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ASP.NET Core Vacation Planner storing activities as {_id, username,
activity, timestamp} documents in an Azure Cosmos DB for MongoDB
collection through MongoDB.Driver, under
samples/web-app-cosmosdb-mongodb-api/dotnet. Same connection string,
database, collection and index setup as the Python version, md5 ids,
deletes keyed by document id, and the update flash only when the document
changed. Verified on the emulator's AKS: rollout, port-forward and
in-cluster smoke tests, then the Python image rolled over the same
Deployment.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ASP.NET Core Vacation Planner storing activities as {id, username,
activity, timestamp} items in an Azure Cosmos DB for NoSQL container
partitioned by /username, through Microsoft.Azure.Cosmos in Gateway mode,
under samples/web-app-cosmosdb-nosql-api/dotnet. Same endpoint, key,
database and container variables as the Python version, md5 ids and
deletes keyed by item id. Against the emulator the LocalStack root CA is
mounted from the localstack-ca ConfigMap and exposed through SSL_CERT_FILE,
the .NET counterpart of REQUESTS_CA_BUNDLE. Verified on the emulator's
AKS: rollout, port-forward and in-cluster smoke tests.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The Python apps write one access log line per request, because their gunicorn command passes --access-logfile -, plus a line per store operation and a line per activity added, updated or deleted. The .NET ports only logged startup and error paths, so `kubectl logs` showed almost nothing while the app was serving. Add the request-log middleware, the per-operation store lines and the per-action page lines, with the wording of the .NET samples for Azure App Services, and configure the console writer to emit single timestamped lines like the Python logging format does. Document the output in every sample README, both versions. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ASP.NET Core Razor Pages port of the Python Flask sample, with the same behaviour, the same environment variables and the same deployment artifacts: only the container image name carries the -dotnet suffix, so both versions roll over the same Deployment, Service, ConfigMap and Secret. Npgsql over the flexible server with SslMode=Prefer, the 30 x 2s startup retry of the Python version, activities keyed by their store id, GET /health behind both probes, and the Data Protection key ring derived from SECRET_KEY so the three replicas validate each other's antiforgery tokens and flashes. Validated on the LocalStack AKS emulator: 3/3 pods Ready through the /health probes, add/list/update/delete through a port-forward and from inside the cluster across all replicas, and the expected request, store and page log lines. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ASP.NET Core Razor Pages port of the Python Flask sample, with the same behaviour, environment variables and deployment artifacts; only the container image name carries the -dotnet suffix, so both versions roll over the same Deployment, Service, ConfigMap and Secret. MySqlConnector with SslMode=Required when MYSQL_SSL=true and, as in PyMySQL, UseAffectedRows=true so an update that changes nothing reports no change and flashes nothing. Same 30 x 2s startup retry, activities keyed by their store id, GET /health behind both probes, and the Data Protection key ring derived from SECRET_KEY so all three replicas share antiforgery tokens and flashes. Validated on the LocalStack AKS emulator: 3/3 pods Ready through the /health probes, add/list/update/delete through a port-forward and from inside the cluster across all replicas, identical no-op-update behaviour to the Python version, and the expected request, store and page log lines. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ASP.NET Core Razor Pages port of the Python Flask sample, with the same
behaviour, environment variables and deployment artifacts; only the container
image name carries the -dotnet suffix, so both versions roll over the same
Deployment, Service, ConfigMap and Secret. FLASK_SECRET_KEY is renamed to
SECRET_KEY in the .NET copies of the Secret and the Deployment, the only
deliberate contract change, because the name is language-specific.
Microsoft.Data.SqlClient with Encrypt=Mandatory and TrustServerCertificate,
an optional Entra token through SqlConnection.AccessToken, no DDL (the table
comes from 01-deploy-resources.sh) and no startup retry, matching the Python
version. Activities are addressed by their UNIQUEIDENTIFIER, /update/{id} is
kept for route parity, GET /health sits behind both probes, and the Data
Protection key ring is derived from SECRET_KEY so the replicas share
antiforgery tokens and flashes.
Validated on the LocalStack AKS emulator: 3/3 pods Ready through the /health
probes, add/list/update/delete through a port-forward and from inside the
cluster across all replicas, /update/{id} redirecting to the edit form, and
the expected request, store and page log lines.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ASP.NET Core Razor Pages port of the Python Flask sample, with the same behaviour, environment variables and deployment artifacts; only the container image name carries the -dotnet suffix, so both versions roll over the same Deployment, Service, ConfigMap and Secret, and both talk to the same PostgreSQL StatefulSet running in the cluster. Npgsql with SslMode=Prefer, which falls back to plaintext against the in-cluster server, the 30 x 2s startup retry of the Python version, activities keyed by their store id, GET /health behind both probes, and the Data Protection key ring derived from SECRET_KEY so the replicas share antiforgery tokens and flashes. 05-deploy-app.sh now waits for the rollout and prints the port-forward hint, like the other .NET samples. Validated on the LocalStack AKS emulator against the 3-replica StatefulSet: 3/3 app pods Ready through the /health probes, add/list/update/delete through a port-forward and from inside the cluster across all replicas, and the expected request, store and page log lines. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Samples table now points at both implementations, the intro explains that they behave identically and share the Kubernetes names (so a sample can be switched from one to the other in place), the layout tree shows the python/ and dotnet/ subfolders, and the prerequisites mention the optional .NET SDK, needed only to build outside Docker. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
web-app-managed-identity used the namespace, Deployment, Service, ConfigMap, Secret and image of web-app-blob-storage, and web-app-in-cluster-postgresql used those of web-app-postgresql-flexible-server, so nine samples shared seven namespaces and seven image repositories. Two samples could not run at the same time, and whichever was pushed last overwrote the other's image in the registry under the same tag, so the first sample's pods then pulled the wrong app. Rename the second sample of each pair (the canonical one keeps its name): web-app-managed-identity vacation-planner-blob -> vacation-planner-identity web-app-in-cluster-postgresql vacation-planner-postgres -> vacation-planner-postgres-in-cluster in both the Python and the .NET version, covering the namespace, Deployment, Service, ConfigMap, Secret, ServiceAccount, Gateway/HTTPRoute/Issuer, StatefulSet references, image name and the README commands. Renaming the namespace also broke the workload identity of the managed-identity sample: the federated identity credential's subject embeds the namespace and the service account, and 05-deploy-app.sh only ever created the credential when it was missing, leaving a stale subject behind. It now compares the subject and recreates the credential when it no longer matches, so the rename is safe on a cluster that already ran the old version. Validated on the LocalStack AKS emulator: all four affected samples in both languages (3/3 pods Ready through /health, add/list/update/delete through a port-forward and from inside the cluster), both pairs running side by side at the same time from their own images, and a from-scratch deployment of managed-identity (namespace and credential deleted first) coming up with zero restarts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Seven of the nine Python apps deleted the activity at a position in the rendered page (POST /delete/<index>), resolved against a module-level list that each replica fills on its own GET. With three replicas the delete lands on a replica whose list is stale, so it deletes a different activity than the one the user clicked. Caught on web-app-in-cluster-postgresql: the cross-replica run left the activity it had asked to delete in the database and removed one of the seeded rows instead. Every delete now addresses the activity by its store id, which the page already carries in the row's data-id attribute: the blob or file name for the storage samples, the document id for Cosmos DB, the row id for PostgreSQL, MySQL and SQL Database. web-app-sql-database's /update/<id> route reads the current text from the database instead of the in-process list for the same reason. Two more bugs found while testing: - The blob name now arrives from a form field, so blob-storage and managed-identity check its shape (yyyy-MM-dd-HH-mm-ss-activity.txt) before a delete or an in-place update reaches the container, as file-storage does for the file share. - Deleting an activity that another replica had already deleted answered HTTP 500 in web-app-cosmosdb-nosql-api and logged an error while listing the share in web-app-file-storage. Both now treat "already gone" as done and converge. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
05-deploy-app.sh generated a new SECRET_KEY on every run and wrote it to the Secret. The pods that are already running keep the value they started with, so after a re-run the replicas sign with different keys and sessions, flash messages and antiforgery tokens break until every pod has restarted. The script now reuses the key already stored in the Secret and only generates one when there is none. web-app-sql-database's 01-deploy-resources.sh re-inserted its nine seed rows on every run, so the table filled up with duplicates. The insert is now guarded by IF NOT EXISTS. web-app-in-cluster-postgresql's 01-deploy-resources.sh pointed at a 06-create-test-data.sh that does not exist; 05-deploy-app.sh deploys the StatefulSet and seeds it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The blob name arrives from a form field, so blob-storage and managed-identity check its shape (yyyy-MM-dd-HH-mm-ss-activity.txt) before an in-place update or a delete reaches the container, the same guard file-storage already applies to the file share. Deleting an item another replica had already deleted reported "nothing to delete" in web-app-cosmosdb-nosql-api, so the user saw no confirmation for work that was done. Already gone now counts as deleted, as in every other store. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The .NET file-storage health check proves the mounted share is writable by writing a dot file and deleting it, and it named that file after the process id. Every container runs the app as PID 1, so all three replicas used the same /data/.write-probe-1 on the same share: one replica deleted the probe while another was writing it, and the write failed with FileNotFoundException. The pod then failed its liveness probe with 503 and restarted in a loop, while the share itself was perfectly healthy. The probe name now carries the pod name and a GUID. The Python version is unaffected: its health check uses os.access instead of writing a file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rebuilding and pushing the image keeps the tag :v1, so the pod template that 05-deploy-app.sh applies is unchanged, kubectl apply reports no change and the running pods keep serving the image they started with. A rebuilt image only reached the cluster when the image name changed, which happens when switching between the Python and the .NET version but not when redeploying the same one. Both versions of every sample now restart the deployment after applying it, so the pods always end up on the image that was just pushed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Several security- and correctness-impacting issues were identified in the changed artifacts (hardcoded credentials, misconfigured cert-manager Gateway solver sectionName, and inconsistent secret key environment variable naming across implementations).
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR restructures each AKS Vacation Planner sample to include both python/ and dotnet/ implementations (targeting .NET 10), aiming for side-by-side parity in behavior, environment variables, deployment artifacts, health probing, and logging—while also fixing several cross-replica and redeploy bugs found during comparative testing.
Changes:
- Introduces a .NET 10 Razor Pages implementation for each sample alongside the existing Python version, plus
GET /healthand probe updates. - Updates Kubernetes/deploy scripts to reuse existing secrets (stable session/Data Protection) and to force pod rollouts when re-pushing the same image tag.
- Fixes correctness issues (notably id-based deletes) and improves operational reliability (health checks, seed guards, etc.).
File summaries
| File | Description |
|---|---|
| samples/web-app-sql-database/python/src/requirements.txt | Pin Python dependencies |
| samples/web-app-sql-database/python/src/gunicorn.conf.py | Gunicorn signal handling |
| samples/web-app-sql-database/python/scripts/service.yml | K8s Service manifest |
| samples/web-app-sql-database/python/scripts/secret.yml | K8s Secret manifest |
| samples/web-app-sql-database/python/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-sql-database/python/scripts/deployment.yml | K8s Deployment (health probes) |
| samples/web-app-sql-database/python/scripts/configmap.yml | K8s ConfigMap manifest |
| samples/web-app-sql-database/python/scripts/05-deploy-app.sh | Deploy: stable secret + rollout restart |
| samples/web-app-sql-database/python/scripts/04-push-docker-image.sh | Push image to ACR |
| samples/web-app-sql-database/python/scripts/03-run-docker-container.sh | Local docker run helper |
| samples/web-app-sql-database/python/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-sql-database/python/scripts/00-variables.sh | Shared variables (incl. creds) |
| samples/web-app-sql-database/dotnet/src/VacationPlanner.csproj | .NET 10 project file |
| samples/web-app-sql-database/dotnet/src/Services/StoreInitializer.cs | Startup store initialization |
| samples/web-app-sql-database/dotnet/src/Services/IActivityStore.cs | Store interface contract |
| samples/web-app-sql-database/dotnet/src/Pages/Update.cshtml.cs | Update redirect behavior |
| samples/web-app-sql-database/dotnet/src/Pages/Update.cshtml | Update route page |
| samples/web-app-sql-database/dotnet/src/Pages/Delete.cshtml.cs | Delete handler by id |
| samples/web-app-sql-database/dotnet/src/Pages/Delete.cshtml | Delete route page |
| samples/web-app-sql-database/dotnet/src/Pages/_ViewImports.cshtml | Razor imports |
| samples/web-app-sql-database/dotnet/src/Models/Activity.cs | Activity model |
| samples/web-app-sql-database/dotnet/src/appsettings.json | Console logging config |
| samples/web-app-sql-database/dotnet/src/.dockerignore | Docker ignore outputs |
| samples/web-app-sql-database/dotnet/scripts/service.yml | K8s Service manifest |
| samples/web-app-sql-database/dotnet/scripts/secret.yml | K8s Secret manifest |
| samples/web-app-sql-database/dotnet/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-sql-database/dotnet/scripts/Dockerfile | .NET container build |
| samples/web-app-sql-database/dotnet/scripts/configmap.yml | K8s ConfigMap manifest |
| samples/web-app-sql-database/dotnet/scripts/04-push-docker-image.sh | Push image to ACR |
| samples/web-app-sql-database/dotnet/scripts/03-run-docker-container.sh | Local docker run helper |
| samples/web-app-sql-database/dotnet/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-sql-database/dotnet/scripts/01-deploy-resources.sh | SQL seed guard (IF NOT EXISTS) |
| samples/web-app-sql-database/dotnet/scripts/00-variables.sh | Shared variables (incl. creds) |
| samples/web-app-postgresql-flexible-server/python/src/requirements.txt | Pin Python dependencies |
| samples/web-app-postgresql-flexible-server/python/src/gunicorn.conf.py | Gunicorn signal handling |
| samples/web-app-postgresql-flexible-server/python/src/database.py | Add connectivity ping |
| samples/web-app-postgresql-flexible-server/python/scripts/service.yml | K8s Service manifest |
| samples/web-app-postgresql-flexible-server/python/scripts/secret.yml | K8s Secret manifest |
| samples/web-app-postgresql-flexible-server/python/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-postgresql-flexible-server/python/scripts/deployment.yml | K8s Deployment (health probes) |
| samples/web-app-postgresql-flexible-server/python/scripts/configmap.yml | K8s ConfigMap manifest |
| samples/web-app-postgresql-flexible-server/python/scripts/05-deploy-app.sh | Deploy: stable secret + rollout restart |
| samples/web-app-postgresql-flexible-server/python/scripts/04-push-docker-image.sh | Push image to ACR |
| samples/web-app-postgresql-flexible-server/python/scripts/03-run-docker-container.sh | Local docker run helper |
| samples/web-app-postgresql-flexible-server/python/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-postgresql-flexible-server/dotnet/src/VacationPlanner.csproj | .NET 10 project file |
| samples/web-app-postgresql-flexible-server/dotnet/src/Services/StoreInitializer.cs | Startup store initialization |
| samples/web-app-postgresql-flexible-server/dotnet/src/Services/PostgresOptions.cs | Env var parsing/validation |
| samples/web-app-postgresql-flexible-server/dotnet/src/Services/IActivityStore.cs | Store interface contract |
| samples/web-app-postgresql-flexible-server/dotnet/src/Services/ActivityId.cs | Shared ID scheme |
| samples/web-app-postgresql-flexible-server/dotnet/src/Pages/Delete.cshtml.cs | Delete handler by id |
| samples/web-app-postgresql-flexible-server/dotnet/src/Pages/Delete.cshtml | Delete route page |
| samples/web-app-postgresql-flexible-server/dotnet/src/Pages/_ViewImports.cshtml | Razor imports |
| samples/web-app-postgresql-flexible-server/dotnet/src/Models/Activity.cs | Activity model |
| samples/web-app-postgresql-flexible-server/dotnet/src/appsettings.json | Console logging config |
| samples/web-app-postgresql-flexible-server/dotnet/src/.dockerignore | Docker ignore outputs |
| samples/web-app-postgresql-flexible-server/dotnet/scripts/service.yml | K8s Service manifest |
| samples/web-app-postgresql-flexible-server/dotnet/scripts/secret.yml | K8s Secret manifest |
| samples/web-app-postgresql-flexible-server/dotnet/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-postgresql-flexible-server/dotnet/scripts/Dockerfile | .NET container build |
| samples/web-app-postgresql-flexible-server/dotnet/scripts/deployment.yml | K8s Deployment (image + health probes) |
| samples/web-app-postgresql-flexible-server/dotnet/scripts/configmap.yml | K8s ConfigMap manifest |
| samples/web-app-postgresql-flexible-server/dotnet/scripts/03-run-docker-container.sh | Local docker run helper |
| samples/web-app-postgresql-flexible-server/dotnet/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-mysql-flexible-server/python/src/requirements.txt | Pin Python dependencies |
| samples/web-app-mysql-flexible-server/python/src/gunicorn.conf.py | Gunicorn signal handling |
| samples/web-app-mysql-flexible-server/python/src/database.py | Add connectivity ping |
| samples/web-app-mysql-flexible-server/python/scripts/service.yml | K8s Service manifest |
| samples/web-app-mysql-flexible-server/python/scripts/secret.yml | K8s Secret manifest |
| samples/web-app-mysql-flexible-server/python/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-mysql-flexible-server/python/scripts/deployment.yml | K8s Deployment (health probes) |
| samples/web-app-mysql-flexible-server/python/scripts/configmap.yml | K8s ConfigMap manifest |
| samples/web-app-mysql-flexible-server/python/scripts/05-deploy-app.sh | Deploy: stable secret + rollout restart |
| samples/web-app-mysql-flexible-server/python/scripts/04-push-docker-image.sh | Push image to ACR |
| samples/web-app-mysql-flexible-server/python/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-mysql-flexible-server/dotnet/src/VacationPlanner.csproj | .NET 10 project file |
| samples/web-app-mysql-flexible-server/dotnet/src/Services/StoreInitializer.cs | Startup store initialization |
| samples/web-app-mysql-flexible-server/dotnet/src/Services/MySqlOptions.cs | Env var parsing/validation |
| samples/web-app-mysql-flexible-server/dotnet/src/Services/IActivityStore.cs | Store interface contract |
| samples/web-app-mysql-flexible-server/dotnet/src/Services/ActivityId.cs | Shared ID scheme |
| samples/web-app-mysql-flexible-server/dotnet/src/Pages/Delete.cshtml.cs | Delete handler by id |
| samples/web-app-mysql-flexible-server/dotnet/src/Pages/Delete.cshtml | Delete route page |
| samples/web-app-mysql-flexible-server/dotnet/src/Pages/_ViewImports.cshtml | Razor imports |
| samples/web-app-mysql-flexible-server/dotnet/src/Models/Activity.cs | Activity model |
| samples/web-app-mysql-flexible-server/dotnet/src/appsettings.json | Console logging config |
| samples/web-app-mysql-flexible-server/dotnet/src/.dockerignore | Docker ignore outputs |
| samples/web-app-mysql-flexible-server/dotnet/scripts/service.yml | K8s Service manifest |
| samples/web-app-mysql-flexible-server/dotnet/scripts/secret.yml | K8s Secret manifest |
| samples/web-app-mysql-flexible-server/dotnet/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-mysql-flexible-server/dotnet/scripts/Dockerfile | .NET container build |
| samples/web-app-mysql-flexible-server/dotnet/scripts/configmap.yml | K8s ConfigMap manifest |
| samples/web-app-mysql-flexible-server/dotnet/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-managed-identity/python/src/templates/index.html | Fix delete to use store id |
| samples/web-app-managed-identity/python/src/requirements.txt | Pin Python dependencies |
| samples/web-app-managed-identity/python/src/gunicorn.conf.py | Gunicorn signal handling |
| samples/web-app-managed-identity/python/scripts/service.yml | K8s Service manifest (renamed) |
| samples/web-app-managed-identity/python/scripts/secret.yml | K8s Secret manifest |
| samples/web-app-managed-identity/python/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-managed-identity/python/scripts/issuer.yml | cert-manager Issuer manifest |
| samples/web-app-managed-identity/python/scripts/httproute.yml | Gateway API HTTPRoute |
| samples/web-app-managed-identity/python/scripts/gateway.yml | Gateway API Gateway |
| samples/web-app-managed-identity/python/scripts/configmap.yml | K8s ConfigMap manifest |
| samples/web-app-managed-identity/python/scripts/04-push-docker-image.sh | Push image to ACR |
| samples/web-app-managed-identity/python/scripts/03-run-docker-container.sh | Local docker run helper |
| samples/web-app-managed-identity/python/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-managed-identity/python/scripts/00-variables.sh | Shared variables (renamed sample) |
| samples/web-app-managed-identity/dotnet/src/VacationPlanner.csproj | .NET 10 project file |
| samples/web-app-managed-identity/dotnet/src/Services/StoreInitializer.cs | Startup store initialization |
| samples/web-app-managed-identity/dotnet/src/Services/IActivityStore.cs | Store interface contract |
| samples/web-app-managed-identity/dotnet/src/Services/BlobStorageOptions.cs | Blob env var settings |
| samples/web-app-managed-identity/dotnet/src/Pages/Delete.cshtml.cs | Delete handler by id |
| samples/web-app-managed-identity/dotnet/src/Pages/Delete.cshtml | Delete route page |
| samples/web-app-managed-identity/dotnet/src/Pages/_ViewImports.cshtml | Razor imports |
| samples/web-app-managed-identity/dotnet/src/Models/Activity.cs | Activity model |
| samples/web-app-managed-identity/dotnet/src/appsettings.json | Console logging config |
| samples/web-app-managed-identity/dotnet/src/.dockerignore | Docker ignore outputs |
| samples/web-app-managed-identity/dotnet/scripts/service.yml | K8s Service manifest (renamed) |
| samples/web-app-managed-identity/dotnet/scripts/secret.yml | K8s Secret manifest |
| samples/web-app-managed-identity/dotnet/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-managed-identity/dotnet/scripts/issuer.yml | cert-manager Issuer manifest |
| samples/web-app-managed-identity/dotnet/scripts/httproute.yml | Gateway API HTTPRoute |
| samples/web-app-managed-identity/dotnet/scripts/gateway.yml | Gateway API Gateway |
| samples/web-app-managed-identity/dotnet/scripts/Dockerfile | .NET container build |
| samples/web-app-managed-identity/dotnet/scripts/configmap.yml | K8s ConfigMap manifest |
| samples/web-app-managed-identity/dotnet/scripts/04-push-docker-image.sh | Push image to ACR |
| samples/web-app-managed-identity/dotnet/scripts/03-run-docker-container.sh | Local docker run helper |
| samples/web-app-managed-identity/dotnet/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-managed-identity/dotnet/scripts/00-variables.sh | Shared variables (renamed sample) |
| samples/web-app-in-cluster-postgresql/python/src/templates/index.html | Fix delete to use store id |
| samples/web-app-in-cluster-postgresql/python/src/requirements.txt | Pin Python dependencies |
| samples/web-app-in-cluster-postgresql/python/src/gunicorn.conf.py | Gunicorn signal handling |
| samples/web-app-in-cluster-postgresql/python/src/database.py | Add connectivity ping |
| samples/web-app-in-cluster-postgresql/python/scripts/service.yml | K8s Service manifest (renamed) |
| samples/web-app-in-cluster-postgresql/python/scripts/secret.yml | K8s Secret/namespace rename |
| samples/web-app-in-cluster-postgresql/python/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-in-cluster-postgresql/python/scripts/configmap.yml | K8s ConfigMap manifest |
| samples/web-app-in-cluster-postgresql/python/scripts/05-deploy-app.sh | Deploy: stable secret + rollout restart |
| samples/web-app-in-cluster-postgresql/python/scripts/04-push-docker-image.sh | Push image to ACR |
| samples/web-app-in-cluster-postgresql/python/scripts/03-run-docker-container.sh | Local docker run helper |
| samples/web-app-in-cluster-postgresql/python/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-in-cluster-postgresql/python/scripts/00-variables.sh | Shared variables (renamed sample) |
| samples/web-app-in-cluster-postgresql/dotnet/src/VacationPlanner.csproj | .NET 10 project file |
| samples/web-app-in-cluster-postgresql/dotnet/src/Services/StoreInitializer.cs | Startup store initialization |
| samples/web-app-in-cluster-postgresql/dotnet/src/Services/PostgresOptions.cs | Env var parsing/validation |
| samples/web-app-in-cluster-postgresql/dotnet/src/Services/IActivityStore.cs | Store interface contract |
| samples/web-app-in-cluster-postgresql/dotnet/src/Services/ActivityId.cs | Shared ID scheme |
| samples/web-app-in-cluster-postgresql/dotnet/src/Pages/Delete.cshtml.cs | Delete handler by id |
| samples/web-app-in-cluster-postgresql/dotnet/src/Pages/Delete.cshtml | Delete route page |
| samples/web-app-in-cluster-postgresql/dotnet/src/Pages/_ViewImports.cshtml | Razor imports |
| samples/web-app-in-cluster-postgresql/dotnet/src/Models/Activity.cs | Activity model |
| samples/web-app-in-cluster-postgresql/dotnet/src/appsettings.json | Console logging config |
| samples/web-app-in-cluster-postgresql/dotnet/src/.dockerignore | Docker ignore outputs |
| samples/web-app-in-cluster-postgresql/dotnet/scripts/service.yml | K8s Service manifest (renamed) |
| samples/web-app-in-cluster-postgresql/dotnet/scripts/secret.yml | K8s Secret manifest |
| samples/web-app-in-cluster-postgresql/dotnet/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-in-cluster-postgresql/dotnet/scripts/Dockerfile | .NET container build |
| samples/web-app-in-cluster-postgresql/dotnet/scripts/configmap.yml | K8s ConfigMap manifest (renamed) |
| samples/web-app-in-cluster-postgresql/dotnet/scripts/03-run-docker-container.sh | Local docker run helper |
| samples/web-app-in-cluster-postgresql/dotnet/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-in-cluster-postgresql/dotnet/scripts/01-deploy-resources.sh | Docs update for in-cluster DB |
| samples/web-app-file-storage/python/src/requirements.txt | Pin Python dependencies |
| samples/web-app-file-storage/python/src/gunicorn.conf.py | Gunicorn signal handling |
| samples/web-app-file-storage/python/scripts/storageclass-nfs.yml | NFS StorageClass manifest |
| samples/web-app-file-storage/python/scripts/storage-secret.yml | CSI mount secret (SMB) |
| samples/web-app-file-storage/python/scripts/service.yml | K8s Service manifest |
| samples/web-app-file-storage/python/scripts/seed-configmap.yml | Seed activities ConfigMap |
| samples/web-app-file-storage/python/scripts/secret.yml | K8s Secret manifest |
| samples/web-app-file-storage/python/scripts/persistentvolumeclaim.yml | PVC manifest |
| samples/web-app-file-storage/python/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-file-storage/python/scripts/deployment.yml | Deployment probes -> /health |
| samples/web-app-file-storage/python/scripts/configmap.yml | App mount path config |
| samples/web-app-file-storage/python/scripts/05-deploy-app.sh | Deploy: stable secret + rollout restart |
| samples/web-app-file-storage/python/scripts/04-push-docker-image.sh | Push image to ACR |
| samples/web-app-file-storage/python/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-file-storage/dotnet/src/VacationPlanner.csproj | .NET 10 project file |
| samples/web-app-file-storage/dotnet/src/Services/StoreInitializer.cs | Startup store initialization |
| samples/web-app-file-storage/dotnet/src/Services/IActivityStore.cs | Store interface contract |
| samples/web-app-file-storage/dotnet/src/Services/FileStorageOptions.cs | File share settings |
| samples/web-app-file-storage/dotnet/src/Pages/Delete.cshtml.cs | Delete by filename/id |
| samples/web-app-file-storage/dotnet/src/Pages/Delete.cshtml | Delete route page |
| samples/web-app-file-storage/dotnet/src/Pages/_ViewImports.cshtml | Razor imports |
| samples/web-app-file-storage/dotnet/src/Models/Activity.cs | Activity model |
| samples/web-app-file-storage/dotnet/src/appsettings.json | Console logging config |
| samples/web-app-file-storage/dotnet/src/.dockerignore | Docker ignore outputs |
| samples/web-app-file-storage/dotnet/scripts/storageclass-nfs.yml | NFS StorageClass manifest |
| samples/web-app-file-storage/dotnet/scripts/storage-secret.yml | CSI mount secret (SMB) |
| samples/web-app-file-storage/dotnet/scripts/service.yml | K8s Service manifest |
| samples/web-app-file-storage/dotnet/scripts/seed-configmap.yml | Seed activities ConfigMap |
| samples/web-app-file-storage/dotnet/scripts/secret.yml | K8s Secret manifest |
| samples/web-app-file-storage/dotnet/scripts/persistentvolumeclaim.yml | PVC manifest |
| samples/web-app-file-storage/dotnet/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-file-storage/dotnet/scripts/configmap.yml | App mount path config |
| samples/web-app-file-storage/dotnet/scripts/04-push-docker-image.sh | Push image to ACR |
| samples/web-app-file-storage/dotnet/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-cosmosdb-nosql-api/python/src/templates/index.html | Fix delete to use store id |
| samples/web-app-cosmosdb-nosql-api/python/src/requirements.txt | Pin Python dependencies |
| samples/web-app-cosmosdb-nosql-api/python/src/gunicorn.conf.py | Gunicorn signal handling |
| samples/web-app-cosmosdb-nosql-api/python/src/cosmosdb_client.py | Add ping helper |
| samples/web-app-cosmosdb-nosql-api/python/scripts/service.yml | K8s Service manifest |
| samples/web-app-cosmosdb-nosql-api/python/scripts/secret.yml | K8s Secret manifest |
| samples/web-app-cosmosdb-nosql-api/python/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-cosmosdb-nosql-api/python/scripts/deployment.yml | Deployment probes -> /health |
| samples/web-app-cosmosdb-nosql-api/python/scripts/configmap.yml | Cosmos env var config |
| samples/web-app-cosmosdb-nosql-api/python/scripts/05-deploy-app.sh | Deploy: stable secret + rollout restart |
| samples/web-app-cosmosdb-nosql-api/python/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-cosmosdb-nosql-api/dotnet/src/VacationPlanner.csproj | .NET 10 project file |
| samples/web-app-cosmosdb-nosql-api/dotnet/src/Services/StoreInitializer.cs | Startup store initialization |
| samples/web-app-cosmosdb-nosql-api/dotnet/src/Services/IActivityStore.cs | Store interface contract |
| samples/web-app-cosmosdb-nosql-api/dotnet/src/Services/CosmosOptions.cs | Cosmos env var parsing |
| samples/web-app-cosmosdb-nosql-api/dotnet/src/Services/ActivityId.cs | Shared ID scheme |
| samples/web-app-cosmosdb-nosql-api/dotnet/src/Services/ActivityDocument.cs | Cosmos document model |
| samples/web-app-cosmosdb-nosql-api/dotnet/src/Pages/Delete.cshtml.cs | Delete handler by id |
| samples/web-app-cosmosdb-nosql-api/dotnet/src/Pages/Delete.cshtml | Delete route page |
| samples/web-app-cosmosdb-nosql-api/dotnet/src/Pages/_ViewImports.cshtml | Razor imports |
| samples/web-app-cosmosdb-nosql-api/dotnet/src/Models/Activity.cs | Activity model |
| samples/web-app-cosmosdb-nosql-api/dotnet/src/appsettings.json | Console logging config |
| samples/web-app-cosmosdb-nosql-api/dotnet/src/.dockerignore | Docker ignore outputs |
| samples/web-app-cosmosdb-nosql-api/dotnet/scripts/service.yml | K8s Service manifest |
| samples/web-app-cosmosdb-nosql-api/dotnet/scripts/secret.yml | K8s Secret manifest |
| samples/web-app-cosmosdb-nosql-api/dotnet/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-cosmosdb-nosql-api/dotnet/scripts/Dockerfile | .NET container build |
| samples/web-app-cosmosdb-nosql-api/dotnet/scripts/configmap.yml | Cosmos env var config |
| samples/web-app-cosmosdb-nosql-api/dotnet/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-cosmosdb-mongodb-api/python/src/templates/index.html | Fix delete to use store id |
| samples/web-app-cosmosdb-mongodb-api/python/src/requirements.txt | Pin Python dependencies |
| samples/web-app-cosmosdb-mongodb-api/python/src/gunicorn.conf.py | Gunicorn signal handling |
| samples/web-app-cosmosdb-mongodb-api/python/scripts/service.yml | K8s Service manifest |
| samples/web-app-cosmosdb-mongodb-api/python/scripts/secret.yml | K8s Secret manifest |
| samples/web-app-cosmosdb-mongodb-api/python/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-cosmosdb-mongodb-api/python/scripts/deployment.yml | Deployment probes -> /health |
| samples/web-app-cosmosdb-mongodb-api/python/scripts/configmap.yml | Mongo env var config |
| samples/web-app-cosmosdb-mongodb-api/python/scripts/05-deploy-app.sh | Deploy: stable secret + rollout restart |
| samples/web-app-cosmosdb-mongodb-api/python/scripts/03-run-docker-container.sh | Local docker run helper |
| samples/web-app-cosmosdb-mongodb-api/python/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-cosmosdb-mongodb-api/python/scripts/00-variables.sh | Shared variables (incl. creds) |
| samples/web-app-cosmosdb-mongodb-api/dotnet/src/VacationPlanner.csproj | .NET 10 project file |
| samples/web-app-cosmosdb-mongodb-api/dotnet/src/Services/StoreInitializer.cs | Startup store initialization |
| samples/web-app-cosmosdb-mongodb-api/dotnet/src/Services/MongoOptions.cs | Mongo env var parsing |
| samples/web-app-cosmosdb-mongodb-api/dotnet/src/Services/IActivityStore.cs | Store interface contract |
| samples/web-app-cosmosdb-mongodb-api/dotnet/src/Services/ActivityId.cs | Shared ID scheme |
| samples/web-app-cosmosdb-mongodb-api/dotnet/src/Pages/Delete.cshtml.cs | Delete handler by id |
| samples/web-app-cosmosdb-mongodb-api/dotnet/src/Pages/Delete.cshtml | Delete route page |
| samples/web-app-cosmosdb-mongodb-api/dotnet/src/Pages/_ViewImports.cshtml | Razor imports |
| samples/web-app-cosmosdb-mongodb-api/dotnet/src/Models/Activity.cs | Activity model |
| samples/web-app-cosmosdb-mongodb-api/dotnet/src/appsettings.json | Console logging config |
| samples/web-app-cosmosdb-mongodb-api/dotnet/src/.dockerignore | Docker ignore outputs |
| samples/web-app-cosmosdb-mongodb-api/dotnet/scripts/service.yml | K8s Service manifest |
| samples/web-app-cosmosdb-mongodb-api/dotnet/scripts/secret.yml | K8s Secret manifest |
| samples/web-app-cosmosdb-mongodb-api/dotnet/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-cosmosdb-mongodb-api/dotnet/scripts/Dockerfile | .NET container build |
| samples/web-app-cosmosdb-mongodb-api/dotnet/scripts/configmap.yml | Mongo env var config |
| samples/web-app-cosmosdb-mongodb-api/dotnet/scripts/03-run-docker-container.sh | Local docker run helper |
| samples/web-app-cosmosdb-mongodb-api/dotnet/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-cosmosdb-mongodb-api/dotnet/scripts/00-variables.sh | Shared variables (incl. creds) |
| samples/web-app-blob-storage/python/src/requirements.txt | Pin Python dependencies |
| samples/web-app-blob-storage/python/src/gunicorn.conf.py | Gunicorn signal handling |
| samples/web-app-blob-storage/python/scripts/service.yml | K8s Service manifest |
| samples/web-app-blob-storage/python/scripts/secret.yml | Remove unused secret key |
| samples/web-app-blob-storage/python/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-blob-storage/python/scripts/deployment.yml | Deployment probes -> /health |
| samples/web-app-blob-storage/python/scripts/configmap.yml | Remove workload-identity-only vars |
| samples/web-app-blob-storage/python/scripts/05-deploy-app.sh | Deploy: stable secret + rollout restart |
| samples/web-app-blob-storage/python/scripts/04-push-docker-image.sh | Push image to ACR |
| samples/web-app-blob-storage/python/scripts/03-run-docker-container.sh | Local docker run helper |
| samples/web-app-blob-storage/python/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-blob-storage/python/scripts/00-variables.sh | Shared variables |
| samples/web-app-blob-storage/dotnet/src/VacationPlanner.csproj | .NET 10 project file |
| samples/web-app-blob-storage/dotnet/src/Services/StoreInitializer.cs | Startup store initialization |
| samples/web-app-blob-storage/dotnet/src/Services/IActivityStore.cs | Store interface contract |
| samples/web-app-blob-storage/dotnet/src/Services/BlobStorageOptions.cs | Blob env var settings |
| samples/web-app-blob-storage/dotnet/src/Pages/Delete.cshtml.cs | Delete handler by id |
| samples/web-app-blob-storage/dotnet/src/Pages/Delete.cshtml | Delete route page |
| samples/web-app-blob-storage/dotnet/src/Pages/_ViewImports.cshtml | Razor imports |
| samples/web-app-blob-storage/dotnet/src/Models/Activity.cs | Activity model |
| samples/web-app-blob-storage/dotnet/src/appsettings.json | Console logging config |
| samples/web-app-blob-storage/dotnet/src/.dockerignore | Docker ignore outputs |
| samples/web-app-blob-storage/dotnet/scripts/service.yml | K8s Service manifest |
| samples/web-app-blob-storage/dotnet/scripts/secret.yml | K8s Secret manifest |
| samples/web-app-blob-storage/dotnet/scripts/namespace.yml | K8s Namespace manifest |
| samples/web-app-blob-storage/dotnet/scripts/Dockerfile | .NET container build |
| samples/web-app-blob-storage/dotnet/scripts/configmap.yml | Blob env var config |
| samples/web-app-blob-storage/dotnet/scripts/04-push-docker-image.sh | Push image to ACR |
| samples/web-app-blob-storage/dotnet/scripts/03-run-docker-container.sh | Local docker run helper |
| samples/web-app-blob-storage/dotnet/scripts/02-build-docker-image.sh | Build docker image helper |
| samples/web-app-blob-storage/dotnet/scripts/00-variables.sh | Shared variables |
| .gitattributes | Normalize line endings |
Review details
- Files reviewed: 101/896 changed files
- Comments generated: 10
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
From the Copilot review of PR #30: - gateway.yml listed a leftover hostname (local.echo.babosbird.com) while httproute.yml matched planner.local.babosbird.com. 05-deploy-app.sh templates both from $SUBDOMAIN.$DNS_ZONE_NAME, so routing was correct at deploy time, but the checked-in manifests now agree with each other and with the deployed value. - issuer.yml hardcoded a personal ACME registration address. It now carries admin@example.com, and 00-variables.sh defines ACME_EMAIL (overridable through the environment) which 05-deploy-app.sh templates into .spec.acme.email. - The exception thrown for an empty LOGIN_NAME said "Username cannot be None or empty", the Python wording, without naming the variable. All three .NET samples that validate it now say "LOGIN_NAME is set to an empty value". Two defects found while working through the review: - The ACME solver in issuer.yml referenced sectionName vacation-planner-identity-http, while the Gateway listeners are named http and https, so the HTTP-01 challenge could never be routed to the Gateway. - The rollout restart added to 05-deploy-app.sh landed inside the DEPLOY_GATEWAY=="true" branch in the managed-identity sample, so a redeploy of the same image tag did not roll the pods in the default configuration. It now runs at the top level, right after the Service is applied, in both languages. Validated on the emulator: the .NET and the Python version of web-app-managed-identity deploy, pass the functional smoke test through a port-forward and from inside the cluster across all replicas, and re-running 05-deploy-app.sh alone now creates a new Deployment revision. Two comments were answered without a change: the sample database passwords (copies of the unchanged Python values, for resources the samples create themselves; changing them belongs in a repository-wide PR) and the delete flash wording (deliberately per sample, matching each Python sibling). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Motivation
The nine samples in this repository deploy the same Vacation Planner web app to AKS and differ only in the Azure data service behind it, but the app existed in Python only. This PR gives every sample a .NET 10 twin with the same behaviour, the same environment variables and the same deployment artifacts, so the two implementations can be compared side by side and either one can be deployed in place of the other. The .NET version follows the ASP.NET Core port of the App Service samples in
localstack-samples/localstack-azure-samples, adapted to Kubernetes.Testing the two implementations against each other also surfaced a set of pre-existing bugs, which are fixed here.
Fixes SMF-878
Changes
Layout. Each sample now holds its content under
python/anddotnet/; the moves are recorded as renames, so history is preserved. The root README links both versions of every sample and documents the new layout.The .NET version of all nine samples. ASP.NET Core Razor Pages on .NET 10, one
dotnet/folder per sample with its own source, Dockerfile, numbered deployment scripts, Kubernetes manifests, README and architecture diagram. Behaviour matches the Python sibling in flash wording, list ordering, startup retries and environment variables. Only the container image name carries a-dotnetsuffix, so both versions roll over the same Deployment, Service, ConfigMap and Secret.Two Kubernetes-specific pieces have no equivalent in the App Service port:
SECRET_KEYSecret (HKDF-SHA256 over the value Flask signs its session cookie with), so antiforgery tokens and TempData flashes validate on any replica.GET /healthwas added to both implementations of every sample, and the liveness and readiness probes now call it instead of/.Logging parity. The Python images log an access line per request (gunicorn runs with
--access-logfile -) plus a line per store operation. The .NET apps now do the same: a request-log middleware, per-operation store lines, per-action page lines, and single timestamped console lines, documented in a## Logssection of every sample README.Unique names per sample.
web-app-managed-identityshared its namespace, workloads and image repository withweb-app-blob-storage, andweb-app-in-cluster-postgresqlshared them withweb-app-postgresql-flexible-server. Two such samples could not run at the same time, and whichever image was pushed last overwrote the other under the same tag, so the other sample then pulled the wrong app. The second sample of each pair is renamed (vacation-planner-identity,vacation-planner-postgres-in-cluster) in both languages.Bug fixes found while testing (each applied to both implementations where it applies):
web-app-in-cluster-postgresqlthe requested activity stayed in the database while a seeded row disappeared. Every delete now addresses the activity by its store id, which the page already carries indata-id.05-deploy-app.shgenerated a newSECRET_KEYon every run while the running pods kept the old one, breaking sessions and antiforgery tokens across replicas until every pod restarted. It now reuses the value already stored in the Secret.05-deploy-app.shleft the pods on the old image when the same:v1tag was re-pushed, because the pod template is unchanged andkubectl applyreports no change. It now restarts the deployment after applying it./data/.write-probe-$ProcessId, and every container runs the app as PID 1, so all replicas raced on one file on the shared SMB share; the write failed and the pod restarted in a loop with a healthy share. The probe name now carries the pod name and a GUID.web-app-sql-database's01-deploy-resources.shre-inserted its nine seed rows on every run; the insert is now guarded byIF NOT EXISTS.AADSTS70021. The script now compares the subject and recreates the credential when it differs.Repository hygiene.
.gitignoregained the .NET build outputs and the files the sample scripts drop intoscripts/; a new.gitattributesnormalizes*.sh,*.yml,*.cs,*.csproj,*.cshtmlandDockerfileto LF.Testing
Everything was validated on the LocalStack Azure emulator with a k3d-backed AKS cluster, in two passes: all nine Python samples on a fresh emulator and cluster, then the emulator stopped and restarted, the cluster recreated, and all nine .NET samples deployed and tested. Every one of the eighteen runs covers:
01-05from the sample'sscripts/folder, thenkubectl rollout status.GET /healthendpoint answers, since both probes call it.Sample-specific checks: workload identity through
DefaultAzureCredentialwith the webhook-injected federated token (managed-identity), the static SMB share with its seeded files (file-storage), Gateway mode against the emulated account (Cosmos DB for NoSQL), a real update flashing while a no-op update does not, identically in both languages (MySQL, matching PyMySQL's changed-rows semantics),GET /update/{id}redirecting to the edit form (SQL Database), and the three-replica StatefulSet with its PVC (in-cluster PostgreSQL). Both formerly colliding pairs were also verified running side by side at the same time, and theSECRET_KEYreuse and the SQL seed guard were verified by re-running the scripts and comparing the Secret and the row count.To reproduce: create the cluster with
scripts/01-user-assigned-managed-identity.sh, then run the numbered scripts insamples/<sample>/<language>/scriptsin order and port-forward the service.TODO
Copied for parity but only the default flow was exercised:
web-app-file-storageindynamicprovisioning mode and over NFS (static SMB was validated).web-app-managed-identitybehind the Gateway API with a managed TLS certificate (DEPLOY_GATEWAY="true").03-run-docker-container.sh, the optional local Docker run, for the .NET images.🤖 Generated with Claude Code