annet 0.16.18__tar.gz → 0.16.19__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 (181) hide show
  1. {annet-0.16.18/annet.egg-info → annet-0.16.19}/PKG-INFO +1 -1
  2. {annet-0.16.18 → annet-0.16.19}/annet/adapters/netbox/common/manufacturer.py +4 -1
  3. {annet-0.16.18 → annet-0.16.19}/annet/annlib/netdev/devdb/data/devdb.json +1 -0
  4. {annet-0.16.18 → annet-0.16.19}/annet/annlib/rbparser/platform.py +6 -0
  5. {annet-0.16.18 → annet-0.16.19}/annet/annlib/rulebook/common.py +4 -0
  6. {annet-0.16.18 → annet-0.16.19}/annet/annlib/tabparser.py +57 -2
  7. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/__init__.py +3 -2
  8. annet-0.16.19/annet/rulebook/cisco/misc.py +59 -0
  9. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/cisco.rul +1 -1
  10. {annet-0.16.18 → annet-0.16.19}/annet/tabparser.py +2 -0
  11. {annet-0.16.18 → annet-0.16.19/annet.egg-info}/PKG-INFO +1 -1
  12. annet-0.16.18/annet/rulebook/cisco/misc.py +0 -149
  13. {annet-0.16.18 → annet-0.16.19}/AUTHORS +0 -0
  14. {annet-0.16.18 → annet-0.16.19}/LICENSE +0 -0
  15. {annet-0.16.18 → annet-0.16.19}/MANIFEST.in +0 -0
  16. {annet-0.16.18 → annet-0.16.19}/README.md +0 -0
  17. {annet-0.16.18 → annet-0.16.19}/annet/__init__.py +0 -0
  18. {annet-0.16.18 → annet-0.16.19}/annet/adapters/__init__.py +0 -0
  19. {annet-0.16.18 → annet-0.16.19}/annet/adapters/fetchers/__init__.py +0 -0
  20. {annet-0.16.18 → annet-0.16.19}/annet/adapters/fetchers/stub/__init__.py +0 -0
  21. {annet-0.16.18 → annet-0.16.19}/annet/adapters/fetchers/stub/fetcher.py +0 -0
  22. {annet-0.16.18 → annet-0.16.19}/annet/adapters/file/__init__.py +0 -0
  23. {annet-0.16.18 → annet-0.16.19}/annet/adapters/file/provider.py +0 -0
  24. {annet-0.16.18 → annet-0.16.19}/annet/adapters/netbox/__init__.py +0 -0
  25. {annet-0.16.18 → annet-0.16.19}/annet/adapters/netbox/common/__init__.py +0 -0
  26. {annet-0.16.18 → annet-0.16.19}/annet/adapters/netbox/common/client.py +0 -0
  27. {annet-0.16.18 → annet-0.16.19}/annet/adapters/netbox/common/models.py +0 -0
  28. {annet-0.16.18 → annet-0.16.19}/annet/adapters/netbox/common/query.py +0 -0
  29. {annet-0.16.18 → annet-0.16.19}/annet/adapters/netbox/common/status_client.py +0 -0
  30. {annet-0.16.18 → annet-0.16.19}/annet/adapters/netbox/common/storage_opts.py +0 -0
  31. {annet-0.16.18 → annet-0.16.19}/annet/adapters/netbox/provider.py +0 -0
  32. {annet-0.16.18 → annet-0.16.19}/annet/adapters/netbox/v24/__init__.py +0 -0
  33. {annet-0.16.18 → annet-0.16.19}/annet/adapters/netbox/v24/storage.py +0 -0
  34. {annet-0.16.18 → annet-0.16.19}/annet/adapters/netbox/v37/__init__.py +0 -0
  35. {annet-0.16.18 → annet-0.16.19}/annet/adapters/netbox/v37/storage.py +0 -0
  36. {annet-0.16.18 → annet-0.16.19}/annet/annet.py +0 -0
  37. {annet-0.16.18 → annet-0.16.19}/annet/annlib/__init__.py +0 -0
  38. {annet-0.16.18 → annet-0.16.19}/annet/annlib/command.py +0 -0
  39. {annet-0.16.18 → annet-0.16.19}/annet/annlib/diff.py +0 -0
  40. {annet-0.16.18 → annet-0.16.19}/annet/annlib/errors.py +0 -0
  41. {annet-0.16.18 → annet-0.16.19}/annet/annlib/filter_acl.py +0 -0
  42. {annet-0.16.18 → annet-0.16.19}/annet/annlib/jsontools.py +0 -0
  43. {annet-0.16.18 → annet-0.16.19}/annet/annlib/lib.py +0 -0
  44. {annet-0.16.18 → annet-0.16.19}/annet/annlib/netdev/__init__.py +0 -0
  45. {annet-0.16.18 → annet-0.16.19}/annet/annlib/netdev/db.py +0 -0
  46. {annet-0.16.18 → annet-0.16.19}/annet/annlib/netdev/devdb/__init__.py +0 -0
  47. {annet-0.16.18 → annet-0.16.19}/annet/annlib/netdev/views/__init__.py +0 -0
  48. {annet-0.16.18 → annet-0.16.19}/annet/annlib/netdev/views/dump.py +0 -0
  49. {annet-0.16.18 → annet-0.16.19}/annet/annlib/netdev/views/hardware.py +0 -0
  50. {annet-0.16.18 → annet-0.16.19}/annet/annlib/output.py +0 -0
  51. {annet-0.16.18 → annet-0.16.19}/annet/annlib/patching.py +0 -0
  52. {annet-0.16.18 → annet-0.16.19}/annet/annlib/rbparser/__init__.py +0 -0
  53. {annet-0.16.18 → annet-0.16.19}/annet/annlib/rbparser/acl.py +0 -0
  54. {annet-0.16.18 → annet-0.16.19}/annet/annlib/rbparser/deploying.py +0 -0
  55. {annet-0.16.18 → annet-0.16.19}/annet/annlib/rbparser/ordering.py +0 -0
  56. {annet-0.16.18 → annet-0.16.19}/annet/annlib/rbparser/syntax.py +0 -0
  57. {annet-0.16.18 → annet-0.16.19}/annet/annlib/rulebook/__init__.py +0 -0
  58. {annet-0.16.18 → annet-0.16.19}/annet/annlib/types.py +0 -0
  59. {annet-0.16.18 → annet-0.16.19}/annet/api/__init__.py +0 -0
  60. {annet-0.16.18 → annet-0.16.19}/annet/argparse.py +0 -0
  61. {annet-0.16.18 → annet-0.16.19}/annet/bgp_models.py +0 -0
  62. {annet-0.16.18 → annet-0.16.19}/annet/cli.py +0 -0
  63. {annet-0.16.18 → annet-0.16.19}/annet/cli_args.py +0 -0
  64. {annet-0.16.18 → annet-0.16.19}/annet/configs/context.yml +0 -0
  65. {annet-0.16.18 → annet-0.16.19}/annet/configs/logging.yaml +0 -0
  66. {annet-0.16.18 → annet-0.16.19}/annet/connectors.py +0 -0
  67. {annet-0.16.18 → annet-0.16.19}/annet/deploy.py +0 -0
  68. {annet-0.16.18 → annet-0.16.19}/annet/diff.py +0 -0
  69. {annet-0.16.18 → annet-0.16.19}/annet/executor.py +0 -0
  70. {annet-0.16.18 → annet-0.16.19}/annet/filtering.py +0 -0
  71. {annet-0.16.18 → annet-0.16.19}/annet/gen.py +0 -0
  72. {annet-0.16.18 → annet-0.16.19}/annet/generators/__init__.py +0 -0
  73. {annet-0.16.18 → annet-0.16.19}/annet/generators/base.py +0 -0
  74. {annet-0.16.18 → annet-0.16.19}/annet/generators/common/__init__.py +0 -0
  75. {annet-0.16.18 → annet-0.16.19}/annet/generators/common/initial.py +0 -0
  76. {annet-0.16.18 → annet-0.16.19}/annet/generators/entire.py +0 -0
  77. {annet-0.16.18 → annet-0.16.19}/annet/generators/exceptions.py +0 -0
  78. {annet-0.16.18 → annet-0.16.19}/annet/generators/jsonfragment.py +0 -0
  79. {annet-0.16.18 → annet-0.16.19}/annet/generators/partial.py +0 -0
  80. {annet-0.16.18 → annet-0.16.19}/annet/generators/perf.py +0 -0
  81. {annet-0.16.18 → annet-0.16.19}/annet/generators/ref.py +0 -0
  82. {annet-0.16.18 → annet-0.16.19}/annet/generators/result.py +0 -0
  83. {annet-0.16.18 → annet-0.16.19}/annet/hardware.py +0 -0
  84. {annet-0.16.18 → annet-0.16.19}/annet/implicit.py +0 -0
  85. {annet-0.16.18 → annet-0.16.19}/annet/lib.py +0 -0
  86. {annet-0.16.18 → annet-0.16.19}/annet/mesh/__init__.py +0 -0
  87. {annet-0.16.18 → annet-0.16.19}/annet/mesh/basemodel.py +0 -0
  88. {annet-0.16.18 → annet-0.16.19}/annet/mesh/device_models.py +0 -0
  89. {annet-0.16.18 → annet-0.16.19}/annet/mesh/executor.py +0 -0
  90. {annet-0.16.18 → annet-0.16.19}/annet/mesh/match_args.py +0 -0
  91. {annet-0.16.18 → annet-0.16.19}/annet/mesh/models_converter.py +0 -0
  92. {annet-0.16.18 → annet-0.16.19}/annet/mesh/peer_models.py +0 -0
  93. {annet-0.16.18 → annet-0.16.19}/annet/mesh/registry.py +0 -0
  94. {annet-0.16.18 → annet-0.16.19}/annet/output.py +0 -0
  95. {annet-0.16.18 → annet-0.16.19}/annet/parallel.py +0 -0
  96. {annet-0.16.18 → annet-0.16.19}/annet/patching.py +0 -0
  97. {annet-0.16.18 → annet-0.16.19}/annet/reference.py +0 -0
  98. {annet-0.16.18 → annet-0.16.19}/annet/rpl/__init__.py +0 -0
  99. {annet-0.16.18 → annet-0.16.19}/annet/rpl/action.py +0 -0
  100. {annet-0.16.18 → annet-0.16.19}/annet/rpl/condition.py +0 -0
  101. {annet-0.16.18 → annet-0.16.19}/annet/rpl/match_builder.py +0 -0
  102. {annet-0.16.18 → annet-0.16.19}/annet/rpl/policy.py +0 -0
  103. {annet-0.16.18 → annet-0.16.19}/annet/rpl/result.py +0 -0
  104. {annet-0.16.18 → annet-0.16.19}/annet/rpl/routemap.py +0 -0
  105. {annet-0.16.18 → annet-0.16.19}/annet/rpl/statement_builder.py +0 -0
  106. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/arista/__init__.py +0 -0
  107. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/arista/iface.py +0 -0
  108. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/aruba/__init__.py +0 -0
  109. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/aruba/ap_env.py +0 -0
  110. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/aruba/misc.py +0 -0
  111. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/b4com/__init__.py +0 -0
  112. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/b4com/file.py +0 -0
  113. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/cisco/__init__.py +0 -0
  114. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/cisco/iface.py +0 -0
  115. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/cisco/vlandb.py +0 -0
  116. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/common.py +0 -0
  117. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/deploying.py +0 -0
  118. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/huawei/__init__.py +0 -0
  119. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/huawei/aaa.py +0 -0
  120. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/huawei/bgp.py +0 -0
  121. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/huawei/iface.py +0 -0
  122. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/huawei/misc.py +0 -0
  123. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/huawei/vlandb.py +0 -0
  124. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/juniper/__init__.py +0 -0
  125. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/nexus/__init__.py +0 -0
  126. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/nexus/iface.py +0 -0
  127. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/patching.py +0 -0
  128. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/ribbon/__init__.py +0 -0
  129. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/routeros/__init__.py +0 -0
  130. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/routeros/file.py +0 -0
  131. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/arista.deploy +0 -0
  132. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/arista.order +0 -0
  133. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/arista.rul +0 -0
  134. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/aruba.deploy +0 -0
  135. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/aruba.order +0 -0
  136. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/aruba.rul +0 -0
  137. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/b4com.deploy +0 -0
  138. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/b4com.order +0 -0
  139. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/b4com.rul +0 -0
  140. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/cisco.deploy +0 -0
  141. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/cisco.order +0 -0
  142. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/huawei.deploy +0 -0
  143. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/huawei.order +0 -0
  144. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/huawei.rul +0 -0
  145. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/juniper.rul +0 -0
  146. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/nexus.deploy +0 -0
  147. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/nexus.order +0 -0
  148. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/nexus.rul +0 -0
  149. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/nokia.rul +0 -0
  150. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/optixtrans.deploy +0 -0
  151. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/optixtrans.order +0 -0
  152. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/optixtrans.rul +0 -0
  153. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/pc.deploy +0 -0
  154. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/pc.order +0 -0
  155. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/pc.rul +0 -0
  156. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/ribbon.deploy +0 -0
  157. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/ribbon.rul +0 -0
  158. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/routeros.order +0 -0
  159. {annet-0.16.18 → annet-0.16.19}/annet/rulebook/texts/routeros.rul +0 -0
  160. {annet-0.16.18 → annet-0.16.19}/annet/storage.py +0 -0
  161. {annet-0.16.18 → annet-0.16.19}/annet/text_term_format.py +0 -0
  162. {annet-0.16.18 → annet-0.16.19}/annet/tracing.py +0 -0
  163. {annet-0.16.18 → annet-0.16.19}/annet/types.py +0 -0
  164. {annet-0.16.18 → annet-0.16.19}/annet.egg-info/SOURCES.txt +0 -0
  165. {annet-0.16.18 → annet-0.16.19}/annet.egg-info/dependency_links.txt +0 -0
  166. {annet-0.16.18 → annet-0.16.19}/annet.egg-info/entry_points.txt +0 -0
  167. {annet-0.16.18 → annet-0.16.19}/annet.egg-info/requires.txt +0 -0
  168. {annet-0.16.18 → annet-0.16.19}/annet.egg-info/top_level.txt +0 -0
  169. {annet-0.16.18 → annet-0.16.19}/annet_generators/__init__.py +0 -0
  170. {annet-0.16.18 → annet-0.16.19}/annet_generators/example/__init__.py +0 -0
  171. {annet-0.16.18 → annet-0.16.19}/annet_generators/example/lldp.py +0 -0
  172. {annet-0.16.18 → annet-0.16.19}/annet_generators/mesh_example/__init__.py +0 -0
  173. {annet-0.16.18 → annet-0.16.19}/annet_generators/mesh_example/bgp.py +0 -0
  174. {annet-0.16.18 → annet-0.16.19}/annet_generators/mesh_example/mesh_logic.py +0 -0
  175. {annet-0.16.18 → annet-0.16.19}/annet_generators/rpl_example/__init__.py +0 -0
  176. {annet-0.16.18 → annet-0.16.19}/annet_generators/rpl_example/items.py +0 -0
  177. {annet-0.16.18 → annet-0.16.19}/annet_generators/rpl_example/policy_generator.py +0 -0
  178. {annet-0.16.18 → annet-0.16.19}/annet_generators/rpl_example/route_policy.py +0 -0
  179. {annet-0.16.18 → annet-0.16.19}/requirements.txt +0 -0
  180. {annet-0.16.18 → annet-0.16.19}/setup.cfg +0 -0
  181. {annet-0.16.18 → annet-0.16.19}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: annet
3
- Version: 0.16.18
3
+ Version: 0.16.19
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -17,7 +17,8 @@ _VENDORS = {
17
17
  "aruba": "Aruba",
18
18
  "routeros": "RouterOS",
19
19
  "ribbon": "Ribbon",
20
- "b4com": "B4com"
20
+ "b4com": "B4com",
21
+ "h3c": "H3C",
21
22
  }
22
23
 
23
24
 
@@ -37,6 +38,8 @@ def get_breed(manufacturer: str, model: str):
37
38
  return "vrp85"
38
39
  elif manufacturer == "Huawei":
39
40
  return "vrp55"
41
+ elif manufacturer == "H3C":
42
+ return "h3c"
40
43
  elif manufacturer in ("Mellanox", "NVIDIA"):
41
44
  return "cuml2"
42
45
  elif manufacturer == "Juniper":
@@ -53,6 +53,7 @@
53
53
  "Huawei.CE.CE8800.CE8850": " CE8850",
54
54
  "Huawei.CE.CE8800.CE8851": " CE8851",
55
55
  "Huawei.CE.CE8800.CE8855": " CE8855",
56
+ "Huawei.CE.CE8800.CE8875": " CE8875",
56
57
  "Huawei.CE.CE9800": " CE98\\d\\d",
57
58
  "Huawei.CE.CE9800.CE9855": " CE9855",
58
59
  "Huawei.CE.CE9800.CE9860": " CE9860",
@@ -1,5 +1,6 @@
1
1
  VENDOR_REVERSES = {
2
2
  "huawei": "undo",
3
+ "h3c": "undo",
3
4
  "optixtrans": "undo",
4
5
  "cisco": "no",
5
6
  "nexus": "no",
@@ -45,6 +46,7 @@ VENDOR_DIFF_ORDERED = {
45
46
 
46
47
  VENDOR_EXIT = {
47
48
  "huawei": "quit",
49
+ "h3c": "quit",
48
50
  "optixtrans": "quit",
49
51
  "cisco": "exit",
50
52
  "nexus": "exit",
@@ -57,3 +59,7 @@ VENDOR_EXIT = {
57
59
  "ribbon": "exit",
58
60
  "b4com": "exit",
59
61
  }
62
+
63
+ VENDOR_ALIASES = {
64
+ "h3c": "huawei",
65
+ }
@@ -356,6 +356,10 @@ def apply(hw, do_commit, do_finalize, **_):
356
356
  after.add_cmd(Command("commit"))
357
357
  if do_finalize:
358
358
  after.add_cmd(Command("write", timeout=40))
359
+ elif hw.H3C:
360
+ before.add_cmd(Command("system-view"))
361
+ if do_finalize:
362
+ after.add_cmd(Command("save force", timeout=20))
359
363
  else:
360
364
  raise Exception("unknown hw %s" % hw)
361
365
 
@@ -2,7 +2,7 @@ import dataclasses
2
2
  import itertools
3
3
  import re
4
4
  from collections import OrderedDict as odict
5
- from typing import TYPE_CHECKING, Any, Dict, Iterable, Optional, Tuple, Union
5
+ from typing import TYPE_CHECKING, Any, Dict, Iterable, Optional, Tuple, Union, List
6
6
 
7
7
  from .types import Op
8
8
 
@@ -271,8 +271,63 @@ class CiscoFormatter(BlockExitFormatter):
271
271
  def __init__(self, indent=" "):
272
272
  super().__init__("exit", indent)
273
273
 
274
+ def _split_indent(
275
+ self, line: str, indent: int, block_exit_strings: List[str]
276
+ ) -> Tuple[List[str], int]:
277
+ """
278
+ The small helper calculates indent shift based on block exit string.
279
+ If configuration line has non-default block exit string it means that
280
+ new subsection is started and indent should be increased.
281
+ If configuration line exists in list of block exit strings,
282
+ it means that subsection is finished and indent should be decreased
283
+
284
+ Args:
285
+ line: just configuration line
286
+ indent: current indent
287
+ block_exit_strings: list of previously seen block exit strings
288
+ Returns:
289
+ new indent and list of previously seen block exit strings
290
+ """
291
+
292
+ if line.strip() in block_exit_strings:
293
+ indent -= 1
294
+ block_exit_strings.remove(line.strip())
295
+ return block_exit_strings, indent
296
+
297
+ block_exit_wrapped = [
298
+ v for v in self.block_exit(FormatterContext(current=(line.strip(), {})))
299
+ ]
300
+
301
+ if not block_exit_wrapped or len(block_exit_wrapped) != 3:
302
+ return block_exit_strings, indent
303
+ if not isinstance(block_exit_wrapped[1], str):
304
+ return block_exit_strings, indent
305
+ if block_exit_wrapped[1] == self._block_exit:
306
+ return block_exit_strings, indent
307
+
308
+ indent += 1
309
+ block_exit_strings.append(block_exit_wrapped[1])
310
+ return block_exit_strings, indent
311
+
274
312
  def split(self, text):
275
- return self.split_remove_spaces(text)
313
+ additional_indent = 0
314
+ block_exit_strings = [self._block_exit]
315
+ tree = self.split_remove_spaces(text)
316
+ for i, item in enumerate(tree):
317
+ block_exit_strings, new_indent = self._split_indent(
318
+ item, additional_indent, block_exit_strings
319
+ )
320
+ tree[i] = f"{' ' * additional_indent}{item}"
321
+ additional_indent = new_indent
322
+ return tree
323
+
324
+ def block_exit(self, context: Optional[FormatterContext]) -> str:
325
+ current = context and context.row or ""
326
+
327
+ if current.startswith(("address-family")):
328
+ yield from block_wrapper("exit-address-family")
329
+ else:
330
+ yield from super().block_exit(context)
276
331
 
277
332
 
278
333
  class AsrFormatter(BlockExitFormatter):
@@ -5,7 +5,7 @@ from typing import Iterable, Union
5
5
 
6
6
  from annet.annlib.lib import mako_render
7
7
  from annet.annlib.rbparser.ordering import compile_ordering_text
8
- from annet.annlib.rbparser.platform import VENDOR_REVERSES
8
+ from annet.annlib.rbparser.platform import VENDOR_REVERSES, VENDOR_ALIASES
9
9
 
10
10
  from annet.connectors import CachedConnector
11
11
  from annet.rulebook.deploying import compile_deploying_text
@@ -64,7 +64,8 @@ class DefaultRulebookProvider(RulebookProvider):
64
64
  return self._rulebook_cache[hw]
65
65
 
66
66
  assert hw.vendor in VENDOR_REVERSES, "Unknown vendor: %s" % (hw.vendor)
67
- patching = compile_patching_text(self._render_rul(hw.vendor + ".rul", hw), hw.vendor)
67
+ rul_vendor_name = VENDOR_ALIASES.get(hw.vendor, hw.vendor)
68
+ patching = compile_patching_text(self._render_rul(rul_vendor_name + ".rul", hw), rul_vendor_name)
68
69
 
69
70
  try:
70
71
  ordering_text = self._render_rul(hw.vendor + ".order", hw)
@@ -0,0 +1,59 @@
1
+ import re
2
+ from collections import OrderedDict
3
+ from typing import Any
4
+
5
+ from annet.annlib.types import Op
6
+
7
+ from annet.rulebook import common
8
+
9
+
10
+ def ssh_key(rule, key, diff, hw, **_):
11
+ """
12
+ При включении ssh надо еще сгенерировать ключ. По конфигу никак не понять есть ли ключ на свитче или нет.
13
+ """
14
+ if diff[Op.ADDED]:
15
+ added = sorted([x["row"] for x in diff[Op.ADDED]])
16
+ if added == ["ip ssh version 2"]:
17
+ # Отсыпаем mpdaemon-у подсказок для дополнительной команды при наливке
18
+ comment = rule["comment"]
19
+ rule["comment"] = ["!!suppress_errors!!", "!!timeout=240!!"]
20
+ if hw.Cisco.C2960:
21
+ yield (False, "crypto key generate rsa modulus 2048", None)
22
+ else:
23
+ yield (False, "crypto key generate rsa general-keys modulus 2048", None)
24
+ rule["comment"] = comment
25
+ yield from common.default(rule, key, diff)
26
+
27
+
28
+ def no_ipv6_nd_suppress_ra(rule, key, diff, **_):
29
+ """
30
+ При конфигурации ipv6 nd на нексусах нужно добавлять
31
+ no ipv6 nd suppress-ra
32
+ иначе RA не будет включен.
33
+ К сожалению данной команды не видно в running-config.
34
+ Поэтому подмешиваем ее в патч вместо генератора
35
+ """
36
+ if diff[Op.ADDED]:
37
+ yield (False, "no ipv6 nd suppress-ra", None)
38
+ yield from common.default(rule, key, diff)
39
+
40
+
41
+ def no_ntp_distribute(rule, key, diff, **_):
42
+ """
43
+ Для того, чтобы удалить NTP из CFS, сначала нужно сбросить активные
44
+ NTP сессии.
45
+ """
46
+ if diff[Op.REMOVED]:
47
+ yield (False, "clear ntp session", None)
48
+ yield from common.default(rule, key, diff)
49
+
50
+
51
+ def banner_login(rule, key, diff, **_):
52
+ if diff[Op.REMOVED]:
53
+ yield (False, "no banner login", None)
54
+ elif diff[Op.ADDED]:
55
+ # Убираем дополнительный экранирующий сиимвол
56
+ key = re.sub(r"\^C", "^", key[0])
57
+ yield (False, f"banner login {key}", None)
58
+ else:
59
+ yield from common.default(rule, key, diff)
@@ -73,7 +73,7 @@ interface */\w*Ethernet[0-9\/]+$/ %logic=common.permanent %diff_logic=cisco.
73
73
  storm-control * level
74
74
  spanning-tree portfast
75
75
 
76
- router bgp * %diff_logic=cisco.misc.bgp_diff
76
+ router bgp
77
77
  router-id
78
78
  vrf *
79
79
  router-id
@@ -33,6 +33,8 @@ def make_formatter(hw, **kwargs):
33
33
  cls = CommonFormatter
34
34
  elif hw.Ribbon:
35
35
  cls = RibbonFormatter
36
+ elif hw.H3C:
37
+ cls = HuaweiFormatter
36
38
  else:
37
39
  raise NotImplementedError("Unknown formatter for hw '%s'" % hw)
38
40
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: annet
3
- Version: 0.16.18
3
+ Version: 0.16.19
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -1,149 +0,0 @@
1
- import re
2
- from collections import OrderedDict
3
- from typing import Any
4
-
5
- from annet.annlib.types import Op
6
-
7
- from annet.rulebook import common
8
-
9
-
10
- def ssh_key(rule, key, diff, hw, **_):
11
- """
12
- При включении ssh надо еще сгенерировать ключ. По конфигу никак не понять есть ли ключ на свитче или нет.
13
- """
14
- if diff[Op.ADDED]:
15
- added = sorted([x["row"] for x in diff[Op.ADDED]])
16
- if added == ["ip ssh version 2"]:
17
- # Отсыпаем mpdaemon-у подсказок для дополнительной команды при наливке
18
- comment = rule["comment"]
19
- rule["comment"] = ["!!suppress_errors!!", "!!timeout=240!!"]
20
- if hw.Cisco.C2960:
21
- yield (False, "crypto key generate rsa modulus 2048", None)
22
- else:
23
- yield (False, "crypto key generate rsa general-keys modulus 2048", None)
24
- rule["comment"] = comment
25
- yield from common.default(rule, key, diff)
26
-
27
-
28
- def no_ipv6_nd_suppress_ra(rule, key, diff, **_):
29
- """
30
- При конфигурации ipv6 nd на нексусах нужно добавлять
31
- no ipv6 nd suppress-ra
32
- иначе RA не будет включен.
33
- К сожалению данной команды не видно в running-config.
34
- Поэтому подмешиваем ее в патч вместо генератора
35
- """
36
- if diff[Op.ADDED]:
37
- yield (False, "no ipv6 nd suppress-ra", None)
38
- yield from common.default(rule, key, diff)
39
-
40
-
41
- def no_ntp_distribute(rule, key, diff, **_):
42
- """
43
- Для того, чтобы удалить NTP из CFS, сначала нужно сбросить активные
44
- NTP сессии.
45
- """
46
- if diff[Op.REMOVED]:
47
- yield (False, "clear ntp session", None)
48
- yield from common.default(rule, key, diff)
49
-
50
-
51
- def banner_login(rule, key, diff, **_):
52
- if diff[Op.REMOVED]:
53
- yield (False, "no banner login", None)
54
- elif diff[Op.ADDED]:
55
- # Убираем дополнительный экранирующий сиимвол
56
- key = re.sub(r"\^C", "^", key[0])
57
- yield (False, f"banner login {key}", None)
58
- else:
59
- yield from common.default(rule, key, diff)
60
-
61
-
62
- def bgp_diff(old, new, diff_pre, _pops=(Op.AFFECTED,)):
63
- """
64
- Some oder versions of Cisco IOS doesn't create subsection for address family block.
65
-
66
- it looks like:
67
-
68
- router bgp 65111
69
- bgp router-id 1.1.1.1
70
- bgp log-neighbor-changes
71
- neighbor SPINE peer-group
72
- !
73
- address-family ipv4
74
- neighbor SPINE send-community both
75
- neighbor SPINE soft-reconfiguration inbound
76
- neighbor SPINE route-map TOR_IMPORT_SPINE in
77
- neighbor SPINE route-map TOR_EXPORT_SPINE out
78
- exit-address-family
79
-
80
- but should be
81
-
82
- router bgp 65111
83
- bgp router-id 1.1.1.1
84
- bgp log-neighbor-changes
85
- neighbor SPINE peer-group
86
- !
87
- address-family ipv4
88
- neighbor SPINE send-community both
89
- neighbor SPINE soft-reconfiguration inbound
90
- neighbor SPINE route-map TOR_IMPORT_SPINE in
91
- neighbor SPINE route-map TOR_EXPORT_SPINE out
92
- exit-address-family
93
-
94
- The diff_logic func do it before make diff.
95
- """
96
- corrected_old = _create_subsections(old, "address-family")
97
-
98
- yield from common.default_diff(corrected_old, new, diff_pre, _pops)
99
-
100
-
101
- def _create_subsections(data: OrderedDict[str, Any], sub_section_prefix: str) -> OrderedDict[str, Any]:
102
- """
103
- Reorganizes the given OrderedDict to nest commands under their respective
104
- sub_section_prefix keys.
105
-
106
- This function traverses the entries in the provided OrderedDict and groups
107
- together all entries that are between keys with sub_section_prefix under those
108
- keys as nested OrderedDicts. The reorganization keeps the order of entries
109
- stable, only adding nesting where appropriate.
110
-
111
- Args:
112
- data (OrderedDict): The original configuration to be transformed.
113
- sub_section_prefix (str): Prefix of subsection key
114
-
115
- Returns:
116
- OrderedDict: A new OrderedDict with nested 'address-family' sections.
117
- """
118
-
119
- result = OrderedDict()
120
- sub_section = None
121
- temp: OrderedDict = OrderedDict()
122
-
123
- for key, value in data.items():
124
- # make nested loop if found nested values
125
- if value:
126
- fixed_value: OrderedDict[str, Any] = _create_subsections(value, sub_section_prefix)
127
- else:
128
- fixed_value = value
129
- if key.startswith(sub_section_prefix):
130
- # in case of data has already had subsections
131
- if value:
132
- result[key] = fixed_value
133
- continue
134
- # if previous subsection present save collected data from temporary dict
135
- if sub_section:
136
- result[sub_section] = temp
137
- # find a new subsection and initialize new dict
138
- sub_section = key
139
- temp = OrderedDict()
140
- # put found data to temporary dict
141
- elif sub_section:
142
- temp[key] = fixed_value
143
- else:
144
- result[key] = fixed_value
145
- # if data is finished save collected data from temporary dict
146
- if sub_section:
147
- result[sub_section] = temp
148
-
149
- return result
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
File without changes
File without changes