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
trigger/rancid.py
ADDED
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Parse RANCID db files so they can be converted into Trigger NetDevice objects.
|
|
5
|
+
|
|
6
|
+
.. versionadded:: 1.2
|
|
7
|
+
|
|
8
|
+
Far from complete. Very early in development. Here is a basic example.
|
|
9
|
+
|
|
10
|
+
>>> from trigger import rancid
|
|
11
|
+
>>> rancid_root = '/path/to/rancid/data'
|
|
12
|
+
>>> r = Rancid(rancid_root)
|
|
13
|
+
>>> dev = r.devices.get('test1-abc.net.aol.com')
|
|
14
|
+
>>> dev
|
|
15
|
+
RancidDevice(nodeName='test-abc.net.aol.com', manufacturer='juniper', deviceStatus='up', deviceType=None)
|
|
16
|
+
|
|
17
|
+
Another option if you want to get the parsed RANCID data directly without
|
|
18
|
+
having to create an object is as simple as this::
|
|
19
|
+
|
|
20
|
+
>>> parsed = rancid.parse_rancid_data('/path/to/dancid/data')
|
|
21
|
+
|
|
22
|
+
Or using multiple RANCID instances within a single root::
|
|
23
|
+
|
|
24
|
+
>>> multi_parsed = rancid.parse_rancid_data('/path/to/rancid/data', recurse_subdirs=True)
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
__author__ = "Jathan McCollum"
|
|
29
|
+
__maintainer__ = "Jathan McCollum"
|
|
30
|
+
__email__ = "jathan.mccollum@teamaol.com"
|
|
31
|
+
__copyright__ = "Copyright 2012-2012, AOL Inc.; 2013 Salesforce.com"
|
|
32
|
+
__version__ = "0.1.1"
|
|
33
|
+
|
|
34
|
+
import collections
|
|
35
|
+
import csv
|
|
36
|
+
import itertools
|
|
37
|
+
import os
|
|
38
|
+
|
|
39
|
+
__all__ = (
|
|
40
|
+
"parse_rancid_file",
|
|
41
|
+
"parse_devices",
|
|
42
|
+
"walk_rancid_subdirs",
|
|
43
|
+
"parse_rancid_data",
|
|
44
|
+
"gather_devices",
|
|
45
|
+
"Rancid",
|
|
46
|
+
"RancidDevice",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Constants
|
|
50
|
+
CONFIG_DIRNAME = "configs"
|
|
51
|
+
RANCID_DB_FILE = "router.db"
|
|
52
|
+
RANCID_ALL_FILE = "routers.all"
|
|
53
|
+
RANCID_DOWN_FILE = "routers.down"
|
|
54
|
+
RANCID_UP_FILE = "routers.up"
|
|
55
|
+
NETDEVICE_FIELDS = ["nodeName", "manufacturer", "deviceStatus", "deviceType"]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# Functions
|
|
59
|
+
def _parse_delimited_file(root_dir, filename, delimiter=":"):
|
|
60
|
+
"""
|
|
61
|
+
Parse a colon-delimited file and return the contents as a list of lists.
|
|
62
|
+
|
|
63
|
+
Intended to be used for parsing of all RANCID files.
|
|
64
|
+
|
|
65
|
+
:param root_dir:
|
|
66
|
+
Where to find the file
|
|
67
|
+
|
|
68
|
+
:param filename:
|
|
69
|
+
Name of the file to parse
|
|
70
|
+
|
|
71
|
+
:param delimiter:
|
|
72
|
+
(Optional) Field delimiter
|
|
73
|
+
"""
|
|
74
|
+
filepath = os.path.join(root_dir, filename)
|
|
75
|
+
with open(filepath) as f:
|
|
76
|
+
reader = csv.reader(f, delimiter=delimiter)
|
|
77
|
+
return [r for r in reader if len(r) > 1] # Skip unparsed lines
|
|
78
|
+
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def parse_rancid_file(rancid_root, filename=RANCID_DB_FILE, fields=None, delimiter=":"):
|
|
83
|
+
"""
|
|
84
|
+
Parse a RANCID file and return generator representing a list of lists
|
|
85
|
+
mapped to the ``fields``.
|
|
86
|
+
|
|
87
|
+
:param rancid_root:
|
|
88
|
+
Where to find the file
|
|
89
|
+
|
|
90
|
+
:param filename:
|
|
91
|
+
Name of the file to parse (e.g. ``router.db``)
|
|
92
|
+
|
|
93
|
+
:param fields:
|
|
94
|
+
(Optional) A list of field names used to map to the device data
|
|
95
|
+
|
|
96
|
+
:param delimiter:
|
|
97
|
+
(Optional) Field delimiter
|
|
98
|
+
"""
|
|
99
|
+
device_data = _parse_delimited_file(rancid_root, filename, delimiter)
|
|
100
|
+
if not device_data:
|
|
101
|
+
return None # Always return None if there are no results
|
|
102
|
+
|
|
103
|
+
# Make sure fields is not null and is some kind of iterable
|
|
104
|
+
if not fields:
|
|
105
|
+
fields = NETDEVICE_FIELDS
|
|
106
|
+
else:
|
|
107
|
+
if not isinstance(fields, collections.Iterable):
|
|
108
|
+
raise RuntimeError("`fields` must be iterable")
|
|
109
|
+
|
|
110
|
+
# Map fields to generator of generators (!!)
|
|
111
|
+
# Python 3: izip_longest renamed to zip_longest
|
|
112
|
+
metadata = (itertools.zip_longest(fields, vals) for vals in device_data)
|
|
113
|
+
|
|
114
|
+
return metadata
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def walk_rancid_subdirs(rancid_root, config_dirname=CONFIG_DIRNAME, fields=None):
|
|
118
|
+
"""
|
|
119
|
+
Walk the ``rancid_root`` and parse the included RANCID files.
|
|
120
|
+
|
|
121
|
+
Returns a dictionary keyed by the name of the subdirs with values set to
|
|
122
|
+
the parsed data for each RANCID file found inside.
|
|
123
|
+
|
|
124
|
+
>>> from trigger import rancid
|
|
125
|
+
>>> subdirs = rancid.walk_rancid_subdirs('/data/rancid')
|
|
126
|
+
>>> subdirs.get('network-security')
|
|
127
|
+
{'router.db': <generator object <genexpr> at 0xa5b852c>,
|
|
128
|
+
'routers.all': <generator object <genexpr> at 0xa5a348c>,
|
|
129
|
+
'routers.down': <generator object <genexpr> at 0xa5be9dc>,
|
|
130
|
+
'routers.up': <generator object <genexpr> at 0xa5bea54>}
|
|
131
|
+
|
|
132
|
+
:param rancid_root:
|
|
133
|
+
Where to find the file
|
|
134
|
+
|
|
135
|
+
:param config_dirname:
|
|
136
|
+
If the 'configs' dir is named something else
|
|
137
|
+
|
|
138
|
+
:param fields:
|
|
139
|
+
(Optional) A list of field names used to map to the device data
|
|
140
|
+
"""
|
|
141
|
+
walker = os.walk(rancid_root)
|
|
142
|
+
baseroot, basedirs, basefiles = walker.next() # First item is base
|
|
143
|
+
|
|
144
|
+
results = {}
|
|
145
|
+
for root, dirnames, filenames in walker:
|
|
146
|
+
# Skip any path with CVS in it
|
|
147
|
+
if "CVS" in root:
|
|
148
|
+
# print 'skipping CVS:', root
|
|
149
|
+
continue
|
|
150
|
+
|
|
151
|
+
# Don't visit CVS directories
|
|
152
|
+
if "CVS" in dirnames:
|
|
153
|
+
dirnames.remove("CVS")
|
|
154
|
+
|
|
155
|
+
# Skip directories with nothing in them
|
|
156
|
+
if not filenames or not dirnames:
|
|
157
|
+
continue
|
|
158
|
+
|
|
159
|
+
# Only walk directories in which we also have configs
|
|
160
|
+
if config_dirname in dirnames:
|
|
161
|
+
owner = os.path.basename(root)
|
|
162
|
+
results[owner] = {}
|
|
163
|
+
for file_ in filenames:
|
|
164
|
+
results[owner][file_] = parse_rancid_file(root, file_, fields)
|
|
165
|
+
|
|
166
|
+
return results
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def parse_rancid_data(
|
|
170
|
+
rancid_root,
|
|
171
|
+
filename=RANCID_DB_FILE,
|
|
172
|
+
fields=None,
|
|
173
|
+
config_dirname=CONFIG_DIRNAME,
|
|
174
|
+
recurse_subdirs=False,
|
|
175
|
+
):
|
|
176
|
+
"""
|
|
177
|
+
Parse single or multiple RANCID instances and return an iterator of the
|
|
178
|
+
device metadata.
|
|
179
|
+
|
|
180
|
+
A single instance expects to find 'router.db' in ``rancid_root``.
|
|
181
|
+
|
|
182
|
+
If you set ``recurise_subdirs``, multiple instances will be expected, and a
|
|
183
|
+
`router.db` will be expected to be found in each subdirectory.
|
|
184
|
+
|
|
185
|
+
:param rancid_root:
|
|
186
|
+
Where to find the file
|
|
187
|
+
|
|
188
|
+
:param filename:
|
|
189
|
+
Name of the file to parse (e.g. ``router.db``)
|
|
190
|
+
|
|
191
|
+
:param fields:
|
|
192
|
+
(Optional) A list of field names used to map to the device data
|
|
193
|
+
|
|
194
|
+
:param config_dirname:
|
|
195
|
+
If the 'configs' dir is named something else
|
|
196
|
+
|
|
197
|
+
:param recurse_subdirs:
|
|
198
|
+
Whether to recurse directories (e.g. multiple instances)
|
|
199
|
+
"""
|
|
200
|
+
if recurse_subdirs:
|
|
201
|
+
subdirs = walk_rancid_subdirs(rancid_root, config_dirname, fields)
|
|
202
|
+
metadata = gather_devices(subdirs, filename)
|
|
203
|
+
else:
|
|
204
|
+
metadata = parse_rancid_file(rancid_root, filename, fields)
|
|
205
|
+
|
|
206
|
+
return metadata
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def parse_devices(metadata, parser):
|
|
210
|
+
"""
|
|
211
|
+
Iterate device ``metadata`` to use ``parser`` to create and return a
|
|
212
|
+
list of network device objects.
|
|
213
|
+
|
|
214
|
+
:param metadata:
|
|
215
|
+
A collection of key/value pairs (Generally returned from
|
|
216
|
+
`~trigger.rancid.parse_rancid_file`)
|
|
217
|
+
|
|
218
|
+
:param parser:
|
|
219
|
+
A callabale used to create your objects
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
# Two tees of `metadata` iterator, in case a TypeError is encountered, we
|
|
223
|
+
# aren't losing the first item.
|
|
224
|
+
md_original, md_backup = itertools.tee(metadata)
|
|
225
|
+
try:
|
|
226
|
+
# Try to parse using the generator (most efficient)
|
|
227
|
+
return [parser(d) for d in md_original]
|
|
228
|
+
except TypeError:
|
|
229
|
+
# Try to parse by unpacking a dict into kwargs
|
|
230
|
+
return [parser(**dict(d)) for d in md_backup]
|
|
231
|
+
except Exception as err:
|
|
232
|
+
# Or just give up
|
|
233
|
+
print(f"Parser failed with this error: {repr(err)!r}")
|
|
234
|
+
return None
|
|
235
|
+
else:
|
|
236
|
+
raise RuntimeError("This should never happen!")
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def gather_devices(subdir_data, rancid_db_file=RANCID_DB_FILE):
|
|
240
|
+
"""
|
|
241
|
+
Returns a chained iterator of parsed RANCID data, based from the results of
|
|
242
|
+
`~trigger.rancid.walk_rancid_subdirs`.
|
|
243
|
+
|
|
244
|
+
This iterator is suitable for consumption by
|
|
245
|
+
`~trigger.rancid.parse_devices` or Trigger's
|
|
246
|
+
`~trigger.netdevices.NetDevices`.
|
|
247
|
+
|
|
248
|
+
:param rancid_root:
|
|
249
|
+
Where to find your RANCID files (router.db, et al.)
|
|
250
|
+
|
|
251
|
+
:param rancid_db_file:
|
|
252
|
+
If it's named other than ``router.db``
|
|
253
|
+
"""
|
|
254
|
+
iters = []
|
|
255
|
+
for rdir, files in subdir_data.items():
|
|
256
|
+
# Only carry on if we find 'router.db' or it's equivalent
|
|
257
|
+
metadata = files.get(rancid_db_file)
|
|
258
|
+
if metadata is None:
|
|
259
|
+
continue
|
|
260
|
+
|
|
261
|
+
iters.append(metadata)
|
|
262
|
+
|
|
263
|
+
return itertools.chain(*iters)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _parse_config_file(
|
|
267
|
+
rancid_root, filename, parser=None, config_dirname=CONFIG_DIRNAME, max_lines=30
|
|
268
|
+
):
|
|
269
|
+
"""Parse device config file for metadata (make, model, etc.)"""
|
|
270
|
+
filepath = os.path.join(rancid_root, config_dirname, filename)
|
|
271
|
+
try:
|
|
272
|
+
with open(filepath) as f:
|
|
273
|
+
config = []
|
|
274
|
+
for idx, line in enumerate(f):
|
|
275
|
+
if idx >= max_lines:
|
|
276
|
+
break
|
|
277
|
+
|
|
278
|
+
if any([line.startswith("#"), line.startswith("!") and len(line) > 2]):
|
|
279
|
+
config.append(line.strip())
|
|
280
|
+
|
|
281
|
+
return config
|
|
282
|
+
|
|
283
|
+
except OSError:
|
|
284
|
+
return None
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def _parse_config_files(devices, rancid_root, config_dirname=CONFIG_DIRNAME):
|
|
288
|
+
"""Parse multiple device config files"""
|
|
289
|
+
return_data = {}
|
|
290
|
+
for dev in devices:
|
|
291
|
+
return_data[dev.nodeName] = _parse_config_file(
|
|
292
|
+
rancid_root, dev.nodeName, config_dirname
|
|
293
|
+
)
|
|
294
|
+
return return_data
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def _parse_cisco(config):
|
|
298
|
+
"""NYI - Parse Cisco config to get metadata"""
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def _parse_juniper(config):
|
|
302
|
+
"""NYI - Parse Juniper config to get metadata"""
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def _parse_netscreen(config):
|
|
306
|
+
"""NYI - Parse NetScreen config to get metadata"""
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def massage_data(device_list):
|
|
310
|
+
""" "
|
|
311
|
+
Given a list of objects, try to fixup their metadata based on thse rules.
|
|
312
|
+
|
|
313
|
+
INCOMPLETE.
|
|
314
|
+
"""
|
|
315
|
+
devices = device_list
|
|
316
|
+
|
|
317
|
+
netdevices = {}
|
|
318
|
+
for idx, dev in enumerate(devices):
|
|
319
|
+
if dev.manufacturer == "netscreen":
|
|
320
|
+
dev.manufacturer = "juniper"
|
|
321
|
+
dev.deviceType = "FIREWALL"
|
|
322
|
+
|
|
323
|
+
elif dev.manufacturer == "cisco":
|
|
324
|
+
dev.deviceType = "ROUTER"
|
|
325
|
+
|
|
326
|
+
elif dev.manufacturer == "juniper":
|
|
327
|
+
dev.deviceType = "ROUTER"
|
|
328
|
+
else:
|
|
329
|
+
print("WTF", dev.nodeName, "requires no massaging!")
|
|
330
|
+
|
|
331
|
+
"""
|
|
332
|
+
# Asset
|
|
333
|
+
dev.serialNumber = dev.assetID = None
|
|
334
|
+
dev.lastUpdate = datetime.datetime.today()
|
|
335
|
+
"""
|
|
336
|
+
netdevices[dev.nodeName] = dev
|
|
337
|
+
|
|
338
|
+
return netdevices
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
# Classes
|
|
342
|
+
class RancidDevice(collections.namedtuple("RancidDevice", NETDEVICE_FIELDS)):
|
|
343
|
+
"""
|
|
344
|
+
A simple subclass of namedtuple to store contents of parsed RANCID files.
|
|
345
|
+
|
|
346
|
+
Designed to support all router.* files. The field names are intended to be
|
|
347
|
+
compatible with Trigger's NetDevice objects.
|
|
348
|
+
|
|
349
|
+
:param nodeName:
|
|
350
|
+
Hostname of device
|
|
351
|
+
|
|
352
|
+
:param manufacturer:
|
|
353
|
+
Vendor/manufacturer name of device
|
|
354
|
+
|
|
355
|
+
:param deviceStatus:
|
|
356
|
+
(Optional) Up/down status of device
|
|
357
|
+
|
|
358
|
+
:param deviceType:
|
|
359
|
+
(Optional) The device type... determined somehow
|
|
360
|
+
"""
|
|
361
|
+
|
|
362
|
+
__slots__ = ()
|
|
363
|
+
|
|
364
|
+
def __new__(cls, nodeName, manufacturer, deviceStatus=None, deviceType=None):
|
|
365
|
+
return super(cls, RancidDevice).__new__(
|
|
366
|
+
cls, nodeName, manufacturer, deviceStatus, deviceType
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
class Rancid:
|
|
371
|
+
"""
|
|
372
|
+
Holds RANCID data. INCOMPLETE.
|
|
373
|
+
|
|
374
|
+
Defaults to a single RANID instance specified as ``rancid_root``. It will
|
|
375
|
+
parse the file found at ``rancid_db_file`` and use this to populate the
|
|
376
|
+
``devices`` dictionary with instances of ``device_class``.
|
|
377
|
+
|
|
378
|
+
If you set ``recurse_subdirs``, it is assumed that ``rancid_root`` holds
|
|
379
|
+
one or more individual RANCID instances and will attempt to walk them,
|
|
380
|
+
parse them, and then aggregate all of the resulting device instances into
|
|
381
|
+
the ``devices`` dictionary.
|
|
382
|
+
|
|
383
|
+
Still needs:
|
|
384
|
+
|
|
385
|
+
+ Config parsing for metadata (make, model, type, serial, etc.)
|
|
386
|
+
+ Recursive Config file population/parsing when ``recurse_subdirs`` is set
|
|
387
|
+
|
|
388
|
+
:param rancid_root:
|
|
389
|
+
Where to find your RANCID files (router.db, et al.)
|
|
390
|
+
|
|
391
|
+
:param rancid_db_file:
|
|
392
|
+
If it's named other than ``router.db``
|
|
393
|
+
|
|
394
|
+
:param config_dir:
|
|
395
|
+
If it's named other than ``configs``
|
|
396
|
+
|
|
397
|
+
:param device_fields:
|
|
398
|
+
A list of field names used to map to the device data. These must match
|
|
399
|
+
the attributes expected by ``device_class``.
|
|
400
|
+
|
|
401
|
+
:param device_class:
|
|
402
|
+
If you want something other than ``RancidDevice``
|
|
403
|
+
|
|
404
|
+
:param recurse_subdirs:
|
|
405
|
+
Whether you want to recurse directories.
|
|
406
|
+
"""
|
|
407
|
+
|
|
408
|
+
def __init__(
|
|
409
|
+
self,
|
|
410
|
+
rancid_root,
|
|
411
|
+
rancid_db_file=RANCID_DB_FILE,
|
|
412
|
+
config_dirname=CONFIG_DIRNAME,
|
|
413
|
+
device_fields=None,
|
|
414
|
+
device_class=None,
|
|
415
|
+
recurse_subdirs=False,
|
|
416
|
+
):
|
|
417
|
+
if device_class is None:
|
|
418
|
+
device_class = RancidDevice
|
|
419
|
+
|
|
420
|
+
self.rancid_root = rancid_root
|
|
421
|
+
self.rancid_db_file = rancid_db_file
|
|
422
|
+
self.config_dirname = config_dirname
|
|
423
|
+
self.device_fields = device_fields
|
|
424
|
+
self.device_class = device_class
|
|
425
|
+
self.recurse_subdirs = recurse_subdirs
|
|
426
|
+
self.configs = {}
|
|
427
|
+
self.data = {}
|
|
428
|
+
self.devices = {}
|
|
429
|
+
self._populate()
|
|
430
|
+
|
|
431
|
+
def _populate(self):
|
|
432
|
+
"""Fired after init, does all the stuff to populate RANCID data."""
|
|
433
|
+
self._populate_devices()
|
|
434
|
+
|
|
435
|
+
def _populate_devices(self):
|
|
436
|
+
"""
|
|
437
|
+
Read router.db or equivalent and populate ``devices`` dictionary
|
|
438
|
+
with objects.
|
|
439
|
+
"""
|
|
440
|
+
metadata = parse_rancid_data(
|
|
441
|
+
self.rancid_root,
|
|
442
|
+
filename=self.rancid_db_file,
|
|
443
|
+
fields=self.device_fields,
|
|
444
|
+
config_dirname=self.config_dirname,
|
|
445
|
+
recurse_subdirs=self.recurse_subdirs,
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
objects = parse_devices(metadata, self.device_class)
|
|
449
|
+
self.devices = dict((d.nodeName, d) for d in objects)
|
|
450
|
+
|
|
451
|
+
def _populate_configs(self):
|
|
452
|
+
"""NYI - Read configs"""
|
|
453
|
+
self.configs = _parse_config_files(self.devices.values(), self.rancid_root)
|
|
454
|
+
|
|
455
|
+
def _populate_data(self):
|
|
456
|
+
"""NYI - Maybe keep the other metadata but how?"""
|
|
457
|
+
# self.data['routers.all'] = parse_rancid_file(root, RANCID_ALL_FILE)
|
|
458
|
+
# self.data['routers.down'] = parse_rancid_file(root, RANCID_DOWN_FILE)
|
|
459
|
+
# self.data['routers.up'] = parse_rancid_file(root, RANCID_UP_FILE)
|
|
460
|
+
pass
|
|
461
|
+
|
|
462
|
+
def __repr__(self):
|
|
463
|
+
return f"Rancid({self.rancid_root!r}, recurse_subdirs={self.recurse_subdirs})"
|