]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/ifupdown/ifupdownmain.py
Support value-in-range with <number> keyword
[mirror_ifupdown2.git] / ifupdown2 / ifupdown / ifupdownmain.py
1 #!/usr/bin/env python3
2 #
3 # Copyright 2014-2017 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 #
6 # ifupdownMain --
7 # ifupdown main module
8 #
9
10 import re
11 import os
12 import logging
13 import itertools
14 import traceback
15 import pprint
16
17 from collections import OrderedDict
18
19 try:
20 import ifupdown2.lib.nlcache as nlcache
21
22 import ifupdown2.ifupdownaddons.mstpctlutil
23
24 import ifupdown2.nlmanager.ipnetwork as ipnetwork
25
26 import ifupdown2.ifupdown.policymanager
27 import ifupdown2.ifupdown.statemanager as statemanager
28 import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
29 import ifupdown2.ifupdown.ifupdownconfig as ifupdownConfig
30
31 from ifupdown2.ifupdown.graph import *
32 from ifupdown2.ifupdown.iface import *
33 from ifupdown2.ifupdown.scheduler import *
34 from ifupdown2.ifupdown.exceptions import *
35 from ifupdown2.ifupdown.networkinterfaces import *
36 from ifupdown2.ifupdown.config import ADDON_MODULES_DIR, ADDONS_CONF_PATH, IFUPDOWN2_ADDON_DROPIN_FOLDER
37 except (ImportError, ModuleNotFoundError):
38 import lib.nlcache as nlcache
39
40 import ifupdownaddons.mstpctlutil
41
42 import nlmanager.ipnetwork as ipnetwork
43
44 import ifupdown.ifupdownflags
45 import ifupdown.policymanager
46 import ifupdown.statemanager as statemanager
47 import ifupdown.ifupdownflags as ifupdownflags
48 import ifupdown.ifupdownconfig as ifupdownConfig
49
50 from ifupdown.graph import *
51 from ifupdown.iface import *
52 from ifupdown.scheduler import *
53 from ifupdown.exceptions import *
54 from ifupdown.networkinterfaces import *
55 from ifupdown.config import ADDON_MODULES_DIR, ADDONS_CONF_PATH, IFUPDOWN2_ADDON_DROPIN_FOLDER
56
57
58 """
59 .. module:: ifupdownmain
60 :synopsis: main module for ifupdown package
61
62 .. moduleauthor:: Roopa Prabhu <roopa@cumulusnetworks.com>
63
64 """
65
66 _tickmark = '\u2713'
67 _crossmark = '\u2717'
68 _success_sym = '(%s)' %_tickmark
69 _error_sym = '(%s)' %_crossmark
70
71 class ifupdownMainFlags():
72 COMPAT_EXEC_SCRIPTS = False
73 STATEMANAGER_ENABLE = True
74 STATEMANAGER_UPDATE = True
75 ADDONS_ENABLE = False
76 DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
77 SCHED_SKIP_CHECK_UPPERIFACES = False
78 CHECK_SHARED_DEPENDENTS = True
79
80 class ifacePrivFlags():
81 # priv flags to mark iface objects
82 BUILTIN = False
83 NOCONFIG = False
84
85 def __init__(self, builtin=False, noconfig=False):
86 self.BUILTIN = builtin
87 self.NOCONFIG = noconfig
88
89 class ifupdownMain:
90 """ ifupdown2 main class """
91
92 scripts_dir = '/etc/network'
93 addon_modules_dir = ADDON_MODULES_DIR
94 addon_modules_configfile = ADDONS_CONF_PATH
95
96 # Handlers for ops that ifupdown2 owns
97 def run_up(self, ifaceobj):
98 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs).
99 # there is no real interface behind it
100 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
101 return
102 if ((ifaceobj.link_kind & ifaceLinkKind.VRF) or
103 (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE)):
104 self._keep_link_down(ifaceobj)
105 return
106 if self._delay_admin_state:
107 self._delay_admin_state_iface_queue.append(ifaceobj.name)
108 return
109 # If this object is a link slave, ie its link is controlled
110 # by its link master interface, then dont set the link state.
111 # But do allow user to change state of the link if the interface
112 # is already with its link master (hence the master check).
113 if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
114 return
115 if not self.link_exists(ifaceobj.name):
116 return
117 if self._keep_link_down(ifaceobj):
118 return
119 try:
120 self.netlink.link_up(ifaceobj.name)
121 except Exception:
122 if ifaceobj.addr_method == 'manual':
123 pass
124 else:
125 raise
126
127 def _keep_link_down(self, ifaceobj):
128 if ifaceobj.link_privflags & ifaceLinkPrivFlags.KEEP_LINK_DOWN:
129 # user has asked to explicitly keep the link down,
130 # so, force link down
131 self.logger.info('%s: keeping link down due to user config' %ifaceobj.name)
132 self.netlink.link_down(ifaceobj.name)
133 return True
134 return False
135
136 def run_down(self, ifaceobj):
137 if ((ifaceobj.link_kind & ifaceLinkKind.VRF) or
138 (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE)):
139 return
140 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs)
141 # there is no real interface behind it
142 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
143 return
144 if self._delay_admin_state:
145 self._delay_admin_state_iface_queue.append(ifaceobj.name)
146 return
147 # If this object is a link slave, ie its link is controlled
148 # by its link master interface, then dont set the link state.
149 # But do allow user to change state of the link if the interface
150 # is already with its link master (hence the master check).
151 if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
152 return
153 if not self.link_exists(ifaceobj.name):
154 return
155 try:
156 if not ifaceobj.link_privflags & ifaceLinkPrivFlags.LOOPBACK:
157 # set intf down (except loopback)
158 self.netlink.link_down(ifaceobj.name)
159 else:
160 self.logger.info("%s: ifupdown2 cannot bring loopback interface down" % ifaceobj.name)
161 except Exception:
162 if ifaceobj.addr_method == 'manual':
163 pass
164 else:
165 raise
166
167 # ifupdown object interface operation handlers
168 ops_handlers = OrderedDict([('up', run_up),
169 ('down', run_down)])
170
171 def run_sched_ifaceobj_posthook(self, ifaceobj, op):
172 if (ifaceobj.priv_flags and (ifaceobj.priv_flags.BUILTIN or
173 ifaceobj.priv_flags.NOCONFIG)):
174 return
175 if self.flags.STATEMANAGER_UPDATE:
176 self.statemanager.ifaceobj_sync(ifaceobj, op)
177
178 # ifupdown object interface scheduler pre and posthooks
179 sched_hooks = {'posthook' : run_sched_ifaceobj_posthook}
180
181 def reset_ifupdown2(self):
182 self.modules = OrderedDict({})
183 self.module_attrs = {}
184
185 ifaceScheduler.reset()
186 try:
187 ifupdown2.ifupdown.statemanager.reset()
188 ifupdown2.ifupdown.policymanager.reset()
189 ifupdown2.ifupdown.ifupdownflags.reset()
190 ifupdownConfig.reset()
191 ifupdown2.ifupdownaddons.mstpctlutil.mstpctlutil.reset()
192 except Exception:
193 try:
194 ifupdown.statemanager.reset()
195 ifupdown.policymanager.reset()
196 ifupdown.ifupdownflags.reset()
197 ifupdownConfig.reset()
198 ifupdownaddons.mstpctlutil.mstpctlutil.reset()
199 except Exception:
200 pass
201
202 def ignore_error(self, errmsg):
203 if (ifupdownflags.flags.FORCE == True or re.search(r'exists', errmsg,
204 re.IGNORECASE | re.MULTILINE) is not None):
205 return True
206 return False
207
208 def log_warn(self, str):
209 if self.ignore_error(str) == False:
210 if self.logger.getEffectiveLevel() == logging.DEBUG:
211 traceback.print_stack()
212 traceback.print_exc()
213 self.logger.warning(str)
214 pass
215
216 def log_error(self, str):
217 if self.ignore_error(str) == False:
218 raise Exception(str)
219 else:
220 pass
221
222 def link_exists(self, ifacename):
223 return os.path.exists('/sys/class/net/%s' %ifacename)
224
225 def __init__(self, config={}, args=None,
226 daemon=False, force=False, dryrun=False, nowait=False,
227 perfmode=False, withdepends=False, njobs=1,
228 cache=False, addons_enable=True, statemanager_enable=True,
229 interfacesfile='/etc/network/interfaces',
230 interfacesfileiobuf=None,
231 interfacesfileformat='native',
232 withdefaults=False):
233 """This member function initializes the ifupdownmain object.
234
235 Kwargs:
236 config (dict): config dict from /etc/network/ifupdown2/ifupdown2.conf
237 force (bool): force interface configuration
238 dryrun (bool): dryrun interface configuration
239 withdepends (bool): apply interface configuration on all depends
240 interfacesfile (str): interfaces file. default is /etc/network/interfaces
241 interfacesfileformat (str): default is 'native'. Other choices are 'json'
242
243 Raises:
244 AttributeError, KeyError """
245
246 modulename = self.__class__.__name__
247 self.logger = logging.getLogger('ifupdown.' + modulename)
248
249 if daemon:
250 self.reset_ifupdown2()
251 else:
252 # init nlcache with appropriate log level
253 nlcache.NetlinkListenerWithCache.init(logging.DEBUG if args.nldebug else logging.WARNING)
254
255 # start netlink listener and cache link/addr/netconf dumps
256 nlcache.NetlinkListenerWithCache.get_instance().start()
257
258 # save reference to nlcache
259 self.netlink = nlcache.NetlinkListenerWithCache.get_instance()
260 self.netlink.reset_errorq()
261
262 # iface dictionary in the below format:
263 # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
264 # eg:
265 # { 'swp1' : [<iface swp1>, <iface swp2> ..] }
266 #
267 # Each ifaceobject corresponds to a configuration block for
268 # that interface
269 # The value in the dictionary is a list because the network
270 # interface configuration file supports more than one iface section
271 # in the interfaces file
272 self.ifaceobjdict = OrderedDict()
273
274 # iface dictionary representing the curr running state of an iface
275 # in the below format:
276 # {'<ifacename>' : <ifaceobject>}
277 self.ifaceobjcurrdict = OrderedDict()
278
279 # Dictionary representing operation and modules
280 # for every operation
281 self.module_ops = OrderedDict([('pre-up', []),
282 ('up', []),
283 ('post-up', []),
284 ('query-checkcurr', []),
285 ('query-running', []),
286 ('query-dependency', []),
287 ('query', []),
288 ('query-raw', []),
289 ('pre-down', []),
290 ('down', []),
291 ('post-down', [])])
292
293 # For old style /etc/network/ bash scripts
294 self.script_ops = OrderedDict([('pre-up', []),
295 ('up', []),
296 ('post-up', []),
297 ('pre-down', []),
298 ('down', []),
299 ('post-down', [])])
300
301
302 self.logger = logging.getLogger('ifupdown')
303 ifupdownflags.flags.FORCE = force
304 ifupdownflags.flags.DRYRUN = dryrun
305 ifupdownflags.flags.WITHDEFAULTS = withdefaults
306 ifupdownflags.flags.NOWAIT = nowait
307 ifupdownflags.flags.PERFMODE = perfmode
308 ifupdownflags.flags.CACHE = cache
309 ifupdownflags.flags.WITH_DEPENDS = withdepends
310
311 # Can be used to provide hints for caching
312 ifupdownflags.flags.CACHE_FLAGS = 0x0
313
314 self.flags = ifupdownMainFlags()
315
316 self.flags.STATEMANAGER_ENABLE = statemanager_enable
317 self.interfacesfile = interfacesfile
318 self.interfacesfileiobuf = interfacesfileiobuf
319 self.interfacesfileformat = interfacesfileformat
320 self.config = config
321 self.logger.debug(self.config)
322 self.blacklisted_ifaces_present = False
323
324 self.type = ifaceType.UNKNOWN
325
326 self.flags.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
327 self.flags.ADDONS_ENABLE = addons_enable
328
329 self.ifaces = OrderedDict()
330 self.njobs = njobs
331 self.pp = pprint.PrettyPrinter(indent=4)
332 self.modules = OrderedDict({})
333 self.module_attrs = {}
334 self.overridden_ifupdown_scripts = []
335
336 if self.config.get('addon_python_modules_support', '1') == '1':
337 self.load_addon_modules(self.addon_modules_dir)
338 if self.config.get('addon_scripts_support', '0') == '1':
339 self.load_scripts(self.scripts_dir)
340 self.dependency_graph = OrderedDict({})
341
342 self._cache_no_repeats = {}
343
344 # initialize global config object with config passed by the user
345 # This makes config available to addon modules
346 ifupdownConfig.config = self.config
347 statemanager.statemanager_api.init()
348
349 if self.flags.STATEMANAGER_ENABLE:
350 self.statemanager = statemanager.statemanager_api
351 try:
352 self.statemanager.read_saved_state()
353 except Exception as e:
354 # if read_saved_state fails, state file might be corrupt.
355 # Ignore old state and continue
356 self.logger.warning('error reading state (%s)' %str(e))
357 import traceback
358 traceback.print_exc()
359 else:
360 self.flags.STATEMANAGER_UPDATE = False
361 self._delay_admin_state = True if self.config.get(
362 'delay_admin_state_change', '0') == '1' else False
363 self._delay_admin_state_iface_queue = []
364 if self._delay_admin_state:
365 self.logger.info('\'delay_admin_state_change\' is set. admin ' +
366 'state changes will be delayed till the end.')
367
368 self._link_master_slave = True if self.config.get(
369 'link_master_slave', '0') == '1' else False
370 if self._link_master_slave:
371 self.logger.info('\'link_master_slave\' is set. slave admin ' +
372 'state changes will be delayed till the ' +
373 'masters admin state change.')
374
375 # squash iface objects for same interface both internal and
376 # external representation. It is off by default.
377 self._ifaceobj_squash = True if self.config.get(
378 'ifaceobj_squash', '0') == '1' else False
379
380 # squash iface objects for same interface internal
381 # representation only. External representation as seen by ifquery
382 # will continue to see multiple iface stanzas if it was specified
383 # that way by the user. It is on by default.
384 self._ifaceobj_squash_internal = True if self.config.get(
385 'ifaceobj_squash_internal', '1') == '1' else False
386
387 self.mgmt_iface_default_prefix = self._get_mgmt_iface_default_prefix()
388 self.logger.info('using mgmt iface default prefix %s' %self.mgmt_iface_default_prefix)
389
390 self.validate_keywords = {
391 '<mac>': self._keyword_mac,
392 '<text>': self._keyword_text,
393 '<ipv4>': self._keyword_ipv4,
394 '<ipv6>': self._keyword_ipv6,
395 '<ip>': self._keyword_ip,
396 '<number>': self._keyword_number,
397 '<interface>': self._keyword_interface,
398 '<ipv4-vrf-text>': self._keyword_ipv4_vrf_text,
399 '<number-ipv4-list>': self._keyword_number_ipv4_list,
400 '<interface-list>': self._keyword_interface_list,
401 '<ipv4/prefixlen>': self._keyword_ipv4_prefixlen,
402 '<ipv6/prefixlen>': self._keyword_ipv6_prefixlen,
403 '<ip/prefixlen>': self._keyword_ip_prefixlen,
404 '<number-range-list>': self._keyword_number_range_list,
405 '<number-comma-range-list>': self._keyword_number_comma_range_list,
406 '<interface-range-list>': self._keyword_interface_range_list,
407 '<interface-range-list-multiple-of-16>': self._keyword_interface_range_list_multiple_of_16,
408 '<mac-ip/prefixlen-list>': self._keyword_mac_ip_prefixlen_list,
409 '<number-interface-list>': self._keyword_number_interface_list,
410 '<interface-yes-no-list>': self._keyword_interface_yes_no_list,
411 '<interface-on-off-list>': self._keyword_interface_on_off_list,
412 '<interface-yes-no-0-1-list>': self._keyword_interface_yes_no_0_1_list,
413 '<interface-disabled-automatic-enabled>': self._keyword_interface_disabled_automatic_enabled_list,
414 '<interface-yes-no-auto-list>': self._keyword_interface_yes_no_auto_list,
415 '<interface-l2protocol-tunnel-list>': self._keyword_interface_l2protocol_tunnel_list
416 }
417
418 def _get_mgmt_iface_default_prefix(self):
419 mgmt_iface_default_prefix = None
420 try:
421 mgmt_iface_default_prefix = ifupdown2.ifupdown.policymanager.policymanager_api.get_module_globals(
422 module_name='main', attr='mgmt_intf_prefix'
423 )
424 except Exception:
425 try:
426 mgmt_iface_default_prefix = ifupdown.policymanager.policymanager_api.get_module_globals(
427 module_name='main', attr='mgmt_intf_prefix'
428 )
429 except Exception:
430 pass
431 if not mgmt_iface_default_prefix:
432 mgmt_iface_default_prefix = "eth"
433
434 return mgmt_iface_default_prefix
435
436 def link_master_slave_ignore_error(self, errorstr):
437 # If link master slave flag is set,
438 # there may be cases where the lowerdev may not be
439 # up resulting in 'Network is down' error
440 # This can happen if the lowerdev is a LINK_SLAVE
441 # of another interface which is not up yet
442 # example of such a case:
443 # bringing up a vlan on a bond interface and the bond
444 # is a LINK_SLAVE of a bridge (in other words the bond is
445 # part of a bridge) which is not up yet
446 if self._link_master_slave:
447 if 'Network is down' in errorstr:
448 return True
449 return False
450
451 def get_ifaceobjs(self, ifacename):
452 return self.ifaceobjdict.get(ifacename)
453
454 def get_ifaceobjs_saved(self, ifacename):
455 """ Return ifaceobjects from statemanager """
456 if self.flags.STATEMANAGER_ENABLE:
457 return self.statemanager.get_ifaceobjs(ifacename)
458 else:
459 return None
460
461 def get_ifaceobj_first(self, ifacename):
462 ifaceobjs = self.get_ifaceobjs(ifacename)
463 if ifaceobjs:
464 return ifaceobjs[0]
465 return None
466
467 def get_ifacenames(self):
468 return list(self.ifaceobjdict.keys())
469
470 def get_iface_obj_last(self, ifacename):
471 return self.ifaceobjdict.get(ifacename)[-1]
472
473
474 def must_follow_upperifaces(self, ifacename):
475 #
476 # XXX: This bleeds the knowledge of iface
477 # types in the infrastructure module.
478 # Cant think of a better fix at the moment.
479 # In future maybe the module can set a flag
480 # to indicate if we should follow upperifaces
481 #
482 ifaceobj = self.get_ifaceobj_first(ifacename)
483 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
484 return False
485 return True
486
487 def create_n_save_ifaceobj(self, ifacename, priv_flags=None,
488 increfcnt=False):
489 """ creates a iface object and adds it to the iface dictionary """
490 ifaceobj = iface()
491 ifaceobj.name = ifacename
492 ifaceobj.priv_flags = priv_flags
493 ifaceobj.auto = True
494 if not self._link_master_slave:
495 ifaceobj.link_type = ifaceLinkType.LINK_NA
496 if increfcnt:
497 ifaceobj.inc_refcnt()
498 self.ifaceobjdict[ifacename] = [ifaceobj]
499 return ifaceobj
500
501 def create_n_save_ifaceobjcurr(self, ifaceobj):
502 """ creates a copy of iface object and adds it to the iface
503 dict containing current iface objects
504 """
505 ifaceobjcurr = iface()
506 ifaceobjcurr.name = ifaceobj.name
507 ifaceobjcurr.type = ifaceobj.type
508 ifaceobjcurr.lowerifaces = ifaceobj.lowerifaces
509 ifaceobjcurr.priv_flags = copy.deepcopy(ifaceobj.priv_flags)
510 ifaceobjcurr.auto = ifaceobj.auto
511 self.ifaceobjcurrdict.setdefault(ifaceobj.name,
512 []).append(ifaceobjcurr)
513 return ifaceobjcurr
514
515 def get_ifaceobjcurr(self, ifacename, idx=0):
516 ifaceobjlist = self.ifaceobjcurrdict.get(ifacename)
517 if not ifaceobjlist:
518 return None
519 if not idx:
520 return ifaceobjlist
521 else:
522 return ifaceobjlist[idx]
523
524 def get_iface_refcnt(self, ifacename):
525 """ Return iface ref count """
526 max = 0
527 ifaceobjs = self.get_ifaceobjs(ifacename)
528 if not ifaceobjs:
529 return 0
530 for i in ifaceobjs:
531 if i.refcnt > max:
532 max = i.refcnt
533 return max
534
535 def is_iface_builtin_byname(self, ifacename):
536 """ Returns true if iface name is a builtin interface.
537
538 A builtin interface is an interface which ifupdown understands.
539 The following are currently considered builtin ifaces:
540 - vlan interfaces in the format <ifacename>.<vlanid>
541 """
542 return '.' in ifacename
543
544 def is_ifaceobj_builtin(self, ifaceobj):
545 """ Returns true if iface name is a builtin interface.
546
547 A builtin interface is an interface which ifupdown understands.
548 The following are currently considered builtin ifaces:
549 - vlan interfaces in the format <ifacename>.<vlanid>
550 """
551 if (ifaceobj.priv_flags and ifaceobj.priv_flags.BUILTIN):
552 return True
553 return False
554
555 def is_ifaceobj_noconfig(self, ifaceobj):
556 """ Returns true if iface object did not have a user defined config.
557
558 These interfaces appear only when they are dependents of interfaces
559 which have user defined config
560 """
561 return (ifaceobj.priv_flags and ifaceobj.priv_flags.NOCONFIG)
562
563 def is_iface_noconfig(self, ifacename):
564 """ Returns true if iface has no config """
565
566 ifaceobj = self.get_ifaceobj_first(ifacename)
567 if not ifaceobj: return True
568 return self.is_ifaceobj_noconfig(ifaceobj)
569
570 def check_shared_dependents(self, ifaceobj, dlist):
571 """ ABSOLETE: Check if dlist intersects with any other
572 interface with slave dependents.
573 example: bond and bridges.
574 This function logs such errors """
575 setdlist = set(dlist)
576 for ifacename, ifacedlist in list(self.dependency_graph.items()):
577 if not ifacedlist:
578 continue
579 check_depends = False
580 iobjs = self.get_ifaceobjs(ifacename)
581 if not iobjs:
582 continue
583 for i in iobjs:
584 if (i.dependency_type == ifaceDependencyType.MASTER_SLAVE):
585 check_depends = True
586 if check_depends:
587 common = set(ifacedlist).intersection(setdlist)
588 if common:
589 self.logger.error('misconfig..?. iface %s and %s '
590 %(ifaceobj.name, ifacename) +
591 'seem to share dependents/ports %s' %str(list(common)))
592
593 def _set_iface_role(self, ifaceobj, role, upperifaceobj):
594 if (self.flags.CHECK_SHARED_DEPENDENTS and
595 (ifaceobj.role & ifaceRole.SLAVE) and
596 (role == ifaceRole.SLAVE) and (upperifaceobj.role & ifaceRole.MASTER)):
597 self.logger.error("misconfig..? %s %s is enslaved to multiple interfaces %s"
598 % (ifaceobj.name,
599 ifaceLinkPrivFlags.get_str(ifaceobj.link_privflags), str(ifaceobj.upperifaces)))
600 ifaceobj.set_status(ifaceStatus.ERROR)
601 return
602 ifaceobj.role = role
603
604 def _set_iface_role_n_kind(self, ifaceobj, upperifaceobj):
605 if (upperifaceobj.link_kind & ifaceLinkKind.BOND):
606 self._set_iface_role(ifaceobj, ifaceRole.SLAVE, upperifaceobj)
607 ifaceobj.link_privflags |= ifaceLinkPrivFlags.BOND_SLAVE
608
609 if (upperifaceobj.link_kind & ifaceLinkKind.BRIDGE):
610 self._set_iface_role(ifaceobj, ifaceRole.SLAVE, upperifaceobj)
611 ifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_PORT
612
613 if (ifaceobj.link_kind & ifaceLinkKind.VXLAN) \
614 and (upperifaceobj.link_kind & ifaceLinkKind.BRIDGE):
615 upperifaceobj.link_privflags |= ifaceLinkPrivFlags.BRIDGE_VXLAN
616
617 # vrf masters get processed after slaves, which means
618 # check both link_kind vrf and vrf slave
619 if ((upperifaceobj.link_kind & ifaceLinkKind.VRF) or
620 (ifaceobj.link_privflags & ifaceLinkPrivFlags.VRF_SLAVE)):
621 self._set_iface_role(ifaceobj, ifaceRole.SLAVE, upperifaceobj)
622 ifaceobj.link_privflags |= ifaceLinkPrivFlags.VRF_SLAVE
623 if self._link_master_slave:
624 if upperifaceobj.link_type == ifaceLinkType.LINK_MASTER:
625 ifaceobj.link_type = ifaceLinkType.LINK_SLAVE
626 else:
627 upperifaceobj.link_type = ifaceLinkType.LINK_NA
628 ifaceobj.link_type = ifaceLinkType.LINK_NA
629
630 def dump_iface_dependency_info(self):
631 """ debug funtion to print raw dependency
632 info - lower and upper devices"""
633
634 for ifacename, ifaceobjs in self.ifaceobjdict.items():
635 iobj = ifaceobjs[0]
636 self.logger.info("%s: refcnt: %d, lower: %s, upper: %s" %(ifacename,
637 self.get_iface_refcnt(ifacename),
638 str(iobj.lowerifaces) if iobj.lowerifaces else [],
639 str(iobj.upperifaces) if iobj.upperifaces else []))
640
641
642 def preprocess_dependency_list(self, upperifaceobj, dlist, ops):
643 """ We go through the dependency list and
644 delete or add interfaces from the interfaces dict by
645 applying the following rules:
646 if flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is True:
647 we only consider devices whose configuration was
648 specified in the network interfaces file. We delete
649 any interface whose config was not specified except
650 for vlan devices. vlan devices get special treatment.
651 Even if they are not present they are created and added
652 to the ifacesdict
653 elif flag DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is False:
654 we create objects for all dependent devices that are not
655 present in the ifacesdict
656 """
657 del_list = []
658
659 for d in dlist:
660 dilist = self.get_ifaceobjs(d)
661 if not dilist:
662 ni = None
663 if self.is_iface_builtin_byname(d):
664 ni = self.create_n_save_ifaceobj(d,
665 ifacePrivFlags(True, True), True)
666 elif not self.flags.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG:
667 ni = self.create_n_save_ifaceobj(d,
668 ifacePrivFlags(False, True), True)
669 else:
670 del_list.append(d)
671 if ni:
672 ni.add_to_upperifaces(upperifaceobj.name)
673 self._set_iface_role_n_kind(ni, upperifaceobj)
674 else:
675 for di in dilist:
676 di.inc_refcnt()
677 di.add_to_upperifaces(upperifaceobj.name)
678 self._set_iface_role_n_kind(di, upperifaceobj)
679 for d in del_list:
680 dlist.remove(d)
681
682 def preprocess_upperiface(self, lowerifaceobj, ulist, ops):
683 for u in ulist:
684 if (lowerifaceobj.upperifaces and
685 u in lowerifaceobj.upperifaces):
686 continue
687 lowerifaceobj.add_to_upperifaces(u)
688 uifacelist = self.get_ifaceobjs(u)
689 if uifacelist:
690 for ui in uifacelist:
691 lowerifaceobj.inc_refcnt()
692 self._set_iface_role_n_kind(lowerifaceobj, ui)
693 ui.add_to_lowerifaces(lowerifaceobj.name)
694
695 def query_lowerifaces(self, ifaceobj, ops, ifacenames, type=None):
696 """ Gets iface dependents by calling into respective modules """
697 ret_dlist = []
698
699 # Get dependents for interface by querying respective modules
700 for module in list(self.modules.values()):
701 try:
702 if ops[0] == 'query-running':
703 if (not hasattr(module,
704 'get_dependent_ifacenames_running')):
705 continue
706 dlist = module.get_dependent_ifacenames_running(ifaceobj)
707 else:
708 if (not hasattr(module, 'get_dependent_ifacenames')):
709 continue
710 dlist = module.get_dependent_ifacenames(ifaceobj,
711 ifacenames)
712 except Exception as e:
713 self.logger.warning('%s: error getting dependent interfaces (%s)'
714 %(ifaceobj.name, str(e)))
715 dlist = None
716 pass
717 if dlist: ret_dlist.extend(dlist)
718 return list(set(ret_dlist))
719
720 def query_upperifaces(self, ifaceobj, ops, ifacenames, type=None):
721 """ Gets iface upperifaces by calling into respective modules """
722 ret_ulist = []
723
724 # Get upperifaces for interface by querying respective modules
725 for module in list(self.modules.values()):
726 try:
727 if ops[0] == 'query-running':
728 if (not hasattr(module,
729 'get_upper_ifacenames_running')):
730 continue
731 ulist = module.get_upper_ifacenames_running(ifaceobj)
732 else:
733 if (not hasattr(module, 'get_upper_ifacenames')):
734 continue
735 ulist = module.get_upper_ifacenames(ifaceobj, ifacenames)
736 except Exception as e:
737 self.logger.warning('%s: error getting upper interfaces (%s)'
738 %(ifaceobj.name, str(e)))
739 ulist = None
740 pass
741 if ulist: ret_ulist.extend(ulist)
742 return list(set(ret_ulist))
743
744 def _remove_circular_veth_dependencies(self, ifaceobj, dlist):
745 # if ifaceobj isn't a veth link, ignore it.
746 if ifaceobj.get_attr_value_first('link-type') != "veth":
747 return
748
749 for diface in dlist:
750 difaceobj = self.get_ifaceobj_first(diface)
751 # If the dependent iface isn't a veth link - which shouldn't
752 # happen - ignore it to be save.
753 if not difaceobj or (difaceobj and difaceobj.get_attr_value_first('link-type') != "veth"):
754 continue
755
756 # If the peer has a desired peer name set and this is us,
757 # see if the peer has a dependency to us too and remove our
758 # redundant dependency to the peer.
759 diface_peer_name = difaceobj.get_attr_value_first('veth-peer-name')
760 if diface_peer_name and diface_peer_name == ifaceobj.name:
761 peer_dlist = difaceobj.lowerifaces
762 if not peer_dlist:
763 # Not list of dependent interface on the peer.
764 continue
765
766 # We aleady are in the peers dlist, don't add dependcy from us to peer
767 if ifaceobj.name in peer_dlist:
768 dlist.remove(difaceobj.name)
769
770 def populate_dependency_info(self, ops, ifacenames=None):
771 """ recursive function to generate iface dependency info """
772
773 if not ifacenames:
774 ifacenames = list(self.ifaceobjdict.keys())
775
776 iqueue = deque(ifacenames)
777 while iqueue:
778 i = iqueue.popleft()
779 # Go through all modules and find dependent ifaces
780 dlist = None
781 ulist = None
782 ifaceobjs = self.get_ifaceobjs(i)
783 if not ifaceobjs:
784 continue
785 dependents_processed = False
786
787 # Store all dependency info in the first ifaceobj
788 # but get dependency info from all ifaceobjs
789 ifaceobj = ifaceobjs[0]
790 for iobj in ifaceobjs:
791 ulist = self.query_upperifaces(iobj, ops, ifacenames)
792 if iobj.lowerifaces:
793 dependents_processed = True
794 break
795 dlist = self.query_lowerifaces(iobj, ops, ifacenames)
796 if dlist:
797 break
798 if ulist:
799 self.preprocess_upperiface(ifaceobj, ulist, ops)
800 if dependents_processed:
801 continue
802 if dlist:
803 self._remove_circular_veth_dependencies(ifaceobj, dlist)
804 self.preprocess_dependency_list(ifaceobj,
805 dlist, ops)
806 ifaceobj.lowerifaces = dlist
807 [iqueue.append(d) for d in dlist]
808 #if not self.dependency_graph.get(i):
809 # self.dependency_graph[i] = dlist
810
811 for i in list(self.ifaceobjdict.keys()):
812 iobj = self.get_ifaceobj_first(i)
813 if (not iobj.link_kind and
814 not (iobj.link_privflags & ifaceLinkPrivFlags.LOOPBACK) and
815 iobj.name == 'lo'):
816 iobj.link_privflags |= ifaceLinkPrivFlags.LOOPBACK
817 if iobj.name.startswith(self.mgmt_iface_default_prefix):
818 self.logger.debug('%s: marking interface with mgmt flag' %iobj.name)
819 iobj.link_privflags |= ifaceLinkPrivFlags.MGMT_INTF
820 if iobj.lowerifaces:
821 self.dependency_graph[i] = iobj.lowerifaces
822 else:
823 self.dependency_graph[i] = []
824
825 if not self.blacklisted_ifaces_present:
826 return
827
828 # Walk through the dependency graph and remove blacklisted
829 # interfaces that were picked up as dependents
830 for i in list(self.dependency_graph.keys()):
831 ifaceobj = self.get_ifaceobj_first(i)
832 if not ifaceobj:
833 continue
834
835 if ifaceobj.blacklisted and not ifaceobj.upperifaces:
836 # if blacklisted and was not picked up as a
837 # dependent of a upper interface, delete the
838 # interface from the dependency graph
839 dlist = ifaceobj.lowerifaces
840 if dlist:
841 for d in dlist:
842 difaceobjs = self.get_ifaceobjs(d)
843 if not difaceobjs:
844 continue
845 try:
846 for d in difaceobjs:
847 d.dec_refcnt()
848 d.upperifaces.remove(i)
849 except Exception:
850 self.logger.debug('error removing %s from %s upperifaces' %(i, d))
851 pass
852 self.logger.debug("populate_dependency_info: deleting blacklisted interface %s" %i)
853 del self.dependency_graph[i]
854 continue
855
856 def _check_config_no_repeats(self, ifaceobj):
857 """ check if object has an attribute that is
858 restricted to a single object in the system.
859 if yes, warn and return """
860 for k,v in list(self._cache_no_repeats.items()):
861 iv = ifaceobj.config.get(k)
862 if iv and iv[0] == v:
863 self.logger.error('ignoring interface %s. ' %ifaceobj.name +
864 'Only one object with attribute ' +
865 '\'%s %s\' allowed.' %(k, v))
866 return True
867 for k, v in list(self.config.get('no_repeats', {}).items()):
868 iv = ifaceobj.config.get(k)
869 if iv and iv[0] == v:
870 self._cache_no_repeats[k] = v
871 return False
872
873 def _save_iface_squash(self, ifaceobj):
874 """ squash ifaceobjects belonging to same iface
875 into a single object """
876 if self._check_config_no_repeats(ifaceobj):
877 return
878 ifaceobj.priv_flags = ifacePrivFlags()
879 if not self._link_master_slave:
880 ifaceobj.link_type = ifaceLinkType.LINK_NA
881 currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
882 if not currentifaceobjlist:
883 self.ifaceobjdict[ifaceobj.name] = [ifaceobj]
884 return
885 if ifaceobj.compare(currentifaceobjlist[0]):
886 self.logger.warning('duplicate interface %s found' %ifaceobj.name)
887 return
888 for obj in self.ifaceobjdict[ifaceobj.name]:
889 if obj.type == ifaceobj.type:
890 obj.squash(ifaceobj)
891 return
892 self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
893
894 def _save_iface(self, ifaceobj):
895 if self._check_config_no_repeats(ifaceobj):
896 return
897 ifaceobj.priv_flags = ifacePrivFlags()
898 if not self._link_master_slave:
899 ifaceobj.link_type = ifaceLinkType.LINK_NA
900 currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
901 if not currentifaceobjlist:
902 self.ifaceobjdict[ifaceobj.name]= [ifaceobj]
903 if not self._ifaceobj_squash:
904 ifaceobj.flags |= ifaceobj.YOUNGEST_SIBLING
905 return
906 if ifaceobj.compare(currentifaceobjlist[0]):
907 self.logger.warning('duplicate interface %s found' %ifaceobj.name)
908 return
909 if currentifaceobjlist[0].type == ifaceobj.type:
910 currentifaceobjlist[0].flags |= ifaceobj.HAS_SIBLINGS
911 ifaceobj.flags |= ifaceobj.HAS_SIBLINGS
912 # clear the OLDEST_SIBLING from all the siblings
913 for iface in self.ifaceobjdict[ifaceobj.name]:
914 iface.flags &= ~ifaceobj.OLDEST_SIBLING
915 # current sibling is the oldest
916 ifaceobj.flags |= ifaceobj.OLDEST_SIBLING
917 self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
918
919 def _keyword_text(self, value, validrange=None):
920 return isinstance(value, str) and len(value) > 0
921
922 def _keyword_mac(self, value, validrange=None):
923 if value.strip().startswith('ether'):
924 value = value.strip()[6:]
925 return re.match('[0-9a-f]{1,2}([-:])[0-9a-f]{1,2}(\\1[0-9a-f]{1,2}){4}$',
926 value.lower())
927
928 def _keyword_check_list(self, _list, obj, limit=None):
929 try:
930 if limit and limit > 0:
931 for i in range(0, limit):
932 obj(_list[i])
933 return len(_list) == limit
934 else:
935 for elem in _list:
936 obj(elem)
937 return True
938 except Exception as e:
939 self.logger.debug('keyword: check list: %s' % str(e))
940 return False
941
942 def _keyword_ipv4(self, value, validrange=None):
943 return self._keyword_check_list(value.split(), ipnetwork.IPv4Address, limit=1)
944
945 def _keyword_ipv4_prefixlen(self, value, validrange=None):
946 return self._keyword_check_list(value.split(), ipnetwork.IPv4Network, limit=1)
947
948 def _keyword_ipv6(self, value, validrange=None):
949 return self._keyword_check_list(value.split(), ipnetwork.IPv6Address, limit=1)
950
951 def _keyword_ipv6_prefixlen(self, value, validrange=None):
952 return self._keyword_check_list(value.split(), ipnetwork.IPv6Network, limit=1)
953
954 def _keyword_ip(self, value, validrange=None):
955 return self._keyword_check_list(value.split(), ipnetwork.IPAddress, limit=1)
956
957 def _keyword_ip_prefixlen(self, value, validrange=None):
958 return self._keyword_check_list(value.split(), ipnetwork.IPNetwork, limit=1)
959
960 def _keyword_mac_ip_prefixlen_list(self, value, validrange=None):
961 """
962 MAC address followed by optional list of ip addresses
963 <mac> [<ip> <ip> ...]
964 ex: address-virtual 00:11:22:33:44:01 11.0.1.1/24 11.0.1.2/24
965 """
966 try:
967 res = value.split()
968 if not self._keyword_mac(res[0]):
969 return False
970 for ip in res[1:]:
971 if not self._keyword_ip_prefixlen(ip):
972 return False
973 return True
974 except Exception as e:
975 self.logger.debug('keyword: mac ipaddr prefixlen: %s' % str(e))
976 return False
977
978 def _keyword_number_ipv4_list(self, value, validrange=None):
979 """
980 <number>=<ipv4> [<number>=<ipv4> ...]
981 ex: bridge-mcqv4src 100=172.16.100.1 101=172.16.101.1
982 """
983 try:
984 elements = value.split(' ')
985 if not elements:
986 return False
987 for elem in elements:
988 v = elem.split('=')
989 int(v[0])
990 ipnetwork.IPv4Address(v[1])
991 return True
992 except Exception as e:
993 self.logger.debug('keyword: number ipv4: %s' % str(e))
994 return False
995
996 def _keyword_interface(self, ifacename, validrange=None):
997 return self.get_ifaceobjs(ifacename)
998
999 def _keyword_ipv4_vrf_text(self, value, validrange=None):
1000 """
1001 <ipv4> "vrf" <text>
1002 ex: clagd-backup-ip 10.10.10.42 vrf blue
1003 """
1004 values = value.split()
1005 size = len(values)
1006
1007 if size > 3 or size < 1:
1008 return False
1009 try:
1010 ipnetwork.IPv4Address(values[0])
1011 if size > 1:
1012 if values[1] != 'vrf':
1013 return False
1014 if size > 2:
1015 if not self._keyword_text(values[2]):
1016 return False
1017 return True
1018 except Exception as e:
1019 self.logger.debug('keyword: ipv4 vrf text: %s' % str(e))
1020 return False
1021
1022 def _keyword_interface_list_with_value(self, value, validvals):
1023 values = value.split()
1024 try:
1025 if len(values) == 1:
1026 if values[0] in validvals:
1027 return True
1028 for v in values:
1029 iface_value = v.split('=')
1030 size = len(iface_value)
1031 if size != 2:
1032 if iface_value[0] == 'glob' or iface_value[0] == 'regex':
1033 continue
1034 return False
1035 if not iface_value[1] in validvals:
1036 return False
1037 return True
1038 except Exception as e:
1039 self.logger.debug('keyword: interface list with value: %s' % str(e))
1040 return False
1041
1042 def _keyword_interface_on_off_list(self, value, validrange=None):
1043 """
1044 <yes|no> | ( <interface>=<on|off> [<interface>=<on|off> ...] )
1045 ex: bridge-learning swp1=on swp2=off
1046 """
1047 return self._keyword_interface_list_with_value(value, ['on', 'off'])
1048
1049 def _keyword_interface_yes_no_list(self, value, validrange=None):
1050 """
1051 <yes|no> | ( <interface>=<yes|no> [<interface>=<yes|no> ...] )
1052 ex: mstpctl-portrestrrole swp1=yes swp2=no
1053 """
1054 return self._keyword_interface_list_with_value(value, ['yes', 'no'])
1055
1056 def _keyword_interface_yes_no_auto_list(self, value, validrange=None):
1057 """
1058 <yes|no|auto> |
1059 ( <interface>=<yes|no|auto> [<interface>=<yes|no|auto> ...] )
1060 ex: mstpctl-portp2p swp1=yes swp2=no swp3=auto
1061 """
1062 return self._keyword_interface_list_with_value(value,
1063 ['yes', 'no', 'auto'])
1064
1065 def _keyword_interface_l2protocol_tunnel_list(self, value, validrange=None):
1066 """
1067 bridge-l2protocol-tunnel swpX=lacp,stp swpY=cdp swpZ=all
1068 bridge-l2protocol-tunnel lacp stp,lldp,cdp
1069 bridge-l2protocol-tunnel stp lacp cdp
1070 bridge-l2protocol-tunnel lldp pvst
1071 bridge-l2protocol-tunnel stp
1072 bridge-l2protocol-tunnel all
1073 """
1074 try:
1075 if '=' in value:
1076 for intf_arg in value.split():
1077 intf_arg_split = intf_arg.split('=')
1078 for arg in intf_arg_split[1].replace(",", " ").split():
1079 if arg not in ['all', 'stp', 'lldp', 'lacp', 'cdp', 'pvst']:
1080 return False
1081 else:
1082 for arg in value.replace(",", " ").split():
1083 if arg not in ['all', 'stp', 'lldp', 'lacp', 'cdp', 'pvst']:
1084 return False
1085 except Exception:
1086 return False
1087 return True
1088
1089 def _keyword_interface_yes_no_0_1_list(self, value, validrange=None):
1090 """
1091 <yes|no|0|1> |
1092 ( <interface>=<yes|no|0|1> [<interface>=<yes|no|0|1> ...] )
1093 ex: bridge-portmcrouter swp1=yes swp2=yes swp3=1
1094 """
1095 return self._keyword_interface_list_with_value(value,
1096 ['yes', 'no', '1', '0', '2'])
1097
1098 def _keyword_interface_disabled_automatic_enabled_list(self, value, validrange=None):
1099 return self._keyword_interface_list_with_value(value, [
1100 '0', 'disabled', 'no',
1101 '1', 'automatic', 'yes',
1102 '2', 'enabled'])
1103
1104 def _keyword_interface_range_list_multiple_of_16(self, value, validrange):
1105 return self._keyword_interface_range_list(value, validrange, multiple=16)
1106
1107 def _keyword_interface_range_list(self, value, validrange, multiple=None):
1108 """
1109 <number> | ( <interface>=<number> [ <interface>=number> ...] )
1110 ex: mstpctl-portpathcost swp1=0 swp2=1
1111 """
1112 values = value.split()
1113 try:
1114 if len(values) == 1 and '=' not in values[0]:
1115 try:
1116 n = int(values[0])
1117 if n < int(validrange[0]) or n > int(
1118 validrange[1]):
1119 raise invalidValueError('value of out range "%s":'
1120 ' valid attribute range: %s'
1121 % (values[0],
1122 '-'.join(validrange)))
1123
1124 if multiple is not None:
1125 if not (n % multiple == 0):
1126 raise invalidValueError('invalid value %s: must be a multiple of %s' % (n, multiple))
1127
1128 return True
1129 except invalidValueError as e:
1130 raise e
1131 except Exception as e:
1132 self.logger.debug('keyword: interface range list: %s'
1133 % str(e))
1134 return False
1135 for v in values:
1136 iface_value = v.split('=')
1137 size = len(iface_value)
1138 if size != 2:
1139 return False
1140 number = int(iface_value[1])
1141 if number < int(validrange[0]) or number > int(
1142 validrange[1]):
1143 raise invalidValueError(
1144 'value of out range "%s" for iface "%s":'
1145 ' valid attribute range: %s'
1146 % (iface_value[1],
1147 iface_value[0],
1148 '-'.join(validrange)))
1149
1150 if multiple is not None:
1151 if not (number % multiple == 0):
1152 raise invalidValueError('invalid value %s: must be a multiple of %s' % (number, multiple))
1153
1154 return True
1155 except invalidValueError as e:
1156 raise e
1157 except Exception as e:
1158 self.logger.debug('keyword: interface range list: %s' % str(e))
1159 return False
1160
1161 def _keyword_interface_list(self, value, validrange=None):
1162 """
1163 [glob|regex] <interface> [ [glob|regex] <interface> ...]
1164 ex: bridge-ports swp1 swp2 glob swp3-5.100 regex (swp[6|7|8].100)
1165 """
1166 interface_list = value.split()
1167 size = len(interface_list)
1168 i = 0
1169 while i < size:
1170 if interface_list[i] == 'glob' or interface_list[i] == 'regex':
1171 i += 1
1172 else:
1173 if not self._keyword_interface(interface_list[i]):
1174 return False
1175 i += 1
1176 return True
1177
1178 def _keyword_number_range_list(self, value, validrange=None):
1179 """
1180 <number> [<number>-<number>]
1181 ex: bridge-vids 42 100-200
1182 """
1183 number_list = value.split()
1184 try:
1185 i = 0
1186 while i < len(number_list):
1187 if '-' in number_list[i]:
1188 range = number_list[i].split('-')
1189 a = int(range[0])
1190 b = int(range[1])
1191 if a > b:
1192 return False
1193 else:
1194 int(number_list[i])
1195 i += 1
1196 return True
1197 except Exception as e:
1198 self.logger.debug('keyword: number range list: %s' % str(e))
1199 return False
1200
1201 def _keyword_number_interface_list(self, value, validrange=None):
1202 """
1203 <number> <interface> [<interface>... [<number> <interface> ... ]]
1204 bridge-waitport 42 swp1 swp2 swp3 9 swp4
1205 """
1206 interface_list = value.split()
1207 if not interface_list:
1208 return False
1209 try:
1210 int(interface_list[0])
1211 prev = True
1212 for elem in interface_list[1:]:
1213 try:
1214 int(elem)
1215 if prev:
1216 return False
1217 prev = True
1218 except Exception:
1219 prev = False
1220 return not prev
1221 except Exception as e:
1222 self.logger.debug('keyword: number interface list: %s' % str(e))
1223 return False
1224
1225 def _keyword_number(self, value, validrange=None):
1226 try:
1227 int_value = int(value)
1228 if validrange is not None:
1229 return int(validrange[0]) <= int_value <= int(validrange[1])
1230 return True
1231 except Exception as e:
1232 self.logger.debug('keyword: number: %s' % str(e))
1233 return False
1234
1235 def _is_keyword(self, value):
1236 if isinstance(value, tuple):
1237 return True
1238 keyword_found = value in self.validate_keywords
1239 if value.startswith('<') and value.endswith('>') and not keyword_found:
1240 raise Exception('%s: invalid keyword, please make sure to use'
1241 ' a valid keyword see `ifquery -s`' % value)
1242 return keyword_found
1243
1244 def _check_validvals_value(self, attrname, value, validvals, validrange):
1245 if validvals and value not in validvals:
1246 is_valid = False
1247 for keyword in validvals:
1248 if self._is_keyword(keyword):
1249 if validrange:
1250 if self.validate_keywords[keyword](value, validrange):
1251 return {'result': True}
1252 else:
1253 if self.validate_keywords[keyword](value):
1254 return {'result': True}
1255 if not is_valid:
1256 return {
1257 'result': False,
1258 'message': 'invalid value "%s": valid attribute values: %s'
1259 % (value, validvals)
1260 }
1261 elif validvals and value in validvals:
1262 pass
1263 elif validrange:
1264 if len(validrange) != 2:
1265 raise Exception('%s: invalid range in addon configuration'
1266 % '-'.join(validrange))
1267 _value = int(value)
1268 if _value < int(validrange[0]) or _value > int(validrange[1]):
1269 return {
1270 'result': False,
1271 'message': 'value of out range "%s": '
1272 'valid attribute range: %s'
1273 % (value, '-'.join(validrange))
1274 }
1275 return {'result': True}
1276
1277 def _check_validvals(self, ifacename, module_name, attrs):
1278 ifaceobj = self.get_ifaceobjs(ifacename)
1279 if not ifaceobj:
1280 return
1281 success = True
1282 for attrname, attrvalue in list(ifaceobj[0].config.items()):
1283 try:
1284 attrname_dict = attrs.get(attrname, {})
1285 validvals = attrname_dict.get('validvals', [])
1286 validrange = attrname_dict.get('validrange', [])
1287 for value in attrvalue:
1288 res = self._check_validvals_value(attrname,
1289 value,
1290 validvals,
1291 validrange)
1292 if not res['result']:
1293 self.logger.warning('%s: %s: %s' %
1294 (ifacename, attrname, res['message']))
1295 success = False
1296 except Exception as e:
1297 self.logger.warning('addon \'%s\': %s: %s' % (module_name,
1298 attrname,
1299 str(e)))
1300 success = False
1301 return success
1302
1303 def _module_syntax_check(self, filtered_ifacenames):
1304 result = True
1305 for ifacename in filtered_ifacenames:
1306 for module in list(self.modules.values()):
1307 try:
1308 if hasattr(module, '_modinfo'):
1309 if not self._check_validvals(ifacename,
1310 module.__class__.__name__,
1311 module._modinfo.get('attrs', {})):
1312 result = False
1313 if hasattr(module, 'syntax_check') and callable(module.syntax_check):
1314 if not module.syntax_check(self.get_ifaceobjs(ifacename)[0],
1315 self.get_ifaceobjs):
1316 result = False
1317 except Exception as e:
1318 self.logger.warning('%s: %s' % (ifacename, str(e)))
1319 result = False
1320 return result
1321
1322 def _iface_configattr_syntax_checker(self, attrname, attrval):
1323 for m, mdict in list(self.module_attrs.items()):
1324 if not mdict:
1325 continue
1326 attrsdict = mdict.get('attrs')
1327 try:
1328 a = attrsdict.get(attrname)
1329 if a:
1330 if a.get('deprecated'):
1331 newa = a.get('new-attribute')
1332 if newa:
1333 self.logger.warning('attribute %s is deprecated. use %s instead.' %(attrname, newa))
1334 else:
1335 self.logger.warning('attribute %s is deprecated.'
1336 %attrname)
1337 return True
1338 else:
1339 for key in attrsdict:
1340 if 'aliases' in attrsdict[key]:
1341 if attrname in attrsdict[key]['aliases']:
1342 return True
1343 except AttributeError:
1344 pass
1345 return False
1346
1347 def _ifaceobj_syntax_checker(self, ifaceobj):
1348 ret = True
1349 for attrname, attrvalue in list(ifaceobj.config.items()):
1350 found = False
1351 for k, v in list(self.module_attrs.items()):
1352 if v and v.get('attrs', {}).get(attrname):
1353 found = True
1354 break
1355 if not found:
1356 ret = False
1357 self.logger.warning('%s: unsupported attribute \'%s\'' \
1358 % (ifaceobj.name, attrname))
1359 continue
1360 return ret
1361
1362 def read_iface_config(self, raw=False):
1363 """ Reads default network interface config /etc/network/interfaces. """
1364 ret = True
1365 nifaces = networkInterfaces(self.interfacesfile,
1366 self.interfacesfileiobuf,
1367 self.interfacesfileformat,
1368 template_enable=self.config.get('template_enable', 0),
1369 template_engine=self.config.get('template_engine'),
1370 template_lookuppath=self.config.get('template_lookuppath'),
1371 raw=raw)
1372 if self._ifaceobj_squash or self._ifaceobj_squash_internal:
1373 nifaces.subscribe('iface_found', self._save_iface_squash)
1374 else:
1375 nifaces.subscribe('iface_found', self._save_iface)
1376 if self.config.get('addon_syntax_check', '1') == '1':
1377 nifaces.subscribe('validateifaceattr',
1378 self._iface_configattr_syntax_checker)
1379 nifaces.subscribe('validateifaceobj', self._ifaceobj_syntax_checker)
1380 nifaces.load()
1381 if nifaces.errors or nifaces.warns:
1382 ret = False
1383
1384 self._schedule_addon_translate()
1385 return ret
1386
1387 def read_old_iface_config(self):
1388 """ Reads the saved iface config instead of default iface config.
1389 And saved iface config is already read by the statemanager """
1390 self.ifaceobjdict = copy.deepcopy(self.statemanager.ifaceobjdict)
1391
1392 def _load_addon_modules_config(self):
1393 """ Load addon modules config file """
1394
1395 with open(self.addon_modules_configfile, 'r') as f:
1396 lines = f.readlines()
1397 for l in lines:
1398 try:
1399 litems = l.strip(' \n\t\r').split(',')
1400 if not litems or len(litems) < 2:
1401 continue
1402 operation = litems[0]
1403 mname = litems[1]
1404 self.module_ops[operation].append(mname)
1405 except Exception as e:
1406 self.logger.warning('error reading line \'%s\' %s:' %(l, str(e)))
1407 continue
1408
1409 def load_addon_modules(self, modules_dir_list):
1410 """ load python modules from modules_dir
1411
1412 Default modules_dir is /usr/share/ifupdownmodules
1413
1414 """
1415 failed_import = list()
1416
1417 self.logger.info('loading builtin modules from %s' % str(modules_dir_list))
1418 self._load_addon_modules_config()
1419
1420 for modules_dir in modules_dir_list:
1421 if not modules_dir in sys.path:
1422 sys.path.insert(1, modules_dir)
1423 try:
1424 for op, mlist in list(self.module_ops.items()):
1425 for mname in mlist:
1426 if self.modules.get(mname):
1427 continue
1428 mpath = modules_dir + '/' + mname + '.py'
1429 if os.path.exists(mpath) and mpath not in failed_import:
1430 try:
1431 m = __import__(mname)
1432 mclass = getattr(m, mname)
1433 except Exception as e:
1434 self.logger.warning('cannot load "%s" module: %s' % (mname, str(e)))
1435 failed_import.append(mpath)
1436 continue
1437 try:
1438 minstance = mclass()
1439 script_override = minstance.get_overrides_ifupdown_scripts()
1440 self.overridden_ifupdown_scripts.extend(script_override)
1441 except moduleNotSupported as e:
1442 self.logger.info('module %s not loaded (%s)'
1443 %(mname, str(e)))
1444 continue
1445 except Exception:
1446 raise
1447 self.modules[mname] = minstance
1448 try:
1449 self.module_attrs[mname] = minstance.get_modinfo()
1450 except Exception:
1451 pass
1452 except Exception:
1453 raise
1454
1455 # Assign all modules to query operations
1456 self.module_ops['query-checkcurr'] = list(self.modules.keys())
1457 self.module_ops['query-running'] = list(self.modules.keys())
1458 self.module_ops['query-dependency'] = list(self.modules.keys())
1459 self.module_ops['query'] = list(self.modules.keys())
1460 self.module_ops['query-raw'] = list(self.modules.keys())
1461
1462 def _keyword_number_comma_range_list(self, value, validrange=None):
1463 return self._keyword_number_range_list(value.replace(',', ' '), validrange=validrange)
1464
1465
1466 def _modules_help(self, fmt):
1467 """ Prints addon modules supported syntax """
1468
1469 if fmt == 'json':
1470 modinfos = {}
1471 for key, value in list(self.modules.items()):
1472 if hasattr(value, '_modinfo'):
1473 modinfos[key] = {
1474 'mhelp': value._modinfo['mhelp'],
1475 'attrs': value.merge_modinfo_with_policy_files()
1476 }
1477 print(json.dumps(modinfos))
1478 else:
1479 indent = ' '
1480 for m, mdict in list(self.module_attrs.items()):
1481 if not mdict:
1482 continue
1483 print(('%s: %s' %(m, mdict.get('mhelp'))))
1484 attrdict = self.modules[m].merge_modinfo_with_policy_files()
1485 if not attrdict:
1486 continue
1487 try:
1488 for attrname, attrvaldict in list(attrdict.items()):
1489 if attrvaldict.get('compat', False):
1490 continue
1491 print(('%s%s' %(indent, attrname)))
1492 print(('%shelp: %s' %(indent + ' ',
1493 attrvaldict.get('help', ''))))
1494 print(('%srequired: %s' %(indent + ' ',
1495 attrvaldict.get('required', False))))
1496 default = attrvaldict.get('default')
1497 if default:
1498 print(('%sdefault: %s' %(indent + ' ', default)))
1499
1500 validrange = attrvaldict.get('validrange')
1501 if validrange:
1502 print(('%svalidrange: %s-%s'
1503 %(indent + ' ', validrange[0], validrange[1])))
1504
1505 validvals = attrvaldict.get('validvals')
1506 if validvals:
1507 print(('%svalidvals: %s'
1508 %(indent + ' ', ','.join(validvals))))
1509
1510 examples = attrvaldict.get('example')
1511 if not examples:
1512 continue
1513
1514 print('%sexample:' %(indent + ' '))
1515 for e in examples:
1516 print('%s%s' %(indent + ' ', e))
1517 except Exception:
1518 pass
1519 print('')
1520
1521 def load_scripts(self, modules_dir):
1522 """ loading user modules from /etc/network/.
1523
1524 Note that previously loaded python modules override modules found
1525 under /etc/network if any
1526
1527 """
1528
1529 self.logger.info('looking for user scripts under %s' %modules_dir)
1530 for op, mlist in list(self.script_ops.items()):
1531 msubdir = modules_dir + '/if-%s.d' %op
1532 self.logger.info('loading scripts under %s ...' %msubdir)
1533 try:
1534 module_list = os.listdir(msubdir)
1535 for module in module_list:
1536 if self.modules.get(module) or module in self.overridden_ifupdown_scripts:
1537 continue
1538 self.script_ops[op].append(msubdir + '/' + module)
1539 except Exception:
1540 # continue reading
1541 pass
1542
1543
1544 def _schedule_addon_translate(self):
1545 merged_ifaceobjs = list(itertools.chain.from_iterable(self.ifaceobjdict.values()))
1546
1547 for addon in self.modules.values():
1548 try:
1549 addon.translate(merged_ifaceobjs)
1550 except AttributeError:
1551 pass
1552
1553 def _sched_ifaces(self, ifacenames, ops, skipupperifaces=False,
1554 followdependents=True, sort=False):
1555 self.logger.debug('scheduling \'%s\' for %s'
1556 %(str(ops), str(ifacenames)))
1557 self._pretty_print_ordered_dict('dependency graph',
1558 self.dependency_graph)
1559 ifaceScheduler.sched_ifaces(self, ifacenames, ops,
1560 dependency_graph=self.dependency_graph,
1561 order=ifaceSchedulerFlags.INORDER
1562 if 'down' in ops[0]
1563 else ifaceSchedulerFlags.POSTORDER,
1564 followdependents=followdependents,
1565 skipupperifaces=skipupperifaces,
1566 sort=True if (sort or ifupdownflags.flags.CLASS) else False)
1567 return ifaceScheduler.get_sched_status()
1568
1569 def _render_ifacename(self, ifacename):
1570 new_ifacenames = []
1571 vlan_match = re.match("^([\d]+)-([\d]+)", ifacename)
1572 if vlan_match:
1573 vlan_groups = vlan_match.groups()
1574 if vlan_groups[0] and vlan_groups[1]:
1575 [new_ifacenames.append('%d' %v)
1576 for v in range(int(vlan_groups[0]),
1577 int(vlan_groups[1])+1)]
1578 return new_ifacenames
1579
1580 def _preprocess_ifacenames(self, ifacenames):
1581 """ validates interface list for config existance.
1582
1583 returns -1 if one or more interface not found. else, returns 0
1584
1585 """
1586 new_ifacenames = []
1587 err_iface = ''
1588 for i in ifacenames:
1589 ifaceobjs = self.get_ifaceobjs(i)
1590 if not ifaceobjs:
1591 # if name not available, render interface name and check again
1592 rendered_ifacenames = utils.expand_iface_range(i)
1593 if rendered_ifacenames:
1594 for ri in rendered_ifacenames:
1595 ifaceobjs = self.get_ifaceobjs(ri)
1596 if not ifaceobjs:
1597 err_iface += ' ' + ri
1598 else:
1599 new_ifacenames.append(ri)
1600 else:
1601 err_iface += ' ' + i
1602 else:
1603 new_ifacenames.append(i)
1604 if err_iface:
1605 raise Exception('cannot find interfaces:%s' %err_iface)
1606 return new_ifacenames
1607
1608 def _iface_whitelisted(self, auto, allow_classes, excludepats, ifacename):
1609 """ Checks if interface is whitelisted depending on set of parameters.
1610
1611 interfaces are checked against the allow_classes and auto lists.
1612
1613 """
1614
1615 ret = True
1616
1617 # Check if interface matches the exclude patter
1618 if excludepats:
1619 for e in excludepats:
1620 if re.search(e, ifacename):
1621 ret = False
1622 ifaceobjs = self.get_ifaceobjs(ifacename)
1623 if not ifaceobjs:
1624 if ret:
1625 self.logger.debug('iface %s' %ifacename + ' not found')
1626 return ret
1627 # If matched exclude pattern, return false
1628 if not ret:
1629 for i in ifaceobjs:
1630 i.blacklisted = True
1631 self.blacklisted_ifaces_present = True
1632 return ret
1633 # Check if interface belongs to the class
1634 # the user is interested in, if not return false
1635 if allow_classes:
1636 ret = False
1637 for i in ifaceobjs:
1638 if i.classes:
1639 common = set(allow_classes).intersection(set(i.classes))
1640 if common:
1641 ret = True
1642 if not ret:
1643 # If a class was requested and interface does not belong
1644 # to the class, only then mark the ifaceobjs as blacklisted
1645 self.blacklisted_ifaces_present = True
1646 for i in ifaceobjs:
1647 i.blacklisted = True
1648 return ret
1649 # If the user has requested auto class, check if the interface
1650 # is marked auto
1651 if auto:
1652 ret = False
1653 for i in ifaceobjs:
1654 if i.auto:
1655 ret = True
1656 if not ret:
1657 # If auto was requested and interface was not marked auto,
1658 # only then mark all of them as blacklisted
1659 self.blacklisted_ifaces_present = True
1660 for i in ifaceobjs:
1661 i.blacklisted = True
1662 return ret
1663
1664 def _compat_conv_op_to_mode(self, op):
1665 """ Returns old op name to work with existing scripts """
1666 if 'up' in op:
1667 return 'start'
1668 elif 'down' in op:
1669 return 'stop'
1670 else:
1671 return op
1672
1673 def generate_running_env(self, ifaceobj, op):
1674 """ Generates a dictionary with env variables required for
1675 an interface. Used to support script execution for interfaces.
1676 """
1677
1678 cenv = None
1679 iface_env = ifaceobj.get_env()
1680 if iface_env:
1681 cenv = dict(os.environ)
1682 if cenv:
1683 cenv.update(iface_env)
1684 else:
1685 cenv = iface_env
1686 else:
1687 cenv = {}
1688 cenv['MODE'] = self._compat_conv_op_to_mode(op)
1689 cenv['PHASE'] = op
1690
1691 return cenv
1692
1693 def _save_state(self):
1694 if (not self.flags.STATEMANAGER_ENABLE or
1695 not self.flags.STATEMANAGER_UPDATE):
1696 return
1697 try:
1698 # Update persistant iface states
1699 self.statemanager.save_state()
1700 except Exception as e:
1701 if self.logger.isEnabledFor(logging.DEBUG):
1702 t = sys.exc_info()[2]
1703 traceback.print_tb(t)
1704 self.logger.warning('error saving state (%s)' %str(e))
1705
1706 def set_type(self, type):
1707 if type == 'iface':
1708 self.type = ifaceType.IFACE
1709 elif type == 'vlan':
1710 self.type = ifaceType.BRIDGE_VLAN
1711 else:
1712 self.type = ifaceType.UNKNOWN
1713
1714 def _process_delay_admin_state_queue(self, op):
1715 if not self._delay_admin_state_iface_queue:
1716 return
1717 if op == 'up':
1718 func = self.netlink.link_up
1719 elif op == 'down':
1720 func = self.netlink.link_down
1721 else:
1722 return
1723 for i in self._delay_admin_state_iface_queue:
1724 try:
1725 if self.link_exists(i):
1726 func(i)
1727 except Exception as e:
1728 self.logger.warning(str(e))
1729 pass
1730
1731 def _get_iface_exclude_companion(self, ifacename):
1732 try:
1733 return ifupdown2.ifupdown.policymanager.policymanager_api.get_iface_default(
1734 module_name='main', ifname=ifacename,
1735 attr='exclude-companion')
1736 except Exception:
1737 return ifupdown.policymanager.policymanager_api.get_iface_default(
1738 module_name='main', ifname=ifacename,
1739 attr='exclude-companion')
1740
1741 def _preprocess_excludepats(self, excludepats):
1742 new_excludepats = excludepats
1743 for e in excludepats:
1744 ifaceobjs = self.get_ifaceobjs(e)
1745 for iobj in ifaceobjs or []:
1746 ec = iobj.get_attr_value_first('exclude-companion')
1747 if not ec:
1748 ec = self._get_iface_exclude_companion(e)
1749 if not ec:
1750 continue
1751 else:
1752 for ee in ec.split():
1753 if ee in new_excludepats:
1754 continue
1755 if self.get_ifaceobjs(ee):
1756 # if we know the object add it to the new
1757 # excludepats list
1758 new_excludepats.append(ee)
1759 self.logger.info('excludepats after processing companions [%s]' %' '.join(new_excludepats))
1760 return new_excludepats
1761
1762 def up(self, ops, auto=False, allow_classes=None, ifacenames=None,
1763 excludepats=None, printdependency=None, syntaxcheck=False,
1764 type=None, skipupperifaces=False):
1765 """This brings the interface(s) up
1766
1767 Args:
1768 ops (list): list of ops to perform on the interface(s).
1769 Eg: ['pre-up', 'up', 'post-up'
1770
1771 Kwargs:
1772 auto (bool): act on interfaces marked auto
1773 allow_classes (list): act on interfaces belonging to classes in the list
1774 ifacenames (list): act on interfaces specified in this list
1775 excludepats (list): list of patterns of interfaces to exclude
1776 syntaxcheck (bool): only perform syntax check
1777 """
1778
1779 self.set_type(type)
1780
1781 if allow_classes:
1782 ifupdownflags.flags.CLASS = True
1783 if not self.flags.ADDONS_ENABLE:
1784 self.flags.STATEMANAGER_UPDATE = False
1785 if auto:
1786 ifupdownflags.flags.ALL = True
1787 ifupdownflags.flags.WITH_DEPENDS = True
1788 try:
1789 iface_read_ret = self.read_iface_config()
1790 except Exception:
1791 raise
1792
1793 if excludepats:
1794 excludepats = self._preprocess_excludepats(excludepats)
1795
1796 filtered_ifacenames = None
1797 if ifacenames:
1798 ifacenames = self._preprocess_ifacenames(ifacenames)
1799
1800 if allow_classes:
1801 filtered_ifacenames = self._get_filtered_ifacenames_with_classes(auto, allow_classes, excludepats, ifacenames)
1802
1803 # if iface list not given by user, assume all from config file
1804 if not ifacenames: ifacenames = list(self.ifaceobjdict.keys())
1805
1806 if not filtered_ifacenames:
1807 # filter interfaces based on auto and allow classes
1808 filtered_ifacenames = [i for i in ifacenames
1809 if self._iface_whitelisted(auto, allow_classes,
1810 excludepats, i)]
1811
1812 if not filtered_ifacenames:
1813 raise Exception('no ifaces found matching given allow lists')
1814
1815 if printdependency:
1816 self.populate_dependency_info(ops, filtered_ifacenames)
1817 self.print_dependency(filtered_ifacenames, printdependency)
1818 return
1819 else:
1820 self.populate_dependency_info(ops)
1821
1822 # If only syntax check was requested, return here.
1823 # return here because we want to make sure most
1824 # errors above are caught and reported.
1825 if syntaxcheck:
1826 if not self._module_syntax_check(filtered_ifacenames):
1827 raise Exception()
1828 if not iface_read_ret:
1829 raise Exception()
1830 elif self._any_iface_errors(filtered_ifacenames):
1831 raise Exception()
1832 return
1833
1834 ret = None
1835 try:
1836 ret = self._sched_ifaces(filtered_ifacenames, ops,
1837 skipupperifaces=skipupperifaces,
1838 followdependents=True
1839 if ifupdownflags.flags.WITH_DEPENDS
1840 else False)
1841 finally:
1842 self._process_delay_admin_state_queue('up')
1843 if not ifupdownflags.flags.DRYRUN and self.flags.ADDONS_ENABLE:
1844 self._save_state()
1845
1846 if not iface_read_ret or not ret:
1847 raise Exception()
1848
1849 self.check_running_configuration(filtered_ifacenames)
1850
1851 def check_running_configuration(self, filtered_ifacenames, all=False):
1852 """
1853 Print warning and better info message when we don't recognize an interface
1854 AKA when the interface wasn't created.
1855
1856 :param filtered_ifacenames:
1857 :param all:
1858 :return:
1859 """
1860 if not filtered_ifacenames:
1861 filtered_ifacenames = []
1862
1863 for ifname, ifaceobj_list in self.ifaceobjdict.items():
1864
1865 if not all and ifname not in filtered_ifacenames:
1866 continue
1867
1868 auto = True
1869
1870 for ifaceobj in ifaceobj_list:
1871 if not ifaceobj.auto:
1872 auto = False
1873 break
1874
1875 if not ifupdownflags.flags.DRYRUN and auto and not os.path.exists("/sys/class/net/%s" % ifname):
1876 self.logger.warning("%s: interface not recognized - please check interface configuration" % ifname)
1877
1878 def _get_filtered_ifacenames_with_classes(self, auto, allow_classes, excludepats, ifacenames):
1879 # if user has specified ifacelist and allow_classes
1880 # append the allow_classes interfaces to user
1881 # ifacelist
1882 filtered_ifacenames = [i for i in list(self.ifaceobjdict.keys())
1883 if self._iface_whitelisted(auto, allow_classes,
1884 excludepats, i)]
1885 filtered_ifacenames += ifacenames
1886
1887 for intf in ifacenames:
1888 for obj in self.get_ifaceobjs(intf) or []:
1889 obj.blacklisted = False
1890
1891 return filtered_ifacenames
1892
1893 def down(self, ops, auto=False, allow_classes=None, ifacenames=None,
1894 excludepats=None, printdependency=None, usecurrentconfig=False,
1895 type=None):
1896 """ down an interface """
1897
1898 self.set_type(type)
1899
1900 if allow_classes:
1901 ifupdownflags.flags.CLASS = True
1902 if not self.flags.ADDONS_ENABLE:
1903 self.flags.STATEMANAGER_UPDATE = False
1904 if auto:
1905 ifupdownflags.flags.ALL = True
1906 ifupdownflags.flags.WITH_DEPENDS = True
1907 # For down we need to look at old state, unless usecurrentconfig
1908 # is set
1909 if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE and
1910 self.statemanager.ifaceobjdict):
1911 # Since we are using state manager objects,
1912 # skip the updating of state manager objects
1913 self.logger.debug('Looking at old state ..')
1914 self.read_old_iface_config()
1915 else:
1916 # If no old state available
1917 try:
1918 self.read_iface_config()
1919 except Exception as e:
1920 raise Exception('error reading iface config (%s)' %str(e))
1921
1922 if excludepats:
1923 excludepats = self._preprocess_excludepats(excludepats)
1924
1925 filtered_ifacenames = None
1926 if ifacenames:
1927 # If iface list is given by the caller, always check if iface
1928 # is present
1929 try:
1930 ifacenames = self._preprocess_ifacenames(ifacenames)
1931
1932 if allow_classes:
1933 filtered_ifacenames = self._get_filtered_ifacenames_with_classes(auto, allow_classes, excludepats, ifacenames)
1934
1935 except Exception as e:
1936 raise Exception('%s' %str(e) +
1937 ' (interface was probably never up ?)')
1938
1939
1940 # if iface list not given by user, assume all from config file
1941 if not ifacenames: ifacenames = list(self.ifaceobjdict.keys())
1942
1943 if not filtered_ifacenames:
1944 # filter interfaces based on auto and allow classes
1945 filtered_ifacenames = [i for i in ifacenames
1946 if self._iface_whitelisted(auto, allow_classes,
1947 excludepats, i)]
1948
1949 if not filtered_ifacenames:
1950 raise Exception('no ifaces found matching given allow lists ' +
1951 '(or interfaces were probably never up ?)')
1952
1953 if printdependency:
1954 self.populate_dependency_info(ops, filtered_ifacenames)
1955 self.print_dependency(filtered_ifacenames, printdependency)
1956 return
1957 else:
1958 self.populate_dependency_info(ops)
1959
1960 try:
1961 self._sched_ifaces(filtered_ifacenames, ops,
1962 followdependents=True
1963 if ifupdownflags.flags.WITH_DEPENDS else False)
1964 finally:
1965 self._process_delay_admin_state_queue('down')
1966 if not ifupdownflags.flags.DRYRUN and self.flags.ADDONS_ENABLE:
1967 self._save_state()
1968
1969 def query(self, ops, auto=False, format_list=False, allow_classes=None,
1970 ifacenames=None,
1971 excludepats=None, printdependency=None,
1972 format='native', type=None):
1973 """ query an interface """
1974
1975 self.set_type(type)
1976
1977 # Let us forget internal squashing when it comes to
1978 # ifquery. It can surprise people relying of ifquery
1979 # output
1980 self._ifaceobj_squash_internal = False
1981
1982 if allow_classes:
1983 ifupdownflags.flags.CLASS = True
1984 if self.flags.STATEMANAGER_ENABLE and ops[0] == 'query-savedstate':
1985 return self.statemanager.dump_pretty(ifacenames)
1986 self.flags.STATEMANAGER_UPDATE = False
1987
1988 iface_read_ret = True
1989
1990 if auto:
1991 self.logger.debug('setting flag ALL')
1992 ifupdownflags.flags.ALL = True
1993 ifupdownflags.flags.WITH_DEPENDS = True
1994
1995 if ops[0] == 'query-syntax':
1996 self._modules_help(format)
1997 return
1998 elif ops[0] == 'query-running':
1999 # create fake devices to all dependents that dont have config
2000 for i in ifacenames:
2001 self.create_n_save_ifaceobj(i, ifacePrivFlags(False, True))
2002 else:
2003 try:
2004 iface_read_ret = self.read_iface_config(raw=ops[0] == "query-raw")
2005 except Exception:
2006 raise
2007
2008 if ifacenames and ops[0] != 'query-running':
2009 # If iface list is given, always check if iface is present
2010 ifacenames = self._preprocess_ifacenames(ifacenames)
2011
2012 if allow_classes:
2013 filtered_ifacenames = self._get_filtered_ifacenames_with_classes(auto, allow_classes, excludepats, ifacenames)
2014
2015 # if iface list not given by user, assume all from config file
2016 if not ifacenames: ifacenames = list(self.ifaceobjdict.keys())
2017
2018 # filter interfaces based on auto and allow classes
2019 if ops[0] == 'query-running':
2020 filtered_ifacenames = ifacenames
2021 elif not allow_classes:
2022 filtered_ifacenames = [
2023 i for i in ifacenames
2024 if self._iface_whitelisted(
2025 auto,
2026 allow_classes,
2027 excludepats, i
2028 )
2029 ]
2030
2031 if not filtered_ifacenames:
2032 raise Exception('no ifaces found matching ' +
2033 'given allow lists')
2034
2035 self.populate_dependency_info(ops)
2036 if ops[0] == 'query-dependency' and printdependency:
2037 self.print_dependency(filtered_ifacenames, printdependency)
2038 return
2039
2040 if format_list and (ops[0] == 'query' or ops[0] == 'query-raw'):
2041 return self.print_ifaceobjs_list(filtered_ifacenames)
2042
2043 if ops[0] == 'query' and not ifupdownflags.flags.WITHDEFAULTS:
2044 return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
2045 elif ops[0] == 'query-raw':
2046 return self.print_ifaceobjs_raw(filtered_ifacenames, format)
2047
2048 ret = self._sched_ifaces(filtered_ifacenames, ops,
2049 followdependents=True
2050 if ifupdownflags.flags.WITH_DEPENDS else False)
2051
2052 if ops[0] == 'query' and ifupdownflags.flags.WITHDEFAULTS:
2053 return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
2054 elif ops[0] == 'query-checkcurr':
2055 if self.print_ifaceobjscurr_pretty(filtered_ifacenames, format):
2056 # if any of the object has an error, signal that silently
2057 raise Exception('')
2058 elif ops[0] == 'query-running':
2059 self.print_ifaceobjsrunning_pretty(filtered_ifacenames, format)
2060 return
2061
2062 if not iface_read_ret or not ret:
2063 raise Exception()
2064
2065 def _reload_currentlyup(self, upops, downops, auto=False, allow=None,
2066 ifacenames=None, excludepats=None, usecurrentconfig=False,
2067 syntaxcheck=False, **extra_args):
2068 """ reload currently up interfaces """
2069 new_ifaceobjdict = {}
2070
2071 self.logger.info('reloading interfaces that are currently up ..')
2072
2073 try:
2074 iface_read_ret = self.read_iface_config()
2075 except Exception:
2076 raise
2077 if not self.ifaceobjdict:
2078 self.logger.warning("nothing to reload ..exiting.")
2079 return
2080 already_up_ifacenames = []
2081 if not ifacenames: ifacenames = list(self.ifaceobjdict.keys())
2082
2083 if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE
2084 and self.statemanager.ifaceobjdict):
2085 already_up_ifacenames = list(self.statemanager.ifaceobjdict.keys())
2086
2087 # Get already up interfaces that still exist in the interfaces file
2088 already_up_ifacenames_not_present = set(
2089 already_up_ifacenames).difference(ifacenames)
2090 already_up_ifacenames_still_present = set(
2091 already_up_ifacenames).difference(
2092 already_up_ifacenames_not_present)
2093
2094 interfaces_to_up = already_up_ifacenames_still_present
2095
2096 # generate dependency graph of interfaces
2097 self.populate_dependency_info(upops, interfaces_to_up)
2098
2099 # If only syntax check was requested, return here.
2100 # return here because we want to make sure most
2101 # errors above are caught and reported.
2102 if syntaxcheck:
2103 if not self._module_syntax_check(interfaces_to_up):
2104 raise Exception()
2105 if not iface_read_ret:
2106 raise Exception()
2107 elif self._any_iface_errors(interfaces_to_up):
2108 raise Exception()
2109 return
2110
2111 if (already_up_ifacenames_not_present and
2112 self.config.get('ifreload_currentlyup_down_notpresent') == '1'):
2113 self.logger.info('reload: schedule down on interfaces: %s'
2114 %str(already_up_ifacenames_not_present))
2115
2116 # Save a copy of new iface objects and dependency_graph
2117 new_ifaceobjdict = dict(self.ifaceobjdict)
2118 new_dependency_graph = dict(self.dependency_graph)
2119
2120 # old interface config is read into self.ifaceobjdict
2121 self.read_old_iface_config()
2122
2123 # reinitialize dependency graph
2124 self.dependency_graph = OrderedDict({})
2125 falready_up_ifacenames_not_present = [i for i in
2126 already_up_ifacenames_not_present
2127 if self._iface_whitelisted(auto, allow,
2128 excludepats, i)]
2129 self.populate_dependency_info(downops,
2130 falready_up_ifacenames_not_present)
2131 self._sched_ifaces(falready_up_ifacenames_not_present, downops,
2132 followdependents=False, sort=True)
2133 else:
2134 self.logger.info('no interfaces to down ..')
2135
2136 # Now, run 'up' with new config dict
2137 # reset statemanager update flag to default
2138 if auto:
2139 ifupdownflags.flags.ALL = True
2140 ifupdownflags.flags.WITH_DEPENDS = True
2141 if new_ifaceobjdict:
2142 # and now, ifaceobjdict is back to current config
2143 self.ifaceobjdict = new_ifaceobjdict
2144 self.dependency_graph = new_dependency_graph
2145
2146 if not self.ifaceobjdict:
2147 self.logger.info('no interfaces to up')
2148 return
2149 self.logger.info('reload: scheduling up on interfaces: %s'
2150 %str(interfaces_to_up))
2151 ret = self._sched_ifaces(interfaces_to_up, upops,
2152 followdependents=True
2153 if ifupdownflags.flags.WITH_DEPENDS else False)
2154 if ifupdownflags.flags.DRYRUN:
2155 return
2156 self._save_state()
2157
2158 if not iface_read_ret or not ret:
2159 raise Exception()
2160
2161 def _reload_default(self, upops, downops, auto=False, allow=None,
2162 ifacenames=None, excludepats=None, usecurrentconfig=False,
2163 syntaxcheck=False, **extra_args):
2164 """ reload interface config """
2165 new_ifaceobjdict = {}
2166
2167 try:
2168 iface_read_ret = self.read_iface_config()
2169 except Exception:
2170 raise
2171
2172 if not self.ifaceobjdict:
2173 self.logger.warning("nothing to reload ..exiting.")
2174 return
2175
2176 if not ifacenames: ifacenames = list(self.ifaceobjdict.keys())
2177 new_filtered_ifacenames = [i for i in ifacenames
2178 if self._iface_whitelisted(auto, allow,
2179 excludepats, i)]
2180 # generate dependency graph of interfaces
2181 self.populate_dependency_info(upops)
2182
2183 # If only syntax check was requested, return here.
2184 # return here because we want to make sure most
2185 # errors above are caught and reported.
2186 if syntaxcheck:
2187 if not self._module_syntax_check(new_filtered_ifacenames):
2188 raise Exception()
2189 if not iface_read_ret:
2190 raise Exception()
2191 elif self._any_iface_errors(new_filtered_ifacenames):
2192 raise Exception()
2193 return
2194
2195 if (not usecurrentconfig and self.flags.STATEMANAGER_ENABLE
2196 and self.statemanager.ifaceobjdict):
2197 # Save a copy of new iface objects and dependency_graph
2198 new_ifaceobjdict = dict(self.ifaceobjdict)
2199 new_dependency_graph = dict(self.dependency_graph)
2200
2201 self.ifaceobjdict = OrderedDict({})
2202 self.dependency_graph = OrderedDict({})
2203
2204 # if old state is present, read old state and mark op for 'down'
2205 # followed by 'up' aka: reload
2206 # old interface config is read into self.ifaceobjdict
2207 self.read_old_iface_config()
2208 op = 'reload'
2209 else:
2210 # oldconfig not available, continue with 'up' with new config
2211 op = 'up'
2212 new_ifaceobjdict = self.ifaceobjdict
2213 new_dependency_graph = self.dependency_graph
2214
2215 if excludepats:
2216 excludepats = self._preprocess_excludepats(excludepats)
2217
2218 if op == 'reload' and ifacenames:
2219 ifacenames = list(self.ifaceobjdict.keys())
2220 old_filtered_ifacenames = [i for i in ifacenames
2221 if self._iface_whitelisted(auto, allow,
2222 excludepats, i)]
2223
2224 # generate dependency graph of old interfaces,
2225 # This should make sure built in interfaces are
2226 # populated. disable check shared dependents as an optimization.
2227 # these are saved interfaces and dependency for these
2228 # have been checked before they became part of saved state.
2229 try:
2230 self.flags.CHECK_SHARED_DEPENDENTS = False
2231 self.populate_dependency_info(upops)
2232 self.flags.CHECK_SHARED_DEPENDENTS = True
2233 except Exception as e:
2234 self.logger.info("error generating dependency graph for "
2235 "saved interfaces (%s)" %str(e))
2236 pass
2237
2238 # make sure we pick up built-in interfaces
2239 # if config file had 'ifreload_down_changed' variable
2240 # set, also look for interfaces that changed to down them
2241 down_changed = int(self.config.get('ifreload_down_changed', '1'))
2242
2243 # Generate the interface down list
2244 # Interfaces that go into the down list:
2245 # - interfaces that were present in last config and are not
2246 # present in the new config
2247 # - interfaces that were changed between the last and current
2248 # config
2249 ifacedownlist = []
2250 for ifname in list(self.ifaceobjdict.keys()):
2251 lastifaceobjlist = self.ifaceobjdict.get(ifname)
2252 if not self.is_ifaceobj_builtin(lastifaceobjlist[0]):
2253 # if interface is not built-in and is not in
2254 # old filtered ifacenames
2255 if ifname not in old_filtered_ifacenames:
2256 continue
2257 objidx = 0
2258 # If interface is not present in the new file
2259 # append it to the down list
2260 newifaceobjlist = new_ifaceobjdict.get(ifname)
2261 if not newifaceobjlist:
2262 ifacedownlist.append(ifname)
2263 continue
2264 # If ifaceobj was present in the old interfaces file,
2265 # and does not have a config in the new interfaces file
2266 # but has been picked up as a dependent of another
2267 # interface, catch it here. This catches a common error
2268 # for example: remove a bond section from the interfaces
2269 # file, but leave it around as a bridge port
2270 # XXX: Ideally its better to just add it to the
2271 # ifacedownlist. But we will be cautious here
2272 # and just print a warning
2273 if (self.is_ifaceobj_noconfig(newifaceobjlist[0]) and
2274 not self.is_ifaceobj_builtin(newifaceobjlist[0]) and
2275 lastifaceobjlist[0].is_config_present() and
2276 lastifaceobjlist[0].link_kind):
2277
2278 # Check if interface is picked up by a regex in the upperifaces.
2279 print_warning = True
2280
2281 for upper in newifaceobjlist[objidx].upperifaces or []:
2282 slaves = []
2283 for upper_ifaceobj in self.ifaceobjdict.get(upper):
2284 slaves.extend(upper_ifaceobj.get_attr_value("bond-slaves") or [])
2285 slaves.extend(upper_ifaceobj.get_attr_value("bridge-ports") or [])
2286 slaves_string = " ".join(slaves)
2287 if newifaceobjlist[objidx].name not in slaves_string:
2288 print_warning = "regex" not in slaves_string
2289 if not print_warning:
2290 break
2291 ###############################################################
2292
2293 warning_no_config_regex = (
2294 "%s: misconfig ? removed but still exists as a dependency of %s.\n"
2295 "Please remove the dependency manually `ifdown %s` if it is being "
2296 "picked up as part of a regex" % (
2297 newifaceobjlist[objidx].name,
2298 str(newifaceobjlist[objidx].upperifaces),
2299 newifaceobjlist[objidx].name
2300 )
2301 )
2302
2303 if print_warning:
2304 self.logger.warning(warning_no_config_regex)
2305 else:
2306 # The warning shouldn't be printed because we've detected that this
2307 # interface was pick up as part of a regex but the config doesn't
2308 # exist anymore. It was most likely removed from the config file itself
2309 # We should down this interface and remove it from the ifaceobjdict
2310 # and dependency graph used for the following ifreload.
2311 ifname_to_remove = newifaceobjlist[objidx].name
2312 ifacedownlist.append(ifname_to_remove)
2313
2314 try:
2315 if new_ifaceobjdict:
2316 del new_ifaceobjdict[ifname_to_remove]
2317
2318 for k, v in new_dependency_graph.items():
2319 if ifname_to_remove in v:
2320 v.remove(ifname_to_remove)
2321 del new_dependency_graph[ifname_to_remove]
2322 except Exception as e:
2323 self.logger.warning(warning_no_config_regex)
2324 self.logger.warning("while trying to fix this situation "
2325 "we ran into the following issues: %s" % str(e))
2326
2327 elif (lastifaceobjlist[0].link_kind and
2328 not newifaceobjlist[0].link_kind):
2329 self.logger.warning('%s: moved from being a %s to a'
2330 ' physical interface (non-logical interface).'
2331 'This interface will be downed.\n'
2332 ' If this was not intentional, please restore the'
2333 ' original interface definition and execute ifreload'
2334 % (newifaceobjlist[objidx].name,
2335 ifaceLinkKind.to_str(lastifaceobjlist[0].link_kind)))
2336 ifacedownlist.append(newifaceobjlist[objidx].name)
2337 if not down_changed:
2338 continue
2339 if len(newifaceobjlist) != len(lastifaceobjlist):
2340 ifacedownlist.append(ifname)
2341 continue
2342
2343 # If interface has changed between the current file
2344 # and the last installed append it to the down list
2345 # compare object list
2346 for objidx in range(0, len(lastifaceobjlist)):
2347 oldobj = lastifaceobjlist[objidx]
2348 newobj = newifaceobjlist[objidx]
2349 if not newobj.compare(oldobj):
2350 ifacedownlist.append(ifname)
2351 continue
2352
2353 if ifacedownlist:
2354 self.logger.info('reload: scheduling down on interfaces: %s'
2355 %str(ifacedownlist))
2356 # reinitialize dependency graph
2357 self.dependency_graph = OrderedDict({})
2358
2359 # Generate dependency info for old config
2360 self.flags.CHECK_SHARED_DEPENDENTS = False
2361 self.populate_dependency_info(downops, ifacedownlist)
2362 self.flags.CHECK_SHARED_DEPENDENTS = True
2363
2364 try:
2365 # XXX: Hack to skip checking upperifaces during down.
2366 # the dependency list is not complete here
2367 # and we dont want to down the upperiface.
2368 # Hence during reload, set this to true.
2369 # This is being added to avoid a failure in
2370 # scheduler._check_upperifaces when we are dowing
2371 # a builtin bridge port
2372 self.flags.SCHED_SKIP_CHECK_UPPERIFACES = True
2373 self._sched_ifaces(ifacedownlist, downops,
2374 followdependents=False,
2375 sort=True)
2376 except Exception as e:
2377 self.logger.error(str(e))
2378 pass
2379 finally:
2380 self.flags.SCHED_SKIP_CHECK_UPPERIFACES = False
2381 self._process_delay_admin_state_queue('down')
2382 else:
2383 self.logger.info('no interfaces to down ..')
2384
2385 # Now, run 'up' with new config dict
2386 # reset statemanager update flag to default
2387 if not new_ifaceobjdict:
2388 self.logger.debug('no interfaces to up')
2389 return
2390
2391 if auto:
2392 ifupdownflags.flags.ALL = True
2393 ifupdownflags.flags.WITH_DEPENDS = True
2394 # and now, we are back to the current config in ifaceobjdict
2395 self.ifaceobjdict = new_ifaceobjdict
2396 self.dependency_graph = new_dependency_graph
2397
2398 self.logger.info('reload: scheduling up on interfaces: %s'
2399 %str(new_filtered_ifacenames))
2400 ifupdownflags.flags.CACHE = True
2401 try:
2402 ret = self._sched_ifaces(new_filtered_ifacenames, upops,
2403 followdependents=True
2404 if ifupdownflags.flags.WITH_DEPENDS
2405 else False)
2406 except Exception as e:
2407 ret = None
2408 self.logger.error(str(e))
2409 finally:
2410 self._process_delay_admin_state_queue('up')
2411 if ifupdownflags.flags.DRYRUN:
2412 return
2413 self._save_state()
2414
2415 if not iface_read_ret or not ret:
2416 raise Exception()
2417
2418 def reload(self, *args, **kargs):
2419 """ reload interface config """
2420 self.logger.debug('reloading interface config ..')
2421 if kargs.get('currentlyup', False):
2422 self._reload_currentlyup(*args, **kargs)
2423 else:
2424 self._reload_default(*args, **kargs)
2425
2426 self.check_running_configuration([], all=True)
2427
2428 def _any_iface_errors(self, ifacenames):
2429 for i in ifacenames:
2430 ifaceobjs = self.get_ifaceobjs(i)
2431 if not ifaceobjs: continue
2432 for ifaceobj in ifaceobjs:
2433 if (ifaceobj.status == ifaceStatus.NOTFOUND or
2434 ifaceobj.status == ifaceStatus.ERROR):
2435 return True
2436 return False
2437
2438 def _pretty_print_ordered_dict(self, prefix, argdict):
2439 outbuf = prefix + ' {\n'
2440 for k, vlist in list(argdict.items()):
2441 outbuf += '\t%s : %s\n' %(k, str(vlist))
2442 self.logger.debug(outbuf + '}')
2443
2444 def print_dependency(self, ifacenames, format):
2445 """ prints iface dependency information """
2446
2447 if not ifacenames:
2448 ifacenames = list(self.ifaceobjdict.keys())
2449 if format == 'list':
2450 for k,v in list(self.dependency_graph.items()):
2451 print('%s : %s' %(k, str(v)))
2452 elif format == 'dot':
2453 indegrees = {}
2454 for i in list(self.dependency_graph.keys()):
2455 indegrees.update({i: self.get_iface_refcnt(i)})
2456 graph.generate_dots(self.dependency_graph, indegrees)
2457
2458 def print_ifaceobjs_list(self, ifacenames):
2459 for i in ifacenames:
2460 print(i)
2461
2462 def print_ifaceobjs_raw(self, ifacenames, format=None):
2463 """ prints raw lines for ifaces from config file """
2464
2465 if format == "json":
2466 self.print_ifaceobjs_pretty(ifacenames, format)
2467 return
2468
2469 for i in ifacenames:
2470 for ifaceobj in self.get_ifaceobjs(i):
2471 if self.is_ifaceobj_builtin(ifaceobj):
2472 continue
2473 ifaceobj.dump_raw(self.logger)
2474 if (ifupdownflags.flags.WITH_DEPENDS and
2475 not ifupdownflags.flags.ALL):
2476 dlist = ifaceobj.lowerifaces
2477 if not dlist: continue
2478 self.print_ifaceobjs_raw(dlist)
2479
2480 def _get_ifaceobjs_pretty(self, ifacenames, ifaceobjs, running=False):
2481 """ returns iface obj list """
2482
2483 for i in ifacenames:
2484 for ifaceobj in self.get_ifaceobjs(i):
2485 if ((not running and self.is_ifaceobj_noconfig(ifaceobj)) or
2486 (running and not ifaceobj.is_config_present() and
2487 not self.is_iface_builtin_byname(i) and
2488 not ifaceobj.upperifaces)):
2489 continue
2490 ifaceobjs.append(ifaceobj)
2491 if (ifupdownflags.flags.WITH_DEPENDS and
2492 not ifupdownflags.flags.ALL):
2493 dlist = ifaceobj.lowerifaces
2494 if not dlist: continue
2495 self._get_ifaceobjs_pretty(dlist, ifaceobjs, running)
2496
2497 def print_ifaceobjs_pretty(self, ifacenames, format='native'):
2498 """ pretty prints iface in format given by keyword arg format """
2499
2500 ifaceobjs = []
2501 self._get_ifaceobjs_pretty(ifacenames, ifaceobjs)
2502 if not ifaceobjs: return
2503 if format == 'json':
2504 print(json.dumps(ifaceobjs, cls=ifaceJsonEncoder,
2505 indent=4, separators=(',', ': ')))
2506 else:
2507 expand = int(self.config.get('ifquery_ifacename_expand_range', '0'))
2508 for i in ifaceobjs:
2509 if not expand and (i.flags & iface.IFACERANGE_ENTRY):
2510 # print only the first one
2511 if i.flags & iface.IFACERANGE_START:
2512 i.dump_pretty(use_realname=True)
2513 else:
2514 i.dump_pretty()
2515
2516 def _get_ifaceobjscurr_pretty(self, ifacenames, ifaceobjs):
2517 ret = 0
2518 for i in ifacenames:
2519 ifaceobjscurr = self.get_ifaceobjcurr(i)
2520 if not ifaceobjscurr: continue
2521 for ifaceobj in ifaceobjscurr:
2522 if (ifaceobj.status == ifaceStatus.NOTFOUND or
2523 ifaceobj.status == ifaceStatus.ERROR):
2524 ret = 1
2525 if self.is_ifaceobj_noconfig(ifaceobj):
2526 continue
2527 ifaceobjs.append(ifaceobj)
2528 if (ifupdownflags.flags.WITH_DEPENDS and
2529 not ifupdownflags.flags.ALL):
2530 dlist = ifaceobj.lowerifaces
2531 if not dlist: continue
2532 dret = self._get_ifaceobjscurr_pretty(dlist, ifaceobjs)
2533 if dret: ret = 1
2534 return ret
2535
2536 def print_ifaceobjscurr_pretty(self, ifacenames, format='native'):
2537 """ pretty prints current running state of interfaces with status.
2538
2539 returns 1 if any of the interface has an error,
2540 else returns 0
2541 """
2542 ifaceobjs = []
2543 ret = self._get_ifaceobjscurr_pretty(ifacenames, ifaceobjs)
2544 if not ifaceobjs: return
2545
2546 # override ifaceStatusUserStrs
2547 ifaceStatusUserStrs.SUCCESS = self.config.get('ifquery_check_success_str', _success_sym)
2548 ifaceStatusUserStrs.ERROR = self.config.get('ifquery_check_error_str', _error_sym)
2549 ifaceStatusUserStrs.UNKNOWN = self.config.get('ifquery_check_unknown_str', '')
2550 if format == 'json':
2551 print(json.dumps(ifaceobjs, cls=ifaceJsonEncoderWithStatus,
2552 indent=2, separators=(',', ': ')))
2553 else:
2554 for ifaceobj in ifaceobjs:
2555 ifaceobj.dump_pretty(with_status=True)
2556 return ret
2557
2558 def print_ifaceobjsrunning_pretty(self, ifacenames, format='native'):
2559 """ pretty prints iface running state """
2560
2561 ifaceobjs = []
2562 self._get_ifaceobjs_pretty(ifacenames, ifaceobjs, running=True)
2563 if not ifaceobjs: return
2564 if format == 'json':
2565 print(json.dumps(ifaceobjs, cls=ifaceJsonEncoder, indent=2,
2566 separators=(',', ': ')))
2567 else:
2568 for i in ifaceobjs:
2569 i.dump_pretty()
2570
2571 def _dump(self):
2572 print('ifupdown main object dump')
2573 print(self.pp.pprint(self.modules))
2574 print(self.pp.pprint(self.ifaceobjdict))
2575
2576 def _dump_ifaceobjs(self, ifacenames):
2577 for i in ifacenames:
2578 ifaceobjs = self.get_ifaceobjs(i)
2579 for i in ifaceobjs:
2580 i.dump(self.logger)
2581 print('\n')