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.
Files changed (61) hide show
  1. trigger/__init__.py +7 -0
  2. trigger/acl/__init__.py +32 -0
  3. trigger/acl/autoacl.py +70 -0
  4. trigger/acl/db.py +324 -0
  5. trigger/acl/dicts.py +357 -0
  6. trigger/acl/grammar.py +112 -0
  7. trigger/acl/ios.py +222 -0
  8. trigger/acl/junos.py +422 -0
  9. trigger/acl/models.py +118 -0
  10. trigger/acl/parser.py +168 -0
  11. trigger/acl/queue.py +296 -0
  12. trigger/acl/support.py +1431 -0
  13. trigger/acl/tools.py +746 -0
  14. trigger/bin/__init__.py +0 -0
  15. trigger/bin/acl.py +233 -0
  16. trigger/bin/acl_script.py +574 -0
  17. trigger/bin/aclconv.py +82 -0
  18. trigger/bin/check_access.py +93 -0
  19. trigger/bin/check_syntax.py +66 -0
  20. trigger/bin/fe.py +197 -0
  21. trigger/bin/find_access.py +191 -0
  22. trigger/bin/gnng.py +434 -0
  23. trigger/bin/gong.py +86 -0
  24. trigger/bin/load_acl.py +841 -0
  25. trigger/bin/load_config.py +18 -0
  26. trigger/bin/netdev.py +317 -0
  27. trigger/bin/optimizer.py +638 -0
  28. trigger/bin/run_cmds.py +18 -0
  29. trigger/changemgmt/__init__.py +352 -0
  30. trigger/changemgmt/bounce.py +57 -0
  31. trigger/cmds.py +1217 -0
  32. trigger/conf/__init__.py +94 -0
  33. trigger/conf/global_settings.py +674 -0
  34. trigger/contrib/__init__.py +7 -0
  35. trigger/exceptions.py +307 -0
  36. trigger/gorc.py +172 -0
  37. trigger/netdevices/__init__.py +1288 -0
  38. trigger/netdevices/loader.py +174 -0
  39. trigger/netscreen.py +1030 -0
  40. trigger/packages/__init__.py +6 -0
  41. trigger/packages/peewee.py +8084 -0
  42. trigger/rancid.py +463 -0
  43. trigger/tacacsrc.py +584 -0
  44. trigger/twister.py +2203 -0
  45. trigger/twister2.py +745 -0
  46. trigger/utils/__init__.py +88 -0
  47. trigger/utils/cli.py +349 -0
  48. trigger/utils/importlib.py +77 -0
  49. trigger/utils/network.py +157 -0
  50. trigger/utils/rcs.py +178 -0
  51. trigger/utils/templates.py +81 -0
  52. trigger/utils/url.py +78 -0
  53. trigger/utils/xmltodict.py +298 -0
  54. trigger-2.0.0.dist-info/METADATA +146 -0
  55. trigger-2.0.0.dist-info/RECORD +61 -0
  56. trigger-2.0.0.dist-info/WHEEL +5 -0
  57. trigger-2.0.0.dist-info/entry_points.txt +15 -0
  58. trigger-2.0.0.dist-info/licenses/AUTHORS.md +20 -0
  59. trigger-2.0.0.dist-info/licenses/LICENSE.md +28 -0
  60. trigger-2.0.0.dist-info/top_level.txt +2 -0
  61. 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"))