annet 0.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.

Files changed (113) hide show
  1. annet/__init__.py +61 -0
  2. annet/annet.py +25 -0
  3. annet/annlib/__init__.py +7 -0
  4. annet/annlib/command.py +49 -0
  5. annet/annlib/diff.py +158 -0
  6. annet/annlib/errors.py +8 -0
  7. annet/annlib/filter_acl.py +196 -0
  8. annet/annlib/jsontools.py +89 -0
  9. annet/annlib/lib.py +495 -0
  10. annet/annlib/netdev/__init__.py +0 -0
  11. annet/annlib/netdev/db.py +62 -0
  12. annet/annlib/netdev/devdb/__init__.py +28 -0
  13. annet/annlib/netdev/devdb/data/devdb.json +137 -0
  14. annet/annlib/netdev/views/__init__.py +0 -0
  15. annet/annlib/netdev/views/dump.py +121 -0
  16. annet/annlib/netdev/views/hardware.py +112 -0
  17. annet/annlib/output.py +246 -0
  18. annet/annlib/patching.py +533 -0
  19. annet/annlib/rbparser/__init__.py +0 -0
  20. annet/annlib/rbparser/acl.py +120 -0
  21. annet/annlib/rbparser/deploying.py +55 -0
  22. annet/annlib/rbparser/ordering.py +52 -0
  23. annet/annlib/rbparser/platform.py +51 -0
  24. annet/annlib/rbparser/syntax.py +115 -0
  25. annet/annlib/rulebook/__init__.py +0 -0
  26. annet/annlib/rulebook/common.py +350 -0
  27. annet/annlib/tabparser.py +648 -0
  28. annet/annlib/types.py +35 -0
  29. annet/api/__init__.py +807 -0
  30. annet/argparse.py +415 -0
  31. annet/cli.py +192 -0
  32. annet/cli_args.py +493 -0
  33. annet/configs/context.yml +18 -0
  34. annet/configs/logging.yaml +39 -0
  35. annet/connectors.py +64 -0
  36. annet/deploy.py +441 -0
  37. annet/diff.py +85 -0
  38. annet/executor.py +551 -0
  39. annet/filtering.py +40 -0
  40. annet/gen.py +828 -0
  41. annet/generators/__init__.py +987 -0
  42. annet/generators/common/__init__.py +0 -0
  43. annet/generators/common/initial.py +33 -0
  44. annet/hardware.py +45 -0
  45. annet/implicit.py +139 -0
  46. annet/lib.py +128 -0
  47. annet/output.py +170 -0
  48. annet/parallel.py +448 -0
  49. annet/patching.py +25 -0
  50. annet/reference.py +148 -0
  51. annet/rulebook/__init__.py +114 -0
  52. annet/rulebook/arista/__init__.py +0 -0
  53. annet/rulebook/arista/iface.py +16 -0
  54. annet/rulebook/aruba/__init__.py +16 -0
  55. annet/rulebook/aruba/ap_env.py +146 -0
  56. annet/rulebook/aruba/misc.py +8 -0
  57. annet/rulebook/cisco/__init__.py +0 -0
  58. annet/rulebook/cisco/iface.py +68 -0
  59. annet/rulebook/cisco/misc.py +57 -0
  60. annet/rulebook/cisco/vlandb.py +90 -0
  61. annet/rulebook/common.py +19 -0
  62. annet/rulebook/deploying.py +87 -0
  63. annet/rulebook/huawei/__init__.py +0 -0
  64. annet/rulebook/huawei/aaa.py +75 -0
  65. annet/rulebook/huawei/bgp.py +97 -0
  66. annet/rulebook/huawei/iface.py +33 -0
  67. annet/rulebook/huawei/misc.py +337 -0
  68. annet/rulebook/huawei/vlandb.py +115 -0
  69. annet/rulebook/juniper/__init__.py +107 -0
  70. annet/rulebook/nexus/__init__.py +0 -0
  71. annet/rulebook/nexus/iface.py +92 -0
  72. annet/rulebook/patching.py +143 -0
  73. annet/rulebook/ribbon/__init__.py +12 -0
  74. annet/rulebook/texts/arista.deploy +20 -0
  75. annet/rulebook/texts/arista.order +125 -0
  76. annet/rulebook/texts/arista.rul +59 -0
  77. annet/rulebook/texts/aruba.deploy +20 -0
  78. annet/rulebook/texts/aruba.order +83 -0
  79. annet/rulebook/texts/aruba.rul +87 -0
  80. annet/rulebook/texts/cisco.deploy +27 -0
  81. annet/rulebook/texts/cisco.order +82 -0
  82. annet/rulebook/texts/cisco.rul +105 -0
  83. annet/rulebook/texts/huawei.deploy +188 -0
  84. annet/rulebook/texts/huawei.order +388 -0
  85. annet/rulebook/texts/huawei.rul +471 -0
  86. annet/rulebook/texts/juniper.rul +120 -0
  87. annet/rulebook/texts/nexus.deploy +24 -0
  88. annet/rulebook/texts/nexus.order +85 -0
  89. annet/rulebook/texts/nexus.rul +83 -0
  90. annet/rulebook/texts/nokia.rul +31 -0
  91. annet/rulebook/texts/pc.order +5 -0
  92. annet/rulebook/texts/pc.rul +9 -0
  93. annet/rulebook/texts/ribbon.deploy +22 -0
  94. annet/rulebook/texts/ribbon.rul +77 -0
  95. annet/rulebook/texts/routeros.order +38 -0
  96. annet/rulebook/texts/routeros.rul +45 -0
  97. annet/storage.py +121 -0
  98. annet/tabparser.py +36 -0
  99. annet/text_term_format.py +95 -0
  100. annet/tracing.py +170 -0
  101. annet/types.py +223 -0
  102. annet-0.1.dist-info/AUTHORS +21 -0
  103. annet-0.1.dist-info/LICENSE +21 -0
  104. annet-0.1.dist-info/METADATA +24 -0
  105. annet-0.1.dist-info/RECORD +113 -0
  106. annet-0.1.dist-info/WHEEL +5 -0
  107. annet-0.1.dist-info/entry_points.txt +6 -0
  108. annet-0.1.dist-info/top_level.txt +3 -0
  109. annet_generators/__init__.py +0 -0
  110. annet_generators/example/__init__.py +12 -0
  111. annet_generators/example/lldp.py +52 -0
  112. annet_nbexport/__init__.py +220 -0
  113. annet_nbexport/main.py +46 -0
@@ -0,0 +1,220 @@
1
+ import csv
2
+ import dataclasses
3
+ import operator
4
+ import os
5
+ import os.path
6
+ import pathlib
7
+ from typing import List
8
+
9
+ from annet.storage import Device, Storage, Query, StorageOpts, StorageProvider
10
+ from annet.annlib.netdev.views.hardware import HardwareView
11
+
12
+
13
+ class AnnetNbExportProvder(StorageProvider):
14
+ def storage(self):
15
+ return AnnetNbExportStorage
16
+
17
+ def opts(self):
18
+ return AnnetNbExportStorageOpts
19
+
20
+ def query(self):
21
+ return AnnetNbExportQuery
22
+
23
+
24
+ @dataclasses.dataclass
25
+ class AnnetNbExportQuery(Query):
26
+ query: List[str]
27
+
28
+ @classmethod
29
+ def new(cls, query, hosts_range) -> "AnnetNbExportQuery":
30
+ if hosts_range is not None:
31
+ raise ValueError("host_range is not supported")
32
+ return cls(query=query)
33
+
34
+ @property
35
+ def globs(self):
36
+ # We process every query host as a glob
37
+ return self.query
38
+
39
+
40
+ @dataclasses.dataclass
41
+ class AnnetNbExportStorageOpts(StorageOpts):
42
+ @classmethod
43
+ def from_cli_opts(cls, cli_opts) -> "AnnetNbExportQuery":
44
+ return cls()
45
+
46
+
47
+ class DeviceNb(Device):
48
+ def __init__(self, storage: "Storage", dto: "NetboxDTO", region: str):
49
+ self.dto = dto
50
+ self.storage = storage
51
+ self.region = region
52
+
53
+ def __hash__(self):
54
+ return hash(self.id)
55
+
56
+ def is_pc(self):
57
+ return self.dto.manufacturer == "Mellanox"
58
+
59
+ @property
60
+ def hw(self):
61
+ manufacturer = self.dto.manufacturer
62
+ model_name = self.dto.model_name
63
+ # по какой-то причине модели mellanox SN в нетбоксе называются MSN
64
+ # чтобы использовать выгрузку as is и не править devdb.json патчим тут
65
+ if manufacturer == "Mellanox" and model_name.startswith("MSN"):
66
+ model_name = model_name.replace("MSN", "SN", 1)
67
+ hw = _vendor_to_hw(manufacturer + " " + model_name)
68
+ assert hw.vendor, "unsupported manufacturer %s" % self.dto.manufacturer
69
+ return hw
70
+
71
+ @property
72
+ def id(self):
73
+ return self.dto.name
74
+
75
+ @property
76
+ def fqdn(self):
77
+ return self.dto.name
78
+
79
+ @property
80
+ def hostname(self):
81
+ return self.dto.name
82
+
83
+ @property
84
+ def neighbours_ids(self):
85
+ return set()
86
+
87
+ @property
88
+ def breed(self):
89
+ if self.dto.manufacturer == "Huawei" and self.dto.model_name.startswith("CE"):
90
+ return "vrp85"
91
+ elif self.dto.manufacturer == "Huawei" and self.dto.model_name.startswith("NE"):
92
+ return "vrp85"
93
+ elif self.dto.manufacturer == "Huawei":
94
+ return "vrp55"
95
+ elif self.dto.manufacturer == "Mellanox":
96
+ return "cuml2"
97
+ elif self.dto.manufacturer == "Juniper":
98
+ return "jun10"
99
+ elif self.dto.manufacturer == "Cisco":
100
+ return "ios12"
101
+ elif self.dto.manufacturer == "Adva":
102
+ return "adva8"
103
+ elif self.dto.manufacturer == "Arista":
104
+ return "eos4"
105
+ assert False, "unknown manufacturer %s" % self.dto.manufacturer
106
+
107
+
108
+ @dataclasses.dataclass
109
+ class NetboxDTO:
110
+ name: str
111
+ device_role: str
112
+ tenant: str
113
+ manufacturer: str
114
+ model_name: str
115
+ platform: str
116
+ serial: str
117
+ asset_tag: str
118
+ status: str
119
+ site: str
120
+ rack_group: str
121
+ rack_name: str
122
+ position: str
123
+ face: str
124
+ comments: str
125
+
126
+
127
+ class AnnetNbExportStorage(Storage):
128
+ def __init__(self, opts: "Optional[StorageOpts]" = None):
129
+ self._dump_dir = os.path.join(os.path.dirname(__file__))
130
+
131
+ def __enter__(self):
132
+ return self
133
+
134
+ def __exit__(self, _, __, ___):
135
+ pass
136
+
137
+ def resolve_object_ids_by_query(self, query):
138
+ ret = []
139
+ for device_data in _read_dump(self._dump_dir):
140
+ if _match_query(query, device_data):
141
+ ret.append(device_data["name"])
142
+ return ret
143
+
144
+ def resolve_fdnds_by_query(self, query):
145
+ return self.resolve_object_ids_by_query(query)
146
+
147
+ def make_devices(
148
+ self,
149
+ query: "inventory.Query",
150
+ preload_neighbors=False,
151
+ use_mesh=None,
152
+ preload_extra_fields=False,
153
+ **kwargs,
154
+ ):
155
+ ret = []
156
+ for file_path, device_data in _read_dump(self._dump_dir):
157
+ if _match_query(query, device_data):
158
+ ret.append(DeviceNb(self, NetboxDTO(**device_data), region=file_path.parent.name))
159
+ return ret
160
+
161
+ def get_device(self, obj_id, preload_neighbors=False, use_mesh=None, **kwargs) -> "DeviceView":
162
+ for file_path, device_data in _read_dump(self._dump_dir):
163
+ if device_data["name"] == obj_id:
164
+ return DeviceNb(self, NetboxDTO(**device_data), region=file_path.parent.name)
165
+
166
+ def flush_perf(self):
167
+ pass
168
+
169
+
170
+ def _read_dump(dump_dir):
171
+ for (dirpath, _dirnames, filenames) in os.walk(dump_dir):
172
+ for filename in filenames:
173
+ if filename != "devices.csv":
174
+ continue
175
+ with open(os.path.join(dirpath, filename)) as fh:
176
+ file_path = pathlib.Path(os.path.join(dirpath, filename))
177
+ for device_data in csv.DictReader(fh):
178
+ yield file_path, device_data
179
+
180
+
181
+ def _match_query(query, device_data) -> bool:
182
+ for subquery in query.globs:
183
+ matches = []
184
+ for field_filter in subquery.split("@"):
185
+ if "=" in field_filter:
186
+ field, value = field_filter.split("=")
187
+ field = field.strip()
188
+ value = value.strip()
189
+ op = operator.eq
190
+ else:
191
+ field = "name"
192
+ value = field_filter.strip()
193
+ op = operator.contains
194
+ if field in device_data and op(device_data[field], value):
195
+ matches.append(True)
196
+ else:
197
+ matches.append(False)
198
+ if all(matches):
199
+ return True
200
+ return False
201
+
202
+
203
+ def _vendor_to_hw(vendor):
204
+ hw = HardwareView(
205
+ {
206
+ "cisco": "Cisco",
207
+ "catalyst": "Cisco Catalyst",
208
+ "nexus": "Cisco Nexus",
209
+ "huawei": "Huawei",
210
+ "juniper": "Juniper",
211
+ "arista": "Arista",
212
+ "pc": "PC",
213
+ "nokia": "Nokia",
214
+ "aruba": "Aruba",
215
+ "routeros": "RouterOS",
216
+ "ribbon": "Ribbon",
217
+ }.get(vendor.lower(), vendor),
218
+ None,
219
+ )
220
+ return hw
annet_nbexport/main.py ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import argparse
4
+ import asyncio
5
+ import os
6
+ import typing
7
+
8
+ import aiohttp
9
+ import yarl
10
+
11
+
12
+ async def download(url: yarl.URL, dest: typing.BinaryIO):
13
+ async with aiohttp.ClientSession() as session:
14
+ async with session.get(url) as resp:
15
+ async for b in resp.content.iter_any():
16
+ dest.write(b)
17
+
18
+
19
+ async def download_devices(url: yarl.URL, region: str):
20
+ basedir = os.path.dirname(__file__)
21
+ regiondir = os.path.join(basedir, "data", region)
22
+ os.makedirs(regiondir, exist_ok=True)
23
+ with open(os.path.join(regiondir, "devices.csv"), "wb") as fh:
24
+ await download(url.with_path("/dcim/devices/").with_query("export"), fh)
25
+
26
+
27
+ async def amain():
28
+ p = argparse.ArgumentParser()
29
+ p.add_argument("--region-name", default=None, help="The name of the region to download cvs to")
30
+ p.add_argument("netbox_url", type=yarl.URL, help="The URL to access netbox API")
31
+ args = p.parse_args()
32
+
33
+ if args.region_name is None:
34
+ region_name = args.netbox_url.host
35
+ else:
36
+ region_name = args.region_name
37
+
38
+ await download_devices(args.netbox_url, region_name)
39
+
40
+
41
+ def main():
42
+ asyncio.run(amain())
43
+
44
+
45
+ if __name__ == "__main__":
46
+ main()