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