]>
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(): |
24 | INORDER = 1 | |
25 | POSTORDER = 2 | |
26 | ||
be0b20f2 | 27 | class ifaceScheduler(): |
28 | """ scheduler functions to schedule configuration of interfaces. | |
a6f80f0e | 29 | |
30 | ||
31 | supports scheduling of interfaces serially in plain interface list | |
32 | or dependency graph format. | |
33 | """ | |
34 | ||
be0b20f2 | 35 | token_pool = None |
d08d5f54 | 36 | |
be0b20f2 | 37 | @classmethod |
38 | def run_iface_op(cls, ifupdownobj, ifaceobj, op, cenv): | |
a6f80f0e | 39 | """ Runs sub operation on an interface """ |
d08d5f54 | 40 | ifacename = ifaceobj.get_name() |
a6f80f0e | 41 | |
d08d5f54 | 42 | if (ifaceobj.get_state() >= ifaceState.from_str(op) and |
43 | ifaceobj.get_status() == ifaceStatus.SUCCESS): | |
be0b20f2 | 44 | ifupdownobj.logger.debug('%s: already in state %s' %(ifacename, op)) |
d08d5f54 | 45 | return |
a6f80f0e | 46 | |
be0b20f2 | 47 | # first run ifupdownobj handlers |
48 | handler = ifupdownobj.ops_handlers.get(op) | |
49 | if handler: | |
50 | addr_method = ifaceobj.get_addr_method() | |
51 | if not addr_method or (addr_method and addr_method != 'manual'): | |
52 | handler(ifupdownobj, ifaceobj) | |
53 | ||
20dd6242 | 54 | if not ifupdownobj.ADDONS_ENABLE: return |
55 | ||
be0b20f2 | 56 | for mname in ifupdownobj.module_ops.get(op): |
37c0543d | 57 | m = ifupdownobj.modules.get(mname) |
a6f80f0e | 58 | err = 0 |
59 | try: | |
d08d5f54 | 60 | if hasattr(m, 'run'): |
be0b20f2 | 61 | ifupdownobj.logger.debug('%s: %s : running module %s' |
d08d5f54 | 62 | %(ifacename, op, mname)) |
739f665b | 63 | if op == 'query-checkcurr': |
d08d5f54 | 64 | # Dont check curr if the interface object was |
37c0543d | 65 | # auto generated |
d08d5f54 | 66 | if (ifaceobj.priv_flags & ifupdownobj.NOCONFIG): |
37c0543d | 67 | continue |
d08d5f54 | 68 | m.run(ifaceobj, op, |
69 | query_ifaceobj=ifupdownobj.create_n_save_ifaceobjcurr(ifaceobj)) | |
a6f80f0e | 70 | else: |
d08d5f54 | 71 | m.run(ifaceobj, op) |
a6f80f0e | 72 | except Exception, e: |
73 | err = 1 | |
be0b20f2 | 74 | ifupdownobj.log_error(str(e)) |
a6f80f0e | 75 | finally: |
31a5f4c3 | 76 | if err: |
77 | ifaceobj.set_state_n_status(ifaceState.from_str(op), | |
78 | ifaceStatus.ERROR) | |
d08d5f54 | 79 | else: |
31a5f4c3 | 80 | ifaceobj.set_state_n_status(ifaceState.from_str(op), |
81 | ifaceStatus.SUCCESS) | |
6bd7fc74 | 82 | |
83 | if ifupdownobj.COMPAT_EXEC_SCRIPTS: | |
84 | # execute /etc/network/ scripts | |
85 | for mname in ifupdownobj.script_ops.get(op, []): | |
86 | ifupdownobj.logger.debug('%s: %s : running script %s' | |
d08d5f54 | 87 | %(ifacename, op, mname)) |
6bd7fc74 | 88 | try: |
89 | ifupdownobj.exec_command(mname, cmdenv=cenv) | |
90 | except Exception, e: | |
91 | ifupdownobj.log_error(str(e)) | |
37c0543d | 92 | |
be0b20f2 | 93 | @classmethod |
94 | def run_iface_ops(cls, ifupdownobj, ifaceobj, ops): | |
31a5f4c3 | 95 | """ Runs all operations on an interface """ |
6bd7fc74 | 96 | cenv=None |
6bd7fc74 | 97 | if ifupdownobj.COMPAT_EXEC_SCRIPTS: |
98 | # For backward compatibility generate env variables | |
99 | # for attributes | |
100 | cenv = ifupdownobj.generate_running_env(ifaceobj, ops[0]) | |
6bd7fc74 | 101 | map(lambda op: cls.run_iface_op(ifupdownobj, ifaceobj, op, cenv), ops) |
31a5f4c3 | 102 | posthookfunc = ifupdownobj.sched_hooks.get('posthook') |
103 | if posthookfunc: | |
104 | posthookfunc(ifupdownobj, ifaceobj) | |
a6f80f0e | 105 | |
be0b20f2 | 106 | @classmethod |
107 | def run_iface_graph(cls, ifupdownobj, ifacename, ops, parent=None, | |
d08d5f54 | 108 | order=ifaceSchedulerFlags.POSTORDER, |
109 | followdependents=True): | |
6ef5bfa2 | 110 | """ runs interface by traversing all nodes rooted at itself """ |
111 | ||
112 | # minor optimization. If operation is 'down', proceed only | |
113 | # if interface exists in the system | |
be0b20f2 | 114 | if 'down' in ops[0] and not ifupdownobj.link_exists(ifacename): |
115 | ifupdownobj.logger.info('%s: does not exist' %ifacename) | |
6ef5bfa2 | 116 | return |
a6f80f0e | 117 | |
d08d5f54 | 118 | # Each ifacename can have a list of iface objects |
31a5f4c3 | 119 | ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename) |
120 | if not ifaceobjs: | |
d08d5f54 | 121 | raise Exception('%s: not found' %ifacename) |
a6f80f0e | 122 | |
d08d5f54 | 123 | for ifaceobj in ifaceobjs: |
f3215127 | 124 | # Deal with upperdevs first |
125 | ulist = ifaceobj.get_upperifaces() | |
126 | if ulist: | |
f3215127 | 127 | tmpulist = ([u for u in ulist if u != parent] if parent |
128 | else ulist) | |
129 | if tmpulist: | |
f3215127 | 130 | if 'down' in ops[0]: |
131 | # XXX: This is expensive. Find a cheaper way to do this | |
132 | # if any of the upperdevs are present, | |
133 | # dont down this interface | |
134 | for u in tmpulist: | |
be0b20f2 | 135 | if ifupdownobj.link_exists(u): |
f3215127 | 136 | if not ifupdownobj.ALL: |
be0b20f2 | 137 | ifupdownobj.logger.warn('%s: ' %ifacename + |
138 | ' skip interface down,' + | |
139 | ' upperiface %s still around' %u) | |
f3215127 | 140 | return |
141 | elif 'up' in ops[0] and not ifupdownobj.ALL: | |
142 | # For 'up', just warn that there is an upperdev which is | |
143 | # probably not up | |
144 | for u in tmpulist: | |
be0b20f2 | 145 | if not ifupdownobj.link_exists(u): |
146 | ifupdownobj.logger.warn('%s: upper iface %s ' | |
147 | %(ifacename, u) + 'does not exist') | |
f3215127 | 148 | |
d08d5f54 | 149 | if order == ifaceSchedulerFlags.INORDER: |
f3215127 | 150 | # If inorder, run the iface first and then its dependents |
be0b20f2 | 151 | cls.run_iface_ops(ifupdownobj, ifaceobj, ops) |
f3215127 | 152 | |
153 | # Run lowerifaces or dependents | |
154 | dlist = ifaceobj.get_lowerifaces() | |
155 | if dlist: | |
20dd6242 | 156 | ifupdownobj.logger.debug('%s:' %ifacename + |
d08d5f54 | 157 | ' found dependents: %s' %str(dlist)) |
158 | try: | |
159 | if not followdependents: | |
160 | # XXX: this is yet another extra step, | |
161 | # but is needed for interfaces that are | |
f3215127 | 162 | # implicit dependents. even though we are asked to |
163 | # not follow dependents, we must follow the ones | |
164 | # that dont have user given config. Because we own them | |
d08d5f54 | 165 | new_dlist = [d for d in dlist |
166 | if ifupdownobj.is_iface_noconfig(d)] | |
6ef5bfa2 | 167 | if new_dlist: |
be0b20f2 | 168 | cls.run_iface_list(ifupdownobj, new_dlist, ops, |
f3215127 | 169 | ifacename, order, |
170 | followdependents, | |
6ef5bfa2 | 171 | continueonfailure=False) |
d08d5f54 | 172 | else: |
be0b20f2 | 173 | cls.run_iface_list(ifupdownobj, dlist, ops, |
f3215127 | 174 | ifacename, order, |
175 | followdependents, | |
6ef5bfa2 | 176 | continueonfailure=False) |
d08d5f54 | 177 | except Exception, e: |
be0b20f2 | 178 | if (ifupdownobj.ignore_error(str(e))): |
d08d5f54 | 179 | pass |
180 | else: | |
181 | # Dont bring the iface up if children did not come up | |
31a5f4c3 | 182 | ifaceobj.set_state_n_sttaus(ifaceState.NEW, |
183 | ifacestatus.ERROR) | |
d08d5f54 | 184 | raise |
d08d5f54 | 185 | if order == ifaceSchedulerFlags.POSTORDER: |
be0b20f2 | 186 | cls.run_iface_ops(ifupdownobj, ifaceobj, ops) |
a6f80f0e | 187 | |
be0b20f2 | 188 | @classmethod |
189 | def run_iface_list(cls, ifupdownobj, ifacenames, | |
f3215127 | 190 | ops, parent=None, order=ifaceSchedulerFlags.POSTORDER, |
6ef5bfa2 | 191 | followdependents=True, continueonfailure=True): |
d08d5f54 | 192 | """ Runs interface list """ |
a6f80f0e | 193 | |
d08d5f54 | 194 | for ifacename in ifacenames: |
a6f80f0e | 195 | try: |
be0b20f2 | 196 | cls.run_iface_graph(ifupdownobj, ifacename, ops, parent, |
d08d5f54 | 197 | order, followdependents) |
a6f80f0e | 198 | except Exception, e: |
6ef5bfa2 | 199 | if continueonfailure: |
69f58278 | 200 | if ifupdownobj.logger.isEnabledFor(logging.DEBUG): |
201 | traceback.print_tb(sys.exc_info()[2]) | |
be0b20f2 | 202 | ifupdownobj.logger.error('%s : %s' %(ifacename, str(e))) |
d08d5f54 | 203 | pass |
204 | else: | |
be0b20f2 | 205 | if (ifupdownobj.ignore_error(str(e))): |
6ef5bfa2 | 206 | pass |
207 | else: | |
208 | raise Exception('error running iface %s (%s)' | |
209 | %(ifacename, str(e))) | |
d08d5f54 | 210 | |
be0b20f2 | 211 | @classmethod |
212 | def run_iface_dependency_graphs(cls, ifupdownobj, | |
d08d5f54 | 213 | dependency_graph, ops, indegrees=None, |
214 | order=ifaceSchedulerFlags.POSTORDER, | |
215 | followdependents=True): | |
216 | """ Runs iface dependeny graph by visiting all the nodes | |
217 | ||
218 | Parameters: | |
219 | ----------- | |
220 | ifupdownobj : ifupdown object (used for getting and updating iface | |
221 | object state) | |
222 | dependency_graph : dependency graph in adjacency list | |
223 | format (contains more than one dependency graph) | |
224 | ops : list of operations to perform eg ['pre-up', 'up', 'post-up'] | |
225 | ||
226 | indegrees : indegree array if present is used to determine roots | |
227 | of the graphs in the dependency_graph | |
228 | """ | |
d08d5f54 | 229 | run_queue = [] |
f3215127 | 230 | |
20dd6242 | 231 | if not indegrees: |
f3215127 | 232 | indegrees = OrderedDict() |
d08d5f54 | 233 | for ifacename in dependency_graph.keys(): |
f3215127 | 234 | indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename) |
235 | ||
236 | sorted_ifacenames = graph.topological_sort_graphs_all(dependency_graph, | |
237 | dict(indegrees)) | |
be0b20f2 | 238 | ifupdownobj.logger.debug('sorted ifacenames %s : ' |
239 | %str(sorted_ifacenames)) | |
f3215127 | 240 | |
241 | # Build a list of ifaces that dont have any dependencies | |
242 | for ifacename in sorted_ifacenames: | |
243 | if not indegrees.get(ifacename): | |
244 | run_queue.append(ifacename) | |
d08d5f54 | 245 | |
20dd6242 | 246 | ifupdownobj.logger.debug('graph roots (interfaces that dont have ' |
247 | 'dependents):' + ' %s' %str(run_queue)) | |
d08d5f54 | 248 | |
be0b20f2 | 249 | return cls.run_iface_list(ifupdownobj, run_queue, ops, |
250 | parent=None,order=order, | |
251 | followdependents=followdependents) | |
d08d5f54 | 252 | |
be0b20f2 | 253 | @classmethod |
254 | def run_iface(cls, ifupdownobj, ifacename, ops): | |
d08d5f54 | 255 | """ Runs operation on an interface """ |
256 | ||
31a5f4c3 | 257 | ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename) |
d08d5f54 | 258 | for i in ifaceobjs: |
be0b20f2 | 259 | cls.run_iface_ops(ifupdownobj, i, ops) |
d08d5f54 | 260 | |
be0b20f2 | 261 | @classmethod |
262 | def run_iface_list_op(cls, ifupdownobj, ifacenames, op, | |
263 | sorted_by_dependency=False): | |
a6f80f0e | 264 | """ Runs interface list through sub operation handler. """ |
265 | ||
be0b20f2 | 266 | ifupdownobj.logger.debug('running operation %s on all given interfaces' |
267 | %op) | |
a6f80f0e | 268 | iface_run_queue = deque(ifacenames) |
269 | for i in range(0, len(iface_run_queue)): | |
d08d5f54 | 270 | if op.endswith('up'): |
a6f80f0e | 271 | # XXX: simplify this |
d08d5f54 | 272 | if sorted_by_dependency: |
a6f80f0e | 273 | ifacename = iface_run_queue.pop() |
274 | else: | |
275 | ifacename = iface_run_queue.popleft() | |
276 | else: | |
d08d5f54 | 277 | if sorted_by_dependency: |
a6f80f0e | 278 | ifacename = iface_run_queue.popleft() |
279 | else: | |
280 | ifacename = iface_run_queue.pop() | |
281 | ||
282 | try: | |
31a5f4c3 | 283 | ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename) |
a6f80f0e | 284 | for ifaceobj in ifaceobjs: |
a6f80f0e | 285 | cenv = ifupdownobj.generate_running_env(ifaceobj, op) |
be0b20f2 | 286 | cls.run_iface_op(ifupdownobj, ifaceobj, op, cenv) |
a6f80f0e | 287 | except Exception, e: |
be0b20f2 | 288 | ifupdownobj.log_error(str(e)) |
a6f80f0e | 289 | |
be0b20f2 | 290 | @classmethod |
291 | def run_iface_list_ops(cls, ifupdownobj, ifacenames, ops, | |
292 | sorted_by_dependency=False): | |
a6f80f0e | 293 | """ Runs interface list through sub operations handler |
294 | ||
295 | Unlike run_iface_list, this method executes a sub operation on the | |
296 | entire interface list before proceeding to the next sub-operation. | |
297 | ie operation 'pre-up' is run through the entire interface list before | |
298 | 'up' | |
299 | """ | |
a6f80f0e | 300 | # Each sub operation has a module list |
be0b20f2 | 301 | [cls.run_iface_list_op(ifupdownobj, ifacenames, op, |
d08d5f54 | 302 | sorted_by_dependency) for op in ops] |
a6f80f0e | 303 | |
be0b20f2 | 304 | @classmethod |
305 | def run_iface_dependency_graphs_sorted(cls, ifupdownobj, | |
306 | dependency_graphs, | |
307 | ops, indegrees=None, | |
308 | graphsortall=False): | |
d08d5f54 | 309 | """ runs interface dependency graph by topologically sorting the interfaces """ |
a6f80f0e | 310 | |
37c0543d | 311 | if indegrees is None: |
312 | indegrees = OrderedDict() | |
313 | for ifacename in dependency_graphs.keys(): | |
314 | indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename) | |
a6f80f0e | 315 | |
be0b20f2 | 316 | ifupdownobj.logger.debug('indegree array :') |
317 | ifupdownobj.logger.debug(ifupdownobj.pp.pformat(indegrees)) | |
a6f80f0e | 318 | |
319 | try: | |
be0b20f2 | 320 | ifupdownobj.logger.debug('calling topological sort on the graph ' + |
321 | '...') | |
d08d5f54 | 322 | if graphsortall: |
37c0543d | 323 | sorted_ifacenames = graph.topological_sort_graphs_all( |
324 | dependency_graphs, indegrees) | |
325 | else: | |
326 | sorted_ifacenames = graph.topological_sort_graphs( | |
327 | dependency_graphs, indegrees) | |
cca03c30 | 328 | except Exception: |
a6f80f0e | 329 | raise |
330 | ||
be0b20f2 | 331 | ifupdownobj.logger.debug('sorted iface list = %s' %sorted_ifacenames) |
332 | cls.run_iface_list_ops(ifupdownobj, sorted_ifacenames, ops, | |
333 | sorted_by_dependency=True) | |
a6f80f0e | 334 | |
335 | ||
d08d5f54 | 336 | """ Methods to execute interfaces in parallel """ |
be0b20f2 | 337 | @classmethod |
338 | def init_tokens(cls, count): | |
339 | cls.token_pool = BoundedSemaphore(count) | |
a6f80f0e | 340 | |
be0b20f2 | 341 | @classmethod |
342 | def accquire_token(cls, logprefix=''): | |
343 | cls.token_pool.acquire() | |
a6f80f0e | 344 | |
be0b20f2 | 345 | @classmethod |
346 | def release_token(cls, logprefix=''): | |
347 | cls.token_pool.release() | |
a6f80f0e | 348 | |
be0b20f2 | 349 | @classmethod |
350 | def run_iface_parallel(cls, ifupdownobj, ifacename, op): | |
a6f80f0e | 351 | """ Configures interface in parallel. |
352 | ||
353 | Executes all its direct dependents in parallel | |
354 | ||
355 | """ | |
356 | ||
be0b20f2 | 357 | ifupdownobj.logger.debug('%s:' %ifacename + ' %s' %op) |
358 | cls.accquire_token(iface) | |
a6f80f0e | 359 | |
360 | # Each iface can have a list of objects | |
31a5f4c3 | 361 | ifaceobjs = ifupdownobj.get_ifaceobjs(ifacename) |
a6f80f0e | 362 | if ifaceobjs is None: |
be0b20f2 | 363 | ifupdownobj.logger.warning('%s: ' %ifacename + 'not found') |
364 | cls.release_token(ifacename) | |
a6f80f0e | 365 | return -1 |
366 | ||
367 | for ifaceobj in ifaceobjs: | |
368 | # Run dependents | |
f3215127 | 369 | dlist = ifaceobj.get_lowerifaces() |
be0b20f2 | 370 | if dlist: |
371 | ifupdownobj.logger.debug('%s:' %ifacename + | |
a6f80f0e | 372 | ' found dependents: %s' %str(dlist)) |
373 | try: | |
be0b20f2 | 374 | cls.release_token(ifacename) |
375 | cls.run_iface_list_parallel(ifacename, ifupdownobj, | |
a6f80f0e | 376 | dlist, op) |
be0b20f2 | 377 | cls.accquire_token(ifacename) |
a6f80f0e | 378 | except Exception, e: |
be0b20f2 | 379 | if ifupdownobj.ignore_error(str(e)): |
a6f80f0e | 380 | pass |
381 | else: | |
382 | # Dont bring the iface up if children did not come up | |
be0b20f2 | 383 | ifupdownobj.logger.debug('%s:' %ifacename + |
a6f80f0e | 384 | ' there was an error bringing %s' %op + |
385 | ' dependents (%s)', str(e)) | |
386 | ifupdownobj.set_iface_state(ifaceobj, | |
d08d5f54 | 387 | ifaceState.from_str(ops[0]), |
a6f80f0e | 388 | ifaceStatus.ERROR) |
389 | return -1 | |
390 | ||
a6f80f0e | 391 | # Run all sub operations sequentially |
392 | try: | |
be0b20f2 | 393 | ifupdownobj.logger.debug('%s:' %ifacename + |
394 | ' running sub-operations') | |
395 | cls.run_iface_ops(ifupdownobj, ifaceobj, op) | |
a6f80f0e | 396 | except Exception, e: |
be0b20f2 | 397 | ifupdownobj.logger.error('%s:' %ifacename + |
a6f80f0e | 398 | ' error running sub operations (%s)' %str(e)) |
399 | ||
be0b20f2 | 400 | cls.release_token(ifacename) |
a6f80f0e | 401 | |
be0b20f2 | 402 | @classmethod |
403 | def run_iface_list_parallel(cls, parent, ifupdownobj, ifacenames, op): | |
a6f80f0e | 404 | """ Runs interface list in parallel """ |
405 | ||
406 | running_threads = OrderedDict() | |
407 | err = 0 | |
408 | ||
409 | for ifacename in ifacenames: | |
410 | try: | |
be0b20f2 | 411 | cls.accquire_token(parent) |
a6f80f0e | 412 | running_threads[ifacename] = Thread(None, |
be0b20f2 | 413 | cls.run_iface_parallel, ifacename, |
a6f80f0e | 414 | args=(ifupdownobj, ifacename, op)) |
415 | running_threads[ifacename].start() | |
be0b20f2 | 416 | cls.release_token(parent) |
a6f80f0e | 417 | except Exception, e: |
be0b20f2 | 418 | cls.release_token(parent) |
d08d5f54 | 419 | if ifupdownobj.ignore_error(str(e)): |
a6f80f0e | 420 | pass |
421 | else: | |
422 | raise Exception('error starting thread for iface %s' | |
423 | %ifacename) | |
424 | ||
425 | ||
be0b20f2 | 426 | ifupdownobj.logger.debug('%s ' %parent + |
427 | 'waiting for all the threads ...') | |
a6f80f0e | 428 | for ifacename, t in running_threads.items(): |
429 | t.join() | |
430 | if ifupdownobj.get_iface_status(ifacename) != ifaceStatus.SUCCESS: | |
431 | err += 1 | |
432 | ||
433 | return err | |
434 | ||
be0b20f2 | 435 | @classmethod |
436 | def run_iface_graphs_parallel(cls, parent, ifupdownobj, ifacenames, op): | |
a6f80f0e | 437 | """ Runs iface graphs in parallel """ |
438 | ||
439 | running_threads = OrderedDict() | |
440 | err = 0 | |
441 | ||
442 | for ifacename in ifacenames: | |
443 | try: | |
be0b20f2 | 444 | cls.accquire_graph_token(parent) |
a6f80f0e | 445 | running_threads[ifacename] = Thread(None, |
be0b20f2 | 446 | cls.run_iface_parallel, ifacename, |
a6f80f0e | 447 | args=(ifupdownobj, ifacename, op)) |
448 | running_threads[ifacename].start() | |
be0b20f2 | 449 | cls.release_graph_token(parent) |
a6f80f0e | 450 | except Exception, e: |
be0b20f2 | 451 | cls.release_graph_token(parent) |
d08d5f54 | 452 | if ifupdownobj.ignore_error(str(e)): |
a6f80f0e | 453 | pass |
454 | else: | |
455 | raise Exception('error starting thread for iface %s' | |
456 | %ifacename) | |
457 | ||
be0b20f2 | 458 | ifupdownobj.logger.info('%s ' %parent + |
459 | 'waiting for all the threads ...') | |
460 | for ifacename, t in running_threads.items(): | |
a6f80f0e | 461 | t.join() |
462 | # Check status of thread | |
463 | # XXX: Check all objs | |
464 | if ifupdownobj.get_iface_status(ifacename) != ifaceStatus.SUCCESS: | |
465 | err += 1 | |
a6f80f0e | 466 | return err |
467 | ||
be0b20f2 | 468 | @classmethod |
469 | def run_iface_dependency_graph_parallel(cls, ifupdownobj, dependency_graph, | |
a6f80f0e | 470 | operation): |
471 | """ Runs iface dependeny graph in parallel. | |
472 | ||
473 | arguments: | |
474 | ifupdownobj -- ifupdown object (used for getting and updating iface | |
475 | object state) | |
476 | dependency_graph -- dependency graph with | |
477 | operation -- 'up' or 'down' or 'query' | |
478 | ||
479 | """ | |
480 | ||
be0b20f2 | 481 | ifupdownobj.logger.debug('running dependency graph in parallel ..') |
a6f80f0e | 482 | run_queue = [] |
a6f80f0e | 483 | # Build a list of ifaces that dont have any dependencies |
484 | for ifacename in dependency_graph.keys(): | |
485 | if ifupdownobj.get_iface_refcnt(ifacename) == 0: | |
486 | run_queue.append(ifacename) | |
487 | ||
be0b20f2 | 488 | ifupdownobj.logger.debug('graph roots (interfaces that dont' |
d08d5f54 | 489 | ' have dependents):' + ' %s' %str(run_queue)) |
be0b20f2 | 490 | cls.init_tokens(ifupdownobj.get_njobs()) |
491 | return cls.run_iface_list_parallel('main', ifupdownobj, run_queue, | |
a6f80f0e | 492 | operation) |
493 | ||
494 | # OR | |
495 | # Run one graph at a time | |
496 | #for iface in run_queue: | |
497 | # self.run_iface_list_parallel('main', ifupdownobj, [iface], | |
498 | # operation) | |
499 |