annet 2.5.4__tar.gz → 3.0.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.5.4/annet.egg-info → annet-3.0.0}/PKG-INFO +1 -1
  2. {annet-2.5.4 → annet-3.0.0}/annet/adapters/file/provider.py +49 -26
  3. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/common/manufacturer.py +3 -21
  4. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/common/models.py +4 -3
  5. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/v24/models.py +4 -3
  6. {annet-2.5.4 → annet-3.0.0}/annet/annet.py +8 -1
  7. {annet-2.5.4 → annet-3.0.0}/annet/annlib/netdev/devdb/data/devdb.json +1 -0
  8. {annet-2.5.4 → annet-3.0.0}/annet/annlib/netdev/views/hardware.py +15 -67
  9. {annet-2.5.4 → annet-3.0.0}/annet/annlib/patching.py +7 -5
  10. {annet-2.5.4 → annet-3.0.0}/annet/annlib/rbparser/acl.py +3 -2
  11. {annet-2.5.4 → annet-3.0.0}/annet/annlib/rbparser/ordering.py +3 -2
  12. {annet-2.5.4 → annet-3.0.0}/annet/annlib/rbparser/platform.py +4 -0
  13. {annet-2.5.4 → annet-3.0.0}/annet/annlib/rulebook/common.py +1 -1
  14. {annet-2.5.4 → annet-3.0.0}/annet/api/__init__.py +2 -1
  15. {annet-2.5.4 → annet-3.0.0}/annet/generators/__init__.py +1 -1
  16. {annet-2.5.4 → annet-3.0.0}/annet/hardware.py +8 -12
  17. {annet-2.5.4 → annet-3.0.0}/annet/parallel.py +28 -9
  18. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/__init__.py +2 -1
  19. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/deploying.py +3 -2
  20. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/patching.py +2 -2
  21. annet-3.0.0/annet/rulebook/texts/arista.rul +82 -0
  22. annet-3.0.0/annet/rulebook/texts/iosxr.deploy +27 -0
  23. annet-3.0.0/annet/rulebook/texts/iosxr.order +85 -0
  24. annet-3.0.0/annet/rulebook/texts/iosxr.rul +110 -0
  25. {annet-2.5.4 → annet-3.0.0}/annet/tabparser.py +1 -1
  26. annet-3.0.0/annet/vendors/__init__.py +33 -0
  27. annet-3.0.0/annet/vendors/base.py +25 -0
  28. annet-3.0.0/annet/vendors/registry.py +84 -0
  29. {annet-2.5.4 → annet-3.0.0/annet.egg-info}/PKG-INFO +1 -1
  30. {annet-2.5.4 → annet-3.0.0}/annet.egg-info/SOURCES.txt +7 -0
  31. {annet-2.5.4 → annet-3.0.0}/annet_generators/example/__init__.py +6 -1
  32. annet-3.0.0/annet_generators/example/hostname.py +113 -0
  33. {annet-2.5.4 → annet-3.0.0}/annet_generators/rpl_example/generator.py +3 -0
  34. annet-2.5.4/annet/rulebook/texts/arista.rul +0 -60
  35. {annet-2.5.4 → annet-3.0.0}/AUTHORS +0 -0
  36. {annet-2.5.4 → annet-3.0.0}/LICENSE +0 -0
  37. {annet-2.5.4 → annet-3.0.0}/MANIFEST.in +0 -0
  38. {annet-2.5.4 → annet-3.0.0}/README.md +0 -0
  39. {annet-2.5.4 → annet-3.0.0}/annet/__init__.py +0 -0
  40. {annet-2.5.4 → annet-3.0.0}/annet/adapters/__init__.py +0 -0
  41. {annet-2.5.4 → annet-3.0.0}/annet/adapters/fetchers/__init__.py +0 -0
  42. {annet-2.5.4 → annet-3.0.0}/annet/adapters/fetchers/stub/__init__.py +0 -0
  43. {annet-2.5.4 → annet-3.0.0}/annet/adapters/fetchers/stub/fetcher.py +0 -0
  44. {annet-2.5.4 → annet-3.0.0}/annet/adapters/file/__init__.py +0 -0
  45. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/__init__.py +0 -0
  46. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/common/__init__.py +0 -0
  47. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/common/adapter.py +0 -0
  48. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/common/client.py +0 -0
  49. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/common/query.py +0 -0
  50. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/common/status_client.py +0 -0
  51. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/common/storage_base.py +0 -0
  52. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/common/storage_opts.py +0 -0
  53. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/provider.py +0 -0
  54. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/v24/__init__.py +0 -0
  55. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/v24/storage.py +0 -0
  56. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/v37/__init__.py +0 -0
  57. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/v37/models.py +0 -0
  58. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/v37/storage.py +0 -0
  59. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/v41/__init__.py +0 -0
  60. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/v41/models.py +0 -0
  61. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/v41/storage.py +0 -0
  62. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/v42/__init__.py +0 -0
  63. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/v42/models.py +0 -0
  64. {annet-2.5.4 → annet-3.0.0}/annet/adapters/netbox/v42/storage.py +0 -0
  65. {annet-2.5.4 → annet-3.0.0}/annet/annlib/__init__.py +0 -0
  66. {annet-2.5.4 → annet-3.0.0}/annet/annlib/command.py +0 -0
  67. {annet-2.5.4 → annet-3.0.0}/annet/annlib/diff.py +0 -0
  68. {annet-2.5.4 → annet-3.0.0}/annet/annlib/errors.py +0 -0
  69. {annet-2.5.4 → annet-3.0.0}/annet/annlib/filter_acl.py +0 -0
  70. {annet-2.5.4 → annet-3.0.0}/annet/annlib/jsontools.py +0 -0
  71. {annet-2.5.4 → annet-3.0.0}/annet/annlib/lib.py +0 -0
  72. {annet-2.5.4 → annet-3.0.0}/annet/annlib/netdev/__init__.py +0 -0
  73. {annet-2.5.4 → annet-3.0.0}/annet/annlib/netdev/db.py +0 -0
  74. {annet-2.5.4 → annet-3.0.0}/annet/annlib/netdev/devdb/__init__.py +0 -0
  75. {annet-2.5.4 → annet-3.0.0}/annet/annlib/netdev/views/__init__.py +0 -0
  76. {annet-2.5.4 → annet-3.0.0}/annet/annlib/netdev/views/dump.py +0 -0
  77. {annet-2.5.4 → annet-3.0.0}/annet/annlib/output.py +0 -0
  78. {annet-2.5.4 → annet-3.0.0}/annet/annlib/rbparser/__init__.py +0 -0
  79. {annet-2.5.4 → annet-3.0.0}/annet/annlib/rbparser/deploying.py +0 -0
  80. {annet-2.5.4 → annet-3.0.0}/annet/annlib/rbparser/syntax.py +0 -0
  81. {annet-2.5.4 → annet-3.0.0}/annet/annlib/rulebook/__init__.py +0 -0
  82. {annet-2.5.4 → annet-3.0.0}/annet/annlib/tabparser.py +0 -0
  83. {annet-2.5.4 → annet-3.0.0}/annet/annlib/types.py +0 -0
  84. {annet-2.5.4 → annet-3.0.0}/annet/argparse.py +0 -0
  85. {annet-2.5.4 → annet-3.0.0}/annet/bgp_models.py +0 -0
  86. {annet-2.5.4 → annet-3.0.0}/annet/cli.py +0 -0
  87. {annet-2.5.4 → annet-3.0.0}/annet/cli_args.py +0 -0
  88. {annet-2.5.4 → annet-3.0.0}/annet/configs/context.yml +0 -0
  89. {annet-2.5.4 → annet-3.0.0}/annet/configs/logging.yaml +0 -0
  90. {annet-2.5.4 → annet-3.0.0}/annet/connectors.py +0 -0
  91. {annet-2.5.4 → annet-3.0.0}/annet/deploy.py +0 -0
  92. {annet-2.5.4 → annet-3.0.0}/annet/deploy_ui.py +0 -0
  93. {annet-2.5.4 → annet-3.0.0}/annet/diff.py +0 -0
  94. {annet-2.5.4 → annet-3.0.0}/annet/executor.py +0 -0
  95. {annet-2.5.4 → annet-3.0.0}/annet/filtering.py +0 -0
  96. {annet-2.5.4 → annet-3.0.0}/annet/gen.py +0 -0
  97. {annet-2.5.4 → annet-3.0.0}/annet/generators/base.py +0 -0
  98. {annet-2.5.4 → annet-3.0.0}/annet/generators/common/__init__.py +0 -0
  99. {annet-2.5.4 → annet-3.0.0}/annet/generators/common/initial.py +0 -0
  100. {annet-2.5.4 → annet-3.0.0}/annet/generators/entire.py +0 -0
  101. {annet-2.5.4 → annet-3.0.0}/annet/generators/exceptions.py +0 -0
  102. {annet-2.5.4 → annet-3.0.0}/annet/generators/jsonfragment.py +0 -0
  103. {annet-2.5.4 → annet-3.0.0}/annet/generators/partial.py +0 -0
  104. {annet-2.5.4 → annet-3.0.0}/annet/generators/perf.py +0 -0
  105. {annet-2.5.4 → annet-3.0.0}/annet/generators/ref.py +0 -0
  106. {annet-2.5.4 → annet-3.0.0}/annet/generators/result.py +0 -0
  107. {annet-2.5.4 → annet-3.0.0}/annet/implicit.py +0 -0
  108. {annet-2.5.4 → annet-3.0.0}/annet/lib.py +0 -0
  109. {annet-2.5.4 → annet-3.0.0}/annet/mesh/__init__.py +0 -0
  110. {annet-2.5.4 → annet-3.0.0}/annet/mesh/basemodel.py +0 -0
  111. {annet-2.5.4 → annet-3.0.0}/annet/mesh/device_models.py +0 -0
  112. {annet-2.5.4 → annet-3.0.0}/annet/mesh/executor.py +0 -0
  113. {annet-2.5.4 → annet-3.0.0}/annet/mesh/match_args.py +0 -0
  114. {annet-2.5.4 → annet-3.0.0}/annet/mesh/models_converter.py +0 -0
  115. {annet-2.5.4 → annet-3.0.0}/annet/mesh/peer_models.py +0 -0
  116. {annet-2.5.4 → annet-3.0.0}/annet/mesh/port_processor.py +0 -0
  117. {annet-2.5.4 → annet-3.0.0}/annet/mesh/registry.py +0 -0
  118. {annet-2.5.4 → annet-3.0.0}/annet/output.py +0 -0
  119. {annet-2.5.4 → annet-3.0.0}/annet/patching.py +0 -0
  120. {annet-2.5.4 → annet-3.0.0}/annet/reference.py +0 -0
  121. {annet-2.5.4 → annet-3.0.0}/annet/rpl/__init__.py +0 -0
  122. {annet-2.5.4 → annet-3.0.0}/annet/rpl/action.py +0 -0
  123. {annet-2.5.4 → annet-3.0.0}/annet/rpl/condition.py +0 -0
  124. {annet-2.5.4 → annet-3.0.0}/annet/rpl/match_builder.py +0 -0
  125. {annet-2.5.4 → annet-3.0.0}/annet/rpl/policy.py +0 -0
  126. {annet-2.5.4 → annet-3.0.0}/annet/rpl/result.py +0 -0
  127. {annet-2.5.4 → annet-3.0.0}/annet/rpl/routemap.py +0 -0
  128. {annet-2.5.4 → annet-3.0.0}/annet/rpl/statement_builder.py +0 -0
  129. {annet-2.5.4 → annet-3.0.0}/annet/rpl_generators/__init__.py +0 -0
  130. {annet-2.5.4 → annet-3.0.0}/annet/rpl_generators/aspath.py +0 -0
  131. {annet-2.5.4 → annet-3.0.0}/annet/rpl_generators/community.py +0 -0
  132. {annet-2.5.4 → annet-3.0.0}/annet/rpl_generators/cumulus_frr.py +0 -0
  133. {annet-2.5.4 → annet-3.0.0}/annet/rpl_generators/entities.py +0 -0
  134. {annet-2.5.4 → annet-3.0.0}/annet/rpl_generators/execute.py +0 -0
  135. {annet-2.5.4 → annet-3.0.0}/annet/rpl_generators/policy.py +0 -0
  136. {annet-2.5.4 → annet-3.0.0}/annet/rpl_generators/prefix_lists.py +0 -0
  137. {annet-2.5.4 → annet-3.0.0}/annet/rpl_generators/rd.py +0 -0
  138. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/arista/__init__.py +0 -0
  139. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/arista/aaa.py +0 -0
  140. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/arista/iface.py +0 -0
  141. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/aruba/__init__.py +0 -0
  142. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/aruba/ap_env.py +0 -0
  143. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/aruba/misc.py +0 -0
  144. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/b4com/__init__.py +0 -0
  145. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/b4com/file.py +0 -0
  146. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/b4com/iface.py +0 -0
  147. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/cisco/__init__.py +0 -0
  148. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/cisco/iface.py +0 -0
  149. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/cisco/misc.py +0 -0
  150. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/cisco/vlandb.py +0 -0
  151. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/common.py +0 -0
  152. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/huawei/__init__.py +0 -0
  153. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/huawei/aaa.py +0 -0
  154. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/huawei/bgp.py +0 -0
  155. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/huawei/iface.py +0 -0
  156. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/huawei/misc.py +0 -0
  157. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/huawei/vlandb.py +0 -0
  158. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/juniper/__init__.py +0 -0
  159. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/nexus/__init__.py +0 -0
  160. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/nexus/iface.py +0 -0
  161. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/routeros/__init__.py +0 -0
  162. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/routeros/file.py +0 -0
  163. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/arista.deploy +0 -0
  164. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/arista.order +0 -0
  165. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/aruba.deploy +0 -0
  166. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/aruba.order +0 -0
  167. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/aruba.rul +0 -0
  168. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/b4com.deploy +0 -0
  169. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/b4com.order +0 -0
  170. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/b4com.rul +0 -0
  171. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/cisco.deploy +0 -0
  172. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/cisco.order +0 -0
  173. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/cisco.rul +0 -0
  174. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/huawei.deploy +0 -0
  175. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/huawei.order +0 -0
  176. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/huawei.rul +0 -0
  177. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/juniper.order +0 -0
  178. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/juniper.rul +0 -0
  179. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/nexus.deploy +0 -0
  180. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/nexus.order +0 -0
  181. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/nexus.rul +0 -0
  182. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/nokia.rul +0 -0
  183. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/optixtrans.deploy +0 -0
  184. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/optixtrans.order +0 -0
  185. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/optixtrans.rul +0 -0
  186. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/pc.deploy +0 -0
  187. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/pc.order +0 -0
  188. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/pc.rul +0 -0
  189. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/ribbon.deploy +0 -0
  190. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/ribbon.rul +0 -0
  191. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/routeros.order +0 -0
  192. {annet-2.5.4 → annet-3.0.0}/annet/rulebook/texts/routeros.rul +0 -0
  193. {annet-2.5.4 → annet-3.0.0}/annet/storage.py +0 -0
  194. {annet-2.5.4 → annet-3.0.0}/annet/text_term_format.py +0 -0
  195. {annet-2.5.4 → annet-3.0.0}/annet/tracing.py +0 -0
  196. {annet-2.5.4 → annet-3.0.0}/annet/types.py +0 -0
  197. {annet-2.5.4 → annet-3.0.0}/annet.egg-info/dependency_links.txt +0 -0
  198. {annet-2.5.4 → annet-3.0.0}/annet.egg-info/entry_points.txt +0 -0
  199. {annet-2.5.4 → annet-3.0.0}/annet.egg-info/requires.txt +0 -0
  200. {annet-2.5.4 → annet-3.0.0}/annet.egg-info/top_level.txt +0 -0
  201. {annet-2.5.4 → annet-3.0.0}/annet_generators/__init__.py +0 -0
  202. {annet-2.5.4 → annet-3.0.0}/annet_generators/example/lldp.py +0 -0
  203. {annet-2.5.4 → annet-3.0.0}/annet_generators/mesh_example/__init__.py +0 -0
  204. {annet-2.5.4 → annet-3.0.0}/annet_generators/mesh_example/bgp.py +0 -0
  205. {annet-2.5.4 → annet-3.0.0}/annet_generators/mesh_example/mesh_logic.py +0 -0
  206. {annet-2.5.4 → annet-3.0.0}/annet_generators/rpl_example/__init__.py +0 -0
  207. {annet-2.5.4 → annet-3.0.0}/annet_generators/rpl_example/items.py +0 -0
  208. {annet-2.5.4 → annet-3.0.0}/annet_generators/rpl_example/mesh.py +0 -0
  209. {annet-2.5.4 → annet-3.0.0}/annet_generators/rpl_example/route_policy.py +0 -0
  210. {annet-2.5.4 → annet-3.0.0}/requirements.txt +0 -0
  211. {annet-2.5.4 → annet-3.0.0}/setup.cfg +0 -0
  212. {annet-2.5.4 → annet-3.0.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: annet
3
- Version: 2.5.4
3
+ Version: 3.0.0
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -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,31 +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
- "huawei": "Huawei",
12
- "optixtrans": "Huawei OptiXtrans",
13
- "juniper": "Juniper",
14
- "arista": "Arista",
15
- "pc": "PC",
16
- "nokia": "Nokia",
17
- "aruba": "Aruba",
18
- "routeros": "RouterOS",
19
- "ribbon": "Ribbon",
20
- "b4com": "B4com",
21
- "h3c": "H3C",
22
- }
23
-
24
7
 
25
8
  def get_hw(manufacturer: str, model: str, platform_name: str):
26
- # 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
27
10
  if manufacturer == "Mellanox" and model.startswith("MSN"):
28
11
  model = model.replace("MSN", "SN", 1)
29
- vendor = manufacturer + " " + model
30
- hw = HardwareView(_VENDORS.get(vendor.lower(), vendor), platform_name)
31
- return hw
12
+
13
+ return HardwareView(manufacturer + " " + model, platform_name)
32
14
 
33
15
 
34
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
@@ -140,7 +141,7 @@ class Interface(Entity, Generic[_IpAddressT]):
140
141
  mode: Optional[InterfaceMode]
141
142
  untagged_vlan: Optional[InterfaceVlan]
142
143
  tagged_vlans: Optional[List[InterfaceVlan]]
143
- tags: List[EntityWithSlug]
144
+ tags: List[EntityWithSlug] = field(default_factory=list)
144
145
  display: str = ""
145
146
  ip_addresses: List[_IpAddressT] = field(default_factory=list)
146
147
  vrf: Optional[Entity] = None
@@ -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,4 +1,5 @@
1
1
  #!/usr/bin/env python3
2
+ import logging
2
3
  import sys
3
4
 
4
5
  import annet
@@ -18,8 +19,14 @@ def main():
18
19
  parser.add_commands(parser.find_subcommands(cli.list_subcommands()))
19
20
  try:
20
21
  return parser.dispatch(pre_call=annet.init, add_help_command=True)
21
- except (generators.GeneratorError, annet.ExecError):
22
+ except (generators.GeneratorError, annet.ExecError) as e:
23
+ logging.error(e)
22
24
  return 1
25
+ except BaseException as e:
26
+ if formatted_output := getattr(e, "formatted_output", None):
27
+ logging.error(formatted_output)
28
+ return 1
29
+ raise e
23
30
 
24
31
 
25
32
  if __name__ == "__main__":
@@ -6,6 +6,7 @@
6
6
  "Cisco.ASR": " ASR",
7
7
  "Cisco.ASR.ASR9000": " 9\\d{3}",
8
8
  "Cisco.XRV": "XRv",
9
+ "Cisco.XR": " 8[\\d\\d\\d]",
9
10
  "Cisco.Catalyst": " (Catalyst |WS-C)",
10
11
  "Cisco.Catalyst.C2900": "29\\d\\d",
11
12
  "Cisco.Catalyst.C2900.C2950": "2950",
@@ -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,59 +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:
79
- return "cisco"
80
- elif hw.OptiXtrans:
81
- return "optixtrans"
82
- elif hw.Huawei:
83
- return "huawei"
84
- elif hw.Juniper:
85
- return "juniper"
86
- elif hw.Arista:
87
- return "arista"
88
- elif hw.PC:
89
- return "pc"
90
- elif hw.Nokia:
91
- return "nokia"
92
- elif hw.RouterOS:
93
- return "routeros"
94
- elif hw.Aruba:
95
- return "aruba"
96
- elif hw.Ribbon:
97
- return "ribbon"
98
- elif hw.H3C:
99
- return "h3c"
100
- elif hw.B4com:
101
- return "b4com"
102
- return None
103
-
104
-
105
- def vendor_to_hw(vendor):
106
- hw = HardwareView(
107
- {
108
- "cisco": "Cisco",
109
- "catalyst": "Cisco Catalyst",
110
- "nexus": "Cisco Nexus",
111
- "huawei": "Huawei",
112
- "optixtrans": "Huawei OptiXtrans",
113
- "juniper": "Juniper",
114
- "arista": "Arista",
115
- "pc": "PC",
116
- "nokia": "Nokia",
117
- "aruba": "Aruba",
118
- "routeros": "RouterOS",
119
- "ribbon": "Ribbon",
120
- "h3c": "H3C",
121
- "b4com": "B4com",
122
- }.get(vendor.lower(), vendor),
123
- None,
124
- )
125
- return hw
126
-
127
-
128
87
  def lag_name(hw: HardwareView, nlagg: int) -> str:
129
88
  if hw.Huawei:
130
89
  return f"Eth-Trunk{nlagg}"
@@ -145,14 +104,3 @@ def lag_name(hw: HardwareView, nlagg: int) -> str:
145
104
  if hw.Nokia:
146
105
  return f"lagg-{nlagg}"
147
106
  raise NotImplementedError(hw)
148
-
149
-
150
- def svi_name(hw: HardwareView, num: int) -> str:
151
- if hw.Juniper:
152
- return f"irb.{num}"
153
- elif hw.Huawei:
154
- return f"Vlanif{num}"
155
- elif hw.Arista or hw.Cisco:
156
- return f"Vlan{num}"
157
- else:
158
- 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
  # =====
@@ -224,14 +225,15 @@ class Orderer:
224
225
  return (f_order or 0), cmd_direct, odict(children), f_rule
225
226
 
226
227
  def order_config(self, config):
227
- if self.vendor not in platform.VENDOR_REVERSES:
228
+ if self.vendor not in registry_connector.get():
228
229
  return config
229
-
230
- ordered = []
231
- reverse_prefix = platform.VENDOR_REVERSES[self.vendor]
232
230
  if not config:
233
231
  return odict()
234
- for (row, children) in config.items():
232
+
233
+ ordered = []
234
+ reverse_prefix = registry_connector.get()[self.vendor].reverse
235
+
236
+ for row, children in config.items():
235
237
  cmd_direct = not row.startswith(reverse_prefix)
236
238
  (order, direct, rb, _) = self.get_order(row, cmd_direct)
237
239
  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
 
@@ -3,6 +3,7 @@ VENDOR_REVERSES = {
3
3
  "h3c": "undo",
4
4
  "optixtrans": "undo",
5
5
  "cisco": "no",
6
+ "iosxr": "no",
6
7
  "nexus": "no",
7
8
  "juniper": "delete",
8
9
  "arista": "no",
@@ -18,6 +19,7 @@ VENDOR_DIFF = {
18
19
  "huawei": "common.default_diff",
19
20
  "optixtrans": "common.default_diff",
20
21
  "cisco": "common.default_diff",
22
+ "iosxr": "common.default_diff",
21
23
  "nexus": "common.default_diff",
22
24
  "juniper": "juniper.default_diff",
23
25
  "arista": "common.default_diff",
@@ -33,6 +35,7 @@ VENDOR_DIFF_ORDERED = {
33
35
  "huawei": "common.ordered_diff",
34
36
  "optixtrans": "common.ordered_diff",
35
37
  "cisco": "common.ordered_diff",
38
+ "iosxr": "common.ordered_diff",
36
39
  "nexus": "common.ordered_diff",
37
40
  "juniper": "juniper.ordered_diff",
38
41
  "arista": "common.ordered_diff",
@@ -49,6 +52,7 @@ VENDOR_EXIT = {
49
52
  "h3c": "quit",
50
53
  "optixtrans": "quit",
51
54
  "cisco": "exit",
55
+ "iosxr": "exit",
52
56
  "nexus": "exit",
53
57
  "arista": "exit",
54
58
  "juniper": "",
@@ -297,7 +297,7 @@ def apply(hw, do_commit, do_finalize, **_):
297
297
  after.add_cmd(Command("abort")) # просто exit оставит висеть configure session
298
298
  if do_finalize:
299
299
  after.add_cmd(Command("write memory"))
300
- elif hw.ASR or hw.XRV:
300
+ elif hw.ASR or hw.XRV or hw.XR:
301
301
  # коммит сам сохраняет изменения в стартап do_finalize не применим
302
302
  before.add_cmd(Command("configure exclusive"))
303
303
  if do_commit:
@@ -48,6 +48,7 @@ from annet.parallel import Parallel, TaskResult
48
48
  from annet.reference import RefTracker
49
49
  from annet.storage import Device, get_storage
50
50
  from annet.types import Diff, ExitCode, OldNewResult, Op, PCDiff, PCDiffFile
51
+ from annet.vendors import registry_connector
51
52
 
52
53
  DEFAULT_INDENT = " "
53
54
 
@@ -786,7 +787,7 @@ def guess_hw(config_text: str):
786
787
  текста конфига и annet/rulebook/texts/*.rul"""
787
788
  scores = {}
788
789
  hw_provider = hardware_connector.get()
789
- for vendor in VENDOR_REVERSES:
790
+ for vendor in registry_connector.get():
790
791
  hw = hw_provider.vendor_to_hw(vendor)
791
792
  fmtr = tabparser.make_formatter(hw)
792
793
  rb = rulebook.get_rulebook(hw)
@@ -197,7 +197,7 @@ def _run_partial_generator(gen: "PartialGenerator", run_args: GeneratorPartialRu
197
197
  raise
198
198
  except Exception as err:
199
199
  filename, lineno = gen.get_running_line()
200
- logger.exception("Generator error in file '%s:%i'", filename, lineno)
200
+ logger.error("Generator error in file '%s:%i'", filename, lineno)
201
201
  raise GeneratorError(f"{gen} on {device}") from err
202
202
 
203
203
  fmtr = tabparser.make_formatter(device.hw)
@@ -1,17 +1,11 @@
1
1
  import abc
2
2
  from typing import Any
3
3
 
4
- from annet.annlib.netdev.views.hardware import HardwareView, hw_to_vendor
5
-
4
+ from annet.annlib.netdev.views.hardware import HardwareView
5
+ from annet.vendors import registry_connector
6
6
  from annet.connectors import Connector
7
7
 
8
8
 
9
- try:
10
- from annet.annlib.netdev.views.hardware import vendor_to_hw
11
- except ImportError:
12
- from netdev.views.hardware import vendor_to_hw
13
-
14
-
15
9
  class _HardwareConnector(Connector["HarwareProvider"]):
16
10
  name = "Hardware"
17
11
  ep_name = "hardware"
@@ -31,7 +25,7 @@ class HarwareProvider(abc.ABC):
31
25
  pass
32
26
 
33
27
  @abc.abstractmethod
34
- def hw_to_vendor(self, hw: Any) -> str:
28
+ def hw_to_vendor(self, hw: Any) -> str | None:
35
29
  pass
36
30
 
37
31
 
@@ -40,7 +34,9 @@ class AnnetHardwareProvider(HarwareProvider):
40
34
  return HardwareView(hw_model, sw_version)
41
35
 
42
36
  def vendor_to_hw(self, vendor: str) -> HardwareView:
43
- return vendor_to_hw(vendor)
37
+ return registry_connector.get().get(vendor.lower()).hardware
44
38
 
45
- def hw_to_vendor(self, hw: HardwareView) -> str:
46
- return hw_to_vendor(hw)
39
+ def hw_to_vendor(self, hw: HardwareView) -> str | None:
40
+ if vendor := registry_connector.get().match(hw, None):
41
+ return vendor.NAME
42
+ return None
@@ -15,13 +15,14 @@ import tempfile
15
15
  import time
16
16
  import traceback
17
17
  import warnings
18
- from typing import Any, List, Optional, Type
18
+ from typing import Any, List, Optional, Type, Callable
19
19
  from uuid import uuid4
20
20
 
21
21
  from contextlog import get_logger
22
22
 
23
23
  import annet
24
24
  from annet import tracing
25
+ from annet.connectors import Connector
25
26
  from annet.lib import catch_ctrl_c, find_exc_in_stack
26
27
  from annet.output import capture_output
27
28
  from annet.tracing import tracing_connector
@@ -38,6 +39,20 @@ class PoolWorkerTask:
38
39
  payload: Optional[Any] = None
39
40
 
40
41
 
42
+ class _PickleSafeTracebackFormatterConnector(Connector[Callable[[BaseException], str]]):
43
+ name = "PickleSafeTraceBackFormatter"
44
+ ep_name = "pickle_safe_traceback_formatter"
45
+
46
+ def _get_default(self) -> Callable[[], Callable[[BaseException], str]]:
47
+ def wrapper():
48
+ return lambda x: "".join(traceback.format_exception(x))
49
+
50
+ return wrapper
51
+
52
+
53
+ pickle_safe_traceback_formatter_connector = _PickleSafeTracebackFormatterConnector()
54
+
55
+
41
56
  class PickleSafeException(Exception):
42
57
  """An exception that can be safely pickled and passed between processes."""
43
58
 
@@ -59,9 +74,14 @@ class PickleSafeException(Exception):
59
74
  pretty_lines.append(self.formatted_output)
60
75
  return "\n".join(pretty_lines)
61
76
 
62
- @staticmethod
63
- def from_exc(orig_exc: Exception, device_id: str, formatted_output: str) -> "PickleSafeException":
64
- return PickleSafeException(orig_exc.__class__, str(orig_exc), device_id, formatted_output)
77
+ @classmethod
78
+ def from_exc(cls, orig_exc: Exception, device_id: str) -> "PickleSafeException":
79
+ return PickleSafeException(
80
+ orig_exc.__class__,
81
+ str(orig_exc),
82
+ device_id,
83
+ pickle_safe_traceback_formatter_connector.get()(orig_exc)
84
+ )
65
85
 
66
86
 
67
87
  @catch_ctrl_c
@@ -164,7 +184,7 @@ def _pool_worker(pool, index, task_queue, done_queue):
164
184
  except KeyboardInterrupt: # pylint: disable=try-except-raise
165
185
  raise
166
186
  except Exception as exc:
167
- safe_exc = PickleSafeException.from_exc(exc, task.payload, traceback.format_exc())
187
+ safe_exc = PickleSafeException.from_exc(exc, task.payload)
168
188
  ret_exc = safe_exc
169
189
  task_result.exc = safe_exc
170
190
  task_result.result = None
@@ -301,11 +321,10 @@ class Parallel:
301
321
  **self.kwargs
302
322
  )
303
323
  except Exception as exc:
324
+ safe_exc = PickleSafeException.from_exc(exc, device_id)
304
325
  if not tolerate_fails:
305
- raise
306
- exc.device_id = device_id
307
- exc.formatted_output = traceback.format_exc()
308
- task_result.exc = exc
326
+ raise safe_exc
327
+ task_result.exc = safe_exc
309
328
  if self.capture_output:
310
329
  task_result.extra["cap_stdout"] = cap_stdout.read()
311
330
  task_result.extra["cap_stderr"] = cap_stderr.read()
@@ -10,6 +10,7 @@ from annet.annlib.rbparser.platform import VENDOR_REVERSES, VENDOR_ALIASES
10
10
  from annet.connectors import CachedConnector
11
11
  from annet.rulebook.deploying import compile_deploying_text
12
12
  from annet.rulebook.patching import compile_patching_text
13
+ from annet.vendors import registry_connector
13
14
 
14
15
 
15
16
  class RulebookProvider(ABC):
@@ -63,7 +64,7 @@ class DefaultRulebookProvider(RulebookProvider):
63
64
  if hw in self._rulebook_cache:
64
65
  return self._rulebook_cache[hw]
65
66
 
66
- assert hw.vendor in VENDOR_REVERSES, "Unknown vendor: %s" % (hw.vendor)
67
+ assert hw.vendor in registry_connector.get(), "Unknown vendor: %s" % (hw.vendor)
67
68
  rul_vendor_name = VENDOR_ALIASES.get(hw.vendor, hw.vendor)
68
69
  patching = compile_patching_text(self._render_rul(rul_vendor_name + ".rul", hw), rul_vendor_name)
69
70