ifstate 1.13.7__py3-none-any.whl → 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ifstate/ifstate.py +15 -8
- {ifstate-1.13.7.dist-info → ifstate-2.0.0.dist-info}/METADATA +2 -2
- ifstate-2.0.0.dist-info/RECORD +39 -0
- libifstate/__init__.py +147 -78
- libifstate/address/__init__.py +1 -1
- libifstate/exception.py +6 -12
- libifstate/hook/__init__.py +195 -0
- libifstate/hook/wrapper.sh +50 -0
- libifstate/link/base.py +29 -34
- libifstate/link/dsa.py +1 -1
- libifstate/link/physical.py +3 -3
- libifstate/link/tun.py +3 -3
- libifstate/link/veth.py +2 -2
- libifstate/log.py +7 -4
- libifstate/netns/__init__.py +44 -6
- libifstate/parser/__init__.py +1 -1
- libifstate/parser/base.py +131 -85
- libifstate/routing/__init__.py +63 -17
- libifstate/schema/2/ifstate.conf.schema.json +4442 -0
- libifstate/sysctl/__init__.py +20 -2
- libifstate/tc/__init__.py +1 -1
- libifstate/util.py +153 -147
- libifstate/wireguard/__init__.py +82 -21
- ifstate-1.13.7.dist-info/RECORD +0 -37
- schema/ifstate.conf.schema.json +0 -4259
- {ifstate-1.13.7.dist-info → ifstate-2.0.0.dist-info}/WHEEL +0 -0
- {ifstate-1.13.7.dist-info → ifstate-2.0.0.dist-info}/entry_points.txt +0 -0
- {ifstate-1.13.7.dist-info → ifstate-2.0.0.dist-info}/licenses/LICENSE +0 -0
- {ifstate-1.13.7.dist-info → ifstate-2.0.0.dist-info}/top_level.txt +0 -0
ifstate/ifstate.py
CHANGED
@@ -21,6 +21,7 @@ import yaml
|
|
21
21
|
class Actions():
|
22
22
|
CHECK = "check"
|
23
23
|
APPLY = "apply"
|
24
|
+
IDENTIFY = "identify"
|
24
25
|
SHOW = "show"
|
25
26
|
SHOWALL = "showall"
|
26
27
|
VRRP = "vrrp"
|
@@ -31,6 +32,7 @@ class Actions():
|
|
31
32
|
ACTIONS_HELP = {
|
32
33
|
"CHECK" : "dry run update the network config",
|
33
34
|
"APPLY" : "update the network config",
|
35
|
+
"IDENTIFY" : "show interface attributes available for identification",
|
34
36
|
"SHOW" : "show running network config",
|
35
37
|
"SHOWALL" : "show running network config (more settings)",
|
36
38
|
"VRRP" : "run as keepalived notify script",
|
@@ -128,14 +130,16 @@ def main():
|
|
128
130
|
group = parser.add_mutually_exclusive_group()
|
129
131
|
parser.add_argument('--version', action='version',
|
130
132
|
version='%(prog)s {version}'.format(version=__version__))
|
131
|
-
group.add_argument("-v", "--verbose", action="
|
132
|
-
help="be more verbose")
|
133
|
+
group.add_argument("-v", "--verbose", action="count", default=0,
|
134
|
+
help="be more verbose (twice for very verbose)")
|
133
135
|
group.add_argument("-q", "--quiet", action="store_true",
|
134
136
|
help="be more quiet, print only warnings and errors")
|
135
137
|
parser.add_argument("-s", "--soft-schema", action="store_true",
|
136
138
|
help="ignore schema validation errors, expect ifstatecli to trigger internal exceptions")
|
139
|
+
parser.add_argument("-S", "--show-secrets", action="store_true",
|
140
|
+
help="show secrets when dumping config")
|
137
141
|
parser.add_argument("-c", "--config", type=str,
|
138
|
-
default="/etc/ifstate/
|
142
|
+
default="/etc/ifstate/ifstate.yaml", help="configuration YaML filename")
|
139
143
|
subparsers = parser.add_subparsers(
|
140
144
|
dest='action', required=True, help="specifies the action to perform")
|
141
145
|
|
@@ -162,10 +166,10 @@ def main():
|
|
162
166
|
"name", type=str, help="name of the vrrp group or instance")
|
163
167
|
|
164
168
|
args = parser.parse_args()
|
165
|
-
if args.verbose:
|
169
|
+
if args.verbose > 0:
|
166
170
|
lvl = logging.DEBUG
|
167
171
|
elif args.quiet:
|
168
|
-
lvl = logging.
|
172
|
+
lvl = logging.WARNING
|
169
173
|
else:
|
170
174
|
lvl = logging.INFO
|
171
175
|
|
@@ -178,15 +182,18 @@ def main():
|
|
178
182
|
shell()
|
179
183
|
exit(0)
|
180
184
|
|
181
|
-
ifslog = IfStateLogging(lvl, action=args.action)
|
185
|
+
ifslog = IfStateLogging(lvl, args.verbose > 1, action=args.action)
|
182
186
|
|
183
|
-
if args.action in [Actions.SHOW, Actions.SHOWALL]:
|
187
|
+
if args.action in [Actions.IDENTIFY, Actions.SHOW, Actions.SHOWALL]:
|
184
188
|
# preserve dict order on python 3.7+
|
185
189
|
if sys.version_info >= (3, 7):
|
186
190
|
yaml.add_representer(
|
187
191
|
dict, lambda self, data: yaml.representer.SafeRepresenter.represent_dict(self, data.items()))
|
188
192
|
ifs = IfState()
|
189
|
-
|
193
|
+
if args.action == Actions.IDENTIFY:
|
194
|
+
print(yaml.dump(ifs.identify()))
|
195
|
+
else:
|
196
|
+
print(yaml.dump(ifs.show(args.action == Actions.SHOWALL, args.show_secrets)))
|
190
197
|
|
191
198
|
ifslog.quit()
|
192
199
|
exit(0)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ifstate
|
3
|
-
Version:
|
3
|
+
Version: 2.0.0
|
4
4
|
Summary: Manage host interface settings in a declarative manner
|
5
5
|
Home-page: https://ifstate.net/
|
6
6
|
Author: Thomas Liske
|
@@ -9,7 +9,7 @@ License: GPL3+
|
|
9
9
|
Description-Content-Type: text/markdown
|
10
10
|
License-File: LICENSE
|
11
11
|
Requires-Dist: jsonschema
|
12
|
-
Requires-Dist: pyroute2
|
12
|
+
Requires-Dist: pyroute2!=0.9.3
|
13
13
|
Requires-Dist: pyyaml
|
14
14
|
Requires-Dist: setproctitle
|
15
15
|
Provides-Extra: shell
|
@@ -0,0 +1,39 @@
|
|
1
|
+
ifstate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
ifstate/ifstate.py,sha256=Vot_Bo0MGT_5MUKD5-pt2xB-fLLkjwvJo24KgtETtR8,9329
|
3
|
+
ifstate/shell.py,sha256=7_JFpi4icr9MijynDzbb0v5mxhFsng6PCC4m3uQ255A,2177
|
4
|
+
ifstate/vrrp.py,sha256=FJ9b1eJseTtZFfknHU-xV68Qz7cPrRrc5PTcjUVj-fY,5953
|
5
|
+
ifstate-2.0.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
6
|
+
libifstate/__init__.py,sha256=HFLB_cWQSAUarRzPCDdTFuL5EB1WjV1Fn0q_ut0RVvo,34053
|
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=v0S_R_aMZBdHJPI3zdelv5G0Xha-pUV2DRdmxhD7390,6624
|
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=_QNmH0CirbBy8VAupTm6UhIhB88fGWqUy9TnfmS0j5I,3637
|
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.0.dist-info/METADATA,sha256=f8JoMVgocYw7ow9r6dny6Hrpk1UQRUkrjEN0ASmYkwE,1604
|
36
|
+
ifstate-2.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
37
|
+
ifstate-2.0.0.dist-info/entry_points.txt,sha256=HF6jX7Uu_nF1Ly-J9uEPeiRapOxnM6LuHsb2y6Mt-k4,52
|
38
|
+
ifstate-2.0.0.dist-info/top_level.txt,sha256=A7peI7aKBaM69fsiSPvMbL3rzTKZZr5qDxKC-pHMGdE,19
|
39
|
+
ifstate-2.0.0.dist-info/RECORD,,
|
libifstate/__init__.py
CHANGED
@@ -2,9 +2,10 @@ from libifstate.exception import LinkDuplicate, NetnsUnknown
|
|
2
2
|
from libifstate.link.base import ethtool_path, Link
|
3
3
|
from libifstate.address import Addresses
|
4
4
|
from libifstate.fdb import FDB
|
5
|
+
from libifstate.hook import Hooks
|
5
6
|
from libifstate.neighbour import Neighbours
|
6
7
|
from libifstate.routing import Tables, Rules, RTLookups
|
7
|
-
from libifstate.parser import Parser
|
8
|
+
from libifstate.parser import Parser, get_available_hooks
|
8
9
|
from libifstate.tc import TC
|
9
10
|
from libifstate.exception import netlinkerror_classes
|
10
11
|
import bisect
|
@@ -34,11 +35,16 @@ except ModuleNotFoundError:
|
|
34
35
|
# ignore missing plugin
|
35
36
|
pass
|
36
37
|
|
38
|
+
try:
|
39
|
+
from jsonschema import validate, ValidationError, FormatChecker
|
40
|
+
except ModuleNotFoundError:
|
41
|
+
# fail open and ignore missing jsonschema dependency
|
42
|
+
pass
|
43
|
+
|
37
44
|
from libifstate.netns import NetNameSpace, prepare_netns, LinkRegistry, get_netns_instances
|
38
|
-
from libifstate.util import logger, IfStateLogging, LinkDependency
|
45
|
+
from libifstate.util import logger, root_iw, kind_has_identify, IfStateLogging, LinkDependency, IDENTIFY_LOOKUPS
|
39
46
|
from libifstate.exception import FeatureMissingError, LinkCircularLinked, LinkNoConfigFound, ParserValidationError
|
40
47
|
from ipaddress import ip_network, ip_interface
|
41
|
-
from jsonschema import validate, ValidationError, FormatChecker
|
42
48
|
from copy import deepcopy
|
43
49
|
import os
|
44
50
|
import pkgutil
|
@@ -48,8 +54,7 @@ import json
|
|
48
54
|
import errno
|
49
55
|
import logging
|
50
56
|
|
51
|
-
__version__ = "
|
52
|
-
|
57
|
+
__version__ = "2.0.0"
|
53
58
|
|
54
59
|
class IfState():
|
55
60
|
def __init__(self):
|
@@ -61,9 +66,12 @@ class IfState():
|
|
61
66
|
self.ignore = {}
|
62
67
|
self.features = {
|
63
68
|
'brport': True,
|
69
|
+
'devicetree': os.access('/sys/firmware/devicetree', os.R_OK),
|
70
|
+
'iw': root_iw is not None,
|
64
71
|
'link': True,
|
65
72
|
'sysctl': os.access('/proc/sys/net', os.R_OK),
|
66
73
|
'ethtool': not ethtool_path is None,
|
74
|
+
'schema': not globals().get("validate") is None,
|
67
75
|
'tc': True,
|
68
76
|
'wireguard': not globals().get("WireGuard") is None,
|
69
77
|
'bpf': not globals().get("libbpf") is None,
|
@@ -79,35 +87,38 @@ class IfState():
|
|
79
87
|
libbpf.libbpf_set_print(0)
|
80
88
|
|
81
89
|
def update(self, ifstates, soft_schema):
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
path
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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)
|
96
105
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
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.')
|
104
115
|
|
105
116
|
# add interface defaults
|
106
117
|
if 'defaults' in ifstates:
|
107
|
-
self.defaults = ifstates['defaults']
|
118
|
+
self.defaults = ifstates['parameters']['defaults']
|
108
119
|
|
109
120
|
# add ignore list items
|
110
|
-
self.ignore.update(ifstates['ignore'])
|
121
|
+
self.ignore.update(ifstates['parameters']['ignore'])
|
111
122
|
self.ipaddr_ignore = set()
|
112
123
|
for ip in self.ignore.get('ipaddr', []):
|
113
124
|
self.ipaddr_ignore.add(ip_network(ip))
|
@@ -116,7 +127,10 @@ class IfState():
|
|
116
127
|
self.fdb_ignore = re.compile('|'.join(self.ignore.get('fdb')))
|
117
128
|
|
118
129
|
# save cshaper profiles
|
119
|
-
self.cshaper_profiles = ifstates['cshaper']
|
130
|
+
self.cshaper_profiles = ifstates['parameters']['cshaper']
|
131
|
+
|
132
|
+
# prepare hooks
|
133
|
+
self.hooks = Hooks(ifstates['parameters'].get('hooks', {}))
|
120
134
|
|
121
135
|
# build link registry over all named netns
|
122
136
|
self.link_registry = LinkRegistry(self.ignore.get('ifname', []), self.root_netns)
|
@@ -134,17 +148,15 @@ class IfState():
|
|
134
148
|
self._update(self.namespaces[netns_name], netns_ifstates)
|
135
149
|
|
136
150
|
def _update(self, netns, ifstates):
|
137
|
-
# parse
|
138
|
-
if '
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
netns.sysctl.add_global(
|
147
|
-
proto, ifstates['options']['sysctl'][proto])
|
151
|
+
# parse network sysctl settings
|
152
|
+
if 'sysctl' in ifstates:
|
153
|
+
for proto in ifstates['sysctl'].keys():
|
154
|
+
if proto in ['all', 'default']:
|
155
|
+
netns.sysctl.add(
|
156
|
+
proto, ifstates['sysctl'][proto])
|
157
|
+
else:
|
158
|
+
netns.sysctl.add_global(
|
159
|
+
proto, ifstates['sysctl'][proto])
|
148
160
|
|
149
161
|
# load BPF programs
|
150
162
|
if 'bpf' in ifstates:
|
@@ -157,8 +169,7 @@ class IfState():
|
|
157
169
|
netns.bpf_progs.add(name, config)
|
158
170
|
|
159
171
|
# add interfaces from config
|
160
|
-
for ifstate in ifstates['interfaces']:
|
161
|
-
name = ifstate['name']
|
172
|
+
for name, ifstate in ifstates['interfaces'].items():
|
162
173
|
kind = ifstate['link']['kind']
|
163
174
|
defaults = self.get_defaults(
|
164
175
|
ifname=name,
|
@@ -189,7 +200,7 @@ class IfState():
|
|
189
200
|
link.update(ifstate['link'])
|
190
201
|
if link:
|
191
202
|
netns.links[name] = Link(self,
|
192
|
-
netns, name, link, ethtool, ifstate.get('vrrp'), ifstate.get('brport'))
|
203
|
+
netns, name, link, ifstate.get('identify', {}), ethtool, ifstate.get('hooks', []), ifstate.get('vrrp'), ifstate.get('brport'))
|
193
204
|
else:
|
194
205
|
netns.links[name] = None
|
195
206
|
|
@@ -224,7 +235,7 @@ class IfState():
|
|
224
235
|
netns.sysctl.add(name, ifstate['sysctl'])
|
225
236
|
|
226
237
|
if 'cshaper' in ifstate:
|
227
|
-
profile_name = ifstate['cshaper'].get(
|
238
|
+
profile_name = ifstate['parameters']['cshaper'].get(
|
228
239
|
'profile', 'default')
|
229
240
|
logger.debug('cshaper profile {} enabled'.format(profile_name),
|
230
241
|
extra={'iface': name, 'netns': netns})
|
@@ -246,7 +257,7 @@ class IfState():
|
|
246
257
|
'qdisc': cshaper_profile['ingress_qdisc'],
|
247
258
|
}
|
248
259
|
}
|
249
|
-
ifb_state['tc']['qdisc']['bandwidth'] = ifstate['cshaper'].get(
|
260
|
+
ifb_state['tc']['qdisc']['bandwidth'] = ifstate['parameters']['cshaper'].get(
|
250
261
|
'ingress', 'unlimited')
|
251
262
|
|
252
263
|
if 'vrrp' in ifstate:
|
@@ -279,10 +290,10 @@ class IfState():
|
|
279
290
|
]
|
280
291
|
}
|
281
292
|
|
282
|
-
ifstate['tc']['qdisc']['bandwidth'] = ifstate['cshaper'].get(
|
293
|
+
ifstate['tc']['qdisc']['bandwidth'] = ifstate['parameters']['cshaper'].get(
|
283
294
|
'egress', 'unlimited')
|
284
295
|
|
285
|
-
del ifstate['cshaper']
|
296
|
+
del ifstate['parameters']['cshaper']
|
286
297
|
|
287
298
|
if 'tc' in ifstate:
|
288
299
|
netns.tc[name] = TC(
|
@@ -347,8 +358,8 @@ class IfState():
|
|
347
358
|
# ignore if the link is already gone, this might happen
|
348
359
|
# when removing veth link peers
|
349
360
|
if err.code != errno.ENODEV:
|
350
|
-
logger.warning('removing
|
351
|
-
|
361
|
+
logger.warning('removing failed: {}'.format(
|
362
|
+
err.args[1]), extra={'iface': ifname, 'netns': item.netns})
|
352
363
|
return True
|
353
364
|
else:
|
354
365
|
# shutdown physical interfaces
|
@@ -362,8 +373,8 @@ class IfState():
|
|
362
373
|
except Exception as err:
|
363
374
|
if not isinstance(err, netlinkerror_classes):
|
364
375
|
raise
|
365
|
-
logger.warning('updating
|
366
|
-
|
376
|
+
logger.warning('updating failed: {}'.format(
|
377
|
+
err.args[1]), extra={'iface': ifname, 'netns': item.netns})
|
367
378
|
return False
|
368
379
|
|
369
380
|
def _dependencies(self, netns):
|
@@ -516,9 +527,8 @@ class IfState():
|
|
516
527
|
if link_dep.netns is None:
|
517
528
|
self._apply_iface(do_apply, self.root_netns, link_dep, by_vrrp, vrrp_type, vrrp_name, vrrp_state)
|
518
529
|
else:
|
519
|
-
if link_dep.netns not in self.namespaces:
|
520
|
-
logger.warning("
|
521
|
-
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))
|
522
532
|
else:
|
523
533
|
self._apply_iface(do_apply, self.namespaces[link_dep.netns], link_dep, by_vrrp, vrrp_type, vrrp_name, vrrp_state)
|
524
534
|
|
@@ -557,8 +567,10 @@ class IfState():
|
|
557
567
|
|
558
568
|
def _apply_iface(self, do_apply, netns, link_dep, by_vrrp, vrrp_type, vrrp_name, vrrp_state):
|
559
569
|
ifname = link_dep.ifname
|
560
|
-
if ifname in netns.links:
|
561
|
-
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]
|
562
574
|
|
563
575
|
# check for vrrp mode:
|
564
576
|
# disable: vrrp type & name matches, but vrrp state not
|
@@ -611,6 +623,8 @@ class IfState():
|
|
611
623
|
if ifname in netns.wireguard:
|
612
624
|
netns.wireguard[ifname].apply(do_apply)
|
613
625
|
|
626
|
+
self.hooks.apply(link, do_apply)
|
627
|
+
|
614
628
|
def _apply_routing(self, do_apply, netns, by_vrrp, vrrp_type, vrrp_name, vrrp_state):
|
615
629
|
if not netns.tables is None:
|
616
630
|
netns.tables.apply(self.ignore.get('routes', []), do_apply, by_vrrp, vrrp_type, vrrp_name, vrrp_state)
|
@@ -618,36 +632,86 @@ class IfState():
|
|
618
632
|
if not netns.rules is None:
|
619
633
|
netns.rules.apply(self.ignore.get('rules', []), do_apply, by_vrrp, vrrp_type, vrrp_name, vrrp_state)
|
620
634
|
|
621
|
-
def
|
635
|
+
def identify(self):
|
636
|
+
root_config = self._identify_netns(self.root_netns)
|
637
|
+
netns_instances = get_netns_instances()
|
638
|
+
if len(netns_instances) > 0:
|
639
|
+
netns_identifies = {}
|
640
|
+
for netns in netns_instances:
|
641
|
+
netns_identify = self._identify_netns(netns)
|
642
|
+
if netns_identify is not None:
|
643
|
+
netns_identifies[netns.netns] = netns_identify
|
644
|
+
|
645
|
+
if netns_identifies:
|
646
|
+
return {**root_config, 'namespaces': netns_identifies}
|
647
|
+
|
648
|
+
return {**root_config}
|
649
|
+
|
650
|
+
def _identify_netns(self, netns):
|
651
|
+
ifs_links = {}
|
652
|
+
for ipr_link in netns.ipr.get_links():
|
653
|
+
name = ipr_link.get_attr('IFLA_IFNAME')
|
654
|
+
# skip links on ignore list
|
655
|
+
if name != 'lo' and not any(re.match(regex, name) for regex in Parser._default_ifstates['parameters']['ignore']['ifname_builtin']):
|
656
|
+
info = ipr_link.get_attr('IFLA_LINKINFO')
|
657
|
+
if info is None:
|
658
|
+
kind = None
|
659
|
+
else:
|
660
|
+
kind = info.get_attr('IFLA_INFO_KIND')
|
661
|
+
|
662
|
+
if not kind_has_identify(kind):
|
663
|
+
continue
|
664
|
+
|
665
|
+
ifs_link = {
|
666
|
+
'identify': {
|
667
|
+
},
|
668
|
+
}
|
669
|
+
|
670
|
+
for attr, lookup in IDENTIFY_LOOKUPS.items():
|
671
|
+
value = lookup(netns, ipr_link)
|
672
|
+
if value is not None:
|
673
|
+
ifs_link['identify'][attr] = value
|
674
|
+
|
675
|
+
ifs_links[name] = ifs_link
|
676
|
+
|
677
|
+
if ifs_links:
|
678
|
+
return {**{'interfaces': ifs_links}}
|
679
|
+
else:
|
680
|
+
return None
|
681
|
+
|
682
|
+
def show(self, showall=False, show_secrets=False):
|
622
683
|
if showall:
|
623
684
|
defaults = deepcopy(Parser._default_ifstates)
|
685
|
+
|
686
|
+
hooks = get_available_hooks()
|
687
|
+
if hooks:
|
688
|
+
defaults['parameters']['hooks'] = hooks
|
624
689
|
else:
|
625
690
|
defaults = {}
|
626
691
|
|
627
692
|
ipaddr_ignore = []
|
628
|
-
for ip in Parser._default_ifstates['ignore']['ipaddr_builtin']:
|
693
|
+
for ip in Parser._default_ifstates['parameters']['ignore']['ipaddr_builtin']:
|
629
694
|
ipaddr_ignore.append(ip_network(ip))
|
630
695
|
|
631
|
-
root_config = self._show_netns(self.root_netns, showall, ipaddr_ignore)
|
696
|
+
root_config = self._show_netns(self.root_netns, showall, show_secrets, ipaddr_ignore)
|
632
697
|
netns_instances = get_netns_instances()
|
633
698
|
if len(netns_instances) > 0:
|
634
699
|
netns_configs = {}
|
635
700
|
for netns in netns_instances:
|
636
|
-
netns_configs[netns.netns] = self._show_netns(netns, showall, ipaddr_ignore)
|
701
|
+
netns_configs[netns.netns] = self._show_netns(netns, showall, show_secrets, ipaddr_ignore)
|
637
702
|
|
638
703
|
return {**defaults, **root_config, 'namespaces': netns_configs}
|
639
704
|
|
640
705
|
|
641
706
|
return {**defaults, **root_config}
|
642
707
|
|
643
|
-
def _show_netns(self, netns, showall, ipaddr_ignore):
|
644
|
-
ifs_links =
|
708
|
+
def _show_netns(self, netns, showall, show_secrets, ipaddr_ignore):
|
709
|
+
ifs_links = {}
|
645
710
|
for ipr_link in netns.ipr.get_links():
|
646
711
|
name = ipr_link.get_attr('IFLA_IFNAME')
|
647
712
|
# skip links on ignore list
|
648
|
-
if name != 'lo' and not any(re.match(regex, name) for regex in Parser._default_ifstates['ignore']['ifname_builtin']):
|
713
|
+
if name != 'lo' and not any(re.match(regex, name) for regex in Parser._default_ifstates['parameters']['ignore']['ifname_builtin']):
|
649
714
|
ifs_link = {
|
650
|
-
'name': name,
|
651
715
|
'addresses': [],
|
652
716
|
'link': {
|
653
717
|
'state': ipr_link['state'],
|
@@ -661,12 +725,16 @@ class IfState():
|
|
661
725
|
if not any(ip in net for net in ipaddr_ignore):
|
662
726
|
ifs_link['addresses'].append(ip.with_prefixlen)
|
663
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
|
+
|
664
732
|
info = ipr_link.get_attr('IFLA_LINKINFO')
|
665
733
|
if info is None:
|
666
734
|
kind = None
|
667
735
|
else:
|
668
736
|
kind = info.get_attr('IFLA_INFO_KIND')
|
669
|
-
if
|
737
|
+
if not kind_has_identify(kind):
|
670
738
|
ifs_link['link']['kind'] = kind
|
671
739
|
|
672
740
|
data = info.get_attr('IFLA_INFO_DATA')
|
@@ -687,15 +755,13 @@ class IfState():
|
|
687
755
|
addr = ipr_link.get_attr('IFLA_ADDRESS')
|
688
756
|
if not addr is None:
|
689
757
|
ifs_link['link']['address'] = addr
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
if not businfo is None:
|
698
|
-
ifs_link['link']['businfo'] = businfo
|
758
|
+
|
759
|
+
# add identify section for physical links
|
760
|
+
ifs_link['identify'] = {}
|
761
|
+
for attr, func in IDENTIFY_LOOKUPS.items():
|
762
|
+
value = func(netns, ipr_link)
|
763
|
+
if value:
|
764
|
+
ifs_link['identify'][attr] = value
|
699
765
|
|
700
766
|
# add device group if not 0
|
701
767
|
group = ipr_link.get_attr('IFLA_GROUP')
|
@@ -722,6 +788,9 @@ class IfState():
|
|
722
788
|
|
723
789
|
brport.BRPort.show(netns.ipr, showall, ipr_link['index'], ifs_link)
|
724
790
|
|
791
|
+
if ifs_link['link']['kind'] == 'wireguard':
|
792
|
+
wireguard.WireGuard.show(netns, showall, show_secrets, name, ifs_link)
|
793
|
+
|
725
794
|
if name == 'lo':
|
726
795
|
if ifs_link['addresses'] == Parser._default_lo_link['addresses']:
|
727
796
|
del(ifs_link['addresses'])
|
@@ -730,13 +799,13 @@ class IfState():
|
|
730
799
|
del(ifs_link['link'])
|
731
800
|
|
732
801
|
if len(ifs_link) > 1:
|
733
|
-
ifs_links
|
802
|
+
ifs_links['lo'] = ifs_link
|
734
803
|
else:
|
735
|
-
ifs_links
|
804
|
+
ifs_links[name] = ifs_link
|
736
805
|
|
737
806
|
routing = {
|
738
|
-
'routes': Tables(netns).show_routes(Parser._default_ifstates['ignore']['routes_builtin']),
|
739
|
-
'rules': Rules(netns).show_rules(Parser._default_ifstates['ignore']['rules_builtin']),
|
807
|
+
'routes': Tables(netns).show_routes(Parser._default_ifstates['parameters']['ignore']['routes_builtin']),
|
808
|
+
'rules': Rules(netns).show_rules(Parser._default_ifstates['parameters']['ignore']['rules_builtin']),
|
740
809
|
}
|
741
810
|
|
742
811
|
return {**{'interfaces': ifs_links, 'routing': routing}}
|
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
@@ -1,19 +1,12 @@
|
|
1
|
-
from pyroute2
|
1
|
+
from pyroute2 import NetlinkError
|
2
2
|
from libifstate.util import logger
|
3
3
|
|
4
|
-
# pyroute2.minimal exceptions might be broken
|
5
|
-
# => workaround for pyroute2 #845 #847
|
6
4
|
netlinkerror_classes = (NetlinkError)
|
7
|
-
try:
|
8
|
-
from pr2modules.netlink.exceptions import NetlinkError as Pr2mNetlinkError
|
9
|
-
netlinkerror_classes = (NetlinkError, Pr2mNetlinkError)
|
10
|
-
except ModuleNotFoundError:
|
11
|
-
# required for pyroute2 before 0.6.0
|
12
|
-
pass
|
13
5
|
|
14
6
|
class ExceptionCollector():
|
15
|
-
def __init__(self, ifname):
|
7
|
+
def __init__(self, ifname, netns):
|
16
8
|
self.ifname = ifname
|
9
|
+
self.netns = netns
|
17
10
|
self.reset()
|
18
11
|
|
19
12
|
def reset(self):
|
@@ -27,8 +20,9 @@ class ExceptionCollector():
|
|
27
20
|
'args': kwargs,
|
28
21
|
})
|
29
22
|
if not self.quiet:
|
30
|
-
logger.warning('{}
|
31
|
-
op,
|
23
|
+
logger.warning('{} failed: {}'.format(
|
24
|
+
op, excpt.args[1]),
|
25
|
+
extra={'iface': self.ifname, 'netns': self.netns})
|
32
26
|
|
33
27
|
def has_op(self, op):
|
34
28
|
for e in self.excpts:
|