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