scrapli 2.0.0a2__py3-none-manylinux2010_x86_64.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.
@@ -0,0 +1,64 @@
1
+ ---
2
+ prompt_pattern: '^.*[>#$]\s?+$'
3
+ default_mode: 'privileged_exec'
4
+ modes:
5
+ - name: 'exec'
6
+ prompt_pattern: '^[\w.\-]{1,63}(\(maint\-mode\))?>\s?$'
7
+ accessible_modes:
8
+ - name: 'privileged_exec'
9
+ instructions:
10
+ - send_prompted_input:
11
+ input: 'enable'
12
+ prompt_exact: 'Password:'
13
+ response: '__lookup::enable'
14
+ - name: 'privileged_exec'
15
+ prompt_pattern: '^[\w.\-]{1,63}(\(maint\-mode\))?#\s?$'
16
+ accessible_modes:
17
+ - name: 'exec'
18
+ instructions:
19
+ - send_input:
20
+ input: 'disable'
21
+ - name: 'configuration'
22
+ instructions:
23
+ - send_input:
24
+ input: 'configure terminal'
25
+ - name: 'tclsh'
26
+ instructions:
27
+ - send_input:
28
+ input: 'tclsh'
29
+ - name: 'configuration'
30
+ prompt_pattern: '^[\w.\-]{1,63}(\(maint\-mode\))?\(conf[\w.\-@/:\+]{0,32}\)#\s?$'
31
+ prompt_excludes:
32
+ - 'config-tcl'
33
+ - 'config-s)'
34
+ - 'config-s-'
35
+ accessible_modes:
36
+ - name: 'privileged_exec'
37
+ instructions:
38
+ - send_input:
39
+ input: 'end'
40
+ - name: 'tclsh'
41
+ prompt_pattern: '(^[\w.\-]{1,63}\-tcl#\s?$)|(^[\w.\-]{1,63}\(config\-tcl\)#\s?$)|(^>\s?$)|(^[\w.\-]{1,63}\(maint\-mode\-tcl\)#\s?$)|(^[\w.\-]{1,63}\(maint\-mode\)\(config\-tcl\)#\s?$)'
42
+ accessible_modes:
43
+ - name: 'privileged_exec'
44
+ instructions:
45
+ - send_input:
46
+ input: 'tclquit'
47
+ failure_indicators:
48
+ - '% Ambiguous command'
49
+ - '% Incomplete command'
50
+ - '% Invalid input detected'
51
+ - '% Invalid command at'
52
+ - '% Invalid parameter'
53
+ on_open_instructions:
54
+ - enter_mode:
55
+ requested_mode: 'privileged_exec'
56
+ - send_input:
57
+ input: 'term width 511'
58
+ - send_input:
59
+ input: 'term len 0'
60
+ on_close_instructions:
61
+ - enter_mode:
62
+ requested_mode: 'privileged_exec'
63
+ - write:
64
+ input: 'exit'
@@ -0,0 +1,85 @@
1
+ ---
2
+ prompt_pattern: '^.*[>#$%]\s?+$'
3
+ default_mode: 'exec'
4
+ modes:
5
+ - name: 'exec'
6
+ prompt_pattern: '^({\w+(:(\w+){0,1}\d){0,1}}\n){0,1}[\w\-@()/:\.]{1,63}>\s?$'
7
+ accessible_modes:
8
+ - name: 'configuration'
9
+ instructions:
10
+ - send_input:
11
+ input: 'configure'
12
+ - name: 'configuration_exclusive'
13
+ instructions:
14
+ - send_input:
15
+ input: 'configure exclusive'
16
+ - name: 'configuration_private'
17
+ instructions:
18
+ - send_input:
19
+ input: 'configure private'
20
+ - name: 'shell'
21
+ instructions:
22
+ - send_input:
23
+ input: 'start shell'
24
+ - name: 'root_shell'
25
+ instructions:
26
+ - send_prompted_input:
27
+ input: 'start shell user root'
28
+ prompt_pattern: '^[pP]assword:\s?$'
29
+ response: '__lookup::root'
30
+ - name: 'configuration'
31
+ prompt_pattern: '^({\w+(:(\w+){0,1}\d){0,1}}\[edit\]\n){0,1}[\w\-@()/:\.]{1,63}#\s?$'
32
+ accessible_modes:
33
+ - name: 'exec'
34
+ instructions:
35
+ - send_input:
36
+ input: 'exit configuration-mode'
37
+ - name: 'configuration_exclusive'
38
+ prompt_pattern: '^({\w+(:(\w+){0,1}\d){0,1}}\[edit\]\n){0,1}[\w\-@()/:\.]{1,63}#\s?$'
39
+ accessible_modes:
40
+ - name: 'exec'
41
+ instructions:
42
+ - send_input:
43
+ input: 'exit configuration-mode'
44
+ - name: 'configuration_private'
45
+ prompt_pattern: '^({\w+(:(\w+){0,1}\d){0,1}}\[edit\]\n){0,1}[\w\-@()/:\.]{1,63}#\s?$'
46
+ accessible_modes:
47
+ - name: 'exec'
48
+ instructions:
49
+ - send_input:
50
+ input: 'exit configuration-mode'
51
+ - name: 'shell'
52
+ prompt_pattern: '^.*[%\$]\s?$'
53
+ prompt_excludes:
54
+ - 'root'
55
+ accessible_modes:
56
+ - name: 'exec'
57
+ instructions:
58
+ - send_input:
59
+ input: 'exit'
60
+ - name: 'root_shell'
61
+ prompt_pattern: '^.*root@(?:\S*:?\S*\s?)?[%\#]\s?$'
62
+ accessible_modes:
63
+ - name: 'exec'
64
+ instructions:
65
+ - send_input:
66
+ input: 'exit'
67
+ failure_indicators:
68
+ - 'is ambiguous'
69
+ - 'No valid completions'
70
+ - 'unknown command'
71
+ - 'syntax error'
72
+ on_open_instructions:
73
+ - enter_mode:
74
+ requested_mode: 'exec'
75
+ - send_input:
76
+ input: 'set cli screen-width 511'
77
+ - send_input:
78
+ input: 'set cli screen-length 0'
79
+ - send_input:
80
+ input: 'set cli complete-on-space off'
81
+ on_close_instructions:
82
+ - enter_mode:
83
+ requested_mode: 'exec'
84
+ - write:
85
+ input: 'exit'
@@ -0,0 +1,35 @@
1
+ ---
2
+ # https://regex101.com/r/U5mgK9/1
3
+ prompt_pattern: '^--.*--\s*\n[abcd]:\S+#\s*$'
4
+ default_mode: 'exec'
5
+ modes:
6
+ - name: 'exec'
7
+ # https://regex101.com/r/PGLSJJ/1
8
+ prompt_pattern: '^--{(\s\[[\w\s]+\]){0,5}[\+\*\s]{1,}running\s}--\[.+?\]--\s*\n[abcd]:\S+#\s*$'
9
+ accessible_modes:
10
+ - name: 'configuration'
11
+ instructions:
12
+ - send_input:
13
+ input: 'enter candidate private'
14
+ - name: 'configuration'
15
+ # https://regex101.com/r/JsaUZy/1
16
+ prompt_pattern: '^--{(\s\[[\w\s]+\]){0,5}[\+\*\!\s]{1,}candidate[\-\w\s]+}--\[.+?\]--\s*\n[abcd]:\S+#\s*$'
17
+ accessible_modes:
18
+ - name: 'exec'
19
+ instructions:
20
+ - send_input:
21
+ input: 'discard now'
22
+ failure_indicators:
23
+ - 'Error:'
24
+ on_open_instructions:
25
+ - enter_mode:
26
+ requested_mode: 'exec'
27
+ - send_input:
28
+ input: 'environment cli-engine type basic'
29
+ - send_input:
30
+ input: 'environment complete-on-space false'
31
+ on_close_instructions:
32
+ - enter_mode:
33
+ requested_mode: 'exec'
34
+ - write:
35
+ input: 'quit'
scrapli/exceptions.py ADDED
@@ -0,0 +1,49 @@
1
+ """scrapli.exceptions"""
2
+
3
+
4
+ class ScrapliException(Exception):
5
+ """Base Exception for all scrapli exceptions"""
6
+
7
+
8
+ class LibScrapliException(ScrapliException):
9
+ """Exception raised when encountering errors loading libscrapli shared library"""
10
+
11
+
12
+ class OptionsException(ScrapliException):
13
+ """Exception raised when encountering errors applying options"""
14
+
15
+
16
+ class AllocationException(ScrapliException):
17
+ """Exception raised when encountering errors allocating a cli/netconf object"""
18
+
19
+
20
+ class OpenException(ScrapliException):
21
+ """Exception raised when encountering errors opening a cli/netconf object"""
22
+
23
+
24
+ class CloseException(ScrapliException):
25
+ """Exception raised when encountering errors closing a cli/netconf object"""
26
+
27
+
28
+ class GetResultException(ScrapliException):
29
+ """Exception raised when encountering errors polling/fetching an operation result"""
30
+
31
+
32
+ class SubmitOperationException(ScrapliException):
33
+ """Exception raised when encountering errors submitting an operation result"""
34
+
35
+
36
+ class NotOpenedException(ScrapliException):
37
+ """Exception raised when attempting to call methods of cli/netconf object and ptr is None"""
38
+
39
+
40
+ class OperationException(ScrapliException):
41
+ """Exception raised when an error is returned from an operation"""
42
+
43
+
44
+ class ParsingException(ScrapliException):
45
+ """Exception raised when parsing (usually cli) output fails"""
46
+
47
+
48
+ class NoMessagesException(ScrapliException):
49
+ """Exception raised when attempting to request notifications or subscriptions and none exist"""
scrapli/ffi.py ADDED
@@ -0,0 +1,76 @@
1
+ """scrapli.ffi"""
2
+
3
+ import importlib.resources
4
+ import os
5
+ import sys
6
+ from logging import getLogger
7
+ from pathlib import Path
8
+
9
+ from scrapli.exceptions import LibScrapliException
10
+
11
+ logger = getLogger(__name__)
12
+
13
+ LIBSCRAPLI_VERSION = "0.0.1-alpha.10"
14
+ LIBSCRAPLI_PATH_OVERRIDE_ENV = "LIBSCRAPLI_PATH"
15
+ LIBSCRAPLI_CACHE_PATH_OVERRIDE_ENV = "LIBSCRAPLI_CACHE_PATH"
16
+ XDG_CACHE_HOME_ENV = "XDG_CACHE_HOME"
17
+
18
+
19
+ def get_libscrapli_shared_object_filename(version: str = LIBSCRAPLI_VERSION) -> str:
20
+ """
21
+ Returns the name of the libscrapli shared object for the given version/platform.
22
+
23
+ Args:
24
+ version: the libscrapli version
25
+
26
+ Returns:
27
+ str: filename of the shared object
28
+
29
+ Raises:
30
+ LibScrapliException: if unsupported platform
31
+
32
+ """
33
+ if sys.platform == "linux":
34
+ lib_filename = f"libscrapli.so.{version}"
35
+ elif sys.platform == "darwin":
36
+ lib_filename = f"libscrapli.{version}.dylib"
37
+ else:
38
+ raise LibScrapliException("unsupported platform")
39
+
40
+ return lib_filename
41
+
42
+
43
+ def get_libscrapli_path() -> str:
44
+ """
45
+ Returns the file path to the libscrapli shared library.
46
+
47
+ Attempts to load from override paths or from installed path in scrapli itself -- this would be
48
+ either the shared object(s) from source (i.e. cloning the repo) or from the installation either
49
+ via a wheel or sdist.
50
+
51
+ Args:
52
+ N/A
53
+
54
+ Returns:
55
+ str: libscrapli shared library path
56
+
57
+ Raises:
58
+ LibScrapliException: if libscrapli is not found at override path or default installation
59
+ path
60
+
61
+ """
62
+ override_path = os.environ.get(LIBSCRAPLI_PATH_OVERRIDE_ENV)
63
+ if override_path is not None:
64
+ logger.debug("using libscrapli path override '%s'", override_path)
65
+
66
+ return override_path
67
+
68
+ source_lib_dir = importlib.resources.files("scrapli.lib")
69
+ source_lib_filename = f"{source_lib_dir}/{get_libscrapli_shared_object_filename()}"
70
+
71
+ logger.debug("loading libscrapli from scrapli installation '%s'", source_lib_filename)
72
+
73
+ if Path(source_lib_filename).exists():
74
+ return source_lib_filename
75
+
76
+ raise LibScrapliException("libscrapli not available")
scrapli/ffi_mapping.py ADDED
@@ -0,0 +1,202 @@
1
+ """scrapli.ffi_mapping"""
2
+
3
+ from collections.abc import Callable
4
+ from ctypes import (
5
+ CDLL,
6
+ c_bool,
7
+ c_char_p,
8
+ c_int,
9
+ c_uint8,
10
+ c_uint32,
11
+ )
12
+
13
+ from scrapli.ffi import get_libscrapli_path
14
+ from scrapli.ffi_mapping_cli import LibScrapliCliMapping
15
+ from scrapli.ffi_mapping_netconf import LibScrapliNetconfMapping
16
+ from scrapli.ffi_mapping_options import LibScrapliOptionsMapping
17
+ from scrapli.ffi_types import (
18
+ DriverPointer,
19
+ IntPointer,
20
+ StringPointer,
21
+ )
22
+
23
+
24
+ class LibScrapliSharedMapping:
25
+ """
26
+ Mapping to libscrapli shared (between cli/netconf) object functions mapping.
27
+
28
+ Should not be used/called directly.
29
+
30
+ Args:
31
+ N/A
32
+
33
+ Returns:
34
+ None
35
+
36
+ Raises:
37
+ N/A
38
+
39
+ """
40
+
41
+ def __init__(self, lib: CDLL) -> None:
42
+ self._get_poll_fd: Callable[
43
+ [
44
+ DriverPointer,
45
+ ],
46
+ c_uint32,
47
+ ] = lib.ls_shared_get_poll_fd
48
+ lib.ls_shared_get_poll_fd.argtypes = [
49
+ DriverPointer,
50
+ ]
51
+ lib.ls_cli_alloc.restype = c_uint32
52
+
53
+ self._free: Callable[
54
+ [
55
+ DriverPointer,
56
+ ],
57
+ int,
58
+ ] = lib.ls_shared_free
59
+ lib.ls_shared_free.argtypes = [
60
+ DriverPointer,
61
+ ]
62
+ lib.ls_shared_free.restype = None
63
+
64
+ self._read: Callable[
65
+ [
66
+ DriverPointer,
67
+ StringPointer,
68
+ IntPointer,
69
+ ],
70
+ int,
71
+ ] = lib.ls_shared_read_session
72
+ lib.ls_shared_read_session.argtypes = [
73
+ DriverPointer,
74
+ StringPointer,
75
+ IntPointer,
76
+ ]
77
+ lib.ls_shared_read_session.restype = c_int
78
+
79
+ self._write: Callable[
80
+ [
81
+ DriverPointer,
82
+ c_char_p,
83
+ c_bool,
84
+ ],
85
+ int,
86
+ ] = lib.ls_shared_write_session
87
+ lib.ls_shared_write_session.argtypes = [
88
+ DriverPointer,
89
+ c_char_p,
90
+ c_bool,
91
+ ]
92
+ lib.ls_shared_write_session.restype = c_uint8
93
+
94
+ def get_poll_fd(self, ptr: DriverPointer) -> c_uint32:
95
+ """
96
+ Get the operation poll fd from the driver at ptr.
97
+
98
+ Should (generally) not be called directly/by users.
99
+
100
+ Args:
101
+ ptr: the ptr to the libscrapli cli/netconf object.
102
+
103
+ Returns:
104
+ c_uint32: the poll fd for the driver.
105
+
106
+ Raises:
107
+ N/A
108
+
109
+ """
110
+ return self._get_poll_fd(ptr)
111
+
112
+ def free(self, ptr: DriverPointer) -> int:
113
+ """
114
+ Free the driver at ptr.
115
+
116
+ Should (generally) not be called directly/by users.
117
+
118
+ Args:
119
+ ptr: the ptr to the libscrapli cli/netconf object.
120
+
121
+ Returns:
122
+ c_uint8: return code, non-zero value indicates an error.
123
+
124
+ Raises:
125
+ N/A
126
+
127
+ """
128
+ return self._free(ptr)
129
+
130
+ def read(self, ptr: DriverPointer, buf: StringPointer, read_size: IntPointer) -> int:
131
+ """
132
+ Read from the session of driver at ptr.
133
+
134
+ Should (generally) not be called directly/by users.
135
+
136
+ Args:
137
+ ptr: the ptr to the libscrapli cli/netconf object.
138
+ buf: buffer to fill during the read operation.
139
+ read_size: c_int pointer that is filled with number of bytes written into buf.
140
+
141
+ Returns:
142
+ int: return code, non-zero value indicates an error. technically a c_uint8 converted by
143
+ ctypes.
144
+
145
+ Raises:
146
+ N/A
147
+
148
+ """
149
+ return self._read(ptr, buf, read_size)
150
+
151
+ def write(self, ptr: DriverPointer, buf: c_char_p, redacted: c_bool) -> int:
152
+ """
153
+ Write to the session of driver at ptr.
154
+
155
+ Should (generally) not be called directly/by users.
156
+
157
+ Args:
158
+ ptr: the ptr to the libscrapli cli/netconf object.
159
+ buf: buffer contents to write during the write operation..
160
+ redacted: bool indicated if the write contents should be redacted from logs.
161
+
162
+ Returns:
163
+ int: return code, non-zero value indicates an error. technically a c_uint8 converted by
164
+ ctypes.
165
+
166
+ Raises:
167
+ N/A
168
+
169
+ """
170
+ return self._write(ptr, buf, redacted)
171
+
172
+
173
+ class LibScrapliMapping:
174
+ """
175
+ Single mapping to libscrapli shared library exported functions.
176
+
177
+ Args:
178
+ N/A
179
+
180
+ Returns:
181
+ None
182
+
183
+ Raises:
184
+ N/A
185
+
186
+ """
187
+
188
+ _instance = None
189
+
190
+ def __new__(cls) -> "LibScrapliMapping":
191
+ """Returns the singleton instance of the ffi mapping"""
192
+ if not cls._instance:
193
+ cls._instance = super().__new__(cls)
194
+
195
+ return cls._instance
196
+
197
+ def __init__(self) -> None:
198
+ self.lib = CDLL(get_libscrapli_path())
199
+ self.shared_mapping = LibScrapliSharedMapping(self.lib)
200
+ self.cli_mapping = LibScrapliCliMapping(self.lib)
201
+ self.netconf_mapping = LibScrapliNetconfMapping(self.lib)
202
+ self.options_mapping = LibScrapliOptionsMapping(self.lib)