ifstate 2.0.0rc3__py3-none-any.whl → 2.0.0rc5__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.
- ifstate/ifstate.py +5 -5
- {ifstate-2.0.0rc3.dist-info → ifstate-2.0.0rc5.dist-info}/METADATA +1 -1
- ifstate-2.0.0rc5.dist-info/RECORD +39 -0
- libifstate/__init__.py +54 -36
- libifstate/address/__init__.py +1 -1
- libifstate/exception.py +5 -3
- libifstate/hook/__init__.py +1 -1
- libifstate/link/__init__.py +1 -0
- libifstate/link/base.py +6 -3
- libifstate/link/dsa.py +10 -0
- libifstate/link/physical.py +1 -1
- libifstate/link/tun.py +1 -1
- libifstate/log.py +7 -4
- libifstate/netns/__init__.py +4 -1
- libifstate/parser/__init__.py +1 -1
- libifstate/parser/base.py +23 -0
- {schema → libifstate/schema}/2/ifstate.conf.schema.json +43 -0
- libifstate/sysctl/__init__.py +10 -1
- libifstate/tc/__init__.py +1 -1
- libifstate/util.py +9 -2
- libifstate/wireguard/__init__.py +5 -0
- ifstate-2.0.0rc3.dist-info/RECORD +0 -38
- {ifstate-2.0.0rc3.dist-info → ifstate-2.0.0rc5.dist-info}/WHEEL +0 -0
- {ifstate-2.0.0rc3.dist-info → ifstate-2.0.0rc5.dist-info}/entry_points.txt +0 -0
- {ifstate-2.0.0rc3.dist-info → ifstate-2.0.0rc5.dist-info}/licenses/LICENSE +0 -0
- {ifstate-2.0.0rc3.dist-info → ifstate-2.0.0rc5.dist-info}/top_level.txt +0 -0
- {hooks → libifstate/hook}/wrapper.sh +0 -0
ifstate/ifstate.py
CHANGED
@@ -130,7 +130,7 @@ def main():
|
|
130
130
|
group = parser.add_mutually_exclusive_group()
|
131
131
|
parser.add_argument('--version', action='version',
|
132
132
|
version='%(prog)s {version}'.format(version=__version__))
|
133
|
-
group.add_argument("-v", "--verbose", action="
|
133
|
+
group.add_argument("-v", "--verbose", action="count", default=0,
|
134
134
|
help="be more verbose")
|
135
135
|
group.add_argument("-q", "--quiet", action="store_true",
|
136
136
|
help="be more quiet, print only warnings and errors")
|
@@ -139,7 +139,7 @@ def main():
|
|
139
139
|
parser.add_argument("-S", "--show-secrets", action="store_true",
|
140
140
|
help="show secrets when dumping config")
|
141
141
|
parser.add_argument("-c", "--config", type=str,
|
142
|
-
default="/etc/ifstate/
|
142
|
+
default="/etc/ifstate/ifstate.yaml", help="configuration YaML filename")
|
143
143
|
subparsers = parser.add_subparsers(
|
144
144
|
dest='action', required=True, help="specifies the action to perform")
|
145
145
|
|
@@ -166,10 +166,10 @@ def main():
|
|
166
166
|
"name", type=str, help="name of the vrrp group or instance")
|
167
167
|
|
168
168
|
args = parser.parse_args()
|
169
|
-
if args.verbose:
|
169
|
+
if args.verbose > 0:
|
170
170
|
lvl = logging.DEBUG
|
171
171
|
elif args.quiet:
|
172
|
-
lvl = logging.
|
172
|
+
lvl = logging.WARNING
|
173
173
|
else:
|
174
174
|
lvl = logging.INFO
|
175
175
|
|
@@ -182,7 +182,7 @@ def main():
|
|
182
182
|
shell()
|
183
183
|
exit(0)
|
184
184
|
|
185
|
-
ifslog = IfStateLogging(lvl, action=args.action)
|
185
|
+
ifslog = IfStateLogging(lvl, args.verbose > 1, action=args.action)
|
186
186
|
|
187
187
|
if args.action in [Actions.IDENTIFY, Actions.SHOW, Actions.SHOWALL]:
|
188
188
|
# preserve dict order on python 3.7+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
ifstate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
ifstate/ifstate.py,sha256=hmc_AWohcYVzWHU7vooWey0HDqZQOs6Yq8YZAMZBCgo,9304
|
3
|
+
ifstate/shell.py,sha256=7_JFpi4icr9MijynDzbb0v5mxhFsng6PCC4m3uQ255A,2177
|
4
|
+
ifstate/vrrp.py,sha256=FJ9b1eJseTtZFfknHU-xV68Qz7cPrRrc5PTcjUVj-fY,5953
|
5
|
+
ifstate-2.0.0rc5.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
6
|
+
libifstate/__init__.py,sha256=43OxRa35lKLNpMIR3_jmDICD_R0DUZqpAvasIzfatew,34059
|
7
|
+
libifstate/exception.py,sha256=NmKqD9O8dRWBgO__Pt0_wGSR5GWZ1RHXZZEUI3ArVLo,2360
|
8
|
+
libifstate/log.py,sha256=rG0ISWyeGGlC_jRREoSpkdySc5EmyhOQIgSfvRqlaZA,4651
|
9
|
+
libifstate/util.py,sha256=DqYyFzNqRceJxxGqTg94gT8OTHQQ2gZxQOo5Gzx6-6s,11555
|
10
|
+
libifstate/address/__init__.py,sha256=SobrZ9e2ItrmEidnKPBhUMitRDdTEajbkU9Rkmtx-gQ,3165
|
11
|
+
libifstate/bpf/__init__.py,sha256=NVzaunTmJU2PbIQg9eWBMKpFgLh3EnD3ujNa7Yt6rNc,7699
|
12
|
+
libifstate/bpf/ctypes.py,sha256=kLZJHZlba09Vc-tbsJAcKpDwdoNO2IjlYVLCopawHmA,4274
|
13
|
+
libifstate/bpf/map.py,sha256=cLHNMvRBDNW2yVCEf3z242_oRdU0HqVbFEYVkKXng0w,10818
|
14
|
+
libifstate/brport/__init__.py,sha256=NzdA8F4hr2se1bXKNnyKZbvOFlCWBq_cdjwsL1H0Y-o,2964
|
15
|
+
libifstate/fdb/__init__.py,sha256=9dpL5n8ct3CaA-z8I6ZEkD3yL6yWJQeq3fpIe9pc2zw,6486
|
16
|
+
libifstate/hook/__init__.py,sha256=012SIm1aULlXG4SoOYFV46u9k-4pPgtIENaUlRWPpe8,7375
|
17
|
+
libifstate/hook/wrapper.sh,sha256=ipCmvcadJbXTT6oUR7BIhT5uglITnHfiAdm44vydZuw,1101
|
18
|
+
libifstate/link/__init__.py,sha256=epVw6jY8exNeJZUmmUas91yJoeupfgIY7rthq7SGIIw,142
|
19
|
+
libifstate/link/base.py,sha256=zsitL1kSPLvjzZqyUIyEoCVlE_dhX2z5acNL1iZ2EAE,34508
|
20
|
+
libifstate/link/dsa.py,sha256=zOdatHE9_TLVVqP2H87V3d_M6Y3fRke2FqHj0u_Su2c,260
|
21
|
+
libifstate/link/physical.py,sha256=IG1OXG2q25QmvhxEDhyT-bf7guwIyXl0OzSJgQOqXzY,613
|
22
|
+
libifstate/link/tun.py,sha256=Rzn3ysE0cVuQGi3naxs9QXYBrLwVQTaVrFv2dtR1D60,1012
|
23
|
+
libifstate/link/veth.py,sha256=Sv5WZMMsefYFz9I0BQSZyKytCQYxv0vjwAnB7FYHR1A,2283
|
24
|
+
libifstate/neighbour/__init__.py,sha256=FJJpbJvqnxvOEii6QDMYzW5jQDEbiEy71GQOEbqaS48,2463
|
25
|
+
libifstate/netns/__init__.py,sha256=5Ak4vHU5UvdSYPFIQ8i8VMba2luyUeSpYAtRXxdTGPE,10287
|
26
|
+
libifstate/parser/__init__.py,sha256=uzv5U-6RPy-SSIyxR6H_F0SvAOQQF8x5ygErpUhsa7Y,109
|
27
|
+
libifstate/parser/base.py,sha256=PPUXWzZ1iMWseZzeV2uWmFIInmi8xxGDgul6afmVjd4,6584
|
28
|
+
libifstate/parser/yaml.py,sha256=MC0kmwqt3P45z61fb_wfUqoj0iZyhFYkdPyr0UqMSZA,1415
|
29
|
+
libifstate/routing/__init__.py,sha256=O4lbaCJvLgx-iQUa0WDgRmSPR4AKvveqPgxxb4HwYQ4,25305
|
30
|
+
libifstate/schema/2/ifstate.conf.schema.json,sha256=hVf0fduVV09uw3ZphWWwGpeQ7nL5z1aLTHUEemn34wc,221185
|
31
|
+
libifstate/sysctl/__init__.py,sha256=VLzz1YcNEclRMVvwZuJgkYxPTjErl-7-rwSOKiEG6_M,3544
|
32
|
+
libifstate/tc/__init__.py,sha256=T8LEBxiHZH4sayPn9lK5hK8eB8dskuw6-kw81W_aMWU,12097
|
33
|
+
libifstate/wireguard/__init__.py,sha256=VSn3PzQXwZeRV1qf5nOc_RbeePQlXu8FUh2Lg356-ZA,8869
|
34
|
+
libifstate/xdp/__init__.py,sha256=X1xhEIGng7R5d5F4KsChykT2g6H-XBRWbWABijoYDQA,7208
|
35
|
+
ifstate-2.0.0rc5.dist-info/METADATA,sha256=u2yC0kTPo9uQx80fkxj5vp6XnKJh9-EWovvA8ShO9ZA,1607
|
36
|
+
ifstate-2.0.0rc5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
37
|
+
ifstate-2.0.0rc5.dist-info/entry_points.txt,sha256=HF6jX7Uu_nF1Ly-J9uEPeiRapOxnM6LuHsb2y6Mt-k4,52
|
38
|
+
ifstate-2.0.0rc5.dist-info/top_level.txt,sha256=A7peI7aKBaM69fsiSPvMbL3rzTKZZr5qDxKC-pHMGdE,19
|
39
|
+
ifstate-2.0.0rc5.dist-info/RECORD,,
|
libifstate/__init__.py
CHANGED
@@ -5,7 +5,7 @@ from libifstate.fdb import FDB
|
|
5
5
|
from libifstate.hook import Hooks
|
6
6
|
from libifstate.neighbour import Neighbours
|
7
7
|
from libifstate.routing import Tables, Rules, RTLookups
|
8
|
-
from libifstate.parser import Parser
|
8
|
+
from libifstate.parser import Parser, get_available_hooks
|
9
9
|
from libifstate.tc import TC
|
10
10
|
from libifstate.exception import netlinkerror_classes
|
11
11
|
import bisect
|
@@ -35,11 +35,16 @@ except ModuleNotFoundError:
|
|
35
35
|
# ignore missing plugin
|
36
36
|
pass
|
37
37
|
|
38
|
+
try:
|
39
|
+
from jsonschema import validate, ValidationError, FormatChecker
|
40
|
+
except ModuleNotFoundError:
|
41
|
+
# fail open and ignore missing jsonschema dependency
|
42
|
+
pass
|
43
|
+
|
38
44
|
from libifstate.netns import NetNameSpace, prepare_netns, LinkRegistry, get_netns_instances
|
39
|
-
from libifstate.util import logger, root_iw, IfStateLogging, LinkDependency, IDENTIFY_LOOKUPS
|
45
|
+
from libifstate.util import logger, root_iw, kind_has_identify, IfStateLogging, LinkDependency, IDENTIFY_LOOKUPS
|
40
46
|
from libifstate.exception import FeatureMissingError, LinkCircularLinked, LinkNoConfigFound, ParserValidationError
|
41
47
|
from ipaddress import ip_network, ip_interface
|
42
|
-
from jsonschema import validate, ValidationError, FormatChecker
|
43
48
|
from copy import deepcopy
|
44
49
|
import os
|
45
50
|
import pkgutil
|
@@ -49,7 +54,7 @@ import json
|
|
49
54
|
import errno
|
50
55
|
import logging
|
51
56
|
|
52
|
-
__version__ = "2.0.
|
57
|
+
__version__ = "2.0.0rc5"
|
53
58
|
|
54
59
|
class IfState():
|
55
60
|
def __init__(self):
|
@@ -66,6 +71,7 @@ class IfState():
|
|
66
71
|
'link': True,
|
67
72
|
'sysctl': os.access('/proc/sys/net', os.R_OK),
|
68
73
|
'ethtool': not ethtool_path is None,
|
74
|
+
'schema': not globals().get("validate") is None,
|
69
75
|
'tc': True,
|
70
76
|
'wireguard': not globals().get("WireGuard") is None,
|
71
77
|
'bpf': not globals().get("libbpf") is None,
|
@@ -81,28 +87,31 @@ class IfState():
|
|
81
87
|
libbpf.libbpf_set_print(0)
|
82
88
|
|
83
89
|
def update(self, ifstates, soft_schema):
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
path
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
90
|
+
if self.features['schema']:
|
91
|
+
# check config schema
|
92
|
+
schema = json.loads(pkgutil.get_data(
|
93
|
+
"libifstate", "../schema/{}/ifstate.conf.schema.json".format(__version__.split('.')[0])))
|
94
|
+
try:
|
95
|
+
validate(ifstates, schema, format_checker=FormatChecker())
|
96
|
+
except ValidationError as ex:
|
97
|
+
if len(ex.path) > 0:
|
98
|
+
path = ["$"]
|
99
|
+
for i, p in enumerate(ex.absolute_path):
|
100
|
+
if type(p) == int:
|
101
|
+
path.append("[{}]".format(p))
|
102
|
+
else:
|
103
|
+
path.append(".")
|
104
|
+
path.append(p)
|
98
105
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
+
detail = "{}: {}".format("".join(path), ex.message)
|
107
|
+
else:
|
108
|
+
detail = ex.message
|
109
|
+
if soft_schema:
|
110
|
+
logger.error("Config validation failed for {}".format(detail))
|
111
|
+
else:
|
112
|
+
raise ParserValidationError(detail)
|
113
|
+
else:
|
114
|
+
logger.debug('Python package jsonschema not available, skipping config validation.')
|
106
115
|
|
107
116
|
# add interface defaults
|
108
117
|
if 'defaults' in ifstates:
|
@@ -349,8 +358,8 @@ class IfState():
|
|
349
358
|
# ignore if the link is already gone, this might happen
|
350
359
|
# when removing veth link peers
|
351
360
|
if err.code != errno.ENODEV:
|
352
|
-
logger.warning('removing
|
353
|
-
|
361
|
+
logger.warning('removing failed: {}'.format(
|
362
|
+
err.args[1]), extra={'iface': ifname, 'netns': item.netns})
|
354
363
|
return True
|
355
364
|
else:
|
356
365
|
# shutdown physical interfaces
|
@@ -364,8 +373,8 @@ class IfState():
|
|
364
373
|
except Exception as err:
|
365
374
|
if not isinstance(err, netlinkerror_classes):
|
366
375
|
raise
|
367
|
-
logger.warning('updating
|
368
|
-
|
376
|
+
logger.warning('updating failed: {}'.format(
|
377
|
+
err.args[1]), extra={'iface': ifname, 'netns': item.netns})
|
369
378
|
return False
|
370
379
|
|
371
380
|
def _dependencies(self, netns):
|
@@ -518,9 +527,8 @@ class IfState():
|
|
518
527
|
if link_dep.netns is None:
|
519
528
|
self._apply_iface(do_apply, self.root_netns, link_dep, by_vrrp, vrrp_type, vrrp_name, vrrp_state)
|
520
529
|
else:
|
521
|
-
if link_dep.netns not in self.namespaces:
|
522
|
-
logger.warning("
|
523
|
-
return
|
530
|
+
if self.namespaces is None or link_dep.netns not in self.namespaces:
|
531
|
+
logger.warning("apply link {} failed: netns '{}' is unknown".format(link_dep.ifname, link_dep.netns))
|
524
532
|
else:
|
525
533
|
self._apply_iface(do_apply, self.namespaces[link_dep.netns], link_dep, by_vrrp, vrrp_type, vrrp_name, vrrp_state)
|
526
534
|
|
@@ -559,8 +567,10 @@ class IfState():
|
|
559
567
|
|
560
568
|
def _apply_iface(self, do_apply, netns, link_dep, by_vrrp, vrrp_type, vrrp_name, vrrp_state):
|
561
569
|
ifname = link_dep.ifname
|
562
|
-
if ifname in netns.links:
|
563
|
-
link = netns
|
570
|
+
if not ifname in netns.links:
|
571
|
+
logger.warning('no link settings found', extra={'iface': ifname, 'netns': netns})
|
572
|
+
return
|
573
|
+
link = netns.links[ifname]
|
564
574
|
|
565
575
|
# check for vrrp mode:
|
566
576
|
# disable: vrrp type & name matches, but vrrp state not
|
@@ -649,7 +659,7 @@ class IfState():
|
|
649
659
|
else:
|
650
660
|
kind = info.get_attr('IFLA_INFO_KIND')
|
651
661
|
|
652
|
-
if
|
662
|
+
if not kind_has_identify(kind):
|
653
663
|
continue
|
654
664
|
|
655
665
|
ifs_link = {
|
@@ -672,6 +682,10 @@ class IfState():
|
|
672
682
|
def show(self, showall=False, show_secrets=False):
|
673
683
|
if showall:
|
674
684
|
defaults = deepcopy(Parser._default_ifstates)
|
685
|
+
|
686
|
+
hooks = get_available_hooks()
|
687
|
+
if hooks:
|
688
|
+
defaults['parameters']['hooks'] = hooks
|
675
689
|
else:
|
676
690
|
defaults = {}
|
677
691
|
|
@@ -711,12 +725,16 @@ class IfState():
|
|
711
725
|
if not any(ip in net for net in ipaddr_ignore):
|
712
726
|
ifs_link['addresses'].append(ip.with_prefixlen)
|
713
727
|
|
728
|
+
# drop empty ip addresses list, they are cleaned up by default
|
729
|
+
if not ifs_link['addresses']:
|
730
|
+
del(ifs_link['addresses'])
|
731
|
+
|
714
732
|
info = ipr_link.get_attr('IFLA_LINKINFO')
|
715
733
|
if info is None:
|
716
734
|
kind = None
|
717
735
|
else:
|
718
736
|
kind = info.get_attr('IFLA_INFO_KIND')
|
719
|
-
if
|
737
|
+
if not kind_has_identify(kind):
|
720
738
|
ifs_link['link']['kind'] = kind
|
721
739
|
|
722
740
|
data = info.get_attr('IFLA_INFO_DATA')
|
libifstate/address/__init__.py
CHANGED
@@ -18,8 +18,8 @@ class Addresses():
|
|
18
18
|
# get ifindex
|
19
19
|
idx = next(iter(self.netns.ipr.link_lookup(ifname=self.iface)), None)
|
20
20
|
|
21
|
+
# check if interface exists
|
21
22
|
if idx == None:
|
22
|
-
logger.warning('link missing', extra={'iface': self.iface, 'netns': self.netns})
|
23
23
|
return
|
24
24
|
|
25
25
|
# get active ip addresses
|
libifstate/exception.py
CHANGED
@@ -4,8 +4,9 @@ from libifstate.util import logger
|
|
4
4
|
netlinkerror_classes = (NetlinkError)
|
5
5
|
|
6
6
|
class ExceptionCollector():
|
7
|
-
def __init__(self, ifname):
|
7
|
+
def __init__(self, ifname, netns):
|
8
8
|
self.ifname = ifname
|
9
|
+
self.netns = netns
|
9
10
|
self.reset()
|
10
11
|
|
11
12
|
def reset(self):
|
@@ -19,8 +20,9 @@ class ExceptionCollector():
|
|
19
20
|
'args': kwargs,
|
20
21
|
})
|
21
22
|
if not self.quiet:
|
22
|
-
logger.warning('{}
|
23
|
-
op,
|
23
|
+
logger.warning('{} failed: {}'.format(
|
24
|
+
op, excpt.args[1]),
|
25
|
+
extra={'iface': self.ifname, 'netns': self.netns})
|
24
26
|
|
25
27
|
def has_op(self, op):
|
26
28
|
for e in self.excpts:
|
libifstate/hook/__init__.py
CHANGED
@@ -13,7 +13,7 @@ import tempfile
|
|
13
13
|
|
14
14
|
|
15
15
|
HOOK_DIR = '/etc/ifstate/hooks'
|
16
|
-
HOOK_WRAPPER = Template(pkgutil.get_data("libifstate", "
|
16
|
+
HOOK_WRAPPER = Template(pkgutil.get_data("libifstate", "hook/wrapper.sh").decode("utf-8"))
|
17
17
|
|
18
18
|
RC_OK = 0
|
19
19
|
RC_ERROR = 1
|
libifstate/link/__init__.py
CHANGED
libifstate/link/base.py
CHANGED
@@ -436,7 +436,7 @@ class Link(ABC):
|
|
436
436
|
return self.match_vrrp_select(vrrp_type, vrrp_name) and (vrrp_state in self.vrrp['states'])
|
437
437
|
|
438
438
|
def apply(self, do_apply, sysctl):
|
439
|
-
excpts = ExceptionCollector(self.settings['ifname'])
|
439
|
+
excpts = ExceptionCollector(self.settings['ifname'], self.netns)
|
440
440
|
osettings = copy.deepcopy(self.settings)
|
441
441
|
|
442
442
|
# lookup for attributes requiring a interface index
|
@@ -448,8 +448,11 @@ class Link(ABC):
|
|
448
448
|
# ignore *_netns settings if the netns is the same as the interface's one
|
449
449
|
# (there is no IFLA_LINK_NETNSID attribute in such cases)
|
450
450
|
if self.settings[netns_attr] != self.netns.netns:
|
451
|
-
|
452
|
-
|
451
|
+
try:
|
452
|
+
(peer_ipr, peer_nsid) = self.netns.get_netnsid(self.settings[netns_attr])
|
453
|
+
except NetnsUnknown as ex:
|
454
|
+
excpts.add('apply', ex)
|
455
|
+
return excpts
|
453
456
|
self.settings[netnsid_attr] = peer_nsid
|
454
457
|
idx = next(iter(peer_ipr.link_lookup(
|
455
458
|
ifname=self.settings[attr])), None)
|
libifstate/link/dsa.py
ADDED
libifstate/link/physical.py
CHANGED
@@ -10,4 +10,4 @@ class PhysicalLink(Link):
|
|
10
10
|
self.ethtool = ethtool
|
11
11
|
|
12
12
|
def create(self, do_apply, sysctl, excpts, oper="add"):
|
13
|
-
logger.warning('
|
13
|
+
logger.warning('unable to create physical link', extra={'iface': self.settings.get('ifname'), 'netns': self.netns})
|
libifstate/link/tun.py
CHANGED
@@ -18,6 +18,6 @@ class TunLink(Link):
|
|
18
18
|
|
19
19
|
def create(self, do_apply, sysctl, excpts, oper="add"):
|
20
20
|
if not self.cap_create:
|
21
|
-
logger.warning('
|
21
|
+
logger.warning('unable to create non-persistent tuntap link', extra={'iface': self.settings.get('ifname'), 'netns': self.netns})
|
22
22
|
else:
|
23
23
|
super().create(do_apply, sysctl, excpts, oper)
|
libifstate/log.py
CHANGED
@@ -73,13 +73,16 @@ class IfStateLogging:
|
|
73
73
|
return IfStateLogging.ANSI_YELLOW
|
74
74
|
return ""
|
75
75
|
|
76
|
-
def __init__(self, level, handlers=[], action=None, log_stderr=True):
|
76
|
+
def __init__(self, level, global_level, handlers=[], action=None, log_stderr=True):
|
77
77
|
if level != logging.DEBUG:
|
78
78
|
sys.tracebacklimit = 0
|
79
79
|
|
80
|
-
|
81
|
-
|
82
|
-
|
80
|
+
if global_level:
|
81
|
+
logging.basicConfig(
|
82
|
+
level=level,
|
83
|
+
)
|
84
|
+
else:
|
85
|
+
logger.level = level
|
83
86
|
|
84
87
|
if log_stderr:
|
85
88
|
has_stderr = sys.stderr is not None
|
libifstate/netns/__init__.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
from libifstate.exception import NetnsUnknown
|
1
2
|
from libifstate.util import logger, IfStateLogging, IPRouteExt, NetNSExt, root_ipr, root_iw, IDENTIFY_LOOKUPS
|
2
3
|
from libifstate.sysctl import Sysctl
|
3
4
|
|
@@ -88,9 +89,11 @@ class NetNameSpace():
|
|
88
89
|
if peer_netns_name is None:
|
89
90
|
peer_ipr = root_ipr
|
90
91
|
peer_pid = 1
|
91
|
-
|
92
|
+
elif peer_netns_name in netns_name_map:
|
92
93
|
peer_ipr = netns_name_map[peer_netns_name]
|
93
94
|
peer_pid = peer_ipr.child
|
95
|
+
else:
|
96
|
+
raise NetnsUnknown(peer_netns_name)
|
94
97
|
|
95
98
|
result = self.ipr.get_netnsid(pid=peer_pid)
|
96
99
|
if result['nsid'] == 4294967295:
|
libifstate/parser/__init__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
from libifstate.parser.base import Parser
|
1
|
+
from libifstate.parser.base import Parser, get_available_hooks
|
2
2
|
from libifstate.parser.yaml import YamlParser
|
libifstate/parser/base.py
CHANGED
@@ -1,7 +1,22 @@
|
|
1
|
+
from libifstate.hook import HOOK_DIR
|
1
2
|
from libifstate.util import logger
|
2
3
|
from libifstate.exception import ParserValidationError
|
3
4
|
from abc import ABC, abstractmethod
|
4
5
|
from copy import deepcopy
|
6
|
+
import os
|
7
|
+
|
8
|
+
|
9
|
+
def get_available_hooks():
|
10
|
+
# check if there is a hooks dir before trying to scan it
|
11
|
+
if not os.path.isdir(HOOK_DIR):
|
12
|
+
return {}
|
13
|
+
|
14
|
+
hooks = {}
|
15
|
+
with os.scandir(HOOK_DIR) as it:
|
16
|
+
for dentry in it:
|
17
|
+
if dentry.is_file():
|
18
|
+
hooks[dentry.name] = {}
|
19
|
+
return hooks
|
5
20
|
|
6
21
|
|
7
22
|
class Parser(ABC):
|
@@ -151,6 +166,14 @@ class Parser(ABC):
|
|
151
166
|
for namespace in cfg.get('namespaces', {}):
|
152
167
|
self._update_lo(cfg['namespaces'][namespace])
|
153
168
|
|
169
|
+
# add available hooks
|
170
|
+
if "hooks" in cfg["parameters"]:
|
171
|
+
hooks = get_available_hooks()
|
172
|
+
hooks.update(cfg["parameters"]["hooks"])
|
173
|
+
cfg["parameters"]["hooks"] = hooks
|
174
|
+
else:
|
175
|
+
cfg["parameters"]["hooks"] = get_available_hooks()
|
176
|
+
|
154
177
|
# merge builtin defaults
|
155
178
|
if "defaults" in cfg["parameters"]:
|
156
179
|
cfg["parameters"]["defaults"].extend(cfg["parameters"]["defaults_builtin"])
|
@@ -2851,6 +2851,49 @@
|
|
2851
2851
|
}
|
2852
2852
|
}
|
2853
2853
|
},
|
2854
|
+
{
|
2855
|
+
"description": "Distributed Switch Architecture (DSA) user interface",
|
2856
|
+
"required": [
|
2857
|
+
"kind"
|
2858
|
+
],
|
2859
|
+
"additionalProperties": false,
|
2860
|
+
"properties": {
|
2861
|
+
"kind": {
|
2862
|
+
"type": "string",
|
2863
|
+
"description": "link type",
|
2864
|
+
"enum": [
|
2865
|
+
"dsa"
|
2866
|
+
]
|
2867
|
+
},
|
2868
|
+
"address": {
|
2869
|
+
"$ref": "#/$defs/iface-link_address"
|
2870
|
+
},
|
2871
|
+
"group": {
|
2872
|
+
"$ref": "#/$defs/iface-link_group"
|
2873
|
+
},
|
2874
|
+
"state": {
|
2875
|
+
"$ref": "#/$defs/iface-link_state"
|
2876
|
+
},
|
2877
|
+
"master": {
|
2878
|
+
"$ref": "#/$defs/iface-link_master"
|
2879
|
+
},
|
2880
|
+
"mtu": {
|
2881
|
+
"$ref": "#/$defs/iface-link_mtu"
|
2882
|
+
},
|
2883
|
+
"txqlen": {
|
2884
|
+
"$ref": "#/$defs/iface-link_txqlen"
|
2885
|
+
},
|
2886
|
+
"ifalias": {
|
2887
|
+
"$ref": "#/$defs/iface-link_ifalias"
|
2888
|
+
},
|
2889
|
+
"link": {
|
2890
|
+
"$ref": "#/$defs/iface-link_link"
|
2891
|
+
},
|
2892
|
+
"link_netns": {
|
2893
|
+
"$ref": "#/$defs/iface-link_link-netns"
|
2894
|
+
}
|
2895
|
+
}
|
2896
|
+
},
|
2854
2897
|
{
|
2855
2898
|
"description": "Physical network interface",
|
2856
2899
|
"required": [
|
libifstate/sysctl/__init__.py
CHANGED
@@ -3,6 +3,14 @@ import pyroute2.netns
|
|
3
3
|
|
4
4
|
import os
|
5
5
|
|
6
|
+
def deep_update(d, u):
|
7
|
+
"""update the nested dict `d` with values from `u`"""
|
8
|
+
for k, v in u.items():
|
9
|
+
if isinstance(v, dict):
|
10
|
+
d[k] = deep_update(d.get(k, {}), v)
|
11
|
+
else:
|
12
|
+
d[k] = v
|
13
|
+
return d
|
6
14
|
|
7
15
|
class Sysctl():
|
8
16
|
def __init__(self, netns):
|
@@ -17,7 +25,8 @@ class Sysctl():
|
|
17
25
|
self.netns = netns
|
18
26
|
|
19
27
|
def add(self, iface, sysctl):
|
20
|
-
|
28
|
+
# deeply apply changes to the default/previously defined values
|
29
|
+
self.sysctls[iface] = deep_update(self.sysctls[iface], sysctl)
|
21
30
|
|
22
31
|
def add_global(self, proto, sysctl):
|
23
32
|
self.globals[proto] = sysctl
|
libifstate/tc/__init__.py
CHANGED
@@ -254,7 +254,7 @@ class TC():
|
|
254
254
|
return changes
|
255
255
|
|
256
256
|
def apply(self, do_apply):
|
257
|
-
excpts = ExceptionCollector(
|
257
|
+
excpts = ExceptionCollector(self.iface, self.netns)
|
258
258
|
|
259
259
|
# get ifindex
|
260
260
|
self.idx = next(iter(self.netns.ipr.link_lookup(ifname=self.iface)), None)
|
libifstate/util.py
CHANGED
@@ -128,7 +128,7 @@ def get_netns_run_dir(function, netns, *args):
|
|
128
128
|
|
129
129
|
def dump_yaml_file(fn, obj, opener=None):
|
130
130
|
"""
|
131
|
-
Dump obj to a
|
131
|
+
Dump obj to a YAML file, create directories if needed and catch file
|
132
132
|
I/O errors.
|
133
133
|
"""
|
134
134
|
try:
|
@@ -144,7 +144,7 @@ def dump_yaml_file(fn, obj, opener=None):
|
|
144
144
|
|
145
145
|
def slurp_yaml_file(fn, default=None):
|
146
146
|
"""
|
147
|
-
Read the content of a
|
147
|
+
Read the content of a YAML file, returns *default* if the file could not be
|
148
148
|
found, read or parsed.
|
149
149
|
"""
|
150
150
|
try:
|
@@ -157,6 +157,13 @@ def slurp_yaml_file(fn, default=None):
|
|
157
157
|
|
158
158
|
return default
|
159
159
|
|
160
|
+
def kind_has_identify(kind):
|
161
|
+
"""
|
162
|
+
Return True if the interface kind can be identified by some unique
|
163
|
+
properties. These are all types of physical interfaces.
|
164
|
+
"""
|
165
|
+
return kind is None or kind in ['dsa']
|
166
|
+
|
160
167
|
class IPRouteExt(IPRoute):
|
161
168
|
def __init__(self, *args, **kwargs):
|
162
169
|
super().__init__(*args, **kwargs)
|
libifstate/wireguard/__init__.py
CHANGED
@@ -4,7 +4,9 @@ import wgnlpy
|
|
4
4
|
import ipaddress
|
5
5
|
import collections
|
6
6
|
from copy import deepcopy
|
7
|
+
import os
|
7
8
|
import pyroute2.netns
|
9
|
+
from pyroute2 import NetlinkError
|
8
10
|
import socket
|
9
11
|
|
10
12
|
SECRET_SETTINGS = ['private_key', 'preshared_key']
|
@@ -58,6 +60,9 @@ class WireGuard():
|
|
58
60
|
try:
|
59
61
|
state = self.wg.get_interface(
|
60
62
|
self.iface, spill_private_key=True, spill_preshared_keys=True)
|
63
|
+
except NetlinkError as err:
|
64
|
+
logger.warning('query wireguard details failed: {}'.format(os.strerror(err.code)), extra={'iface': self.iface, 'netns': self.netns})
|
65
|
+
return
|
61
66
|
except TypeError as err:
|
62
67
|
# wgnlpy 0.1.5 can triggger a TypeError exception
|
63
68
|
# if the WGPEER_A_LAST_HANDSHAKE_TIME NLA does not
|
@@ -1,38 +0,0 @@
|
|
1
|
-
hooks/wrapper.sh,sha256=ipCmvcadJbXTT6oUR7BIhT5uglITnHfiAdm44vydZuw,1101
|
2
|
-
ifstate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
-
ifstate/ifstate.py,sha256=ioiM9xgVWdrpTpK_UxJdaJFlmpFM9R-2_d5pq9_Hepo,9272
|
4
|
-
ifstate/shell.py,sha256=7_JFpi4icr9MijynDzbb0v5mxhFsng6PCC4m3uQ255A,2177
|
5
|
-
ifstate/vrrp.py,sha256=FJ9b1eJseTtZFfknHU-xV68Qz7cPrRrc5PTcjUVj-fY,5953
|
6
|
-
ifstate-2.0.0rc3.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
7
|
-
libifstate/__init__.py,sha256=iDV2VI11gPAIDrTXKqkWbo4B9bRcokiY3Fzyu440ayg,33194
|
8
|
-
libifstate/exception.py,sha256=jhLN46mqlyGNEz7lmc0K2d3SoZJtKzEVyPduPh22oC0,2280
|
9
|
-
libifstate/log.py,sha256=XVoZdwdQoWsjuupFIuG6OP0OrBpXpx7oqyAaUhQ-nJk,4553
|
10
|
-
libifstate/util.py,sha256=raYAaRy15JQNUbU3_4GchYV_PkaCvWR_8xjt7NTzMYw,11335
|
11
|
-
libifstate/address/__init__.py,sha256=zIGM7UWXSvoijHMD06DfS2CDtiHpiJlqDgJG7Dl1IPE,3222
|
12
|
-
libifstate/bpf/__init__.py,sha256=NVzaunTmJU2PbIQg9eWBMKpFgLh3EnD3ujNa7Yt6rNc,7699
|
13
|
-
libifstate/bpf/ctypes.py,sha256=kLZJHZlba09Vc-tbsJAcKpDwdoNO2IjlYVLCopawHmA,4274
|
14
|
-
libifstate/bpf/map.py,sha256=cLHNMvRBDNW2yVCEf3z242_oRdU0HqVbFEYVkKXng0w,10818
|
15
|
-
libifstate/brport/__init__.py,sha256=NzdA8F4hr2se1bXKNnyKZbvOFlCWBq_cdjwsL1H0Y-o,2964
|
16
|
-
libifstate/fdb/__init__.py,sha256=9dpL5n8ct3CaA-z8I6ZEkD3yL6yWJQeq3fpIe9pc2zw,6486
|
17
|
-
libifstate/hook/__init__.py,sha256=OPUyhrr-eT1UNp8ryYoJyvi4WWqL2Ql33szir673Td4,7379
|
18
|
-
libifstate/link/__init__.py,sha256=QZggoC-bIscqwVedqVycaSqS1CmXB3Bx3m2FZei8Q_4,115
|
19
|
-
libifstate/link/base.py,sha256=dazZVPRMyXms-ICiL7VOCUXwZnqNr1X6R2NjTlm2nEU,34384
|
20
|
-
libifstate/link/physical.py,sha256=ectyXVchCHqWZR8qsjAD9667wjQbGW1OUKLQheTUFys,594
|
21
|
-
libifstate/link/tun.py,sha256=SWkscSAgIk3DWFPWHo9Cmokhj88rO1_sR7Z0Qlg2xGA,993
|
22
|
-
libifstate/link/veth.py,sha256=Sv5WZMMsefYFz9I0BQSZyKytCQYxv0vjwAnB7FYHR1A,2283
|
23
|
-
libifstate/neighbour/__init__.py,sha256=FJJpbJvqnxvOEii6QDMYzW5jQDEbiEy71GQOEbqaS48,2463
|
24
|
-
libifstate/netns/__init__.py,sha256=ptSIVld_BNXPE6f4SiIPVdYOE1sgprf5-ZhR-L_3BPE,10145
|
25
|
-
libifstate/parser/__init__.py,sha256=byz1W0G7UewVc5FFie-ti3UZjGK3-75wHIaOeq0oySQ,88
|
26
|
-
libifstate/parser/base.py,sha256=EV7uJYdVke3a2ghkUZ6ZeaIeVQAPVS4rFnYhebXeQm0,5932
|
27
|
-
libifstate/parser/yaml.py,sha256=MC0kmwqt3P45z61fb_wfUqoj0iZyhFYkdPyr0UqMSZA,1415
|
28
|
-
libifstate/routing/__init__.py,sha256=O4lbaCJvLgx-iQUa0WDgRmSPR4AKvveqPgxxb4HwYQ4,25305
|
29
|
-
libifstate/sysctl/__init__.py,sha256=u1VJ1aPXeGCl3rwj3g0bDbz6k5k9YS5hQIsgFOBokpk,3202
|
30
|
-
libifstate/tc/__init__.py,sha256=inPdampCOIr_4oKNB3awqMkW0Eh4fpPh9jvSba6sPVg,12092
|
31
|
-
libifstate/wireguard/__init__.py,sha256=dXILLIuahBCkX2ONhre28SzJrVNksbjOICs-cSGGaRg,8625
|
32
|
-
libifstate/xdp/__init__.py,sha256=X1xhEIGng7R5d5F4KsChykT2g6H-XBRWbWABijoYDQA,7208
|
33
|
-
schema/2/ifstate.conf.schema.json,sha256=ukCafLPfHCXpk44u5RMMhWIh9JoIAt2j_3idysAVHaQ,218763
|
34
|
-
ifstate-2.0.0rc3.dist-info/METADATA,sha256=hdygdnfWvpggPIMQXwGSHPovg8Xt8VzsE-gAlPf1y-Y,1607
|
35
|
-
ifstate-2.0.0rc3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
36
|
-
ifstate-2.0.0rc3.dist-info/entry_points.txt,sha256=HF6jX7Uu_nF1Ly-J9uEPeiRapOxnM6LuHsb2y6Mt-k4,52
|
37
|
-
ifstate-2.0.0rc3.dist-info/top_level.txt,sha256=A7peI7aKBaM69fsiSPvMbL3rzTKZZr5qDxKC-pHMGdE,19
|
38
|
-
ifstate-2.0.0rc3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|