nd_fabric_prepare_update - ND 4.2 software staging - #291
Conversation
3c80477 to
67167cd
Compare
fc757df to
49a49b9
Compare
67167cd to
fbf128d
Compare
542a13f to
5f144b3
Compare
ae32c0e to
a9575ad
Compare
b06785f to
f5a5e6d
Compare
afbd34b to
8bb515f
Compare
f5a5e6d to
2ed1e9d
Compare
2ed1e9d to
7167190
Compare
7167190 to
12e2301
Compare
There was a problem hiding this comment.
Pull request overview
Adds a new one-shot Ansible module to drive Nexus Dashboard 4.2 “Prepare” (stage + validate) for one or more fabric software update groups, including a dedicated orchestrator, endpoint models, response parsing models, and test coverage.
Changes:
- Introduces
nd_fabric_prepare_updatemodule with preflight mixed-role rejection, idempotency detection, and optional wait/poll-to-completion behavior. - Adds
FabricPrepareUpdateOrchestratorplus new Manage endpoint models forsoftwareUpdatePlan/summaryandsoftwareUpdatePlan/actions/stage. - Adds unit tests (orchestrator + models), fixtures, and an integration test target.
Reviewed changes
Copilot reviewed 14 out of 15 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/module_utils/orchestrators/test_fabric_prepare_update.py | Unit tests covering orchestrator preflight, stage call, idempotency snapshot logic, and polling behavior. |
| tests/unit/module_utils/models/test_fabric_prepare_update.py | Unit tests validating Pydantic parsing/aliasing for the summary response models. |
| tests/unit/module_utils/fixtures/fixture_data/test_fabric_prepare_update.json | Fixture responses for summary/stage workflows and polling scenarios. |
| tests/integration/targets/nd_fabric_prepare_update/vars/main.yaml | Integration test variables for real ND 4.2.1 fabric + switches + image name. |
| tests/integration/targets/nd_fabric_prepare_update/tasks/setup.yaml | Creates prerequisite update groups (single-role and mixed-role) for integration tests. |
| tests/integration/targets/nd_fabric_prepare_update/tasks/prepare.yaml | Executes prepare module scenarios (mixed-role rejection, check mode, real stage+wait, idempotency). |
| tests/integration/targets/nd_fabric_prepare_update/tasks/main.yaml | Integration test harness with module defaults/timeouts and setup/cleanup blocks. |
| tests/integration/targets/nd_fabric_prepare_update/tasks/cleanup.yaml | Removes created update groups after test run. |
| tests/integration/targets/nd_fabric_prepare_update/meta/main.yml | Declares integration target metadata (no dependencies). |
| plugins/modules/nd_fabric_prepare_update.py | New module implementing prepare/stage workflow and documentation/examples. |
| plugins/module_utils/orchestrators/fabric_prepare_update.py | Orchestrator implementing summary fetch, preflight checks, stage action, and poll loop with transient-failure tolerance. |
| plugins/module_utils/models/fabric_prepare_update/software_update_plan_summary.py | Pydantic models for softwareUpdatePlan/summary response parsing. |
| plugins/module_utils/models/fabric_prepare_update/init.py | Package init for the new model namespace. |
| plugins/module_utils/endpoints/v1/manage/software_update_plan_summary.py | New endpoint model for GET summary. |
| plugins/module_utils/endpoints/v1/manage/software_update_plan_actions.py | Adds endpoint model for POST stage action. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
12e2301 to
ce02880
Compare
Resolve reviewer feedback on the fabric prepare-update (stage) module: - Clamp wait_interval to >= 0 in wait_for_completion so a negative interval no-ops instead of raising ValueError from time.sleep (Copilot). - Fix the multi-group EXAMPLES wait_interval (60 -> 20) so it no longer contradicts the "keep below persistent_command_timeout (30s)" guidance (Copilot). - Enforce a non-empty update_groups via a _validate_update_groups guard in the module wrapper; required=True alone accepts an empty list (akinross). - snapshot_fully_prepared now returns True for an empty/switch-less snapshot (vacuously prepared, changed=False), consistent with wait_for_completion treating a switch-less group as already satisfied (akinross). - Scope summary polls with the API's updateGroupName query parameter for the common single-group prepare, avoiding a fabric-wide GET every wait_interval; multi-group prepares keep the single fabric-wide fetch and filter in memory to avoid N+1 requests (mikewiebe). Models the param on EpFabricSoftwareUpdatePlanSummary via EndpointQueryParams. - Add module-wrapper unit tests (tests/unit/modules/test_nd_fabric_prepare_update.py) covering the update_groups guard and the _run_prepare decision surface, plus endpoint tests for the new scoped summary path (mikewiebe). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
639eb93 to
c9bbb83
Compare
Resolve reviewer feedback on the fabric prepare-update (stage) module: - Clamp wait_interval to >= 0 in wait_for_completion so a negative interval no-ops instead of raising ValueError from time.sleep (Copilot). - Fix the multi-group EXAMPLES wait_interval (60 -> 20) so it no longer contradicts the "keep below persistent_command_timeout (30s)" guidance (Copilot). - Enforce a non-empty update_groups via a _validate_update_groups guard in the module wrapper; required=True alone accepts an empty list (akinross). - snapshot_fully_prepared now returns True for an empty/switch-less snapshot (vacuously prepared, changed=False), consistent with wait_for_completion treating a switch-less group as already satisfied (akinross). - Scope summary polls with the API's updateGroupName query parameter for the common single-group prepare, avoiding a fabric-wide GET every wait_interval; multi-group prepares keep the single fabric-wide fetch and filter in memory to avoid N+1 requests (mikewiebe). Models the param on EpFabricSoftwareUpdatePlanSummary via EndpointQueryParams. - Add module-wrapper unit tests (tests/unit/modules/test_nd_fabric_prepare_update.py) covering the update_groups guard and the _run_prepare decision surface, plus endpoint tests for the new scoped summary path (mikewiebe). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
c9bbb83 to
c2fe075
Compare
Resolve reviewer feedback on the fabric prepare-update (stage) module: - Clamp wait_interval to >= 0 in wait_for_completion so a negative interval no-ops instead of raising ValueError from time.sleep (Copilot). - Fix the multi-group EXAMPLES wait_interval (60 -> 20) so it no longer contradicts the "keep below persistent_command_timeout (30s)" guidance (Copilot). - Enforce a non-empty update_groups via a _validate_update_groups guard in the module wrapper; required=True alone accepts an empty list (akinross). - snapshot_fully_prepared now returns True for an empty/switch-less snapshot (vacuously prepared, changed=False), consistent with wait_for_completion treating a switch-less group as already satisfied (akinross). - Scope summary polls with the API's updateGroupName query parameter for the common single-group prepare, avoiding a fabric-wide GET every wait_interval; multi-group prepares keep the single fabric-wide fetch and filter in memory to avoid N+1 requests (mikewiebe). Models the param on EpFabricSoftwareUpdatePlanSummary via EndpointQueryParams. - Add module-wrapper unit tests (tests/unit/modules/test_nd_fabric_prepare_update.py) covering the update_groups guard and the _run_prepare decision surface, plus endpoint tests for the new scoped summary path (mikewiebe). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
c2fe075 to
5cb4cb4
Compare
Resolve reviewer feedback on the fabric prepare-update (stage) module: - Clamp wait_interval to >= 0 in wait_for_completion so a negative interval no-ops instead of raising ValueError from time.sleep (Copilot). - Fix the multi-group EXAMPLES wait_interval (60 -> 20) so it no longer contradicts the "keep below persistent_command_timeout (30s)" guidance (Copilot). - Enforce a non-empty update_groups via a _validate_update_groups guard in the module wrapper; required=True alone accepts an empty list (akinross). - snapshot_fully_prepared now returns True for an empty/switch-less snapshot (vacuously prepared, changed=False), consistent with wait_for_completion treating a switch-less group as already satisfied (akinross). - Scope summary polls with the API's updateGroupName query parameter for the common single-group prepare, avoiding a fabric-wide GET every wait_interval; multi-group prepares keep the single fabric-wide fetch and filter in memory to avoid N+1 requests (mikewiebe). Models the param on EpFabricSoftwareUpdatePlanSummary via EndpointQueryParams. - Add module-wrapper unit tests (tests/unit/modules/test_nd_fabric_prepare_update.py) covering the update_groups guard and the _run_prepare decision surface, plus endpoint tests for the new scoped summary path (mikewiebe). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5cb4cb4 to
1f82ed3
Compare
Resolve reviewer feedback on the fabric prepare-update (stage) module: - Clamp wait_interval to >= 0 in wait_for_completion so a negative interval no-ops instead of raising ValueError from time.sleep (Copilot). - Fix the multi-group EXAMPLES wait_interval (60 -> 20) so it no longer contradicts the "keep below persistent_command_timeout (30s)" guidance (Copilot). - Enforce a non-empty update_groups via a _validate_update_groups guard in the module wrapper; required=True alone accepts an empty list (akinross). - snapshot_fully_prepared now returns True for an empty/switch-less snapshot (vacuously prepared, changed=False), consistent with wait_for_completion treating a switch-less group as already satisfied (akinross). - Scope summary polls with the API's updateGroupName query parameter for the common single-group prepare, avoiding a fabric-wide GET every wait_interval; multi-group prepares keep the single fabric-wide fetch and filter in memory to avoid N+1 requests (mikewiebe). Models the param on EpFabricSoftwareUpdatePlanSummary via EndpointQueryParams. - Add module-wrapper unit tests (tests/unit/modules/test_nd_fabric_prepare_update.py) covering the update_groups guard and the _run_prepare decision surface, plus endpoint tests for the new scoped summary path (mikewiebe). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1f82ed3 to
d50c7d3
Compare
Resolve reviewer feedback on the fabric prepare-update (stage) module: - Clamp wait_interval to >= 0 in wait_for_completion so a negative interval no-ops instead of raising ValueError from time.sleep (Copilot). - Fix the multi-group EXAMPLES wait_interval (60 -> 20) so it no longer contradicts the "keep below persistent_command_timeout (30s)" guidance (Copilot). - Enforce a non-empty update_groups via a _validate_update_groups guard in the module wrapper; required=True alone accepts an empty list (akinross). - snapshot_fully_prepared now returns True for an empty/switch-less snapshot (vacuously prepared, changed=False), consistent with wait_for_completion treating a switch-less group as already satisfied (akinross). - Scope summary polls with the API's updateGroupName query parameter for the common single-group prepare, avoiding a fabric-wide GET every wait_interval; multi-group prepares keep the single fabric-wide fetch and filter in memory to avoid N+1 requests (mikewiebe). Models the param on EpFabricSoftwareUpdatePlanSummary via EndpointQueryParams. - Add module-wrapper unit tests (tests/unit/modules/test_nd_fabric_prepare_update.py) covering the update_groups guard and the _run_prepare decision surface, plus endpoint tests for the new scoped summary path (mikewiebe). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
d50c7d3 to
e532084
Compare
Resolve reviewer feedback on the fabric prepare-update (stage) module: - Clamp wait_interval to >= 0 in wait_for_completion so a negative interval no-ops instead of raising ValueError from time.sleep (Copilot). - Fix the multi-group EXAMPLES wait_interval (60 -> 20) so it no longer contradicts the "keep below persistent_command_timeout (30s)" guidance (Copilot). - Enforce a non-empty update_groups via a _validate_update_groups guard in the module wrapper; required=True alone accepts an empty list (akinross). - snapshot_fully_prepared now returns True for an empty/switch-less snapshot (vacuously prepared, changed=False), consistent with wait_for_completion treating a switch-less group as already satisfied (akinross). - Scope summary polls with the API's updateGroupName query parameter for the common single-group prepare, avoiding a fabric-wide GET every wait_interval; multi-group prepares keep the single fabric-wide fetch and filter in memory to avoid N+1 requests (mikewiebe). Models the param on EpFabricSoftwareUpdatePlanSummary via EndpointQueryParams. - Add module-wrapper unit tests (tests/unit/modules/test_nd_fabric_prepare_update.py) covering the update_groups guard and the _run_prepare decision surface, plus endpoint tests for the new scoped summary path (mikewiebe). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
e532084 to
55e4611
Compare
Resolve reviewer feedback on the fabric prepare-update (stage) module: - Clamp wait_interval to >= 0 in wait_for_completion so a negative interval no-ops instead of raising ValueError from time.sleep (Copilot). - Fix the multi-group EXAMPLES wait_interval (60 -> 20) so it no longer contradicts the "keep below persistent_command_timeout (30s)" guidance (Copilot). - Enforce a non-empty update_groups via a _validate_update_groups guard in the module wrapper; required=True alone accepts an empty list (akinross). - snapshot_fully_prepared now returns True for an empty/switch-less snapshot (vacuously prepared, changed=False), consistent with wait_for_completion treating a switch-less group as already satisfied (akinross). - Scope summary polls with the API's updateGroupName query parameter for the common single-group prepare, avoiding a fabric-wide GET every wait_interval; multi-group prepares keep the single fabric-wide fetch and filter in memory to avoid N+1 requests (mikewiebe). Models the param on EpFabricSoftwareUpdatePlanSummary via EndpointQueryParams. - Add module-wrapper unit tests (tests/unit/modules/test_nd_fabric_prepare_update.py) covering the update_groups guard and the _run_prepare decision surface, plus endpoint tests for the new scoped summary path (mikewiebe). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
55e4611 to
d38a62e
Compare
| """ | ||
|
|
||
| update_group_name: str | None = Field(default=None, alias="updateGroupName") | ||
| update_group_status: str | None = Field(default=None, alias="updateGroupStatus") |
There was a problem hiding this comment.
does the same free-form comment about string apply to update_group_status?
| `image_staged_status` and `image_validated_status` are kept as free-form strings (not a | ||
| `Literal`) so an unrecognized status from a newer ND release parses rather than raising during | ||
| a poll. Known values: `none`, `inProgress`, `success`, `failed`, `skipped`. |
There was a problem hiding this comment.
Did you consider a Literal and TypeAlias combination for this case, in a way that known values for the status are Literals and the states can contain that TypeAlias or a string?
from typing import Literal, TypeAlias
KnownImageStatus: TypeAlias = Literal[
"none", "inProgress", "success", "failed", "skipped",
]
ImageStatus: TypeAlias = KnownImageStatus | str
At runtime that is effectively str, but it makes the known vocabulary visible to readers and can generate a schema with both the enum branch and the general-string fallback.
| try: | ||
| summary = self.get_summary(update_group_name=scope) | ||
| groups = self._resolve_groups(summary, update_group_names) | ||
| switches = [sw for group in groups for sw in (group.update_group_switches or [])] |
There was a problem hiding this comment.
I assume we need the or [] because group.update_group_switches can be None according to update_group_switches: list[SwitchStageStatusModel] | None = Field(default=None, alias="updateGroupSwitches").
I am confused on when the case would be None, is this when the field is missing from response (since the model is only used for response as documented)? Should we simplify the model to not write None and default to an empty list? Another option would be to error when updateGroupSwitches is not part of the response, assuming that would lead to None?
| f"Polling staging status for update group(s) {update_group_names} in fabric " | ||
| f"'{self.fabric_name}' failed {consecutive_failures} times in a row: {e}" | ||
| ) from e | ||
| time.sleep(interval) |
There was a problem hiding this comment.
When the remaining timeout is shorter than wait_interval, the loop still sleeps for the full interval before checking the deadline again. For example, wait_timeout=65 and wait_interval=30 can time out around 90 seconds. I think we should wait for a maximum of the remaining time until deadline, so in the example wait 30, 30 and 5 instead of 30, 30, 30.
same applies to the timeout below
| summary = self.get_summary(update_group_name=scope) | ||
| groups = self._resolve_groups(summary, update_group_names) | ||
| switches = [sw for group in groups for sw in (group.update_group_switches or [])] | ||
| except Exception as e: # pylint: disable=broad-except |
There was a problem hiding this comment.
Do we want to retry pydantic validation errors that potentially could be raised in this try/except block? I assume the chance we hit those are small, but they should not be retried in my opinion.
| description: | ||
| - Whether to wait for staging to complete on every switch before returning. | ||
| - When V(true), the module polls Nexus Dashboard until every switch has staged and validated, or until O(wait_timeout) is reached. | ||
| - When V(false), the module returns as soon as Nexus Dashboard accepts the stage action; staging continues on Nexus Dashboard. |
There was a problem hiding this comment.
I think we need to reword this because the module still performs the status snapshot for after in results, so it does not return immediately.
| - The name of the fabric that contains the update groups to prepare. | ||
| type: str | ||
| required: true | ||
| update_groups: |
There was a problem hiding this comment.
should we document the validation rule that at least on entry is required?
| options: | ||
| fabric_name: | ||
| description: | ||
| - The name of the fabric that contains the update groups to prepare. |
There was a problem hiding this comment.
should we add a similar line as https://github.com/CiscoDevNet/ansible-nd/pull/291/changes#diff-bf975127beb2e5715317b385312125224e9f0924145cf7193b491e94c60e7b86R39 for fabric name?
| sender = Sender() | ||
| sender.ansible_module = module | ||
| rest_send_params = dict(module.params) | ||
| rest_send_params["check_mode"] = module.check_mode | ||
| rest_send = RestSend(rest_send_params) | ||
| rest_send.sender = sender | ||
| rest_send.response_handler = ResponseHandler() | ||
|
|
||
| orchestrator = FabricPrepareUpdateOrchestrator(rest_send=rest_send, results=Results()) |
There was a problem hiding this comment.
not wrong but more stylistic inconsistency question as to why some parts are assigned to variable first but FabricPrepareUpdateOrchestrator is constructed directly with the objects and functions.
| sender = Sender() | |
| sender.ansible_module = module | |
| rest_send_params = dict(module.params) | |
| rest_send_params["check_mode"] = module.check_mode | |
| rest_send = RestSend(rest_send_params) | |
| rest_send.sender = sender | |
| rest_send.response_handler = ResponseHandler() | |
| orchestrator = FabricPrepareUpdateOrchestrator(rest_send=rest_send, results=Results()) | |
| rest_send = RestSend({**module.params, "check_mode": module.check_mode}) | |
| rest_send.sender = Sender(ansible_module=module) | |
| rest_send.response_handler = ResponseHandler() | |
| orchestrator = FabricPrepareUpdateOrchestrator(rest_send=rest_send, results=Results()) |
| - The target image, whether the upgrade is disruptive or non-disruptive, maintenance mode, and the report checks | ||
| are properties of the update group itself, not of this module. Configure them with M(cisco.nd.nd_fabric_update_group) | ||
| before preparing. This module only selects which update groups to prepare. | ||
| - In check mode, when staging is required, the module reports a change but does not stage, because the stage |
There was a problem hiding this comment.
I would slight reword the description in check mode
| - In check mode, when staging is required, the module reports a change but does not stage, because the stage | |
| - In check mode, if staging is required, the module reports changed=true but does not invoke the stage action because it cannot be previewed. Consequently, the returned after status is unchanged from before. |
Implements the Fabric Software Management "Prepare" step on Nexus Dashboard 4.2 - the softwareUpdatePlan/actions/stage action - which stages and validates the configured image on the switches of one or more update groups. - New module nd_fabric_prepare_update: a one-shot action module that pre-flight checks for mixed-role update groups, is idempotent against already-staged groups, and (with wait) polls to completion. - FabricPrepareUpdateOrchestrator: drives the stage action and a poll loop that tolerates transient transport errors during the long wait. - EpFabricSoftwareUpdatePlanStage and EpFabricSoftwareUpdatePlanSummary endpoint models; softwareUpdatePlan/summary response models. - 33 unit tests (orchestrator + models) and an integration test target. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
preflight_role_check and status_snapshot each fetched softwareUpdatePlan/summary independently, so a prepare run made two identical GETs back-to-back at startup. Both now accept an optional pre-fetched summary; _run_prepare fetches it once and passes it to both. Startup now costs one summary GET instead of two (check mode included), and the role check and `before` snapshot observe the same point-in-time summary. Adds test_fabric_prepare_update_00220 asserting a single GET across the three startup calls. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two review fixes for nd_fabric_prepare_update: - Surface the orchestrator's Results in module output. _register_api_call was recording every REST call, but the module returned output.format(...) so none of it reached the user. main() now extracts module._verbosity and calls format_with_verbosity(verbosity, results, ...), matching the nd_local_user / nd_manage_fabric_* pattern; -vv shows the stage write summary and -vvv shows full controller detail. - wait_for_completion no longer polls a switch-less update group until wait_timeout. The success guard "if switches and all(...)" could never satisfy a group that resolved with zero member switches, causing a ~30-minute hang and a misleading timeout. Added "if not switches: return". Adds test_fabric_prepare_update_00550 (+fixture) covering the switch-less wait case. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Three lower-priority review fixes for nd_fabric_prepare_update (wait_for_completion); the duplication finding is tracked in #336. - Honor wait_timeout ahead of the retry budget. The transient-failure branch checked the consecutive-failure count before the deadline, so a small wait_timeout could be overshot by up to (_MAX+1)*interval and report "failed N times in a row" instead of a timeout. The deadline check now runs first. - Retry an unresolved poll. _resolve_groups ran outside the try, so a summary that briefly fails to resolve the requested groups (e.g. a partial body during a controller hiccup, or a 404 ResponseHandler maps to an empty body) aborted the whole prepare. It now runs inside the try and is absorbed by the same consecutive-failure budget. - Reuse the final poll summary for the `after` snapshot. wait_for_completion now returns the last SoftwareUpdatePlanSummaryModel, and the module passes it to status_snapshot, saving one GET per waited run. Adds tests 00560 (timeout-over-retry ordering) and 00570 (unresolved-poll retry), and asserts the wait return contract in 00500. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The _run_prepare return annotation tuple[Results | None, dict] is evaluated at runtime because the module lacked from __future__ import annotations. ansible-test sanity's pinned pylint/astroid flags an evaluated `Class | None` union as unsupported-binary-operation (independent of the runtime Python, which supports PEP 604). Making annotations lazy (PEP 563) silences it. Placed before ANSIBLE_METADATA as the first statement, matching nd_log.py and nd_manage_switches.py. Verified with: ansible-test sanity --test pylint --docker default <module> (exit 0). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve reviewer feedback on the fabric prepare-update (stage) module: - Clamp wait_interval to >= 0 in wait_for_completion so a negative interval no-ops instead of raising ValueError from time.sleep (Copilot). - Fix the multi-group EXAMPLES wait_interval (60 -> 20) so it no longer contradicts the "keep below persistent_command_timeout (30s)" guidance (Copilot). - Enforce a non-empty update_groups via a _validate_update_groups guard in the module wrapper; required=True alone accepts an empty list (akinross). - snapshot_fully_prepared now returns True for an empty/switch-less snapshot (vacuously prepared, changed=False), consistent with wait_for_completion treating a switch-less group as already satisfied (akinross). - Scope summary polls with the API's updateGroupName query parameter for the common single-group prepare, avoiding a fabric-wide GET every wait_interval; multi-group prepares keep the single fabric-wide fetch and filter in memory to avoid N+1 requests (mikewiebe). Models the param on EpFabricSoftwareUpdatePlanSummary via EndpointQueryParams. - Add module-wrapper unit tests (tests/unit/modules/test_nd_fabric_prepare_update.py) covering the update_groups guard and the _run_prepare decision surface, plus endpoint tests for the new scoped summary path (mikewiebe). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Related Issue(s)
N/A — new module.
Proposed Changes
nd_fabric_prepare_update— the Fabric Software Management "Prepare" step on Nexus Dashboard 4.2, i.e. thesoftwareUpdatePlan/actions/stageaction: stages and validates the configured image on the switches of one or more update groups.wait: truepolls to completion.FabricPrepareUpdateOrchestrator— drives the stage action and a poll loop that tolerates transient transport errors during the long wait.EpFabricSoftwareUpdatePlanStageandEpFabricSoftwareUpdatePlanSummary; Pydantic models for thesoftwareUpdatePlan/summaryresponse.Test Notes
python -m pytest tests/unit/module_utils/models/test_fabric_prepare_update.py tests/unit/module_utils/orchestrators/test_fabric_prepare_update.py— 33 pass.ansible-test sanity --dockerpasses for all new/changed files.ansible-test integration nd_fabric_prepare_update— green against a live ND 4.2.1 lab (fabric SITE1), covering mixed-role pre-flight rejection, check mode, a real stage + wait, and idempotency.Cisco Nexus Dashboard Version
4.2.1
Related ND API Resource Category
Checklist
🤖 Generated with Claude Code