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