annet 3.4.1__py3-none-any.whl → 3.5.0__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/__init__.py +1 -1
- annet/adapters/netbox/common/models.py +14 -6
- annet/annlib/command.py +2 -1
- annet/annlib/filter_acl.py +2 -1
- annet/annlib/patching.py +1 -1
- annet/annlib/rbparser/syntax.py +2 -1
- annet/api/__init__.py +2 -3
- annet/bgp_models.py +9 -1
- annet/deploy_ui.py +2 -1
- annet/diff.py +2 -2
- annet/executor.py +1 -1
- annet/gen.py +2 -1
- annet/generators/__init__.py +2 -2
- annet/generators/base.py +2 -1
- annet/implicit.py +2 -2
- annet/mesh/device_models.py +6 -0
- annet/mesh/executor.py +10 -18
- annet/mesh/models_converter.py +12 -2
- annet/mesh/peer_models.py +1 -5
- annet/parallel.py +0 -6
- annet/rpl/match_builder.py +1 -1
- annet/rpl_generators/aspath.py +16 -0
- annet/rpl_generators/community.py +37 -3
- annet/rpl_generators/policy.py +340 -5
- annet/rpl_generators/prefix_lists.py +51 -1
- annet/rpl_generators/rd.py +16 -0
- annet/rulebook/__init__.py +1 -1
- annet/rulebook/b4com/iface.py +5 -1
- annet/rulebook/juniper/__init__.py +1 -1
- annet/rulebook/texts/b4com.order +1 -0
- annet/rulebook/texts/b4com.rul +2 -1
- annet/rulebook/texts/cisco.order +2 -0
- annet/rulebook/texts/huawei.rul +5 -0
- annet/rulebook/texts/iosxr.order +21 -4
- annet/rulebook/texts/juniper.rul +5 -0
- annet/vendors/base.py +1 -1
- annet/vendors/library/arista.py +1 -1
- annet/vendors/library/aruba.py +1 -1
- annet/vendors/library/b4com.py +1 -1
- annet/vendors/library/cisco.py +1 -1
- annet/vendors/library/h3c.py +1 -1
- annet/vendors/library/huawei.py +1 -1
- annet/vendors/library/iosxr.py +1 -1
- annet/vendors/library/juniper.py +1 -1
- annet/vendors/library/nexus.py +1 -1
- annet/vendors/library/nokia.py +1 -1
- annet/vendors/library/optixtrans.py +1 -1
- annet/vendors/library/pc.py +1 -1
- annet/vendors/library/ribbon.py +1 -1
- annet/vendors/library/routeros.py +1 -1
- annet/vendors/registry.py +1 -1
- annet/{annlib → vendors}/tabparser.py +3 -3
- {annet-3.4.1.dist-info → annet-3.5.0.dist-info}/METADATA +1 -1
- {annet-3.4.1.dist-info → annet-3.5.0.dist-info}/RECORD +60 -60
- {annet-3.4.1.dist-info → annet-3.5.0.dist-info}/WHEEL +1 -1
- annet_generators/rpl_example/items.py +13 -5
- {annet-3.4.1.dist-info → annet-3.5.0.dist-info}/entry_points.txt +0 -0
- {annet-3.4.1.dist-info → annet-3.5.0.dist-info}/licenses/AUTHORS +0 -0
- {annet-3.4.1.dist-info → annet-3.5.0.dist-info}/licenses/LICENSE +0 -0
- {annet-3.4.1.dist-info → annet-3.5.0.dist-info}/top_level.txt +0 -0
annet/__init__.py
CHANGED
|
@@ -11,7 +11,7 @@ from contextlog import patch_logging, patch_threading
|
|
|
11
11
|
from valkit.python import valid_logging_level
|
|
12
12
|
|
|
13
13
|
import annet.argparse
|
|
14
|
-
from annet.
|
|
14
|
+
from annet.vendors import tabparser # pylint: disable=unused-import
|
|
15
15
|
from annet.annlib.errors import ( # pylint: disable=wrong-import-position
|
|
16
16
|
DeployCancelled,
|
|
17
17
|
ExecError,
|
|
@@ -101,7 +101,7 @@ class IpAddress(DumpableView, Generic[_PrefixT]):
|
|
|
101
101
|
|
|
102
102
|
@dataclass
|
|
103
103
|
class InterfaceConnectedEndpoint(Entity):
|
|
104
|
-
device: Entity
|
|
104
|
+
device: Entity | None
|
|
105
105
|
|
|
106
106
|
|
|
107
107
|
@dataclass
|
|
@@ -151,14 +151,22 @@ class Interface(Entity, Generic[_IpAddressT]):
|
|
|
151
151
|
speed: int | None = None
|
|
152
152
|
|
|
153
153
|
def add_addr(self, address_mask: str, vrf: str | None) -> None:
|
|
154
|
+
addr = ip_interface(address_mask)
|
|
155
|
+
|
|
156
|
+
# when comparing ip addressess
|
|
157
|
+
# we dont care about the vrf of an addr
|
|
158
|
+
# because the actual vrf will be
|
|
159
|
+
# determined by an interface's vrf
|
|
160
|
+
# and there can be only one
|
|
161
|
+
#
|
|
162
|
+
# also we dont care about a mask
|
|
163
|
+
# because no device will allow
|
|
164
|
+
# the same addr with multiple masks
|
|
154
165
|
for existing_addr in self.ip_addresses:
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
(existing_addr.vrf is not None and existing_addr.vrf.name == vrf)
|
|
158
|
-
):
|
|
166
|
+
existing = ip_interface(existing_addr.address)
|
|
167
|
+
if existing.ip == addr.ip:
|
|
159
168
|
return
|
|
160
169
|
|
|
161
|
-
addr = ip_interface(address_mask)
|
|
162
170
|
vrf_obj = vrf_object(vrf)
|
|
163
171
|
if isinstance(addr, IPv6Interface):
|
|
164
172
|
family = IpFamily(value=6, label="IPv6")
|
annet/annlib/command.py
CHANGED
|
@@ -19,7 +19,8 @@ class Command:
|
|
|
19
19
|
cmd: str
|
|
20
20
|
questions: Optional[List[Question]] = None
|
|
21
21
|
exc_handler: Optional[List[Question]] = None
|
|
22
|
-
timeout: Optional[int] = None
|
|
22
|
+
timeout: Optional[int] = None # total timeout
|
|
23
|
+
read_timeout: Optional[int] = None # timeout between consecutive reads
|
|
23
24
|
suppress_nonzero: bool = False
|
|
24
25
|
suppress_eof: bool = False
|
|
25
26
|
|
annet/annlib/filter_acl.py
CHANGED
annet/annlib/patching.py
CHANGED
|
@@ -17,7 +17,7 @@ from .rbparser import platform
|
|
|
17
17
|
from .rbparser.ordering import compile_ordering_text
|
|
18
18
|
from .rulebook.common import call_diff_logic
|
|
19
19
|
from .rulebook.common import default as common_default
|
|
20
|
-
from .tabparser import CommonFormatter
|
|
20
|
+
from annet.vendors.tabparser import CommonFormatter
|
|
21
21
|
from .types import Diff, Op
|
|
22
22
|
from ..vendors import registry_connector
|
|
23
23
|
|
annet/annlib/rbparser/syntax.py
CHANGED
annet/api/__init__.py
CHANGED
|
@@ -31,7 +31,8 @@ from annet import cli_args
|
|
|
31
31
|
from annet import diff as ann_diff
|
|
32
32
|
from annet import filtering
|
|
33
33
|
from annet import gen as ann_gen
|
|
34
|
-
from annet import patching, rulebook,
|
|
34
|
+
from annet import patching, rulebook, tracing
|
|
35
|
+
from annet.vendors import tabparser
|
|
35
36
|
from annet.annlib import jsontools
|
|
36
37
|
from annet.annlib.netdev.views.hardware import HardwareView
|
|
37
38
|
from annet.annlib.types import GeneratorType
|
|
@@ -188,8 +189,6 @@ def _print_pre_as_diff(pre, show_rules, indent, file=None, _level=0):
|
|
|
188
189
|
(Op.AFFECTED, colorama.Fore.CYAN + " "),
|
|
189
190
|
]:
|
|
190
191
|
items = content["items"].items()
|
|
191
|
-
if not content["attrs"]["multiline"]:
|
|
192
|
-
items = sorted(items, key=itemgetter(0))
|
|
193
192
|
for (_, diff) in items: # pylint: disable=redefined-outer-name
|
|
194
193
|
if show_rules and not rule_printed and not raw_rule == "__MULTILINE_BODY__":
|
|
195
194
|
print("%s%s# %s%s%s" % (colorama.Style.BRIGHT, colorama.Fore.BLACK, (indent * _level),
|
annet/bgp_models.py
CHANGED
|
@@ -139,7 +139,15 @@ class BFDTimers:
|
|
|
139
139
|
multiplier: int = 4
|
|
140
140
|
|
|
141
141
|
|
|
142
|
-
Family = Literal[
|
|
142
|
+
Family = Literal[
|
|
143
|
+
"ipv4_unicast",
|
|
144
|
+
"ipv6_unicast",
|
|
145
|
+
"ipv4_vpn_unicast",
|
|
146
|
+
"ipv6_vpn_unicast",
|
|
147
|
+
"ipv4_labeled_unicast",
|
|
148
|
+
"ipv6_labeled_unicast",
|
|
149
|
+
"l2vpn_evpn",
|
|
150
|
+
]
|
|
143
151
|
|
|
144
152
|
|
|
145
153
|
@dataclass(frozen=True)
|
annet/deploy_ui.py
CHANGED
|
@@ -5,6 +5,7 @@ import os
|
|
|
5
5
|
import sys
|
|
6
6
|
import math
|
|
7
7
|
import asyncio
|
|
8
|
+
import platform
|
|
8
9
|
import textwrap
|
|
9
10
|
import time
|
|
10
11
|
import traceback
|
|
@@ -23,7 +24,7 @@ try:
|
|
|
23
24
|
except ImportError:
|
|
24
25
|
curses = None
|
|
25
26
|
|
|
26
|
-
uname =
|
|
27
|
+
uname = platform.uname()[0]
|
|
27
28
|
NCURSES_SIZE_T = 2 ** 15 - 1
|
|
28
29
|
MIN_CONTENT_HEIGHT = 20
|
|
29
30
|
|
annet/diff.py
CHANGED
|
@@ -6,7 +6,7 @@ from itertools import groupby
|
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from typing import Any, Dict, Generator, List, Mapping, Optional, Protocol, Tuple, Union
|
|
8
8
|
|
|
9
|
-
from annet import cli_args, filtering, patching, rulebook
|
|
9
|
+
from annet import cli_args, filtering, patching, rulebook
|
|
10
10
|
from annet.annlib import jsontools
|
|
11
11
|
from annet.annlib.diff import ( # pylint: disable=unused-import
|
|
12
12
|
colorize_line,
|
|
@@ -22,7 +22,7 @@ from annet.connectors import CachedConnector
|
|
|
22
22
|
from annet.output import output_driver_connector
|
|
23
23
|
from annet.storage import Device
|
|
24
24
|
from annet.types import Diff, PCDiff, PCDiffFile
|
|
25
|
-
from annet.vendors import registry_connector
|
|
25
|
+
from annet.vendors import registry_connector, tabparser
|
|
26
26
|
|
|
27
27
|
from .gen import Loader, old_new
|
|
28
28
|
|
annet/executor.py
CHANGED
annet/gen.py
CHANGED
|
@@ -25,7 +25,8 @@ from typing import (
|
|
|
25
25
|
import tabulate
|
|
26
26
|
from contextlog import get_logger
|
|
27
27
|
|
|
28
|
-
from annet import generators, implicit, patching,
|
|
28
|
+
from annet import generators, implicit, patching, tracing
|
|
29
|
+
from annet.vendors import tabparser
|
|
29
30
|
from annet.annlib import jsontools
|
|
30
31
|
from annet.annlib.rbparser.acl import compile_acl_text
|
|
31
32
|
from annet.cli_args import DeployOptions, GenOptions, ShowGenOptions
|
annet/generators/__init__.py
CHANGED
|
@@ -11,7 +11,7 @@ from typing import FrozenSet, Iterable, List, Optional, Union
|
|
|
11
11
|
|
|
12
12
|
from contextlog import get_logger
|
|
13
13
|
|
|
14
|
-
from annet import patching,
|
|
14
|
+
from annet import patching, tracing
|
|
15
15
|
from annet.annlib.rbparser.acl import compile_acl_text
|
|
16
16
|
from annet.cli_args import GenSelectOptions, ShowGeneratorsOptions
|
|
17
17
|
from annet.lib import get_context
|
|
@@ -24,7 +24,7 @@ from annet.types import (
|
|
|
24
24
|
GeneratorPartialRunArgs,
|
|
25
25
|
GeneratorResult,
|
|
26
26
|
)
|
|
27
|
-
from annet.vendors import registry_connector
|
|
27
|
+
from annet.vendors import registry_connector, tabparser
|
|
28
28
|
|
|
29
29
|
from .base import BaseGenerator
|
|
30
30
|
from .base import ParamsList as ParamsList
|
annet/generators/base.py
CHANGED
|
@@ -5,7 +5,8 @@ import contextlib
|
|
|
5
5
|
import textwrap
|
|
6
6
|
from typing import Union, List
|
|
7
7
|
|
|
8
|
-
from annet import
|
|
8
|
+
from annet import tracing
|
|
9
|
+
from annet.vendors import tabparser
|
|
9
10
|
from annet.tracing import tracing_connector
|
|
10
11
|
from .exceptions import InvalidValueFromGenerator
|
|
11
12
|
|
annet/implicit.py
CHANGED
|
@@ -133,9 +133,9 @@ def _implicit_tree(device):
|
|
|
133
133
|
no shutdown
|
|
134
134
|
"""
|
|
135
135
|
elif device.hw.Cisco:
|
|
136
|
-
# C2900/C3500/C3600 does not support the MTU on a per-interface basis
|
|
136
|
+
# C2900/C3500/C3600/AIR does not support the MTU on a per-interface basis
|
|
137
137
|
if device.hw.Cisco.Catalyst.C2900 or device.hw.Cisco.Catalyst.C3500 \
|
|
138
|
-
or device.hw.Cisco.Catalyst.C3600:
|
|
138
|
+
or device.hw.Cisco.Catalyst.C3600 or device.hw.Cisco.AIR:
|
|
139
139
|
text += r"""
|
|
140
140
|
!interface */\S*Ethernet\S+/
|
|
141
141
|
no shutdown
|
annet/mesh/device_models.py
CHANGED
|
@@ -40,12 +40,16 @@ class _FamiliesMixin:
|
|
|
40
40
|
def __init__(self, **kwargs):
|
|
41
41
|
kwargs.setdefault("ipv4_unicast", FamilyOptions(family="ipv4_unicast"))
|
|
42
42
|
kwargs.setdefault("ipv6_unicast", FamilyOptions(family="ipv6_unicast"))
|
|
43
|
+
kwargs.setdefault("ipv4_vpn_unicast", FamilyOptions(family="ipv4_vpn_unicast"))
|
|
44
|
+
kwargs.setdefault("ipv6_vpn_unicast", FamilyOptions(family="ipv6_vpn_unicast"))
|
|
43
45
|
kwargs.setdefault("ipv4_labeled_unicast", FamilyOptions(family="ipv4_labeled_unicast"))
|
|
44
46
|
kwargs.setdefault("ipv6_labeled_unicast", FamilyOptions(family="ipv6_labeled_unicast"))
|
|
45
47
|
kwargs.setdefault("l2vpn_evpn", FamilyOptions(family="l2vpn_evpn"))
|
|
46
48
|
super().__init__(**kwargs)
|
|
47
49
|
ipv4_unicast: Annotated[FamilyOptions, Merge()]
|
|
48
50
|
ipv6_unicast: Annotated[FamilyOptions, Merge()]
|
|
51
|
+
ipv4_vpn_unicast: Annotated[FamilyOptions, Merge()]
|
|
52
|
+
ipv6_vpn_unicast: Annotated[FamilyOptions, Merge()]
|
|
49
53
|
ipv4_labeled_unicast: Annotated[FamilyOptions, Merge()]
|
|
50
54
|
ipv6_labeled_unicast: Annotated[FamilyOptions, Merge()]
|
|
51
55
|
l2vpn_evpn: Annotated[FamilyOptions, Merge()]
|
|
@@ -55,6 +59,8 @@ class VrfOptions(_FamiliesMixin, BaseMeshModel):
|
|
|
55
59
|
def __init__(self, vrf_name: str, **kwargs):
|
|
56
60
|
kwargs.setdefault("ipv4_unicast", FamilyOptions(family="ipv4_unicast", vrf_name=vrf_name))
|
|
57
61
|
kwargs.setdefault("ipv6_unicast", FamilyOptions(family="ipv6_unicast", vrf_name=vrf_name))
|
|
62
|
+
kwargs.setdefault("ipv4_vpn_unicast", FamilyOptions(family="ipv4_unicast", vrf_name=vrf_name))
|
|
63
|
+
kwargs.setdefault("ipv6_vpn_unicast", FamilyOptions(family="ipv6_unicast", vrf_name=vrf_name))
|
|
58
64
|
kwargs.setdefault("ipv4_labeled_unicast", FamilyOptions(family="ipv4_labeled_unicast", vrf_name=vrf_name))
|
|
59
65
|
kwargs.setdefault("ipv6_labeled_unicast", FamilyOptions(family="ipv6_labeled_unicast", vrf_name=vrf_name))
|
|
60
66
|
kwargs.setdefault("l2vpn_evpn", FamilyOptions(family="l2vpn_evpn", vrf_name=vrf_name))
|
annet/mesh/executor.py
CHANGED
|
@@ -194,7 +194,7 @@ class MeshExecutor:
|
|
|
194
194
|
for rule in self._registry.lookup_virtual(device.fqdn):
|
|
195
195
|
for order_number in rule.num:
|
|
196
196
|
handler_name = self._handler_name(rule.handler)
|
|
197
|
-
logger.debug("Running
|
|
197
|
+
logger.debug("Running virtual handler: %s", handler_name)
|
|
198
198
|
session = MeshSession()
|
|
199
199
|
peer_device = VirtualLocal(rule.match, device)
|
|
200
200
|
peer_virtual = VirtualPeer(num=order_number)
|
|
@@ -219,11 +219,6 @@ class MeshExecutor:
|
|
|
219
219
|
f"peer data for device `{device.fqdn}`:\n" + str(e)
|
|
220
220
|
) from e
|
|
221
221
|
|
|
222
|
-
if not hasattr(device_dto, "svi"):
|
|
223
|
-
raise ValueError(
|
|
224
|
-
f"Handler `{handler_name}` did not provide `svi` number. "
|
|
225
|
-
"Virtual peer must be connected to SVI interface."
|
|
226
|
-
)
|
|
227
222
|
pair = VirtualPair(local=device_dto, connected=virtual_dto)
|
|
228
223
|
virtual_peers.append(pair)
|
|
229
224
|
return virtual_peers
|
|
@@ -345,11 +340,11 @@ class MeshExecutor:
|
|
|
345
340
|
target_interface.add_addr(changes.addr, changes.vrf)
|
|
346
341
|
return target_interface.name
|
|
347
342
|
|
|
348
|
-
def
|
|
349
|
-
self, device: Device,
|
|
343
|
+
def _apply_nondirect_interface_changes(
|
|
344
|
+
self, device: Device, ifname: Optional[str], changes: InterfaceChanges,
|
|
350
345
|
) -> Optional[str]:
|
|
351
346
|
if changes.lag is not None:
|
|
352
|
-
raise ValueError("LAG creation unsupported for indirect peers")
|
|
347
|
+
raise ValueError("LAG creation unsupported for indirect and virtual peers")
|
|
353
348
|
elif changes.subif is not None:
|
|
354
349
|
target_interface = device.add_subif(ifname, changes.subif)
|
|
355
350
|
elif changes.svi is not None:
|
|
@@ -363,9 +358,6 @@ class MeshExecutor:
|
|
|
363
358
|
target_interface.add_addr(changes.addr, changes.vrf)
|
|
364
359
|
return target_interface.name
|
|
365
360
|
|
|
366
|
-
def _apply_virtual_interface_changes(self, device: Device, local: VirtualLocalDTO) -> str:
|
|
367
|
-
return device.add_svi(local.svi).name # we check if SVI configured in execute method
|
|
368
|
-
|
|
369
361
|
def execute_for(self, device: Device) -> BgpConfig:
|
|
370
362
|
all_fqdns = self._storage.resolve_all_fdnds()
|
|
371
363
|
|
|
@@ -378,23 +370,23 @@ class MeshExecutor:
|
|
|
378
370
|
device,
|
|
379
371
|
direct_pair.device,
|
|
380
372
|
direct_pair.ports,
|
|
381
|
-
to_interface_changes(direct_pair.local),
|
|
373
|
+
to_interface_changes(direct_pair.local, direct_pair.connected),
|
|
382
374
|
)
|
|
383
375
|
peers.append(self._to_bgp_peer(direct_pair, target_interface))
|
|
384
376
|
|
|
385
377
|
for virtual_pair in self._execute_virtual(device):
|
|
386
|
-
target_interface = self.
|
|
378
|
+
target_interface = self._apply_nondirect_interface_changes(
|
|
387
379
|
device,
|
|
388
|
-
virtual_pair.local,
|
|
380
|
+
getattr(virtual_pair.local, "ifname", None),
|
|
381
|
+
to_interface_changes(virtual_pair.local, virtual_pair.connected),
|
|
389
382
|
)
|
|
390
383
|
peers.append(self._virtual_to_bgp_peer(virtual_pair, target_interface))
|
|
391
384
|
|
|
392
385
|
for connected_pair in self._execute_indirect(device, all_fqdns):
|
|
393
|
-
target_interface = self.
|
|
386
|
+
target_interface = self._apply_nondirect_interface_changes(
|
|
394
387
|
device,
|
|
395
|
-
connected_pair.device,
|
|
396
388
|
getattr(connected_pair.local, "ifname", None),
|
|
397
|
-
to_interface_changes(connected_pair.local),
|
|
389
|
+
to_interface_changes(connected_pair.local, connected_pair.connected),
|
|
398
390
|
)
|
|
399
391
|
peers.append(self._to_bgp_peer(connected_pair, target_interface))
|
|
400
392
|
|
annet/mesh/models_converter.py
CHANGED
|
@@ -17,7 +17,7 @@ LocalDTO = Union[DirectPeerDTO, IndirectPeerDTO, VirtualLocalDTO]
|
|
|
17
17
|
|
|
18
18
|
@dataclass
|
|
19
19
|
class InterfaceChanges:
|
|
20
|
-
addr: str
|
|
20
|
+
addr: Optional[str] = None
|
|
21
21
|
lag: Optional[int] = None
|
|
22
22
|
lag_links_min: Optional[int] = None
|
|
23
23
|
svi: Optional[int] = None
|
|
@@ -67,7 +67,17 @@ retort = Retort(
|
|
|
67
67
|
)
|
|
68
68
|
|
|
69
69
|
to_bgp_global_options = retort.get_loader(GlobalOptions)
|
|
70
|
-
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def to_interface_changes(local: LocalDTO, peer: PeerDTO) -> InterfaceChanges:
|
|
73
|
+
return InterfaceChanges(
|
|
74
|
+
addr=getattr(local, "addr", None),
|
|
75
|
+
lag_links_min=getattr(local, "lag_links_min", None),
|
|
76
|
+
svi=getattr(local, "svi", None),
|
|
77
|
+
subif=getattr(local, "subif", None),
|
|
78
|
+
vrf=getattr(peer, "vrf", None),
|
|
79
|
+
lag=getattr(local, "lag", None),
|
|
80
|
+
)
|
|
71
81
|
|
|
72
82
|
|
|
73
83
|
def to_bgp_peer(local: LocalDTO, connected: PeerDTO, connected_hostname: str, interface: Optional[str]) -> Peer:
|
annet/mesh/peer_models.py
CHANGED
|
@@ -100,14 +100,10 @@ class IndirectPeerDTO(MeshSession, _OptionsDTO):
|
|
|
100
100
|
svi: Optional[int]
|
|
101
101
|
|
|
102
102
|
|
|
103
|
-
class VirtualLocalDTO(_OptionsDTO):
|
|
104
|
-
asnum: Union[int, str]
|
|
103
|
+
class VirtualLocalDTO(MeshSession, _OptionsDTO):
|
|
105
104
|
pod: int
|
|
106
105
|
addr: str
|
|
107
106
|
description: str
|
|
108
|
-
|
|
109
|
-
import_policy: str
|
|
110
|
-
export_policy: str
|
|
111
107
|
update_source: str
|
|
112
108
|
|
|
113
109
|
svi: int
|
annet/parallel.py
CHANGED
|
@@ -156,12 +156,6 @@ def _pool_worker(pool, index, task_queue, done_queue):
|
|
|
156
156
|
capture_output_ctx = capture_output(cap_stdout, cap_stderr)
|
|
157
157
|
|
|
158
158
|
with invoke_span_ctx as invoke_span, capture_output_ctx as _:
|
|
159
|
-
invoke_trace_id = invoke_span.get_span_context().trace_id
|
|
160
|
-
if invoke_trace_id:
|
|
161
|
-
span.set_attribute(
|
|
162
|
-
"link",
|
|
163
|
-
f"https://t.yandex-team.ru/trace/{invoke_trace_id:x}"
|
|
164
|
-
)
|
|
165
159
|
invoke_span.set_attribute("func", pool.func.__name__)
|
|
166
160
|
invoke_span.set_attribute("worker.id", worker_id)
|
|
167
161
|
if device_id:
|
annet/rpl/match_builder.py
CHANGED
|
@@ -84,7 +84,7 @@ class Checkable:
|
|
|
84
84
|
self.interface = ConditionFactory[str](MatchField.interface, ["=="])
|
|
85
85
|
self.protocol = ConditionFactory[str](MatchField.protocol, ["=="])
|
|
86
86
|
self.net_len = ConditionFactory[int](MatchField.net_len, ["==", "!="])
|
|
87
|
-
self.local_pref = ConditionFactory[int](MatchField.local_pref, ["<"])
|
|
87
|
+
self.local_pref = ConditionFactory[int](MatchField.local_pref, ["<", "==", ">=", "<=", "BETWEEN_INCLUDED"])
|
|
88
88
|
self.metric = ConditionFactory[int](MatchField.metric, ["=="])
|
|
89
89
|
self.family = ConditionFactory[int](MatchField.family, ["=="])
|
|
90
90
|
self.as_path_length = ConditionFactory[int](MatchField.as_path_length, ["==", ">=", "<=", "BETWEEN_INCLUDED"])
|
annet/rpl_generators/aspath.py
CHANGED
|
@@ -55,3 +55,19 @@ class AsPathFilterGenerator(PartialGenerator, ABC):
|
|
|
55
55
|
for as_path_filter in self.get_used_as_path_filters(device):
|
|
56
56
|
values = "_".join((x for x in as_path_filter.filters if x != ".*"))
|
|
57
57
|
yield "ip as-path access-list", as_path_filter.name, "permit", f"_{values}_"
|
|
58
|
+
|
|
59
|
+
def acl_iosxr(self, _):
|
|
60
|
+
return r"""
|
|
61
|
+
as-path-set *
|
|
62
|
+
~ %global=1
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
def run_iosxr(self, device: Any):
|
|
66
|
+
for as_path_filter in self.get_used_as_path_filters(device):
|
|
67
|
+
with self.block("as-path-set", as_path_filter.name):
|
|
68
|
+
for n, filter_item in enumerate(as_path_filter.filters):
|
|
69
|
+
if n + 1 < len(as_path_filter.filters):
|
|
70
|
+
comma = ","
|
|
71
|
+
else:
|
|
72
|
+
comma = ""
|
|
73
|
+
yield "ios-regex", f"'{filter_item}'{comma}"
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
|
-
from collections.abc import Sequence, Collection
|
|
2
|
+
from collections.abc import Sequence, Collection, Iterator
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
5
|
from annet.generators import PartialGenerator
|
|
6
|
-
from annet.rpl import
|
|
6
|
+
from annet.rpl import SingleCondition, MatchField, ThenField, RoutingPolicy, ConditionOperator
|
|
7
7
|
from .entities import (
|
|
8
8
|
CommunityList, CommunityLogic, CommunityType, arista_well_known_community, mangle_united_community_list_name,
|
|
9
9
|
)
|
|
@@ -25,7 +25,8 @@ def get_used_community_lists(
|
|
|
25
25
|
used_communities.update(condition.value)
|
|
26
26
|
for then_field in (
|
|
27
27
|
ThenField.community, ThenField.large_community,
|
|
28
|
-
ThenField.extcommunity_rt, ThenField.extcommunity_soo
|
|
28
|
+
ThenField.extcommunity_rt, ThenField.extcommunity_soo,
|
|
29
|
+
ThenField.extcommunity,
|
|
29
30
|
):
|
|
30
31
|
for action in statement.then.find_all(then_field):
|
|
31
32
|
if action.value.replaced is not None:
|
|
@@ -240,3 +241,36 @@ class CommunityListGenerator(PartialGenerator, ABC):
|
|
|
240
241
|
)
|
|
241
242
|
else:
|
|
242
243
|
raise NotImplementedError(f"Community logic {community_list.logic} is not implemented for arista")
|
|
244
|
+
|
|
245
|
+
def acl_iosxr(self, _) -> str:
|
|
246
|
+
return r"""
|
|
247
|
+
community-set *
|
|
248
|
+
~ %global=1
|
|
249
|
+
extcommunity-set *
|
|
250
|
+
~ %global=1
|
|
251
|
+
"""
|
|
252
|
+
|
|
253
|
+
def _iosxr_community_list(self, community_list: CommunityList) -> Iterator[Sequence[str]]:
|
|
254
|
+
if community_list.type is CommunityType.BASIC:
|
|
255
|
+
name = "community-set"
|
|
256
|
+
elif community_list.type is CommunityType.RT:
|
|
257
|
+
name = "extcommunity-set rt"
|
|
258
|
+
elif community_list.type is CommunityType.SOO:
|
|
259
|
+
name = "extcommunity-set soo"
|
|
260
|
+
else:
|
|
261
|
+
raise NotImplementedError(f"CommunityList type {community_list.type} not implemented for Cisco IOS XR")
|
|
262
|
+
|
|
263
|
+
with self.block(name, community_list.name):
|
|
264
|
+
for n, community in enumerate(community_list.members):
|
|
265
|
+
if n + 1 < len(community_list.members):
|
|
266
|
+
comma = ","
|
|
267
|
+
else:
|
|
268
|
+
comma = ""
|
|
269
|
+
if community_list.use_regex:
|
|
270
|
+
yield "ios-regex", f"'{community}'"
|
|
271
|
+
else:
|
|
272
|
+
yield f"{community}{comma}",
|
|
273
|
+
|
|
274
|
+
def run_iosxr(self, device):
|
|
275
|
+
for community_list in self.get_used_community_lists(device):
|
|
276
|
+
yield from self._iosxr_community_list(community_list)
|