]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/ifupdown/networkinterfaces.py
SONAR: fix iface.py: Import only needed names or import the module and then use its...
[mirror_ifupdown2.git] / ifupdown2 / ifupdown / networkinterfaces.py
CommitLineData
35681c06 1#!/usr/bin/env python3
3e8ee54f 2#
d486dd0d 3# Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
3e8ee54f 4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6# networkInterfaces --
7# ifupdown network interfaces file parser
8#
a6f80f0e 9
0845cc57 10import collections
679e6567 11import copy
d486dd0d
JF
12import glob
13import logging
0845cc57
PKS
14import os
15import re
d486dd0d
JF
16
17try:
421e9573 18 from ifupdown2.ifupdown.iface import ifaceType, ifaceJsonDecoder, iface
d486dd0d
JF
19 from ifupdown2.ifupdown.utils import utils
20 from ifupdown2.ifupdown.template import templateEngine
bd441a51 21except (ImportError, ModuleNotFoundError):
421e9573 22 from ifupdown.iface import ifaceType, ifaceJsonDecoder, iface
d486dd0d
JF
23 from ifupdown.utils import utils
24 from ifupdown.template import templateEngine
25
a6f80f0e 26
c0071225
RP
27whitespaces = '\n\t\r '
28
a6f80f0e 29class networkInterfaces():
2c0ad8b3 30 """ debian ifupdown /etc/network/interfaces file parser """
a6f80f0e 31
77054f7f
SA
32 _addrfams = {'inet' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6', 'ppp', 'tunnel'],
33 'inet6' : ['static', 'manual', 'loopback', 'dhcp', 'dhcp6', 'ppp', 'tunnel']}
223ba5af 34 # tunnel is part of the address family for backward compatibility but is not required.
d913472d 35
14dc390d 36 def __init__(self, interfacesfile='/etc/network/interfaces',
3dcc1d0e 37 interfacesfileiobuf=None, interfacesfileformat='native',
f27710fe 38 template_enable='0', template_engine=None,
223ba5af 39 template_lookuppath=None, raw=False):
2c0ad8b3
RP
40 """This member function initializes the networkinterfaces parser object.
41
42 Kwargs:
904908bc
RP
43 **interfacesfile** (str): path to the interfaces file (default is /etc/network/interfaces)
44
45 **interfacesfileiobuf** (object): interfaces file io stream
46
47 **interfacesfileformat** (str): format of interfaces file (choices are 'native' and 'json'. 'native' being the default)
48
49 **template_engine** (str): template engine name
50
51 **template_lookuppath** (str): template lookup path
2c0ad8b3
RP
52
53 Raises:
54 AttributeError, KeyError """
55
d486dd0d
JF
56 self.auto_ifaces = []
57 self.callbacks = {}
58 self.auto_all = False
223ba5af 59 self.raw = raw
a6f80f0e 60 self.logger = logging.getLogger('ifupdown.' +
61 self.__class__.__name__)
d08d5f54 62 self.callbacks = {'iface_found' : None,
3dcc1d0e 63 'validateifaceattr' : None,
64 'validateifaceobj' : None}
a6f80f0e 65 self.allow_classes = {}
14dc390d 66 self.interfacesfile = interfacesfile
3dcc1d0e 67 self.interfacesfileiobuf = interfacesfileiobuf
68 self.interfacesfileformat = interfacesfileformat
14dc390d 69 self._filestack = [self.interfacesfile]
e272efd9
JF
70
71 self._template_engine = None
1f5db4a8 72 self._template_enable = template_enable
e272efd9
JF
73 self._template_engine_name = template_engine
74 self._template_engine_path = template_lookuppath
75
d40e96ee 76 self._currentfile_has_template = False
f102ef63 77 self._ws_split_regex = re.compile(r'[\s\t]\s*')
a6f80f0e 78
cfa06db6
RP
79 self.errors = 0
80 self.warns = 0
81
9dce3561 82 @property
83 def _currentfile(self):
84 try:
85 return self._filestack[-1]
3218f49d 86 except Exception:
14dc390d 87 return self.interfacesfile
9dce3561 88
89 def _parse_error(self, filename, lineno, msg):
d40e96ee 90 if lineno == -1 or self._currentfile_has_template:
9dce3561 91 self.logger.error('%s: %s' %(filename, msg))
92 else:
93 self.logger.error('%s: line%d: %s' %(filename, lineno, msg))
cfa06db6 94 self.errors += 1
a6f80f0e 95
aa5751ba
RP
96 def _parse_warn(self, filename, lineno, msg):
97 if lineno == -1 or self._currentfile_has_template:
c46af1c9 98 self.logger.warning('%s: %s' %(filename, msg))
aa5751ba 99 else:
c46af1c9 100 self.logger.warning('%s: line%d: %s' %(filename, lineno, msg))
cfa06db6 101 self.warns += 1
aa5751ba 102
3dcc1d0e 103 def _validate_addr_family(self, ifaceobj, lineno=-1):
004d1e65
JF
104 for family in ifaceobj.addr_family:
105 if not self._addrfams.get(family):
d913472d 106 self._parse_error(self._currentfile, lineno,
004d1e65
JF
107 'iface %s: unsupported address family \'%s\''
108 % (ifaceobj.name, family))
109 ifaceobj.addr_family = []
d913472d 110 ifaceobj.addr_method = None
111 return
112 if ifaceobj.addr_method:
004d1e65 113 if ifaceobj.addr_method not in self._addrfams.get(family):
d913472d 114 self._parse_error(self._currentfile, lineno,
004d1e65
JF
115 'iface %s: unsupported '
116 'address method \'%s\''
117 % (ifaceobj.name, ifaceobj.addr_method))
d913472d 118 else:
119 ifaceobj.addr_method = 'static'
120
a6f80f0e 121 def subscribe(self, callback_name, callback_func):
904908bc 122 """This member function registers callback functions.
2c0ad8b3
RP
123
124 Args:
904908bc
RP
125 **callback_name** (str): callback function name (supported names: 'iface_found', 'validateifaceattr', 'validateifaceobj')
126
127 **callback_func** (function pointer): callback function pointer
2c0ad8b3
RP
128
129 Warns on error
130 """
131
3b01ed76
JF
132 if callback_name not in list(self.callbacks.keys()):
133 print('warning: invalid callback ' + callback_name)
a6f80f0e 134 return -1
135
136 self.callbacks[callback_name] = callback_func
137
a6f80f0e 138 def ignore_line(self, line):
c0071225 139 l = line.strip(whitespaces)
fe0a57d3 140 if not l or l[0] == '#':
a6f80f0e 141 return 1
a6f80f0e 142 return 0
143
144 def process_allow(self, lines, cur_idx, lineno):
3e8ee54f 145 allow_line = lines[cur_idx]
a6f80f0e 146
f102ef63 147 words = re.split(self._ws_split_regex, allow_line)
a6f80f0e 148 if len(words) <= 1:
be0b20f2 149 raise Exception('invalid allow line \'%s\' at line %d'
150 %(allow_line, lineno))
a6f80f0e 151
152 allow_class = words[0].split('-')[1]
153 ifacenames = words[1:]
154
62ddec8b 155 if self.allow_classes.get(allow_class):
a6f80f0e 156 for i in ifacenames:
157 self.allow_classes[allow_class].append(i)
158 else:
159 self.allow_classes[allow_class] = ifacenames
a6f80f0e 160 return 0
161
a6f80f0e 162 def process_source(self, lines, cur_idx, lineno):
163 # Support regex
9a810db1 164 self.logger.debug('processing sourced line ..\'%s\'' % lines[cur_idx])
f102ef63 165 sourced_file = re.split(self._ws_split_regex, lines[cur_idx], 2)[1]
9a810db1 166
62ddec8b 167 if sourced_file:
9a810db1
PKS
168 if not os.path.isabs(sourced_file):
169 sourced_file = os.path.join(os.path.dirname(self._currentfile), sourced_file)
170
bb23b2f2 171 filenames = sorted(glob.glob(sourced_file))
2b5635d4 172 if not filenames:
3cdb1619
RP
173 if '*' not in sourced_file:
174 self._parse_warn(self._currentfile, lineno,
2b5635d4
RP
175 'cannot find source file %s' %sourced_file)
176 return 0
177 for f in filenames:
eab25b7c 178 self.read_file(f)
a6f80f0e 179 else:
9dce3561 180 self._parse_error(self._currentfile, lineno,
181 'unable to read source line')
a6f80f0e 182 return 0
183
0845cc57
PKS
184 def process_source_directory(self, lines, cur_idx, lineno):
185 self.logger.debug('processing source-directory line ..\'%s\'' % lines[cur_idx])
186 sourced_directory = re.split(self._ws_split_regex, lines[cur_idx], 2)[1]
9a810db1 187
0845cc57 188 if sourced_directory:
9a810db1
PKS
189 if not os.path.isabs(sourced_directory):
190 sourced_directory = os.path.join(os.path.dirname(self._currentfile), sourced_directory)
191
0845cc57
PKS
192 folders = glob.glob(sourced_directory)
193 for folder in folders:
0b48d2cf
PKS
194 for file in os.listdir(folder):
195 self.read_file(os.path.join(folder, file))
0845cc57
PKS
196 else:
197 self._parse_error(self._currentfile, lineno,
198 'unable to read source-directory line')
199 return 0
200
a6f80f0e 201 def process_auto(self, lines, cur_idx, lineno):
f102ef63 202 auto_ifaces = re.split(self._ws_split_regex, lines[cur_idx])[1:]
9dce3561 203 if not auto_ifaces:
d913472d 204 self._parse_error(self._currentfile, lineno,
9dce3561 205 'invalid auto line \'%s\''%lines[cur_idx])
206 return 0
679e6567
RP
207 for a in auto_ifaces:
208 if a == 'all':
209 self.auto_all = True
210 break
211 r = utils.parse_iface_range(a)
212 if r:
eba4da6e
RP
213 if len(r) == 3:
214 # eg swp1.[2-4], r = "swp1.", 2, 4)
215 for i in range(r[1], r[2]+1):
216 self.auto_ifaces.append('%s%d' %(r[0], i))
217 elif len(r) == 4:
218 for i in range(r[1], r[2]+1):
219 # eg swp[2-4].100, r = ("swp", 2, 4, ".100")
220 self.auto_ifaces.append('%s%d%s' %(r[0], i, r[3]))
679e6567 221 self.auto_ifaces.append(a)
a6f80f0e 222 return 0
223
14dc390d 224 def _add_to_iface_config(self, ifacename, iface_config, attrname,
225 attrval, lineno):
7a51240e 226 newattrname = attrname.replace("_", "-")
7949b8a5 227 try:
9e012f9e
RP
228 if not self.callbacks.get('validateifaceattr')(newattrname,
229 attrval):
7949b8a5 230 self._parse_error(self._currentfile, lineno,
14dc390d 231 'iface %s: unsupported keyword (%s)'
232 %(ifacename, attrname))
7949b8a5 233 return
3218f49d 234 except Exception:
7949b8a5 235 pass
7a51240e 236 attrvallist = iface_config.get(newattrname, [])
3fd6c201 237 if newattrname in ['scope', 'netmask', 'broadcast', 'preferred-lifetime']:
be0b20f2 238 # For attributes that are related and that can have multiple
239 # entries, store them at the same index as their parent attribute.
240 # The example of such attributes is 'address' and its related
d486dd0d 241 # attributes. since the related attributes can be optional,
be0b20f2 242 # we add null string '' in places where they are optional.
243 # XXX: this introduces awareness of attribute names in
244 # this class which is a violation.
245
246 # get the index corresponding to the 'address'
247 addrlist = iface_config.get('address')
248 if addrlist:
249 # find the index of last address element
250 for i in range(0, len(addrlist) - len(attrvallist) -1):
251 attrvallist.append('')
252 attrvallist.append(attrval)
7a51240e 253 iface_config[newattrname] = attrvallist
be0b20f2 254 elif not attrvallist:
7a51240e 255 iface_config[newattrname] = [attrval]
be0b20f2 256 else:
7a51240e 257 iface_config[newattrname].append(attrval)
a6f80f0e 258
679e6567 259 def parse_iface(self, lines, cur_idx, lineno, ifaceobj):
a6f80f0e 260 lines_consumed = 0
579b3f25 261 line_idx = cur_idx
a6f80f0e 262
c0071225 263 iface_line = lines[cur_idx].strip(whitespaces)
f102ef63 264 iface_attrs = re.split(self._ws_split_regex, iface_line)
739f665b 265 ifacename = iface_attrs[1]
a6f80f0e 266
eba4da6e
RP
267 if (not utils.is_ifname_range(ifacename) and
268 utils.check_ifname_size_invalid(ifacename)):
9432c671
RP
269 self._parse_warn(self._currentfile, lineno,
270 '%s: interface name too long' %ifacename)
271
ef892ccc
RP
272 # in cases where mako is unable to render the template
273 # or incorrectly renders it due to user template
274 # errors, we maybe left with interface names with
275 # mako variables in them. There is no easy way to
276 # recognize and warn about these. In the below check
277 # we try to warn the user of such cases by looking for
278 # variable patterns ('$') in interface names.
279 if '$' in ifacename:
280 self._parse_warn(self._currentfile, lineno,
281 '%s: unexpected characters in interface name' %ifacename)
282
223ba5af
JF
283 if self.raw:
284 ifaceobj.raw_config.append(iface_line)
a6f80f0e 285 iface_config = collections.OrderedDict()
286 for line_idx in range(cur_idx + 1, len(lines)):
c0071225 287 l = lines[line_idx].strip(whitespaces)
a6f80f0e 288 if self.ignore_line(l) == 1:
223ba5af
JF
289 if self.raw:
290 ifaceobj.raw_config.append(l)
a6f80f0e 291 continue
f102ef63
RP
292 attrs = re.split(self._ws_split_regex, l, 1)
293 if self._is_keyword(attrs[0]):
a6f80f0e 294 line_idx -= 1
295 break
f102ef63 296 # if not a keyword, every line must have at least a key and value
eab25b7c 297 if len(attrs) < 2:
9dce3561 298 self._parse_error(self._currentfile, line_idx,
14dc390d 299 'iface %s: invalid syntax \'%s\'' %(ifacename, l))
eab25b7c 300 continue
223ba5af
JF
301 if self.raw:
302 ifaceobj.raw_config.append(l)
d08d5f54 303 attrname = attrs[0]
f102ef63
RP
304 # preprocess vars (XXX: only preprocesses $IFACE for now)
305 attrval = re.sub(r'\$IFACE', ifacename, attrs[1])
14dc390d 306 self._add_to_iface_config(ifacename, iface_config, attrname,
307 attrval, line_idx+1)
a6f80f0e 308 lines_consumed = line_idx - cur_idx
309
310 # Create iface object
37c0543d 311 if ifacename.find(':') != -1:
62ddec8b 312 ifaceobj.name = ifacename.split(':')[0]
37c0543d 313 else:
62ddec8b 314 ifaceobj.name = ifacename
37c0543d 315
62ddec8b 316 ifaceobj.config = iface_config
a6f80f0e 317 ifaceobj.generate_env()
d913472d 318
319 try:
004d1e65
JF
320 if iface_attrs[2]:
321 ifaceobj.addr_family.append(iface_attrs[2])
62ddec8b 322 ifaceobj.addr_method = iface_attrs[3]
d913472d 323 except IndexError:
324 # ignore
325 pass
326 self._validate_addr_family(ifaceobj, lineno)
a6f80f0e 327
679e6567 328 if self.auto_all or (ifaceobj.name in self.auto_ifaces):
62ddec8b 329 ifaceobj.auto = True
a6f80f0e 330
62ddec8b 331 classes = self.get_allow_classes_for_iface(ifaceobj.name)
fe0a57d3 332 if classes:
62ddec8b 333 [ifaceobj.set_class(c) for c in classes]
d486dd0d 334
a6f80f0e 335 return lines_consumed # Return next index
336
eba4da6e
RP
337 def _create_ifaceobj_clone(self, ifaceobj, newifaceobjname,
338 newifaceobjtype, newifaceobjflags):
339 ifaceobj_new = copy.deepcopy(ifaceobj)
340 ifaceobj_new.realname = '%s' %ifaceobj.name
341 ifaceobj_new.name = newifaceobjname
342 ifaceobj_new.type = newifaceobjtype
343 ifaceobj_new.flags = newifaceobjflags
344
345 return ifaceobj_new
346
679e6567
RP
347 def process_iface(self, lines, cur_idx, lineno):
348 ifaceobj = iface()
349 lines_consumed = self.parse_iface(lines, cur_idx, lineno, ifaceobj)
350
351 range_val = utils.parse_iface_range(ifaceobj.name)
352 if range_val:
eba4da6e
RP
353 if len(range_val) == 3:
354 for v in range(range_val[1], range_val[2]+1):
355 ifacename = '%s%d' %(range_val[0], v)
356 if utils.check_ifname_size_invalid(ifacename):
357 self._parse_warn(self._currentfile, lineno,
358 '%s: interface name too long' %ifacename)
359 flags = iface.IFACERANGE_ENTRY
360 if v == range_val[1]:
361 flags |= iface.IFACERANGE_START
362 ifaceobj_new = self._create_ifaceobj_clone(ifaceobj,
363 ifacename, ifaceobj.type, flags)
364 self.callbacks.get('iface_found')(ifaceobj_new)
365 elif len(range_val) == 4:
366 for v in range(range_val[1], range_val[2]+1):
367 ifacename = '%s%d%s' %(range_val[0], v, range_val[3])
368 if utils.check_ifname_size_invalid(ifacename):
369 self._parse_warn(self._currentfile, lineno,
370 '%s: interface name too long' %ifacename)
371 flags = iface.IFACERANGE_ENTRY
372 if v == range_val[1]:
373 flags |= iface.IFACERANGE_START
374 ifaceobj_new = self._create_ifaceobj_clone(ifaceobj,
375 ifacename, ifaceobj.type, flags)
376 self.callbacks.get('iface_found')(ifaceobj_new)
679e6567
RP
377 else:
378 self.callbacks.get('iface_found')(ifaceobj)
379
380 return lines_consumed # Return next index
a6f80f0e 381
84ca006f
RP
382 def process_vlan(self, lines, cur_idx, lineno):
383 ifaceobj = iface()
384 lines_consumed = self.parse_iface(lines, cur_idx, lineno, ifaceobj)
385
386 range_val = utils.parse_iface_range(ifaceobj.name)
387 if range_val:
eba4da6e
RP
388 if len(range_val) == 3:
389 for v in range(range_val[1], range_val[2]+1):
390 flags = iface.IFACERANGE_ENTRY
391 if v == range_val[1]:
392 flags |= iface.IFACERANGE_START
393 ifaceobj_new = self._create_ifaceobj_clone(ifaceobj,
394 '%s%d' %(range_val[0], v),
395 ifaceType.BRIDGE_VLAN, flags)
396 self.callbacks.get('iface_found')(ifaceobj_new)
397 elif len(range_val) == 4:
398 for v in range(range_val[1], range_val[2]+1):
399 flags = iface.IFACERANGE_ENTRY
400 if v == range_val[1]:
401 flags |= iface.IFACERANGE_START
402 ifaceobj_new = self._create_ifaceobj_clone(ifaceobj,
403 '%s%d%s' %(range_val[0], v, range_val[3]),
404 ifaceType.BRIDGE_VLAN,
405 flags)
406 self.callbacks.get('iface_found')(ifaceobj_new)
84ca006f
RP
407 else:
408 ifaceobj.type = ifaceType.BRIDGE_VLAN
409 self.callbacks.get('iface_found')(ifaceobj)
410
411 return lines_consumed # Return next index
412
0845cc57
PKS
413 network_elems = {
414 'source': process_source,
415 'source-directory': process_source_directory,
416 'allow': process_allow,
417 'auto': process_auto,
418 'iface': process_iface,
419 'vlan': process_vlan
420 }
a6f80f0e 421
9dce3561 422 def _is_keyword(self, str):
a6f80f0e 423 # The additional split here is for allow- keyword
3b01ed76 424 if (str in list(self.network_elems.keys()) or
3d58f6af 425 str.split('-')[0] == 'allow'):
a6f80f0e 426 return 1
a6f80f0e 427 return 0
428
0845cc57
PKS
429 def _get_keyword_func(self, str_):
430 tmp_str = str_.split('-')[0]
431 if tmp_str == "allow":
432 return self.network_elems.get(tmp_str)
433 else:
434 return self.network_elems.get(str_)
a6f80f0e 435
436 def get_allow_classes_for_iface(self, ifacename):
437 classes = []
3b01ed76 438 for class_name, ifacenames in list(self.allow_classes.items()):
a6f80f0e 439 if ifacename in ifacenames:
440 classes.append(class_name)
a6f80f0e 441 return classes
442
3dcc1d0e 443 def process_interfaces(self, filedata):
5b65654f
RP
444
445 # process line continuations
446 filedata = ' '.join(d.strip() for d in filedata.split('\\'))
447
a6f80f0e 448 line_idx = 0
449 lines_consumed = 0
62ddec8b 450 raw_config = filedata.split('\n')
c0071225 451 lines = [l.strip(whitespaces) for l in raw_config]
579b3f25 452 while (line_idx < len(lines)):
579b3f25 453 if self.ignore_line(lines[line_idx]):
454 line_idx += 1
455 continue
f102ef63 456 words = re.split(self._ws_split_regex, lines[line_idx])
c0071225
RP
457 if not words:
458 line_idx += 1
459 continue
579b3f25 460 # Check if first element is a supported keyword
9dce3561 461 if self._is_keyword(words[0]):
462 keyword_func = self._get_keyword_func(words[0])
d913472d 463 lines_consumed = keyword_func(self, lines, line_idx, line_idx+1)
579b3f25 464 line_idx += lines_consumed
465 else:
9dce3561 466 self._parse_error(self._currentfile, line_idx + 1,
467 'error processing line \'%s\'' %lines[line_idx])
579b3f25 468 line_idx += 1
579b3f25 469 return 0
a6f80f0e 470
3dcc1d0e 471 def read_filedata(self, filedata):
d40e96ee 472 self._currentfile_has_template = False
579b3f25 473 # run through template engine
e272efd9
JF
474 if filedata and '%' in filedata:
475 try:
800417ae
JF
476 if not self._template_engine:
477 self._template_engine = templateEngine(
1f5db4a8
MG
478 template_engine=self._template_engine_name,
479 template_enable=self._template_enable,
480 template_lookuppath=self._template_engine_path)
e272efd9
JF
481 rendered_filedata = self._template_engine.render(filedata)
482 if rendered_filedata is filedata:
483 self._currentfile_has_template = False
484 else:
485 self._currentfile_has_template = True
3b01ed76 486 except Exception as e:
e272efd9
JF
487 self._parse_error(self._currentfile, -1,
488 'failed to render template (%s). Continue without template rendering ...'
489 % str(e))
490 rendered_filedata = None
491 if rendered_filedata:
c44a7a36
JF
492
493 if isinstance(rendered_filedata, bytes):
494 # some template engine might return bytes but we want str
495 rendered_filedata = rendered_filedata.decode()
496
e272efd9
JF
497 self.process_interfaces(rendered_filedata)
498 return
499 self.process_interfaces(filedata)
3dcc1d0e 500
501 def read_file(self, filename, fileiobuf=None):
502 if fileiobuf:
503 self.read_filedata(fileiobuf)
504 return
505 self._filestack.append(filename)
506 self.logger.info('processing interfaces file %s' %filename)
38510743 507 try:
a193d8d1
JF
508 with open(filename) as f:
509 filedata = f.read()
3b01ed76 510 except Exception as e:
c46af1c9 511 self.logger.warning('error processing file %s (%s)',
38510743
RP
512 filename, str(e))
513 return
3dcc1d0e 514 self.read_filedata(filedata)
9dce3561 515 self._filestack.pop()
a6f80f0e 516
3dcc1d0e 517 def read_file_json(self, filename, fileiobuf=None):
518 if fileiobuf:
519 ifacedicts = json.loads(fileiobuf, encoding="utf-8")
520 #object_hook=ifaceJsonDecoder.json_object_hook)
521 elif filename:
522 self.logger.info('processing interfaces file %s' %filename)
a193d8d1
JF
523 with open(filename) as fp:
524 ifacedicts = json.load(fp)
3dcc1d0e 525 #object_hook=ifaceJsonDecoder.json_object_hook)
b6c1f551
ST
526
527 # we need to handle both lists and non lists formats (e.g. {{}})
528 if not isinstance(ifacedicts,list):
529 ifacedicts = [ifacedicts]
530
cfa06db6 531 errors = 0
3dcc1d0e 532 for ifacedict in ifacedicts:
533 ifaceobj = ifaceJsonDecoder.json_to_ifaceobj(ifacedict)
534 if ifaceobj:
535 self._validate_addr_family(ifaceobj)
cfa06db6
RP
536 if not self.callbacks.get('validateifaceobj')(ifaceobj):
537 errors += 1
3dcc1d0e 538 self.callbacks.get('iface_found')(ifaceobj)
cfa06db6 539 self.errors += errors
d486dd0d 540
3dcc1d0e 541 def load(self):
2c0ad8b3
RP
542 """ This member function loads the networkinterfaces file.
543
544 Assumes networkinterfaces parser object is initialized with the
545 parser arguments
546 """
c28fc55e 547 if not self.interfacesfile and not self.interfacesfileiobuf:
c46af1c9
JF
548 self.logger.warning('no terminal line stdin used or ')
549 self.logger.warning('no network interfaces file defined.')
cfa06db6 550 self.warns += 1
1e6d7bd7
ST
551 return
552
3dcc1d0e 553 if self.interfacesfileformat == 'json':
554 return self.read_file_json(self.interfacesfile,
555 self.interfacesfileiobuf)
556 return self.read_file(self.interfacesfile,
557 self.interfacesfileiobuf)