annet 2.6.0__tar.gz → 3.1.0__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 (212) hide show
  1. {annet-2.6.0/annet.egg-info → annet-3.1.0}/PKG-INFO +1 -1
  2. {annet-2.6.0 → annet-3.1.0}/annet/__init__.py +5 -4
  3. {annet-2.6.0 → annet-3.1.0}/annet/adapters/file/provider.py +49 -26
  4. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/manufacturer.py +3 -22
  5. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/models.py +3 -2
  6. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v24/models.py +4 -3
  7. {annet-2.6.0 → annet-3.1.0}/annet/annlib/netdev/views/hardware.py +15 -70
  8. {annet-2.6.0 → annet-3.1.0}/annet/annlib/patching.py +9 -6
  9. {annet-2.6.0 → annet-3.1.0}/annet/annlib/rbparser/acl.py +3 -2
  10. {annet-2.6.0 → annet-3.1.0}/annet/annlib/rbparser/ordering.py +3 -2
  11. annet-3.1.0/annet/annlib/rbparser/platform.py +3 -0
  12. {annet-2.6.0 → annet-3.1.0}/annet/annlib/rulebook/common.py +21 -14
  13. {annet-2.6.0 → annet-3.1.0}/annet/annlib/tabparser.py +0 -18
  14. {annet-2.6.0 → annet-3.1.0}/annet/api/__init__.py +16 -7
  15. {annet-2.6.0 → annet-3.1.0}/annet/diff.py +3 -3
  16. {annet-2.6.0 → annet-3.1.0}/annet/gen.py +6 -6
  17. {annet-2.6.0 → annet-3.1.0}/annet/generators/__init__.py +15 -22
  18. {annet-2.6.0 → annet-3.1.0}/annet/hardware.py +8 -12
  19. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/__init__.py +3 -2
  20. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/deploying.py +3 -2
  21. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/juniper/__init__.py +2 -2
  22. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/patching.py +5 -5
  23. annet-3.1.0/annet/vendors/__init__.py +33 -0
  24. annet-3.1.0/annet/vendors/base.py +38 -0
  25. annet-3.1.0/annet/vendors/registry.py +93 -0
  26. {annet-2.6.0 → annet-3.1.0/annet.egg-info}/PKG-INFO +1 -1
  27. {annet-2.6.0 → annet-3.1.0}/annet.egg-info/SOURCES.txt +4 -1
  28. {annet-2.6.0 → annet-3.1.0}/annet_generators/example/__init__.py +6 -1
  29. annet-3.1.0/annet_generators/example/hostname.py +113 -0
  30. annet-2.6.0/annet/annlib/rbparser/platform.py +0 -69
  31. annet-2.6.0/annet/tabparser.py +0 -53
  32. {annet-2.6.0 → annet-3.1.0}/AUTHORS +0 -0
  33. {annet-2.6.0 → annet-3.1.0}/LICENSE +0 -0
  34. {annet-2.6.0 → annet-3.1.0}/MANIFEST.in +0 -0
  35. {annet-2.6.0 → annet-3.1.0}/README.md +0 -0
  36. {annet-2.6.0 → annet-3.1.0}/annet/adapters/__init__.py +0 -0
  37. {annet-2.6.0 → annet-3.1.0}/annet/adapters/fetchers/__init__.py +0 -0
  38. {annet-2.6.0 → annet-3.1.0}/annet/adapters/fetchers/stub/__init__.py +0 -0
  39. {annet-2.6.0 → annet-3.1.0}/annet/adapters/fetchers/stub/fetcher.py +0 -0
  40. {annet-2.6.0 → annet-3.1.0}/annet/adapters/file/__init__.py +0 -0
  41. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/__init__.py +0 -0
  42. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/__init__.py +0 -0
  43. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/adapter.py +0 -0
  44. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/client.py +0 -0
  45. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/query.py +0 -0
  46. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/status_client.py +0 -0
  47. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/storage_base.py +0 -0
  48. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/storage_opts.py +0 -0
  49. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/provider.py +0 -0
  50. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v24/__init__.py +0 -0
  51. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v24/storage.py +0 -0
  52. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v37/__init__.py +0 -0
  53. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v37/models.py +0 -0
  54. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v37/storage.py +0 -0
  55. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v41/__init__.py +0 -0
  56. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v41/models.py +0 -0
  57. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v41/storage.py +0 -0
  58. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v42/__init__.py +0 -0
  59. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v42/models.py +0 -0
  60. {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v42/storage.py +0 -0
  61. {annet-2.6.0 → annet-3.1.0}/annet/annet.py +0 -0
  62. {annet-2.6.0 → annet-3.1.0}/annet/annlib/__init__.py +0 -0
  63. {annet-2.6.0 → annet-3.1.0}/annet/annlib/command.py +0 -0
  64. {annet-2.6.0 → annet-3.1.0}/annet/annlib/diff.py +0 -0
  65. {annet-2.6.0 → annet-3.1.0}/annet/annlib/errors.py +0 -0
  66. {annet-2.6.0 → annet-3.1.0}/annet/annlib/filter_acl.py +0 -0
  67. {annet-2.6.0 → annet-3.1.0}/annet/annlib/jsontools.py +0 -0
  68. {annet-2.6.0 → annet-3.1.0}/annet/annlib/lib.py +0 -0
  69. {annet-2.6.0 → annet-3.1.0}/annet/annlib/netdev/__init__.py +0 -0
  70. {annet-2.6.0 → annet-3.1.0}/annet/annlib/netdev/db.py +0 -0
  71. {annet-2.6.0 → annet-3.1.0}/annet/annlib/netdev/devdb/__init__.py +0 -0
  72. {annet-2.6.0 → annet-3.1.0}/annet/annlib/netdev/devdb/data/devdb.json +0 -0
  73. {annet-2.6.0 → annet-3.1.0}/annet/annlib/netdev/views/__init__.py +0 -0
  74. {annet-2.6.0 → annet-3.1.0}/annet/annlib/netdev/views/dump.py +0 -0
  75. {annet-2.6.0 → annet-3.1.0}/annet/annlib/output.py +0 -0
  76. {annet-2.6.0 → annet-3.1.0}/annet/annlib/rbparser/__init__.py +0 -0
  77. {annet-2.6.0 → annet-3.1.0}/annet/annlib/rbparser/deploying.py +0 -0
  78. {annet-2.6.0 → annet-3.1.0}/annet/annlib/rbparser/syntax.py +0 -0
  79. {annet-2.6.0 → annet-3.1.0}/annet/annlib/rulebook/__init__.py +0 -0
  80. {annet-2.6.0 → annet-3.1.0}/annet/annlib/types.py +0 -0
  81. {annet-2.6.0 → annet-3.1.0}/annet/argparse.py +0 -0
  82. {annet-2.6.0 → annet-3.1.0}/annet/bgp_models.py +0 -0
  83. {annet-2.6.0 → annet-3.1.0}/annet/cli.py +0 -0
  84. {annet-2.6.0 → annet-3.1.0}/annet/cli_args.py +0 -0
  85. {annet-2.6.0 → annet-3.1.0}/annet/configs/context.yml +0 -0
  86. {annet-2.6.0 → annet-3.1.0}/annet/configs/logging.yaml +0 -0
  87. {annet-2.6.0 → annet-3.1.0}/annet/connectors.py +0 -0
  88. {annet-2.6.0 → annet-3.1.0}/annet/deploy.py +0 -0
  89. {annet-2.6.0 → annet-3.1.0}/annet/deploy_ui.py +0 -0
  90. {annet-2.6.0 → annet-3.1.0}/annet/executor.py +0 -0
  91. {annet-2.6.0 → annet-3.1.0}/annet/filtering.py +0 -0
  92. {annet-2.6.0 → annet-3.1.0}/annet/generators/base.py +0 -0
  93. {annet-2.6.0 → annet-3.1.0}/annet/generators/common/__init__.py +0 -0
  94. {annet-2.6.0 → annet-3.1.0}/annet/generators/common/initial.py +0 -0
  95. {annet-2.6.0 → annet-3.1.0}/annet/generators/entire.py +0 -0
  96. {annet-2.6.0 → annet-3.1.0}/annet/generators/exceptions.py +0 -0
  97. {annet-2.6.0 → annet-3.1.0}/annet/generators/jsonfragment.py +0 -0
  98. {annet-2.6.0 → annet-3.1.0}/annet/generators/partial.py +0 -0
  99. {annet-2.6.0 → annet-3.1.0}/annet/generators/perf.py +0 -0
  100. {annet-2.6.0 → annet-3.1.0}/annet/generators/ref.py +0 -0
  101. {annet-2.6.0 → annet-3.1.0}/annet/generators/result.py +0 -0
  102. {annet-2.6.0 → annet-3.1.0}/annet/implicit.py +0 -0
  103. {annet-2.6.0 → annet-3.1.0}/annet/lib.py +0 -0
  104. {annet-2.6.0 → annet-3.1.0}/annet/mesh/__init__.py +0 -0
  105. {annet-2.6.0 → annet-3.1.0}/annet/mesh/basemodel.py +0 -0
  106. {annet-2.6.0 → annet-3.1.0}/annet/mesh/device_models.py +0 -0
  107. {annet-2.6.0 → annet-3.1.0}/annet/mesh/executor.py +0 -0
  108. {annet-2.6.0 → annet-3.1.0}/annet/mesh/match_args.py +0 -0
  109. {annet-2.6.0 → annet-3.1.0}/annet/mesh/models_converter.py +0 -0
  110. {annet-2.6.0 → annet-3.1.0}/annet/mesh/peer_models.py +0 -0
  111. {annet-2.6.0 → annet-3.1.0}/annet/mesh/port_processor.py +0 -0
  112. {annet-2.6.0 → annet-3.1.0}/annet/mesh/registry.py +0 -0
  113. {annet-2.6.0 → annet-3.1.0}/annet/output.py +0 -0
  114. {annet-2.6.0 → annet-3.1.0}/annet/parallel.py +0 -0
  115. {annet-2.6.0 → annet-3.1.0}/annet/patching.py +0 -0
  116. {annet-2.6.0 → annet-3.1.0}/annet/reference.py +0 -0
  117. {annet-2.6.0 → annet-3.1.0}/annet/rpl/__init__.py +0 -0
  118. {annet-2.6.0 → annet-3.1.0}/annet/rpl/action.py +0 -0
  119. {annet-2.6.0 → annet-3.1.0}/annet/rpl/condition.py +0 -0
  120. {annet-2.6.0 → annet-3.1.0}/annet/rpl/match_builder.py +0 -0
  121. {annet-2.6.0 → annet-3.1.0}/annet/rpl/policy.py +0 -0
  122. {annet-2.6.0 → annet-3.1.0}/annet/rpl/result.py +0 -0
  123. {annet-2.6.0 → annet-3.1.0}/annet/rpl/routemap.py +0 -0
  124. {annet-2.6.0 → annet-3.1.0}/annet/rpl/statement_builder.py +0 -0
  125. {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/__init__.py +0 -0
  126. {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/aspath.py +0 -0
  127. {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/community.py +0 -0
  128. {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/cumulus_frr.py +0 -0
  129. {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/entities.py +0 -0
  130. {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/execute.py +0 -0
  131. {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/policy.py +0 -0
  132. {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/prefix_lists.py +0 -0
  133. {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/rd.py +0 -0
  134. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/arista/__init__.py +0 -0
  135. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/arista/aaa.py +0 -0
  136. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/arista/iface.py +0 -0
  137. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/aruba/__init__.py +0 -0
  138. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/aruba/ap_env.py +0 -0
  139. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/aruba/misc.py +0 -0
  140. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/b4com/__init__.py +0 -0
  141. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/b4com/file.py +0 -0
  142. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/b4com/iface.py +0 -0
  143. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/cisco/__init__.py +0 -0
  144. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/cisco/iface.py +0 -0
  145. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/cisco/misc.py +0 -0
  146. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/cisco/vlandb.py +0 -0
  147. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/common.py +0 -0
  148. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/huawei/__init__.py +0 -0
  149. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/huawei/aaa.py +0 -0
  150. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/huawei/bgp.py +0 -0
  151. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/huawei/iface.py +0 -0
  152. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/huawei/misc.py +0 -0
  153. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/huawei/vlandb.py +0 -0
  154. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/nexus/__init__.py +0 -0
  155. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/nexus/iface.py +0 -0
  156. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/routeros/__init__.py +0 -0
  157. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/routeros/file.py +0 -0
  158. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/arista.deploy +0 -0
  159. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/arista.order +0 -0
  160. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/arista.rul +0 -0
  161. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/aruba.deploy +0 -0
  162. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/aruba.order +0 -0
  163. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/aruba.rul +0 -0
  164. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/b4com.deploy +0 -0
  165. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/b4com.order +0 -0
  166. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/b4com.rul +0 -0
  167. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/cisco.deploy +0 -0
  168. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/cisco.order +0 -0
  169. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/cisco.rul +0 -0
  170. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/huawei.deploy +0 -0
  171. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/huawei.order +0 -0
  172. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/huawei.rul +0 -0
  173. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/iosxr.deploy +0 -0
  174. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/iosxr.order +0 -0
  175. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/iosxr.rul +0 -0
  176. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/juniper.order +0 -0
  177. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/juniper.rul +0 -0
  178. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/nexus.deploy +0 -0
  179. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/nexus.order +0 -0
  180. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/nexus.rul +0 -0
  181. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/nokia.rul +0 -0
  182. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/optixtrans.deploy +0 -0
  183. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/optixtrans.order +0 -0
  184. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/optixtrans.rul +0 -0
  185. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/pc.deploy +0 -0
  186. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/pc.order +0 -0
  187. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/pc.rul +0 -0
  188. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/ribbon.deploy +0 -0
  189. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/ribbon.rul +0 -0
  190. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/routeros.order +0 -0
  191. {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/routeros.rul +0 -0
  192. {annet-2.6.0 → annet-3.1.0}/annet/storage.py +0 -0
  193. {annet-2.6.0 → annet-3.1.0}/annet/text_term_format.py +0 -0
  194. {annet-2.6.0 → annet-3.1.0}/annet/tracing.py +0 -0
  195. {annet-2.6.0 → annet-3.1.0}/annet/types.py +0 -0
  196. {annet-2.6.0 → annet-3.1.0}/annet.egg-info/dependency_links.txt +0 -0
  197. {annet-2.6.0 → annet-3.1.0}/annet.egg-info/entry_points.txt +0 -0
  198. {annet-2.6.0 → annet-3.1.0}/annet.egg-info/requires.txt +0 -0
  199. {annet-2.6.0 → annet-3.1.0}/annet.egg-info/top_level.txt +0 -0
  200. {annet-2.6.0 → annet-3.1.0}/annet_generators/__init__.py +0 -0
  201. {annet-2.6.0 → annet-3.1.0}/annet_generators/example/lldp.py +0 -0
  202. {annet-2.6.0 → annet-3.1.0}/annet_generators/mesh_example/__init__.py +0 -0
  203. {annet-2.6.0 → annet-3.1.0}/annet_generators/mesh_example/bgp.py +0 -0
  204. {annet-2.6.0 → annet-3.1.0}/annet_generators/mesh_example/mesh_logic.py +0 -0
  205. {annet-2.6.0 → annet-3.1.0}/annet_generators/rpl_example/__init__.py +0 -0
  206. {annet-2.6.0 → annet-3.1.0}/annet_generators/rpl_example/generator.py +0 -0
  207. {annet-2.6.0 → annet-3.1.0}/annet_generators/rpl_example/items.py +0 -0
  208. {annet-2.6.0 → annet-3.1.0}/annet_generators/rpl_example/mesh.py +0 -0
  209. {annet-2.6.0 → annet-3.1.0}/annet_generators/rpl_example/route_policy.py +0 -0
  210. {annet-2.6.0 → annet-3.1.0}/requirements.txt +0 -0
  211. {annet-2.6.0 → annet-3.1.0}/setup.cfg +0 -0
  212. {annet-2.6.0 → annet-3.1.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: annet
3
- Version: 2.6.0
3
+ Version: 3.1.0
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -7,14 +7,15 @@ from argparse import SUPPRESS, Namespace
7
7
 
8
8
  import colorama
9
9
  import yaml
10
- from annet.annlib.errors import ( # pylint: disable=wrong-import-position
11
- DeployCancelled,
12
- ExecError,
13
- )
14
10
  from contextlog import patch_logging, patch_threading
15
11
  from valkit.python import valid_logging_level
16
12
 
17
13
  import annet.argparse
14
+ from annet.annlib import tabparser # pylint: disable=unused-import
15
+ from annet.annlib.errors import ( # pylint: disable=wrong-import-position
16
+ DeployCancelled,
17
+ ExecError,
18
+ )
18
19
 
19
20
 
20
21
  __all__ = ("DeployCancelled", "ExecError")
@@ -1,13 +1,16 @@
1
- from annet.annlib.netdev.views.dump import DumpableView
2
- from annet.storage import Query
1
+ import dataclasses
3
2
  from dataclasses import dataclass, fields
4
- from typing import List, Iterable, Optional, Any, Sequence
5
- from annet.storage import StorageProvider, Storage
6
- from annet.connectors import AdapterWithName
7
- from annet.storage import Device as DeviceCls
8
- from annet.annlib.netdev.views.hardware import vendor_to_hw, HardwareView
3
+ from typing import Any, Iterable, List, Optional, Sequence
4
+
9
5
  import yaml
10
6
 
7
+ from annet.annlib.netdev.views.dump import DumpableView
8
+ from annet.annlib.netdev.views.hardware import HardwareView
9
+ from annet.connectors import AdapterWithName
10
+ from annet.hardware import hardware_connector
11
+ from annet.storage import Device as DeviceProtocol
12
+ from annet.storage import Query, Storage, StorageProvider
13
+
11
14
 
12
15
  @dataclass
13
16
  class Interface(DumpableView):
@@ -23,29 +26,46 @@ class Interface(DumpableView):
23
26
  @dataclass
24
27
  class DeviceStorage:
25
28
  fqdn: str
26
- vendor: str
29
+
30
+ vendor: Optional[str] = None
31
+ hw_model: Optional[str] = None
32
+ sw_version: Optional[str] = None
33
+
27
34
  hostname: Optional[str] = None
28
35
  serial: Optional[str] = None
29
36
  id: Optional[str] = None
30
37
  interfaces: Optional[list[Interface]] = None
31
38
  storage: Optional[Storage] = None
32
39
 
40
+ hw: HardwareView = dataclasses.field(init=False)
41
+
33
42
  def __post_init__(self):
34
43
  if not self.id:
35
44
  self.id = self.fqdn
36
45
  if not self.hostname:
37
46
  self.hostname = self.fqdn.split(".")[0]
38
- hw = vendor_to_hw(self.vendor)
39
- if not hw:
40
- raise Exception("unknown vendor")
47
+
48
+ if self.hw_model:
49
+ hw = HardwareView(self.hw_model, self.sw_version)
50
+ if self.vendor and self.vendor != hw.vendor:
51
+ raise Exception(f"Vendor {self.vendor} is not vendor from hw model ({hw.vendor})")
52
+ else:
53
+ self.vendor = hw.vendor
54
+ else:
55
+ hw_provider = hardware_connector.get()
56
+ hw: HardwareView = hw_provider.vendor_to_hw(self.vendor)
57
+ if not hw:
58
+ raise Exception("unknown vendor")
59
+ self.hw_model = hw.model
41
60
  self.hw = hw
61
+
42
62
  if isinstance(self.interfaces, list):
43
63
  interfaces = []
44
64
  for iface in self.interfaces:
45
65
  try:
46
66
  interfaces.append(Interface(**iface))
47
67
  except Exception as e:
48
- raise Exception("unable to parse %s as Interface %s" % (iface, e))
68
+ raise Exception("unable to parse %s as Interface: %s" % (iface, e))
49
69
  self.interfaces = interfaces
50
70
 
51
71
  def set_storage(self, storage: Storage):
@@ -53,7 +73,7 @@ class DeviceStorage:
53
73
 
54
74
 
55
75
  @dataclass
56
- class Device(DeviceCls, DumpableView):
76
+ class Device(DeviceProtocol, DumpableView):
57
77
  dev: DeviceStorage
58
78
 
59
79
  def __hash__(self):
@@ -79,7 +99,7 @@ class Device(DeviceCls, DumpableView):
79
99
 
80
100
  @property
81
101
  def storage(self) -> Storage:
82
- return self
102
+ return self.dev.storage
83
103
 
84
104
  @property
85
105
  def hw(self) -> HardwareView:
@@ -91,7 +111,11 @@ class Device(DeviceCls, DumpableView):
91
111
 
92
112
  @property
93
113
  def neighbours_ids(self):
94
- pass
114
+ return []
115
+
116
+ @property
117
+ def neighbours_fqdns(self) -> list[str]:
118
+ return []
95
119
 
96
120
  def make_lag(self, lag: int, ports: Sequence[str], lag_min_links: Optional[int]) -> Interface:
97
121
  raise NotImplementedError
@@ -105,8 +129,8 @@ class Device(DeviceCls, DumpableView):
105
129
  def find_interface(self, name: str) -> Optional[Interface]:
106
130
  raise NotImplementedError
107
131
 
108
- def neighbours_fqdns(self) -> list[str]:
109
- return []
132
+ def flush_perf(self):
133
+ pass
110
134
 
111
135
 
112
136
  @dataclass
@@ -120,7 +144,7 @@ class Devices:
120
144
  try:
121
145
  devices.append(Device(dev=DeviceStorage(**dev)))
122
146
  except Exception as e:
123
- raise Exception("unable to parse %s as Device %s" % (dev, e))
147
+ raise Exception("unable to parse %s as Device: %s" % (dev, e))
124
148
  self.devices = devices
125
149
 
126
150
 
@@ -193,12 +217,12 @@ class FS(Storage):
193
217
  return [dev.fqdn for dev in result]
194
218
 
195
219
  def make_devices(
196
- self,
197
- query: Query | list,
198
- preload_neighbors=False,
199
- use_mesh=None,
200
- preload_extra_fields=False,
201
- **kwargs,
220
+ self,
221
+ query: Query | list,
222
+ preload_neighbors=False,
223
+ use_mesh=None,
224
+ preload_extra_fields=False,
225
+ **kwargs,
202
226
  ) -> list[Device]:
203
227
  if isinstance(query, list):
204
228
  query = Query.new(query)
@@ -231,8 +255,7 @@ def filter_query(devices: list[Device], query: Query) -> list[Device]:
231
255
 
232
256
  def read_inventory(path: str, storage: Storage) -> Devices:
233
257
  with open(path, "r") as f:
234
- data = f.read()
235
- file_data = yaml.load(data, Loader=yaml.BaseLoader)
258
+ file_data = yaml.load(f, Loader=yaml.SafeLoader)
236
259
  res = dataclass_from_dict(Devices, file_data)
237
260
  for dev in res.devices:
238
261
  dev.dev.set_storage(storage)
@@ -4,32 +4,13 @@ from annet.annlib.netdev.views.hardware import HardwareView
4
4
 
5
5
  logger = getLogger(__name__)
6
6
 
7
- _VENDORS = {
8
- "cisco": "Cisco",
9
- "catalyst": "Cisco Catalyst",
10
- "nexus": "Cisco Nexus",
11
- "iosxr": "Cisco XR",
12
- "huawei": "Huawei",
13
- "optixtrans": "Huawei OptiXtrans",
14
- "juniper": "Juniper",
15
- "arista": "Arista",
16
- "pc": "PC",
17
- "nokia": "Nokia",
18
- "aruba": "Aruba",
19
- "routeros": "RouterOS",
20
- "ribbon": "Ribbon",
21
- "b4com": "B4com",
22
- "h3c": "H3C",
23
- }
24
-
25
7
 
26
8
  def get_hw(manufacturer: str, model: str, platform_name: str):
27
- # by some reason Netbox calls Mellanox SN as MSN, so we fix them here
9
+ # By some reason Netbox calls Mellanox SN as MSN, so we fix them here
28
10
  if manufacturer == "Mellanox" and model.startswith("MSN"):
29
11
  model = model.replace("MSN", "SN", 1)
30
- vendor = manufacturer + " " + model
31
- hw = HardwareView(_VENDORS.get(vendor.lower(), vendor), platform_name)
32
- return hw
12
+
13
+ return HardwareView(manufacturer + " " + model, platform_name)
33
14
 
34
15
 
35
16
  def get_breed(manufacturer: str, model: str):
@@ -5,8 +5,9 @@ from ipaddress import ip_interface, IPv6Interface
5
5
  from typing import List, Optional, Any, Dict, Sequence, TypeVar, Generic
6
6
 
7
7
  from annet.annlib.netdev.views.dump import DumpableView
8
- from annet.annlib.netdev.views.hardware import HardwareView, lag_name, svi_name
8
+ from annet.annlib.netdev.views.hardware import HardwareView, lag_name
9
9
  from annet.storage import Storage
10
+ from annet.vendors import registry_connector
10
11
 
11
12
 
12
13
  @dataclass
@@ -259,7 +260,7 @@ class NetboxDevice(Entity, Generic[_InterfaceT]):
259
260
  return lag_interface
260
261
 
261
262
  def _svi_name(self, svi: int) -> str:
262
- return svi_name(self.hw, svi)
263
+ return registry_connector.get().match(self.hw).svi_name(svi)
263
264
 
264
265
  def add_svi(self, svi: int) -> _InterfaceT:
265
266
  name = self._svi_name(svi)
@@ -1,11 +1,12 @@
1
1
  from dataclasses import dataclass, field
2
2
  from datetime import datetime, timezone
3
3
  from ipaddress import ip_interface, IPv6Interface
4
- from typing import List, Optional, Any, Dict, Sequence, Callable
4
+ from typing import List, Optional, Any, Dict, Sequence
5
5
 
6
6
  from annet.annlib.netdev.views.dump import DumpableView
7
- from annet.annlib.netdev.views.hardware import HardwareView, lag_name, svi_name
7
+ from annet.annlib.netdev.views.hardware import HardwareView, lag_name
8
8
  from annet.storage import Storage
9
+ from annet.vendors import registry_connector
9
10
 
10
11
 
11
12
  @dataclass
@@ -259,7 +260,7 @@ class NetboxDevice(Entity):
259
260
  return lag_interface
260
261
 
261
262
  def _svi_name(self, svi: int) -> str:
262
- return svi_name(self.hw, svi)
263
+ return registry_connector.get().match(self.hw).svi_name(svi)
263
264
 
264
265
  def add_svi(self, svi: int) -> Interface:
265
266
  name = self._svi_name(svi)
@@ -1,3 +1,4 @@
1
+ import functools
1
2
  from typing import Optional
2
3
 
3
4
  from annet.annlib.netdev.devdb import parse_hw_model
@@ -51,20 +52,31 @@ class HardwareLeaf(DumpableView):
51
52
 
52
53
 
53
54
  class HardwareView(HardwareLeaf):
54
- def __init__(self, hw_model, sw_version):
55
- (true_sequences, false_sequences) = parse_hw_model(hw_model or "")
55
+ def __init__(self, hw_model, sw_version: Optional[str] = None):
56
+ true_sequences, false_sequences = parse_hw_model(hw_model or "")
56
57
  super().__init__((), true_sequences, false_sequences)
57
58
  self.model = hw_model or ""
58
59
  self._soft = sw_version or ""
59
60
 
60
61
  @property
61
62
  def vendor(self) -> Optional[str]:
62
- return hw_to_vendor(self)
63
+ from annet.hardware import hardware_connector
64
+ return hardware_connector.get().hw_to_vendor(self)
63
65
 
64
66
  @property
65
67
  def soft(self) -> str:
66
68
  return self._soft
67
69
 
70
+ @soft.setter
71
+ def soft(self, value: str) -> None:
72
+ self._soft = value
73
+
74
+ def match(self, expr: str) -> bool:
75
+ dev_path = expr.split(".")
76
+ if dev_path and dev_path[0] == "hw":
77
+ dev_path = dev_path[1:]
78
+ return bool(functools.reduce(getattr, dev_path, self))
79
+
68
80
  def __hash__(self):
69
81
  return hash(self.model)
70
82
 
@@ -72,62 +84,6 @@ class HardwareView(HardwareLeaf):
72
84
  return self.model == other.model
73
85
 
74
86
 
75
- def hw_to_vendor(hw: HardwareView) -> Optional[str]:
76
- if hw.Nexus:
77
- return "nexus"
78
- elif hw.Cisco.XR or hw.Cisco.ASR or hw.Cisco.XRV:
79
- return "iosxr"
80
- elif hw.Cisco:
81
- return "cisco"
82
- elif hw.OptiXtrans:
83
- return "optixtrans"
84
- elif hw.Huawei:
85
- return "huawei"
86
- elif hw.Juniper:
87
- return "juniper"
88
- elif hw.Arista:
89
- return "arista"
90
- elif hw.PC:
91
- return "pc"
92
- elif hw.Nokia:
93
- return "nokia"
94
- elif hw.RouterOS:
95
- return "routeros"
96
- elif hw.Aruba:
97
- return "aruba"
98
- elif hw.Ribbon:
99
- return "ribbon"
100
- elif hw.H3C:
101
- return "h3c"
102
- elif hw.B4com:
103
- return "b4com"
104
- return None
105
-
106
-
107
- def vendor_to_hw(vendor):
108
- hw = HardwareView(
109
- {
110
- "cisco": "Cisco",
111
- "catalyst": "Cisco Catalyst",
112
- "nexus": "Cisco Nexus",
113
- "iosxr": "Cisco XR",
114
- "huawei": "Huawei",
115
- "optixtrans": "Huawei OptiXtrans",
116
- "juniper": "Juniper",
117
- "arista": "Arista",
118
- "pc": "PC",
119
- "nokia": "Nokia",
120
- "aruba": "Aruba",
121
- "routeros": "RouterOS",
122
- "ribbon": "Ribbon",
123
- "h3c": "H3C",
124
- "b4com": "B4com",
125
- }.get(vendor.lower(), vendor),
126
- None,
127
- )
128
- return hw
129
-
130
-
131
87
  def lag_name(hw: HardwareView, nlagg: int) -> str:
132
88
  if hw.Huawei:
133
89
  return f"Eth-Trunk{nlagg}"
@@ -148,14 +104,3 @@ def lag_name(hw: HardwareView, nlagg: int) -> str:
148
104
  if hw.Nokia:
149
105
  return f"lagg-{nlagg}"
150
106
  raise NotImplementedError(hw)
151
-
152
-
153
- def svi_name(hw: HardwareView, num: int) -> str:
154
- if hw.Juniper:
155
- return f"irb.{num}"
156
- elif hw.Huawei:
157
- return f"Vlanif{num}"
158
- elif hw.Arista or hw.Cisco:
159
- return f"Vlan{num}"
160
- else:
161
- return f"vlan{num}"
@@ -19,6 +19,7 @@ from .rulebook.common import call_diff_logic
19
19
  from .rulebook.common import default as common_default
20
20
  from .tabparser import CommonFormatter
21
21
  from .types import Diff, Op
22
+ from ..vendors import registry_connector
22
23
 
23
24
 
24
25
  # =====
@@ -183,7 +184,8 @@ class Orderer:
183
184
  f_rule = ""
184
185
  children = []
185
186
  ordering = self.rb
186
- block_exit = platform.VENDOR_EXIT[self.vendor]
187
+
188
+ block_exit = registry_connector.get()[self.vendor].exit
187
189
 
188
190
  for (order, (raw_rule, rule)) in enumerate(ordering.items()):
189
191
  if (
@@ -224,14 +226,15 @@ class Orderer:
224
226
  return (f_order or 0), cmd_direct, odict(children), f_rule
225
227
 
226
228
  def order_config(self, config):
227
- if self.vendor not in platform.VENDOR_REVERSES:
229
+ if self.vendor not in registry_connector.get():
228
230
  return config
229
-
230
- ordered = []
231
- reverse_prefix = platform.VENDOR_REVERSES[self.vendor]
232
231
  if not config:
233
232
  return odict()
234
- for (row, children) in config.items():
233
+
234
+ ordered = []
235
+ reverse_prefix = registry_connector.get()[self.vendor].reverse
236
+
237
+ for row, children in config.items():
235
238
  cmd_direct = not row.startswith(reverse_prefix)
236
239
  (order, direct, rb, _) = self.get_order(row, cmd_direct)
237
240
  child_orderer = Orderer(rb, self.vendor)
@@ -5,7 +5,8 @@ from typing import Any, Callable, List, Optional
5
5
  from valkit import add_validator_magic
6
6
  from valkit.common import valid_bool, valid_number, valid_string_list
7
7
 
8
- from . import platform, syntax
8
+ from annet.vendors import registry_connector
9
+ from . import syntax
9
10
 
10
11
 
11
12
  # =====
@@ -13,7 +14,7 @@ from . import platform, syntax
13
14
  def compile_acl_text(text, vendor, allow_ignore=False):
14
15
  return _compile_acl(
15
16
  trees=[syntax.parse_text(text, _PARAMS_SCHEME)],
16
- reverse_prefix=platform.VENDOR_REVERSES[vendor],
17
+ reverse_prefix=registry_connector.get()[vendor].reverse,
17
18
  allow_ignore=allow_ignore,
18
19
  vendor=vendor,
19
20
  )
@@ -4,7 +4,8 @@ from collections import OrderedDict as odict
4
4
 
5
5
  from valkit.common import valid_bool, valid_string_list
6
6
 
7
- from . import platform, syntax
7
+ from annet.vendors import registry_connector
8
+ from . import syntax
8
9
 
9
10
 
10
11
  # =====
@@ -25,7 +26,7 @@ def compile_ordering_text(text, vendor):
25
26
  "default": None,
26
27
  }
27
28
  }),
28
- reverse_prefix=platform.VENDOR_REVERSES[vendor],
29
+ reverse_prefix=registry_connector.get()[vendor].reverse,
29
30
  )
30
31
 
31
32
 
@@ -0,0 +1,3 @@
1
+ VENDOR_ALIASES = {
2
+ "h3c": "huawei",
3
+ }
@@ -135,20 +135,21 @@ class DiffItem(typing.NamedTuple):
135
135
  diff_pre: typing.Dict[str, typing.Any]
136
136
 
137
137
 
138
- def default_diff(old, new, diff_pre, _pops=(Op.AFFECTED,)):
138
+ Differ = typing.Callable[[odict, odict, odict, tuple[Op, ...]], list[DiffItem]]
139
+
140
+
141
+ def default_diff(old: odict, new: odict, diff_pre: odict, _pops: tuple[Op, ...] = (Op.AFFECTED,)) -> list[DiffItem]:
139
142
  diff = base_diff(old, new, diff_pre, _pops, moved_to_affected=True)
140
143
  return diff
141
144
 
142
145
 
143
- def ordered_diff(old, new, diff_pre, _pops=(Op.AFFECTED,)):
146
+ def ordered_diff(old: odict, new: odict, diff_pre: odict, _pops: tuple[Op, ...] = (Op.AFFECTED,)) -> list[DiffItem]:
144
147
  diff = base_diff(old, new, diff_pre, _pops, moved_to_affected=False)
145
148
  return diff
146
149
 
147
150
 
148
- def rewrite_diff(old, new, diff_pre, _pops=(Op.AFFECTED,)):
149
- def iter_diff(
150
- diff: typing.List[DiffItem],
151
- ) -> typing.Iterable[typing.Tuple[int, typing.List[DiffItem]]]:
151
+ def rewrite_diff(old: odict, new: odict, diff_pre: odict, _pops: tuple[Op, ...] = (Op.AFFECTED,)) -> list[DiffItem]:
152
+ def iter_diff(diff: list[DiffItem]) -> typing.Iterable[tuple[int, list[DiffItem]]]:
152
153
  queue = [diff]
153
154
  while queue:
154
155
  items, queue = queue[0], queue[1:]
@@ -173,16 +174,18 @@ def rewrite_diff(old, new, diff_pre, _pops=(Op.AFFECTED,)):
173
174
  return diff
174
175
 
175
176
 
176
- def multiline_diff(old, new, diff_pre, _pops=(Op.AFFECTED,)):
177
+ def multiline_diff(old: odict, new: odict, diff_pre: odict, _pops: tuple[Op, ...] = (Op.AFFECTED,)) -> list[DiffItem]:
177
178
  """
178
179
  Особая логика diff'a для хуавейных мультилайнов.
179
180
  Она трактует все дочерние элементы %multiline-команды как
180
181
  одну общую команду, покидывая внутрь тот Op который был
181
182
  определен на вернем уровне
182
183
  """
184
+
183
185
  def process_multiline(op, tree):
184
- for (row, children) in tree.items():
185
- yield (op, row, list(process_multiline(op, children)), None)
186
+ for row, children in tree.items():
187
+ yield op, row, list(process_multiline(op, children)), None
188
+
186
189
  ret = []
187
190
  for item in default_diff(old, new, diff_pre, _pops):
188
191
  if old.get(item.row, {}) == new.get(item.row, {}):
@@ -192,23 +195,27 @@ def multiline_diff(old, new, diff_pre, _pops=(Op.AFFECTED,)):
192
195
  op, tree = Op.REMOVED, old
193
196
  children = list(process_multiline(op, tree[item.row]))
194
197
  ret.append(DiffItem(item.op, item.row, children, item.diff_pre))
198
+
195
199
  return ret
196
200
 
197
201
 
198
- def base_diff(old, new, diff_pre, pops, moved_to_affected=False) -> typing.List[DiffItem]:
202
+ def base_diff(
203
+ old: odict, new: odict, diff_pre: odict, pops: tuple[Op, ...], moved_to_affected: bool = False
204
+ ) -> list[DiffItem]:
199
205
  diff_indexed: typing.List[typing.Tuple[int, DiffItem]] = []
200
206
  old = _ignore_case(diff_pre, old)
201
207
  new = _ignore_case(diff_pre, new)
202
208
 
203
- for (index, row) in enumerate(old):
209
+ for index, row in enumerate(old):
204
210
  if row not in new:
205
- children = call_diff_logic(diff_pre[row]["subtree"], old[row], {}, pops + (Op.REMOVED,))
211
+ children = call_diff_logic(diff_pre[row]["subtree"], old[row], odict(), pops + (Op.REMOVED,))
206
212
  diff_indexed.append((index, DiffItem(
207
213
  op=Op.REMOVED,
208
214
  row=row,
209
215
  children=children,
210
216
  diff_pre=diff_pre[row]["match"],
211
217
  )))
218
+
212
219
  old_indexes = {row: index for (index, row) in enumerate(old)}
213
220
  block_in_disorder = False
214
221
  parent_op = pops[-1]
@@ -232,13 +239,13 @@ def base_diff(old, new, diff_pre, pops, moved_to_affected=False) -> typing.List[
232
239
  return [x[1] for x in diff_indexed]
233
240
 
234
241
 
235
- def call_diff_logic(diff_pre, old, new, pops=(Op.AFFECTED,)):
242
+ def call_diff_logic(diff_pre: odict, old: odict, new: odict, pops: tuple[Op, ...] = (Op.AFFECTED,)):
236
243
  """
237
244
  Группируем команды в старом и новом конфиге согласно выставленным
238
245
  в рулбуке атрибутам %diff_logic и вызывает их поочереди согласно
239
246
  порядку команд в old и new, предпочитая old (т.е. сначала удаления)
240
247
  """
241
- diff_logics = odict()
248
+ diff_logics: odict = odict()
242
249
  for row in old:
243
250
  logic = diff_pre[row]["match"]["attrs"]["diff_logic"]
244
251
  if logic not in diff_logics:
@@ -819,24 +819,6 @@ class RosFormatter(CommonFormatter):
819
819
  return commands
820
820
 
821
821
 
822
- def make_formatter(vendor, **kwargs):
823
- formatters = {
824
- "juniper": JuniperFormatter,
825
- "cisco": CiscoFormatter,
826
- "nexus": NexusFormatter,
827
- "huawei": HuaweiFormatter,
828
- "optixtrans": OptixtransFormatter,
829
- "arista": AristaFormatter,
830
- "nokia": NokiaFormatter,
831
- "routeros": RosFormatter,
832
- "aruba": ArubaFormatter,
833
- "pc": CommonFormatter,
834
- "ribbon": RibbonFormatter,
835
- "b4com": B4comFormatter,
836
- }
837
- return formatters[vendor](**kwargs)
838
-
839
-
840
822
  # ====
841
823
  def parse_to_tree(text, splitter, comments=("!", "#")):
842
824
  tree = odict()
@@ -25,7 +25,6 @@ import annet.deploy_ui
25
25
  import annet.lib
26
26
  from annet.annlib import jsontools
27
27
  from annet.annlib.netdev.views.hardware import HardwareView
28
- from annet.annlib.rbparser.platform import VENDOR_REVERSES
29
28
  from annet.annlib.types import GeneratorType
30
29
  from contextlog import get_logger
31
30
 
@@ -48,6 +47,7 @@ from annet.parallel import Parallel, TaskResult
48
47
  from annet.reference import RefTracker
49
48
  from annet.storage import Device, get_storage
50
49
  from annet.types import Diff, ExitCode, OldNewResult, Op, PCDiff, PCDiffFile
50
+ from annet.vendors import registry_connector
51
51
 
52
52
  DEFAULT_INDENT = " "
53
53
 
@@ -138,16 +138,19 @@ def _read_device_config(path, hw):
138
138
  _logger = get_logger()
139
139
  _logger.debug("Reading %r ...", path)
140
140
  score = 1
141
+ vendor_registry = registry_connector.get()
141
142
 
142
143
  with open(path) as cfgdump_file:
143
144
  text = cfgdump_file.read()
144
145
  try:
145
146
  if not hw:
146
147
  hw, score = guess_hw(text)
148
+
147
149
  config = tabparser.parse_to_tree(
148
150
  text=text,
149
- splitter=tabparser.make_formatter(hw).split,
151
+ splitter=vendor_registry.match(hw).make_formatter().split,
150
152
  )
153
+
151
154
  return config, hw, score
152
155
  except tabparser.ParserError:
153
156
  _logger.exception("Parser error: %r", path)
@@ -156,7 +159,7 @@ def _read_device_config(path, hw):
156
159
 
157
160
  # =====
158
161
  def _format_patch_blocks(patch_tree, hw, indent):
159
- formatter = tabparser.make_formatter(hw, indent=indent)
162
+ formatter = registry_connector.get().match(hw).make_formatter(indent=indent)
160
163
  return formatter.patch(patch_tree)
161
164
 
162
165
 
@@ -395,9 +398,12 @@ class CliDeployerJob(DeployerJob):
395
398
  (diff_obj, patch_tree) = _diff_and_patch(device, old, new, acl_rules,
396
399
  res.filter_acl_rules, self.add_comments,
397
400
  do_commit=not self.args.dont_commit)
398
- cmds = tabparser.make_formatter(device.hw, indent="").cmd_paths(patch_tree)
401
+
402
+ formatter = registry_connector.get().match(device.hw).make_formatter(indent="")
403
+ cmds = formatter.cmd_paths(patch_tree)
399
404
  if not cmds:
400
405
  return
406
+
401
407
  self._has_diff = True
402
408
  self.diffs[device] = diff_obj
403
409
  self.cmd_lines.extend(["= %s " % device.hostname, ""])
@@ -550,7 +556,7 @@ class Deployer:
550
556
  dest_name = "= %s" % ", ".join([dev.hostname for dev in devices])
551
557
  diff_lines.extend([dest_name, ""])
552
558
 
553
- for line in tabparser.make_formatter(devices[0].hw).diff(diff_obj):
559
+ for line in registry_connector.get().match(devices[0].hw).make_formatter().diff(diff_obj):
554
560
  diff_lines.append(line)
555
561
  diff_lines.append("")
556
562
  return diff_lines
@@ -786,14 +792,17 @@ def guess_hw(config_text: str):
786
792
  текста конфига и annet/rulebook/texts/*.rul"""
787
793
  scores = {}
788
794
  hw_provider = hardware_connector.get()
789
- for vendor in VENDOR_REVERSES:
795
+ vendor_registry = registry_connector.get()
796
+ for vendor in vendor_registry:
790
797
  hw = hw_provider.vendor_to_hw(vendor)
791
- fmtr = tabparser.make_formatter(hw)
792
798
  rb = rulebook.get_rulebook(hw)
799
+ fmtr = vendor_registry[vendor].make_formatter()
800
+
793
801
  try:
794
802
  config = tabparser.parse_to_tree(config_text, fmtr.split)
795
803
  except Exception:
796
804
  continue
805
+
797
806
  pre = patching.make_pre(patching.make_diff({}, config, rb, []))
798
807
  metric = _count_pre_score(pre)
799
808
  scores[metric] = hw