]>
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
)
117 def _check_upperifaces(cls
, ifupdownobj
, ifaceobj
, ops
, parent
,
118 followdependents
=False):
119 """ Check if conflicting upper ifaces are around and warn if required
121 Returns False if this interface needs to be skipped,
124 # XXX: simply return for now, the warnings this function prints
125 # are very confusing. Get rid of this function soon
128 if 'up' in ops
[0] and followdependents
:
131 # Deal with upperdevs first
132 ulist
= ifaceobj
.upperifaces
134 tmpulist
= ([u
for u
in ulist
if u
!= parent
] if parent
139 # XXX: This is expensive. Find a cheaper way to do this
140 # if any of the upperdevs are present,
141 # dont down this interface
143 if ifupdownobj
.link_exists(u
):
144 if not ifupdownobj
.FORCE
and not ifupdownobj
.ALL
:
145 ifupdownobj
.logger
.warn('%s: ' %ifaceobj
.name
+
146 'upperiface %s still around' %u)
148 elif 'up' in ops
[0] and not ifupdownobj
.ALL
:
149 # For 'up', just warn that there is an upperdev which is
152 if not ifupdownobj
.link_exists(u
):
153 ifupdownobj
.logger
.warn('%s: ' %ifaceobj
.name
+
154 'upper iface %s does not exist' %u)
158 def run_iface_graph(cls
, ifupdownobj
, ifacename
, ops
, parent
=None,
159 order
=ifaceSchedulerFlags
.POSTORDER
,
160 followdependents
=True):
161 """ runs interface by traversing all nodes rooted at itself """
163 # Each ifacename can have a list of iface objects
164 ifaceobjs
= ifupdownobj
.get_ifaceobjs(ifacename
)
166 raise Exception('%s: not found' %ifacename
)
168 for ifaceobj
in ifaceobjs
:
169 if not cls
._check
_upperifaces
(ifupdownobj
, ifaceobj
,
170 ops
, parent
, followdependents
):
172 if order
== ifaceSchedulerFlags
.INORDER
:
173 # If inorder, run the iface first and then its dependents
174 cls
.run_iface_ops(ifupdownobj
, ifaceobj
, ops
)
176 # Run lowerifaces or dependents
177 dlist
= ifaceobj
.lowerifaces
179 ifupdownobj
.logger
.debug('%s: found dependents %s'
180 %(ifacename
, str(dlist
)))
182 if not followdependents
:
183 # XXX: this is yet another extra step,
184 # but is needed for interfaces that are
185 # implicit dependents. even though we are asked to
186 # not follow dependents, we must follow the ones
187 # that dont have user given config. Because we own them
188 new_dlist
= [d
for d
in dlist
189 if ifupdownobj
.is_iface_noconfig(d
)]
191 cls
.run_iface_list(ifupdownobj
, new_dlist
, ops
,
194 continueonfailure
=False)
196 cls
.run_iface_list(ifupdownobj
, dlist
, ops
,
199 continueonfailure
=False)
201 if (ifupdownobj
.ignore_error(str(e
))):
204 # Dont bring the iface up if children did not come up
205 ifaceobj
.set_state_n_status(ifaceState
.NEW
,
208 if order
== ifaceSchedulerFlags
.POSTORDER
:
209 cls
.run_iface_ops(ifupdownobj
, ifaceobj
, ops
)
212 def run_iface_list(cls
, ifupdownobj
, ifacenames
,
213 ops
, parent
=None, order
=ifaceSchedulerFlags
.POSTORDER
,
214 followdependents
=True, continueonfailure
=True):
215 """ Runs interface list """
217 for ifacename
in ifacenames
:
219 cls
.run_iface_graph(ifupdownobj
, ifacename
, ops
, parent
,
220 order
, followdependents
)
222 if continueonfailure
:
223 if ifupdownobj
.logger
.isEnabledFor(logging
.DEBUG
):
224 traceback
.print_tb(sys
.exc_info()[2])
225 ifupdownobj
.logger
.error('%s : %s' %(ifacename
, str(e
)))
228 if (ifupdownobj
.ignore_error(str(e
))):
231 raise Exception('error running iface %s (%s)'
232 %(ifacename
, str(e
)))
235 def run_iface_graph_upper(cls
, ifupdownobj
, ifacename
, ops
, parent
=None,
236 followdependents
=True, skip_root
=False):
237 """ runs interface by traversing all nodes rooted at itself """
239 # Each ifacename can have a list of iface objects
240 ifaceobjs
= ifupdownobj
.get_ifaceobjs(ifacename
)
242 raise Exception('%s: not found' %ifacename
)
244 for ifaceobj
in ifaceobjs
:
246 # run the iface first and then its upperifaces
247 cls
.run_iface_ops(ifupdownobj
, ifaceobj
, ops
)
250 ulist
= ifaceobj
.upperifaces
252 ifupdownobj
.logger
.debug('%s: found upperifaces %s'
253 %(ifacename
, str(ulist
)))
255 cls
.run_iface_list_upper(ifupdownobj
, ulist
, ops
,
258 continueonfailure
=True)
260 if (ifupdownobj
.ignore_error(str(e
))):
266 def run_iface_list_upper(cls
, ifupdownobj
, ifacenames
,
267 ops
, parent
=None, followdependents
=True,
268 continueonfailure
=True, skip_root
=False):
269 """ Runs interface list """
271 for ifacename
in ifacenames
:
273 cls
.run_iface_graph_upper(ifupdownobj
, ifacename
, ops
, parent
,
274 followdependents
, skip_root
)
276 if continueonfailure
:
277 if ifupdownobj
.logger
.isEnabledFor(logging
.DEBUG
):
278 traceback
.print_tb(sys
.exc_info()[2])
279 ifupdownobj
.logger
.error('%s : %s' %(ifacename
, str(e
)))
282 if (ifupdownobj
.ignore_error(str(e
))):
285 raise Exception('error running iface %s (%s)'
286 %(ifacename
, str(e
)))
289 def sched_ifaces(cls
, ifupdownobj
, ifacenames
, ops
,
290 dependency_graph
=None, indegrees
=None,
291 order
=ifaceSchedulerFlags
.POSTORDER
,
292 followdependents
=True):
293 """ Runs iface dependeny graph by visiting all the nodes
297 ifupdownobj : ifupdown object (used for getting and updating iface
299 dependency_graph : dependency graph in adjacency list
300 format (contains more than one dependency graph)
301 ops : list of operations to perform eg ['pre-up', 'up', 'post-up']
303 indegrees : indegree array if present is used to determine roots
304 of the graphs in the dependency_graph
307 if not ifupdownobj
.ALL
or not followdependents
or len(ifacenames
) == 1:
308 # If there is any interface that does exist, maybe it is a
309 # logical interface and we have to followupperifaces
310 followupperifaces
= (True if
311 [i
for i
in ifacenames
312 if not ifupdownobj
.link_exists(i
)]
314 cls
.run_iface_list(ifupdownobj
, ifacenames
, ops
,
315 parent
=None,order
=order
,
316 followdependents
=followdependents
)
317 if (not ifupdownobj
.ALL
and
318 (followdependents
or followupperifaces
) and 'up' in ops
[0]):
319 # If user had given a set of interfaces to bring up
320 # try and execute 'up' on the upperifaces
321 ifupdownobj
.logger
.info('running upperifaces if available')
322 cls
._STATE
_CHECK
= False
323 cls
.run_iface_list_upper(ifupdownobj
, ifacenames
, ops
,
325 cls
._STATE
_CHECK
= True
329 # Get a sorted list of all interfaces
331 indegrees
= OrderedDict()
332 for ifacename
in dependency_graph
.keys():
333 indegrees
[ifacename
] = ifupdownobj
.get_iface_refcnt(ifacename
)
334 sorted_ifacenames
= graph
.topological_sort_graphs_all(dependency_graph
,
336 ifupdownobj
.logger
.debug('sorted ifacenames %s : '
337 %str
(sorted_ifacenames
))
339 # From the sorted list, pick interfaces that user asked
340 # and those that dont have any dependents first
341 [run_queue
.append(ifacename
)
342 for ifacename
in sorted_ifacenames
343 if ifacename
in ifacenames
and
344 not indegrees
.get(ifacename
)]
346 ifupdownobj
.logger
.debug('graph roots (interfaces that dont have '
347 'dependents):' + ' %s' %str
(run_queue
))
348 cls
.run_iface_list(ifupdownobj
, run_queue
, ops
,
349 parent
=None,order
=order
,
350 followdependents
=followdependents
)