annet 0.16.29__tar.gz → 0.16.30__tar.gz

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 (191) hide show
  1. {annet-0.16.29/annet.egg-info → annet-0.16.30}/PKG-INFO +8 -2
  2. {annet-0.16.29 → annet-0.16.30}/annet/adapters/file/provider.py +3 -0
  3. {annet-0.16.29 → annet-0.16.30}/annet/adapters/netbox/common/models.py +6 -0
  4. {annet-0.16.29 → annet-0.16.30}/annet/annlib/netdev/devdb/data/devdb.json +1 -0
  5. {annet-0.16.29 → annet-0.16.30}/annet/bgp_models.py +17 -0
  6. {annet-0.16.29 → annet-0.16.30}/annet/mesh/executor.py +51 -9
  7. {annet-0.16.29 → annet-0.16.30}/annet/mesh/peer_models.py +4 -0
  8. {annet-0.16.29 → annet-0.16.30}/annet/rpl_generators/community.py +1 -1
  9. {annet-0.16.29 → annet-0.16.30}/annet/storage.py +4 -0
  10. {annet-0.16.29 → annet-0.16.30/annet.egg-info}/PKG-INFO +8 -2
  11. {annet-0.16.29 → annet-0.16.30}/AUTHORS +0 -0
  12. {annet-0.16.29 → annet-0.16.30}/LICENSE +0 -0
  13. {annet-0.16.29 → annet-0.16.30}/MANIFEST.in +0 -0
  14. {annet-0.16.29 → annet-0.16.30}/README.md +0 -0
  15. {annet-0.16.29 → annet-0.16.30}/annet/__init__.py +0 -0
  16. {annet-0.16.29 → annet-0.16.30}/annet/adapters/__init__.py +0 -0
  17. {annet-0.16.29 → annet-0.16.30}/annet/adapters/fetchers/__init__.py +0 -0
  18. {annet-0.16.29 → annet-0.16.30}/annet/adapters/fetchers/stub/__init__.py +0 -0
  19. {annet-0.16.29 → annet-0.16.30}/annet/adapters/fetchers/stub/fetcher.py +0 -0
  20. {annet-0.16.29 → annet-0.16.30}/annet/adapters/file/__init__.py +0 -0
  21. {annet-0.16.29 → annet-0.16.30}/annet/adapters/netbox/__init__.py +0 -0
  22. {annet-0.16.29 → annet-0.16.30}/annet/adapters/netbox/common/__init__.py +0 -0
  23. {annet-0.16.29 → annet-0.16.30}/annet/adapters/netbox/common/client.py +0 -0
  24. {annet-0.16.29 → annet-0.16.30}/annet/adapters/netbox/common/manufacturer.py +0 -0
  25. {annet-0.16.29 → annet-0.16.30}/annet/adapters/netbox/common/query.py +0 -0
  26. {annet-0.16.29 → annet-0.16.30}/annet/adapters/netbox/common/status_client.py +0 -0
  27. {annet-0.16.29 → annet-0.16.30}/annet/adapters/netbox/common/storage_opts.py +0 -0
  28. {annet-0.16.29 → annet-0.16.30}/annet/adapters/netbox/provider.py +0 -0
  29. {annet-0.16.29 → annet-0.16.30}/annet/adapters/netbox/v24/__init__.py +0 -0
  30. {annet-0.16.29 → annet-0.16.30}/annet/adapters/netbox/v24/storage.py +0 -0
  31. {annet-0.16.29 → annet-0.16.30}/annet/adapters/netbox/v37/__init__.py +0 -0
  32. {annet-0.16.29 → annet-0.16.30}/annet/adapters/netbox/v37/storage.py +0 -0
  33. {annet-0.16.29 → annet-0.16.30}/annet/annet.py +0 -0
  34. {annet-0.16.29 → annet-0.16.30}/annet/annlib/__init__.py +0 -0
  35. {annet-0.16.29 → annet-0.16.30}/annet/annlib/command.py +0 -0
  36. {annet-0.16.29 → annet-0.16.30}/annet/annlib/diff.py +0 -0
  37. {annet-0.16.29 → annet-0.16.30}/annet/annlib/errors.py +0 -0
  38. {annet-0.16.29 → annet-0.16.30}/annet/annlib/filter_acl.py +0 -0
  39. {annet-0.16.29 → annet-0.16.30}/annet/annlib/jsontools.py +0 -0
  40. {annet-0.16.29 → annet-0.16.30}/annet/annlib/lib.py +0 -0
  41. {annet-0.16.29 → annet-0.16.30}/annet/annlib/netdev/__init__.py +0 -0
  42. {annet-0.16.29 → annet-0.16.30}/annet/annlib/netdev/db.py +0 -0
  43. {annet-0.16.29 → annet-0.16.30}/annet/annlib/netdev/devdb/__init__.py +0 -0
  44. {annet-0.16.29 → annet-0.16.30}/annet/annlib/netdev/views/__init__.py +0 -0
  45. {annet-0.16.29 → annet-0.16.30}/annet/annlib/netdev/views/dump.py +0 -0
  46. {annet-0.16.29 → annet-0.16.30}/annet/annlib/netdev/views/hardware.py +0 -0
  47. {annet-0.16.29 → annet-0.16.30}/annet/annlib/output.py +0 -0
  48. {annet-0.16.29 → annet-0.16.30}/annet/annlib/patching.py +0 -0
  49. {annet-0.16.29 → annet-0.16.30}/annet/annlib/rbparser/__init__.py +0 -0
  50. {annet-0.16.29 → annet-0.16.30}/annet/annlib/rbparser/acl.py +0 -0
  51. {annet-0.16.29 → annet-0.16.30}/annet/annlib/rbparser/deploying.py +0 -0
  52. {annet-0.16.29 → annet-0.16.30}/annet/annlib/rbparser/ordering.py +0 -0
  53. {annet-0.16.29 → annet-0.16.30}/annet/annlib/rbparser/platform.py +0 -0
  54. {annet-0.16.29 → annet-0.16.30}/annet/annlib/rbparser/syntax.py +0 -0
  55. {annet-0.16.29 → annet-0.16.30}/annet/annlib/rulebook/__init__.py +0 -0
  56. {annet-0.16.29 → annet-0.16.30}/annet/annlib/rulebook/common.py +0 -0
  57. {annet-0.16.29 → annet-0.16.30}/annet/annlib/tabparser.py +0 -0
  58. {annet-0.16.29 → annet-0.16.30}/annet/annlib/types.py +0 -0
  59. {annet-0.16.29 → annet-0.16.30}/annet/api/__init__.py +0 -0
  60. {annet-0.16.29 → annet-0.16.30}/annet/argparse.py +0 -0
  61. {annet-0.16.29 → annet-0.16.30}/annet/cli.py +0 -0
  62. {annet-0.16.29 → annet-0.16.30}/annet/cli_args.py +0 -0
  63. {annet-0.16.29 → annet-0.16.30}/annet/configs/context.yml +0 -0
  64. {annet-0.16.29 → annet-0.16.30}/annet/configs/logging.yaml +0 -0
  65. {annet-0.16.29 → annet-0.16.30}/annet/connectors.py +0 -0
  66. {annet-0.16.29 → annet-0.16.30}/annet/deploy.py +0 -0
  67. {annet-0.16.29 → annet-0.16.30}/annet/diff.py +0 -0
  68. {annet-0.16.29 → annet-0.16.30}/annet/executor.py +0 -0
  69. {annet-0.16.29 → annet-0.16.30}/annet/filtering.py +0 -0
  70. {annet-0.16.29 → annet-0.16.30}/annet/gen.py +0 -0
  71. {annet-0.16.29 → annet-0.16.30}/annet/generators/__init__.py +0 -0
  72. {annet-0.16.29 → annet-0.16.30}/annet/generators/base.py +0 -0
  73. {annet-0.16.29 → annet-0.16.30}/annet/generators/common/__init__.py +0 -0
  74. {annet-0.16.29 → annet-0.16.30}/annet/generators/common/initial.py +0 -0
  75. {annet-0.16.29 → annet-0.16.30}/annet/generators/entire.py +0 -0
  76. {annet-0.16.29 → annet-0.16.30}/annet/generators/exceptions.py +0 -0
  77. {annet-0.16.29 → annet-0.16.30}/annet/generators/jsonfragment.py +0 -0
  78. {annet-0.16.29 → annet-0.16.30}/annet/generators/partial.py +0 -0
  79. {annet-0.16.29 → annet-0.16.30}/annet/generators/perf.py +0 -0
  80. {annet-0.16.29 → annet-0.16.30}/annet/generators/ref.py +0 -0
  81. {annet-0.16.29 → annet-0.16.30}/annet/generators/result.py +0 -0
  82. {annet-0.16.29 → annet-0.16.30}/annet/hardware.py +0 -0
  83. {annet-0.16.29 → annet-0.16.30}/annet/implicit.py +0 -0
  84. {annet-0.16.29 → annet-0.16.30}/annet/lib.py +0 -0
  85. {annet-0.16.29 → annet-0.16.30}/annet/mesh/__init__.py +0 -0
  86. {annet-0.16.29 → annet-0.16.30}/annet/mesh/basemodel.py +0 -0
  87. {annet-0.16.29 → annet-0.16.30}/annet/mesh/device_models.py +0 -0
  88. {annet-0.16.29 → annet-0.16.30}/annet/mesh/match_args.py +0 -0
  89. {annet-0.16.29 → annet-0.16.30}/annet/mesh/models_converter.py +0 -0
  90. {annet-0.16.29 → annet-0.16.30}/annet/mesh/port_processor.py +0 -0
  91. {annet-0.16.29 → annet-0.16.30}/annet/mesh/registry.py +0 -0
  92. {annet-0.16.29 → annet-0.16.30}/annet/output.py +0 -0
  93. {annet-0.16.29 → annet-0.16.30}/annet/parallel.py +0 -0
  94. {annet-0.16.29 → annet-0.16.30}/annet/patching.py +0 -0
  95. {annet-0.16.29 → annet-0.16.30}/annet/reference.py +0 -0
  96. {annet-0.16.29 → annet-0.16.30}/annet/rpl/__init__.py +0 -0
  97. {annet-0.16.29 → annet-0.16.30}/annet/rpl/action.py +0 -0
  98. {annet-0.16.29 → annet-0.16.30}/annet/rpl/condition.py +0 -0
  99. {annet-0.16.29 → annet-0.16.30}/annet/rpl/match_builder.py +0 -0
  100. {annet-0.16.29 → annet-0.16.30}/annet/rpl/policy.py +0 -0
  101. {annet-0.16.29 → annet-0.16.30}/annet/rpl/result.py +0 -0
  102. {annet-0.16.29 → annet-0.16.30}/annet/rpl/routemap.py +0 -0
  103. {annet-0.16.29 → annet-0.16.30}/annet/rpl/statement_builder.py +0 -0
  104. {annet-0.16.29 → annet-0.16.30}/annet/rpl_generators/__init__.py +0 -0
  105. {annet-0.16.29 → annet-0.16.30}/annet/rpl_generators/aspath.py +0 -0
  106. {annet-0.16.29 → annet-0.16.30}/annet/rpl_generators/cumulus_frr.py +0 -0
  107. {annet-0.16.29 → annet-0.16.30}/annet/rpl_generators/entities.py +0 -0
  108. {annet-0.16.29 → annet-0.16.30}/annet/rpl_generators/execute.py +0 -0
  109. {annet-0.16.29 → annet-0.16.30}/annet/rpl_generators/policy.py +0 -0
  110. {annet-0.16.29 → annet-0.16.30}/annet/rpl_generators/prefix_lists.py +0 -0
  111. {annet-0.16.29 → annet-0.16.30}/annet/rpl_generators/rd.py +0 -0
  112. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/__init__.py +0 -0
  113. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/arista/__init__.py +0 -0
  114. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/arista/iface.py +0 -0
  115. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/aruba/__init__.py +0 -0
  116. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/aruba/ap_env.py +0 -0
  117. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/aruba/misc.py +0 -0
  118. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/b4com/__init__.py +0 -0
  119. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/b4com/file.py +0 -0
  120. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/cisco/__init__.py +0 -0
  121. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/cisco/iface.py +0 -0
  122. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/cisco/misc.py +0 -0
  123. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/cisco/vlandb.py +0 -0
  124. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/common.py +0 -0
  125. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/deploying.py +0 -0
  126. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/huawei/__init__.py +0 -0
  127. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/huawei/aaa.py +0 -0
  128. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/huawei/bgp.py +0 -0
  129. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/huawei/iface.py +0 -0
  130. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/huawei/misc.py +0 -0
  131. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/huawei/vlandb.py +0 -0
  132. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/juniper/__init__.py +0 -0
  133. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/nexus/__init__.py +0 -0
  134. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/nexus/iface.py +0 -0
  135. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/patching.py +0 -0
  136. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/ribbon/__init__.py +0 -0
  137. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/routeros/__init__.py +0 -0
  138. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/routeros/file.py +0 -0
  139. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/arista.deploy +0 -0
  140. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/arista.order +0 -0
  141. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/arista.rul +0 -0
  142. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/aruba.deploy +0 -0
  143. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/aruba.order +0 -0
  144. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/aruba.rul +0 -0
  145. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/b4com.deploy +0 -0
  146. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/b4com.order +0 -0
  147. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/b4com.rul +0 -0
  148. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/cisco.deploy +0 -0
  149. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/cisco.order +0 -0
  150. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/cisco.rul +0 -0
  151. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/huawei.deploy +0 -0
  152. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/huawei.order +0 -0
  153. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/huawei.rul +0 -0
  154. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/juniper.rul +0 -0
  155. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/nexus.deploy +0 -0
  156. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/nexus.order +0 -0
  157. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/nexus.rul +0 -0
  158. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/nokia.rul +0 -0
  159. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/optixtrans.deploy +0 -0
  160. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/optixtrans.order +0 -0
  161. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/optixtrans.rul +0 -0
  162. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/pc.deploy +0 -0
  163. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/pc.order +0 -0
  164. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/pc.rul +0 -0
  165. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/ribbon.deploy +0 -0
  166. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/ribbon.rul +0 -0
  167. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/routeros.order +0 -0
  168. {annet-0.16.29 → annet-0.16.30}/annet/rulebook/texts/routeros.rul +0 -0
  169. {annet-0.16.29 → annet-0.16.30}/annet/tabparser.py +0 -0
  170. {annet-0.16.29 → annet-0.16.30}/annet/text_term_format.py +0 -0
  171. {annet-0.16.29 → annet-0.16.30}/annet/tracing.py +0 -0
  172. {annet-0.16.29 → annet-0.16.30}/annet/types.py +0 -0
  173. {annet-0.16.29 → annet-0.16.30}/annet.egg-info/SOURCES.txt +0 -0
  174. {annet-0.16.29 → annet-0.16.30}/annet.egg-info/dependency_links.txt +0 -0
  175. {annet-0.16.29 → annet-0.16.30}/annet.egg-info/entry_points.txt +0 -0
  176. {annet-0.16.29 → annet-0.16.30}/annet.egg-info/requires.txt +0 -0
  177. {annet-0.16.29 → annet-0.16.30}/annet.egg-info/top_level.txt +0 -0
  178. {annet-0.16.29 → annet-0.16.30}/annet_generators/__init__.py +0 -0
  179. {annet-0.16.29 → annet-0.16.30}/annet_generators/example/__init__.py +0 -0
  180. {annet-0.16.29 → annet-0.16.30}/annet_generators/example/lldp.py +0 -0
  181. {annet-0.16.29 → annet-0.16.30}/annet_generators/mesh_example/__init__.py +0 -0
  182. {annet-0.16.29 → annet-0.16.30}/annet_generators/mesh_example/bgp.py +0 -0
  183. {annet-0.16.29 → annet-0.16.30}/annet_generators/mesh_example/mesh_logic.py +0 -0
  184. {annet-0.16.29 → annet-0.16.30}/annet_generators/rpl_example/__init__.py +0 -0
  185. {annet-0.16.29 → annet-0.16.30}/annet_generators/rpl_example/generator.py +0 -0
  186. {annet-0.16.29 → annet-0.16.30}/annet_generators/rpl_example/items.py +0 -0
  187. {annet-0.16.29 → annet-0.16.30}/annet_generators/rpl_example/mesh.py +0 -0
  188. {annet-0.16.29 → annet-0.16.30}/annet_generators/rpl_example/route_policy.py +0 -0
  189. {annet-0.16.29 → annet-0.16.30}/requirements.txt +0 -0
  190. {annet-0.16.29 → annet-0.16.30}/setup.cfg +0 -0
  191. {annet-0.16.29 → annet-0.16.30}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: annet
3
- Version: 0.16.29
3
+ Version: 0.16.30
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -24,3 +24,9 @@ Requires-Dist: adaptix==3.0.0b7
24
24
  Requires-Dist: dataclass-rest==0.4
25
25
  Provides-Extra: netbox
26
26
  Requires-Dist: annetbox[sync]>=0.1.10; extra == "netbox"
27
+ Dynamic: home-page
28
+ Dynamic: license
29
+ Dynamic: provides-extra
30
+ Dynamic: requires-dist
31
+ Dynamic: requires-python
32
+ Dynamic: summary
@@ -102,6 +102,9 @@ class Device(DeviceCls, DumpableView):
102
102
  def add_subif(self, interface: str, subif: int) -> Interface:
103
103
  raise NotImplementedError
104
104
 
105
+ def find_interface(self, name: str) -> Optional[Interface]:
106
+ raise NotImplementedError
107
+
105
108
  def neighbours_fqdns(self) -> list[str]:
106
109
  return []
107
110
 
@@ -281,3 +281,9 @@ class NetboxDevice(Entity):
281
281
  )
282
282
  self.interfaces.append(target_port)
283
283
  return target_port
284
+
285
+ def find_interface(self, name: str) -> Optional[Interface]:
286
+ for iface in self.interfaces:
287
+ if iface.name == name:
288
+ return iface
289
+ return None
@@ -116,6 +116,7 @@
116
116
  "PC.Whitebox.Edgecore": "[Ee]dge-?[Cc]ore",
117
117
  "PC.Whitebox.Edgecore.AS": "AS",
118
118
  "PC.Whitebox.Edgecore.AS9736": "AS9736",
119
+ "PC.Whitebox.Edgecore.AS9817": "AS9817",
119
120
  "PC.Whitebox.NVIDIA": "NVIDIA",
120
121
  "PC.Whitebox.NVIDIA.SN": " SN",
121
122
  "PC.Whitebox.NVIDIA.SN.SN5400": " SN5400",
@@ -286,13 +286,30 @@ def _used_policies(peer: Union[Peer, PeerGroup]) -> Iterable[str]:
286
286
  yield peer.export_policy
287
287
 
288
288
 
289
+ def _used_redistribute_policies(opts: Union[GlobalOptions, VrfOptions]) -> Iterable[str]:
290
+ for red in opts.ipv4_unicast.redistributes:
291
+ if red.policy:
292
+ yield red.policy
293
+ for red in opts.ipv6_unicast.redistributes:
294
+ if red.policy:
295
+ yield red.policy
296
+ for red in opts.ipv4_labeled_unicast.redistributes:
297
+ if red.policy:
298
+ yield red.policy
299
+ for red in opts.ipv6_labeled_unicast.redistributes:
300
+ if red.policy:
301
+ yield red.policy
302
+
303
+
289
304
  def extract_policies(config: BgpConfig) -> Sequence[str]:
290
305
  result: list[str] = []
291
306
  for vrf in config.global_options.vrf.values():
292
307
  for group in vrf.groups:
293
308
  result.extend(_used_policies(group))
309
+ result.extend(_used_redistribute_policies(vrf))
294
310
  for group in config.global_options.groups:
295
311
  result.extend(_used_policies(group))
296
312
  for peer in config.peers:
297
313
  result.extend(_used_policies(peer))
314
+ result.extend(_used_redistribute_policies(config.global_options))
298
315
  return result
@@ -124,12 +124,20 @@ class MeshExecutor:
124
124
  # we merge them according to remote fqdn
125
125
  neighbor_peers: dict[PeerKey, Pair] = {}
126
126
  # TODO batch resolve
127
- for rule in self._registry.lookup_direct(device.fqdn, device.neighbours_fqdns):
127
+ rules = self._registry.lookup_direct(device.fqdn, device.neighbours_fqdns)
128
+ fqdns = {
129
+ rule.name_right if rule.direct_order else rule.name_left
130
+ for rule in rules
131
+ }
132
+ neigbors = {
133
+ d.fqdn: d for d in self._storage.make_devices(list(fqdns))
134
+ }
135
+ for rule in rules:
128
136
  handler_name = self._handler_name(rule.handler)
129
137
  if rule.direct_order:
130
- neighbor_device = self._storage.make_devices([rule.name_right])[0]
138
+ neighbor_device = neigbors[rule.name_right]
131
139
  else:
132
- neighbor_device = self._storage.make_devices([rule.name_left])[0]
140
+ neighbor_device = neigbors[rule.name_left]
133
141
  all_connected_ports = [
134
142
  (p1.name, p2.name)
135
143
  for p1, p2 in self._storage.search_connections(device, neighbor_device)
@@ -200,17 +208,26 @@ class MeshExecutor:
200
208
  # we can have multiple rules for the same pair
201
209
  # we merge them according to remote fqdn
202
210
  connected_peers: dict[PeerKey, Pair] = {}
203
- for rule in self._registry.lookup_indirect(device.fqdn, all_fqdns):
211
+
212
+ rules = self._registry.lookup_indirect(device.fqdn, all_fqdns)
213
+ fqdns = {
214
+ rule.name_right if rule.direct_order else rule.name_left
215
+ for rule in rules
216
+ }
217
+ connected_devices = {
218
+ d.fqdn: d for d in self._storage.make_devices(list(fqdns))
219
+ }
220
+ for rule in rules:
204
221
  session = MeshSession()
205
222
  handler_name = self._handler_name(rule.handler)
206
223
  logger.debug("Running indirect handler: %s", handler_name)
207
224
  if rule.direct_order:
208
- connected_device = self._storage.make_devices([rule.name_right])[0]
225
+ connected_device = connected_devices[rule.name_right]
209
226
  peer_device = IndirectPeer(rule.match_left, device)
210
227
  peer_connected = IndirectPeer(rule.match_right, connected_device)
211
228
  rule.handler(peer_device, peer_connected, session)
212
229
  else:
213
- connected_device = self._storage.make_devices([rule.name_left])[0]
230
+ connected_device = connected_devices[rule.name_left]
214
231
  peer_connected = IndirectPeer(rule.match_left, connected_device)
215
232
  peer_device = IndirectPeer(rule.match_right, device)
216
233
  rule.handler(peer_connected, peer_device, session)
@@ -265,7 +282,7 @@ class MeshExecutor:
265
282
  def _to_bgp_global(self, global_options: GlobalOptionsDTO) -> GlobalOptions:
266
283
  return to_bgp_global_options(global_options)
267
284
 
268
- def _apply_interface_changes(
285
+ def _apply_direct_interface_changes(
269
286
  self, device: Device, neighbor: Device, ports: list[str], changes: InterfaceChanges,
270
287
  ) -> str:
271
288
  # filter ports according to processed in pair
@@ -299,6 +316,24 @@ class MeshExecutor:
299
316
  target_interface.add_addr(changes.addr, changes.vrf)
300
317
  return target_interface.name
301
318
 
319
+ def _apply_indirect_interface_changes(
320
+ self, device: Device, neighbor: Device, ifname: Optional[str], changes: InterfaceChanges,
321
+ ) -> Optional[str]:
322
+ if changes.lag is not None:
323
+ raise ValueError("LAG creation unsupported for indirect peers")
324
+ elif changes.subif is not None:
325
+ target_interface = device.add_subif(ifname, changes.subif)
326
+ elif changes.svi is not None:
327
+ target_interface = device.add_svi(changes.svi)
328
+ elif not ifname:
329
+ return None
330
+ else:
331
+ target_interface = device.find_interface(ifname)
332
+ if not target_interface:
333
+ raise ValueError(f"Interface {ifname} not found for device {device.fqdn}")
334
+ target_interface.add_addr(changes.addr, changes.vrf)
335
+ return target_interface.name
336
+
302
337
  def _apply_virtual_interface_changes(self, device: Device, local: VirtualLocalDTO) -> str:
303
338
  return device.add_svi(local.svi).name # we check if SVI configured in execute method
304
339
 
@@ -308,8 +343,9 @@ class MeshExecutor:
308
343
  global_options = self._to_bgp_global(self._execute_globals(device))
309
344
 
310
345
  peers = []
346
+ target_interface: Optional[str]
311
347
  for direct_pair in self._execute_direct(device):
312
- target_interface = self._apply_interface_changes(
348
+ target_interface = self._apply_direct_interface_changes(
313
349
  device,
314
350
  direct_pair.device,
315
351
  direct_pair.ports,
@@ -325,7 +361,13 @@ class MeshExecutor:
325
361
  peers.append(self._virtual_to_bgp_peer(virtual_pair, target_interface))
326
362
 
327
363
  for connected_pair in self._execute_indirect(device, all_fqdns):
328
- peers.append(self._to_bgp_peer(connected_pair, None))
364
+ target_interface = self._apply_indirect_interface_changes(
365
+ device,
366
+ connected_pair.device,
367
+ getattr(connected_pair.local, "ifname", None),
368
+ to_interface_changes(connected_pair.local),
369
+ )
370
+ peers.append(self._to_bgp_peer(connected_pair, target_interface))
329
371
 
330
372
  return BgpConfig(
331
373
  global_options=global_options,
@@ -95,6 +95,10 @@ class IndirectPeerDTO(MeshSession, _OptionsDTO):
95
95
  description: str
96
96
  update_source: str
97
97
 
98
+ ifname: Optional[str]
99
+ subif: int
100
+ svi: Optional[int]
101
+
98
102
 
99
103
  class VirtualLocalDTO(_OptionsDTO):
100
104
  asnum: int
@@ -164,7 +164,7 @@ class CommunityListGenerator(PartialGenerator, ABC):
164
164
  yield self._huawei_community_filter(10, community_list, " ".join(members))
165
165
  elif community_list.logic == CommunityLogic.OR:
166
166
  for i, member in enumerate(members):
167
- member_id = (i + 1) * 10 + 5
167
+ member_id = (i + 1) * 10
168
168
  yield self._huawei_community_filter(member_id, community_list, member)
169
169
  else:
170
170
  raise NotImplementedError(f"Community logic {community_list.logic} is not implemented for huawei")
@@ -168,6 +168,10 @@ class Device(Protocol):
168
168
  """Add sub interface or return existing one"""
169
169
  raise NotImplementedError
170
170
 
171
+ @abc.abstractmethod
172
+ def find_interface(self, name: str) -> Optional[Interface]:
173
+ raise NotImplementedError
174
+
171
175
 
172
176
  def get_storage() -> tuple[StorageProvider, Dict[str, Any]]:
173
177
  connectors = storage_connector.get_all()
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: annet
3
- Version: 0.16.29
3
+ Version: 0.16.30
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -24,3 +24,9 @@ Requires-Dist: adaptix==3.0.0b7
24
24
  Requires-Dist: dataclass-rest==0.4
25
25
  Provides-Extra: netbox
26
26
  Requires-Dist: annetbox[sync]>=0.1.10; extra == "netbox"
27
+ Dynamic: home-page
28
+ Dynamic: license
29
+ Dynamic: provides-extra
30
+ Dynamic: requires-dist
31
+ Dynamic: requires-python
32
+ Dynamic: summary
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes