ifstate 1.8.2__py3-none-any.whl → 1.8.4__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
@@ -86,7 +86,7 @@ def main():
86
86
  shell()
87
87
  exit(0)
88
88
 
89
- ifslog = IfStateLogging(lvl)
89
+ ifslog = IfStateLogging(lvl, action=args.action)
90
90
  ifs = IfState()
91
91
 
92
92
  if args.action in [Actions.SHOW, Actions.SHOWALL]:
@@ -137,7 +137,7 @@ def main():
137
137
  pass
138
138
  elif args.action == Actions.VRRP_FIFO:
139
139
  status_pattern = re.compile(
140
- r'(group|instance) "([^"]+)" (unknown|fault|backup|master)$', re.IGNORECASE)
140
+ r'(group|instance) "([^"]+)" (unknown|fault|backup|master)( \d+)?$', re.IGNORECASE)
141
141
 
142
142
  with open(args.fifo) as fifo:
143
143
  for line in fifo:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ifstate
3
- Version: 1.8.2
3
+ Version: 1.8.4
4
4
  Summary: Manage host interface settings in a declarative manner
5
5
  Home-page: https://ifstate.net/
6
6
  Author: Thomas Liske
@@ -1,18 +1,19 @@
1
1
  ifstate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- ifstate/ifstate.py,sha256=OozPkGJc5zH3p4Mo9GZc0vaInpwGZS0fo-dvjb3h0WA,6364
2
+ ifstate/ifstate.py,sha256=QXHkvhg4DSthU4V480RbaP4Hp00QMqSPlx2m4-UnD_g,6391
3
3
  ifstate/shell.py,sha256=8rzOu6VoKrsxenXLXnYiCLKoyDPnM1WCoUr-NUh9so8,2129
4
- libifstate/__init__.py,sha256=s2UNRDjzbYLSwYBEKgswsCi9KFhp1GJTMIIR9AitqoM,23262
4
+ libifstate/__init__.py,sha256=LsIGh4pdVGzyBuEpwZ45gOUG1ekzll0Ah4dmOt68JAw,23902
5
5
  libifstate/exception.py,sha256=x6jupUpOL1YVG_erjmgTqnSQEU8rMHYNcY3d4iERGko,2146
6
- libifstate/log.py,sha256=3mX8HsFDVfu-2U7Sr7JSZ1peBSWGOgfuougez-NEWlo,2369
6
+ libifstate/log.py,sha256=4hh0G5EqvTsmBzFAxC8uBXmdC9Nrze65bJZq77DOZgU,3264
7
7
  libifstate/util.py,sha256=mOgdPnvdQZ6jw4aY7rfvWupNA5jni1KFaa2-VWecA2E,3824
8
8
  libifstate/address/__init__.py,sha256=XRoQy12Byq2VeLkP40V-E2uUO2RZJODAtvxh-vRAuWw,2796
9
9
  libifstate/bpf/__init__.py,sha256=j8tpAuJodoiEu5x7tRN6oinXxInB3ZhdepkXdc1Bk10,6818
10
10
  libifstate/bpf/ctypes.py,sha256=kLZJHZlba09Vc-tbsJAcKpDwdoNO2IjlYVLCopawHmA,4274
11
11
  libifstate/bpf/map.py,sha256=cLHNMvRBDNW2yVCEf3z242_oRdU0HqVbFEYVkKXng0w,10818
12
12
  libifstate/brport/__init__.py,sha256=scUs3ZfAcvxx5bNLsWnOhVZiBdLvw7qrS8ttIxpDwCc,2868
13
- libifstate/link/__init__.py,sha256=7_AfXP98zNPNgEiJ6djlA0hlYpoIDy-X7ZQPd1Q9Pag,88
14
- libifstate/link/base.py,sha256=CHM0tMPLUHNd_XUNNK977hIwCFpxYLUpSD3jJtQzlL8,21912
13
+ libifstate/link/__init__.py,sha256=QZggoC-bIscqwVedqVycaSqS1CmXB3Bx3m2FZei8Q_4,115
14
+ libifstate/link/base.py,sha256=HWnnzJo9ukMwbsrz9K-yPeSTNKUyx8VzV-7Fb588EJc,22110
15
15
  libifstate/link/physical.py,sha256=J5vRPZ1ceOg1cI8EBT97NlS4cp0Nxq34ULSl3XYlVXM,528
16
+ libifstate/link/tun.py,sha256=FQa0iaEE2WoCuEapTXIYbtxPTRAwZsYSONc-hGaNhQo,927
16
17
  libifstate/link/veth.py,sha256=zLL86kgsIvVu4PBzbR078sm_akb6FqPR8BIwUwyJ0fY,597
17
18
  libifstate/neighbour/__init__.py,sha256=SJEcYJzunqlZjBr_pAk4yGGp0kzH2rleSB7yHmvzJX8,2577
18
19
  libifstate/parser/__init__.py,sha256=byz1W0G7UewVc5FFie-ti3UZjGK3-75wHIaOeq0oySQ,88
@@ -23,10 +24,10 @@ libifstate/sysctl/__init__.py,sha256=rfjdwXHrAoizIGATMdxI1sVEzedKeJCt6AUcxyomPVo
23
24
  libifstate/tc/__init__.py,sha256=1YWndT6MHtdsZ86O0a9_SmOBEsM7WCz7Bayo4j3wavc,11188
24
25
  libifstate/wireguard/__init__.py,sha256=nTA0bNglV8UbheJ4otEuAIZ9J_GFIQMf66MAS-Y4DtQ,5207
25
26
  libifstate/xdp/__init__.py,sha256=pjeNzofe4kQ7ZKNwonvjiu6YpWO2H1M7j91X4zPiVhA,6662
26
- schema/ifstate.conf.schema.json,sha256=TWw78ofzsPbl9fZqOkZbTYs8P7ZL6u75ar0OFZigVQM,174283
27
- ifstate-1.8.2.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
28
- ifstate-1.8.2.dist-info/METADATA,sha256=bQyu5Y5hXgBCt8g35fgBac05U47UcaLOwNgCqchGwZw,1359
29
- ifstate-1.8.2.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
30
- ifstate-1.8.2.dist-info/entry_points.txt,sha256=HF6jX7Uu_nF1Ly-J9uEPeiRapOxnM6LuHsb2y6Mt-k4,52
31
- ifstate-1.8.2.dist-info/top_level.txt,sha256=A7peI7aKBaM69fsiSPvMbL3rzTKZZr5qDxKC-pHMGdE,19
32
- ifstate-1.8.2.dist-info/RECORD,,
27
+ schema/ifstate.conf.schema.json,sha256=hkC_HSZwanxdviilVkxq1ja6VvpJiFPqG3Tz41ahSfM,178382
28
+ ifstate-1.8.4.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
29
+ ifstate-1.8.4.dist-info/METADATA,sha256=sSaV6k8urvdZ7O-BnMfd4DqFL_UQuViqJVyyvKab4Rk,1359
30
+ ifstate-1.8.4.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
31
+ ifstate-1.8.4.dist-info/entry_points.txt,sha256=HF6jX7Uu_nF1Ly-J9uEPeiRapOxnM6LuHsb2y6Mt-k4,52
32
+ ifstate-1.8.4.dist-info/top_level.txt,sha256=A7peI7aKBaM69fsiSPvMbL3rzTKZZr5qDxKC-pHMGdE,19
33
+ ifstate-1.8.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.38.4)
2
+ Generator: bdist_wheel (0.40.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
libifstate/__init__.py CHANGED
@@ -43,7 +43,7 @@ import json
43
43
  import errno
44
44
  import logging
45
45
 
46
- __version__ = "1.8.2"
46
+ __version__ = "1.8.4"
47
47
 
48
48
 
49
49
  class IfState():
@@ -262,11 +262,21 @@ class IfState():
262
262
 
263
263
  def _apply(self, do_apply, vrrp_type, vrrp_name, vrrp_state):
264
264
  vrrp_ignore = []
265
- vrrp_remove = []
265
+ vrrp_disable = []
266
266
 
267
267
  by_vrrp = not None in [
268
268
  vrrp_type, vrrp_name, vrrp_state]
269
269
 
270
+ if by_vrrp:
271
+ logger.info("vrrp state change: {} {} => {}".format(vrrp_type, vrrp_name, vrrp_state))
272
+
273
+ # ifstate schema requires lower case keywords
274
+ vrrp_type = vrrp_type.lower()
275
+ vrrp_state = vrrp_state.lower()
276
+
277
+ # check which links to remove or ignore:
278
+ # remove: vrrp type & name matches, but vrrp state not
279
+ # ignore: vrrp type & name does not match
270
280
  for ifname, link in self.links.items():
271
281
  if ifname in self.vrrp['links']:
272
282
  if not by_vrrp:
@@ -275,9 +285,11 @@ class IfState():
275
285
  if not link.match_vrrp_select(vrrp_type, vrrp_name):
276
286
  vrrp_ignore.append(ifname)
277
287
  elif not vrrp_name in self.vrrp[vrrp_type] or not vrrp_state in self.vrrp[vrrp_type][vrrp_name] or not ifname in self.vrrp[vrrp_type][vrrp_name][vrrp_state]:
278
- vrrp_remove.append(ifname)
288
+ vrrp_disable.append(ifname)
279
289
  elif by_vrrp:
280
290
  vrrp_ignore.append(ifname)
291
+ logger.debug("vrrp links to be disabled: {}".format(", ".join(vrrp_disable)))
292
+ logger.debug("vrrp links to be ignored: {}".format(", ".join(vrrp_ignore)))
281
293
 
282
294
  self.ipaddr_ignore = set()
283
295
  for ip in self.ignore.get('ipaddr', []):
@@ -299,10 +311,10 @@ class IfState():
299
311
  if stage == 0:
300
312
  logger.info("\nconfiguring interface links")
301
313
 
302
- for ifname in vrrp_remove:
303
- logger.debug('to be removed due to vrrp constraint',
314
+ for ifname in vrrp_disable:
315
+ logger.debug('to be disabled due to vrrp constraint',
304
316
  extra={'iface': ifname})
305
- del self.links[ifname]
317
+ self.links[ifname].settings['state'] = 'down'
306
318
  else:
307
319
  logger.info("\nconfiguring interface links (stage 2)")
308
320
 
@@ -325,7 +337,7 @@ class IfState():
325
337
  applied.append(name)
326
338
  else:
327
339
  deps = link.depends()
328
- if all(x in applied for x in deps):
340
+ if all(x in applied+vrrp_ignore for x in deps):
329
341
  excpts = link.apply(do_apply, self.sysctl)
330
342
  if excpts.has_errno(errno.EEXIST):
331
343
  retry = True
@@ -1,3 +1,4 @@
1
1
  import libifstate.link.base
2
2
  import libifstate.link.physical
3
+ import libifstate.link.tun
3
4
  import libifstate.link.veth
libifstate/link/base.py CHANGED
@@ -66,6 +66,11 @@ class Link(ABC):
66
66
  1: "bandwidth",
67
67
  2: "count",
68
68
  },
69
+ # === tuntap ===
70
+ 'tun_type': {
71
+ 1: 'tun',
72
+ 2: 'tap',
73
+ },
69
74
  # === vlan ===
70
75
  'vlan_protocol': {
71
76
  0x88a8: '802.1ad',
@@ -108,7 +113,7 @@ class Link(ABC):
108
113
  'ip6gre_link', 'vxlan_link', 'xfrm_link']
109
114
  self.idx = None
110
115
 
111
- if 'address' in self.settings:
116
+ if 'address' in self.settings and self.settings['kind'] == 'physical':
112
117
  self.settings['address'] = self.settings['address'].lower()
113
118
  self.idx = next(iter(ipr.link_lookup(
114
119
  address=self.settings['address'])), None)
@@ -369,7 +374,7 @@ class Link(ABC):
369
374
  raise
370
375
  excpts.add('del', err)
371
376
  self.idx = None
372
- self.create(do_apply, ifstate, excpts, "replace")
377
+ self.create(do_apply, sysctl, excpts, "replace")
373
378
 
374
379
  def update(self, do_apply, sysctl, excpts):
375
380
  logger.debug('checking link', extra={'iface': self.settings['ifname']})
@@ -505,13 +510,14 @@ class Link(ABC):
505
510
  self.brport.apply(do_apply, self.idx, excpts)
506
511
 
507
512
  if has_state_changes:
508
- try:
509
- ipr.link('set', index=self.idx,
510
- state=self.settings["state"])
511
- except Exception as err:
512
- if not isinstance(err, netlinkerror_classes):
513
- raise
514
- excpts.add('set', err, state=state)
513
+ if do_apply:
514
+ try:
515
+ ipr.link('set', index=self.idx,
516
+ state=self.settings["state"])
517
+ except Exception as err:
518
+ if not isinstance(err, netlinkerror_classes):
519
+ raise
520
+ excpts.add('set', err, state=state)
515
521
  logger.info('change', extra={
516
522
  'iface': self.settings['ifname'], 'style': IfStateLogging.STYLE_CHG})
517
523
 
libifstate/link/tun.py ADDED
@@ -0,0 +1,23 @@
1
+ from libifstate.util import logger
2
+ from libifstate.link.base import Link
3
+ from libifstate.exception import LinkCannotAdd
4
+
5
+ from pwd import getpwnam
6
+ from grp import getgrnam
7
+
8
+ class TunLink(Link):
9
+ def __init__(self, name, link, ethtool, vrrp, brport):
10
+ if 'tun_owner' in link and isinstance(link['tun_owner'], str):
11
+ link['tun_owner'] = getpwnam(link['tun_owner'])[2]
12
+
13
+ if 'tun_group' in link and isinstance(link['tun_group'], str):
14
+ link['tun_group'] = getgrnam(link['tun_group'])[2]
15
+
16
+ super().__init__(name, link, ethtool, vrrp, brport)
17
+ self.cap_create = bool(link.get('tun_persist'))
18
+
19
+ def create(self, do_apply, sysctl, excpts, oper="add"):
20
+ if not self.cap_create:
21
+ logger.warning('Unable to create missing non-persistent tuntap link: {}'.format(self.settings.get('ifname')))
22
+ else:
23
+ super().create(do_apply, sysctl, excpts, oper)
libifstate/log.py CHANGED
@@ -1,44 +1,46 @@
1
1
  import logging
2
2
  from logging.handlers import QueueHandler, QueueListener
3
+ import os
3
4
  import queue
4
5
  import sys
5
6
 
6
7
  logger = logging.getLogger('ifstate')
8
+ logger.propagate = False
9
+
10
+ formatter = logging.Formatter('%(bol)s%(prefix)s%(style)s%(message)s%(eol)s')
7
11
 
8
12
  class IfStateLogFilter(logging.Filter):
9
- def __init__(self, terminal):
13
+ def __init__(self, is_terminal):
10
14
  super().__init__()
11
- self.terminal = terminal
15
+ self.is_terminal = is_terminal
12
16
 
13
17
  def filter(self, record):
14
18
  record.levelshort = record.levelname[:1]
19
+
15
20
  if hasattr(record, 'iface'):
16
21
  record.prefix = " {:15} ".format(record.iface)
17
22
  else:
18
23
  record.prefix = ''
19
24
 
20
- if self.terminal:
25
+ if self.is_terminal and record.levelno >= logging.WARNING:
21
26
  if record.levelno >= logging.ERROR:
22
27
  record.bol = IfStateLogging.ANSI_RED
23
- elif record.levelno >= logging.WARNING:
24
- record.bol = IfStateLogging.ANSI_MAGENTA
25
28
  else:
26
- record.bol = ''
29
+ record.bol = IfStateLogging.ANSI_MAGENTA
27
30
  record.eol = IfStateLogging.ANSI_RESET
28
31
  else:
29
32
  record.bol = ''
30
33
  record.eol = ''
31
34
 
32
- if hasattr(record, 'style'):
33
- if self.terminal:
34
- record.style = IfStateLogging.colorize(record.style)
35
- else:
36
- record.style = ""
35
+ if self.is_terminal and hasattr(record, 'style'):
36
+ record.style = IfStateLogging.colorize(record.style)
37
+ record.eol = IfStateLogging.ANSI_RESET
37
38
  else:
38
39
  record.style = ""
39
40
 
40
41
  return True
41
42
 
43
+
42
44
  class IfStateLogging:
43
45
  STYLE_OK = "ok"
44
46
  STYLE_CHG = "chg"
@@ -61,22 +63,44 @@ class IfStateLogging:
61
63
  return IfStateLogging.ANSI_YELLOW
62
64
  return ""
63
65
 
64
- def __init__(self, level, handlers=[]):
66
+ def __init__(self, level, handlers=[], action=None):
65
67
  if level != logging.DEBUG:
66
68
  sys.tracebacklimit = 0
67
69
 
68
70
  logging.basicConfig(
69
71
  level=level,
70
- format='%(bol)s%(prefix)s%(style)s%(message)s%(eol)s',
71
72
  )
72
73
 
73
- is_terminal = sys.stderr is not None and sys.stderr.isatty()
74
- f = IfStateLogFilter(is_terminal)
75
- logger.addFilter(f)
74
+ has_stderr = sys.stderr is not None
75
+ is_terminal = has_stderr and sys.stderr.isatty()
76
+
77
+ # add custom logging handlers
78
+ if not handlers:
79
+ handlers = []
80
+
81
+ if has_stderr:
82
+ # log to stderr
83
+ stream = logging.StreamHandler(sys.stderr)
84
+ stream.addFilter(IfStateLogFilter(is_terminal))
85
+ stream.setFormatter(formatter)
86
+ handlers.append(stream)
87
+
88
+ # log to syslog
89
+ syslog = logging.handlers.SysLogHandler('/dev/log', facility=logging.handlers.SysLogHandler.LOG_DAEMON)
90
+ if action is None:
91
+ syslog.ident = 'ifstate[{}] '.format(os.getpid())
92
+ else:
93
+ syslog.ident = 'ifstate-{}[{}] '.format(action, os.getpid())
94
+ syslog.addFilter(IfStateLogFilter(False))
95
+ syslog.setFormatter(formatter)
96
+ handlers.append(syslog)
76
97
 
77
98
  qu = queue.SimpleQueue()
78
- logger.addHandler(QueueHandler(qu))
79
- self.listener = QueueListener(qu, *handlers, respect_handler_level=True)
99
+ queue_handler = QueueHandler(qu)
100
+ queue_handler.setLevel(level)
101
+ logger.addHandler(queue_handler)
102
+ self.listener = QueueListener(
103
+ qu, *handlers, respect_handler_level=True)
80
104
  self.listener.start()
81
105
 
82
106
  def quit(self):
@@ -1449,13 +1449,15 @@
1449
1449
  }
1450
1450
  },
1451
1451
  {
1452
- "description": "Virtual software device",
1452
+ "description": "Virtual software device (TUN/TAP)",
1453
1453
  "required": [
1454
- "kind"
1454
+ "kind",
1455
+ "tun_type"
1455
1456
  ],
1457
+ "additionalProperties": false,
1456
1458
  "properties": {
1457
1459
  "kind": {
1458
- "const": "tuntap",
1460
+ "const": "tun",
1459
1461
  "description": "link type"
1460
1462
  },
1461
1463
  "address": {
@@ -1478,6 +1480,82 @@
1478
1480
  },
1479
1481
  "ifalias": {
1480
1482
  "$ref": "#/$defs/iface-link_ifalias"
1483
+ },
1484
+ "tun_type": {
1485
+ "description": "device mode (Ethernet headers)",
1486
+ "default": "tap",
1487
+ "enum": [
1488
+ 1,
1489
+ "tun",
1490
+ 2,
1491
+ "tap"
1492
+ ]
1493
+ },
1494
+ "tun_pi": {
1495
+ "description": "provide packet information",
1496
+ "type": [
1497
+ "boolean",
1498
+ "integer"
1499
+ ],
1500
+ "default": false,
1501
+ "enum": [
1502
+ 0,
1503
+ false,
1504
+ 1,
1505
+ true
1506
+ ]
1507
+ },
1508
+ "tun_persist": {
1509
+ "description": "persistent device; non-persistent devices cannot be created",
1510
+ "type": [
1511
+ "boolean",
1512
+ "integer"
1513
+ ],
1514
+ "default": false,
1515
+ "enum": [
1516
+ 0,
1517
+ false,
1518
+ 1,
1519
+ true
1520
+ ]
1521
+ },
1522
+ "tun_vnet_hdr": {
1523
+ "description": "prepend frames with struct virtio_net_hdr",
1524
+ "default": false,
1525
+ "enum": [
1526
+ 0,
1527
+ false,
1528
+ 1,
1529
+ true
1530
+ ]
1531
+ },
1532
+ "tun_multi_queue": {
1533
+ "description": "enable multiqueue tuntap",
1534
+ "type": [
1535
+ "boolean",
1536
+ "integer"
1537
+ ],
1538
+ "default": false,
1539
+ "enum": [
1540
+ 0,
1541
+ false,
1542
+ 1,
1543
+ true
1544
+ ]
1545
+ },
1546
+ "tun_owner": {
1547
+ "description": "device owner",
1548
+ "type": [
1549
+ "integer",
1550
+ "string"
1551
+ ]
1552
+ },
1553
+ "tun_group": {
1554
+ "description": "device group",
1555
+ "type": [
1556
+ "integer",
1557
+ "string"
1558
+ ]
1481
1559
  }
1482
1560
  }
1483
1561
  },