scrapli 2.0.0a4__py3-none-macosx_11_0_arm64.whl → 2.0.0a5__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 +5 -6
- scrapli/auth.py +14 -7
- scrapli/cli.py +300 -0
- scrapli/cli_parse.py +1 -1
- scrapli/cli_result.py +42 -0
- scrapli/definitions/aethra_atosnt.yaml +9 -0
- scrapli/definitions/alcatel_aos.yaml +9 -0
- scrapli/definitions/arista_eos.yaml +1 -0
- scrapli/definitions/aruba_aoscx.yaml +33 -0
- scrapli/definitions/cisco_aireos.yaml +31 -0
- scrapli/definitions/cisco_asa.yaml +48 -0
- scrapli/definitions/cisco_cbs.yaml +50 -0
- scrapli/definitions/cisco_ftd.yaml +42 -0
- scrapli/definitions/cisco_nxos.yaml +2 -0
- scrapli/definitions/cumulus_linux.yaml +28 -0
- scrapli/definitions/cumulus_vtysh.yaml +42 -0
- scrapli/definitions/datacom_dmos.yaml +30 -0
- scrapli/definitions/datacom_dmswitch.yaml +32 -0
- scrapli/definitions/default.yaml +9 -0
- scrapli/definitions/dell_emc.yaml +46 -0
- scrapli/definitions/dell_enterprisesonic.yaml +40 -0
- scrapli/definitions/dlink_os.yaml +46 -0
- scrapli/definitions/edgecore_ecs.yaml +35 -0
- scrapli/definitions/eltex_esr.yaml +43 -0
- scrapli/definitions/fortinet_fortios.yaml +20 -0
- scrapli/definitions/fortinet_wlc.yaml +33 -0
- scrapli/definitions/hp_comware.yaml +31 -0
- scrapli/definitions/huawei_smartax.yaml +61 -0
- scrapli/definitions/huawei_vrp.yaml +56 -0
- scrapli/definitions/juniper_junos.yaml +3 -0
- scrapli/definitions/nokia_srlinux.yaml +13 -2
- scrapli/definitions/nokia_sros.yaml +31 -0
- scrapli/definitions/nokia_sros_classic.yaml +33 -0
- scrapli/definitions/nokia_sros_classic_aram.yaml +25 -0
- scrapli/definitions/paloalto_panos.yaml +36 -0
- scrapli/definitions/raisecom_ros.yaml +45 -0
- scrapli/definitions/ruckus_fastiron.yaml +45 -0
- scrapli/definitions/ruckus_unleashed.yaml +64 -0
- scrapli/definitions/siemens_roxii.yaml +28 -0
- scrapli/definitions/versa_flexvnf.yaml +45 -0
- scrapli/definitions/vyos_vyos.yaml +35 -0
- scrapli/definitions/zyxel_dslam.yaml +18 -0
- scrapli/ffi.py +1 -1
- scrapli/ffi_mapping.py +89 -33
- scrapli/ffi_mapping_cli.py +104 -0
- scrapli/ffi_mapping_options.py +38 -6
- scrapli/ffi_types.py +1 -1
- scrapli/helper.py +56 -0
- scrapli/lib/{libscrapli.0.0.1-alpha.13.dylib → libscrapli.0.0.1-alpha.17.dylib} +0 -0
- {scrapli-2.0.0a4.dist-info → scrapli-2.0.0a5.dist-info}/METADATA +1 -1
- scrapli-2.0.0a5.dist-info/RECORD +67 -0
- scrapli-2.0.0a4.dist-info/RECORD +0 -34
- {scrapli-2.0.0a4.dist-info → scrapli-2.0.0a5.dist-info}/WHEEL +0 -0
- {scrapli-2.0.0a4.dist-info → scrapli-2.0.0a5.dist-info}/licenses/LICENSE +0 -0
- {scrapli-2.0.0a4.dist-info → scrapli-2.0.0a5.dist-info}/top_level.txt +0 -0
scrapli/__init__.py
CHANGED
@@ -2,19 +2,18 @@
|
|
2
2
|
|
3
3
|
from scrapli.auth import LookupKeyValue
|
4
4
|
from scrapli.auth import Options as AuthOptions
|
5
|
-
from scrapli.cli import Cli
|
5
|
+
from scrapli.cli import Cli, ReadCallback
|
6
6
|
from scrapli.netconf import Netconf
|
7
7
|
from scrapli.netconf import Options as NetconfOptions
|
8
8
|
from scrapli.session import Options as SessionOptions
|
9
9
|
from scrapli.transport import BinOptions as TransportBinOptions
|
10
|
-
from scrapli.transport import Options as TransportOptions
|
11
10
|
from scrapli.transport import Ssh2Options as TransportSsh2Options
|
12
11
|
from scrapli.transport import TelnetOptions as TransportTelnetOptions
|
13
12
|
from scrapli.transport import TestOptions as TransportTestOptions
|
14
13
|
|
15
|
-
__version__ = "2.0.0-alpha.
|
16
|
-
__calendar_version__ = "2025.
|
17
|
-
__definitions_version__ = "
|
14
|
+
__version__ = "2.0.0-alpha.5"
|
15
|
+
__calendar_version__ = "2025.7.12"
|
16
|
+
__definitions_version__ = "c38ec6d"
|
18
17
|
|
19
18
|
__all__ = (
|
20
19
|
"AuthOptions",
|
@@ -22,9 +21,9 @@ __all__ = (
|
|
22
21
|
"LookupKeyValue",
|
23
22
|
"Netconf",
|
24
23
|
"NetconfOptions",
|
24
|
+
"ReadCallback",
|
25
25
|
"SessionOptions",
|
26
26
|
"TransportBinOptions",
|
27
|
-
"TransportOptions",
|
28
27
|
"TransportSsh2Options",
|
29
28
|
"TransportTelnetOptions",
|
30
29
|
"TransportTestOptions",
|
scrapli/auth.py
CHANGED
@@ -63,8 +63,8 @@ class Options:
|
|
63
63
|
lookups: a list of key/values that can be "looked up" from a connection -- used in
|
64
64
|
conjunction with platform definition templating like `__lookup::enable` where "enable"
|
65
65
|
is the key to "lookup" in the list of lookup key/values.
|
66
|
-
|
67
|
-
|
66
|
+
force_in_session_auth: unconditionally force the in session auth process.
|
67
|
+
bypass_in_session_auth: skip in session auth even if transport (telnet/bin) expect it.
|
68
68
|
username_pattern: the regex pattern to use to look for a username prompt
|
69
69
|
password_pattern: the regex pattern to use to look for a password prompt
|
70
70
|
private_key_passphrase_pattern: the regex pattern to use to look for a passphrase prompt
|
@@ -82,7 +82,8 @@ class Options:
|
|
82
82
|
private_key_path: str | None = None
|
83
83
|
private_key_passphrase: str | None = None
|
84
84
|
lookups: list[LookupKeyValue] | None = None
|
85
|
-
|
85
|
+
force_in_session_auth: bool | None = None
|
86
|
+
bypass_in_session_auth: bool | None = None
|
86
87
|
username_pattern: str | None = None
|
87
88
|
password_pattern: str | None = None
|
88
89
|
private_key_passphrase_pattern: str | None = None
|
@@ -154,10 +155,15 @@ class Options:
|
|
154
155
|
if status != 0:
|
155
156
|
raise OptionsException("failed to set auth lookup key/value")
|
156
157
|
|
157
|
-
if self.
|
158
|
-
status = ffi_mapping.options_mapping.auth.
|
158
|
+
if self.force_in_session_auth is not None:
|
159
|
+
status = ffi_mapping.options_mapping.auth.set_force_in_session_auth(ptr)
|
159
160
|
if status != 0:
|
160
|
-
raise OptionsException("failed to set
|
161
|
+
raise OptionsException("failed to set force in session auth")
|
162
|
+
|
163
|
+
if self.bypass_in_session_auth is not None:
|
164
|
+
status = ffi_mapping.options_mapping.auth.set_bypass_in_session_auth(ptr)
|
165
|
+
if status != 0:
|
166
|
+
raise OptionsException("failed to set bypass in session auth")
|
161
167
|
|
162
168
|
if self.username_pattern is not None:
|
163
169
|
self._username_pattern = to_c_string(self.username_pattern)
|
@@ -209,7 +215,8 @@ class Options:
|
|
209
215
|
f"private_key_path={self.private_key_path!r} "
|
210
216
|
f"private_key_passphrase={self.private_key_passphrase!r} "
|
211
217
|
f"lookups={self.lookups!r}) "
|
212
|
-
f"
|
218
|
+
f"force_in_session_auth={self.force_in_session_auth!r}) "
|
219
|
+
f"bypass_in_session_auth={self.bypass_in_session_auth!r}) "
|
213
220
|
f"username_pattern={self.username_pattern!r}) "
|
214
221
|
f"password_pattern={self.password_pattern!r}) "
|
215
222
|
f"private_key_passphrase_pattern={self.private_key_passphrase_pattern!r}) "
|
scrapli/cli.py
CHANGED
@@ -1,17 +1,21 @@
|
|
1
1
|
"""scrapli.cli"""
|
2
2
|
|
3
3
|
import importlib.resources
|
4
|
+
from collections.abc import Awaitable, Callable
|
4
5
|
from ctypes import (
|
5
6
|
c_bool,
|
6
7
|
c_char_p,
|
7
8
|
c_int,
|
8
9
|
c_uint,
|
9
10
|
c_uint64,
|
11
|
+
pointer,
|
10
12
|
)
|
13
|
+
from dataclasses import dataclass
|
11
14
|
from enum import Enum
|
12
15
|
from logging import getLogger
|
13
16
|
from os import environ
|
14
17
|
from pathlib import Path
|
18
|
+
from time import time_ns
|
15
19
|
from types import TracebackType
|
16
20
|
from typing import Any
|
17
21
|
|
@@ -72,6 +76,50 @@ class InputHandling(str, Enum):
|
|
72
76
|
IGNORE = "ignore"
|
73
77
|
|
74
78
|
|
79
|
+
@dataclass
|
80
|
+
class ReadCallback:
|
81
|
+
"""
|
82
|
+
ReadCallback represents a callback and how it should be executed in a read_with_callbacks op.
|
83
|
+
|
84
|
+
Args:
|
85
|
+
name: friendly name for the callback
|
86
|
+
contains: string that when contained in the buf being processed indicates this callback
|
87
|
+
should be executed
|
88
|
+
contains_pattern: string representing a pcre2 pattern that, if found in the buf being
|
89
|
+
processed indicates this callback should be executed -- note: ignored if contains is set
|
90
|
+
not_contains: a string that if found in the buf being processed nullifies the containment
|
91
|
+
check
|
92
|
+
once: bool indicating if this is an "only once" callback or if it can be executed multiple
|
93
|
+
times
|
94
|
+
completes: bool indicated if, after execution, this callback should "complete" (end) the
|
95
|
+
read_with_callbacks operation
|
96
|
+
callback: the callback func to execute
|
97
|
+
|
98
|
+
Returns:
|
99
|
+
None
|
100
|
+
|
101
|
+
Raises:
|
102
|
+
N/A
|
103
|
+
|
104
|
+
"""
|
105
|
+
|
106
|
+
name: str
|
107
|
+
contains: str = ""
|
108
|
+
contains_pattern: str = ""
|
109
|
+
not_contains: str = ""
|
110
|
+
once: bool = False
|
111
|
+
completes: bool = False
|
112
|
+
callback: Callable[["Cli"], None] | None = None
|
113
|
+
callback_async: Callable[["Cli"], Awaitable[None]] | None = None
|
114
|
+
|
115
|
+
def __post_init__(self) -> None:
|
116
|
+
if not self.contains and not self.contains_pattern:
|
117
|
+
raise OperationException("one of 'contains' or 'contains_pattern' must be set")
|
118
|
+
|
119
|
+
if self.callback is None and self.callback_async is None:
|
120
|
+
raise OperationException("one of 'callback' or 'callback_async' must be set")
|
121
|
+
|
122
|
+
|
75
123
|
class Cli:
|
76
124
|
"""
|
77
125
|
Cli represents a cli connection object.
|
@@ -282,6 +330,8 @@ class Cli:
|
|
282
330
|
with open(definition_file_or_name, "rb") as f:
|
283
331
|
self.definition_string = f.read()
|
284
332
|
|
333
|
+
return
|
334
|
+
|
285
335
|
raise OptionsException(
|
286
336
|
f"definition platform name or filename '{definition_file_or_name}' not found"
|
287
337
|
)
|
@@ -512,6 +562,60 @@ class Cli:
|
|
512
562
|
|
513
563
|
return result
|
514
564
|
|
565
|
+
def write(self, input_: str) -> None:
|
566
|
+
"""
|
567
|
+
Write the given input.
|
568
|
+
|
569
|
+
Args:
|
570
|
+
input_: the input to write
|
571
|
+
|
572
|
+
Returns:
|
573
|
+
Result: a Result object representing the operation
|
574
|
+
|
575
|
+
Raises:
|
576
|
+
NotOpenedException: if the ptr to the cli object is None (via _ptr_or_exception)
|
577
|
+
SubmitOperationException: if the operation fails
|
578
|
+
|
579
|
+
"""
|
580
|
+
_input = to_c_string(s=input_)
|
581
|
+
|
582
|
+
status = self.ffi_mapping.session_mapping.write(
|
583
|
+
ptr=self._ptr_or_exception(),
|
584
|
+
input_=_input,
|
585
|
+
redacted=c_bool(False),
|
586
|
+
)
|
587
|
+
if status != 0:
|
588
|
+
raise SubmitOperationException("executing write and return operation failed")
|
589
|
+
|
590
|
+
_ = _input
|
591
|
+
|
592
|
+
def write_and_return(self, input_: str) -> None:
|
593
|
+
"""
|
594
|
+
Write the given input then send a return character.
|
595
|
+
|
596
|
+
Args:
|
597
|
+
input_: the input to write
|
598
|
+
|
599
|
+
Returns:
|
600
|
+
Result: a Result object representing the operation
|
601
|
+
|
602
|
+
Raises:
|
603
|
+
NotOpenedException: if the ptr to the cli object is None (via _ptr_or_exception)
|
604
|
+
SubmitOperationException: if the operation fails
|
605
|
+
|
606
|
+
"""
|
607
|
+
_input = to_c_string(s=input_)
|
608
|
+
|
609
|
+
status = self.ffi_mapping.session_mapping.write_and_return(
|
610
|
+
ptr=self._ptr_or_exception(),
|
611
|
+
input_=_input,
|
612
|
+
redacted=c_bool(False),
|
613
|
+
)
|
614
|
+
if status != 0:
|
615
|
+
raise SubmitOperationException("executing write and return operation failed")
|
616
|
+
|
617
|
+
_ = _input
|
618
|
+
|
515
619
|
def _get_result(
|
516
620
|
self,
|
517
621
|
operation_id: c_uint,
|
@@ -1315,6 +1419,202 @@ class Cli:
|
|
1315
1419
|
|
1316
1420
|
return await self._get_result_async(operation_id=operation_id)
|
1317
1421
|
|
1422
|
+
@handle_operation_timeout
|
1423
|
+
def read_with_callbacks(
|
1424
|
+
self,
|
1425
|
+
callbacks: list[ReadCallback],
|
1426
|
+
*,
|
1427
|
+
initial_input: str = "",
|
1428
|
+
operation_timeout_ns: int | None = None,
|
1429
|
+
) -> Result:
|
1430
|
+
"""
|
1431
|
+
Read from the device and react to the output with some callback.
|
1432
|
+
|
1433
|
+
Args:
|
1434
|
+
callbacks: a list of callbacks to process when reading from the session
|
1435
|
+
initial_input: an initial input to send
|
1436
|
+
operation_timeout_ns: operation timeout in ns for this operation
|
1437
|
+
|
1438
|
+
Returns:
|
1439
|
+
Result: a Result object representing the operation
|
1440
|
+
|
1441
|
+
Raises:
|
1442
|
+
NotOpenedException: if the ptr to the cli object is None (via _ptr_or_exception)
|
1443
|
+
SubmitOperationException: if the operation fails
|
1444
|
+
|
1445
|
+
"""
|
1446
|
+
# only used in the decorator
|
1447
|
+
_ = operation_timeout_ns
|
1448
|
+
|
1449
|
+
start_time = time_ns()
|
1450
|
+
|
1451
|
+
if initial_input:
|
1452
|
+
self.write_and_return(input_=initial_input)
|
1453
|
+
|
1454
|
+
pos = 0
|
1455
|
+
|
1456
|
+
result = ""
|
1457
|
+
result_raw = b""
|
1458
|
+
|
1459
|
+
executed_callbacks = set()
|
1460
|
+
|
1461
|
+
while True:
|
1462
|
+
operation_id = OperationIdPointer(c_uint(0))
|
1463
|
+
|
1464
|
+
status = self.ffi_mapping.cli_mapping.read_any(
|
1465
|
+
ptr=self._ptr_or_exception(),
|
1466
|
+
operation_id=operation_id,
|
1467
|
+
)
|
1468
|
+
if status != 0:
|
1469
|
+
raise SubmitOperationException("submitting read any operation failed")
|
1470
|
+
|
1471
|
+
intermediate_result = self._get_result(operation_id=operation_id.contents.value)
|
1472
|
+
|
1473
|
+
result += intermediate_result.result
|
1474
|
+
result_raw += intermediate_result.result_raw
|
1475
|
+
|
1476
|
+
for callback in callbacks:
|
1477
|
+
if callback.name in executed_callbacks and callback.once:
|
1478
|
+
continue
|
1479
|
+
|
1480
|
+
execute = pointer(c_bool(False))
|
1481
|
+
|
1482
|
+
status = self.ffi_mapping.cli_mapping.read_callback_should_execute(
|
1483
|
+
buf=to_c_string(result[pos:]),
|
1484
|
+
name=to_c_string(callback.name),
|
1485
|
+
contains=to_c_string(callback.contains),
|
1486
|
+
contains_pattern=to_c_string(callback.contains_pattern),
|
1487
|
+
not_contains=to_c_string(callback.not_contains),
|
1488
|
+
execute=execute,
|
1489
|
+
)
|
1490
|
+
if status != 0:
|
1491
|
+
raise OperationException("failed checking if callback should execute")
|
1492
|
+
|
1493
|
+
if execute.contents.value is False:
|
1494
|
+
continue
|
1495
|
+
|
1496
|
+
executed_callbacks.add(callback.name)
|
1497
|
+
|
1498
|
+
pos = len(result)
|
1499
|
+
|
1500
|
+
if callback.callback is None:
|
1501
|
+
raise OperationException("callback is None, cannot proceed")
|
1502
|
+
else:
|
1503
|
+
callback.callback(self)
|
1504
|
+
|
1505
|
+
if callback.completes is True:
|
1506
|
+
return Result(
|
1507
|
+
inputs=initial_input,
|
1508
|
+
host=self.host,
|
1509
|
+
port=self.port,
|
1510
|
+
start_time=start_time,
|
1511
|
+
splits=[time_ns()],
|
1512
|
+
results_raw=result_raw,
|
1513
|
+
results=result,
|
1514
|
+
results_failed_indicator="",
|
1515
|
+
textfsm_platform=self.ntc_templates_platform,
|
1516
|
+
genie_platform=self.genie_platform,
|
1517
|
+
)
|
1518
|
+
|
1519
|
+
@handle_operation_timeout_async
|
1520
|
+
async def read_with_callbacks_async(
|
1521
|
+
self,
|
1522
|
+
callbacks: list[ReadCallback],
|
1523
|
+
*,
|
1524
|
+
initial_input: str = "",
|
1525
|
+
operation_timeout_ns: int | None = None,
|
1526
|
+
) -> Result:
|
1527
|
+
"""
|
1528
|
+
Read from the device and react to the output with some callback.
|
1529
|
+
|
1530
|
+
Args:
|
1531
|
+
callbacks: a list of callbacks to process when reading from the session
|
1532
|
+
initial_input: an initial input to send
|
1533
|
+
operation_timeout_ns: operation timeout in ns for this operation
|
1534
|
+
|
1535
|
+
Returns:
|
1536
|
+
Result: a Result object representing the operation
|
1537
|
+
|
1538
|
+
Raises:
|
1539
|
+
NotOpenedException: if the ptr to the cli object is None (via _ptr_or_exception)
|
1540
|
+
SubmitOperationException: if the operation fails
|
1541
|
+
|
1542
|
+
"""
|
1543
|
+
# only used in the decorator
|
1544
|
+
_ = operation_timeout_ns
|
1545
|
+
|
1546
|
+
start_time = time_ns()
|
1547
|
+
|
1548
|
+
if initial_input:
|
1549
|
+
self.write_and_return(input_=initial_input)
|
1550
|
+
|
1551
|
+
pos = 0
|
1552
|
+
|
1553
|
+
result = ""
|
1554
|
+
result_raw = b""
|
1555
|
+
|
1556
|
+
executed_callbacks = set()
|
1557
|
+
|
1558
|
+
while True:
|
1559
|
+
operation_id = OperationIdPointer(c_uint(0))
|
1560
|
+
|
1561
|
+
status = self.ffi_mapping.cli_mapping.read_any(
|
1562
|
+
ptr=self._ptr_or_exception(),
|
1563
|
+
operation_id=operation_id,
|
1564
|
+
)
|
1565
|
+
if status != 0:
|
1566
|
+
raise SubmitOperationException("submitting read any operation failed")
|
1567
|
+
|
1568
|
+
intermediate_result = await self._get_result_async(
|
1569
|
+
operation_id=operation_id.contents.value
|
1570
|
+
)
|
1571
|
+
|
1572
|
+
result += intermediate_result.result
|
1573
|
+
result_raw += intermediate_result.result_raw
|
1574
|
+
|
1575
|
+
for callback in callbacks:
|
1576
|
+
if callback.name in executed_callbacks and callback.once:
|
1577
|
+
continue
|
1578
|
+
|
1579
|
+
execute = pointer(c_bool(False))
|
1580
|
+
|
1581
|
+
status = self.ffi_mapping.cli_mapping.read_callback_should_execute(
|
1582
|
+
buf=to_c_string(result[pos:]),
|
1583
|
+
name=to_c_string(callback.name),
|
1584
|
+
contains=to_c_string(callback.contains),
|
1585
|
+
contains_pattern=to_c_string(callback.contains_pattern),
|
1586
|
+
not_contains=to_c_string(callback.not_contains),
|
1587
|
+
execute=execute,
|
1588
|
+
)
|
1589
|
+
if status != 0:
|
1590
|
+
raise OperationException("failed checking if callback should execute")
|
1591
|
+
|
1592
|
+
if execute.contents.value is False:
|
1593
|
+
continue
|
1594
|
+
|
1595
|
+
executed_callbacks.add(callback.name)
|
1596
|
+
|
1597
|
+
pos = len(result)
|
1598
|
+
|
1599
|
+
if callback.callback is None:
|
1600
|
+
raise OperationException("callback is None, cannot proceed")
|
1601
|
+
else:
|
1602
|
+
callback.callback(self)
|
1603
|
+
|
1604
|
+
if callback.completes is True:
|
1605
|
+
return Result(
|
1606
|
+
inputs=initial_input,
|
1607
|
+
host=self.host,
|
1608
|
+
port=self.port,
|
1609
|
+
start_time=start_time,
|
1610
|
+
splits=[time_ns()],
|
1611
|
+
results_raw=result_raw,
|
1612
|
+
results=result,
|
1613
|
+
results_failed_indicator="",
|
1614
|
+
textfsm_platform=self.ntc_templates_platform,
|
1615
|
+
genie_platform=self.genie_platform,
|
1616
|
+
)
|
1617
|
+
|
1318
1618
|
@staticmethod
|
1319
1619
|
def ___getwide___() -> None: # pragma: no cover
|
1320
1620
|
"""
|
scrapli/cli_parse.py
CHANGED
scrapli/cli_result.py
CHANGED
@@ -4,6 +4,7 @@ from typing import Any, TextIO
|
|
4
4
|
|
5
5
|
from scrapli.cli_parse import genie_parse, textfsm_get_template, textfsm_parse
|
6
6
|
from scrapli.exceptions import ParsingException
|
7
|
+
from scrapli.helper import bulid_result_preview, unix_nano_timestmap_to_iso
|
7
8
|
|
8
9
|
OPERATION_DELIMITER = "__libscrapli__"
|
9
10
|
|
@@ -48,6 +49,30 @@ class Result:
|
|
48
49
|
self.textfsm_platform = textfsm_platform
|
49
50
|
self.genie_platform = genie_platform
|
50
51
|
|
52
|
+
def __str__(self) -> str:
|
53
|
+
"""
|
54
|
+
Magic str method for Result class
|
55
|
+
|
56
|
+
Args:
|
57
|
+
N/A
|
58
|
+
|
59
|
+
Returns:
|
60
|
+
str: str for class object
|
61
|
+
|
62
|
+
Raises:
|
63
|
+
N/A
|
64
|
+
|
65
|
+
"""
|
66
|
+
return (
|
67
|
+
"<-----\n"
|
68
|
+
f"\tInput(s) : {self.inputs}\n"
|
69
|
+
f"\tStart Time : {unix_nano_timestmap_to_iso(timestamp=self.start_time)}\n"
|
70
|
+
f"\tEnd Time : {unix_nano_timestmap_to_iso(timestamp=self.end_time)}\n"
|
71
|
+
f"\tElapsed Time (s) : {self.elapsed_time_seconds:.2f}s\n"
|
72
|
+
f"\tResult : {bulid_result_preview(result=self.result)}\n"
|
73
|
+
"----->"
|
74
|
+
)
|
75
|
+
|
51
76
|
def extend(self, result: "Result") -> None:
|
52
77
|
"""
|
53
78
|
Extends this Result object with another Result object.
|
@@ -141,6 +166,23 @@ class Result:
|
|
141
166
|
"""
|
142
167
|
return "\n".join(self.results)
|
143
168
|
|
169
|
+
@property
|
170
|
+
def result_raw(self) -> bytes:
|
171
|
+
"""
|
172
|
+
Returns the results (raw) joined on newline chars. Note this does *not* include inputs sent.
|
173
|
+
|
174
|
+
Args:
|
175
|
+
N/A
|
176
|
+
|
177
|
+
Returns:
|
178
|
+
bytes: joined results
|
179
|
+
|
180
|
+
Raises:
|
181
|
+
N/A
|
182
|
+
|
183
|
+
"""
|
184
|
+
return b"\n".join(self.results_raw)
|
185
|
+
|
144
186
|
def textfsm_parse(
|
145
187
|
self,
|
146
188
|
index: int = 0,
|
@@ -0,0 +1,33 @@
|
|
1
|
+
---
|
2
|
+
prompt_pattern: '^.*[>#$]\s?+$'
|
3
|
+
default_mode: 'privileged_exec'
|
4
|
+
modes:
|
5
|
+
- name: 'privileged_exec'
|
6
|
+
prompt_pattern: '^[\w.\-@/:]{1,63}#\s?$'
|
7
|
+
accessible_modes:
|
8
|
+
- name: 'configuration'
|
9
|
+
instructions:
|
10
|
+
- send_input:
|
11
|
+
input: 'configure terminal'
|
12
|
+
- name: 'configuration'
|
13
|
+
prompt_pattern: '^[\w.\-@/:]{1,63}\(config[\w.\-@/:]{0,32}\)#\s?$'
|
14
|
+
accessible_modes:
|
15
|
+
- name: 'privileged_exec'
|
16
|
+
instructions:
|
17
|
+
- send_input:
|
18
|
+
input: 'exit'
|
19
|
+
failure_indicators:
|
20
|
+
- '% Command incomplete.'
|
21
|
+
- 'Invalid input:'
|
22
|
+
- 'doesn''t exist'
|
23
|
+
on_open_instructions:
|
24
|
+
- enter_mode:
|
25
|
+
requested_mode: 'privileged_exec'
|
26
|
+
- send_input:
|
27
|
+
input: 'no page'
|
28
|
+
on_close_instructions:
|
29
|
+
- enter_mode:
|
30
|
+
requested_mode: 'privileged_exec'
|
31
|
+
- write:
|
32
|
+
input: 'exit'
|
33
|
+
ntc_templates_platform: 'aruba_aoscx'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
---
|
2
|
+
prompt_pattern: '^.*[>#$]\s?+$'
|
3
|
+
default_mode: 'exec'
|
4
|
+
modes:
|
5
|
+
- name: 'exec'
|
6
|
+
prompt_pattern: '^\([\w. -]{1,31}\) >$'
|
7
|
+
accessible_modes:
|
8
|
+
- name: 'configuration'
|
9
|
+
instructions:
|
10
|
+
- send_input:
|
11
|
+
input: 'config'
|
12
|
+
- name: 'configuration'
|
13
|
+
prompt_pattern: '^\([\w. -]{1,31}\) config>$'
|
14
|
+
accessible_modes:
|
15
|
+
- name: 'exec'
|
16
|
+
instructions:
|
17
|
+
- send_input:
|
18
|
+
input: 'exit'
|
19
|
+
failure_indicators:
|
20
|
+
- 'Incorrect Usage. Use the ''?'' or <TAB> key to list commands.'
|
21
|
+
- 'Incorrect input!'
|
22
|
+
on_open_instructions:
|
23
|
+
- send_input:
|
24
|
+
input: 'config paging disable'
|
25
|
+
on_close_instructions:
|
26
|
+
- enter_mode:
|
27
|
+
requested_mode: 'exec'
|
28
|
+
- write:
|
29
|
+
input: 'logout'
|
30
|
+
force_in_session_auth: true
|
31
|
+
ntc_templates_platform: 'cisco_wlc_ssh'
|
@@ -0,0 +1,48 @@
|
|
1
|
+
---
|
2
|
+
prompt_pattern: '^.*[>#$]\s?+$'
|
3
|
+
default_mode: 'privileged_exec'
|
4
|
+
modes:
|
5
|
+
- name: 'exec'
|
6
|
+
prompt_pattern: '^[\w\./-]{1,63}>\s?$'
|
7
|
+
accessible_modes:
|
8
|
+
- name: 'privileged_exec'
|
9
|
+
instructions:
|
10
|
+
- send_prompted_input:
|
11
|
+
input: 'enable'
|
12
|
+
prompt_pattern: '^(P|p)assword:\s?$'
|
13
|
+
response: '__lookup::enable'
|
14
|
+
- name: 'privileged_exec'
|
15
|
+
prompt_pattern: '^[\w\./-]{1,63}#\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: 'configuration'
|
26
|
+
prompt_pattern: '^[\w\./-]{1,63}\([\w-]{0,32}\)#\s?$'
|
27
|
+
accessible_modes:
|
28
|
+
- name: 'privileged_exec'
|
29
|
+
instructions:
|
30
|
+
- send_input:
|
31
|
+
input: 'exit'
|
32
|
+
failure_indicators:
|
33
|
+
- '% Ambiguous command'
|
34
|
+
- '% Incomplete command'
|
35
|
+
- '% Invalid input detected'
|
36
|
+
- '% Unknown command'
|
37
|
+
on_open_instructions:
|
38
|
+
- enter_mode:
|
39
|
+
requested_mode: 'privileged_exec'
|
40
|
+
- send_input:
|
41
|
+
input: 'terminal pager 0'
|
42
|
+
on_close_instructions:
|
43
|
+
- enter_mode:
|
44
|
+
requested_mode: 'privileged_exec'
|
45
|
+
- write:
|
46
|
+
input: 'logout'
|
47
|
+
ntc_templates_platform: 'cisco_asa'
|
48
|
+
genie_platform: 'asa'
|
@@ -0,0 +1,50 @@
|
|
1
|
+
---
|
2
|
+
prompt_pattern: '^.*[>#$]\s?+$'
|
3
|
+
default_mode: 'privileged_exec'
|
4
|
+
modes:
|
5
|
+
- name: 'exec'
|
6
|
+
prompt_pattern: '^[a-zA-Z0-9-.]{1,58}>$'
|
7
|
+
accessible_modes:
|
8
|
+
- name: 'privileged_exec'
|
9
|
+
instructions:
|
10
|
+
- send_prompted_input:
|
11
|
+
input: 'enable'
|
12
|
+
prompt_exact: '^(?:enable\s){0,1}Password:\s?$'
|
13
|
+
response: '__lookup::enable'
|
14
|
+
- name: 'privileged_exec'
|
15
|
+
prompt_pattern: '^[a-zA-Z0-9-.]{1,58}#$'
|
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: 'configuration'
|
26
|
+
prompt_pattern: '^[a-zA-Z0-9-.]{1,58}\([\w.\-@/:+]{1,32}\)#$'
|
27
|
+
accessible_modes:
|
28
|
+
- name: 'privileged_exec'
|
29
|
+
instructions:
|
30
|
+
- send_input:
|
31
|
+
input: 'end'
|
32
|
+
failure_indicators:
|
33
|
+
- '% Incomplete command'
|
34
|
+
- '% Unrecognized command'
|
35
|
+
- '% missing mandatory parameter'
|
36
|
+
- '% bad parameter value'
|
37
|
+
- '% Ambiguous command'
|
38
|
+
on_open_instructions:
|
39
|
+
- enter_mode:
|
40
|
+
requested_mode: 'privileged_exec'
|
41
|
+
- send_input:
|
42
|
+
input: 'terminal datadump'
|
43
|
+
- send_input:
|
44
|
+
input: 'terminal width 0'
|
45
|
+
on_close_instructions:
|
46
|
+
- enter_mode:
|
47
|
+
requested_mode: 'privileged_exec'
|
48
|
+
- write:
|
49
|
+
input: 'exit'
|
50
|
+
ntc_templates_platform: 'cisco_s300'
|