annet 0.14.7__tar.gz → 0.14.9__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 (140) hide show
  1. {annet-0.14.7/annet.egg-info → annet-0.14.9}/PKG-INFO +1 -1
  2. {annet-0.14.7 → annet-0.14.9}/annet/adapters/netbox/common/manufacturer.py +1 -12
  3. {annet-0.14.7 → annet-0.14.9}/annet/adapters/netbox/common/models.py +21 -4
  4. {annet-0.14.7 → annet-0.14.9}/annet/adapters/netbox/v24/storage.py +2 -2
  5. {annet-0.14.7 → annet-0.14.9}/annet/adapters/netbox/v37/storage.py +13 -9
  6. {annet-0.14.7 → annet-0.14.9}/annet/annlib/netdev/views/dump.py +8 -0
  7. {annet-0.14.7 → annet-0.14.9}/annet/argparse.py +6 -2
  8. {annet-0.14.7 → annet-0.14.9}/annet/cli.py +49 -19
  9. {annet-0.14.7 → annet-0.14.9}/annet/cli_args.py +55 -57
  10. {annet-0.14.7 → annet-0.14.9}/annet/executor.py +1 -5
  11. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/aruba/ap_env.py +1 -6
  12. {annet-0.14.7 → annet-0.14.9}/annet/storage.py +1 -1
  13. {annet-0.14.7 → annet-0.14.9/annet.egg-info}/PKG-INFO +1 -1
  14. {annet-0.14.7 → annet-0.14.9}/AUTHORS +0 -0
  15. {annet-0.14.7 → annet-0.14.9}/LICENSE +0 -0
  16. {annet-0.14.7 → annet-0.14.9}/MANIFEST.in +0 -0
  17. {annet-0.14.7 → annet-0.14.9}/README.md +0 -0
  18. {annet-0.14.7 → annet-0.14.9}/annet/__init__.py +0 -0
  19. {annet-0.14.7 → annet-0.14.9}/annet/adapters/__init__.py +0 -0
  20. {annet-0.14.7 → annet-0.14.9}/annet/adapters/netbox/__init__.py +0 -0
  21. {annet-0.14.7 → annet-0.14.9}/annet/adapters/netbox/common/__init__.py +0 -0
  22. {annet-0.14.7 → annet-0.14.9}/annet/adapters/netbox/common/client.py +0 -0
  23. {annet-0.14.7 → annet-0.14.9}/annet/adapters/netbox/common/query.py +0 -0
  24. {annet-0.14.7 → annet-0.14.9}/annet/adapters/netbox/common/status_client.py +0 -0
  25. {annet-0.14.7 → annet-0.14.9}/annet/adapters/netbox/common/storage_opts.py +0 -0
  26. {annet-0.14.7 → annet-0.14.9}/annet/adapters/netbox/provider.py +0 -0
  27. {annet-0.14.7 → annet-0.14.9}/annet/adapters/netbox/v24/__init__.py +0 -0
  28. {annet-0.14.7 → annet-0.14.9}/annet/adapters/netbox/v37/__init__.py +0 -0
  29. {annet-0.14.7 → annet-0.14.9}/annet/annet.py +0 -0
  30. {annet-0.14.7 → annet-0.14.9}/annet/annlib/__init__.py +0 -0
  31. {annet-0.14.7 → annet-0.14.9}/annet/annlib/command.py +0 -0
  32. {annet-0.14.7 → annet-0.14.9}/annet/annlib/diff.py +0 -0
  33. {annet-0.14.7 → annet-0.14.9}/annet/annlib/errors.py +0 -0
  34. {annet-0.14.7 → annet-0.14.9}/annet/annlib/filter_acl.py +0 -0
  35. {annet-0.14.7 → annet-0.14.9}/annet/annlib/jsontools.py +0 -0
  36. {annet-0.14.7 → annet-0.14.9}/annet/annlib/lib.py +0 -0
  37. {annet-0.14.7 → annet-0.14.9}/annet/annlib/netdev/__init__.py +0 -0
  38. {annet-0.14.7 → annet-0.14.9}/annet/annlib/netdev/db.py +0 -0
  39. {annet-0.14.7 → annet-0.14.9}/annet/annlib/netdev/devdb/__init__.py +0 -0
  40. {annet-0.14.7 → annet-0.14.9}/annet/annlib/netdev/devdb/data/devdb.json +0 -0
  41. {annet-0.14.7 → annet-0.14.9}/annet/annlib/netdev/views/__init__.py +0 -0
  42. {annet-0.14.7 → annet-0.14.9}/annet/annlib/netdev/views/hardware.py +0 -0
  43. {annet-0.14.7 → annet-0.14.9}/annet/annlib/output.py +0 -0
  44. {annet-0.14.7 → annet-0.14.9}/annet/annlib/patching.py +0 -0
  45. {annet-0.14.7 → annet-0.14.9}/annet/annlib/rbparser/__init__.py +0 -0
  46. {annet-0.14.7 → annet-0.14.9}/annet/annlib/rbparser/acl.py +0 -0
  47. {annet-0.14.7 → annet-0.14.9}/annet/annlib/rbparser/deploying.py +0 -0
  48. {annet-0.14.7 → annet-0.14.9}/annet/annlib/rbparser/ordering.py +0 -0
  49. {annet-0.14.7 → annet-0.14.9}/annet/annlib/rbparser/platform.py +0 -0
  50. {annet-0.14.7 → annet-0.14.9}/annet/annlib/rbparser/syntax.py +0 -0
  51. {annet-0.14.7 → annet-0.14.9}/annet/annlib/rulebook/__init__.py +0 -0
  52. {annet-0.14.7 → annet-0.14.9}/annet/annlib/rulebook/common.py +0 -0
  53. {annet-0.14.7 → annet-0.14.9}/annet/annlib/tabparser.py +0 -0
  54. {annet-0.14.7 → annet-0.14.9}/annet/annlib/types.py +0 -0
  55. {annet-0.14.7 → annet-0.14.9}/annet/api/__init__.py +0 -0
  56. {annet-0.14.7 → annet-0.14.9}/annet/configs/context.yml +0 -0
  57. {annet-0.14.7 → annet-0.14.9}/annet/configs/logging.yaml +0 -0
  58. {annet-0.14.7 → annet-0.14.9}/annet/connectors.py +0 -0
  59. {annet-0.14.7 → annet-0.14.9}/annet/deploy.py +0 -0
  60. {annet-0.14.7 → annet-0.14.9}/annet/diff.py +0 -0
  61. {annet-0.14.7 → annet-0.14.9}/annet/filtering.py +0 -0
  62. {annet-0.14.7 → annet-0.14.9}/annet/gen.py +0 -0
  63. {annet-0.14.7 → annet-0.14.9}/annet/generators/__init__.py +0 -0
  64. {annet-0.14.7 → annet-0.14.9}/annet/generators/base.py +0 -0
  65. {annet-0.14.7 → annet-0.14.9}/annet/generators/common/__init__.py +0 -0
  66. {annet-0.14.7 → annet-0.14.9}/annet/generators/common/initial.py +0 -0
  67. {annet-0.14.7 → annet-0.14.9}/annet/generators/entire.py +0 -0
  68. {annet-0.14.7 → annet-0.14.9}/annet/generators/exceptions.py +0 -0
  69. {annet-0.14.7 → annet-0.14.9}/annet/generators/jsonfragment.py +0 -0
  70. {annet-0.14.7 → annet-0.14.9}/annet/generators/partial.py +0 -0
  71. {annet-0.14.7 → annet-0.14.9}/annet/generators/perf.py +0 -0
  72. {annet-0.14.7 → annet-0.14.9}/annet/generators/ref.py +0 -0
  73. {annet-0.14.7 → annet-0.14.9}/annet/generators/result.py +0 -0
  74. {annet-0.14.7 → annet-0.14.9}/annet/hardware.py +0 -0
  75. {annet-0.14.7 → annet-0.14.9}/annet/implicit.py +0 -0
  76. {annet-0.14.7 → annet-0.14.9}/annet/lib.py +0 -0
  77. {annet-0.14.7 → annet-0.14.9}/annet/output.py +0 -0
  78. {annet-0.14.7 → annet-0.14.9}/annet/parallel.py +0 -0
  79. {annet-0.14.7 → annet-0.14.9}/annet/patching.py +0 -0
  80. {annet-0.14.7 → annet-0.14.9}/annet/reference.py +0 -0
  81. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/__init__.py +0 -0
  82. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/arista/__init__.py +0 -0
  83. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/arista/iface.py +0 -0
  84. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/aruba/__init__.py +0 -0
  85. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/aruba/misc.py +0 -0
  86. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/cisco/__init__.py +0 -0
  87. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/cisco/iface.py +0 -0
  88. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/cisco/misc.py +0 -0
  89. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/cisco/vlandb.py +0 -0
  90. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/common.py +0 -0
  91. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/deploying.py +0 -0
  92. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/huawei/__init__.py +0 -0
  93. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/huawei/aaa.py +0 -0
  94. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/huawei/bgp.py +0 -0
  95. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/huawei/iface.py +0 -0
  96. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/huawei/misc.py +0 -0
  97. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/huawei/vlandb.py +0 -0
  98. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/juniper/__init__.py +0 -0
  99. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/nexus/__init__.py +0 -0
  100. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/nexus/iface.py +0 -0
  101. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/patching.py +0 -0
  102. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/ribbon/__init__.py +0 -0
  103. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/arista.deploy +0 -0
  104. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/arista.order +0 -0
  105. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/arista.rul +0 -0
  106. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/aruba.deploy +0 -0
  107. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/aruba.order +0 -0
  108. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/aruba.rul +0 -0
  109. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/cisco.deploy +0 -0
  110. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/cisco.order +0 -0
  111. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/cisco.rul +0 -0
  112. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/huawei.deploy +0 -0
  113. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/huawei.order +0 -0
  114. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/huawei.rul +0 -0
  115. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/juniper.rul +0 -0
  116. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/nexus.deploy +0 -0
  117. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/nexus.order +0 -0
  118. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/nexus.rul +0 -0
  119. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/nokia.rul +0 -0
  120. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/pc.order +0 -0
  121. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/pc.rul +0 -0
  122. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/ribbon.deploy +0 -0
  123. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/ribbon.rul +0 -0
  124. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/routeros.order +0 -0
  125. {annet-0.14.7 → annet-0.14.9}/annet/rulebook/texts/routeros.rul +0 -0
  126. {annet-0.14.7 → annet-0.14.9}/annet/tabparser.py +0 -0
  127. {annet-0.14.7 → annet-0.14.9}/annet/text_term_format.py +0 -0
  128. {annet-0.14.7 → annet-0.14.9}/annet/tracing.py +0 -0
  129. {annet-0.14.7 → annet-0.14.9}/annet/types.py +0 -0
  130. {annet-0.14.7 → annet-0.14.9}/annet.egg-info/SOURCES.txt +0 -0
  131. {annet-0.14.7 → annet-0.14.9}/annet.egg-info/dependency_links.txt +0 -0
  132. {annet-0.14.7 → annet-0.14.9}/annet.egg-info/entry_points.txt +0 -0
  133. {annet-0.14.7 → annet-0.14.9}/annet.egg-info/requires.txt +0 -0
  134. {annet-0.14.7 → annet-0.14.9}/annet.egg-info/top_level.txt +0 -0
  135. {annet-0.14.7 → annet-0.14.9}/annet_generators/__init__.py +0 -0
  136. {annet-0.14.7 → annet-0.14.9}/annet_generators/example/__init__.py +0 -0
  137. {annet-0.14.7 → annet-0.14.9}/annet_generators/example/lldp.py +0 -0
  138. {annet-0.14.7 → annet-0.14.9}/requirements.txt +0 -0
  139. {annet-0.14.7 → annet-0.14.9}/setup.cfg +0 -0
  140. {annet-0.14.7 → annet-0.14.9}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: annet
3
- Version: 0.14.7
3
+ Version: 0.14.9
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -25,8 +25,6 @@ def get_hw(manufacturer: str, model: str, platform_name: str):
25
25
  model = model.replace("MSN", "SN", 1)
26
26
  vendor = manufacturer + " " + model
27
27
  hw = HardwareView(_VENDORS.get(vendor.lower(), vendor), platform_name)
28
- if not hw:
29
- raise ValueError(f"unsupported manufacturer {manufacturer}")
30
28
  return hw
31
29
 
32
30
 
@@ -47,13 +45,4 @@ def get_breed(manufacturer: str, model: str):
47
45
  return "adva8"
48
46
  elif manufacturer == "Arista":
49
47
  return "eos4"
50
- raise ValueError(f"unsupported manufacturer {manufacturer}")
51
-
52
-
53
- def is_supported(manufacturer: str) -> bool:
54
- if manufacturer not in (
55
- "Huawei", "Mellanox", "Juniper", "Cisco", "Adva", "Arista",
56
- ):
57
- logger.warning("Unsupported manufacturer `%s`", manufacturer)
58
- return False
59
- return True
48
+ return ""
@@ -2,15 +2,20 @@ from dataclasses import dataclass, field
2
2
  from datetime import datetime
3
3
  from typing import List, Optional, Any, Dict
4
4
 
5
+ from annet.annlib.netdev.views.dump import DumpableView
5
6
  from annet.annlib.netdev.views.hardware import HardwareView
6
7
  from annet.storage import Storage
7
8
 
8
9
 
9
10
  @dataclass
10
- class Entity:
11
+ class Entity(DumpableView):
11
12
  id: int
12
13
  name: str
13
14
 
15
+ @property
16
+ def _dump__list_key(self):
17
+ return self.name
18
+
14
19
 
15
20
  @dataclass
16
21
  class Label:
@@ -32,15 +37,19 @@ class DeviceType:
32
37
 
33
38
 
34
39
  @dataclass
35
- class DeviceIp:
40
+ class DeviceIp(DumpableView):
36
41
  id: int
37
42
  display: str
38
43
  address: str
39
44
  family: int
40
45
 
46
+ @property
47
+ def _dump__list_key(self):
48
+ return self.address
49
+
41
50
 
42
51
  @dataclass
43
- class Prefix:
52
+ class Prefix(DumpableView):
44
53
  id: int
45
54
  prefix: str
46
55
  site: Entity | None
@@ -55,9 +64,13 @@ class Prefix:
55
64
  last_updated: datetime
56
65
  description: str | None = ""
57
66
 
67
+ @property
68
+ def _dump__list_key(self):
69
+ return self.prefix
70
+
58
71
 
59
72
  @dataclass
60
- class IpAddress:
73
+ class IpAddress(DumpableView):
61
74
  id: int
62
75
  assigned_object_id: int
63
76
  display: str
@@ -70,6 +83,10 @@ class IpAddress:
70
83
  prefix: Optional[Prefix] = None
71
84
  vrf: Optional[Entity] = None
72
85
 
86
+ @property
87
+ def _dump__list_key(self):
88
+ return self.address
89
+
73
90
 
74
91
  @dataclass
75
92
  class InterfaceConnectedEndpoint(Entity):
@@ -6,10 +6,11 @@ from annetbox.v24.client_sync import NetboxV24
6
6
 
7
7
  from annet.adapters.netbox.common import models
8
8
  from annet.adapters.netbox.common.manufacturer import (
9
- is_supported, get_hw, get_breed,
9
+ get_hw, get_breed,
10
10
  )
11
11
  from annet.adapters.netbox.common.query import NetboxQuery
12
12
  from annet.adapters.netbox.common.storage_opts import NetboxStorageOpts
13
+ from annet.annlib.netdev.views.hardware import HardwareView
13
14
  from annet.storage import Storage
14
15
 
15
16
  logger = getLogger(__name__)
@@ -162,7 +163,6 @@ class NetboxStorageV24(Storage):
162
163
  device
163
164
  for device in self.netbox.dcim_all_devices().results
164
165
  if _match_query(query, device)
165
- if is_supported(device.device_type.manufacturer.name)
166
166
  ]
167
167
 
168
168
  def _load_interfaces(self, device_ids: List[int]) -> List[
@@ -10,7 +10,7 @@ from annetbox.v37.client_sync import NetboxV37
10
10
 
11
11
  from annet.adapters.netbox.common import models
12
12
  from annet.adapters.netbox.common.manufacturer import (
13
- is_supported, get_hw, get_breed,
13
+ get_hw, get_breed,
14
14
  )
15
15
  from annet.adapters.netbox.common.query import NetboxQuery
16
16
  from annet.adapters.netbox.common.storage_opts import NetboxStorageOpts
@@ -43,20 +43,25 @@ def extend_device(
43
43
  storage: Storage,
44
44
  ) -> models.NetboxDevice:
45
45
  platform_name: str = ""
46
+ breed: str = ""
47
+ hw = HardwareView("", "")
46
48
  if device.platform:
47
49
  platform_name = device.platform.name
48
- res = extend_device_base(
49
- device=device,
50
- interfaces=interfaces,
51
- breed=get_breed(
50
+ if device.device_type and device.device_type.manufacturer:
51
+ breed = get_breed(
52
52
  device.device_type.manufacturer.name,
53
53
  device.device_type.model,
54
- ),
55
- hw=get_hw(
54
+ )
55
+ hw = get_hw(
56
56
  device.device_type.manufacturer.name,
57
57
  device.device_type.model,
58
58
  platform_name,
59
- ),
59
+ )
60
+ res = extend_device_base(
61
+ device=device,
62
+ interfaces=interfaces,
63
+ breed=breed,
64
+ hw=hw,
60
65
  storage=storage,
61
66
  )
62
67
  res.neighbours = neighbours
@@ -146,7 +151,6 @@ class NetboxStorageV37(Storage):
146
151
  name__ic=query.globs,
147
152
  ).results
148
153
  if _match_query(query, device)
149
- if is_supported(device.device_type.manufacturer.name)
150
154
  ]
151
155
 
152
156
  def _extend_interfaces(self, interfaces: List[models.Interface]) -> List[models.Interface]:
@@ -73,6 +73,14 @@ class DumpableView:
73
73
 
74
74
  if isinstance(value, DumpableView):
75
75
  ret += value.dump(prefix, seen=seen) # pylint: disable=no-member
76
+ elif isinstance(value, dict):
77
+ for k, v in value.items():
78
+ ret.extend(self.__dump_value(f"{prefix}[{repr(k)}]", v, seen))
79
+ elif isinstance(value, (list, tuple)):
80
+ for i, v in enumerate(value):
81
+ name = getattr(v, "_dump__list_key", None)
82
+ name = repr(name) if name is not None else str(i)
83
+ ret.extend(self.__dump_value(f"{prefix}[{name}]", v, seen))
76
84
  else:
77
85
  fmt = repr(value)
78
86
  vtype = type(value)
@@ -370,7 +370,7 @@ class ArgParser(argparse.ArgumentParser):
370
370
  yield from _get_meta(func).opts
371
371
 
372
372
 
373
- def subcommand(*arg_list: Union[Arg, Type[ArgGroup]], parent: Callable = None):
373
+ def subcommand(*arg_list: Union[Arg, Type[ArgGroup]], parent: Callable = None, is_group: bool = False):
374
374
  """
375
375
  декоратор, задающий cli-аргументы подпрограммы
376
376
 
@@ -382,7 +382,7 @@ def subcommand(*arg_list: Union[Arg, Type[ArgGroup]], parent: Callable = None):
382
382
  Связь аргументов происходит только по порядковому номеру, каждый аргумент subcommand становится аргументом функции.
383
383
  Функция вызывается только с позиционными аргументами, всегда с одним и тем же количеством аргументов.
384
384
 
385
- Для создания более одного уровня команд используeтся агрумент parent
385
+ Для создания более одного уровня команд используется аргумент parent
386
386
 
387
387
  Пример: 'ann some thing' - вызовет some_thing()
388
388
 
@@ -397,6 +397,10 @@ def subcommand(*arg_list: Union[Arg, Type[ArgGroup]], parent: Callable = None):
397
397
  """
398
398
  def _amend_func(func):
399
399
  meta = _get_meta(func)
400
+ if is_group:
401
+ @functools.wraps(func)
402
+ def func():
403
+ meta.parser.print_help()
400
404
  cmd_name = func.__name__
401
405
  if parent:
402
406
  parentprefix = parent.__name__ + "_"
@@ -70,9 +70,15 @@ def get_loader(gen_args: cli_args.GenOptions, args: cli_args.QueryOptions):
70
70
  yield Loader(*storages, args=gen_args)
71
71
 
72
72
 
73
- @subcommand(cli_args.QueryOptions, cli_args.opt_config, cli_args.FileOutOptions)
73
+ @subcommand(is_group=True)
74
+ def show():
75
+ """ A group of commands for showing parameters/configurations/data from deivces and data sources """
76
+ pass
77
+
78
+
79
+ @subcommand(cli_args.QueryOptions, cli_args.opt_config, cli_args.FileOutOptions, parent=show)
74
80
  def show_current(args: cli_args.QueryOptions, config, arg_out: cli_args.FileOutOptions) -> None:
75
- """ Показать текущий конфиг устройств """
81
+ """ Show current devices' configuration """
76
82
  gen_args = cli_args.GenOptions(args, no_acl=True)
77
83
  output_driver = output_driver_connector.get()
78
84
  with get_loader(gen_args, args) as loader:
@@ -89,9 +95,34 @@ def show_current(args: cli_args.QueryOptions, config, arg_out: cli_args.FileOutO
89
95
  output_driver.write_output(arg_out, items, len(loader.devices))
90
96
 
91
97
 
98
+ @subcommand(cli_args.QueryOptions, cli_args.FileOutOptions, parent=show)
99
+ def show_device_dump(args: cli_args.QueryOptions, arg_out: cli_args.FileOutOptions):
100
+ """ Show a dump of network devices' structure """
101
+ def _show_device_dump_items(devices):
102
+ for device in devices:
103
+ get_logger(host=device.hostname) # add hostname into context
104
+ if hasattr(device, "dump"):
105
+ yield (
106
+ device.hostname,
107
+ "\n".join(device.dump("device")),
108
+ False,
109
+ )
110
+ else:
111
+ get_logger().warning("method `dump` not implemented for %s", type(device))
112
+ arg_gens = cli_args.GenOptions(arg_out, args)
113
+ with get_loader(arg_gens, args) as loader:
114
+ if not loader.devices:
115
+ get_logger().error("No devices found for %s", args.query)
116
+ output_driver_connector.get().write_output(
117
+ arg_out,
118
+ _show_device_dump_items(loader.devices),
119
+ len(loader.device_ids),
120
+ )
121
+
122
+
92
123
  @subcommand(cli_args.ShowGenOptions)
93
124
  def gen(args: cli_args.ShowGenOptions):
94
- """ Сгенерировать конфиг для устройств """
125
+ """ Generate configuration for devices """
95
126
  with get_loader(args, args) as loader:
96
127
  (success, fail) = api.gen(args, loader)
97
128
 
@@ -110,7 +141,7 @@ def gen(args: cli_args.ShowGenOptions):
110
141
 
111
142
  @subcommand(cli_args.ShowDiffOptions)
112
143
  def diff(args: cli_args.ShowDiffOptions):
113
- """ Сгенерировать конфиг для устройств и показать дифф по рулбуку с текущим """
144
+ """ Generate configuration for devices and show a diff with current configuration using the rulebook """
114
145
  with get_loader(args, args) as loader:
115
146
  filterer = filtering.filterer_connector.get()
116
147
  device_ids = loader.device_ids
@@ -123,7 +154,7 @@ def diff(args: cli_args.ShowDiffOptions):
123
154
 
124
155
  @subcommand(cli_args.ShowPatchOptions)
125
156
  def patch(args: cli_args.ShowPatchOptions):
126
- """ Сгенерировать конфиг для устройств и сформировать патч """
157
+ """ Generate configuration patch for devices """
127
158
  with get_loader(args, args) as loader:
128
159
  (success, fail) = api.patch(args, loader)
129
160
 
@@ -138,7 +169,7 @@ def patch(args: cli_args.ShowPatchOptions):
138
169
 
139
170
  @subcommand(cli_args.DeployOptions)
140
171
  def deploy(args: cli_args.DeployOptions):
141
- """ Сгенерировать конфиг для устройств и задеплоить его """
172
+ """ Generate and deploy configuration for devices """
142
173
 
143
174
  deployer = Deployer(args)
144
175
  filterer = filtering.filterer_connector.get()
@@ -155,7 +186,7 @@ def deploy(args: cli_args.DeployOptions):
155
186
 
156
187
  @subcommand(cli_args.FileDiffOptions)
157
188
  def file_diff(args: cli_args.FileDiffOptions):
158
- """ Показать дифф по рулбуку между файлами или каталогами """
189
+ """ Generate a diff between files or directories using the rulebook """
159
190
  (success, fail) = api.file_diff(args)
160
191
  out = []
161
192
  output_driver = output_driver_connector.get()
@@ -168,7 +199,7 @@ def file_diff(args: cli_args.FileDiffOptions):
168
199
 
169
200
  @subcommand(cli_args.FilePatchOptions)
170
201
  def file_patch(args: cli_args.FilePatchOptions):
171
- """ Сформировать патч для файлов или каталогов """
202
+ """ Generate configuration patch for files or directories """
172
203
  (success, fail) = api.file_patch(args)
173
204
  out = []
174
205
  output_driver = output_driver_connector.get()
@@ -178,26 +209,27 @@ def file_patch(args: cli_args.FilePatchOptions):
178
209
  output_driver.write_output(args, out, len(out))
179
210
 
180
211
 
181
- @subcommand()
212
+ @subcommand(is_group=True)
182
213
  def context():
183
- """ Операции для управления файлом контекста.
214
+ """ A group of commands for manipulating context.
184
215
 
185
- По-умолчанию находится в '~/.annushka/context.yml', либо по пути в переменной окружения ANN_CONTEXT_CONFIG_PATH.
216
+ By default, the context file is located in '~/.annushka/context.yml',
217
+ but it can be set with the ANN_CONTEXT_CONFIG_PATH environment variable.
186
218
  """
187
219
  context_touch()
188
220
 
189
221
 
190
222
  @subcommand(parent=context)
191
223
  def context_touch():
192
- """ Вывести путь к файлу контекста и, при отсутствии, создать его и наполнить данными (команда по-умолчанию) """
224
+ """ Show the context file path, and if the file is not present, create it with the default configuration """
193
225
  print(get_context_path(touch=True))
194
226
 
195
227
 
196
228
  @subcommand(cli_args.SelectContext, parent=context)
197
229
  def context_set_context(args: cli_args.SelectContext):
198
- """ Задать текущий активный контекст по имени в конфигурации
230
+ """ Set the current active context.
199
231
 
200
- Выбранный контекст будет использоваться по-умолчанию при незаданной переменной окружения ANN_SELECTED_CONTEXT
232
+ The selected context is used by default unless the environment variable ANN_SELECTED_CONTEXT is set
201
233
  """
202
234
  with open(path := get_context_path(touch=True)) as f:
203
235
  data = yaml.safe_load(f)
@@ -211,12 +243,10 @@ def context_set_context(args: cli_args.SelectContext):
211
243
 
212
244
  @subcommand(parent=context)
213
245
  def context_edit():
214
- """ Открыть файл конфигурации контекста в редакторе из переменной окружения EDITOR
246
+ """ Open the context file using an editor from the EDITOR environment variable.
215
247
 
216
- Если переменная окружения EDITOR не задана,
217
- для Windows пытаемся открыть файл средствами ОС, для остальных случаев пытаемся открыть в vi
248
+ If the EDITOR variable is not set, default variables are: "notepad.exe" for Windows and "vi" otherwise
218
249
  """
219
- editor = ""
220
250
  if e := os.getenv("EDITOR"):
221
251
  editor = e
222
252
  elif platform.system() == "Windows":
@@ -232,5 +262,5 @@ def context_edit():
232
262
 
233
263
  @subcommand(parent=context)
234
264
  def context_repair():
235
- """ Попытаться исправить расхождения в формате файла контекста после изменении версии """
265
+ """ Try to fix the context file's structure if it was generated for the older versions of annet """
236
266
  repair_context_file()