]>
git.proxmox.com Git - mirror_ifupdown2.git/blob - pkg/scheduler.py
3 # Copyright 2013. Cumulus Networks, Inc.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
10 from statemanager
import *
13 from collections
import deque
14 from collections
import OrderedDict
19 from collections
import deque
20 from threading
import *
21 from ifupdownbase
import *
23 class ifaceSchedulerFlags():
27 class ifaceScheduler():
28 """ scheduler functions to schedule configuration of interfaces.
30 supports scheduling of interfaces serially in plain interface list
31 or dependency graph format.
39 def run_iface_op(cls
, ifupdownobj
, ifaceobj
, op
, cenv
):
40 """ Runs sub operation on an interface """
41 ifacename
= ifaceobj
.name
43 if (cls
._STATE
_CHECK
and
44 (ifaceobj
.state
>= ifaceState
.from_str(op
)) and
45 (ifaceobj
.status
== ifaceStatus
.SUCCESS
)):
46 ifupdownobj
.logger
.debug('%s: already in state %s' %(ifacename
, op
))
49 # first run ifupdownobj handlers
50 handler
= ifupdownobj
.ops_handlers
.get(op
)
52 if not ifaceobj
.addr_method
or (ifaceobj
.addr_method
and
53 ifaceobj
.addr_method
!= 'manual'):
54 handler(ifupdownobj
, ifaceobj
)
56 if not ifupdownobj
.ADDONS_ENABLE
: return
58 for mname
in ifupdownobj
.module_ops
.get(op
):
59 m
= ifupdownobj
.modules
.get(mname
)
63 msg
= ('%s: %s : running module %s' %(ifacename
, op
, mname
))
64 if op
== 'query-checkcurr':
65 # Dont check curr if the interface object was
67 if (ifaceobj
.priv_flags
& ifupdownobj
.NOCONFIG
):
69 ifupdownobj
.logger
.debug(msg
)
71 query_ifaceobj
=ifupdownobj
.create_n_save_ifaceobjcurr(ifaceobj
))
73 ifupdownobj
.logger
.debug(msg
)
77 ifupdownobj
.log_error(str(e
))
80 ifaceobj
.set_state_n_status(ifaceState
.from_str(op
),
83 ifaceobj
.set_state_n_status(ifaceState
.from_str(op
),
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'
90 %(ifacename
, op
, mname
))
92 ifupdownobj
.exec_command(mname
, cmdenv
=cenv
)
94 ifupdownobj
.log_error(str(e
))
97 def run_iface_ops(cls
, ifupdownobj
, ifaceobj
, ops
):
98 """ Runs all operations on an interface """
99 ifacename
= ifaceobj
.name
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
)
106 if ifupdownobj
.COMPAT_EXEC_SCRIPTS
:
107 # For backward compatibility generate env variables
109 cenv
= ifupdownobj
.generate_running_env(ifaceobj
, ops
[0])
110 map(lambda op
: cls
.run_iface_op(ifupdownobj
, ifaceobj
, op
, cenv
), ops
)
111 posthookfunc
= ifupdownobj
.sched_hooks
.get('posthook')
113 posthookfunc(ifupdownobj
, ifaceobj
, ops
[0])
116 def _check_upperifaces(cls
, ifupdownobj
, ifaceobj
, ops
, parent
,
117 followdependents
=False):
118 """ Check if conflicting upper ifaces are around and warn if required
120 Returns False if this interface needs to be skipped,
123 # XXX: simply return for now, the warnings this function prints
124 # are very confusing. Get rid of this function soon
127 if 'up' in ops
[0] and followdependents
:
130 # Deal with upperdevs first
131 ulist
= ifaceobj
.upperifaces
133 tmpulist
= ([u
for u
in ulist
if u
!= parent
] if parent
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
142 if ifupdownobj
.link_exists(u
):
143 if not ifupdownobj
.FORCE
and not ifupdownobj
.ALL
:
144 ifupdownobj
.logger
.warn('%s: ' %ifaceobj
.name
+
145 'upperiface %s still around' %u)
147 elif 'up' in ops
[0] and not ifupdownobj
.ALL
:
148 # For 'up', just warn that there is an upperdev which is
151 if not ifupdownobj
.link_exists(u
):
152 ifupdownobj
.logger
.warn('%s: ' %ifaceobj
.name
+
153 'upper iface %s does not exist' %u)
157 def run_iface_graph(cls
, ifupdownobj
, ifacename
, ops
, parent
=None,
158 order
=ifaceSchedulerFlags
.POSTORDER
,
159 followdependents
=True):
160 """ runs interface by traversing all nodes rooted at itself """
162 # Each ifacename can have a list of iface objects
163 ifaceobjs
= ifupdownobj
.get_ifaceobjs(ifacename
)
165 raise Exception('%s: not found' %ifacename
)
167 for ifaceobj
in ifaceobjs
:
168 if not cls
._check
_upperifaces
(ifupdownobj
, ifaceobj
,
169 ops
, parent
, followdependents
):
171 if order
== ifaceSchedulerFlags
.INORDER
:
172 # If inorder, run the iface first and then its dependents
173 cls
.run_iface_ops(ifupdownobj
, ifaceobj
, ops
)
175 # Run lowerifaces or dependents
176 dlist
= ifaceobj
.lowerifaces
178 ifupdownobj
.logger
.debug('%s: found dependents %s'
179 %(ifacename
, str(dlist
)))
181 if not followdependents
:
182 # XXX: this is yet another extra step,
183 # but is needed for interfaces that are
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
187 new_dlist
= [d
for d
in dlist
188 if ifupdownobj
.is_iface_noconfig(d
)]
190 cls
.run_iface_list(ifupdownobj
, new_dlist
, ops
,
193 continueonfailure
=False)
195 cls
.run_iface_list(ifupdownobj
, dlist
, ops
,
198 continueonfailure
=False)
200 if (ifupdownobj
.ignore_error(str(e
))):
203 # Dont bring the iface up if children did not come up
204 ifaceobj
.set_state_n_status(ifaceState
.NEW
,
207 if order
== ifaceSchedulerFlags
.POSTORDER
:
208 cls
.run_iface_ops(ifupdownobj
, ifaceobj
, ops
)
211 def run_iface_list(cls
, ifupdownobj
, ifacenames
,
212 ops
, parent
=None, order
=ifaceSchedulerFlags
.POSTORDER
,
213 followdependents
=True, continueonfailure
=True):
214 """ Runs interface list """
216 for ifacename
in ifacenames
:
218 cls
.run_iface_graph(ifupdownobj
, ifacename
, ops
, parent
,
219 order
, followdependents
)
221 if continueonfailure
:
222 if ifupdownobj
.logger
.isEnabledFor(logging
.DEBUG
):
223 traceback
.print_tb(sys
.exc_info()[2])
224 ifupdownobj
.logger
.error('%s : %s' %(ifacename
, str(e
)))
227 if (ifupdownobj
.ignore_error(str(e
))):
230 raise Exception('%s : (%s)' %(ifacename
, str(e
)))
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 """
237 # Each ifacename can have a list of iface objects
238 ifaceobjs
= ifupdownobj
.get_ifaceobjs(ifacename
)
240 raise Exception('%s: not found' %ifacename
)
242 for ifaceobj
in ifaceobjs
:
244 # run the iface first and then its upperifaces
245 cls
.run_iface_ops(ifupdownobj
, ifaceobj
, ops
)
248 ulist
= ifaceobj
.upperifaces
250 ifupdownobj
.logger
.debug('%s: found upperifaces %s'
251 %(ifacename
, str(ulist
)))
253 cls
.run_iface_list_upper(ifupdownobj
, ulist
, ops
,
256 continueonfailure
=True)
258 if (ifupdownobj
.ignore_error(str(e
))):
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 """
269 for ifacename
in ifacenames
:
271 cls
.run_iface_graph_upper(ifupdownobj
, ifacename
, ops
, parent
,
272 followdependents
, skip_root
)
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
)))
280 if (ifupdownobj
.ignore_error(str(e
))):
283 raise Exception('%s : (%s)' %(ifacename
, str(e
)))
286 def sched_ifaces(cls
, ifupdownobj
, ifacenames
, ops
,
287 dependency_graph
=None, indegrees
=None,
288 order
=ifaceSchedulerFlags
.POSTORDER
,
289 followdependents
=True):
290 """ Runs iface dependeny graph by visiting all the nodes
294 ifupdownobj : ifupdown object (used for getting and updating iface
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']
300 indegrees : indegree array if present is used to determine roots
301 of the graphs in the dependency_graph
304 if not ifupdownobj
.ALL
or not followdependents
or len(ifacenames
) == 1:
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
)]
311 cls
.run_iface_list(ifupdownobj
, ifacenames
, ops
,
312 parent
=None,order
=order
,
313 followdependents
=followdependents
)
314 if (not ifupdownobj
.ALL
and
315 (followdependents
or followupperifaces
) and 'up' in ops
[0]):
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
,
322 cls
._STATE
_CHECK
= True
326 # Get a sorted list of all interfaces
328 indegrees
= OrderedDict()
329 for ifacename
in dependency_graph
.keys():
330 indegrees
[ifacename
] = ifupdownobj
.get_iface_refcnt(ifacename
)
331 sorted_ifacenames
= graph
.topological_sort_graphs_all(dependency_graph
,
333 ifupdownobj
.logger
.debug('sorted ifacenames %s : '
334 %str
(sorted_ifacenames
))
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
)]
343 ifupdownobj
.logger
.debug('graph roots (interfaces that dont have '
344 'dependents):' + ' %s' %str
(run_queue
))
345 cls
.run_iface_list(ifupdownobj
, run_queue
, ops
,
346 parent
=None,order
=order
,
347 followdependents
=followdependents
)