trigger 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- trigger/__init__.py +7 -0
- trigger/acl/__init__.py +32 -0
- trigger/acl/autoacl.py +70 -0
- trigger/acl/db.py +324 -0
- trigger/acl/dicts.py +357 -0
- trigger/acl/grammar.py +112 -0
- trigger/acl/ios.py +222 -0
- trigger/acl/junos.py +422 -0
- trigger/acl/models.py +118 -0
- trigger/acl/parser.py +168 -0
- trigger/acl/queue.py +296 -0
- trigger/acl/support.py +1431 -0
- trigger/acl/tools.py +746 -0
- trigger/bin/__init__.py +0 -0
- trigger/bin/acl.py +233 -0
- trigger/bin/acl_script.py +574 -0
- trigger/bin/aclconv.py +82 -0
- trigger/bin/check_access.py +93 -0
- trigger/bin/check_syntax.py +66 -0
- trigger/bin/fe.py +197 -0
- trigger/bin/find_access.py +191 -0
- trigger/bin/gnng.py +434 -0
- trigger/bin/gong.py +86 -0
- trigger/bin/load_acl.py +841 -0
- trigger/bin/load_config.py +18 -0
- trigger/bin/netdev.py +317 -0
- trigger/bin/optimizer.py +638 -0
- trigger/bin/run_cmds.py +18 -0
- trigger/changemgmt/__init__.py +352 -0
- trigger/changemgmt/bounce.py +57 -0
- trigger/cmds.py +1217 -0
- trigger/conf/__init__.py +94 -0
- trigger/conf/global_settings.py +674 -0
- trigger/contrib/__init__.py +7 -0
- trigger/exceptions.py +307 -0
- trigger/gorc.py +172 -0
- trigger/netdevices/__init__.py +1288 -0
- trigger/netdevices/loader.py +174 -0
- trigger/netscreen.py +1030 -0
- trigger/packages/__init__.py +6 -0
- trigger/packages/peewee.py +8084 -0
- trigger/rancid.py +463 -0
- trigger/tacacsrc.py +584 -0
- trigger/twister.py +2203 -0
- trigger/twister2.py +745 -0
- trigger/utils/__init__.py +88 -0
- trigger/utils/cli.py +349 -0
- trigger/utils/importlib.py +77 -0
- trigger/utils/network.py +157 -0
- trigger/utils/rcs.py +178 -0
- trigger/utils/templates.py +81 -0
- trigger/utils/url.py +78 -0
- trigger/utils/xmltodict.py +298 -0
- trigger-2.0.0.dist-info/METADATA +146 -0
- trigger-2.0.0.dist-info/RECORD +61 -0
- trigger-2.0.0.dist-info/WHEEL +5 -0
- trigger-2.0.0.dist-info/entry_points.txt +15 -0
- trigger-2.0.0.dist-info/licenses/AUTHORS.md +20 -0
- trigger-2.0.0.dist-info/licenses/LICENSE.md +28 -0
- trigger-2.0.0.dist-info/top_level.txt +2 -0
- twisted/plugins/trigger_xmlrpc.py +124 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Wrapper for loading metadata from storage of some sort (e.g. filesystem,
|
|
3
|
+
database)
|
|
4
|
+
|
|
5
|
+
This uses NETDEVICE_LOADERS settings, which is a list of loaders to use.
|
|
6
|
+
Each loader is expected to have this interface::
|
|
7
|
+
|
|
8
|
+
callable(data_source, **kwargs)
|
|
9
|
+
|
|
10
|
+
``data_source`` is typically a file path from which to load the metadata, but can
|
|
11
|
+
be also be a list/tuple of [data_source, *args]
|
|
12
|
+
``kwargs`` are any optional keyword arguments you wish to send along.
|
|
13
|
+
|
|
14
|
+
The loader must return an iterable of key/value pairs (dicts, 2-tuples, etc.).
|
|
15
|
+
|
|
16
|
+
Each loader should have an ``is_usable`` attribute set. This is a boolean that
|
|
17
|
+
specifies whether the loader can be used with this Python installation. Each
|
|
18
|
+
loader is responsible for setting this when it is initialized.
|
|
19
|
+
|
|
20
|
+
This code is based on Django's template loader code: http://bit.ly/WWOLU3
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from collections import namedtuple
|
|
24
|
+
|
|
25
|
+
from twisted.python import log
|
|
26
|
+
|
|
27
|
+
from trigger.conf import settings
|
|
28
|
+
from trigger.exceptions import ImproperlyConfigured, LoaderFailed
|
|
29
|
+
from trigger.utils.importlib import import_module
|
|
30
|
+
|
|
31
|
+
# Exports
|
|
32
|
+
__all__ = ("BaseLoader", "load_metadata")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# Classes
|
|
36
|
+
class BaseLoader:
|
|
37
|
+
is_usable = False
|
|
38
|
+
|
|
39
|
+
def __init__(self, *args, **kwargs):
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
def __call__(self, data_source, **kwargs):
|
|
43
|
+
return self.load_data(data_source, **kwargs)
|
|
44
|
+
|
|
45
|
+
def load_data(self, data_source, **kwargs):
|
|
46
|
+
data = self.load_data_source(data_source, **kwargs)
|
|
47
|
+
return data
|
|
48
|
+
|
|
49
|
+
def load_data_source(self, data_source, **kwargs):
|
|
50
|
+
"""
|
|
51
|
+
Returns an iterable of key/value pairs for the given ``data_source``.
|
|
52
|
+
"""
|
|
53
|
+
raise NotImplementedError
|
|
54
|
+
|
|
55
|
+
def reset(self):
|
|
56
|
+
"""
|
|
57
|
+
Resets any state maintained by the loader instance.
|
|
58
|
+
"""
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# Functions
|
|
63
|
+
def find_data_loader(loader):
|
|
64
|
+
"""
|
|
65
|
+
Given a ``loader`` string/list/tuple, try to unpack, load it, and return the
|
|
66
|
+
callable loader object.
|
|
67
|
+
|
|
68
|
+
If ``loader`` is specified as string, treat it as the fully-qualified
|
|
69
|
+
Python path to the callable Loader object.
|
|
70
|
+
|
|
71
|
+
Optionally, if `loader`` is a list/tuple, the first item in the tuple should be the
|
|
72
|
+
Loader's module path, and subsequent items are passed to the Loader object
|
|
73
|
+
during initialization. This could be useful in initializing a custom Loader
|
|
74
|
+
for a database backend, for example.
|
|
75
|
+
|
|
76
|
+
:param loader:
|
|
77
|
+
A string represnting the Python path to a Loader object, or list/tuple
|
|
78
|
+
of loader path and args to pass to the Loader.
|
|
79
|
+
"""
|
|
80
|
+
if isinstance(loader, (tuple, list)):
|
|
81
|
+
loader, args = loader[0], loader[1:]
|
|
82
|
+
else:
|
|
83
|
+
args = []
|
|
84
|
+
|
|
85
|
+
log.msg(f"BUILDING LOADER: {loader}; WITH ARGS: {args}")
|
|
86
|
+
err_template = "Error importing data source loader %s: '%s'"
|
|
87
|
+
if isinstance(loader, str):
|
|
88
|
+
module, attr = loader.rsplit(".", 1)
|
|
89
|
+
try:
|
|
90
|
+
mod = import_module(module)
|
|
91
|
+
except ImportError as err:
|
|
92
|
+
raise ImproperlyConfigured(err_template % (loader, err))
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
DataLoader = getattr(mod, attr)
|
|
96
|
+
except AttributeError as err:
|
|
97
|
+
raise ImproperlyConfigured(err_template % (loader, err))
|
|
98
|
+
|
|
99
|
+
if hasattr(DataLoader, "load_data_source"):
|
|
100
|
+
func = DataLoader(*args)
|
|
101
|
+
else:
|
|
102
|
+
# Try loading module the old-fashioned way where string is full
|
|
103
|
+
# path to callabale.
|
|
104
|
+
if args:
|
|
105
|
+
raise ImproperlyConfigured(
|
|
106
|
+
f"Error importing data source loader {loader}: Can't pass arguments to function-based loader!"
|
|
107
|
+
)
|
|
108
|
+
func = DataLoader
|
|
109
|
+
|
|
110
|
+
if not func.is_usable:
|
|
111
|
+
import warnings
|
|
112
|
+
|
|
113
|
+
warnings.warn(
|
|
114
|
+
f"Your NETDEVICES_LOADERS setting includes {loader!r}, but your Python installation doesn't support that type of data loading. Consider removing that line from NETDEVICES_LOADERS."
|
|
115
|
+
)
|
|
116
|
+
return None
|
|
117
|
+
else:
|
|
118
|
+
return func
|
|
119
|
+
else:
|
|
120
|
+
raise ImproperlyConfigured(
|
|
121
|
+
'Loader does not define a "load_data" callable data source loader.'
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
#: Namedtuple that holds loader instance and device metadata
|
|
126
|
+
LoaderMetadata = namedtuple("LoaderMetadata", "loader metadata")
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def load_metadata(data_source, **kwargs):
|
|
130
|
+
"""
|
|
131
|
+
Iterate thru data loaders to load metadata.
|
|
132
|
+
|
|
133
|
+
Loaders should return an iterable of dict/2-tuples or ``None``. It will try
|
|
134
|
+
each one until it can return data. The first one to return data wins.
|
|
135
|
+
|
|
136
|
+
:param data_source:
|
|
137
|
+
Typically a file path, but it can be any data format you desire that
|
|
138
|
+
can be passed onto a Loader object to retrieve metadata.
|
|
139
|
+
|
|
140
|
+
:param kwargs:
|
|
141
|
+
Optional keyword arguments you wish to pass to the Loader.
|
|
142
|
+
|
|
143
|
+
:returns:
|
|
144
|
+
`~trigger.netdevices.loader.LoaderMetadata` instance
|
|
145
|
+
"""
|
|
146
|
+
# Iterate and build a loader callables, call them, stop when we get data.
|
|
147
|
+
tried = []
|
|
148
|
+
log.msg("LOADING DATA FROM:", data_source)
|
|
149
|
+
for loader_name in settings.NETDEVICES_LOADERS:
|
|
150
|
+
loader = find_data_loader(loader_name)
|
|
151
|
+
log.msg("TRYING LOADER:", loader)
|
|
152
|
+
if loader is None:
|
|
153
|
+
log.msg("CANNOT USE LOADER:", loader)
|
|
154
|
+
continue
|
|
155
|
+
|
|
156
|
+
try:
|
|
157
|
+
# Pass the args to the loader!
|
|
158
|
+
data = loader(data_source, **kwargs)
|
|
159
|
+
log.msg("LOADER: SUCCESS!")
|
|
160
|
+
except LoaderFailed as err:
|
|
161
|
+
tried.append(loader)
|
|
162
|
+
log.msg(f"LOADER - FAILURE: {err}")
|
|
163
|
+
continue
|
|
164
|
+
else:
|
|
165
|
+
# Successfully parsed (we hope)
|
|
166
|
+
if data is not None:
|
|
167
|
+
log.msg(f"LOADERS TRIED: {tried!r}")
|
|
168
|
+
return LoaderMetadata(loader, data)
|
|
169
|
+
else:
|
|
170
|
+
tried.append(loader)
|
|
171
|
+
continue
|
|
172
|
+
|
|
173
|
+
# All loaders failed. We don't want to get to this point!
|
|
174
|
+
raise RuntimeError(f"No data loaders succeeded. Tried: {tried!r}")
|