Skip to content

fix(switch-controller): make NVOS credential gaps retryable during cert setup - #4169

Merged
jayzhudev merged 1 commit into
NVIDIA:mainfrom
jayzhudev:fix/switch-cert-nvos-credential-wait
Jul 25, 2026
Merged

fix(switch-controller): make NVOS credential gaps retryable during cert setup#4169
jayzhudev merged 1 commit into
NVIDIA:mainfrom
jayzhudev:fix/switch-cert-nvos-credential-wait

Conversation

@jayzhudev

@jayzhudev jayzhudev commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Fix switch certificate setup so missing per-switch NVOS admin credentials do not strand a switch in non-retryable Error.

When certificate setup is actionable, the switch controller now checks for SwitchNvosAdmin credentials before endpoint resolution. If the credential is missing, it uses the existing NVOS credential resolver to seed expected-switch bootstrap credentials when available. If no usable credential source exists yet, it stays in ConfigureCertificate::Start with Wait, so later credential import can retry automatically.

Existing imported credentials are preserved.

Related issues

Fixes #4168

Type of Change

  • Add - New feature or capability
  • Change - Changes in existing functionality
  • Fix - Bug fixes
  • Remove - Removed features or deprecated functionality
  • Internal - Internal changes (refactoring, tests, docs, etc.)

Breaking Changes

  • This PR contains breaking changes

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • No testing required (docs, internal refactor, etc.)

Manual Testing Results

Validated both recovery paths against real hardware.

Method

  1. Removed the per-switch SwitchNvosAdmin credential and expected-switch NVOS fields, then set lifecycle state to ConfigureCertificate::Start.
  2. Verified the controller remained in Start with Wait.
  3. Imported a valid SwitchNvosAdmin credential into Vault and waited for scheduled reconciliation.
  4. Repeated with only the per-switch credential absent while expected-switch credentials remained available.

Missing credential is retryable

{"state": "configuring", "config_state": {"ConfigureCertificate": {"configure_certificate": "Start"}}}
{"reason": "switch ...: waiting for NVOS admin credentials", "outcome": "wait"}

This shows the controller did not transition to lifecycle Error.

Imported credential self-heals

{"state": "ready"}
{"outcome": "donothing"}

After Vault import, a later periodic controller pass completed the lifecycle without operator state reset.

Expected-switch bootstrap seeds the per-switch credential

msg="Switch: restored NVOS admin credentials" source="expected switch"
msg="Switch: started switch certificate configuration" mode=BringUp
msg="Switch: switch certificate configuration completed"
msg="BOM Validating Switch: BomValidationComplete, moving to Ready"

This exercises the fix: resolve and persist expected-switch bootstrap credentials before certificate endpoint resolution.

RMS job completed

msg="ConfigureSwitchCertificate request received" node_count=1 service_count=1
msg="ConfigureSwitchCertificate jobs dispatched" services=[NvueApi] skipped=0
msg="switch mTLS unset job completed"

Note: RMS was run with --insecure-switch mode during tests, hence it performed mTLS unset.

@jayzhudev jayzhudev self-assigned this Jul 25, 2026
@jayzhudev jayzhudev added the rack lifecycle Issues that relate to managing the lifecycle of a full rack (compute, switches and powershelves) label Jul 25, 2026
@jayzhudev
jayzhudev requested a review from a team as a code owner July 25, 2026 16:29
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Certificate setup now checks NVOS admin credentials before starting, seeds missing credentials when possible, waits when unavailable, and proceeds after credentials are imported. Tests cover credential persistence, rack association, and retry transitions.

Changes

NVOS credential gating

Layer / File(s) Summary
Credential preflight and wait outcomes
crates/switch-controller/src/configuring.rs
handle_configure_certificate_start checks prerequisites, seeds missing NVOS admin credentials, continues when available, and returns persistent waits for skipped or inconsistent credential states.
Credential seeding and retry validation
crates/api-core/src/tests/switch_state_controller/mod.rs
Tests verify expected credential seeding, persisted rack association, credential persistence, and transition from waiting to WaitForComplete after import.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes address #4168 by waiting and retrying when per-switch NVOS credentials are absent instead of entering a permanent Error.
Out of Scope Changes check ✅ Passed The diff stays within the bug fix and test coverage needed for credential retry behavior, with no obvious unrelated additions.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Title check ✅ Passed The title accurately summarizes the main change: making NVOS credential gaps retryable during switch certificate setup.
Description check ✅ Passed The description is directly related to the changeset and correctly explains the retryable credential-gap fix and test updates.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
crates/api-core/src/tests/switch_state_controller/mod.rs (1)

462-470: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing coverage for the Errorwait branch.

The three tests cover Available (pre-seeded), the expected-switch seeding path, and Skip → retry. The remaining branch — NvosAdminCredentialStatus::Error(cause) mapped to wait at crates/switch-controller/src/configuring.rs Lines 397-403 — is untested, yet it is precisely the branch that decides whether an inconsistent switch stalls retryably or strands in Error. A case with, say, an expected-switch row carrying a username but no password would pin the "waiting for valid NVOS admin credentials: {cause}" contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/api-core/src/tests/switch_state_controller/mod.rs` around lines 462 -
470, Add a test in the switch state controller test suite covering an
expected-switch credential row with a username but no password, causing
NvosAdminCredentialStatus::Error(cause). Assert the controller transitions to
ConfigureCertificateState::WaitForComplete and preserves the “waiting for valid
NVOS admin credentials: {cause}” wait/retry behavior.

Source: Path instructions

crates/switch-controller/src/configuring.rs (1)

373-405: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The preflight read duplicates the resolver's first step.

ensure_nvos_admin_credentials already opens with the identical get_credentials(&key) read and the byte-identical map_err message (Lines 157-166), and it already preserves an existing credential rather than clobbering it (Lines 298-315). The local read is therefore a pure short-circuit whose only benefit is skipping the expected-switch/rotation DB queries — at the cost of duplicating the error string in two places, where they will inevitably drift.

If the short-circuit is worth keeping, consider returning the read credential from a small shared helper so the error mapping lives in exactly one place; otherwise call the resolver unconditionally and let Available cover the existing-credential case.

♻️ Sketch: unconditional resolver call
-        let key = CredentialKey::SwitchNvosAdmin { bmc_mac_address };
-
-        let credential_exists = ctx
-            .services
-            .credential_manager
-            .get_credentials(&key)
-            .await
-            .map_err(|error| {
-                StateHandlerError::GenericError(eyre::eyre!(
-                    "switch {switch_id}: failed to read NVOS credentials from credential store: {error}"
-                ))
-            })?
-            .is_some();
-
-        if !credential_exists {
-            match ensure_nvos_admin_credentials(switch_id, bmc_mac_address, ctx).await? {
-                NvosAdminCredentialStatus::Available => {}
-                NvosAdminCredentialStatus::Skip => {
-                    // Stay in `ConfigureCertificate::Start` so periodic
-                    // reconciliation retries after credentials are imported.
-                    return Ok(StateHandlerOutcome::wait(format!(
-                        "switch {switch_id}: waiting for NVOS admin credentials"
-                    )));
-                }
-                NvosAdminCredentialStatus::Error(cause) => {
-                    // Expected-switch credential metadata can be corrected
-                    // without resetting the switch controller state.
-                    return Ok(StateHandlerOutcome::wait(format!(
-                        "switch {switch_id}: waiting for valid NVOS admin credentials: {cause}"
-                    )));
-                }
-            }
-        }
+        match ensure_nvos_admin_credentials(switch_id, bmc_mac_address, ctx).await? {
+            NvosAdminCredentialStatus::Available => {}
+            NvosAdminCredentialStatus::Skip => {
+                // Stay in `ConfigureCertificate::Start` so periodic
+                // reconciliation retries after credentials are imported.
+                return Ok(StateHandlerOutcome::wait(format!(
+                    "switch {switch_id}: waiting for NVOS admin credentials"
+                )));
+            }
+            NvosAdminCredentialStatus::Error(cause) => {
+                // Expected-switch credential metadata can be corrected
+                // without resetting the switch controller state.
+                return Ok(StateHandlerOutcome::wait(format!(
+                    "switch {switch_id}: waiting for valid NVOS admin credentials: {cause}"
+                )));
+            }
+        }

Note this trades the short-circuit for a per-iteration credential rewrite via persist_nvos_admin_credentials; if that write cost is the reason for the guard, prefer the shared-helper option instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/switch-controller/src/configuring.rs` around lines 373 - 405, Remove
the duplicated credential preflight read in the configuration flow and call
ensure_nvos_admin_credentials unconditionally, letting its Available result
handle existing credentials; preserve the existing Skip and Error wait outcomes.
Alternatively, if retaining the short-circuit is required, extract the shared
get_credentials and StateHandlerError mapping into a helper used by both paths
so the read and error message are defined once.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/switch-controller/src/configuring.rs`:
- Around line 397-403: Separate unrecoverable credential inconsistencies from
recoverable NvosAdminCredentialStatus::Error cases. Update the status
construction for “No expected switch found…” and empty confirmed-password
conditions to use a distinct terminal variant, then map that variant in the
configuring state handler to an Error outcome. Preserve the existing wait
behavior for credentials that operators can import or correct.

---

Nitpick comments:
In `@crates/api-core/src/tests/switch_state_controller/mod.rs`:
- Around line 462-470: Add a test in the switch state controller test suite
covering an expected-switch credential row with a username but no password,
causing NvosAdminCredentialStatus::Error(cause). Assert the controller
transitions to ConfigureCertificateState::WaitForComplete and preserves the
“waiting for valid NVOS admin credentials: {cause}” wait/retry behavior.

In `@crates/switch-controller/src/configuring.rs`:
- Around line 373-405: Remove the duplicated credential preflight read in the
configuration flow and call ensure_nvos_admin_credentials unconditionally,
letting its Available result handle existing credentials; preserve the existing
Skip and Error wait outcomes. Alternatively, if retaining the short-circuit is
required, extract the shared get_credentials and StateHandlerError mapping into
a helper used by both paths so the read and error message are defined once.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6fa34dd9-8fbe-432d-add3-4a45d6dc69d6

📥 Commits

Reviewing files that changed from the base of the PR and between 665a468 and 04bf375.

📒 Files selected for processing (2)
  • crates/api-core/src/tests/switch_state_controller/mod.rs
  • crates/switch-controller/src/configuring.rs

Comment thread crates/switch-controller/src/configuring.rs
…rt setup

Signed-off-by: Jay Zhu <jayzhu@nvidia.com>
@jayzhudev
jayzhudev force-pushed the fix/switch-cert-nvos-credential-wait branch from 04bf375 to 6858a0c Compare July 25, 2026 17:21
@jayzhudev
jayzhudev merged commit 4ee77ea into NVIDIA:main Jul 25, 2026
62 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rack lifecycle Issues that relate to managing the lifecycle of a full rack (compute, switches and powershelves)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: certificate setup can strand newly ingested switches without NVOS credentials

2 participants