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 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="store_true",
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/config.yml", help="configuration YaML filename")
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.ERROR
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+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ifstate
3
- Version: 2.0.0rc3
3
+ Version: 2.0.0rc5
4
4
  Summary: Manage host interface settings in a declarative manner
5
5
  Home-page: https://ifstate.net/
6
6
  Author: Thomas Liske
@@ -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.0rc3"
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
- # check config schema
85
- schema = json.loads(pkgutil.get_data(
86
- "libifstate", "../schema/{}/ifstate.conf.schema.json".format(__version__.split('.')[0])))
87
- try:
88
- validate(ifstates, schema, format_checker=FormatChecker())
89
- except ValidationError as ex:
90
- if len(ex.path) > 0:
91
- path = ["$"]
92
- for i, p in enumerate(ex.absolute_path):
93
- if type(p) == int:
94
- path.append("[{}]".format(p))
95
- else:
96
- path.append(".")
97
- path.append(p)
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
- detail = "{}: {}".format("".join(path), ex.message)
100
- else:
101
- detail = ex.message
102
- if soft_schema:
103
- logger.error("Config validation failed for {}".format(detail))
104
- else:
105
- raise ParserValidationError(detail)
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 link {} failed: {}'.format(
353
- ifname, err.args[1]), extra={'netns': item.netns})
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 link {} failed: {}'.format(
368
- ifname, err.args[1]), extra={'netns': item.netns})
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("add link {} failed: netns '{}' is unknown".format(link_dep.ifname, link_dep.netns))
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.links[ifname]
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 kind is not None:
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 kind is not None:
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')
@@ -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('{} link {} failed: {}'.format(
23
- op, self.ifname, excpt.args[1]))
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:
@@ -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", "../hooks/wrapper.sh").decode("utf-8"))
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
@@ -1,4 +1,5 @@
1
1
  import libifstate.link.base
2
+ import libifstate.link.dsa
2
3
  import libifstate.link.physical
3
4
  import libifstate.link.tun
4
5
  import libifstate.link.veth
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
- # ToDo: throw exception for unknown netns
452
- (peer_ipr, peer_nsid) = self.netns.get_netnsid(self.settings[netns_attr])
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
@@ -0,0 +1,10 @@
1
+ from libifstate.util import logger
2
+ from libifstate.link.physical import PhysicalLink
3
+
4
+ class DsaLink(PhysicalLink):
5
+ """
6
+ Distributed Switch Architecture (DSA) user interface
7
+
8
+ https://docs.kernel.org/networking/dsa/configuration.html
9
+ """
10
+ pass
@@ -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('Unable to create missing physical link: {}'.format(self.settings.get('ifname')))
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('Unable to create missing non-persistent tuntap link: {}'.format(self.settings.get('ifname')))
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
- logging.basicConfig(
81
- level=level,
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
@@ -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
- else:
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:
@@ -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": [
@@ -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
- self.sysctls[iface] = sysctl
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(ifname=self.iface)
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 YaML file, create directories if needed and catch file
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 YaML file, returns *default* if the file could not be
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)
@@ -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