]>
Commit | Line | Data |
---|---|---|
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 | 10 | from statemanager import * |
11 | from iface import * | |
12 | from graph import * | |
13 | from collections import deque | |
14 | from collections import OrderedDict | |
a6f80f0e | 15 | import logging |
d08d5f54 | 16 | import traceback |
69f58278 | 17 | import sys |
a6f80f0e | 18 | from graph import * |
19 | from collections import deque | |
20 | from threading import * | |
21 | from ifupdownbase import * | |
22 | ||
d08d5f54 | 23 | class ifaceSchedulerFlags(): |
c798b0f4 | 24 | INORDER = 0x1 |
25 | POSTORDER = 0x2 | |
d08d5f54 | 26 | |
be0b20f2 | 27 | class 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): | |
103 | ifupdownobj.logger.info('%s: does not exist' %ifacename) | |
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: | |
113 | posthookfunc(ifupdownobj, ifaceobj) | |
a6f80f0e | 114 | |
21c7daa7 | 115 | |
116 | @classmethod | |
c798b0f4 | 117 | def _check_upperifaces(cls, ifupdownobj, ifaceobj, ops, parent, followdependents=False): |
21c7daa7 | 118 | """ Check if conflicting upper ifaces are around and warn if required |
119 | ||
120 | Returns False if this interface needs to be skipped, else return True """ | |
121 | ||
c798b0f4 | 122 | if 'up' in ops[0] and followdependents: |
123 | return True | |
124 | ||
62ddec8b | 125 | ifacename = ifaceobj.name |
21c7daa7 | 126 | # Deal with upperdevs first |
62ddec8b | 127 | ulist = ifaceobj.upperifaces |
21c7daa7 | 128 | if ulist: |
129 | tmpulist = ([u for u in ulist if u != parent] if parent | |
130 | else ulist) | |
131 | if not tmpulist: | |
21c7daa7 | 132 | return True |
133 | if 'down' in ops[0]: | |
134 | # XXX: This is expensive. Find a cheaper way to do this | |
135 | # if any of the upperdevs are present, | |
136 | # dont down this interface | |
137 | for u in tmpulist: | |
138 | if ifupdownobj.link_exists(u): | |
139 | if not ifupdownobj.FORCE and not ifupdownobj.ALL: | |
140 | ifupdownobj.logger.warn('%s: ' %ifacename + | |
141 | ' skip interface down,' + | |
142 | ' upperiface %s still around' %u) | |
143 | return False | |
144 | elif 'up' in ops[0] and not ifupdownobj.ALL: | |
145 | # For 'up', just warn that there is an upperdev which is | |
146 | # probably not up | |
147 | for u in tmpulist: | |
148 | if not ifupdownobj.link_exists(u): | |
149 | ifupdownobj.logger.warn('%s: upper iface %s ' | |
150 | %(ifacename, u) + 'does not exist') | |
151 | return True | |
152 | ||
be0b20f2 | 153 | @classmethod |
154 | def run_iface_graph(cls, ifupdownobj, ifacename, ops, parent=None, | |
d08d5f54 | 155 | order=ifaceSchedulerFlags.POSTORDER, |
156 | followdependents=True): | |
6ef5bfa2 | 157 | """ runs interface by traversing all nodes rooted at itself """ |
158 | ||
d08d5f54 | 159 | # Each ifacename can have a list of iface objects |
31a5f4c3 | 160 | ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename) |
161 | if not ifaceobjs: | |
d08d5f54 | 162 | raise Exception('%s: not found' %ifacename) |
a6f80f0e | 163 | |
d08d5f54 | 164 | for ifaceobj in ifaceobjs: |
c798b0f4 | 165 | if not cls._check_upperifaces(ifupdownobj, ifaceobj, ops, parent, |
166 | followdependents): | |
21c7daa7 | 167 | return |
d08d5f54 | 168 | if order == ifaceSchedulerFlags.INORDER: |
f3215127 | 169 | # If inorder, run the iface first and then its dependents |
be0b20f2 | 170 | cls.run_iface_ops(ifupdownobj, ifaceobj, ops) |
f3215127 | 171 | |
172 | # Run lowerifaces or dependents | |
62ddec8b | 173 | dlist = ifaceobj.lowerifaces |
f3215127 | 174 | if dlist: |
20dd6242 | 175 | ifupdownobj.logger.debug('%s:' %ifacename + |
d08d5f54 | 176 | ' found dependents: %s' %str(dlist)) |
177 | try: | |
178 | if not followdependents: | |
179 | # XXX: this is yet another extra step, | |
180 | # but is needed for interfaces that are | |
f3215127 | 181 | # implicit dependents. even though we are asked to |
182 | # not follow dependents, we must follow the ones | |
183 | # that dont have user given config. Because we own them | |
d08d5f54 | 184 | new_dlist = [d for d in dlist |
185 | if ifupdownobj.is_iface_noconfig(d)] | |
6ef5bfa2 | 186 | if new_dlist: |
be0b20f2 | 187 | cls.run_iface_list(ifupdownobj, new_dlist, ops, |
f3215127 | 188 | ifacename, order, |
189 | followdependents, | |
6ef5bfa2 | 190 | continueonfailure=False) |
d08d5f54 | 191 | else: |
be0b20f2 | 192 | cls.run_iface_list(ifupdownobj, dlist, ops, |
f3215127 | 193 | ifacename, order, |
194 | followdependents, | |
6ef5bfa2 | 195 | continueonfailure=False) |
d08d5f54 | 196 | except Exception, e: |
be0b20f2 | 197 | if (ifupdownobj.ignore_error(str(e))): |
d08d5f54 | 198 | pass |
199 | else: | |
200 | # Dont bring the iface up if children did not come up | |
a690dfae | 201 | ifaceobj.set_state_n_status(ifaceState.NEW, |
202 | ifaceStatus.ERROR) | |
d08d5f54 | 203 | raise |
d08d5f54 | 204 | if order == ifaceSchedulerFlags.POSTORDER: |
be0b20f2 | 205 | cls.run_iface_ops(ifupdownobj, ifaceobj, ops) |
a6f80f0e | 206 | |
be0b20f2 | 207 | @classmethod |
208 | def run_iface_list(cls, ifupdownobj, ifacenames, | |
f3215127 | 209 | ops, parent=None, order=ifaceSchedulerFlags.POSTORDER, |
6ef5bfa2 | 210 | followdependents=True, continueonfailure=True): |
d08d5f54 | 211 | """ Runs interface list """ |
a6f80f0e | 212 | |
d08d5f54 | 213 | for ifacename in ifacenames: |
a6f80f0e | 214 | try: |
be0b20f2 | 215 | cls.run_iface_graph(ifupdownobj, ifacename, ops, parent, |
d08d5f54 | 216 | order, followdependents) |
a6f80f0e | 217 | except Exception, e: |
6ef5bfa2 | 218 | if continueonfailure: |
69f58278 | 219 | if ifupdownobj.logger.isEnabledFor(logging.DEBUG): |
220 | traceback.print_tb(sys.exc_info()[2]) | |
be0b20f2 | 221 | ifupdownobj.logger.error('%s : %s' %(ifacename, str(e))) |
d08d5f54 | 222 | pass |
223 | else: | |
be0b20f2 | 224 | if (ifupdownobj.ignore_error(str(e))): |
6ef5bfa2 | 225 | pass |
226 | else: | |
227 | raise Exception('error running iface %s (%s)' | |
228 | %(ifacename, str(e))) | |
d08d5f54 | 229 | |
be0b20f2 | 230 | @classmethod |
c798b0f4 | 231 | def run_iface_graph_upper(cls, ifupdownobj, ifacename, ops, parent=None, |
232 | followdependents=True, skip_root=False): | |
233 | """ runs interface by traversing all nodes rooted at itself """ | |
234 | ||
235 | # Each ifacename can have a list of iface objects | |
236 | ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename) | |
237 | if not ifaceobjs: | |
238 | raise Exception('%s: not found' %ifacename) | |
239 | ||
240 | for ifaceobj in ifaceobjs: | |
241 | if not skip_root: | |
242 | # run the iface first and then its upperifaces | |
243 | cls.run_iface_ops(ifupdownobj, ifaceobj, ops) | |
244 | ||
245 | # Run upperifaces | |
62ddec8b | 246 | ulist = ifaceobj.upperifaces |
c798b0f4 | 247 | if ulist: |
248 | ifupdownobj.logger.debug('%s:' %ifacename + | |
249 | ' found upperifaces: %s' %str(ulist)) | |
250 | try: | |
251 | cls.run_iface_list_upper(ifupdownobj, ulist, ops, | |
252 | ifacename, | |
253 | followdependents, | |
254 | continueonfailure=True) | |
255 | except Exception, e: | |
256 | if (ifupdownobj.ignore_error(str(e))): | |
257 | pass | |
258 | else: | |
259 | raise | |
260 | ||
261 | @classmethod | |
262 | def run_iface_list_upper(cls, ifupdownobj, ifacenames, | |
263 | ops, parent=None, followdependents=True, | |
264 | continueonfailure=True, skip_root=False): | |
265 | """ Runs interface list """ | |
266 | ||
267 | for ifacename in ifacenames: | |
268 | try: | |
269 | cls.run_iface_graph_upper(ifupdownobj, ifacename, ops, parent, | |
270 | followdependents, skip_root) | |
271 | except Exception, e: | |
272 | if continueonfailure: | |
273 | if ifupdownobj.logger.isEnabledFor(logging.DEBUG): | |
274 | traceback.print_tb(sys.exc_info()[2]) | |
275 | ifupdownobj.logger.error('%s : %s' %(ifacename, str(e))) | |
276 | pass | |
277 | else: | |
278 | if (ifupdownobj.ignore_error(str(e))): | |
279 | pass | |
280 | else: | |
281 | raise Exception('error running iface %s (%s)' | |
282 | %(ifacename, str(e))) | |
283 | ||
284 | @classmethod | |
285 | def sched_ifaces(cls, ifupdownobj, ifacenames, ops, | |
286 | dependency_graph=None, indegrees=None, | |
d08d5f54 | 287 | order=ifaceSchedulerFlags.POSTORDER, |
288 | followdependents=True): | |
289 | """ Runs iface dependeny graph by visiting all the nodes | |
290 | ||
291 | Parameters: | |
292 | ----------- | |
293 | ifupdownobj : ifupdown object (used for getting and updating iface | |
294 | object state) | |
295 | dependency_graph : dependency graph in adjacency list | |
296 | format (contains more than one dependency graph) | |
297 | ops : list of operations to perform eg ['pre-up', 'up', 'post-up'] | |
298 | ||
299 | indegrees : indegree array if present is used to determine roots | |
300 | of the graphs in the dependency_graph | |
301 | """ | |
c798b0f4 | 302 | |
303 | if not ifupdownobj.ALL or not followdependents or len(ifacenames) == 1: | |
304 | cls.run_iface_list(ifupdownobj, ifacenames, ops, | |
305 | parent=None,order=order, | |
306 | followdependents=followdependents) | |
307 | if not ifupdownobj.ALL and followdependents and 'up' in ops[0]: | |
308 | # If user had given a set of interfaces to bring up | |
309 | # try and execute 'up' on the upperifaces | |
310 | ifupdownobj.logger.info('running upperifaces if available') | |
311 | cls._STATE_CHECK = False | |
312 | cls.run_iface_list_upper(ifupdownobj, ifacenames, ops, | |
313 | skip_root=True) | |
314 | cls._STATE_CHECK = True | |
315 | return | |
d08d5f54 | 316 | run_queue = [] |
f3215127 | 317 | |
c798b0f4 | 318 | # Get a sorted list of all interfaces |
20dd6242 | 319 | if not indegrees: |
f3215127 | 320 | indegrees = OrderedDict() |
d08d5f54 | 321 | for ifacename in dependency_graph.keys(): |
f3215127 | 322 | indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename) |
f3215127 | 323 | sorted_ifacenames = graph.topological_sort_graphs_all(dependency_graph, |
324 | dict(indegrees)) | |
be0b20f2 | 325 | ifupdownobj.logger.debug('sorted ifacenames %s : ' |
326 | %str(sorted_ifacenames)) | |
f3215127 | 327 | |
c798b0f4 | 328 | # From the sorted list, pick interfaces that user asked |
329 | # and those that dont have any dependents first | |
330 | [run_queue.append(ifacename) | |
331 | for ifacename in sorted_ifacenames | |
332 | if ifacename in ifacenames and | |
333 | not indegrees.get(ifacename)] | |
d08d5f54 | 334 | |
20dd6242 | 335 | ifupdownobj.logger.debug('graph roots (interfaces that dont have ' |
336 | 'dependents):' + ' %s' %str(run_queue)) | |
c798b0f4 | 337 | cls.run_iface_list(ifupdownobj, run_queue, ops, |
be0b20f2 | 338 | parent=None,order=order, |
339 | followdependents=followdependents) | |
d08d5f54 | 340 | |
be0b20f2 | 341 | @classmethod |
342 | def run_iface(cls, ifupdownobj, ifacename, ops): | |
d08d5f54 | 343 | """ Runs operation on an interface """ |
344 | ||
31a5f4c3 | 345 | ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename) |
d08d5f54 | 346 | for i in ifaceobjs: |
be0b20f2 | 347 | cls.run_iface_ops(ifupdownobj, i, ops) |
d08d5f54 | 348 | |
be0b20f2 | 349 | @classmethod |
350 | def run_iface_list_op(cls, ifupdownobj, ifacenames, op, | |
351 | sorted_by_dependency=False): | |
a6f80f0e | 352 | """ Runs interface list through sub operation handler. """ |
353 | ||
be0b20f2 | 354 | ifupdownobj.logger.debug('running operation %s on all given interfaces' |
355 | %op) | |
a6f80f0e | 356 | iface_run_queue = deque(ifacenames) |
357 | for i in range(0, len(iface_run_queue)): | |
d08d5f54 | 358 | if op.endswith('up'): |
a6f80f0e | 359 | # XXX: simplify this |
d08d5f54 | 360 | if sorted_by_dependency: |
a6f80f0e | 361 | ifacename = iface_run_queue.pop() |
362 | else: | |
363 | ifacename = iface_run_queue.popleft() | |
364 | else: | |
d08d5f54 | 365 | if sorted_by_dependency: |
a6f80f0e | 366 | ifacename = iface_run_queue.popleft() |
367 | else: | |
368 | ifacename = iface_run_queue.pop() | |
369 | ||
370 | try: | |
31a5f4c3 | 371 | ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename) |
a6f80f0e | 372 | for ifaceobj in ifaceobjs: |
a6f80f0e | 373 | cenv = ifupdownobj.generate_running_env(ifaceobj, op) |
be0b20f2 | 374 | cls.run_iface_op(ifupdownobj, ifaceobj, op, cenv) |
a6f80f0e | 375 | except Exception, e: |
be0b20f2 | 376 | ifupdownobj.log_error(str(e)) |
a6f80f0e | 377 | |
be0b20f2 | 378 | @classmethod |
379 | def run_iface_list_ops(cls, ifupdownobj, ifacenames, ops, | |
380 | sorted_by_dependency=False): | |
a6f80f0e | 381 | """ Runs interface list through sub operations handler |
382 | ||
383 | Unlike run_iface_list, this method executes a sub operation on the | |
384 | entire interface list before proceeding to the next sub-operation. | |
385 | ie operation 'pre-up' is run through the entire interface list before | |
386 | 'up' | |
387 | """ | |
a6f80f0e | 388 | # Each sub operation has a module list |
be0b20f2 | 389 | [cls.run_iface_list_op(ifupdownobj, ifacenames, op, |
d08d5f54 | 390 | sorted_by_dependency) for op in ops] |
a6f80f0e | 391 | |
be0b20f2 | 392 | @classmethod |
393 | def run_iface_dependency_graphs_sorted(cls, ifupdownobj, | |
394 | dependency_graphs, | |
395 | ops, indegrees=None, | |
396 | graphsortall=False): | |
d08d5f54 | 397 | """ runs interface dependency graph by topologically sorting the interfaces """ |
a6f80f0e | 398 | |
37c0543d | 399 | if indegrees is None: |
400 | indegrees = OrderedDict() | |
401 | for ifacename in dependency_graphs.keys(): | |
402 | indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename) | |
a6f80f0e | 403 | |
be0b20f2 | 404 | ifupdownobj.logger.debug('indegree array :') |
405 | ifupdownobj.logger.debug(ifupdownobj.pp.pformat(indegrees)) | |
a6f80f0e | 406 | |
407 | try: | |
be0b20f2 | 408 | ifupdownobj.logger.debug('calling topological sort on the graph ' + |
409 | '...') | |
d08d5f54 | 410 | if graphsortall: |
37c0543d | 411 | sorted_ifacenames = graph.topological_sort_graphs_all( |
412 | dependency_graphs, indegrees) | |
413 | else: | |
414 | sorted_ifacenames = graph.topological_sort_graphs( | |
415 | dependency_graphs, indegrees) | |
cca03c30 | 416 | except Exception: |
a6f80f0e | 417 | raise |
418 | ||
be0b20f2 | 419 | ifupdownobj.logger.debug('sorted iface list = %s' %sorted_ifacenames) |
420 | cls.run_iface_list_ops(ifupdownobj, sorted_ifacenames, ops, | |
421 | sorted_by_dependency=True) | |
a6f80f0e | 422 | |
423 | ||
d08d5f54 | 424 | """ Methods to execute interfaces in parallel """ |
be0b20f2 | 425 | @classmethod |
426 | def init_tokens(cls, count): | |
427 | cls.token_pool = BoundedSemaphore(count) | |
a6f80f0e | 428 | |
be0b20f2 | 429 | @classmethod |
430 | def accquire_token(cls, logprefix=''): | |
431 | cls.token_pool.acquire() | |
a6f80f0e | 432 | |
be0b20f2 | 433 | @classmethod |
434 | def release_token(cls, logprefix=''): | |
435 | cls.token_pool.release() | |
a6f80f0e | 436 | |
be0b20f2 | 437 | @classmethod |
438 | def run_iface_parallel(cls, ifupdownobj, ifacename, op): | |
a6f80f0e | 439 | """ Configures interface in parallel. |
440 | ||
441 | Executes all its direct dependents in parallel | |
442 | ||
443 | """ | |
444 | ||
be0b20f2 | 445 | ifupdownobj.logger.debug('%s:' %ifacename + ' %s' %op) |
446 | cls.accquire_token(iface) | |
a6f80f0e | 447 | |
448 | # Each iface can have a list of objects | |
31a5f4c3 | 449 | ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename) |
a6f80f0e | 450 | if ifaceobjs is None: |
be0b20f2 | 451 | ifupdownobj.logger.warning('%s: ' %ifacename + 'not found') |
452 | cls.release_token(ifacename) | |
a6f80f0e | 453 | return -1 |
454 | ||
455 | for ifaceobj in ifaceobjs: | |
456 | # Run dependents | |
62ddec8b | 457 | dlist = ifaceobj.lowerifaces |
be0b20f2 | 458 | if dlist: |
459 | ifupdownobj.logger.debug('%s:' %ifacename + | |
a6f80f0e | 460 | ' found dependents: %s' %str(dlist)) |
461 | try: | |
be0b20f2 | 462 | cls.release_token(ifacename) |
463 | cls.run_iface_list_parallel(ifacename, ifupdownobj, | |
a6f80f0e | 464 | dlist, op) |
be0b20f2 | 465 | cls.accquire_token(ifacename) |
a6f80f0e | 466 | except Exception, e: |
be0b20f2 | 467 | if ifupdownobj.ignore_error(str(e)): |
a6f80f0e | 468 | pass |
469 | else: | |
470 | # Dont bring the iface up if children did not come up | |
be0b20f2 | 471 | ifupdownobj.logger.debug('%s:' %ifacename + |
a6f80f0e | 472 | ' there was an error bringing %s' %op + |
473 | ' dependents (%s)', str(e)) | |
474 | ifupdownobj.set_iface_state(ifaceobj, | |
d08d5f54 | 475 | ifaceState.from_str(ops[0]), |
a6f80f0e | 476 | ifaceStatus.ERROR) |
477 | return -1 | |
478 | ||
a6f80f0e | 479 | # Run all sub operations sequentially |
480 | try: | |
be0b20f2 | 481 | ifupdownobj.logger.debug('%s:' %ifacename + |
482 | ' running sub-operations') | |
483 | cls.run_iface_ops(ifupdownobj, ifaceobj, op) | |
a6f80f0e | 484 | except Exception, e: |
be0b20f2 | 485 | ifupdownobj.logger.error('%s:' %ifacename + |
a6f80f0e | 486 | ' error running sub operations (%s)' %str(e)) |
487 | ||
be0b20f2 | 488 | cls.release_token(ifacename) |
a6f80f0e | 489 | |
be0b20f2 | 490 | @classmethod |
491 | def run_iface_list_parallel(cls, parent, ifupdownobj, ifacenames, op): | |
a6f80f0e | 492 | """ Runs interface list in parallel """ |
493 | ||
494 | running_threads = OrderedDict() | |
495 | err = 0 | |
496 | ||
497 | for ifacename in ifacenames: | |
498 | try: | |
be0b20f2 | 499 | cls.accquire_token(parent) |
a6f80f0e | 500 | running_threads[ifacename] = Thread(None, |
be0b20f2 | 501 | cls.run_iface_parallel, ifacename, |
a6f80f0e | 502 | args=(ifupdownobj, ifacename, op)) |
503 | running_threads[ifacename].start() | |
be0b20f2 | 504 | cls.release_token(parent) |
a6f80f0e | 505 | except Exception, e: |
be0b20f2 | 506 | cls.release_token(parent) |
d08d5f54 | 507 | if ifupdownobj.ignore_error(str(e)): |
a6f80f0e | 508 | pass |
509 | else: | |
510 | raise Exception('error starting thread for iface %s' | |
511 | %ifacename) | |
512 | ||
513 | ||
be0b20f2 | 514 | ifupdownobj.logger.debug('%s ' %parent + |
515 | 'waiting for all the threads ...') | |
a6f80f0e | 516 | for ifacename, t in running_threads.items(): |
517 | t.join() | |
518 | if ifupdownobj.get_iface_status(ifacename) != ifaceStatus.SUCCESS: | |
519 | err += 1 | |
520 | ||
521 | return err | |
522 | ||
be0b20f2 | 523 | @classmethod |
524 | def run_iface_graphs_parallel(cls, parent, ifupdownobj, ifacenames, op): | |
a6f80f0e | 525 | """ Runs iface graphs in parallel """ |
526 | ||
527 | running_threads = OrderedDict() | |
528 | err = 0 | |
529 | ||
530 | for ifacename in ifacenames: | |
531 | try: | |
be0b20f2 | 532 | cls.accquire_graph_token(parent) |
a6f80f0e | 533 | running_threads[ifacename] = Thread(None, |
be0b20f2 | 534 | cls.run_iface_parallel, ifacename, |
a6f80f0e | 535 | args=(ifupdownobj, ifacename, op)) |
536 | running_threads[ifacename].start() | |
be0b20f2 | 537 | cls.release_graph_token(parent) |
a6f80f0e | 538 | except Exception, e: |
be0b20f2 | 539 | cls.release_graph_token(parent) |
d08d5f54 | 540 | if ifupdownobj.ignore_error(str(e)): |
a6f80f0e | 541 | pass |
542 | else: | |
543 | raise Exception('error starting thread for iface %s' | |
544 | %ifacename) | |
545 | ||
be0b20f2 | 546 | ifupdownobj.logger.info('%s ' %parent + |
547 | 'waiting for all the threads ...') | |
548 | for ifacename, t in running_threads.items(): | |
a6f80f0e | 549 | t.join() |
550 | # Check status of thread | |
551 | # XXX: Check all objs | |
552 | if ifupdownobj.get_iface_status(ifacename) != ifaceStatus.SUCCESS: | |
553 | err += 1 | |
a6f80f0e | 554 | return err |
555 | ||
be0b20f2 | 556 | @classmethod |
557 | def run_iface_dependency_graph_parallel(cls, ifupdownobj, dependency_graph, | |
a6f80f0e | 558 | operation): |
559 | """ Runs iface dependeny graph in parallel. | |
560 | ||
561 | arguments: | |
562 | ifupdownobj -- ifupdown object (used for getting and updating iface | |
563 | object state) | |
564 | dependency_graph -- dependency graph with | |
565 | operation -- 'up' or 'down' or 'query' | |
566 | ||
567 | """ | |
568 | ||
be0b20f2 | 569 | ifupdownobj.logger.debug('running dependency graph in parallel ..') |
a6f80f0e | 570 | run_queue = [] |
a6f80f0e | 571 | # Build a list of ifaces that dont have any dependencies |
572 | for ifacename in dependency_graph.keys(): | |
573 | if ifupdownobj.get_iface_refcnt(ifacename) == 0: | |
574 | run_queue.append(ifacename) | |
575 | ||
be0b20f2 | 576 | ifupdownobj.logger.debug('graph roots (interfaces that dont' |
d08d5f54 | 577 | ' have dependents):' + ' %s' %str(run_queue)) |
be0b20f2 | 578 | cls.init_tokens(ifupdownobj.get_njobs()) |
579 | return cls.run_iface_list_parallel('main', ifupdownobj, run_queue, | |
a6f80f0e | 580 | operation) |
581 | ||
582 | # OR | |
583 | # Run one graph at a time | |
584 | #for iface in run_queue: | |
585 | # self.run_iface_list_parallel('main', ifupdownobj, [iface], | |
586 | # operation) | |
587 |