Ansible ND 4.X | WIP | ND Manage Policies Module + Pydantic Models + Smart Endpoints #261
Ansible ND 4.X | WIP | ND Manage Policies Module + Pydantic Models + Smart Endpoints #261nikhilsrikrishna wants to merge 3 commits intoCiscoDevNet:developfrom
Conversation
34ca31a to
2a38048
Compare
2a38048 to
10670a7
Compare
allenrobel
left a comment
There was a problem hiding this comment.
Requesting a few changes.
| ``config[]`` schema exactly for copy-paste round-trips. | ||
| """ | ||
|
|
||
| from __future__ import absolute_import, annotations, division, print_function |
There was a problem hiding this comment.
Replace with:
from __future__ annotationsThere was a problem hiding this comment.
@allenrobel Replaced the imports, Thank you
allenrobel
left a comment
There was a problem hiding this comment.
Added several comments where legacy annotations are still being used. Please review your files more closely to remove remaining. Of you're using Claude Code, just ask Claude to update his memory, or update his Claude.md file, to use modern type annotations in all future code. You can also ask him to cleanup existing code.
| - POST /fabrics/{fabricName}/policyActions/remove - Remove policies in bulk | ||
| """ | ||
|
|
||
| from __future__ import absolute_import, annotations, division, print_function |
There was a problem hiding this comment.
Replace with:
from __future__ import annotationsThere was a problem hiding this comment.
@allenrobel Made the changes, Thank you
|
|
||
| __author__ = "L Nikhil Sri Krishna" | ||
|
|
||
| from typing import Literal, Optional |
There was a problem hiding this comment.
Remove Optional import and replace use of Optional with modern equivalents e.g.:
Optional[str] -> str | None
Comment applies throughout.
There was a problem hiding this comment.
@allenrobel Made the changes, Thank you
|
|
||
| model_config = ConfigDict(extra="forbid") | ||
|
|
||
| cluster_name: Optional[str] = Field( |
There was a problem hiding this comment.
Should be:
cluster_name: str | None = Field(Same comment applies throughout.
If you're using Claude Code, ask Claude to update his memory, or his Claude.md, file to use modern type annotations in all new code so that he stops using legacy annotations.
There was a problem hiding this comment.
@allenrobel Made the changes, Thank you
| - POST /fabrics/{fabricName}/switchActions/deploy - Deploy config to switches | ||
| """ | ||
|
|
||
| from __future__ import absolute_import, annotations, division, print_function |
There was a problem hiding this comment.
Replace with:
from __future__ import annotationsThere was a problem hiding this comment.
@allenrobel Made the changes, Thank you
| default_factory=dict, | ||
| description="Name/value pairs passed to the policy template", | ||
| ) | ||
| switch: Optional[List[PlaybookSwitchEntry]] = Field( |
There was a problem hiding this comment.
switch: list[PlaybookSwitchEntry] | None = Field(There was a problem hiding this comment.
@allenrobel Made the changes, Thank you
| return self | ||
|
|
||
| @classmethod | ||
| def get_argument_spec(cls) -> Dict[str, Any]: |
There was a problem hiding this comment.
def get_argument_spec(cls) -> dict[str, Any]:There was a problem hiding this comment.
@allenrobel Made the changes, Thank you
| INTERFACE = "interface" | ||
|
|
||
| @classmethod | ||
| def choices(cls) -> List[str]: |
There was a problem hiding this comment.
def choices(cls) -> list[str]:There was a problem hiding this comment.
@allenrobel Made the changes, Thank you
| raise ValueError(f"Invalid entity type: {value}. Valid options: {cls.choices()}") | ||
|
|
||
| @classmethod | ||
| def normalize(cls, value: Union[str, "PolicyEntityType", None]) -> "PolicyEntityType": |
There was a problem hiding this comment.
def normalize(cls, value: str | PolicyEntityType | None) -> PolicyEntityType:Note, forward reference quotes are no longer needed since from __future__ import annotations converts all annotations to strings.
Same comment applies throughout.
There was a problem hiding this comment.
@allenrobel Made the changes, Thank you!
|
|
||
| from __future__ import absolute_import, annotations, division, print_function | ||
|
|
||
| __metaclass__ = type |
There was a problem hiding this comment.
Remove, no longer needed.
There was a problem hiding this comment.
@allenrobel Removed in the latest commit. Thanks!
81c9e78 to
ac56d9f
Compare
ac56d9f to
f20a710
Compare
allenrobel
left a comment
There was a problem hiding this comment.
LGTM after the previous comments were addressed.
|
|
||
| force_show_run: bool | None = Field( | ||
| default=None, | ||
| description=("If true, Config compliance fetches the latest running config " "from the device. If false, uses the cached version."), |
There was a problem hiding this comment.
seems something went wrong with copy pasting?
| description=("If true, Config compliance fetches the latest running config " "from the device. If false, uses the cached version."), | |
| description=("If true, Config compliance fetches the latest running config from the device. If false, uses the cached version."), |
This PR adds the nd_policy module for switch policy management in the cisco.nd collection, including the core resource handler, endpoint wrappers, and Pydantic models.
What's Included
Policy resource handler —
nd_policy_resources.pysupportsgathered,merged, anddeletedstates. Uses bulk create, bulk delete with 207 response handling, the mark-delete → push-config → remove pipeline, and deploy through switch actions.Endpoint definitions — Three endpoint classes:
manage_fabrics_policies.py,manage_fabrics_policy_actions.py,manage_fabrics_switch_actions.py.Pydantic model layer — Model classes:
config_models.py,gathered_models.py,policy_actions.py,policy_base.py,policy_crud.py. These cover input validation, API response parsing, and gathered output formatting.Input aliasing —
switch_idis aliased asswitch_ipin the argument spec, allowing users to specify either name interchangeably. Pydantic validators normalize both to the field expected by the API.Template inputs validation — User-provided
template_inputsare validated at runtime against the template's parameter schema fetched from the controller, checking for unknown keys, missing required parameters, and basic type correctness. System-injected keys are stripped from gathered output so only user-defined variables are returned.Unit tests — Endpoint-level tests covering all three endpoint classes.
Notes
Delete workflow — Delete follows a 3-step flow: markDelete → pushConfig → remove. PYTHON content-type templates (e.g., switch_freeform, Ext_VRF_Lite_SVI) fail on markDelete with "Content type is PYTHON, cannot mark for deletion". Instead of maintaining a hardcoded list of these template names, the module inspects the 207 response — any policy that fails with this specific message is automatically retried via direct DELETE /policies/{policyId}, then deployed via switchActions/deploy to push the config removal to the switch.
Gathered state and policy_id — The gathered output includes a policy_id field (e.g., POLICY-28440) alongside the template name. When this output is fed back into state=merged, the policy_id can be directly used to identify the exact policy.
Work In Progress