scrapli 2.0.0a1__py3-none-manylinux2014_aarch64.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/lib/libscrapli.so.0.0.1-alpha.10 +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.0a1.dist-info/METADATA +49 -0
- scrapli-2.0.0a1.dist-info/RECORD +35 -0
- scrapli-2.0.0a1.dist-info/WHEEL +5 -0
- scrapli-2.0.0a1.dist-info/licenses/LICENSE +21 -0
- scrapli-2.0.0a1.dist-info/top_level.txt +1 -0
@@ -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)
|