Add Smart Endpoints framework for ND API v1#186
Add Smart Endpoints framework for ND API v1#186allenrobel wants to merge 21 commits intond42_integrationfrom
Conversation
Base classes: - plugins/module_utils/ep/base_path.py: ApiPath base class for type-safe endpoint path construction - plugins/module_utils/ep/base_paths_ndfc.py: NDFC base path constants - plugins/module_utils/ep/endpoint_mixins.py: Reusable endpoint mixins (e.g. LoginIdMixin) - plugins/module_utils/ep/query_params.py: EndpointQueryParams, LuceneQueryParams, CompositeQueryParams for structured query string building ND API v1 endpoints: - plugins/module_utils/ep/v1/base_paths_infra.py: Infra API base paths - plugins/module_utils/ep/v1/base_paths_manage.py: Manage API base paths - plugins/module_utils/ep/v1/ep_infra_aaa.py: AAA (login) endpoint - plugins/module_utils/ep/v1/ep_infra_clusterhealth.py: Cluster health endpoint - plugins/module_utils/ep/v1/ep_manage_switches.py: Switch management endpoint Design documentation: - plugins/module_utils/ep/ANALYSIS_COMPLEXITY.md - plugins/module_utils/ep/ANALYSIS_ENDPOINT_DESIGN.md - plugins/module_utils/ep/ANALYSIS_TYPE_SAFETY.md Unit tests: - tests/unit/module_utils/ep/test_base_path.py - tests/unit/module_utils/ep/test_base_paths_infra.py - tests/unit/module_utils/ep/test_base_paths_manage.py - tests/unit/module_utils/ep/test_endpoint_mixins.py - tests/unit/module_utils/ep/test_ep_api_v1_infra_aaa.py - tests/unit/module_utils/ep/test_ep_api_v1_infra_clusterhealth.py - tests/unit/module_utils/ep/test_ep_api_v1_manage_switches.py - tests/unit/module_utils/ep/test_query_params.py Note: tests depend on enums.py, pydantic_compat.py, and shared test infrastructure (common_utils, etc.) from nd42_rest_send, and on log.py from nd42_logging. Tests will not run until all branches are merged into nd42_integration. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| @@ -0,0 +1,88 @@ | |||
| # -*- coding: utf-8 -*- | |||
|
|
|||
There was a problem hiding this comment.
Would like to discuss this in the standup today
There was a problem hiding this comment.
Yes, this is a holdover from Python v2 and is no longer needed in v3. If non-ASCII character accidentally made its way into a Python v2 file, you'd get a SyntaxError exception without it (though, I'd argue that would be a good thing).
Anyway, I'll remove these from all the files in my PRs.
There was a problem hiding this comment.
Removed from all files in this PR. Need to do the same for the other PRs.
1. Remove /mso, /appcenter/*, /login paths TODO: Need to add /api/v1/infra/login under infra endpoints.
Removed the following from all files: # -*- coding: utf-8 -*-
- plugins/module_utils/ep/ → plugins/module_utils/endpoints/ - v1/ep_infra_aaa.py → v1/infra_aaa.py - v1/ep_infra_clusterhealth.py → v1/infra_clusterhealth.py - v1/ep_manage_switches.py → v1/manage_switches.py - tests/unit/module_utils/ep/ → tests/unit/module_utils/endpoints/ - test_ep_api_v1_*.py → test_endpoints_api_v1_*.py - Update all internal imports to reflect new paths Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the test_ep_ prefix in all test function names within the three ep-specific test files to match the renamed file and directory. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ansible sanity tests use a regex to verify the __metaclass__ = type declaration and do not expect an inline comment. Move the pylint disable/enable directives to separate lines. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| @@ -0,0 +1,89 @@ | |||
| # Copyright: (c) 2026, Allen Robel (@arobel) <arobel@cisco.com> | |||
There was a problem hiding this comment.
do we need endpoint_ in this name can be mixins.py
There was a problem hiding this comment.
Akshay has mixins and others will have mixins so should we put them all in onen file called mixins.py or only put "common" things in mixins.py and use a module_name directory or some other way to separate mixin files?
There was a problem hiding this comment.
Renamed to mixins.py with commit: 26cbd52
Endpoint mixins are associated with endpoints rather than than modules. So, I'd lean toward keeping them in one file (or, if we use multiple files, name them e.g. infra_mixins.py, manage_mixins.py, etc). I had Claude do an analysis of the query parameter usage in infra and manage where he read the schema and reported on the percentage sharing of query params across all endpoints, max query params used by endpoints, etc.
Claude found zero overlap between infra and manage, so these should probably be separate files:
https://github.com/CiscoDevNet/ansible-nd/blob/rest_send_integration/ANALYSIS_ENDPOINT_PARAMETERS.md
There was a problem hiding this comment.
Another conclusion Claude made is that there are several mixins defined in mixins.py that are not used in either infra or manage schemas. These are probably legacy mixins from NDFC, so I'll open an issue to remove them. I'll double check these though...
"Key Finding: Only 3 of 11 defined mixins are actually used (LoginIdMixin, FabricNameMixin, ForceShowRunMixin). The 8 unused mixins (ClusterNameMixin, HealthCategoryMixin, InclAllMsdSwitchesMixin, LinkUuidMixin, NetworkNameMixin, NodeNameMixin, SwitchSerialNumberMixin, VrfNameMixin) have no corresponding parameters in either schema."
| @@ -0,0 +1,178 @@ | |||
| # Copyright: (c) 2026, Allen Robel (@arobel) <arobel@cisco.com> | |||
|
|
|||
| # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) | |||
|
|
||
| ## Current Stable API Version | ||
|
|
||
| v1 (ND 3.0+, NDFC 12+) |
There was a problem hiding this comment.
Update to be ND 4.2+, Remove NDFC reference
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pydantic_compat was moved into module_utils/commmon in nd42_rest_send branch. nd42_smart_endpoints and nd42_rest_send will be merged into a common integration branch shortly, so am updating at least some of the imports that are known to have changed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Forgot to add this in the earlier commit.
typing.Final was added in Python 3.8. Since all affected files already use from __future__ import annotations (PEP 563), Final is only needed during static type checking and never evaluated at runtime. Guarding the import with TYPE_CHECKING avoids the ImportError on Python 3.7 with no dependency on typing_extensions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adding for Ansible sanity tests.
Literal was added in Python 3.8. ansible-test sanity runs against Python 3.7, so importing it directly causes ImportError. Since all three files already have `from __future__ import annotations`, all annotations are lazy strings at runtime and the TYPE_CHECKING guard is safe. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ansible-test sanity requires all __init__.py files under plugins/ to be completely empty. No imports are broken since all consumers already import directly from submodules. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
Adds the Smart Endpoints framework — a type-safe, Pydantic-validated approach to constructing ND REST API endpoint paths and query parameters. This PR is one of three companion PRs targeting
nd42_integration:nd42_rest_sendenums.py, shared test infrastructurend42_loggingLogclass and logging confignd42_smart_endpointsPlugin files added
Base classes (
plugins/module_utils/endpoints/)base_path.pyApiPath— string enum providing type-safe base API path constants shared across all endpoint versionsendpoint_mixins.pyLoginIdMixinfor endpoints requiring a login ID)query_params.pyEndpointQueryParams,LuceneQueryParams,CompositeQueryParams— Pydantic models for structured, validated query string constructionND API v1 endpoints (
plugins/module_utils/endpoints/v1/)base_paths_infra.py/api/v1/infranamespacebase_paths_manage.py/api/v1/managenamespaceinfra_aaa.pyinfra_clusterhealth.pyinfra_login.pyEpInfraLoginPost) for/api/v1/infra/loginmanage_switches.pyUnit tests added
test_base_path.pyApiPathbase classtest_base_paths_infra.pytest_base_paths_manage.pytest_endpoint_mixins.pyLoginIdMixinand other mixinstest_endpoints_api_v1_infra_aaa.pytest_endpoints_api_v1_infra_clusterhealth.pytest_endpoints_api_v1_infra_login.pytest_endpoints_api_v1_manage_switches.pytest_query_params.pyDependencies
plugins/module_utils/enums.py—HttpVerbEnum,BooleanStringEnum(fromnd42_rest_sendAdd RestSend framework, enums, and shared unit test infrastructure #185)plugins/module_utils/pydantic_compat.py— Pydantic shim (fromnd42_rest_sendAdd RestSend framework, enums, and shared unit test infrastructure #185)tests/unit/module_utils/common_utils.py—does_not_raise()(fromnd42_rest_sendAdd RestSend framework, enums, and shared unit test infrastructure #185)Merge order
nd42_rest_send(Add RestSend framework, enums, and shared unit test infrastructure #185) →nd42_integrationnd42_logging(Add Log class and logging config #184) →nd42_integrationnd42_integrationTest plan
nd42_integration:python -m pytest tests/unit/module_utils/endpoints/passes cleanlytox -e linterspasses (black, isort, pylint, mypy)ansible-test sanity --dockerpasses🤖 Generated with Claude Code