scrapli 2.0.0a0__py3-none-macosx_11_0_arm64.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.
- scrapli/__init__.py +30 -0
- scrapli/auth.py +216 -0
- scrapli/cli.py +1414 -0
- scrapli/cli_decorators.py +148 -0
- scrapli/cli_parse.py +161 -0
- scrapli/cli_result.py +197 -0
- scrapli/definitions/__init__.py +1 -0
- scrapli/definitions/arista_eos.yaml +64 -0
- scrapli/definitions/cisco_iosxe.yaml +63 -0
- scrapli/definitions/cisco_iosxr.yaml +47 -0
- scrapli/definitions/cisco_nxos.yaml +64 -0
- scrapli/definitions/juniper_junos.yaml +85 -0
- scrapli/definitions/nokia_srlinux.yaml +35 -0
- scrapli/exceptions.py +49 -0
- scrapli/ffi.py +76 -0
- scrapli/ffi_mapping.py +202 -0
- scrapli/ffi_mapping_cli.py +646 -0
- scrapli/ffi_mapping_netconf.py +1612 -0
- scrapli/ffi_mapping_options.py +1031 -0
- scrapli/ffi_types.py +154 -0
- scrapli/helper.py +95 -0
- scrapli/lib/__init__.py +1 -0
- scrapli/lib/libscrapli.0.0.1-alpha.10.dylib +0 -0
- scrapli/netconf.py +2804 -0
- scrapli/netconf_decorators.py +148 -0
- scrapli/netconf_result.py +72 -0
- scrapli/py.typed +0 -0
- scrapli/session.py +122 -0
- scrapli/transport.py +401 -0
- scrapli-2.0.0a0.dist-info/METADATA +49 -0
- scrapli-2.0.0a0.dist-info/RECORD +34 -0
- scrapli-2.0.0a0.dist-info/WHEEL +5 -0
- scrapli-2.0.0a0.dist-info/licenses/LICENSE +21 -0
- scrapli-2.0.0a0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,148 @@
|
|
1
|
+
"""scrapli.netconf_decorators"""
|
2
|
+
|
3
|
+
from collections.abc import Awaitable, Callable
|
4
|
+
from ctypes import c_uint64
|
5
|
+
from functools import update_wrapper
|
6
|
+
from typing import TYPE_CHECKING, Concatenate, ParamSpec
|
7
|
+
|
8
|
+
from scrapli.exceptions import OptionsException
|
9
|
+
from scrapli.netconf_result import Result
|
10
|
+
|
11
|
+
if TYPE_CHECKING:
|
12
|
+
from scrapli.netconf import Netconf
|
13
|
+
|
14
|
+
P = ParamSpec("P")
|
15
|
+
|
16
|
+
|
17
|
+
def handle_operation_timeout(
|
18
|
+
wrapped: Callable[Concatenate["Netconf", P], Result],
|
19
|
+
) -> Callable[Concatenate["Netconf", P], Result]:
|
20
|
+
"""
|
21
|
+
Wraps a Netconf operation and sets the timeout value for the duration of the operation
|
22
|
+
|
23
|
+
Args:
|
24
|
+
wrapped: the operation function
|
25
|
+
|
26
|
+
Returns:
|
27
|
+
callable: the wrapper function
|
28
|
+
|
29
|
+
Raises:
|
30
|
+
N/A
|
31
|
+
|
32
|
+
"""
|
33
|
+
|
34
|
+
def wrapper(inst: "Netconf", /, *args: P.args, **kwargs: P.kwargs) -> Result:
|
35
|
+
"""
|
36
|
+
The operation timeout wrapper
|
37
|
+
|
38
|
+
Args:
|
39
|
+
inst: the Netconf instance
|
40
|
+
args: the arguments to pass to the wrapped function
|
41
|
+
kwargs: the keyword arguments to pass to the wrapped function
|
42
|
+
|
43
|
+
Returns:
|
44
|
+
Result: the result of the wrapped function
|
45
|
+
|
46
|
+
Raises:
|
47
|
+
OptionsException: if the operation timeout failed to set
|
48
|
+
|
49
|
+
"""
|
50
|
+
operation_timeout_ns = kwargs.get("operation_timeout_ns")
|
51
|
+
if operation_timeout_ns is None:
|
52
|
+
return wrapped(inst, *args, **kwargs)
|
53
|
+
|
54
|
+
if operation_timeout_ns == inst.session_options.operation_timeout_ns:
|
55
|
+
return wrapped(inst, *args, **kwargs)
|
56
|
+
|
57
|
+
if not isinstance(operation_timeout_ns, int):
|
58
|
+
# ignore an invalid type for the timeout
|
59
|
+
return wrapped(inst, *args, **kwargs)
|
60
|
+
|
61
|
+
status = inst.ffi_mapping.options_mapping.session.set_operation_timeout_ns(
|
62
|
+
inst._ptr_or_exception(),
|
63
|
+
c_uint64(operation_timeout_ns),
|
64
|
+
)
|
65
|
+
if status != 0:
|
66
|
+
raise OptionsException("failed to set session operation timeout")
|
67
|
+
|
68
|
+
res = wrapped(inst, *args, **kwargs)
|
69
|
+
|
70
|
+
status = inst.ffi_mapping.options_mapping.session.set_operation_timeout_ns(
|
71
|
+
inst._ptr_or_exception(),
|
72
|
+
c_uint64(operation_timeout_ns),
|
73
|
+
)
|
74
|
+
if status != 0:
|
75
|
+
raise OptionsException("failed to set session operation timeout")
|
76
|
+
|
77
|
+
return res
|
78
|
+
|
79
|
+
update_wrapper(wrapper=wrapper, wrapped=wrapped)
|
80
|
+
|
81
|
+
return wrapper
|
82
|
+
|
83
|
+
|
84
|
+
def handle_operation_timeout_async(
|
85
|
+
wrapped: Callable[Concatenate["Netconf", P], Awaitable[Result]],
|
86
|
+
) -> Callable[Concatenate["Netconf", P], Awaitable[Result]]:
|
87
|
+
"""
|
88
|
+
Wraps a Netconf operation and sets the timeout value for the duration of the operation
|
89
|
+
|
90
|
+
Args:
|
91
|
+
wrapped: the operation function
|
92
|
+
|
93
|
+
Returns:
|
94
|
+
callable: the wrapper function
|
95
|
+
|
96
|
+
Raises:
|
97
|
+
N/A
|
98
|
+
|
99
|
+
"""
|
100
|
+
|
101
|
+
async def wrapper(inst: "Netconf", /, *args: P.args, **kwargs: P.kwargs) -> Result:
|
102
|
+
"""
|
103
|
+
The operation timeout wrapper
|
104
|
+
|
105
|
+
Args:
|
106
|
+
inst: the Netconf instance
|
107
|
+
args: the arguments to pass to the wrapped function
|
108
|
+
kwargs: the keyword arguments to pass to the wrapped function
|
109
|
+
|
110
|
+
Returns:
|
111
|
+
Result: the result of the wrapped function
|
112
|
+
|
113
|
+
Raises:
|
114
|
+
OptionsException: if the operation timeout failed to set
|
115
|
+
|
116
|
+
"""
|
117
|
+
operation_timeout_ns = kwargs.get("operation_timeout_ns")
|
118
|
+
if operation_timeout_ns is None:
|
119
|
+
return await wrapped(inst, *args, **kwargs)
|
120
|
+
|
121
|
+
if operation_timeout_ns == inst.session_options.operation_timeout_ns:
|
122
|
+
return await wrapped(inst, *args, **kwargs)
|
123
|
+
|
124
|
+
if not isinstance(operation_timeout_ns, int):
|
125
|
+
# ignore an invalid type for the timeout
|
126
|
+
return await wrapped(inst, *args, **kwargs)
|
127
|
+
|
128
|
+
status = inst.ffi_mapping.options_mapping.session.set_operation_timeout_ns(
|
129
|
+
inst._ptr_or_exception(),
|
130
|
+
c_uint64(operation_timeout_ns),
|
131
|
+
)
|
132
|
+
if status != 0:
|
133
|
+
raise OptionsException("failed to set session operation timeout")
|
134
|
+
|
135
|
+
res = await wrapped(inst, *args, **kwargs)
|
136
|
+
|
137
|
+
status = inst.ffi_mapping.options_mapping.session.set_operation_timeout_ns(
|
138
|
+
inst._ptr_or_exception(),
|
139
|
+
c_uint64(operation_timeout_ns),
|
140
|
+
)
|
141
|
+
if status != 0:
|
142
|
+
raise OptionsException("failed to set session operation timeout")
|
143
|
+
|
144
|
+
return res
|
145
|
+
|
146
|
+
update_wrapper(wrapper=wrapper, wrapped=wrapped)
|
147
|
+
|
148
|
+
return wrapper
|
@@ -0,0 +1,72 @@
|
|
1
|
+
"""scrapli.result"""
|
2
|
+
|
3
|
+
from dataclasses import dataclass
|
4
|
+
|
5
|
+
|
6
|
+
@dataclass
|
7
|
+
class Result:
|
8
|
+
"""
|
9
|
+
Result holds the result of an operation.
|
10
|
+
|
11
|
+
Args:
|
12
|
+
input_:
|
13
|
+
host:
|
14
|
+
port:
|
15
|
+
start_time:
|
16
|
+
end_time:
|
17
|
+
result_raw:
|
18
|
+
result:
|
19
|
+
rpc_warnings:
|
20
|
+
rpc_errors:
|
21
|
+
|
22
|
+
Returns:
|
23
|
+
None
|
24
|
+
|
25
|
+
Raises:
|
26
|
+
N/A
|
27
|
+
|
28
|
+
"""
|
29
|
+
|
30
|
+
input_: str
|
31
|
+
host: str
|
32
|
+
port: int
|
33
|
+
start_time: int
|
34
|
+
end_time: int
|
35
|
+
result_raw: bytes
|
36
|
+
result: str
|
37
|
+
rpc_warnings: str
|
38
|
+
rpc_errors: str
|
39
|
+
|
40
|
+
@property
|
41
|
+
def failed(self) -> bool:
|
42
|
+
"""
|
43
|
+
Returns True if any failed indicators were seen, otherwise False.
|
44
|
+
|
45
|
+
Args:
|
46
|
+
N/A
|
47
|
+
|
48
|
+
Returns:
|
49
|
+
bool: True for failed, otherwise False
|
50
|
+
|
51
|
+
Raises:
|
52
|
+
N/A
|
53
|
+
|
54
|
+
"""
|
55
|
+
return bool(self.rpc_errors)
|
56
|
+
|
57
|
+
@property
|
58
|
+
def elapsed_time_seconds(self) -> float:
|
59
|
+
"""
|
60
|
+
Returns the number of seconds the operation took.
|
61
|
+
|
62
|
+
Args:
|
63
|
+
N/A
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
float: duration in seconds
|
67
|
+
|
68
|
+
Raises:
|
69
|
+
N/A
|
70
|
+
|
71
|
+
"""
|
72
|
+
return (self.end_time - self.start_time) / 1_000_000_000
|
scrapli/py.typed
ADDED
File without changes
|
scrapli/session.py
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
"""scrapli.session"""
|
2
|
+
|
3
|
+
from ctypes import c_char_p, c_uint64
|
4
|
+
from dataclasses import dataclass, field
|
5
|
+
|
6
|
+
from scrapli.exceptions import OptionsException
|
7
|
+
from scrapli.ffi_mapping import LibScrapliMapping
|
8
|
+
from scrapli.ffi_types import DriverPointer, to_c_string
|
9
|
+
|
10
|
+
|
11
|
+
@dataclass
|
12
|
+
class Options:
|
13
|
+
"""
|
14
|
+
Options holds session related options to pass to the ffi layer.
|
15
|
+
|
16
|
+
Args:
|
17
|
+
read_size: read size
|
18
|
+
return_char: return char
|
19
|
+
operation_timeout_s: operation timeout in s, ignored if operation_timeout_ns set
|
20
|
+
operation_timeout_ns: operation timeout in ns
|
21
|
+
operation_max_search_depth: operation maximum search depth
|
22
|
+
recorder_path: path for session recorder output to write to
|
23
|
+
|
24
|
+
Returns:
|
25
|
+
None
|
26
|
+
|
27
|
+
Raises:
|
28
|
+
N/A
|
29
|
+
|
30
|
+
"""
|
31
|
+
|
32
|
+
read_size: int | None = None
|
33
|
+
return_char: str | None = None
|
34
|
+
operation_timeout_s: int | None = None
|
35
|
+
operation_timeout_ns: int | None = None
|
36
|
+
operation_max_search_depth: int | None = None
|
37
|
+
recorder_path: str | None = None
|
38
|
+
|
39
|
+
_return_char: c_char_p | None = field(init=False, default=None, repr=False)
|
40
|
+
_recorder_path: c_char_p | None = field(init=False, default=None, repr=False)
|
41
|
+
|
42
|
+
def __post_init__(self) -> None:
|
43
|
+
if self.operation_timeout_s is not None or self.operation_timeout_ns is not None:
|
44
|
+
if self.operation_timeout_ns is None and self.operation_timeout_s is not None:
|
45
|
+
self.operation_timeout_ns = int(self.operation_timeout_s / 1e-9)
|
46
|
+
|
47
|
+
def apply(self, ffi_mapping: LibScrapliMapping, ptr: DriverPointer) -> None: # noqa: C901
|
48
|
+
"""
|
49
|
+
Applies the options to the given driver pointer.
|
50
|
+
|
51
|
+
Should not be called directly/by users.
|
52
|
+
|
53
|
+
Args:
|
54
|
+
ffi_mapping: the handle to the ffi mapping singleton
|
55
|
+
ptr: the pointer to the underlying cli or netconf object
|
56
|
+
|
57
|
+
Returns:
|
58
|
+
None
|
59
|
+
|
60
|
+
Raises:
|
61
|
+
OptionsException: if any option apply returns a non-zero return code.
|
62
|
+
|
63
|
+
"""
|
64
|
+
if self.read_size is not None:
|
65
|
+
status = ffi_mapping.options_mapping.session.set_read_size(
|
66
|
+
ptr, c_uint64(self.read_size)
|
67
|
+
)
|
68
|
+
if status != 0:
|
69
|
+
raise OptionsException("failed to set session read size")
|
70
|
+
|
71
|
+
if self.return_char is not None:
|
72
|
+
self._return_char = to_c_string(self.return_char)
|
73
|
+
|
74
|
+
status = ffi_mapping.options_mapping.session.set_return_char(ptr, self._return_char)
|
75
|
+
if status != 0:
|
76
|
+
raise OptionsException("failed to set session return char")
|
77
|
+
|
78
|
+
if self.operation_timeout_ns is not None:
|
79
|
+
status = ffi_mapping.options_mapping.session.set_operation_timeout_ns(
|
80
|
+
ptr, c_uint64(self.operation_timeout_ns)
|
81
|
+
)
|
82
|
+
if status != 0:
|
83
|
+
raise OptionsException("failed to set session operation timeout")
|
84
|
+
|
85
|
+
if self.operation_max_search_depth is not None:
|
86
|
+
status = ffi_mapping.options_mapping.session.set_operation_max_search_depth(
|
87
|
+
ptr, c_uint64(self.operation_max_search_depth)
|
88
|
+
)
|
89
|
+
if status != 0:
|
90
|
+
raise OptionsException("failed to set session operation max search depth")
|
91
|
+
|
92
|
+
if self.recorder_path is not None:
|
93
|
+
self._recorder_path = to_c_string(self.recorder_path)
|
94
|
+
|
95
|
+
status = ffi_mapping.options_mapping.session.set_recorder_path(ptr, self._recorder_path)
|
96
|
+
if status != 0:
|
97
|
+
raise OptionsException("failed to set session recorder path")
|
98
|
+
|
99
|
+
def __repr__(self) -> str:
|
100
|
+
"""
|
101
|
+
Magic repr method for Options object
|
102
|
+
|
103
|
+
Args:
|
104
|
+
N/A
|
105
|
+
|
106
|
+
Returns:
|
107
|
+
str: repr for Options object
|
108
|
+
|
109
|
+
Raises:
|
110
|
+
N/A
|
111
|
+
|
112
|
+
"""
|
113
|
+
return (
|
114
|
+
# it will probably be "canonical" to import Options as SessionOptions, so we'll make
|
115
|
+
# the repr do that too
|
116
|
+
f"Session{self.__class__.__name__}("
|
117
|
+
f"read_size={self.read_size!r}, "
|
118
|
+
f"return_char={self.return_char!r}) "
|
119
|
+
f"operation_timeout_ns={self.operation_timeout_ns!r}) "
|
120
|
+
f"operation_max_search_depth={self.operation_max_search_depth!r}) "
|
121
|
+
f"recorder_path={self.recorder_path!r}) "
|
122
|
+
)
|