annet 2.2.2__py3-none-any.whl → 2.3.1__py3-none-any.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.
Potentially problematic release.
This version of annet might be problematic. Click here for more details.
- annet/api/__init__.py +53 -102
- annet/cli.py +15 -8
- annet/cli_args.py +1 -0
- annet/deploy.py +2 -2
- annet/diff.py +102 -9
- {annet-2.2.2.dist-info → annet-2.3.1.dist-info}/METADATA +1 -1
- {annet-2.2.2.dist-info → annet-2.3.1.dist-info}/RECORD +12 -12
- {annet-2.2.2.dist-info → annet-2.3.1.dist-info}/WHEEL +1 -1
- {annet-2.2.2.dist-info → annet-2.3.1.dist-info}/AUTHORS +0 -0
- {annet-2.2.2.dist-info → annet-2.3.1.dist-info}/LICENSE +0 -0
- {annet-2.2.2.dist-info → annet-2.3.1.dist-info}/entry_points.txt +0 -0
- {annet-2.2.2.dist-info → annet-2.3.1.dist-info}/top_level.txt +0 -0
annet/api/__init__.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import abc
|
|
2
|
+
import inspect
|
|
2
3
|
import os
|
|
3
4
|
import re
|
|
4
5
|
import sys
|
|
@@ -8,16 +9,14 @@ from collections import OrderedDict as odict
|
|
|
8
9
|
from itertools import groupby, chain
|
|
9
10
|
from operator import itemgetter
|
|
10
11
|
from typing import (
|
|
11
|
-
Any,
|
|
12
12
|
Dict,
|
|
13
13
|
Generator,
|
|
14
14
|
Iterable,
|
|
15
15
|
List,
|
|
16
16
|
Mapping,
|
|
17
|
-
Optional,
|
|
18
17
|
Set,
|
|
19
18
|
Tuple,
|
|
20
|
-
Union, cast,
|
|
19
|
+
Union, cast, Any,
|
|
21
20
|
)
|
|
22
21
|
|
|
23
22
|
import colorama
|
|
@@ -41,7 +40,6 @@ from annet.rulebook import deploying
|
|
|
41
40
|
from annet.filtering import Filterer
|
|
42
41
|
from annet.hardware import hardware_connector
|
|
43
42
|
from annet.output import (
|
|
44
|
-
LABEL_NEW_PREFIX,
|
|
45
43
|
format_file_diff,
|
|
46
44
|
output_driver_connector,
|
|
47
45
|
print_err_label,
|
|
@@ -51,7 +49,6 @@ from annet.reference import RefTracker
|
|
|
51
49
|
from annet.storage import Device, get_storage
|
|
52
50
|
from annet.types import Diff, ExitCode, OldNewResult, Op, PCDiff, PCDiffFile
|
|
53
51
|
|
|
54
|
-
|
|
55
52
|
DEFAULT_INDENT = " "
|
|
56
53
|
|
|
57
54
|
|
|
@@ -240,15 +237,6 @@ def gen(args: cli_args.ShowGenOptions, loader: ann_gen.Loader):
|
|
|
240
237
|
|
|
241
238
|
|
|
242
239
|
# =====
|
|
243
|
-
def _diff_files(hw, old_files, new_files):
|
|
244
|
-
ret = {}
|
|
245
|
-
differ = file_differ_connector.get()
|
|
246
|
-
for (path, (new_text, reload_data)) in new_files.items():
|
|
247
|
-
old_text = old_files.get(path)
|
|
248
|
-
is_new = old_text is None
|
|
249
|
-
diff_lines = differ.diff_file(hw, path, old_text, new_text)
|
|
250
|
-
ret[path] = (diff_lines, reload_data, is_new)
|
|
251
|
-
return ret
|
|
252
240
|
|
|
253
241
|
|
|
254
242
|
def patch(args: cli_args.ShowPatchOptions, loader: ann_gen.Loader):
|
|
@@ -322,62 +310,41 @@ def res_diff_patch(
|
|
|
322
310
|
|
|
323
311
|
|
|
324
312
|
def diff(
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
for res in ann_gen.old_new(
|
|
332
|
-
args,
|
|
333
|
-
config=args.config,
|
|
334
|
-
loader=loader,
|
|
335
|
-
no_new=args.clear,
|
|
336
|
-
do_files_download=True,
|
|
337
|
-
device_ids=device_ids,
|
|
338
|
-
filterer=filterer,
|
|
339
|
-
):
|
|
340
|
-
old = res.get_old(args.acl_safe)
|
|
341
|
-
new = res.get_new(args.acl_safe)
|
|
342
|
-
device = res.device
|
|
343
|
-
acl_rules = res.get_acl_rules(args.acl_safe)
|
|
344
|
-
new_files = res.get_new_files(args.acl_safe)
|
|
345
|
-
new_json_fragment_files = res.get_new_file_fragments(args.acl_safe)
|
|
346
|
-
|
|
347
|
-
pc_diff_files = []
|
|
348
|
-
if res.old_files or new_files:
|
|
349
|
-
pc_diff_files.extend(_pc_diff(res.device.hw, device.hostname, res.old_files, new_files))
|
|
350
|
-
if res.old_json_fragment_files or new_json_fragment_files:
|
|
351
|
-
pc_diff_files.extend(_json_fragment_diff(res.device.hw, device.hostname, res.old_json_fragment_files, new_json_fragment_files))
|
|
313
|
+
args: cli_args.DiffOptions,
|
|
314
|
+
loader: ann_gen.Loader,
|
|
315
|
+
device_ids: List[Any]
|
|
316
|
+
) -> tuple[Mapping[Device, Union[Diff, PCDiff]], Mapping[Device, Exception]]:
|
|
317
|
+
""" Сгенерировать конфиг для устройств """
|
|
318
|
+
stdin = args.stdin(filter_acl=args.filter_acl, config=None)
|
|
352
319
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
rb = rulebook.get_rulebook(device.hw)
|
|
359
|
-
diff_tree = patching.make_diff(
|
|
360
|
-
old,
|
|
361
|
-
orderer.order_config(new),
|
|
362
|
-
rb,
|
|
363
|
-
[acl_rules, res.filter_acl_rules],
|
|
364
|
-
)
|
|
365
|
-
diff_tree = patching.strip_unchanged(diff_tree)
|
|
366
|
-
ret[device] = diff_tree
|
|
320
|
+
filterer = filtering.filterer_connector.get()
|
|
321
|
+
pool = Parallel(ann_diff.worker, args, stdin, loader, filterer).tune_args(args)
|
|
322
|
+
if args.show_hosts_progress:
|
|
323
|
+
fqdns = {k: v for k, v in loader.device_fqdns.items() if k in device_ids}
|
|
324
|
+
pool.add_callback(PoolProgressLogger(fqdns))
|
|
367
325
|
|
|
368
|
-
return
|
|
326
|
+
return pool.run(device_ids, args.tolerate_fails, args.strict_exit_code)
|
|
369
327
|
|
|
370
328
|
|
|
371
|
-
def collapse_texts(texts: Mapping[str, str]) -> Mapping[Tuple[str, ...], str]:
|
|
329
|
+
def collapse_texts(texts: Mapping[str, str | Generator[str, None, None]]) -> Mapping[Tuple[str, ...], str]:
|
|
372
330
|
"""
|
|
373
331
|
Группировка текстов.
|
|
374
332
|
:param texts:
|
|
375
333
|
:return: словарь с несколькими хостнеймами в ключе.
|
|
376
334
|
"""
|
|
377
|
-
diffs_with_orig = {
|
|
335
|
+
diffs_with_orig = {}
|
|
336
|
+
for key, value in texts.items():
|
|
337
|
+
if inspect.isgenerator(value):
|
|
338
|
+
lines = list(value)
|
|
339
|
+
diffs_with_orig[key] = ["".join(lines), lines]
|
|
340
|
+
else:
|
|
341
|
+
diffs_with_orig[key] = [value, value.splitlines()]
|
|
342
|
+
|
|
378
343
|
res = {}
|
|
379
|
-
for _, collapsed_diff_iter in groupby(
|
|
380
|
-
|
|
344
|
+
for _, collapsed_diff_iter in groupby(
|
|
345
|
+
sorted(diffs_with_orig.items(), key=lambda x: (x[0], x[1][1])),
|
|
346
|
+
key=lambda x: x[1][1]
|
|
347
|
+
):
|
|
381
348
|
collapsed_diff = list(collapsed_diff_iter)
|
|
382
349
|
res[tuple(x[0] for x in collapsed_diff)] = collapsed_diff[0][1][0]
|
|
383
350
|
|
|
@@ -535,7 +502,6 @@ class Deployer:
|
|
|
535
502
|
|
|
536
503
|
self._collapseable_diffs = {}
|
|
537
504
|
self._diff_lines: List[str] = []
|
|
538
|
-
self._filterer = filtering.filterer_connector.get()
|
|
539
505
|
|
|
540
506
|
def parse_result(self, job: DeployerJob, result: ann_gen.OldNewResult):
|
|
541
507
|
logger = get_logger(job.device.hostname)
|
|
@@ -629,14 +595,28 @@ class Deployer:
|
|
|
629
595
|
self.args,
|
|
630
596
|
config="running",
|
|
631
597
|
)
|
|
598
|
+
|
|
632
599
|
if diff_args.query:
|
|
633
600
|
ann_gen.live_configs = None
|
|
634
|
-
|
|
635
|
-
|
|
601
|
+
|
|
602
|
+
diffs, failed = diff(diff_args, loader, success_device_ids)
|
|
603
|
+
for device_id, exc in failed.items():
|
|
604
|
+
self.failed_configs[loader.get_device(device_id).fqdn] = exc
|
|
605
|
+
|
|
606
|
+
non_pc_diffs = {
|
|
607
|
+
loader.get_device(device_id): diff
|
|
608
|
+
for device_id, diff in diffs.items()
|
|
609
|
+
if not isinstance(diff, PCDiff)
|
|
610
|
+
}
|
|
636
611
|
devices_to_diff = ann_diff.collapse_diffs(non_pc_diffs)
|
|
637
|
-
devices_to_diff.update({
|
|
612
|
+
devices_to_diff.update({
|
|
613
|
+
(loader.get_device(device_id),): diff
|
|
614
|
+
for device_id, diff in diffs.items()
|
|
615
|
+
if isinstance(diff, PCDiff)}
|
|
616
|
+
)
|
|
638
617
|
else:
|
|
639
618
|
devices_to_diff = {}
|
|
619
|
+
|
|
640
620
|
for devices, diff_obj in devices_to_diff.items():
|
|
641
621
|
if diff_obj:
|
|
642
622
|
for dev in devices:
|
|
@@ -744,8 +724,10 @@ def file_diff(args: cli_args.FileDiffOptions):
|
|
|
744
724
|
return pool.run(old_new, tolerate_fails=True)
|
|
745
725
|
|
|
746
726
|
|
|
747
|
-
def file_diff_worker(
|
|
748
|
-
Tuple[str, str
|
|
727
|
+
def file_diff_worker(
|
|
728
|
+
old_new: Tuple[str, str],
|
|
729
|
+
args: cli_args.FileDiffOptions
|
|
730
|
+
) -> Generator[Tuple[str, str, bool], None, None]:
|
|
749
731
|
old_path, new_path = old_new
|
|
750
732
|
hw = args.hw
|
|
751
733
|
if isinstance(args.hw, str):
|
|
@@ -753,10 +735,12 @@ def file_diff_worker(old_new: Tuple[str, str], args: cli_args.FileDiffOptions) -
|
|
|
753
735
|
|
|
754
736
|
if os.path.isdir(old_path) and os.path.isdir(new_path):
|
|
755
737
|
hostname = os.path.basename(new_path)
|
|
756
|
-
new_files = {
|
|
757
|
-
|
|
738
|
+
new_files = {
|
|
739
|
+
relative_cfg_path: (cfg_text, "")
|
|
740
|
+
for relative_cfg_path, cfg_text in ann_gen.load_pc_config(new_path).items()
|
|
741
|
+
}
|
|
758
742
|
old_files = ann_gen.load_pc_config(old_path)
|
|
759
|
-
for diff_file in
|
|
743
|
+
for diff_file in ann_diff.pc_diff(hw, hostname, old_files, new_files):
|
|
760
744
|
diff_text = (
|
|
761
745
|
"\n".join(diff_file.diff_lines)
|
|
762
746
|
if args.no_color
|
|
@@ -796,39 +780,6 @@ def file_patch_worker(old_new: Tuple[str, str], args: cli_args.FileDiffOptions)
|
|
|
796
780
|
yield dest_name, patch_text, False
|
|
797
781
|
|
|
798
782
|
|
|
799
|
-
def _pc_diff(hw, hostname: str, old_files: Dict[str, str], new_files: Dict[str, str]) -> Generator[PCDiffFile, None, None]:
|
|
800
|
-
sorted_lines = sorted(_diff_files(hw, old_files, new_files).items())
|
|
801
|
-
for (path, (diff_lines, _reload_data, is_new)) in sorted_lines:
|
|
802
|
-
if not diff_lines:
|
|
803
|
-
continue
|
|
804
|
-
label = hostname + os.sep + path
|
|
805
|
-
if is_new:
|
|
806
|
-
label = LABEL_NEW_PREFIX + label
|
|
807
|
-
yield PCDiffFile(label=label, diff_lines=diff_lines)
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
def _json_fragment_diff(
|
|
811
|
-
hw,
|
|
812
|
-
hostname: str,
|
|
813
|
-
old_files: Dict[str, Any],
|
|
814
|
-
new_files: Dict[str, Tuple[Any, Optional[str]]],
|
|
815
|
-
) -> Generator[PCDiffFile, None, None]:
|
|
816
|
-
def jsonify_multi(files):
|
|
817
|
-
return {
|
|
818
|
-
path: jsontools.format_json(cfg)
|
|
819
|
-
for path, cfg in files.items()
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
def jsonify_multi_with_cmd(files):
|
|
823
|
-
ret = {}
|
|
824
|
-
for path, cfg_reload_cmd in files.items():
|
|
825
|
-
cfg, reload_cmd = cfg_reload_cmd
|
|
826
|
-
ret[path] = (jsontools.format_json(cfg), reload_cmd)
|
|
827
|
-
return ret
|
|
828
|
-
jold, jnew = jsonify_multi(old_files), jsonify_multi_with_cmd(new_files)
|
|
829
|
-
return _pc_diff(hw, hostname, jold, jnew)
|
|
830
|
-
|
|
831
|
-
|
|
832
783
|
def guess_hw(config_text: str):
|
|
833
784
|
"""Пытаемся угадать вендора и hw на основе
|
|
834
785
|
текста конфига и annet/rulebook/texts/*.rul"""
|
annet/cli.py
CHANGED
|
@@ -113,6 +113,7 @@ def show_device_dump(args: cli_args.QueryOptions, arg_out: cli_args.FileOutOptio
|
|
|
113
113
|
)
|
|
114
114
|
else:
|
|
115
115
|
get_logger().warning("method `dump` not implemented for %s", type(device))
|
|
116
|
+
|
|
116
117
|
arg_gens = cli_args.GenOptions(arg_out, args)
|
|
117
118
|
with get_loader(arg_gens, args) as loader:
|
|
118
119
|
if not loader.devices:
|
|
@@ -190,7 +191,7 @@ def gen(args: cli_args.ShowGenOptions):
|
|
|
190
191
|
output_driver = output_driver_connector.get()
|
|
191
192
|
if args.dest is None:
|
|
192
193
|
text_mapping = {item[0]: item[1] for item in out}
|
|
193
|
-
out = [(",".join(key), value, False) for key, value in collapse_texts(text_mapping).items()]
|
|
194
|
+
out = [(", ".join(key), value, False) for key, value in collapse_texts(text_mapping).items()]
|
|
194
195
|
|
|
195
196
|
out.extend(output_driver.format_fails(fail, loader.device_fqdns))
|
|
196
197
|
total = len(success) + len(fail)
|
|
@@ -203,13 +204,19 @@ def gen(args: cli_args.ShowGenOptions):
|
|
|
203
204
|
def diff(args: cli_args.ShowDiffOptions):
|
|
204
205
|
""" Generate configuration for devices and show a diff with current configuration using the rulebook """
|
|
205
206
|
with get_loader(args, args) as loader:
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
207
|
+
success, fail = api.diff(args, loader, loader.device_ids)
|
|
208
|
+
|
|
209
|
+
out = list(gen_sort_diff({loader.get_device(k): v for k, v in success.items()}, args))
|
|
210
|
+
output_driver = output_driver_connector.get()
|
|
211
|
+
if args.dest is None:
|
|
212
|
+
text_mapping = {item[0]: item[1] for item in out}
|
|
213
|
+
out = [(", ".join(key), value, False) for key, value in collapse_texts(text_mapping).items()]
|
|
214
|
+
out.extend(output_driver.format_fails(fail, loader.device_fqdns))
|
|
215
|
+
|
|
216
|
+
if total := len(success) + len(fail):
|
|
217
|
+
output_driver.write_output(args, out, total)
|
|
218
|
+
else:
|
|
219
|
+
get_logger().error("No devices found for %s", args.query)
|
|
213
220
|
|
|
214
221
|
|
|
215
222
|
@subcommand(cli_args.ShowPatchOptions)
|
annet/cli_args.py
CHANGED
annet/deploy.py
CHANGED
|
@@ -49,8 +49,8 @@ class ProgressBar(abc.ABC):
|
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
class DeployResult(_DeployResultBase): # noqa: E302
|
|
52
|
-
def add_results(self, results: dict[str,
|
|
53
|
-
for hostname,
|
|
52
|
+
def add_results(self, results: dict[str, Exception]) -> None:
|
|
53
|
+
for hostname, excs in results.items():
|
|
54
54
|
self.hostnames.append(hostname)
|
|
55
55
|
self.results[hostname] = excs
|
|
56
56
|
self.durations[hostname] = 0.0
|
annet/diff.py
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import abc
|
|
2
2
|
import difflib
|
|
3
|
+
import os
|
|
3
4
|
import re
|
|
4
5
|
from itertools import groupby
|
|
5
6
|
from pathlib import Path
|
|
6
|
-
from typing import Generator, List, Mapping, Tuple, Union
|
|
7
|
+
from typing import Any, Dict, Generator, List, Mapping, Optional, Protocol, Tuple, Union
|
|
7
8
|
|
|
9
|
+
from annet import cli_args, filtering, patching, rulebook, tabparser
|
|
10
|
+
from annet.annlib import jsontools
|
|
8
11
|
from annet.annlib.diff import ( # pylint: disable=unused-import
|
|
9
12
|
colorize_line,
|
|
10
13
|
diff_cmp,
|
|
@@ -13,23 +16,113 @@ from annet.annlib.diff import ( # pylint: disable=unused-import
|
|
|
13
16
|
resort_diff,
|
|
14
17
|
)
|
|
15
18
|
from annet.annlib.netdev.views.hardware import HardwareView
|
|
16
|
-
from annet.annlib.output import format_file_diff
|
|
17
|
-
|
|
18
|
-
from annet import patching, rulebook, tabparser, hardware
|
|
19
|
+
from annet.annlib.output import LABEL_NEW_PREFIX, format_file_diff
|
|
19
20
|
from annet.cli_args import ShowDiffOptions
|
|
20
21
|
from annet.connectors import CachedConnector
|
|
21
22
|
from annet.output import output_driver_connector
|
|
22
23
|
from annet.storage import Device
|
|
23
24
|
from annet.tabparser import make_formatter
|
|
24
|
-
from annet.types import Diff, PCDiff
|
|
25
|
+
from annet.types import Diff, PCDiff, PCDiffFile
|
|
26
|
+
|
|
27
|
+
from .gen import Loader, old_new
|
|
28
|
+
|
|
25
29
|
|
|
30
|
+
def _diff_files(hw, old_files, new_files):
|
|
31
|
+
ret = {}
|
|
32
|
+
differ = file_differ_connector.get()
|
|
33
|
+
for (path, (new_text, reload_data)) in new_files.items():
|
|
34
|
+
old_text = old_files.get(path)
|
|
35
|
+
is_new = old_text is None
|
|
36
|
+
diff_lines = differ.diff_file(hw, path, old_text, new_text)
|
|
37
|
+
ret[path] = (diff_lines, reload_data, is_new)
|
|
38
|
+
return ret
|
|
26
39
|
|
|
27
|
-
|
|
40
|
+
|
|
41
|
+
def pc_diff(hw, hostname: str, old_files: Dict[str, str], new_files: Dict[str, str]) -> Generator[
|
|
42
|
+
PCDiffFile, None, None]:
|
|
43
|
+
sorted_lines = sorted(_diff_files(hw, old_files, new_files).items())
|
|
44
|
+
for (path, (diff_lines, _reload_data, is_new)) in sorted_lines:
|
|
45
|
+
if not diff_lines:
|
|
46
|
+
continue
|
|
47
|
+
label = hostname + os.sep + path
|
|
48
|
+
if is_new:
|
|
49
|
+
label = LABEL_NEW_PREFIX + label
|
|
50
|
+
yield PCDiffFile(label=label, diff_lines=diff_lines)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def json_fragment_diff(
|
|
54
|
+
hw,
|
|
55
|
+
hostname: str,
|
|
56
|
+
old_files: Dict[str, Any],
|
|
57
|
+
new_files: Dict[str, Tuple[Any, Optional[str]]],
|
|
58
|
+
) -> Generator[PCDiffFile, None, None]:
|
|
59
|
+
def jsonify_multi(files):
|
|
60
|
+
return {
|
|
61
|
+
path: jsontools.format_json(cfg)
|
|
62
|
+
for path, cfg in files.items()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
def jsonify_multi_with_cmd(files):
|
|
66
|
+
ret = {}
|
|
67
|
+
for path, cfg_reload_cmd in files.items():
|
|
68
|
+
cfg, reload_cmd = cfg_reload_cmd
|
|
69
|
+
ret[path] = (jsontools.format_json(cfg), reload_cmd)
|
|
70
|
+
return ret
|
|
71
|
+
|
|
72
|
+
jold, jnew = jsonify_multi(old_files), jsonify_multi_with_cmd(new_files)
|
|
73
|
+
return pc_diff(hw, hostname, jold, jnew)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def worker(
|
|
77
|
+
device_id,
|
|
78
|
+
args: cli_args.DiffOptions,
|
|
79
|
+
stdin,
|
|
80
|
+
loader: Loader,
|
|
81
|
+
filterer: filtering.Filterer,
|
|
82
|
+
) -> Union[Diff, PCDiff, None]:
|
|
83
|
+
for res in old_new(
|
|
84
|
+
args,
|
|
85
|
+
config=args.config,
|
|
86
|
+
loader=loader,
|
|
87
|
+
no_new=args.clear,
|
|
88
|
+
do_files_download=True,
|
|
89
|
+
device_ids=[device_id],
|
|
90
|
+
filterer=filterer,
|
|
91
|
+
stdin=stdin,
|
|
92
|
+
):
|
|
93
|
+
old = res.get_old(args.acl_safe)
|
|
94
|
+
new = res.get_new(args.acl_safe)
|
|
95
|
+
device = res.device
|
|
96
|
+
acl_rules = res.get_acl_rules(args.acl_safe)
|
|
97
|
+
new_files = res.get_new_files(args.acl_safe)
|
|
98
|
+
new_json_fragment_files = res.get_new_file_fragments(args.acl_safe)
|
|
99
|
+
|
|
100
|
+
pc_diff_files = []
|
|
101
|
+
if res.old_files or new_files:
|
|
102
|
+
pc_diff_files.extend(pc_diff(res.device.hw, device.hostname, res.old_files, new_files))
|
|
103
|
+
if res.old_json_fragment_files or new_json_fragment_files:
|
|
104
|
+
pc_diff_files.extend(json_fragment_diff(res.device.hw, device.hostname, res.old_json_fragment_files,
|
|
105
|
+
new_json_fragment_files))
|
|
106
|
+
|
|
107
|
+
if pc_diff_files:
|
|
108
|
+
pc_diff_files.sort(key=lambda f: f.label)
|
|
109
|
+
return PCDiff(hostname=device.hostname, diff_files=pc_diff_files)
|
|
110
|
+
elif old is not None:
|
|
111
|
+
orderer = patching.Orderer.from_hw(device.hw)
|
|
112
|
+
rb = rulebook.get_rulebook(device.hw)
|
|
113
|
+
diff_tree = patching.make_diff(
|
|
114
|
+
old,
|
|
115
|
+
orderer.order_config(new),
|
|
116
|
+
rb,
|
|
117
|
+
[acl_rules, res.filter_acl_rules],
|
|
118
|
+
)
|
|
119
|
+
diff_tree = patching.strip_unchanged(diff_tree)
|
|
120
|
+
return diff_tree
|
|
28
121
|
|
|
29
122
|
|
|
30
123
|
def gen_sort_diff(
|
|
31
124
|
diffs: Mapping[Device, Union[Diff, PCDiff]], args: ShowDiffOptions
|
|
32
|
-
) -> Generator[Tuple[str, Generator[str, None, None], bool], None, None]:
|
|
125
|
+
) -> Generator[Tuple[str, Generator[str, None, None] | str, bool], None, None]:
|
|
33
126
|
"""
|
|
34
127
|
Возвращает осортированный дифф, совместимый с write_output
|
|
35
128
|
:param diffs: Маппинг устройства в дифф
|
|
@@ -71,7 +164,7 @@ def _make_text_diff(device: Device, diff: Diff) -> List[str]:
|
|
|
71
164
|
return res
|
|
72
165
|
|
|
73
166
|
|
|
74
|
-
def collapse_diffs(diffs: Mapping[Device, Diff]) ->
|
|
167
|
+
def collapse_diffs(diffs: Mapping[Device, Diff]) -> Dict[Tuple[Device, ...], Diff]:
|
|
75
168
|
"""
|
|
76
169
|
Группировка диффов.
|
|
77
170
|
:param diffs:
|
|
@@ -128,7 +221,7 @@ class FrrFileDiffer(UnifiedFileDiffer):
|
|
|
128
221
|
return self._diff_frr_conf(hw, old, new)
|
|
129
222
|
return super().diff_file(hw, path, old, new)
|
|
130
223
|
|
|
131
|
-
def _diff_frr_conf(self,
|
|
224
|
+
def _diff_frr_conf(self, hw: HardwareView, old_text: str | None, new_text: str | None) -> list[str]:
|
|
132
225
|
"""Calculate the differences for frr.conf files."""
|
|
133
226
|
indent = " "
|
|
134
227
|
rb = rulebook.rulebook_provider_connector.get()
|
|
@@ -2,12 +2,12 @@ annet/__init__.py,sha256=0OKkFkqog8As7B6ApdpKQkrEAcEELUREWp82D8WvGA8,1846
|
|
|
2
2
|
annet/annet.py,sha256=8Hc-n0S6d-YhcMpMiMET_SsYKfHFJeCA_E2gKgzK-2Y,790
|
|
3
3
|
annet/argparse.py,sha256=v1MfhjR0B8qahza0WinmXClpR8UiDFhmwDDWtNroJPA,12855
|
|
4
4
|
annet/bgp_models.py,sha256=oibTSdipNkGL4t8Xn94bhyKHMOtwbPBqmYaAy4FmTxQ,12361
|
|
5
|
-
annet/cli.py,sha256=
|
|
6
|
-
annet/cli_args.py,sha256=
|
|
5
|
+
annet/cli.py,sha256=shq3hHzrTxFL3x1_zTOR43QHo0JYs8QSwyOvGtL86Co,12733
|
|
6
|
+
annet/cli_args.py,sha256=jzMKRezWe_87k7VBNzgwPjWGMROJksbgrlX-GDd6oQs,13533
|
|
7
7
|
annet/connectors.py,sha256=aoiDVLPizx8CW2p8SAwGCzyO_WW8H9xc2aujbGC4bDg,4882
|
|
8
|
-
annet/deploy.py,sha256=
|
|
8
|
+
annet/deploy.py,sha256=JCcJ2hUmUsaOSrcxFuW8SlN0ubXSnHQ7H_nP_tx-PgE,7698
|
|
9
9
|
annet/deploy_ui.py,sha256=KcP1g_c1HSA3n5qFxbGHd8t_arL4_xJV46PFO-7FLg8,28650
|
|
10
|
-
annet/diff.py,sha256=
|
|
10
|
+
annet/diff.py,sha256=vz51az7RrXdYXsPbNMi9Y2awbjNRPQSFl6zzvE36Kx4,9441
|
|
11
11
|
annet/executor.py,sha256=lcKI-EbYqeCiBNpL729kSltduzxbAzOkQ1L_QK7tNv8,5112
|
|
12
12
|
annet/filtering.py,sha256=ZtqxPsKdV9reZoRxtQyBg22BqyMqd-2SotYcxZ-68AQ,903
|
|
13
13
|
annet/gen.py,sha256=m76bL6rVbusNV_uVHrHnA3D7TUvvLtckXx7hlr5HGA0,31897
|
|
@@ -68,7 +68,7 @@ annet/annlib/rbparser/platform.py,sha256=65-r9mboRA3gaz9DRkSwPCdCRQneItqxppdMB6z
|
|
|
68
68
|
annet/annlib/rbparser/syntax.py,sha256=iZ7Y-4QQBw4L3UtjEh54qisiRDhobl7HZxFNdP8mi54,3577
|
|
69
69
|
annet/annlib/rulebook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
70
70
|
annet/annlib/rulebook/common.py,sha256=hqwmmNofm5q2f-hV2usMY-IPMeiANLth28tZcRBYJTw,16640
|
|
71
|
-
annet/api/__init__.py,sha256=
|
|
71
|
+
annet/api/__init__.py,sha256=BnFu1BbGZVgiT4GKa5x8reIHV40hl8UGR4vtwD8VREI,32992
|
|
72
72
|
annet/configs/context.yml,sha256=RVLrKLIHpCty7AGwOnmqf7Uu0iZQCn-AjYhophDJer8,259
|
|
73
73
|
annet/configs/logging.yaml,sha256=EUagfir99QqA73Scc3k7sfQccbU3E1SvEQdyhLFtCl4,997
|
|
74
74
|
annet/generators/__init__.py,sha256=rVHHDTPKHPZsml1eNEAj3o-8RweFTN8J7LX3tKMXdIY,16402
|
|
@@ -178,10 +178,10 @@ annet_generators/rpl_example/generator.py,sha256=zndIGfV4ZlTxPgAGYs7bMQvTc_tYScO
|
|
|
178
178
|
annet_generators/rpl_example/items.py,sha256=d99HSXDHFjZq511EvGhIqRTWK3F4ZsCWfdUqFYQcyhE,772
|
|
179
179
|
annet_generators/rpl_example/mesh.py,sha256=z_WgfDZZ4xnyh3cSf75igyH09hGvtexEVwy1gCD_DzA,288
|
|
180
180
|
annet_generators/rpl_example/route_policy.py,sha256=z6nPb0VDeQtKD1NIg9sFvmUxBD5tVs2frfNIuKdM-5c,2318
|
|
181
|
-
annet-2.
|
|
182
|
-
annet-2.
|
|
183
|
-
annet-2.
|
|
184
|
-
annet-2.
|
|
185
|
-
annet-2.
|
|
186
|
-
annet-2.
|
|
187
|
-
annet-2.
|
|
181
|
+
annet-2.3.1.dist-info/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
|
|
182
|
+
annet-2.3.1.dist-info/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
|
|
183
|
+
annet-2.3.1.dist-info/METADATA,sha256=U_8hFGlPprmgg8gwixbZkAinKUK9VW--rWrkVGPNiC0,793
|
|
184
|
+
annet-2.3.1.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
|
|
185
|
+
annet-2.3.1.dist-info/entry_points.txt,sha256=5lIaDGlGi3l6QQ2ry2jZaqViP5Lvt8AmsegdD0Uznck,192
|
|
186
|
+
annet-2.3.1.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
|
|
187
|
+
annet-2.3.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|