annet 0.15.5__py3-none-any.whl → 0.16.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.

@@ -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 ""
@@ -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"
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
- pointer = jsonpointer.JsonPointer(acl_item)
28
+ new_pointers = _resolve_json_pointers(acl_item, new_fragment)
29
+ old_pointers = _resolve_json_pointers(acl_item, full_new_config)
27
30
 
28
- try:
31
+ for pointer in new_pointers:
29
32
  new_value = pointer.get(new_fragment)
30
- except jsonpointer.JsonPointerException:
31
- # no value found in new_fragment by the pointer,
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
- _ensure_pointer_exists(full_new_config, pointer)
43
- pointer.set(full_new_config, new_value)
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
- pointer = jsonpointer.JsonPointer(filter_text)
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": filter_text, "value": part}])
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
  }
@@ -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
@@ -656,6 +656,7 @@ def make_formatter(vendor, **kwargs):
656
656
  "aruba": CiscoFormatter,
657
657
  "pc": CommonFormatter,
658
658
  "ribbon": RibbonFormatter,
659
+ "b4com": CiscoFormatter,
659
660
  }
660
661
  return formatters[vendor](**kwargs)
661
662
 
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
- for file in self.deploy_cmds[device]["files"]:
503
- if before:
504
- cmds_pre_files[file] = "\n".join(map(str, before)).encode(encoding="utf-8")
505
- self.deploy_cmds[device]["cmds"][file] += "\n".join(map(str, after)).encode(encoding="utf-8")
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/deploy.py CHANGED
@@ -100,7 +100,7 @@ class DeployDriver(abc.ABC):
100
100
 
101
101
 
102
102
  def get_deployer() -> DeployDriver:
103
- connectors = fetcher_connector.get_all()
103
+ connectors = driver_connector.get_all()
104
104
  deployer, _ = get_connector_from_config("deployer", connectors)
105
105
  return deployer
106
106
 
@@ -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: str | None = 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
@@ -141,6 +141,4 @@ def repair_context_file() -> None:
141
141
 
142
142
 
143
143
  def do_async(coro: Awaitable):
144
- loop = asyncio.get_event_loop()
145
- res = loop.run_until_complete(coro)
146
- return res
144
+ return asyncio.run(coro)
File without changes
@@ -0,0 +1,5 @@
1
+ from annet.annlib.types import Op
2
+
3
+
4
+ def change(key, diff, **kwargs):
5
+ yield from [(True, add["row"], None) for add in diff[Op.ADDED]]
@@ -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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: annet
3
- Version: 0.15.5
3
+ Version: 0.16.0
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -4,20 +4,20 @@ annet/argparse.py,sha256=v1MfhjR0B8qahza0WinmXClpR8UiDFhmwDDWtNroJPA,12855
4
4
  annet/cli.py,sha256=ugxI_NFi-yuMn4RIlFKlqCDUurPXlSAa7kR9hkd1OxA,12329
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=h5lQK2zI-aL0S67dl3aXabjr0uy-DvfEKR_Rqk02uQQ,18886
7
+ annet/deploy.py,sha256=JLS9F67QHOccm-EEEzM8JlfIITmlx0D__XoOL4lEcD8,18953
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=W6Z9UurcyF1zU3gAd8hIec9yBzeeHzxZEkvf1cIg8KI,4280
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=lL33L4s63sMTS4n0kzC2mtrhpXAu0RYBvKC6U7I--gs,2706
20
- annet/tabparser.py,sha256=dEavhVBd9TEFf2NOW_JpTDcz2rzNtP4siQPceWalpl0,957
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,8 +26,8 @@ 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=K1z2ioP9ZikxjjfSAuAAszZALW0o9w1kLTnW5cR16tU,1412
30
- annet/adapters/netbox/common/models.py,sha256=Vgxbl_Mm-zOAi2BTlEzDppTTgZjafFEC5F9s_MTd_xU,3263
29
+ annet/adapters/netbox/common/manufacturer.py,sha256=WZsBfHq6kohbbkszxPARjMdXB5rWGBO4Gz1rA-IlqL8,1555
30
+ annet/adapters/netbox/common/models.py,sha256=enTd2c3pcs6KIMAeRquDMGtq-lZ_2_68JkF_mCKedoc,3271
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
33
  annet/adapters/netbox/common/storage_opts.py,sha256=afBMiIOOHFRJLh4KCLPflCCXKxh7D7VX9EL5wxFkuZI,494
@@ -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=J_pToAAXQphP1QFh6uLQH9PnmHO68I5WV64qIQXLeDQ,3807
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=djxW4d3pozqrNT6ZkrOxIUZkgGiZXHy7JvQSjao5MyY,25964
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=pW4gwys2SbduBC65hepV_HOv9uxn8pxz0ckvGFJiPoU,5727
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=6453atMaeoLWJSXzZxQ0zeTrdtRwCv0dlu6ivvpcdYE,3423
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=_W84Gt3XwURT2MLngZSmwZbWgqsnbrwzjNgHIHa8Xug,1365
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=9kCZwZpsH5UliF2OzaN9nLs2eLlz_d__4L7_oZ3SrCw,16054
64
- annet/api/__init__.py,sha256=xC4a-iSQACUZYoBujjZa1CjVWlNqxWpif15zCdvS828,33128
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=68CLrK7vxTQQy9XIBxtywuEdBNlIlfXGYj8_wYWs5UI,1146
130
- annet-0.15.5.dist-info/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
131
- annet-0.15.5.dist-info/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
132
- annet-0.15.5.dist-info/METADATA,sha256=UHKSe-jhGivq07JINzgUFWBm5LJNsanJQgAXoxPuZ6Y,694
133
- annet-0.15.5.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
134
- annet-0.15.5.dist-info/entry_points.txt,sha256=5lIaDGlGi3l6QQ2ry2jZaqViP5Lvt8AmsegdD0Uznck,192
135
- annet-0.15.5.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
136
- annet-0.15.5.dist-info/RECORD,,
135
+ annet_generators/example/lldp.py,sha256=24bGvShxbio-JxUdaehyPRu31LhH9YwSwFDrWVRn6yo,2100
136
+ annet-0.16.0.dist-info/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
137
+ annet-0.16.0.dist-info/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
138
+ annet-0.16.0.dist-info/METADATA,sha256=EAGnX05mQrFRr9TUWUKNUWlrP53XGcPPURku-e3llFw,694
139
+ annet-0.16.0.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
140
+ annet-0.16.0.dist-info/entry_points.txt,sha256=5lIaDGlGi3l6QQ2ry2jZaqViP5Lvt8AmsegdD0Uznck,192
141
+ annet-0.16.0.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
142
+ annet-0.16.0.dist-info/RECORD,,
@@ -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