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/exceptions.py
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"""
|
|
2
|
+
All custom exceptions used by Trigger. Where possible built-in exceptions are
|
|
3
|
+
used, but sometimes we need more descriptive errors.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
__author__ = "Jathan McCollum"
|
|
7
|
+
__maintainer__ = "Jathan McCollum"
|
|
8
|
+
__email__ = "jathan@gmail.com"
|
|
9
|
+
__copyright__ = "Copyright 2012-2012, AOL Inc."
|
|
10
|
+
__version__ = "1.9"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# Imports
|
|
14
|
+
from simpleparse.error import ParserSyntaxError # noqa: F401
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Exceptions
|
|
18
|
+
class TriggerError(Exception):
|
|
19
|
+
"""A base exception for all Trigger-related errors."""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ImproperlyConfigured(TriggerError):
|
|
23
|
+
"""Raised when something is improperly... configured..."""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
################
|
|
27
|
+
# ACL Exceptions
|
|
28
|
+
################
|
|
29
|
+
class ACLError(TriggerError):
|
|
30
|
+
"""Base exception for all ACL-related errors."""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ParseError(ACLError):
|
|
34
|
+
"""
|
|
35
|
+
Raised when there is an error parsing/normalizing an ACL that tries to tell
|
|
36
|
+
you where it failed.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(self, reason, line=None, column=None):
|
|
40
|
+
self.reason = reason
|
|
41
|
+
self.line = line
|
|
42
|
+
self.column = column
|
|
43
|
+
|
|
44
|
+
def __str__(self):
|
|
45
|
+
s = self.reason
|
|
46
|
+
if self.line is not None and self.line > 1:
|
|
47
|
+
s += " at line %d" % self.line
|
|
48
|
+
return s
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# ACL validation/formating errors
|
|
52
|
+
class BadTermName(ACLError):
|
|
53
|
+
"""
|
|
54
|
+
Raised when an invalid name is assigned to a `~trigger.acl.parser.Term`
|
|
55
|
+
object
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class MissingTermName(ACLError):
|
|
60
|
+
"""
|
|
61
|
+
Raised when a an un-named Term is output to a format that requires Terms to
|
|
62
|
+
be named (e.g. Juniper).
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class VendorSupportLacking(ACLError):
|
|
67
|
+
"""Raised when a feature is not supported by a given vendor."""
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# ACL naming errors
|
|
71
|
+
class ACLNameError(ACLError):
|
|
72
|
+
"""A base exception for all ACL naming errors."""
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class MissingACLName(ACLNameError):
|
|
76
|
+
"""Raised when an ACL object is missing a name."""
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class BadACLName(ACLNameError):
|
|
80
|
+
"""Raised when an ACL object is assigned an invalid name."""
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# Misc. action errors
|
|
84
|
+
class ActionError(ACLError):
|
|
85
|
+
"""A base exception for all `~trigger.acl.parser.Term` action errors."""
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class UnknownActionName(ActionError):
|
|
89
|
+
"""
|
|
90
|
+
Raised when an action assigned to a ~trigger.acl.parser.Term` object is
|
|
91
|
+
unknown.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class BadRoutingInstanceName(ActionError):
|
|
96
|
+
"""
|
|
97
|
+
Raised when a routing-instance name specified in an action is invalid.
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class BadRejectCode(ActionError):
|
|
102
|
+
"""Raised when an invalid rejection code is specified."""
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class BadCounterName(ActionError):
|
|
106
|
+
"""Raised when a counter name is invalid."""
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class BadForwardingClassName(ActionError):
|
|
110
|
+
"""Raised when a forwarding-class name is invalid."""
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class BadIPSecSAName(ActionError):
|
|
114
|
+
"""Raised when an IPSec SA name is invalid."""
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class BadPolicerName(ActionError):
|
|
118
|
+
"""Raised when a policer name is invalid."""
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# Argument matching errors
|
|
122
|
+
class MatchError(ACLError):
|
|
123
|
+
"""
|
|
124
|
+
A base exception for all errors related to Term
|
|
125
|
+
`~trigger.acl.parser.Matches` objects.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class BadMatchArgRange(MatchError):
|
|
130
|
+
"""
|
|
131
|
+
Raised when a match condition argument does not fall within a specified
|
|
132
|
+
range.
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class UnknownMatchType(MatchError):
|
|
137
|
+
"""Raised when an unknown match condition is specified."""
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class UnknownMatchArg(MatchError):
|
|
141
|
+
"""Raised when an unknown match argument is specified."""
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# ACLs database errors
|
|
145
|
+
class ACLSetError(ACLError):
|
|
146
|
+
"""A base exception for all ACL Set errors."""
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class InvalidACLSet(ACLSetError):
|
|
150
|
+
"""Raised when an invalid ACL set is specified."""
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
# ACL/task queue errors
|
|
154
|
+
class ACLQueueError(TriggerError):
|
|
155
|
+
"""Raised when we encounter errors communicating with the Queue."""
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
# ACL workflow errors
|
|
159
|
+
class ACLStagingFailed(ACLError):
|
|
160
|
+
"""Raised when we encounter errors staging a file for loading."""
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
######################
|
|
164
|
+
# NetScreen Exceptions
|
|
165
|
+
######################
|
|
166
|
+
class NetScreenError(TriggerError):
|
|
167
|
+
"""A general exception for NetScreen devices."""
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class NetScreenParseError(NetScreenError):
|
|
171
|
+
"""Raised when a NetScreen policy cannot be parsed."""
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
#####################
|
|
175
|
+
# Commando Exceptions
|
|
176
|
+
#####################
|
|
177
|
+
class CommandoError(TriggerError):
|
|
178
|
+
"""A base exception for all Commando-related errors."""
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class UnsupportedVendor(CommandoError):
|
|
182
|
+
"""Raised when a vendor is not supported by Trigger."""
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class UnsupportedDeviceType(CommandoError):
|
|
186
|
+
"""Raised when a device type is not supported by Trigger."""
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class MissingPlatform(CommandoError):
|
|
190
|
+
"""Raised when a specific device platform is not supported."""
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
####################
|
|
194
|
+
# Twister Exceptions
|
|
195
|
+
####################
|
|
196
|
+
class TwisterError(TriggerError):
|
|
197
|
+
"""A base exception for all errors related to Twister."""
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class LoginFailure(TwisterError):
|
|
201
|
+
"""Raised when authentication to a remote system fails."""
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class EnablePasswordFailure(LoginFailure):
|
|
205
|
+
"""Raised when enable password was required but not found."""
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class LoginTimeout(LoginFailure):
|
|
209
|
+
"""Raised when login to a remote systems times out."""
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class ConnectionFailure(TwisterError):
|
|
213
|
+
"""Raised when a connection attempt totally fails."""
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
class SSHConnectionLost(TwisterError):
|
|
217
|
+
"""Raised when an SSH connection is lost for any reason."""
|
|
218
|
+
|
|
219
|
+
def __init__(self, code, desc):
|
|
220
|
+
self.code = code
|
|
221
|
+
TwisterError.__init__(self, desc)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class CommandTimeout(TwisterError):
|
|
225
|
+
"""Raised when a command times out while executing."""
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class CommandFailure(TwisterError):
|
|
229
|
+
"""
|
|
230
|
+
Raised when a command fails to execute, such as when it results in an
|
|
231
|
+
error.
|
|
232
|
+
"""
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class IoslikeCommandFailure(CommandFailure):
|
|
236
|
+
"""Raised when a command fails on an IOS-like device."""
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class NetscalerCommandFailure(CommandFailure):
|
|
240
|
+
"""Raised when a command fails on a NetScaler device."""
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
class JunoscriptCommandFailure(CommandFailure):
|
|
244
|
+
"""Raised when a Junoscript command fails on a Juniper device."""
|
|
245
|
+
|
|
246
|
+
def __init__(self, tag):
|
|
247
|
+
self.tag = tag
|
|
248
|
+
|
|
249
|
+
def __str__(self):
|
|
250
|
+
s = "JunOS XML command failure:\n"
|
|
251
|
+
ns = "{http://xml.juniper.net/xnm/1.1/xnm}"
|
|
252
|
+
for e in self.tag.findall(f".//{ns}error"):
|
|
253
|
+
for e2 in e:
|
|
254
|
+
s += " {}: {}\n".format(e2.tag.replace(ns, ""), e2.text)
|
|
255
|
+
return s
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
#######################
|
|
259
|
+
# NetDevices Exceptions
|
|
260
|
+
#######################
|
|
261
|
+
class NetDeviceError(TriggerError):
|
|
262
|
+
"""A base exception for all NetDevices related errors."""
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
class BadVendorName(NetDeviceError):
|
|
266
|
+
"""Raised when a Vendor object has a problem with the name."""
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class LoaderFailed(NetDeviceError):
|
|
270
|
+
"""Raised when a metadata loader failed to load from data source."""
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
#########################
|
|
274
|
+
# Notification Exceptions
|
|
275
|
+
#########################
|
|
276
|
+
class NotificationFailure(TriggerError):
|
|
277
|
+
"""Raised when a notification fails and has not been silenced."""
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
##############################
|
|
281
|
+
# Bounce/Changemgmt Exceptions
|
|
282
|
+
##############################
|
|
283
|
+
class InvalidBounceWindow(TriggerError):
|
|
284
|
+
"""Raised when a BounceWindow object is kind of not good."""
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
#####################
|
|
288
|
+
# TACACSrc Exceptions
|
|
289
|
+
#####################
|
|
290
|
+
class TacacsrcError(Exception):
|
|
291
|
+
"""Base exception for TACACSrc errors."""
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
class CouldNotParse(TacacsrcError):
|
|
295
|
+
"""Raised when a ``.tacacsrc`` file failed to parse."""
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class MissingPassword(TacacsrcError):
|
|
299
|
+
"""Raised when a credential is missing a password."""
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
class MissingRealmName(TacacsrcError):
|
|
303
|
+
"""Raised when a credential is missing a realm."""
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
class VersionMismatch(TacacsrcError):
|
|
307
|
+
"""Raised when the TACACSrc version does not match."""
|
trigger/gorc.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This is used by :doc:`../usage/scripts/go` to execute commands upon login to a
|
|
3
|
+
device. A user may specify a list of commands to execute for each vendor. If
|
|
4
|
+
the file is not found, or the syntax is bad, no commands will be passed to the
|
|
5
|
+
device.
|
|
6
|
+
|
|
7
|
+
By default, only a very limited subset of root commands are allowed to be
|
|
8
|
+
specified within the ``.gorc``. Any root commands not explicitly permitted will
|
|
9
|
+
be filtered out prior to passing them along to the device.
|
|
10
|
+
|
|
11
|
+
The only public interface to this module is `~trigger.gorc.get_init_commands`.
|
|
12
|
+
Given a ``.gorc`` That looks like this::
|
|
13
|
+
|
|
14
|
+
[init_commands]
|
|
15
|
+
cisco:
|
|
16
|
+
term mon
|
|
17
|
+
terminal length 0
|
|
18
|
+
show clock
|
|
19
|
+
|
|
20
|
+
This is what is returned::
|
|
21
|
+
|
|
22
|
+
>>> from trigger import gorc
|
|
23
|
+
>>> gorc.get_init_commands('cisco')
|
|
24
|
+
['term mon', 'terminal length 0', 'show clock']
|
|
25
|
+
|
|
26
|
+
You may also pass a list of commands as the ``init_commands`` argument to the
|
|
27
|
+
`~trigger.twister.connect` function (or a `~trigger.netdevices.NetDevice`
|
|
28
|
+
object's method of the same name) to override anything specified in a user's
|
|
29
|
+
``.gorc``::
|
|
30
|
+
|
|
31
|
+
>>> from trigger.netdevices import NetDevices
|
|
32
|
+
>>> nd = NetDevices()
|
|
33
|
+
>>> dev = nd.find('foo1-abc')
|
|
34
|
+
>>> dev.connect(init_commands=['show clock', 'exit'])
|
|
35
|
+
Connecting to foo1-abc.net.aol.com. Use ^X to exit.
|
|
36
|
+
|
|
37
|
+
Fetching credentials from /home/jathan/.tacacsrc
|
|
38
|
+
foo1-abc#show clock
|
|
39
|
+
22:48:24.445 UTC Sat Jun 23 2012
|
|
40
|
+
foo1-abc#exit
|
|
41
|
+
>>>
|
|
42
|
+
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
# Imports
|
|
46
|
+
import configparser
|
|
47
|
+
import os
|
|
48
|
+
import sys
|
|
49
|
+
|
|
50
|
+
from twisted.python import log
|
|
51
|
+
|
|
52
|
+
from trigger.conf import settings
|
|
53
|
+
|
|
54
|
+
# Constants
|
|
55
|
+
GORC_PATH = os.path.expanduser(settings.GORC_FILE)
|
|
56
|
+
INIT_COMMANDS_SECTION = "init_commands"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# Exports
|
|
60
|
+
# __all__ = ('get_init_commands',)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# Functions
|
|
64
|
+
def read_config(filepath=GORC_PATH):
|
|
65
|
+
"""
|
|
66
|
+
Read the .gorc file
|
|
67
|
+
|
|
68
|
+
:param filepath: The path to the .gorc file
|
|
69
|
+
:returns: A parsed ConfigParser object
|
|
70
|
+
"""
|
|
71
|
+
config = configparser.RawConfigParser()
|
|
72
|
+
try:
|
|
73
|
+
status = config.read(filepath)
|
|
74
|
+
if filepath not in status:
|
|
75
|
+
log.msg(f"File not found: {filepath!r}")
|
|
76
|
+
return None
|
|
77
|
+
except (configparser.MissingSectionHeaderError, configparser.ParsingError) as err:
|
|
78
|
+
log.msg(err, debug=True)
|
|
79
|
+
return None
|
|
80
|
+
else:
|
|
81
|
+
return config
|
|
82
|
+
|
|
83
|
+
raise RuntimeError("Something went crazy wrong with read_config()")
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def filter_commands(cmds, allowed_commands=None):
|
|
87
|
+
"""
|
|
88
|
+
Filters root commands from ``cmds`` that are not explicitly allowed.
|
|
89
|
+
|
|
90
|
+
Allowed commands are defined using :setting:`GORC_ALLOWED_COMMANDS`.
|
|
91
|
+
|
|
92
|
+
:param cmds:
|
|
93
|
+
A list of commands that should be filtered
|
|
94
|
+
|
|
95
|
+
:param allowed_commands:
|
|
96
|
+
A list of commands that are allowed
|
|
97
|
+
|
|
98
|
+
:returns:
|
|
99
|
+
Filtered list of commands
|
|
100
|
+
"""
|
|
101
|
+
if allowed_commands is None:
|
|
102
|
+
allowed_commands = settings.GORC_ALLOWED_COMMANDS
|
|
103
|
+
ret = []
|
|
104
|
+
for cmd in cmds:
|
|
105
|
+
root = cmd.split()[0]
|
|
106
|
+
if root in allowed_commands:
|
|
107
|
+
ret.append(cmd)
|
|
108
|
+
else:
|
|
109
|
+
log.msg(f"init_command not allowed: {cmd!r}", debug=True)
|
|
110
|
+
return ret
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def parse_commands(vendor, section=INIT_COMMANDS_SECTION, config=None):
|
|
114
|
+
"""
|
|
115
|
+
Fetch the init commands.
|
|
116
|
+
|
|
117
|
+
:param vendors:
|
|
118
|
+
A vendor name (e.g. 'juniper')
|
|
119
|
+
|
|
120
|
+
:param section:
|
|
121
|
+
The section of the config
|
|
122
|
+
|
|
123
|
+
:param config:
|
|
124
|
+
A parsed ConfigParser object
|
|
125
|
+
|
|
126
|
+
:returns:
|
|
127
|
+
List of commands
|
|
128
|
+
"""
|
|
129
|
+
if config is None:
|
|
130
|
+
log.msg("No config data, not sending init commands", debug=True)
|
|
131
|
+
return []
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
cmdstr = config.get(section, vendor)
|
|
135
|
+
except configparser.NoSectionError as err:
|
|
136
|
+
log.msg(f"{err} in {GORC_PATH}", debug=True)
|
|
137
|
+
return []
|
|
138
|
+
except configparser.NoOptionError as err:
|
|
139
|
+
log.msg(err, debug=True)
|
|
140
|
+
return []
|
|
141
|
+
else:
|
|
142
|
+
cmds = (c for c in cmdstr.splitlines() if c != "")
|
|
143
|
+
cmds = filter_commands(cmds)
|
|
144
|
+
return cmds
|
|
145
|
+
|
|
146
|
+
raise RuntimeError("Something went crazy wrong with get_init_commands()")
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def get_init_commands(vendor):
|
|
150
|
+
"""
|
|
151
|
+
Return a list of init commands for a given vendor name. In all failure
|
|
152
|
+
cases it will return an empty list.
|
|
153
|
+
|
|
154
|
+
:param vendor:
|
|
155
|
+
A vendor name (e.g. 'juniper')
|
|
156
|
+
|
|
157
|
+
:returns:
|
|
158
|
+
list of commands
|
|
159
|
+
"""
|
|
160
|
+
config = read_config()
|
|
161
|
+
return parse_commands(vendor, config=config)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
if __name__ == "__main__":
|
|
165
|
+
# os.environ['DEBUG'] = '1'
|
|
166
|
+
if os.environ.get("DEBUG", None) is not None:
|
|
167
|
+
log.startLogging(sys.stdout, setStdout=False)
|
|
168
|
+
|
|
169
|
+
print(get_init_commands("juniper"))
|
|
170
|
+
print(get_init_commands("cisco"))
|
|
171
|
+
print(get_init_commands("arista"))
|
|
172
|
+
print(get_init_commands("foundry"))
|