Add opt-in gathered-state filtering for loopback and local users - #391
Add opt-in gathered-state filtering for loopback and local users#391deekpand-cisco wants to merge 7 commits into
Conversation
7a31104 to
3a3e41b
Compare
| Returned objects remain in API shape for NDConfigCollection.from_api_response(). | ||
| """ | ||
|
|
||
| if not filters: |
There was a problem hiding this comment.
Should we still deduplicate the results when no filters are provided? Right now this returns before the deduplication logic runs.
There was a problem hiding this comment.
Removed the early return so deduplication now runs unconditionally. The to_config() function is only called when active filters exist to avoid unnecessary work.
| query_kwargs["gathered_filters"] = raw_config | ||
|
|
||
| response_data = self.model_orchestrator.query_all(**query_kwargs) | ||
|
|
There was a problem hiding this comment.
Can we validate the gathered filters before calling query_all()? Otherwise, an invalid filter may make unnecessary API calls before it fails.
There was a problem hiding this comment.
Added a validate_gathered_filters() function as a pre-flight check in the state machine, called before query_all(). Invalid filters now fail fast without making API calls.
| meta = result.get("meta") or {} | ||
| counts = meta.get("counts") or {} | ||
| try: | ||
| remaining = int(counts.get("remaining", 0)) |
There was a problem hiding this comment.
If remaining is missing or invalid, this treats it as zero and stops pagination. Could this return incomplete gathered results when the first page is full? Or, may be continue based on the page size or fail instead of returning partial data?
Add gathered_all state to the state machine for modules that retrieve all instances, mask_secrets helper for sensitive field redaction, and associated unit tests. Note: gathered-all framework cherry-picked from PR CiscoDevNet#312
Add server-side Lucene candidate filtering for gathered loopback interfaces with pagination, deduplication, and final local matching. Support gather-all and login-ID filtering for local users while rejecting unsupported gathered criteria. Add unit and integration coverage for filtering, validation, secrecy, and reusable output.
- Remove early return in filter_gathered_response() so deduplication runs unconditionally regardless of whether filters are provided - Add validate_gathered_filters() pre-flight check called before query_all() to reject invalid filters without wasted API calls
- Add gathered_filter_properties ClassVar to NDBaseModel for declarative filter whitelisting per module - Add pre-flight property validation (_extract_active_leaf_paths, _reject_unsupported_filter_properties) that rejects unsupported filter fields before any API call - Replace local_user custom normalize_gathered_filter validation with shared gathered_filter_properties tuple (login_id, email, first_name, last_name) - Add gathered_filter_properties to loopback model (switch_ip, interface_name, admin_state, ip, ipv6, vrf) - Pass supported_properties from model to validate_gathered_filters in state machine - Add gathered_transform support in NDOutput for modules with input/output shape differences - Fix loopback pagination: add max_pages safety cap, handle missing or invalid remaining metadata gracefully - Update nd_local_user DOCUMENTATION with supported filter properties - Update local_user unit tests to use shared validation path
b2f84a4 to
687baef
Compare
- Apply black formatting to all gathered filtering module and test files - Add gathered state as no-op pass in manage_state() so modules can call manage_state unconditionally without raising InvalidState - Address review formatting feedback (trailing whitespace, blank lines)
687baef to
8d216fa
Compare
6c0f646 to
da41a29
Compare
- Extract gathered query logic into _query_existing() private helper - Move user-input validation outside try block for clean error messages - Build proposed before querying ND (fail-fast on bad config) - Declare get_argument_spec on NDBaseModel and gathered_transform on NDBaseOrchestrator; remove getattr probes for discoverability - Rename supports_gathered_lucene_filtering to supports_gathered_server_filtering (mechanism-neutral) - Normalize filters once in state machine; pass normalize_filter=None downstream to eliminate triple normalization - Return models from filter_gathered_response to avoid double Pydantic validation; use pre-built models for NDConfigCollection construction - Cap Lucene query fan-out at 3 expressions per switch; collapse to base expression beyond threshold - Raise ValueError for unknown switch_ip in gathered filters instead of silently returning empty results - Raise RuntimeError on pagination limit exhaustion instead of silently truncating gathered results - Update unit tests for new return types, renamed flags, and pre-normalized filter inputs
da41a29 to
01537ab
Compare
Related Issue(s)
Related to #340.
This PR builds on the foundational framework established in
#312
including the state machine, base model infrastructure, orchestrator pattern,
and secrets handling.
Proposed Changes
This PR introduces an opt-in gathered-state filtering framework for modules
using
NDStateMachineand enables it for:cisco.nd.nd_interface_loopbackcisco.nd.nd_local_userShared gathered-filtering framework
The shared implementation:
state: gathered;supports_gathered_filtering;configas partial filter criteria for supported gathered operations;gathered_filter_propertiesand rejects unsupported properties before any API request;normalize_gathered_filter;matches_gathered_filter;proposedconfiguration;The generic local filter remains the final correctness layer. Endpoint-specific filtering is used only to reduce the number of API candidates where the endpoint safely supports it.
Loopback-interface filtering
The loopback module supports gather-all and partial gathered filters across switches in a fabric.
Gathered loopback queries use the interface-list endpoint and its Lucene
filterquery parameter:interfaceType:loopbackandpolicyType:loopback;switch_ipis resolved to a switch serial number and limits the query to that switch;switch_ipqueries all switches in the fabric;interface_nameis translated into an exact-match Lucene term;maxandoffsetuntil the API reports no remaining results;Lucene expressions are built only from structured module input. Raw Lucene expressions are not accepted from users.
The module continues to enforce its resource-ownership boundary:
interfaceTypemust beloopback;policyTypemust beloopback;underlayLoopbackinterfaces are excluded;ipfmLoopbackanduserDefinedpolicies are excluded.Nested criteria such as IP address, administrative state, IPv6 address, and VRF are evaluated by the generic final local filter.
Interface names supplied as filters are normalized to lowercase to match the existing model and Nexus Dashboard API behavior.
Local-user filtering
The local-user endpoint does not expose documented server-side Lucene filtering. Gather-all retrieves the available local users, and optional filter criteria are evaluated through the shared final local-matching layer.
Supported gathered filter properties for local users are
login_id,email,first_name, andlast_name. Other configuration fields (such asuser_password,reuse_limitation, orsecurity_domains) are rejected with a validation error before any API request.Multiple filter items use OR semantics. String matching is case-sensitive.
Local-user passwords are not returned by Nexus Dashboard and remain excluded from gathered output. Gathered output for an existing user can be reused as configuration, but recreating a deleted user still requires a new password.
Argument validation and gathered output
For both modules:
configcan be omitted for gather-all operations;configremains required for write states throughrequired_if;config;changed: false.For loopback gathered operations,
switch_ip,interface_name, and nested policy fields (admin_state,ip,ipv6,vrf) can be supplied as partial filtering criteria.For local-user gathered operations,
login_id,email,first_name, andlast_namecan be supplied as partial filtering criteria.Compatibility and rollout
Test Notes
Unit coverage includes Lucene expression construction and escaping, query planning, pagination, deduplication, local matching, gathered/write-state isolation, local-user filtering, property validation, and password secrecy.
Integration coverage was added for gather-all, exact and multiple filters, OR semantics, no-match behavior, unsupported filter rejection, empty filter rejection, password secrecy, and gathered-output reuse.
Cisco Nexus Dashboard Version
Cisco Nexus Dashboard 4.2 lab environment.
Related ND API Resource Category
The loopback-interface module uses the Manage API, while the local-user module uses the Infra AAA API.
Checklist