trigger 2.2.6__tar.gz → 2.3.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.
- {trigger-2.2.6/trigger.egg-info → trigger-2.3.0}/PKG-INFO +2 -2
- {trigger-2.2.6 → trigger-2.3.0}/pyproject.toml +2 -2
- {trigger-2.2.6 → trigger-2.3.0}/trigger/acl/ios.py +2 -2
- {trigger-2.2.6 → trigger-2.3.0}/trigger/acl/support.py +104 -58
- {trigger-2.2.6 → trigger-2.3.0}/trigger/acl/tools.py +5 -6
- {trigger-2.2.6 → trigger-2.3.0}/trigger/cmds.py +9 -7
- {trigger-2.2.6 → trigger-2.3.0}/trigger/conf/global_settings.py +4 -4
- {trigger-2.2.6 → trigger-2.3.0}/trigger/netscreen.py +5 -5
- {trigger-2.2.6 → trigger-2.3.0/trigger.egg-info}/PKG-INFO +2 -2
- {trigger-2.2.6 → trigger-2.3.0}/trigger.egg-info/requires.txt +1 -1
- {trigger-2.2.6 → trigger-2.3.0}/AUTHORS.md +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/LICENSE.md +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/README.md +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/setup.cfg +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/tests/test_acl.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/tests/test_acl_db.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/tests/test_acl_queue.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/tests/test_changemgmt.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/tests/test_except.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/tests/test_netdevices.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/tests/test_scripts.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/tests/test_tacacsrc.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/tests/test_templates.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/tests/test_twister.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/tests/test_twister2.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/tests/test_utils.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/__init__.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/acl/__init__.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/acl/autoacl.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/acl/db.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/acl/dicts.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/acl/grammar.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/acl/junos.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/acl/models.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/acl/parser.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/acl/queue.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/bin/__init__.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/bin/acl.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/bin/acl_script.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/bin/aclconv.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/bin/check_access.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/bin/check_syntax.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/bin/fe.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/bin/find_access.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/bin/gnng.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/bin/gong.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/bin/load_acl.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/bin/load_config.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/bin/netdev.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/bin/optimizer.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/bin/run_cmds.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/changemgmt/__init__.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/changemgmt/bounce.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/conf/__init__.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/contrib/__init__.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/exceptions.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/gorc.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/netdevices/__init__.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/netdevices/loader.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/packages/__init__.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/packages/peewee.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/rancid.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/tacacsrc.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/twister.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/twister2.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/utils/__init__.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/utils/cli.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/utils/importlib.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/utils/network.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/utils/rcs.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/utils/templates.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/utils/url.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger/utils/xmltodict.py +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger.egg-info/SOURCES.txt +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger.egg-info/dependency_links.txt +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger.egg-info/entry_points.txt +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/trigger.egg-info/top_level.txt +0 -0
- {trigger-2.2.6 → trigger-2.3.0}/twisted/plugins/trigger_xmlrpc.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: trigger
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Network automation toolkit for managing network devices
|
|
5
5
|
Author-email: Jathan McCollum <jathan@gmail.com>
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -13,7 +13,7 @@ Requires-Python: <3.12,>=3.10
|
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE.md
|
|
15
15
|
License-File: AUTHORS.md
|
|
16
|
-
Requires-Dist:
|
|
16
|
+
Requires-Dist: netaddr<2,>=1.0.0
|
|
17
17
|
Requires-Dist: cryptography>=41.0.0
|
|
18
18
|
Requires-Dist: Twisted>=22.10.0
|
|
19
19
|
Requires-Dist: crochet>=2.0.0
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "trigger"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.3.0"
|
|
8
8
|
description = "Network automation toolkit for managing network devices"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "BSD-3-Clause"
|
|
@@ -18,7 +18,7 @@ classifiers = [
|
|
|
18
18
|
"Framework :: Twisted",
|
|
19
19
|
]
|
|
20
20
|
dependencies = [
|
|
21
|
-
"
|
|
21
|
+
"netaddr>=1.0.0,<2",
|
|
22
22
|
"cryptography>=41.0.0",
|
|
23
23
|
"Twisted>=22.10.0",
|
|
24
24
|
"crochet>=2.0.0",
|
|
@@ -27,7 +27,7 @@ class Remark(Comment): # noqa: F405
|
|
|
27
27
|
# Build a table to unwind Cisco's weird inverse netmask.
|
|
28
28
|
# TODO (jathan): These don't actually get sorted properly, but it doesn't seem
|
|
29
29
|
# to have mattered up until now. Worth looking into it at some point, though.
|
|
30
|
-
inverse_mask_table =
|
|
30
|
+
inverse_mask_table = {str(make_inverse_mask(x)): x for x in range(33)} # noqa: F405
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
def handle_ios_match(a): # noqa: D103, PLR0912
|
|
@@ -129,7 +129,7 @@ rules.update( # noqa: F405
|
|
|
129
129
|
),
|
|
130
130
|
"ipv4_inverse_mask": (
|
|
131
131
|
literals(inverse_mask_table), # noqa: F405
|
|
132
|
-
lambda x: inverse_mask_table[
|
|
132
|
+
lambda x: inverse_mask_table[x],
|
|
133
133
|
),
|
|
134
134
|
"kw_ip": ('"ip"', None),
|
|
135
135
|
S("ios_match"): ( # noqa: F405
|
|
@@ -29,15 +29,12 @@ support the various modules for parsing. This file is not meant to by used by it
|
|
|
29
29
|
import contextlib
|
|
30
30
|
from typing import ClassVar
|
|
31
31
|
|
|
32
|
-
import
|
|
32
|
+
import netaddr
|
|
33
33
|
|
|
34
34
|
from trigger import exceptions
|
|
35
35
|
|
|
36
36
|
from .dicts import * # noqa: F403
|
|
37
37
|
|
|
38
|
-
# Python 2/3 compatibility
|
|
39
|
-
unicode = str
|
|
40
|
-
|
|
41
38
|
# Temporary resting place for comments, so the rest of the parser can
|
|
42
39
|
# ignore them. Yes, this makes the library not thread-safe.
|
|
43
40
|
Comments = []
|
|
@@ -130,13 +127,13 @@ def do_dscp_lookup(arg): # noqa: D103
|
|
|
130
127
|
|
|
131
128
|
|
|
132
129
|
def make_inverse_mask(prefixlen):
|
|
133
|
-
"""Return an IP object of the inverse mask of the CIDR prefix.
|
|
130
|
+
"""Return an IP address object of the inverse mask of the CIDR prefix.
|
|
134
131
|
|
|
135
132
|
:param prefixlen:
|
|
136
133
|
CIDR prefix
|
|
137
134
|
"""
|
|
138
135
|
inverse_bits = 2 ** (32 - prefixlen) - 1
|
|
139
|
-
return
|
|
136
|
+
return netaddr.IPAddress(inverse_bits)
|
|
140
137
|
|
|
141
138
|
|
|
142
139
|
def strip_comments(tags): # noqa: D103
|
|
@@ -431,12 +428,13 @@ class RangeList:
|
|
|
431
428
|
return self.data.__iter__()
|
|
432
429
|
|
|
433
430
|
|
|
434
|
-
class TIP(
|
|
435
|
-
"""Class based on
|
|
431
|
+
class TIP(netaddr.IPNetwork):
|
|
432
|
+
"""Class based on netaddr.IPNetwork, but with extensions for Trigger.
|
|
436
433
|
|
|
437
434
|
Currently, only the only extension is the ability to negate a network
|
|
438
435
|
block. Only used internally within the parser, as it's not complete
|
|
439
|
-
(doesn't interact well with
|
|
436
|
+
(doesn't interact well with netaddr.IPNetwork objects). Does not handle
|
|
437
|
+
IPv6 yet.
|
|
440
438
|
"""
|
|
441
439
|
|
|
442
440
|
def __init__(self, data, **kwargs): # noqa: D107
|
|
@@ -448,7 +446,7 @@ class TIP(IPy.IP):
|
|
|
448
446
|
inactive = getattr(data, "inactive", False)
|
|
449
447
|
|
|
450
448
|
# Is data a string?
|
|
451
|
-
if isinstance(data,
|
|
449
|
+
if isinstance(data, str):
|
|
452
450
|
d = data.split()
|
|
453
451
|
# This means we got something like "1.2.3.4 except" or "inactive:
|
|
454
452
|
# 1.2.3.4'
|
|
@@ -471,87 +469,101 @@ class TIP(IPy.IP):
|
|
|
471
469
|
|
|
472
470
|
self.negated = negated # Set 'negated' variable
|
|
473
471
|
self.inactive = inactive # Set 'inactive' variable
|
|
474
|
-
IPy.IP.__init__(self, data, **kwargs)
|
|
475
472
|
|
|
476
|
-
#
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
473
|
+
# Expand partial IPv4 addresses like "10/8" → "10.0.0.0/8"
|
|
474
|
+
if isinstance(data, str) and "/" in data:
|
|
475
|
+
parts = data.split("/")
|
|
476
|
+
addr_part = parts[0]
|
|
477
|
+
# Only apply to IPv4 (no colons in address part)
|
|
478
|
+
if ":" not in addr_part:
|
|
479
|
+
octets = addr_part.split(".")
|
|
480
|
+
while len(octets) < 4: # noqa: PLR2004
|
|
481
|
+
octets.append("0")
|
|
482
|
+
data = ".".join(octets) + "/" + parts[1]
|
|
483
|
+
|
|
484
|
+
super().__init__(data, **kwargs)
|
|
480
485
|
|
|
481
486
|
def _compare_to(self, other):
|
|
482
487
|
"""Helper method for comparison. Returns -1, 0, or 1.""" # noqa: D401
|
|
483
|
-
#
|
|
484
|
-
# (our baseline) does not. We also need comparisons to be different for
|
|
485
|
-
# negation. Following Juniper's sorting, use IP compare, and then break
|
|
488
|
+
# Following Juniper's sorting, use IP compare, and then break
|
|
486
489
|
# ties where negated < not negated.
|
|
487
|
-
|
|
488
|
-
if
|
|
490
|
+
self_first = self.first
|
|
491
|
+
if hasattr(other, "first"):
|
|
492
|
+
other_first = other.first
|
|
493
|
+
else:
|
|
494
|
+
return NotImplemented
|
|
495
|
+
if self_first < other_first:
|
|
489
496
|
diff = -1
|
|
490
|
-
elif
|
|
497
|
+
elif self_first > other_first:
|
|
491
498
|
diff = 1
|
|
492
499
|
else:
|
|
493
500
|
diff = 0
|
|
494
501
|
|
|
495
502
|
if diff == 0:
|
|
496
503
|
# If the same IP, compare by prefixlen
|
|
497
|
-
if self.prefixlen
|
|
504
|
+
if self.prefixlen < other.prefixlen:
|
|
498
505
|
diff = -1
|
|
499
|
-
elif self.prefixlen
|
|
506
|
+
elif self.prefixlen > other.prefixlen:
|
|
500
507
|
diff = 1
|
|
501
508
|
else:
|
|
502
509
|
diff = 0
|
|
503
510
|
|
|
504
511
|
# If both negated, they're the same
|
|
505
|
-
|
|
512
|
+
other_negated = getattr(other, "negated", False)
|
|
513
|
+
if self.negated == other_negated:
|
|
506
514
|
return diff
|
|
507
515
|
# Sort to make negated < not negated
|
|
508
516
|
return -1 if self.negated else 1
|
|
509
|
-
# Return the base comparison
|
|
510
517
|
|
|
511
518
|
def __lt__(self, other): # noqa: D105
|
|
512
|
-
|
|
519
|
+
result = self._compare_to(other)
|
|
520
|
+
if result is NotImplemented:
|
|
521
|
+
return NotImplemented
|
|
522
|
+
return result < 0
|
|
513
523
|
|
|
514
524
|
def __le__(self, other): # noqa: D105
|
|
515
|
-
|
|
525
|
+
result = self._compare_to(other)
|
|
526
|
+
if result is NotImplemented:
|
|
527
|
+
return NotImplemented
|
|
528
|
+
return result <= 0
|
|
516
529
|
|
|
517
530
|
def __gt__(self, other): # noqa: D105
|
|
518
|
-
|
|
531
|
+
result = self._compare_to(other)
|
|
532
|
+
if result is NotImplemented:
|
|
533
|
+
return NotImplemented
|
|
534
|
+
return result > 0
|
|
519
535
|
|
|
520
536
|
def __ge__(self, other): # noqa: D105
|
|
521
|
-
|
|
537
|
+
result = self._compare_to(other)
|
|
538
|
+
if result is NotImplemented:
|
|
539
|
+
return NotImplemented
|
|
540
|
+
return result >= 0
|
|
522
541
|
|
|
523
542
|
def __eq__(self, other): # noqa: D105
|
|
524
|
-
|
|
543
|
+
result = self._compare_to(other)
|
|
544
|
+
if result is NotImplemented:
|
|
545
|
+
return NotImplemented
|
|
546
|
+
return result == 0
|
|
525
547
|
|
|
526
548
|
def __ne__(self, other): # noqa: D105
|
|
527
|
-
|
|
549
|
+
result = self._compare_to(other)
|
|
550
|
+
if result is NotImplemented:
|
|
551
|
+
return NotImplemented
|
|
552
|
+
return result != 0
|
|
528
553
|
|
|
529
554
|
def __hash__(self): # noqa: D105
|
|
530
|
-
|
|
531
|
-
# Base hash on IP address, prefix length, and negation status
|
|
532
|
-
return hash((str(self.ip), self.prefixlen(), self.negated, self.inactive))
|
|
555
|
+
return hash((self.first, self.prefixlen, self.negated, self.inactive))
|
|
533
556
|
|
|
534
557
|
def __repr__(self): # noqa: D105
|
|
535
|
-
|
|
536
|
-
# code to accept this in the constructor really just provided, for now,
|
|
537
|
-
# as a debugging aid.
|
|
538
|
-
rs = IPy.IP.__repr__(self)
|
|
539
|
-
if self.negated:
|
|
540
|
-
# Insert ' except' into the repr. (Yes, it's a hack!)
|
|
541
|
-
rs = rs.split("'")
|
|
542
|
-
rs[1] += " except"
|
|
543
|
-
rs = "'".join(rs) # Restore original repr
|
|
544
|
-
if self.inactive:
|
|
545
|
-
# Insert 'inactive: ' into the repr. (Yes, it's also a hack!)
|
|
546
|
-
rs = rs.split("'")
|
|
547
|
-
rs[1] = "inactive: " + rs[1]
|
|
548
|
-
rs = "'".join(rs) # Restore original repr
|
|
549
|
-
return rs
|
|
558
|
+
return f"TIP('{self!s}')"
|
|
550
559
|
|
|
551
560
|
def __str__(self): # noqa: D105
|
|
552
|
-
#
|
|
553
|
-
#
|
|
554
|
-
|
|
561
|
+
# Show prefix for all networks, but omit for single hosts (/32, /128)
|
|
562
|
+
# unless negated or inactive (Juniper ACL style needs prefix)
|
|
563
|
+
if self.prefixlen in (32, 128) and not self.negated and not self.inactive:
|
|
564
|
+
rs = str(self.ip)
|
|
565
|
+
else:
|
|
566
|
+
rs = f"{self.network}/{self.prefixlen}"
|
|
555
567
|
if self.negated:
|
|
556
568
|
rs += " except"
|
|
557
569
|
if self.inactive:
|
|
@@ -566,9 +578,39 @@ class TIP(IPy.IP):
|
|
|
566
578
|
# If one item is negated, it's never contained.
|
|
567
579
|
if xor:
|
|
568
580
|
return False
|
|
569
|
-
matched =
|
|
581
|
+
matched = super().__contains__(item)
|
|
570
582
|
return matched ^ self.negated
|
|
571
583
|
|
|
584
|
+
# Prevent netaddr's iteration/subscript protocol from interfering with
|
|
585
|
+
# RangeList, which would otherwise treat TIP as a sequence of integers.
|
|
586
|
+
def __iter__(self): # noqa: D105
|
|
587
|
+
msg = f"'{type(self).__name__}' object is not iterable"
|
|
588
|
+
raise TypeError(msg)
|
|
589
|
+
|
|
590
|
+
def __getitem__(self, index): # noqa: D105
|
|
591
|
+
msg = f"'{type(self).__name__}' object is not subscriptable"
|
|
592
|
+
raise TypeError(msg)
|
|
593
|
+
|
|
594
|
+
def __len__(self): # noqa: D105
|
|
595
|
+
msg = f"'{type(self).__name__}' object has no len()"
|
|
596
|
+
raise TypeError(msg)
|
|
597
|
+
|
|
598
|
+
# Compatibility methods for code that uses IPy-style API
|
|
599
|
+
def net(self):
|
|
600
|
+
"""Return the network address as an IPAddress object."""
|
|
601
|
+
return self.network
|
|
602
|
+
|
|
603
|
+
def strNormal(self, mode=0):
|
|
604
|
+
"""Return string representation compatible with IPy's strNormal.
|
|
605
|
+
|
|
606
|
+
:param mode:
|
|
607
|
+
0 = address without prefix for host, with prefix for network
|
|
608
|
+
1 = address with prefix always
|
|
609
|
+
"""
|
|
610
|
+
if mode == 0 and self.prefixlen in (32, 128):
|
|
611
|
+
return str(self.ip)
|
|
612
|
+
return f"{self.network}/{self.prefixlen}"
|
|
613
|
+
|
|
572
614
|
|
|
573
615
|
class Comment:
|
|
574
616
|
"""Container for inline comments."""
|
|
@@ -1246,8 +1288,12 @@ class Matches(MyDict):
|
|
|
1246
1288
|
return "%s-%s" % pair # noqa: UP031 # Tuples back to ranges.
|
|
1247
1289
|
except TypeError:
|
|
1248
1290
|
with contextlib.suppress(AttributeError):
|
|
1249
|
-
#
|
|
1250
|
-
pair.
|
|
1291
|
+
# Force prefix display for /32 and /128 in JunOS output
|
|
1292
|
+
if hasattr(pair, "prefixlen") and pair.prefixlen in (32, 128):
|
|
1293
|
+
result = f"{pair.network}/{pair.prefixlen}"
|
|
1294
|
+
if getattr(pair, "negated", False):
|
|
1295
|
+
result += " except"
|
|
1296
|
+
return result
|
|
1251
1297
|
return str(pair)
|
|
1252
1298
|
|
|
1253
1299
|
def ios_port_str(self, ports):
|
|
@@ -1286,12 +1332,12 @@ class Matches(MyDict):
|
|
|
1286
1332
|
raise exceptions.VendorSupportLacking(
|
|
1287
1333
|
msg,
|
|
1288
1334
|
)
|
|
1289
|
-
if addr.prefixlen
|
|
1335
|
+
if addr.prefixlen == 0:
|
|
1290
1336
|
a.append("any")
|
|
1291
|
-
elif addr.prefixlen
|
|
1337
|
+
elif addr.prefixlen == 32: # noqa: PLR2004
|
|
1292
1338
|
a.append(f"host {addr.net()}")
|
|
1293
1339
|
else:
|
|
1294
|
-
inverse_mask = make_inverse_mask(addr.prefixlen
|
|
1340
|
+
inverse_mask = make_inverse_mask(addr.prefixlen)
|
|
1295
1341
|
a.append(f"{addr.net()} {inverse_mask}")
|
|
1296
1342
|
return a
|
|
1297
1343
|
|
|
@@ -9,9 +9,8 @@ import tempfile
|
|
|
9
9
|
from collections import defaultdict
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
|
|
12
|
-
import IPy
|
|
13
|
-
|
|
14
12
|
from trigger.acl.parser import * # noqa: F403
|
|
13
|
+
from trigger.acl.support import TIP
|
|
15
14
|
from trigger.conf import settings
|
|
16
15
|
|
|
17
16
|
# Defaults
|
|
@@ -667,10 +666,10 @@ class ACLScript:
|
|
|
667
666
|
def _add_addr(self, to, src):
|
|
668
667
|
if isinstance(src, list):
|
|
669
668
|
for x in src:
|
|
670
|
-
if
|
|
671
|
-
to.append(
|
|
672
|
-
elif
|
|
673
|
-
to.append(
|
|
669
|
+
if TIP(x) not in to:
|
|
670
|
+
to.append(TIP(x))
|
|
671
|
+
elif TIP(src) not in to:
|
|
672
|
+
to.append(TIP(src))
|
|
674
673
|
|
|
675
674
|
def _add_port(self, to, src):
|
|
676
675
|
if isinstance(src, list):
|
|
@@ -11,11 +11,12 @@ import collections
|
|
|
11
11
|
import itertools
|
|
12
12
|
from xml.etree.ElementTree import Element, SubElement
|
|
13
13
|
|
|
14
|
-
from
|
|
14
|
+
from netaddr import IPNetwork as IP
|
|
15
15
|
from twisted.internet import defer, task
|
|
16
16
|
from twisted.python import log
|
|
17
17
|
|
|
18
18
|
from trigger import exceptions
|
|
19
|
+
from trigger.acl.support import TIP
|
|
19
20
|
from trigger.conf import settings
|
|
20
21
|
from trigger.netdevices import NetDevices
|
|
21
22
|
from trigger.utils.templates import (
|
|
@@ -808,12 +809,13 @@ class NetACLInfo(Commando):
|
|
|
808
809
|
super().__init__(**args)
|
|
809
810
|
|
|
810
811
|
def IPsubnet(self, addr):
|
|
811
|
-
"""Given '172.20.1.4/24', return
|
|
812
|
-
|
|
812
|
+
"""Given '172.20.1.4/24', return TIP('172.20.1.0/24')."""
|
|
813
|
+
net = IP(addr)
|
|
814
|
+
return TIP(f"{net.network}/{net.prefixlen}")
|
|
813
815
|
|
|
814
816
|
def IPhost(self, addr):
|
|
815
|
-
"""Given '172.20.1.4/24', return
|
|
816
|
-
return
|
|
817
|
+
"""Given '172.20.1.4/24', return TIP('172.20.1.4/32')."""
|
|
818
|
+
return TIP(addr[: addr.index("/")]) # Only keep before "/"
|
|
817
819
|
|
|
818
820
|
# =======================================
|
|
819
821
|
# Vendor-specific generate (to_)/parse (from_) methods
|
|
@@ -1165,14 +1167,14 @@ def _make_ipy(nets):
|
|
|
1165
1167
|
"""Given a list of 2-tuples of (address, netmask), returns a list of
|
|
1166
1168
|
IP address objects.
|
|
1167
1169
|
""" # noqa: D205
|
|
1168
|
-
return [
|
|
1170
|
+
return [TIP(addr) for addr, mask in nets]
|
|
1169
1171
|
|
|
1170
1172
|
|
|
1171
1173
|
def _make_cidrs(nets):
|
|
1172
1174
|
"""Given a list of 2-tuples of (address, netmask), returns a list CIDR
|
|
1173
1175
|
blocks.
|
|
1174
1176
|
""" # noqa: D205
|
|
1175
|
-
return [IP(addr).
|
|
1177
|
+
return [TIP(IP(f"{addr}/{mask}").cidr) for addr, mask in nets]
|
|
1176
1178
|
|
|
1177
1179
|
|
|
1178
1180
|
def _dump_interfaces(idict):
|
|
@@ -9,7 +9,7 @@ import os
|
|
|
9
9
|
import socket
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
|
|
12
|
-
import
|
|
12
|
+
import netaddr
|
|
13
13
|
|
|
14
14
|
# ===============================
|
|
15
15
|
# Global Settings
|
|
@@ -67,9 +67,9 @@ TFTP_HOST = ""
|
|
|
67
67
|
# Add internally owned networks here. All network blocks owned/operated and
|
|
68
68
|
# considered part of your network should be included.
|
|
69
69
|
INTERNAL_NETWORKS = [
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
netaddr.IPNetwork("10.0.0.0/8"),
|
|
71
|
+
netaddr.IPNetwork("172.16.0.0/12"),
|
|
72
|
+
netaddr.IPNetwork("192.168.0.0/16"),
|
|
73
73
|
]
|
|
74
74
|
|
|
75
75
|
# A dictionary keyed by manufacturer name containing a list of the device types
|
|
@@ -3,7 +3,7 @@ Broken apart from acl.parser because the approaches are vastly different from ea
|
|
|
3
3
|
other.
|
|
4
4
|
""" # noqa: D205
|
|
5
5
|
|
|
6
|
-
import
|
|
6
|
+
import netaddr
|
|
7
7
|
|
|
8
8
|
from trigger import exceptions
|
|
9
9
|
from trigger.acl.parser import (
|
|
@@ -555,11 +555,11 @@ class NSAddressBook(NetScreen):
|
|
|
555
555
|
self.any = NSAddress(name="ANY")
|
|
556
556
|
|
|
557
557
|
def find(self, address, zone): # noqa: D102
|
|
558
|
-
if not self.entries
|
|
558
|
+
if zone not in self.entries:
|
|
559
559
|
return None
|
|
560
560
|
|
|
561
561
|
for nsaddr in self.entries[zone]:
|
|
562
|
-
if isinstance(address,
|
|
562
|
+
if isinstance(address, netaddr.IPNetwork):
|
|
563
563
|
if nsaddr.addr == address:
|
|
564
564
|
return nsaddr
|
|
565
565
|
elif isinstance(address, str):
|
|
@@ -646,7 +646,7 @@ class NSAddress(NetScreen):
|
|
|
646
646
|
self.zone,
|
|
647
647
|
self.name,
|
|
648
648
|
self.addr.strNormal(0),
|
|
649
|
-
self.addr.netmask
|
|
649
|
+
str(self.addr.netmask),
|
|
650
650
|
self.comment,
|
|
651
651
|
)
|
|
652
652
|
return [output]
|
|
@@ -808,7 +808,7 @@ class NSPolicy(NetScreen):
|
|
|
808
808
|
addr = TIP(address)
|
|
809
809
|
found = address_book.find(addr, zone)
|
|
810
810
|
if not found:
|
|
811
|
-
if addr.prefixlen
|
|
811
|
+
if addr.prefixlen == 32: # noqa: PLR2004
|
|
812
812
|
name = f"h{addr.strNormal(0)}"
|
|
813
813
|
else:
|
|
814
814
|
name = f"n{addr.strNormal()}"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: trigger
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Network automation toolkit for managing network devices
|
|
5
5
|
Author-email: Jathan McCollum <jathan@gmail.com>
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -13,7 +13,7 @@ Requires-Python: <3.12,>=3.10
|
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE.md
|
|
15
15
|
License-File: AUTHORS.md
|
|
16
|
-
Requires-Dist:
|
|
16
|
+
Requires-Dist: netaddr<2,>=1.0.0
|
|
17
17
|
Requires-Dist: cryptography>=41.0.0
|
|
18
18
|
Requires-Dist: Twisted>=22.10.0
|
|
19
19
|
Requires-Dist: crochet>=2.0.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|