annet 0.16.35__tar.gz → 1.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 (195) hide show
  1. {annet-0.16.35/annet.egg-info → annet-1.0.0}/PKG-INFO +1 -1
  2. annet-1.0.0/annet/adapters/fetchers/stub/fetcher.py +25 -0
  3. {annet-0.16.35 → annet-1.0.0}/annet/api/__init__.py +32 -8
  4. annet-1.0.0/annet/deploy.py +223 -0
  5. annet-1.0.0/annet/deploy_ui.py +774 -0
  6. {annet-0.16.35 → annet-1.0.0}/annet/gen.py +5 -5
  7. {annet-0.16.35 → annet-1.0.0}/annet/lib.py +19 -3
  8. {annet-0.16.35 → annet-1.0.0/annet.egg-info}/PKG-INFO +1 -1
  9. {annet-0.16.35 → annet-1.0.0}/annet.egg-info/SOURCES.txt +1 -0
  10. annet-0.16.35/annet/adapters/fetchers/stub/fetcher.py +0 -19
  11. annet-0.16.35/annet/deploy.py +0 -529
  12. {annet-0.16.35 → annet-1.0.0}/AUTHORS +0 -0
  13. {annet-0.16.35 → annet-1.0.0}/LICENSE +0 -0
  14. {annet-0.16.35 → annet-1.0.0}/MANIFEST.in +0 -0
  15. {annet-0.16.35 → annet-1.0.0}/README.md +0 -0
  16. {annet-0.16.35 → annet-1.0.0}/annet/__init__.py +0 -0
  17. {annet-0.16.35 → annet-1.0.0}/annet/adapters/__init__.py +0 -0
  18. {annet-0.16.35 → annet-1.0.0}/annet/adapters/fetchers/__init__.py +0 -0
  19. {annet-0.16.35 → annet-1.0.0}/annet/adapters/fetchers/stub/__init__.py +0 -0
  20. {annet-0.16.35 → annet-1.0.0}/annet/adapters/file/__init__.py +0 -0
  21. {annet-0.16.35 → annet-1.0.0}/annet/adapters/file/provider.py +0 -0
  22. {annet-0.16.35 → annet-1.0.0}/annet/adapters/netbox/__init__.py +0 -0
  23. {annet-0.16.35 → annet-1.0.0}/annet/adapters/netbox/common/__init__.py +0 -0
  24. {annet-0.16.35 → annet-1.0.0}/annet/adapters/netbox/common/client.py +0 -0
  25. {annet-0.16.35 → annet-1.0.0}/annet/adapters/netbox/common/manufacturer.py +0 -0
  26. {annet-0.16.35 → annet-1.0.0}/annet/adapters/netbox/common/models.py +0 -0
  27. {annet-0.16.35 → annet-1.0.0}/annet/adapters/netbox/common/query.py +0 -0
  28. {annet-0.16.35 → annet-1.0.0}/annet/adapters/netbox/common/status_client.py +0 -0
  29. {annet-0.16.35 → annet-1.0.0}/annet/adapters/netbox/common/storage_opts.py +0 -0
  30. {annet-0.16.35 → annet-1.0.0}/annet/adapters/netbox/provider.py +0 -0
  31. {annet-0.16.35 → annet-1.0.0}/annet/adapters/netbox/v24/__init__.py +0 -0
  32. {annet-0.16.35 → annet-1.0.0}/annet/adapters/netbox/v24/storage.py +0 -0
  33. {annet-0.16.35 → annet-1.0.0}/annet/adapters/netbox/v37/__init__.py +0 -0
  34. {annet-0.16.35 → annet-1.0.0}/annet/adapters/netbox/v37/storage.py +0 -0
  35. {annet-0.16.35 → annet-1.0.0}/annet/annet.py +0 -0
  36. {annet-0.16.35 → annet-1.0.0}/annet/annlib/__init__.py +0 -0
  37. {annet-0.16.35 → annet-1.0.0}/annet/annlib/command.py +0 -0
  38. {annet-0.16.35 → annet-1.0.0}/annet/annlib/diff.py +0 -0
  39. {annet-0.16.35 → annet-1.0.0}/annet/annlib/errors.py +0 -0
  40. {annet-0.16.35 → annet-1.0.0}/annet/annlib/filter_acl.py +0 -0
  41. {annet-0.16.35 → annet-1.0.0}/annet/annlib/jsontools.py +0 -0
  42. {annet-0.16.35 → annet-1.0.0}/annet/annlib/lib.py +0 -0
  43. {annet-0.16.35 → annet-1.0.0}/annet/annlib/netdev/__init__.py +0 -0
  44. {annet-0.16.35 → annet-1.0.0}/annet/annlib/netdev/db.py +0 -0
  45. {annet-0.16.35 → annet-1.0.0}/annet/annlib/netdev/devdb/__init__.py +0 -0
  46. {annet-0.16.35 → annet-1.0.0}/annet/annlib/netdev/devdb/data/devdb.json +0 -0
  47. {annet-0.16.35 → annet-1.0.0}/annet/annlib/netdev/views/__init__.py +0 -0
  48. {annet-0.16.35 → annet-1.0.0}/annet/annlib/netdev/views/dump.py +0 -0
  49. {annet-0.16.35 → annet-1.0.0}/annet/annlib/netdev/views/hardware.py +0 -0
  50. {annet-0.16.35 → annet-1.0.0}/annet/annlib/output.py +0 -0
  51. {annet-0.16.35 → annet-1.0.0}/annet/annlib/patching.py +0 -0
  52. {annet-0.16.35 → annet-1.0.0}/annet/annlib/rbparser/__init__.py +0 -0
  53. {annet-0.16.35 → annet-1.0.0}/annet/annlib/rbparser/acl.py +0 -0
  54. {annet-0.16.35 → annet-1.0.0}/annet/annlib/rbparser/deploying.py +0 -0
  55. {annet-0.16.35 → annet-1.0.0}/annet/annlib/rbparser/ordering.py +0 -0
  56. {annet-0.16.35 → annet-1.0.0}/annet/annlib/rbparser/platform.py +0 -0
  57. {annet-0.16.35 → annet-1.0.0}/annet/annlib/rbparser/syntax.py +0 -0
  58. {annet-0.16.35 → annet-1.0.0}/annet/annlib/rulebook/__init__.py +0 -0
  59. {annet-0.16.35 → annet-1.0.0}/annet/annlib/rulebook/common.py +0 -0
  60. {annet-0.16.35 → annet-1.0.0}/annet/annlib/tabparser.py +0 -0
  61. {annet-0.16.35 → annet-1.0.0}/annet/annlib/types.py +0 -0
  62. {annet-0.16.35 → annet-1.0.0}/annet/argparse.py +0 -0
  63. {annet-0.16.35 → annet-1.0.0}/annet/bgp_models.py +0 -0
  64. {annet-0.16.35 → annet-1.0.0}/annet/cli.py +0 -0
  65. {annet-0.16.35 → annet-1.0.0}/annet/cli_args.py +0 -0
  66. {annet-0.16.35 → annet-1.0.0}/annet/configs/context.yml +0 -0
  67. {annet-0.16.35 → annet-1.0.0}/annet/configs/logging.yaml +0 -0
  68. {annet-0.16.35 → annet-1.0.0}/annet/connectors.py +0 -0
  69. {annet-0.16.35 → annet-1.0.0}/annet/diff.py +0 -0
  70. {annet-0.16.35 → annet-1.0.0}/annet/executor.py +0 -0
  71. {annet-0.16.35 → annet-1.0.0}/annet/filtering.py +0 -0
  72. {annet-0.16.35 → annet-1.0.0}/annet/generators/__init__.py +0 -0
  73. {annet-0.16.35 → annet-1.0.0}/annet/generators/base.py +0 -0
  74. {annet-0.16.35 → annet-1.0.0}/annet/generators/common/__init__.py +0 -0
  75. {annet-0.16.35 → annet-1.0.0}/annet/generators/common/initial.py +0 -0
  76. {annet-0.16.35 → annet-1.0.0}/annet/generators/entire.py +0 -0
  77. {annet-0.16.35 → annet-1.0.0}/annet/generators/exceptions.py +0 -0
  78. {annet-0.16.35 → annet-1.0.0}/annet/generators/jsonfragment.py +0 -0
  79. {annet-0.16.35 → annet-1.0.0}/annet/generators/partial.py +0 -0
  80. {annet-0.16.35 → annet-1.0.0}/annet/generators/perf.py +0 -0
  81. {annet-0.16.35 → annet-1.0.0}/annet/generators/ref.py +0 -0
  82. {annet-0.16.35 → annet-1.0.0}/annet/generators/result.py +0 -0
  83. {annet-0.16.35 → annet-1.0.0}/annet/hardware.py +0 -0
  84. {annet-0.16.35 → annet-1.0.0}/annet/implicit.py +0 -0
  85. {annet-0.16.35 → annet-1.0.0}/annet/mesh/__init__.py +0 -0
  86. {annet-0.16.35 → annet-1.0.0}/annet/mesh/basemodel.py +0 -0
  87. {annet-0.16.35 → annet-1.0.0}/annet/mesh/device_models.py +0 -0
  88. {annet-0.16.35 → annet-1.0.0}/annet/mesh/executor.py +0 -0
  89. {annet-0.16.35 → annet-1.0.0}/annet/mesh/match_args.py +0 -0
  90. {annet-0.16.35 → annet-1.0.0}/annet/mesh/models_converter.py +0 -0
  91. {annet-0.16.35 → annet-1.0.0}/annet/mesh/peer_models.py +0 -0
  92. {annet-0.16.35 → annet-1.0.0}/annet/mesh/port_processor.py +0 -0
  93. {annet-0.16.35 → annet-1.0.0}/annet/mesh/registry.py +0 -0
  94. {annet-0.16.35 → annet-1.0.0}/annet/output.py +0 -0
  95. {annet-0.16.35 → annet-1.0.0}/annet/parallel.py +0 -0
  96. {annet-0.16.35 → annet-1.0.0}/annet/patching.py +0 -0
  97. {annet-0.16.35 → annet-1.0.0}/annet/reference.py +0 -0
  98. {annet-0.16.35 → annet-1.0.0}/annet/rpl/__init__.py +0 -0
  99. {annet-0.16.35 → annet-1.0.0}/annet/rpl/action.py +0 -0
  100. {annet-0.16.35 → annet-1.0.0}/annet/rpl/condition.py +0 -0
  101. {annet-0.16.35 → annet-1.0.0}/annet/rpl/match_builder.py +0 -0
  102. {annet-0.16.35 → annet-1.0.0}/annet/rpl/policy.py +0 -0
  103. {annet-0.16.35 → annet-1.0.0}/annet/rpl/result.py +0 -0
  104. {annet-0.16.35 → annet-1.0.0}/annet/rpl/routemap.py +0 -0
  105. {annet-0.16.35 → annet-1.0.0}/annet/rpl/statement_builder.py +0 -0
  106. {annet-0.16.35 → annet-1.0.0}/annet/rpl_generators/__init__.py +0 -0
  107. {annet-0.16.35 → annet-1.0.0}/annet/rpl_generators/aspath.py +0 -0
  108. {annet-0.16.35 → annet-1.0.0}/annet/rpl_generators/community.py +0 -0
  109. {annet-0.16.35 → annet-1.0.0}/annet/rpl_generators/cumulus_frr.py +0 -0
  110. {annet-0.16.35 → annet-1.0.0}/annet/rpl_generators/entities.py +0 -0
  111. {annet-0.16.35 → annet-1.0.0}/annet/rpl_generators/execute.py +0 -0
  112. {annet-0.16.35 → annet-1.0.0}/annet/rpl_generators/policy.py +0 -0
  113. {annet-0.16.35 → annet-1.0.0}/annet/rpl_generators/prefix_lists.py +0 -0
  114. {annet-0.16.35 → annet-1.0.0}/annet/rpl_generators/rd.py +0 -0
  115. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/__init__.py +0 -0
  116. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/arista/__init__.py +0 -0
  117. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/arista/iface.py +0 -0
  118. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/aruba/__init__.py +0 -0
  119. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/aruba/ap_env.py +0 -0
  120. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/aruba/misc.py +0 -0
  121. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/b4com/__init__.py +0 -0
  122. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/b4com/file.py +0 -0
  123. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/b4com/iface.py +0 -0
  124. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/cisco/__init__.py +0 -0
  125. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/cisco/iface.py +0 -0
  126. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/cisco/misc.py +0 -0
  127. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/cisco/vlandb.py +0 -0
  128. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/common.py +0 -0
  129. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/deploying.py +0 -0
  130. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/huawei/__init__.py +0 -0
  131. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/huawei/aaa.py +0 -0
  132. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/huawei/bgp.py +0 -0
  133. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/huawei/iface.py +0 -0
  134. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/huawei/misc.py +0 -0
  135. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/huawei/vlandb.py +0 -0
  136. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/juniper/__init__.py +0 -0
  137. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/nexus/__init__.py +0 -0
  138. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/nexus/iface.py +0 -0
  139. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/patching.py +0 -0
  140. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/ribbon/__init__.py +0 -0
  141. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/routeros/__init__.py +0 -0
  142. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/routeros/file.py +0 -0
  143. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/arista.deploy +0 -0
  144. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/arista.order +0 -0
  145. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/arista.rul +0 -0
  146. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/aruba.deploy +0 -0
  147. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/aruba.order +0 -0
  148. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/aruba.rul +0 -0
  149. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/b4com.deploy +0 -0
  150. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/b4com.order +0 -0
  151. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/b4com.rul +0 -0
  152. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/cisco.deploy +0 -0
  153. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/cisco.order +0 -0
  154. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/cisco.rul +0 -0
  155. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/huawei.deploy +0 -0
  156. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/huawei.order +0 -0
  157. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/huawei.rul +0 -0
  158. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/juniper.rul +0 -0
  159. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/nexus.deploy +0 -0
  160. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/nexus.order +0 -0
  161. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/nexus.rul +0 -0
  162. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/nokia.rul +0 -0
  163. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/optixtrans.deploy +0 -0
  164. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/optixtrans.order +0 -0
  165. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/optixtrans.rul +0 -0
  166. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/pc.deploy +0 -0
  167. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/pc.order +0 -0
  168. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/pc.rul +0 -0
  169. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/ribbon.deploy +0 -0
  170. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/ribbon.rul +0 -0
  171. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/routeros.order +0 -0
  172. {annet-0.16.35 → annet-1.0.0}/annet/rulebook/texts/routeros.rul +0 -0
  173. {annet-0.16.35 → annet-1.0.0}/annet/storage.py +0 -0
  174. {annet-0.16.35 → annet-1.0.0}/annet/tabparser.py +0 -0
  175. {annet-0.16.35 → annet-1.0.0}/annet/text_term_format.py +0 -0
  176. {annet-0.16.35 → annet-1.0.0}/annet/tracing.py +0 -0
  177. {annet-0.16.35 → annet-1.0.0}/annet/types.py +0 -0
  178. {annet-0.16.35 → annet-1.0.0}/annet.egg-info/dependency_links.txt +0 -0
  179. {annet-0.16.35 → annet-1.0.0}/annet.egg-info/entry_points.txt +0 -0
  180. {annet-0.16.35 → annet-1.0.0}/annet.egg-info/requires.txt +0 -0
  181. {annet-0.16.35 → annet-1.0.0}/annet.egg-info/top_level.txt +0 -0
  182. {annet-0.16.35 → annet-1.0.0}/annet_generators/__init__.py +0 -0
  183. {annet-0.16.35 → annet-1.0.0}/annet_generators/example/__init__.py +0 -0
  184. {annet-0.16.35 → annet-1.0.0}/annet_generators/example/lldp.py +0 -0
  185. {annet-0.16.35 → annet-1.0.0}/annet_generators/mesh_example/__init__.py +0 -0
  186. {annet-0.16.35 → annet-1.0.0}/annet_generators/mesh_example/bgp.py +0 -0
  187. {annet-0.16.35 → annet-1.0.0}/annet_generators/mesh_example/mesh_logic.py +0 -0
  188. {annet-0.16.35 → annet-1.0.0}/annet_generators/rpl_example/__init__.py +0 -0
  189. {annet-0.16.35 → annet-1.0.0}/annet_generators/rpl_example/generator.py +0 -0
  190. {annet-0.16.35 → annet-1.0.0}/annet_generators/rpl_example/items.py +0 -0
  191. {annet-0.16.35 → annet-1.0.0}/annet_generators/rpl_example/mesh.py +0 -0
  192. {annet-0.16.35 → annet-1.0.0}/annet_generators/rpl_example/route_policy.py +0 -0
  193. {annet-0.16.35 → annet-1.0.0}/requirements.txt +0 -0
  194. {annet-0.16.35 → annet-1.0.0}/setup.cfg +0 -0
  195. {annet-0.16.35 → annet-1.0.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: annet
3
- Version: 0.16.35
3
+ Version: 1.0.0
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -0,0 +1,25 @@
1
+ from annet.deploy import Fetcher
2
+ from annet.connectors import AdapterWithConfig
3
+ from typing import Dict, List, Any
4
+ from annet.storage import Device
5
+
6
+
7
+ class StubFetcher(Fetcher, AdapterWithConfig):
8
+ @classmethod
9
+ def with_config(cls, **kwargs: Dict[str, Any]) -> Fetcher:
10
+ return cls(**kwargs)
11
+
12
+ async def fetch_packages(self,
13
+ devices: list[Device],
14
+ processes: int = 1,
15
+ max_slots: int = 0,
16
+ ) -> tuple[dict[Device, str], dict[Device, Any]]:
17
+ raise NotImplementedError()
18
+
19
+ async def fetch(self,
20
+ devices: list[Device],
21
+ files_to_download: dict[str, list[str]] | None = None,
22
+ processes: int = 1,
23
+ max_slots: int = 0,
24
+ ):
25
+ raise NotImplementedError()
@@ -22,6 +22,8 @@ from typing import (
22
22
  )
23
23
 
24
24
  import colorama
25
+ import annet.deploy
26
+ import annet.deploy_ui
25
27
  import annet.lib
26
28
  from annet.annlib import jsontools
27
29
  from annet.annlib.netdev.views.hardware import HardwareView
@@ -262,7 +264,7 @@ def patch(args: cli_args.ShowPatchOptions, loader: ann_gen.Loader):
262
264
  global live_configs # pylint: disable=global-statement
263
265
  if args.config == "running":
264
266
  fetcher = annet.deploy.get_fetcher()
265
- live_configs = fetcher.fetch(loader.devices, processes=args.parallel)
267
+ live_configs = annet.lib.do_async(fetcher.fetch(loader.devices, processes=args.parallel))
266
268
  stdin = args.stdin(filter_acl=args.filter_acl, config=args.config)
267
269
 
268
270
  filterer = filtering.filterer_connector.get()
@@ -567,7 +569,7 @@ class Deployer:
567
569
  if not diff_obj:
568
570
  self.empty_diff_hostnames.update(dev.hostname for dev in devices)
569
571
  if not self.args.no_ask_deploy:
570
- # разобъем список устройств на несколько линий
572
+ # разобьём список устройств на несколько линий
571
573
  dest_name = ""
572
574
  try:
573
575
  _, term_columns_str = os.popen("stty size", "r").read().split()
@@ -596,18 +598,18 @@ class Deployer:
596
598
  return diff_lines
597
599
 
598
600
  def ask_deploy(self) -> str:
599
- return self._ask("y", annet.deploy.AskConfirm(
601
+ return self._ask("y", annet.deploy_ui.AskConfirm(
600
602
  text="\n".join(self.diff_lines()),
601
603
  alternative_text="\n".join(self.cmd_lines),
602
604
  ))
603
605
 
604
606
  def ask_rollback(self) -> str:
605
- return self._ask("n", annet.deploy.AskConfirm(
607
+ return self._ask("n", annet.deploy_ui.AskConfirm(
606
608
  text="Execute rollback?\n",
607
609
  alternative_text="",
608
610
  ))
609
611
 
610
- def _ask(self, default_ans: str, ask: annet.deploy.AskConfirm) -> str:
612
+ def _ask(self, default_ans: str, ask: annet.deploy_ui.AskConfirm) -> str:
611
613
  # если filter_acl из stdin то с ним уже не получится работать как с терминалом
612
614
  ans = default_ans
613
615
  if not self.args.no_ask_deploy:
@@ -666,11 +668,22 @@ def deploy(
666
668
  filterer: Filterer,
667
669
  fetcher: Fetcher,
668
670
  deploy_driver: DeployDriver,
671
+ ) -> ExitCode:
672
+ return annet.lib.do_async(adeploy(args, loader, deployer, filterer, fetcher, deploy_driver))
673
+
674
+
675
+ async def adeploy(
676
+ args: cli_args.DeployOptions,
677
+ loader: ann_gen.Loader,
678
+ deployer: Deployer,
679
+ filterer: Filterer,
680
+ fetcher: Fetcher,
681
+ deploy_driver: DeployDriver,
669
682
  ) -> ExitCode:
670
683
  """ Сгенерировать конфиг для устройств и задеплоить его """
671
684
  ret: ExitCode = 0
672
685
  global live_configs # pylint: disable=global-statement
673
- live_configs = fetcher.fetch(devices=loader.devices, processes=args.parallel)
686
+ live_configs = await fetcher.fetch(devices=loader.devices, processes=args.parallel)
674
687
  pool = ann_gen.OldNewParallel(args, loader, filterer)
675
688
 
676
689
  for res in pool.generated_configs(loader.devices):
@@ -687,7 +700,18 @@ def deploy(
687
700
  ans = deployer.ask_deploy()
688
701
  if ans != "y":
689
702
  return 2 ** 2
690
- result = annet.lib.do_async(deploy_driver.bulk_deploy(deploy_cmds, args))
703
+ progress_bar = None
704
+ if sys.stdout.isatty() and not args.no_progress:
705
+ progress_bar = annet.deploy_ui.ProgressBars(odict([(device.fqdn, {}) for device in deploy_cmds]))
706
+ progress_bar.init()
707
+ with progress_bar:
708
+ progress_bar.start_terminal_refresher()
709
+ result = await deploy_driver.bulk_deploy(deploy_cmds, args, progress_bar=progress_bar)
710
+ await progress_bar.wait_for_exit()
711
+ progress_bar.screen.clear()
712
+ progress_bar.stop_terminal_refresher()
713
+ else:
714
+ result = await deploy_driver.bulk_deploy(deploy_cmds, args)
691
715
 
692
716
  rolled_back = False
693
717
  rollback_cmds = {deployer.fqdn_to_device[x]: cc for x, cc in result.original_states.items() if cc}
@@ -695,7 +719,7 @@ def deploy(
695
719
  ans = deployer.ask_rollback()
696
720
  if rollback_cmds and ans == "y":
697
721
  rolled_back = True
698
- annet.lib.do_async(deploy_driver.bulk_deploy(rollback_cmds, args))
722
+ await deploy_driver.bulk_deploy(rollback_cmds, args)
699
723
 
700
724
  if not args.no_check_diff and not rolled_back:
701
725
  deployer.check_diff(result, loader)
@@ -0,0 +1,223 @@
1
+ # pylint: disable=unused-argument
2
+ import abc
3
+ import itertools
4
+ from collections import namedtuple
5
+ from typing import Dict, List, Optional, Any, OrderedDict, Tuple, Type
6
+
7
+ from contextlog import get_logger
8
+
9
+ from annet.annlib.command import Command, Question, CommandList
10
+ from annet.annlib.netdev.views.hardware import HardwareView
11
+ from annet.annlib.rbparser.deploying import MakeMessageMatcher, Answer
12
+ from annet.cli_args import DeployOptions
13
+ from annet.connectors import Connector, get_connector_from_config
14
+ from annet.rulebook import get_rulebook, deploying
15
+ from annet.storage import Device
16
+
17
+
18
+ _DeployResultBase = namedtuple("_DeployResultBase", ("hostnames", "results", "durations", "original_states"))
19
+
20
+
21
+ class ProgressBar(abc.ABC):
22
+ @abc.abstractmethod
23
+ def set_content(self, tile_name: str, content: str):
24
+ ...
25
+
26
+ @abc.abstractmethod
27
+ def set_progress(self,
28
+ tile_name: str,
29
+ iteration: int,
30
+ total: int,
31
+ prefix: str = "",
32
+ suffix: str = "",
33
+ fill: str = "",
34
+ error: bool = False,
35
+ ):
36
+ ...
37
+
38
+ @abc.abstractmethod
39
+ def set_exception(self, tile_name: str, cmd_exc: str, last_cmd: str, progress_max: int):
40
+ ...
41
+
42
+
43
+ class DeployResult(_DeployResultBase): # noqa: E302
44
+ def add_results(self, results: dict[str, tuple[list[str], list[Exception]]]) -> None:
45
+ for hostname, (excs, result) in results.items():
46
+ self.hostnames.append(hostname)
47
+ self.results[hostname] = excs
48
+ self.durations[hostname] = 0.0
49
+ self.original_states[hostname] = None
50
+
51
+
52
+ class _FetcherConnector(Connector["Fetcher"]):
53
+ name = "Fetcher"
54
+ ep_name = "deploy_fetcher"
55
+ ep_by_group_only = "annet.connectors.fetcher"
56
+
57
+ def _get_default(self) -> Type["Fetcher"]:
58
+ # if entry points are broken, try to use direct import
59
+ import annet.adapters.fetchers.stub.fetcher as stub_fetcher
60
+ return stub_fetcher.StubFetcher
61
+
62
+
63
+ class _DriverConnector(Connector["DeployDriver"]):
64
+ name = "DeployDriver"
65
+ ep_name = "deploy_driver"
66
+ ep_by_group_only = "annet.connectors.deployer"
67
+
68
+ def _get_default(self) -> Type["DeployDriver"]:
69
+ # if entry points are broken, try to use direct import
70
+ import annet.adapters.deployers.stub.deployer as stub_deployer
71
+ return stub_deployer.StubDeployDriver
72
+
73
+
74
+ fetcher_connector = _FetcherConnector()
75
+ driver_connector = _DriverConnector()
76
+
77
+
78
+ class Fetcher(abc.ABC):
79
+ @abc.abstractmethod
80
+ async def fetch_packages(self,
81
+ devices: list[Device],
82
+ processes: int = 1,
83
+ max_slots: int = 0,
84
+ ) -> tuple[dict[Device, str], dict[Device, Any]]:
85
+ pass
86
+
87
+ @abc.abstractmethod
88
+ async def fetch(self,
89
+ devices: list[Device],
90
+ files_to_download: dict[str, list[str]] | None = None,
91
+ processes: int = 1,
92
+ max_slots: int = 0,
93
+ ):
94
+ pass
95
+
96
+
97
+ def get_fetcher() -> Fetcher:
98
+ connectors = fetcher_connector.get_all()
99
+ fetcher, _ = get_connector_from_config("fetcher", connectors)
100
+ return fetcher
101
+
102
+
103
+ class DeployDriver(abc.ABC):
104
+ @abc.abstractmethod
105
+ async def bulk_deploy(self, deploy_cmds: dict, args: DeployOptions, progress_bar: ProgressBar | None = None) -> DeployResult:
106
+ pass
107
+
108
+ @abc.abstractmethod
109
+ def apply_deploy_rulebook(self, hw: HardwareView, cmd_paths, do_finalize=True, do_commit=True):
110
+ pass
111
+
112
+ @abc.abstractmethod
113
+ def build_configuration_cmdlist(self, hw: HardwareView, do_finalize=True, do_commit=True):
114
+ pass
115
+
116
+ @abc.abstractmethod
117
+ def build_exit_cmdlist(self, hw):
118
+ pass
119
+
120
+
121
+ def get_deployer() -> DeployDriver:
122
+ connectors = driver_connector.get_all()
123
+ deployer, _ = get_connector_from_config("deployer", connectors)
124
+ return deployer
125
+
126
+
127
+ # ===
128
+ def scrub_config(text: str, breed: str) -> str:
129
+ return text
130
+
131
+
132
+ def show_bulk_report(hostnames, results, durations, log_dir):
133
+ pass
134
+
135
+
136
+ class RulebookQuestionHandler:
137
+ def __init__(self, dialogs):
138
+ self._dialogs = dialogs
139
+
140
+ def __call__(self, dev: Connector, cmd: Command, match_content: bytes):
141
+ content = match_content.strip()
142
+ content = content.decode()
143
+ for matcher, answer in self._dialogs.items():
144
+ if matcher(content):
145
+ return Command(answer.text)
146
+
147
+ get_logger().info("no answer in rulebook. dialogs=%s match_content=%s", self._dialogs, match_content)
148
+ return None
149
+
150
+
151
+ def rb_question_to_question(q: MakeMessageMatcher, a: Answer) -> Question: # TODO: drop MakeMessageMatcher
152
+ if not a.send_nl:
153
+ raise Exception("not supported false send_nl")
154
+ text: str = q._text # pylint: disable=protected-access
155
+ is_regexp = False
156
+ if text.startswith("/") and text.endswith("/"):
157
+ is_regexp = True
158
+ text = text[1:-1]
159
+ res = Question(question=text, answer=a.text, is_regexp=is_regexp)
160
+ return res
161
+
162
+
163
+ def make_cmd_params(rule: Dict[str, Any]) -> Dict[str, Any]:
164
+ if rule:
165
+ qa_handler = RulebookQuestionHandler(rule["attrs"]["dialogs"])
166
+ qa_list: List[Question] = []
167
+ for matcher, answer in qa_handler._dialogs.items(): # pylint: disable=protected-access
168
+ qa_list.append(rb_question_to_question(matcher, answer))
169
+ return {
170
+ "questions": qa_list,
171
+ "timeout": rule["attrs"]["timeout"],
172
+ }
173
+ return {
174
+ "timeout": 30,
175
+ }
176
+
177
+
178
+ def make_apply_commands(rule: dict, hw: HardwareView, do_commit: bool, do_finalize: bool, path: Optional[str] = None):
179
+ apply_logic = rule["attrs"]["apply_logic"]
180
+ before, after = apply_logic(hw, do_commit=do_commit, do_finalize=do_finalize, path=path)
181
+ return before, after
182
+
183
+
184
+ def fill_cmd_params(rules: OrderedDict, cmd: Command):
185
+ rule = deploying.match_deploy_rule(rules, (cmd.cmd,), {})
186
+ if rule:
187
+ cmd_params = make_cmd_params(rule)
188
+ cmd.questions = cmd_params.get("questions", None)
189
+ cmd.timeout = cmd_params["timeout"]
190
+
191
+
192
+ def apply_deploy_rulebook(hw: HardwareView, cmd_paths, do_finalize=True, do_commit=True):
193
+ rules = get_rulebook(hw)["deploying"]
194
+ cmds_with_apply = []
195
+ for cmd_path, context in cmd_paths.items():
196
+ rule = deploying.match_deploy_rule(rules, cmd_path, context)
197
+ cmd_params = make_cmd_params(rule)
198
+ before, after = make_apply_commands(rule, hw, do_commit, do_finalize)
199
+
200
+ cmd = Command(cmd_path[-1], **cmd_params)
201
+ # XXX более чистый способ передавать-мета инфу о команде
202
+ cmd.level = len(cmd_path) - 1
203
+ cmds_with_apply.append((cmd, before, after))
204
+
205
+ def _key(item):
206
+ _cmd, before, after = item
207
+ return (tuple(cmd.cmd for cmd in before), tuple(cmd.cmd for cmd in after))
208
+
209
+ cmdlist = CommandList()
210
+ for _k, cmd_before_after in itertools.groupby(cmds_with_apply, key=_key):
211
+ cmd_before_after = list(cmd_before_after)
212
+ _, before, after = cmd_before_after[0]
213
+ for c in before:
214
+ c.level = 0
215
+ fill_cmd_params(rules, c)
216
+ cmdlist.add_cmd(c)
217
+ for cmd, _before, _after in cmd_before_after:
218
+ cmdlist.add_cmd(cmd)
219
+ for c in after:
220
+ c.level = 0
221
+ fill_cmd_params(rules, c)
222
+ cmdlist.add_cmd(c)
223
+ return cmdlist