annet 3.2.0__py3-none-any.whl → 3.3.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.

@@ -3,6 +3,7 @@ from datetime import datetime, timezone
3
3
  from typing import Optional
4
4
  from annet.adapters.netbox.common.models import InterfaceType, IpFamily, Label, Prefix, Entity
5
5
  from annet.adapters.netbox.v41.models import InterfaceV41, IpAddressV41, NetboxDeviceV41
6
+ import annetbox.v42.models
6
7
 
7
8
 
8
9
  @dataclass
@@ -61,3 +62,8 @@ class NetboxDeviceV42(NetboxDeviceV41):
61
62
  connected_endpoints=[],
62
63
  mode=None,
63
64
  )
65
+
66
+
67
+ # should be unified in case of netbox update
68
+ Vrf = annetbox.v42.models.Vrf
69
+ Vlan = annetbox.v42.models.Vlan
@@ -1,4 +1,6 @@
1
1
  import ssl
2
+ from typing import Optional
3
+
2
4
  from adaptix import P
3
5
  from adaptix.conversion import get_converter, link, link_constant, link_function
4
6
  from annetbox.v42 import client_sync
@@ -6,7 +8,8 @@ from annetbox.v42 import models as api_models
6
8
 
7
9
  from annet.adapters.netbox.common.adapter import NetboxAdapter, get_device_breed, get_device_hw
8
10
  from annet.adapters.netbox.common.storage_base import BaseNetboxStorage
9
- from annet.adapters.netbox.v42.models import InterfaceV42, NetboxDeviceV42, PrefixV42, IpAddressV42
11
+ from annet.adapters.netbox.common.storage_opts import NetboxStorageOpts
12
+ from annet.adapters.netbox.v42.models import InterfaceV42, NetboxDeviceV42, PrefixV42, IpAddressV42, Vlan, Vrf
10
13
  from annet.storage import Storage
11
14
 
12
15
 
@@ -79,8 +82,21 @@ class NetboxV42Adapter(NetboxAdapter[NetboxDeviceV42, InterfaceV42, IpAddressV42
79
82
  def list_ipprefixes(self, prefixes: list[str]) -> list[PrefixV42]:
80
83
  return self.convert_ip_prefixes(self.netbox.ipam_all_prefixes(prefix=prefixes).results)
81
84
 
85
+ def list_all_vrfs(self) -> list[Vrf]:
86
+ return self.netbox.ipam_all_vrfs().results
87
+
88
+ def list_all_vlans(self) -> list[Vlan]:
89
+ return self.netbox.ipam_all_vlans().results
90
+
82
91
 
83
92
  class NetboxStorageV42(BaseNetboxStorage[NetboxDeviceV42, InterfaceV42, IpAddressV42, PrefixV42]):
93
+ netbox: NetboxV42Adapter
94
+
95
+ def __init__(self, opts: Optional[NetboxStorageOpts] = None):
96
+ super().__init__(opts)
97
+ self._all_vlans: list[Vlan] | None = None
98
+ self._all_vrfs: list[Vrf] | None = None
99
+
84
100
  def _init_adapter(
85
101
  self,
86
102
  url: str,
@@ -89,3 +105,13 @@ class NetboxStorageV42(BaseNetboxStorage[NetboxDeviceV42, InterfaceV42, IpAddres
89
105
  threads: int,
90
106
  ) -> NetboxAdapter[NetboxDeviceV42, InterfaceV42, IpAddressV42, PrefixV42]:
91
107
  return NetboxV42Adapter(self, url, token, ssl_context, threads)
108
+
109
+ def resolve_all_vlans(self) -> list[Vlan]:
110
+ if self._all_vlans is None:
111
+ self._all_vlans = self.netbox.list_all_vlans()
112
+ return self._all_vlans
113
+
114
+ def resolve_all_vrfs(self) -> list[Vrf]:
115
+ if self._all_vrfs is None:
116
+ self._all_vrfs = self.netbox.list_all_vrfs()
117
+ return self._all_vrfs
@@ -157,7 +157,7 @@ def run_partial_generators(
157
157
 
158
158
 
159
159
  @tracing.function(name="run_partial_generator")
160
- def _run_partial_generator(gen: "PartialGenerator", run_args: GeneratorPartialRunArgs) -> Optional[GeneratorPartialResult]:
160
+ def _run_partial_generator(gen: "PartialGenerator", run_args: GeneratorPartialRunArgs) -> GeneratorPartialResult | None:
161
161
  logger = get_logger(generator=_make_generator_ctx(gen))
162
162
  device = run_args.device
163
163
  output = ""
@@ -207,7 +207,9 @@ def _run_partial_generator(gen: "PartialGenerator", run_args: GeneratorPartialRu
207
207
 
208
208
  if run_args.use_acl:
209
209
  try:
210
- with tracing_connector.get().start_as_current_span("apply_acl", tracer_name=__name__, min_duration="0.01") as acl_span:
210
+ with tracing_connector.get().start_as_current_span(
211
+ "apply_acl", tracer_name=__name__, min_duration="0.01"
212
+ ) as acl_span:
211
213
  tracing_connector.get().set_device_attributes(acl_span, run_args.device)
212
214
  config = patching.apply_acl(
213
215
  config=config,
@@ -265,8 +267,8 @@ def check_entire_generators_required_packages(gens, device_packages: FrozenSet[s
265
267
 
266
268
  @tracing.function
267
269
  def run_file_generators(
268
- gens: Iterable[Union["JSONFragment", "Entire"]],
269
- device: "Device",
270
+ gens: Iterable[Union["JSONFragment", "Entire"]],
271
+ device: "Device",
270
272
  ) -> RunGeneratorResult:
271
273
  """Run generators that generate files or file parts."""
272
274
  ret = RunGeneratorResult()
@@ -295,21 +297,22 @@ def run_file_generators(
295
297
  @tracing.function(min_duration="0.5")
296
298
  def _run_entire_generator(gen: "Entire", device: "Device") -> Optional[GeneratorResult]:
297
299
  logger = get_logger(generator=_make_generator_ctx(gen))
298
- if not gen.supports_device(device):
299
- logger.info("generator %s is not supported for device %s", gen, device.hostname)
300
- return
301
-
302
300
  span = tracing_connector.get().get_current_span()
303
301
  if span:
304
302
  tracing_connector.get().set_device_attributes(span, device)
305
303
  tracing_connector.get().set_dimensions_attributes(span, gen, device)
306
304
 
307
- path = gen.path(device)
308
- if not path:
309
- raise RuntimeError("entire generator should return non-empty path")
310
-
311
- logger.info("Generating ENTIRE ...")
312
305
  with GeneratorPerfMesurer(gen, trace_min_duration="0.5") as pm:
306
+ if not gen.supports_device(device):
307
+ logger.debug("generator %s is not supported for device %s", gen, device.hostname)
308
+ return
309
+
310
+ path = gen.path(device)
311
+ if not path:
312
+ raise RuntimeError("entire generator should return non-empty path")
313
+
314
+ logger.info("Generating ENTIRE ...")
315
+
313
316
  output = gen(device)
314
317
 
315
318
  return GeneratorEntireResult(
@@ -329,35 +332,37 @@ def _make_generator_ctx(gen):
329
332
 
330
333
 
331
334
  def _run_json_fragment_generator(
332
- gen: "JSONFragment",
333
- device: "Device",
335
+ gen: "JSONFragment",
336
+ device: "Device",
334
337
  ) -> Optional[GeneratorResult]:
335
338
  logger = get_logger(generator=_make_generator_ctx(gen))
336
- if not gen.supports_device(device):
337
- logger.info("generator %s is not supported for device %s", gen, device.hostname)
338
- return
339
-
340
- path = gen.path(device)
341
- if not path:
342
- raise RuntimeError("json fragment generator should return non-empty path")
343
-
344
- acl_item_or_list_of_items = gen.acl(device)
345
- safe_acl_item_or_list_of_items = gen.acl_safe(device)
346
- if not acl_item_or_list_of_items:
347
- raise RuntimeError("json fragment generator should return non-empty acl")
348
- if isinstance(acl_item_or_list_of_items, list):
349
- acl = acl_item_or_list_of_items
350
- else:
351
- acl = [acl_item_or_list_of_items]
352
- if isinstance(safe_acl_item_or_list_of_items, list):
353
- acl_safe = safe_acl_item_or_list_of_items
354
- else:
355
- acl_safe = [safe_acl_item_or_list_of_items]
356
-
357
- logger.info("Generating JSON_FRAGMENT ...")
339
+
358
340
  with GeneratorPerfMesurer(gen) as pm:
341
+ if not gen.supports_device(device):
342
+ logger.info("generator %s is not supported for device %s", gen, device.hostname)
343
+ return
344
+
345
+ path = gen.path(device)
346
+ if not path:
347
+ raise RuntimeError("json fragment generator should return non-empty path")
348
+
349
+ acl_item_or_list_of_items = gen.acl(device)
350
+ safe_acl_item_or_list_of_items = gen.acl_safe(device)
351
+ if not acl_item_or_list_of_items:
352
+ raise RuntimeError("json fragment generator should return non-empty acl")
353
+ if isinstance(acl_item_or_list_of_items, list):
354
+ acl = acl_item_or_list_of_items
355
+ else:
356
+ acl = [acl_item_or_list_of_items]
357
+ if isinstance(safe_acl_item_or_list_of_items, list):
358
+ acl_safe = safe_acl_item_or_list_of_items
359
+ else:
360
+ acl_safe = [safe_acl_item_or_list_of_items]
361
+
362
+ logger.info("Generating JSON_FRAGMENT ...")
363
+
359
364
  config = gen(device)
360
- reload_cmds = gen.get_reload_cmds(device)
365
+ reload_cmds = gen.get_reload_cmds(device)
361
366
  return GeneratorJSONFragmentResult(
362
367
  name=gen.__class__.__name__,
363
368
  tags=gen.TAGS,
@@ -407,7 +412,8 @@ def _load_gen_module(module_path: str):
407
412
  except ModuleNotFoundError as e:
408
413
  try: # maybe it's a path to module
409
414
  module_abs_path = os.path.abspath(module_path)
410
- module = importlib.machinery.SourceFileLoader(re.sub(r"[./]", "_", module_abs_path).strip("_"), module_abs_path).load_module()
415
+ module = importlib.machinery.SourceFileLoader(re.sub(r"[./]", "_", module_abs_path).strip("_"),
416
+ module_abs_path).load_module()
411
417
  except ModuleNotFoundError:
412
418
  raise e
413
419
  return module
@@ -3,19 +3,10 @@ from __future__ import annotations
3
3
  import pkgutil
4
4
  import re
5
5
  import types
6
- from typing import (
7
- FrozenSet,
8
- Iterable,
9
- List,
10
- Optional,
11
- Set,
12
- Union,
13
- )
14
-
15
- from annet.lib import (
16
- flatten,
17
- mako_render,
18
- )
6
+ from typing import FrozenSet, Iterable, List, Optional, Set, Union
7
+
8
+ from annet.lib import flatten, mako_render
9
+
19
10
  from .base import BaseGenerator, _filter_str
20
11
  from .exceptions import NotSupportedDevice
21
12
 
@@ -39,8 +30,7 @@ class Entire(BaseGenerator):
39
30
  def run(self, device) -> Union[None, str, Iterable[Union[str, tuple]]]:
40
31
  raise NotImplementedError
41
32
 
42
- def reload(self, device) -> Optional[
43
- str]: # pylint: disable=unused-argument
33
+ def reload(self, device) -> Optional[str]: # pylint: disable=unused-argument
44
34
  return
45
35
 
46
36
  def get_reload_cmds(self, device) -> str:
annet/generators/perf.py CHANGED
@@ -1,27 +1,19 @@
1
- from __future__ import annotations
2
-
3
1
  import time
4
- from typing import (
5
- Optional,
6
- Union,
7
- )
2
+ from typing import Optional, Union
8
3
 
9
4
  from annet import tracing
10
5
  from annet.tracing import tracing_connector
11
- from annet.types import (
12
- GeneratorPartialRunArgs,
13
- GeneratorPerf,
14
- )
15
- from .entire import Entire
16
- from .partial import PartialGenerator
6
+ from annet.types import GeneratorPartialRunArgs, GeneratorPerf
7
+
8
+ from .base import BaseGenerator
17
9
 
18
10
 
19
11
  class GeneratorPerfMesurer:
20
12
  def __init__(
21
- self,
22
- gen: Union[PartialGenerator, Entire],
23
- run_args: Optional[GeneratorPartialRunArgs] = None,
24
- trace_min_duration: tracing.MinDurationT = None
13
+ self,
14
+ gen: BaseGenerator,
15
+ run_args: Optional[GeneratorPartialRunArgs] = None,
16
+ trace_min_duration: tracing.MinDurationT = None
25
17
  ):
26
18
  self._gen = gen
27
19
  self._run_args = run_args
@@ -44,8 +36,7 @@ class GeneratorPerfMesurer:
44
36
  self._span = self._span_ctx.__enter__() # pylint: disable=unnecessary-dunder-call
45
37
 
46
38
  if self._span:
47
- self._span.set_attributes(
48
- {"generator.class": self._gen.__class__.__name__})
39
+ self._span.set_attributes({"generator.class": self._gen.__class__.__name__})
49
40
  if self._run_args:
50
41
  tracing_connector.get().set_device_attributes(
51
42
  self._span, self._run_args.device,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: annet
3
- Version: 3.2.0
3
+ Version: 3.3.0
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -21,7 +21,7 @@ Requires-Dist: yarl>=1.8.2
21
21
  Requires-Dist: adaptix==3.0.0b7
22
22
  Requires-Dist: dataclass-rest==0.4
23
23
  Provides-Extra: netbox
24
- Requires-Dist: annetbox[sync]>=0.3.0; extra == "netbox"
24
+ Requires-Dist: annetbox[sync]>=0.4.0; extra == "netbox"
25
25
  Dynamic: home-page
26
26
  Dynamic: license
27
27
  Dynamic: license-file
@@ -49,8 +49,8 @@ annet/adapters/netbox/v41/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
49
49
  annet/adapters/netbox/v41/models.py,sha256=nunqgxffobE2C3_g1bkHXWffStBdAJxHfx0eAbvnWAU,2068
50
50
  annet/adapters/netbox/v41/storage.py,sha256=h6e7V4Od5o7P3Ssr_vUQ1IBjsxdnug4YGvG1BokwKuk,3795
51
51
  annet/adapters/netbox/v42/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
- annet/adapters/netbox/v42/models.py,sha256=xo5TB6VE0KNvQwUB_zasl2bDbNuKCCjcsHB3P-JVLgk,1784
53
- annet/adapters/netbox/v42/storage.py,sha256=atiThgkDGVdJStvFCDn4JtPZfEAhUNbw5IH_W-ijFDg,3795
52
+ annet/adapters/netbox/v42/models.py,sha256=UWrnRh1k3a048XsVmqh50dF91dunrolIJzmTLT0QExw,1920
53
+ annet/adapters/netbox/v42/storage.py,sha256=iMhdrdAAYZXS_VHoqi_5azFB3BVmp4daK4TVCI9vhxM,4666
54
54
  annet/annlib/__init__.py,sha256=fT1l4xV5fqqg8HPw9HqmZVN2qwS8i6X1aIm2zGDjxKY,252
55
55
  annet/annlib/command.py,sha256=uuBddMQphtn8P5MO5kzIa8_QrtMns-k05VeKv1bcAuA,1043
56
56
  annet/annlib/diff.py,sha256=MZ6eQAU3cadQp8KaSE6uAYFtcfMDCIe_eNuVROnYkCk,4496
@@ -80,13 +80,13 @@ annet/annlib/rulebook/common.py,sha256=2ZMu7Z47Ip7d8yMjihDNKKhwl9aV5U4IeCcyXM4Cj
80
80
  annet/api/__init__.py,sha256=EMGUgt3pTi2MDF8DfXlS8PGX2zT0iGLY01R6QlQHvGg,33305
81
81
  annet/configs/context.yml,sha256=RVLrKLIHpCty7AGwOnmqf7Uu0iZQCn-AjYhophDJer8,259
82
82
  annet/configs/logging.yaml,sha256=EUagfir99QqA73Scc3k7sfQccbU3E1SvEQdyhLFtCl4,997
83
- annet/generators/__init__.py,sha256=wJbNLI1bMppE71tnjJrqNGtbtLZ_gdRd-HytdZPzBiY,16451
83
+ annet/generators/__init__.py,sha256=p71npgfOVie1jtbkGd_Uw_sD1STl6-HdddcfcPOBMVg,16632
84
84
  annet/generators/base.py,sha256=rgQLcQBPZm4ecbKmRhVOpBR-GFJAiVfdb_y5f2-LUR8,3670
85
- annet/generators/entire.py,sha256=mfnKtn5GcHiqjGjuhETkOVm-0ppMELAPsmg5jQrYTZc,2922
85
+ annet/generators/entire.py,sha256=jFTbx9BKoiXMstq_QeesRH2yi01LHyYHxgCtvvwBmeM,2872
86
86
  annet/generators/exceptions.py,sha256=GPXTBgn2xZ3Ev_bdOPlfCLGRC1kQHe_dEq88S-uyi5s,151
87
87
  annet/generators/jsonfragment.py,sha256=Cl43t9_OtNWRxesk3B69h60KvD37tiK9W7sLLmppAT4,4379
88
88
  annet/generators/partial.py,sha256=XI01KDA--XwjSEU33SOQCCJZRXFq5boRz1uJA8lVA1g,3502
89
- annet/generators/perf.py,sha256=K72ivUuXbNXrsHrLeKWhGmczGYWsB7kUDdDzqOX6j3c,2370
89
+ annet/generators/perf.py,sha256=IaAcfEVtX7UNO11VOCXzp-FPj_tOx_CDQ34HGThCn4c,2225
90
90
  annet/generators/ref.py,sha256=QVdeL8po1D0kBsVLOpCjFR81D8yNTk-kaQj5WUM4hng,438
91
91
  annet/generators/result.py,sha256=zMAvGOYQU803bGy6datZduHLgrEqK2Zba_Jcf9Qn9p0,4976
92
92
  annet/generators/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -197,8 +197,8 @@ annet/vendors/library/optixtrans.py,sha256=xNurVzIrr7cefVUCzhxI-7xnCnayk1kIyRfU8
197
197
  annet/vendors/library/pc.py,sha256=4lPTvtvjGDCUuZ6yDyi-U4X9HPZRtj_CoYZM38jxwzo,1085
198
198
  annet/vendors/library/ribbon.py,sha256=55tlhY8weGTE9x-CDpFUMvEX6pg0KnrXnd-P8bxceGk,1215
199
199
  annet/vendors/library/routeros.py,sha256=0Hi-tDBjgBwfewiZi0EAnXkgGGHlOc_uwpY8xd9p3TM,1253
200
- annet-3.2.0.dist-info/licenses/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
201
- annet-3.2.0.dist-info/licenses/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
200
+ annet-3.3.0.dist-info/licenses/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
201
+ annet-3.3.0.dist-info/licenses/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
202
202
  annet_generators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
203
203
  annet_generators/example/__init__.py,sha256=OJ77uj8axc-FIyIu_Xdcnzmde3oQW5mk5qbODkhuVc8,355
204
204
  annet_generators/example/hostname.py,sha256=RloLzNVetEoWPLITzfJ13Nk3CC0yi-cZB1RTd6dnuhI,2541
@@ -211,8 +211,8 @@ annet_generators/rpl_example/generator.py,sha256=EWah19gOH8G-QyNyWqxCqdRi0BK7GbM
211
211
  annet_generators/rpl_example/items.py,sha256=d99HSXDHFjZq511EvGhIqRTWK3F4ZsCWfdUqFYQcyhE,772
212
212
  annet_generators/rpl_example/mesh.py,sha256=z_WgfDZZ4xnyh3cSf75igyH09hGvtexEVwy1gCD_DzA,288
213
213
  annet_generators/rpl_example/route_policy.py,sha256=z6nPb0VDeQtKD1NIg9sFvmUxBD5tVs2frfNIuKdM-5c,2318
214
- annet-3.2.0.dist-info/METADATA,sha256=z0WLRhcHfc4EychYiW7rFhzAu8MT3YZSvFrkFCxiRCk,815
215
- annet-3.2.0.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
216
- annet-3.2.0.dist-info/entry_points.txt,sha256=5lIaDGlGi3l6QQ2ry2jZaqViP5Lvt8AmsegdD0Uznck,192
217
- annet-3.2.0.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
218
- annet-3.2.0.dist-info/RECORD,,
214
+ annet-3.3.0.dist-info/METADATA,sha256=5C_NTl6Czb2mm3dWoXxyGwGlcuGcdN3kAVYBBWD6Ie0,815
215
+ annet-3.3.0.dist-info/WHEEL,sha256=ck4Vq1_RXyvS4Jt6SI0Vz6fyVs4GWg7AINwpsaGEgPE,91
216
+ annet-3.3.0.dist-info/entry_points.txt,sha256=5lIaDGlGi3l6QQ2ry2jZaqViP5Lvt8AmsegdD0Uznck,192
217
+ annet-3.3.0.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
218
+ annet-3.3.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (79.0.1)
2
+ Generator: setuptools (80.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5