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