annet 0.14.8__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.
- {annet-0.14.8/annet.egg-info → annet-0.14.9}/PKG-INFO +1 -1
- {annet-0.14.8 → annet-0.14.9}/annet/adapters/netbox/common/manufacturer.py +1 -12
- {annet-0.14.8 → annet-0.14.9}/annet/adapters/netbox/common/models.py +21 -4
- {annet-0.14.8 → annet-0.14.9}/annet/adapters/netbox/v24/storage.py +2 -2
- {annet-0.14.8 → annet-0.14.9}/annet/adapters/netbox/v37/storage.py +13 -9
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/netdev/views/dump.py +8 -0
- {annet-0.14.8 → annet-0.14.9}/annet/argparse.py +6 -2
- {annet-0.14.8 → annet-0.14.9}/annet/cli.py +49 -19
- {annet-0.14.8 → annet-0.14.9}/annet/cli_args.py +55 -57
- {annet-0.14.8 → annet-0.14.9}/annet/executor.py +1 -5
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/aruba/ap_env.py +1 -6
- {annet-0.14.8 → annet-0.14.9/annet.egg-info}/PKG-INFO +1 -1
- {annet-0.14.8 → annet-0.14.9}/AUTHORS +0 -0
- {annet-0.14.8 → annet-0.14.9}/LICENSE +0 -0
- {annet-0.14.8 → annet-0.14.9}/MANIFEST.in +0 -0
- {annet-0.14.8 → annet-0.14.9}/README.md +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/adapters/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/adapters/netbox/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/adapters/netbox/common/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/adapters/netbox/common/client.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/adapters/netbox/common/query.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/adapters/netbox/common/status_client.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/adapters/netbox/common/storage_opts.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/adapters/netbox/provider.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/adapters/netbox/v24/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/adapters/netbox/v37/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annet.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/command.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/diff.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/errors.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/filter_acl.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/jsontools.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/lib.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/netdev/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/netdev/db.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/netdev/devdb/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/netdev/devdb/data/devdb.json +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/netdev/views/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/netdev/views/hardware.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/output.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/patching.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/rbparser/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/rbparser/acl.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/rbparser/deploying.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/rbparser/ordering.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/rbparser/platform.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/rbparser/syntax.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/rulebook/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/rulebook/common.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/tabparser.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/annlib/types.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/api/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/configs/context.yml +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/configs/logging.yaml +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/connectors.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/deploy.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/diff.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/filtering.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/gen.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/generators/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/generators/base.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/generators/common/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/generators/common/initial.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/generators/entire.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/generators/exceptions.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/generators/jsonfragment.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/generators/partial.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/generators/perf.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/generators/ref.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/generators/result.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/hardware.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/implicit.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/lib.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/output.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/parallel.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/patching.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/reference.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/arista/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/arista/iface.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/aruba/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/aruba/misc.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/cisco/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/cisco/iface.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/cisco/misc.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/cisco/vlandb.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/common.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/deploying.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/huawei/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/huawei/aaa.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/huawei/bgp.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/huawei/iface.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/huawei/misc.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/huawei/vlandb.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/juniper/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/nexus/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/nexus/iface.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/patching.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/ribbon/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/arista.deploy +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/arista.order +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/arista.rul +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/aruba.deploy +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/aruba.order +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/aruba.rul +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/cisco.deploy +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/cisco.order +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/cisco.rul +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/huawei.deploy +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/huawei.order +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/huawei.rul +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/juniper.rul +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/nexus.deploy +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/nexus.order +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/nexus.rul +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/nokia.rul +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/pc.order +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/pc.rul +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/ribbon.deploy +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/ribbon.rul +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/routeros.order +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/rulebook/texts/routeros.rul +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/storage.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/tabparser.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/text_term_format.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/tracing.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet/types.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet.egg-info/SOURCES.txt +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet.egg-info/dependency_links.txt +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet.egg-info/entry_points.txt +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet.egg-info/requires.txt +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet.egg-info/top_level.txt +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet_generators/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet_generators/example/__init__.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/annet_generators/example/lldp.py +0 -0
- {annet-0.14.8 → annet-0.14.9}/requirements.txt +0 -0
- {annet-0.14.8 → annet-0.14.9}/setup.cfg +0 -0
- {annet-0.14.8 → annet-0.14.9}/setup.py +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)
|
|
@@ -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__ + "_"
|
|
@@ -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()
|