Skip to content

feat(admin-cli): add --host_nics to expected-machine patch#3360

Open
lauragra-y wants to merge 1 commit into
NVIDIA:mainfrom
lauragra-y:expected-machine-patch-host-nics
Open

feat(admin-cli): add --host_nics to expected-machine patch#3360
lauragra-y wants to merge 1 commit into
NVIDIA:mainfrom
lauragra-y:expected-machine-patch-host-nics

Conversation

@lauragra-y

@lauragra-y lauragra-y commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Description

nico-admin-cli expected-machine patch could not update a machine's host NICs: the merge path in patch_expected_machine preserved the existing list behind an old TODO(chet), so the field was never patchable.

This exposes --host_nics on patch, mirroring expected-machine add - a JSON array of ExpectedHostNic that full-replaces the machine's host NIC list. Omitting the flag preserves the existing list; --host_nics '[]' clears it.

Also fixes a pre-existing bug this path newly exposes: partial patches passed the raw --sku-id straight through, and the DB update binds sku_id directly (not COALESCE), so any patch without --sku-id (now including a host-NIC-only patch) silently cleared an existing SKU. It now falls back to the stored value via .or(expected_machine.sku_id), matching the other preserved fields.

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

Related Issues (Optional)

Closes #3376

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

Additional Notes

@copy-pr-bot

copy-pr-bot Bot commented Jul 10, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The expected-machine patch command adds a --host_nics JSON argument, validates it as a patch option, forwards it through the API client, and preserves stored host NICs for file-based updates.

Changes

Expected-machine host NIC patching

Layer / File(s) Summary
CLI host NIC patch contract
crates/admin-cli/src/expected_machines/patch/args.rs, crates/admin-cli/src/expected_machines/tests.rs
Adds host_nics to clap’s required patch options, exposes it on Args, includes it in validation, and tests host-NIC-only patches.
Patch forwarding and RPC mapping
crates/admin-cli/src/expected_machines/patch/mod.rs, crates/admin-cli/src/rpc.rs
Forwards host NIC input to patch_expected_machine, parses provided JSON into RPC host NICs, and preserves stored values when omitted.
File-based update preservation
crates/admin-cli/src/expected_machines/update/mod.rs
Passes None for host NICs during file-based updates, preserving the server-side list.

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

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: adding --host_nics to expected-machine patch.
Description check ✅ Passed The description accurately covers the host_nics patch behavior and the sku_id preservation fix.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@lauragra-y lauragra-y force-pushed the expected-machine-patch-host-nics branch 4 times, most recently from bafc611 to fabc496 Compare July 10, 2026 11:08
`expected-machine patch` could not update a machine's host NICs -- the
merge path preserved the existing list (per an old TODO). Expose
`--host_nics` on patch, mirroring `expected-machine add`: a JSON array
of ExpectedHostNic that full-replaces the machine's host NIC list.
Omitting the flag preserves the existing list.

Also preserve sku_id on partial patches: the merge passed the raw
`--sku-id` param straight through, and the DB update binds sku_id
directly (not COALESCE), so any patch without `--sku-id` (now including
a host-NIC-only patch) silently cleared an existing SKU. Fall back to
the stored value with `.or(expected_machine.sku_id)`, matching the
other preserved fields.

File-based `expected-machine update` keeps its prior behavior (host_nics
untouched); its JSON cannot distinguish an omitted list from a cleared
one, so wiring that through is left as a separate change.
@lauragra-y lauragra-y force-pushed the expected-machine-patch-host-nics branch from fabc496 to 5f38986 Compare July 10, 2026 11:57
@lauragra-y lauragra-y marked this pull request as ready for review July 10, 2026 11:58
@lauragra-y lauragra-y requested a review from a team as a code owner July 10, 2026 11:58

@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 (6)
crates/admin-cli/src/rpc.rs (3)

810-812: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Doc comment doesn't call out host_nics's full-replace semantics.

Unlike labels/metadata (merged field-by-field), host_nics fully replaces the stored list when provided (including clearing it with []). Worth a line in the doc comment so future readers don't assume merge semantics.

🤖 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/admin-cli/src/rpc.rs` around lines 810 - 812, Update the doc comment
for the partial expected-machine update function near `update_expected_machine`
to explicitly state that a provided `host_nics` list fully replaces the stored
list, including that `[]` clears it, unlike field-by-field merged labels and
metadata.

813-834: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Parameter list keeps growing on an already-#[allow(clippy::too_many_arguments)]'d function.

patch_expected_machine now takes 19 parameters and still needs the clippy allow it already carries. Per repo style guide, code with "a large struct with lots of required fields and lots of non-required fields" should be split into a required-fields type plus a Config/Params type for the rest — the same principle applies to this parameter list. Consolidating into a PatchExpectedMachineRequest { .. } struct literal would let this allow be removed and make future additions (like host_nics here) additive without further bloating the signature.

🤖 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/admin-cli/src/rpc.rs` around lines 813 - 834, Refactor
patch_expected_machine to accept a PatchExpectedMachineRequest struct containing
the current parameters, separating required fields from optional configuration
fields as appropriate. Update all callers to construct a
PatchExpectedMachineRequest literal, preserve existing behavior and validation,
and remove the #[allow(clippy::too_many_arguments)] attribute from
patch_expected_machine.

Source: Coding guidelines


906-909: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

JSON parse error lacks field context, and the parser itself is untested.

.transpose()? propagates a bare serde_json::Error with no indication it came from --host_nics, contrary to this crate's guidance to write error chains that read as a coherent "while attempting to …" story. Additionally, this JSON→Vec<ExpectedHostNic> conversion is a pure parser with zero test coverage; per the style guide, parsers/conversions should get table-driven scenarios!/value_scenarios! coverage, which is easiest if extracted into a small named function.

♻️ Suggested tweak for actionable error context
-            host_nics: host_nics
-                .map(|s| serde_json::from_str::<Vec<rpc::ExpectedHostNic>>(&s))
-                .transpose()?
-                .unwrap_or(expected_machine.host_nics),
+            host_nics: host_nics
+                .map(|s| {
+                    serde_json::from_str::<Vec<rpc::ExpectedHostNic>>(&s).map_err(|e| {
+                        CarbideCliError::GenericError(format!(
+                            "invalid --host_nics JSON while patching expected machine: {e}"
+                        ))
+                    })
+                })
+                .transpose()?
+                .unwrap_or(expected_machine.host_nics),
#!/bin/bash
# Confirm CarbideCliError's conversion from serde_json::Error (used implicitly via `?` here and in update/mod.rs)
rg -n "From<serde_json::Error>|serde_json::Error" crates/admin-cli/src -A3 -B3
🤖 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/admin-cli/src/rpc.rs` around lines 906 - 909, Extract the
`--host_nics` JSON conversion from the surrounding RPC construction into a named
parser function, such as `parse_host_nics`, returning
`Result<Vec<rpc::ExpectedHostNic>, _>`. Add field-specific context to its
deserialization error so the chain clearly identifies `--host_nics`, then use
the helper in the `host_nics` assignment while preserving the default fallback.
Add table-driven `scenarios!` or `value_scenarios!` tests covering valid JSON,
invalid JSON, and relevant empty/default cases.

Source: Coding guidelines

crates/admin-cli/src/expected_machines/patch/args.rs (2)

221-260: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Validate host_nics JSON eagerly instead of deferring to patch_expected_machine.

validate() only checks that host_nics is present, not that it's well-formed JSON. Malformed input is only caught deep inside patch_expected_machine (crates/admin-cli/src/rpc.rs), after an unnecessary get_expected_machine round-trip. Parsing (and surfacing the error) here would fail fast and keep the RPC parsing logic simpler.

♻️ Proposed eager-validation sketch
         if self
             .fallback_dpu_serial_numbers
             .as_ref()
             .is_some_and(has_duplicates)
         {
             return Err(CarbideCliError::GenericError(
                 "Duplicate dpu serial numbers found".to_string(),
             ));
         }
+        if let Some(json) = &self.host_nics {
+            serde_json::from_str::<Vec<::rpc::forge::ExpectedHostNic>>(json).map_err(|e| {
+                CarbideCliError::GenericError(format!("invalid --host_nics JSON: {e}"))
+            })?;
+        }
         Ok(())
🤖 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/admin-cli/src/expected_machines/patch/args.rs` around lines 221 - 260,
Update Args::validate to eagerly parse self.host_nics when present, returning a
CarbideCliError containing the JSON parsing failure; leave it absent as valid.
Then simplify patch_expected_machine’s host_nics handling by using the
already-validated representation or retaining only the necessary conversion
without deferring malformed-JSON errors until after get_expected_machine.

205-212: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a --host_nics example to the EXAMPLES: block. The help text already covers the command, but it still does not show the JSON array payload for --host_nics; add one copy-pasteable invocation so operators can see the expected format.

🤖 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/admin-cli/src/expected_machines/patch/args.rs` around lines 205 - 212,
Add a copy-pasteable `--host_nics` invocation to the `EXAMPLES:` block
associated with the expected-machine patch arguments, using a JSON array
containing the documented fields and valid shell quoting. Keep the example
consistent with the `host_nics` option defined in the `host_nics` argument
declaration.

Sources: Coding guidelines, Path instructions

crates/admin-cli/src/expected_machines/update/mod.rs (1)

78-80: 🗄️ Data Integrity & Integration | 🔵 Trivial

TODO acknowledged — file-based update intentionally doesn't touch host_nics yet.

Passing None correctly preserves the stored list given rpc.rs's unwrap_or(expected_machine.host_nics) fallback, and this matches the PR's stated scope (file-based update behavior unchanged). Once ready, wiring expected_machine.host_nics in here (serialized to JSON, matching the --host_nics contract) would close the gap with the patch command. Happy to draft that follow-up if useful.

🤖 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/admin-cli/src/expected_machines/update/mod.rs` around lines 78 - 80,
Leave the file-based update behavior unchanged: retain None at the host_nics
argument in the update flow so rpc.rs preserves the stored list via its
fallback. Treat wiring expected_machine.host_nics as a separate follow-up,
serialized to JSON consistently with the --host_nics contract and patch command.
🤖 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/admin-cli/src/expected_machines/patch/args.rs`:
- Around line 221-260: Update Args::validate to eagerly parse self.host_nics
when present, returning a CarbideCliError containing the JSON parsing failure;
leave it absent as valid. Then simplify patch_expected_machine’s host_nics
handling by using the already-validated representation or retaining only the
necessary conversion without deferring malformed-JSON errors until after
get_expected_machine.
- Around line 205-212: Add a copy-pasteable `--host_nics` invocation to the
`EXAMPLES:` block associated with the expected-machine patch arguments, using a
JSON array containing the documented fields and valid shell quoting. Keep the
example consistent with the `host_nics` option defined in the `host_nics`
argument declaration.

In `@crates/admin-cli/src/expected_machines/update/mod.rs`:
- Around line 78-80: Leave the file-based update behavior unchanged: retain None
at the host_nics argument in the update flow so rpc.rs preserves the stored list
via its fallback. Treat wiring expected_machine.host_nics as a separate
follow-up, serialized to JSON consistently with the --host_nics contract and
patch command.

In `@crates/admin-cli/src/rpc.rs`:
- Around line 810-812: Update the doc comment for the partial expected-machine
update function near `update_expected_machine` to explicitly state that a
provided `host_nics` list fully replaces the stored list, including that `[]`
clears it, unlike field-by-field merged labels and metadata.
- Around line 813-834: Refactor patch_expected_machine to accept a
PatchExpectedMachineRequest struct containing the current parameters, separating
required fields from optional configuration fields as appropriate. Update all
callers to construct a PatchExpectedMachineRequest literal, preserve existing
behavior and validation, and remove the #[allow(clippy::too_many_arguments)]
attribute from patch_expected_machine.
- Around line 906-909: Extract the `--host_nics` JSON conversion from the
surrounding RPC construction into a named parser function, such as
`parse_host_nics`, returning `Result<Vec<rpc::ExpectedHostNic>, _>`. Add
field-specific context to its deserialization error so the chain clearly
identifies `--host_nics`, then use the helper in the `host_nics` assignment
while preserving the default fallback. Add table-driven `scenarios!` or
`value_scenarios!` tests covering valid JSON, invalid JSON, and relevant
empty/default cases.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b8094938-4625-4f3e-8939-977236d9aea1

📥 Commits

Reviewing files that changed from the base of the PR and between 16d6e35 and 5f38986.

📒 Files selected for processing (5)
  • crates/admin-cli/src/expected_machines/patch/args.rs
  • crates/admin-cli/src/expected_machines/patch/mod.rs
  • crates/admin-cli/src/expected_machines/tests.rs
  • crates/admin-cli/src/expected_machines/update/mod.rs
  • crates/admin-cli/src/rpc.rs

@github-actions

Copy link
Copy Markdown

🔍 Container Scan Summary

Service Total Critical High Medium Low Other
boot-artifacts-aarch64 3 0 0 3 0 0
boot-artifacts-x86_64 3 0 0 3 0 0
forge-admin-cli-x86_64 271 13 34 91 7 126
machine-validation-runner 804 40 237 296 36 195
machine_validation 804 40 237 296 36 195
machine_validation-aarch64 804 40 237 296 36 195
nvmetal-carbide 804 40 237 296 36 195
TOTAL 3493 173 982 1281 151 906

Per-CVE detail lives in the per-service grype-* artifacts (JSON + SARIF). Severity counts only — no CVE IDs published here.

@lauragra-y lauragra-y self-assigned this Jul 10, 2026
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.

feat: admin-cli expected-machine patch: support updating a machine's host NICs

3 participants