]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/ifupdown/scheduler.py
python3: scheduler: python3 set can't handle None value
[mirror_ifupdown2.git] / ifupdown2 / ifupdown / scheduler.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# ifaceScheduler --
7# interface scheduler
8#
a6f80f0e 9
739f9c7e 10import os
69f58278 11import sys
d486dd0d 12
d486dd0d
JF
13try:
14 from ifupdown2.ifupdown.graph import *
d486dd0d
JF
15 from ifupdown2.ifupdown.iface import *
16 from ifupdown2.ifupdown.utils import utils
17 from ifupdown2.ifupdown.statemanager import *
18
223ba5af 19 import ifupdown2.ifupdown.policymanager as policymanager
d486dd0d
JF
20 import ifupdown2.ifupdown.ifupdownflags as ifupdownflags
21except ImportError:
22 from ifupdown.graph import *
d486dd0d
JF
23 from ifupdown.iface import *
24 from ifupdown.utils import utils
25 from ifupdown.statemanager import *
26
27 import ifupdown.ifupdownflags as ifupdownflags
223ba5af 28 import ifupdown.policymanager as policymanager
d486dd0d
JF
29
30
d08d5f54 31class ifaceSchedulerFlags():
904908bc
RP
32 """ Enumerates scheduler flags """
33
c798b0f4 34 INORDER = 0x1
35 POSTORDER = 0x2
d08d5f54 36
be0b20f2 37class ifaceScheduler():
38 """ scheduler functions to schedule configuration of interfaces.
a6f80f0e 39
a6f80f0e 40 supports scheduling of interfaces serially in plain interface list
41 or dependency graph format.
99b212b0 42
a6f80f0e 43 """
44
c798b0f4 45 _STATE_CHECK = True
46
2009513f
RP
47 _SCHED_STATUS = True
48
223ba5af
JF
49 VRF_MGMT_DEVNAME = policymanager.policymanager_api.get_module_globals(
50 module_name="vrf",
51 attr="vrf-mgmt-devname"
52 )
53
d486dd0d
JF
54 @classmethod
55 def reset(cls):
56 cls._STATE_CHECK = True
57 cls._SCHED_STATUS = True
58
2009513f
RP
59 @classmethod
60 def get_sched_status(cls):
61 return cls._SCHED_STATUS
5973036b 62
892c495e
RP
63 @classmethod
64 def set_sched_status(cls, state):
65 cls._SCHED_STATUS = state
66
be0b20f2 67 @classmethod
6e16e5ae 68 def run_iface_op(cls, ifupdownobj, ifaceobj, op, cenv=None):
a6f80f0e 69 """ Runs sub operation on an interface """
62ddec8b 70 ifacename = ifaceobj.name
a6f80f0e 71
3e6ea735 72 if ifupdownobj.type and ifupdownobj.type != ifaceobj.type:
2da58137
RP
73 return
74
dbc018d3 75 if not ifupdownobj.flags.ADDONS_ENABLE: return
44a6ca06
RP
76 if op == 'query-checkcurr':
77 query_ifaceobj=ifupdownobj.create_n_save_ifaceobjcurr(ifaceobj)
16d854b4
RP
78 # If not type bridge vlan and the object does not exist,
79 # mark not found and return
80 if (not ifupdownobj.link_exists(ifaceobj.name) and
81 ifaceobj.type != ifaceType.BRIDGE_VLAN):
82 query_ifaceobj.set_state_n_status(ifaceState.from_str(op),
83 ifaceStatus.NOTFOUND)
84 return
be0b20f2 85 for mname in ifupdownobj.module_ops.get(op):
37c0543d 86 m = ifupdownobj.modules.get(mname)
a6f80f0e 87 err = 0
88 try:
d08d5f54 89 if hasattr(m, 'run'):
a690dfae 90 msg = ('%s: %s : running module %s' %(ifacename, op, mname))
739f665b 91 if op == 'query-checkcurr':
d486dd0d 92 # Dont check curr if the interface object was
37c0543d 93 # auto generated
dbc018d3
RP
94 if (ifaceobj.priv_flags and
95 ifaceobj.priv_flags.NOCONFIG):
37c0543d 96 continue
a690dfae 97 ifupdownobj.logger.debug(msg)
e1601369 98 m.run(ifaceobj, op, query_ifaceobj,
6e16e5ae 99 ifaceobj_getfunc=ifupdownobj.get_ifaceobjs)
a6f80f0e 100 else:
a690dfae 101 ifupdownobj.logger.debug(msg)
3e6ea735 102 m.run(ifaceobj, op,
6e16e5ae 103 ifaceobj_getfunc=ifupdownobj.get_ifaceobjs)
3b01ed76 104 except Exception as e:
3e6ea735 105 if not ifupdownobj.ignore_error(str(e)):
223ba5af 106 err = 1
502eb023
JF
107 import traceback
108 traceback.print_exc()
223ba5af 109 ifupdownobj.logger.error(str(e))
3e6ea735
RP
110 # Continue with rest of the modules
111 pass
a6f80f0e 112 finally:
ca105861 113 if err or ifaceobj.status == ifaceStatus.ERROR:
31a5f4c3 114 ifaceobj.set_state_n_status(ifaceState.from_str(op),
115 ifaceStatus.ERROR)
2009513f 116 if 'up' in op or 'down' in op or 'query-checkcurr' in op:
892c495e 117 cls.set_sched_status(False)
d08d5f54 118 else:
3e6ea735
RP
119 # Mark success only if the interface was not already
120 # marked with error
121 status = (ifaceobj.status
122 if ifaceobj.status == ifaceStatus.ERROR
123 else ifaceStatus.SUCCESS)
31a5f4c3 124 ifaceobj.set_state_n_status(ifaceState.from_str(op),
3e6ea735 125 status)
6bd7fc74 126
ee3fcf44 127 if ifupdownobj.config.get('addon_scripts_support', '0') == '1':
d486dd0d 128 # execute /etc/network/ scripts
ca2ec1ac
GS
129 os.environ['IFACE'] = ifaceobj.name if ifaceobj.name else ''
130 os.environ['LOGICAL'] = ifaceobj.name if ifaceobj.name else ''
131 os.environ['METHOD'] = ifaceobj.addr_method if ifaceobj.addr_method else ''
132 os.environ['ADDRFAM'] = ','.join(ifaceobj.addr_family) if ifaceobj.addr_family else ''
6bd7fc74 133 for mname in ifupdownobj.script_ops.get(op, []):
134 ifupdownobj.logger.debug('%s: %s : running script %s'
d08d5f54 135 %(ifacename, op, mname))
6bd7fc74 136 try:
a193d8d1 137 utils.exec_command(mname, env=cenv)
3b01ed76 138 except Exception as e:
739f9c7e
JF
139 if "permission denied" in str(e).lower():
140 ifupdownobj.logger.warning('%s: %s %s' % (ifacename, op, str(e)))
141 else:
142 ifupdownobj.log_error('%s: %s %s' % (ifacename, op, str(e)))
37c0543d 143
be0b20f2 144 @classmethod
6e16e5ae 145 def run_iface_list_ops(cls, ifupdownobj, ifaceobjs, ops):
923290bd 146 """ Runs all operations on a list of interface
147 configurations for the same interface
148 """
a070c90e 149
a690dfae 150 # minor optimization. If operation is 'down', proceed only
151 # if interface exists in the system
923290bd 152 ifacename = ifaceobjs[0].name
8c13865c 153 ifupdownobj.logger.info('%s: running ops ...' %ifacename)
16d854b4
RP
154 if ('down' in ops[0] and
155 ifaceobjs[0].type != ifaceType.BRIDGE_VLAN and
77054f7f 156 ifaceobjs[0].addr_method != 'ppp' and
923290bd 157 not ifupdownobj.link_exists(ifacename)):
525f0a30 158 ifupdownobj.logger.debug('%s: does not exist' %ifacename)
923290bd 159 # run posthook before you get out of here, so that
160 # appropriate cleanup is done
161 posthookfunc = ifupdownobj.sched_hooks.get('posthook')
162 if posthookfunc:
163 for ifaceobj in ifaceobjs:
164 ifaceobj.status = ifaceStatus.SUCCESS
165 posthookfunc(ifupdownobj, ifaceobj, 'down')
d486dd0d 166 return
923290bd 167 for op in ops:
168 # first run ifupdownobj handlers. This is good enough
169 # for the first object in the list
170 handler = ifupdownobj.ops_handlers.get(op)
171 if handler:
a070c90e
RP
172 try:
173 handler(ifupdownobj, ifaceobjs[0])
3b01ed76 174 except Exception as e:
61c4d724 175 if not ifupdownobj.link_master_slave_ignore_error(str(e)):
c46af1c9 176 ifupdownobj.logger.warning('%s: %s'
61c4d724 177 %(ifaceobjs[0].name, str(e)))
a070c90e 178 pass
923290bd 179 for ifaceobj in ifaceobjs:
6e16e5ae 180 cls.run_iface_op(ifupdownobj, ifaceobj, op,
923290bd 181 cenv=ifupdownobj.generate_running_env(ifaceobj, op)
ee3fcf44
RP
182 if ifupdownobj.config.get('addon_scripts_support',
183 '0') == '1' else None)
184 posthookfunc = ifupdownobj.sched_hooks.get('posthook')
185 if posthookfunc:
40ed8c4d
RP
186 try:
187 [posthookfunc(ifupdownobj, ifaceobj, ops[0])
188 for ifaceobj in ifaceobjs]
3b01ed76 189 except Exception as e:
c46af1c9 190 ifupdownobj.logger.warning('%s' %str(e))
40ed8c4d 191 pass
21c7daa7 192
193 @classmethod
fa3da4be 194 def _check_upperifaces(cls, ifupdownobj, ifaceobj, ops, parent,
195 followdependents=False):
99b212b0 196 """ Check if upperifaces are hanging off us and help caller decide
197 if he can proceed with the ops on this device
21c7daa7 198
99b212b0 199 Returns True or False indicating the caller to proceed with the
200 operation.
201 """
86fc62e2 202 # proceed only for down operation
203 if 'down' not in ops[0]:
204 return True
205
dbc018d3
RP
206 if (ifupdownobj.flags.SCHED_SKIP_CHECK_UPPERIFACES):
207 return True
208
fc5e1735 209 if (ifupdownflags.flags.FORCE or
dbc018d3 210 not ifupdownobj.flags.ADDONS_ENABLE or
86fc62e2 211 (not ifupdownobj.is_ifaceobj_noconfig(ifaceobj) and
33e106da 212 ifupdownobj.config.get('warn_on_ifdown', '0') == '0' and
d2b35716 213 not ifupdownflags.flags.ALL)):
99b212b0 214 return True
65c48517 215
62ddec8b 216 ulist = ifaceobj.upperifaces
99b212b0 217 if not ulist:
218 return True
33e106da 219
99b212b0 220 # Get the list of upper ifaces other than the parent
221 tmpulist = ([u for u in ulist if u != parent] if parent
222 else ulist)
223 if not tmpulist:
224 return True
225 # XXX: This is expensive. Find a cheaper way to do this.
226 # if any of the upperdevs are present,
227 # return false to the caller to skip this interface
228 for u in tmpulist:
229 if ifupdownobj.link_exists(u):
d2b35716 230 if not ifupdownflags.flags.ALL:
86fc62e2 231 if ifupdownobj.is_ifaceobj_noconfig(ifaceobj):
232 ifupdownobj.logger.info('%s: skipping interface down,'
233 %ifaceobj.name + ' upperiface %s still around ' %u)
234 else:
c46af1c9 235 ifupdownobj.logger.warning('%s: skipping interface down,'
86fc62e2 236 %ifaceobj.name + ' upperiface %s still around ' %u)
99b212b0 237 return False
21c7daa7 238 return True
239
be0b20f2 240 @classmethod
6e16e5ae
N
241 def run_iface_graph(cls, ifupdownobj, ifacename, ops, parent=None,
242 order=ifaceSchedulerFlags.POSTORDER,
d08d5f54 243 followdependents=True):
6ef5bfa2 244 """ runs interface by traversing all nodes rooted at itself """
245
d08d5f54 246 # Each ifacename can have a list of iface objects
31a5f4c3 247 ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename)
248 if not ifaceobjs:
d08d5f54 249 raise Exception('%s: not found' %ifacename)
a6f80f0e 250
a070c90e
RP
251 # Check state of the dependent. If it is already brought up, return
252 if (cls._STATE_CHECK and
253 (ifaceobjs[0].state == ifaceState.from_str(ops[-1]))):
254 ifupdownobj.logger.debug('%s: already processed' %ifacename)
255 return
256
d08d5f54 257 for ifaceobj in ifaceobjs:
ca3f4fc7 258 if not cls._check_upperifaces(ifupdownobj, ifaceobj,
259 ops, parent, followdependents):
a070c90e 260 return
f3215127 261
923290bd 262 # If inorder, run the iface first and then its dependents
263 if order == ifaceSchedulerFlags.INORDER:
6e16e5ae 264 cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
923290bd 265
266 for ifaceobj in ifaceobjs:
f3215127 267 # Run lowerifaces or dependents
62ddec8b 268 dlist = ifaceobj.lowerifaces
f3215127 269 if dlist:
223ba5af
JF
270
271 if ifaceobj.link_kind == ifaceLinkKind.VRF:
272 # remove non-auto lowerifaces from 'dlist'
273 for lower_ifname in list(dlist):
274 for lower_ifaceobj in ifupdownobj.get_ifaceobjs(lower_ifname) or []:
275 if lower_ifaceobj and not lower_ifaceobj.auto and ifaceobj.name == cls.VRF_MGMT_DEVNAME:
276 dlist.remove(lower_ifname)
277
fa3da4be 278 ifupdownobj.logger.debug('%s: found dependents %s'
279 %(ifacename, str(dlist)))
d08d5f54 280 try:
281 if not followdependents:
282 # XXX: this is yet another extra step,
283 # but is needed for interfaces that are
f3215127 284 # implicit dependents. even though we are asked to
285 # not follow dependents, we must follow the ones
286 # that dont have user given config. Because we own them
d08d5f54 287 new_dlist = [d for d in dlist
923290bd 288 if ifupdownobj.is_iface_noconfig(d)]
6ef5bfa2 289 if new_dlist:
be0b20f2 290 cls.run_iface_list(ifupdownobj, new_dlist, ops,
6e16e5ae 291 ifacename, order, followdependents,
923290bd 292 continueonfailure=False)
d08d5f54 293 else:
be0b20f2 294 cls.run_iface_list(ifupdownobj, dlist, ops,
6e16e5ae 295 ifacename, order,
f3215127 296 followdependents,
6ef5bfa2 297 continueonfailure=False)
3b01ed76 298 except Exception as e:
be0b20f2 299 if (ifupdownobj.ignore_error(str(e))):
d08d5f54 300 pass
301 else:
302 # Dont bring the iface up if children did not come up
a690dfae 303 ifaceobj.set_state_n_status(ifaceState.NEW,
923290bd 304 ifaceStatus.ERROR)
d08d5f54 305 raise
923290bd 306 if order == ifaceSchedulerFlags.POSTORDER:
6e16e5ae 307 cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
a6f80f0e 308
be0b20f2 309 @classmethod
6e16e5ae
N
310 def run_iface_list(cls, ifupdownobj, ifacenames,
311 ops, parent=None, order=ifaceSchedulerFlags.POSTORDER,
6ef5bfa2 312 followdependents=True, continueonfailure=True):
d08d5f54 313 """ Runs interface list """
6e16e5ae 314
d08d5f54 315 for ifacename in ifacenames:
a6f80f0e 316 try:
6e16e5ae
N
317 cls.run_iface_graph(ifupdownobj, ifacename, ops, parent,
318 order, followdependents)
3b01ed76 319 except Exception as e:
6ef5bfa2 320 if continueonfailure:
69f58278 321 if ifupdownobj.logger.isEnabledFor(logging.DEBUG):
322 traceback.print_tb(sys.exc_info()[2])
be0b20f2 323 ifupdownobj.logger.error('%s : %s' %(ifacename, str(e)))
d08d5f54 324 pass
325 else:
be0b20f2 326 if (ifupdownobj.ignore_error(str(e))):
6ef5bfa2 327 pass
328 else:
9dce3561 329 raise Exception('%s : (%s)' %(ifacename, str(e)))
d08d5f54 330
be0b20f2 331 @classmethod
c798b0f4 332 def run_iface_graph_upper(cls, ifupdownobj, ifacename, ops, parent=None,
333 followdependents=True, skip_root=False):
334 """ runs interface by traversing all nodes rooted at itself """
335
336 # Each ifacename can have a list of iface objects
337 ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename)
338 if not ifaceobjs:
339 raise Exception('%s: not found' %ifacename)
340
a070c90e
RP
341 if (cls._STATE_CHECK and
342 (ifaceobjs[0].state == ifaceState.from_str(ops[-1]))):
343 ifupdownobj.logger.debug('%s: already processed' %ifacename)
344 return
345
923290bd 346 if not skip_root:
347 # run the iface first and then its upperifaces
6e16e5ae 348 cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
c798b0f4 349 for ifaceobj in ifaceobjs:
c798b0f4 350 # Run upperifaces
62ddec8b 351 ulist = ifaceobj.upperifaces
c798b0f4 352 if ulist:
fa3da4be 353 ifupdownobj.logger.debug('%s: found upperifaces %s'
354 %(ifacename, str(ulist)))
c798b0f4 355 try:
356 cls.run_iface_list_upper(ifupdownobj, ulist, ops,
357 ifacename,
358 followdependents,
359 continueonfailure=True)
3b01ed76 360 except Exception as e:
c798b0f4 361 if (ifupdownobj.ignore_error(str(e))):
362 pass
363 else:
364 raise
365
366 @classmethod
367 def run_iface_list_upper(cls, ifupdownobj, ifacenames,
368 ops, parent=None, followdependents=True,
369 continueonfailure=True, skip_root=False):
370 """ Runs interface list """
371
372 for ifacename in ifacenames:
373 try:
374 cls.run_iface_graph_upper(ifupdownobj, ifacename, ops, parent,
375 followdependents, skip_root)
3b01ed76 376 except Exception as e:
09a304ca
RP
377 if ifupdownobj.logger.isEnabledFor(logging.DEBUG):
378 traceback.print_tb(sys.exc_info()[2])
c46af1c9 379 ifupdownobj.logger.warning('%s : %s' %(ifacename, str(e)))
09a304ca 380 pass
c798b0f4 381
a9ab1b4f
RP
382 @classmethod
383 def _get_valid_upperifaces(cls, ifupdownobj, ifacenames,
384 allupperifacenames):
385 """ Recursively find valid upperifaces
386
387 valid upperifaces are:
388 - An upperiface which had no user config (example builtin
389 interfaces. usually vlan interfaces.)
390 - or had config and previously up
391 - and interface currently does not exist
392 - or is a bridge (because if your upperiface was a bridge
393 - u will have to execute up on the bridge
394 to enslave the port and apply bridge attributes to the port) """
395
396 upperifacenames = []
397 for ifacename in ifacenames:
398 # get upperifaces
399 ifaceobj = ifupdownobj.get_ifaceobj_first(ifacename)
400 if not ifaceobj:
401 continue
6f89e489 402 ulist = set(ifaceobj.upperifaces or []).difference(upperifacenames)
a9ab1b4f
RP
403 nulist = []
404 for u in ulist:
405 uifaceobj = ifupdownobj.get_ifaceobj_first(u)
406 if not uifaceobj:
407 continue
dbc018d3
RP
408 has_config = not (uifaceobj.priv_flags and
409 uifaceobj.priv_flags.NOCONFIG)
a9ab1b4f
RP
410 if (((has_config and ifupdownobj.get_ifaceobjs_saved(u)) or
411 not has_config) and (not ifupdownobj.link_exists(u)
65e0c276
RP
412 # Do this always for a bridge. Note that this is
413 # not done for a vlan aware bridge because,
414 # in the vlan aware bridge case, the bridge module
415 # applies the bridge port configuration on the port
416 # when up is scheduled on the port.
417 or (uifaceobj.link_kind == ifaceLinkKind.BRIDGE))):
a9ab1b4f
RP
418 nulist.append(u)
419 upperifacenames.extend(nulist)
420 allupperifacenames.extend(upperifacenames)
421 if upperifacenames:
422 cls._get_valid_upperifaces(ifupdownobj, upperifacenames,
423 allupperifacenames)
424 return
425
426 @classmethod
427 def run_upperifaces(cls, ifupdownobj, ifacenames, ops,
428 continueonfailure=True):
d486dd0d 429 """ Run through valid upperifaces """
a9ab1b4f
RP
430 upperifaces = []
431
432 cls._get_valid_upperifaces(ifupdownobj, ifacenames, upperifaces)
433 if not upperifaces:
434 return
435 # dump valid upperifaces
436 ifupdownobj.logger.debug(upperifaces)
437 for u in upperifaces:
438 try:
439 ifaceobjs = ifupdownobj.get_ifaceobjs(u)
440 if not ifaceobjs:
441 continue
6e16e5ae 442 cls.run_iface_list_ops(ifupdownobj, ifaceobjs, ops)
3b01ed76 443 except Exception as e:
a9ab1b4f 444 if continueonfailure:
c46af1c9 445 ifupdownobj.logger.warning('%s' %str(e))
a9ab1b4f 446
54ebaf3e
RP
447 @classmethod
448 def _dump_dependency_info(cls, ifupdownobj, ifacenames,
449 dependency_graph=None, indegrees=None):
450 ifupdownobj.logger.info('{\n')
451 ifupdownobj.logger.info('\nifaceobjs:')
452 for iname in ifacenames:
3b01ed76
JF
453 iobjs = ifupdownobj.get_ifaceobjs(iname)
454 for iobj in iobjs:
455 iobj.dump(ifupdownobj.logger)
54ebaf3e
RP
456 if (dependency_graph):
457 ifupdownobj.logger.info('\nDependency Graph:')
458 ifupdownobj.logger.info(dependency_graph)
3b01ed76
JF
459 if (indegrees):
460 ifupdownobj.logger.info('\nIndegrees:')
461 ifupdownobj.logger.info(indegrees)
462 ifupdownobj.logger.info('}\n')
54ebaf3e 463
5ee3e1a8
RP
464 @classmethod
465 def get_sorted_iface_list(cls, ifupdownobj, ifacenames, ops,
466 dependency_graph, indegrees=None):
467 if len(ifacenames) == 1:
468 return ifacenames
469 # Get a sorted list of all interfaces
470 if not indegrees:
471 indegrees = OrderedDict()
3b01ed76 472 for ifacename in list(dependency_graph.keys()):
5ee3e1a8 473 indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
54ebaf3e
RP
474
475 #cls._dump_dependency_info(ifupdownobj, ifacenames,
476 # dependency_graph, indegrees)
477
5ee3e1a8
RP
478 ifacenames_all_sorted = graph.topological_sort_graphs_all(
479 dependency_graph, indegrees)
480 # if ALL was set, return all interfaces
d2b35716 481 if ifupdownflags.flags.ALL:
5ee3e1a8
RP
482 return ifacenames_all_sorted
483
484 # else return ifacenames passed as argument in sorted order
485 ifacenames_sorted = []
486 [ifacenames_sorted.append(ifacename)
487 for ifacename in ifacenames_all_sorted
488 if ifacename in ifacenames]
489 return ifacenames_sorted
490
c798b0f4 491 @classmethod
6e16e5ae 492 def sched_ifaces(cls, ifupdownobj, ifacenames, ops,
c798b0f4 493 dependency_graph=None, indegrees=None,
d08d5f54 494 order=ifaceSchedulerFlags.POSTORDER,
e308cb82 495 followdependents=True, skipupperifaces=False, sort=False):
2c0ad8b3
RP
496 """ runs interface configuration modules on interfaces passed as
497 argument. Runs topological sort on interface dependency graph.
498
499 Args:
d486dd0d 500 **ifupdownobj** (object): ifupdownMain object
904908bc
RP
501
502 **ifacenames** (list): list of interface names
503
504 **ops** : list of operations to perform eg ['pre-up', 'up', 'post-up']
505
506 **dependency_graph** (dict): dependency graph in adjacency list format
2c0ad8b3
RP
507
508 Kwargs:
904908bc
RP
509 **indegrees** (dict): indegree array of the dependency graph
510
511 **order** (int): ifaceSchedulerFlags (POSTORDER, INORDER)
512
513 **followdependents** (bool): follow dependent interfaces if true
2c0ad8b3 514
e308cb82
RP
515 **sort** (bool): sort ifacelist in the case where ALL is not set
516
d08d5f54 517 """
5ee3e1a8
RP
518 #
519 # Algo:
520 # if ALL/auto interfaces are specified,
521 # - walk the dependency tree in postorder or inorder depending
522 # on the operation.
523 # (This is to run interfaces correctly in order)
524 # else:
525 # - sort iface list if the ifaces belong to a "class"
526 # - else just run iface list in the order they were specified
527 #
528 # Run any upperifaces if available
529 #
8c13865c 530 followupperifaces = False
5ee3e1a8
RP
531 run_queue = []
532 skip_ifacesort = int(ifupdownobj.config.get('skip_ifacesort', '0'))
533 if not skip_ifacesort and not indegrees:
534 indegrees = OrderedDict()
3b01ed76 535 for ifacename in list(dependency_graph.keys()):
5ee3e1a8 536 indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
c798b0f4 537
d2b35716 538 if not ifupdownflags.flags.ALL:
e308cb82
RP
539 if 'up' in ops[0]:
540 # If there is any interface that does not exist, maybe it
541 # is a logical interface and we have to followupperifaces
542 # when it comes up, so lets get that list.
543 if any([True for i in ifacenames
544 if ifupdownobj.must_follow_upperifaces(i)]):
545 followupperifaces = (True if
ca3f4fc7 546 [i for i in ifacenames
923290bd 547 if not ifupdownobj.link_exists(i)]
548 else False)
e308cb82
RP
549 # sort interfaces only if the caller asked to sort
550 # and skip_ifacesort is not on.
551 if not skip_ifacesort and sort:
5ee3e1a8
RP
552 run_queue = cls.get_sorted_iface_list(ifupdownobj, ifacenames,
553 ops, dependency_graph, indegrees)
554 if run_queue and 'up' in ops[0]:
555 run_queue.reverse()
ba7b1d60 556 else:
e308cb82
RP
557 # if -a is set, we pick the interfaces
558 # that have no parents and use a sorted list of those
5ee3e1a8
RP
559 if not skip_ifacesort:
560 sorted_ifacenames = cls.get_sorted_iface_list(ifupdownobj,
561 ifacenames, ops, dependency_graph,
562 indegrees)
563 if sorted_ifacenames:
564 # pick interfaces that user asked
565 # and those that dont have any dependents first
566 [run_queue.append(ifacename)
567 for ifacename in sorted_ifacenames
568 if ifacename in ifacenames and
569 not indegrees.get(ifacename)]
570 ifupdownobj.logger.debug('graph roots (interfaces that ' +
571 'dont have dependents):' + ' %s' %str(run_queue))
572 else:
c46af1c9 573 ifupdownobj.logger.warning('interface sort returned None')
5ee3e1a8 574
e308cb82
RP
575 # If queue not present, just run interfaces that were asked by the
576 # user
5ee3e1a8
RP
577 if not run_queue:
578 run_queue = list(ifacenames)
e308cb82
RP
579 # if we are taking the order of interfaces as specified
580 # in the interfaces file, we should reverse the list if we
581 # want to down. This can happen if 'skip_ifacesort'
582 # is been specified.
5ee3e1a8
RP
583 if 'down' in ops[0]:
584 run_queue.reverse()
585
586 # run interface list
6e16e5ae 587 cls.run_iface_list(ifupdownobj, run_queue, ops,
5ee3e1a8
RP
588 parent=None, order=order,
589 followdependents=followdependents)
892c495e 590 if not cls.get_sched_status():
2009513f 591 return
09a304ca 592
ad25e7bb
RP
593 if (not skipupperifaces and
594 ifupdownobj.config.get('skip_upperifaces', '0') == '0' and
d2b35716 595 ((not ifupdownflags.flags.ALL and followdependents) or
d486dd0d 596 followupperifaces) and
5ee3e1a8
RP
597 'up' in ops[0]):
598 # If user had given a set of interfaces to bring up
599 # try and execute 'up' on the upperifaces
09a304ca
RP
600 ifupdownobj.logger.info('running upperifaces (parent interfaces) ' +
601 'if available ..')
892c495e 602 try:
3fb52fa3
RP
603 # upperiface bring up is best effort.
604 # eg case: if we are bringing up a bridge port
605 # this section does an 'ifup on the bridge'
606 # so that the recently up'ed bridge port gets enslaved
607 # to the bridge. But the up on the bridge may
608 # throw out more errors if the bridge is not
609 # in the correct state. Lets not surprise
610 # the user with such errors when he has
611 # only requested to bring up the bridge port.
892c495e 612 cls._STATE_CHECK = False
3fb52fa3 613 ifupdownflags.flags.IGNORE_ERRORS = True
892c495e 614 cls.run_upperifaces(ifupdownobj, ifacenames, ops)
892c495e 615 finally:
3fb52fa3
RP
616 ifupdownflags.flags.IGNORE_ERRORS = False
617 cls._STATE_CHECK = True
892c495e
RP
618 # upperiface bringup is best effort, so dont propagate errors
619 # reset scheduler status to True
620 cls.set_sched_status(True)