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.
- annet/adapters/netbox/common/manufacturer.py +1 -12
- annet/adapters/netbox/common/models.py +21 -4
- annet/adapters/netbox/v24/storage.py +2 -2
- annet/adapters/netbox/v37/storage.py +13 -9
- annet/annlib/netdev/views/dump.py +8 -0
- annet/argparse.py +6 -2
- annet/cli.py +49 -19
- annet/cli_args.py +55 -57
- annet/executor.py +1 -5
- annet/rulebook/aruba/ap_env.py +1 -6
- annet/storage.py +1 -1
- {annet-0.14.7.dist-info → annet-0.14.9.dist-info}/METADATA +1 -1
- {annet-0.14.7.dist-info → annet-0.14.9.dist-info}/RECORD +18 -18
- {annet-0.14.7.dist-info → annet-0.14.9.dist-info}/WHEEL +1 -1
- {annet-0.14.7.dist-info → annet-0.14.9.dist-info}/AUTHORS +0 -0
- {annet-0.14.7.dist-info → annet-0.14.9.dist-info}/LICENSE +0 -0
- {annet-0.14.7.dist-info → annet-0.14.9.dist-info}/entry_points.txt +0 -0
- {annet-0.14.7.dist-info → annet-0.14.9.dist-info}/top_level.txt +0 -0
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
49
|
-
|
|
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
|
-
Для создания более одного уровня команд
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
"""
|
|
246
|
+
""" Open the context file using an editor from the EDITOR environment variable.
|
|
215
247
|
|
|
216
|
-
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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
|
-
"
|
|
179
|
-
"
|
|
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="
|
|
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="
|
|
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="
|
|
196
|
-
"
|
|
197
|
-
"
|
|
198
|
-
"
|
|
199
|
-
"
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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=
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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
|
-
"
|
|
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__)
|
annet/rulebook/aruba/ap_env.py
CHANGED
|
@@ -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]
|
|
72
|
+
def parse_params(cls, conf_params: Optional[Dict[str, str]], cli_opts: Any):
|
|
73
73
|
pass
|
|
74
74
|
|
|
75
75
|
|
|
@@ -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=
|
|
4
|
-
annet/cli.py,sha256=
|
|
5
|
-
annet/cli_args.py,sha256=
|
|
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=
|
|
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
|
|
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=
|
|
30
|
-
annet/adapters/netbox/common/models.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
128
|
-
annet-0.14.
|
|
129
|
-
annet-0.14.
|
|
130
|
-
annet-0.14.
|
|
131
|
-
annet-0.14.
|
|
132
|
-
annet-0.14.
|
|
133
|
-
annet-0.14.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|