Skip to content

Commit 45f16e0

Browse files
mtarkingallenrobelgmicolsamiibmikewiebe
authored
Initial ND 4.2 Integration Work (#225)
* [ignore] Add generic logger facility through the Log class and logging config * [ignore] Add Endpoints framework for ND API v1 (#186) * [ignore] Add RestSend framework, enums, and shared unit test infrastructure (#185) * [ignore] Fix broken imports after nd42_rest_send restructuring * [minor_change] Add nd_local_user as a new network resource module for Nexus Dashboard v4.1.0 and higher. * [ignore] First Pydantic implementation: Add Pydantic Models for nd_local_user. * [ignore] Second Pydantic Implementation: Create a NDBaseModel to be inherited from future class models. Modify class models for local_user. * [ignore] Pydantic Models: Modify and Clean both local_user.py and base.py based on comments. Add a get method and get_identifier_value function to NDBaseModel. * [ignore] Pydantic ND base models and local_user models: Final proposition of core design adding new methods which will be used in NDConfigCollection and NDNetworkResourceModule classes as well as basic error handling and simple docstrings. * [ignore] Pydantic ND Config Collection: Final proposition of core design changing existing methods and adding new ones which will be used in NDNetworkResourceModule class as well as basic error handling and simple docstrings. * [ignore] Pydantic Base ND Network Resource Module: Final proposition of core design changing existing methods and adding new ones which will be used in future as a based for ND network resource modules as well as basic error handling and simple docstrings. * [ignore] Modify nd_local_user based on Pydantic implementation and changes added to NDNetworkResourceModule. * [ignore] Add api_endpoints for configuring endpoints and orchestrators for orchestrating crud api operations with model instances and endpoints. * [ignore] Modifiy models/local_user to take full advantage of Pydantic built-in functionalities. Slightly modify models/base.py to enforce identifiers definitions in NDBaseModel subclasses. Added multiple notes to assert next steps. * [ignore] Adapt the Network Resource Module architecture for ND to smart endpoints and Pydantic models modification (works for merge and replace states). Add comments for next steps. * [ignore] Default to none and update condition for regarding in models/base.py. * [ignore] Add choice for when no identifier is needed. Add quick comments and changes to models/local_user.py and api_endpoints/base.py * [ignore] Complete orchestrators/base.py by making simple CRUD operations methods that work for single_identifier strategy (meant to be overridden if needed). * [ignore] Fix and in nd_config_collections.py. Move to utils.py. * [ignore] Rename NDNetworkResourceModule to NDStateMachine. Add file for NDNestedModel. Add types.file. Various Renaming and small Modifications across the repo. WIP. * [ignore] Make a small change to NDModule request function. * [ignore] Modify nd_state_machine to work with orchestrators/models/api_endpoints. Adapt api_endpoints, models, orchestrators accordingly. Integration Tests passing for nd_local_user module. Still WIP. * [ignore] Add proper path dependencies and Ran black formatting. * [ignore] Clean code for sanity purposes (except Pydantic import checks. * [ignore] Restructure api_endpoints folder into endpoints -> v1. Fix some sanity issues. * [ignore] Remove NDModule inheritence from NDStateMachine. Add first iteration of (Mock Pydantic objects/methods) to pass sanity checks for Pydantic importation. * [ignore] Rename NDBaseSmartEndpoint to NDBaseEndpoint. Fix importation issues. * [ignore] Replace all pydantic imports with pydantic_compat. Fix sanity issues. * [ignore] Add NDOutput class. Modify NDStateMachine and nd_local_user accordingly * [ignore] Update NDOutput class. Remove all fail_json dependencies in NDStateMachineand add custom Exception for it in common/exceptions dir. Set json mode for to_diff_dict method in NDBaseModel. * [ignore] Fix serialization of model with minimal changes to base.py and local_user.py. Add method to NDBaseModel and apply relevant changes to nd_config_collection. * [ignore] Complete nd_local_user integration test for creation and update asserts. * [ignore] Finish integration test file for nd_local_user module. Remove Generic Class inheritence from NDConfigCollection. Clean Pydantic imports. * [ignore] Fix sanity issues by enhancing pydantic_compat.py. Fix Black formatting. * [ignore] Remove all TODO comments. * [ignore] Update endpoints to match latest nd42_integration branch. Update orchestrators accordingly. * [ignore] Update pydantic_compat.py to support extra Pydantic methods and classes. * [ignore] Remove Python 2.7 compatibilities. * [ignore] Fix comments and docstrings. made and static methods for class. * [ignore] Slightly modify Exceptions handling in NDStateMachine. Remove self.send from check_mode guards in NDStateMachine. Fix documentation for nd_local_user. * [ignore] Rename aaa_local_users.py to infra_aaa_local_users.py. Move models/local_user.py to new dir models/local_user. * [ignore] Update integration tests for nd_local_user module. * [ignore] Revert local users endpoints filename to aaa_local_users.py. * [ignore] Change in NDStateMachine initialization to take advantage of from_ansible_config static method from NDConfigCollection. * [ignore] Remove ValidationError import from nd_state_machine.py. * [ignore] Add function to nd_local_user module. Slighty fix Documentation and Example sections in nd_local_user module. Remove Dict class inheritance from NDConstantMapping. * [ignore] Make NDBaseOrchestrator a Generic class. * [ignore] Enable CI unit tests * [ignore] Add pydantic to requirements.txt * temp update to pr branch list for ci * Ansible ND 4.X Fabric Modules for iBGP, eBGP and External Fabric Types (#209) * Fabric modules for ibgp,ebgp,external fabrics * Update ibgp model enums * Update pydantic model and module docstrings for ibgp * Update pydantic model for ebgp * Update ebgp module doc headers * Update enums and pydantic model descriptions for external fabrics * Update ebgp module doc strings * Fix ansible sanity tests failures * Black formatting * Move common models into common location for import * Fix black formatting issue * Add unit tests for fabric endpoints * Fix ansible sanity test failures * Test cleanup * Add ibgp testing params * Fix for merged state and tests * Add more properties in ibgp merged test * Add more properties in ibgp replaced test * Refactor merged fix * Change name property to fabric_name * Add nd_info into integration tests * remove underscore between un & numbered * Address review comments * Fix list behavior bug and update module docs * Make ansible sanity happy * Make netflow_exporter udp_port optional * Organize ibgp module doc header --------- Co-authored-by: Matt Tarkington <mtarking@cisco.com> * update actions --------- Co-authored-by: Allen Robel <arobel@cisco.com> Co-authored-by: Allen Robel <arobel@me.com> Co-authored-by: Gaspard Micol <gmicol@cisco.com> Co-authored-by: samitab <samitab@cisco.com> Co-authored-by: Mike Wiebe <mwiebe@cisco.com>
1 parent de87304 commit 45f16e0

98 files changed

Lines changed: 30111 additions & 77 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ansible-test.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,6 @@ jobs:
199199

200200
units:
201201
name: Unit Tests
202-
if: false # No unit tests yet
203202
needs:
204203
- ansible-galaxy-importer
205204
runs-on: ubuntu-latest
@@ -242,7 +241,7 @@ jobs:
242241
name: Integration Tests
243242
if: false # No integration tests for now
244243
needs:
245-
# - units
244+
- units
246245
- ansible-test
247246
runs-on: ubuntu-latest
248247
strategy: *ansible_strategy

plugins/module_utils/__init__.py

Whitespace-only changes.

plugins/module_utils/common/__init__.py

Whitespace-only changes.
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# Copyright: (c) 2026, Allen Robel (@arobel) <arobel@cisco.com>
2+
# Copyright: (c) 2026, Gaspard Micol (@gmicol) <gmicol@cisco.com>
3+
4+
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
5+
"""
6+
# exceptions.py
7+
8+
Exception classes for the cisco.nd Ansible collection.
9+
"""
10+
11+
# isort: off
12+
# fmt: off
13+
from __future__ import (absolute_import, division, print_function)
14+
from __future__ import annotations
15+
# fmt: on
16+
# isort: on
17+
18+
from typing import Any, Optional
19+
20+
from ansible_collections.cisco.nd.plugins.module_utils.common.pydantic_compat import (
21+
BaseModel,
22+
ConfigDict,
23+
)
24+
25+
26+
class NDErrorData(BaseModel):
27+
"""
28+
# Summary
29+
30+
Pydantic model for structured error data from NDModule requests.
31+
32+
This model provides type-safe error information that can be serialized
33+
to a dict for use with Ansible's fail_json.
34+
35+
## Attributes
36+
37+
- msg: Human-readable error message (required)
38+
- status: HTTP status code as integer (optional)
39+
- request_payload: Request payload that was sent (optional)
40+
- response_payload: Response payload from controller (optional)
41+
- raw: Raw response content for non-JSON responses (optional)
42+
43+
## Raises
44+
45+
- None
46+
"""
47+
48+
model_config = ConfigDict(extra="forbid")
49+
50+
msg: str
51+
status: Optional[int] = None
52+
request_payload: Optional[dict[str, Any]] = None
53+
response_payload: Optional[dict[str, Any]] = None
54+
raw: Optional[Any] = None
55+
56+
57+
class NDModuleError(Exception):
58+
"""
59+
# Summary
60+
61+
Exception raised by NDModule when a request fails.
62+
63+
This exception wraps an NDErrorData Pydantic model, providing structured
64+
error information that can be used by callers to build appropriate error
65+
responses (e.g., Ansible fail_json).
66+
67+
## Usage Example
68+
69+
```python
70+
try:
71+
data = nd.request("/api/v1/endpoint", HttpVerbEnum.POST, payload)
72+
except NDModuleError as e:
73+
print(f"Error: {e.msg}")
74+
print(f"Status: {e.status}")
75+
if e.response_payload:
76+
print(f"Response: {e.response_payload}")
77+
# Use to_dict() for fail_json
78+
module.fail_json(**e.to_dict())
79+
```
80+
81+
## Raises
82+
83+
- None
84+
"""
85+
86+
# pylint: disable=too-many-arguments
87+
def __init__(
88+
self,
89+
msg: str,
90+
status: Optional[int] = None,
91+
request_payload: Optional[dict[str, Any]] = None,
92+
response_payload: Optional[dict[str, Any]] = None,
93+
raw: Optional[Any] = None,
94+
) -> None:
95+
self.error_data = NDErrorData(
96+
msg=msg,
97+
status=status,
98+
request_payload=request_payload,
99+
response_payload=response_payload,
100+
raw=raw,
101+
)
102+
super().__init__(msg)
103+
104+
@property
105+
def msg(self) -> str:
106+
"""Human-readable error message."""
107+
return self.error_data.msg
108+
109+
@property
110+
def status(self) -> Optional[int]:
111+
"""HTTP status code."""
112+
return self.error_data.status
113+
114+
@property
115+
def request_payload(self) -> Optional[dict[str, Any]]:
116+
"""Request payload that was sent."""
117+
return self.error_data.request_payload
118+
119+
@property
120+
def response_payload(self) -> Optional[dict[str, Any]]:
121+
"""Response payload from controller."""
122+
return self.error_data.response_payload
123+
124+
@property
125+
def raw(self) -> Optional[Any]:
126+
"""Raw response content for non-JSON responses."""
127+
return self.error_data.raw
128+
129+
def to_dict(self) -> dict[str, Any]:
130+
"""
131+
# Summary
132+
133+
Convert exception attributes to a dict for use with fail_json.
134+
135+
Returns a dict containing only non-None attributes.
136+
137+
## Raises
138+
139+
- None
140+
"""
141+
return self.error_data.model_dump(exclude_none=True)
142+
143+
144+
class NDStateMachineError(Exception):
145+
"""
146+
Raised when NDStateMachine is failing.
147+
"""
148+
149+
pass

0 commit comments

Comments
 (0)