Skip to content

fix(azure): deploy to a second region without re-creating groups - #86

Open
autoidm-jon wants to merge 5 commits into
mainfrom
azure-region-names
Open

autoidm-jon wants to merge 5 commits into
mainfrom
azure-region-names

Conversation

@autoidm-jon

@autoidm-jon autoidm-jon commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Why

A deploy to a second Azure region failed at the first group step. Deploy sent az group create --location <new region> for pdt-shared and pdt on every run. Azure refuses that call for a group that exists in another region (InvalidResourceGroupLocation). A group's location is only where Azure keeps the group's metadata. Microsoft Learn says "the resources in a resource group can be located in different regions than the resource group", so pdt does not need a group for each region. It must stop re-creating groups that exist.

Once the groups pass, two more problems show. The shared pdt-logs workspace takes the logs of every region, so a new region's logs cross to the first region. And an app whose region changed gets its job updated in the old region, because az containerapp job update cannot change a job's environment.

Scope

  • deploy_azure.ensure_group creates a group only when az group show finds none. ensure_group_and_vault (pdt), ensure_environment (pdt-shared), and ensure_store (pdt-data) call it. ensure_shared_group is gone.
  • The default workspace is pdt-logs-<region>, next to the environment pdt-<region>. ensure_environment returns early for an existing environment, so an environment that logs to the old pdt-logs keeps it. The plan shows a workspace line only when it creates the environment.
  • log_query reads the workspace customer id from the environment (properties.appLogsConfiguration.logAnalyticsConfiguration.customerId), not from a workspace name. This works for pdt-logs, pdt-logs-<region>, and a user's own environment.
  • Destroy deletes a region's workspace (--force, no soft delete) when it releases that region's environment and other regions keep pdt-shared. Release has a new workspace field.
  • deploy stops before the plan when the app's job exists in another region. The message names both regions and the destroy and deploy steps to move the job.
  • AGENTS.md and the deploy_azure_container_apps docstring describe one environment and one workspace per region.

Out of scope, see #33: one data store for each region, and a real move of a job to a new region. Google Cloud and AWS behave the same way for both, so each needs a change on every provider.

Tradeoffs

  • The region check stops the deploy and does not move the job. A move needs destroy's cleanup of locks, grants, and the old environment. I left that to a change that covers all three providers.
  • An existing pdt-logs workspace stays until pdt-shared is deleted. It serves only the first region's environment, because a second region could not deploy before this change.
  • PDT_AZURE_LOG_WORKSPACE still names one workspace for every region. Destroy of one region could then delete a workspace that another region uses. No default setup sets that variable.

Blast Radius

Azure deploy, destroy, pdt runs, and pdt logs. A single-region project sees one change: deploy no longer re-sends az group create for its groups, which also stops that call from replacing tags a user put on the group. New regions get pdt-logs-<region>. Google Cloud and AWS code does not change.

Verification

  • tests/test_azure_second_region.py came first and failed on origin/dev: 3 failed, 773 passed. The group commit makes it pass. The full suite has 782 passed at the head. ruff check src tests passes.
  • A live test on a scratch group in the pdt test subscription reproduced InvalidResourceGroupLocation for a create in a second region. A managed identity in westus2 inside the eastus2 group worked. The group is deleted.
  • Live read-only checks against the test subscription with a copy of pdt-examples:
    • pdt runs hello-world and pdt logs hello-world with the new code read the eastus2 runs and the log line Hello, world! through the environment's customer id. That id is the id of the old pdt-logs workspace.
    • With region: centralus, pdt deploy hello-world on origin/dev printed a plan that reused pdt-logs, created pdt-centralus with a lock, and said "update Container Apps Job pdt-hello-world". The job stays in eastus2. The new code stops before the plan with the region message.
    • For a new app in centralus, the new plan says "use existing resource group pdt-shared", "create Log Analytics workspace pdt-logs-centralus in pdt-shared", and "create Container Apps Job".
  • Not run: a real deploy with --yes into a second region, followed by destroy. It creates billed resources in the shared test subscription.

Closes #33

🤖 Generated with Claude Code


Moved from GitLab autoidm/pdt!144 (https://gitlab.com/autoidm/pdt/-/merge_requests/144), opened by autoidm-jon on 2026-09-26.

@cursor

cursor Bot commented Oct 1, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown

PR tier: tier::architectural (rules and Claude agree)

  • AGENTS.md is repo rules
  • agree with floor — AGENTS.md:82 rewrites the Azure shared-resource rule (one environment and one workspace per region, existing environment keeps its workspace)
  • src/pdt/deploy_azure.py:221 changes the shared workspace default name from pdt-logs to pdt-logs-{region}, altering a shared resource's naming and lifecycle scope for subscriptions that already have apps deployed
  • src/pdt/deploy_azure_container_apps.py:560 adds a new user-facing hard failure when an app's platform.region changes, telling the user to set the region back and destroy first — removed behaviour plus a manual step no other provider requires
  • destroy lifecycle changes: new Release.workspace branch in environment_release/release_environment deletes the workspace separately from the group, so what destroy reclaims for shared resources is different

A changed diff is scored again. Job log: https://github.com/AutoIDM/pdt/actions/runs/37006898248

@github-actions

Copy link
Copy Markdown

PR tier: tier::architectural (rules and Claude agree)

  • AGENTS.md is repo rules
  • AGENTS.md: the Azure shared-resource rule is rewritten — one Container Apps environment and one Log Analytics workspace per region, and 'an existing environment keeps the workspace it already logs to'
  • src/pdt/deploy_azure.py changes the default shared workspace name from 'pdt-logs' to 'pdt-logs-{region}', changing the lifecycle scope of a shared resource and risking an orphaned 'pdt-logs' workspace in subscriptions already deployed
  • src/pdt/deploy_azure_container_apps.py adds a new hard deploy failure (moved_region_message) that stops a deploy that previously proceeded when platform.region changed, and gives Azure a region-move step the other providers do not have

A changed diff is scored again. Job log: https://github.com/AutoIDM/pdt/actions/runs/38892821448

autoidm-jon and others added 2 commits November 3, 2026 14:04
The test fails: ensure_group_and_vault, ensure_shared_group, and
ensure_store send az group create with the new region for groups that
already exist in the first region. Azure refuses that call with
InvalidResourceGroupLocation.

Refs #77

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`az group create` on an existing group with another location fails with
InvalidResourceGroupLocation, so a deploy to a second region stopped at
the first group it reconciled. A group's location is only where its
metadata lives, and its resources may be in any region, so an existing
group is used as it is.

Refs #77

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
autoidm-jon and others added 3 commits November 3, 2026 14:36
A single pdt-logs workspace sat in the region of the first deploy, so a
second region's environment sent its logs across regions. Each region now
gets pdt-logs-<region>. An existing environment keeps the workspace it
already logs to, and logs are read from the workspace the environment
names, so subscriptions set up with pdt-logs keep working. Destroy deletes
a region's workspace with its environment when pdt-shared stays for other
regions.

Refs #77

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`az containerapp job update` cannot change a job's environment, so a
deploy after a region change updated the job where it was, reported an
update, and locked an environment the job never used. Deploy now stops
before the plan and says how to keep the job or move it.

Refs #77

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@autoidm-jon

autoidm-jon commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor Author

Goal: an app deploys to an additional Azure region without an InvalidResourceGroupLocation error, with a Log Analytics workspace for each region.

Reviewer: Cursor gpt-5.6-luna-high.

# Severity Disposition Finding Action
1 should-fix fixed The region check in deploy read only the job under its current name. A job under the old name (legacy_job_name) in another region was deleted and re-created in the new region, and its lock on the old environment stayed. The PR's own commit had this gap; the rebase did not add it. The check now reads the current job or the owned old-name job, and the stop message names the job that exists. Fixed in the fix(azure) commit that stops a deploy when the job of the app exists in a different region. New test test_a_job_with_the_old_name_in_another_region_fails_before_the_plan fails without the change.
2 should-fix fixed When other regions keep pdt-shared, destroy looked for pdt-logs-<region> only. An older environment logs to pdt-logs, so destroy left pdt-logs in place. The PR's own commit had this gap; the rebase did not add it. environment_release now finds the workspace through the environment's customer id (log_workspace). Release.workspace holds that name, and the plan line and the delete use it. Fixed in "fix(azure): keep one Log Analytics workspace per region". New test test_destroy_deletes_the_workspace_an_older_environment_logs_to fails without the change.
3 nit fixed The permission warning of pdt runs and pdt health named pdt-logs-<region> when the environment logs to pdt-logs. The PR's own commit had this gap. The warning now names the workspace from log_workspace. It reads that name only when the query is refused, so a run with permission costs no extra read. The test test_a_log_analytics_query_this_account_may_not_run_names_the_action_and_the_role now asserts pdt-logs and fails without the change.

Conflict resolutions in this rebase (unchanged from the review):

  • deploy: main's parallel read_state; the workspace result is used only when the environment does not exist.
  • environment_release: the PR's per-region workspace rule with main's ARM reads and environment_users(settings, token).
  • Region stop: placed after main's ownership check; a --plan after a region move that .pdt/state records plans a new job, because a deploy first removes the old one.
  • pdt logs --list and --open name the workspace the environment logs to.

Checks that passed at 96a54ee: uv run --group dev ruff check (all checks passed); uv run pytest -q (2541 passed, 9 skipped; the skips need PowerShell, gcsfs, or a downloaded IntuneManagement copy, which the empty test data folder does not hold).

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

PR tier: tier::architectural (rules and Claude agree)

  • AGENTS.md is repo rules
  • AGENTS.md:93 rewrites the shared-resource rule for Azure (one environment and one workspace per region, existing environment keeps its workspace) — a repo rule change the team should ratify
  • src/pdt/deploy_azure.py:371 changes the default shared name from pdt-logs to pdt-logs-{region}, altering the lifecycle scope of a shared resource; AGENTS.md requires the same prefix/tag/lifecycle pattern on every provider, so the parity of this per-region scope with AWS/GCP needs a decision
  • src/pdt/deploy_azure_container_apps.py:1159 adds a new user-facing stop: a deploy of an app whose job is in another region now fails with moved_region_message instead of proceeding, and destroy gains a workspace release step (Release.workspace) that deletes a shared resource

A changed diff is scored again. Job log: https://github.com/AutoIDM/pdt/actions/runs/41847620266

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Azure deploy to a second region fails at az group create

1 participant