Skip to content

fix: publish provision result atomically - #9401

Open
r2k1 wants to merge 3 commits into
mainfrom
r2k1-analyze-provision-state
Open

fix: publish provision result atomically#9401
r2k1 wants to merge 3 commits into
mainfrom
r2k1-analyze-provision-state

Conversation

@r2k1

@r2k1 r2k1 commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

What this PR does / why we need it:

provision-wait uses provision.complete because writers could expose a partial provision.json. Both Linux writers now stage the result beside the target and rename it into place. Bash keeps the detailed CSE result; ANC writes a fallback when bootstrap cannot start.

The PR keeps provision.complete for compatibility. We can remove it after 2026-10-01, once compatible VHDs have shipped.

Which issue(s) this PR fixes:

N/A

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Windows Unit Test Results

  3 files   13 suites   48s ⏱️
409 tests 409 ✅ 0 💤 0 ❌
412 runs  412 ✅ 0 💤 0 ❌

Results for commit 2bdd729.

♻️ This comment has been updated with latest results.

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.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

This PR makes provisioning result publication atomic so readers never observe a partially-written provision.json, while keeping provision.complete as a compatibility signal until the deprecation window ends.

Changes:

  • Add atomic “stage then rename” publishing for provision.json in cse_start.sh, and ensure completion markers are created after publication.
  • Add Go-side atomic fallback publishing (writeProvisionResultAtomically) and tests covering preservation/idempotency/error paths.
  • Update documentation to describe the new provisioning result semantics and compatibility plan.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
spec/parts/linux/cloud-init/artifacts/cse_start_spec.sh Adds shellspec coverage for atomic provision result publishing and failure modes.
parts/linux/cloud-init/artifacts/cse_start.sh Introduces publishProvisionResponse to stage+rename provision.json and write completion markers.
aks-node-controller/const.go Documents future removal of provision.complete compatibility.
aks-node-controller/app_test.go Adds tests for atomic publishing, preservation, and fsnotify event semantics.
aks-node-controller/app.go Implements Go fallback atomic write + completion marker logic.
aks-node-controller/README.md Updates provisioning flow docs to emphasize atomic provision.json publication and compatibility behavior.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread parts/linux/cloud-init/artifacts/cse_start.sh Outdated
Comment on lines +726 to +727
data, marshalErr := json.Marshal(provisionResult)
if marshalErr != nil {
Comment on lines +741 to +743
if _, statErr := os.Stat(filepaths.ProvisionCompleteFile); statErr == nil {
return nil
} else if !errors.Is(statErr, os.ErrNotExist) {
Comment on lines +771 to +773
}
if err := tmp.Chmod(0644); err != nil {
return fmt.Errorf("set temporary provision result mode %s: %w", tmpPath, err)
})
}

func TestAtomicRenameProducesCreateEvent(t *testing.T) {
case watchErr := <-watcher.Errors:
require.NoError(t, watchErr)
case <-timeout:
t.Fatal("timed out waiting for Create event after atomic rename")
Comment thread spec/parts/linux/cloud-init/artifacts/cse_start_spec.sh
Comment thread spec/parts/linux/cloud-init/artifacts/cse_start_spec.sh
### Provisioning Flow

Here is an indepth explanation of the provisioning flow. Upon first startup, CustomData is made available to the VM, after which cloud-init is able to process the content, in this case, writing the bootstrap config to disk. The binary is triggered by a systemd unit, [`aks-node-controller.service`](https://github.com/Azure/AgentBaker/blob/dev/parts/linux/cloud-init/artifacts/aks-node-controller.service) which is automatically run once cloud-init is complete. In this way, we are ensuring the bootstrapping config is present on the node and can proceeed to run the go binary to start the bootstrapping process.
On first startup, cloud-init processes CustomData and writes the bootstrap configuration to disk. The cloud boothook starts [`aks-node-controller.service`](../parts/linux/cloud-init/artifacts/aks-node-controller.service) after the configuration is available, and the controller starts the bootstrap process.
Comment on lines +777 to 782
}
if err := os.Rename(tmpPath, path); err != nil {
return fmt.Errorf("publish provision result %s: %w", path, err)
}
return nil
}
Copilot AI review requested due to automatic review settings September 4, 2026 09:32

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.

🟡 Changes recommended

Unquoted JSON expansion can corrupt results, and baked PIS results can mask real-node bootstrap failures.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

parts/linux/cloud-init/artifacts/cse_start.sh:17

  • 🟡 Medium Risk — 🔧 Script Logic: Expanding response unquoted allows field splitting and pathname expansion in both emitted and staged JSON. For example, an Output value containing files * here is rewritten using filenames from the working directory, corrupting diagnostics and potentially producing invalid JSON. Use printf with a quoted argument for both writes.
    if ! echo ${response} > "${response_tmp}" ||
  • Files reviewed: 6/6 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread aks-node-controller/app.go
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings September 7, 2026 02:26

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.

🟢 Approval recommended

Atomic publication, failure handling, compatibility behavior, and relevant tests are consistent and complete.

Review details
  • Files reviewed: 6/6 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants