Skip to content

Make a first-class DeviceId type - #4381

Merged
kensimon merged 3 commits into
NVIDIA:mainfrom
kensimon:common-device-id
Jul 30, 2026
Merged

Make a first-class DeviceId type#4381
kensimon merged 3 commits into
NVIDIA:mainfrom
kensimon:common-device-id

Conversation

@kensimon

@kensimon kensimon commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

BmcCredentialRotationRequest has a use case where we pass one of a few different Device ID types that are parseable (MachineId, SwitchId, PowerShelfId)... make this a first-class carbide_uuid type instead of a type embedded in that message. It allows cleaning up some of the admin-cli code, using a DeviceId directly instead of explicit --machine-id/--switch-id flags.

The PR #4344 actually broke the RPC wire format for BmcCredentialRotationRequest, but since this message is not part of a released branch yet, I've opted not to un-break it and instead have broken it a bit further by changing the field type of DeviceId.

Related issues

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

This breaks the BmcCredentialRotationRequest message format, but BmcCredentialRotationRequest is not part of the 2.0 release, and 2.1 hasn't branched yet, so we don't yet consider that message "supported". Such breakages should be considered acceptable.

Testing

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

Additional Notes

BmcCredentialRotationRequest has a use case where we pass one of a few
different Device ID types that are parseable (MachineId, SwitchId,
PowerShelfId)... make this a first-class carbide_uuid type instead of a
type embedded in that message. It allows cleaning up some of the
admin-cli code, using a DeviceId directly instead of explicit
--machine-id/--switch-id flags.

The PR NVIDIA#4344 actually broke the RPC wire format for
BmcCredentialRotationRequest, so this also puts that back: leave
MachineId its own field and mark it deprecated, and put the field
numbering back too. 4344 was also the one to add the --switch-id flag to
the admin-cli, so removing it shouldn't be a problem (it was merged
hours ago.)
@kensimon
kensimon requested a review from a team as a code owner July 30, 2026 17:12
@kensimon

Copy link
Copy Markdown
Contributor Author

@spydaNVIDIA (This was originally PR feedback on #4344 but it merged before I could request changes.)

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 81706ed7-7fc2-47ad-af5c-3e5a9c8ebe0d

📥 Commits

Reviewing files that changed from the base of the PR and between b4e8501 and 13ae6aa.

📒 Files selected for processing (1)
  • crates/uuid/src/device/mod.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/uuid/src/device/mod.rs

Summary by CodeRabbit

  • New Features
    • Unified BMC credential rotation target selection for machines, switches, and power-shelf IDs using a single --id selector (with --bmc-mac as an alternative).
    • Updated command help text, examples, and confirmation messaging for the new --id workflow and forward-compatibility wording.
  • Bug Fixes
    • Improved request validation and error handling to consistently reject unsupported power-shelf rotation targets and mismatched device_id/bmc_mac ownership.
    • Updated CLI parsing behavior so requests fail when neither --id nor --bmc-mac is provided.

Walkthrough

The PR introduces shared DeviceId targeting, updates BMC rotation protobuf contracts and API validation, and changes force-BMC CLI commands to use a unified --id selector for machine, switch, and power-shelf identifiers.

Changes

BMC device targeting

Layer / File(s) Summary
DeviceId type and identifier parsing
crates/uuid/src/{lib,machine,power_shelf,switch}/mod.rs, crates/uuid/src/device/mod.rs
Exports DeviceId and standardizes device-prefix matching, formatting, parsing, and parse-error text.
Rotation protobuf contracts
crates/rpc/proto/{common,forge}.proto, rest-api/proto/core/src/v1/{common_nico,nico_nico}.proto, crates/rpc/build.rs, crates/rpc/src/lib.rs
Adds shared DeviceId messages, removes legacy machine targeting, updates field numbers, maps generated types, and verifies wire round-tripping.
Target resolution and validation
crates/api-core/src/handlers/bmc_credential_rotation.rs
Resolves device IDs and BMC MAC ownership, validates mismatches, rejects power-shelf rotation, and records requests.
Force-BMC CLI integration
crates/admin-cli/src/credential/force_bmc/{args,cmd}.rs
Uses --id for typed targets, updates request mapping and help text, validates selectors, and formats confirmation targets.

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

Sequence Diagram(s)

sequenceDiagram
  participant AdminCLI
  participant BmcCredentialRotationHandler
  participant TargetResolver
  participant MachineOrSwitchLookup
  AdminCLI->>BmcCredentialRotationHandler: Submit DeviceId and/or bmc_mac
  BmcCredentialRotationHandler->>TargetResolver: Resolve and validate identifiers
  TargetResolver->>MachineOrSwitchLookup: Resolve BMC MAC owner
  MachineOrSwitchLookup-->>TargetResolver: Machine or switch DeviceId
  TargetResolver-->>BmcCredentialRotationHandler: Validated target
  BmcCredentialRotationHandler-->>AdminCLI: Record rotation request
Loading

Possibly related PRs

Suggested labels: rest-api

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly reflects the main change: introducing DeviceId as a first-class type and using it across the PR.
Description check ✅ Passed The description is directly about the same refactor and breaking protocol change, so it is clearly on-topic.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@github-actions

Copy link
Copy Markdown

🔐 TruffleHog Secret Scan

No secrets or credentials found!

Your code has been scanned for 700+ types of secrets and credentials. All clear! 🎉

🔗 View scan details

🕐 Last updated: 2026-07-30 17:18:43 UTC | Commit: 4373b10

Comment thread rest-api/proto/core/src/v1/nico_nico.proto Outdated
Comment thread crates/admin-cli/src/credential/force_bmc/args.rs Outdated

@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: 2

🧹 Nitpick comments (1)
crates/api-core/src/handlers/bmc_credential_rotation.rs (1)

43-78: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the repeated "power shelf ... not yet supported" message into a shared helper/constant.

The exact string "power shelf BMC credential rotation is not yet supported" is duplicated four times across this file (reject_unsupported_device_id, resolve_target, and both Mode::Set/Mode::Clear arms in trigger_bmc_credential_rotation). A future wording tweak risks silently drifting between call sites. Consider a single fn power_shelf_unsupported_error() -> CarbideError (or a const message) reused everywhere. The .expect("a mac target implies a parsed mac") literal in resolve_target is similarly duplicated four times and could share the same treatment.

Note also that, because reject_unsupported_device_id already filters out DeviceId::PowerShelf before resolve_target is ever invoked (and resolve_mac_owner only ever returns Machine/Switch), the DeviceId::PowerShelf(_) arms inside trigger_bmc_credential_rotation's Mode::Set/Mode::Clear matches are currently unreachable in practice — they only exist to satisfy exhaustiveness. Worth a comment noting this invariant so a future refactor doesn't assume they're live paths.

♻️ Suggested extraction
+fn power_shelf_unsupported() -> CarbideError {
+    CarbideError::InvalidArgument(
+        "power shelf BMC credential rotation is not yet supported".to_string(),
+    )
+}
+
 fn reject_unsupported_device_id(
     device_id: Option<DeviceId>,
 ) -> Result<Option<DeviceId>, CarbideError> {
     match device_id {
-        Some(DeviceId::PowerShelf(_)) => Err(CarbideError::InvalidArgument(
-            "power shelf BMC credential rotation is not yet supported".to_string(),
-        )),
+        Some(DeviceId::PowerShelf(_)) => Err(power_shelf_unsupported()),
         device_id => Ok(device_id),
     }
 }

Also applies to: 113-122, 152-199

🤖 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/handlers/bmc_credential_rotation.rs` around lines 43 -
78, Extract the duplicated power-shelf unsupported error text and the repeated
parsed-MAC expectation message into shared helpers or constants, then reuse them
in reject_unsupported_device_id, resolve_target, and both Mode::Set/Mode::Clear
branches of trigger_bmc_credential_rotation. Add a comment to the PowerShelf
arms in trigger_bmc_credential_rotation noting they are unreachable because
reject_unsupported_device_id filters that variant and resolve_mac_owner returns
only Machine or Switch.
🤖 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/uuid/src/device/mod.rs`:
- Around line 266-275: Update the error messages in the DeviceIdParseError enum
to use lowercase phrases, changing “Invalid” and “Unable” in the Machine,
Switch, PowerShelf, and UnknownId variants while preserving their existing
wording and interpolation.
- Around line 149-154: Update the DeviceId conversion/parsing logic around the
Default implementation so a present but empty device_id message is rejected with
an error instead of falling back to MachineId::default(). Preserve valid device
ID variants, and add a regression test covering device_id {}.

---

Nitpick comments:
In `@crates/api-core/src/handlers/bmc_credential_rotation.rs`:
- Around line 43-78: Extract the duplicated power-shelf unsupported error text
and the repeated parsed-MAC expectation message into shared helpers or
constants, then reuse them in reject_unsupported_device_id, resolve_target, and
both Mode::Set/Mode::Clear branches of trigger_bmc_credential_rotation. Add a
comment to the PowerShelf arms in trigger_bmc_credential_rotation noting they
are unreachable because reject_unsupported_device_id filters that variant and
resolve_mac_owner returns only Machine or Switch.
🪄 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: 4608b157-bb10-4417-af4a-8e5f260fce0d

📥 Commits

Reviewing files that changed from the base of the PR and between 9a2e537 and 4373b10.

⛔ Files ignored due to path filters (2)
  • rest-api/proto/core/gen/v1/common_nico.pb.go is excluded by !**/*.pb.go, !**/gen/**, !rest-api/**/*.pb.go
  • rest-api/proto/core/gen/v1/nico_nico.pb.go is excluded by !**/*.pb.go, !**/gen/**, !rest-api/**/*.pb.go
📒 Files selected for processing (14)
  • crates/admin-cli/src/credential/force_bmc/args.rs
  • crates/admin-cli/src/credential/force_bmc/cmd.rs
  • crates/api-core/src/handlers/bmc_credential_rotation.rs
  • crates/rpc/build.rs
  • crates/rpc/proto/common.proto
  • crates/rpc/proto/forge.proto
  • crates/rpc/src/lib.rs
  • crates/uuid/src/device/mod.rs
  • crates/uuid/src/lib.rs
  • crates/uuid/src/machine/mod.rs
  • crates/uuid/src/power_shelf/mod.rs
  • crates/uuid/src/switch/mod.rs
  • rest-api/proto/core/src/v1/common_nico.proto
  • rest-api/proto/core/src/v1/nico_nico.proto

Comment thread crates/uuid/src/device/mod.rs
Comment thread crates/uuid/src/device/mod.rs
Since BmcCredentialRotationRequest has not landed in a release yet (it
won't be a part of 2.0, and 2.1 hasn't branched yet) we don't need to
consider it "supported", so we should be ok breaking it.

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

lgtm

@kensimon
kensimon enabled auto-merge (squash) July 30, 2026 17:51

@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/api-core/src/handlers/bmc_credential_rotation.rs (1)

208-235: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add coverage for the target-resolution matrix.

The remaining tests cover only reject_unsupported_device_id; they do not exercise resolve_target or resolve_mac_owner. Add table-driven cases for device-only, MAC-only, matching and mismatched selectors, unknown MACs, missing selectors, and legacy-selector translation.

As per coding guidelines, Rust input/output and error variants should use table-driven cases; as per path instructions, prioritize missing tests for changed behavior.

🤖 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/handlers/bmc_credential_rotation.rs` around lines 208 -
235, Extend the test module with table-driven coverage for resolve_target and
resolve_mac_owner, covering device-only, MAC-only, matching and mismatched
selectors, unknown MACs, missing selectors, and legacy-selector translation.
Reuse the existing MachineId, SwitchId, PowerShelfId, and scenario-style test
setup where applicable, and assert each expected resolved owner or specific
error variant.

Sources: Coding guidelines, Path instructions

🤖 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/handlers/bmc_credential_rotation.rs`:
- Around line 208-235: Extend the test module with table-driven coverage for
resolve_target and resolve_mac_owner, covering device-only, MAC-only, matching
and mismatched selectors, unknown MACs, missing selectors, and legacy-selector
translation. Reuse the existing MachineId, SwitchId, PowerShelfId, and
scenario-style test setup where applicable, and assert each expected resolved
owner or specific error variant.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 573c2a24-2fdb-42ae-8916-49d3e34f4875

📥 Commits

Reviewing files that changed from the base of the PR and between 4373b10 and b4e8501.

⛔ Files ignored due to path filters (1)
  • rest-api/proto/core/gen/v1/nico_nico.pb.go is excluded by !**/*.pb.go, !**/gen/**, !rest-api/**/*.pb.go
📒 Files selected for processing (5)
  • crates/admin-cli/src/credential/force_bmc/args.rs
  • crates/api-core/src/handlers/bmc_credential_rotation.rs
  • crates/rpc/proto/forge.proto
  • crates/rpc/src/lib.rs
  • rest-api/proto/core/src/v1/nico_nico.proto
💤 Files with no reviewable changes (2)
  • crates/admin-cli/src/credential/force_bmc/args.rs
  • crates/rpc/src/lib.rs

@kensimon
kensimon merged commit 70a64d3 into NVIDIA:main Jul 30, 2026
118 of 119 checks passed
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.

3 participants