Skip to content

Fix corrupt state archive: self-heal the default group and guard rad shutdown - #12840

Merged
sk593 merged 5 commits into
mainfrom
sk593/fix-restore-state-group-order
Aug 27, 2026
Merged

sk593 merged 5 commits into
mainfrom
sk593/fix-restore-state-group-order

Conversation

@sk593

@sk593 sk593 commented Aug 26, 2026 •

Copy link
Copy Markdown
Contributor

Description

The repo-based deploy pipeline (run-rad-commands-azure.yml / run-rad-commands-aws.yml, and the delete-* workflows) restores control-plane state at setup with rad startup and persists it at teardown with rad shutdown. rad startup restores the previous run's snapshot with pg_dump --clean --if-exists — a wholesale drop-and-replace of the control-plane PostgreSQL databases, not a merge.

Two independent problems corrupted the shared state archive and made deploys fail deterministically with resource group "default" not found:

  1. A corrupt (group-less) archive never repaired itself. After Revert default resource group and environment creation from rad install kubernetes #12829 stopped rad install kubernetes from re-seeding the default group server-side, the pipeline created it before rad startup. Since startup restores the databases wholesale, a group created before it is dropped whenever the restored snapshot lacks the group — so once the archive was group-less it stayed that way, and every deploy failed:

    21:43:55  rad group create default                 # created...
    21:43:57  Restoring control-plane databases...      # ...then dropped by the wholesale restore
    21:44:21  State restored successfully.
    21:44:22  rad deploy $ENV_BICEP  ->  NotFound: resource group ".../resourcegroups/default" not found
    
  2. A pre-startup failure overwrote the good archive with blank state. rad shutdown ran unconditionally under if: always(). A workflow that failed before rad startup completed (setup, cluster connect, OIDC, credential registration, or startup itself) still hit teardown, backed up the uninitialized databases, and overwrote the archive. The next run restored that blank state wholesale and re-persisted it — self-perpetuating corruption.

Fix

A two-part fix; neither half is sufficient alone.

1. Create the default group after rad startup (self-heal). Moving rad group create/switch below the restore means the group is (re)created on top of whatever the restore produced, so it is present for the deploy and persisted by the next rad shutdown. A group-less archive now heals itself on the next successful run. rad startup has no resource-group dependency, so nothing needs the group earlier.

2. Guard rad shutdown on a successful restore. restore-state exposes a state-restored output, set to true only after rad startup succeeds. The workflow passes it into teardown's state-restored input; when it is not true, teardown skips rad shutdown (emitting a ::warning::) so a run that never reached startup cannot overwrite the archive. This replaces the earlier ${RUNNER_TEMP} file marker with an explicit action output→input, so the dependency is visible in the workflow YAML and fails safe if the steps are ever split across jobs.

This preserves the behaviors we do want:

  • First-run seeding. rad startup is a no-op on the first run (empty archive) but still succeeds and sets the output, so rad shutdown runs and seeds the archive.
  • Persist after a later failure. If startup succeeded and a later step fails (e.g. a partially-applied Terraform deploy), the output is true, so rad shutdown still runs and that work is not lost.

The guard is pure workflow orchestration — it does not couple rad startup and rad shutdown as commands.

Also in this PR

  • teardown: rad app list → rad app list --preview. The pipeline deploys Radius.Core applications, but the teardown status step queried the legacy Applications.Core plane and listed nothing. --preview matches the surface the rest of the pipeline uses, and a failed listing now surfaces a ::warning:: instead of being swallowed by || true.

Type of change

  • Bugfix

Fixes

Fixes #12838

Testing

  • .github/extension/actions/teardown/teardown_test.sh (wired into build/test.mk as test-teardown) extracts the actual run: blocks from the restore-state and teardown composite actions and executes them with stubbed rad/git (no cluster/CLI), asserting real behavior:
    • restore-state sets state-restored=true on $GITHUB_OUTPUT after rad startup, and creates the default group after startup (order asserted from the invocation log).
    • Negative path: when rad startup fails, the block exits non-zero and never sets the output.
    • First run: a no-op rad startup still sets the output.
    • teardown runs rad shutdown only when state-restored == "true", and otherwise skips with a ::warning::.
    • teardown lists apps via rad app list --preview and warns (does not swallow) on failure.
    • All four workflows wire restore-state → teardown within the same job.
      Verified by mutation that each invariant, when broken, fails the test.
  • make test-teardown and make test-extension-action-shell-syntax pass; the test is shellcheck-clean.

Follow-ups (out of scope)

Raised in review and intentionally deferred — neither is required to fix #12838:

Notes

Example failing runs (before this fix): https://github.com/sk593/aks-store-demo/actions/runs/33015265288, https://github.com/sk593/aks-store-demo/actions/runs/33016468544

@sk593
sk593 requested review from a team as code owners August 26, 2026 22:10
Copilot AI lite review requested due to automatic review settings August 26, 2026 22:10
@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@sk593 sk593 added the pr:standard Ongoing maintenance, minor improvements, documentation updates, and routine development work label Aug 26, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a deterministic failure in the repo-based deploy pipeline where the default resource group was being created before rad startup and then wiped when rad startup restored the control-plane database snapshot.

Changes:

  • Stop creating/switching the default resource group in the “Configure Radius workspace” step (leave workspace creation only).
  • Create and switch to the default resource group after rad startup completes, with expanded inline documentation explaining why.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions

github-actions Bot commented Aug 26, 2026 •

Copy link
Copy Markdown

Unit Tests

    2 files  ±0    459 suites  ±0   8m 45s ⏱️ +27s
6 518 tests ±0  6 516 ✅ ±0  2 💤 ±0  0 ❌ ±0 
7 794 runs  ±0  7 792 ✅ ±0  2 💤 ±0  0 ❌ ±0 

Results for commit 99dedbd. ± Comparison against base commit f00bb86.

♻️ This comment has been updated with latest results.

@codecov

codecov Bot commented Aug 26, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 59.98%. Comparing base (f00bb86) to head (99dedbd).

Additional details and impacted files
@@           Coverage Diff           @@
##             main   #12840   +/-   ##
=======================================
  Coverage   59.97%   59.98%           
=======================================
  Files         776      776           
  Lines       46410    46410           
=======================================
+ Hits        27836    27837    +1     
+ Misses      18574    18573    -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@willtsai willtsai added github-copilot triaged This issue has been reviewed and triaged usability-review labels Aug 26, 2026
@sk593 sk593 changed the title Create default resource group after rad startup in restore-state Create default resource group after rad startup in the deploy workflow Aug 26, 2026
The repo-based deploy pipeline persists control-plane state at teardown via
rad shutdown, which runs under if: always() so a partially-applied deploy is
not lost. But it ran unconditionally: a workflow that failed before the
restore-state action's rad startup completed would still back up the
uninitialized control-plane databases and push them over the durable state
archive. Because rad startup restores that archive wholesale (pg_dump --clean
--if-exists), one such run corrupts state for every future run -- the archive
is replaced with blank state, restored on the next run, re-persisted, and so
on. This is what surfaced as a deterministic 'resource group "default" not
found' after #12829 stopped rad install kubernetes from re-seeding the group
server-side.

Gate persistence on a successful restore: restore-state writes a marker after
rad startup succeeds, and teardown skips rad shutdown when the marker is
absent. rad startup is still a legitimate no-op on the first run (empty
archive) but succeeds and writes the marker, so first-run seeding and
persistence after a later deploy failure both still happen; only runs that
never reached a successful startup are prevented from overwriting the archive.

Add a wiring test asserting the marker is written after rad startup and that
teardown gates rad shutdown on it.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: sk593 <shruthikumar@microsoft.com>
@sk593
sk593 force-pushed the sk593/fix-restore-state-group-order branch from d53bef2 to ff82857 Compare August 26, 2026 23:37
@sk593 sk593 changed the title Create default resource group after rad startup in the deploy workflow Guard rad shutdown so a pre-startup failure cannot overwrite persisted state Aug 26, 2026
sk593 and others added 2 commits August 26, 2026 16:56
The repo-based pipeline deploys Radius.Core applications, but the teardown
'Show application status' step ran the legacy 'rad app list', which queries
the Applications.Core plane and lists none of the deployed apps. Use
'rad app list --preview' to match the Radius.Core surface the rest of the
pipeline uses.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: sk593 <shruthikumar@microsoft.com>
Replace the grep-based wiring test with one that extracts the actual run
blocks from the restore-state and teardown composite actions and executes
them with stubbed rad/git, asserting real behavior:

- restore-state writes the state-restored marker after rad startup succeeds
- teardown skips rad shutdown when the marker is absent (a run that failed
  before startup must not overwrite the durable state archive)
- teardown runs rad shutdown when the marker is present
- teardown lists applications with rad app list --preview, not the legacy
  Applications.Core plane

Renamed the target to test-teardown and verified via mutation that each
assertion fails when its invariant is broken.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: sk593 <shruthikumar@microsoft.com>
@github-actions

github-actions Bot commented Aug 27, 2026 •

Copy link
Copy Markdown

Functional Tests - corerp-noncloud

188 tests  ±0   186 ✅ ±0   1h 12m 50s ⏱️ -57s
  3 suites ±0     2 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 2eef265. ± Comparison against base commit f00bb86.

♻️ This comment has been updated with latest results.

Comment thread .github/extension/actions/restore-state/action.yml
Comment thread .github/extension/actions/restore-state/action.yml Outdated
Comment thread .github/extension/actions/teardown/action.yml Outdated
Comment thread .github/extension/actions/teardown/action.yml Outdated
Comment thread .github/extension/actions/teardown/action.yml
Comment thread .github/extension/README.md
Comment thread .github/extension/actions/teardown/teardown_test.sh Outdated
Comment thread .github/extension/actions/teardown/teardown_test.sh Outdated
Comment thread .github/extension/actions/teardown/teardown_test.sh Outdated
Comment thread .github/extension/actions/teardown/teardown_test.sh Outdated
Replace the RUNNER_TEMP file marker with an explicit composite-action
output (restore-state's state-restored) piped to the teardown action's
state-restored input, so the startup->shutdown dependency is visible in
the workflow YAML and fails safe if the steps are split across jobs.

Move rad group create/switch after rad startup so an already-corrupt,
group-less state archive self-heals on the next run, and emit a
::warning:: when persistence is skipped. Surface (not swallow) a failed
rad app list --preview at teardown.

Rework teardown_test.sh for the output/input mechanism: assert the
group is created after startup, add a negative path where rad startup
fails and the output is never set, assert the first-run no-op still
sets it, assert every workflow wires restore-state->teardown in the
same job, and clean up a single scratch dir on exit.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: sk593 <shruthikumar@microsoft.com>
@sk593 sk593 changed the title Guard rad shutdown so a pre-startup failure cannot overwrite persisted state Fix corrupt state archive: self-heal the default group and guard rad shutdown Aug 27, 2026
kachawla
kachawla previously approved these changes Aug 27, 2026
Discover teardown-using workflows dynamically instead of hardcoding, so
a new caller is covered automatically, and assert teardown and
restore-state are used by the same set of workflows. Extract the wiring
check into a reusable helper and, for every discovered workflow, assert
both the real (positive) wiring and that the check rejects each broken
variant: missing `id: restore-state`, missing state-restored
pass-through, and restore-state/teardown split across jobs.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: sk593 <shruthikumar@microsoft.com>
@radius-functional-tests

radius-functional-tests Bot commented Aug 27, 2026 •

Copy link
Copy Markdown

Radius functional test overview

🔍 Go to test action run

Click here to see the test run details
Name Value
Repository radius-project/radius
Commit ref 99dedbd
Unique ID func9288c505fe
Image tag pr-func9288c505fe
  • Dapr: 1.14.4
  • Azure KeyVault CSI driver: 1.4.2
  • Azure Workload identity webhook: 1.3.0
  • Bicep recipe location ghcr.io/radius-project/dev/test/testrecipes/test-bicep-recipes/<name>:pr-func9288c505fe
  • Terraform recipe location http://tf-module-server.radius-test-tf-module-server.svc.cluster.local/<name>.zip (in cluster)
  • applications-rp test image location: ghcr.io/radius-project/dev/applications-rp:pr-func9288c505fe
  • dynamic-rp test image location: ghcr.io/radius-project/dev/dynamic-rp:pr-func9288c505fe
  • controller test image location: ghcr.io/radius-project/dev/controller:pr-func9288c505fe
  • ucp test image location: ghcr.io/radius-project/dev/ucpd:pr-func9288c505fe
  • deployment-engine test image location: ghcr.io/radius-project/deployment-engine:latest

Test Status

⌛ Building Radius and pushing container images for functional tests...
✅ Container images build succeeded
⌛ Publishing Bicep Recipes for functional tests...
✅ Recipe publishing succeeded
⌛ Starting corerp-cloud functional tests...
⌛ Starting ucp-cloud functional tests...
✅ ucp-cloud functional tests succeeded
✅ corerp-cloud functional tests succeeded

@sk593
sk593 enabled auto-merge August 27, 2026 06:29
@sk593
sk593 added this pull request to the merge queue Aug 27, 2026
Merged via the queue into main with commit 745ce9c Aug 27, 2026
76 checks passed
@sk593
sk593 deleted the sk593/fix-restore-state-group-order branch August 27, 2026 07:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

github-copilot pr:standard Ongoing maintenance, minor improvements, documentation updates, and routine development work triaged This issue has been reviewed and triaged usability-review

Projects

None yet

4 participants