nac-test-pyats-common 0.2.0__py3-none-any.whl → 0.2.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.
- nac_test_pyats_common/aci/auth.py +177 -53
- nac_test_pyats_common/aci/test_base.py +35 -12
- nac_test_pyats_common/catc/api_test_base.py +35 -11
- nac_test_pyats_common/catc/auth.py +116 -49
- nac_test_pyats_common/catc/device_resolver.py +12 -5
- nac_test_pyats_common/common/base_device_resolver.py +71 -24
- nac_test_pyats_common/iosxe/iosxe_resolver.py +2 -2
- nac_test_pyats_common/sdwan/api_test_base.py +28 -7
- nac_test_pyats_common/sdwan/auth.py +125 -64
- nac_test_pyats_common/sdwan/device_resolver.py +23 -8
- {nac_test_pyats_common-0.2.0.dist-info → nac_test_pyats_common-0.2.1.dist-info}/METADATA +3 -2
- nac_test_pyats_common-0.2.1.dist-info/RECORD +25 -0
- nac_test_pyats_common-0.2.0.dist-info/RECORD +0 -25
- {nac_test_pyats_common-0.2.0.dist-info → nac_test_pyats_common-0.2.1.dist-info}/WHEEL +0 -0
- {nac_test_pyats_common-0.2.0.dist-info → nac_test_pyats_common-0.2.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -14,14 +14,21 @@ The module implements a two-tier API design:
|
|
|
14
14
|
|
|
15
15
|
This design ensures efficient session management by reusing valid sessions and only
|
|
16
16
|
re-authenticating when necessary, reducing unnecessary API calls to the SDWAN Manager.
|
|
17
|
+
|
|
18
|
+
Note on Fork Safety:
|
|
19
|
+
This module uses urllib instead of httpx for synchronous authentication requests.
|
|
20
|
+
httpx is NOT fork-safe on macOS - creating httpx.Client after fork() causes
|
|
21
|
+
silent crashes due to OpenSSL threading issues. urllib uses simpler primitives
|
|
22
|
+
that work correctly after fork().
|
|
17
23
|
"""
|
|
18
24
|
|
|
19
25
|
import os
|
|
20
26
|
from typing import Any
|
|
21
27
|
|
|
22
|
-
import
|
|
23
|
-
from nac_test.pyats_core.common.
|
|
24
|
-
|
|
28
|
+
from nac_test.pyats_core.common.auth_cache import AuthCache
|
|
29
|
+
from nac_test.pyats_core.common.subprocess_auth import (
|
|
30
|
+
SubprocessAuthError, # noqa: F401 - re-exported for callers to catch
|
|
31
|
+
execute_auth_subprocess,
|
|
25
32
|
)
|
|
26
33
|
|
|
27
34
|
# Default session lifetime for SDWAN Manager authentication in seconds
|
|
@@ -63,7 +70,7 @@ class SDWANManagerAuth:
|
|
|
63
70
|
|
|
64
71
|
@staticmethod
|
|
65
72
|
def _authenticate(
|
|
66
|
-
url: str, username: str, password: str
|
|
73
|
+
url: str, username: str, password: str, verify_ssl: bool = False
|
|
67
74
|
) -> tuple[dict[str, Any], int]:
|
|
68
75
|
"""Perform direct SDWAN Manager authentication and obtain session data.
|
|
69
76
|
|
|
@@ -77,12 +84,19 @@ class SDWANManagerAuth:
|
|
|
77
84
|
3. Attempt to fetch XSRF token (for 19.2+ only)
|
|
78
85
|
4. Return session data with TTL
|
|
79
86
|
|
|
87
|
+
Note: On macOS, SSL operations in forked processes crash due to OpenSSL
|
|
88
|
+
threading issues. This method uses subprocess with spawn context to perform
|
|
89
|
+
authentication in a fresh process, avoiding the fork+SSL crash.
|
|
90
|
+
|
|
80
91
|
Args:
|
|
81
92
|
url: Base URL of the SDWAN Manager (e.g., "https://sdwan-manager.example.com").
|
|
82
93
|
Should not include trailing slashes or API paths.
|
|
83
94
|
username: SDWAN Manager username for authentication. This should be a valid
|
|
84
95
|
user configured with appropriate permissions.
|
|
85
96
|
password: Password for the specified user account.
|
|
97
|
+
verify_ssl: Whether to verify SSL certificates. Defaults to False to
|
|
98
|
+
handle self-signed certificates commonly used in lab and development
|
|
99
|
+
deployments.
|
|
86
100
|
|
|
87
101
|
Returns:
|
|
88
102
|
A tuple containing:
|
|
@@ -91,61 +105,99 @@ class SDWANManagerAuth:
|
|
|
91
105
|
- expires_in (int): Session lifetime in seconds (typically 1800).
|
|
92
106
|
|
|
93
107
|
Raises:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
httpx.RequestError: If the request fails due to network issues,
|
|
97
|
-
connection timeouts, or other transport-level problems.
|
|
98
|
-
ValueError: If the JSESSIONID cookie is not received in the response,
|
|
99
|
-
indicating a malformed or unexpected response.
|
|
100
|
-
|
|
101
|
-
Note:
|
|
102
|
-
SSL verification is disabled (verify=False) to handle self-signed
|
|
103
|
-
certificates commonly used in lab and development deployments.
|
|
104
|
-
In production environments, proper certificate validation should be enabled
|
|
105
|
-
by either installing the certificate in the trust store or providing
|
|
106
|
-
a custom CA bundle via the verify parameter.
|
|
108
|
+
SubprocessAuthError: If authentication subprocess fails.
|
|
109
|
+
ValueError: If the authentication response is malformed.
|
|
107
110
|
"""
|
|
108
|
-
#
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
111
|
+
# Build auth parameters for subprocess
|
|
112
|
+
auth_params = {
|
|
113
|
+
"url": url,
|
|
114
|
+
"username": username,
|
|
115
|
+
"password": password,
|
|
116
|
+
"timeout": AUTH_REQUEST_TIMEOUT_SECONDS,
|
|
117
|
+
"xsrf_timeout": XSRF_TOKEN_FETCH_TIMEOUT_SECONDS,
|
|
118
|
+
"verify_ssl": verify_ssl,
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# SDWAN-specific authentication logic
|
|
122
|
+
# This script assumes `params` dict is already loaded by execute_auth_subprocess
|
|
123
|
+
auth_script_body = """
|
|
124
|
+
import http.cookiejar
|
|
125
|
+
import ssl
|
|
126
|
+
import urllib.parse
|
|
127
|
+
import urllib.request
|
|
128
|
+
|
|
129
|
+
url = params["url"]
|
|
130
|
+
username = params["username"]
|
|
131
|
+
password = params["password"]
|
|
132
|
+
timeout = params["timeout"]
|
|
133
|
+
xsrf_timeout = params["xsrf_timeout"]
|
|
134
|
+
verify_ssl = params["verify_ssl"]
|
|
135
|
+
|
|
136
|
+
# Create SSL context
|
|
137
|
+
ssl_context = ssl.create_default_context()
|
|
138
|
+
if not verify_ssl:
|
|
139
|
+
ssl_context.check_hostname = False
|
|
140
|
+
ssl_context.verify_mode = ssl.CERT_NONE
|
|
141
|
+
|
|
142
|
+
# Create cookie jar and opener
|
|
143
|
+
cookie_jar = http.cookiejar.CookieJar()
|
|
144
|
+
https_handler = urllib.request.HTTPSHandler(context=ssl_context)
|
|
145
|
+
cookie_handler = urllib.request.HTTPCookieProcessor(cookie_jar)
|
|
146
|
+
opener = urllib.request.build_opener(https_handler, cookie_handler)
|
|
147
|
+
|
|
148
|
+
# Step 1: Form-based login to /j_security_check
|
|
149
|
+
auth_data = urllib.parse.urlencode({
|
|
150
|
+
"j_username": username,
|
|
151
|
+
"j_password": password
|
|
152
|
+
}).encode("utf-8")
|
|
153
|
+
|
|
154
|
+
auth_request = urllib.request.Request(
|
|
155
|
+
f"{url}/j_security_check",
|
|
156
|
+
data=auth_data,
|
|
157
|
+
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
|
158
|
+
method="POST"
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
try:
|
|
162
|
+
opener.open(auth_request, timeout=timeout)
|
|
163
|
+
except urllib.error.HTTPError as e:
|
|
164
|
+
if e.code != 302: # 302 redirect is expected on successful login
|
|
165
|
+
raise
|
|
166
|
+
|
|
167
|
+
# Extract JSESSIONID from cookies
|
|
168
|
+
jsessionid = None
|
|
169
|
+
for cookie in cookie_jar:
|
|
170
|
+
if cookie.name == "JSESSIONID":
|
|
171
|
+
jsessionid = cookie.value
|
|
172
|
+
break
|
|
173
|
+
|
|
174
|
+
if jsessionid is None:
|
|
175
|
+
result = {"error": "No JSESSIONID cookie received - authentication may have failed"}
|
|
176
|
+
else:
|
|
177
|
+
# Step 2: Fetch XSRF token (required for SDWAN Manager 19.2+)
|
|
178
|
+
xsrf_token = None
|
|
179
|
+
try:
|
|
180
|
+
token_request = urllib.request.Request(
|
|
181
|
+
f"{url}/dataservice/client/token",
|
|
182
|
+
headers={"Cookie": f"JSESSIONID={jsessionid}"},
|
|
183
|
+
method="GET"
|
|
184
|
+
)
|
|
185
|
+
token_response = opener.open(token_request, timeout=xsrf_timeout)
|
|
186
|
+
if token_response.status == 200:
|
|
187
|
+
xsrf_token = token_response.read().decode("utf-8").strip()
|
|
188
|
+
except Exception:
|
|
189
|
+
pass # Pre-19.2 versions do not support XSRF tokens
|
|
190
|
+
|
|
191
|
+
result = {"jsessionid": jsessionid, "xsrf_token": xsrf_token}
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
# Execute authentication in subprocess (fork-safe on macOS)
|
|
195
|
+
auth_result = execute_auth_subprocess(auth_params, auth_script_body)
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
"jsessionid": auth_result["jsessionid"],
|
|
199
|
+
"xsrf_token": auth_result.get("xsrf_token"),
|
|
200
|
+
}, SDWAN_MANAGER_SESSION_LIFETIME_SECONDS
|
|
149
201
|
|
|
150
202
|
@classmethod
|
|
151
203
|
def get_auth(cls) -> dict[str, Any]:
|
|
@@ -165,6 +217,8 @@ class SDWANManagerAuth:
|
|
|
165
217
|
SDWAN_URL: Base URL of the SDWAN Manager
|
|
166
218
|
SDWAN_USERNAME: SDWAN Manager username for authentication
|
|
167
219
|
SDWAN_PASSWORD: SDWAN Manager password for authentication
|
|
220
|
+
SDWAN_INSECURE: If "True", "1", or "yes" (default: "True"), SSL certificate
|
|
221
|
+
verification is disabled. Set to "False" to enable SSL verification.
|
|
168
222
|
|
|
169
223
|
Returns:
|
|
170
224
|
A dictionary containing:
|
|
@@ -175,11 +229,10 @@ class SDWANManagerAuth:
|
|
|
175
229
|
Raises:
|
|
176
230
|
ValueError: If any required environment variables (SDWAN_URL,
|
|
177
231
|
SDWAN_USERNAME, SDWAN_PASSWORD) are not set.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
connection timeouts, or other transport-level problems.
|
|
232
|
+
SubprocessAuthError: If authentication fails due to invalid credentials,
|
|
233
|
+
network issues, connection timeouts, or SDWAN Manager server errors.
|
|
234
|
+
The error message will contain details from the authentication
|
|
235
|
+
subprocess.
|
|
183
236
|
|
|
184
237
|
Example:
|
|
185
238
|
>>> # Set environment variables first
|
|
@@ -197,6 +250,11 @@ class SDWANManagerAuth:
|
|
|
197
250
|
url = os.environ.get("SDWAN_URL")
|
|
198
251
|
username = os.environ.get("SDWAN_USERNAME")
|
|
199
252
|
password = os.environ.get("SDWAN_PASSWORD")
|
|
253
|
+
insecure = os.environ.get("SDWAN_INSECURE", "True").lower() in (
|
|
254
|
+
"true",
|
|
255
|
+
"1",
|
|
256
|
+
"yes",
|
|
257
|
+
)
|
|
200
258
|
|
|
201
259
|
if not all([url, username, password]):
|
|
202
260
|
missing_vars: list[str] = []
|
|
@@ -213,9 +271,12 @@ class SDWANManagerAuth:
|
|
|
213
271
|
# Normalize URL by removing trailing slash
|
|
214
272
|
url = url.rstrip("/") # type: ignore[union-attr]
|
|
215
273
|
|
|
274
|
+
# SDWAN_INSECURE=True means verify_ssl=False
|
|
275
|
+
verify_ssl = not insecure
|
|
276
|
+
|
|
216
277
|
def auth_wrapper() -> tuple[dict[str, Any], int]:
|
|
217
278
|
"""Wrapper for authentication that captures closure variables."""
|
|
218
|
-
return cls._authenticate(url, username, password) # type: ignore[arg-type]
|
|
279
|
+
return cls._authenticate(url, username, password, verify_ssl) # type: ignore[arg-type]
|
|
219
280
|
|
|
220
281
|
# AuthCache.get_or_create returns dict[str, Any], but mypy can't verify this
|
|
221
282
|
# because nac_test lacks py.typed marker.
|
|
@@ -5,6 +5,16 @@
|
|
|
5
5
|
|
|
6
6
|
This module provides the SDWANDeviceResolver class, which extends
|
|
7
7
|
BaseDeviceResolver to implement SD-WAN schema navigation.
|
|
8
|
+
|
|
9
|
+
Device Fields Returned:
|
|
10
|
+
- hostname: System hostname from device_variables.system_hostname
|
|
11
|
+
- host: Management IP address (CIDR stripped)
|
|
12
|
+
- os: Always 'iosxe' (SD-WAN edges are IOS-XE based)
|
|
13
|
+
- platform: Always 'sdwan' (for PyATS abstraction optimization)
|
|
14
|
+
- device_id: Chassis ID
|
|
15
|
+
- type: Always 'router'
|
|
16
|
+
- username: From IOSXE_USERNAME environment variable
|
|
17
|
+
- password: From IOSXE_PASSWORD environment variable
|
|
8
18
|
"""
|
|
9
19
|
|
|
10
20
|
import logging
|
|
@@ -173,28 +183,33 @@ class SDWANDeviceResolver(BaseDeviceResolver):
|
|
|
173
183
|
|
|
174
184
|
return ip_value
|
|
175
185
|
|
|
176
|
-
def
|
|
177
|
-
"""Return
|
|
186
|
+
def extract_os_platform_type(self, device_data: dict[str, Any]) -> dict[str, str]:
|
|
187
|
+
"""Return PyATS abstraction info for SD-WAN edge devices.
|
|
188
|
+
|
|
189
|
+
All SD-WAN edge devices are IOS-XE based with 'sdwan' platform.
|
|
178
190
|
|
|
179
191
|
Args:
|
|
180
|
-
device_data: Router data dictionary (unused,
|
|
192
|
+
device_data: Router data dictionary (unused, values are hardcoded).
|
|
181
193
|
|
|
182
194
|
Returns:
|
|
183
|
-
|
|
195
|
+
Dictionary with 'os' and 'platform' keys.
|
|
184
196
|
"""
|
|
185
|
-
return
|
|
197
|
+
return {
|
|
198
|
+
"os": "iosxe",
|
|
199
|
+
"platform": "sdwan",
|
|
200
|
+
}
|
|
186
201
|
|
|
187
202
|
def build_device_dict(self, device_data: dict[str, Any]) -> dict[str, Any]:
|
|
188
203
|
"""Build device dictionary with SD-WAN specific defaults.
|
|
189
204
|
|
|
190
|
-
Extends the base implementation to add type='router'
|
|
191
|
-
|
|
205
|
+
Extends the base implementation to add type='router'.
|
|
206
|
+
Platform is set to 'sdwan' via extract_os_platform_type().
|
|
192
207
|
|
|
193
208
|
Args:
|
|
194
209
|
device_data: Router data dictionary from the data model.
|
|
195
210
|
|
|
196
211
|
Returns:
|
|
197
|
-
Device dictionary with hostname, host, os, device_id, and type.
|
|
212
|
+
Device dictionary with hostname, host, os, platform, device_id, and type.
|
|
198
213
|
"""
|
|
199
214
|
# Get base device dict from parent
|
|
200
215
|
device_dict = super().build_device_dict(device_data)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nac-test-pyats-common
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.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
|
|
@@ -23,8 +23,9 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
23
23
|
Classifier: Topic :: Software Development :: Testing
|
|
24
24
|
Classifier: Topic :: System :: Networking
|
|
25
25
|
Requires-Python: >=3.10
|
|
26
|
+
Requires-Dist: filelock>=3.20.1
|
|
26
27
|
Requires-Dist: httpx>=0.28
|
|
27
|
-
Requires-Dist: nac-test==1.1.
|
|
28
|
+
Requires-Dist: nac-test==1.1.0b3
|
|
28
29
|
Provides-Extra: dev
|
|
29
30
|
Requires-Dist: bandit[toml]>=1.8.6; extra == 'dev'
|
|
30
31
|
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
nac_test_pyats_common/__init__.py,sha256=4fOaRhzkJJDyW00-wPzEzgWdmLXSLfxkiV-Z39RWmq8,1770
|
|
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=pkM7BRWJ1doajqZr73T4Gd3vPWydttk_QtOIEcf8tS4,11558
|
|
5
|
+
nac_test_pyats_common/aci/test_base.py,sha256=Kz_TpY3yeveAfSUMVGhSiQ3s7AHOzIJEz97rpy6pVWE,7575
|
|
6
|
+
nac_test_pyats_common/catc/__init__.py,sha256=ZGOQBvjFvq7h9LtfOyxFEmlir7htpy8sfWoJuDwGjsA,1986
|
|
7
|
+
nac_test_pyats_common/catc/api_test_base.py,sha256=F1zNKaYfHV_vRxJ30TcebDj26itNZ05lLHtUa4wslA0,8905
|
|
8
|
+
nac_test_pyats_common/catc/auth.py,sha256=u-kasgmoZCvZBKwrZUsoo9e1azxJUJg9odZkpXkUq7g,11623
|
|
9
|
+
nac_test_pyats_common/catc/device_resolver.py,sha256=I17QuPQpJj4p7zXzAjHJrHZcaICcHdAX9DV_0qgQni8,5754
|
|
10
|
+
nac_test_pyats_common/catc/ssh_test_base.py,sha256=wUldp2T9cmSEALBtbOgUQvQ2txuid3ErJEO27kM-kiI,4482
|
|
11
|
+
nac_test_pyats_common/common/__init__.py,sha256=Y0qrZEKx2g8Zm1CTHJpeLocwMasspP6NQuhyrRiA1wA,1084
|
|
12
|
+
nac_test_pyats_common/common/base_device_resolver.py,sha256=ul-zao-qcLZc1p_xvDCUAnvR5zqZM8mZda4iBP5S7LU,17625
|
|
13
|
+
nac_test_pyats_common/iosxe/__init__.py,sha256=GSuLGyxcu8dFouspTjXuQ1Mi27vDluVR8ZCcJrPcIiY,2147
|
|
14
|
+
nac_test_pyats_common/iosxe/iosxe_resolver.py,sha256=_2cug-eZfO5iKE3Po2kh9hJB7StRjs-Cm-BdXqKb5pg,2388
|
|
15
|
+
nac_test_pyats_common/iosxe/registry.py,sha256=djRFzxuEu8IdyTmi1puhIHGZGSMjys0l1v4-uzYCwAU,5723
|
|
16
|
+
nac_test_pyats_common/iosxe/test_base.py,sha256=NjXbf0ZY-CBWhd3jpIAhylL5kyRrHM6FlhGlFtjLSjM,4569
|
|
17
|
+
nac_test_pyats_common/sdwan/__init__.py,sha256=mrziVp5kMgykKnFPvWykuVLuky6xwEv6oEcfrbxFXxY,1777
|
|
18
|
+
nac_test_pyats_common/sdwan/api_test_base.py,sha256=dtPKd094gdQTNHaYeoPQxNle6uCULNII2sroAweZ5Jw,8834
|
|
19
|
+
nac_test_pyats_common/sdwan/auth.py,sha256=4qIi2ypMPK2Pkw6rfhSkxpoJGDRRvt4fJ5rO01p-4II,11790
|
|
20
|
+
nac_test_pyats_common/sdwan/device_resolver.py,sha256=5cTfcH6OUH98AiJCDo9uQL3GUcudGkE2V_nlysl6eHk,7811
|
|
21
|
+
nac_test_pyats_common/sdwan/ssh_test_base.py,sha256=rZF7txhu0FGtPtTzGMZFqB9hwClmtggroZwRuX3BGU4,4210
|
|
22
|
+
nac_test_pyats_common-0.2.1.dist-info/METADATA,sha256=cOKNshimaxKY2EHl51EWxhnhsOG8wteZGTRPqf6G6OY,13104
|
|
23
|
+
nac_test_pyats_common-0.2.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
24
|
+
nac_test_pyats_common-0.2.1.dist-info/licenses/LICENSE,sha256=zt2sx-c0iEk6-OO0iqRQ4l6fIGazRKW_qLMqfDpLm6M,16295
|
|
25
|
+
nac_test_pyats_common-0.2.1.dist-info/RECORD,,
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
nac_test_pyats_common/__init__.py,sha256=4fOaRhzkJJDyW00-wPzEzgWdmLXSLfxkiV-Z39RWmq8,1770
|
|
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=ZGOQBvjFvq7h9LtfOyxFEmlir7htpy8sfWoJuDwGjsA,1986
|
|
7
|
-
nac_test_pyats_common/catc/api_test_base.py,sha256=kGp6rZ4S3zP3MW5BD02K5uVxmtE-vRlG2A99kaLgyDo,7507
|
|
8
|
-
nac_test_pyats_common/catc/auth.py,sha256=1oDZr_PEWOz1IZOUm_kyKzIFPQubMo_wemj-Q3D7ALU,9522
|
|
9
|
-
nac_test_pyats_common/catc/device_resolver.py,sha256=YgJJn1pXONXCAMnfXA-_Iuo6tkLtD9EekHbPbae6mRg,5363
|
|
10
|
-
nac_test_pyats_common/catc/ssh_test_base.py,sha256=wUldp2T9cmSEALBtbOgUQvQ2txuid3ErJEO27kM-kiI,4482
|
|
11
|
-
nac_test_pyats_common/common/__init__.py,sha256=Y0qrZEKx2g8Zm1CTHJpeLocwMasspP6NQuhyrRiA1wA,1084
|
|
12
|
-
nac_test_pyats_common/common/base_device_resolver.py,sha256=xP4QF-kNp_8rFo9N6wzfJSIpNOgnPkeZmWAbH0k5tGo,15091
|
|
13
|
-
nac_test_pyats_common/iosxe/__init__.py,sha256=GSuLGyxcu8dFouspTjXuQ1Mi27vDluVR8ZCcJrPcIiY,2147
|
|
14
|
-
nac_test_pyats_common/iosxe/iosxe_resolver.py,sha256=XzzwRCa1cuQ6HmeUB1Z2vITOwYdhuDlugDD1eVXAoIE,2355
|
|
15
|
-
nac_test_pyats_common/iosxe/registry.py,sha256=djRFzxuEu8IdyTmi1puhIHGZGSMjys0l1v4-uzYCwAU,5723
|
|
16
|
-
nac_test_pyats_common/iosxe/test_base.py,sha256=NjXbf0ZY-CBWhd3jpIAhylL5kyRrHM6FlhGlFtjLSjM,4569
|
|
17
|
-
nac_test_pyats_common/sdwan/__init__.py,sha256=mrziVp5kMgykKnFPvWykuVLuky6xwEv6oEcfrbxFXxY,1777
|
|
18
|
-
nac_test_pyats_common/sdwan/api_test_base.py,sha256=NuqrxODrRw7ZvEIuoc1Bup60thKqJOfiGz96T4QJ8Ng,7632
|
|
19
|
-
nac_test_pyats_common/sdwan/auth.py,sha256=CMgf_AYCalVQNjdUfDlE-0-z5tnhU_Wnscgt5ZW61RY,10322
|
|
20
|
-
nac_test_pyats_common/sdwan/device_resolver.py,sha256=1GdM5QKftj4F5bGmsbH90--VqoFZaDPMerHF1dAceMQ,7169
|
|
21
|
-
nac_test_pyats_common/sdwan/ssh_test_base.py,sha256=rZF7txhu0FGtPtTzGMZFqB9hwClmtggroZwRuX3BGU4,4210
|
|
22
|
-
nac_test_pyats_common-0.2.0.dist-info/METADATA,sha256=9Qbd0AYAGd33wI1iwbynSClOmApEC-Iny0geUrBoIzA,13072
|
|
23
|
-
nac_test_pyats_common-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
24
|
-
nac_test_pyats_common-0.2.0.dist-info/licenses/LICENSE,sha256=zt2sx-c0iEk6-OO0iqRQ4l6fIGazRKW_qLMqfDpLm6M,16295
|
|
25
|
-
nac_test_pyats_common-0.2.0.dist-info/RECORD,,
|
|
File without changes
|
{nac_test_pyats_common-0.2.0.dist-info → nac_test_pyats_common-0.2.1.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|