annet 2.6.0__py3-none-any.whl → 3.0.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/adapters/file/provider.py +49 -26
- annet/adapters/netbox/common/manufacturer.py +3 -22
- annet/adapters/netbox/common/models.py +3 -2
- annet/adapters/netbox/v24/models.py +4 -3
- annet/annlib/netdev/views/hardware.py +15 -70
- annet/annlib/patching.py +7 -5
- annet/annlib/rbparser/acl.py +3 -2
- annet/annlib/rbparser/ordering.py +3 -2
- annet/api/__init__.py +2 -1
- annet/hardware.py +8 -12
- annet/rulebook/__init__.py +2 -1
- annet/rulebook/deploying.py +3 -2
- annet/rulebook/patching.py +2 -2
- annet/vendors/__init__.py +33 -0
- annet/vendors/base.py +25 -0
- annet/vendors/registry.py +84 -0
- {annet-2.6.0.dist-info → annet-3.0.0.dist-info}/METADATA +1 -1
- {annet-2.6.0.dist-info → annet-3.0.0.dist-info}/RECORD +25 -21
- annet_generators/example/__init__.py +6 -1
- annet_generators/example/hostname.py +113 -0
- {annet-2.6.0.dist-info → annet-3.0.0.dist-info}/WHEEL +0 -0
- {annet-2.6.0.dist-info → annet-3.0.0.dist-info}/entry_points.txt +0 -0
- {annet-2.6.0.dist-info → annet-3.0.0.dist-info}/licenses/AUTHORS +0 -0
- {annet-2.6.0.dist-info → annet-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {annet-2.6.0.dist-info → annet-3.0.0.dist-info}/top_level.txt +0 -0
annet/adapters/file/provider.py
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
from annet.storage import Query
|
|
1
|
+
import dataclasses
|
|
3
2
|
from dataclasses import dataclass, fields
|
|
4
|
-
from typing import
|
|
5
|
-
|
|
6
|
-
from annet.connectors import AdapterWithName
|
|
7
|
-
from annet.storage import Device as DeviceCls
|
|
8
|
-
from annet.annlib.netdev.views.hardware import vendor_to_hw, HardwareView
|
|
3
|
+
from typing import Any, Iterable, List, Optional, Sequence
|
|
4
|
+
|
|
9
5
|
import yaml
|
|
10
6
|
|
|
7
|
+
from annet.annlib.netdev.views.dump import DumpableView
|
|
8
|
+
from annet.annlib.netdev.views.hardware import HardwareView
|
|
9
|
+
from annet.connectors import AdapterWithName
|
|
10
|
+
from annet.hardware import hardware_connector
|
|
11
|
+
from annet.storage import Device as DeviceProtocol
|
|
12
|
+
from annet.storage import Query, Storage, StorageProvider
|
|
13
|
+
|
|
11
14
|
|
|
12
15
|
@dataclass
|
|
13
16
|
class Interface(DumpableView):
|
|
@@ -23,29 +26,46 @@ class Interface(DumpableView):
|
|
|
23
26
|
@dataclass
|
|
24
27
|
class DeviceStorage:
|
|
25
28
|
fqdn: str
|
|
26
|
-
|
|
29
|
+
|
|
30
|
+
vendor: Optional[str] = None
|
|
31
|
+
hw_model: Optional[str] = None
|
|
32
|
+
sw_version: Optional[str] = None
|
|
33
|
+
|
|
27
34
|
hostname: Optional[str] = None
|
|
28
35
|
serial: Optional[str] = None
|
|
29
36
|
id: Optional[str] = None
|
|
30
37
|
interfaces: Optional[list[Interface]] = None
|
|
31
38
|
storage: Optional[Storage] = None
|
|
32
39
|
|
|
40
|
+
hw: HardwareView = dataclasses.field(init=False)
|
|
41
|
+
|
|
33
42
|
def __post_init__(self):
|
|
34
43
|
if not self.id:
|
|
35
44
|
self.id = self.fqdn
|
|
36
45
|
if not self.hostname:
|
|
37
46
|
self.hostname = self.fqdn.split(".")[0]
|
|
38
|
-
|
|
39
|
-
if
|
|
40
|
-
|
|
47
|
+
|
|
48
|
+
if self.hw_model:
|
|
49
|
+
hw = HardwareView(self.hw_model, self.sw_version)
|
|
50
|
+
if self.vendor and self.vendor != hw.vendor:
|
|
51
|
+
raise Exception(f"Vendor {self.vendor} is not vendor from hw model ({hw.vendor})")
|
|
52
|
+
else:
|
|
53
|
+
self.vendor = hw.vendor
|
|
54
|
+
else:
|
|
55
|
+
hw_provider = hardware_connector.get()
|
|
56
|
+
hw: HardwareView = hw_provider.vendor_to_hw(self.vendor)
|
|
57
|
+
if not hw:
|
|
58
|
+
raise Exception("unknown vendor")
|
|
59
|
+
self.hw_model = hw.model
|
|
41
60
|
self.hw = hw
|
|
61
|
+
|
|
42
62
|
if isinstance(self.interfaces, list):
|
|
43
63
|
interfaces = []
|
|
44
64
|
for iface in self.interfaces:
|
|
45
65
|
try:
|
|
46
66
|
interfaces.append(Interface(**iface))
|
|
47
67
|
except Exception as e:
|
|
48
|
-
raise Exception("unable to parse %s as Interface %s" % (iface, e))
|
|
68
|
+
raise Exception("unable to parse %s as Interface: %s" % (iface, e))
|
|
49
69
|
self.interfaces = interfaces
|
|
50
70
|
|
|
51
71
|
def set_storage(self, storage: Storage):
|
|
@@ -53,7 +73,7 @@ class DeviceStorage:
|
|
|
53
73
|
|
|
54
74
|
|
|
55
75
|
@dataclass
|
|
56
|
-
class Device(
|
|
76
|
+
class Device(DeviceProtocol, DumpableView):
|
|
57
77
|
dev: DeviceStorage
|
|
58
78
|
|
|
59
79
|
def __hash__(self):
|
|
@@ -79,7 +99,7 @@ class Device(DeviceCls, DumpableView):
|
|
|
79
99
|
|
|
80
100
|
@property
|
|
81
101
|
def storage(self) -> Storage:
|
|
82
|
-
return self
|
|
102
|
+
return self.dev.storage
|
|
83
103
|
|
|
84
104
|
@property
|
|
85
105
|
def hw(self) -> HardwareView:
|
|
@@ -91,7 +111,11 @@ class Device(DeviceCls, DumpableView):
|
|
|
91
111
|
|
|
92
112
|
@property
|
|
93
113
|
def neighbours_ids(self):
|
|
94
|
-
|
|
114
|
+
return []
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def neighbours_fqdns(self) -> list[str]:
|
|
118
|
+
return []
|
|
95
119
|
|
|
96
120
|
def make_lag(self, lag: int, ports: Sequence[str], lag_min_links: Optional[int]) -> Interface:
|
|
97
121
|
raise NotImplementedError
|
|
@@ -105,8 +129,8 @@ class Device(DeviceCls, DumpableView):
|
|
|
105
129
|
def find_interface(self, name: str) -> Optional[Interface]:
|
|
106
130
|
raise NotImplementedError
|
|
107
131
|
|
|
108
|
-
def
|
|
109
|
-
|
|
132
|
+
def flush_perf(self):
|
|
133
|
+
pass
|
|
110
134
|
|
|
111
135
|
|
|
112
136
|
@dataclass
|
|
@@ -120,7 +144,7 @@ class Devices:
|
|
|
120
144
|
try:
|
|
121
145
|
devices.append(Device(dev=DeviceStorage(**dev)))
|
|
122
146
|
except Exception as e:
|
|
123
|
-
raise Exception("unable to parse %s as Device %s" % (dev, e))
|
|
147
|
+
raise Exception("unable to parse %s as Device: %s" % (dev, e))
|
|
124
148
|
self.devices = devices
|
|
125
149
|
|
|
126
150
|
|
|
@@ -193,12 +217,12 @@ class FS(Storage):
|
|
|
193
217
|
return [dev.fqdn for dev in result]
|
|
194
218
|
|
|
195
219
|
def make_devices(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
220
|
+
self,
|
|
221
|
+
query: Query | list,
|
|
222
|
+
preload_neighbors=False,
|
|
223
|
+
use_mesh=None,
|
|
224
|
+
preload_extra_fields=False,
|
|
225
|
+
**kwargs,
|
|
202
226
|
) -> list[Device]:
|
|
203
227
|
if isinstance(query, list):
|
|
204
228
|
query = Query.new(query)
|
|
@@ -231,8 +255,7 @@ def filter_query(devices: list[Device], query: Query) -> list[Device]:
|
|
|
231
255
|
|
|
232
256
|
def read_inventory(path: str, storage: Storage) -> Devices:
|
|
233
257
|
with open(path, "r") as f:
|
|
234
|
-
|
|
235
|
-
file_data = yaml.load(data, Loader=yaml.BaseLoader)
|
|
258
|
+
file_data = yaml.load(f, Loader=yaml.SafeLoader)
|
|
236
259
|
res = dataclass_from_dict(Devices, file_data)
|
|
237
260
|
for dev in res.devices:
|
|
238
261
|
dev.dev.set_storage(storage)
|
|
@@ -4,32 +4,13 @@ from annet.annlib.netdev.views.hardware import HardwareView
|
|
|
4
4
|
|
|
5
5
|
logger = getLogger(__name__)
|
|
6
6
|
|
|
7
|
-
_VENDORS = {
|
|
8
|
-
"cisco": "Cisco",
|
|
9
|
-
"catalyst": "Cisco Catalyst",
|
|
10
|
-
"nexus": "Cisco Nexus",
|
|
11
|
-
"iosxr": "Cisco XR",
|
|
12
|
-
"huawei": "Huawei",
|
|
13
|
-
"optixtrans": "Huawei OptiXtrans",
|
|
14
|
-
"juniper": "Juniper",
|
|
15
|
-
"arista": "Arista",
|
|
16
|
-
"pc": "PC",
|
|
17
|
-
"nokia": "Nokia",
|
|
18
|
-
"aruba": "Aruba",
|
|
19
|
-
"routeros": "RouterOS",
|
|
20
|
-
"ribbon": "Ribbon",
|
|
21
|
-
"b4com": "B4com",
|
|
22
|
-
"h3c": "H3C",
|
|
23
|
-
}
|
|
24
|
-
|
|
25
7
|
|
|
26
8
|
def get_hw(manufacturer: str, model: str, platform_name: str):
|
|
27
|
-
#
|
|
9
|
+
# By some reason Netbox calls Mellanox SN as MSN, so we fix them here
|
|
28
10
|
if manufacturer == "Mellanox" and model.startswith("MSN"):
|
|
29
11
|
model = model.replace("MSN", "SN", 1)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return hw
|
|
12
|
+
|
|
13
|
+
return HardwareView(manufacturer + " " + model, platform_name)
|
|
33
14
|
|
|
34
15
|
|
|
35
16
|
def get_breed(manufacturer: str, model: str):
|
|
@@ -5,8 +5,9 @@ from ipaddress import ip_interface, IPv6Interface
|
|
|
5
5
|
from typing import List, Optional, Any, Dict, Sequence, TypeVar, Generic
|
|
6
6
|
|
|
7
7
|
from annet.annlib.netdev.views.dump import DumpableView
|
|
8
|
-
from annet.annlib.netdev.views.hardware import HardwareView, lag_name
|
|
8
|
+
from annet.annlib.netdev.views.hardware import HardwareView, lag_name
|
|
9
9
|
from annet.storage import Storage
|
|
10
|
+
from annet.vendors import registry_connector
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
@dataclass
|
|
@@ -259,7 +260,7 @@ class NetboxDevice(Entity, Generic[_InterfaceT]):
|
|
|
259
260
|
return lag_interface
|
|
260
261
|
|
|
261
262
|
def _svi_name(self, svi: int) -> str:
|
|
262
|
-
return
|
|
263
|
+
return registry_connector.get().match(self.hw).svi_name(svi)
|
|
263
264
|
|
|
264
265
|
def add_svi(self, svi: int) -> _InterfaceT:
|
|
265
266
|
name = self._svi_name(svi)
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
from dataclasses import dataclass, field
|
|
2
2
|
from datetime import datetime, timezone
|
|
3
3
|
from ipaddress import ip_interface, IPv6Interface
|
|
4
|
-
from typing import List, Optional, Any, Dict, Sequence
|
|
4
|
+
from typing import List, Optional, Any, Dict, Sequence
|
|
5
5
|
|
|
6
6
|
from annet.annlib.netdev.views.dump import DumpableView
|
|
7
|
-
from annet.annlib.netdev.views.hardware import HardwareView, lag_name
|
|
7
|
+
from annet.annlib.netdev.views.hardware import HardwareView, lag_name
|
|
8
8
|
from annet.storage import Storage
|
|
9
|
+
from annet.vendors import registry_connector
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
@dataclass
|
|
@@ -259,7 +260,7 @@ class NetboxDevice(Entity):
|
|
|
259
260
|
return lag_interface
|
|
260
261
|
|
|
261
262
|
def _svi_name(self, svi: int) -> str:
|
|
262
|
-
return
|
|
263
|
+
return registry_connector.get().match(self.hw).svi_name(svi)
|
|
263
264
|
|
|
264
265
|
def add_svi(self, svi: int) -> Interface:
|
|
265
266
|
name = self._svi_name(svi)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import functools
|
|
1
2
|
from typing import Optional
|
|
2
3
|
|
|
3
4
|
from annet.annlib.netdev.devdb import parse_hw_model
|
|
@@ -51,20 +52,31 @@ class HardwareLeaf(DumpableView):
|
|
|
51
52
|
|
|
52
53
|
|
|
53
54
|
class HardwareView(HardwareLeaf):
|
|
54
|
-
def __init__(self, hw_model, sw_version):
|
|
55
|
-
|
|
55
|
+
def __init__(self, hw_model, sw_version: Optional[str] = None):
|
|
56
|
+
true_sequences, false_sequences = parse_hw_model(hw_model or "")
|
|
56
57
|
super().__init__((), true_sequences, false_sequences)
|
|
57
58
|
self.model = hw_model or ""
|
|
58
59
|
self._soft = sw_version or ""
|
|
59
60
|
|
|
60
61
|
@property
|
|
61
62
|
def vendor(self) -> Optional[str]:
|
|
62
|
-
|
|
63
|
+
from annet.hardware import hardware_connector
|
|
64
|
+
return hardware_connector.get().hw_to_vendor(self)
|
|
63
65
|
|
|
64
66
|
@property
|
|
65
67
|
def soft(self) -> str:
|
|
66
68
|
return self._soft
|
|
67
69
|
|
|
70
|
+
@soft.setter
|
|
71
|
+
def soft(self, value: str) -> None:
|
|
72
|
+
self._soft = value
|
|
73
|
+
|
|
74
|
+
def match(self, expr: str) -> bool:
|
|
75
|
+
dev_path = expr.split(".")
|
|
76
|
+
if dev_path and dev_path[0] == "hw":
|
|
77
|
+
dev_path = dev_path[1:]
|
|
78
|
+
return bool(functools.reduce(getattr, dev_path, self))
|
|
79
|
+
|
|
68
80
|
def __hash__(self):
|
|
69
81
|
return hash(self.model)
|
|
70
82
|
|
|
@@ -72,62 +84,6 @@ class HardwareView(HardwareLeaf):
|
|
|
72
84
|
return self.model == other.model
|
|
73
85
|
|
|
74
86
|
|
|
75
|
-
def hw_to_vendor(hw: HardwareView) -> Optional[str]:
|
|
76
|
-
if hw.Nexus:
|
|
77
|
-
return "nexus"
|
|
78
|
-
elif hw.Cisco.XR or hw.Cisco.ASR or hw.Cisco.XRV:
|
|
79
|
-
return "iosxr"
|
|
80
|
-
elif hw.Cisco:
|
|
81
|
-
return "cisco"
|
|
82
|
-
elif hw.OptiXtrans:
|
|
83
|
-
return "optixtrans"
|
|
84
|
-
elif hw.Huawei:
|
|
85
|
-
return "huawei"
|
|
86
|
-
elif hw.Juniper:
|
|
87
|
-
return "juniper"
|
|
88
|
-
elif hw.Arista:
|
|
89
|
-
return "arista"
|
|
90
|
-
elif hw.PC:
|
|
91
|
-
return "pc"
|
|
92
|
-
elif hw.Nokia:
|
|
93
|
-
return "nokia"
|
|
94
|
-
elif hw.RouterOS:
|
|
95
|
-
return "routeros"
|
|
96
|
-
elif hw.Aruba:
|
|
97
|
-
return "aruba"
|
|
98
|
-
elif hw.Ribbon:
|
|
99
|
-
return "ribbon"
|
|
100
|
-
elif hw.H3C:
|
|
101
|
-
return "h3c"
|
|
102
|
-
elif hw.B4com:
|
|
103
|
-
return "b4com"
|
|
104
|
-
return None
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def vendor_to_hw(vendor):
|
|
108
|
-
hw = HardwareView(
|
|
109
|
-
{
|
|
110
|
-
"cisco": "Cisco",
|
|
111
|
-
"catalyst": "Cisco Catalyst",
|
|
112
|
-
"nexus": "Cisco Nexus",
|
|
113
|
-
"iosxr": "Cisco XR",
|
|
114
|
-
"huawei": "Huawei",
|
|
115
|
-
"optixtrans": "Huawei OptiXtrans",
|
|
116
|
-
"juniper": "Juniper",
|
|
117
|
-
"arista": "Arista",
|
|
118
|
-
"pc": "PC",
|
|
119
|
-
"nokia": "Nokia",
|
|
120
|
-
"aruba": "Aruba",
|
|
121
|
-
"routeros": "RouterOS",
|
|
122
|
-
"ribbon": "Ribbon",
|
|
123
|
-
"h3c": "H3C",
|
|
124
|
-
"b4com": "B4com",
|
|
125
|
-
}.get(vendor.lower(), vendor),
|
|
126
|
-
None,
|
|
127
|
-
)
|
|
128
|
-
return hw
|
|
129
|
-
|
|
130
|
-
|
|
131
87
|
def lag_name(hw: HardwareView, nlagg: int) -> str:
|
|
132
88
|
if hw.Huawei:
|
|
133
89
|
return f"Eth-Trunk{nlagg}"
|
|
@@ -148,14 +104,3 @@ def lag_name(hw: HardwareView, nlagg: int) -> str:
|
|
|
148
104
|
if hw.Nokia:
|
|
149
105
|
return f"lagg-{nlagg}"
|
|
150
106
|
raise NotImplementedError(hw)
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
def svi_name(hw: HardwareView, num: int) -> str:
|
|
154
|
-
if hw.Juniper:
|
|
155
|
-
return f"irb.{num}"
|
|
156
|
-
elif hw.Huawei:
|
|
157
|
-
return f"Vlanif{num}"
|
|
158
|
-
elif hw.Arista or hw.Cisco:
|
|
159
|
-
return f"Vlan{num}"
|
|
160
|
-
else:
|
|
161
|
-
return f"vlan{num}"
|
annet/annlib/patching.py
CHANGED
|
@@ -19,6 +19,7 @@ from .rulebook.common import call_diff_logic
|
|
|
19
19
|
from .rulebook.common import default as common_default
|
|
20
20
|
from .tabparser import CommonFormatter
|
|
21
21
|
from .types import Diff, Op
|
|
22
|
+
from ..vendors import registry_connector
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
# =====
|
|
@@ -224,14 +225,15 @@ class Orderer:
|
|
|
224
225
|
return (f_order or 0), cmd_direct, odict(children), f_rule
|
|
225
226
|
|
|
226
227
|
def order_config(self, config):
|
|
227
|
-
if self.vendor not in
|
|
228
|
+
if self.vendor not in registry_connector.get():
|
|
228
229
|
return config
|
|
229
|
-
|
|
230
|
-
ordered = []
|
|
231
|
-
reverse_prefix = platform.VENDOR_REVERSES[self.vendor]
|
|
232
230
|
if not config:
|
|
233
231
|
return odict()
|
|
234
|
-
|
|
232
|
+
|
|
233
|
+
ordered = []
|
|
234
|
+
reverse_prefix = registry_connector.get()[self.vendor].reverse
|
|
235
|
+
|
|
236
|
+
for row, children in config.items():
|
|
235
237
|
cmd_direct = not row.startswith(reverse_prefix)
|
|
236
238
|
(order, direct, rb, _) = self.get_order(row, cmd_direct)
|
|
237
239
|
child_orderer = Orderer(rb, self.vendor)
|
annet/annlib/rbparser/acl.py
CHANGED
|
@@ -5,7 +5,8 @@ from typing import Any, Callable, List, Optional
|
|
|
5
5
|
from valkit import add_validator_magic
|
|
6
6
|
from valkit.common import valid_bool, valid_number, valid_string_list
|
|
7
7
|
|
|
8
|
-
from . import
|
|
8
|
+
from annet.vendors import registry_connector
|
|
9
|
+
from . import syntax
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
# =====
|
|
@@ -13,7 +14,7 @@ from . import platform, syntax
|
|
|
13
14
|
def compile_acl_text(text, vendor, allow_ignore=False):
|
|
14
15
|
return _compile_acl(
|
|
15
16
|
trees=[syntax.parse_text(text, _PARAMS_SCHEME)],
|
|
16
|
-
reverse_prefix=
|
|
17
|
+
reverse_prefix=registry_connector.get()[vendor].reverse,
|
|
17
18
|
allow_ignore=allow_ignore,
|
|
18
19
|
vendor=vendor,
|
|
19
20
|
)
|
|
@@ -4,7 +4,8 @@ from collections import OrderedDict as odict
|
|
|
4
4
|
|
|
5
5
|
from valkit.common import valid_bool, valid_string_list
|
|
6
6
|
|
|
7
|
-
from . import
|
|
7
|
+
from annet.vendors import registry_connector
|
|
8
|
+
from . import syntax
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
# =====
|
|
@@ -25,7 +26,7 @@ def compile_ordering_text(text, vendor):
|
|
|
25
26
|
"default": None,
|
|
26
27
|
}
|
|
27
28
|
}),
|
|
28
|
-
reverse_prefix=
|
|
29
|
+
reverse_prefix=registry_connector.get()[vendor].reverse,
|
|
29
30
|
)
|
|
30
31
|
|
|
31
32
|
|
annet/api/__init__.py
CHANGED
|
@@ -48,6 +48,7 @@ from annet.parallel import Parallel, TaskResult
|
|
|
48
48
|
from annet.reference import RefTracker
|
|
49
49
|
from annet.storage import Device, get_storage
|
|
50
50
|
from annet.types import Diff, ExitCode, OldNewResult, Op, PCDiff, PCDiffFile
|
|
51
|
+
from annet.vendors import registry_connector
|
|
51
52
|
|
|
52
53
|
DEFAULT_INDENT = " "
|
|
53
54
|
|
|
@@ -786,7 +787,7 @@ def guess_hw(config_text: str):
|
|
|
786
787
|
текста конфига и annet/rulebook/texts/*.rul"""
|
|
787
788
|
scores = {}
|
|
788
789
|
hw_provider = hardware_connector.get()
|
|
789
|
-
for vendor in
|
|
790
|
+
for vendor in registry_connector.get():
|
|
790
791
|
hw = hw_provider.vendor_to_hw(vendor)
|
|
791
792
|
fmtr = tabparser.make_formatter(hw)
|
|
792
793
|
rb = rulebook.get_rulebook(hw)
|
annet/hardware.py
CHANGED
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
import abc
|
|
2
2
|
from typing import Any
|
|
3
3
|
|
|
4
|
-
from annet.annlib.netdev.views.hardware import HardwareView
|
|
5
|
-
|
|
4
|
+
from annet.annlib.netdev.views.hardware import HardwareView
|
|
5
|
+
from annet.vendors import registry_connector
|
|
6
6
|
from annet.connectors import Connector
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
try:
|
|
10
|
-
from annet.annlib.netdev.views.hardware import vendor_to_hw
|
|
11
|
-
except ImportError:
|
|
12
|
-
from netdev.views.hardware import vendor_to_hw
|
|
13
|
-
|
|
14
|
-
|
|
15
9
|
class _HardwareConnector(Connector["HarwareProvider"]):
|
|
16
10
|
name = "Hardware"
|
|
17
11
|
ep_name = "hardware"
|
|
@@ -31,7 +25,7 @@ class HarwareProvider(abc.ABC):
|
|
|
31
25
|
pass
|
|
32
26
|
|
|
33
27
|
@abc.abstractmethod
|
|
34
|
-
def hw_to_vendor(self, hw: Any) -> str:
|
|
28
|
+
def hw_to_vendor(self, hw: Any) -> str | None:
|
|
35
29
|
pass
|
|
36
30
|
|
|
37
31
|
|
|
@@ -40,7 +34,9 @@ class AnnetHardwareProvider(HarwareProvider):
|
|
|
40
34
|
return HardwareView(hw_model, sw_version)
|
|
41
35
|
|
|
42
36
|
def vendor_to_hw(self, vendor: str) -> HardwareView:
|
|
43
|
-
return
|
|
37
|
+
return registry_connector.get().get(vendor.lower()).hardware
|
|
44
38
|
|
|
45
|
-
def hw_to_vendor(self, hw: HardwareView) -> str:
|
|
46
|
-
|
|
39
|
+
def hw_to_vendor(self, hw: HardwareView) -> str | None:
|
|
40
|
+
if vendor := registry_connector.get().match(hw, None):
|
|
41
|
+
return vendor.NAME
|
|
42
|
+
return None
|
annet/rulebook/__init__.py
CHANGED
|
@@ -10,6 +10,7 @@ from annet.annlib.rbparser.platform import VENDOR_REVERSES, VENDOR_ALIASES
|
|
|
10
10
|
from annet.connectors import CachedConnector
|
|
11
11
|
from annet.rulebook.deploying import compile_deploying_text
|
|
12
12
|
from annet.rulebook.patching import compile_patching_text
|
|
13
|
+
from annet.vendors import registry_connector
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class RulebookProvider(ABC):
|
|
@@ -63,7 +64,7 @@ class DefaultRulebookProvider(RulebookProvider):
|
|
|
63
64
|
if hw in self._rulebook_cache:
|
|
64
65
|
return self._rulebook_cache[hw]
|
|
65
66
|
|
|
66
|
-
assert hw.vendor in
|
|
67
|
+
assert hw.vendor in registry_connector.get(), "Unknown vendor: %s" % (hw.vendor)
|
|
67
68
|
rul_vendor_name = VENDOR_ALIASES.get(hw.vendor, hw.vendor)
|
|
68
69
|
patching = compile_patching_text(self._render_rul(rul_vendor_name + ".rul", hw), rul_vendor_name)
|
|
69
70
|
|
annet/rulebook/deploying.py
CHANGED
|
@@ -2,8 +2,9 @@ import functools
|
|
|
2
2
|
from collections import OrderedDict as odict
|
|
3
3
|
from collections import namedtuple
|
|
4
4
|
|
|
5
|
-
from annet.annlib.rbparser import
|
|
5
|
+
from annet.annlib.rbparser import syntax
|
|
6
6
|
from annet.annlib.rbparser.deploying import compile_messages
|
|
7
|
+
from annet.vendors import registry_connector
|
|
7
8
|
from valkit.common import valid_bool, valid_number, valid_string_list
|
|
8
9
|
from valkit.python import valid_object_path
|
|
9
10
|
|
|
@@ -38,7 +39,7 @@ def compile_deploying_text(text, vendor):
|
|
|
38
39
|
"default": [],
|
|
39
40
|
}
|
|
40
41
|
}),
|
|
41
|
-
reverse_prefix=
|
|
42
|
+
reverse_prefix=registry_connector.get()[vendor].reverse,
|
|
42
43
|
)
|
|
43
44
|
|
|
44
45
|
|
annet/rulebook/patching.py
CHANGED
|
@@ -3,12 +3,12 @@ import re
|
|
|
3
3
|
from collections import OrderedDict as odict
|
|
4
4
|
|
|
5
5
|
from annet.annlib.rbparser import platform, syntax
|
|
6
|
+
from annet.vendors import registry_connector
|
|
6
7
|
from valkit.common import valid_bool, valid_string_list
|
|
7
8
|
from valkit.python import valid_object_path
|
|
8
9
|
|
|
9
10
|
from .common import import_rulebook_function
|
|
10
11
|
|
|
11
|
-
|
|
12
12
|
DEFAULT_PATCH_LOGIC = "common.default"
|
|
13
13
|
ORDERED_PATCH_LOGIC = "common.ordered"
|
|
14
14
|
REWRITE_PATCH_LOGIC = "common.rewrite"
|
|
@@ -62,7 +62,7 @@ def compile_patching_text(text, vendor):
|
|
|
62
62
|
"default": False,
|
|
63
63
|
},
|
|
64
64
|
}),
|
|
65
|
-
reverse_prefix=
|
|
65
|
+
reverse_prefix=registry_connector.get()[vendor].reverse,
|
|
66
66
|
vendor=vendor,
|
|
67
67
|
)
|
|
68
68
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from typing import Callable
|
|
2
|
+
|
|
3
|
+
from annet.connectors import Connector
|
|
4
|
+
from annet.vendors.base import AbstractVendor
|
|
5
|
+
|
|
6
|
+
from .library import (
|
|
7
|
+
arista,
|
|
8
|
+
aruba,
|
|
9
|
+
b4com,
|
|
10
|
+
cisco,
|
|
11
|
+
h3c,
|
|
12
|
+
huawei,
|
|
13
|
+
iosxr,
|
|
14
|
+
juniper,
|
|
15
|
+
nexus,
|
|
16
|
+
nokia,
|
|
17
|
+
optixtrans,
|
|
18
|
+
pc,
|
|
19
|
+
ribbon,
|
|
20
|
+
routeros,
|
|
21
|
+
)
|
|
22
|
+
from .registry import Registry, registry
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class _RegistryConnector(Connector[Registry]):
|
|
26
|
+
name = "Registry"
|
|
27
|
+
ep_name = "vendors"
|
|
28
|
+
|
|
29
|
+
def _get_default(self) -> Callable[[], Registry]:
|
|
30
|
+
return lambda: registry
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
registry_connector = _RegistryConnector()
|
annet/vendors/base.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
from typing import ClassVar
|
|
3
|
+
|
|
4
|
+
from annet.annlib.netdev.views.hardware import HardwareView
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AbstractVendor(abc.ABC):
|
|
8
|
+
NAME: ClassVar[str]
|
|
9
|
+
|
|
10
|
+
@abc.abstractmethod
|
|
11
|
+
def match(self) -> list[str]:
|
|
12
|
+
raise NotImplementedError
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
@abc.abstractmethod
|
|
16
|
+
def reverse(self) -> str:
|
|
17
|
+
raise NotImplementedError
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
@abc.abstractmethod
|
|
21
|
+
def hardware(self) -> HardwareView:
|
|
22
|
+
raise NotImplementedError
|
|
23
|
+
|
|
24
|
+
def svi_name(self, num: int) -> str:
|
|
25
|
+
return f"vlan{num}"
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import enum
|
|
2
|
+
from operator import itemgetter
|
|
3
|
+
|
|
4
|
+
from annet.annlib.netdev.views.hardware import HardwareView
|
|
5
|
+
|
|
6
|
+
from .base import AbstractVendor
|
|
7
|
+
|
|
8
|
+
_SENTINEL = enum.Enum("_SENTINEL", "sentinel")
|
|
9
|
+
sentinel = _SENTINEL.sentinel
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class GenericVendor(AbstractVendor):
|
|
13
|
+
def match(self) -> list[str]:
|
|
14
|
+
return []
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def reverse(self) -> str:
|
|
18
|
+
return "-"
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def hardware(self) -> HardwareView:
|
|
22
|
+
return HardwareView("")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
GENERIC_VENDOR = GenericVendor()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Registry:
|
|
29
|
+
def __init__(self):
|
|
30
|
+
self.vendors: dict[str, AbstractVendor] = {}
|
|
31
|
+
self._matchers = {}
|
|
32
|
+
|
|
33
|
+
def register(self, cls: type[AbstractVendor]) -> type[AbstractVendor]:
|
|
34
|
+
if not cls.NAME:
|
|
35
|
+
raise RuntimeError(f"{cls.__name__} has empty NAME field")
|
|
36
|
+
if cls.NAME in self.vendors:
|
|
37
|
+
raise RuntimeError(f"{cls.__name__} with name {cls.NAME} already registered")
|
|
38
|
+
self.vendors[cls.NAME] = cls()
|
|
39
|
+
|
|
40
|
+
return cls
|
|
41
|
+
|
|
42
|
+
def __add__(self, other: "Registry"):
|
|
43
|
+
self.vendors = dict(**other.vendors, **self.vendors)
|
|
44
|
+
|
|
45
|
+
def __getitem__(self, item) -> AbstractVendor:
|
|
46
|
+
if item in self.vendors:
|
|
47
|
+
return self.vendors[item]
|
|
48
|
+
raise RuntimeError(f"Unknown vendor {item}")
|
|
49
|
+
|
|
50
|
+
def match(
|
|
51
|
+
self,
|
|
52
|
+
hw: HardwareView | str,
|
|
53
|
+
default: _SENTINEL | AbstractVendor | None = sentinel
|
|
54
|
+
) -> AbstractVendor | None:
|
|
55
|
+
if isinstance(hw, str):
|
|
56
|
+
hw = HardwareView(hw, "")
|
|
57
|
+
|
|
58
|
+
matched: list[tuple[AbstractVendor, int]] = []
|
|
59
|
+
for name, vendor in self.vendors.items():
|
|
60
|
+
for item in vendor.match():
|
|
61
|
+
if hw.match(item):
|
|
62
|
+
matched.append((vendor, item.count(".")))
|
|
63
|
+
|
|
64
|
+
if matched:
|
|
65
|
+
return next(iter(sorted(matched, key=itemgetter(1), reverse=True)))[0]
|
|
66
|
+
if default is sentinel:
|
|
67
|
+
return GENERIC_VENDOR
|
|
68
|
+
return default
|
|
69
|
+
|
|
70
|
+
def get(self, item: str, default: _SENTINEL | AbstractVendor | None = sentinel) -> AbstractVendor | None:
|
|
71
|
+
if item in self:
|
|
72
|
+
return self[item]
|
|
73
|
+
if default is sentinel:
|
|
74
|
+
return GENERIC_VENDOR
|
|
75
|
+
return default
|
|
76
|
+
|
|
77
|
+
def __contains__(self, item):
|
|
78
|
+
return item in self.vendors
|
|
79
|
+
|
|
80
|
+
def __iter__(self):
|
|
81
|
+
return iter(self.vendors)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
registry = Registry()
|
|
@@ -11,7 +11,7 @@ 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
|
|
14
|
-
annet/hardware.py,sha256=
|
|
14
|
+
annet/hardware.py,sha256=e7RWc5yPdEDT5hxNqcqWv9g9DRWIgwAieA2iT4FdPqc,1158
|
|
15
15
|
annet/implicit.py,sha256=G6EwZbrtUp089qRAwh96hminp236-1pJbeKAedoEafg,6056
|
|
16
16
|
annet/lib.py,sha256=4N4X6jCCrig5rk7Ua4AofrV9zK9jhzkBq57fLsfBJjw,4812
|
|
17
17
|
annet/output.py,sha256=se8EpyNS9f9kPOlOaAV0ht4DjzDoBr8F2UafiezLPYw,7743
|
|
@@ -28,20 +28,20 @@ annet/adapters/fetchers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
|
|
|
28
28
|
annet/adapters/fetchers/stub/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
29
|
annet/adapters/fetchers/stub/fetcher.py,sha256=FzpkIzPJBQVuNNSdXKoGzkALmIGMgo2gmGLXzYWdDYA,891
|
|
30
30
|
annet/adapters/file/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
|
-
annet/adapters/file/provider.py,sha256=
|
|
31
|
+
annet/adapters/file/provider.py,sha256=3hNt0QQg46SVymLQ4Bh9G4VNYyhnB7gV5yu5OiIJpZE,7307
|
|
32
32
|
annet/adapters/netbox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
33
|
annet/adapters/netbox/provider.py,sha256=SrxW_uBLvMTqtRiYXreL6RrZK4MpxVguF2ITnYOnVHU,2226
|
|
34
34
|
annet/adapters/netbox/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
35
|
annet/adapters/netbox/common/adapter.py,sha256=-YcO3371D8hupNXKf5f4-FdFSjTto-7VKDvz29Gid38,2016
|
|
36
36
|
annet/adapters/netbox/common/client.py,sha256=PaxHG4W9H8_uunIwMBNYkLq4eQJYoO6p6gY-ciQs7Nc,2563
|
|
37
|
-
annet/adapters/netbox/common/manufacturer.py,sha256=
|
|
38
|
-
annet/adapters/netbox/common/models.py,sha256=
|
|
37
|
+
annet/adapters/netbox/common/manufacturer.py,sha256=n1RxJSGqXilKcGSqwIc7d2jD1NCaUXG5kQcOO93WTxw,1319
|
|
38
|
+
annet/adapters/netbox/common/models.py,sha256=IS9q5ZhrDhp74sjl5exSQu6lVOrQCX_I_RRtA9uCcdg,7686
|
|
39
39
|
annet/adapters/netbox/common/query.py,sha256=kbNQSZwkjFeDArHwA8INHUauxCxYElXtNh58pZipWdo,1867
|
|
40
40
|
annet/adapters/netbox/common/status_client.py,sha256=POaqiQJ0jPcqUQH-X_fWHVnKB7TBYveNriaT0eNTlfI,769
|
|
41
41
|
annet/adapters/netbox/common/storage_base.py,sha256=3dn42CWTEZVBig4ABhy5BMQQ3YGb28InncWZoGvrgKk,8768
|
|
42
42
|
annet/adapters/netbox/common/storage_opts.py,sha256=wfv1spElomwgVYMCgGth3SWVF0RsRgtUgq9GpFL9hJs,1520
|
|
43
43
|
annet/adapters/netbox/v24/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
44
|
-
annet/adapters/netbox/v24/models.py,sha256=
|
|
44
|
+
annet/adapters/netbox/v24/models.py,sha256=RH2ooUPHOtHT0q1ZQE7v23FgmcsGenzzSgJyft13o1k,7605
|
|
45
45
|
annet/adapters/netbox/v24/storage.py,sha256=zptzrW4aZUv_exuGw0DqQPm_kXZR3DwL4zRHYL6twTk,6219
|
|
46
46
|
annet/adapters/netbox/v37/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
47
47
|
annet/adapters/netbox/v37/models.py,sha256=VqI1bT5E5pFIaDJWxWMU6bioNyrXKJuNq-_J8YIJIbw,1613
|
|
@@ -60,7 +60,7 @@ annet/annlib/filter_acl.py,sha256=mxDga-3SXqpPEsdQypTq0ScqUqP625lxX-DmJalEc3s,71
|
|
|
60
60
|
annet/annlib/jsontools.py,sha256=BS7s4rI8R9c_y3zz0zYl1l6con65oQ0MvfsC1dsXZts,5535
|
|
61
61
|
annet/annlib/lib.py,sha256=lxmYrbeablFMhFtvFmADVpVShSFi9TN4gNWaBs_Ygm0,14952
|
|
62
62
|
annet/annlib/output.py,sha256=_SjJ6G6bejvnTKqNHw6xeio0FT9oO3OIkLaOC3cEga4,7569
|
|
63
|
-
annet/annlib/patching.py,sha256=
|
|
63
|
+
annet/annlib/patching.py,sha256=1Ku5dNCQS9nlsMEr7tt7o1uGBsBeqfVFw4NY8aWYvnc,21483
|
|
64
64
|
annet/annlib/tabparser.py,sha256=aXwY0glVQ4__Sg1FFXiSPghyoNQRrMUQ7XCjMq__3lM,32016
|
|
65
65
|
annet/annlib/types.py,sha256=VHU0CBADfYmO0xzB_c5f-mcuU3dUumuJczQnqGlib9M,852
|
|
66
66
|
annet/annlib/netdev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -69,16 +69,16 @@ annet/annlib/netdev/devdb/__init__.py,sha256=aKYjjLbJebdKBjnGDpVLQdSqrV2JL24spGm
|
|
|
69
69
|
annet/annlib/netdev/devdb/data/devdb.json,sha256=t-j7SjEqSWNPhYV3cPQCSpODc3VGcRKJze9fgj4L9Uw,6710
|
|
70
70
|
annet/annlib/netdev/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
71
71
|
annet/annlib/netdev/views/dump.py,sha256=rIlyvnA3uM8bB_7oq1nS2KDxTp6dQh2hz-FbNhYIpOU,4630
|
|
72
|
-
annet/annlib/netdev/views/hardware.py,sha256=
|
|
72
|
+
annet/annlib/netdev/views/hardware.py,sha256=XvHtRn29SROKtxqMyr86oc1ItUKy36N98ppfuJQL8PY,3235
|
|
73
73
|
annet/annlib/rbparser/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
74
|
-
annet/annlib/rbparser/acl.py,sha256=
|
|
74
|
+
annet/annlib/rbparser/acl.py,sha256=I_1VUZQgF-s4dYTxyEDxQ-GkAP2MeXonzzsc2xROpTM,3974
|
|
75
75
|
annet/annlib/rbparser/deploying.py,sha256=ACT8QNhDAhJx3ZKuGh2nYBOrpdka2qEKuLDxvQAGKLk,1649
|
|
76
|
-
annet/annlib/rbparser/ordering.py,sha256=
|
|
76
|
+
annet/annlib/rbparser/ordering.py,sha256=XknggB92N4IbhHBZZHL0StwCCITt8mkho4D4Nu5Kb4k,2185
|
|
77
77
|
annet/annlib/rbparser/platform.py,sha256=vNoK25ACNQuDRv5I9uDfmNi8Y8yi10XWSbWIeKEVUgs,1672
|
|
78
78
|
annet/annlib/rbparser/syntax.py,sha256=iZ7Y-4QQBw4L3UtjEh54qisiRDhobl7HZxFNdP8mi54,3577
|
|
79
79
|
annet/annlib/rulebook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
80
80
|
annet/annlib/rulebook/common.py,sha256=-E6ATuFkSjNhyK0hiGd-iap5Ch5up2MNuVCbobWfmeU,16649
|
|
81
|
-
annet/api/__init__.py,sha256=
|
|
81
|
+
annet/api/__init__.py,sha256=KYtCj2Kgj2Qt1eqhk8kpSz4QgXToDdK2Okvtac3UD-w,33152
|
|
82
82
|
annet/configs/context.yml,sha256=RVLrKLIHpCty7AGwOnmqf7Uu0iZQCn-AjYhophDJer8,259
|
|
83
83
|
annet/configs/logging.yaml,sha256=EUagfir99QqA73Scc3k7sfQccbU3E1SvEQdyhLFtCl4,997
|
|
84
84
|
annet/generators/__init__.py,sha256=9MmstB59DlHGnY7GP36nyTiAdKtHdsJTyOYc0cxwm5U,16398
|
|
@@ -118,10 +118,10 @@ annet/rpl_generators/execute.py,sha256=wS6e6fwcPWywsHB0gBMqZ17eF0s4YOBgDgwPB_cr5
|
|
|
118
118
|
annet/rpl_generators/policy.py,sha256=j_2EtAsaxldhZZT4kRXKZacuAsGnHr3JSc2BMxr_Pow,37174
|
|
119
119
|
annet/rpl_generators/prefix_lists.py,sha256=5jM5Xj0dtx5xF9ap-TgExs0ofRAzm0LN2j3aL5Ub_yc,4778
|
|
120
120
|
annet/rpl_generators/rd.py,sha256=YGXgx1D2D0-pixgspXJzA6NvW8lx3AmHMxIY2l5rraI,1457
|
|
121
|
-
annet/rulebook/__init__.py,sha256=
|
|
121
|
+
annet/rulebook/__init__.py,sha256=WtDrO9BrbrF1o06zOTVrEMGuTgDtv7MfF8B29pRW77U,3996
|
|
122
122
|
annet/rulebook/common.py,sha256=zK1s2c5lc5HQbIlMUQ4HARQudXSgOYiZ_Sxc2I_tHqg,721
|
|
123
|
-
annet/rulebook/deploying.py,sha256=
|
|
124
|
-
annet/rulebook/patching.py,sha256=
|
|
123
|
+
annet/rulebook/deploying.py,sha256=9CMeOUw5L1OWdrccSRfpJyH9H_jH7xWNU1JldviBNrk,3015
|
|
124
|
+
annet/rulebook/patching.py,sha256=4JQE_qmdHb0Eggj9ytp99P1Z59uW5ZeUrPJIOdfgi_0,5022
|
|
125
125
|
annet/rulebook/arista/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
126
126
|
annet/rulebook/arista/aaa.py,sha256=7fBTwBnz9SOqYbwG8GBeEQTJG0e4uC4HkuZJeMG-kAY,2250
|
|
127
127
|
annet/rulebook/arista/iface.py,sha256=bgj6a3r__-OE6VyYbSfnD6ps2QJKyX028W7IFJww-UY,720
|
|
@@ -180,10 +180,14 @@ annet/rulebook/texts/ribbon.deploy,sha256=hCq2XeAcwaYanyQ8lTdnez6Pgq-gRqpNuR8dAl
|
|
|
180
180
|
annet/rulebook/texts/ribbon.rul,sha256=609LyLTDCtXPVQNAzqS-VEyCpW3byHP8TCMJLFMn5cc,2108
|
|
181
181
|
annet/rulebook/texts/routeros.order,sha256=M71uy_hf0KAjLNS3zZY3uih4m2xLUcu26FEoVVjC6k0,905
|
|
182
182
|
annet/rulebook/texts/routeros.rul,sha256=ipfxjj0mjFef6IsUlupqx4BY_Je_OUb8u_U1019O1DE,1203
|
|
183
|
-
annet
|
|
184
|
-
annet
|
|
183
|
+
annet/vendors/__init__.py,sha256=gQcDFlKeWDZB6vxJ_MdPWEoE-C5dg-YgXvgGkuV9YLw,569
|
|
184
|
+
annet/vendors/base.py,sha256=ll7WKL9KtHiNl9Cs6pQs4bJH6c6JRhyHIM7wdgkysdU,536
|
|
185
|
+
annet/vendors/registry.py,sha256=hav8ONavMAM7FCHgF-0_NKC_ntNAtcTicjxqXNtbovw,2326
|
|
186
|
+
annet-3.0.0.dist-info/licenses/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
|
|
187
|
+
annet-3.0.0.dist-info/licenses/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
|
|
185
188
|
annet_generators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
186
|
-
annet_generators/example/__init__.py,sha256=
|
|
189
|
+
annet_generators/example/__init__.py,sha256=OJ77uj8axc-FIyIu_Xdcnzmde3oQW5mk5qbODkhuVc8,355
|
|
190
|
+
annet_generators/example/hostname.py,sha256=RloLzNVetEoWPLITzfJ13Nk3CC0yi-cZB1RTd6dnuhI,2541
|
|
187
191
|
annet_generators/example/lldp.py,sha256=24bGvShxbio-JxUdaehyPRu31LhH9YwSwFDrWVRn6yo,2100
|
|
188
192
|
annet_generators/mesh_example/__init__.py,sha256=NfNWgXn1TNiWI6A5tmU6Y-4QV2i33td0Qs3re0MNNMo,218
|
|
189
193
|
annet_generators/mesh_example/bgp.py,sha256=jzyDndSSGYyYBquDnLlR-7P5lzmUKcSyYCml3VsoMC0,1385
|
|
@@ -193,8 +197,8 @@ annet_generators/rpl_example/generator.py,sha256=EWah19gOH8G-QyNyWqxCqdRi0BK7GbM
|
|
|
193
197
|
annet_generators/rpl_example/items.py,sha256=d99HSXDHFjZq511EvGhIqRTWK3F4ZsCWfdUqFYQcyhE,772
|
|
194
198
|
annet_generators/rpl_example/mesh.py,sha256=z_WgfDZZ4xnyh3cSf75igyH09hGvtexEVwy1gCD_DzA,288
|
|
195
199
|
annet_generators/rpl_example/route_policy.py,sha256=z6nPb0VDeQtKD1NIg9sFvmUxBD5tVs2frfNIuKdM-5c,2318
|
|
196
|
-
annet-
|
|
197
|
-
annet-
|
|
198
|
-
annet-
|
|
199
|
-
annet-
|
|
200
|
-
annet-
|
|
200
|
+
annet-3.0.0.dist-info/METADATA,sha256=x8H3f6rBvrh1jfXlkoWpqA5LiH7ZB6mnoc04Yhb6o6I,815
|
|
201
|
+
annet-3.0.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
202
|
+
annet-3.0.0.dist-info/entry_points.txt,sha256=5lIaDGlGi3l6QQ2ry2jZaqViP5Lvt8AmsegdD0Uznck,192
|
|
203
|
+
annet-3.0.0.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
|
|
204
|
+
annet-3.0.0.dist-info/RECORD,,
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import itertools
|
|
1
2
|
from typing import List
|
|
2
3
|
|
|
3
4
|
from annet.generators import BaseGenerator
|
|
4
5
|
from annet.storage import Storage
|
|
5
6
|
|
|
6
7
|
from . import lldp
|
|
8
|
+
from . import hostname
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
def get_generators(store: Storage) -> List[BaseGenerator]:
|
|
10
|
-
return
|
|
12
|
+
return list(itertools.chain.from_iterable([
|
|
13
|
+
hostname.get_generators(store),
|
|
14
|
+
lldp.get_generators(store),
|
|
15
|
+
]))
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from annet.generators import BaseGenerator, PartialGenerator
|
|
4
|
+
from annet.storage import Storage
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Hostname(PartialGenerator):
|
|
8
|
+
TAGS = ["hostname"]
|
|
9
|
+
|
|
10
|
+
def acl_huawei(self, _):
|
|
11
|
+
return """
|
|
12
|
+
sysname
|
|
13
|
+
header
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def acl_safe_huawei(self, _):
|
|
17
|
+
return """
|
|
18
|
+
sysname
|
|
19
|
+
header
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def run_huawei(self, device):
|
|
23
|
+
yield "sysname", device.hostname
|
|
24
|
+
yield 'header login information "%s"' % device.hostname
|
|
25
|
+
|
|
26
|
+
def acl_cisco(self, _):
|
|
27
|
+
return """
|
|
28
|
+
hostname
|
|
29
|
+
banner login
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def acl_safe_cisco(self, _):
|
|
33
|
+
return """
|
|
34
|
+
hostname
|
|
35
|
+
banner login
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def run_cisco(self, device):
|
|
39
|
+
if device.hw.Cisco.AIR and device.tags["Lightweight WiFi точка"]:
|
|
40
|
+
return
|
|
41
|
+
elif device.hw.Catalyst:
|
|
42
|
+
yield "banner login ^C%s^C" % device.hostname
|
|
43
|
+
yield "hostname", device.hostname
|
|
44
|
+
|
|
45
|
+
def acl_arista(self, _):
|
|
46
|
+
return """
|
|
47
|
+
hostname
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def acl_safe_arista(self, _):
|
|
51
|
+
return """
|
|
52
|
+
hostname
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def run_arista(self, device):
|
|
56
|
+
yield "hostname", device.hostname
|
|
57
|
+
|
|
58
|
+
acl_nexus = acl_arista
|
|
59
|
+
run_nexus = run_arista
|
|
60
|
+
|
|
61
|
+
def acl_juniper(self, _):
|
|
62
|
+
return """
|
|
63
|
+
system %cant_delete
|
|
64
|
+
host-name
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
def acl_safe_juniper(self, _):
|
|
68
|
+
return """
|
|
69
|
+
system %cant_delete
|
|
70
|
+
host-name
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
def run_juniper(self, device):
|
|
74
|
+
with self.block("system"):
|
|
75
|
+
yield "host-name", device.hostname
|
|
76
|
+
|
|
77
|
+
acl_ribbon = acl_juniper
|
|
78
|
+
acl_safe_ribbon = acl_safe_juniper
|
|
79
|
+
run_ribbon = run_juniper
|
|
80
|
+
|
|
81
|
+
def acl_nokia(self, _):
|
|
82
|
+
return """
|
|
83
|
+
system
|
|
84
|
+
name
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
def acl_safe_nokia(self, _):
|
|
88
|
+
return """
|
|
89
|
+
system
|
|
90
|
+
name
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
def run_nokia(self, device):
|
|
94
|
+
with self.block("system"):
|
|
95
|
+
yield "name", self.literal(device.hostname)
|
|
96
|
+
|
|
97
|
+
def acl_routeros(self, _):
|
|
98
|
+
return """
|
|
99
|
+
system %cant_delete
|
|
100
|
+
identity %cant_delete
|
|
101
|
+
set ~ %cant_delete
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
def run_routeros(self, device):
|
|
105
|
+
with self.block("system"):
|
|
106
|
+
with self.block("identity"):
|
|
107
|
+
yield f"set name={device.hostname}"
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def get_generators(store: Storage) -> List[BaseGenerator]:
|
|
111
|
+
return [
|
|
112
|
+
Hostname(store),
|
|
113
|
+
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|