annet 2.6.0__tar.gz → 3.1.0__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-2.6.0/annet.egg-info → annet-3.1.0}/PKG-INFO +1 -1
- {annet-2.6.0 → annet-3.1.0}/annet/__init__.py +5 -4
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/file/provider.py +49 -26
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/manufacturer.py +3 -22
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/models.py +3 -2
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v24/models.py +4 -3
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/netdev/views/hardware.py +15 -70
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/patching.py +9 -6
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/rbparser/acl.py +3 -2
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/rbparser/ordering.py +3 -2
- annet-3.1.0/annet/annlib/rbparser/platform.py +3 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/rulebook/common.py +21 -14
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/tabparser.py +0 -18
- {annet-2.6.0 → annet-3.1.0}/annet/api/__init__.py +16 -7
- {annet-2.6.0 → annet-3.1.0}/annet/diff.py +3 -3
- {annet-2.6.0 → annet-3.1.0}/annet/gen.py +6 -6
- {annet-2.6.0 → annet-3.1.0}/annet/generators/__init__.py +15 -22
- {annet-2.6.0 → annet-3.1.0}/annet/hardware.py +8 -12
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/__init__.py +3 -2
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/deploying.py +3 -2
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/juniper/__init__.py +2 -2
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/patching.py +5 -5
- annet-3.1.0/annet/vendors/__init__.py +33 -0
- annet-3.1.0/annet/vendors/base.py +38 -0
- annet-3.1.0/annet/vendors/registry.py +93 -0
- {annet-2.6.0 → annet-3.1.0/annet.egg-info}/PKG-INFO +1 -1
- {annet-2.6.0 → annet-3.1.0}/annet.egg-info/SOURCES.txt +4 -1
- {annet-2.6.0 → annet-3.1.0}/annet_generators/example/__init__.py +6 -1
- annet-3.1.0/annet_generators/example/hostname.py +113 -0
- annet-2.6.0/annet/annlib/rbparser/platform.py +0 -69
- annet-2.6.0/annet/tabparser.py +0 -53
- {annet-2.6.0 → annet-3.1.0}/AUTHORS +0 -0
- {annet-2.6.0 → annet-3.1.0}/LICENSE +0 -0
- {annet-2.6.0 → annet-3.1.0}/MANIFEST.in +0 -0
- {annet-2.6.0 → annet-3.1.0}/README.md +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/fetchers/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/fetchers/stub/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/fetchers/stub/fetcher.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/file/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/adapter.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/client.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/query.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/status_client.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/storage_base.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/common/storage_opts.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/provider.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v24/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v24/storage.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v37/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v37/models.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v37/storage.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v41/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v41/models.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v41/storage.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v42/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v42/models.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/adapters/netbox/v42/storage.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annet.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/command.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/diff.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/errors.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/filter_acl.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/jsontools.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/lib.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/netdev/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/netdev/db.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/netdev/devdb/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/netdev/devdb/data/devdb.json +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/netdev/views/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/netdev/views/dump.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/output.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/rbparser/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/rbparser/deploying.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/rbparser/syntax.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/rulebook/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/annlib/types.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/argparse.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/bgp_models.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/cli.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/cli_args.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/configs/context.yml +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/configs/logging.yaml +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/connectors.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/deploy.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/deploy_ui.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/executor.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/filtering.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/generators/base.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/generators/common/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/generators/common/initial.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/generators/entire.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/generators/exceptions.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/generators/jsonfragment.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/generators/partial.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/generators/perf.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/generators/ref.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/generators/result.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/implicit.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/lib.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/mesh/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/mesh/basemodel.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/mesh/device_models.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/mesh/executor.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/mesh/match_args.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/mesh/models_converter.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/mesh/peer_models.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/mesh/port_processor.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/mesh/registry.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/output.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/parallel.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/patching.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/reference.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rpl/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rpl/action.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rpl/condition.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rpl/match_builder.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rpl/policy.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rpl/result.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rpl/routemap.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rpl/statement_builder.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/aspath.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/community.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/cumulus_frr.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/entities.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/execute.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/policy.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/prefix_lists.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rpl_generators/rd.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/arista/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/arista/aaa.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/arista/iface.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/aruba/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/aruba/ap_env.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/aruba/misc.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/b4com/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/b4com/file.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/b4com/iface.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/cisco/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/cisco/iface.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/cisco/misc.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/cisco/vlandb.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/common.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/huawei/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/huawei/aaa.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/huawei/bgp.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/huawei/iface.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/huawei/misc.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/huawei/vlandb.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/nexus/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/nexus/iface.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/routeros/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/routeros/file.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/arista.deploy +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/arista.order +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/arista.rul +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/aruba.deploy +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/aruba.order +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/aruba.rul +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/b4com.deploy +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/b4com.order +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/b4com.rul +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/cisco.deploy +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/cisco.order +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/cisco.rul +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/huawei.deploy +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/huawei.order +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/huawei.rul +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/iosxr.deploy +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/iosxr.order +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/iosxr.rul +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/juniper.order +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/juniper.rul +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/nexus.deploy +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/nexus.order +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/nexus.rul +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/nokia.rul +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/optixtrans.deploy +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/optixtrans.order +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/optixtrans.rul +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/pc.deploy +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/pc.order +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/pc.rul +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/ribbon.deploy +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/ribbon.rul +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/routeros.order +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/rulebook/texts/routeros.rul +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/storage.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/text_term_format.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/tracing.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet/types.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet.egg-info/dependency_links.txt +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet.egg-info/entry_points.txt +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet.egg-info/requires.txt +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet.egg-info/top_level.txt +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet_generators/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet_generators/example/lldp.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet_generators/mesh_example/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet_generators/mesh_example/bgp.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet_generators/mesh_example/mesh_logic.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet_generators/rpl_example/__init__.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet_generators/rpl_example/generator.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet_generators/rpl_example/items.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet_generators/rpl_example/mesh.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/annet_generators/rpl_example/route_policy.py +0 -0
- {annet-2.6.0 → annet-3.1.0}/requirements.txt +0 -0
- {annet-2.6.0 → annet-3.1.0}/setup.cfg +0 -0
- {annet-2.6.0 → annet-3.1.0}/setup.py +0 -0
|
@@ -7,14 +7,15 @@ from argparse import SUPPRESS, Namespace
|
|
|
7
7
|
|
|
8
8
|
import colorama
|
|
9
9
|
import yaml
|
|
10
|
-
from annet.annlib.errors import ( # pylint: disable=wrong-import-position
|
|
11
|
-
DeployCancelled,
|
|
12
|
-
ExecError,
|
|
13
|
-
)
|
|
14
10
|
from contextlog import patch_logging, patch_threading
|
|
15
11
|
from valkit.python import valid_logging_level
|
|
16
12
|
|
|
17
13
|
import annet.argparse
|
|
14
|
+
from annet.annlib import tabparser # pylint: disable=unused-import
|
|
15
|
+
from annet.annlib.errors import ( # pylint: disable=wrong-import-position
|
|
16
|
+
DeployCancelled,
|
|
17
|
+
ExecError,
|
|
18
|
+
)
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
__all__ = ("DeployCancelled", "ExecError")
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
from annet.storage import Query
|
|
1
|
+
import dataclasses
|
|
3
2
|
from dataclasses import dataclass, fields
|
|
4
|
-
from typing import
|
|
5
|
-
|
|
6
|
-
from annet.connectors import AdapterWithName
|
|
7
|
-
from annet.storage import Device as DeviceCls
|
|
8
|
-
from annet.annlib.netdev.views.hardware import vendor_to_hw, HardwareView
|
|
3
|
+
from typing import Any, Iterable, List, Optional, Sequence
|
|
4
|
+
|
|
9
5
|
import yaml
|
|
10
6
|
|
|
7
|
+
from annet.annlib.netdev.views.dump import DumpableView
|
|
8
|
+
from annet.annlib.netdev.views.hardware import HardwareView
|
|
9
|
+
from annet.connectors import AdapterWithName
|
|
10
|
+
from annet.hardware import hardware_connector
|
|
11
|
+
from annet.storage import Device as DeviceProtocol
|
|
12
|
+
from annet.storage import Query, Storage, StorageProvider
|
|
13
|
+
|
|
11
14
|
|
|
12
15
|
@dataclass
|
|
13
16
|
class Interface(DumpableView):
|
|
@@ -23,29 +26,46 @@ class Interface(DumpableView):
|
|
|
23
26
|
@dataclass
|
|
24
27
|
class DeviceStorage:
|
|
25
28
|
fqdn: str
|
|
26
|
-
|
|
29
|
+
|
|
30
|
+
vendor: Optional[str] = None
|
|
31
|
+
hw_model: Optional[str] = None
|
|
32
|
+
sw_version: Optional[str] = None
|
|
33
|
+
|
|
27
34
|
hostname: Optional[str] = None
|
|
28
35
|
serial: Optional[str] = None
|
|
29
36
|
id: Optional[str] = None
|
|
30
37
|
interfaces: Optional[list[Interface]] = None
|
|
31
38
|
storage: Optional[Storage] = None
|
|
32
39
|
|
|
40
|
+
hw: HardwareView = dataclasses.field(init=False)
|
|
41
|
+
|
|
33
42
|
def __post_init__(self):
|
|
34
43
|
if not self.id:
|
|
35
44
|
self.id = self.fqdn
|
|
36
45
|
if not self.hostname:
|
|
37
46
|
self.hostname = self.fqdn.split(".")[0]
|
|
38
|
-
|
|
39
|
-
if
|
|
40
|
-
|
|
47
|
+
|
|
48
|
+
if self.hw_model:
|
|
49
|
+
hw = HardwareView(self.hw_model, self.sw_version)
|
|
50
|
+
if self.vendor and self.vendor != hw.vendor:
|
|
51
|
+
raise Exception(f"Vendor {self.vendor} is not vendor from hw model ({hw.vendor})")
|
|
52
|
+
else:
|
|
53
|
+
self.vendor = hw.vendor
|
|
54
|
+
else:
|
|
55
|
+
hw_provider = hardware_connector.get()
|
|
56
|
+
hw: HardwareView = hw_provider.vendor_to_hw(self.vendor)
|
|
57
|
+
if not hw:
|
|
58
|
+
raise Exception("unknown vendor")
|
|
59
|
+
self.hw_model = hw.model
|
|
41
60
|
self.hw = hw
|
|
61
|
+
|
|
42
62
|
if isinstance(self.interfaces, list):
|
|
43
63
|
interfaces = []
|
|
44
64
|
for iface in self.interfaces:
|
|
45
65
|
try:
|
|
46
66
|
interfaces.append(Interface(**iface))
|
|
47
67
|
except Exception as e:
|
|
48
|
-
raise Exception("unable to parse %s as Interface %s" % (iface, e))
|
|
68
|
+
raise Exception("unable to parse %s as Interface: %s" % (iface, e))
|
|
49
69
|
self.interfaces = interfaces
|
|
50
70
|
|
|
51
71
|
def set_storage(self, storage: Storage):
|
|
@@ -53,7 +73,7 @@ class DeviceStorage:
|
|
|
53
73
|
|
|
54
74
|
|
|
55
75
|
@dataclass
|
|
56
|
-
class Device(
|
|
76
|
+
class Device(DeviceProtocol, DumpableView):
|
|
57
77
|
dev: DeviceStorage
|
|
58
78
|
|
|
59
79
|
def __hash__(self):
|
|
@@ -79,7 +99,7 @@ class Device(DeviceCls, DumpableView):
|
|
|
79
99
|
|
|
80
100
|
@property
|
|
81
101
|
def storage(self) -> Storage:
|
|
82
|
-
return self
|
|
102
|
+
return self.dev.storage
|
|
83
103
|
|
|
84
104
|
@property
|
|
85
105
|
def hw(self) -> HardwareView:
|
|
@@ -91,7 +111,11 @@ class Device(DeviceCls, DumpableView):
|
|
|
91
111
|
|
|
92
112
|
@property
|
|
93
113
|
def neighbours_ids(self):
|
|
94
|
-
|
|
114
|
+
return []
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def neighbours_fqdns(self) -> list[str]:
|
|
118
|
+
return []
|
|
95
119
|
|
|
96
120
|
def make_lag(self, lag: int, ports: Sequence[str], lag_min_links: Optional[int]) -> Interface:
|
|
97
121
|
raise NotImplementedError
|
|
@@ -105,8 +129,8 @@ class Device(DeviceCls, DumpableView):
|
|
|
105
129
|
def find_interface(self, name: str) -> Optional[Interface]:
|
|
106
130
|
raise NotImplementedError
|
|
107
131
|
|
|
108
|
-
def
|
|
109
|
-
|
|
132
|
+
def flush_perf(self):
|
|
133
|
+
pass
|
|
110
134
|
|
|
111
135
|
|
|
112
136
|
@dataclass
|
|
@@ -120,7 +144,7 @@ class Devices:
|
|
|
120
144
|
try:
|
|
121
145
|
devices.append(Device(dev=DeviceStorage(**dev)))
|
|
122
146
|
except Exception as e:
|
|
123
|
-
raise Exception("unable to parse %s as Device %s" % (dev, e))
|
|
147
|
+
raise Exception("unable to parse %s as Device: %s" % (dev, e))
|
|
124
148
|
self.devices = devices
|
|
125
149
|
|
|
126
150
|
|
|
@@ -193,12 +217,12 @@ class FS(Storage):
|
|
|
193
217
|
return [dev.fqdn for dev in result]
|
|
194
218
|
|
|
195
219
|
def make_devices(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
220
|
+
self,
|
|
221
|
+
query: Query | list,
|
|
222
|
+
preload_neighbors=False,
|
|
223
|
+
use_mesh=None,
|
|
224
|
+
preload_extra_fields=False,
|
|
225
|
+
**kwargs,
|
|
202
226
|
) -> list[Device]:
|
|
203
227
|
if isinstance(query, list):
|
|
204
228
|
query = Query.new(query)
|
|
@@ -231,8 +255,7 @@ def filter_query(devices: list[Device], query: Query) -> list[Device]:
|
|
|
231
255
|
|
|
232
256
|
def read_inventory(path: str, storage: Storage) -> Devices:
|
|
233
257
|
with open(path, "r") as f:
|
|
234
|
-
|
|
235
|
-
file_data = yaml.load(data, Loader=yaml.BaseLoader)
|
|
258
|
+
file_data = yaml.load(f, Loader=yaml.SafeLoader)
|
|
236
259
|
res = dataclass_from_dict(Devices, file_data)
|
|
237
260
|
for dev in res.devices:
|
|
238
261
|
dev.dev.set_storage(storage)
|
|
@@ -4,32 +4,13 @@ from annet.annlib.netdev.views.hardware import HardwareView
|
|
|
4
4
|
|
|
5
5
|
logger = getLogger(__name__)
|
|
6
6
|
|
|
7
|
-
_VENDORS = {
|
|
8
|
-
"cisco": "Cisco",
|
|
9
|
-
"catalyst": "Cisco Catalyst",
|
|
10
|
-
"nexus": "Cisco Nexus",
|
|
11
|
-
"iosxr": "Cisco XR",
|
|
12
|
-
"huawei": "Huawei",
|
|
13
|
-
"optixtrans": "Huawei OptiXtrans",
|
|
14
|
-
"juniper": "Juniper",
|
|
15
|
-
"arista": "Arista",
|
|
16
|
-
"pc": "PC",
|
|
17
|
-
"nokia": "Nokia",
|
|
18
|
-
"aruba": "Aruba",
|
|
19
|
-
"routeros": "RouterOS",
|
|
20
|
-
"ribbon": "Ribbon",
|
|
21
|
-
"b4com": "B4com",
|
|
22
|
-
"h3c": "H3C",
|
|
23
|
-
}
|
|
24
|
-
|
|
25
7
|
|
|
26
8
|
def get_hw(manufacturer: str, model: str, platform_name: str):
|
|
27
|
-
#
|
|
9
|
+
# By some reason Netbox calls Mellanox SN as MSN, so we fix them here
|
|
28
10
|
if manufacturer == "Mellanox" and model.startswith("MSN"):
|
|
29
11
|
model = model.replace("MSN", "SN", 1)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return hw
|
|
12
|
+
|
|
13
|
+
return HardwareView(manufacturer + " " + model, platform_name)
|
|
33
14
|
|
|
34
15
|
|
|
35
16
|
def get_breed(manufacturer: str, model: str):
|
|
@@ -5,8 +5,9 @@ from ipaddress import ip_interface, IPv6Interface
|
|
|
5
5
|
from typing import List, Optional, Any, Dict, Sequence, TypeVar, Generic
|
|
6
6
|
|
|
7
7
|
from annet.annlib.netdev.views.dump import DumpableView
|
|
8
|
-
from annet.annlib.netdev.views.hardware import HardwareView, lag_name
|
|
8
|
+
from annet.annlib.netdev.views.hardware import HardwareView, lag_name
|
|
9
9
|
from annet.storage import Storage
|
|
10
|
+
from annet.vendors import registry_connector
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
@dataclass
|
|
@@ -259,7 +260,7 @@ class NetboxDevice(Entity, Generic[_InterfaceT]):
|
|
|
259
260
|
return lag_interface
|
|
260
261
|
|
|
261
262
|
def _svi_name(self, svi: int) -> str:
|
|
262
|
-
return
|
|
263
|
+
return registry_connector.get().match(self.hw).svi_name(svi)
|
|
263
264
|
|
|
264
265
|
def add_svi(self, svi: int) -> _InterfaceT:
|
|
265
266
|
name = self._svi_name(svi)
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
from dataclasses import dataclass, field
|
|
2
2
|
from datetime import datetime, timezone
|
|
3
3
|
from ipaddress import ip_interface, IPv6Interface
|
|
4
|
-
from typing import List, Optional, Any, Dict, Sequence
|
|
4
|
+
from typing import List, Optional, Any, Dict, Sequence
|
|
5
5
|
|
|
6
6
|
from annet.annlib.netdev.views.dump import DumpableView
|
|
7
|
-
from annet.annlib.netdev.views.hardware import HardwareView, lag_name
|
|
7
|
+
from annet.annlib.netdev.views.hardware import HardwareView, lag_name
|
|
8
8
|
from annet.storage import Storage
|
|
9
|
+
from annet.vendors import registry_connector
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
@dataclass
|
|
@@ -259,7 +260,7 @@ class NetboxDevice(Entity):
|
|
|
259
260
|
return lag_interface
|
|
260
261
|
|
|
261
262
|
def _svi_name(self, svi: int) -> str:
|
|
262
|
-
return
|
|
263
|
+
return registry_connector.get().match(self.hw).svi_name(svi)
|
|
263
264
|
|
|
264
265
|
def add_svi(self, svi: int) -> Interface:
|
|
265
266
|
name = self._svi_name(svi)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import functools
|
|
1
2
|
from typing import Optional
|
|
2
3
|
|
|
3
4
|
from annet.annlib.netdev.devdb import parse_hw_model
|
|
@@ -51,20 +52,31 @@ class HardwareLeaf(DumpableView):
|
|
|
51
52
|
|
|
52
53
|
|
|
53
54
|
class HardwareView(HardwareLeaf):
|
|
54
|
-
def __init__(self, hw_model, sw_version):
|
|
55
|
-
|
|
55
|
+
def __init__(self, hw_model, sw_version: Optional[str] = None):
|
|
56
|
+
true_sequences, false_sequences = parse_hw_model(hw_model or "")
|
|
56
57
|
super().__init__((), true_sequences, false_sequences)
|
|
57
58
|
self.model = hw_model or ""
|
|
58
59
|
self._soft = sw_version or ""
|
|
59
60
|
|
|
60
61
|
@property
|
|
61
62
|
def vendor(self) -> Optional[str]:
|
|
62
|
-
|
|
63
|
+
from annet.hardware import hardware_connector
|
|
64
|
+
return hardware_connector.get().hw_to_vendor(self)
|
|
63
65
|
|
|
64
66
|
@property
|
|
65
67
|
def soft(self) -> str:
|
|
66
68
|
return self._soft
|
|
67
69
|
|
|
70
|
+
@soft.setter
|
|
71
|
+
def soft(self, value: str) -> None:
|
|
72
|
+
self._soft = value
|
|
73
|
+
|
|
74
|
+
def match(self, expr: str) -> bool:
|
|
75
|
+
dev_path = expr.split(".")
|
|
76
|
+
if dev_path and dev_path[0] == "hw":
|
|
77
|
+
dev_path = dev_path[1:]
|
|
78
|
+
return bool(functools.reduce(getattr, dev_path, self))
|
|
79
|
+
|
|
68
80
|
def __hash__(self):
|
|
69
81
|
return hash(self.model)
|
|
70
82
|
|
|
@@ -72,62 +84,6 @@ class HardwareView(HardwareLeaf):
|
|
|
72
84
|
return self.model == other.model
|
|
73
85
|
|
|
74
86
|
|
|
75
|
-
def hw_to_vendor(hw: HardwareView) -> Optional[str]:
|
|
76
|
-
if hw.Nexus:
|
|
77
|
-
return "nexus"
|
|
78
|
-
elif hw.Cisco.XR or hw.Cisco.ASR or hw.Cisco.XRV:
|
|
79
|
-
return "iosxr"
|
|
80
|
-
elif hw.Cisco:
|
|
81
|
-
return "cisco"
|
|
82
|
-
elif hw.OptiXtrans:
|
|
83
|
-
return "optixtrans"
|
|
84
|
-
elif hw.Huawei:
|
|
85
|
-
return "huawei"
|
|
86
|
-
elif hw.Juniper:
|
|
87
|
-
return "juniper"
|
|
88
|
-
elif hw.Arista:
|
|
89
|
-
return "arista"
|
|
90
|
-
elif hw.PC:
|
|
91
|
-
return "pc"
|
|
92
|
-
elif hw.Nokia:
|
|
93
|
-
return "nokia"
|
|
94
|
-
elif hw.RouterOS:
|
|
95
|
-
return "routeros"
|
|
96
|
-
elif hw.Aruba:
|
|
97
|
-
return "aruba"
|
|
98
|
-
elif hw.Ribbon:
|
|
99
|
-
return "ribbon"
|
|
100
|
-
elif hw.H3C:
|
|
101
|
-
return "h3c"
|
|
102
|
-
elif hw.B4com:
|
|
103
|
-
return "b4com"
|
|
104
|
-
return None
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def vendor_to_hw(vendor):
|
|
108
|
-
hw = HardwareView(
|
|
109
|
-
{
|
|
110
|
-
"cisco": "Cisco",
|
|
111
|
-
"catalyst": "Cisco Catalyst",
|
|
112
|
-
"nexus": "Cisco Nexus",
|
|
113
|
-
"iosxr": "Cisco XR",
|
|
114
|
-
"huawei": "Huawei",
|
|
115
|
-
"optixtrans": "Huawei OptiXtrans",
|
|
116
|
-
"juniper": "Juniper",
|
|
117
|
-
"arista": "Arista",
|
|
118
|
-
"pc": "PC",
|
|
119
|
-
"nokia": "Nokia",
|
|
120
|
-
"aruba": "Aruba",
|
|
121
|
-
"routeros": "RouterOS",
|
|
122
|
-
"ribbon": "Ribbon",
|
|
123
|
-
"h3c": "H3C",
|
|
124
|
-
"b4com": "B4com",
|
|
125
|
-
}.get(vendor.lower(), vendor),
|
|
126
|
-
None,
|
|
127
|
-
)
|
|
128
|
-
return hw
|
|
129
|
-
|
|
130
|
-
|
|
131
87
|
def lag_name(hw: HardwareView, nlagg: int) -> str:
|
|
132
88
|
if hw.Huawei:
|
|
133
89
|
return f"Eth-Trunk{nlagg}"
|
|
@@ -148,14 +104,3 @@ def lag_name(hw: HardwareView, nlagg: int) -> str:
|
|
|
148
104
|
if hw.Nokia:
|
|
149
105
|
return f"lagg-{nlagg}"
|
|
150
106
|
raise NotImplementedError(hw)
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
def svi_name(hw: HardwareView, num: int) -> str:
|
|
154
|
-
if hw.Juniper:
|
|
155
|
-
return f"irb.{num}"
|
|
156
|
-
elif hw.Huawei:
|
|
157
|
-
return f"Vlanif{num}"
|
|
158
|
-
elif hw.Arista or hw.Cisco:
|
|
159
|
-
return f"Vlan{num}"
|
|
160
|
-
else:
|
|
161
|
-
return f"vlan{num}"
|
|
@@ -19,6 +19,7 @@ from .rulebook.common import call_diff_logic
|
|
|
19
19
|
from .rulebook.common import default as common_default
|
|
20
20
|
from .tabparser import CommonFormatter
|
|
21
21
|
from .types import Diff, Op
|
|
22
|
+
from ..vendors import registry_connector
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
# =====
|
|
@@ -183,7 +184,8 @@ class Orderer:
|
|
|
183
184
|
f_rule = ""
|
|
184
185
|
children = []
|
|
185
186
|
ordering = self.rb
|
|
186
|
-
|
|
187
|
+
|
|
188
|
+
block_exit = registry_connector.get()[self.vendor].exit
|
|
187
189
|
|
|
188
190
|
for (order, (raw_rule, rule)) in enumerate(ordering.items()):
|
|
189
191
|
if (
|
|
@@ -224,14 +226,15 @@ class Orderer:
|
|
|
224
226
|
return (f_order or 0), cmd_direct, odict(children), f_rule
|
|
225
227
|
|
|
226
228
|
def order_config(self, config):
|
|
227
|
-
if self.vendor not in
|
|
229
|
+
if self.vendor not in registry_connector.get():
|
|
228
230
|
return config
|
|
229
|
-
|
|
230
|
-
ordered = []
|
|
231
|
-
reverse_prefix = platform.VENDOR_REVERSES[self.vendor]
|
|
232
231
|
if not config:
|
|
233
232
|
return odict()
|
|
234
|
-
|
|
233
|
+
|
|
234
|
+
ordered = []
|
|
235
|
+
reverse_prefix = registry_connector.get()[self.vendor].reverse
|
|
236
|
+
|
|
237
|
+
for row, children in config.items():
|
|
235
238
|
cmd_direct = not row.startswith(reverse_prefix)
|
|
236
239
|
(order, direct, rb, _) = self.get_order(row, cmd_direct)
|
|
237
240
|
child_orderer = Orderer(rb, self.vendor)
|
|
@@ -5,7 +5,8 @@ from typing import Any, Callable, List, Optional
|
|
|
5
5
|
from valkit import add_validator_magic
|
|
6
6
|
from valkit.common import valid_bool, valid_number, valid_string_list
|
|
7
7
|
|
|
8
|
-
from . import
|
|
8
|
+
from annet.vendors import registry_connector
|
|
9
|
+
from . import syntax
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
# =====
|
|
@@ -13,7 +14,7 @@ from . import platform, syntax
|
|
|
13
14
|
def compile_acl_text(text, vendor, allow_ignore=False):
|
|
14
15
|
return _compile_acl(
|
|
15
16
|
trees=[syntax.parse_text(text, _PARAMS_SCHEME)],
|
|
16
|
-
reverse_prefix=
|
|
17
|
+
reverse_prefix=registry_connector.get()[vendor].reverse,
|
|
17
18
|
allow_ignore=allow_ignore,
|
|
18
19
|
vendor=vendor,
|
|
19
20
|
)
|
|
@@ -4,7 +4,8 @@ from collections import OrderedDict as odict
|
|
|
4
4
|
|
|
5
5
|
from valkit.common import valid_bool, valid_string_list
|
|
6
6
|
|
|
7
|
-
from . import
|
|
7
|
+
from annet.vendors import registry_connector
|
|
8
|
+
from . import syntax
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
# =====
|
|
@@ -25,7 +26,7 @@ def compile_ordering_text(text, vendor):
|
|
|
25
26
|
"default": None,
|
|
26
27
|
}
|
|
27
28
|
}),
|
|
28
|
-
reverse_prefix=
|
|
29
|
+
reverse_prefix=registry_connector.get()[vendor].reverse,
|
|
29
30
|
)
|
|
30
31
|
|
|
31
32
|
|
|
@@ -135,20 +135,21 @@ class DiffItem(typing.NamedTuple):
|
|
|
135
135
|
diff_pre: typing.Dict[str, typing.Any]
|
|
136
136
|
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
Differ = typing.Callable[[odict, odict, odict, tuple[Op, ...]], list[DiffItem]]
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def default_diff(old: odict, new: odict, diff_pre: odict, _pops: tuple[Op, ...] = (Op.AFFECTED,)) -> list[DiffItem]:
|
|
139
142
|
diff = base_diff(old, new, diff_pre, _pops, moved_to_affected=True)
|
|
140
143
|
return diff
|
|
141
144
|
|
|
142
145
|
|
|
143
|
-
def ordered_diff(old, new, diff_pre, _pops=(Op.AFFECTED,)):
|
|
146
|
+
def ordered_diff(old: odict, new: odict, diff_pre: odict, _pops: tuple[Op, ...] = (Op.AFFECTED,)) -> list[DiffItem]:
|
|
144
147
|
diff = base_diff(old, new, diff_pre, _pops, moved_to_affected=False)
|
|
145
148
|
return diff
|
|
146
149
|
|
|
147
150
|
|
|
148
|
-
def rewrite_diff(old, new, diff_pre, _pops=(Op.AFFECTED,)):
|
|
149
|
-
def iter_diff(
|
|
150
|
-
diff: typing.List[DiffItem],
|
|
151
|
-
) -> typing.Iterable[typing.Tuple[int, typing.List[DiffItem]]]:
|
|
151
|
+
def rewrite_diff(old: odict, new: odict, diff_pre: odict, _pops: tuple[Op, ...] = (Op.AFFECTED,)) -> list[DiffItem]:
|
|
152
|
+
def iter_diff(diff: list[DiffItem]) -> typing.Iterable[tuple[int, list[DiffItem]]]:
|
|
152
153
|
queue = [diff]
|
|
153
154
|
while queue:
|
|
154
155
|
items, queue = queue[0], queue[1:]
|
|
@@ -173,16 +174,18 @@ def rewrite_diff(old, new, diff_pre, _pops=(Op.AFFECTED,)):
|
|
|
173
174
|
return diff
|
|
174
175
|
|
|
175
176
|
|
|
176
|
-
def multiline_diff(old, new, diff_pre, _pops=(Op.AFFECTED,)):
|
|
177
|
+
def multiline_diff(old: odict, new: odict, diff_pre: odict, _pops: tuple[Op, ...] = (Op.AFFECTED,)) -> list[DiffItem]:
|
|
177
178
|
"""
|
|
178
179
|
Особая логика diff'a для хуавейных мультилайнов.
|
|
179
180
|
Она трактует все дочерние элементы %multiline-команды как
|
|
180
181
|
одну общую команду, покидывая внутрь тот Op который был
|
|
181
182
|
определен на вернем уровне
|
|
182
183
|
"""
|
|
184
|
+
|
|
183
185
|
def process_multiline(op, tree):
|
|
184
|
-
for
|
|
185
|
-
yield
|
|
186
|
+
for row, children in tree.items():
|
|
187
|
+
yield op, row, list(process_multiline(op, children)), None
|
|
188
|
+
|
|
186
189
|
ret = []
|
|
187
190
|
for item in default_diff(old, new, diff_pre, _pops):
|
|
188
191
|
if old.get(item.row, {}) == new.get(item.row, {}):
|
|
@@ -192,23 +195,27 @@ def multiline_diff(old, new, diff_pre, _pops=(Op.AFFECTED,)):
|
|
|
192
195
|
op, tree = Op.REMOVED, old
|
|
193
196
|
children = list(process_multiline(op, tree[item.row]))
|
|
194
197
|
ret.append(DiffItem(item.op, item.row, children, item.diff_pre))
|
|
198
|
+
|
|
195
199
|
return ret
|
|
196
200
|
|
|
197
201
|
|
|
198
|
-
def base_diff(
|
|
202
|
+
def base_diff(
|
|
203
|
+
old: odict, new: odict, diff_pre: odict, pops: tuple[Op, ...], moved_to_affected: bool = False
|
|
204
|
+
) -> list[DiffItem]:
|
|
199
205
|
diff_indexed: typing.List[typing.Tuple[int, DiffItem]] = []
|
|
200
206
|
old = _ignore_case(diff_pre, old)
|
|
201
207
|
new = _ignore_case(diff_pre, new)
|
|
202
208
|
|
|
203
|
-
for
|
|
209
|
+
for index, row in enumerate(old):
|
|
204
210
|
if row not in new:
|
|
205
|
-
children = call_diff_logic(diff_pre[row]["subtree"], old[row],
|
|
211
|
+
children = call_diff_logic(diff_pre[row]["subtree"], old[row], odict(), pops + (Op.REMOVED,))
|
|
206
212
|
diff_indexed.append((index, DiffItem(
|
|
207
213
|
op=Op.REMOVED,
|
|
208
214
|
row=row,
|
|
209
215
|
children=children,
|
|
210
216
|
diff_pre=diff_pre[row]["match"],
|
|
211
217
|
)))
|
|
218
|
+
|
|
212
219
|
old_indexes = {row: index for (index, row) in enumerate(old)}
|
|
213
220
|
block_in_disorder = False
|
|
214
221
|
parent_op = pops[-1]
|
|
@@ -232,13 +239,13 @@ def base_diff(old, new, diff_pre, pops, moved_to_affected=False) -> typing.List[
|
|
|
232
239
|
return [x[1] for x in diff_indexed]
|
|
233
240
|
|
|
234
241
|
|
|
235
|
-
def call_diff_logic(diff_pre, old, new, pops=(Op.AFFECTED,)):
|
|
242
|
+
def call_diff_logic(diff_pre: odict, old: odict, new: odict, pops: tuple[Op, ...] = (Op.AFFECTED,)):
|
|
236
243
|
"""
|
|
237
244
|
Группируем команды в старом и новом конфиге согласно выставленным
|
|
238
245
|
в рулбуке атрибутам %diff_logic и вызывает их поочереди согласно
|
|
239
246
|
порядку команд в old и new, предпочитая old (т.е. сначала удаления)
|
|
240
247
|
"""
|
|
241
|
-
diff_logics = odict()
|
|
248
|
+
diff_logics: odict = odict()
|
|
242
249
|
for row in old:
|
|
243
250
|
logic = diff_pre[row]["match"]["attrs"]["diff_logic"]
|
|
244
251
|
if logic not in diff_logics:
|
|
@@ -819,24 +819,6 @@ class RosFormatter(CommonFormatter):
|
|
|
819
819
|
return commands
|
|
820
820
|
|
|
821
821
|
|
|
822
|
-
def make_formatter(vendor, **kwargs):
|
|
823
|
-
formatters = {
|
|
824
|
-
"juniper": JuniperFormatter,
|
|
825
|
-
"cisco": CiscoFormatter,
|
|
826
|
-
"nexus": NexusFormatter,
|
|
827
|
-
"huawei": HuaweiFormatter,
|
|
828
|
-
"optixtrans": OptixtransFormatter,
|
|
829
|
-
"arista": AristaFormatter,
|
|
830
|
-
"nokia": NokiaFormatter,
|
|
831
|
-
"routeros": RosFormatter,
|
|
832
|
-
"aruba": ArubaFormatter,
|
|
833
|
-
"pc": CommonFormatter,
|
|
834
|
-
"ribbon": RibbonFormatter,
|
|
835
|
-
"b4com": B4comFormatter,
|
|
836
|
-
}
|
|
837
|
-
return formatters[vendor](**kwargs)
|
|
838
|
-
|
|
839
|
-
|
|
840
822
|
# ====
|
|
841
823
|
def parse_to_tree(text, splitter, comments=("!", "#")):
|
|
842
824
|
tree = odict()
|
|
@@ -25,7 +25,6 @@ import annet.deploy_ui
|
|
|
25
25
|
import annet.lib
|
|
26
26
|
from annet.annlib import jsontools
|
|
27
27
|
from annet.annlib.netdev.views.hardware import HardwareView
|
|
28
|
-
from annet.annlib.rbparser.platform import VENDOR_REVERSES
|
|
29
28
|
from annet.annlib.types import GeneratorType
|
|
30
29
|
from contextlog import get_logger
|
|
31
30
|
|
|
@@ -48,6 +47,7 @@ from annet.parallel import Parallel, TaskResult
|
|
|
48
47
|
from annet.reference import RefTracker
|
|
49
48
|
from annet.storage import Device, get_storage
|
|
50
49
|
from annet.types import Diff, ExitCode, OldNewResult, Op, PCDiff, PCDiffFile
|
|
50
|
+
from annet.vendors import registry_connector
|
|
51
51
|
|
|
52
52
|
DEFAULT_INDENT = " "
|
|
53
53
|
|
|
@@ -138,16 +138,19 @@ def _read_device_config(path, hw):
|
|
|
138
138
|
_logger = get_logger()
|
|
139
139
|
_logger.debug("Reading %r ...", path)
|
|
140
140
|
score = 1
|
|
141
|
+
vendor_registry = registry_connector.get()
|
|
141
142
|
|
|
142
143
|
with open(path) as cfgdump_file:
|
|
143
144
|
text = cfgdump_file.read()
|
|
144
145
|
try:
|
|
145
146
|
if not hw:
|
|
146
147
|
hw, score = guess_hw(text)
|
|
148
|
+
|
|
147
149
|
config = tabparser.parse_to_tree(
|
|
148
150
|
text=text,
|
|
149
|
-
splitter=
|
|
151
|
+
splitter=vendor_registry.match(hw).make_formatter().split,
|
|
150
152
|
)
|
|
153
|
+
|
|
151
154
|
return config, hw, score
|
|
152
155
|
except tabparser.ParserError:
|
|
153
156
|
_logger.exception("Parser error: %r", path)
|
|
@@ -156,7 +159,7 @@ def _read_device_config(path, hw):
|
|
|
156
159
|
|
|
157
160
|
# =====
|
|
158
161
|
def _format_patch_blocks(patch_tree, hw, indent):
|
|
159
|
-
formatter =
|
|
162
|
+
formatter = registry_connector.get().match(hw).make_formatter(indent=indent)
|
|
160
163
|
return formatter.patch(patch_tree)
|
|
161
164
|
|
|
162
165
|
|
|
@@ -395,9 +398,12 @@ class CliDeployerJob(DeployerJob):
|
|
|
395
398
|
(diff_obj, patch_tree) = _diff_and_patch(device, old, new, acl_rules,
|
|
396
399
|
res.filter_acl_rules, self.add_comments,
|
|
397
400
|
do_commit=not self.args.dont_commit)
|
|
398
|
-
|
|
401
|
+
|
|
402
|
+
formatter = registry_connector.get().match(device.hw).make_formatter(indent="")
|
|
403
|
+
cmds = formatter.cmd_paths(patch_tree)
|
|
399
404
|
if not cmds:
|
|
400
405
|
return
|
|
406
|
+
|
|
401
407
|
self._has_diff = True
|
|
402
408
|
self.diffs[device] = diff_obj
|
|
403
409
|
self.cmd_lines.extend(["= %s " % device.hostname, ""])
|
|
@@ -550,7 +556,7 @@ class Deployer:
|
|
|
550
556
|
dest_name = "= %s" % ", ".join([dev.hostname for dev in devices])
|
|
551
557
|
diff_lines.extend([dest_name, ""])
|
|
552
558
|
|
|
553
|
-
for line in
|
|
559
|
+
for line in registry_connector.get().match(devices[0].hw).make_formatter().diff(diff_obj):
|
|
554
560
|
diff_lines.append(line)
|
|
555
561
|
diff_lines.append("")
|
|
556
562
|
return diff_lines
|
|
@@ -786,14 +792,17 @@ def guess_hw(config_text: str):
|
|
|
786
792
|
текста конфига и annet/rulebook/texts/*.rul"""
|
|
787
793
|
scores = {}
|
|
788
794
|
hw_provider = hardware_connector.get()
|
|
789
|
-
|
|
795
|
+
vendor_registry = registry_connector.get()
|
|
796
|
+
for vendor in vendor_registry:
|
|
790
797
|
hw = hw_provider.vendor_to_hw(vendor)
|
|
791
|
-
fmtr = tabparser.make_formatter(hw)
|
|
792
798
|
rb = rulebook.get_rulebook(hw)
|
|
799
|
+
fmtr = vendor_registry[vendor].make_formatter()
|
|
800
|
+
|
|
793
801
|
try:
|
|
794
802
|
config = tabparser.parse_to_tree(config_text, fmtr.split)
|
|
795
803
|
except Exception:
|
|
796
804
|
continue
|
|
805
|
+
|
|
797
806
|
pre = patching.make_pre(patching.make_diff({}, config, rb, []))
|
|
798
807
|
metric = _count_pre_score(pre)
|
|
799
808
|
scores[metric] = hw
|