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