]> git.proxmox.com Git - mirror_ifupdown2.git/blame - pkg/scheduler.py
support json input + multiple instance running check
[mirror_ifupdown2.git] / pkg / scheduler.py
CommitLineData
a6f80f0e 1#!/usr/bin/python
3e8ee54f 2#
3# Copyright 2013. Cumulus Networks, Inc.
4# Author: Roopa Prabhu, roopa@cumulusnetworks.com
5#
6# ifaceScheduler --
7# interface scheduler
8#
a6f80f0e 9
a6f80f0e 10from statemanager import *
11from iface import *
12from graph import *
13from collections import deque
14from collections import OrderedDict
a6f80f0e 15import logging
d08d5f54 16import traceback
69f58278 17import sys
a6f80f0e 18from graph import *
19from collections import deque
20from threading import *
21from ifupdownbase import *
22
d08d5f54 23class ifaceSchedulerFlags():
c798b0f4 24 INORDER = 0x1
25 POSTORDER = 0x2
d08d5f54 26
be0b20f2 27class ifaceScheduler():
28 """ scheduler functions to schedule configuration of interfaces.
a6f80f0e 29
a6f80f0e 30 supports scheduling of interfaces serially in plain interface list
31 or dependency graph format.
32 """
33
c798b0f4 34 _STATE_CHECK = True
35
be0b20f2 36 token_pool = None
d08d5f54 37
be0b20f2 38 @classmethod
39 def run_iface_op(cls, ifupdownobj, ifaceobj, op, cenv):
a6f80f0e 40 """ Runs sub operation on an interface """
62ddec8b 41 ifacename = ifaceobj.name
a6f80f0e 42
c798b0f4 43 if (cls._STATE_CHECK and
62ddec8b 44 (ifaceobj.state >= ifaceState.from_str(op)) and
45 (ifaceobj.status == ifaceStatus.SUCCESS)):
be0b20f2 46 ifupdownobj.logger.debug('%s: already in state %s' %(ifacename, op))
d08d5f54 47 return
a6f80f0e 48
be0b20f2 49 # first run ifupdownobj handlers
50 handler = ifupdownobj.ops_handlers.get(op)
51 if handler:
62ddec8b 52 if not ifaceobj.addr_method or (ifaceobj.addr_method and
53 ifaceobj.addr_method != 'manual'):
be0b20f2 54 handler(ifupdownobj, ifaceobj)
55
20dd6242 56 if not ifupdownobj.ADDONS_ENABLE: return
57
be0b20f2 58 for mname in ifupdownobj.module_ops.get(op):
37c0543d 59 m = ifupdownobj.modules.get(mname)
a6f80f0e 60 err = 0
61 try:
d08d5f54 62 if hasattr(m, 'run'):
a690dfae 63 msg = ('%s: %s : running module %s' %(ifacename, op, mname))
739f665b 64 if op == 'query-checkcurr':
d08d5f54 65 # Dont check curr if the interface object was
37c0543d 66 # auto generated
d08d5f54 67 if (ifaceobj.priv_flags & ifupdownobj.NOCONFIG):
37c0543d 68 continue
a690dfae 69 ifupdownobj.logger.debug(msg)
d08d5f54 70 m.run(ifaceobj, op,
71 query_ifaceobj=ifupdownobj.create_n_save_ifaceobjcurr(ifaceobj))
a6f80f0e 72 else:
a690dfae 73 ifupdownobj.logger.debug(msg)
d08d5f54 74 m.run(ifaceobj, op)
a6f80f0e 75 except Exception, e:
76 err = 1
be0b20f2 77 ifupdownobj.log_error(str(e))
a6f80f0e 78 finally:
31a5f4c3 79 if err:
80 ifaceobj.set_state_n_status(ifaceState.from_str(op),
81 ifaceStatus.ERROR)
d08d5f54 82 else:
31a5f4c3 83 ifaceobj.set_state_n_status(ifaceState.from_str(op),
84 ifaceStatus.SUCCESS)
6bd7fc74 85
86 if ifupdownobj.COMPAT_EXEC_SCRIPTS:
87 # execute /etc/network/ scripts
88 for mname in ifupdownobj.script_ops.get(op, []):
89 ifupdownobj.logger.debug('%s: %s : running script %s'
d08d5f54 90 %(ifacename, op, mname))
6bd7fc74 91 try:
92 ifupdownobj.exec_command(mname, cmdenv=cenv)
93 except Exception, e:
94 ifupdownobj.log_error(str(e))
37c0543d 95
be0b20f2 96 @classmethod
97 def run_iface_ops(cls, ifupdownobj, ifaceobj, ops):
31a5f4c3 98 """ Runs all operations on an interface """
62ddec8b 99 ifacename = ifaceobj.name
a690dfae 100 # minor optimization. If operation is 'down', proceed only
101 # if interface exists in the system
102 if 'down' in ops[0] and not ifupdownobj.link_exists(ifacename):
525f0a30 103 ifupdownobj.logger.debug('%s: does not exist' %ifacename)
a690dfae 104 return
6bd7fc74 105 cenv=None
6bd7fc74 106 if ifupdownobj.COMPAT_EXEC_SCRIPTS:
107 # For backward compatibility generate env variables
108 # for attributes
109 cenv = ifupdownobj.generate_running_env(ifaceobj, ops[0])
6bd7fc74 110 map(lambda op: cls.run_iface_op(ifupdownobj, ifaceobj, op, cenv), ops)
31a5f4c3 111 posthookfunc = ifupdownobj.sched_hooks.get('posthook')
112 if posthookfunc:
cb7cc592 113 posthookfunc(ifupdownobj, ifaceobj, ops[0])
21c7daa7 114
115 @classmethod
fa3da4be 116 def _check_upperifaces(cls, ifupdownobj, ifaceobj, ops, parent,
117 followdependents=False):
21c7daa7 118 """ Check if conflicting upper ifaces are around and warn if required
119
ca3f4fc7 120 Returns False if this interface needs to be skipped,
121 else return True """
122
123 # XXX: simply return for now, the warnings this function prints
124 # are very confusing. Get rid of this function soon
125 return True
21c7daa7 126
c798b0f4 127 if 'up' in ops[0] and followdependents:
128 return True
129
21c7daa7 130 # Deal with upperdevs first
62ddec8b 131 ulist = ifaceobj.upperifaces
21c7daa7 132 if ulist:
133 tmpulist = ([u for u in ulist if u != parent] if parent
134 else ulist)
135 if not tmpulist:
21c7daa7 136 return True
137 if 'down' in ops[0]:
138 # XXX: This is expensive. Find a cheaper way to do this
139 # if any of the upperdevs are present,
140 # dont down this interface
141 for u in tmpulist:
142 if ifupdownobj.link_exists(u):
143 if not ifupdownobj.FORCE and not ifupdownobj.ALL:
fa3da4be 144 ifupdownobj.logger.warn('%s: ' %ifaceobj.name +
145 'upperiface %s still around' %u)
146 return True
21c7daa7 147 elif 'up' in ops[0] and not ifupdownobj.ALL:
148 # For 'up', just warn that there is an upperdev which is
149 # probably not up
150 for u in tmpulist:
151 if not ifupdownobj.link_exists(u):
fa3da4be 152 ifupdownobj.logger.warn('%s: ' %ifaceobj.name +
153 'upper iface %s does not exist' %u)
21c7daa7 154 return True
155
be0b20f2 156 @classmethod
157 def run_iface_graph(cls, ifupdownobj, ifacename, ops, parent=None,
d08d5f54 158 order=ifaceSchedulerFlags.POSTORDER,
159 followdependents=True):
6ef5bfa2 160 """ runs interface by traversing all nodes rooted at itself """
161
d08d5f54 162 # Each ifacename can have a list of iface objects
31a5f4c3 163 ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename)
164 if not ifaceobjs:
d08d5f54 165 raise Exception('%s: not found' %ifacename)
a6f80f0e 166
d08d5f54 167 for ifaceobj in ifaceobjs:
ca3f4fc7 168 if not cls._check_upperifaces(ifupdownobj, ifaceobj,
169 ops, parent, followdependents):
21c7daa7 170 return
d08d5f54 171 if order == ifaceSchedulerFlags.INORDER:
f3215127 172 # If inorder, run the iface first and then its dependents
be0b20f2 173 cls.run_iface_ops(ifupdownobj, ifaceobj, ops)
f3215127 174
175 # Run lowerifaces or dependents
62ddec8b 176 dlist = ifaceobj.lowerifaces
f3215127 177 if dlist:
fa3da4be 178 ifupdownobj.logger.debug('%s: found dependents %s'
179 %(ifacename, str(dlist)))
d08d5f54 180 try:
181 if not followdependents:
182 # XXX: this is yet another extra step,
183 # but is needed for interfaces that are
f3215127 184 # implicit dependents. even though we are asked to
185 # not follow dependents, we must follow the ones
186 # that dont have user given config. Because we own them
d08d5f54 187 new_dlist = [d for d in dlist
188 if ifupdownobj.is_iface_noconfig(d)]
6ef5bfa2 189 if new_dlist:
be0b20f2 190 cls.run_iface_list(ifupdownobj, new_dlist, ops,
f3215127 191 ifacename, order,
192 followdependents,
6ef5bfa2 193 continueonfailure=False)
d08d5f54 194 else:
be0b20f2 195 cls.run_iface_list(ifupdownobj, dlist, ops,
f3215127 196 ifacename, order,
197 followdependents,
6ef5bfa2 198 continueonfailure=False)
d08d5f54 199 except Exception, e:
be0b20f2 200 if (ifupdownobj.ignore_error(str(e))):
d08d5f54 201 pass
202 else:
203 # Dont bring the iface up if children did not come up
a690dfae 204 ifaceobj.set_state_n_status(ifaceState.NEW,
205 ifaceStatus.ERROR)
d08d5f54 206 raise
d08d5f54 207 if order == ifaceSchedulerFlags.POSTORDER:
be0b20f2 208 cls.run_iface_ops(ifupdownobj, ifaceobj, ops)
a6f80f0e 209
be0b20f2 210 @classmethod
211 def run_iface_list(cls, ifupdownobj, ifacenames,
f3215127 212 ops, parent=None, order=ifaceSchedulerFlags.POSTORDER,
6ef5bfa2 213 followdependents=True, continueonfailure=True):
d08d5f54 214 """ Runs interface list """
a6f80f0e 215
d08d5f54 216 for ifacename in ifacenames:
a6f80f0e 217 try:
be0b20f2 218 cls.run_iface_graph(ifupdownobj, ifacename, ops, parent,
d08d5f54 219 order, followdependents)
a6f80f0e 220 except Exception, e:
6ef5bfa2 221 if continueonfailure:
69f58278 222 if ifupdownobj.logger.isEnabledFor(logging.DEBUG):
223 traceback.print_tb(sys.exc_info()[2])
be0b20f2 224 ifupdownobj.logger.error('%s : %s' %(ifacename, str(e)))
d08d5f54 225 pass
226 else:
be0b20f2 227 if (ifupdownobj.ignore_error(str(e))):
6ef5bfa2 228 pass
229 else:
9dce3561 230 raise Exception('%s : (%s)' %(ifacename, str(e)))
d08d5f54 231
be0b20f2 232 @classmethod
c798b0f4 233 def run_iface_graph_upper(cls, ifupdownobj, ifacename, ops, parent=None,
234 followdependents=True, skip_root=False):
235 """ runs interface by traversing all nodes rooted at itself """
236
237 # Each ifacename can have a list of iface objects
238 ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename)
239 if not ifaceobjs:
240 raise Exception('%s: not found' %ifacename)
241
242 for ifaceobj in ifaceobjs:
243 if not skip_root:
244 # run the iface first and then its upperifaces
245 cls.run_iface_ops(ifupdownobj, ifaceobj, ops)
246
247 # Run upperifaces
62ddec8b 248 ulist = ifaceobj.upperifaces
c798b0f4 249 if ulist:
fa3da4be 250 ifupdownobj.logger.debug('%s: found upperifaces %s'
251 %(ifacename, str(ulist)))
c798b0f4 252 try:
253 cls.run_iface_list_upper(ifupdownobj, ulist, ops,
254 ifacename,
255 followdependents,
256 continueonfailure=True)
257 except Exception, e:
258 if (ifupdownobj.ignore_error(str(e))):
259 pass
260 else:
261 raise
262
263 @classmethod
264 def run_iface_list_upper(cls, ifupdownobj, ifacenames,
265 ops, parent=None, followdependents=True,
266 continueonfailure=True, skip_root=False):
267 """ Runs interface list """
268
269 for ifacename in ifacenames:
270 try:
271 cls.run_iface_graph_upper(ifupdownobj, ifacename, ops, parent,
272 followdependents, skip_root)
273 except Exception, e:
274 if continueonfailure:
275 if ifupdownobj.logger.isEnabledFor(logging.DEBUG):
276 traceback.print_tb(sys.exc_info()[2])
277 ifupdownobj.logger.error('%s : %s' %(ifacename, str(e)))
278 pass
279 else:
280 if (ifupdownobj.ignore_error(str(e))):
281 pass
282 else:
9dce3561 283 raise Exception('%s : (%s)' %(ifacename, str(e)))
c798b0f4 284
285 @classmethod
286 def sched_ifaces(cls, ifupdownobj, ifacenames, ops,
287 dependency_graph=None, indegrees=None,
d08d5f54 288 order=ifaceSchedulerFlags.POSTORDER,
289 followdependents=True):
290 """ Runs iface dependeny graph by visiting all the nodes
291
292 Parameters:
293 -----------
294 ifupdownobj : ifupdown object (used for getting and updating iface
295 object state)
296 dependency_graph : dependency graph in adjacency list
297 format (contains more than one dependency graph)
298 ops : list of operations to perform eg ['pre-up', 'up', 'post-up']
299
300 indegrees : indegree array if present is used to determine roots
301 of the graphs in the dependency_graph
302 """
c798b0f4 303
304 if not ifupdownobj.ALL or not followdependents or len(ifacenames) == 1:
ca3f4fc7 305 # If there is any interface that does exist, maybe it is a
306 # logical interface and we have to followupperifaces
307 followupperifaces = (True if
308 [i for i in ifacenames
309 if not ifupdownobj.link_exists(i)]
310 else False)
c798b0f4 311 cls.run_iface_list(ifupdownobj, ifacenames, ops,
312 parent=None,order=order,
313 followdependents=followdependents)
ca3f4fc7 314 if (not ifupdownobj.ALL and
315 (followdependents or followupperifaces) and 'up' in ops[0]):
c798b0f4 316 # If user had given a set of interfaces to bring up
317 # try and execute 'up' on the upperifaces
318 ifupdownobj.logger.info('running upperifaces if available')
319 cls._STATE_CHECK = False
320 cls.run_iface_list_upper(ifupdownobj, ifacenames, ops,
321 skip_root=True)
322 cls._STATE_CHECK = True
323 return
d08d5f54 324 run_queue = []
f3215127 325
c798b0f4 326 # Get a sorted list of all interfaces
20dd6242 327 if not indegrees:
f3215127 328 indegrees = OrderedDict()
d08d5f54 329 for ifacename in dependency_graph.keys():
f3215127 330 indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename)
f3215127 331 sorted_ifacenames = graph.topological_sort_graphs_all(dependency_graph,
332 dict(indegrees))
be0b20f2 333 ifupdownobj.logger.debug('sorted ifacenames %s : '
334 %str(sorted_ifacenames))
f3215127 335
c798b0f4 336 # From the sorted list, pick interfaces that user asked
337 # and those that dont have any dependents first
338 [run_queue.append(ifacename)
339 for ifacename in sorted_ifacenames
340 if ifacename in ifacenames and
341 not indegrees.get(ifacename)]
d08d5f54 342
20dd6242 343 ifupdownobj.logger.debug('graph roots (interfaces that dont have '
344 'dependents):' + ' %s' %str(run_queue))
c798b0f4 345 cls.run_iface_list(ifupdownobj, run_queue, ops,
be0b20f2 346 parent=None,order=order,
347 followdependents=followdependents)