annet 0.15.0__py3-none-any.whl → 0.15.2__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.

@@ -1,5 +1,5 @@
1
1
  from logging import getLogger
2
- from typing import Optional, List, Union, Dict
2
+ from typing import Any, Optional, List, Union, Dict
3
3
  from ipaddress import ip_interface
4
4
  from collections import defaultdict
5
5
 
@@ -145,6 +145,7 @@ class NetboxStorageV37(Storage):
145
145
  def _load_devices(self, query: NetboxQuery) -> List[api_models.Device]:
146
146
  if not query.globs:
147
147
  return []
148
+ query = _hostname_dot_hack(query)
148
149
  return [
149
150
  device
150
151
  for device in self.netbox.dcim_all_devices(
@@ -223,3 +224,23 @@ def _match_query(query: NetboxQuery, device_data: api_models.Device) -> bool:
223
224
  if subquery.strip() in device_data.name:
224
225
  return True
225
226
  return False
227
+
228
+
229
+ def _hostname_dot_hack(netbox_query: NetboxQuery) -> NetboxQuery:
230
+ # there is no proper way to lookup host by its hostname
231
+ # ie find "host" with fqdn "host.example.com"
232
+ # besides using name__ic (ie startswith)
233
+ # since there is no direct analogue for this field in netbox
234
+ # so we need to add a dot to hostnames (top-level fqdn part)
235
+ # so we would not receive devices with a common name prefix
236
+ def add_dot(raw_query: Any) -> Any:
237
+ if isinstance(raw_query, str) and "." not in raw_query:
238
+ raw_query = raw_query + "."
239
+ return raw_query
240
+
241
+ raw_query = netbox_query.query
242
+ if isinstance(raw_query, list):
243
+ for i, name in enumerate(raw_query):
244
+ raw_query[i] = add_dot(name)
245
+
246
+ return NetboxQuery(raw_query)
@@ -6,18 +6,19 @@
6
6
  "Cisco.ASR": " ASR",
7
7
  "Cisco.ASR.ASR9000": " 9\\d{3}",
8
8
  "Cisco.XRV": "XRv",
9
- "Cisco.Catalyst": "Catalyst",
10
- "Cisco.Catalyst.C2900": " 29\\d\\d",
11
- "Cisco.Catalyst.C2900.C2950": " 2950",
12
- "Cisco.Catalyst.C2900.C2960": " 2960",
13
- "Cisco.Catalyst.C2900.C2960.C2960Plus": " 2960-Plus",
14
- "Cisco.Catalyst.C2900.C2960.C2960S": " 2960S",
15
- "Cisco.Catalyst.C2900.C2960.C2960X": " 2960X",
16
- "Cisco.Catalyst.C3500": " 35\\d\\d",
17
- "Cisco.Catalyst.C3600": " 36\\d\\d",
18
- "Cisco.Catalyst.C3700": " 37\\d\\d",
19
- "Cisco.Catalyst.C4900": " 49\\d\\d",
20
- "Cisco.Catalyst.C6500": " 65\\d\\d",
9
+ "Cisco.Catalyst": " (Catalyst |WS-C)",
10
+ "Cisco.Catalyst.C2900": "29\\d\\d",
11
+ "Cisco.Catalyst.C2900.C2950": "2950",
12
+ "Cisco.Catalyst.C2900.C2960": "2960",
13
+ "Cisco.Catalyst.C2900.C2960.C2960Plus": "2960-Plus",
14
+ "Cisco.Catalyst.C2900.C2960.C2960S": "2960S",
15
+ "Cisco.Catalyst.C2900.C2960.C2960X": "2960X",
16
+ "Cisco.Catalyst.C2900.C2960.C2960G": "2960G",
17
+ "Cisco.Catalyst.C3500": "35\\d\\d",
18
+ "Cisco.Catalyst.C3600": "36\\d\\d",
19
+ "Cisco.Catalyst.C3700": "37\\d\\d",
20
+ "Cisco.Catalyst.C4900": "49\\d\\d",
21
+ "Cisco.Catalyst.C6500": "65\\d\\d",
21
22
  "Cisco.Nexus": " [Nn]exus",
22
23
  "Cisco.Nexus.N3x": " 3\\d\\d\\d",
23
24
  "Cisco.Nexus.N3x.N3100": " 31\\d\\d",
@@ -52,13 +53,13 @@
52
53
  "Huawei.CE.CE8800.CE8850": " CE8850",
53
54
  "Huawei.CE.CE8800.CE8851": " CE8851",
54
55
  "Huawei.CE.CE9800": " CE98\\d\\d",
55
- "Huawei.Quidway": " S\\d+",
56
- "Huawei.Quidway.S2x": " S2\\d{3}",
57
- "Huawei.Quidway.S2x.S2300": " S23\\d\\d",
58
- "Huawei.Quidway.S2x.S2700": " S27\\d\\d",
59
- "Huawei.Quidway.S5300": " S53\\d\\d",
60
- "Huawei.Quidway.S5700": " S57\\d\\d",
61
- "Huawei.Quidway.S6700": " S67\\d\\d",
56
+ "Huawei.Quidway": " (LS-)?S",
57
+ "Huawei.Quidway.S2x": "2\\d{3}",
58
+ "Huawei.Quidway.S2x.S2300": "23\\d\\d",
59
+ "Huawei.Quidway.S2x.S2700": "27\\d\\d",
60
+ "Huawei.Quidway.S5300": "53\\d\\d",
61
+ "Huawei.Quidway.S5700": "57\\d\\d",
62
+ "Huawei.Quidway.S6700": "67\\d\\d",
62
63
  "Huawei.NE": " NE\\d+",
63
64
  "Huawei.NE.NE40E": " NE40E",
64
65
  "Huawei.NE.NE8000": " NE8000",
@@ -111,6 +112,9 @@
111
112
  "PC.Whitebox.Edgecore": "[Ee]dge-?[Cc]ore",
112
113
  "PC.Whitebox.Edgecore.AS": "AS",
113
114
  "PC.Whitebox.Edgecore.AS9736": "AS9736",
115
+ "PC.Whitebox.NVIDIA": "NVIDIA",
116
+ "PC.Whitebox.NVIDIA.SN": " SN",
117
+ "PC.Whitebox.NVIDIA.SN.SN5600": " SN5600",
114
118
  "PC.Moxa": "[Mm]oxa",
115
119
  "PC.Moxa.NPort": " [Nn][Pp]ort",
116
120
  "PC.Moxa.NPort.6610": "6610",
annet/api/__init__.py CHANGED
@@ -346,7 +346,7 @@ def diff(
346
346
  device = res.device
347
347
  acl_rules = res.get_acl_rules(args.acl_safe)
348
348
  new_files = res.get_new_files(args.acl_safe)
349
- new_json_fragment_files = res.get_new_file_fragments()
349
+ new_json_fragment_files = res.get_new_file_fragments(args.acl_safe)
350
350
 
351
351
  pc_diff_files = []
352
352
  if res.old_files or new_files:
annet/argparse.py CHANGED
@@ -107,6 +107,8 @@ class Arg:
107
107
  default = self.kwargs.get("default", None)
108
108
  if isinstance(default, ConvertibleDefault) and "type" in self.kwargs:
109
109
  default = self.kwargs["default"] = default.convert(self.kwargs["type"])
110
+ elif isinstance(default, Callable):
111
+ default = self.kwargs["default"] = default()
110
112
  elif default is False and "action" not in self.kwargs:
111
113
  self.kwargs["action"] = "store_true"
112
114
  self.default = default
annet/cli.py CHANGED
@@ -273,7 +273,7 @@ def file_patch(args: cli_args.FilePatchOptions):
273
273
  def context():
274
274
  """ A group of commands for manipulating context.
275
275
 
276
- By default, the context file is located in '~/.annushka/context.yml',
276
+ By default, the context file is located in '~/.annet/context.yml',
277
277
  but it can be set with the ANN_CONTEXT_CONFIG_PATH environment variable.
278
278
  """
279
279
  context_touch()
annet/cli_args.py CHANGED
@@ -8,6 +8,7 @@ import os
8
8
 
9
9
  from valkit.common import valid_string_list
10
10
 
11
+ import annet.lib
11
12
  from annet.argparse import Arg, ArgGroup, DefaultFromEnv
12
13
  from annet.hardware import hardware_connector
13
14
  from annet.storage import Query, get_storage
@@ -69,6 +70,11 @@ opt_expand_path = Arg(
69
70
  help="Use full paths of Entire-generators and no just names when writing them to the file system"
70
71
  )
71
72
 
73
+ opt_dest_force_create_dir = Arg(
74
+ "--dest-force-create-dir", default=False,
75
+ help="Output generated data to dir, even for blackboxes"
76
+ )
77
+
72
78
  opt_old = Arg(
73
79
  "old",
74
80
  help="A path to a file (or a directory with a batch of files) that contains the old config"
@@ -228,7 +234,7 @@ opt_log_json = Arg(
228
234
  )
229
235
 
230
236
  opt_log_dest = Arg(
231
- "--log-dest", default="deploy/",
237
+ "--log-dest", default=annet.lib.get_default_log_dest,
232
238
  help="Log to a specified file, directory, or '-' (stdout)"
233
239
  )
234
240
 
@@ -425,6 +431,7 @@ class FileOutOptions(ArgGroup):
425
431
  expand_path = opt_expand_path
426
432
  no_label = opt_no_label
427
433
  no_color = opt_no_color
434
+ dest_force_create_dir = opt_dest_force_create_dir
428
435
 
429
436
  def __init__(self, *args, **kwargs):
430
437
  super().__init__(*args, **kwargs)
annet/lib.py CHANGED
@@ -37,8 +37,20 @@ from annet.annlib.lib import ( # pylint: disable=unused-import
37
37
  from contextlog import get_logger
38
38
 
39
39
 
40
- _TEMPLATE_CONTEXT_PATH: Optional[str] = None
41
- _DEFAULT_CONTEXT_PATH: Optional[str] = None
40
+ _HOMEDIR_PATH: Optional[str] = None # defaults to ~/.annet
41
+ _TEMPLATE_CONTEXT_PATH: Optional[str] = None # defaults to annet/configs/context.yml
42
+ _DEFAULT_CONTEXT_PATH: Optional[str] = None # defaults to ~/.annet/context.yml
43
+
44
+
45
+ def get_homedir_path() -> str:
46
+ if _HOMEDIR_PATH is None:
47
+ set_homedir_path("~/.annet/")
48
+ return _HOMEDIR_PATH
49
+
50
+
51
+ def set_homedir_path(path: str) -> None:
52
+ global _HOMEDIR_PATH # pylint: disable=global-statement
53
+ _HOMEDIR_PATH = path
42
54
 
43
55
 
44
56
  def get_template_context_path() -> str:
@@ -63,6 +75,11 @@ def set_default_context_path(path: str) -> None:
63
75
  _DEFAULT_CONTEXT_PATH = path
64
76
 
65
77
 
78
+ def get_default_log_dest() -> str:
79
+ homedir = get_homedir_path()
80
+ return os.path.join(homedir, "deploy/")
81
+
82
+
66
83
  @lru_cache(maxsize=1)
67
84
  def _get_template_context():
68
85
  with open(get_template_context_path()) as f:
annet/output.py CHANGED
@@ -24,6 +24,9 @@ from annet.connectors import Connector
24
24
  from annet.storage import Device, storage_connector
25
25
 
26
26
 
27
+ BLACKBOX_FILENAME = "config.cfg"
28
+
29
+
27
30
  class _DriverConnector(Connector["OutputDriver"]):
28
31
  name = "OutputDriver"
29
32
  ep_name = "output"
@@ -77,7 +80,8 @@ class OutputDriverBasic(OutputDriver):
77
80
  yield from items_iter
78
81
 
79
82
  dest = arg_out.dest
80
- dir_mode = dir_or_file_output(dest, query_result_count, suggest_dir=(os.sep in first_result[0]))
83
+ suggest_dir = arg_out.dest_force_create_dir or os.sep in first_result[0]
84
+ dir_mode = dir_or_file_output(dest, query_result_count, suggest_dir=suggest_dir)
81
85
  _reassembled_items = list(_reassemble_items())
82
86
 
83
87
  for output_no, (label, output, is_fail) in enumerate(_reassembled_items):
@@ -99,6 +103,9 @@ class OutputDriverBasic(OutputDriver):
99
103
  print_label(label, back_color=label_color)
100
104
  writer.write(sys.stdout)
101
105
  elif dir_mode:
106
+ if arg_out.dest_force_create_dir and os.sep not in label:
107
+ label = os.path.join(label, BLACKBOX_FILENAME)
108
+
102
109
  if label.startswith(LABEL_NEW_PREFIX):
103
110
  label = label[len(LABEL_NEW_PREFIX):]
104
111
  if label.startswith(os.sep):
@@ -114,7 +121,7 @@ class OutputDriverBasic(OutputDriver):
114
121
  label = os.sep.join(parts[1:])
115
122
  if not arg_out.expand_path:
116
123
  label = os.path.basename(label)
117
- if query_result_count > 1:
124
+ if query_result_count > 1 or arg_out.dest_force_create_dir:
118
125
  label = os.path.join(hostname, label)
119
126
  file_dest = os.path.join(dest, "errors") if is_fail else dest
120
127
  out_file = os.path.normpath(os.path.join(file_dest, label))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: annet
3
- Version: 0.15.0
3
+ Version: 0.15.2
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -1,8 +1,8 @@
1
1
  annet/__init__.py,sha256=oyElxAW97sHgQccGafhaWVBveBn1gSjjdP_xHROaRLg,2139
2
2
  annet/annet.py,sha256=TMdEuM7GJQ4TjRVmuK3bCTZN-21lxjQ9sXqEdILUuBk,725
3
- annet/argparse.py,sha256=ZHKQriVCysSnox5stZnYxKLaPKzDjXbShxFyNW6LiiQ,12754
4
- annet/cli.py,sha256=yUStwwUKGgGuNw94EvabUEMhBs0YsIsc4omUivst8H0,12366
5
- annet/cli_args.py,sha256=_Du9Jhe86F4fsx7u9njjvg25jTdoBsdbTEzbuDFgrFU,13248
3
+ annet/argparse.py,sha256=v1MfhjR0B8qahza0WinmXClpR8UiDFhmwDDWtNroJPA,12855
4
+ annet/cli.py,sha256=AcSiqNa5Wk3yJks5LYcXqbYMZuySmQqMQK5hW_-irFw,12363
5
+ annet/cli_args.py,sha256=KQlihxSl-Phhq1-9oJDdNSbIllEX55LlPfH6viEKOuw,13483
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
@@ -11,8 +11,8 @@ annet/filtering.py,sha256=F4ZKUCU3Yb1RlL2zKdyHtVUaWPzjWF4vWyMcdygKNYk,852
11
11
  annet/gen.py,sha256=8IPejduvYXmezUDolLKg4Imt1TxEp0KJ7kSgMtFcaCY,33628
12
12
  annet/hardware.py,sha256=HYPDfji_GdRn5S0_0fl4rvM7byOY9aHxG6VMAtsLaxE,1090
13
13
  annet/implicit.py,sha256=_3eY9NKqpLUm25vlJIP2cHN4gdTgzO6rG6mwCKJYMnQ,5439
14
- annet/lib.py,sha256=tQQlxZg1A2Q-tp18PoqBuORQmvP5dAAmAPvP6bBA6a0,3764
15
- annet/output.py,sha256=hJNGzL4Z3KgvqaCBkkmuuiXPhb64F1QV8YHkwnfhaaI,6852
14
+ annet/lib.py,sha256=W6Z9UurcyF1zU3gAd8hIec9yBzeeHzxZEkvf1cIg8KI,4280
15
+ annet/output.py,sha256=zAP3XixfSLNL988IF9ttyIbGaN4M6XhO5IhKkD1R-J8,7127
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
@@ -34,7 +34,7 @@ annet/adapters/netbox/common/storage_opts.py,sha256=idOm1na_2Axdi4MdLN4tAsPvsp5z
34
34
  annet/adapters/netbox/v24/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
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=z0WCVApf7vHL6bxLiF_f6FVo6AVm_hZuiMib4dDJt0w,7595
37
+ annet/adapters/netbox/v37/storage.py,sha256=TonXJuR6ng6xiczHsxsm0Zlo5Wokl3N_Uqg4r7HHj6c,8421
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
@@ -49,7 +49,7 @@ annet/annlib/types.py,sha256=VHU0CBADfYmO0xzB_c5f-mcuU3dUumuJczQnqGlib9M,852
49
49
  annet/annlib/netdev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
50
  annet/annlib/netdev/db.py,sha256=fI_u5aya4l61mbYSjj4JwlVfi3s7obt2jqERSuXGRUI,1634
51
51
  annet/annlib/netdev/devdb/__init__.py,sha256=aKYjjLbJebdKBjnGDpVLQdSqrV2JL24spGm58tmMWVU,892
52
- annet/annlib/netdev/devdb/data/devdb.json,sha256=0c7r0_NF0QQVPd0p84yyFLKIn5iusuU0S45NDorLWEM,5570
52
+ annet/annlib/netdev/devdb/data/devdb.json,sha256=pW4gwys2SbduBC65hepV_HOv9uxn8pxz0ckvGFJiPoU,5727
53
53
  annet/annlib/netdev/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
54
  annet/annlib/netdev/views/dump.py,sha256=rIlyvnA3uM8bB_7oq1nS2KDxTp6dQh2hz-FbNhYIpOU,4630
55
55
  annet/annlib/netdev/views/hardware.py,sha256=6453atMaeoLWJSXzZxQ0zeTrdtRwCv0dlu6ivvpcdYE,3423
@@ -61,7 +61,7 @@ annet/annlib/rbparser/platform.py,sha256=_W84Gt3XwURT2MLngZSmwZbWgqsnbrwzjNgHIHa
61
61
  annet/annlib/rbparser/syntax.py,sha256=iZ7Y-4QQBw4L3UtjEh54qisiRDhobl7HZxFNdP8mi54,3577
62
62
  annet/annlib/rulebook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
63
  annet/annlib/rulebook/common.py,sha256=9kCZwZpsH5UliF2OzaN9nLs2eLlz_d__4L7_oZ3SrCw,16054
64
- annet/api/__init__.py,sha256=-G9wlYePC3ZgNo1p8r17vmx0WLb3UNvCw3ZJ9UhYJ-I,33169
64
+ annet/api/__init__.py,sha256=vh3FVvhghxEEskLM9TuGBSnYDXN5L8iUFBB-iV46WAA,33182
65
65
  annet/configs/context.yml,sha256=jzAQX9WbjFw_nsju8FLCCGfRc4ZXD0Mhb5pvO9emegI,413
66
66
  annet/configs/logging.yaml,sha256=Hu42lRK248dssp9TgkbHCaZNl0E6f4IChGb0XaQnTVo,970
67
67
  annet/generators/__init__.py,sha256=ACMH9UQ4I3uq2b8nDzOn2dgYxreDq4_3ojOGwht0-No,15543
@@ -127,10 +127,10 @@ annet/rulebook/texts/routeros.rul,sha256=ipfxjj0mjFef6IsUlupqx4BY_Je_OUb8u_U1019
127
127
  annet_generators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
128
128
  annet_generators/example/__init__.py,sha256=zVd8_DrXuOASrNzg2Ab94rPyvJff83L-_HppDFxnUjM,228
129
129
  annet_generators/example/lldp.py,sha256=68CLrK7vxTQQy9XIBxtywuEdBNlIlfXGYj8_wYWs5UI,1146
130
- annet-0.15.0.dist-info/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
131
- annet-0.15.0.dist-info/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
132
- annet-0.15.0.dist-info/METADATA,sha256=YnR3Nr5WQwY-i1k4A8V_fKC_QIVrG36hp_oEhzebxTA,694
133
- annet-0.15.0.dist-info/WHEEL,sha256=ixB2d4u7mugx_bCBycvM9OzZ5yD7NmPXFRtKlORZS2Y,91
134
- annet-0.15.0.dist-info/entry_points.txt,sha256=yHimujIzR2bwNIbb--MTs_GpXiAve89Egpu2LlgTEkg,119
135
- annet-0.15.0.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
136
- annet-0.15.0.dist-info/RECORD,,
130
+ annet-0.15.2.dist-info/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
131
+ annet-0.15.2.dist-info/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
132
+ annet-0.15.2.dist-info/METADATA,sha256=zYV7OYVW5PBLs0_QUocznhtW6jKa1QpYr9bY0C9m3lE,694
133
+ annet-0.15.2.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
134
+ annet-0.15.2.dist-info/entry_points.txt,sha256=yHimujIzR2bwNIbb--MTs_GpXiAve89Egpu2LlgTEkg,119
135
+ annet-0.15.2.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
136
+ annet-0.15.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (74.1.0)
2
+ Generator: setuptools (74.1.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5