]> git.proxmox.com Git - mirror_ifupdown2.git/blob - pkg/ifupdownmain.py
cleanup + fix some reload caching issues
[mirror_ifupdown2.git] / pkg / ifupdownmain.py
1 #!/usr/bin/python
2 #
3 # Copyright 2013. Cumulus Networks, Inc.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
5 #
6 # ifupdownMain --
7 # ifupdown main module
8 #
9
10 import os
11 import re
12 import imp
13 import pprint
14 import logging
15 import sys, traceback
16 import copy
17 from statemanager import *
18 from networkinterfaces import *
19 from iface import *
20 from scheduler import *
21 from collections import deque
22 from collections import OrderedDict
23 from graph import *
24 from sets import Set
25
26 class ifupdownMain(ifupdownBase):
27 """ ifupdown2 main class """
28
29 # Flags
30 WITH_DEPENDS = False
31 ALL = False
32 COMPAT_EXEC_SCRIPTS = False
33 STATEMANAGER_ENABLE = True
34 STATEMANAGER_UPDATE = True
35 ADDONS_ENABLE = False
36
37 # priv flags to mark iface objects
38 BUILTIN = 0x1
39 NOCONFIG = 0x2
40
41 scripts_dir='/etc/network'
42 addon_modules_dir='/usr/share/ifupdownaddons'
43 addon_modules_configfile='/etc/network/.addons.conf'
44
45 # iface dictionary in the below format:
46 # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
47 # eg:
48 # { 'swp1' : [<iface swp1>, <iface swp2> ..] }
49 #
50 # Each ifaceobject corresponds to a configuration block for
51 # that interface
52 # The value in the dictionary is a list because the network
53 # interface configuration file supports more than one iface section
54 # in the interfaces file
55 ifaceobjdict = OrderedDict()
56
57 # iface dictionary representing the curr running state of an iface
58 # in the below format:
59 # {'<ifacename>' : <ifaceobject>}
60 ifaceobjcurrdict = OrderedDict()
61
62 # Dictionary representing operation and modules
63 # for every operation
64 module_ops = OrderedDict([('pre-up', []),
65 ('up' , []),
66 ('post-up' , []),
67 ('query-checkcurr', []),
68 ('query-running', []),
69 ('query-dependency', []),
70 ('query', []),
71 ('query-raw', []),
72 ('pre-down', []),
73 ('down' , []),
74 ('post-down' , [])])
75
76 # For old style /etc/network/ bash scripts
77 script_ops = OrderedDict([('pre-up', []),
78 ('up' , []),
79 ('post-up' , []),
80 ('pre-down', []),
81 ('down' , []),
82 ('post-down' , [])])
83
84 # Handlers for ops that ifupdown2 owns
85 def run_up(self, ifaceobj):
86 ifacename = ifaceobj.name
87 if self.link_exists(ifacename):
88 self.link_up(ifacename)
89
90 def run_down(self, ifaceobj):
91 ifacename = ifaceobj.name
92 if self.link_exists(ifacename):
93 self.link_down(ifacename)
94
95 # ifupdown object interface operation handlers
96 ops_handlers = OrderedDict([('up', run_up),
97 ('down', run_down)])
98
99 def run_sched_ifaceobj_posthook(self, ifaceobj, op):
100 if ((ifaceobj.priv_flags & self.BUILTIN) or
101 (ifaceobj.priv_flags & self.NOCONFIG)):
102 return
103 if self.STATEMANAGER_UPDATE:
104 self.statemanager.ifaceobj_sync(ifaceobj, op)
105
106 # ifupdown object interface scheduler pre and posthooks
107 sched_hooks = {'posthook' : run_sched_ifaceobj_posthook}
108
109 def __init__(self, force=False, dryrun=False, nowait=False,
110 perfmode=False, withdepends=False, njobs=1,
111 cache=False, addons_enable=True, statemanager_enable=True):
112 self.logger = logging.getLogger('ifupdown')
113 self.FORCE = force
114 self.DRYRUN = dryrun
115 self.NOWAIT = nowait
116 self.PERFMODE = perfmode
117 self.WITH_DEPENDS = withdepends
118 self.STATEMANAGER_ENABLE = statemanager_enable
119 self.CACHE = cache
120
121 self.logger.debug("Roopa: DRYRUN = %s" %self.DRYRUN)
122
123 # Can be used to provide hints for caching
124 self.CACHE_FLAGS = 0x0
125 self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
126 self.ADDONS_ENABLE = addons_enable
127
128 self.ifaces = OrderedDict()
129 self.njobs = njobs
130 self.pp = pprint.PrettyPrinter(indent=4)
131 self.modules = OrderedDict({})
132 self.module_attrs = {}
133
134 self.load_addon_modules(self.addon_modules_dir)
135 if self.COMPAT_EXEC_SCRIPTS:
136 self.load_scripts(self.scripts_dir)
137 self.dependency_graph = OrderedDict({})
138
139 if self.STATEMANAGER_ENABLE:
140 try:
141 self.statemanager = stateManager()
142 self.statemanager.read_saved_state()
143 except Exception, e:
144 # XXX Maybe we should continue by ignoring old state
145 self.logger.warning('error reading state (%s)' %str(e))
146 raise
147 else:
148 self.STATEMANAGER_UPDATE = False
149
150 def get_ifaceobjs(self, ifacename):
151 return self.ifaceobjdict.get(ifacename)
152
153 def get_ifaceobj_first(self, ifacename):
154 ifaceobjs = self.get_ifaceobjs(ifacename)
155 if ifaceobjs:
156 return ifaceobjs[0]
157 return None
158
159 def get_ifacenames(self):
160 return self.ifaceobjdict.keys()
161
162 def get_iface_obj_last(self, ifacename):
163 return self.ifaceobjdict.get(ifacename)[-1]
164
165 def create_n_save_ifaceobj(self, ifacename, priv_flags=None,
166 increfcnt=False):
167 """ creates a iface object and adds it to the iface dictionary """
168 ifaceobj = iface()
169 ifaceobj.name = ifacename
170 ifaceobj.priv_flags = priv_flags
171 ifaceobj.auto = True
172 if increfcnt:
173 ifaceobj.inc_refcnt()
174 self.ifaceobjdict[ifacename] = [ifaceobj]
175 return ifaceobj
176
177 def create_n_save_ifaceobjcurr(self, ifaceobj):
178 """ creates a copy of iface object and adds it to the iface dict containing current iface objects
179 """
180 ifaceobjcurr = self.get_ifaceobjcurr(ifaceobj.name)
181 if ifaceobjcurr:
182 return ifaceobjcurr
183 ifaceobjcurr = iface()
184 ifaceobjcurr.name = ifaceobj.name
185 ifaceobjcurr.lowerifaces = ifaceobj.lowerifaces
186 ifaceobjcurr.priv_flags = ifaceobj.priv_flags
187 self.ifaceobjcurrdict[ifaceobj.name] = ifaceobjcurr
188 return ifaceobjcurr
189
190 def get_ifaceobjcurr(self, ifacename):
191 return self.ifaceobjcurrdict.get(ifacename)
192
193 def get_ifaceobjrunning(self, ifacename):
194 return self.ifaceobjrunningdict.get(ifacename)
195
196 def get_iface_refcnt(self, ifacename):
197 """ Return iface ref count """
198 max = 0
199 ifaceobjs = self.get_ifaceobjs(ifacename)
200 if not ifaceobjs:
201 return 0
202 for i in ifaceobjs:
203 if i.refcnt > max:
204 max = i.refcnt
205 return max
206
207 def is_iface_builtin_byname(self, ifacename):
208 """ Returns true if iface name is a builtin interface.
209
210 A builtin interface is an interface which ifupdown understands.
211 The following are currently considered builtin ifaces:
212 - vlan interfaces in the format <ifacename>.<vlanid>
213 """
214 return '.' in ifacename
215
216 def is_ifaceobj_builtin(self, ifaceobj):
217 """ Returns true if iface name is a builtin interface.
218
219 A builtin interface is an interface which ifupdown understands.
220 The following are currently considered builtin ifaces:
221 - vlan interfaces in the format <ifacename>.<vlanid>
222 """
223 return (ifaceobj.priv_flags & self.BUILTIN)
224
225 def is_ifaceobj_noconfig(self, ifaceobj):
226 """ Returns true if iface object did not have a user defined config.
227
228 These interfaces appear only when they are dependents of interfaces
229 which have user defined config
230 """
231 return (ifaceobj.priv_flags & self.NOCONFIG)
232
233 def is_iface_noconfig(self, ifacename):
234 """ Returns true if iface has no config """
235
236 ifaceobj = self.get_ifaceobj_first(ifacename)
237 if not ifaceobj: return True
238 return self.is_ifaceobj_noconfig(ifaceobj)
239
240 def preprocess_dependency_list(self, upperifacename, dlist, ops):
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 """
255 del_list = []
256
257 for d in dlist:
258 dilist = self.get_ifaceobjs(d)
259 if not dilist:
260 if self.is_iface_builtin_byname(d):
261 self.create_n_save_ifaceobj(d, self.BUILTIN | self.NOCONFIG,
262 True).add_to_upperifaces(upperifacename)
263 elif not self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG:
264 self.create_n_save_ifaceobj(d, self.NOCONFIG,
265 True).add_to_upperifaces(upperifacename)
266 else:
267 del_list.append(d)
268 else:
269 for di in dilist:
270 di.inc_refcnt()
271 di.add_to_upperifaces(upperifacename)
272
273 for d in del_list:
274 dlist.remove(d)
275
276 def query_dependents(self, ifaceobj, ops):
277 """ Gets iface dependents by calling into respective modules """
278 dlist = None
279
280 # Get dependents for interface by querying respective modules
281 for mname, module in self.modules.items():
282 module = self.modules.get(mname)
283 if ops[0] == 'query-running':
284 if (not hasattr(module,
285 'get_dependent_ifacenames_running')):
286 continue
287 dlist = module.get_dependent_ifacenames_running(ifaceobj)
288 else:
289 if (not hasattr(module, 'get_dependent_ifacenames')):
290 continue
291 dlist = module.get_dependent_ifacenames(ifaceobj,
292 self.ifaceobjdict.keys())
293 if dlist:
294 self.logger.debug('%s: ' %ifaceobj.name +
295 'lowerifaces/dependents: %s' %str(dlist))
296 break
297 return dlist
298
299 def populate_dependency_info(self, ops, ifacenames=None):
300 """ recursive function to generate iface dependency info """
301
302 if not ifacenames:
303 ifacenames = self.ifaceobjdict.keys()
304
305 self.logger.debug('populating dependency info for %s' %str(ifacenames))
306 iqueue = deque(ifacenames)
307 while iqueue:
308 i = iqueue.popleft()
309 # Go through all modules and find dependent ifaces
310 dlist = None
311 ifaceobj = self.get_ifaceobj_first(i)
312 if not ifaceobj:
313 continue
314 dlist = ifaceobj.lowerifaces
315 if not dlist:
316 dlist = self.query_dependents(ifaceobj, ops)
317 else:
318 continue
319 if dlist:
320 self.preprocess_dependency_list(ifaceobj.name,
321 dlist, ops)
322 self.logger.debug('%s: lowerifaces/dependents after processing: %s'
323 %(i, str(dlist)))
324 ifaceobj.lowerifaces = dlist
325 [iqueue.append(d) for d in dlist]
326 if not self.dependency_graph.get(i):
327 self.dependency_graph[i] = dlist
328
329 def _save_iface(self, ifaceobj):
330 currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
331 if not currentifaceobjlist:
332 self.ifaceobjdict[ifaceobj.name]= [ifaceobj]
333 return
334 if ifaceobj.compare(currentifaceobjlist[0]):
335 self.logger.warn('duplicate interface %s found' %ifaceobj.name)
336 return
337 self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
338
339 def _module_syntax_checker(self, attrname, attrval):
340 for m, mdict in self.module_attrs.items():
341 attrsdict = mdict.get('attrs')
342 if attrsdict and attrname in attrsdict.keys():
343 return True
344 return False
345
346 def read_default_iface_config(self):
347 """ Reads default network interface config /etc/network/interfaces. """
348 nifaces = networkInterfaces()
349 nifaces.subscribe('iface_found', self._save_iface)
350 nifaces.subscribe('validate', self._module_syntax_checker)
351 nifaces.load()
352
353 def read_iface_config(self):
354 return self.read_default_iface_config()
355
356 def read_old_iface_config(self):
357 """ Reads the saved iface config instead of default iface config. """
358 self.ifaceobjdict = copy.deepcopy(self.statemanager.ifaceobjdict)
359
360 def _load_addon_modules_config(self):
361 """ Load addon modules config file """
362
363 with open(self.addon_modules_configfile, 'r') as f:
364 lines = f.readlines()
365 for l in lines:
366 litems = l.rstrip(' \n').split(',')
367 operation = litems[0]
368 mname = litems[1]
369 self.module_ops[operation].append(mname)
370
371 def load_addon_modules(self, modules_dir):
372 """ load python modules from modules_dir
373
374 Default modules_dir is /usr/share/ifupdownmodules
375
376 """
377 self.logger.info('loading builtin modules from %s' %modules_dir)
378 self._load_addon_modules_config()
379 if not modules_dir in sys.path:
380 sys.path.append(modules_dir)
381 try:
382 for op, mlist in self.module_ops.items():
383 for mname in mlist:
384 if self.modules.get(mname):
385 continue
386 mpath = modules_dir + '/' + mname + '.py'
387 if os.path.exists(mpath):
388 try:
389 m = __import__(mname)
390 mclass = getattr(m, mname)
391 except:
392 raise
393 minstance = mclass(force=self.FORCE,
394 dryrun=self.DRYRUN,
395 nowait=self.NOWAIT,
396 perfmode=self.PERFMODE,
397 cache=self.CACHE,
398 cacheflags=self.CACHE_FLAGS)
399 self.modules[mname] = minstance
400 try:
401 self.module_attrs[mname] = minstance.get_modinfo()
402 except:
403 pass
404 except:
405 raise
406
407 # Assign all modules to query operations
408 self.module_ops['query-checkcurr'] = self.modules.keys()
409 self.module_ops['query-running'] = self.modules.keys()
410 self.module_ops['query-dependency'] = self.modules.keys()
411 self.module_ops['query'] = self.modules.keys()
412 self.module_ops['query-raw'] = self.modules.keys()
413
414 def _modules_help(self):
415 """ Prints addon modules supported syntax """
416
417 indent = ' '
418 for m, mdict in self.module_attrs.items():
419 if not mdict:
420 continue
421 print('%s: %s' %(m, mdict.get('mhelp')))
422 attrdict = mdict.get('attrs')
423 if not attrdict:
424 continue
425 try:
426 for attrname, attrvaldict in attrdict.items():
427 if attrvaldict.get('compat', False):
428 continue
429 print('%s%s' %(indent, attrname))
430 print('%shelp: %s' %(indent + ' ',
431 attrvaldict.get('help', '')))
432 print ('%srequired: %s' %(indent + ' ',
433 attrvaldict.get('required', False)))
434 default = attrvaldict.get('default')
435 if default:
436 print('%sdefault: %s' %(indent + ' ', default))
437
438 validrange = attrvaldict.get('validrange')
439 if validrange:
440 print('%svalidrange: %s'
441 %(indent + ' ', '-'.join(validrange)))
442
443 validvals = attrvaldict.get('validvals')
444 if validvals:
445 print('%svalidvals: %s'
446 %(indent + ' ', ','.join(validvals)))
447
448 examples = attrvaldict.get('example')
449 if not examples:
450 continue
451
452 print '%sexample:' %(indent + ' ')
453 for e in examples:
454 print '%s%s' %(indent + ' ', e)
455 except:
456 pass
457 print ''
458
459 def load_scripts(self, modules_dir):
460 """ loading user modules from /etc/network/.
461
462 Note that previously loaded python modules override modules found
463 under /etc/network if any
464
465 """
466
467 self.logger.info('looking for user scripts under %s' %modules_dir)
468 for op, mlist in self.script_ops.items():
469 msubdir = modules_dir + '/if-%s.d' %op
470 self.logger.info('loading scripts under %s ...' %msubdir)
471 try:
472 module_list = os.listdir(msubdir)
473 for module in module_list:
474 if self.modules.get(module) is not None:
475 continue
476 self.script_ops[op].append(
477 msubdir + '/' + module)
478 except:
479 # continue reading
480 pass
481
482 def _sched_ifaces(self, ifacenames, ops):
483 self.logger.debug('scheduling \'%s\' for %s'
484 %(str(ops), str(ifacenames)))
485
486 self._pretty_print_ordered_dict('dependency graph',
487 self.dependency_graph)
488 return ifaceScheduler.sched_ifaces(self, ifacenames, ops,
489 dependency_graph=self.dependency_graph,
490 order=ifaceSchedulerFlags.INORDER
491 if 'down' in ops[0]
492 else ifaceSchedulerFlags.POSTORDER,
493 followdependents=True if self.WITH_DEPENDS else False)
494
495 def _validate_ifaces(self, ifacenames):
496 """ validates interface list for config existance.
497
498 returns -1 if one or more interface not found. else, returns 0
499
500 """
501 err_iface = ''
502 for i in ifacenames:
503 ifaceobjs = self.get_ifaceobjs(i)
504 if not ifaceobjs:
505 err_iface += ' ' + i
506 if err_iface:
507 self.logger.error('cannot find interfaces: %s' %err_iface)
508 return False
509 return True
510
511 def _iface_whitelisted(self, auto, allow_classes, excludepats, ifacename):
512 """ Checks if interface is whitelisted depending on set of parameters.
513
514 interfaces are checked against the allow_classes and auto lists.
515
516 """
517
518 if excludepats:
519 for e in excludepats:
520 if re.search(e, ifacename):
521 return False
522 ifaceobjs = self.get_ifaceobjs(ifacename)
523 if not ifaceobjs:
524 self.logger.debug('iface %s' %ifacename + ' not found')
525 return False
526 # We check classes first
527 if allow_classes:
528 for i in ifaceobjs:
529 if i.classes:
530 common = Set([allow_classes]).intersection(
531 Set(i.classes))
532 if common:
533 return True
534 return False
535 if auto:
536 for i in ifaceobjs:
537 if i.auto:
538 return True
539 return False
540 return True
541
542 def _compat_conv_op_to_mode(self, op):
543 """ Returns old op name to work with existing scripts """
544 if op == 'pre-up':
545 return 'start'
546 elif op == 'pre-down':
547 return 'stop'
548 else:
549 return op
550
551 def generate_running_env(self, ifaceobj, op):
552 """ Generates a dictionary with env variables required for
553 an interface. Used to support script execution for interfaces.
554 """
555
556 cenv = None
557 iface_env = ifaceobj.env
558 if iface_env:
559 cenv = os.environ
560 if cenv:
561 cenv.update(iface_env)
562 else:
563 cenv = iface_env
564 cenv['MODE'] = self._compat_conv_op_to_mode(op)
565 return cenv
566
567 def _save_state(self):
568 if not self.STATEMANAGER_ENABLE or not self.STATEMANAGER_UPDATE:
569 return
570 try:
571 # Update persistant iface states
572 self.statemanager.save_state()
573 except Exception, e:
574 if self.logger.isEnabledFor(logging.DEBUG):
575 t = sys.exc_info()[2]
576 traceback.print_tb(t)
577 self.logger.warning('error saving state (%s)' %str(e))
578
579 def up(self, ops, auto=False, allow_classes=None, ifacenames=None,
580 excludepats=None, printdependency=None, syntaxcheck=False):
581 """ up an interface """
582
583 if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False
584 if auto:
585 self.ALL = True
586 self.WITH_DEPENDS = True
587 try:
588 self.read_iface_config()
589 except Exception:
590 raise
591
592 # If only syntax check was requested, return here
593 if syntaxcheck:
594 return
595
596 if ifacenames:
597 # If iface list is given by the caller, always check if iface
598 # is present
599 if not self._validate_ifaces(ifacenames):
600 raise Exception('all or some interfaces not found')
601
602 # if iface list not given by user, assume all from config file
603 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
604
605 # filter interfaces based on auto and allow classes
606 filtered_ifacenames = [i for i in ifacenames
607 if self._iface_whitelisted(auto, allow_classes,
608 excludepats, i)]
609 if not filtered_ifacenames:
610 raise Exception('no ifaces found matching given allow lists')
611
612 if printdependency:
613 self.populate_dependency_info(ops, filtered_ifacenames)
614 self.print_dependency(filtered_ifacenames, printdependency)
615 return
616 else:
617 self.populate_dependency_info(ops)
618
619 try:
620 self._sched_ifaces(filtered_ifacenames, ops)
621 finally:
622 if not self.DRYRUN and self.ADDONS_ENABLE:
623 self._save_state()
624
625 def down(self, ops, auto=False, allow_classes=None, ifacenames=None,
626 excludepats=None, printdependency=None, usecurrentconfig=False):
627 """ down an interface """
628
629 if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False
630 if auto:
631 self.ALL = True
632 self.WITH_DEPENDS = True
633 # For down we need to look at old state, unless usecurrentconfig
634 # is set
635 if (not usecurrentconfig and self.STATEMANAGER_ENABLE and
636 self.statemanager.ifaceobjdict):
637 # Since we are using state manager objects,
638 # skip the updating of state manager objects
639 self.logger.debug('Looking at old state ..')
640 self.read_old_iface_config()
641 else:
642 # If no old state available
643 self.logger.info('Loading current iface config file')
644 try:
645 self.read_iface_config()
646 except Exception, e:
647 raise Exception('error reading iface config (%s)' %str(e))
648 if ifacenames:
649 # If iface list is given by the caller, always check if iface
650 # is present
651 if not self._validate_ifaces(ifacenames):
652 raise Exception('interface(s) was probably never up')
653 # if iface list not given by user, assume all from config file
654 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
655
656 # filter interfaces based on auto and allow classes
657 filtered_ifacenames = [i for i in ifacenames
658 if self._iface_whitelisted(auto, allow_classes,
659 excludepats, i)]
660 if not filtered_ifacenames:
661 raise Exception('no ifaces found matching given allow lists')
662 if printdependency:
663 self.populate_dependency_info(ops, filtered_ifacenames)
664 self.print_dependency(filtered_ifacenames, printdependency)
665 return
666 else:
667 self.populate_dependency_info(ops)
668
669 try:
670 self._sched_ifaces(filtered_ifacenames, ops)
671 finally:
672 if not self.DRYRUN and self.ADDONS_ENABLE:
673 self._save_state()
674
675 def query(self, ops, auto=False, allow_classes=None, ifacenames=None,
676 excludepats=None, printdependency=None,
677 format='native'):
678 """ query an interface """
679
680 if self.STATEMANAGER_ENABLE and ops[0] == 'query-savedstate':
681 return self.statemanager.dump_pretty(ifacenames)
682
683 self.STATEMANAGER_UPDATE = False
684 if auto:
685 self.logger.debug('setting flag ALL')
686 self.ALL = True
687 self.WITH_DEPENDS = True
688
689 if ops[0] == 'query-syntax':
690 self._modules_help()
691 return
692 elif ops[0] == 'query-running':
693 # create fake devices to all dependents that dont have config
694 map(lambda i: self.create_n_save_ifaceobj(i, self.NOCONFIG),
695 ifacenames)
696 else:
697 try:
698 self.read_iface_config()
699 except Exception:
700 raise
701
702 if ifacenames and ops[0] != 'query-running':
703 # If iface list is given, always check if iface is present
704 if not self._validate_ifaces(ifacenames):
705 raise Exception('all or some interfaces not found')
706
707 # if iface list not given by user, assume all from config file
708 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
709
710 # filter interfaces based on auto and allow classes
711 if ops[0] == 'query-running':
712 filtered_ifacenames = ifacenames
713 else:
714 filtered_ifacenames = [i for i in ifacenames
715 if self._iface_whitelisted(auto, allow_classes,
716 excludepats, i)]
717 if not filtered_ifacenames:
718 raise Exception('no ifaces found matching ' +
719 'given allow lists')
720
721 if ops[0] == 'query-dependency' and printdependency:
722 self.populate_dependency_info(ops, filtered_ifacenames)
723 self.print_dependency(filtered_ifacenames, printdependency)
724 return
725 else:
726 self.populate_dependency_info(ops)
727
728 if ops[0] == 'query':
729 return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
730 elif ops[0] == 'query-raw':
731 return self.print_ifaceobjs_raw(filtered_ifacenames)
732
733 self._sched_ifaces(filtered_ifacenames, ops)
734
735 if ops[0] == 'query-checkcurr':
736 ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames, format)
737 if ret != 0:
738 # if any of the object has an error, signal that silently
739 raise Exception('')
740 elif ops[0] == 'query-running':
741 self.print_ifaceobjsrunning_pretty(filtered_ifacenames, format)
742 return
743
744 def reload(self, upops, downops, auto=False, allow=None,
745 ifacenames=None, excludepats=None):
746 """ reload interface config """
747
748 allow_classes = []
749
750 self.logger.debug('reloading interface config ..')
751 if auto:
752 self.ALL = True
753 self.WITH_DEPENDS = True
754
755 try:
756 # Read the current interface config
757 self.read_iface_config()
758 except:
759 raise
760
761 # generate dependency graph of interfaces
762 self.populate_dependency_info(upops)
763
764 # Save a copy of new iface objects and dependency_graph
765 new_ifaceobjdict = dict(self.ifaceobjdict)
766 new_dependency_graph = dict(self.dependency_graph)
767
768 if self.STATEMANAGER_ENABLE and self.statemanager.ifaceobjdict:
769 # if old state is present, read old state and mark op for 'down'
770 # followed by 'up' aka: reload
771 # old interface config is read into self.ifaceobjdict
772 #
773 self.read_old_iface_config()
774 op = 'reload'
775 else:
776 # oldconfig not available, continue with 'up' with new config
777 op = 'up'
778
779 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
780 if op == 'reload' and ifacenames:
781 filtered_ifacenames = [i for i in ifacenames
782 if self._iface_whitelisted(auto, allow_classes,
783 excludepats, i)]
784 # Generate the interface down list
785 # Interfaces that go into the down list:
786 # - interfaces that were present in last config and are not
787 # present in the new config
788 # - interfaces that were changed between the last and current
789 # config
790 #
791 ifacedownlist = []
792 for ifname, lastifaceobjlist in self.ifaceobjdict.items():
793 objidx = 0
794 # If interface is not present in the new file
795 # append it to the down list
796 newifaceobjlist = new_ifaceobjdict.get(ifname)
797 if not newifaceobjlist:
798 ifacedownlist.append(ifname)
799 continue
800 # If interface has changed between the current file
801 # and the last installed append it to the down list
802 if len(newifaceobjlist) != len(lastifaceobjlist):
803 ifacedownlist.append(ifname)
804 continue
805 # compare object list
806 for objidx in range(0, len(lastifaceobjlist)):
807 oldobj = lastifaceobjlist[objidx]
808 newobj = newifaceobjlist[objidx]
809 if not newobj.compare(oldobj):
810 ifacedownlist.append(ifname)
811 continue
812
813 if ifacedownlist:
814 self.logger.info('Executing down on interfaces: %s'
815 %str(ifacedownlist))
816 # reinitialize dependency graph
817 self.dependency_graph = OrderedDict({})
818 # Generate dependency info for old config
819 self.populate_dependency_info(downops)
820 self._sched_ifaces(ifacedownlist, downops)
821 else:
822 self.logger.debug('no interfaces to down ..')
823
824 # Now, run 'up' with new config dict
825 # reset statemanager update flag to default
826 self.ifaceobjdict = new_ifaceobjdict
827 self.dependency_graph = new_dependency_graph
828 ifacenames = self.ifaceobjdict.keys()
829 filtered_ifacenames = [i for i in ifacenames
830 if self._iface_whitelisted(auto, allow_classes,
831 excludepats, i)]
832
833 self.logger.info('Scheduling up on interfaces: %s'
834 %str(filtered_ifacenames))
835 self._sched_ifaces(filtered_ifacenames, upops)
836 if self.DRYRUN:
837 return
838 self._save_state()
839
840 def _pretty_print_ordered_dict(self, prefix, argdict):
841 outbuf = prefix + ' {\n'
842 for k, vlist in argdict.items():
843 outbuf += '\t%s : %s\n' %(k, str(vlist))
844 self.logger.debug(outbuf + '}')
845
846 def print_dependency(self, ifacenames, format):
847 """ prints iface dependency information """
848
849 if not ifacenames:
850 ifacenames = self.ifaceobjdict.keys()
851 if format == 'list':
852 for k,v in self.dependency_graph.items():
853 print '%s : %s' %(k, str(v))
854 elif format == 'dot':
855 indegrees = {}
856 map(lambda i: indegrees.update({i :
857 self.get_iface_refcnt(i)}),
858 self.dependency_graph.keys())
859 graph.generate_dots(self.dependency_graph, indegrees)
860
861 def print_ifaceobjs_raw(self, ifacenames):
862 """ prints raw lines for ifaces from config file """
863
864 for i in ifacenames:
865 for ifaceobj in self.get_ifaceobjs(i):
866 if (self.is_ifaceobj_builtin(ifaceobj) or
867 not ifaceobj.is_config_present()):
868 continue
869 ifaceobj.dump_raw(self.logger)
870 print '\n'
871 if self.WITH_DEPENDS and not self.ALL:
872 dlist = ifaceobj.lowerifaces
873 if not dlist: continue
874 self.print_ifaceobjs_raw(dlist)
875
876 def print_ifaceobjs_pretty(self, ifacenames, format='native'):
877 """ pretty prints iface in format given by keyword arg format """
878
879 for i in ifacenames:
880 for ifaceobj in self.get_ifaceobjs(i):
881 if (self.is_ifaceobj_noconfig(ifaceobj)):
882 continue
883 if format == 'json':
884 ifaceobj.dump_json()
885 else:
886 ifaceobj.dump_pretty()
887 if self.WITH_DEPENDS and not self.ALL:
888 dlist = ifaceobj.lowerifaces
889 if not dlist: continue
890 self.print_ifaceobjs_pretty(dlist, format)
891
892 def print_ifaceobjscurr_pretty(self, ifacenames, format='native'):
893 """ pretty prints current running state of interfaces with status.
894
895 returns 1 if any of the interface has an error,
896 else returns 0
897 """
898
899 ret = 0
900 for i in ifacenames:
901 ifaceobj = self.get_ifaceobjcurr(i)
902 if not ifaceobj: continue
903 if ifaceobj.status == ifaceStatus.NOTFOUND:
904 print 'iface %s (%s)\n' %(ifaceobj.name,
905 ifaceStatus.to_str(ifaceStatus.NOTFOUND))
906 ret = 1
907 continue
908 elif ifaceobj.status == ifaceStatus.ERROR:
909 ret = 1
910 if (self.is_ifaceobj_noconfig(ifaceobj)):
911 continue
912 if format == 'json':
913 ifaceobj.dump_json(with_status=True)
914 else:
915 ifaceobj.dump_pretty(with_status=True)
916 if self.WITH_DEPENDS and not self.ALL:
917 dlist = ifaceobj.lowerifaces
918 if not dlist: continue
919 self.print_ifaceobjscurr_pretty(dlist, format)
920 return ret
921
922 def print_ifaceobjsrunning_pretty(self, ifacenames, format='native'):
923 """ pretty prints iface running state """
924
925 for i in ifacenames:
926 ifaceobj = self.get_ifaceobj_first(i)
927 if ifaceobj.status == ifaceStatus.NOTFOUND:
928 print 'iface %s' %ifaceobj.name + ' (not found)\n'
929 continue
930 if not ifaceobj.is_config_present():
931 continue
932 if format == 'json':
933 ifaceobj.dump_json()
934 else:
935 ifaceobj.dump_pretty()
936 if self.WITH_DEPENDS and not self.ALL:
937 dlist = ifaceobj.lowerifaces
938 if not dlist: continue
939 self.print_ifaceobjsrunning_pretty(dlist, format)
940 return
941
942 def _dump(self):
943 print 'ifupdown main object dump'
944 print self.pp.pprint(self.modules)
945 print self.pp.pprint(self.ifaceobjdict)
946
947 def _dump_ifaceobjs(self, ifacenames):
948 for i in ifacenames:
949 ifaceobjs = self.get_ifaceobjs(i)
950 for i in ifaceobjs:
951 i.dump(self.logger)
952 print '\n'