annet 0.15.6__py3-none-any.whl → 0.16.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/adapters/netbox/common/manufacturer.py +5 -0
- annet/adapters/netbox/common/models.py +7 -7
- annet/adapters/netbox/common/storage_opts.py +2 -2
- annet/annlib/jsontools.py +81 -23
- annet/annlib/netdev/devdb/data/devdb.json +6 -1
- annet/annlib/netdev/views/hardware.py +3 -0
- annet/annlib/rbparser/platform.py +4 -0
- annet/annlib/rulebook/common.py +12 -0
- annet/annlib/tabparser.py +1 -0
- annet/api/__init__.py +11 -5
- annet/cli.py +2 -2
- annet/deploy.py +2 -2
- annet/lib.py +1 -3
- annet/rulebook/b4com/__init__.py +0 -0
- annet/rulebook/b4com/file.py +5 -0
- annet/rulebook/texts/b4com.deploy +18 -0
- annet/rulebook/texts/b4com.order +8 -0
- annet/rulebook/texts/b4com.rul +18 -0
- annet/rulebook/texts/pc.deploy +0 -0
- annet/storage.py +6 -5
- annet/tabparser.py +1 -1
- {annet-0.15.6.dist-info → annet-0.16.1.dist-info}/METADATA +1 -1
- {annet-0.15.6.dist-info → annet-0.16.1.dist-info}/RECORD +29 -23
- annet_generators/example/lldp.py +28 -0
- {annet-0.15.6.dist-info → annet-0.16.1.dist-info}/AUTHORS +0 -0
- {annet-0.15.6.dist-info → annet-0.16.1.dist-info}/LICENSE +0 -0
- {annet-0.15.6.dist-info → annet-0.16.1.dist-info}/WHEEL +0 -0
- {annet-0.15.6.dist-info → annet-0.16.1.dist-info}/entry_points.txt +0 -0
- {annet-0.15.6.dist-info → annet-0.16.1.dist-info}/top_level.txt +0 -0
|
@@ -17,6 +17,7 @@ _VENDORS = {
|
|
|
17
17
|
"aruba": "Aruba",
|
|
18
18
|
"routeros": "RouterOS",
|
|
19
19
|
"ribbon": "Ribbon",
|
|
20
|
+
"b4com": "B4com"
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
|
|
@@ -46,4 +47,8 @@ def get_breed(manufacturer: str, model: str):
|
|
|
46
47
|
return "adva8"
|
|
47
48
|
elif manufacturer == "Arista":
|
|
48
49
|
return "eos4"
|
|
50
|
+
elif manufacturer == "B4com":
|
|
51
|
+
return "bcom-os"
|
|
52
|
+
elif manufacturer == "MikroTik":
|
|
53
|
+
return "routeros"
|
|
49
54
|
return ""
|
|
@@ -52,17 +52,17 @@ class DeviceIp(DumpableView):
|
|
|
52
52
|
class Prefix(DumpableView):
|
|
53
53
|
id: int
|
|
54
54
|
prefix: str
|
|
55
|
-
site: Entity
|
|
56
|
-
vrf: Entity
|
|
57
|
-
tenant: Entity
|
|
58
|
-
vlan: Entity
|
|
59
|
-
role: Entity
|
|
55
|
+
site: Optional[Entity]
|
|
56
|
+
vrf: Optional[Entity]
|
|
57
|
+
tenant: Optional[Entity]
|
|
58
|
+
vlan: Optional[Entity]
|
|
59
|
+
role: Optional[Entity]
|
|
60
60
|
status: Label
|
|
61
61
|
is_pool: bool
|
|
62
62
|
custom_fields: dict[str, Any]
|
|
63
63
|
created: datetime
|
|
64
64
|
last_updated: datetime
|
|
65
|
-
description: str
|
|
65
|
+
description: Optional[str] = ""
|
|
66
66
|
|
|
67
67
|
@property
|
|
68
68
|
def _dump__list_key(self):
|
|
@@ -166,5 +166,5 @@ class NetboxDevice(Entity):
|
|
|
166
166
|
def __eq__(self, other):
|
|
167
167
|
return type(self) is type(other) and self.url == other.url
|
|
168
168
|
|
|
169
|
-
def is_pc(self):
|
|
169
|
+
def is_pc(self) -> bool:
|
|
170
170
|
return self.device_type.manufacturer.name == "Mellanox"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
-
from typing import Any
|
|
2
|
+
from typing import Any, Optional
|
|
3
3
|
|
|
4
4
|
DEFAULT_URL = "http://localhost"
|
|
5
5
|
|
|
@@ -10,7 +10,7 @@ class NetboxStorageOpts:
|
|
|
10
10
|
self.token = token
|
|
11
11
|
|
|
12
12
|
@classmethod
|
|
13
|
-
def parse_params(cls, conf_params: dict[str, str]
|
|
13
|
+
def parse_params(cls, conf_params: Optional[dict[str, str]], cli_opts: Any):
|
|
14
14
|
url = os.getenv("NETBOX_URL") or conf_params.get("url") or DEFAULT_URL
|
|
15
15
|
token = os.getenv("NETBOX_TOKEN", "").strip() or conf_params.get("token") or ""
|
|
16
16
|
return cls(url=url, token=token)
|
annet/annlib/jsontools.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
"""Support JSON patch (RFC 6902) and JSON Pointer (RFC 6901)."""
|
|
1
|
+
"""Support JSON patch (RFC 6902) and JSON Pointer (RFC 6901) with globs."""
|
|
2
2
|
|
|
3
3
|
import copy
|
|
4
|
+
import fnmatch
|
|
4
5
|
import json
|
|
6
|
+
from collections.abc import Mapping, Sequence
|
|
5
7
|
from typing import Any, Dict, List, Optional
|
|
6
8
|
|
|
7
9
|
import jsonpatch
|
|
@@ -23,24 +25,21 @@ def apply_json_fragment(
|
|
|
23
25
|
"""
|
|
24
26
|
full_new_config = copy.deepcopy(old)
|
|
25
27
|
for acl_item in acl:
|
|
26
|
-
|
|
28
|
+
new_pointers = _resolve_json_pointers(acl_item, new_fragment)
|
|
29
|
+
old_pointers = _resolve_json_pointers(acl_item, full_new_config)
|
|
27
30
|
|
|
28
|
-
|
|
31
|
+
for pointer in new_pointers:
|
|
29
32
|
new_value = pointer.get(new_fragment)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
# try to delete it from the new config
|
|
33
|
-
try:
|
|
34
|
-
doc, part = pointer.to_last(full_new_config)
|
|
35
|
-
if isinstance(doc, dict) and isinstance(part, str):
|
|
36
|
-
doc.pop(part, None)
|
|
37
|
-
except jsonpointer.JsonPointerException:
|
|
38
|
-
# not found in the old config either
|
|
39
|
-
pass
|
|
40
|
-
continue
|
|
33
|
+
_ensure_pointer_exists(full_new_config, pointer)
|
|
34
|
+
pointer.set(full_new_config, new_value)
|
|
41
35
|
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
# delete matched parts in old config whicn are not present in the new
|
|
37
|
+
paths = {p.path for p in new_pointers}
|
|
38
|
+
to_delete = [p for p in old_pointers if p.path not in paths]
|
|
39
|
+
for pointer in to_delete:
|
|
40
|
+
doc, part = pointer.to_last(full_new_config)
|
|
41
|
+
if isinstance(doc, dict) and isinstance(part, str):
|
|
42
|
+
doc.pop(part, None)
|
|
44
43
|
|
|
45
44
|
return full_new_config
|
|
46
45
|
|
|
@@ -104,9 +103,8 @@ def apply_acl_filters(content: Dict[str, Any], filters: List[str]) -> Dict[str,
|
|
|
104
103
|
if not filter_text:
|
|
105
104
|
continue
|
|
106
105
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
try:
|
|
106
|
+
pointers = _resolve_json_pointers(filter_text, content)
|
|
107
|
+
for pointer in pointers:
|
|
110
108
|
part = pointer.get(copy.deepcopy(content))
|
|
111
109
|
|
|
112
110
|
sub_tree = result
|
|
@@ -115,10 +113,70 @@ def apply_acl_filters(content: Dict[str, Any], filters: List[str]) -> Dict[str,
|
|
|
115
113
|
sub_tree[i] = {}
|
|
116
114
|
sub_tree = sub_tree[i]
|
|
117
115
|
|
|
118
|
-
patch = jsonpatch.JsonPatch([{"op": "add", "path":
|
|
116
|
+
patch = jsonpatch.JsonPatch([{"op": "add", "path": pointer.path, "value": part}])
|
|
119
117
|
result = patch.apply(result)
|
|
120
|
-
except jsonpointer.JsonPointerException:
|
|
121
|
-
# no value found in content by the pointer, skip the ACL item
|
|
122
|
-
continue
|
|
123
118
|
|
|
124
119
|
return result
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _resolve_json_pointers(pattern: str, content: Dict[str, Any]) -> List[jsonpointer.JsonPointer]:
|
|
123
|
+
"""
|
|
124
|
+
Resolve globbed json pointer pattern to a list of actual pointers, existing in the document.
|
|
125
|
+
|
|
126
|
+
For example, given the following document:
|
|
127
|
+
|
|
128
|
+
{
|
|
129
|
+
"foo": {
|
|
130
|
+
"bar": {
|
|
131
|
+
"baz": [1, 2]
|
|
132
|
+
},
|
|
133
|
+
"qux": {
|
|
134
|
+
"baz": [3, 4]
|
|
135
|
+
},
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
Pattern "/f*/*/baz" will resolve to:
|
|
140
|
+
|
|
141
|
+
[
|
|
142
|
+
"/foo/bar/baz"",
|
|
143
|
+
"/foo/qux/baz",
|
|
144
|
+
]
|
|
145
|
+
|
|
146
|
+
Pattern "/f*/q*/baz/*" will resolve to:
|
|
147
|
+
|
|
148
|
+
[
|
|
149
|
+
"/foo/qux/baz/0",
|
|
150
|
+
"/foo/qux/baz/1",
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
Pattern "/*" will resolve to:
|
|
154
|
+
|
|
155
|
+
[
|
|
156
|
+
"/foo"
|
|
157
|
+
]
|
|
158
|
+
"""
|
|
159
|
+
parts = jsonpointer.JsonPointer(pattern).parts
|
|
160
|
+
matched = [([], content)]
|
|
161
|
+
for part in parts:
|
|
162
|
+
new_matched = []
|
|
163
|
+
for matched_parts, doc in matched:
|
|
164
|
+
keys_and_docs = []
|
|
165
|
+
if isinstance(doc, Mapping):
|
|
166
|
+
keys_and_docs = [
|
|
167
|
+
(key, doc[key]) for key in doc.keys()
|
|
168
|
+
if fnmatch.fnmatchcase(key, part)
|
|
169
|
+
]
|
|
170
|
+
elif isinstance(doc, Sequence):
|
|
171
|
+
keys_and_docs = [
|
|
172
|
+
(str(i), doc[i]) for i in range(len(doc))
|
|
173
|
+
if fnmatch.fnmatchcase(str(i), part)
|
|
174
|
+
]
|
|
175
|
+
for key, sub_doc in keys_and_docs:
|
|
176
|
+
new_matched.append((matched_parts + [key], sub_doc))
|
|
177
|
+
matched = new_matched
|
|
178
|
+
|
|
179
|
+
ret: List[jsonpointer.JsonPointer] = []
|
|
180
|
+
for matched_parts, _ in matched:
|
|
181
|
+
ret.append(jsonpointer.JsonPointer("/" + "/".join(matched_parts)))
|
|
182
|
+
return ret
|
|
@@ -156,5 +156,10 @@
|
|
|
156
156
|
|
|
157
157
|
"H3C": "^[Hh]3[Cc]",
|
|
158
158
|
"H3C.S12500": " S125\\d{2}",
|
|
159
|
-
"H3C.S12500.S12500R": " S12500R"
|
|
159
|
+
"H3C.S12500.S12500R": " S12500R",
|
|
160
|
+
|
|
161
|
+
"B4com": "^[Bb]4com",
|
|
162
|
+
"B4com.CS2148P": "^[Bb]4com B4T-CS2148P.*",
|
|
163
|
+
"B4com.CS4148Q": "^[Bb]4com B4T-CS4148Q.*",
|
|
164
|
+
"B4com.CS4146U": "^[Bb]4com B4T-CS4146U.*"
|
|
160
165
|
}
|
|
@@ -97,6 +97,8 @@ def hw_to_vendor(hw: HardwareView) -> Optional[str]:
|
|
|
97
97
|
return "ribbon"
|
|
98
98
|
elif hw.H3C:
|
|
99
99
|
return "h3c"
|
|
100
|
+
elif hw.B4com:
|
|
101
|
+
return "b4com"
|
|
100
102
|
return None
|
|
101
103
|
|
|
102
104
|
|
|
@@ -116,6 +118,7 @@ def vendor_to_hw(vendor):
|
|
|
116
118
|
"routeros": "RouterOS",
|
|
117
119
|
"ribbon": "Ribbon",
|
|
118
120
|
"h3c": "H3C",
|
|
121
|
+
"b4com": "B4com",
|
|
119
122
|
}.get(vendor.lower(), vendor),
|
|
120
123
|
None,
|
|
121
124
|
)
|
|
@@ -10,6 +10,7 @@ VENDOR_REVERSES = {
|
|
|
10
10
|
"aruba": "no",
|
|
11
11
|
"pc": "-",
|
|
12
12
|
"ribbon": "delete",
|
|
13
|
+
"b4com": "no",
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
VENDOR_DIFF = {
|
|
@@ -24,6 +25,7 @@ VENDOR_DIFF = {
|
|
|
24
25
|
"aruba": "aruba.default_diff",
|
|
25
26
|
"pc": "common.default_diff",
|
|
26
27
|
"ribbon": "ribbon.default_diff",
|
|
28
|
+
"b4com": "common.default_diff",
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
VENDOR_DIFF_ORDERED = {
|
|
@@ -38,6 +40,7 @@ VENDOR_DIFF_ORDERED = {
|
|
|
38
40
|
"aruba": "common.ordered_diff",
|
|
39
41
|
"pc": "common.ordered_diff",
|
|
40
42
|
"ribbon": "ribbon.default_diff",
|
|
43
|
+
"b4com": "common.ordered_diff",
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
VENDOR_EXIT = {
|
|
@@ -52,4 +55,5 @@ VENDOR_EXIT = {
|
|
|
52
55
|
"aruba": "exit",
|
|
53
56
|
"pc": "",
|
|
54
57
|
"ribbon": "exit",
|
|
58
|
+
"b4com": "exit",
|
|
55
59
|
}
|
annet/annlib/rulebook/common.py
CHANGED
|
@@ -344,6 +344,18 @@ def apply(hw, do_commit, do_finalize, **_):
|
|
|
344
344
|
if do_commit:
|
|
345
345
|
after.add_cmd(Command("commit", timeout=30))
|
|
346
346
|
after.add_cmd(Command("exit"))
|
|
347
|
+
elif hw.B4com.CS2148P:
|
|
348
|
+
before.add_cmd(Command("conf t"))
|
|
349
|
+
after.add_cmd(Command("exit"))
|
|
350
|
+
if do_finalize:
|
|
351
|
+
after.add_cmd(Command("write", timeout=40))
|
|
352
|
+
elif hw.B4com:
|
|
353
|
+
before.add_cmd(Command("conf t"))
|
|
354
|
+
after.add_cmd(Command("exit"))
|
|
355
|
+
if do_commit:
|
|
356
|
+
after.add_cmd(Command("commit"))
|
|
357
|
+
if do_finalize:
|
|
358
|
+
after.add_cmd(Command("write", timeout=40))
|
|
347
359
|
else:
|
|
348
360
|
raise Exception("unknown hw %s" % hw)
|
|
349
361
|
|
annet/annlib/tabparser.py
CHANGED
annet/api/__init__.py
CHANGED
|
@@ -6,7 +6,7 @@ import sys
|
|
|
6
6
|
import time
|
|
7
7
|
import warnings
|
|
8
8
|
from collections import OrderedDict as odict
|
|
9
|
-
from itertools import groupby
|
|
9
|
+
from itertools import groupby, chain
|
|
10
10
|
from operator import itemgetter
|
|
11
11
|
from typing import (
|
|
12
12
|
Any,
|
|
@@ -35,6 +35,7 @@ from annet import diff as ann_diff
|
|
|
35
35
|
from annet import filtering
|
|
36
36
|
from annet import gen as ann_gen
|
|
37
37
|
from annet import patching, rulebook, tabparser, tracing
|
|
38
|
+
from annet.rulebook import deploying
|
|
38
39
|
from annet.filtering import Filterer
|
|
39
40
|
from annet.hardware import hardware_connector
|
|
40
41
|
from annet.output import (
|
|
@@ -499,10 +500,15 @@ class PCDeployerJob(DeployerJob):
|
|
|
499
500
|
for cmd in deployer_driver.build_exit_cmdlist(device.hw):
|
|
500
501
|
after.add_cmd(cmd)
|
|
501
502
|
cmds_pre_files = {}
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
503
|
+
rules = rulebook.get_rulebook(device.hw)["deploying"]
|
|
504
|
+
for file, content in self.deploy_cmds[device]["files"].items():
|
|
505
|
+
rule = deploying.match_deploy_rule(rules, [file], content)
|
|
506
|
+
before_more, after_more = annet.deploy.make_apply_commands(rule, res.device.hw, do_commit=True, do_finalize=True, path=file)
|
|
507
|
+
|
|
508
|
+
cmds_pre_files[file] = "\n".join(map(str, chain(before, before_more))).encode(encoding="utf-8")
|
|
509
|
+
after_cmds = "\n".join(map(str, chain(after, after_more))).encode(encoding="utf-8")
|
|
510
|
+
if after_cmds:
|
|
511
|
+
self.deploy_cmds[device]["cmds"][file] += b"\n" + after_cmds
|
|
506
512
|
self.deploy_cmds[device]["cmds_pre_files"] = cmds_pre_files
|
|
507
513
|
|
|
508
514
|
|
annet/cli.py
CHANGED
|
@@ -8,7 +8,7 @@ import subprocess
|
|
|
8
8
|
import shutil
|
|
9
9
|
import sys
|
|
10
10
|
from contextlib import ExitStack, contextmanager
|
|
11
|
-
from typing import Tuple, Iterable
|
|
11
|
+
from typing import Optional, Tuple, Iterable
|
|
12
12
|
|
|
13
13
|
import tabulate
|
|
14
14
|
import yaml
|
|
@@ -129,7 +129,7 @@ def show_generators(args: cli_args.ShowGeneratorsOptions):
|
|
|
129
129
|
""" List applicable generators (for a device if query is set) """
|
|
130
130
|
arg_gens = cli_args.GenOptions(args)
|
|
131
131
|
with get_loader(arg_gens, args) as loader:
|
|
132
|
-
device: Device
|
|
132
|
+
device: Optional[Device] = None
|
|
133
133
|
devices = loader.devices
|
|
134
134
|
if len(devices) == 1:
|
|
135
135
|
device = devices[0]
|
annet/deploy.py
CHANGED
|
@@ -481,9 +481,9 @@ def make_cmd_params(rule: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
481
481
|
}
|
|
482
482
|
|
|
483
483
|
|
|
484
|
-
def make_apply_commands(rule, hw, do_commit, do_finalize):
|
|
484
|
+
def make_apply_commands(rule: dict, hw: HardwareView, do_commit: bool, do_finalize: bool, path: Optional[str] = None):
|
|
485
485
|
apply_logic = rule["attrs"]["apply_logic"]
|
|
486
|
-
before, after = apply_logic(hw, do_commit=do_commit, do_finalize=do_finalize)
|
|
486
|
+
before, after = apply_logic(hw, do_commit=do_commit, do_finalize=do_finalize, path=path)
|
|
487
487
|
return before, after
|
|
488
488
|
|
|
489
489
|
|
annet/lib.py
CHANGED
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Рулбук деплоя на устройства
|
|
2
|
+
#
|
|
3
|
+
# Операторы:
|
|
4
|
+
# * Один аргумент
|
|
5
|
+
# ~ Несколько аргументов (минимум один)
|
|
6
|
+
#
|
|
7
|
+
# Параметры:
|
|
8
|
+
# %timeout=... Таймаут выполнения команды (в секундах, по умолчанию 30)
|
|
9
|
+
#
|
|
10
|
+
# Ответы на вопросы
|
|
11
|
+
#
|
|
12
|
+
# <команда>
|
|
13
|
+
# dialog: <вопрос> ::: <ответ> <параметры>
|
|
14
|
+
#
|
|
15
|
+
# Если <вопрос> заключён в слеши (//), то воспринимается как регулярка, иначе - точное совпадение.
|
|
16
|
+
# Параметы:
|
|
17
|
+
# %send_nl=... Посылать ли перевод строки после ответа (bool, по умолчанию true)
|
|
18
|
+
# -----
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# В этом файле определяется порядок команд, в котором их следует подавать на устройство.
|
|
2
|
+
# - Если порядок команды не важен - ее можно не писать сюда совсем.
|
|
3
|
+
# - Если команда начинается с undo и прописан параметр %order_reverse - команда считается
|
|
4
|
+
# обратной, но занимает место между прямыми там, где указано.
|
|
5
|
+
|
|
6
|
+
# Фичи должны быть включены прежде всего
|
|
7
|
+
feature
|
|
8
|
+
# Далее нужно будет указать команды и их порядок
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Операторы:
|
|
2
|
+
# * Один аргумент в undo
|
|
3
|
+
# ~ Несколько аргументов (минимум один) в undo
|
|
4
|
+
#
|
|
5
|
+
# Параметры:
|
|
6
|
+
# %global Команда действует на любом уровне ниже
|
|
7
|
+
# %logic=... Кастомная функция обработки правила
|
|
8
|
+
# %diff_logic=... Кастомная функция построения диффа.
|
|
9
|
+
# данная функция работает для подблоков (в отличие от %logic)
|
|
10
|
+
# %comment=... Добавить коммент после строки который будет видно с опцией patch --add-comments
|
|
11
|
+
# Сделано в основном для того чтобы генерировать специальные команды для наливки
|
|
12
|
+
# -----
|
|
13
|
+
# Physical
|
|
14
|
+
interface */(ce|xe)[0-9\/]+$/ %logic=common.permanent %diff_logic=cisco.iface.diff
|
|
15
|
+
ipv6 address *
|
|
16
|
+
mtu *
|
|
17
|
+
lldp-agent
|
|
18
|
+
~ %rewrite %global
|
|
File without changes
|
annet/storage.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import abc
|
|
2
2
|
from typing import Any, Iterable, Optional, Type, Union, Protocol, Dict
|
|
3
3
|
from annet.connectors import Connector, get_connector_from_config
|
|
4
|
+
from annet.annlib.netdev.views.hardware import HardwareView
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
class _StorageConnector(Connector["StorageProvider"]):
|
|
@@ -95,12 +96,12 @@ class Device(Protocol):
|
|
|
95
96
|
pass
|
|
96
97
|
|
|
97
98
|
@abc.abstractmethod
|
|
98
|
-
def is_pc(self):
|
|
99
|
+
def is_pc(self) -> bool:
|
|
99
100
|
pass
|
|
100
101
|
|
|
101
102
|
@property
|
|
102
103
|
@abc.abstractmethod
|
|
103
|
-
def hw(self):
|
|
104
|
+
def hw(self) -> HardwareView:
|
|
104
105
|
pass
|
|
105
106
|
|
|
106
107
|
@property
|
|
@@ -110,12 +111,12 @@ class Device(Protocol):
|
|
|
110
111
|
|
|
111
112
|
@property
|
|
112
113
|
@abc.abstractmethod
|
|
113
|
-
def fqdn(self):
|
|
114
|
+
def fqdn(self) -> str:
|
|
114
115
|
pass
|
|
115
116
|
|
|
116
117
|
@property
|
|
117
118
|
@abc.abstractmethod
|
|
118
|
-
def hostname(self):
|
|
119
|
+
def hostname(self) -> str:
|
|
119
120
|
pass
|
|
120
121
|
|
|
121
122
|
@property
|
|
@@ -125,7 +126,7 @@ class Device(Protocol):
|
|
|
125
126
|
|
|
126
127
|
@property
|
|
127
128
|
@abc.abstractmethod
|
|
128
|
-
def breed(self):
|
|
129
|
+
def breed(self) -> str:
|
|
129
130
|
pass
|
|
130
131
|
|
|
131
132
|
|
annet/tabparser.py
CHANGED
|
@@ -21,7 +21,7 @@ def make_formatter(hw, **kwargs):
|
|
|
21
21
|
cls = HuaweiFormatter
|
|
22
22
|
elif hw.Cisco.ASR or hw.Cisco.XRV:
|
|
23
23
|
cls = AsrFormatter
|
|
24
|
-
elif hw.Nexus or hw.Cisco or hw.Arista or hw.Aruba:
|
|
24
|
+
elif hw.Nexus or hw.Cisco or hw.Arista or hw.Aruba or hw.B4com:
|
|
25
25
|
cls = CiscoFormatter
|
|
26
26
|
elif hw.Juniper:
|
|
27
27
|
cls = JuniperFormatter
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
annet/__init__.py,sha256=k2dq8aOYjkjZszKoOlxEmR49uYoKh-8_HC2K8FeqLwA,2139
|
|
2
2
|
annet/annet.py,sha256=TMdEuM7GJQ4TjRVmuK3bCTZN-21lxjQ9sXqEdILUuBk,725
|
|
3
3
|
annet/argparse.py,sha256=v1MfhjR0B8qahza0WinmXClpR8UiDFhmwDDWtNroJPA,12855
|
|
4
|
-
annet/cli.py,sha256=
|
|
4
|
+
annet/cli.py,sha256=hDpjIr3w47lgQ_CvCQS1SXFDK-SJrf5slbT__5u6GIA,12342
|
|
5
5
|
annet/cli_args.py,sha256=KQlihxSl-Phhq1-9oJDdNSbIllEX55LlPfH6viEKOuw,13483
|
|
6
6
|
annet/connectors.py,sha256=_DY5JwR_uU_obOpzo2a_JsexIE-lbNjG1Hq2nOpQm4w,5067
|
|
7
|
-
annet/deploy.py,sha256=
|
|
7
|
+
annet/deploy.py,sha256=pM7r8ipk7y-b4OIenc8FMqZpy5F6TmKdo8DDUJNRBlY,18956
|
|
8
8
|
annet/diff.py,sha256=zLcaCnb4lZRUb7frpH1CstQ3kacRcCblZs1uLG8J5lk,3391
|
|
9
9
|
annet/executor.py,sha256=FrYAUuh2TpSVX42SlTN_PhuSHmXG4Wj1nieY9Wqv9so,19122
|
|
10
10
|
annet/filtering.py,sha256=ZtqxPsKdV9reZoRxtQyBg22BqyMqd-2SotYcxZ-68AQ,903
|
|
11
11
|
annet/gen.py,sha256=Xy4VyK8pfH97wZ8Zv2bD2SNxhEx9-S93Zp7pQm-VnuU,33592
|
|
12
12
|
annet/hardware.py,sha256=_iR28dWiPtt6ZYdk-qg1sxazkSRJE3ukqKB-fFFfQak,1141
|
|
13
13
|
annet/implicit.py,sha256=_3eY9NKqpLUm25vlJIP2cHN4gdTgzO6rG6mwCKJYMnQ,5439
|
|
14
|
-
annet/lib.py,sha256=
|
|
14
|
+
annet/lib.py,sha256=z-qhs68ap0xHZjGdn-vTUqE91IPaUM6eU_Pee7Exniw,4218
|
|
15
15
|
annet/output.py,sha256=BNPzjuhMa7gSJ8ze_1O-Ey0tTxSyhAiwfztZMQwhMzk,7176
|
|
16
16
|
annet/parallel.py,sha256=hLkzEht0KhzmzUWDdO4QFYQHzhxs3wPlTA8DxbB2ziw,17160
|
|
17
17
|
annet/patching.py,sha256=nILbY5oJajN0b1j3f0HEJm05H3HVThnWvB7vDVh7UQw,559
|
|
18
18
|
annet/reference.py,sha256=B8mH8VUMcecPnzULiTVb_kTQ7jQrCL7zp4pfIZQa5fk,4035
|
|
19
|
-
annet/storage.py,sha256=
|
|
20
|
-
annet/tabparser.py,sha256=
|
|
19
|
+
annet/storage.py,sha256=s5kiSonsQZnT-ioAyoLtezLe1QbbJwK5-Wr1QfMxupU,2811
|
|
20
|
+
annet/tabparser.py,sha256=N0O7G9DTdmgcBDxz0PH7B_r-Z8FsUkZqm9hTBy3PZFA,969
|
|
21
21
|
annet/text_term_format.py,sha256=CHb6viv45vmYl-SK1A1vyPHGhaEni6jVybBusaQnct8,2813
|
|
22
22
|
annet/tracing.py,sha256=ndpM-au1c88uBBpOuH_z52qWZL773edYozNyys_wA68,4044
|
|
23
23
|
annet/types.py,sha256=f2HwqoKa6AucwFwDMszoouB6m1B8n6VmdjHMktO30Kc,7175
|
|
@@ -26,11 +26,11 @@ annet/adapters/netbox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
|
|
|
26
26
|
annet/adapters/netbox/provider.py,sha256=mnvxSy3vTwdEHvzfy_Tfji4J4-BDmiKwkcF0s-EAs2M,1449
|
|
27
27
|
annet/adapters/netbox/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
28
|
annet/adapters/netbox/common/client.py,sha256=-lWZmphD-OPuLIHNKhW_h2bnjrVaiyKYAD_MUPasEbo,2483
|
|
29
|
-
annet/adapters/netbox/common/manufacturer.py,sha256=
|
|
30
|
-
annet/adapters/netbox/common/models.py,sha256=
|
|
29
|
+
annet/adapters/netbox/common/manufacturer.py,sha256=WZsBfHq6kohbbkszxPARjMdXB5rWGBO4Gz1rA-IlqL8,1555
|
|
30
|
+
annet/adapters/netbox/common/models.py,sha256=uAUTzyZk9-B4xdVGCe2nSSBO8PXAiUYvYHOTnQAdQbU,3289
|
|
31
31
|
annet/adapters/netbox/common/query.py,sha256=ziUFM7cUEbEIf3k1szTll4aO-OCUa-2Ogxbebi7Tegs,646
|
|
32
32
|
annet/adapters/netbox/common/status_client.py,sha256=W4nTb2yvBlJ2UkWUmUhKQ2PaSQb1shjhHj5ebb4s2s4,591
|
|
33
|
-
annet/adapters/netbox/common/storage_opts.py,sha256=
|
|
33
|
+
annet/adapters/netbox/common/storage_opts.py,sha256=iadgWGMb-rfSp3SnFAw8SH5bMKjwvcAsJ74v_z0CCXQ,507
|
|
34
34
|
annet/adapters/netbox/v24/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
35
|
annet/adapters/netbox/v24/storage.py,sha256=THI592VLx3ehixsPZQ1Ko3mYIAZQbnDY-toIziqBbL8,6005
|
|
36
36
|
annet/adapters/netbox/v37/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -40,28 +40,28 @@ annet/annlib/command.py,sha256=uuBddMQphtn8P5MO5kzIa8_QrtMns-k05VeKv1bcAuA,1043
|
|
|
40
40
|
annet/annlib/diff.py,sha256=UPt3kYFQdQdVVy3ePYzNHPAxMVmHxCrCnZnMCV6ou2Q,4587
|
|
41
41
|
annet/annlib/errors.py,sha256=jBcSFzY6Vj-FxR__vqjFm-87AwYQ0xHuAopTirii5AU,287
|
|
42
42
|
annet/annlib/filter_acl.py,sha256=0w1VF6WcONiTYTQh0yWi6_j9rCTc_kMLAUMr0hbdkNU,7203
|
|
43
|
-
annet/annlib/jsontools.py,sha256=
|
|
43
|
+
annet/annlib/jsontools.py,sha256=4-2r_mPNbecKreuUr3vlLv3ykJdhRmyUD8AdF2nSAxc,5430
|
|
44
44
|
annet/annlib/lib.py,sha256=eJ4hcVuQ6pdYBzLs4YKCHFtq45idOfZCYp92XfF7_QI,15317
|
|
45
45
|
annet/annlib/output.py,sha256=_SjJ6G6bejvnTKqNHw6xeio0FT9oO3OIkLaOC3cEga4,7569
|
|
46
46
|
annet/annlib/patching.py,sha256=GwG2lT4w-I1Ls3Eswn6SPJLBUVt2M3Ysw1fmXsWamYw,19793
|
|
47
|
-
annet/annlib/tabparser.py,sha256=
|
|
47
|
+
annet/annlib/tabparser.py,sha256=9ry4DxZn6ibShd7fFtH_TElm3lT5tgMGkHcpGXNVuUY,25997
|
|
48
48
|
annet/annlib/types.py,sha256=VHU0CBADfYmO0xzB_c5f-mcuU3dUumuJczQnqGlib9M,852
|
|
49
49
|
annet/annlib/netdev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
50
50
|
annet/annlib/netdev/db.py,sha256=fI_u5aya4l61mbYSjj4JwlVfi3s7obt2jqERSuXGRUI,1634
|
|
51
51
|
annet/annlib/netdev/devdb/__init__.py,sha256=aKYjjLbJebdKBjnGDpVLQdSqrV2JL24spGm58tmMWVU,892
|
|
52
|
-
annet/annlib/netdev/devdb/data/devdb.json,sha256=
|
|
52
|
+
annet/annlib/netdev/devdb/data/devdb.json,sha256=GEKBY3Mx1wjLmhlN9h6VIj5RoTCA2thmDIEXBvv6EVg,5898
|
|
53
53
|
annet/annlib/netdev/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
54
|
annet/annlib/netdev/views/dump.py,sha256=rIlyvnA3uM8bB_7oq1nS2KDxTp6dQh2hz-FbNhYIpOU,4630
|
|
55
|
-
annet/annlib/netdev/views/hardware.py,sha256=
|
|
55
|
+
annet/annlib/netdev/views/hardware.py,sha256=1JdTkrumOTYd5GKz4_LKg8G-B6ccrzl5VdNT-JhX40A,3495
|
|
56
56
|
annet/annlib/rbparser/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
57
57
|
annet/annlib/rbparser/acl.py,sha256=RR8yPt6t96_IiyuKVbeZ-3x32cyhBAT2wC1y99oWBO8,3931
|
|
58
58
|
annet/annlib/rbparser/deploying.py,sha256=ACT8QNhDAhJx3ZKuGh2nYBOrpdka2qEKuLDxvQAGKLk,1649
|
|
59
59
|
annet/annlib/rbparser/ordering.py,sha256=DiKqyY8Khz-5MTxNF1GSNtZgtyKwT3YYCXpahIPB6Ps,1779
|
|
60
|
-
annet/annlib/rbparser/platform.py,sha256=
|
|
60
|
+
annet/annlib/rbparser/platform.py,sha256=QI9KuCrel3X19PW5u56hWi1UhJ9mxlTYtUIpmcmGRUc,1477
|
|
61
61
|
annet/annlib/rbparser/syntax.py,sha256=iZ7Y-4QQBw4L3UtjEh54qisiRDhobl7HZxFNdP8mi54,3577
|
|
62
62
|
annet/annlib/rulebook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
63
|
-
annet/annlib/rulebook/common.py,sha256=
|
|
64
|
-
annet/api/__init__.py,sha256=
|
|
63
|
+
annet/annlib/rulebook/common.py,sha256=Kd9Xout0xC6ZZDnyaORx0W-1kSM-gTgjQbp1iIXWxic,16489
|
|
64
|
+
annet/api/__init__.py,sha256=KWoJfo2ByHC8EsIhU4szuhGwE8OKYS7Y1TN2xkhe0qA,33563
|
|
65
65
|
annet/configs/context.yml,sha256=jzAQX9WbjFw_nsju8FLCCGfRc4ZXD0Mhb5pvO9emegI,413
|
|
66
66
|
annet/configs/logging.yaml,sha256=Hu42lRK248dssp9TgkbHCaZNl0E6f4IChGb0XaQnTVo,970
|
|
67
67
|
annet/generators/__init__.py,sha256=ACMH9UQ4I3uq2b8nDzOn2dgYxreDq4_3ojOGwht0-No,15543
|
|
@@ -84,6 +84,8 @@ annet/rulebook/arista/iface.py,sha256=bgj6a3r__-OE6VyYbSfnD6ps2QJKyX028W7IFJww-U
|
|
|
84
84
|
annet/rulebook/aruba/__init__.py,sha256=ILggeID6kNWcDBGzhXm_mebcfkuLSq5prBFU5DyPFs4,500
|
|
85
85
|
annet/rulebook/aruba/ap_env.py,sha256=5fUVLhXH4-0DAtv8t0yoqJUibaRMuzF8Q7mGFzNsEN8,4692
|
|
86
86
|
annet/rulebook/aruba/misc.py,sha256=O0p_wsR07gtB8rm1eJvJ7VYnGm5T8Uau_SVKR9FVInI,234
|
|
87
|
+
annet/rulebook/b4com/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
88
|
+
annet/rulebook/b4com/file.py,sha256=zK7RwBk1YaVoDSFSg1u7Pt8u0Fk3nhhu27aJRngemwc,137
|
|
87
89
|
annet/rulebook/cisco/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
88
90
|
annet/rulebook/cisco/iface.py,sha256=WISkzjp_G7WKPpg098FCIm4b7ipOxtRLOQbu-7gMUL0,1792
|
|
89
91
|
annet/rulebook/cisco/misc.py,sha256=l9NTR6cAsrfFyeC_yoOeQ0fOFoPiJfFwnRva5W9vyL0,2259
|
|
@@ -104,6 +106,9 @@ annet/rulebook/texts/arista.rul,sha256=HUYiN55s8Y6Wrd5q1Awe7-o5BYBh7gIxthUC5Nvrf
|
|
|
104
106
|
annet/rulebook/texts/aruba.deploy,sha256=hI432Bq-of_LMXuUflCu7eNSEFpx6qmj0KItEw6sgHI,841
|
|
105
107
|
annet/rulebook/texts/aruba.order,sha256=ZMakkn0EJ9zomgY6VssoptJImrHrUmYnCqivzLBFTRo,1158
|
|
106
108
|
annet/rulebook/texts/aruba.rul,sha256=zvGVpoYyJvMoL0fb1NQ8we_GCLZXno8nwWpZIOScLQQ,2584
|
|
109
|
+
annet/rulebook/texts/b4com.deploy,sha256=SVX8-yLHM90tJC4M-ekpGuGM1aQZW3euSGyg67l--R0,781
|
|
110
|
+
annet/rulebook/texts/b4com.order,sha256=G3aToAIHHzKzDCM3q7_lyr9wJvuVOXVbVvF3wm5PiTE,707
|
|
111
|
+
annet/rulebook/texts/b4com.rul,sha256=5mqyUg_oLRSny2iH6QdhfDWVu6kzgDURtlSATD7DFno,1056
|
|
107
112
|
annet/rulebook/texts/cisco.deploy,sha256=XvXWeOMahE8Uc9RF0xkJj8jGknD4vit8H_f24ubPX7w,1226
|
|
108
113
|
annet/rulebook/texts/cisco.order,sha256=eE9ddPQr8ZumjffQsMvl-BBymOwV6juETZU3r7kpRvk,1709
|
|
109
114
|
annet/rulebook/texts/cisco.rul,sha256=HGg62zXCn8UVXu9x_Ja5QivPcY5Yo5BYi1CaOXCaDHA,2869
|
|
@@ -118,6 +123,7 @@ annet/rulebook/texts/nokia.rul,sha256=gxK7FCRdjGUs7tDHTUebVOgkzWINAGibMPtz8tzvwg
|
|
|
118
123
|
annet/rulebook/texts/optixtrans.deploy,sha256=SVX8-yLHM90tJC4M-ekpGuGM1aQZW3euSGyg67l--R0,781
|
|
119
124
|
annet/rulebook/texts/optixtrans.order,sha256=NbeEP5oBsC-Iw84T8dpmc_s3BXJofXYeTdGdjUmPsYM,623
|
|
120
125
|
annet/rulebook/texts/optixtrans.rul,sha256=MvQX16Gyc1loCgPgLd2Ei1BYrTDZ33CayQurc_j9xVk,898
|
|
126
|
+
annet/rulebook/texts/pc.deploy,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
121
127
|
annet/rulebook/texts/pc.order,sha256=WTSosHmIA5LyHO_DNAH1VDeuXHEgZ9e_aDFyAtIW6rE,275
|
|
122
128
|
annet/rulebook/texts/pc.rul,sha256=zwIkSdOsJ6gmIj1sfy0xa4_yQRRBRjSQEqopsqFE2u8,302
|
|
123
129
|
annet/rulebook/texts/ribbon.deploy,sha256=hCq2XeAcwaYanyQ8lTdnez6Pgq-gRqpNuR8dAleIn3U,864
|
|
@@ -126,11 +132,11 @@ annet/rulebook/texts/routeros.order,sha256=M71uy_hf0KAjLNS3zZY3uih4m2xLUcu26FEoV
|
|
|
126
132
|
annet/rulebook/texts/routeros.rul,sha256=ipfxjj0mjFef6IsUlupqx4BY_Je_OUb8u_U1019O1DE,1203
|
|
127
133
|
annet_generators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
128
134
|
annet_generators/example/__init__.py,sha256=zVd8_DrXuOASrNzg2Ab94rPyvJff83L-_HppDFxnUjM,228
|
|
129
|
-
annet_generators/example/lldp.py,sha256=
|
|
130
|
-
annet-0.
|
|
131
|
-
annet-0.
|
|
132
|
-
annet-0.
|
|
133
|
-
annet-0.
|
|
134
|
-
annet-0.
|
|
135
|
-
annet-0.
|
|
136
|
-
annet-0.
|
|
135
|
+
annet_generators/example/lldp.py,sha256=24bGvShxbio-JxUdaehyPRu31LhH9YwSwFDrWVRn6yo,2100
|
|
136
|
+
annet-0.16.1.dist-info/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
|
|
137
|
+
annet-0.16.1.dist-info/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
|
|
138
|
+
annet-0.16.1.dist-info/METADATA,sha256=fBLYdAEadQVUPbjdikTJS2OOmaMiWWvIgrGgEv4nLY8,694
|
|
139
|
+
annet-0.16.1.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
140
|
+
annet-0.16.1.dist-info/entry_points.txt,sha256=5lIaDGlGi3l6QQ2ry2jZaqViP5Lvt8AmsegdD0Uznck,192
|
|
141
|
+
annet-0.16.1.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
|
|
142
|
+
annet-0.16.1.dist-info/RECORD,,
|
annet_generators/example/lldp.py
CHANGED
|
@@ -46,6 +46,34 @@ class Lldp(PartialGenerator):
|
|
|
46
46
|
interface all
|
|
47
47
|
"""
|
|
48
48
|
|
|
49
|
+
def acl_b4com(self, device):
|
|
50
|
+
return """
|
|
51
|
+
lldp *
|
|
52
|
+
interface *
|
|
53
|
+
lldp-agent
|
|
54
|
+
*
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def run_b4com(self, device):
|
|
58
|
+
yield """
|
|
59
|
+
lldp run
|
|
60
|
+
lldp tlv-select basic-mgmt port-description
|
|
61
|
+
lldp tlv-select basic-mgmt system-name
|
|
62
|
+
lldp tlv-select basic-mgmt system-capabilities
|
|
63
|
+
lldp tlv-select basic-mgmt system-description
|
|
64
|
+
lldp tlv-select basic-mgmt management-address
|
|
65
|
+
"""
|
|
66
|
+
for iface in device.interfaces:
|
|
67
|
+
with self.multiblock(f"interface {iface.name}"):
|
|
68
|
+
with self.multiblock("lldp-agent"):
|
|
69
|
+
yield """
|
|
70
|
+
set lldp enable txrx
|
|
71
|
+
set lldp chassis-id-tlv ip-address
|
|
72
|
+
set lldp port-id-tlv if-name
|
|
73
|
+
lldp tlv basic-mgmt system-name select
|
|
74
|
+
lldp tlv basic-mgmt system-description select
|
|
75
|
+
"""
|
|
76
|
+
|
|
49
77
|
|
|
50
78
|
def get_generators(store: Storage) -> List[BaseGenerator]:
|
|
51
79
|
return [
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|