annet 0.16.33__tar.gz → 0.16.34__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 (192) hide show
  1. {annet-0.16.33/annet.egg-info → annet-0.16.34}/PKG-INFO +2 -2
  2. {annet-0.16.33 → annet-0.16.34}/annet/adapters/netbox/v37/storage.py +38 -13
  3. {annet-0.16.33 → annet-0.16.34}/annet/annlib/netdev/devdb/data/devdb.json +3 -1
  4. {annet-0.16.33 → annet-0.16.34}/annet/annlib/rulebook/common.py +2 -2
  5. {annet-0.16.33 → annet-0.16.34}/annet/bgp_models.py +12 -16
  6. {annet-0.16.33 → annet-0.16.34}/annet/mesh/device_models.py +1 -2
  7. {annet-0.16.33 → annet-0.16.34}/annet/mesh/executor.py +9 -0
  8. {annet-0.16.33 → annet-0.16.34}/annet/mesh/registry.py +12 -12
  9. annet-0.16.34/annet/rulebook/b4com/iface.py +42 -0
  10. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/b4com.rul +9 -4
  11. {annet-0.16.33 → annet-0.16.34/annet.egg-info}/PKG-INFO +2 -2
  12. {annet-0.16.33 → annet-0.16.34}/annet.egg-info/SOURCES.txt +1 -0
  13. {annet-0.16.33 → annet-0.16.34}/annet.egg-info/requires.txt +1 -1
  14. {annet-0.16.33 → annet-0.16.34}/setup.py +1 -1
  15. {annet-0.16.33 → annet-0.16.34}/AUTHORS +0 -0
  16. {annet-0.16.33 → annet-0.16.34}/LICENSE +0 -0
  17. {annet-0.16.33 → annet-0.16.34}/MANIFEST.in +0 -0
  18. {annet-0.16.33 → annet-0.16.34}/README.md +0 -0
  19. {annet-0.16.33 → annet-0.16.34}/annet/__init__.py +0 -0
  20. {annet-0.16.33 → annet-0.16.34}/annet/adapters/__init__.py +0 -0
  21. {annet-0.16.33 → annet-0.16.34}/annet/adapters/fetchers/__init__.py +0 -0
  22. {annet-0.16.33 → annet-0.16.34}/annet/adapters/fetchers/stub/__init__.py +0 -0
  23. {annet-0.16.33 → annet-0.16.34}/annet/adapters/fetchers/stub/fetcher.py +0 -0
  24. {annet-0.16.33 → annet-0.16.34}/annet/adapters/file/__init__.py +0 -0
  25. {annet-0.16.33 → annet-0.16.34}/annet/adapters/file/provider.py +0 -0
  26. {annet-0.16.33 → annet-0.16.34}/annet/adapters/netbox/__init__.py +0 -0
  27. {annet-0.16.33 → annet-0.16.34}/annet/adapters/netbox/common/__init__.py +0 -0
  28. {annet-0.16.33 → annet-0.16.34}/annet/adapters/netbox/common/client.py +0 -0
  29. {annet-0.16.33 → annet-0.16.34}/annet/adapters/netbox/common/manufacturer.py +0 -0
  30. {annet-0.16.33 → annet-0.16.34}/annet/adapters/netbox/common/models.py +0 -0
  31. {annet-0.16.33 → annet-0.16.34}/annet/adapters/netbox/common/query.py +0 -0
  32. {annet-0.16.33 → annet-0.16.34}/annet/adapters/netbox/common/status_client.py +0 -0
  33. {annet-0.16.33 → annet-0.16.34}/annet/adapters/netbox/common/storage_opts.py +0 -0
  34. {annet-0.16.33 → annet-0.16.34}/annet/adapters/netbox/provider.py +0 -0
  35. {annet-0.16.33 → annet-0.16.34}/annet/adapters/netbox/v24/__init__.py +0 -0
  36. {annet-0.16.33 → annet-0.16.34}/annet/adapters/netbox/v24/storage.py +0 -0
  37. {annet-0.16.33 → annet-0.16.34}/annet/adapters/netbox/v37/__init__.py +0 -0
  38. {annet-0.16.33 → annet-0.16.34}/annet/annet.py +0 -0
  39. {annet-0.16.33 → annet-0.16.34}/annet/annlib/__init__.py +0 -0
  40. {annet-0.16.33 → annet-0.16.34}/annet/annlib/command.py +0 -0
  41. {annet-0.16.33 → annet-0.16.34}/annet/annlib/diff.py +0 -0
  42. {annet-0.16.33 → annet-0.16.34}/annet/annlib/errors.py +0 -0
  43. {annet-0.16.33 → annet-0.16.34}/annet/annlib/filter_acl.py +0 -0
  44. {annet-0.16.33 → annet-0.16.34}/annet/annlib/jsontools.py +0 -0
  45. {annet-0.16.33 → annet-0.16.34}/annet/annlib/lib.py +0 -0
  46. {annet-0.16.33 → annet-0.16.34}/annet/annlib/netdev/__init__.py +0 -0
  47. {annet-0.16.33 → annet-0.16.34}/annet/annlib/netdev/db.py +0 -0
  48. {annet-0.16.33 → annet-0.16.34}/annet/annlib/netdev/devdb/__init__.py +0 -0
  49. {annet-0.16.33 → annet-0.16.34}/annet/annlib/netdev/views/__init__.py +0 -0
  50. {annet-0.16.33 → annet-0.16.34}/annet/annlib/netdev/views/dump.py +0 -0
  51. {annet-0.16.33 → annet-0.16.34}/annet/annlib/netdev/views/hardware.py +0 -0
  52. {annet-0.16.33 → annet-0.16.34}/annet/annlib/output.py +0 -0
  53. {annet-0.16.33 → annet-0.16.34}/annet/annlib/patching.py +0 -0
  54. {annet-0.16.33 → annet-0.16.34}/annet/annlib/rbparser/__init__.py +0 -0
  55. {annet-0.16.33 → annet-0.16.34}/annet/annlib/rbparser/acl.py +0 -0
  56. {annet-0.16.33 → annet-0.16.34}/annet/annlib/rbparser/deploying.py +0 -0
  57. {annet-0.16.33 → annet-0.16.34}/annet/annlib/rbparser/ordering.py +0 -0
  58. {annet-0.16.33 → annet-0.16.34}/annet/annlib/rbparser/platform.py +0 -0
  59. {annet-0.16.33 → annet-0.16.34}/annet/annlib/rbparser/syntax.py +0 -0
  60. {annet-0.16.33 → annet-0.16.34}/annet/annlib/rulebook/__init__.py +0 -0
  61. {annet-0.16.33 → annet-0.16.34}/annet/annlib/tabparser.py +0 -0
  62. {annet-0.16.33 → annet-0.16.34}/annet/annlib/types.py +0 -0
  63. {annet-0.16.33 → annet-0.16.34}/annet/api/__init__.py +0 -0
  64. {annet-0.16.33 → annet-0.16.34}/annet/argparse.py +0 -0
  65. {annet-0.16.33 → annet-0.16.34}/annet/cli.py +0 -0
  66. {annet-0.16.33 → annet-0.16.34}/annet/cli_args.py +0 -0
  67. {annet-0.16.33 → annet-0.16.34}/annet/configs/context.yml +0 -0
  68. {annet-0.16.33 → annet-0.16.34}/annet/configs/logging.yaml +0 -0
  69. {annet-0.16.33 → annet-0.16.34}/annet/connectors.py +0 -0
  70. {annet-0.16.33 → annet-0.16.34}/annet/deploy.py +0 -0
  71. {annet-0.16.33 → annet-0.16.34}/annet/diff.py +0 -0
  72. {annet-0.16.33 → annet-0.16.34}/annet/executor.py +0 -0
  73. {annet-0.16.33 → annet-0.16.34}/annet/filtering.py +0 -0
  74. {annet-0.16.33 → annet-0.16.34}/annet/gen.py +0 -0
  75. {annet-0.16.33 → annet-0.16.34}/annet/generators/__init__.py +0 -0
  76. {annet-0.16.33 → annet-0.16.34}/annet/generators/base.py +0 -0
  77. {annet-0.16.33 → annet-0.16.34}/annet/generators/common/__init__.py +0 -0
  78. {annet-0.16.33 → annet-0.16.34}/annet/generators/common/initial.py +0 -0
  79. {annet-0.16.33 → annet-0.16.34}/annet/generators/entire.py +0 -0
  80. {annet-0.16.33 → annet-0.16.34}/annet/generators/exceptions.py +0 -0
  81. {annet-0.16.33 → annet-0.16.34}/annet/generators/jsonfragment.py +0 -0
  82. {annet-0.16.33 → annet-0.16.34}/annet/generators/partial.py +0 -0
  83. {annet-0.16.33 → annet-0.16.34}/annet/generators/perf.py +0 -0
  84. {annet-0.16.33 → annet-0.16.34}/annet/generators/ref.py +0 -0
  85. {annet-0.16.33 → annet-0.16.34}/annet/generators/result.py +0 -0
  86. {annet-0.16.33 → annet-0.16.34}/annet/hardware.py +0 -0
  87. {annet-0.16.33 → annet-0.16.34}/annet/implicit.py +0 -0
  88. {annet-0.16.33 → annet-0.16.34}/annet/lib.py +0 -0
  89. {annet-0.16.33 → annet-0.16.34}/annet/mesh/__init__.py +0 -0
  90. {annet-0.16.33 → annet-0.16.34}/annet/mesh/basemodel.py +0 -0
  91. {annet-0.16.33 → annet-0.16.34}/annet/mesh/match_args.py +0 -0
  92. {annet-0.16.33 → annet-0.16.34}/annet/mesh/models_converter.py +0 -0
  93. {annet-0.16.33 → annet-0.16.34}/annet/mesh/peer_models.py +0 -0
  94. {annet-0.16.33 → annet-0.16.34}/annet/mesh/port_processor.py +0 -0
  95. {annet-0.16.33 → annet-0.16.34}/annet/output.py +0 -0
  96. {annet-0.16.33 → annet-0.16.34}/annet/parallel.py +0 -0
  97. {annet-0.16.33 → annet-0.16.34}/annet/patching.py +0 -0
  98. {annet-0.16.33 → annet-0.16.34}/annet/reference.py +0 -0
  99. {annet-0.16.33 → annet-0.16.34}/annet/rpl/__init__.py +0 -0
  100. {annet-0.16.33 → annet-0.16.34}/annet/rpl/action.py +0 -0
  101. {annet-0.16.33 → annet-0.16.34}/annet/rpl/condition.py +0 -0
  102. {annet-0.16.33 → annet-0.16.34}/annet/rpl/match_builder.py +0 -0
  103. {annet-0.16.33 → annet-0.16.34}/annet/rpl/policy.py +0 -0
  104. {annet-0.16.33 → annet-0.16.34}/annet/rpl/result.py +0 -0
  105. {annet-0.16.33 → annet-0.16.34}/annet/rpl/routemap.py +0 -0
  106. {annet-0.16.33 → annet-0.16.34}/annet/rpl/statement_builder.py +0 -0
  107. {annet-0.16.33 → annet-0.16.34}/annet/rpl_generators/__init__.py +0 -0
  108. {annet-0.16.33 → annet-0.16.34}/annet/rpl_generators/aspath.py +0 -0
  109. {annet-0.16.33 → annet-0.16.34}/annet/rpl_generators/community.py +0 -0
  110. {annet-0.16.33 → annet-0.16.34}/annet/rpl_generators/cumulus_frr.py +0 -0
  111. {annet-0.16.33 → annet-0.16.34}/annet/rpl_generators/entities.py +0 -0
  112. {annet-0.16.33 → annet-0.16.34}/annet/rpl_generators/execute.py +0 -0
  113. {annet-0.16.33 → annet-0.16.34}/annet/rpl_generators/policy.py +0 -0
  114. {annet-0.16.33 → annet-0.16.34}/annet/rpl_generators/prefix_lists.py +0 -0
  115. {annet-0.16.33 → annet-0.16.34}/annet/rpl_generators/rd.py +0 -0
  116. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/__init__.py +0 -0
  117. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/arista/__init__.py +0 -0
  118. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/arista/iface.py +0 -0
  119. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/aruba/__init__.py +0 -0
  120. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/aruba/ap_env.py +0 -0
  121. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/aruba/misc.py +0 -0
  122. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/b4com/__init__.py +0 -0
  123. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/b4com/file.py +0 -0
  124. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/cisco/__init__.py +0 -0
  125. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/cisco/iface.py +0 -0
  126. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/cisco/misc.py +0 -0
  127. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/cisco/vlandb.py +0 -0
  128. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/common.py +0 -0
  129. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/deploying.py +0 -0
  130. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/huawei/__init__.py +0 -0
  131. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/huawei/aaa.py +0 -0
  132. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/huawei/bgp.py +0 -0
  133. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/huawei/iface.py +0 -0
  134. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/huawei/misc.py +0 -0
  135. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/huawei/vlandb.py +0 -0
  136. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/juniper/__init__.py +0 -0
  137. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/nexus/__init__.py +0 -0
  138. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/nexus/iface.py +0 -0
  139. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/patching.py +0 -0
  140. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/ribbon/__init__.py +0 -0
  141. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/routeros/__init__.py +0 -0
  142. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/routeros/file.py +0 -0
  143. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/arista.deploy +0 -0
  144. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/arista.order +0 -0
  145. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/arista.rul +0 -0
  146. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/aruba.deploy +0 -0
  147. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/aruba.order +0 -0
  148. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/aruba.rul +0 -0
  149. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/b4com.deploy +0 -0
  150. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/b4com.order +0 -0
  151. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/cisco.deploy +0 -0
  152. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/cisco.order +0 -0
  153. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/cisco.rul +0 -0
  154. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/huawei.deploy +0 -0
  155. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/huawei.order +0 -0
  156. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/huawei.rul +0 -0
  157. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/juniper.rul +0 -0
  158. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/nexus.deploy +0 -0
  159. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/nexus.order +0 -0
  160. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/nexus.rul +0 -0
  161. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/nokia.rul +0 -0
  162. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/optixtrans.deploy +0 -0
  163. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/optixtrans.order +0 -0
  164. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/optixtrans.rul +0 -0
  165. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/pc.deploy +0 -0
  166. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/pc.order +0 -0
  167. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/pc.rul +0 -0
  168. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/ribbon.deploy +0 -0
  169. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/ribbon.rul +0 -0
  170. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/routeros.order +0 -0
  171. {annet-0.16.33 → annet-0.16.34}/annet/rulebook/texts/routeros.rul +0 -0
  172. {annet-0.16.33 → annet-0.16.34}/annet/storage.py +0 -0
  173. {annet-0.16.33 → annet-0.16.34}/annet/tabparser.py +0 -0
  174. {annet-0.16.33 → annet-0.16.34}/annet/text_term_format.py +0 -0
  175. {annet-0.16.33 → annet-0.16.34}/annet/tracing.py +0 -0
  176. {annet-0.16.33 → annet-0.16.34}/annet/types.py +0 -0
  177. {annet-0.16.33 → annet-0.16.34}/annet.egg-info/dependency_links.txt +0 -0
  178. {annet-0.16.33 → annet-0.16.34}/annet.egg-info/entry_points.txt +0 -0
  179. {annet-0.16.33 → annet-0.16.34}/annet.egg-info/top_level.txt +0 -0
  180. {annet-0.16.33 → annet-0.16.34}/annet_generators/__init__.py +0 -0
  181. {annet-0.16.33 → annet-0.16.34}/annet_generators/example/__init__.py +0 -0
  182. {annet-0.16.33 → annet-0.16.34}/annet_generators/example/lldp.py +0 -0
  183. {annet-0.16.33 → annet-0.16.34}/annet_generators/mesh_example/__init__.py +0 -0
  184. {annet-0.16.33 → annet-0.16.34}/annet_generators/mesh_example/bgp.py +0 -0
  185. {annet-0.16.33 → annet-0.16.34}/annet_generators/mesh_example/mesh_logic.py +0 -0
  186. {annet-0.16.33 → annet-0.16.34}/annet_generators/rpl_example/__init__.py +0 -0
  187. {annet-0.16.33 → annet-0.16.34}/annet_generators/rpl_example/generator.py +0 -0
  188. {annet-0.16.33 → annet-0.16.34}/annet_generators/rpl_example/items.py +0 -0
  189. {annet-0.16.33 → annet-0.16.34}/annet_generators/rpl_example/mesh.py +0 -0
  190. {annet-0.16.33 → annet-0.16.34}/annet_generators/rpl_example/route_policy.py +0 -0
  191. {annet-0.16.33 → annet-0.16.34}/requirements.txt +0 -0
  192. {annet-0.16.33 → annet-0.16.34}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: annet
3
- Version: 0.16.33
3
+ Version: 0.16.34
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -23,7 +23,7 @@ Requires-Dist: yarl>=1.8.2
23
23
  Requires-Dist: adaptix==3.0.0b7
24
24
  Requires-Dist: dataclass-rest==0.4
25
25
  Provides-Extra: netbox
26
- Requires-Dist: annetbox[sync]>=0.1.10; extra == "netbox"
26
+ Requires-Dist: annetbox[sync]>=0.1.12; extra == "netbox"
27
27
  Dynamic: home-page
28
28
  Dynamic: license
29
29
  Dynamic: provides-extra
@@ -165,17 +165,28 @@ class NetboxStorageV37(Storage):
165
165
  def _load_devices(self, query: NetboxQuery) -> List[api_models.Device]:
166
166
  if not query.globs:
167
167
  return []
168
+ devices = []
169
+ device_ids = set()
170
+ query_groups = parse_glob(query.globs)
168
171
  if self.exact_host_filter:
169
- devices = self.netbox.dcim_all_devices(name__ie=query.globs).results
170
- else:
171
- query = _hostname_dot_hack(query)
172
- devices = [
173
- device
174
- for device in self.netbox.dcim_all_devices(
175
- name__ic=query.globs,
176
- ).results
177
- if _match_query(query, device)
178
- ]
172
+ name_ies = [_hostname_dot_hack(query) for query in query_groups.pop("name__ic", [])]
173
+ query_groups["name__ie"].extend(name_ies)
174
+ for grp, params in query_groups.items():
175
+ if not params:
176
+ continue
177
+ try:
178
+ new_devices = self.netbox.dcim_all_devices(**{grp: params}).results
179
+ except Exception as e:
180
+ # tag and site lookup returns 400 in case of unknown tag or site
181
+ if "is not one of the available choices" in str(e):
182
+ continue
183
+ raise
184
+ if grp == "name__ic":
185
+ new_devices = [device for device in new_devices if _match_query(query, device)]
186
+ for device in new_devices:
187
+ if device.id not in device_ids:
188
+ device_ids.add(device.id)
189
+ devices.extend(new_devices)
179
190
  return devices
180
191
 
181
192
  def _extend_interfaces(self, interfaces: List[models.Interface]) -> List[models.Interface]:
@@ -268,7 +279,7 @@ def _match_query(query: NetboxQuery, device_data: api_models.Device) -> bool:
268
279
  return False
269
280
 
270
281
 
271
- def _hostname_dot_hack(netbox_query: NetboxQuery) -> NetboxQuery:
282
+ def _hostname_dot_hack(raw_query: str) -> str:
272
283
  # there is no proper way to lookup host by its hostname
273
284
  # ie find "host" with fqdn "host.example.com"
274
285
  # besides using name__ic (ie startswith)
@@ -280,9 +291,23 @@ def _hostname_dot_hack(netbox_query: NetboxQuery) -> NetboxQuery:
280
291
  raw_query = raw_query + "."
281
292
  return raw_query
282
293
 
283
- raw_query = netbox_query.query
284
294
  if isinstance(raw_query, list):
285
295
  for i, name in enumerate(raw_query):
286
296
  raw_query[i] = add_dot(name)
287
297
 
288
- return NetboxQuery(raw_query)
298
+ return raw_query
299
+
300
+
301
+ def parse_glob(globs: list[str]) -> dict[str, list[str]]:
302
+ query_groups: dict[str, list[str]] = {"tag": [], "site": [], "name__ic": []}
303
+ for q in globs:
304
+ if ":" in q:
305
+ glob_type, param = q.split(":", 2)
306
+ if glob_type not in query_groups:
307
+ raise Exception(f"unknown query type: '{glob_type}'")
308
+ if not param:
309
+ raise Exception(f"empty param for '{glob_type}'")
310
+ query_groups[glob_type].append(param)
311
+ else:
312
+ query_groups["name__ic"].append(q)
313
+ return query_groups
@@ -166,6 +166,8 @@
166
166
 
167
167
  "B4com": "^[Bb]4com",
168
168
  "B4com.CS2148P": "^[Bb]4com B4T-CS2148P.*",
169
+ "B4com.CS4100": "^[Bb]4com B4T-CS41.*",
170
+ "B4com.CS4132U": "^[Bb]4com B4T-CS4132U.*",
169
171
  "B4com.CS4148Q": "^[Bb]4com B4T-CS4148Q.*",
170
- "B4com.CS4146U": "^[Bb]4com B4T-CS4146U.*"
172
+ "B4com.CS4164U": "^[Bb]4com B4T-CS4164U.*"
171
173
  }
@@ -346,14 +346,14 @@ def apply(hw, do_commit, do_finalize, **_):
346
346
  after.add_cmd(Command("exit"))
347
347
  elif hw.B4com.CS2148P:
348
348
  before.add_cmd(Command("conf t"))
349
- after.add_cmd(Command("exit"))
349
+ after.add_cmd(Command("end"))
350
350
  if do_finalize:
351
351
  after.add_cmd(Command("write", timeout=40))
352
352
  elif hw.B4com:
353
353
  before.add_cmd(Command("conf t"))
354
- after.add_cmd(Command("exit"))
355
354
  if do_commit:
356
355
  after.add_cmd(Command("commit"))
356
+ after.add_cmd(Command("end"))
357
357
  if do_finalize:
358
358
  after.add_cmd(Command("write", timeout=40))
359
359
  elif hw.H3C:
@@ -142,7 +142,6 @@ class Peer:
142
142
  class Aggregate:
143
143
  policy: str = ""
144
144
  routes: tuple[str, ...] = () # "182.168.1.0/24",
145
- export_policy: str = ""
146
145
  as_path: str = ""
147
146
  reference: str = ""
148
147
  suppress: bool = False
@@ -290,21 +289,18 @@ def _used_policies(peer: Union[Peer, PeerGroup]) -> Iterable[str]:
290
289
 
291
290
 
292
291
  def _used_redistribute_policies(opts: Union[GlobalOptions, VrfOptions]) -> Iterable[str]:
293
- for red in opts.ipv4_unicast.redistributes:
294
- if red.policy:
295
- yield red.policy
296
- for red in opts.ipv6_unicast.redistributes:
297
- if red.policy:
298
- yield red.policy
299
- for red in opts.ipv4_labeled_unicast.redistributes:
300
- if red.policy:
301
- yield red.policy
302
- for red in opts.ipv6_labeled_unicast.redistributes:
303
- if red.policy:
304
- yield red.policy
305
- for red in opts.l2vpn_evpn.redistributes:
306
- if red.policy:
307
- yield red.policy
292
+ for family_opts in (
293
+ opts.ipv4_unicast,
294
+ opts.ipv6_unicast,
295
+ opts.ipv4_labeled_unicast,
296
+ opts.ipv6_labeled_unicast,
297
+ opts.l2vpn_evpn,
298
+ ):
299
+ for red in family_opts.redistributes:
300
+ if red.policy:
301
+ yield red.policy
302
+ if family_opts.aggregate and family_opts.aggregate.policy:
303
+ yield family_opts.aggregate.policy
308
304
 
309
305
 
310
306
  def extract_policies(config: BgpConfig) -> Sequence[str]:
@@ -8,7 +8,6 @@ from .peer_models import MeshPeerGroup
8
8
  class Aggregate(BaseMeshModel):
9
9
  policy: str
10
10
  routes: Annotated[tuple[str, ...], Concat()]
11
- export_policy: str
12
11
  as_path: str
13
12
  reference: str
14
13
  suppress: bool
@@ -22,7 +21,7 @@ class FamilyOptions(BaseMeshModel):
22
21
  super().__init__(**kwargs)
23
22
  family: Family
24
23
  vrf_name: str
25
- multipath: int = 0
24
+ multipath: int
26
25
  global_multipath: int
27
26
  aggregate: Annotated[Aggregate, Merge()]
28
27
  redistributes: Annotated[tuple[Redistribute, ...], Concat()]
@@ -144,8 +144,17 @@ class MeshExecutor:
144
144
  for rule in rules:
145
145
  handler_name = self._handler_name(rule.handler)
146
146
  if rule.direct_order:
147
+ if rule.name_right not in neigbors:
148
+ print(list(neigbors), flush=True)
149
+ raise ValueError(
150
+ f"Device `{device.fqdn}` has no neighbor `{rule.name_right}` required for `{handler_name}`. {list(neigbors)}",
151
+ )
147
152
  neighbor_device = neigbors[rule.name_right]
148
153
  else:
154
+ if rule.name_left not in neigbors:
155
+ raise ValueError(
156
+ f"Device `{device.fqdn}` has no neighbor `{rule.name_left}` required for `{handler_name}`",
157
+ )
149
158
  neighbor_device = neigbors[rule.name_left]
150
159
  all_connected_ports = [
151
160
  (p1.name, p2.name)
@@ -208,11 +208,11 @@ class MeshRulesRegistry:
208
208
 
209
209
  def lookup_direct(self, device: str, neighbors: list[str]) -> list[MatchedDirectPair]:
210
210
  found = []
211
- device = self._normalize_host(device)
211
+ device_norm = self._normalize_host(device)
212
212
  for neighbor in neighbors:
213
- neighbor = self._normalize_host(neighbor)
213
+ neighbor_norm = self._normalize_host(neighbor)
214
214
  for rule in self.direct_rules:
215
- if args := rule.matcher.match_pair(device, neighbor):
215
+ if args := rule.matcher.match_pair(device_norm, neighbor_norm):
216
216
  found.append(MatchedDirectPair(
217
217
  handler=rule.handler,
218
218
  port_processor=rule.port_processor,
@@ -222,7 +222,7 @@ class MeshRulesRegistry:
222
222
  match_left=args[0],
223
223
  match_right=args[1],
224
224
  ))
225
- if args := rule.matcher.match_pair(neighbor, device):
225
+ if args := rule.matcher.match_pair(neighbor_norm, device_norm):
226
226
  found.append(MatchedDirectPair(
227
227
  handler=rule.handler,
228
228
  port_processor=rule.port_processor,
@@ -238,11 +238,11 @@ class MeshRulesRegistry:
238
238
 
239
239
  def lookup_indirect(self, device: str, devices: list[str]) -> list[MatchedIndirectPair]:
240
240
  found = []
241
- device = self._normalize_host(device)
241
+ device_norm = self._normalize_host(device)
242
242
  for other_device in devices:
243
- other_device = self._normalize_host(other_device)
243
+ other_device_norm = self._normalize_host(other_device)
244
244
  for rule in self.indirect_rules:
245
- if args := rule.matcher.match_pair(device, other_device):
245
+ if args := rule.matcher.match_pair(device_norm, other_device_norm):
246
246
  found.append(MatchedIndirectPair(
247
247
  handler=rule.handler,
248
248
  direct_order=True,
@@ -251,7 +251,7 @@ class MeshRulesRegistry:
251
251
  match_left=args[0],
252
252
  match_right=args[1],
253
253
  ))
254
- if args := rule.matcher.match_pair(other_device, device):
254
+ if args := rule.matcher.match_pair(other_device_norm, device_norm):
255
255
  found.append(MatchedIndirectPair(
256
256
  handler=rule.handler,
257
257
  direct_order=False,
@@ -266,9 +266,9 @@ class MeshRulesRegistry:
266
266
 
267
267
  def lookup_virtual(self, device: str) -> list[MatchedVirtualPair]:
268
268
  found = []
269
- device = self._normalize_host(device)
269
+ device_norm = self._normalize_host(device)
270
270
  for rule in self.virtual_rules:
271
- if args := rule.matcher.match_one(device):
271
+ if args := rule.matcher.match_one(device_norm):
272
272
  found.append(MatchedVirtualPair(
273
273
  handler=rule.handler,
274
274
  match=args,
@@ -280,9 +280,9 @@ class MeshRulesRegistry:
280
280
 
281
281
  def lookup_global(self, device: str) -> list[MatchedGlobal]:
282
282
  found = []
283
- device = self._normalize_host(device)
283
+ device_norm = self._normalize_host(device)
284
284
  for rule in self.global_rules:
285
- if args := rule.matcher.match_one(device):
285
+ if args := rule.matcher.match_one(device_norm):
286
286
  found.append(MatchedGlobal(
287
287
  handler=rule.handler,
288
288
  match=args,
@@ -0,0 +1,42 @@
1
+ from annet.annlib.types import Op
2
+
3
+ from annet.rulebook import common
4
+
5
+
6
+ def mtu(rule, key, diff, **kwargs):
7
+ """
8
+ Удаляем mtu без указания значения
9
+ """
10
+ if diff[Op.REMOVED]:
11
+ yield (False, "no mtu", None)
12
+ elif diff[Op.ADDED]:
13
+ yield from common.default(rule, key, diff, **kwargs)
14
+
15
+
16
+ def sflow(rule, key, diff, **kwargs):
17
+ """
18
+ Команда sflow sampling-rate * direction ingress max-header-size *
19
+ сносится без указания sampling-rate и max-header-size
20
+ """
21
+ result = common.default(rule, key, diff, **kwargs)
22
+ for op, cmd, ch in result:
23
+ if diff[Op.REMOVED]:
24
+ if "ingress" in diff[Op.REMOVED][0]["row"]:
25
+ yield (op, "no sflow sampling-rate direction ingress", ch)
26
+ elif "egress" in diff[Op.REMOVED][0]["row"]:
27
+ yield (op, "no sflow sampling-rate direction egress", ch)
28
+ else:
29
+ yield (op, cmd, ch)
30
+ return result
31
+
32
+
33
+ def lldp(rule, key, diff, **kwargs):
34
+ """
35
+ Не удаляем все что начинается с set, т.к. set перезаписывает предыдущий конфиг
36
+ """
37
+ result = common.default(rule, key, diff, **kwargs)
38
+ for op, cmd, ch in result:
39
+ if diff[Op.REMOVED] and "set lldp" in cmd:
40
+ pass
41
+ else:
42
+ yield (op, cmd, ch)
@@ -1,6 +1,6 @@
1
1
  # Операторы:
2
- # * Один аргумент в undo
3
- # ~ Несколько аргументов (минимум один) в undo
2
+ # * Один аргумент в no
3
+ # ~ Несколько аргументов (минимум один) в no
4
4
  #
5
5
  # Параметры:
6
6
  # %global Команда действует на любом уровне ниже
@@ -11,8 +11,13 @@
11
11
  # Сделано в основном для того чтобы генерировать специальные команды для наливки
12
12
  # -----
13
13
  # Physical
14
+ sflow *
15
+
14
16
  interface */(ce|xe)[0-9\/]+$/ %logic=common.permanent %diff_logic=cisco.iface.diff
15
17
  ipv6 address *
16
- mtu *
18
+ mtu * %logic=b4com.iface.mtu
19
+ sflow * %logic=b4com.iface.sflow
17
20
  lldp-agent
18
- ~ %rewrite %global
21
+ ~ %global %logic=b4com.iface.lldp
22
+ !dcbx *
23
+ !exit
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: annet
3
- Version: 0.16.33
3
+ Version: 0.16.34
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -23,7 +23,7 @@ Requires-Dist: yarl>=1.8.2
23
23
  Requires-Dist: adaptix==3.0.0b7
24
24
  Requires-Dist: dataclass-rest==0.4
25
25
  Provides-Extra: netbox
26
- Requires-Dist: annetbox[sync]>=0.1.10; extra == "netbox"
26
+ Requires-Dist: annetbox[sync]>=0.1.12; extra == "netbox"
27
27
  Dynamic: home-page
28
28
  Dynamic: license
29
29
  Dynamic: provides-extra
@@ -130,6 +130,7 @@ annet/rulebook/aruba/ap_env.py
130
130
  annet/rulebook/aruba/misc.py
131
131
  annet/rulebook/b4com/__init__.py
132
132
  annet/rulebook/b4com/file.py
133
+ annet/rulebook/b4com/iface.py
133
134
  annet/rulebook/cisco/__init__.py
134
135
  annet/rulebook/cisco/iface.py
135
136
  annet/rulebook/cisco/misc.py
@@ -15,4 +15,4 @@ adaptix==3.0.0b7
15
15
  dataclass-rest==0.4
16
16
 
17
17
  [netbox]
18
- annetbox[sync]>=0.1.10
18
+ annetbox[sync]>=0.1.12
@@ -44,7 +44,7 @@ if __name__ == "__main__":
44
44
  ],
45
45
  },
46
46
  extras_require={
47
- "netbox": ["annetbox[sync]>=0.1.10"],
47
+ "netbox": ["annetbox[sync]>=0.1.12"],
48
48
  },
49
49
  python_requires=">=3.10",
50
50
  install_requires=requirements(),
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