]>
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 | # ifupdownMain -- | |
7 | # ifupdown main module | |
8 | # | |
a6f80f0e | 9 | |
10 | import os | |
11 | import re | |
3e8ee54f | 12 | import imp |
13 | import pprint | |
14 | import logging | |
15 | import sys, traceback | |
a6f80f0e | 16 | from statemanager import * |
17 | from networkinterfaces import * | |
18 | from iface import * | |
19 | from scheduler import * | |
20 | from collections import deque | |
21 | from collections import OrderedDict | |
a6f80f0e | 22 | from graph import * |
3e8ee54f | 23 | from sets import Set |
a6f80f0e | 24 | |
3e8ee54f | 25 | class ifupdownMain(): |
a6f80f0e | 26 | |
27 | # Flags | |
a6f80f0e | 28 | NODEPENDS = False |
29 | ALL = False | |
eab25b7c | 30 | STATE_CHECK = False |
a6f80f0e | 31 | |
32 | modules_dir='/etc/network' | |
33 | builtin_modules_dir='/usr/share/ifupdownaddons' | |
34 | ||
35 | # iface dictionary in the below format: | |
36 | # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] } | |
37 | # eg: | |
38 | # { 'swp1' : [<ifaceobject1>, <ifaceobject2> ..] } | |
39 | # | |
40 | # Each ifaceobject corresponds to a configuration block for | |
41 | # that interface | |
42 | ifaceobjdict = OrderedDict() | |
43 | ||
44 | ||
45 | # iface dictionary representing the curr running state of an iface | |
46 | # in the below format: | |
47 | # {'<ifacename>' : <ifaceobject>} | |
48 | ifaceobjcurrdict = OrderedDict() | |
49 | ||
50 | # Dictionary representing operation, sub operation and modules | |
51 | # for every sub operation | |
52 | operations = { 'up' : | |
53 | OrderedDict([('pre-up', OrderedDict({})), | |
54 | ('up' , OrderedDict({})), | |
55 | ('post-up' , OrderedDict({}))]), | |
739f665b | 56 | 'query-checkcurr' : |
57 | OrderedDict([('query-checkcurr', OrderedDict({}))]), | |
58 | ||
59 | 'query-running' : | |
60 | OrderedDict([('query-running', OrderedDict({}))]), | |
61 | ||
a6f80f0e | 62 | 'down' : |
63 | OrderedDict([('pre-down', OrderedDict({})), | |
64 | ('down' , OrderedDict({})), | |
65 | ('post-down' , OrderedDict({}))])} | |
66 | ||
67 | ||
eab25b7c | 68 | def __init__(self, force=False, dryrun=False, nowait=False, |
739f665b | 69 | perfmode=False, nodepends=False, njobs=1, |
70 | format='nwifaces', cache=False): | |
a6f80f0e | 71 | self.logger = logging.getLogger('ifupdown') |
72 | ||
eab25b7c | 73 | self.FORCE = force |
74 | self.DRYRUN = dryrun | |
75 | self.NOWAIT = nowait | |
76 | self.PERFMODE = perfmode | |
77 | self.NODEPENDS = nodepends | |
739f665b | 78 | self.CACHE = cache |
79 | self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = True | |
eab25b7c | 80 | |
a6f80f0e | 81 | self.ifaces = OrderedDict() |
eab25b7c | 82 | self.njobs = njobs |
a6f80f0e | 83 | self.pp = pprint.PrettyPrinter(indent=4) |
84 | self.load_modules_builtin(self.builtin_modules_dir) | |
85 | self.load_modules(self.modules_dir) | |
86 | ||
87 | try: | |
88 | self.statemanager = stateManager() | |
89 | self.statemanager.read_saved_state() | |
90 | except Exception, e: | |
91 | # XXX Maybe we should continue by ignoring old state | |
92 | self.logger.warning('error reading state (%s)' %str(e)) | |
93 | raise | |
94 | ||
95 | def get_subops(self, op): | |
96 | """ Returns sub-operation list """ | |
97 | return self.operations.get(op).keys() | |
98 | ||
99 | def compat_conv_op_to_mode(self, op): | |
100 | """ Returns old op name to work with existing scripts """ | |
101 | if op == 'up': | |
102 | return 'start' | |
103 | elif op == 'down': | |
104 | return 'stop' | |
105 | else: | |
106 | return op | |
107 | ||
108 | def set_force(self, force): | |
109 | """ Set force flag. """ | |
110 | if force == True: | |
111 | self.logger.debug('setting force to true') | |
112 | self.FORCE = force | |
113 | ||
114 | def get_force(self): | |
115 | """ return force flag. """ | |
116 | return self.FORCE | |
117 | ||
118 | def set_dryrun(self, dryrun): | |
119 | if dryrun == True: | |
120 | self.logger.debug('setting dryrun to true') | |
121 | self.DRYRUN = dryrun | |
122 | ||
123 | def get_dryrun(self): | |
124 | return self.DRYRUN | |
125 | ||
739f665b | 126 | def get_cache(self): |
127 | return self.CACHE | |
128 | ||
129 | def get_ifaceobjdict(self): | |
130 | return self.ifaceobjdict | |
131 | ||
132 | def set_ifaceobjdict(self, ifaceobjdict): | |
133 | del self.ifaceobjdict | |
134 | self.ifaceobjdict = ifaceobjdict | |
135 | ||
eab25b7c | 136 | def set_perfmode(self, perfmode): |
137 | if perfmode == True: | |
138 | self.logger.debug('setting perfmode to true') | |
139 | self.PERFMODE = perfmode | |
140 | ||
141 | def get_perfmode(self): | |
142 | return self.PERFMODE | |
143 | ||
a6f80f0e | 144 | def set_nowait(self, nowait): |
145 | if nowait == True: | |
146 | self.logger.debug('setting dryrun to true') | |
147 | self.NOWAIT = nowait | |
148 | ||
149 | def get_nowait(self): | |
150 | return self.NOWAIT | |
151 | ||
152 | def set_njobs(self, njobs): | |
153 | self.logger.debug('setting njobs to %d' %njobs) | |
154 | self.njobs = njobs | |
155 | ||
156 | def get_njobs(self): | |
157 | return self.njobs | |
158 | ||
a6f80f0e | 159 | def get_nodepends(self): |
160 | return self.NODEPENDS | |
161 | ||
162 | def set_nodepends(self, nodepends): | |
163 | self.logger.debug('setting nodepends to true') | |
164 | self.NODEPENDS = nodepends | |
165 | ||
166 | def set_iface_state(self, ifaceobj, state, status): | |
167 | ifaceobj.set_state(state) | |
168 | ifaceobj.set_status(status) | |
169 | self.statemanager.update_iface_state(ifaceobj) | |
170 | ||
171 | def get_iface_objs(self, ifacename): | |
172 | return self.ifaceobjdict.get(ifacename) | |
173 | ||
174 | def get_iface_obj_first(self, ifacename): | |
175 | ifaceobjs = self.get_iface_objs(ifacename) | |
176 | if ifaceobjs is not None: | |
177 | return ifaceobjs[0] | |
178 | return None | |
179 | ||
180 | def get_iface_obj_last(self, ifacename): | |
181 | return self.ifaceobjdict.get(ifacename)[-1] | |
182 | ||
739f665b | 183 | def create_ifaceobjcurr(self, ifaceobj): |
184 | ifacename = ifaceobj.get_name() | |
185 | ifaceobjcurr = self.get_ifaceobjcurr(ifacename) | |
186 | if ifaceobjcurr is not None: | |
187 | return ifaceobjcurr | |
a6f80f0e | 188 | |
739f665b | 189 | ifaceobjcurr = iface() |
190 | ifaceobjcurr.set_name(ifacename) | |
191 | ifaceobjcurr.set_dependents(ifaceobj.get_dependents()) | |
192 | self.ifaceobjcurrdict[ifacename] = ifaceobjcurr | |
a6f80f0e | 193 | |
194 | return ifaceobj | |
195 | ||
196 | def get_ifaceobjcurr(self, ifacename): | |
197 | return self.ifaceobjcurrdict.get(ifacename) | |
198 | ||
739f665b | 199 | |
200 | def get_ifaceobjrunning(self, ifacename): | |
201 | return self.ifaceobjrunningdict.get(ifacename) | |
202 | ||
a6f80f0e | 203 | def get_iface_status(self, ifacename): |
204 | ifaceobjs = self.get_iface_objs(ifacename) | |
205 | for i in ifaceobjs: | |
206 | if i.get_status() != ifaceStatus.SUCCESS: | |
207 | return i.get_status() | |
208 | ||
209 | return ifaceStatus.SUCCESS | |
210 | ||
211 | def get_iface_refcnt(self, ifacename): | |
212 | max = 0 | |
213 | ifaceobjs = self.get_iface_objs(ifacename) | |
214 | for i in ifaceobjs: | |
215 | if i.get_refcnt() > max: | |
216 | max = i.get_refcnt() | |
217 | return max | |
218 | ||
739f665b | 219 | def create_n_save_ifaceobj(self, ifacename, increfcnt=False): |
a6f80f0e | 220 | """ creates and returns a fake vlan iface object. |
739f665b | 221 | This was added to support creation of simple vlan |
222 | devices without any user specified configuration. | |
a6f80f0e | 223 | """ |
739f665b | 224 | ifaceobj = iface() |
225 | ifaceobj.set_name(ifacename) | |
226 | if increfcnt == True: | |
227 | ifaceobj.inc_refcnt() | |
228 | self.ifaceobjdict[ifacename] = [ifaceobj] | |
a6f80f0e | 229 | |
230 | def is_vlan_device(self, ifacename): | |
231 | """ Returns true if iface name is a vlan interface. | |
232 | ||
233 | only supports vlan interfaces of the format <ifacename>.<vlanid> | |
234 | ||
235 | """ | |
236 | if (re.search(r'\.', ifacename, 0) is not None): | |
237 | return True | |
238 | return False | |
239 | ||
240 | def preprocess_dependency_list(self, dlist, op): | |
739f665b | 241 | """ We go through the dependency list and |
242 | delete or add interfaces from the interfaces dict by | |
243 | applying the following rules: | |
244 | if flag _DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is True: | |
245 | we only consider devices whose configuration was | |
246 | specified in the network interfaces file. We delete | |
247 | any interface whose config was not specified except | |
248 | for vlan devices. vlan devices get special treatment. | |
249 | Even if they are not present they are created and added | |
250 | to the ifacesdict | |
251 | elif flag _DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is False: | |
252 | we create objects for all dependent devices that are not | |
253 | present in the ifacesdict | |
254 | """ | |
a6f80f0e | 255 | del_list = [] |
739f665b | 256 | create_list = [] |
a6f80f0e | 257 | |
258 | self.logger.debug('pre-processing dependency list: %s' %list(dlist)) | |
259 | for d in dlist: | |
260 | dilist = self.get_iface_objs(d) | |
261 | if dilist == None: | |
739f665b | 262 | if (self.is_vlan_device(d) == True or |
263 | self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG == False): | |
264 | create_list.append(d) | |
a6f80f0e | 265 | else: |
a6f80f0e | 266 | del_list.append(d) |
267 | else: | |
268 | for di in dilist: | |
269 | di.inc_refcnt() | |
270 | ||
271 | for d in del_list: | |
272 | dlist.remove(d) | |
273 | ||
739f665b | 274 | # create fake devices to all dependents that dont have config |
275 | map(lambda i: self.create_n_save_ifaceobj(i, increfcnt=True), | |
276 | create_list) | |
277 | ||
a6f80f0e | 278 | self.logger.debug('After Processing dependency list: %s' |
279 | %list(dlist)) | |
280 | ||
a6f80f0e | 281 | def get_dependents(self, ifaceobj, op): |
282 | """ Gets iface dependents by calling into respective modules """ | |
283 | dlist = None | |
284 | ||
285 | self.logger.debug('%s: ' %ifaceobj.get_name() + 'getting dependency') | |
286 | ||
287 | # Get dependents for interface by querying respective modules | |
288 | subopdict = self.operations.get(op) | |
289 | for subop, mdict in subopdict.items(): | |
290 | for mname, mdata in mdict.items(): | |
291 | if mdata.get('ftype') == 'pmodule': | |
292 | module = mdata.get('module') | |
739f665b | 293 | if op == 'query-running': |
294 | if (hasattr(module, | |
295 | 'get_dependent_ifacenames_running') == False): | |
296 | continue | |
297 | dlist = module.get_dependent_ifacenames_running( | |
298 | ifaceobj) | |
299 | else: | |
300 | if (hasattr(module, | |
301 | 'get_dependent_ifacenames') == False): | |
302 | continue | |
303 | dlist = module.get_dependent_ifacenames(ifaceobj, | |
304 | self.ifaceobjdict.keys()) | |
579b3f25 | 305 | if dlist is not None: |
739f665b | 306 | ifaceobj.set_realdev_dependents(dlist[:]) |
a6f80f0e | 307 | self.logger.debug('%s: ' %ifaceobj.get_name() + |
308 | 'got dependency list: %s' %str(dlist)) | |
309 | break | |
a6f80f0e | 310 | return dlist |
311 | ||
a6f80f0e | 312 | def generate_dependency_info(self, ifacenames, dependency_graph, op): |
313 | """ recursive function to generate iface dependency info """ | |
314 | ||
315 | self.logger.debug('generating dependency info for %s' %str(ifacenames)) | |
316 | ||
551a3627 | 317 | iqueue = deque(ifacenames) |
318 | while iqueue: | |
319 | i = iqueue.popleft() | |
320 | ||
a6f80f0e | 321 | # Go through all modules and find dependent ifaces |
322 | dlist = None | |
323 | ifaceobj = self.get_iface_obj_first(i) | |
324 | if ifaceobj is None: | |
325 | continue | |
326 | ||
327 | dlist = ifaceobj.get_dependents() | |
328 | if dlist is None: | |
329 | dlist = self.get_dependents(ifaceobj, op) | |
3e8ee54f | 330 | else: |
3e8ee54f | 331 | continue |
a6f80f0e | 332 | |
10720a53 | 333 | if dlist is not None: |
334 | self.preprocess_dependency_list(dlist, op) | |
335 | ifaceobj.set_dependents(dlist) | |
739f665b | 336 | [iqueue.append(d) for d in dlist] |
a6f80f0e | 337 | |
338 | if dependency_graph.get(i) is None: | |
339 | dependency_graph[i] = dlist | |
340 | ||
a6f80f0e | 341 | def is_valid_state_transition(self, ifname, to_be_state): |
342 | return self.statemanager.is_valid_state_transition(ifname, | |
343 | to_be_state) | |
344 | ||
345 | def save_iface(self, ifaceobj): | |
346 | if self.ifaceobjdict.get(ifaceobj.get_name()) is None: | |
347 | self.ifaceobjdict[ifaceobj.get_name()] = [ifaceobj] | |
348 | else: | |
349 | self.ifaceobjdict[ifaceobj.get_name()].append(ifaceobj) | |
350 | ||
351 | def read_default_iface_config(self): | |
352 | """ Reads default network interface config /etc/network/interfaces. """ | |
353 | nifaces = networkInterfaces() | |
354 | nifaces.subscribe('iface_found', self.save_iface) | |
355 | nifaces.load() | |
356 | ||
357 | def read_iface_config(self): | |
358 | return self.read_default_iface_config() | |
359 | ||
360 | def read_old_iface_config(self): | |
361 | """ Reads the saved iface config instead of default iface config. """ | |
362 | ||
363 | # Read it from the statemanager | |
364 | self.ifaceobjdict = self.statemanager.get_ifaceobjdict() | |
365 | ||
366 | ||
367 | def save_module(self, mkind, msubkind, mname, mftype, module): | |
368 | """ saves a module into internal module dict for later use. | |
369 | ||
370 | mtype - pre-up.d, post-up.d and so on | |
371 | mftype - pmodule (python module), bashscript (bash script) | |
372 | ||
373 | """ | |
374 | ||
739f665b | 375 | try: |
376 | mmetadata = self.operations[mkind][msubkind].get(mname) | |
377 | except KeyError: | |
378 | self.logger.warn('unsupported module type %s' %mname) | |
379 | return | |
380 | ||
a6f80f0e | 381 | if mmetadata is None or mmetadata.get('ftype') != 'pmodule': |
382 | mmetadata = {} | |
383 | mmetadata['ftype'] = mftype | |
384 | mmetadata['module'] = module | |
385 | self.operations[mkind][msubkind][mname] = mmetadata | |
386 | ||
387 | self.logger.debug('saved module %s' %mkind + | |
388 | ' %s' %mname + ' %s' %mftype) | |
389 | else: | |
eab25b7c | 390 | self.logger.info('ignoring module %s' %mkind + ' %s' %msubkind + |
a6f80f0e | 391 | ' %s' %mname + ' of type %s' %mftype) |
392 | ||
393 | ||
394 | def load_modules_builtin(self, modules_dir): | |
395 | """ load python modules from modules_dir | |
396 | ||
397 | Default modules_dir is /usr/share/ifupdownmodules | |
398 | ||
399 | """ | |
400 | ||
401 | self.logger.info('loading builtin modules from %s' %modules_dir) | |
402 | ||
403 | if not modules_dir in sys.path: | |
404 | sys.path.append(modules_dir) | |
405 | try: | |
406 | module_list = os.listdir(modules_dir) | |
407 | for module in module_list: | |
408 | if re.search('.*\.pyc', module, 0) != None: | |
409 | continue | |
410 | ||
411 | mname, mext = os.path.splitext(module) | |
412 | if mext is not None and mext == '.py': | |
413 | self.logger.info('loading ' + modules_dir + '/' + module) | |
414 | try: | |
415 | m = __import__(mname) | |
416 | mclass = getattr(m, mname) | |
417 | except: | |
418 | raise | |
eab25b7c | 419 | |
a6f80f0e | 420 | minstance = mclass(force=self.get_force(), |
421 | dryrun=self.get_dryrun(), | |
eab25b7c | 422 | nowait=self.get_nowait(), |
739f665b | 423 | perfmode=self.get_perfmode(), |
424 | cache=self.get_cache()) | |
a6f80f0e | 425 | ops = minstance.get_ops() |
426 | for op in ops: | |
739f665b | 427 | if re.search('query', op) is not None: |
428 | self.save_module(op, op, mname, 'pmodule', | |
429 | minstance) | |
430 | elif re.search('up', op) is not None: | |
a6f80f0e | 431 | self.save_module('up', op, mname, 'pmodule', |
432 | minstance) | |
433 | else: | |
739f665b | 434 | self.save_module('down', op, mname, |
435 | 'pmodule', minstance) | |
436 | ||
a6f80f0e | 437 | except: |
438 | raise | |
439 | ||
440 | ||
441 | def load_modules(self, modules_dir): | |
442 | """ loading user modules from /etc/network/. | |
443 | ||
444 | Note that previously loaded python modules override modules found | |
445 | under /etc/network if any | |
446 | ||
447 | """ | |
448 | ||
449 | self.logger.info('loading user modules from %s' %modules_dir) | |
450 | for op, subops in self.operations.items(): | |
739f665b | 451 | if re.search('query', op) is not None: |
452 | continue | |
453 | ||
a6f80f0e | 454 | for subop in subops.keys(): |
455 | msubdir = modules_dir + '/if-%s.d' %subop | |
456 | self.logger.info('loading modules under %s ...' %msubdir) | |
457 | try: | |
458 | module_list = os.listdir(msubdir) | |
459 | for module in module_list: | |
460 | if re.search('.*\.pyc', module, 0) != None: | |
461 | continue | |
462 | ||
463 | mname, mext = os.path.splitext(module) | |
464 | if mext is not None and mext == '.py': | |
465 | self.logger.debug('loading ' + msubdir + '/' + module) | |
466 | try: | |
467 | m = imp.load_source(module, | |
468 | msubdir + '/' + module) | |
469 | mclass = getattr(m, mname) | |
470 | except: | |
471 | raise | |
472 | minstance = mclass() | |
473 | self.save_module(op, subop, mname, 'pmodule', | |
474 | minstance) | |
475 | else: | |
476 | self.save_module(op, subop, mname, 'script', | |
477 | msubdir + '/' + module) | |
478 | except: | |
479 | raise | |
480 | ||
481 | #self.logger.debug('modules ...') | |
482 | #self.pp.pprint(self.operations) | |
483 | ||
484 | # For query, we add a special entry, basically use all 'up' modules | |
485 | self.operations['query'] = self.operations.get('up') | |
486 | ||
487 | ||
488 | def conv_iface_namelist_to_objlist(self, intf_list): | |
489 | for intf in intf_list: | |
490 | iface_obj = self.get_iface(intf) | |
491 | if iface_obj == None: | |
492 | raise ifupdownInvalidValue('no iface %s', intf) | |
493 | ||
494 | iface_objs.append(iface_obj) | |
495 | ||
496 | return iface_objs | |
497 | ||
498 | ||
499 | def run_without_dependents(self, op, ifacenames): | |
3e8ee54f | 500 | ifaceSched = ifaceScheduler(force=self.FORCE) |
a6f80f0e | 501 | |
502 | self.logger.debug('run_without_dependents for op %s' %op + | |
503 | ' for %s' %str(ifacenames)) | |
504 | ||
505 | if ifacenames == None: | |
506 | raise ifupdownInvalidValue('no interfaces found') | |
507 | ||
508 | return ifaceSched.run_iface_list(self, ifacenames, op) | |
509 | ||
510 | ||
511 | def run_with_dependents(self, op, ifacenames): | |
512 | dependency_graph = {} | |
513 | ret = 0 | |
514 | self.logger.debug('run_with_dependents for op %s' | |
515 | %op + ' for %s' %str(ifacenames)) | |
516 | ||
517 | ifaceSched = ifaceScheduler() | |
518 | ||
519 | if ifacenames is None: | |
520 | ifacenames = self.ifaceobjdict.keys() | |
521 | ||
522 | # generate dependency graph of interfaces | |
523 | self.generate_dependency_info(ifacenames, dependency_graph, op) | |
524 | ||
525 | if self.logger.isEnabledFor(logging.DEBUG) == True: | |
526 | self.logger.debug('dependency graph:') | |
527 | self.pp.pprint(dependency_graph) | |
528 | ||
529 | if self.njobs > 1: | |
530 | ret = ifaceSched.run_iface_dependency_graph_parallel(self, | |
531 | dependency_graph, op) | |
532 | else: | |
739f665b | 533 | ret = ifaceSched.run_iface_dependency_graph(self, |
534 | dependency_graph, op) | |
a6f80f0e | 535 | return ret |
536 | ||
739f665b | 537 | def print_dependency(self, op, ifacenames, format): |
538 | dependency_graph = {} | |
539 | if ifacenames is None: | |
540 | ifacenames = self.ifaceobjdict.keys() | |
541 | ||
542 | # generate dependency graph of interfaces | |
543 | self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False | |
544 | self.generate_dependency_info(ifacenames, dependency_graph, op) | |
545 | ||
546 | if format == 'list': | |
547 | self.pp.pprint(dependency_graph) | |
548 | elif format == 'dot': | |
549 | indegrees = {} | |
550 | map(lambda i: indegrees.update({i : | |
551 | self.get_iface_refcnt(i)}), | |
552 | dependency_graph.keys()) | |
553 | graph.generate_dots(dependency_graph, indegrees) | |
a6f80f0e | 554 | |
555 | def validate_ifaces(self, ifacenames): | |
556 | """ validates interface list for config existance. | |
557 | ||
558 | returns -1 if one or more interface not found. else, returns 0 | |
559 | ||
560 | """ | |
561 | ||
562 | err_iface = '' | |
563 | for i in ifacenames: | |
564 | ifaceobjs = self.get_iface_objs(i) | |
565 | if ifaceobjs is None: | |
566 | err_iface += ' ' + i | |
567 | ||
568 | if len(err_iface) != 0: | |
eab25b7c | 569 | self.logger.error('did not find interfaces: %s' %err_iface) |
a6f80f0e | 570 | return -1 |
571 | ||
572 | return 0 | |
573 | ||
574 | ||
3e8ee54f | 575 | def iface_whitelisted(self, auto, allow_classes, excludepats, ifacename): |
a6f80f0e | 576 | """ Checks if interface is whitelisted depending on set of parameters. |
577 | ||
578 | ||
579 | interfaces are checked against the allow_classes and auto lists. | |
580 | ||
581 | """ | |
582 | ||
3e8ee54f | 583 | # If the interface matches |
584 | if excludepats is not None and len(excludepats) > 0: | |
585 | for e in excludepats: | |
586 | if re.search(e, ifacename) is not None: | |
587 | return False | |
a6f80f0e | 588 | |
589 | ifaceobjs = self.get_iface_objs(ifacename) | |
590 | if ifaceobjs is None: | |
591 | self.logger.debug('iface %s' %ifacename + ' not found') | |
592 | return False | |
593 | ||
594 | # We check classes first | |
595 | if allow_classes is not None and len(allow_classes) > 0: | |
596 | for i in ifaceobjs: | |
597 | if (len(i.get_classes()) > 0): | |
3e8ee54f | 598 | common = Set([allow_classes]).intersection( |
a6f80f0e | 599 | Set(i.get_classes())) |
600 | if len(common) > 0: | |
601 | return True | |
602 | return False | |
603 | ||
604 | if auto == True: | |
605 | for i in ifaceobjs: | |
606 | if i.get_auto() == True: | |
607 | return True | |
608 | return False | |
609 | ||
610 | return True | |
611 | ||
612 | def generate_running_env(self, ifaceobj, op): | |
739f665b | 613 | """ Generates a dictionary with env variables required for |
614 | an interface. Used to support script execution for interfaces. | |
a6f80f0e | 615 | """ |
616 | ||
617 | cenv = None | |
618 | iface_env = ifaceobj.get_env() | |
619 | if iface_env is not None: | |
620 | cenv = os.environ | |
621 | if cenv is not None: | |
622 | cenv.update(iface_env) | |
623 | else: | |
624 | cenv = iface_env | |
625 | ||
626 | cenv['MODE'] = self.compat_conv_op_to_mode(op) | |
627 | ||
628 | return cenv | |
629 | ||
630 | ||
631 | def run(self, op, auto=False, allow_classes=None, | |
739f665b | 632 | ifacenames=None, excludepats=None, |
633 | format=None, printdependency=None): | |
a6f80f0e | 634 | """ main ifupdown run method """ |
635 | ||
636 | if auto == True: | |
637 | self.logger.debug('setting flag ALL') | |
638 | self.ALL = True | |
639 | ||
640 | # Only read new iface config for 'up' | |
641 | # operations. For 'downs' we only rely on | |
642 | # old state | |
739f665b | 643 | if op == 'query-running': |
644 | # create fake devices to all dependents that dont have config | |
645 | map(lambda i: self.create_n_save_ifaceobj(i), ifacenames) | |
646 | elif op == 'up' or op[:5] == 'query': | |
a6f80f0e | 647 | try: |
648 | self.read_iface_config() | |
649 | except Exception, e: | |
650 | raise | |
739f665b | 651 | elif op == 'down': |
a6f80f0e | 652 | # for down we need to look at old state |
653 | self.logger.debug('down op, looking at old state ..') | |
654 | ||
655 | if len(self.statemanager.get_ifaceobjdict()) > 0: | |
656 | self.read_old_iface_config() | |
657 | elif self.FORCE == True: | |
658 | # If no old state available | |
739f665b | 659 | self.logger.info('old state not available. ' + |
660 | 'Force option set. Loading new iface config file') | |
a6f80f0e | 661 | try: |
662 | self.read_iface_config() | |
663 | except Exception, e: | |
739f665b | 664 | raise Exception('error reading iface config (%s)' |
665 | %str(e)) | |
a6f80f0e | 666 | else: |
667 | raise Exception('old state not available...aborting.' + | |
668 | ' try running with --force option') | |
669 | ||
670 | ||
739f665b | 671 | if ifacenames is not None and op != 'query-running': |
a6f80f0e | 672 | # If iface list is given, always check if iface is present |
673 | if self.validate_ifaces(ifacenames) != 0: | |
eab25b7c | 674 | raise Exception('all or some interfaces not found') |
a6f80f0e | 675 | |
676 | # if iface list not given by user, assume all from config file | |
677 | if ifacenames is None: ifacenames = self.ifaceobjdict.keys() | |
678 | ||
679 | # filter interfaces based on auto and allow classes | |
739f665b | 680 | if op == 'query-running': |
681 | filtered_ifacenames = ifacenames | |
682 | else: | |
683 | filtered_ifacenames = [i for i in ifacenames | |
684 | if self.iface_whitelisted(auto, allow_classes, | |
685 | excludepats, i) == True] | |
a6f80f0e | 686 | |
687 | if len(filtered_ifacenames) == 0: | |
688 | raise Exception('no ifaces found matching ' + | |
689 | 'given allow lists') | |
690 | ||
691 | if op == 'query': | |
739f665b | 692 | return self.print_ifaceobjs_raw(filtered_ifacenames) |
693 | elif op == 'query-presumed': | |
694 | return self.print_ifaceobjs_saved_state_pretty( | |
a6f80f0e | 695 | filtered_ifacenames) |
739f665b | 696 | elif op == 'query-presumeddetailed': |
697 | return self.print_ifaceobjs_saved_state_detailed_pretty( | |
a6f80f0e | 698 | filtered_ifacenames) |
699 | ||
739f665b | 700 | if printdependency is not None: |
701 | self.print_dependency(op, filtered_ifacenames, printdependency) | |
702 | return | |
703 | ||
704 | #if op.split('-')[0] == 'query' or self.NODEPENDS == True: | |
705 | if op.split('-')[0] == 'query' or self.NODEPENDS == True: | |
a6f80f0e | 706 | self.run_without_dependents(op, filtered_ifacenames) |
707 | else: | |
708 | self.run_with_dependents(op, filtered_ifacenames) | |
709 | ||
739f665b | 710 | if op == 'query-checkcurr': |
711 | # print curr state of all interfaces | |
712 | ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames) | |
713 | if ret != 0: | |
714 | # if any of the object has an error, signal that silently | |
715 | raise Exception('') | |
716 | elif op == 'query-running': | |
717 | # print curr state of all interfaces | |
718 | self.print_ifaceobjsrunning_pretty(filtered_ifacenames) | |
a6f80f0e | 719 | return |
720 | ||
721 | # Update persistant iface states | |
722 | try: | |
723 | if self.ALL == True: | |
724 | self.statemanager.flush_state(self.ifaceobjdict) | |
725 | else: | |
726 | self.statemanager.flush_state() | |
727 | except Exception, e: | |
728 | if self.logger.isEnabledFor(logging.DEBUG): | |
729 | t = sys.exc_info()[2] | |
730 | traceback.print_tb(t) | |
731 | self.logger.warning('error saving state (%s)' %str(e)) | |
732 | ||
733 | ||
739f665b | 734 | def up(self, auto=False, allow=None, ifacenames=None, |
735 | excludepats=None, printdependency=None): | |
736 | return self.run('up', auto, allow, ifacenames, | |
737 | excludepats=excludepats, | |
738 | printdependency=printdependency) | |
a6f80f0e | 739 | |
3e8ee54f | 740 | def down(self, auto=False, allow=None, ifacenames=None, excludepats=None): |
741 | return self.run('down', auto, allow, ifacenames, | |
742 | excludepats=excludepats); | |
a6f80f0e | 743 | |
739f665b | 744 | def query(self, op, auto=False, allow_classes=None, ifacenames=None, |
745 | excludepats=None, printdependency=None, | |
746 | format=None): | |
747 | """ main ifupdown run method """ | |
748 | if auto == True: | |
749 | self.logger.debug('setting flag ALL') | |
750 | self.ALL = True | |
751 | ||
752 | if op == 'query-running': | |
753 | self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False | |
754 | # create fake devices to all dependents that dont have config | |
755 | map(lambda i: self.create_n_save_ifaceobj(i), ifacenames) | |
756 | else: | |
757 | try: | |
758 | self.read_iface_config() | |
759 | except Exception: | |
760 | raise | |
761 | ||
762 | if ifacenames is not None and op != 'query-running': | |
763 | # If iface list is given, always check if iface is present | |
764 | if self.validate_ifaces(ifacenames) != 0: | |
765 | raise Exception('all or some interfaces not found') | |
766 | ||
767 | # if iface list not given by user, assume all from config file | |
768 | if ifacenames is None: ifacenames = self.ifaceobjdict.keys() | |
769 | ||
770 | # filter interfaces based on auto and allow classes | |
771 | if op == 'query-running': | |
772 | filtered_ifacenames = ifacenames | |
773 | else: | |
774 | filtered_ifacenames = [i for i in ifacenames | |
775 | if self.iface_whitelisted(auto, allow_classes, | |
776 | excludepats, i) == True] | |
777 | ||
778 | if len(filtered_ifacenames) == 0: | |
779 | raise Exception('no ifaces found matching ' + | |
780 | 'given allow lists') | |
781 | ||
782 | if op == 'query': | |
783 | return self.print_ifaceobjs_raw(filtered_ifacenames) | |
784 | elif op == 'query-presumed': | |
785 | return self.print_ifaceobjs_saved_state_pretty( | |
786 | filtered_ifacenames) | |
787 | elif op == 'query-presumeddetailed': | |
788 | return self.print_ifaceobjs_saved_state_detailed_pretty( | |
789 | filtered_ifacenames) | |
790 | ||
791 | if printdependency is not None: | |
792 | self.print_dependency(op, filtered_ifacenames, printdependency) | |
793 | return | |
794 | ||
795 | if self.NODEPENDS == True: | |
796 | self.run_without_dependents(op, filtered_ifacenames) | |
797 | else: | |
798 | self.run_with_dependents(op, filtered_ifacenames) | |
799 | ||
800 | if op == 'query-checkcurr': | |
801 | ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames) | |
802 | if ret != 0: | |
803 | # if any of the object has an error, signal that silently | |
804 | raise Exception('') | |
805 | elif op == 'query-running': | |
806 | self.print_ifaceobjsrunning_pretty(filtered_ifacenames) | |
807 | return | |
808 | ||
809 | def reload(self, auto=False, allow=None, | |
810 | ifacenames=None, excludepats=None): | |
811 | """ main ifupdown run method """ | |
812 | allow_classes = [] | |
813 | ||
814 | self.logger.debug('reloading interface config ..') | |
815 | ||
816 | if auto == True: | |
817 | self.logger.debug('setting flag ALL') | |
818 | self.ALL = True | |
819 | ||
820 | try: | |
821 | self.read_iface_config() | |
822 | except Exception, e: | |
823 | raise | |
824 | ||
825 | # Save a copy of new iface objects | |
826 | new_ifaceobjdict = self.get_ifaceobjdict() | |
827 | ||
828 | if len(self.statemanager.get_ifaceobjdict()) > 0: | |
829 | # if old state is present, read old state and mark op for 'down' | |
830 | # followed by 'up' aka: reload | |
831 | self.read_old_iface_config() | |
832 | op = 'reload' | |
833 | else: | |
834 | # oldconfig not available, continue with 'up' with new config | |
835 | op = 'up' | |
836 | ||
837 | if ifacenames is None: ifacenames = self.ifaceobjdict.keys() | |
838 | if (op == 'reload' and ifacenames is not None and | |
839 | len(ifacenames) != 0): | |
840 | filtered_ifacenames = [i for i in ifacenames | |
841 | if self.iface_whitelisted(auto, allow_classes, | |
842 | excludepats, i) == True] | |
843 | ifacedownlist = Set(filtered_ifacenames).difference( | |
844 | Set(new_ifaceobjdict.keys())) | |
845 | if ifacedownlist is not None and len(ifacedownlist) > 0: | |
846 | self.logger.debug('bringing down interfaces: %s' | |
847 | %str(ifacedownlist)) | |
848 | if self.NODEPENDS == True: | |
849 | self.run_without_dependents('down', ifacedownlist) | |
850 | else: | |
851 | self.run_with_dependents('down', ifacedownlist) | |
852 | ||
853 | # Update persistant iface states | |
854 | try: | |
855 | if self.ALL == True: | |
856 | self.statemanager.flush_state(self.ifaceobjdict) | |
857 | else: | |
858 | self.statemanager.flush_state() | |
859 | except Exception, e: | |
860 | if self.logger.isEnabledFor(logging.DEBUG): | |
861 | t = sys.exc_info()[2] | |
862 | traceback.print_tb(t) | |
863 | self.logger.warning('error saving state (%s)' %str(e)) | |
864 | ||
865 | # Now, run up with new dict | |
866 | self.set_ifaceobjdict(new_ifaceobjdict) | |
867 | ifacenames = self.ifaceobjdict.keys() | |
868 | filtered_ifacenames = [i for i in ifacenames | |
869 | if self.iface_whitelisted(auto, allow_classes, | |
870 | excludepats, i) == True] | |
871 | ||
872 | self.logger.debug('bringing up interfaces: %s' | |
873 | %str(filtered_ifacenames)) | |
874 | if self.NODEPENDS == True: | |
875 | self.run_without_dependents('up', filtered_ifacenames) | |
876 | else: | |
877 | self.run_with_dependents('up', filtered_ifacenames) | |
878 | ||
879 | # Update persistant iface states | |
880 | try: | |
881 | if self.ALL == True: | |
882 | self.statemanager.flush_state(self.get_ifaceobjdict()) | |
883 | else: | |
884 | self.statemanager.flush_state() | |
885 | except Exception, e: | |
886 | if self.logger.isEnabledFor(logging.DEBUG): | |
887 | t = sys.exc_info()[2] | |
888 | traceback.print_tb(t) | |
889 | self.logger.warning('error saving state (%s)' %str(e)) | |
a6f80f0e | 890 | |
891 | def dump(self): | |
892 | """ all state dump """ | |
893 | ||
894 | print 'ifupdown object dump' | |
895 | print self.pp.pprint(self.modules) | |
896 | print self.pp.pprint(self.ifaces) | |
897 | self.state_manager.dump() | |
898 | ||
899 | def print_state(self, ifacenames=None): | |
900 | self.statemanager.dump(ifacenames) | |
901 | ||
739f665b | 902 | def print_ifaceobjs_raw(self, ifacenames): |
903 | for i in ifacenames: | |
904 | ifaceobjs = self.get_iface_objs(i) | |
905 | for i in ifaceobjs: | |
906 | i.dump_raw(self.logger) | |
907 | print '\n' | |
908 | ||
a6f80f0e | 909 | def print_ifaceobjs_pretty(self, ifacenames): |
910 | for i in ifacenames: | |
911 | ifaceobjs = self.get_iface_objs(i) | |
739f665b | 912 | for i in ifaceobjs: |
913 | i.dump_pretty(self.logger) | |
914 | print '\n' | |
915 | ||
916 | def dump_ifaceobjs(self, ifacenames): | |
917 | for i in ifacenames: | |
918 | ifaceobjs = self.get_iface_objs(i) | |
919 | for i in ifaceobjs: | |
920 | i.dump(self.logger) | |
eab25b7c | 921 | print '\n' |
a6f80f0e | 922 | |
739f665b | 923 | def print_ifaceobjscurr_pretty(self, ifacenames, format=None): |
eab25b7c | 924 | """ Dumps current running state of interfaces. |
925 | ||
926 | returns 1 if any of the interface has an error, | |
927 | else returns 0 | |
eab25b7c | 928 | """ |
eab25b7c | 929 | ret = 0 |
a6f80f0e | 930 | for i in ifacenames: |
931 | ifaceobj = self.get_ifaceobjcurr(i) | |
739f665b | 932 | if ifaceobj is None: continue |
10720a53 | 933 | if ifaceobj.get_status() == ifaceStatus.NOTFOUND: |
934 | print 'iface %s' %ifaceobj.get_name() + ' (not found)' | |
935 | ret = 1 | |
936 | continue | |
937 | elif ifaceobj.get_status() == ifaceStatus.ERROR: | |
eab25b7c | 938 | ret = 1 |
551a3627 | 939 | if format is None or format == 'nwifaces': |
940 | ifaceobj.dump_pretty(self.logger) | |
941 | else: | |
942 | ifaceobj.dump_json(self.logger) | |
eab25b7c | 943 | |
739f665b | 944 | dlist = ifaceobj.get_dependents() |
945 | if dlist is None or len(dlist) == 0: continue | |
946 | self.print_ifaceobjscurr_pretty(dlist, format) | |
947 | ||
eab25b7c | 948 | return ret |
a6f80f0e | 949 | |
739f665b | 950 | def print_ifaceobjsrunning_pretty(self, ifacenames, format=None): |
951 | for i in ifacenames: | |
952 | ifaceobj = self.get_iface_obj_first(i) | |
953 | if ifaceobj.get_status() == ifaceStatus.NOTFOUND: | |
954 | print 'iface %s' %ifaceobj.get_name() + ' (not found)' | |
955 | continue | |
956 | ||
957 | if format is None or format == 'nwifaces': | |
958 | ifaceobj.dump_pretty(self.logger) | |
959 | elif format == 'json': | |
960 | ifaceobj.dump_json(self.logger) | |
961 | ||
962 | dlist = ifaceobj.get_dependents() | |
963 | if dlist is None or len(dlist) == 0: continue | |
964 | self.print_ifaceobjsrunning_pretty(dlist, format) | |
965 | return | |
966 | ||
a6f80f0e | 967 | def print_ifaceobjs_saved_state_pretty(self, ifacenames): |
968 | self.statemanager.print_state_pretty(ifacenames, self.logger) | |
969 | ||
970 | def print_ifaceobjs_saved_state_detailed_pretty(self, ifacenames): | |
971 | self.statemanager.print_state_detailed_pretty(ifacenames, self.logger) |