Skip to content

fix(nvue-client): Add polling in NvueClient::apply_config_revision - #4729

Merged
DrewBloechl merged 6 commits into
NVIDIA:mainfrom
DrewBloechl:drew/agent-nvue-config-apply
Aug 10, 2026
Merged

fix(nvue-client): Add polling in NvueClient::apply_config_revision#4729
DrewBloechl merged 6 commits into
NVIDIA:mainfrom
DrewBloechl:drew/agent-nvue-config-apply

Conversation

@DrewBloechl

@DrewBloechl DrewBloechl commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

I've been overly optimistic in NvueClient::apply_config_revision(), assuming that we don't need to care about checking the state of the revision we just applied. QA found a bug (tracked internally as NVbugs 6563638) that suggests this was a mistake. This branch adds polling logic in apply_config_revision(), with parsing of the revision data derived from the OpenAPI spec from NVUE in Cumulus Linux 5.16.0 (the most recent version I had handy).

Related issues

  • NVbugs 6563638

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

Additional Notes

@DrewBloechl DrewBloechl self-assigned this Aug 7, 2026
@DrewBloechl
DrewBloechl requested a review from a team as a code owner August 7, 2026 22:02
@copy-pr-bot

copy-pr-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Aug 7, 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: b6313ebf-c29c-46c2-a498-d00086b46981

📥 Commits

Reviewing files that changed from the base of the PR and between d04f9d8 and 7ac16bf.

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

Summary by CodeRabbit

  • New Features
    • Added revision status tracking when applying configuration changes.
    • Applications now receive clear success, failure, and timeout results, including relevant issue details.
    • Added support for retrieving revision information and interpreting transition progress.
    • Added structured MAC table entry data with optional VLAN information.

Walkthrough

The client adds revision response models, status classification, revision retrieval, and polling for configuration application. It reports applied, failed, and timed-out revisions with structured error details. The public types module now exposes revision types and MacTableEntry.

Changes

Revision Apply Status

Layer / File(s) Summary
Revision response models and type exports
crates/nvue-client/src/lib.rs, crates/nvue-client/src/types/*
The public types module now exposes RevisionData, revision issue types, revision severity types, and MacTableEntry. Revision models deserialize NVUE responses and classify applied, pending, and failed states. Tests cover classification and JSON parsing.
Revision retrieval and apply polling
crates/nvue-client/Cargo.toml, crates/nvue-client/src/client.rs
NvueClient now provides get_revision and polls configuration revision status at one-second intervals for up to 45 seconds. Applied revisions succeed. Failed and timed-out revisions return structured errors with state, progress, and issue details.

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

Sequence Diagram(s)

sequenceDiagram
  participant NvueClient
  participant NVUE_API
  participant RevisionData
  NvueClient->>NVUE_API: apply configuration revision
  NVUE_API-->>NvueClient: revision identifier
  NvueClient->>NVUE_API: get revision status
  NVUE_API-->>NvueClient: revision response
  NvueClient->>RevisionData: classify status and extract issues
  RevisionData-->>NvueClient: applied, pending, or failed
  NvueClient->>NVUE_API: poll pending revision after interval
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: adding polling to NvueClient::apply_config_revision.
Description check ✅ Passed The description directly explains the polling fix, its motivation, affected API, testing, and related issue.
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.

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

🤖 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/nvue-client/src/client.rs`:
- Around line 150-155: Update the NvueClientError::SchemaMismatch message in the
revision response handling to use the lowercase text “revision response was
null”.
- Around line 192-224: Update the revision polling loop around get_revision to
check the deadline before each request and wrap the request in
tokio::time::timeout using the remaining duration. Convert an expired
pre-request deadline or timed-out response into
RevisionApplyFailureReason::Timeout, including the elapsed wait and latest
available revision context, so delayed Applied responses cannot return success;
add a test covering a delayed response within the configured deadline budget.
- Around line 145-147: Update get_revision and apply_config_revision to
percent-encode revision_id as a single URL path segment before constructing
their NVUE URLs, and update replace_config_revision to encode revision_id as a
query parameter value. Preserve the existing request behavior while ensuring IDs
containing URL-reserved characters are not interpreted as URL syntax.
🪄 Autofix

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: 8f6eea00-24fb-422a-84d9-6136dda42c79

📥 Commits

Reviewing files that changed from the base of the PR and between e05a814 and d04f9d8.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • crates/nvue-client/Cargo.toml
  • crates/nvue-client/src/client.rs
  • crates/nvue-client/src/lib.rs
  • crates/nvue-client/src/types/mod.rs
  • crates/nvue-client/src/types/revision.rs

Comment on lines +145 to +147
pub async fn get_revision(&self, revision_id: &str) -> Result<RevisionData, NvueClientError> {
let revision_path = format!("/nvue_v1/revision/{revision_id}");
let request = self.request(Method::GET, &revision_path)?.build()?;

@coderabbitai coderabbitai Bot Aug 7, 2026

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- client structure ---'
ast-grep outline crates/nvue-client/src/client.rs
printf '%s\n' '--- relevant source ---'
cat -n crates/nvue-client/src/client.rs | sed -n '120,205p'
printf '%s\n' '--- revision path usages ---'
rg -n -C 3 'revision_id|/nvue_v1/revision' crates/nvue-client
printf '%s\n' '--- URL construction and dependency context ---'
rg -n 'urlencoding|percent_encode|path_segments|reqwest|Url::|revision' Cargo.toml crates/nvue-client/Cargo.toml crates/nvue-client/src

Repository: NVIDIA/infra-controller

Length of output: 21543


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- URL helpers and request flow ---'
cat -n crates/nvue-client/src/client.rs | sed -n '1,120p'
cat -n crates/nvue-client/src/client.rs | sed -n '238,305p'
printf '%s\n' '--- dependency versions ---'
rg -n -A 8 -B 2 '^name = "(reqwest|url|urlencoding)"' Cargo.lock
printf '%s\n' '--- existing URL/path encoding tests or helpers ---'
rg -n -i 'percent.?encod|path.?segment|url::|construct_url_string|revision_path|rev=' --glob '*.rs' --glob '*.toml' .

Repository: NVIDIA/infra-controller

Length of output: 30914


🏁 Script executed:

#!/bin/bash
set -eu
python3 - <<'PY'
from urllib.parse import urlsplit

base = "http://localhost"
for revision_id in ["plain", "a/b", "a?b", "a#b", "a b", "a%2Fb"]:
    raw = f"{base}/nvue_v1/revision/{revision_id}"
    parsed = urlsplit(raw)
    print(f"{revision_id!r} -> path={parsed.path!r}, query={parsed.query!r}, fragment={parsed.fragment!r}")
PY

printf '%s\n' '--- workspace dependency selection ---'
sed -n '180,215p' Cargo.toml
cat -n crates/nvue-client/Cargo.toml | sed -n '1,55p'

printf '%s\n' '--- NVUE revision ID parsing and tests ---'
cat -n crates/nvue-client/src/config.rs | sed -n '125,165p'
rg -n -C 4 'NvueClient|get_revision\\(|apply_config_revision\\(|replace_config_revision\\(' crates/nvue-client crates/health

Repository: NVIDIA/infra-controller

Length of output: 4719


🌐 Web query:

reqwest 0.13 RequestBuilder client.request URL string percent-encoding path query fragment behavior url crate Url::parse

💡 Result:

In reqwest 0.13, the client.request and related methods (get, post, etc.) accept a URL argument that implements the IntoUrl trait, which typically handles standard URL strings [1][2]. When these methods are called, the URL is parsed using the url crate [1]. 1. URL Parsing and Percent-Encoding: The reqwest crate uses the url crate for parsing URLs. When you pass a string to client.request or similar methods, it is parsed into a Url object. The url crate automatically handles percent-encoding for path, query, and fragment components according to RFC standards during this parsing and subsequent usage [1][2]. 2. RequestBuilder Behavior: - RequestBuilder::new or those created via Client methods maintain the URL state [2]. - If the provided URL contains embedded credentials (e.g., https://user:pass@example.com), reqwest automatically extracts these, percent-decodes them, removes them from the URL, and converts them into HTTP Basic Authentication headers [2]. - The RequestBuilder::query method, available when the query feature is enabled, provides a structured way to add or modify query parameters [3][4]. It serializes provided key-value pairs and appends them to the URL's query component, ensuring proper percent-encoding is applied [3][5]. 3. Special Configurations: While the library handles standard percent-encoding for general request components, specific features like multipart::Form offer additional configuration for percent-encoding behavior, such as percent_encode_noop, to support servers with non-standard requirements [6][7][8]. In general, users should rely on the default URL parsing behavior provided by the url crate, which ensures compliance with standard URI percent-encoding rules for paths, queries, and fragments [1][2].

Citations:


🌐 Web query:

site:docs.nvidia.com/networking-ethernet-software/cumulus-linux-516 "revision" "NVUE API" revision ID URL

💡 Result:

In the NVIDIA User Experience (NVUE) API for Cumulus Linux, the revision ID is a system-generated identifier used to manage, track, and apply configuration changes [1][2]. The NVUE API typically resides at the endpoint path starting with /nvue_v1/ [1]. To perform operations involving revisions, you interact with the /nvue_v1/revision endpoint [1]. Key concepts for using the revision ID via the REST API include: 1. Creating a Revision: You initiate a new configuration session by sending a POST request to the /nvue_v1/revision endpoint, which returns a new revision ID (e.g., "1" or "2") [1]. 2. Applying Changes: When making configuration changes (using PATCH requests), you link the changes to a specific revision ID. This can be done by including the revision in the URL query parameter (e.g., /nvue_v1/interface/lo/ip/address?rev=2) or by interacting directly with the revision resource (e.g., /nvue_v1/revision/2) [1]. 3. Committing or Managing: You can check the status of a revision (e.g., pending, applied) or finalize the application of changes by sending PATCH requests to the specific revision's URL (e.g., /nvue_v1/revision/2) [1]. For further details on interacting with the NVUE API, including full request structures and authentication, refer to the official NVIDIA documentation for your specific version of Cumulus Linux [1].

Citations:


🌐 Web query:

docs.rs url 2.5 Url::parse path slash question mark fragment path_segments_mut push percent encode reserved characters

💡 Result:

In the Rust url crate (version 2.5), the Url struct and its associated PathSegmentsMut helper provide functionality to parse and manipulate URL paths [1][2][3]. When you call Url::parse, the URL is parsed according to the WHATWG URL Standard [4][5]. Components such as the query and fragment are delimited by the ? and # characters, respectively [6][7][8]. For URLs that are not "cannot-be-a-base" (i.e., they have a host), the path is treated as a series of slash-separated segments [1][5]. You can access these segments mutably using url.path_segments_mut() [2][6]. Regarding the push method on PathSegmentsMut: - The push (and extend) method appends a segment to the end of the URL path [1][9]. - Crucially, push performs percent-encoding on the input segment [1][9]. - Unlike the initial Url::parse, which may leave existing percent-encoding as-is, push and extend will percent-encode reserved characters such as / (to %2F) and % (to %25) [1][9]. This ensures that the added segment remains a single, valid path component [1][10]. Example usage: rust use url::Url; let mut url = Url::parse("http://example.net/foo")?; // Path becomes "/foo/img/2%2F100%25.png" url.path_segments_mut().map_err(|_| "cannot be base")? .push("img").push("2/100%.png"); [1][9] If you need to perform additional manipulation, such as handling trailing slashes, you can use methods like pop() or pop_if_empty() on the PathSegmentsMut object before pushing new segments [1][9].

Citations:


Encode revision_id before building NVUE URLs.

format! treats revision_id as URL syntax. Encode it as one path segment in get_revision and apply_config_revision, and as a query value in replace_config_revision.

🤖 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/nvue-client/src/client.rs` around lines 145 - 147, Update get_revision
and apply_config_revision to percent-encode revision_id as a single URL path
segment before constructing their NVUE URLs, and update replace_config_revision
to encode revision_id as a query parameter value. Preserve the existing request
behavior while ensuring IDs containing URL-reserved characters are not
interpreted as URL syntax.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm aiming to fix up all of the URL construction bugs in this crate in a separate branch, so while this is valid I don't want to fix it without fixing the ones in the other methods (outside the scope for this branch).

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.

@DrewBloechl, acknowledged. A partial fix in this PR would make URL construction inconsistent across the crate.

I will leave this finding unresolved for the separate URL-construction cleanup. Would you like me to open a follow-up issue for that work?

🐇

You are interacting with an AI system.

Comment thread crates/nvue-client/src/client.rs
Comment thread crates/nvue-client/src/client.rs
@DrewBloechl
DrewBloechl force-pushed the drew/agent-nvue-config-apply branch from d04f9d8 to 8043dda Compare August 7, 2026 22:08
@DrewBloechl
DrewBloechl merged commit 29d43d2 into NVIDIA:main Aug 10, 2026
64 checks passed
nv-dmendoza pushed a commit that referenced this pull request Aug 10, 2026
…4791)

This is a backport to v2.1 of #4729 (which the following text is from).

I've been overly optimistic in `NvueClient::apply_config_revision()`,
assuming that we don't need to care about checking the state of the
revision we just applied. QA found a bug (tracked internally as NVbugs
6563638) that suggests this was a mistake. This branch adds polling
logic in `apply_config_revision()`, with parsing of the revision data
derived from the OpenAPI spec from NVUE in Cumulus Linux 5.16.0 (the
most recent version I had handy).

## Related issues
- NVbugs 6563638

## Type of Change
- [ ] **Add** - New feature or capability
- [ ] **Change** - Changes in existing functionality
- [X] **Fix** - Bug fixes
- [ ] **Remove** - Removed features or deprecated functionality
- [ ] **Internal** - Internal changes (refactoring, tests, docs, etc.)

## Breaking Changes
- [ ] **This PR contains breaking changes**

## Testing
- [X] Unit tests added/updated
- [ ] Integration tests added/updated
- [ ] Manual testing performed
- [ ] No testing required (docs, internal refactor, etc.)

## Additional Notes
Sinck pushed a commit to Sinck/infra-controller that referenced this pull request Aug 11, 2026
…VIDIA#4729)

I've been overly optimistic in `NvueClient::apply_config_revision()`,
assuming that we don't need to care about checking the state of the
revision we just applied. QA found a bug (tracked internally as NVbugs
6563638) that suggests this was a mistake. This branch adds polling
logic in `apply_config_revision()`, with parsing of the revision data
derived from the OpenAPI spec from NVUE in Cumulus Linux 5.16.0 (the
most recent version I had handy).

## Related issues
- NVbugs 6563638

## Type of Change
- [ ] **Add** - New feature or capability
- [ ] **Change** - Changes in existing functionality
- [X] **Fix** - Bug fixes
- [ ] **Remove** - Removed features or deprecated functionality
- [ ] **Internal** - Internal changes (refactoring, tests, docs, etc.)

## Breaking Changes
- [ ] **This PR contains breaking changes**

## Testing
- [X] Unit tests added/updated
- [ ] Integration tests added/updated
- [ ] Manual testing performed
- [ ] No testing required (docs, internal refactor, etc.)

## Additional Notes
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