Skip to content

feat(scale-up-fabric): support RMS v2 fabric manager configuration#4158

Open
jayzhudev wants to merge 1 commit into
NVIDIA:mainfrom
jayzhudev:feat/nmx-c-configure-v2
Open

feat(scale-up-fabric): support RMS v2 fabric manager configuration#4158
jayzhudev wants to merge 1 commit into
NVIDIA:mainfrom
jayzhudev:feat/nmx-c-configure-v2

Conversation

@jayzhudev

@jayzhudev jayzhudev commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Add support for the librms v0.10.0 ConfigureScaleUpFabricManagerV2 async RPC.

The V1 requires NICo to coordinate multiple RMS RPCs: disable the cluster state across all switches, query switch tray indexes to select a primary, synchronously configure that primary, and then query fabric status separately. V2 moves this coordination into RMS as a scale-up fabric-wide desired-state reconciliation job.

With the V2 RPC, NICo gains a stronger completion contract: RMS selects the primary, reconciles the scale-up fabric, waits for NMX-C to reach configured state, and verifies final switch and topology readback before completing the job. NICo submits the group of switches and desired topology, polls the job, then reads and persists the RMS-selected primary and per-switch Fabric Manager status.

V1 remains the default for compatibility.

To enable V2 under the RMS configuration:

[rms]
scale_up_fabric_manager_api_version = "v2"

If unset, v1 is used.

Related issues

Resolves #1923

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

V1 remains the default, so existing deployments retain current behavior.

Testing

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

Manual Testing

Validated against two switches using RMS and the V2 selector.

  • V2 certificate preparation completed for both switches.
  • NICo submitted the asynchronous V2 job and polled it to completion.
  • RMS selected the lowest-tray switch as primary.
  • NICo called GetScaleUpFabricStatus after completion and persisted the observed primary and Fabric Manager status.
  • A second reconciliation completed successfully and retained the same primary.
  • No V1 states or NICo BatchSetScaleUpFabricState calls were observed.

Selected redacted logs:

NICo:
05:39:48 msg="Starting ConfigureNmxCluster"
         next_state=ConfigureCertificatesV2(Start)

05:40:20 msg="ConfigureNmxCluster V2 certificate configuration completed;
              advancing to ConfigureScaleUpFabricManagerV2"

05:40:22 msg="Submitting RMS v2 NMX cluster configuration"
         rack_id=<rack-id> switch_count=2
         topology_type=gb200_nvl36r1_c2g4_topology

05:40:23 msg="V2 ConfigureScaleUpFabricManager submitted;
              waiting for RMS job"
         job_id=<job-id>

05:41:32 msg="ConfigureScaleUpFabricManager job completed;
              verifying observed primary switch"

05:41:34 msg="Verified and persisted RMS v2 fabric status; advancing"
         next_state=Completed
         observed_primary_switch=<primary-switch-id>
         switch_count=2
RMS:
05:40:23 msg="selected primary by lowest tray index"
         primary=<primary-switch-id>

05:40:23 msg="scale-up fabric state already set; skipping nv cli update"
         node=<non-primary-switch-id>
         current_state=disabled desired_state=disabled

05:41:08 msg="NMX topology already configured, skipping"
         current_topology=gb200_nvl36r1_c2g4_topology
         desired_topology=gb200_nvl36r1_c2g4_topology

05:41:09 msg="nmx-controller control plane configured"
         node=<primary-switch-id>
         control_plane_state=CONTROL_PLANE_STATE_CONFIGURED

05:41:33 rpc_method=GetScaleUpFabricStatus
         rpc_grpc_status_code=0

Trimmed completed job response:

{
  "executionState": "JOB_EXECUTION_STATE_COMPLETED",
  "stateDescription": "Completed",
  "result": {
    "topology_type": "gb200_nvl36r1_c2g4_topology",
    "switches": [
      {
        "node_id": "<primary-switch-id>",
        "enabled": true,
        "fabric_manager_status": "ok"
      },
      {
        "node_id": "<non-primary-switch-id>",
        "enabled": false,
        "fabric_manager_status": ""
      }
    ]
  }
}

Persisted NICo state:

<primary-switch-id>
Primary       : Yes
Fabric Manager: running
Info          : CONTROL_PLANE_STATE_CONFIGURED

<non-primary-switch-id>
Primary       : No
Fabric Manager: not_running

Repeat reconciliation evidence:

05:44:01 msg="selected primary by lowest tray index"
         primary=<same-primary-switch-id>

05:44:03 msg="NVLink fabric already matches requested state"
         node=<same-primary-switch-id>

05:44:32 rpc_method=GetScaleUpFabricStatus
         rpc_grpc_status_code=0

Additional notes:

  • The first attempt encountered an RMS HTTP/2 REFUSED_STREAM during final readback. RMS rolled both switches back to disabled; retrying the same desired state passed.

Simulation Testing

Tested scenarios:

  • V2 selector: Configured NICo with scale_up_fabric_manager_api_version = "v2" and verified selection of the V2 workflow.
  • Certificate preparation: Verified NICo configured certificates for every rack switch before V2 submission.
  • Simplified V2 workflow: Verified NICo skipped V1-only BatchSetScaleUpFabricState(false) and device-info preparation calls.
  • V2 request construction: Verified NICo submitted one ConfigureScaleUpFabricManager V2 request containing the selected topology, all rack switches, and no primary-switch override.
  • Asynchronous completion: Verified NICo persisted the RMS job ID, polled GetJobStatus, and continued only after job completion.
  • RMS-owned primary selection: Verified NICo called GetScaleUpFabricStatus after completion, accepted the sole primary selected by RMS, and replaced the previously stored primary.
  • Observed-state persistence: Verified NICo queried Fabric Manager status for all switches and persisted both the RMS-selected primary and per-switch Fabric Manager status.

@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 03:38
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Summary by CodeRabbit

  • New Features
    • Added a configurable ScaleUp Fabric Manager API version in RMS settings (default v1, new async job-based v2).
    • Implemented v2 certificate and fabric-manager workflows, including job submission, polling, and post-run verification across all switches, with correct continuation after restart.
    • Updated rack workflow to persist and use the selected API version during state transitions.
  • Bug Fixes
    • Improved certificate configuration control with optional NMX Hello verification support.
  • Tests
    • Extended coverage for v2 workflows and backward-compatible defaulting to v1.

Walkthrough

The change adds selectable RMS V1/V2 scale-up fabric manager workflows. V2 submits rack-wide asynchronous jobs, polls completion, validates returned fabric and service status, persists results, and extends certificate configuration with explicit test_hello propagation.

Changes

RMS v2 fabric manager workflow

Layer / File(s) Summary
Configuration and maintenance state contract
crates/rack-controller/src/config.rs, crates/api-model/src/rack.rs, crates/api-core/src/cfg/README.md
Adds configurable V1/V2 API selection, V2 maintenance states, display formatting, backward-compatible deserialization, and workflow documentation.
Certificate forwarding and status observation
crates/component-manager/..., crates/rack-controller/src/nmx_certificate.rs, crates/rack-controller/src/fabric_manager.rs, crates/api-core/src/handlers/component_manager.rs, crates/switch-controller/src/certificate.rs
Propagates test_hello through certificate configuration and validates RMS primary-switch responses with injectable clients.
V2 certificate and fabric pipeline
crates/rack-controller/src/maintenance.rs
Adds full-rack certificate submission, inventory validation, asynchronous fabric configuration, job polling, verification, persistence, and state-machine routing.
RMS simulation and end-to-end validation
crates/rack/src/rms_client.rs, crates/api-core/src/tests/rack_state_controller/*
Adds queued and recorded V2 RMS interactions and validates full-rack requests, workflow persistence, certificate behavior, and persisted fabric-manager status.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MaintenanceHandler
  participant CertificateWorkflow
  participant FabricWorkflow
  participant RMS
  participant StatusVerification
  MaintenanceHandler->>CertificateWorkflow: submit V2 certificate jobs
  CertificateWorkflow->>FabricWorkflow: transition after completion
  FabricWorkflow->>RMS: submit rack-wide fabric configuration
  RMS-->>FabricWorkflow: return asynchronous job_id
  FabricWorkflow->>RMS: poll job status
  RMS-->>FabricWorkflow: return completion state
  FabricWorkflow->>StatusVerification: verify completed configuration
  StatusVerification->>RMS: retrieve fabric and switch statuses
  RMS-->>StatusVerification: return observed statuses
  StatusVerification-->>MaintenanceHandler: persist status and complete maintenance
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding RMS v2 fabric manager support.
Description check ✅ Passed The description is directly related to the changeset and explains the new RMS v2 async workflow.
Linked Issues check ✅ Passed The PR implements the linked issue's goal by moving the NMX-C coordination into a single async RMS v2 workflow.
Out of Scope Changes check ✅ Passed No clearly unrelated changes stand out; the certificate and client updates appear necessary to support the v2 workflow.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@jayzhudev jayzhudev changed the title feat(nmx-c): support RMS v2 fabric manager configuration feat(scale-up-fabric): support RMS v2 fabric manager configuration Jul 25, 2026

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

🧹 Nitpick comments (3)
crates/api-core/src/tests/rack_state_controller/handler.rs (1)

3681-3722: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Compare the returned node IDs, not just counts. The node payloads include IDs, so these assertions should compare the sorted IDs from each request against switch_ids; count-only checks still pass for duplicated or wrong switches. Apply the same check to status_nodes and fabric_manager_status_nodes.

🤖 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/rack_state_controller/handler.rs` around lines 3681
- 3722, The assertions in the test should validate node identities rather than
only lengths. In the test block containing configure_nodes, status_nodes, and
fabric_manager_status_nodes, extract each payload’s node IDs, sort them, and
compare them with the sorted switch_ids for all three requests while preserving
the existing request-count assertions.
crates/rack-controller/src/maintenance.rs (1)

1704-1714: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider extracting the RMS client-resolution preamble.

This "prefer the NMX-configure client, fall back to the service client" sequence now appears verbatim at lines 1554-1563 and here, alongside the older if let/else variants at lines 536-553, 2698-2714 and 2845-2861. A single helper returning the resolved client (with the Arc clone where the caller must outlive a later &mut ctx borrow, as this call site requires for line 1785) would collapse five near-copies and make the lifetime distinction deliberate rather than incidental.

Entirely optional — the current code is correct as written.

🤖 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/rack-controller/src/maintenance.rs` around lines 1704 - 1714, Extract
the repeated RMS client-resolution logic into a shared helper, including
NMX-configured client preference and service-client fallback. Update the
variants around this preamble and the older if-let branches to use the helper,
preserving an owned Arc clone where callers such as the current maintenance flow
need the client to outlive a later mutable ctx borrow.
crates/rack-controller/src/fabric_manager.rs (1)

671-733: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Express this as a check_values table rather than a hand-rolled loop.

observe_primary_case already reduces the fallible call to a total PrimaryObservation, so this is a textbook input→output mapping. check_values is imported at line 465 and used by test_fabric_manager_status_from_entry in this same module; aligning keeps scenario reporting uniform across the suite.

As per coding guidelines: "Use table-driven tests for functions mapping inputs to outputs or errors. Use scenarios! with Outcome for fallible operations, value_scenarios! for total operations, and direct check_cases/check_values when macros obscure intent."

♻️ Proposed refactor to the established table-driven form
     #[test]
     fn observed_primary_switch_classifies_status_responses() {
         let second_id = SwitchId::new(SwitchIdSource::Tpm, [2; 32], SwitchType::NvLink).to_string();
 
-        for (scenario, input, expect) in [
-            (
-                "one enabled switch is the observed primary",
-                PrimaryResponseCase::Selected,
-                PrimaryObservation::Primary(second_id),
-            ),
-            (
-                "RMS failure can converge",
-                PrimaryResponseCase::RmsFailure,
-                PrimaryObservation::Retryable,
-            ),
-            (
-                "invalid RMS status violates the contract",
-                PrimaryResponseCase::InvalidStatus,
-                PrimaryObservation::Terminal,
-            ),
-            (
-                "missing fabric status violates the contract",
-                PrimaryResponseCase::MissingFabricStatus,
-                PrimaryObservation::Terminal,
-            ),
-            (
-                "unexpected switch violates the contract",
-                PrimaryResponseCase::UnexpectedSwitch,
-                PrimaryObservation::Terminal,
-            ),
-            (
-                "duplicate switch violates the contract",
-                PrimaryResponseCase::DuplicateSwitch,
-                PrimaryObservation::Terminal,
-            ),
-            (
-                "per-switch inspection failure can recover",
-                PrimaryResponseCase::InspectionFailure,
-                PrimaryObservation::Retryable,
-            ),
-            (
-                "omitted switch violates the contract",
-                PrimaryResponseCase::OmittedSwitch,
-                PrimaryObservation::Terminal,
-            ),
-            (
-                "no enabled switch can converge",
-                PrimaryResponseCase::NoPrimary,
-                PrimaryObservation::Retryable,
-            ),
-            (
-                "multiple enabled switches can converge",
-                PrimaryResponseCase::MultiplePrimaries,
-                PrimaryObservation::Retryable,
-            ),
-            (
-                "invalid primary ID violates the contract",
-                PrimaryResponseCase::InvalidPrimaryId,
-                PrimaryObservation::Terminal,
-            ),
-        ] {
-            assert_eq!(observe_primary_case(input), expect, "{scenario}");
-        }
+        check_values(
+            [
+                Check {
+                    scenario: "one enabled switch is the observed primary",
+                    input: PrimaryResponseCase::Selected,
+                    expect: PrimaryObservation::Primary(second_id),
+                },
+                Check {
+                    scenario: "RMS failure can converge",
+                    input: PrimaryResponseCase::RmsFailure,
+                    expect: PrimaryObservation::Retryable,
+                },
+                Check {
+                    scenario: "invalid RMS status violates the contract",
+                    input: PrimaryResponseCase::InvalidStatus,
+                    expect: PrimaryObservation::Terminal,
+                },
+                Check {
+                    scenario: "missing fabric status violates the contract",
+                    input: PrimaryResponseCase::MissingFabricStatus,
+                    expect: PrimaryObservation::Terminal,
+                },
+                Check {
+                    scenario: "unexpected switch violates the contract",
+                    input: PrimaryResponseCase::UnexpectedSwitch,
+                    expect: PrimaryObservation::Terminal,
+                },
+                Check {
+                    scenario: "duplicate switch violates the contract",
+                    input: PrimaryResponseCase::DuplicateSwitch,
+                    expect: PrimaryObservation::Terminal,
+                },
+                Check {
+                    scenario: "per-switch inspection failure can recover",
+                    input: PrimaryResponseCase::InspectionFailure,
+                    expect: PrimaryObservation::Retryable,
+                },
+                Check {
+                    scenario: "omitted switch violates the contract",
+                    input: PrimaryResponseCase::OmittedSwitch,
+                    expect: PrimaryObservation::Terminal,
+                },
+                Check {
+                    scenario: "no enabled switch can converge",
+                    input: PrimaryResponseCase::NoPrimary,
+                    expect: PrimaryObservation::Retryable,
+                },
+                Check {
+                    scenario: "multiple enabled switches can converge",
+                    input: PrimaryResponseCase::MultiplePrimaries,
+                    expect: PrimaryObservation::Retryable,
+                },
+                Check {
+                    scenario: "invalid primary ID violates the contract",
+                    input: PrimaryResponseCase::InvalidPrimaryId,
+                    expect: PrimaryObservation::Terminal,
+                },
+            ],
+            observe_primary_case,
+        );
     }
🤖 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/rack-controller/src/fabric_manager.rs` around lines 671 - 733, Replace
the hand-rolled loop in observed_primary_switch_classifies_status_responses with
the imported check_values table-driven assertion, preserving all existing
scenario inputs, expected PrimaryObservation values, and scenario labels. Keep
the test focused on the total observe_primary_case input-to-output mapping and
follow the check_values usage established by
test_fabric_manager_status_from_entry.

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.

Nitpick comments:
In `@crates/api-core/src/tests/rack_state_controller/handler.rs`:
- Around line 3681-3722: The assertions in the test should validate node
identities rather than only lengths. In the test block containing
configure_nodes, status_nodes, and fabric_manager_status_nodes, extract each
payload’s node IDs, sort them, and compare them with the sorted switch_ids for
all three requests while preserving the existing request-count assertions.

In `@crates/rack-controller/src/fabric_manager.rs`:
- Around line 671-733: Replace the hand-rolled loop in
observed_primary_switch_classifies_status_responses with the imported
check_values table-driven assertion, preserving all existing scenario inputs,
expected PrimaryObservation values, and scenario labels. Keep the test focused
on the total observe_primary_case input-to-output mapping and follow the
check_values usage established by test_fabric_manager_status_from_entry.

In `@crates/rack-controller/src/maintenance.rs`:
- Around line 1704-1714: Extract the repeated RMS client-resolution logic into a
shared helper, including NMX-configured client preference and service-client
fallback. Update the variants around this preamble and the older if-let branches
to use the helper, preserving an owned Arc clone where callers such as the
current maintenance flow need the client to outlive a later mutable ctx borrow.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 458ee8ce-7f6e-46a3-ab4b-eaef103da77f

📥 Commits

Reviewing files that changed from the base of the PR and between 7f3f044 and dd153de.

📒 Files selected for processing (7)
  • crates/api-core/src/cfg/README.md
  • crates/api-core/src/tests/rack_state_controller/handler.rs
  • crates/api-model/src/rack.rs
  • crates/rack-controller/src/config.rs
  • crates/rack-controller/src/fabric_manager.rs
  • crates/rack-controller/src/maintenance.rs
  • crates/rack/src/rms_client.rs

@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 (4)
crates/rack-controller/src/fabric_manager.rs (1)

613-617: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

The table collapses five distinct failure reasons into a single None.

observed_primary_switch produces five carefully differentiated diagnostics (RMS failure, missing fabric status, no primary, multiple primaries, primary outside the rack), yet .ok() discards all of them, so a regression that swaps two of those branches would still pass. Mapping the Result to Result<String, String> and asserting the expected message keeps the table honest about the contract it documents.

🤖 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/rack-controller/src/fabric_manager.rs` around lines 613 - 617, Update
the table closure around observed_primary_switch to preserve its differentiated
error diagnostics instead of discarding them with .ok(). Convert the Result to
Result<String, String> and assert the expected error message for each failure
case, while retaining the existing primary-to-string mapping for successful
cases.
crates/api-model/src/rack.rs (1)

537-540: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider surfacing the selected API version in the ConfigureCertificates display.

The state string is what the rack controller logs on transition (next_state = %configure_nmx_cluster), so discarding scale_up_fabric_manager_api_version via .. hides which of the two workflows a rack is actually executing — precisely the fact an operator debugging a stuck rack wants first.

♻️ Suggested rendering
             ConfigureNmxClusterState::ConfigureCertificates {
+                scale_up_fabric_manager_api_version,
                 configure_certificate,
-                ..
-            } => write!(f, "ConfigureCertificates({configure_certificate})"),
+            } => write!(
+                f,
+                "ConfigureCertificates({scale_up_fabric_manager_api_version:?}, {configure_certificate})"
+            ),
🤖 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-model/src/rack.rs` around lines 537 - 540, Update the
ConfigureNmxClusterState::ConfigureCertificates Display implementation to retain
and include scale_up_fabric_manager_api_version in the ConfigureCertificates
output. Ensure the rendered state distinguishes the API-version workflow while
preserving the existing configure_certificate information.
crates/rack-controller/src/config.rs (1)

105-118: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider expressing the accepted-version cases as a table-driven scenario.

The manual for loop duplicates what value_scenarios!/check_values express declaratively, and a failing iteration reports no scenario label. As per coding guidelines, "Use table-driven tests for functions mapping inputs to outputs, errors, or observable results. Use ... value_scenarios! for total operations".

♻️ Suggested table-driven form
-    #[test]
-    fn rms_config_accepts_supported_scale_up_fabric_manager_apis() {
-        for (value, expected) in [
-            ("v1", ScaleUpFabricManagerApiVersion::V1),
-            ("v2", ScaleUpFabricManagerApiVersion::V2),
-        ] {
-            let config: RmsConfig = serde_json::from_value(serde_json::json!({
-                "scale_up_fabric_manager_api_version": value
-            }))
-            .expect("supported RMS API config should deserialize");
-
-            assert_eq!(config.scale_up_fabric_manager_api_version, expected);
-        }
-    }
+    #[test]
+    fn rms_config_accepts_supported_scale_up_fabric_manager_apis() {
+        carbide_test_support::value_scenarios!(
+            run = |value: &str| {
+                serde_json::from_value::<RmsConfig>(serde_json::json!({
+                    "scale_up_fabric_manager_api_version": value
+                }))
+                .ok()
+                .map(|config| config.scale_up_fabric_manager_api_version)
+            };
+            "supported api versions" {
+                "v1" => Some(ScaleUpFabricManagerApiVersion::V1),
+                "v2" => Some(ScaleUpFabricManagerApiVersion::V2),
+            }
+        );
+    }
🤖 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/rack-controller/src/config.rs` around lines 105 - 118, Rewrite the
test rms_config_accepts_supported_scale_up_fabric_manager_apis to use the
repository’s value_scenarios! and check_values table-driven helpers instead of
the manual for loop. Represent each supported API version and expected
ScaleUpFabricManagerApiVersion as a labeled scenario, while preserving the
existing deserialization assertion and equality checks.

Source: Coding guidelines

crates/rack-controller/src/maintenance.rs (1)

1544-1599: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the shared "load complete fabric + resolve node identity" preamble.

configure_scale_up_fabric_manager_v2 and verify_scale_up_fabric_manager_v2 (lines 1805-1840) repeat the same five steps verbatim: load the fabric inventory, skip on empty, validate NVOS credentials, resolve the profile, and derive the switch node identity. Two copies of a five-branch precondition sequence will drift. A small helper returning (RackSwitchFirmwareInventory, RmsNodeIdentity) — or an outcome enum for the skip/error branches — would keep both V2 entry points on one 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/rack-controller/src/maintenance.rs` around lines 1544 - 1599, Extract
the repeated fabric-manager precondition flow from
configure_scale_up_fabric_manager_v2 and verify_scale_up_fabric_manager_v2 into
a shared helper. Have it load and validate inventory, preserve the
empty-inventory skip and profile-resolution error outcomes, resolve
rack_hardware_topology, and derive switch_node_identity_for_profile, returning
the inventory and RmsNodeIdentity (or an equivalent outcome type); update both
entry points to use this helper.
🤖 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/rack-controller/src/maintenance.rs`:
- Around line 1873-1884: Update the observed_primary handling around
observed_primary_switch so transient transport/read failures continue returning
StateHandlerOutcome::wait, while semantic verification failures (no enabled
switch, multiple enabled switches, or a primary outside the submitted rack) use
bounded retries and then call transition_to_rack_error with an actionable cause.
Preserve retry behavior for genuinely transient failures.

---

Nitpick comments:
In `@crates/api-model/src/rack.rs`:
- Around line 537-540: Update the
ConfigureNmxClusterState::ConfigureCertificates Display implementation to retain
and include scale_up_fabric_manager_api_version in the ConfigureCertificates
output. Ensure the rendered state distinguishes the API-version workflow while
preserving the existing configure_certificate information.

In `@crates/rack-controller/src/config.rs`:
- Around line 105-118: Rewrite the test
rms_config_accepts_supported_scale_up_fabric_manager_apis to use the
repository’s value_scenarios! and check_values table-driven helpers instead of
the manual for loop. Represent each supported API version and expected
ScaleUpFabricManagerApiVersion as a labeled scenario, while preserving the
existing deserialization assertion and equality checks.

In `@crates/rack-controller/src/fabric_manager.rs`:
- Around line 613-617: Update the table closure around observed_primary_switch
to preserve its differentiated error diagnostics instead of discarding them with
.ok(). Convert the Result to Result<String, String> and assert the expected
error message for each failure case, while retaining the existing
primary-to-string mapping for successful cases.

In `@crates/rack-controller/src/maintenance.rs`:
- Around line 1544-1599: Extract the repeated fabric-manager precondition flow
from configure_scale_up_fabric_manager_v2 and verify_scale_up_fabric_manager_v2
into a shared helper. Have it load and validate inventory, preserve the
empty-inventory skip and profile-resolution error outcomes, resolve
rack_hardware_topology, and derive switch_node_identity_for_profile, returning
the inventory and RmsNodeIdentity (or an equivalent outcome type); update both
entry points to use this helper.
🪄 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: f38a2df3-435a-4592-ad25-1d30fcd85fc2

📥 Commits

Reviewing files that changed from the base of the PR and between dd153de and c5baf83.

📒 Files selected for processing (16)
  • crates/api-core/src/cfg/README.md
  • crates/api-core/src/handlers/component_manager.rs
  • crates/api-core/src/tests/rack_state_controller/handler.rs
  • crates/api-core/src/tests/rack_state_controller/mod.rs
  • crates/api-model/src/rack.rs
  • crates/component-manager/src/component_manager.rs
  • crates/component-manager/src/mock.rs
  • crates/component-manager/src/nsm.rs
  • crates/component-manager/src/nv_switch_manager.rs
  • crates/component-manager/src/rms.rs
  • crates/rack-controller/src/config.rs
  • crates/rack-controller/src/fabric_manager.rs
  • crates/rack-controller/src/maintenance.rs
  • crates/rack-controller/src/nmx_certificate.rs
  • crates/rack/src/rms_client.rs
  • crates/switch-controller/src/certificate.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/api-core/src/tests/rack_state_controller/handler.rs

Comment thread crates/rack-controller/src/maintenance.rs
Signed-off-by: Jay Zhu <jayzhu@nvidia.com>
@jayzhudev
jayzhudev force-pushed the feat/nmx-c-configure-v2 branch from c5baf83 to cc97a04 Compare July 27, 2026 06:21

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

🧹 Nitpick comments (1)
crates/rack-controller/src/fabric_manager.rs (1)

423-423: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add missing scenarios for the two newly introduced failure branches.

The scenario table exercises RMS failure, missing fabric status, zero/multiple enabled switches, and an enabled switch outside the submitted rack, but doesn't cover:

  • An enabled switch whose node_id fails SwitchId::from_str parsing (Lines 363-371 of observed_primary_switch).
  • An enabled, submitted switch that reports a non-empty per-switch error_message (Lines 383-388).

Both branches gate whether a candidate primary switch is accepted before being persisted as the rack's primary, so it's worth locking down their behavior with the same table-driven approach already used here.

♻️ Sketch of additional scenarios
         let switch_status = |node_id: &str, enabled| rms::ScaleUpFabricSwitchStatus {
             node_id: node_id.to_string(),
             enabled,
             ..Default::default()
         };
+
+        let switch_status_with_error =
+            |node_id: &str, enabled, error_message: &str| rms::ScaleUpFabricSwitchStatus {
+                node_id: node_id.to_string(),
+                enabled,
+                error_message: error_message.to_string(),
+                ..Default::default()
+            };

Add corresponding Check entries for: enabled_switch.node_id set to a non-SwitchId string, and an enabled/submitted switch with switch_status_with_error(&first_id, true, "inspection failed"), both expecting None.

Also applies to: 534-620

🤖 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/rack-controller/src/fabric_manager.rs` at line 423, Add two
table-driven Check scenarios to the existing scenario table around
observed_primary_switch: one with an enabled switch whose node_id is an invalid
SwitchId string, and one using switch_status_with_error(&first_id, true,
"inspection failed") for an enabled submitted switch. Set both expected results
to None, preserving the existing scenario structure and helpers.
🤖 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.

Nitpick comments:
In `@crates/rack-controller/src/fabric_manager.rs`:
- Line 423: Add two table-driven Check scenarios to the existing scenario table
around observed_primary_switch: one with an enabled switch whose node_id is an
invalid SwitchId string, and one using switch_status_with_error(&first_id, true,
"inspection failed") for an enabled submitted switch. Set both expected results
to None, preserving the existing scenario structure and helpers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a035281f-0074-498e-ad74-cc806551c406

📥 Commits

Reviewing files that changed from the base of the PR and between c5baf83 and cc97a04.

📒 Files selected for processing (16)
  • crates/api-core/src/cfg/README.md
  • crates/api-core/src/handlers/component_manager.rs
  • crates/api-core/src/tests/rack_state_controller/handler.rs
  • crates/api-core/src/tests/rack_state_controller/mod.rs
  • crates/api-model/src/rack.rs
  • crates/component-manager/src/component_manager.rs
  • crates/component-manager/src/mock.rs
  • crates/component-manager/src/nsm.rs
  • crates/component-manager/src/nv_switch_manager.rs
  • crates/component-manager/src/rms.rs
  • crates/rack-controller/src/config.rs
  • crates/rack-controller/src/fabric_manager.rs
  • crates/rack-controller/src/maintenance.rs
  • crates/rack-controller/src/nmx_certificate.rs
  • crates/rack/src/rms_client.rs
  • crates/switch-controller/src/certificate.rs
🚧 Files skipped from review as they are similar to previous changes (15)
  • crates/component-manager/src/mock.rs
  • crates/component-manager/src/nsm.rs
  • crates/api-core/src/tests/rack_state_controller/mod.rs
  • crates/component-manager/src/component_manager.rs
  • crates/api-core/src/cfg/README.md
  • crates/rack-controller/src/nmx_certificate.rs
  • crates/api-core/src/handlers/component_manager.rs
  • crates/switch-controller/src/certificate.rs
  • crates/component-manager/src/nv_switch_manager.rs
  • crates/api-model/src/rack.rs
  • crates/rack-controller/src/config.rs
  • crates/rack/src/rms_client.rs
  • crates/component-manager/src/rms.rs
  • crates/api-core/src/tests/rack_state_controller/handler.rs
  • crates/rack-controller/src/maintenance.rs

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.

feat: move nmxconfiguration sequence from NICo to RMS

1 participant