annet 0.16.9__tar.gz → 0.16.11__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.16.9/annet.egg-info → annet-0.16.11}/PKG-INFO +3 -4
- annet-0.16.11/README.md +62 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/netbox/common/manufacturer.py +2 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/netbox/common/models.py +1 -1
- {annet-0.16.9 → annet-0.16.11}/annet/configs/context.yml +0 -9
- {annet-0.16.9 → annet-0.16.11}/annet/generators/jsonfragment.py +20 -18
- {annet-0.16.9 → annet-0.16.11/annet.egg-info}/PKG-INFO +3 -4
- {annet-0.16.9 → annet-0.16.11}/annet.egg-info/requires.txt +2 -4
- {annet-0.16.9 → annet-0.16.11}/requirements.txt +0 -3
- {annet-0.16.9 → annet-0.16.11}/setup.py +3 -0
- annet-0.16.9/README.md +0 -236
- {annet-0.16.9 → annet-0.16.11}/AUTHORS +0 -0
- {annet-0.16.9 → annet-0.16.11}/LICENSE +0 -0
- {annet-0.16.9 → annet-0.16.11}/MANIFEST.in +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/fetchers/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/fetchers/stub/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/fetchers/stub/fetcher.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/file/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/file/provider.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/netbox/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/netbox/common/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/netbox/common/client.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/netbox/common/query.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/netbox/common/status_client.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/netbox/common/storage_opts.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/netbox/provider.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/netbox/v24/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/netbox/v24/storage.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/netbox/v37/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/adapters/netbox/v37/storage.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annet.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/command.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/diff.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/errors.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/filter_acl.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/jsontools.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/lib.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/netdev/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/netdev/db.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/netdev/devdb/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/netdev/devdb/data/devdb.json +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/netdev/views/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/netdev/views/dump.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/netdev/views/hardware.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/output.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/patching.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/rbparser/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/rbparser/acl.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/rbparser/deploying.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/rbparser/ordering.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/rbparser/platform.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/rbparser/syntax.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/rulebook/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/rulebook/common.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/tabparser.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/annlib/types.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/api/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/argparse.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/bgp_models.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/cli.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/cli_args.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/configs/logging.yaml +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/connectors.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/deploy.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/diff.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/executor.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/filtering.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/gen.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/generators/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/generators/base.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/generators/common/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/generators/common/initial.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/generators/entire.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/generators/exceptions.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/generators/partial.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/generators/perf.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/generators/ref.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/generators/result.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/hardware.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/implicit.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/lib.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/mesh/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/mesh/basemodel.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/mesh/device_models.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/mesh/executor.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/mesh/match_args.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/mesh/models_converter.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/mesh/peer_models.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/mesh/registry.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/output.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/parallel.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/patching.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/reference.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/arista/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/arista/iface.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/aruba/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/aruba/ap_env.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/aruba/misc.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/b4com/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/b4com/file.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/cisco/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/cisco/iface.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/cisco/misc.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/cisco/vlandb.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/common.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/deploying.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/huawei/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/huawei/aaa.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/huawei/bgp.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/huawei/iface.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/huawei/misc.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/huawei/vlandb.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/juniper/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/nexus/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/nexus/iface.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/patching.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/ribbon/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/routeros/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/routeros/file.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/arista.deploy +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/arista.order +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/arista.rul +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/aruba.deploy +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/aruba.order +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/aruba.rul +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/b4com.deploy +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/b4com.order +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/b4com.rul +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/cisco.deploy +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/cisco.order +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/cisco.rul +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/huawei.deploy +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/huawei.order +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/huawei.rul +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/juniper.rul +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/nexus.deploy +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/nexus.order +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/nexus.rul +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/nokia.rul +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/optixtrans.deploy +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/optixtrans.order +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/optixtrans.rul +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/pc.deploy +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/pc.order +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/pc.rul +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/ribbon.deploy +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/ribbon.rul +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/routeros.order +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/rulebook/texts/routeros.rul +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/storage.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/tabparser.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/text_term_format.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/tracing.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet/types.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet.egg-info/SOURCES.txt +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet.egg-info/dependency_links.txt +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet.egg-info/entry_points.txt +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet.egg-info/top_level.txt +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet_generators/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet_generators/example/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet_generators/example/lldp.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet_generators/mesh_example/__init__.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet_generators/mesh_example/bgp.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/annet_generators/mesh_example/mesh_logic.py +0 -0
- {annet-0.16.9 → annet-0.16.11}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: annet
|
|
3
|
-
Version: 0.16.
|
|
3
|
+
Version: 0.16.11
|
|
4
4
|
Summary: annet
|
|
5
5
|
Home-page: https://github.com/annetutil/annet
|
|
6
6
|
License: MIT
|
|
@@ -19,9 +19,8 @@ Requires-Dist: psutil>=5.8.0
|
|
|
19
19
|
Requires-Dist: packaging>=23.2
|
|
20
20
|
Requires-Dist: contextlog>=1.1
|
|
21
21
|
Requires-Dist: valkit>=0.1.4
|
|
22
|
-
Requires-Dist: aiohttp>=3.8.4
|
|
23
22
|
Requires-Dist: yarl>=1.8.2
|
|
24
23
|
Requires-Dist: adaptix==3.0.0b7
|
|
25
24
|
Requires-Dist: dataclass-rest==0.4
|
|
26
|
-
|
|
27
|
-
Requires-Dist: annetbox>=0.1.8;
|
|
25
|
+
Provides-Extra: netbox
|
|
26
|
+
Requires-Dist: annetbox[sync]>=0.1.8; extra == "netbox"
|
annet-0.16.11/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Annet - configuration generation and deploying utility for network equipment
|
|
2
|
+
|
|
3
|
+
Annet is a configuration generator that can translate differences between old and new configurations into sequnce of commands. This feature is vital for CLI-based devices, such as Huawei, Cisco IOS, Cisco NX-OS, Juniper. Devices configured via separate config files, Linux, FreeBSD and Cumulus are also supported.
|
|
4
|
+
|
|
5
|
+
It works this way. Annet `gen`erates configuration for a device by running Python code, which usually goes to the Network Source of Truth, like NetBox. Annet then gets the `diff`erence by getting the configuration from the device and comparing it. Finally, Annet translates the difference into a sequence of commands, called a `patch`. After `deploy`ing these commands, the diff will be empty.
|
|
6
|
+
|
|
7
|
+
Annet has a number of modes (subcommands):
|
|
8
|
+
|
|
9
|
+
- ```annet gen``` - generates the entire config for the specified devices or specified parts of it
|
|
10
|
+
- ```annet diff``` - first does gen and then builds diff with current config version
|
|
11
|
+
- ```annet patch``` - first does diff and then generates a list of commands to apply diff on the device
|
|
12
|
+
- ```annet deploy``` - first does patch and then deploys it to the device
|
|
13
|
+
|
|
14
|
+
Usage help can be obtained by calling ```annet -h``` or for a specific command, such as ```annet gen -h```.
|
|
15
|
+
|
|
16
|
+
<img src="https://github.com/annetutil/annet/blob/main/docs/_static/annet_demo.gif?raw=true" width="800" />
|
|
17
|
+
|
|
18
|
+
## Configuration
|
|
19
|
+
|
|
20
|
+
The path to the configuration file is searched in following order:
|
|
21
|
+
- `ANN_CONTEXT_CONFIG_PATH` env.
|
|
22
|
+
- `~/.annet/context.yml`.
|
|
23
|
+
- `annet/configs/context.yml`.
|
|
24
|
+
|
|
25
|
+
Config example:
|
|
26
|
+
|
|
27
|
+
```yaml
|
|
28
|
+
generators:
|
|
29
|
+
default:
|
|
30
|
+
- my_annet_generators.example
|
|
31
|
+
|
|
32
|
+
storage:
|
|
33
|
+
default:
|
|
34
|
+
adapter: annet.adapters.file.provider
|
|
35
|
+
params:
|
|
36
|
+
path: /path/to/file
|
|
37
|
+
|
|
38
|
+
context:
|
|
39
|
+
default:
|
|
40
|
+
generators: default
|
|
41
|
+
storage: default
|
|
42
|
+
|
|
43
|
+
selected_context: default
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Environment variable `ANN_SELECTED_CONTEXT` can be used to override `selected_context` parameter.
|
|
47
|
+
|
|
48
|
+
## Building doc
|
|
49
|
+
|
|
50
|
+
1. Install dependencies:
|
|
51
|
+
|
|
52
|
+
```shell
|
|
53
|
+
pip install -r requirements-doc.txt
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
2. Build
|
|
57
|
+
|
|
58
|
+
```shell
|
|
59
|
+
sphinx-build -M html docs docs-build
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
3. Open rendered html in browser [docs-build/html/index.html](docs-build/html/index.html)
|
|
@@ -207,7 +207,7 @@ class NetboxDevice(Entity):
|
|
|
207
207
|
return type(self) is type(other) and self.url == other.url
|
|
208
208
|
|
|
209
209
|
def is_pc(self) -> bool:
|
|
210
|
-
return self.device_type.manufacturer.name == "Mellanox"
|
|
210
|
+
return self.device_type.manufacturer.name == "Mellanox" or self.breed == "pc"
|
|
211
211
|
|
|
212
212
|
def _make_interface(self, name: str, type: InterfaceType) -> Interface:
|
|
213
213
|
return Interface(
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
connection:
|
|
2
|
-
default:
|
|
3
|
-
login: ~
|
|
4
|
-
passwords: ~
|
|
5
|
-
enable_ssh_conf: false
|
|
6
|
-
no_nocauth: false
|
|
7
|
-
ssh_forward_agent: ~
|
|
8
|
-
tunnel: ~
|
|
9
1
|
generators:
|
|
10
2
|
default:
|
|
11
3
|
- annet_generators.example
|
|
@@ -17,7 +9,6 @@ storage:
|
|
|
17
9
|
|
|
18
10
|
context:
|
|
19
11
|
default:
|
|
20
|
-
connection: default
|
|
21
12
|
generators: default
|
|
22
13
|
storage: default
|
|
23
14
|
|
|
@@ -86,40 +86,42 @@ class JSONFragment(TreeGenerator):
|
|
|
86
86
|
self._config_pointer.pop()
|
|
87
87
|
|
|
88
88
|
def __call__(self, device: Device, annotate: bool = False):
|
|
89
|
-
|
|
90
|
-
self.
|
|
91
|
-
|
|
89
|
+
try:
|
|
90
|
+
for cfg_fragment in self.run(device):
|
|
91
|
+
self._set_or_replace_dict(self._config_pointer, cfg_fragment)
|
|
92
|
+
return self._json_config
|
|
93
|
+
finally:
|
|
94
|
+
self._json_config = {}
|
|
92
95
|
|
|
93
96
|
def _set_or_replace_dict(self, pointer, value):
|
|
94
97
|
if not pointer:
|
|
95
98
|
if self._json_config == {}:
|
|
96
|
-
self._json_config = value
|
|
99
|
+
self._json_config = self.process_value(value)
|
|
97
100
|
else:
|
|
98
|
-
self._json_config = [self._json_config, value]
|
|
101
|
+
self._json_config = [self._json_config, self.process_value(value)]
|
|
99
102
|
else:
|
|
100
103
|
self._set_dict(self._json_config, pointer, value)
|
|
101
104
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
return [
|
|
105
|
+
def process_scalar_value(self, value: Any) -> Any:
|
|
106
|
+
return str(value)
|
|
107
|
+
|
|
108
|
+
def process_value(self, value: Any) -> Any:
|
|
109
|
+
if isinstance(value, (list, set, frozenset)):
|
|
110
|
+
return [self.process_value(x) for x in value]
|
|
108
111
|
elif isinstance(value, dict):
|
|
109
112
|
for k, v in value.items():
|
|
110
|
-
value[k] =
|
|
113
|
+
value[k] = self.process_value(v)
|
|
111
114
|
return value
|
|
112
|
-
return
|
|
115
|
+
return self.process_scalar_value(value)
|
|
113
116
|
|
|
114
|
-
|
|
115
|
-
def _set_dict(cls, cfg, pointer, value):
|
|
117
|
+
def _set_dict(self, cfg, pointer, value):
|
|
116
118
|
# pointer has at least one key
|
|
117
119
|
if len(pointer) == 1:
|
|
118
120
|
if pointer[0] in cfg:
|
|
119
|
-
cfg[pointer[0]] = [cfg[pointer[0]],
|
|
121
|
+
cfg[pointer[0]] = [cfg[pointer[0]], self.process_value(value)]
|
|
120
122
|
else:
|
|
121
|
-
cfg[pointer[0]] =
|
|
123
|
+
cfg[pointer[0]] = self.process_value(value)
|
|
122
124
|
else:
|
|
123
125
|
if pointer[0] not in cfg:
|
|
124
126
|
cfg[pointer[0]] = {}
|
|
125
|
-
|
|
127
|
+
self._set_dict(cfg[pointer[0]], pointer[1:], self.process_value(value))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: annet
|
|
3
|
-
Version: 0.16.
|
|
3
|
+
Version: 0.16.11
|
|
4
4
|
Summary: annet
|
|
5
5
|
Home-page: https://github.com/annetutil/annet
|
|
6
6
|
License: MIT
|
|
@@ -19,9 +19,8 @@ Requires-Dist: psutil>=5.8.0
|
|
|
19
19
|
Requires-Dist: packaging>=23.2
|
|
20
20
|
Requires-Dist: contextlog>=1.1
|
|
21
21
|
Requires-Dist: valkit>=0.1.4
|
|
22
|
-
Requires-Dist: aiohttp>=3.8.4
|
|
23
22
|
Requires-Dist: yarl>=1.8.2
|
|
24
23
|
Requires-Dist: adaptix==3.0.0b7
|
|
25
24
|
Requires-Dist: dataclass-rest==0.4
|
|
26
|
-
|
|
27
|
-
Requires-Dist: annetbox>=0.1.8;
|
|
25
|
+
Provides-Extra: netbox
|
|
26
|
+
Requires-Dist: annetbox[sync]>=0.1.8; extra == "netbox"
|
|
@@ -10,11 +10,9 @@ psutil>=5.8.0
|
|
|
10
10
|
packaging>=23.2
|
|
11
11
|
contextlog>=1.1
|
|
12
12
|
valkit>=0.1.4
|
|
13
|
-
aiohttp>=3.8.4
|
|
14
13
|
yarl>=1.8.2
|
|
15
14
|
adaptix==3.0.0b7
|
|
16
15
|
dataclass-rest==0.4
|
|
17
|
-
requests>=2.32.3
|
|
18
16
|
|
|
19
|
-
[
|
|
20
|
-
annetbox>=0.1.8
|
|
17
|
+
[netbox]
|
|
18
|
+
annetbox[sync]>=0.1.8
|
annet-0.16.9/README.md
DELETED
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
# Annet - configuration generation and deploying utility for network equipment
|
|
2
|
-
|
|
3
|
-
Annet is a configuration generator that can translate differences between old and new configurations into sequnce of commands. This feature is vital for CLI-based devices, such as Huawei, Cisco IOS, Cisco NX-OS, Juniper. Devices configured via separate config files, Linux, FreeBSD and Cumulus are also supported.
|
|
4
|
-
|
|
5
|
-
It works this way. Annet `gen`erates configuration for a device by running Python code, which usually goes to the Network Source of Truth, like NetBox. Annet then gets the `diff`erence by getting the configuration from the device and comparing it. Finally, Annet translates the difference into a sequence of commands, called a `patch`. After `deploy`ing these commands, the diff will be empty.
|
|
6
|
-
|
|
7
|
-
Annet has a number of modes (subcommands):
|
|
8
|
-
|
|
9
|
-
- ```annet gen``` - generates the entire config for the specified devices or specified parts of it
|
|
10
|
-
- ```annet diff``` - first does gen and then builds diff with current config version
|
|
11
|
-
- ```annet patch``` - first does diff and then generates a list of commands to apply diff on the device
|
|
12
|
-
- ```annet deploy``` - first does patch and then deploys it to the device
|
|
13
|
-
|
|
14
|
-
Usage help can be obtained by calling ```annet -h``` or for a specific command, such as ```annet gen -h```.
|
|
15
|
-
|
|
16
|
-
## Overview
|
|
17
|
-
|
|
18
|
-
### annet gen
|
|
19
|
-
|
|
20
|
-
The annet_generators directory contains many files called generators.
|
|
21
|
-
A generator takes information about the switch as input and returns the configuration.
|
|
22
|
-
The part of the config that the generator is responsible for is specified in the generator's acl function. If a generator returns a configuration that does not fall under acl, an exception will be thrown.
|
|
23
|
-
|
|
24
|
-
Example generator:
|
|
25
|
-
|
|
26
|
-
```python
|
|
27
|
-
from annet.generators import PartialGenerator
|
|
28
|
-
|
|
29
|
-
class Mtu(PartialGenerator):
|
|
30
|
-
TAGS = ["mtu"]
|
|
31
|
-
def acl_cisco(self, _):
|
|
32
|
-
return "system mtu jumbo"
|
|
33
|
-
|
|
34
|
-
def run_cisco(self, device):
|
|
35
|
-
yield "system mtu jumbo %d" % 9000
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
And an example of calling annet:
|
|
40
|
-
```bash
|
|
41
|
-
annet gen -g mtu sw6-i1
|
|
42
|
-
# -------------------- sw6-i1.cfg --------------------
|
|
43
|
-
system mtu jumbo 9000
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Method `acl_cisco` defines scope of the generator, which commands and block it controls.
|
|
47
|
-
The option `-g mtu` means that only generators with the mtu element in the TAGS variable should be called. If no tag is specified, all generators will be executed.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
### annet diff
|
|
51
|
-
|
|
52
|
-
If we were configuring the switch from scratch, these options would be enough, but in our reality we need to be able not only to generate the desired configuration, but also to be able to bring the current configuration to the desired one.
|
|
53
|
-
To do this, you need to be able to delete an outdated configuration and correctly add a new one. The **diff** module, which implements some tricky logic, is responsible for this work.
|
|
54
|
-
This logic is defined in the rulebook/texts/VENDOR folder.
|
|
55
|
-
|
|
56
|
-
Example diff:
|
|
57
|
-
```diff
|
|
58
|
-
# -------------------- sw1-i38.cfg --------------------
|
|
59
|
-
acl number 2610
|
|
60
|
-
- rule 40 permit source 10.11.170.150 0
|
|
61
|
-
+ rule 12 permit source 10.11.133.81 0
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### annet patch
|
|
65
|
-
|
|
66
|
-
Next, you need to create a list of commands from the resulting diff. The **patch** module is responsible for this. It receives the diff, runs the logic specified in rulebook/texts/VENDOR and returns the list of commands.
|
|
67
|
-
Let's take the above diff. It says to remove the command ``rule 40 permit source 10.11.170.150 0`` and add ``rule 12 permit source 10.11.133.81 0``.
|
|
68
|
-
Basic command delete logic for huawei is adding undo to the command. So the undo command will look like this: ``undo rule 40 permit source 10.11.170.150 0```, but this is an invalid command. In case of canceling acl rules, you need to execute ``undo rule N```.
|
|
69
|
-
So you need to write the undo logic for the ```rule ```` command in the ``acl ``` block.
|
|
70
|
-
Here is the part of rulebook/texts/huawei.rul responsible for this:
|
|
71
|
-
```
|
|
72
|
-
acl name *
|
|
73
|
-
rule * %logic=huawei.misc.undo_redo
|
|
74
|
-
```
|
|
75
|
-
The asterisk here means that the key argument of the undo_redo function will contain the first word after rule, namely the rule number.
|
|
76
|
-
|
|
77
|
-
Here, the undo_redo function from the file in rulebook/huawei/misc.py is used to generate the command to remove rules in acl.
|
|
78
|
-
```python
|
|
79
|
-
def undo_redo(rule, key, diff, **_):
|
|
80
|
-
...
|
|
81
|
-
```
|
|
82
|
-
Now calling `annet patch -g snmp sw1-i38` returns the correct set of commands.
|
|
83
|
-
```
|
|
84
|
-
acl number 2610
|
|
85
|
-
undo rule 40
|
|
86
|
-
rule 12 permit source 10.11.133.81 0
|
|
87
|
-
quit
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### annet deploy
|
|
91
|
-
|
|
92
|
-
To apply these commands on a switch there is a **deploy** module.
|
|
93
|
-
Annet can apply changes (roll out) to multiple devices at the same time.
|
|
94
|
-
|
|
95
|
-
By default, the edits that annet proposes to roll out will be shown before the rollout.
|
|
96
|
-
The user must confirm that they agree to roll out the proposed diff to a given list of devices.
|
|
97
|
-
During the rollout, annet will display the overall progress of the task and the log of one of the devices.
|
|
98
|
-
|
|
99
|
-
Normal layout. The screen with patches will be shown and the process of laying out will be displayed.
|
|
100
|
-
|
|
101
|
-
```bash
|
|
102
|
-
annet deploy -g snmp $HOST
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
Credentials will be used from the current user (username, ssh key, ssh agent).
|
|
106
|
-
|
|
107
|
-
## Installation
|
|
108
|
-
|
|
109
|
-
```shell
|
|
110
|
-
mkdir myproject
|
|
111
|
-
cd myproject
|
|
112
|
-
python3 -m venv venv
|
|
113
|
-
source venv/bin/activate
|
|
114
|
-
pip install annet gnetcli_adapter
|
|
115
|
-
|
|
116
|
-
cat > ~/.annet/context.yml_tmp<<EOF
|
|
117
|
-
fetcher:
|
|
118
|
-
default:
|
|
119
|
-
adapter: gnetcli
|
|
120
|
-
deployer:
|
|
121
|
-
default:
|
|
122
|
-
adapter: gnetcli
|
|
123
|
-
generators:
|
|
124
|
-
default:
|
|
125
|
-
- my_generators
|
|
126
|
-
storage:
|
|
127
|
-
netbox:
|
|
128
|
-
adapter: netbox
|
|
129
|
-
params:
|
|
130
|
-
url: http://127.0.0.1:8000
|
|
131
|
-
token: 1234567890abcdef01234567890abcdef0123456
|
|
132
|
-
context:
|
|
133
|
-
default:
|
|
134
|
-
fetcher: default
|
|
135
|
-
deployer: default
|
|
136
|
-
connection: default
|
|
137
|
-
generators: default
|
|
138
|
-
storage: default
|
|
139
|
-
selected_context: default
|
|
140
|
-
EOF
|
|
141
|
-
|
|
142
|
-
cp -r my_generators
|
|
143
|
-
|
|
144
|
-
annet deploy mydevice
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## Configuration
|
|
148
|
-
|
|
149
|
-
The path to the configuration file is searched in following order:
|
|
150
|
-
- `ANN_CONTEXT_CONFIG_PATH` env.
|
|
151
|
-
- `~/.annet/context.yml`.
|
|
152
|
-
- `annet/configs/context.yml`.
|
|
153
|
-
|
|
154
|
-
Config example:
|
|
155
|
-
|
|
156
|
-
```yaml
|
|
157
|
-
connection:
|
|
158
|
-
default:
|
|
159
|
-
login: ~
|
|
160
|
-
passwords: ~
|
|
161
|
-
|
|
162
|
-
generators:
|
|
163
|
-
default:
|
|
164
|
-
- my_annet_generators.example
|
|
165
|
-
|
|
166
|
-
storage:
|
|
167
|
-
default:
|
|
168
|
-
adapter: annet.adapters.file.provider
|
|
169
|
-
params:
|
|
170
|
-
path: /path/to/file
|
|
171
|
-
|
|
172
|
-
context:
|
|
173
|
-
default:
|
|
174
|
-
connection: default
|
|
175
|
-
generators: default
|
|
176
|
-
storage: default
|
|
177
|
-
|
|
178
|
-
selected_context: default
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
Environment variable `ANN_SELECTED_CONTEXT` can be used to override `selected_context` parameter.
|
|
182
|
-
|
|
183
|
-
### Storages
|
|
184
|
-
|
|
185
|
-
Storages provide information about devices like FQDN, interface and so on.
|
|
186
|
-
|
|
187
|
-
#### Netbox storage
|
|
188
|
-
|
|
189
|
-
Provide `NETBOX_URL` and `NETBOX_TOKEN` environment variable to setup data source.
|
|
190
|
-
|
|
191
|
-
```shell
|
|
192
|
-
export NETBOX_URL="https://demo.netbox.dev"
|
|
193
|
-
export NETBOX_TOKEN="1234567890abcdef01234567890abcdef0123456"
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
#### File storage
|
|
197
|
-
```yaml
|
|
198
|
-
storage:
|
|
199
|
-
default:
|
|
200
|
-
adapter: annet.adapters.file.provider
|
|
201
|
-
params:
|
|
202
|
-
path: /path/to/file
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
cat /path/to/file:
|
|
206
|
-
|
|
207
|
-
```yaml
|
|
208
|
-
devices:
|
|
209
|
-
- fqdn: myhost.yndx.net
|
|
210
|
-
vendor: mikrotik
|
|
211
|
-
interfaces:
|
|
212
|
-
- name: eth0
|
|
213
|
-
description: test
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
## Extending
|
|
217
|
-
|
|
218
|
-
Annet uses [Entry Points](https://setuptools.pypa.io/en/latest/userguide/entry_point.html) mechanism for customization.
|
|
219
|
-
For example, you can implement the Storage interface on top of your favorite inventory system.
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
## Building doc
|
|
223
|
-
|
|
224
|
-
1. Install dependencies:
|
|
225
|
-
|
|
226
|
-
```shell
|
|
227
|
-
pip install -r requirements-doc.txt
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
2. Build
|
|
231
|
-
|
|
232
|
-
```shell
|
|
233
|
-
sphinx-build -M html docs docs-build
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
3. Open rendered html in browser [docs-build/html/index.html](docs-build/html/index.html)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|