nac-test-pyats-common 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,6 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """NAC PyATS Common - Architecture adapters for NAC PyATS testing.
2
5
 
3
6
  This package provides architecture-specific authentication, test base classes,
@@ -1,3 +1,6 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """ACI adapter module for PyATS common utilities.
2
5
 
3
6
  This module provides the core ACI-specific components for PyATS testing, including
@@ -1,3 +1,6 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """APIC authentication module for Cisco ACI (Application Centric Infrastructure).
2
5
 
3
6
  This module provides authentication functionality for Cisco APIC (Application Policy
@@ -14,7 +17,9 @@ re-authenticating when necessary, reducing unnecessary API calls to the APIC con
14
17
  """
15
18
 
16
19
  import httpx
17
- from nac_test.pyats_core.common.auth_cache import AuthCache # type: ignore[import-untyped]
20
+ from nac_test.pyats_core.common.auth_cache import (
21
+ AuthCache, # type: ignore[import-untyped]
22
+ )
18
23
 
19
24
  # Default token lifetime for APIC authentication tokens in seconds
20
25
  # APIC tokens are typically valid for 10 minutes (600 seconds) by default
@@ -82,7 +87,8 @@ class APICAuth:
82
87
  response.raise_for_status()
83
88
 
84
89
  # Parse the APIC response and extract the token
85
- # Response structure: {"imdata": [{"aaaLogin": {"attributes": {"token": "..."}}}]}
90
+ # Response structure:
91
+ # {"imdata": [{"aaaLogin": {"attributes": {"token": "..."}}}]}
86
92
  try:
87
93
  response_data = response.json()
88
94
  token = response_data["imdata"][0]["aaaLogin"]["attributes"]["token"]
@@ -1,3 +1,6 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """APIC-specific base test class for ACI API testing.
2
5
 
3
6
  This module provides the APICTestBase class, which extends the generic NACTestBase
@@ -13,7 +16,9 @@ import asyncio
13
16
  from typing import Any
14
17
 
15
18
  import httpx
16
- from nac_test.pyats_core.common.base_test import NACTestBase # type: ignore[import-untyped]
19
+ from nac_test.pyats_core.common.base_test import (
20
+ NACTestBase, # type: ignore[import-untyped]
21
+ )
17
22
  from pyats import aetest # type: ignore[import-untyped]
18
23
 
19
24
  from .auth import APICAuth
@@ -69,7 +74,9 @@ class APICTestBase(NACTestBase): # type: ignore[misc]
69
74
  super().setup()
70
75
 
71
76
  # Get shared APIC token using file-based locking
72
- self.token = APICAuth.get_token(self.controller_url, self.username, self.password)
77
+ self.token = APICAuth.get_token(
78
+ self.controller_url, self.username, self.password
79
+ )
73
80
 
74
81
  # Store the APIC client for use in verification methods
75
82
  self.client = self.get_apic_client()
@@ -94,7 +101,9 @@ class APICTestBase(NACTestBase): # type: ignore[misc]
94
101
  """
95
102
  headers = {"Cookie": f"APIC-cookie={self.token}"}
96
103
  # SSL verification disabled for lab environment compatibility
97
- client = self.pool.get_client(base_url=self.controller_url, headers=headers, verify=False)
104
+ client = self.pool.get_client(
105
+ base_url=self.controller_url, headers=headers, verify=False
106
+ )
98
107
 
99
108
  # Use the generic tracking wrapper from base class
100
109
  return self.wrap_client_for_tracking(client, device_name="APIC") # type: ignore[no-any-return]
@@ -1,3 +1,6 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """Catalyst Center adapter module for NAC PyATS testing.
2
5
 
3
6
  This module provides Catalyst Center-specific authentication and test base class
@@ -1,3 +1,6 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """Catalyst Center-specific authentication implementation.
2
5
 
3
6
  This module provides authentication functionality for Cisco Catalyst Center
@@ -5,7 +8,8 @@ This module provides authentication functionality for Cisco Catalyst Center
5
8
  networks. The authentication mechanism uses token-based login with Basic Auth.
6
9
 
7
10
  The module implements a two-tier API design:
8
- 1. _authenticate() - Low-level method that performs direct Catalyst Center authentication
11
+ 1. _authenticate() - Low-level method that performs direct Catalyst Center
12
+ authentication
9
13
  2. get_auth() - High-level method that leverages caching for efficient token reuse
10
14
 
11
15
  This design ensures efficient token management by reusing valid tokens and only
@@ -16,7 +20,9 @@ import os
16
20
  from typing import Any
17
21
 
18
22
  import httpx
19
- from nac_test.pyats_core.common.auth_cache import AuthCache # type: ignore[import-untyped]
23
+ from nac_test.pyats_core.common.auth_cache import (
24
+ AuthCache, # type: ignore[import-untyped]
25
+ )
20
26
 
21
27
  # Default token lifetime for Catalyst Center authentication in seconds
22
28
  # Catalyst Center tokens are typically valid for 1 hour (3600 seconds) by default
@@ -96,7 +102,9 @@ class CatalystCenterAuth:
96
102
  """
97
103
  last_error: Exception | None = None
98
104
 
99
- with httpx.Client(verify=verify_ssl, timeout=AUTH_REQUEST_TIMEOUT_SECONDS) as client:
105
+ with httpx.Client(
106
+ verify=verify_ssl, timeout=AUTH_REQUEST_TIMEOUT_SECONDS
107
+ ) as client:
100
108
  for endpoint in AUTH_ENDPOINTS:
101
109
  try:
102
110
  auth_response = client.post(
@@ -129,7 +137,8 @@ class CatalystCenterAuth:
129
137
 
130
138
  # All endpoints failed
131
139
  raise RuntimeError(
132
- f"Catalyst Center authentication failed on all endpoints. Last error: {last_error}"
140
+ f"Catalyst Center authentication failed on all endpoints. "
141
+ f"Last error: {last_error}"
133
142
  ) from last_error
134
143
 
135
144
  @classmethod
@@ -148,7 +157,8 @@ class CatalystCenterAuth:
148
157
  CC_URL: Base URL of the Catalyst Center
149
158
  CC_USERNAME: Catalyst Center username for authentication
150
159
  CC_PASSWORD: Catalyst Center password for authentication
151
- CC_INSECURE: Optional. Set to "True" to disable SSL verification (default: True)
160
+ CC_INSECURE: Optional. Set to "True" to disable SSL verification
161
+ (default: True)
152
162
 
153
163
  Returns:
154
164
  A dictionary containing:
@@ -186,7 +196,9 @@ class CatalystCenterAuth:
186
196
  missing_vars.append("CC_USERNAME")
187
197
  if not password:
188
198
  missing_vars.append("CC_PASSWORD")
189
- raise ValueError(f"Missing required environment variables: {', '.join(missing_vars)}")
199
+ raise ValueError(
200
+ f"Missing required environment variables: {', '.join(missing_vars)}"
201
+ )
190
202
 
191
203
  # Normalize URL by removing trailing slash
192
204
  url = url.rstrip("/") # type: ignore[union-attr]
@@ -1,3 +1,6 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """Catalyst Center-specific base test class for API testing.
2
5
 
3
6
  This module provides the CatalystCenterTestBase class, which extends the generic
@@ -14,7 +17,9 @@ import os
14
17
  from typing import Any
15
18
 
16
19
  import httpx
17
- from nac_test.pyats_core.common.base_test import NACTestBase # type: ignore[import-untyped]
20
+ from nac_test.pyats_core.common.base_test import (
21
+ NACTestBase, # type: ignore[import-untyped]
22
+ )
18
23
  from pyats import aetest # type: ignore[import-untyped]
19
24
 
20
25
  from .auth import CatalystCenterAuth
@@ -52,7 +57,9 @@ class CatalystCenterTestBase(NACTestBase): # type: ignore[misc]
52
57
  return ['device1', 'device2']
53
58
 
54
59
  async def verify_item(self, item):
55
- response = await self.client.get(f"/dna/intent/api/v1/network-device/{item}")
60
+ response = await self.client.get(
61
+ f"/dna/intent/api/v1/network-device/{item}"
62
+ )
56
63
  return response.status_code == 200
57
64
 
58
65
  @aetest.test
@@ -90,7 +97,9 @@ class CatalystCenterTestBase(NACTestBase): # type: ignore[misc]
90
97
  self.client = self.get_catc_client()
91
98
 
92
99
  def get_catc_client(self) -> httpx.AsyncClient:
93
- """Get an httpx async client configured for Catalyst Center with response tracking.
100
+ """Get an httpx async client configured for Catalyst Center.
101
+
102
+ Configured with response tracking.
94
103
 
95
104
  Creates an HTTP client specifically configured for Catalyst Center API
96
105
  communication with authentication headers, base URL, and automatic response
@@ -1,3 +1,6 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """Common base classes for nac-test-pyats-common.
2
5
 
3
6
  This module provides architecture-agnostic base classes that can be extended
@@ -1,3 +1,6 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """Base device resolver for SSH/D2D testing.
2
5
 
3
6
  Provides the Template Method pattern for device inventory resolution.
@@ -35,7 +38,8 @@ class BaseDeviceResolver(ABC):
35
38
  - get_credential_env_vars(): Return (username_env_var, password_env_var)
36
39
 
37
40
  Subclasses MAY override:
38
- - get_inventory_filename(): Return inventory filename (default: "test_inventory.yaml")
41
+ - get_inventory_filename(): Return inventory filename
42
+ (default: "test_inventory.yaml")
39
43
  - build_device_dict(): Customize device dict construction
40
44
  - _load_inventory(): Customize inventory loading
41
45
 
@@ -269,7 +273,9 @@ class BaseDeviceResolver(ABC):
269
273
  logger.debug(f"Filtered to {len(devices_to_test)} devices from test inventory")
270
274
  return devices_to_test
271
275
 
272
- def _build_device_index(self, devices: list[dict[str, Any]]) -> dict[str, dict[str, Any]]:
276
+ def _build_device_index(
277
+ self, devices: list[dict[str, Any]]
278
+ ) -> dict[str, dict[str, Any]]:
273
279
  """Build a lookup index of devices by their ID.
274
280
 
275
281
  Args:
@@ -301,7 +307,9 @@ class BaseDeviceResolver(ABC):
301
307
  if key in inventory_entry:
302
308
  return str(inventory_entry[key])
303
309
 
304
- logger.warning(f"Could not extract device ID from inventory entry: {inventory_entry}")
310
+ logger.warning(
311
+ f"Could not extract device ID from inventory entry: {inventory_entry}"
312
+ )
305
313
  return ""
306
314
 
307
315
  def _safe_extract_device_id(self, device_data: dict[str, Any]) -> str:
@@ -333,7 +341,8 @@ class BaseDeviceResolver(ABC):
333
341
 
334
342
  if missing_vars:
335
343
  raise ValueError(
336
- f"Missing required credential environment variables: {', '.join(missing_vars)}. "
344
+ f"Missing required credential environment variables: "
345
+ f"{', '.join(missing_vars)}. "
337
346
  f"These are required for {self.get_architecture_name()} D2D testing."
338
347
  )
339
348
 
@@ -1,3 +1,6 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """IOS-XE adapter module for NAC PyATS testing.
2
5
 
3
6
  This module provides a generic IOS-XE test base class and resolver registry
@@ -1,3 +1,6 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """Catalyst Center device resolver placeholder for D2D testing.
2
5
 
3
6
  This is a placeholder for the Catalyst Center resolver that will be implemented
@@ -1,3 +1,6 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """IOSXE device resolver placeholder for direct IOS-XE device access.
2
5
 
3
6
  This is a placeholder for the IOSXE resolver that will be implemented
@@ -1,3 +1,6 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """Registry for IOS-XE device resolvers.
2
5
 
3
6
  This module implements a plugin architecture for registering and retrieving
@@ -79,20 +82,24 @@ def register_iosxe_resolver(controller_type: str) -> Callable[[type[T]], type[T]
79
82
  """
80
83
  # Validate the class extends BaseDeviceResolver
81
84
  if not issubclass(cls, BaseDeviceResolver):
82
- raise TypeError(f"Resolver class {cls.__name__} must extend BaseDeviceResolver")
85
+ raise TypeError(
86
+ f"Resolver class {cls.__name__} must extend BaseDeviceResolver"
87
+ )
83
88
 
84
89
  # Check for duplicate registration
85
90
  if controller_type in _IOSXE_RESOLVER_REGISTRY:
86
91
  existing_class = _IOSXE_RESOLVER_REGISTRY[controller_type]
87
92
  raise ValueError(
88
- f"A resolver is already registered for controller type '{controller_type}': "
93
+ f"A resolver is already registered for controller type "
94
+ f"'{controller_type}': "
89
95
  f"{existing_class.__module__}.{existing_class.__name__}"
90
96
  )
91
97
 
92
98
  # Register the resolver
93
99
  _IOSXE_RESOLVER_REGISTRY[controller_type] = cls
94
100
  logger.debug(
95
- f"Registered IOS-XE resolver {cls.__name__} for controller type '{controller_type}'"
101
+ f"Registered IOS-XE resolver {cls.__name__} for controller type "
102
+ f"'{controller_type}'"
96
103
  )
97
104
 
98
105
  return cls
@@ -100,7 +107,9 @@ def register_iosxe_resolver(controller_type: str) -> Callable[[type[T]], type[T]
100
107
  return decorator
101
108
 
102
109
 
103
- def get_resolver_for_controller(controller_type: str) -> type[BaseDeviceResolver] | None:
110
+ def get_resolver_for_controller(
111
+ controller_type: str,
112
+ ) -> type[BaseDeviceResolver] | None:
104
113
  """Get the device resolver class for a specific controller type.
105
114
 
106
115
  Retrieves the registered resolver class for the specified controller type.
@@ -124,7 +133,8 @@ def get_resolver_for_controller(controller_type: str) -> type[BaseDeviceResolver
124
133
 
125
134
  if resolver_class:
126
135
  logger.debug(
127
- f"Found resolver {resolver_class.__name__} for controller type '{controller_type}'"
136
+ f"Found resolver {resolver_class.__name__} for controller type "
137
+ f"'{controller_type}'"
128
138
  )
129
139
  else:
130
140
  logger.debug(
@@ -1,3 +1,6 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """IOS-XE test base class for SSH/D2D testing."""
2
5
 
3
6
  import os
@@ -19,7 +22,9 @@ class IOSXETestBase(SSHTestBase): # type: ignore[misc]
19
22
  """
20
23
 
21
24
  @classmethod
22
- def get_ssh_device_inventory(cls, data_model: dict[str, Any]) -> list[dict[str, Any]]:
25
+ def get_ssh_device_inventory(
26
+ cls, data_model: dict[str, Any]
27
+ ) -> list[dict[str, Any]]:
23
28
  """Get the SSH device inventory for IOS-XE devices.
24
29
 
25
30
  Main entry point that detects the architecture and returns
@@ -1,3 +1,6 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """SD-WAN (SDWAN Manager) adapter module for NAC PyATS testing.
2
5
 
3
6
  This module provides SD-WAN-specific authentication, test base classes, and device
@@ -5,7 +8,8 @@ resolver implementations for use with the nac-test framework. It includes suppor
5
8
  for both SDWAN Manager API testing and SSH-based device-to-device (D2D) testing.
6
9
 
7
10
  Classes:
8
- SDWANManagerAuth: SDWAN Manager authentication with JSESSIONID and XSRF token management.
11
+ SDWANManagerAuth: SDWAN Manager authentication with JSESSIONID and XSRF token
12
+ management.
9
13
  SDWANManagerTestBase: Base class for SDWAN Manager API tests with tracking.
10
14
  SDWANTestBase: Base class for SD-WAN SSH/D2D tests with device inventory.
11
15
  SDWANDeviceResolver: Resolves device information from the SD-WAN data model.
@@ -1,9 +1,13 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """SDWAN Manager-specific base test class for SD-WAN API testing.
2
5
 
3
- This module provides the SDWANManagerTestBase class, which extends the generic NACTestBase
4
- to add SDWAN Manager-specific functionality for testing SD-WAN controllers. It handles
5
- session management (JSESSIONID and XSRF token), client configuration, and provides
6
- a standardized interface for running asynchronous verification tests against SDWAN Manager.
6
+ This module provides the SDWANManagerTestBase class, which extends the generic
7
+ NACTestBase to add SDWAN Manager-specific functionality for testing SD-WAN
8
+ controllers. It handles session management (JSESSIONID and XSRF token), client
9
+ configuration, and provides a standardized interface for running asynchronous
10
+ verification tests against SDWAN Manager.
7
11
 
8
12
  The class integrates with PyATS/Genie test frameworks and provides automatic
9
13
  API call tracking for enhanced HTML reporting.
@@ -13,7 +17,9 @@ import asyncio
13
17
  from typing import Any
14
18
 
15
19
  import httpx
16
- from nac_test.pyats_core.common.base_test import NACTestBase # type: ignore[import-untyped]
20
+ from nac_test.pyats_core.common.base_test import (
21
+ NACTestBase, # type: ignore[import-untyped]
22
+ )
17
23
  from pyats import aetest # type: ignore[import-untyped]
18
24
 
19
25
  from .auth import SDWANManagerAuth
@@ -43,7 +49,8 @@ class SDWANManagerTestBase(NACTestBase): # type: ignore[misc]
43
49
 
44
50
  Methods:
45
51
  setup(): Initialize SDWAN Manager authentication and client.
46
- get_sdwan_manager_client(): Create and configure an SDWAN Manager-specific HTTP client.
52
+ get_sdwan_manager_client(): Create and configure an SDWAN Manager-specific
53
+ HTTP client.
47
54
  run_async_verification_test(): Execute async verification tests with PyATS.
48
55
 
49
56
  Example:
@@ -68,7 +75,8 @@ class SDWANManagerTestBase(NACTestBase): # type: ignore[misc]
68
75
 
69
76
  Initializes the SDWAN Manager test environment by:
70
77
  1. Calling the parent class setup method
71
- 2. Obtaining SDWAN Manager session data (jsessionid, xsrf_token) using cached auth
78
+ 2. Obtaining SDWAN Manager session data (jsessionid, xsrf_token) using
79
+ cached auth
72
80
  3. Creating and storing an SDWAN Manager client for use in verification methods
73
81
 
74
82
  The session data is obtained through the SDWANManagerAuth utility which
@@ -84,12 +92,14 @@ class SDWANManagerTestBase(NACTestBase): # type: ignore[misc]
84
92
  self.client = self.get_sdwan_manager_client()
85
93
 
86
94
  def get_sdwan_manager_client(self) -> httpx.AsyncClient:
87
- """Get an httpx async client configured for SDWAN Manager with response tracking.
95
+ """Get an httpx async client configured for SDWAN Manager.
96
+
97
+ Configured with response tracking.
88
98
 
89
- Creates an HTTP client specifically configured for SDWAN Manager API communication
90
- with session headers, base URL, and automatic response tracking for HTML
91
- report generation. The client is wrapped to capture all API interactions
92
- for detailed test reporting.
99
+ Creates an HTTP client specifically configured for SDWAN Manager API
100
+ communication with session headers, base URL, and automatic response
101
+ tracking for HTML report generation. The client is wrapped to capture all
102
+ API interactions for detailed test reporting.
93
103
 
94
104
  The client includes:
95
105
  - JSESSIONID cookie in all requests (via Cookie header)
@@ -98,9 +108,9 @@ class SDWANManagerTestBase(NACTestBase): # type: ignore[misc]
98
108
  - Automatic API call tracking for reporting
99
109
 
100
110
  Returns:
101
- httpx.AsyncClient: Configured client with SDWAN Manager session data, base URL,
102
- and wrapped for automatic API call tracking. The client has SSL
103
- verification disabled for lab environment compatibility.
111
+ httpx.AsyncClient: Configured client with SDWAN Manager session data,
112
+ base URL, and wrapped for automatic API call tracking. The client
113
+ has SSL verification disabled for lab environment compatibility.
104
114
 
105
115
  Note:
106
116
  SSL verification is disabled (verify=False) to support lab environments
@@ -1,8 +1,12 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """SDWAN Manager authentication implementation for Cisco SD-WAN.
2
5
 
3
6
  This module provides authentication functionality for Cisco SDWAN Manager (formerly
4
7
  vManage), which manages the software-defined WAN fabric. The authentication mechanism
5
- uses form-based login with JSESSIONID cookie and optional XSRF token for CSRF protection.
8
+ uses form-based login with JSESSIONID cookie and optional XSRF token for CSRF
9
+ protection.
6
10
 
7
11
  The module implements a two-tier API design:
8
12
  1. _authenticate() - Low-level method that performs direct SDWAN Manager authentication
@@ -16,7 +20,9 @@ import os
16
20
  from typing import Any
17
21
 
18
22
  import httpx
19
- from nac_test.pyats_core.common.auth_cache import AuthCache # type: ignore[import-untyped]
23
+ from nac_test.pyats_core.common.auth_cache import (
24
+ AuthCache, # type: ignore[import-untyped]
25
+ )
20
26
 
21
27
  # Default session lifetime for SDWAN Manager authentication in seconds
22
28
  # SDWAN Manager sessions are typically valid for 30 minutes (1800 seconds) by default
@@ -56,7 +62,9 @@ class SDWANManagerAuth:
56
62
  """
57
63
 
58
64
  @staticmethod
59
- def _authenticate(url: str, username: str, password: str) -> tuple[dict[str, Any], int]:
65
+ def _authenticate(
66
+ url: str, username: str, password: str
67
+ ) -> tuple[dict[str, Any], int]:
60
68
  """Perform direct SDWAN Manager authentication and obtain session data.
61
69
 
62
70
  This method performs a direct authentication request to the SDWAN Manager
@@ -149,8 +157,9 @@ class SDWANManagerAuth:
149
157
  expired ones. This significantly reduces the number of authentication
150
158
  requests to the SDWAN Manager.
151
159
 
152
- The method uses a cache key based on the controller type ("SDWAN_MANAGER") and
153
- URL to ensure proper session isolation between different SDWAN Manager instances.
160
+ The method uses a cache key based on the controller type ("SDWAN_MANAGER")
161
+ and URL to ensure proper session isolation between different SDWAN Manager
162
+ instances.
154
163
 
155
164
  Environment Variables Required:
156
165
  SDWAN_URL: Base URL of the SDWAN Manager
@@ -197,7 +206,9 @@ class SDWANManagerAuth:
197
206
  missing_vars.append("SDWAN_USERNAME")
198
207
  if not password:
199
208
  missing_vars.append("SDWAN_PASSWORD")
200
- raise ValueError(f"Missing required environment variables: {', '.join(missing_vars)}")
209
+ raise ValueError(
210
+ f"Missing required environment variables: {', '.join(missing_vars)}"
211
+ )
201
212
 
202
213
  # Normalize URL by removing trailing slash
203
214
  url = url.rstrip("/") # type: ignore[union-attr]
@@ -1,3 +1,6 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """SD-WAN-specific device resolver for parsing the NAC data model.
2
5
 
3
6
  This module provides the SDWANDeviceResolver class, which extends
@@ -111,7 +114,9 @@ class SDWANDeviceResolver(BaseDeviceResolver):
111
114
 
112
115
  # Fallback to chassis_id
113
116
  chassis_id = device_data.get("chassis_id", "unknown")
114
- logger.warning(f"No system_hostname found for {chassis_id}, using chassis_id as hostname")
117
+ logger.warning(
118
+ f"No system_hostname found for {chassis_id}, using chassis_id as hostname"
119
+ )
115
120
  return str(chassis_id)
116
121
 
117
122
  def extract_host_ip(self, device_data: dict[str, Any]) -> str:
@@ -1,3 +1,6 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (c) 2025 Daniel Schmidt
3
+
1
4
  """SD-WAN specific base test class for SSH/Direct-to-Device testing.
2
5
 
3
6
  This module provides the SDWANTestBase class, which extends the generic SSHTestBase
@@ -17,7 +20,9 @@ import logging
17
20
  import os
18
21
  from typing import Any
19
22
 
20
- from nac_test.pyats_core.common.ssh_base_test import SSHTestBase # type: ignore[import-untyped]
23
+ from nac_test.pyats_core.common.ssh_base_test import (
24
+ SSHTestBase, # type: ignore[import-untyped]
25
+ )
21
26
 
22
27
  from .device_resolver import SDWANDeviceResolver
23
28
 
@@ -44,7 +49,9 @@ class SDWANTestBase(SSHTestBase): # type: ignore[misc]
44
49
  """
45
50
 
46
51
  @classmethod
47
- def get_ssh_device_inventory(cls, data_model: dict[str, Any]) -> list[dict[str, Any]]:
52
+ def get_ssh_device_inventory(
53
+ cls, data_model: dict[str, Any]
54
+ ) -> list[dict[str, Any]]:
48
55
  """Parse the SD-WAN data model to retrieve the device inventory.
49
56
 
50
57
  This method is the entry point called by nac-test's orchestrator.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nac-test-pyats-common
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Architecture adapters for Network as Code (NaC) PyATS testing - auth classes, test base classes, and device resolvers
5
5
  Project-URL: Homepage, https://github.com/netascode/nac-test-pyats-common
6
6
  Project-URL: Documentation, https://github.com/netascode/nac-test-pyats-common
@@ -24,6 +24,7 @@ Classifier: Topic :: Software Development :: Testing
24
24
  Classifier: Topic :: System :: Networking
25
25
  Requires-Python: >=3.10
26
26
  Requires-Dist: httpx>=0.28
27
+ Requires-Dist: nac-test==1.1.0b2
27
28
  Provides-Extra: dev
28
29
  Requires-Dist: bandit[toml]>=1.8.6; extra == 'dev'
29
30
  Requires-Dist: mypy>=1.10; extra == 'dev'
@@ -0,0 +1,24 @@
1
+ nac_test_pyats_common/__init__.py,sha256=bQ3oB1eajVj8pmMnWCxxQEHUW-FkQX94j-6ocBq9OxA,1623
2
+ nac_test_pyats_common/py.typed,sha256=BrP39il8_cNN1K0KDeyBUtySS9oI2_SK5xKx1SxdSoY,59
3
+ nac_test_pyats_common/aci/__init__.py,sha256=Y9VhBZ3_GXLBk3_Wtg1SRG_Dxx134Etf9k-0wvrOMwQ,1335
4
+ nac_test_pyats_common/aci/auth.py,sha256=1Rk2uBGb_CGgkBh9dD3LagIsbJPKRgsSFDYEeyiC50U,7867
5
+ nac_test_pyats_common/aci/test_base.py,sha256=SoPh91AXPvMshJXIyjiZumSgxOAN4xPkpSb3t0B9kdE,6256
6
+ nac_test_pyats_common/catc/__init__.py,sha256=NKIHm6zOiiG8T_wcanPTh8621_RGcVJCMOeQLygTsy8,1319
7
+ nac_test_pyats_common/catc/auth.py,sha256=1oDZr_PEWOz1IZOUm_kyKzIFPQubMo_wemj-Q3D7ALU,9522
8
+ nac_test_pyats_common/catc/test_base.py,sha256=kGp6rZ4S3zP3MW5BD02K5uVxmtE-vRlG2A99kaLgyDo,7507
9
+ nac_test_pyats_common/common/__init__.py,sha256=Y0qrZEKx2g8Zm1CTHJpeLocwMasspP6NQuhyrRiA1wA,1084
10
+ nac_test_pyats_common/common/base_device_resolver.py,sha256=bPZP_dJjBfvaUGg_8F1JhfGAnWzAqI8oIC_JEejDJ4E,18558
11
+ nac_test_pyats_common/iosxe/__init__.py,sha256=GSuLGyxcu8dFouspTjXuQ1Mi27vDluVR8ZCcJrPcIiY,2147
12
+ nac_test_pyats_common/iosxe/catc_resolver.py,sha256=t14Pa6WjrjrbinXTtwc0Wa14Cctcae2yLLgdIpByzoU,2513
13
+ nac_test_pyats_common/iosxe/iosxe_resolver.py,sha256=XzzwRCa1cuQ6HmeUB1Z2vITOwYdhuDlugDD1eVXAoIE,2355
14
+ nac_test_pyats_common/iosxe/registry.py,sha256=djRFzxuEu8IdyTmi1puhIHGZGSMjys0l1v4-uzYCwAU,5723
15
+ nac_test_pyats_common/iosxe/test_base.py,sha256=s-x9hGJ4Yi6313gVamXnHWO7Jzr8tTKXzSOVJ6HcTxU,4306
16
+ nac_test_pyats_common/sdwan/__init__.py,sha256=mrziVp5kMgykKnFPvWykuVLuky6xwEv6oEcfrbxFXxY,1777
17
+ nac_test_pyats_common/sdwan/api_test_base.py,sha256=NuqrxODrRw7ZvEIuoc1Bup60thKqJOfiGz96T4QJ8Ng,7632
18
+ nac_test_pyats_common/sdwan/auth.py,sha256=CMgf_AYCalVQNjdUfDlE-0-z5tnhU_Wnscgt5ZW61RY,10322
19
+ nac_test_pyats_common/sdwan/device_resolver.py,sha256=3eKdIpoZsWHL8EzoKma1ZL6cFiMAQRZiMLp_xf9ZcEw,6062
20
+ nac_test_pyats_common/sdwan/ssh_test_base.py,sha256=8ddzOOyrxVF1uYiOOg2v8kXBI628c6hg-P-hiOC-v3Q,4173
21
+ nac_test_pyats_common-0.1.1.dist-info/METADATA,sha256=1vxKpKhdqZbR0N7wFJH_VYcpGB9MiJiumhUvzaP_4Hg,13072
22
+ nac_test_pyats_common-0.1.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
23
+ nac_test_pyats_common-0.1.1.dist-info/licenses/LICENSE,sha256=zt2sx-c0iEk6-OO0iqRQ4l6fIGazRKW_qLMqfDpLm6M,16295
24
+ nac_test_pyats_common-0.1.1.dist-info/RECORD,,
@@ -1,24 +0,0 @@
1
- nac_test_pyats_common/__init__.py,sha256=yhvIGEkgMoZhwZKWxXUTzkzQT6-6YtpdOOa8mAVgNaY,1551
2
- nac_test_pyats_common/py.typed,sha256=BrP39il8_cNN1K0KDeyBUtySS9oI2_SK5xKx1SxdSoY,59
3
- nac_test_pyats_common/aci/__init__.py,sha256=hEqGdhP_DtCqmLnUncYdmmH5d5WFRsdIkoCzH3DbV1k,1263
4
- nac_test_pyats_common/aci/auth.py,sha256=CSBHmmN8GYNXP-uCC6u31S-AOWcUDhIeLwuolN4OEjU,7772
5
- nac_test_pyats_common/aci/test_base.py,sha256=Em0GTrU0lJLWhwoZOptwnEEDnY3L8YkB-2Sre4endzI,6131
6
- nac_test_pyats_common/catc/__init__.py,sha256=1e5RjeEKApalS9CqSRi_nvER1MRtaCfQJ-kVOq8zp0w,1247
7
- nac_test_pyats_common/catc/auth.py,sha256=yCp9NGe48CngxGN0QVLS17ukfJge7rdBcV-L2_lez7U,9350
8
- nac_test_pyats_common/catc/test_base.py,sha256=myhdMFN310z6D3IC_BcSvtNQ4iyGbZZtiROxoNAHs0I,7367
9
- nac_test_pyats_common/common/__init__.py,sha256=tMBObh27Bl3AHe4UVu3EoI6rbhxWV901WKw4SEMvnwk,1012
10
- nac_test_pyats_common/common/base_device_resolver.py,sha256=VQDkV6EzZCJL9TrJcB2i34BFz9Y8cK7g2Y_8NP7AVrQ,18420
11
- nac_test_pyats_common/iosxe/__init__.py,sha256=dIXPUdOJAy8P7KM4_scfkFSB4g1c-b7AdsEC3Ok8gEE,2075
12
- nac_test_pyats_common/iosxe/catc_resolver.py,sha256=YK8-1Y0EIkX5CBawAqAxYk2kMjYwoBWXLtM3Yz_7kfQ,2441
13
- nac_test_pyats_common/iosxe/iosxe_resolver.py,sha256=CmvbF8eFo5I_Uy_JDx1lO-2YaB_fiDxK-I7WBvu7X5o,2283
14
- nac_test_pyats_common/iosxe/registry.py,sha256=toRNcIcXkPPrm-kC4tpxOf6kTXgvC2Dsh8Vm5EXEwRY,5562
15
- nac_test_pyats_common/iosxe/test_base.py,sha256=dJrTpRy3V8Q0vK5FODHzDh85EZ7eM8dS9PnBvRF-i_0,4220
16
- nac_test_pyats_common/sdwan/__init__.py,sha256=QUnYDV25cwubonnpXkkhGrDcSOcDtmabAAx8fPnM4zQ,1697
17
- nac_test_pyats_common/sdwan/api_test_base.py,sha256=gTy57JSa6pjuCayfZMzS1lUPZHYSTqZjr8LeDNoLouc,7507
18
- nac_test_pyats_common/sdwan/auth.py,sha256=V_OVAZzCSOvfTYrPGyv-xXZEDDHIpTl2BBxDoB5Mwro,10189
19
- nac_test_pyats_common/sdwan/device_resolver.py,sha256=huAfUG6TADF3lWeOUyr244jRogC5SqWhz4k-1191ZnY,5968
20
- nac_test_pyats_common/sdwan/ssh_test_base.py,sha256=KvV_Hw56EiX5HcVRNG2A2ryLH0v6RbmLlUzyJMQ-424,4078
21
- nac_test_pyats_common-0.1.0.dist-info/METADATA,sha256=hZNaqHtElHIADhf2CumhWpg8qf9aEWEE_eM2tIr6IQw,13039
22
- nac_test_pyats_common-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
23
- nac_test_pyats_common-0.1.0.dist-info/licenses/LICENSE,sha256=zt2sx-c0iEk6-OO0iqRQ4l6fIGazRKW_qLMqfDpLm6M,16295
24
- nac_test_pyats_common-0.1.0.dist-info/RECORD,,