annet 3.15.1__tar.gz → 3.16.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 (237) hide show
  1. {annet-3.15.1/annet.egg-info → annet-3.16.0}/PKG-INFO +1 -1
  2. {annet-3.15.1 → annet-3.16.0}/annet/adapters/file/provider.py +11 -1
  3. {annet-3.15.1 → annet-3.16.0}/annet/annlib/netdev/devdb/data/devdb.json +17 -16
  4. {annet-3.15.1 → annet-3.16.0}/annet/annlib/netdev/views/hardware.py +7 -2
  5. {annet-3.15.1 → annet-3.16.0}/annet/annlib/output.py +8 -6
  6. annet-3.16.0/annet/annlib/rbparser/platform.py +1 -0
  7. annet-3.16.0/annet/rulebook/h3c/aaa.py +28 -0
  8. annet-3.16.0/annet/rulebook/h3c/bgp.py +84 -0
  9. annet-3.16.0/annet/rulebook/h3c/iface.py +22 -0
  10. annet-3.16.0/annet/rulebook/h3c/misc.py +280 -0
  11. annet-3.16.0/annet/rulebook/h3c/vlandb.py +118 -0
  12. annet-3.16.0/annet/rulebook/texts/h3c.deploy +196 -0
  13. annet-3.16.0/annet/rulebook/texts/h3c.order +390 -0
  14. annet-3.16.0/annet/rulebook/texts/h3c.rul +432 -0
  15. {annet-3.15.1 → annet-3.16.0}/annet/vendors/library/h3c.py +3 -0
  16. {annet-3.15.1 → annet-3.16.0/annet.egg-info}/PKG-INFO +1 -1
  17. {annet-3.15.1 → annet-3.16.0}/annet.egg-info/SOURCES.txt +9 -0
  18. annet-3.16.0/annet_generators/__init__.py +0 -0
  19. annet-3.15.1/annet/annlib/rbparser/platform.py +0 -3
  20. {annet-3.15.1 → annet-3.16.0}/AUTHORS +0 -0
  21. {annet-3.15.1 → annet-3.16.0}/LICENSE +0 -0
  22. {annet-3.15.1 → annet-3.16.0}/MANIFEST.in +0 -0
  23. {annet-3.15.1 → annet-3.16.0}/README.md +0 -0
  24. {annet-3.15.1 → annet-3.16.0}/annet/__init__.py +0 -0
  25. {annet-3.15.1 → annet-3.16.0}/annet/adapters/__init__.py +0 -0
  26. {annet-3.15.1 → annet-3.16.0}/annet/adapters/fetchers/__init__.py +0 -0
  27. {annet-3.15.1 → annet-3.16.0}/annet/adapters/fetchers/stub/__init__.py +0 -0
  28. {annet-3.15.1 → annet-3.16.0}/annet/adapters/fetchers/stub/fetcher.py +0 -0
  29. {annet-3.15.1 → annet-3.16.0}/annet/adapters/file/__init__.py +0 -0
  30. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/__init__.py +0 -0
  31. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/common/__init__.py +0 -0
  32. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/common/adapter.py +0 -0
  33. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/common/client.py +0 -0
  34. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/common/manufacturer.py +0 -0
  35. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/common/models.py +0 -0
  36. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/common/query.py +0 -0
  37. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/common/status_client.py +0 -0
  38. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/common/storage_base.py +0 -0
  39. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/common/storage_opts.py +0 -0
  40. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/provider.py +0 -0
  41. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/v24/__init__.py +0 -0
  42. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/v24/models.py +0 -0
  43. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/v24/storage.py +0 -0
  44. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/v37/__init__.py +0 -0
  45. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/v37/models.py +0 -0
  46. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/v37/storage.py +0 -0
  47. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/v41/__init__.py +0 -0
  48. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/v41/models.py +0 -0
  49. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/v41/storage.py +0 -0
  50. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/v42/__init__.py +0 -0
  51. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/v42/models.py +0 -0
  52. {annet-3.15.1 → annet-3.16.0}/annet/adapters/netbox/v42/storage.py +0 -0
  53. {annet-3.15.1 → annet-3.16.0}/annet/annet.py +0 -0
  54. {annet-3.15.1 → annet-3.16.0}/annet/annlib/__init__.py +0 -0
  55. {annet-3.15.1 → annet-3.16.0}/annet/annlib/command.py +0 -0
  56. {annet-3.15.1 → annet-3.16.0}/annet/annlib/diff.py +0 -0
  57. {annet-3.15.1 → annet-3.16.0}/annet/annlib/errors.py +0 -0
  58. {annet-3.15.1 → annet-3.16.0}/annet/annlib/filter_acl.py +0 -0
  59. {annet-3.15.1 → annet-3.16.0}/annet/annlib/jsontools.py +0 -0
  60. {annet-3.15.1 → annet-3.16.0}/annet/annlib/lib.py +0 -0
  61. {annet-3.15.1 → annet-3.16.0}/annet/annlib/netdev/__init__.py +0 -0
  62. {annet-3.15.1 → annet-3.16.0}/annet/annlib/netdev/db.py +0 -0
  63. {annet-3.15.1 → annet-3.16.0}/annet/annlib/netdev/devdb/__init__.py +0 -0
  64. {annet-3.15.1 → annet-3.16.0}/annet/annlib/netdev/views/__init__.py +0 -0
  65. {annet-3.15.1 → annet-3.16.0}/annet/annlib/netdev/views/dump.py +0 -0
  66. {annet-3.15.1 → annet-3.16.0}/annet/annlib/patching.py +0 -0
  67. {annet-3.15.1 → annet-3.16.0}/annet/annlib/rbparser/__init__.py +0 -0
  68. {annet-3.15.1 → annet-3.16.0}/annet/annlib/rbparser/acl.py +0 -0
  69. {annet-3.15.1 → annet-3.16.0}/annet/annlib/rbparser/deploying.py +0 -0
  70. {annet-3.15.1 → annet-3.16.0}/annet/annlib/rbparser/ordering.py +0 -0
  71. {annet-3.15.1 → annet-3.16.0}/annet/annlib/rbparser/syntax.py +0 -0
  72. {annet-3.15.1 → annet-3.16.0}/annet/annlib/rulebook/__init__.py +0 -0
  73. {annet-3.15.1 → annet-3.16.0}/annet/annlib/rulebook/common.py +0 -0
  74. {annet-3.15.1 → annet-3.16.0}/annet/annlib/types.py +0 -0
  75. {annet-3.15.1 → annet-3.16.0}/annet/api/__init__.py +0 -0
  76. {annet-3.15.1 → annet-3.16.0}/annet/argparse.py +0 -0
  77. {annet-3.15.1 → annet-3.16.0}/annet/bgp_models.py +0 -0
  78. {annet-3.15.1 → annet-3.16.0}/annet/cli.py +0 -0
  79. {annet-3.15.1 → annet-3.16.0}/annet/cli_args.py +0 -0
  80. {annet-3.15.1 → annet-3.16.0}/annet/configs/context.yml +0 -0
  81. {annet-3.15.1 → annet-3.16.0}/annet/configs/logging.yaml +0 -0
  82. {annet-3.15.1 → annet-3.16.0}/annet/connectors.py +0 -0
  83. {annet-3.15.1 → annet-3.16.0}/annet/deploy.py +0 -0
  84. {annet-3.15.1 → annet-3.16.0}/annet/deploy_ui.py +0 -0
  85. {annet-3.15.1 → annet-3.16.0}/annet/diff.py +0 -0
  86. {annet-3.15.1 → annet-3.16.0}/annet/filtering.py +0 -0
  87. {annet-3.15.1 → annet-3.16.0}/annet/gen.py +0 -0
  88. {annet-3.15.1 → annet-3.16.0}/annet/generators/__init__.py +0 -0
  89. {annet-3.15.1 → annet-3.16.0}/annet/generators/base.py +0 -0
  90. {annet-3.15.1 → annet-3.16.0}/annet/generators/common/__init__.py +0 -0
  91. {annet-3.15.1 → annet-3.16.0}/annet/generators/common/initial.py +0 -0
  92. {annet-3.15.1 → annet-3.16.0}/annet/generators/entire.py +0 -0
  93. {annet-3.15.1 → annet-3.16.0}/annet/generators/exceptions.py +0 -0
  94. {annet-3.15.1 → annet-3.16.0}/annet/generators/jsonfragment.py +0 -0
  95. {annet-3.15.1 → annet-3.16.0}/annet/generators/partial.py +0 -0
  96. {annet-3.15.1 → annet-3.16.0}/annet/generators/perf.py +0 -0
  97. {annet-3.15.1 → annet-3.16.0}/annet/generators/ref.py +0 -0
  98. {annet-3.15.1 → annet-3.16.0}/annet/generators/result.py +0 -0
  99. {annet-3.15.1 → annet-3.16.0}/annet/hardware.py +0 -0
  100. {annet-3.15.1 → annet-3.16.0}/annet/implicit.py +0 -0
  101. {annet-3.15.1 → annet-3.16.0}/annet/lib.py +0 -0
  102. {annet-3.15.1 → annet-3.16.0}/annet/mesh/__init__.py +0 -0
  103. {annet-3.15.1 → annet-3.16.0}/annet/mesh/basemodel.py +0 -0
  104. {annet-3.15.1 → annet-3.16.0}/annet/mesh/device_models.py +0 -0
  105. {annet-3.15.1 → annet-3.16.0}/annet/mesh/executor.py +0 -0
  106. {annet-3.15.1 → annet-3.16.0}/annet/mesh/match_args.py +0 -0
  107. {annet-3.15.1 → annet-3.16.0}/annet/mesh/models_converter.py +0 -0
  108. {annet-3.15.1 → annet-3.16.0}/annet/mesh/peer_models.py +0 -0
  109. {annet-3.15.1 → annet-3.16.0}/annet/mesh/port_processor.py +0 -0
  110. {annet-3.15.1 → annet-3.16.0}/annet/mesh/registry.py +0 -0
  111. {annet-3.15.1 → annet-3.16.0}/annet/output.py +0 -0
  112. {annet-3.15.1 → annet-3.16.0}/annet/parallel.py +0 -0
  113. {annet-3.15.1 → annet-3.16.0}/annet/patching.py +0 -0
  114. {annet-3.15.1 → annet-3.16.0}/annet/reference.py +0 -0
  115. {annet-3.15.1 → annet-3.16.0}/annet/rpl/__init__.py +0 -0
  116. {annet-3.15.1 → annet-3.16.0}/annet/rpl/action.py +0 -0
  117. {annet-3.15.1 → annet-3.16.0}/annet/rpl/condition.py +0 -0
  118. {annet-3.15.1 → annet-3.16.0}/annet/rpl/match_builder.py +0 -0
  119. {annet-3.15.1 → annet-3.16.0}/annet/rpl/policy.py +0 -0
  120. {annet-3.15.1 → annet-3.16.0}/annet/rpl/result.py +0 -0
  121. {annet-3.15.1 → annet-3.16.0}/annet/rpl/routemap.py +0 -0
  122. {annet-3.15.1 → annet-3.16.0}/annet/rpl/statement_builder.py +0 -0
  123. {annet-3.15.1 → annet-3.16.0}/annet/rpl_generators/__init__.py +0 -0
  124. {annet-3.15.1 → annet-3.16.0}/annet/rpl_generators/aspath.py +0 -0
  125. {annet-3.15.1 → annet-3.16.0}/annet/rpl_generators/community.py +0 -0
  126. {annet-3.15.1 → annet-3.16.0}/annet/rpl_generators/cumulus_frr.py +0 -0
  127. {annet-3.15.1 → annet-3.16.0}/annet/rpl_generators/entities.py +0 -0
  128. {annet-3.15.1 → annet-3.16.0}/annet/rpl_generators/execute.py +0 -0
  129. {annet-3.15.1 → annet-3.16.0}/annet/rpl_generators/policy.py +0 -0
  130. {annet-3.15.1 → annet-3.16.0}/annet/rpl_generators/prefix_lists.py +0 -0
  131. {annet-3.15.1 → annet-3.16.0}/annet/rpl_generators/rd.py +0 -0
  132. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/__init__.py +0 -0
  133. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/arista/__init__.py +0 -0
  134. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/arista/aaa.py +0 -0
  135. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/arista/iface.py +0 -0
  136. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/aruba/__init__.py +0 -0
  137. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/aruba/ap_env.py +0 -0
  138. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/aruba/misc.py +0 -0
  139. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/b4com/__init__.py +0 -0
  140. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/b4com/file.py +0 -0
  141. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/b4com/iface.py +0 -0
  142. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/cisco/__init__.py +0 -0
  143. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/cisco/iface.py +0 -0
  144. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/cisco/misc.py +0 -0
  145. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/cisco/vlandb.py +0 -0
  146. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/common.py +0 -0
  147. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/deploying.py +0 -0
  148. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/generic/__init__.py +0 -0
  149. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/generic/misc.py +0 -0
  150. {annet-3.15.1/annet/rulebook/huawei → annet-3.16.0/annet/rulebook/h3c}/__init__.py +0 -0
  151. {annet-3.15.1/annet/rulebook/nexus → annet-3.16.0/annet/rulebook/huawei}/__init__.py +0 -0
  152. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/huawei/aaa.py +0 -0
  153. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/huawei/bgp.py +0 -0
  154. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/huawei/iface.py +0 -0
  155. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/huawei/misc.py +0 -0
  156. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/huawei/vlandb.py +0 -0
  157. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/juniper/__init__.py +0 -0
  158. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/juniper/iface.py +0 -0
  159. {annet-3.15.1/annet/rulebook/routeros → annet-3.16.0/annet/rulebook/nexus}/__init__.py +0 -0
  160. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/nexus/iface.py +0 -0
  161. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/patching.py +0 -0
  162. {annet-3.15.1/annet/vendors/library → annet-3.16.0/annet/rulebook/routeros}/__init__.py +0 -0
  163. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/routeros/file.py +0 -0
  164. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/arista.deploy +0 -0
  165. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/arista.order +0 -0
  166. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/arista.rul +0 -0
  167. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/aruba.deploy +0 -0
  168. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/aruba.order +0 -0
  169. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/aruba.rul +0 -0
  170. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/b4com.deploy +0 -0
  171. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/b4com.order +0 -0
  172. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/b4com.rul +0 -0
  173. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/cisco.deploy +0 -0
  174. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/cisco.order +0 -0
  175. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/cisco.rul +0 -0
  176. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/huawei.deploy +0 -0
  177. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/huawei.order +0 -0
  178. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/huawei.rul +0 -0
  179. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/iosxr.deploy +0 -0
  180. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/iosxr.order +0 -0
  181. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/iosxr.rul +0 -0
  182. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/juniper.order +0 -0
  183. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/juniper.rul +0 -0
  184. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/nexus.deploy +0 -0
  185. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/nexus.order +0 -0
  186. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/nexus.rul +0 -0
  187. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/nokia.rul +0 -0
  188. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/optixtrans.deploy +0 -0
  189. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/optixtrans.order +0 -0
  190. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/optixtrans.rul +0 -0
  191. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/pc.deploy +0 -0
  192. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/pc.order +0 -0
  193. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/pc.rul +0 -0
  194. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/ribbon.deploy +0 -0
  195. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/ribbon.rul +0 -0
  196. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/routeros.order +0 -0
  197. {annet-3.15.1 → annet-3.16.0}/annet/rulebook/texts/routeros.rul +0 -0
  198. {annet-3.15.1 → annet-3.16.0}/annet/storage.py +0 -0
  199. {annet-3.15.1 → annet-3.16.0}/annet/text_term_format.py +0 -0
  200. {annet-3.15.1 → annet-3.16.0}/annet/tracing.py +0 -0
  201. {annet-3.15.1 → annet-3.16.0}/annet/types.py +0 -0
  202. {annet-3.15.1 → annet-3.16.0}/annet/vendors/__init__.py +0 -0
  203. {annet-3.15.1 → annet-3.16.0}/annet/vendors/base.py +0 -0
  204. {annet-3.15.1/annet_generators → annet-3.16.0/annet/vendors/library}/__init__.py +0 -0
  205. {annet-3.15.1 → annet-3.16.0}/annet/vendors/library/arista.py +0 -0
  206. {annet-3.15.1 → annet-3.16.0}/annet/vendors/library/aruba.py +0 -0
  207. {annet-3.15.1 → annet-3.16.0}/annet/vendors/library/b4com.py +0 -0
  208. {annet-3.15.1 → annet-3.16.0}/annet/vendors/library/cisco.py +0 -0
  209. {annet-3.15.1 → annet-3.16.0}/annet/vendors/library/huawei.py +0 -0
  210. {annet-3.15.1 → annet-3.16.0}/annet/vendors/library/iosxr.py +0 -0
  211. {annet-3.15.1 → annet-3.16.0}/annet/vendors/library/juniper.py +0 -0
  212. {annet-3.15.1 → annet-3.16.0}/annet/vendors/library/nexus.py +0 -0
  213. {annet-3.15.1 → annet-3.16.0}/annet/vendors/library/nokia.py +0 -0
  214. {annet-3.15.1 → annet-3.16.0}/annet/vendors/library/optixtrans.py +0 -0
  215. {annet-3.15.1 → annet-3.16.0}/annet/vendors/library/pc.py +0 -0
  216. {annet-3.15.1 → annet-3.16.0}/annet/vendors/library/ribbon.py +0 -0
  217. {annet-3.15.1 → annet-3.16.0}/annet/vendors/library/routeros.py +0 -0
  218. {annet-3.15.1 → annet-3.16.0}/annet/vendors/registry.py +0 -0
  219. {annet-3.15.1 → annet-3.16.0}/annet/vendors/tabparser.py +0 -0
  220. {annet-3.15.1 → annet-3.16.0}/annet.egg-info/dependency_links.txt +0 -0
  221. {annet-3.15.1 → annet-3.16.0}/annet.egg-info/entry_points.txt +0 -0
  222. {annet-3.15.1 → annet-3.16.0}/annet.egg-info/requires.txt +0 -0
  223. {annet-3.15.1 → annet-3.16.0}/annet.egg-info/top_level.txt +0 -0
  224. {annet-3.15.1 → annet-3.16.0}/annet_generators/example/__init__.py +0 -0
  225. {annet-3.15.1 → annet-3.16.0}/annet_generators/example/hostname.py +0 -0
  226. {annet-3.15.1 → annet-3.16.0}/annet_generators/example/lldp.py +0 -0
  227. {annet-3.15.1 → annet-3.16.0}/annet_generators/mesh_example/__init__.py +0 -0
  228. {annet-3.15.1 → annet-3.16.0}/annet_generators/mesh_example/bgp.py +0 -0
  229. {annet-3.15.1 → annet-3.16.0}/annet_generators/mesh_example/mesh_logic.py +0 -0
  230. {annet-3.15.1 → annet-3.16.0}/annet_generators/rpl_example/__init__.py +0 -0
  231. {annet-3.15.1 → annet-3.16.0}/annet_generators/rpl_example/generator.py +0 -0
  232. {annet-3.15.1 → annet-3.16.0}/annet_generators/rpl_example/items.py +0 -0
  233. {annet-3.15.1 → annet-3.16.0}/annet_generators/rpl_example/mesh.py +0 -0
  234. {annet-3.15.1 → annet-3.16.0}/annet_generators/rpl_example/route_policy.py +0 -0
  235. {annet-3.15.1 → annet-3.16.0}/requirements.txt +0 -0
  236. {annet-3.15.1 → annet-3.16.0}/setup.cfg +0 -0
  237. {annet-3.15.1 → annet-3.16.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: annet
3
- Version: 3.15.1
3
+ Version: 3.16.0
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -10,6 +10,7 @@ from annet.connectors import AdapterWithName
10
10
  from annet.hardware import hardware_connector
11
11
  from annet.storage import Device as DeviceProtocol
12
12
  from annet.storage import Query, Storage, StorageProvider
13
+ from annet.adapters.netbox.common.manufacturer import get_breed
13
14
 
14
15
 
15
16
  @dataclass
@@ -30,6 +31,7 @@ class DeviceStorage:
30
31
  vendor: Optional[str] = None
31
32
  hw_model: Optional[str] = None
32
33
  sw_version: Optional[str] = None
34
+ breed: Optional[str] = None
33
35
 
34
36
  hostname: Optional[str] = None
35
37
  serial: Optional[str] = None
@@ -59,6 +61,14 @@ class DeviceStorage:
59
61
  self.hw_model = hw.model
60
62
  self.hw = hw
61
63
 
64
+ if not self.breed:
65
+ if self.hw.model:
66
+ parts = self.hw.model.split(maxsplit=1)
67
+ if len(parts) >= 2:
68
+ self.breed = get_breed(parts[0], parts[1])
69
+ if not self.breed:
70
+ self.breed = self.hw.vendor
71
+
62
72
  if isinstance(self.interfaces, list):
63
73
  interfaces = []
64
74
  for iface in self.interfaces:
@@ -107,7 +117,7 @@ class Device(DeviceProtocol, DumpableView):
107
117
 
108
118
  @property
109
119
  def breed(self) -> str:
110
- return self.dev.hw.vendor
120
+ return self.dev.breed
111
121
 
112
122
  @property
113
123
  def neighbours_ids(self):
@@ -20,23 +20,24 @@
20
20
  "Cisco.Catalyst.C3700": "37\\d\\d",
21
21
  "Cisco.Catalyst.C4900": "49\\d\\d",
22
22
  "Cisco.Catalyst.C6500": "65\\d\\d",
23
- "Cisco.Nexus": " [Nn]exus",
24
- "Cisco.Nexus.N3x": " 3\\d\\d\\d",
25
- "Cisco.Nexus.N3x.N3100": " 31\\d\\d",
26
- "Cisco.Nexus.N3x.N3432": " 3432",
27
- "Cisco.Nexus.N3x.N3500": " 35\\d\\d",
28
- "Cisco.Nexus.N5x": " 5\\d\\d\\d",
29
- "Cisco.Nexus.N5x.N5000": " 50\\d\\d",
30
- "Cisco.Nexus.N5x.N5500": " 55\\d\\d",
31
- "Cisco.Nexus.N6x": " 6\\d\\d\\d",
32
- "Cisco.Nexus.N6x.N6000": " 60\\d\\d",
33
- "Cisco.Nexus.N7x": " 7\\d{3}",
34
- "Cisco.Nexus.N7x.N7000": " 70\\d\\d",
35
- "Cisco.Nexus.N7x.N7700": " 77\\d\\d",
23
+
24
+ "Cisco.Nexus": " [Nn](exus)?",
25
+ "Cisco.Nexus.N3x": " (N3K-[A-Z])?3\\d\\d\\d",
26
+ "Cisco.Nexus.N3x.N3100": "31\\d\\d",
27
+ "Cisco.Nexus.N3x.N3432": "3432",
28
+ "Cisco.Nexus.N3x.N3500": "35\\d\\d",
29
+ "Cisco.Nexus.N5x": " (N5K-[A-Z])?5\\d\\d\\d",
30
+ "Cisco.Nexus.N5x.N5000": "50\\d\\d",
31
+ "Cisco.Nexus.N5x.N5500": "55\\d\\d",
32
+ "Cisco.Nexus.N6x": " (N6K-[A-Z])?6\\d\\d\\d",
33
+ "Cisco.Nexus.N6x.N6000": "60\\d\\d",
34
+ "Cisco.Nexus.N7x": " (N7K-[A-Z])?7\\d\\d\\d",
35
+ "Cisco.Nexus.N7x.N7000": "70\\d\\d",
36
+ "Cisco.Nexus.N7x.N7700": "77\\d\\d",
36
37
  "Cisco.Nexus.N9x": " (N9K-[A-Z])?9\\d\\d\\d",
37
- "Cisco.Nexus.N9x.N9316": " 9316",
38
- "Cisco.Nexus.N9x.N9500": " 95\\d\\d",
39
- "Cisco.Nexus.N9x.N9364": " N9K-C9364",
38
+ "Cisco.Nexus.N9x.N9316": "9316",
39
+ "Cisco.Nexus.N9x.N9500": "95\\d\\d",
40
+ "Cisco.Nexus.N9x.N9364": "9364",
40
41
 
41
42
  "Huawei": "^[Hh]uawei",
42
43
  "Huawei.CE": " CE\\d+",
@@ -36,9 +36,12 @@ class HardwareLeaf(DumpableView):
36
36
  raise AttributeError("HW: " + ".".join(path))
37
37
 
38
38
  def __str__(self):
39
- return str(" | ".join(".".join(x) for x in self.__true_sequences))
39
+ for seq in sorted(self.__true_sequences, key=len, reverse=True):
40
+ return ".".join(seq)
41
+ return ""
40
42
 
41
- __repr__ = __str__
43
+ def __repr__(self):
44
+ return str(" | ".join(".".join(x) for x in self.__true_sequences))
42
45
 
43
46
  def dump(self, prefix, **kwargs): # pylint: disable=arguments-differ
44
47
  ret = super().dump(prefix, **kwargs)
@@ -103,4 +106,6 @@ def lag_name(hw: HardwareView, nlagg: int) -> str:
103
106
  return f"lagg{nlagg}"
104
107
  if hw.Nokia:
105
108
  return f"lagg-{nlagg}"
109
+ if hw.H3C:
110
+ return f"Bridge-Aggregation{nlagg}"
106
111
  raise NotImplementedError(hw)
@@ -114,7 +114,7 @@ class Dumpable(abc.ABC):
114
114
  pass
115
115
 
116
116
 
117
- def print_as_json(data, fh=sys.stdout):
117
+ def print_as_json(data, fh=sys.stdout, highlight=True):
118
118
  """
119
119
  В выводе dict ключи отсортированы по имени, кроме ключей в OrderedDict,
120
120
  которые сохраняют свой оригинальный порядок
@@ -176,17 +176,19 @@ def print_as_json(data, fh=sys.stdout):
176
176
  except TypeError:
177
177
  raise TypeError("can't serialize %r to json" % o)
178
178
 
179
- dump = json.dumps(UnsortableOdict.convert_odicts(data), cls=JsonEncoder,
180
- ensure_ascii=False, indent=4, sort_keys=True) + "\n"
181
- if fh.isatty():
179
+ dump_data = UnsortableOdict.convert_odicts(data)
180
+ dump_kwargs = dict(cls=JsonEncoder, ensure_ascii=False)
181
+
182
+ if fh.isatty() and highlight:
182
183
  pygments.highlight(
183
- code=dump,
184
+ code=json.dumps(dump_data, indent=4, sort_keys=True, **dump_kwargs) + "\n",
184
185
  lexer=pygments.lexers.data.JsonLexer(),
185
186
  formatter=pygments.formatters.TerminalFormatter(bg="dark"),
186
187
  outfile=fh,
187
188
  )
188
189
  else:
189
- fh.write(dump)
190
+ json.dump(dump_data, fh, **dump_kwargs)
191
+ fh.write("\n")
190
192
 
191
193
 
192
194
  class TextArgs:
@@ -0,0 +1 @@
1
+ VENDOR_ALIASES: dict[str, str] = {}
@@ -0,0 +1,28 @@
1
+ from annet.annlib.types import Op
2
+
3
+
4
+ def user(key, diff, **_):
5
+ check_for_remove = True
6
+ added = []
7
+ for add in diff[Op.ADDED]:
8
+ added.append((True, add["row"], None))
9
+ if add["row"].startswith("local-user %s password" % key[0]):
10
+ check_for_remove = False
11
+ if check_for_remove:
12
+ for rem in diff[Op.REMOVED]:
13
+ # we abe able to overwrite new command without undo
14
+ if rem["row"].startswith("local-user %s password" % key[0]):
15
+ yield (False, "undo local-user %s" % key[0], None)
16
+ return
17
+ if (rem["row"].startswith("local-user %s privilege" % key[0])
18
+ and not _added_contains(diff[Op.ADDED], "local-user %s privilege" % key[0])):
19
+ yield (False, "undo local-user %s" % key[0], None)
20
+ return
21
+ yield from added
22
+
23
+
24
+ def _added_contains(array: list[dict], lookup_string: str) -> bool:
25
+ for item in array:
26
+ if item["row"].startswith(lookup_string):
27
+ return True
28
+ return False
@@ -0,0 +1,84 @@
1
+ import socket
2
+
3
+ from annet.annlib.types import Op
4
+
5
+ from annet.rulebook import common
6
+
7
+
8
+ def peer(rule, key, diff, **_): # pylint: disable=unused-argument
9
+ """
10
+ The peculiarity of peer commands is that
11
+ peer IP as-number N
12
+ is the main command, and it can only be removed with
13
+ undo peer IP
14
+ which completely deletes all settings of the peer.
15
+ At the same time, the as-number can also be set for a group:
16
+ group SPINES
17
+ peer SPINES as-number 13238
18
+ In this case, we ignore it and allow this setting to be deleted, since it does not define the group itself:
19
+ undo peer SPINES as-number
20
+ """
21
+
22
+ assert not diff[Op.AFFECTED], "Peer commands could not contain subcommands"
23
+ for action in sorted(diff[Op.REMOVED], key=lambda act: "as-number" not in act["row"].split()):
24
+ tokens = action["row"].split()
25
+ (_, addr_or_group_name, param, *__) = tokens
26
+ if param == "as-number":
27
+ if _is_ip_addr(addr_or_group_name):
28
+ yield (False, "undo peer {}".format(*key), None)
29
+ else:
30
+ # We can’t use common.default because the rule is defined as "peer *" and not "peer * *".
31
+ # Therefore, the default behavior here would be "undo peer PEERGROUP", which is not what we want.
32
+ yield (False, "undo peer {} as-number".format(*key), None)
33
+ break
34
+
35
+ if param in ["connect-interface", "ebgp-max-hop", "local-as", "substitute-as", "password", "preferred-value"]:
36
+ yield (False, "undo " + " ".join(tokens[:3]), None)
37
+ else:
38
+ yield (False, "undo " + action["row"], None)
39
+
40
+ for action in sorted(diff[Op.ADDED], key=lambda act: "as-number" not in act["row"]):
41
+ yield (True, action["row"], None)
42
+
43
+
44
+ def bfd(rule, key, diff, **_):
45
+ """
46
+ [*vla-1x1-bgp]undo peer SPINE1 bfd min-tx-interval 500 min-rx-interval 500 detect-multiplier 4
47
+ │Error: Unrecognized command found at '^' position.
48
+
49
+ [*vla-1x1-bgp]undo peer SPINE1 bfd min-rx-interval
50
+ [~vla-1x1-bgp]undo peer SPINE1 bfd min-tx-interval
51
+ [*vla-1x1-bgp]undo peer SPINE1 bfd detect-multiplier
52
+ """
53
+ if diff[Op.REMOVED]:
54
+ assert len(diff[Op.REMOVED]) <= 1 and len(diff[Op.ADDED]) <= 1
55
+ new_params = set()
56
+ if diff[Op.ADDED]:
57
+ new_params = set(_bfd_params_used(diff[Op.ADDED][0]["row"]))
58
+ for token in _bfd_params_used(diff[Op.REMOVED][0]["row"]):
59
+ if token not in new_params:
60
+ yield (False, rule["reverse"].format(*key) + " " + token, None)
61
+ diff[Op.REMOVED] = []
62
+ if diff[Op.ADDED]:
63
+ yield from common.default(rule, key, diff, **_)
64
+
65
+
66
+ def _is_ip_addr(addr_or_string):
67
+ ret = None
68
+ for af in (socket.AF_INET6, socket.AF_INET):
69
+ try:
70
+ ret = socket.inet_pton(af, addr_or_string)
71
+ except OSError:
72
+ pass
73
+ else:
74
+ break
75
+ return bool(ret)
76
+
77
+
78
+ def _bfd_params_used(row):
79
+ prev = None
80
+ for token in row.split():
81
+ if prev and token.isnumeric():
82
+ if prev and token.isnumeric():
83
+ yield prev
84
+ prev = token
@@ -0,0 +1,22 @@
1
+ from annet.annlib.types import Op
2
+
3
+ from annet.rulebook import common
4
+
5
+
6
+ # [NOCDEV-2180] After vrf was change we put ip config one more time
7
+ def binding_change(old, new, diff_pre, _pops=(Op.AFFECTED,)):
8
+ ret = common.default_diff(old, new, diff_pre, _pops)
9
+ vpn_changed = False
10
+ for (op, cmd, _, _) in ret:
11
+ if op in {Op.ADDED, Op.REMOVED}:
12
+ vpn_changed |= _is_vpn_cmd(cmd)
13
+ if vpn_changed:
14
+ for cmd in list(old.keys()):
15
+ if not _is_vpn_cmd(cmd):
16
+ del old[cmd]
17
+ ret = common.default_diff(old, new, diff_pre, _pops)
18
+ return ret
19
+
20
+
21
+ def _is_vpn_cmd(cmd):
22
+ return cmd.startswith("ip binding vpn-instance")
@@ -0,0 +1,280 @@
1
+ import copy
2
+
3
+ from annet.annlib.types import Op
4
+
5
+ from annet.rulebook import common
6
+
7
+
8
+ def rp_node(rule, key, diff, **_):
9
+ # route-policy NAME ACTION node NUM
10
+ (rp_name, node_id) = key
11
+ if diff[Op.REMOVED]:
12
+ if diff[Op.ADDED]:
13
+ sub_diff = {Op.AFFECTED: [], Op.ADDED: [], Op.REMOVED: [], Op.MOVED: [], Op.UNCHANGED: []}
14
+ sub_diff[Op.AFFECTED] = diff[Op.REMOVED]
15
+ yield from common.default(rule, key, sub_diff)
16
+ else:
17
+ yield (False, "undo route-policy %s node %s" % (rp_name, node_id), None)
18
+
19
+ if diff[Op.AFFECTED] or diff[Op.ADDED]:
20
+ yield from common.default(rule, key, diff)
21
+
22
+
23
+ def undo_redo(rule, key, diff, **_):
24
+ yield from common.undo_redo(rule, key, diff, **_)
25
+
26
+
27
+ def prefix_list(rule, key, diff, **kwargs):
28
+ # To determine whether the prefix list is being fully modified,
29
+ # the key (family, name) is defined in the h3c.rul rulebook.
30
+ # However, from the command’s point of view, each index represents a separate command.
31
+ # Therefore, we group them by index here and pass them to common.
32
+ diff_by_index = {}
33
+ for op, rows in diff.items():
34
+ for row in rows:
35
+ # prefix list format:
36
+ # ip ip-prefix PRFX_CT_LU_ALLOWED_ROUTES index 15 ..
37
+ # ip ipv6-prefix PFXS_SPECIALv6 index 20 ..
38
+ _ip, _family, _name, _index, index, *_ = row["row"].split()
39
+ if index not in diff_by_index:
40
+ sub_diff = {op: [] for op in diff.keys()}
41
+ diff_by_index[index] = sub_diff
42
+ diff_by_index[index][op].append(row)
43
+
44
+ family, name = key
45
+ if family not in {"ip", "ipv6"}:
46
+ raise NotImplementedError("Unknown family '%s'" % family)
47
+ if diff[Op.ADDED] or diff[Op.REMOVED] or diff[Op.MOVED]:
48
+ # Since the rule key originally doesn’t include the index,
49
+ # we need to add it; otherwise, the undo rule will be missing it.
50
+ indexed_rule = copy.deepcopy(rule)
51
+ indexed_rule["reverse"] = "undo ip {}-prefix {} index {}"
52
+
53
+ # The stub_index is referenced in the h3c.order rulebook
54
+ # to ensure that the stub is added or removed first or last in order.
55
+
56
+ stub, stub_index = "", 99999999
57
+
58
+ # If we’re only adding new commands (for example, creating entries) in the prefix list,
59
+ # or deleting/moving them while keeping some parts unchanged,
60
+ # h3c will not treat the list as being removed, and the stub rule is not needed.
61
+
62
+ if (diff[Op.REMOVED] or diff[Op.MOVED]) and not diff[Op.UNCHANGED]:
63
+ stub = "deny 0.0.0.0 32" if family == "ip" else "deny :: 128"
64
+ if stub:
65
+ yield (True, f"ip {family}-prefix {name} index {stub_index} {stub}", None)
66
+ for index, sub_diff in diff_by_index.items():
67
+ yield from common.undo_redo(indexed_rule, (family, name, index), sub_diff, **kwargs)
68
+ if stub:
69
+ yield (False, f"undo ip {family}-prefix {name} index {stub_index}", None)
70
+
71
+
72
+ def static(rule, key, diff, **_):
73
+ """
74
+ To roll back a static route, we actually need to pass almost all arguments
75
+ except for the various "track" options.
76
+ At the same time, the number of arguments may vary — optional VRF, optional interface.
77
+ Therefore, we don’t parse the command itself; we just remove the unnecessary arguments.
78
+ """
79
+ if diff[Op.REMOVED]:
80
+ param = key[0]
81
+ idx = param.find(" track")
82
+ if idx > 0:
83
+ key = (param[0:idx],)
84
+ idx = param.find(" description")
85
+ if idx > 0:
86
+ key = (param[0:idx],)
87
+ idx = param.find(" preference")
88
+ if idx > 0:
89
+ key = (param[0:idx],)
90
+ yield from common.default(rule, key, diff)
91
+
92
+
93
+ def port_queue(rule, key, diff, **_):
94
+ """
95
+ To roll back the port-queue configuration on an interface, only a partial parameter specification is required.
96
+ Example of disabling/enabling:
97
+ interface 100GE0/1/33
98
+ undo port-queue af3 wfq outbound
99
+ port-queue af3 wfq weight 30 port-wred WRED outbound
100
+
101
+ Essentially, we need to remove all parameters between 'wfq' and 'outbound'.
102
+ NOC-19414
103
+ """
104
+ if diff[Op.REMOVED]:
105
+ param = key[0]
106
+ idx = param.find("weight")
107
+ if idx > 0:
108
+ key = (param[0:idx] + "outbound",)
109
+ yield from common.default(rule, key, diff)
110
+
111
+
112
+ def netstream_undo(rule, key, diff, **_):
113
+ if diff[Op.REMOVED]:
114
+ # The only part we need is the last keyword: inbound or outbound
115
+ # Unfortunately, key is a tuple so we cast it to a list and back
116
+ key = list(key)
117
+ key[1] = key[1].split(" ")[-1]
118
+ key = tuple(key)
119
+ yield from common.default(rule, key, diff)
120
+
121
+
122
+ def snmpagent_sysinfo_version(rule, key, diff, hw, **_):
123
+ yield from common.default(rule, key, diff)
124
+
125
+
126
+ def vty_acl_undo(rule, key, diff, **_):
127
+ if diff[Op.REMOVED]:
128
+ chunks = key[0].split()
129
+ result_chunks = ["undo acl"]
130
+ if len(chunks) == 3 and chunks[0] == "ipv6":
131
+ result_chunks.append("ipv6")
132
+ result_chunks.append(chunks[-1])
133
+ yield False, " ".join(result_chunks), None
134
+ else:
135
+ yield from common.default(rule, key, diff)
136
+
137
+
138
+ def port_split(rule, key, diff, **_):
139
+ # pylint: disable=unused-argument
140
+ def _port_split(old, new, old_row, new_row):
141
+ removed = set(old).difference(new)
142
+ added = set(new).difference(old)
143
+ if old and new:
144
+ for ifname in removed:
145
+ yield (False, "undo port split dimension interface " + ifname, None)
146
+ for ifname in added:
147
+ yield (True, "port split dimension interface " + ifname, None)
148
+ elif old and not new:
149
+ yield (False, "undo " + old_row, None)
150
+ elif new and not old:
151
+ yield (True, new_row, None)
152
+
153
+ def _row_slot(row):
154
+ res = ""
155
+ for ch in row:
156
+ if ch == "/":
157
+ break
158
+ res = res + ch if ch.isnumeric() else ""
159
+ return int(res) if res else 0
160
+
161
+ old_by_slot = {_row_slot(x["row"]): x["row"] for x in diff[Op.REMOVED]}
162
+ new_by_slot = {_row_slot(x["row"]): x["row"] for x in diff[Op.ADDED]}
163
+ for slot in set(old_by_slot.keys()).union(new_by_slot.keys()):
164
+ old_row = old_by_slot[slot] if slot in old_by_slot else ""
165
+ new_row = new_by_slot[slot] if slot in new_by_slot else ""
166
+ old = _expand_portsplit(old_row)
167
+ new = _expand_portsplit(new_row)
168
+ yield from _port_split(old, new, old_row, new_row)
169
+ if old_by_slot or new_by_slot:
170
+ yield (True, "port split refresh", None)
171
+
172
+
173
+ def _expand_portsplit(row):
174
+ expanded = []
175
+ row_parts = row.split()
176
+ for (index, part) in enumerate(row_parts):
177
+ if part == "to":
178
+ iface_base = "/".join(row_parts[index - 1].split("/")[:-1])
179
+ left = int(row_parts[index - 1].split("/")[-1])
180
+ right = int(row_parts[index + 1].split("/")[-1])
181
+ for i in range(left + 1, right):
182
+ expanded.append(iface_base + "/" + str(i))
183
+ else:
184
+ expanded.append(part)
185
+ return expanded
186
+
187
+
188
+ def classifier(rule, key, diff, **_):
189
+ # if type changes firstly remove all if-match
190
+ # and then recreate classifier
191
+ if diff[Op.ADDED] and diff[Op.REMOVED]:
192
+ yield (True, diff[Op.REMOVED][0]["row"], diff[Op.REMOVED][0]["children"])
193
+ yield from common.default(rule, key, diff)
194
+
195
+
196
+ def undo_children(rule, key, diff, **_):
197
+ def removed_count(subdiff):
198
+ ret = 0
199
+ for child in subdiff["children"].values():
200
+ for child_diff in child["items"].values():
201
+ ret += len(child_diff[Op.REMOVED])
202
+ return ret
203
+
204
+ def common_default(op, subdiff):
205
+ newdiff = {Op.ADDED: [], Op.REMOVED: [], Op.MOVED: [], Op.AFFECTED: [], Op.UNCHANGED: []}
206
+ newdiff[op] = [subdiff]
207
+ yield from common.default(rule, key, newdiff)
208
+
209
+ # we should say undo because we pretend as single block
210
+ for subdiff in diff[Op.REMOVED]:
211
+ # firstly remove all group-members
212
+ if diff[Op.REMOVED][0]["children"]:
213
+ yield (True, diff[Op.REMOVED][0]["row"], diff[Op.REMOVED][0]["children"])
214
+ yield False, "undo " + subdiff["row"], None
215
+ # firstly destroy affected because inside we can have an undo
216
+ for subdiff in sorted(diff[Op.AFFECTED], key=removed_count, reverse=True):
217
+ yield from common_default(Op.AFFECTED, subdiff)
218
+ for subdiff in diff[Op.ADDED]:
219
+ yield from common_default(Op.ADDED, subdiff)
220
+
221
+
222
+ def clear_instead_undo(rule, key, diff, **_):
223
+ # For some configuration lines, a persistent diff occurs because the line in the config is either explicitly enabled
224
+ # or explicitly disabled. If it is not described in the generator (i.e., we rely on the default),
225
+ # then by using "clear" instead of "undo" we return the configuration to its default state.
226
+ # NOC-20102 @gslv 11-02-2022
227
+ if diff[Op.REMOVED]:
228
+ if diff[Op.REMOVED][0]["row"].endswith(" disable"):
229
+ cmd = diff[Op.REMOVED][0]["row"].replace(" disable", "")
230
+ yield (True, "clear " + cmd, False)
231
+ else:
232
+ yield from common.default(rule, key, diff)
233
+
234
+
235
+ def undo_port_link_mode(rule, key, diff, **_):
236
+ """
237
+ Сhanging port mode from bridge to route and back
238
+ """
239
+
240
+ if diff[Op.REMOVED]:
241
+ if key[0] == "route":
242
+ cmd = f"{diff[Op.REMOVED][0]['row']}".replace(key[0], "bridge")
243
+ yield (True, cmd, False)
244
+
245
+ if key[0] == "bridge":
246
+ cmd = f"{diff[Op.REMOVED][0]['row']}".replace(key[0], "route")
247
+ yield (True, cmd, False)
248
+
249
+
250
+ def hardware_resource_bfd(rule, key, diff, **_):
251
+ """
252
+ Changing hardware-resource firmware-mode from software
253
+ to hardware and back without undo
254
+ """
255
+
256
+ if diff[Op.REMOVED]:
257
+ if key[0] == "INT-PTP":
258
+ cmd = f"{diff[Op.REMOVED][0]['row']}".replace(key[0], "INT-BFD")
259
+ yield (True, cmd, False)
260
+
261
+ if key[0] == "INT-BFD":
262
+ cmd = f"{diff[Op.REMOVED][0]['row']}".replace(key[0], "INT-PTP")
263
+ yield (True, cmd, False)
264
+
265
+
266
+ def change_user_password(rule, key, diff, **_):
267
+ """
268
+ If we have to change password hash
269
+ then we just push new hash to configuration
270
+ without undo
271
+ """
272
+
273
+ if diff[Op.REMOVED]:
274
+ if key[0] == "route":
275
+ cmd = f"{diff[Op.REMOVED][0]['row']}".replace(key[0], "bridge")
276
+ yield (True, cmd, False)
277
+
278
+ if key[0] == "bridge":
279
+ cmd = f"{diff[Op.REMOVED][0]['row']}".replace(key[0], "route")
280
+ yield (True, cmd, False)