scrapli 2.0.0a3__py3-none-musllinux_1_1_aarch64.whl → 2.0.0a5__py3-none-musllinux_1_1_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 +5 -5
- scrapli/auth.py +14 -7
- scrapli/cli.py +334 -66
- 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 +92 -37
- scrapli/ffi_mapping_cli.py +146 -22
- scrapli/ffi_mapping_netconf.py +28 -60
- scrapli/ffi_mapping_options.py +38 -6
- scrapli/ffi_types.py +43 -3
- scrapli/helper.py +56 -0
- scrapli/lib/{libscrapli.0.0.1-alpha.10.dylib → libscrapli.0.0.1-alpha.17.dylib} +0 -0
- scrapli/lib/{libscrapli.so.0.0.1-alpha.10 → libscrapli.so.0.0.1-alpha.17} +0 -0
- scrapli/netconf.py +36 -147
- scrapli/transport.py +71 -130
- {scrapli-2.0.0a3.dist-info → scrapli-2.0.0a5.dist-info}/METADATA +1 -1
- scrapli-2.0.0a5.dist-info/RECORD +68 -0
- scrapli-2.0.0a3.dist-info/RECORD +0 -35
- {scrapli-2.0.0a3.dist-info → scrapli-2.0.0a5.dist-info}/WHEEL +0 -0
- {scrapli-2.0.0a3.dist-info → scrapli-2.0.0a5.dist-info}/licenses/LICENSE +0 -0
- {scrapli-2.0.0a3.dist-info → scrapli-2.0.0a5.dist-info}/top_level.txt +0 -0
scrapli/cli.py
CHANGED
@@ -1,18 +1,21 @@
|
|
1
1
|
"""scrapli.cli"""
|
2
2
|
|
3
3
|
import importlib.resources
|
4
|
-
from collections.abc import Callable
|
4
|
+
from collections.abc import Awaitable, Callable
|
5
5
|
from ctypes import (
|
6
6
|
c_bool,
|
7
7
|
c_char_p,
|
8
8
|
c_int,
|
9
9
|
c_uint,
|
10
10
|
c_uint64,
|
11
|
+
pointer,
|
11
12
|
)
|
13
|
+
from dataclasses import dataclass
|
12
14
|
from enum import Enum
|
13
15
|
from logging import getLogger
|
14
16
|
from os import environ
|
15
17
|
from pathlib import Path
|
18
|
+
from time import time_ns
|
16
19
|
from types import TracebackType
|
17
20
|
from typing import Any
|
18
21
|
|
@@ -31,14 +34,13 @@ from scrapli.exceptions import (
|
|
31
34
|
)
|
32
35
|
from scrapli.ffi_mapping import LibScrapliMapping
|
33
36
|
from scrapli.ffi_types import (
|
34
|
-
CancelPointer,
|
35
37
|
DriverPointer,
|
36
38
|
IntPointer,
|
37
|
-
LogFuncCallback,
|
38
39
|
OperationIdPointer,
|
39
40
|
U64Pointer,
|
40
41
|
ZigSlice,
|
41
42
|
ZigU64Slice,
|
43
|
+
ffi_logger_wrapper,
|
42
44
|
to_c_string,
|
43
45
|
)
|
44
46
|
from scrapli.helper import (
|
@@ -47,6 +49,7 @@ from scrapli.helper import (
|
|
47
49
|
wait_for_available_operation_result_async,
|
48
50
|
)
|
49
51
|
from scrapli.session import Options as SessionOptions
|
52
|
+
from scrapli.transport import BinOptions as TransportBinOptions
|
50
53
|
from scrapli.transport import Options as TransportOptions
|
51
54
|
|
52
55
|
CLI_DEFINITIONS_PATH_OVERRIDE_ENV = "SCRAPLI_DEFINITIONS_PATH"
|
@@ -73,6 +76,50 @@ class InputHandling(str, Enum):
|
|
73
76
|
IGNORE = "ignore"
|
74
77
|
|
75
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
|
+
|
76
123
|
class Cli:
|
77
124
|
"""
|
78
125
|
Cli represents a cli connection object.
|
@@ -93,7 +140,6 @@ class Cli:
|
|
93
140
|
definition_file_or_name: str,
|
94
141
|
host: str,
|
95
142
|
*,
|
96
|
-
logger_callback: Callable[[int, str], None] | None = None,
|
97
143
|
port: int = 22,
|
98
144
|
auth_options: AuthOptions | None = None,
|
99
145
|
session_options: SessionOptions | None = None,
|
@@ -105,6 +151,7 @@ class Cli:
|
|
105
151
|
logger_name += f":{logging_uid}"
|
106
152
|
|
107
153
|
self.logger = getLogger(logger_name)
|
154
|
+
self.logger_callback = ffi_logger_wrapper(logger=self.logger)
|
108
155
|
self._logging_uid = logging_uid
|
109
156
|
|
110
157
|
self.ffi_mapping = LibScrapliMapping()
|
@@ -117,18 +164,13 @@ class Cli:
|
|
117
164
|
# why. in this case we also just store the host since thats cheap and we need it as a string
|
118
165
|
# in places too
|
119
166
|
self.host = host
|
120
|
-
self._host = to_c_string(host)
|
121
|
-
|
122
|
-
self.logger_callback = (
|
123
|
-
LogFuncCallback(logger_callback) if logger_callback else LogFuncCallback(0)
|
124
|
-
)
|
125
|
-
self._logger_callback = logger_callback
|
167
|
+
self._host = to_c_string(s=host)
|
126
168
|
|
127
169
|
self.port = port
|
128
170
|
|
129
171
|
self.auth_options = auth_options or AuthOptions()
|
130
172
|
self.session_options = session_options or SessionOptions()
|
131
|
-
self.transport_options = transport_options or
|
173
|
+
self.transport_options = transport_options or TransportBinOptions()
|
132
174
|
|
133
175
|
self.ptr: DriverPointer | None = None
|
134
176
|
self.poll_fd: int = 0
|
@@ -264,7 +306,6 @@ class Cli:
|
|
264
306
|
return Cli(
|
265
307
|
host=self.host,
|
266
308
|
definition_file_or_name=self.definition_file_or_name,
|
267
|
-
logger_callback=self._logger_callback,
|
268
309
|
port=self.port,
|
269
310
|
auth_options=self.auth_options,
|
270
311
|
session_options=self.session_options,
|
@@ -289,6 +330,8 @@ class Cli:
|
|
289
330
|
with open(definition_file_or_name, "rb") as f:
|
290
331
|
self.definition_string = f.read()
|
291
332
|
|
333
|
+
return
|
334
|
+
|
292
335
|
raise OptionsException(
|
293
336
|
f"definition platform name or filename '{definition_file_or_name}' not found"
|
294
337
|
)
|
@@ -307,7 +350,7 @@ class Cli:
|
|
307
350
|
logger_callback=self.logger_callback,
|
308
351
|
host=self._host,
|
309
352
|
port=c_int(self.port),
|
310
|
-
transport_kind=c_char_p(self.transport_options.
|
353
|
+
transport_kind=c_char_p(self.transport_options.transport_kind.encode(encoding="utf-8")),
|
311
354
|
)
|
312
355
|
if ptr == 0: # type: ignore[comparison-overlap]
|
313
356
|
raise AllocationException("failed to allocate cli")
|
@@ -319,7 +362,7 @@ class Cli:
|
|
319
362
|
ptr=self._ptr_or_exception(),
|
320
363
|
)
|
321
364
|
)
|
322
|
-
if poll_fd
|
365
|
+
if poll_fd <= 0:
|
323
366
|
raise AllocationException("failed to allocate cli")
|
324
367
|
|
325
368
|
self.poll_fd = poll_fd
|
@@ -393,9 +436,9 @@ class Cli:
|
|
393
436
|
|
394
437
|
def _open(
|
395
438
|
self,
|
439
|
+
*,
|
396
440
|
operation_id: OperationIdPointer,
|
397
|
-
|
398
|
-
) -> c_uint:
|
441
|
+
) -> None:
|
399
442
|
self._alloc()
|
400
443
|
|
401
444
|
self.auth_options.apply(self.ffi_mapping, self._ptr_or_exception())
|
@@ -405,15 +448,12 @@ class Cli:
|
|
405
448
|
status = self.ffi_mapping.cli_mapping.open(
|
406
449
|
ptr=self._ptr_or_exception(),
|
407
450
|
operation_id=operation_id,
|
408
|
-
cancel=cancel,
|
409
451
|
)
|
410
452
|
if status != 0:
|
411
453
|
self._free()
|
412
454
|
|
413
455
|
raise OpenException("failed to submit open operation")
|
414
456
|
|
415
|
-
return c_uint(operation_id.contents.value)
|
416
|
-
|
417
457
|
def open(
|
418
458
|
self,
|
419
459
|
) -> Result:
|
@@ -431,11 +471,10 @@ class Cli:
|
|
431
471
|
|
432
472
|
"""
|
433
473
|
operation_id = OperationIdPointer(c_uint(0))
|
434
|
-
cancel = CancelPointer(c_bool(False))
|
435
474
|
|
436
|
-
|
475
|
+
self._open(operation_id=operation_id)
|
437
476
|
|
438
|
-
return self._get_result(operation_id=operation_id)
|
477
|
+
return self._get_result(operation_id=operation_id.contents.value)
|
439
478
|
|
440
479
|
async def open_async(self) -> Result:
|
441
480
|
"""
|
@@ -452,24 +491,23 @@ class Cli:
|
|
452
491
|
|
453
492
|
"""
|
454
493
|
operation_id = OperationIdPointer(c_uint(0))
|
455
|
-
cancel = CancelPointer(c_bool(False))
|
456
494
|
|
457
|
-
|
495
|
+
self._open(operation_id=operation_id)
|
458
496
|
|
459
|
-
return await self._get_result_async(operation_id=operation_id)
|
460
|
-
|
461
|
-
def _close(self) -> c_uint:
|
462
|
-
operation_id = OperationIdPointer(c_uint(0))
|
463
|
-
cancel = CancelPointer(c_bool(False))
|
497
|
+
return await self._get_result_async(operation_id=operation_id.contents.value)
|
464
498
|
|
499
|
+
def _close(
|
500
|
+
self,
|
501
|
+
*,
|
502
|
+
operation_id: OperationIdPointer,
|
503
|
+
) -> None:
|
465
504
|
status = self.ffi_mapping.cli_mapping.close(
|
466
|
-
ptr=self._ptr_or_exception(),
|
505
|
+
ptr=self._ptr_or_exception(),
|
506
|
+
operation_id=operation_id,
|
467
507
|
)
|
468
508
|
if status != 0:
|
469
509
|
raise CloseException("submitting close operation")
|
470
510
|
|
471
|
-
return c_uint(operation_id.contents.value)
|
472
|
-
|
473
511
|
def close(
|
474
512
|
self,
|
475
513
|
) -> Result:
|
@@ -487,9 +525,11 @@ class Cli:
|
|
487
525
|
CloseException: if the operation fails
|
488
526
|
|
489
527
|
"""
|
490
|
-
operation_id =
|
528
|
+
operation_id = OperationIdPointer(c_uint(0))
|
491
529
|
|
492
|
-
|
530
|
+
self._close(operation_id=operation_id)
|
531
|
+
|
532
|
+
result = self._get_result(operation_id=operation_id.contents.value)
|
493
533
|
|
494
534
|
self._free()
|
495
535
|
|
@@ -512,14 +552,70 @@ class Cli:
|
|
512
552
|
CloseException: if the operation fails
|
513
553
|
|
514
554
|
"""
|
515
|
-
operation_id =
|
555
|
+
operation_id = OperationIdPointer(c_uint(0))
|
556
|
+
|
557
|
+
self._close(operation_id=operation_id)
|
516
558
|
|
517
|
-
result = await self._get_result_async(operation_id=operation_id)
|
559
|
+
result = await self._get_result_async(operation_id=operation_id.contents.value)
|
518
560
|
|
519
561
|
self._free()
|
520
562
|
|
521
563
|
return result
|
522
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
|
+
|
523
619
|
def _get_result(
|
524
620
|
self,
|
525
621
|
operation_id: c_uint,
|
@@ -658,13 +754,11 @@ class Cli:
|
|
658
754
|
self,
|
659
755
|
*,
|
660
756
|
operation_id: OperationIdPointer,
|
661
|
-
cancel: CancelPointer,
|
662
757
|
requested_mode: c_char_p,
|
663
758
|
) -> c_uint:
|
664
759
|
status = self.ffi_mapping.cli_mapping.enter_mode(
|
665
760
|
ptr=self._ptr_or_exception(),
|
666
761
|
operation_id=operation_id,
|
667
|
-
cancel=cancel,
|
668
762
|
requested_mode=requested_mode,
|
669
763
|
)
|
670
764
|
if status != 0:
|
@@ -698,12 +792,12 @@ class Cli:
|
|
698
792
|
_ = operation_timeout_ns
|
699
793
|
|
700
794
|
operation_id = OperationIdPointer(c_uint(0))
|
701
|
-
cancel = CancelPointer(c_bool(False))
|
702
795
|
|
703
796
|
_requested_mode = to_c_string(requested_mode)
|
704
797
|
|
705
798
|
operation_id = self._enter_mode(
|
706
|
-
operation_id=operation_id,
|
799
|
+
operation_id=operation_id,
|
800
|
+
requested_mode=_requested_mode,
|
707
801
|
)
|
708
802
|
|
709
803
|
return self._get_result(operation_id=operation_id)
|
@@ -734,12 +828,12 @@ class Cli:
|
|
734
828
|
_ = operation_timeout_ns
|
735
829
|
|
736
830
|
operation_id = OperationIdPointer(c_uint(0))
|
737
|
-
cancel = CancelPointer(c_bool(False))
|
738
831
|
|
739
832
|
_requested_mode = to_c_string(requested_mode)
|
740
833
|
|
741
834
|
operation_id = self._enter_mode(
|
742
|
-
operation_id=operation_id,
|
835
|
+
operation_id=operation_id,
|
836
|
+
requested_mode=_requested_mode,
|
743
837
|
)
|
744
838
|
|
745
839
|
return await self._get_result_async(operation_id=operation_id)
|
@@ -748,12 +842,10 @@ class Cli:
|
|
748
842
|
self,
|
749
843
|
*,
|
750
844
|
operation_id: OperationIdPointer,
|
751
|
-
cancel: CancelPointer,
|
752
845
|
) -> c_uint:
|
753
846
|
status = self.ffi_mapping.cli_mapping.get_prompt(
|
754
847
|
ptr=self._ptr_or_exception(),
|
755
848
|
operation_id=operation_id,
|
756
|
-
cancel=cancel,
|
757
849
|
)
|
758
850
|
if status != 0:
|
759
851
|
raise SubmitOperationException("submitting get prompt operation failed")
|
@@ -784,9 +876,8 @@ class Cli:
|
|
784
876
|
_ = operation_timeout_ns
|
785
877
|
|
786
878
|
operation_id = OperationIdPointer(c_uint(0))
|
787
|
-
cancel = CancelPointer(c_bool(False))
|
788
879
|
|
789
|
-
operation_id = self._get_prompt(operation_id=operation_id
|
880
|
+
operation_id = self._get_prompt(operation_id=operation_id)
|
790
881
|
|
791
882
|
return self._get_result(operation_id=operation_id)
|
792
883
|
|
@@ -814,9 +905,8 @@ class Cli:
|
|
814
905
|
_ = operation_timeout_ns
|
815
906
|
|
816
907
|
operation_id = OperationIdPointer(c_uint(0))
|
817
|
-
cancel = CancelPointer(c_bool(False))
|
818
908
|
|
819
|
-
operation_id = self._get_prompt(operation_id=operation_id
|
909
|
+
operation_id = self._get_prompt(operation_id=operation_id)
|
820
910
|
|
821
911
|
return await self._get_result_async(operation_id=operation_id)
|
822
912
|
|
@@ -824,7 +914,6 @@ class Cli:
|
|
824
914
|
self,
|
825
915
|
*,
|
826
916
|
operation_id: OperationIdPointer,
|
827
|
-
cancel: CancelPointer,
|
828
917
|
input_: c_char_p,
|
829
918
|
requested_mode: c_char_p,
|
830
919
|
input_handling: c_char_p,
|
@@ -834,7 +923,6 @@ class Cli:
|
|
834
923
|
status = self.ffi_mapping.cli_mapping.send_input(
|
835
924
|
ptr=self._ptr_or_exception(),
|
836
925
|
operation_id=operation_id,
|
837
|
-
cancel=cancel,
|
838
926
|
input_=input_,
|
839
927
|
requested_mode=requested_mode,
|
840
928
|
input_handling=input_handling,
|
@@ -880,7 +968,6 @@ class Cli:
|
|
880
968
|
_ = operation_timeout_ns
|
881
969
|
|
882
970
|
operation_id = OperationIdPointer(c_uint(0))
|
883
|
-
cancel = CancelPointer(c_bool(False))
|
884
971
|
|
885
972
|
_input = to_c_string(input_)
|
886
973
|
_requested_mode = to_c_string(requested_mode)
|
@@ -888,7 +975,6 @@ class Cli:
|
|
888
975
|
|
889
976
|
operation_id = self._send_input(
|
890
977
|
operation_id=operation_id,
|
891
|
-
cancel=cancel,
|
892
978
|
input_=_input,
|
893
979
|
requested_mode=_requested_mode,
|
894
980
|
input_handling=_input_handling,
|
@@ -932,7 +1018,6 @@ class Cli:
|
|
932
1018
|
_ = operation_timeout_ns
|
933
1019
|
|
934
1020
|
operation_id = OperationIdPointer(c_uint(0))
|
935
|
-
cancel = CancelPointer(c_bool(False))
|
936
1021
|
|
937
1022
|
_input = to_c_string(input_)
|
938
1023
|
_requested_mode = to_c_string(requested_mode)
|
@@ -940,7 +1025,6 @@ class Cli:
|
|
940
1025
|
|
941
1026
|
operation_id = self._send_input(
|
942
1027
|
operation_id=operation_id,
|
943
|
-
cancel=cancel,
|
944
1028
|
input_=_input,
|
945
1029
|
requested_mode=_requested_mode,
|
946
1030
|
input_handling=_input_handling,
|
@@ -986,8 +1070,6 @@ class Cli:
|
|
986
1070
|
# meaning all the "inputs" combined, not individually
|
987
1071
|
_ = operation_timeout_ns
|
988
1072
|
|
989
|
-
cancel = CancelPointer(c_bool(False))
|
990
|
-
|
991
1073
|
result: Result | None = None
|
992
1074
|
|
993
1075
|
for input_ in inputs:
|
@@ -999,7 +1081,6 @@ class Cli:
|
|
999
1081
|
|
1000
1082
|
operation_id = self._send_input(
|
1001
1083
|
operation_id=operation_id,
|
1002
|
-
cancel=cancel,
|
1003
1084
|
input_=_input,
|
1004
1085
|
requested_mode=_requested_mode,
|
1005
1086
|
input_handling=_input_handling,
|
@@ -1055,8 +1136,6 @@ class Cli:
|
|
1055
1136
|
# meaning all the "inputs" combined, not individually
|
1056
1137
|
_ = operation_timeout_ns
|
1057
1138
|
|
1058
|
-
cancel = CancelPointer(c_bool(False))
|
1059
|
-
|
1060
1139
|
result: Result | None = None
|
1061
1140
|
|
1062
1141
|
for input_ in inputs:
|
@@ -1068,7 +1147,6 @@ class Cli:
|
|
1068
1147
|
|
1069
1148
|
operation_id = self._send_input(
|
1070
1149
|
operation_id=operation_id,
|
1071
|
-
cancel=cancel,
|
1072
1150
|
input_=_input,
|
1073
1151
|
requested_mode=_requested_mode,
|
1074
1152
|
input_handling=_input_handling,
|
@@ -1179,7 +1257,6 @@ class Cli:
|
|
1179
1257
|
self,
|
1180
1258
|
*,
|
1181
1259
|
operation_id: OperationIdPointer,
|
1182
|
-
cancel: CancelPointer,
|
1183
1260
|
input_: c_char_p,
|
1184
1261
|
prompt: c_char_p,
|
1185
1262
|
prompt_pattern: c_char_p,
|
@@ -1193,7 +1270,6 @@ class Cli:
|
|
1193
1270
|
status = self.ffi_mapping.cli_mapping.send_prompted_input(
|
1194
1271
|
ptr=self._ptr_or_exception(),
|
1195
1272
|
operation_id=operation_id,
|
1196
|
-
cancel=cancel,
|
1197
1273
|
input_=input_,
|
1198
1274
|
prompt=prompt,
|
1199
1275
|
prompt_pattern=prompt_pattern,
|
@@ -1252,7 +1328,6 @@ class Cli:
|
|
1252
1328
|
_ = operation_timeout_ns
|
1253
1329
|
|
1254
1330
|
operation_id = OperationIdPointer(c_uint(0))
|
1255
|
-
cancel = CancelPointer(c_bool(False))
|
1256
1331
|
|
1257
1332
|
_input = to_c_string(input_)
|
1258
1333
|
_prompt = to_c_string(prompt)
|
@@ -1264,7 +1339,6 @@ class Cli:
|
|
1264
1339
|
|
1265
1340
|
operation_id = self._send_prompted_input(
|
1266
1341
|
operation_id=operation_id,
|
1267
|
-
cancel=cancel,
|
1268
1342
|
input_=_input,
|
1269
1343
|
prompt=_prompt,
|
1270
1344
|
prompt_pattern=_prompt_pattern,
|
@@ -1321,7 +1395,6 @@ class Cli:
|
|
1321
1395
|
_ = operation_timeout_ns
|
1322
1396
|
|
1323
1397
|
operation_id = OperationIdPointer(c_uint(0))
|
1324
|
-
cancel = CancelPointer(c_bool(False))
|
1325
1398
|
|
1326
1399
|
_input = to_c_string(input_)
|
1327
1400
|
_prompt = to_c_string(prompt)
|
@@ -1333,7 +1406,6 @@ class Cli:
|
|
1333
1406
|
|
1334
1407
|
operation_id = self._send_prompted_input(
|
1335
1408
|
operation_id=operation_id,
|
1336
|
-
cancel=cancel,
|
1337
1409
|
input_=_input,
|
1338
1410
|
prompt=_prompt,
|
1339
1411
|
prompt_pattern=_prompt_pattern,
|
@@ -1347,6 +1419,202 @@ class Cli:
|
|
1347
1419
|
|
1348
1420
|
return await self._get_result_async(operation_id=operation_id)
|
1349
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
|
+
|
1350
1618
|
@staticmethod
|
1351
1619
|
def ___getwide___() -> None: # pragma: no cover
|
1352
1620
|
"""
|