annet 2.2.1__tar.gz → 2.3.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 (194) hide show
  1. {annet-2.2.1/annet.egg-info → annet-2.3.0}/PKG-INFO +1 -1
  2. {annet-2.2.1 → annet-2.3.0}/annet/api/__init__.py +32 -96
  3. {annet-2.2.1 → annet-2.3.0}/annet/cli.py +15 -8
  4. {annet-2.2.1 → annet-2.3.0}/annet/cli_args.py +1 -0
  5. {annet-2.2.1 → annet-2.3.0}/annet/deploy_ui.py +1 -2
  6. {annet-2.2.1 → annet-2.3.0}/annet/diff.py +102 -9
  7. {annet-2.2.1 → annet-2.3.0/annet.egg-info}/PKG-INFO +1 -1
  8. {annet-2.2.1 → annet-2.3.0}/AUTHORS +0 -0
  9. {annet-2.2.1 → annet-2.3.0}/LICENSE +0 -0
  10. {annet-2.2.1 → annet-2.3.0}/MANIFEST.in +0 -0
  11. {annet-2.2.1 → annet-2.3.0}/README.md +0 -0
  12. {annet-2.2.1 → annet-2.3.0}/annet/__init__.py +0 -0
  13. {annet-2.2.1 → annet-2.3.0}/annet/adapters/__init__.py +0 -0
  14. {annet-2.2.1 → annet-2.3.0}/annet/adapters/fetchers/__init__.py +0 -0
  15. {annet-2.2.1 → annet-2.3.0}/annet/adapters/fetchers/stub/__init__.py +0 -0
  16. {annet-2.2.1 → annet-2.3.0}/annet/adapters/fetchers/stub/fetcher.py +0 -0
  17. {annet-2.2.1 → annet-2.3.0}/annet/adapters/file/__init__.py +0 -0
  18. {annet-2.2.1 → annet-2.3.0}/annet/adapters/file/provider.py +0 -0
  19. {annet-2.2.1 → annet-2.3.0}/annet/adapters/netbox/__init__.py +0 -0
  20. {annet-2.2.1 → annet-2.3.0}/annet/adapters/netbox/common/__init__.py +0 -0
  21. {annet-2.2.1 → annet-2.3.0}/annet/adapters/netbox/common/client.py +0 -0
  22. {annet-2.2.1 → annet-2.3.0}/annet/adapters/netbox/common/manufacturer.py +0 -0
  23. {annet-2.2.1 → annet-2.3.0}/annet/adapters/netbox/common/models.py +0 -0
  24. {annet-2.2.1 → annet-2.3.0}/annet/adapters/netbox/common/query.py +0 -0
  25. {annet-2.2.1 → annet-2.3.0}/annet/adapters/netbox/common/status_client.py +0 -0
  26. {annet-2.2.1 → annet-2.3.0}/annet/adapters/netbox/common/storage_opts.py +0 -0
  27. {annet-2.2.1 → annet-2.3.0}/annet/adapters/netbox/provider.py +0 -0
  28. {annet-2.2.1 → annet-2.3.0}/annet/adapters/netbox/v24/__init__.py +0 -0
  29. {annet-2.2.1 → annet-2.3.0}/annet/adapters/netbox/v24/storage.py +0 -0
  30. {annet-2.2.1 → annet-2.3.0}/annet/adapters/netbox/v37/__init__.py +0 -0
  31. {annet-2.2.1 → annet-2.3.0}/annet/adapters/netbox/v37/storage.py +0 -0
  32. {annet-2.2.1 → annet-2.3.0}/annet/annet.py +0 -0
  33. {annet-2.2.1 → annet-2.3.0}/annet/annlib/__init__.py +0 -0
  34. {annet-2.2.1 → annet-2.3.0}/annet/annlib/command.py +0 -0
  35. {annet-2.2.1 → annet-2.3.0}/annet/annlib/diff.py +0 -0
  36. {annet-2.2.1 → annet-2.3.0}/annet/annlib/errors.py +0 -0
  37. {annet-2.2.1 → annet-2.3.0}/annet/annlib/filter_acl.py +0 -0
  38. {annet-2.2.1 → annet-2.3.0}/annet/annlib/jsontools.py +0 -0
  39. {annet-2.2.1 → annet-2.3.0}/annet/annlib/lib.py +0 -0
  40. {annet-2.2.1 → annet-2.3.0}/annet/annlib/netdev/__init__.py +0 -0
  41. {annet-2.2.1 → annet-2.3.0}/annet/annlib/netdev/db.py +0 -0
  42. {annet-2.2.1 → annet-2.3.0}/annet/annlib/netdev/devdb/__init__.py +0 -0
  43. {annet-2.2.1 → annet-2.3.0}/annet/annlib/netdev/devdb/data/devdb.json +0 -0
  44. {annet-2.2.1 → annet-2.3.0}/annet/annlib/netdev/views/__init__.py +0 -0
  45. {annet-2.2.1 → annet-2.3.0}/annet/annlib/netdev/views/dump.py +0 -0
  46. {annet-2.2.1 → annet-2.3.0}/annet/annlib/netdev/views/hardware.py +0 -0
  47. {annet-2.2.1 → annet-2.3.0}/annet/annlib/output.py +0 -0
  48. {annet-2.2.1 → annet-2.3.0}/annet/annlib/patching.py +0 -0
  49. {annet-2.2.1 → annet-2.3.0}/annet/annlib/rbparser/__init__.py +0 -0
  50. {annet-2.2.1 → annet-2.3.0}/annet/annlib/rbparser/acl.py +0 -0
  51. {annet-2.2.1 → annet-2.3.0}/annet/annlib/rbparser/deploying.py +0 -0
  52. {annet-2.2.1 → annet-2.3.0}/annet/annlib/rbparser/ordering.py +0 -0
  53. {annet-2.2.1 → annet-2.3.0}/annet/annlib/rbparser/platform.py +0 -0
  54. {annet-2.2.1 → annet-2.3.0}/annet/annlib/rbparser/syntax.py +0 -0
  55. {annet-2.2.1 → annet-2.3.0}/annet/annlib/rulebook/__init__.py +0 -0
  56. {annet-2.2.1 → annet-2.3.0}/annet/annlib/rulebook/common.py +0 -0
  57. {annet-2.2.1 → annet-2.3.0}/annet/annlib/tabparser.py +0 -0
  58. {annet-2.2.1 → annet-2.3.0}/annet/annlib/types.py +0 -0
  59. {annet-2.2.1 → annet-2.3.0}/annet/argparse.py +0 -0
  60. {annet-2.2.1 → annet-2.3.0}/annet/bgp_models.py +0 -0
  61. {annet-2.2.1 → annet-2.3.0}/annet/configs/context.yml +0 -0
  62. {annet-2.2.1 → annet-2.3.0}/annet/configs/logging.yaml +0 -0
  63. {annet-2.2.1 → annet-2.3.0}/annet/connectors.py +0 -0
  64. {annet-2.2.1 → annet-2.3.0}/annet/deploy.py +0 -0
  65. {annet-2.2.1 → annet-2.3.0}/annet/executor.py +0 -0
  66. {annet-2.2.1 → annet-2.3.0}/annet/filtering.py +0 -0
  67. {annet-2.2.1 → annet-2.3.0}/annet/gen.py +0 -0
  68. {annet-2.2.1 → annet-2.3.0}/annet/generators/__init__.py +0 -0
  69. {annet-2.2.1 → annet-2.3.0}/annet/generators/base.py +0 -0
  70. {annet-2.2.1 → annet-2.3.0}/annet/generators/common/__init__.py +0 -0
  71. {annet-2.2.1 → annet-2.3.0}/annet/generators/common/initial.py +0 -0
  72. {annet-2.2.1 → annet-2.3.0}/annet/generators/entire.py +0 -0
  73. {annet-2.2.1 → annet-2.3.0}/annet/generators/exceptions.py +0 -0
  74. {annet-2.2.1 → annet-2.3.0}/annet/generators/jsonfragment.py +0 -0
  75. {annet-2.2.1 → annet-2.3.0}/annet/generators/partial.py +0 -0
  76. {annet-2.2.1 → annet-2.3.0}/annet/generators/perf.py +0 -0
  77. {annet-2.2.1 → annet-2.3.0}/annet/generators/ref.py +0 -0
  78. {annet-2.2.1 → annet-2.3.0}/annet/generators/result.py +0 -0
  79. {annet-2.2.1 → annet-2.3.0}/annet/hardware.py +0 -0
  80. {annet-2.2.1 → annet-2.3.0}/annet/implicit.py +0 -0
  81. {annet-2.2.1 → annet-2.3.0}/annet/lib.py +0 -0
  82. {annet-2.2.1 → annet-2.3.0}/annet/mesh/__init__.py +0 -0
  83. {annet-2.2.1 → annet-2.3.0}/annet/mesh/basemodel.py +0 -0
  84. {annet-2.2.1 → annet-2.3.0}/annet/mesh/device_models.py +0 -0
  85. {annet-2.2.1 → annet-2.3.0}/annet/mesh/executor.py +0 -0
  86. {annet-2.2.1 → annet-2.3.0}/annet/mesh/match_args.py +0 -0
  87. {annet-2.2.1 → annet-2.3.0}/annet/mesh/models_converter.py +0 -0
  88. {annet-2.2.1 → annet-2.3.0}/annet/mesh/peer_models.py +0 -0
  89. {annet-2.2.1 → annet-2.3.0}/annet/mesh/port_processor.py +0 -0
  90. {annet-2.2.1 → annet-2.3.0}/annet/mesh/registry.py +0 -0
  91. {annet-2.2.1 → annet-2.3.0}/annet/output.py +0 -0
  92. {annet-2.2.1 → annet-2.3.0}/annet/parallel.py +0 -0
  93. {annet-2.2.1 → annet-2.3.0}/annet/patching.py +0 -0
  94. {annet-2.2.1 → annet-2.3.0}/annet/reference.py +0 -0
  95. {annet-2.2.1 → annet-2.3.0}/annet/rpl/__init__.py +0 -0
  96. {annet-2.2.1 → annet-2.3.0}/annet/rpl/action.py +0 -0
  97. {annet-2.2.1 → annet-2.3.0}/annet/rpl/condition.py +0 -0
  98. {annet-2.2.1 → annet-2.3.0}/annet/rpl/match_builder.py +0 -0
  99. {annet-2.2.1 → annet-2.3.0}/annet/rpl/policy.py +0 -0
  100. {annet-2.2.1 → annet-2.3.0}/annet/rpl/result.py +0 -0
  101. {annet-2.2.1 → annet-2.3.0}/annet/rpl/routemap.py +0 -0
  102. {annet-2.2.1 → annet-2.3.0}/annet/rpl/statement_builder.py +0 -0
  103. {annet-2.2.1 → annet-2.3.0}/annet/rpl_generators/__init__.py +0 -0
  104. {annet-2.2.1 → annet-2.3.0}/annet/rpl_generators/aspath.py +0 -0
  105. {annet-2.2.1 → annet-2.3.0}/annet/rpl_generators/community.py +0 -0
  106. {annet-2.2.1 → annet-2.3.0}/annet/rpl_generators/cumulus_frr.py +0 -0
  107. {annet-2.2.1 → annet-2.3.0}/annet/rpl_generators/entities.py +0 -0
  108. {annet-2.2.1 → annet-2.3.0}/annet/rpl_generators/execute.py +0 -0
  109. {annet-2.2.1 → annet-2.3.0}/annet/rpl_generators/policy.py +0 -0
  110. {annet-2.2.1 → annet-2.3.0}/annet/rpl_generators/prefix_lists.py +0 -0
  111. {annet-2.2.1 → annet-2.3.0}/annet/rpl_generators/rd.py +0 -0
  112. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/__init__.py +0 -0
  113. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/arista/__init__.py +0 -0
  114. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/arista/aaa.py +0 -0
  115. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/arista/iface.py +0 -0
  116. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/aruba/__init__.py +0 -0
  117. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/aruba/ap_env.py +0 -0
  118. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/aruba/misc.py +0 -0
  119. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/b4com/__init__.py +0 -0
  120. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/b4com/file.py +0 -0
  121. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/b4com/iface.py +0 -0
  122. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/cisco/__init__.py +0 -0
  123. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/cisco/iface.py +0 -0
  124. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/cisco/misc.py +0 -0
  125. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/cisco/vlandb.py +0 -0
  126. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/common.py +0 -0
  127. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/deploying.py +0 -0
  128. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/huawei/__init__.py +0 -0
  129. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/huawei/aaa.py +0 -0
  130. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/huawei/bgp.py +0 -0
  131. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/huawei/iface.py +0 -0
  132. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/huawei/misc.py +0 -0
  133. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/huawei/vlandb.py +0 -0
  134. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/juniper/__init__.py +0 -0
  135. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/nexus/__init__.py +0 -0
  136. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/nexus/iface.py +0 -0
  137. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/patching.py +0 -0
  138. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/routeros/__init__.py +0 -0
  139. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/routeros/file.py +0 -0
  140. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/arista.deploy +0 -0
  141. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/arista.order +0 -0
  142. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/arista.rul +0 -0
  143. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/aruba.deploy +0 -0
  144. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/aruba.order +0 -0
  145. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/aruba.rul +0 -0
  146. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/b4com.deploy +0 -0
  147. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/b4com.order +0 -0
  148. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/b4com.rul +0 -0
  149. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/cisco.deploy +0 -0
  150. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/cisco.order +0 -0
  151. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/cisco.rul +0 -0
  152. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/huawei.deploy +0 -0
  153. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/huawei.order +0 -0
  154. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/huawei.rul +0 -0
  155. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/juniper.order +0 -0
  156. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/juniper.rul +0 -0
  157. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/nexus.deploy +0 -0
  158. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/nexus.order +0 -0
  159. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/nexus.rul +0 -0
  160. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/nokia.rul +0 -0
  161. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/optixtrans.deploy +0 -0
  162. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/optixtrans.order +0 -0
  163. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/optixtrans.rul +0 -0
  164. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/pc.deploy +0 -0
  165. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/pc.order +0 -0
  166. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/pc.rul +0 -0
  167. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/ribbon.deploy +0 -0
  168. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/ribbon.rul +0 -0
  169. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/routeros.order +0 -0
  170. {annet-2.2.1 → annet-2.3.0}/annet/rulebook/texts/routeros.rul +0 -0
  171. {annet-2.2.1 → annet-2.3.0}/annet/storage.py +0 -0
  172. {annet-2.2.1 → annet-2.3.0}/annet/tabparser.py +0 -0
  173. {annet-2.2.1 → annet-2.3.0}/annet/text_term_format.py +0 -0
  174. {annet-2.2.1 → annet-2.3.0}/annet/tracing.py +0 -0
  175. {annet-2.2.1 → annet-2.3.0}/annet/types.py +0 -0
  176. {annet-2.2.1 → annet-2.3.0}/annet.egg-info/SOURCES.txt +0 -0
  177. {annet-2.2.1 → annet-2.3.0}/annet.egg-info/dependency_links.txt +0 -0
  178. {annet-2.2.1 → annet-2.3.0}/annet.egg-info/entry_points.txt +0 -0
  179. {annet-2.2.1 → annet-2.3.0}/annet.egg-info/requires.txt +0 -0
  180. {annet-2.2.1 → annet-2.3.0}/annet.egg-info/top_level.txt +0 -0
  181. {annet-2.2.1 → annet-2.3.0}/annet_generators/__init__.py +0 -0
  182. {annet-2.2.1 → annet-2.3.0}/annet_generators/example/__init__.py +0 -0
  183. {annet-2.2.1 → annet-2.3.0}/annet_generators/example/lldp.py +0 -0
  184. {annet-2.2.1 → annet-2.3.0}/annet_generators/mesh_example/__init__.py +0 -0
  185. {annet-2.2.1 → annet-2.3.0}/annet_generators/mesh_example/bgp.py +0 -0
  186. {annet-2.2.1 → annet-2.3.0}/annet_generators/mesh_example/mesh_logic.py +0 -0
  187. {annet-2.2.1 → annet-2.3.0}/annet_generators/rpl_example/__init__.py +0 -0
  188. {annet-2.2.1 → annet-2.3.0}/annet_generators/rpl_example/generator.py +0 -0
  189. {annet-2.2.1 → annet-2.3.0}/annet_generators/rpl_example/items.py +0 -0
  190. {annet-2.2.1 → annet-2.3.0}/annet_generators/rpl_example/mesh.py +0 -0
  191. {annet-2.2.1 → annet-2.3.0}/annet_generators/rpl_example/route_policy.py +0 -0
  192. {annet-2.2.1 → annet-2.3.0}/requirements.txt +0 -0
  193. {annet-2.2.1 → annet-2.3.0}/setup.cfg +0 -0
  194. {annet-2.2.1 → annet-2.3.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: annet
3
- Version: 2.2.1
3
+ Version: 2.3.0
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -1,4 +1,5 @@
1
1
  import abc
2
+ import inspect
2
3
  import os
3
4
  import re
4
5
  import sys
@@ -8,13 +9,11 @@ from collections import OrderedDict as odict
8
9
  from itertools import groupby, chain
9
10
  from operator import itemgetter
10
11
  from typing import (
11
- Any,
12
12
  Dict,
13
13
  Generator,
14
14
  Iterable,
15
15
  List,
16
16
  Mapping,
17
- Optional,
18
17
  Set,
19
18
  Tuple,
20
19
  Union, cast,
@@ -41,7 +40,6 @@ from annet.rulebook import deploying
41
40
  from annet.filtering import Filterer
42
41
  from annet.hardware import hardware_connector
43
42
  from annet.output import (
44
- LABEL_NEW_PREFIX,
45
43
  format_file_diff,
46
44
  output_driver_connector,
47
45
  print_err_label,
@@ -51,7 +49,6 @@ from annet.reference import RefTracker
51
49
  from annet.storage import Device, get_storage
52
50
  from annet.types import Diff, ExitCode, OldNewResult, Op, PCDiff, PCDiffFile
53
51
 
54
-
55
52
  DEFAULT_INDENT = " "
56
53
 
57
54
 
@@ -240,15 +237,6 @@ def gen(args: cli_args.ShowGenOptions, loader: ann_gen.Loader):
240
237
 
241
238
 
242
239
  # =====
243
- def _diff_files(hw, old_files, new_files):
244
- ret = {}
245
- differ = file_differ_connector.get()
246
- for (path, (new_text, reload_data)) in new_files.items():
247
- old_text = old_files.get(path)
248
- is_new = old_text is None
249
- diff_lines = differ.diff_file(hw, path, old_text, new_text)
250
- ret[path] = (diff_lines, reload_data, is_new)
251
- return ret
252
240
 
253
241
 
254
242
  def patch(args: cli_args.ShowPatchOptions, loader: ann_gen.Loader):
@@ -322,62 +310,39 @@ def res_diff_patch(
322
310
 
323
311
 
324
312
  def diff(
325
- args: cli_args.DiffOptions,
326
- loader: ann_gen.Loader,
327
- device_ids: List[int],
328
- filterer: filtering.Filterer,
313
+ args: cli_args.DiffOptions,
314
+ loader: ann_gen.Loader,
329
315
  ) -> Mapping[Device, Union[Diff, PCDiff]]:
330
- ret = {}
331
- for res in ann_gen.old_new(
332
- args,
333
- config=args.config,
334
- loader=loader,
335
- no_new=args.clear,
336
- do_files_download=True,
337
- device_ids=device_ids,
338
- filterer=filterer,
339
- ):
340
- old = res.get_old(args.acl_safe)
341
- new = res.get_new(args.acl_safe)
342
- device = res.device
343
- acl_rules = res.get_acl_rules(args.acl_safe)
344
- new_files = res.get_new_files(args.acl_safe)
345
- new_json_fragment_files = res.get_new_file_fragments(args.acl_safe)
346
-
347
- pc_diff_files = []
348
- if res.old_files or new_files:
349
- pc_diff_files.extend(_pc_diff(res.device.hw, device.hostname, res.old_files, new_files))
350
- if res.old_json_fragment_files or new_json_fragment_files:
351
- pc_diff_files.extend(_json_fragment_diff(res.device.hw, device.hostname, res.old_json_fragment_files, new_json_fragment_files))
316
+ """ Сгенерировать конфиг для устройств """
317
+ stdin = args.stdin(filter_acl=args.filter_acl, config=None)
352
318
 
353
- if pc_diff_files:
354
- pc_diff_files.sort(key=lambda f: f.label)
355
- ret[device] = PCDiff(hostname=device.hostname, diff_files=pc_diff_files)
356
- elif old is not None:
357
- orderer = patching.Orderer.from_hw(device.hw)
358
- rb = rulebook.get_rulebook(device.hw)
359
- diff_tree = patching.make_diff(
360
- old,
361
- orderer.order_config(new),
362
- rb,
363
- [acl_rules, res.filter_acl_rules],
364
- )
365
- diff_tree = patching.strip_unchanged(diff_tree)
366
- ret[device] = diff_tree
319
+ filterer = filtering.filterer_connector.get()
320
+ pool = Parallel(ann_diff.worker, args, stdin, loader, filterer).tune_args(args)
321
+ if args.show_hosts_progress:
322
+ pool.add_callback(PoolProgressLogger(loader.device_fqdns))
367
323
 
368
- return ret
324
+ return pool.run(loader.device_ids, args.tolerate_fails, args.strict_exit_code)
369
325
 
370
326
 
371
- def collapse_texts(texts: Mapping[str, str]) -> Mapping[Tuple[str, ...], str]:
327
+ def collapse_texts(texts: Mapping[str, str | Generator[str, None, None]]) -> Mapping[Tuple[str, ...], str]:
372
328
  """
373
329
  Группировка текстов.
374
330
  :param texts:
375
331
  :return: словарь с несколькими хостнеймами в ключе.
376
332
  """
377
- diffs_with_orig = {key: [value, value.splitlines()] for key, value in texts.items()}
333
+ diffs_with_orig = {}
334
+ for key, value in texts.items():
335
+ if inspect.isgenerator(value):
336
+ lines = list(value)
337
+ diffs_with_orig[key] = ["".join(lines), lines]
338
+ else:
339
+ diffs_with_orig[key] = [value, value.splitlines()]
340
+
378
341
  res = {}
379
- for _, collapsed_diff_iter in groupby(sorted(diffs_with_orig.items(), key=lambda x: (x[0], x[1][1])),
380
- key=lambda x: x[1][1]):
342
+ for _, collapsed_diff_iter in groupby(
343
+ sorted(diffs_with_orig.items(), key=lambda x: (x[0], x[1][1])),
344
+ key=lambda x: x[1][1]
345
+ ):
381
346
  collapsed_diff = list(collapsed_diff_iter)
382
347
  res[tuple(x[0] for x in collapsed_diff)] = collapsed_diff[0][1][0]
383
348
 
@@ -744,8 +709,10 @@ def file_diff(args: cli_args.FileDiffOptions):
744
709
  return pool.run(old_new, tolerate_fails=True)
745
710
 
746
711
 
747
- def file_diff_worker(old_new: Tuple[str, str], args: cli_args.FileDiffOptions) -> Generator[
748
- Tuple[str, str, bool], None, None]:
712
+ def file_diff_worker(
713
+ old_new: Tuple[str, str],
714
+ args: cli_args.FileDiffOptions
715
+ ) -> Generator[Tuple[str, str, bool], None, None]:
749
716
  old_path, new_path = old_new
750
717
  hw = args.hw
751
718
  if isinstance(args.hw, str):
@@ -753,10 +720,12 @@ def file_diff_worker(old_new: Tuple[str, str], args: cli_args.FileDiffOptions) -
753
720
 
754
721
  if os.path.isdir(old_path) and os.path.isdir(new_path):
755
722
  hostname = os.path.basename(new_path)
756
- new_files = {relative_cfg_path: (cfg_text, "") for relative_cfg_path, cfg_text in
757
- ann_gen.load_pc_config(new_path).items()}
723
+ new_files = {
724
+ relative_cfg_path: (cfg_text, "")
725
+ for relative_cfg_path, cfg_text in ann_gen.load_pc_config(new_path).items()
726
+ }
758
727
  old_files = ann_gen.load_pc_config(old_path)
759
- for diff_file in _pc_diff(hw, hostname, old_files, new_files):
728
+ for diff_file in ann_diff.pc_diff(hw, hostname, old_files, new_files):
760
729
  diff_text = (
761
730
  "\n".join(diff_file.diff_lines)
762
731
  if args.no_color
@@ -796,39 +765,6 @@ def file_patch_worker(old_new: Tuple[str, str], args: cli_args.FileDiffOptions)
796
765
  yield dest_name, patch_text, False
797
766
 
798
767
 
799
- def _pc_diff(hw, hostname: str, old_files: Dict[str, str], new_files: Dict[str, str]) -> Generator[PCDiffFile, None, None]:
800
- sorted_lines = sorted(_diff_files(hw, old_files, new_files).items())
801
- for (path, (diff_lines, _reload_data, is_new)) in sorted_lines:
802
- if not diff_lines:
803
- continue
804
- label = hostname + os.sep + path
805
- if is_new:
806
- label = LABEL_NEW_PREFIX + label
807
- yield PCDiffFile(label=label, diff_lines=diff_lines)
808
-
809
-
810
- def _json_fragment_diff(
811
- hw,
812
- hostname: str,
813
- old_files: Dict[str, Any],
814
- new_files: Dict[str, Tuple[Any, Optional[str]]],
815
- ) -> Generator[PCDiffFile, None, None]:
816
- def jsonify_multi(files):
817
- return {
818
- path: jsontools.format_json(cfg)
819
- for path, cfg in files.items()
820
- }
821
-
822
- def jsonify_multi_with_cmd(files):
823
- ret = {}
824
- for path, cfg_reload_cmd in files.items():
825
- cfg, reload_cmd = cfg_reload_cmd
826
- ret[path] = (jsontools.format_json(cfg), reload_cmd)
827
- return ret
828
- jold, jnew = jsonify_multi(old_files), jsonify_multi_with_cmd(new_files)
829
- return _pc_diff(hw, hostname, jold, jnew)
830
-
831
-
832
768
  def guess_hw(config_text: str):
833
769
  """Пытаемся угадать вендора и hw на основе
834
770
  текста конфига и annet/rulebook/texts/*.rul"""
@@ -113,6 +113,7 @@ def show_device_dump(args: cli_args.QueryOptions, arg_out: cli_args.FileOutOptio
113
113
  )
114
114
  else:
115
115
  get_logger().warning("method `dump` not implemented for %s", type(device))
116
+
116
117
  arg_gens = cli_args.GenOptions(arg_out, args)
117
118
  with get_loader(arg_gens, args) as loader:
118
119
  if not loader.devices:
@@ -190,7 +191,7 @@ def gen(args: cli_args.ShowGenOptions):
190
191
  output_driver = output_driver_connector.get()
191
192
  if args.dest is None:
192
193
  text_mapping = {item[0]: item[1] for item in out}
193
- out = [(",".join(key), value, False) for key, value in collapse_texts(text_mapping).items()]
194
+ out = [(", ".join(key), value, False) for key, value in collapse_texts(text_mapping).items()]
194
195
 
195
196
  out.extend(output_driver.format_fails(fail, loader.device_fqdns))
196
197
  total = len(success) + len(fail)
@@ -203,13 +204,19 @@ def gen(args: cli_args.ShowGenOptions):
203
204
  def diff(args: cli_args.ShowDiffOptions):
204
205
  """ Generate configuration for devices and show a diff with current configuration using the rulebook """
205
206
  with get_loader(args, args) as loader:
206
- filterer = filtering.filterer_connector.get()
207
- device_ids = loader.device_ids
208
- output_driver_connector.get().write_output(
209
- args,
210
- gen_sort_diff(api.diff(args, loader, device_ids, filterer), args),
211
- len(loader.device_ids)
212
- )
207
+ success, fail = api.diff(args, loader)
208
+
209
+ out = list(gen_sort_diff({loader.get_device(k): v for k, v in success.items()}, args))
210
+ output_driver = output_driver_connector.get()
211
+ if args.dest is None:
212
+ text_mapping = {item[0]: item[1] for item in out}
213
+ out = [(", ".join(key), value, False) for key, value in collapse_texts(text_mapping).items()]
214
+ out.extend(output_driver.format_fails(fail, loader.device_fqdns))
215
+
216
+ if total := len(success) + len(fail):
217
+ output_driver.write_output(args, out, total)
218
+ else:
219
+ get_logger().error("No devices found for %s", args.query)
213
220
 
214
221
 
215
222
  @subcommand(cli_args.ShowPatchOptions)
@@ -442,6 +442,7 @@ class FileOutOptions(ArgGroup):
442
442
  class DiffOptions(GenOptions, ComocutorOptions):
443
443
  clear = opt_clear
444
444
  config = opt_config
445
+ show_hosts_progress = opt_show_hosts_progress
445
446
 
446
447
 
447
448
  class FileInputOptions(ArgGroup):
@@ -782,11 +782,10 @@ def draw_lines_in_win(
782
782
  max_x -= 2 * (margin or x_margin)
783
783
  lines_count = len(lines)
784
784
  if lines_count > max_y:
785
- start_line = lines_count - max_y + 1
785
+ start_line = lines_count - max_y
786
786
  else:
787
787
  start_line = 0
788
788
  for line_no, line_data in enumerate(lines[start_line:]):
789
- line_no = line_no - start_line
790
789
  line_pos_calc = 0
791
790
  for line_part in line_data:
792
791
  if not isinstance(line_part, TextArgs):
@@ -1,10 +1,13 @@
1
1
  import abc
2
2
  import difflib
3
+ import os
3
4
  import re
4
5
  from itertools import groupby
5
6
  from pathlib import Path
6
- from typing import Generator, List, Mapping, Tuple, Union, Protocol
7
+ from typing import Any, Dict, Generator, List, Mapping, Optional, Protocol, Tuple, Union
7
8
 
9
+ from annet import cli_args, filtering, patching, rulebook, tabparser
10
+ from annet.annlib import jsontools
8
11
  from annet.annlib.diff import ( # pylint: disable=unused-import
9
12
  colorize_line,
10
13
  diff_cmp,
@@ -13,23 +16,113 @@ from annet.annlib.diff import ( # pylint: disable=unused-import
13
16
  resort_diff,
14
17
  )
15
18
  from annet.annlib.netdev.views.hardware import HardwareView
16
- from annet.annlib.output import format_file_diff
17
-
18
- from annet import patching, rulebook, tabparser, hardware
19
+ from annet.annlib.output import LABEL_NEW_PREFIX, format_file_diff
19
20
  from annet.cli_args import ShowDiffOptions
20
21
  from annet.connectors import CachedConnector
21
22
  from annet.output import output_driver_connector
22
23
  from annet.storage import Device
23
24
  from annet.tabparser import make_formatter
24
- from annet.types import Diff, PCDiff
25
+ from annet.types import Diff, PCDiff, PCDiffFile
26
+
27
+ from .gen import Loader, old_new
28
+
25
29
 
30
+ def _diff_files(hw, old_files, new_files):
31
+ ret = {}
32
+ differ = file_differ_connector.get()
33
+ for (path, (new_text, reload_data)) in new_files.items():
34
+ old_text = old_files.get(path)
35
+ is_new = old_text is None
36
+ diff_lines = differ.diff_file(hw, path, old_text, new_text)
37
+ ret[path] = (diff_lines, reload_data, is_new)
38
+ return ret
26
39
 
27
- # NOCDEV-1720
40
+
41
+ def pc_diff(hw, hostname: str, old_files: Dict[str, str], new_files: Dict[str, str]) -> Generator[
42
+ PCDiffFile, None, None]:
43
+ sorted_lines = sorted(_diff_files(hw, old_files, new_files).items())
44
+ for (path, (diff_lines, _reload_data, is_new)) in sorted_lines:
45
+ if not diff_lines:
46
+ continue
47
+ label = hostname + os.sep + path
48
+ if is_new:
49
+ label = LABEL_NEW_PREFIX + label
50
+ yield PCDiffFile(label=label, diff_lines=diff_lines)
51
+
52
+
53
+ def json_fragment_diff(
54
+ hw,
55
+ hostname: str,
56
+ old_files: Dict[str, Any],
57
+ new_files: Dict[str, Tuple[Any, Optional[str]]],
58
+ ) -> Generator[PCDiffFile, None, None]:
59
+ def jsonify_multi(files):
60
+ return {
61
+ path: jsontools.format_json(cfg)
62
+ for path, cfg in files.items()
63
+ }
64
+
65
+ def jsonify_multi_with_cmd(files):
66
+ ret = {}
67
+ for path, cfg_reload_cmd in files.items():
68
+ cfg, reload_cmd = cfg_reload_cmd
69
+ ret[path] = (jsontools.format_json(cfg), reload_cmd)
70
+ return ret
71
+
72
+ jold, jnew = jsonify_multi(old_files), jsonify_multi_with_cmd(new_files)
73
+ return pc_diff(hw, hostname, jold, jnew)
74
+
75
+
76
+ def worker(
77
+ device_id,
78
+ args: cli_args.DiffOptions,
79
+ stdin,
80
+ loader: Loader,
81
+ filterer: filtering.Filterer,
82
+ ) -> Union[Diff, PCDiff, None]:
83
+ for res in old_new(
84
+ args,
85
+ config=args.config,
86
+ loader=loader,
87
+ no_new=args.clear,
88
+ do_files_download=True,
89
+ device_ids=[device_id],
90
+ filterer=filterer,
91
+ stdin=stdin,
92
+ ):
93
+ old = res.get_old(args.acl_safe)
94
+ new = res.get_new(args.acl_safe)
95
+ device = res.device
96
+ acl_rules = res.get_acl_rules(args.acl_safe)
97
+ new_files = res.get_new_files(args.acl_safe)
98
+ new_json_fragment_files = res.get_new_file_fragments(args.acl_safe)
99
+
100
+ pc_diff_files = []
101
+ if res.old_files or new_files:
102
+ pc_diff_files.extend(pc_diff(res.device.hw, device.hostname, res.old_files, new_files))
103
+ if res.old_json_fragment_files or new_json_fragment_files:
104
+ pc_diff_files.extend(json_fragment_diff(res.device.hw, device.hostname, res.old_json_fragment_files,
105
+ new_json_fragment_files))
106
+
107
+ if pc_diff_files:
108
+ pc_diff_files.sort(key=lambda f: f.label)
109
+ return PCDiff(hostname=device.hostname, diff_files=pc_diff_files)
110
+ elif old is not None:
111
+ orderer = patching.Orderer.from_hw(device.hw)
112
+ rb = rulebook.get_rulebook(device.hw)
113
+ diff_tree = patching.make_diff(
114
+ old,
115
+ orderer.order_config(new),
116
+ rb,
117
+ [acl_rules, res.filter_acl_rules],
118
+ )
119
+ diff_tree = patching.strip_unchanged(diff_tree)
120
+ return diff_tree
28
121
 
29
122
 
30
123
  def gen_sort_diff(
31
124
  diffs: Mapping[Device, Union[Diff, PCDiff]], args: ShowDiffOptions
32
- ) -> Generator[Tuple[str, Generator[str, None, None], bool], None, None]:
125
+ ) -> Generator[Tuple[str, Generator[str, None, None] | str, bool], None, None]:
33
126
  """
34
127
  Возвращает осортированный дифф, совместимый с write_output
35
128
  :param diffs: Маппинг устройства в дифф
@@ -71,7 +164,7 @@ def _make_text_diff(device: Device, diff: Diff) -> List[str]:
71
164
  return res
72
165
 
73
166
 
74
- def collapse_diffs(diffs: Mapping[Device, Diff]) -> Mapping[Tuple[Device, ...], Diff]:
167
+ def collapse_diffs(diffs: Mapping[Device, Diff]) -> Dict[Tuple[Device, ...], Diff]:
75
168
  """
76
169
  Группировка диффов.
77
170
  :param diffs:
@@ -128,7 +221,7 @@ class FrrFileDiffer(UnifiedFileDiffer):
128
221
  return self._diff_frr_conf(hw, old, new)
129
222
  return super().diff_file(hw, path, old, new)
130
223
 
131
- def _diff_frr_conf(self, hw: HardwareView, old_text: str | None, new_text: str | None) -> list[str]:
224
+ def _diff_frr_conf(self, hw: HardwareView, old_text: str | None, new_text: str | None) -> list[str]:
132
225
  """Calculate the differences for frr.conf files."""
133
226
  indent = " "
134
227
  rb = rulebook.rulebook_provider_connector.get()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: annet
3
- Version: 2.2.1
3
+ Version: 2.3.0
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes