annet 0.14.7__py3-none-any.whl → 0.14.9__py3-none-any.whl

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.

@@ -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)
annet/argparse.py CHANGED
@@ -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__ + "_"
annet/cli.py CHANGED
@@ -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()
annet/cli_args.py CHANGED
@@ -49,8 +49,7 @@ def valid_range(value: str):
49
49
  def opt_query_factory(**kwargs):
50
50
  return Arg(
51
51
  "query",
52
- help="Запрос, определяющий список устройств. Принимается fqdn, rackcode, глоб"
53
- " или путь к файлу со списком запросов (нужно писать @path/to/file)",
52
+ help="A query that defines a list of devices. The query's format depends on a selected storage adapter",
54
53
  **kwargs,
55
54
  )
56
55
 
@@ -62,47 +61,47 @@ opt_query_optional = opt_query_factory(nargs="*", default=[])
62
61
 
63
62
  opt_dest = Arg(
64
63
  "--dest", type=convert_to_none,
65
- help="Файл или каталог для вывода сгенерированных данных"
64
+ help="A file or a directory to output the generated data to"
66
65
  )
67
66
 
68
67
  opt_expand_path = Arg(
69
68
  "--expand-path", default=False,
70
- help="Разворачивать пути entire-генераторов при записи их на файловую систему"
69
+ help="Use full paths of Entire-generators and no just names when writing them to the file system"
71
70
  )
72
71
 
73
72
  opt_old = Arg(
74
73
  "old",
75
- help="Файл со старым конфигом (или каталог с пачкой)"
74
+ help="A path to a file (or a directory with a batch of files) that contains the old config"
76
75
  )
77
76
 
78
77
  opt_new = Arg(
79
78
  "new",
80
- help="Файл с новым конфигом (или каталог с пачкой)"
79
+ help="A path to a file (or a directory with a batch of files) that contains the new config"
81
80
  )
82
81
 
83
82
  opt_hw = Arg(
84
83
  "--hw", default="", type=valid_vendor,
85
- help="Производитель устройства (например Huawei или Cisco) или полное название модели. Если его нет - пытаемся его задетектить"
84
+ help="Device's vendor (Huawei/Cisco/...) or model name. If left empty, annet will try to detect it automatically"
86
85
  )
87
86
 
88
87
  opt_indent = Arg(
89
88
  "--indent", default=" ",
90
- help="Отступ при форматировании блоков"
89
+ help="Symbols to indent blocks with"
91
90
  )
92
91
 
93
92
  opt_allowed_gens = Arg(
94
93
  "-g", "--allowed-gens", type=valid_string_list,
95
- help="Список классов генераторов через запятую, которые нужно запустить"
94
+ help="Comma-separated list of generator classes or tags to run"
96
95
  )
97
96
 
98
97
  opt_excluded_gens = Arg(
99
98
  "-G", "--excluded-gens", type=valid_string_list,
100
- help="Список классов генераторов через запятую, запуск которых следует исключить"
99
+ help="Comma-separated list of generator classes or tags to skip"
101
100
  )
102
101
 
103
102
  opt_force_enabled = Arg(
104
103
  "--force-enabled", type=valid_string_list,
105
- help="Список классов генераторов через запятую, которые не нужно считать DISABLED даже при наличии тега"
104
+ help="Comma-separated list of generator classes or tags, for which the DISABLED tag should be ignored"
106
105
  )
107
106
 
108
107
  opt_generators_context = Arg(
@@ -112,27 +111,27 @@ opt_generators_context = Arg(
112
111
 
113
112
  opt_no_acl = Arg(
114
113
  "--no-acl", default=False,
115
- help="Отключение ACL при генерации"
114
+ help="Disable ACL for config generation"
116
115
  )
117
116
 
118
117
  opt_no_acl_exclusive = Arg(
119
118
  "--no-acl-exclusive", default=False,
120
- help="Проверяем что ACL выполненных генераторов не пересекаются"
119
+ help="Check that ACLs of the executed generators do not intersect"
121
120
  )
122
121
 
123
122
  opt_acl_safe = Arg(
124
123
  "--acl-safe", default=False,
125
- help="Использовать более строгий safe acl для фильтрации результата генерации"
124
+ help="Use stricter safe acl for filtering generation results"
126
125
  )
127
126
 
128
127
  opt_show_rules = Arg(
129
128
  "--show-rules", default=False,
130
- help="Показывать правила rulebook при выводе диффа"
129
+ help="Show rulebook rules when showing the diff"
131
130
  )
132
131
 
133
132
  opt_tolerate_fails = Arg(
134
133
  "--tolerate-fails", default=False,
135
- help="Рапортовать об ошибках без остановки генерации"
134
+ help="Show errors without interrupting the generation"
136
135
  )
137
136
 
138
137
  # При параллельном запуске и включённом --tolerate-fails код возврата
@@ -147,136 +146,135 @@ opt_strict_exit_code = Arg(
147
146
 
148
147
  opt_required_packages_check = Arg(
149
148
  "--required-packages-check", default=False,
150
- help="Включить проверку наличия установленных deb-пакетов для Entire-генераторов"
149
+ help="Check that the deb-packages, required for the Entire-generators, are installed"
151
150
  )
152
151
 
153
152
  opt_profile = Arg(
154
153
  "--profile", default=False,
155
- help="Показать в stderr время, затраченное на работу генераторов и обращениям к RackTables"
154
+ help="Print time spent by generators and inventory requests to stderr"
156
155
  )
157
156
 
158
157
 
159
158
  opt_parallel = Arg(
160
159
  "-P", "--parallel", type=int, default=1,
161
- help="Количество одновременных потоков генерирования"
160
+ help="An amount of threads/processes to use as defined in a configured connector"
162
161
  )
163
162
 
164
163
  opt_max_tasks = Arg(
165
164
  "--max-tasks", type=int, default=None,
166
- help="Рестартовать воркеры каждые N устройств, для сброса кеша и ограничения потребления памяти"
167
- "По умолчанию - не рестартовать"
165
+ help="Maximum consecutive tasks to run in a worker before restarting it to clear memory and cache. "
166
+ "Defaults to infinity"
168
167
  )
169
168
 
170
169
  opt_annotate = Arg(
171
170
  "--annotate", default=False,
172
- help="Добавить к сгенерированному конфигу комментарии о том откуда строчка взялась"
171
+ help="Annotate configuration lines to show their sources"
173
172
  )
174
173
 
175
174
  opt_config = Arg(
176
175
  "--config", default="running", type=valid_config_source,
177
- help="'running', 'empty', путь к файлу конфига, "
178
- "каталогу с файлами конфига в формате <hostname>.cfg "
179
- "или '-' (stdin)"
176
+ help="'running', 'empty', path to a config file or "
177
+ "a directory with config files <hostname>.cfg "
178
+ "or '-' (stdin)"
180
179
  )
181
180
 
182
181
  opt_clear = Arg(
183
182
  "--clear", default=False,
184
- help="Используя acl вычищает команды относящиеся к данному генератору, "
185
- "аналогично использованию return в самом начале генератора"
183
+ help="Remove the generator's commands using its ACL "
186
184
  )
187
185
 
188
186
  opt_filter_acl = Arg(
189
187
  "--filter-acl", default="",
190
- help="путь к файлу с дополнительным фильтрующим acl, или '-' (stdin)"
188
+ help="Additional ACL file path or '-' (stdin)"
191
189
  )
192
190
 
193
191
  opt_filter_ifaces = Arg(
194
192
  "-i", "--filter-ifaces", default=[], type=valid_string_list,
195
- help="Генерирует filter-acl по имени интерфейса. "
196
- "Принимает регекспы, через запятую: '-i 10GE,100GE'. "
197
- "По-умолчанию добавляет '.*' к концу каждого. "
198
- "Для указания имени точно, следует добавлять '$': '-i ae0$'. "
199
- "Если filter-acl передан напрямую, данная опция игнорируется."
193
+ help="Additional filter-acl using interface name. "
194
+ "Accepts comma-separated regular expressions: '-i 10GE,100GE'. "
195
+ "Appends '.*' at the end of every item "
196
+ "One can use '$' for an exact match: '-i ae0$'. "
197
+ "If filter-acl is passed directly, this option is ignored."
200
198
  )
201
199
 
202
200
  opt_filter_peers = Arg(
203
201
  "-fp", "--filter-peers", default=[], type=valid_string_list,
204
- help="Генерирует filter-acl по адресу/имени группы/дескрипшену пира."
202
+ help="Generates filter-acl using an address or name of a peer's group or description."
205
203
  )
206
204
 
207
205
  opt_filter_policies = Arg(
208
206
  "-frp", "--filter-policies", default=[], type=valid_string_list,
209
- help="Генерирует filter-acl по названию политик, название должно строго соответствовать, частичные имена не пройдут"
207
+ help="Generates filter-acl using policies' names. The match has to be exact"
210
208
  )
211
209
 
212
210
  opt_ask_pass = Arg(
213
211
  "--ask-pass", default=False,
214
- help="Спросить пароль на подключение"
212
+ help="Ask for a password when connecting"
215
213
  )
216
214
 
217
215
  opt_no_ask_deploy = Arg(
218
216
  "--no-ask-deploy", default=False,
219
- help="Не подтвеждать команды перед выполнением"
217
+ help="Do not ask for confirmation on commands execution"
220
218
  )
221
219
 
222
220
  opt_no_progress = Arg(
223
221
  "--no-progress", default=False,
224
- help="Выключить графику прогресс баров комокутора"
222
+ help="Do not show deployment progress bars"
225
223
  )
226
224
 
227
225
  opt_log_json = Arg(
228
226
  "--log-json", default=False,
229
- help="Логгировать в формате json (default: plain text)"
227
+ help="Show logs in json format (default: plain text)"
230
228
  )
231
229
 
232
230
  opt_log_dest = Arg(
233
231
  "--log-dest", default="deploy/",
234
- help="Логгировать в указанный файл/директорию, или в stdout, если указать '-'"
232
+ help="Log to a specified file, directory, or '-' (stdout)"
235
233
  )
236
234
 
237
235
  opt_log_nogroup = Arg(
238
236
  "--log-nogroup", default=False,
239
- help="Не создавать в директории LOG-DEST поддиректории DATE_TIME/"
237
+ help="Do not create DATE_TIME/ subdirectories in the LOG-DEST directory"
240
238
  )
241
239
 
242
240
  opt_max_slots = Arg(
243
241
  "--max-slots", default=30, type=int,
244
- help="Количество одновременно обрабатываемых asyncio устройств"
242
+ help="The amount of devices parsed at the same time with asyncio"
245
243
  )
246
244
 
247
245
  opt_hosts_range = Arg(
248
246
  "--hosts-range", type=valid_range,
249
- help="Обработать только указанный диапазон хостов. 10 - первые 10. 10:20 - хосты с 10-го по 20-ый"
247
+ help="Only work with the specified hosts range: 10 - the first 10. 10:20 - host from 10th up to 20th"
250
248
  )
251
249
 
252
250
  opt_add_comments = Arg(
253
251
  "--add-comments", default=False,
254
- help="Добавлять комменты подтверждения для rbprocess"
252
+ help=argparse.SUPPRESS,
255
253
  )
256
254
 
257
255
  opt_no_label = Arg(
258
256
  "--no-label", default=False,
259
- help="Убрать лейбл с именем файла из вывода"
257
+ help="Hide the file name label from the output"
260
258
  )
261
259
 
262
260
  opt_no_color = Arg(
263
261
  "--no-color", default=False,
264
- help="Не делать ANSI-раскраску вывода (при --dest включён)"
262
+ help="Do not use the output ANSI-coloring (turns on when using --dest)"
265
263
  )
266
264
 
267
265
  opt_no_check_diff = Arg(
268
266
  "--no-check-diff", default=False,
269
- help="не запрашивать дифф после деплоя"
267
+ help="Don't check diffs after deploying"
270
268
  )
271
269
 
272
270
  opt_dont_commit = Arg(
273
271
  "--dont-commit", default=False,
274
- help="не добавлять команду commit во время деплоя"
272
+ help="Do not run the 'commit' command during a deploy"
275
273
  )
276
274
 
277
275
  opt_rollback = Arg(
278
276
  "--rollback", default=False,
279
- help="предложить откат после деплоя где это возможно"
277
+ help="Suggest a rollback after a deployment if possible"
280
278
  )
281
279
 
282
280
  opt_fail_on_empty_config = Arg(
@@ -287,7 +285,7 @@ opt_fail_on_empty_config = Arg(
287
285
 
288
286
  opt_show_generators_format = Arg(
289
287
  "--format", default="text", choices=["text", "json"],
290
- help="Формат выдачи"
288
+ help="Output format"
291
289
  )
292
290
 
293
291
 
@@ -312,18 +310,18 @@ opt_entire_reload = Arg(
312
310
  choices=list(EntireReloadFlag),
313
311
  const=EntireReloadFlag.yes,
314
312
  nargs="?",
315
- help="Выполнить reload() при deploy'e entire генераторов. "
316
- "no/yes/force - нет/только если файл изменился/даже если не изменился"
313
+ help="Run reload() when deploying the Entire-generators. "
314
+ "no/yes/force - no/if the file was changed/always"
317
315
  )
318
316
 
319
317
  opt_show_hosts_progress = Arg(
320
318
  "--show-hosts-progress", default=False,
321
- help="Показывать проценты выполнения по хостам"
319
+ help="Show the progress percentage per host"
322
320
  )
323
321
 
324
322
  opt_no_collapse = Arg(
325
323
  "--no-collapse", default=False,
326
- help="Не схлопывать одинаковые diff для группы устройств (при --dest включён)"
324
+ help="Do not collapse identical diffs for a device group (turns on when using --dest)"
327
325
  )
328
326
 
329
327
  opt_fails_only = Arg(
@@ -333,12 +331,12 @@ opt_fails_only = Arg(
333
331
 
334
332
  opt_connect_timeout = Arg(
335
333
  "--connect-timeout", default=DefaultFromEnv("ANN_CONNECT_TIMEOUT", "20.0"), type=float,
336
- help="Таймаут на подключение к устройству в секундах."
337
- " Значение по-умолчанию можно задать в переменной окружения ANN_CONNECT_TIMEOUT"
334
+ help="Timeout for connecting to a device, in seconds."
335
+ " The default value can be set in the ANN_CONNECT_TIMEOUT environment variable."
338
336
  )
339
337
 
340
338
  opt_selected_context_name = Arg(
341
- "context-name", type=str, help="Имя контекста в файле конфигурации"
339
+ "context-name", type=str, help="Name of a context from the context file to use"
342
340
  )
343
341
 
344
342
 
annet/executor.py CHANGED
@@ -16,11 +16,7 @@ from typing import Any, Callable, Dict, List, Optional, Tuple, Union
16
16
  import colorama
17
17
  import psutil
18
18
  from annet.annlib.command import Command, CommandList, Question # noqa: F401
19
-
20
- try:
21
- from annet.storage import Device
22
- except ImportError:
23
- from noc.annushka.annet.storage import Device # noqa: F401
19
+ from annet.storage import Device
24
20
 
25
21
 
26
22
  _logger = logging.getLogger(__name__)
@@ -1,12 +1,7 @@
1
1
  # pylint: disable=unused-argument
2
2
 
3
3
  from annet.annlib.types import Op
4
-
5
-
6
- try:
7
- from annet.executor import CommandList, Command
8
- except ImportError:
9
- from noc.annushka.annet.executor import CommandList, Command
4
+ from annet.executor import CommandList, Command
10
5
 
11
6
 
12
7
  def apply(hw, do_commit, do_finalize, **_):
annet/storage.py CHANGED
@@ -69,7 +69,7 @@ class Storage(abc.ABC):
69
69
  class StorageOpts(abc.ABC):
70
70
  @classmethod
71
71
  @abc.abstractmethod
72
- def parse_params(cls, conf_params: Dict[str, str] | None, cli_opts: Any):
72
+ def parse_params(cls, conf_params: Optional[Dict[str, str]], cli_opts: Any):
73
73
  pass
74
74
 
75
75
 
@@ -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
@@ -1,12 +1,12 @@
1
1
  annet/__init__.py,sha256=oyElxAW97sHgQccGafhaWVBveBn1gSjjdP_xHROaRLg,2139
2
2
  annet/annet.py,sha256=TMdEuM7GJQ4TjRVmuK3bCTZN-21lxjQ9sXqEdILUuBk,725
3
- annet/argparse.py,sha256=MoBD0LPnHdA6HU7z1uQNArYlkD92znoeGIFTMnS4dRM,12608
4
- annet/cli.py,sha256=MxdH5m4r2MfXYwCbgSDUqjSibxw7VzSg7_hsB47RWnw,9601
5
- annet/cli_args.py,sha256=1RZ_Sy5oSiiUNzf4FIefvUa_s-JsR8IYd-SvN7apocw,15823
3
+ annet/argparse.py,sha256=ZHKQriVCysSnox5stZnYxKLaPKzDjXbShxFyNW6LiiQ,12754
4
+ annet/cli.py,sha256=aFFloyl5k2vz8mnm8Q2iwjAOUi4PTFWoVT9JszTkmHo,9969
5
+ annet/cli_args.py,sha256=_Du9Jhe86F4fsx7u9njjvg25jTdoBsdbTEzbuDFgrFU,13248
6
6
  annet/connectors.py,sha256=Xgr7fNopRhFAYnkiDxhohBtjlFOLY8v0xLExHmVMr00,2511
7
7
  annet/deploy.py,sha256=B8E0P_VvCrS2URjFvgmUiIkHp95g7pAWfmT34igaDeo,18893
8
8
  annet/diff.py,sha256=zLcaCnb4lZRUb7frpH1CstQ3kacRcCblZs1uLG8J5lk,3391
9
- annet/executor.py,sha256=EaeQ_JeRFuUUHUoR2LXDcNvY7IVg0eA2d6zSmQVJt-M,19216
9
+ annet/executor.py,sha256=FrYAUuh2TpSVX42SlTN_PhuSHmXG4Wj1nieY9Wqv9so,19122
10
10
  annet/filtering.py,sha256=F4ZKUCU3Yb1RlL2zKdyHtVUaWPzjWF4vWyMcdygKNYk,852
11
11
  annet/gen.py,sha256=jlAkT_phlIYrpOIqVc0GrApWp3Y8zr8lyxnZgIdL2F4,33533
12
12
  annet/hardware.py,sha256=HYPDfji_GdRn5S0_0fl4rvM7byOY9aHxG6VMAtsLaxE,1090
@@ -16,7 +16,7 @@ annet/output.py,sha256=hJNGzL4Z3KgvqaCBkkmuuiXPhb64F1QV8YHkwnfhaaI,6852
16
16
  annet/parallel.py,sha256=hLkzEht0KhzmzUWDdO4QFYQHzhxs3wPlTA8DxbB2ziw,17160
17
17
  annet/patching.py,sha256=nILbY5oJajN0b1j3f0HEJm05H3HVThnWvB7vDVh7UQw,559
18
18
  annet/reference.py,sha256=B8mH8VUMcecPnzULiTVb_kTQ7jQrCL7zp4pfIZQa5fk,4035
19
- annet/storage.py,sha256=BMZPOPrWGyMNmzUl9CJfv8m15xciajGesHcRv9zUaV8,3092
19
+ annet/storage.py,sha256=-l64yc0UfGR7Aqb3GlW18Kg1SJgIF1k6cf7-Ca4MhBc,3095
20
20
  annet/tabparser.py,sha256=ZjiI43ZVbrpMVR8qNbTbNh_U3oZ26VDc_2Y9wkkDkYA,874
21
21
  annet/text_term_format.py,sha256=CHb6viv45vmYl-SK1A1vyPHGhaEni6jVybBusaQnct8,2813
22
22
  annet/tracing.py,sha256=ndpM-au1c88uBBpOuH_z52qWZL773edYozNyys_wA68,4044
@@ -26,15 +26,15 @@ annet/adapters/netbox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
26
26
  annet/adapters/netbox/provider.py,sha256=Gymku2Ad7um4GR9MqzQzm2o2cBLHLhIYbF1Ytl0r0MA,1076
27
27
  annet/adapters/netbox/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  annet/adapters/netbox/common/client.py,sha256=-lWZmphD-OPuLIHNKhW_h2bnjrVaiyKYAD_MUPasEbo,2483
29
- annet/adapters/netbox/common/manufacturer.py,sha256=van_-9-3cnBadZkF3Srae_m8cUSjf8KQCCCHFcdeQyo,1758
30
- annet/adapters/netbox/common/models.py,sha256=bJP6lIWFB85AW5gLNyfd0VHeqEtYIdLJcNH9r8cb8RI,2859
29
+ annet/adapters/netbox/common/manufacturer.py,sha256=i-1mXQheS4ORZav1_xYxMuGBWVWQHolZYkEXNdGyf0g,1361
30
+ annet/adapters/netbox/common/models.py,sha256=Vgxbl_Mm-zOAi2BTlEzDppTTgZjafFEC5F9s_MTd_xU,3263
31
31
  annet/adapters/netbox/common/query.py,sha256=OgUuF-bvshpoBUkrOs0tsMUAhjTsttzx3VV30ryFl0Y,577
32
32
  annet/adapters/netbox/common/status_client.py,sha256=W4nTb2yvBlJ2UkWUmUhKQ2PaSQb1shjhHj5ebb4s2s4,591
33
33
  annet/adapters/netbox/common/storage_opts.py,sha256=idOm1na_2Axdi4MdLN4tAsPvsp5zBtJYD9j7cUiI-W8,400
34
34
  annet/adapters/netbox/v24/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
- annet/adapters/netbox/v24/storage.py,sha256=ogCu5XXIpcpPtuz7dWfDFIbqtz8k5G96PL6mhAQWwBU,6026
35
+ annet/adapters/netbox/v24/storage.py,sha256=THI592VLx3ehixsPZQ1Ko3mYIAZQbnDY-toIziqBbL8,6005
36
36
  annet/adapters/netbox/v37/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
- annet/adapters/netbox/v37/storage.py,sha256=plqHzb_jH0Etagmg3K8lmNw5hOWUocoSZtAPBlnnOQY,7524
37
+ annet/adapters/netbox/v37/storage.py,sha256=z0WCVApf7vHL6bxLiF_f6FVo6AVm_hZuiMib4dDJt0w,7595
38
38
  annet/annlib/__init__.py,sha256=fT1l4xV5fqqg8HPw9HqmZVN2qwS8i6X1aIm2zGDjxKY,252
39
39
  annet/annlib/command.py,sha256=uuBddMQphtn8P5MO5kzIa8_QrtMns-k05VeKv1bcAuA,1043
40
40
  annet/annlib/diff.py,sha256=UPt3kYFQdQdVVy3ePYzNHPAxMVmHxCrCnZnMCV6ou2Q,4587
@@ -51,7 +51,7 @@ annet/annlib/netdev/db.py,sha256=fI_u5aya4l61mbYSjj4JwlVfi3s7obt2jqERSuXGRUI,163
51
51
  annet/annlib/netdev/devdb/__init__.py,sha256=aKYjjLbJebdKBjnGDpVLQdSqrV2JL24spGm58tmMWVU,892
52
52
  annet/annlib/netdev/devdb/data/devdb.json,sha256=8U-2p2yCE6jHdBehASiQoQdJ7c2_Hc9SFGefNLaGiBo,5287
53
53
  annet/annlib/netdev/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
- annet/annlib/netdev/views/dump.py,sha256=XJ6UO6sYSO5pIoe5R4eTQmKwx0_JJ71_h8QSYAURtyk,4184
54
+ annet/annlib/netdev/views/dump.py,sha256=rIlyvnA3uM8bB_7oq1nS2KDxTp6dQh2hz-FbNhYIpOU,4630
55
55
  annet/annlib/netdev/views/hardware.py,sha256=o-w-k1bOORWwEnSGsDq-9Q_oIeH3yQv9eiCJn_UgG-Y,3324
56
56
  annet/annlib/rbparser/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
57
  annet/annlib/rbparser/acl.py,sha256=RR8yPt6t96_IiyuKVbeZ-3x32cyhBAT2wC1y99oWBO8,3931
@@ -82,7 +82,7 @@ annet/rulebook/patching.py,sha256=ve_D-9lnWs6Qb_NwqOLUWX-b_tI_L3pwQ7cgUPnqndY,49
82
82
  annet/rulebook/arista/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
83
83
  annet/rulebook/arista/iface.py,sha256=bgj6a3r__-OE6VyYbSfnD6ps2QJKyX028W7IFJww-UY,720
84
84
  annet/rulebook/aruba/__init__.py,sha256=ILggeID6kNWcDBGzhXm_mebcfkuLSq5prBFU5DyPFs4,500
85
- annet/rulebook/aruba/ap_env.py,sha256=GO97lbMju82MqUUBf76OWiFBjnnF3OOVqsGcJ5jn-0c,4788
85
+ annet/rulebook/aruba/ap_env.py,sha256=5fUVLhXH4-0DAtv8t0yoqJUibaRMuzF8Q7mGFzNsEN8,4692
86
86
  annet/rulebook/aruba/misc.py,sha256=O0p_wsR07gtB8rm1eJvJ7VYnGm5T8Uau_SVKR9FVInI,234
87
87
  annet/rulebook/cisco/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
88
88
  annet/rulebook/cisco/iface.py,sha256=WISkzjp_G7WKPpg098FCIm4b7ipOxtRLOQbu-7gMUL0,1792
@@ -124,10 +124,10 @@ annet/rulebook/texts/routeros.rul,sha256=ipfxjj0mjFef6IsUlupqx4BY_Je_OUb8u_U1019
124
124
  annet_generators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
125
125
  annet_generators/example/__init__.py,sha256=zVd8_DrXuOASrNzg2Ab94rPyvJff83L-_HppDFxnUjM,228
126
126
  annet_generators/example/lldp.py,sha256=68CLrK7vxTQQy9XIBxtywuEdBNlIlfXGYj8_wYWs5UI,1146
127
- annet-0.14.7.dist-info/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
128
- annet-0.14.7.dist-info/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
129
- annet-0.14.7.dist-info/METADATA,sha256=A6QRaGcStR1_xxiKBk1tkpjoFUgY0uohpBY_eU7Vav4,694
130
- annet-0.14.7.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
131
- annet-0.14.7.dist-info/entry_points.txt,sha256=yHimujIzR2bwNIbb--MTs_GpXiAve89Egpu2LlgTEkg,119
132
- annet-0.14.7.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
133
- annet-0.14.7.dist-info/RECORD,,
127
+ annet-0.14.9.dist-info/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
128
+ annet-0.14.9.dist-info/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
129
+ annet-0.14.9.dist-info/METADATA,sha256=8qSsN16lENPe9EcC4dGlPk2hN8JDX690OlbbBaoQ_pE,694
130
+ annet-0.14.9.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
131
+ annet-0.14.9.dist-info/entry_points.txt,sha256=yHimujIzR2bwNIbb--MTs_GpXiAve89Egpu2LlgTEkg,119
132
+ annet-0.14.9.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
133
+ annet-0.14.9.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.2.0)
2
+ Generator: setuptools (73.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5