]> git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/ifupdown/ifupdownmain.py
Dont follow dependents during down of interfaces as part of ifreload
[mirror_ifupdown2.git] / ifupdown2 / ifupdown / ifupdownmain.py
1 #!/usr/bin/python
2 #
3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
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 = '(%s)' %_tickmark
38 _error_sym = '(%s)' %_crossmark
39
40 class ifupdownFlags():
41 FORCE = False
42 DRYRUN = False
43 NOWAIT = False
44 PERFMODE = False
45 CACHE = False
46
47 # Flags
48 CACHE_FLAGS = 0x0
49
50 class ifupdownMain(ifupdownBase):
51 """ ifupdown2 main class """
52
53 # Flags
54 WITH_DEPENDS = False
55 ALL = False
56 IFACE_CLASS = False
57 COMPAT_EXEC_SCRIPTS = False
58 STATEMANAGER_ENABLE = True
59 STATEMANAGER_UPDATE = True
60 ADDONS_ENABLE = False
61
62 # priv flags to mark iface objects
63 BUILTIN = 0x0001
64 NOCONFIG = 0x0010
65
66 scripts_dir='/etc/network'
67 addon_modules_dir='/usr/share/ifupdownaddons'
68 addon_modules_configfile='/var/lib/ifupdownaddons/addons.conf'
69
70 # iface dictionary in the below format:
71 # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
72 # eg:
73 # { 'swp1' : [<iface swp1>, <iface swp2> ..] }
74 #
75 # Each ifaceobject corresponds to a configuration block for
76 # that interface
77 # The value in the dictionary is a list because the network
78 # interface configuration file supports more than one iface section
79 # in the interfaces file
80 ifaceobjdict = OrderedDict()
81
82 # iface dictionary representing the curr running state of an iface
83 # in the below format:
84 # {'<ifacename>' : <ifaceobject>}
85 ifaceobjcurrdict = OrderedDict()
86
87 # Dictionary representing operation and modules
88 # for every operation
89 module_ops = OrderedDict([('pre-up', []),
90 ('up' , []),
91 ('post-up' , []),
92 ('query-checkcurr', []),
93 ('query-running', []),
94 ('query-dependency', []),
95 ('query', []),
96 ('query-raw', []),
97 ('pre-down', []),
98 ('down' , []),
99 ('post-down' , [])])
100
101 # For old style /etc/network/ bash scripts
102 script_ops = OrderedDict([('pre-up', []),
103 ('up' , []),
104 ('post-up' , []),
105 ('pre-down', []),
106 ('down' , []),
107 ('post-down' , [])])
108
109 # Handlers for ops that ifupdown2 owns
110 def run_up(self, ifaceobj):
111 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs).
112 # there is no real interface behind it
113 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
114 return
115 if (ifaceobj.addr_method and
116 ifaceobj.addr_method == 'manual'):
117 return
118 if self._delay_admin_state:
119 self._delay_admin_state_iface_queue.append(ifaceobj.name)
120 return
121 # If this object is a link slave, ie its link is controlled
122 # by its link master interface, then dont set the link state.
123 # But do allow user to change state of the link if the interface
124 # is already with its link master (hence the master check).
125 if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
126 return
127 if not self.link_exists(ifaceobj.name):
128 return
129 self.link_up(ifaceobj.name)
130
131 def run_down(self, ifaceobj):
132 # Skip link sets on ifaceobjs of type 'vlan' (used for l2 attrs)
133 # there is no real interface behind it
134 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
135 return
136 if (ifaceobj.addr_method and
137 ifaceobj.addr_method == 'manual'):
138 return
139 if self._delay_admin_state:
140 self._delay_admin_state_iface_queue.append(ifaceobj.name)
141 return
142 # If this object is a link slave, ie its link is controlled
143 # by its link master interface, then dont set the link state.
144 # But do allow user to change state of the link if the interface
145 # is already with its link master (hence the master check).
146 if ifaceobj.link_type == ifaceLinkType.LINK_SLAVE:
147 return
148 if not self.link_exists(ifaceobj.name):
149 return
150 self.link_down(ifaceobj.name)
151
152 # ifupdown object interface operation handlers
153 ops_handlers = OrderedDict([('up', run_up),
154 ('down', run_down)])
155
156 def run_sched_ifaceobj_posthook(self, ifaceobj, op):
157 if ((ifaceobj.priv_flags & self.BUILTIN) or
158 (ifaceobj.priv_flags & self.NOCONFIG)):
159 return
160 if self.STATEMANAGER_UPDATE:
161 self.statemanager.ifaceobj_sync(ifaceobj, op)
162
163 # ifupdown object interface scheduler pre and posthooks
164 sched_hooks = {'posthook' : run_sched_ifaceobj_posthook}
165
166 def __init__(self, config={},
167 force=False, dryrun=False, nowait=False,
168 perfmode=False, withdepends=False, njobs=1,
169 cache=False, addons_enable=True, statemanager_enable=True,
170 interfacesfile='/etc/network/interfaces',
171 interfacesfileiobuf=None,
172 interfacesfileformat='native'):
173 """This member function initializes the ifupdownmain object.
174
175 Kwargs:
176 config (dict): config dict from /etc/network/ifupdown2/ifupdown2.conf
177 force (bool): force interface configuration
178 dryrun (bool): dryrun interface configuration
179 withdepends (bool): apply interface configuration on all depends
180 interfacesfile (str): interfaces file. default is /etc/network/interfaces
181 interfacesfileformat (str): default is 'native'. Other choices are 'json'
182
183 Raises:
184 AttributeError, KeyError """
185
186 self.logger = logging.getLogger('ifupdown')
187 self.FORCE = force
188 self.DRYRUN = dryrun
189 self.NOWAIT = nowait
190 self.PERFMODE = perfmode
191 self.WITH_DEPENDS = withdepends
192 self.STATEMANAGER_ENABLE = statemanager_enable
193 self.CACHE = cache
194 self.interfacesfile = interfacesfile
195 self.interfacesfileiobuf = interfacesfileiobuf
196 self.interfacesfileformat = interfacesfileformat
197 self.config = config
198 self.logger.debug(self.config)
199
200 self.type = ifaceType.UNKNOWN
201
202 # Can be used to provide hints for caching
203 self.CACHE_FLAGS = 0x0
204 self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
205 self.ADDONS_ENABLE = addons_enable
206
207 # Copy flags into ifupdownFlags
208 # XXX: before we transition fully to ifupdownFlags
209 ifupdownFlags.FORCE = force
210 ifupdownFlags.DRYRUN = dryrun
211 ifupdownFlags.NOWAIT = nowait
212 ifupdownFlags.PERFMODE = perfmode
213 ifupdownFlags.CACHE = cache
214
215 self.ifaces = OrderedDict()
216 self.njobs = njobs
217 self.pp = pprint.PrettyPrinter(indent=4)
218 self.modules = OrderedDict({})
219 self.module_attrs = {}
220
221 self.load_addon_modules(self.addon_modules_dir)
222 if self.COMPAT_EXEC_SCRIPTS:
223 self.load_scripts(self.scripts_dir)
224 self.dependency_graph = OrderedDict({})
225
226 self._cache_no_repeats = {}
227
228 if self.STATEMANAGER_ENABLE:
229 try:
230 self.statemanager = stateManager()
231 self.statemanager.read_saved_state()
232 except Exception, e:
233 # XXX Maybe we should continue by ignoring old state
234 self.logger.warning('error reading state (%s)' %str(e))
235 raise
236 else:
237 self.STATEMANAGER_UPDATE = False
238 self._delay_admin_state = True if self.config.get(
239 'delay_admin_state_change', '0') == '1' else False
240 self._delay_admin_state_iface_queue = []
241 if self._delay_admin_state:
242 self.logger.info('\'delay_admin_state_change\' is set. admin ' +
243 'state changes will be delayed till the end.')
244
245 self._link_master_slave = True if self.config.get(
246 'link_master_slave', '0') == '1' else False
247 if self._link_master_slave:
248 self.logger.info('\'link_master_slave\' is set. slave admin ' +
249 'state changes will be delayed till the ' +
250 'masters admin state change.')
251
252 def link_master_slave_ignore_error(self, errorstr):
253 # If link master slave flag is set,
254 # there may be cases where the lowerdev may not be
255 # up resulting in 'Network is down' error
256 # This can happen if the lowerdev is a LINK_SLAVE
257 # of another interface which is not up yet
258 # example of such a case:
259 # bringing up a vlan on a bond interface and the bond
260 # is a LINK_SLAVE of a bridge (in other words the bond is
261 # part of a bridge) which is not up yet
262 if self._link_master_slave:
263 if 'Network is down':
264 return True
265 return False
266
267 def get_ifaceobjs(self, ifacename):
268 return self.ifaceobjdict.get(ifacename)
269
270 def get_ifaceobjs_saved(self, ifacename):
271 """ Return ifaceobjects from statemanager """
272 if self.STATEMANAGER_ENABLE:
273 return self.statemanager.get_ifaceobjs(ifacename)
274 else:
275 None
276
277 def get_ifaceobj_first(self, ifacename):
278 ifaceobjs = self.get_ifaceobjs(ifacename)
279 if ifaceobjs:
280 return ifaceobjs[0]
281 return None
282
283 def get_ifacenames(self):
284 return self.ifaceobjdict.keys()
285
286 def get_iface_obj_last(self, ifacename):
287 return self.ifaceobjdict.get(ifacename)[-1]
288
289
290 def must_follow_upperifaces(self, ifacename):
291 #
292 # XXX: This bleeds the knowledge of iface
293 # types in the infrastructure module.
294 # Cant think of a better fix at the moment.
295 # In future maybe the module can set a flag
296 # to indicate if we should follow upperifaces
297 #
298 ifaceobj = self.get_ifaceobj_first(ifacename)
299 if ifaceobj.type == ifaceType.BRIDGE_VLAN:
300 return False
301 return True
302
303 def create_n_save_ifaceobj(self, ifacename, priv_flags=None,
304 increfcnt=False):
305 """ creates a iface object and adds it to the iface dictionary """
306 ifaceobj = iface()
307 ifaceobj.name = ifacename
308 ifaceobj.priv_flags = priv_flags
309 ifaceobj.auto = True
310 if not self._link_master_slave:
311 ifaceobj.link_type = ifaceLinkType.LINK_NA
312 if increfcnt:
313 ifaceobj.inc_refcnt()
314 self.ifaceobjdict[ifacename] = [ifaceobj]
315 return ifaceobj
316
317 def create_n_save_ifaceobjcurr(self, ifaceobj):
318 """ creates a copy of iface object and adds it to the iface
319 dict containing current iface objects
320 """
321 ifaceobjcurr = iface()
322 ifaceobjcurr.name = ifaceobj.name
323 ifaceobjcurr.type = ifaceobj.type
324 ifaceobjcurr.lowerifaces = ifaceobj.lowerifaces
325 ifaceobjcurr.priv_flags = ifaceobj.priv_flags
326 ifaceobjcurr.auto = ifaceobj.auto
327 self.ifaceobjcurrdict.setdefault(ifaceobj.name,
328 []).append(ifaceobjcurr)
329 return ifaceobjcurr
330
331 def get_ifaceobjcurr(self, ifacename, idx=0):
332 ifaceobjlist = self.ifaceobjcurrdict.get(ifacename)
333 if not ifaceobjlist:
334 return None
335 if not idx:
336 return ifaceobjlist
337 else:
338 return ifaceobjlist[idx]
339
340 def get_ifaceobjrunning(self, ifacename):
341 return self.ifaceobjrunningdict.get(ifacename)
342
343 def get_iface_refcnt(self, ifacename):
344 """ Return iface ref count """
345 max = 0
346 ifaceobjs = self.get_ifaceobjs(ifacename)
347 if not ifaceobjs:
348 return 0
349 for i in ifaceobjs:
350 if i.refcnt > max:
351 max = i.refcnt
352 return max
353
354 def is_iface_builtin_byname(self, ifacename):
355 """ Returns true if iface name is a builtin interface.
356
357 A builtin interface is an interface which ifupdown understands.
358 The following are currently considered builtin ifaces:
359 - vlan interfaces in the format <ifacename>.<vlanid>
360 """
361 return '.' in ifacename
362
363 def is_ifaceobj_builtin(self, ifaceobj):
364 """ Returns true if iface name is a builtin interface.
365
366 A builtin interface is an interface which ifupdown understands.
367 The following are currently considered builtin ifaces:
368 - vlan interfaces in the format <ifacename>.<vlanid>
369 """
370 return (ifaceobj.priv_flags & self.BUILTIN)
371
372 def is_ifaceobj_noconfig(self, ifaceobj):
373 """ Returns true if iface object did not have a user defined config.
374
375 These interfaces appear only when they are dependents of interfaces
376 which have user defined config
377 """
378 return (ifaceobj.priv_flags & self.NOCONFIG)
379
380 def is_iface_noconfig(self, ifacename):
381 """ Returns true if iface has no config """
382
383 ifaceobj = self.get_ifaceobj_first(ifacename)
384 if not ifaceobj: return True
385 return self.is_ifaceobj_noconfig(ifaceobj)
386
387 def preprocess_dependency_list(self, upperifaceobj, dlist, ops):
388 """ We go through the dependency list and
389 delete or add interfaces from the interfaces dict by
390 applying the following rules:
391 if flag _DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is True:
392 we only consider devices whose configuration was
393 specified in the network interfaces file. We delete
394 any interface whose config was not specified except
395 for vlan devices. vlan devices get special treatment.
396 Even if they are not present they are created and added
397 to the ifacesdict
398 elif flag _DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is False:
399 we create objects for all dependent devices that are not
400 present in the ifacesdict
401 """
402 del_list = []
403
404 for d in dlist:
405 dilist = self.get_ifaceobjs(d)
406 if not dilist:
407 ni = None
408 if self.is_iface_builtin_byname(d):
409 ni = self.create_n_save_ifaceobj(d,
410 self.BUILTIN | self.NOCONFIG, True)
411 elif not self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG:
412 ni = self.create_n_save_ifaceobj(d, self.NOCONFIG,
413 True)
414 else:
415 del_list.append(d)
416 if ni:
417 ni.add_to_upperifaces(upperifaceobj.name)
418 if upperifaceobj.link_type == ifaceLinkType.LINK_MASTER:
419 ni.link_type = ifaceLinkType.LINK_SLAVE
420 else:
421 for di in dilist:
422 di.inc_refcnt()
423 di.add_to_upperifaces(upperifaceobj.name)
424 if upperifaceobj.link_type == ifaceLinkType.LINK_MASTER:
425 di.link_type = ifaceLinkType.LINK_SLAVE
426 for d in del_list:
427 dlist.remove(d)
428
429 def query_dependents(self, ifaceobj, ops, ifacenames, type=None):
430 """ Gets iface dependents by calling into respective modules """
431 ret_dlist = []
432
433 # Get dependents for interface by querying respective modules
434 for module in self.modules.values():
435 try:
436 if ops[0] == 'query-running':
437 if (not hasattr(module,
438 'get_dependent_ifacenames_running')):
439 continue
440 dlist = module.get_dependent_ifacenames_running(ifaceobj)
441 else:
442 if (not hasattr(module, 'get_dependent_ifacenames')):
443 continue
444 dlist = module.get_dependent_ifacenames(ifaceobj,
445 ifacenames)
446 except Exception, e:
447 self.logger.warn('%s: error getting dependent interfaces (%s)'
448 %(ifaceobj.name, str(e)))
449 dlist = None
450 pass
451 if dlist: ret_dlist.extend(dlist)
452 return list(set(ret_dlist))
453
454 def populate_dependency_info(self, ops, ifacenames=None):
455 """ recursive function to generate iface dependency info """
456
457 if not ifacenames:
458 ifacenames = self.ifaceobjdict.keys()
459
460 iqueue = deque(ifacenames)
461 while iqueue:
462 i = iqueue.popleft()
463 # Go through all modules and find dependent ifaces
464 dlist = None
465 ifaceobj = self.get_ifaceobj_first(i)
466 if not ifaceobj:
467 continue
468 dlist = ifaceobj.lowerifaces
469 if not dlist:
470 dlist = self.query_dependents(ifaceobj, ops, ifacenames)
471 else:
472 continue
473 if dlist:
474 self.preprocess_dependency_list(ifaceobj,
475 dlist, ops)
476 ifaceobj.lowerifaces = dlist
477 [iqueue.append(d) for d in dlist]
478 if not self.dependency_graph.get(i):
479 self.dependency_graph[i] = dlist
480
481 def _check_config_no_repeats(self, ifaceobj):
482 """ check if object has an attribute that is
483 restricted to a single object in the system.
484 if yes, warn and return """
485 for k,v in self._cache_no_repeats.items():
486 iv = ifaceobj.config.get(k)
487 if iv and iv[0] == v:
488 self.logger.error('ignoring interface %s. ' %ifaceobj.name +
489 'Only one object with attribute ' +
490 '\'%s %s\' allowed.' %(k, v))
491 return True
492 for k, v in self.config.get('no_repeats', {}).items():
493 iv = ifaceobj.config.get(k)
494 if iv and iv[0] == v:
495 self._cache_no_repeats[k] = v
496 return False
497
498 def _save_iface(self, ifaceobj):
499 if self._check_config_no_repeats(ifaceobj):
500 return
501 if not self._link_master_slave:
502 ifaceobj.link_type = ifaceLinkType.LINK_NA
503 currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
504 if not currentifaceobjlist:
505 self.ifaceobjdict[ifaceobj.name]= [ifaceobj]
506 return
507 if ifaceobj.compare(currentifaceobjlist[0]):
508 self.logger.warn('duplicate interface %s found' %ifaceobj.name)
509 return
510 if currentifaceobjlist[0].type == ifaceobj.type:
511 currentifaceobjlist[0].flags |= iface.HAS_SIBLINGS
512 ifaceobj.flags |= iface.HAS_SIBLINGS
513 self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
514
515 def _iface_configattr_syntax_checker(self, attrname, attrval):
516 for m, mdict in self.module_attrs.items():
517 if not mdict:
518 continue
519 attrsdict = mdict.get('attrs')
520 try:
521 if attrsdict.get(attrname):
522 return True
523 except AttributeError:
524 pass
525 return False
526
527 def _ifaceobj_syntax_checker(self, ifaceobj):
528 err = False
529 for attrname, attrvalue in ifaceobj.config.items():
530 found = False
531 for k, v in self.module_attrs.items():
532 if v and v.get('attrs', {}).get(attrname):
533 found = True
534 break
535 if not found:
536 err = True
537 self.logger.warn('%s: unsupported attribute \'%s\'' \
538 % (ifaceobj.name, attrname))
539 continue
540 return err
541
542 def read_iface_config(self):
543 """ Reads default network interface config /etc/network/interfaces. """
544 nifaces = networkInterfaces(self.interfacesfile,
545 self.interfacesfileiobuf,
546 self.interfacesfileformat,
547 template_engine=self.config.get('template_engine'),
548 template_lookuppath=self.config.get('template_lookuppath'))
549 nifaces.subscribe('iface_found', self._save_iface)
550 nifaces.subscribe('validateifaceattr',
551 self._iface_configattr_syntax_checker)
552 nifaces.subscribe('validateifaceobj', self._ifaceobj_syntax_checker)
553 nifaces.load()
554
555 def read_old_iface_config(self):
556 """ Reads the saved iface config instead of default iface config.
557 And saved iface config is already read by the statemanager """
558 self.ifaceobjdict = copy.deepcopy(self.statemanager.ifaceobjdict)
559
560 def _load_addon_modules_config(self):
561 """ Load addon modules config file """
562
563 with open(self.addon_modules_configfile, 'r') as f:
564 lines = f.readlines()
565 for l in lines:
566 try:
567 litems = l.strip(' \n\t\r').split(',')
568 if not litems or len(litems) < 2:
569 continue
570 operation = litems[0]
571 mname = litems[1]
572 self.module_ops[operation].append(mname)
573 except Exception, e:
574 self.logger.warn('error reading line \'%s\'' %(l, str(e)))
575 continue
576
577 def load_addon_modules(self, modules_dir):
578 """ load python modules from modules_dir
579
580 Default modules_dir is /usr/share/ifupdownmodules
581
582 """
583 self.logger.info('loading builtin modules from %s' %modules_dir)
584 self._load_addon_modules_config()
585 if not modules_dir in sys.path:
586 sys.path.append(modules_dir)
587 try:
588 for op, mlist in self.module_ops.items():
589 for mname in mlist:
590 if self.modules.get(mname):
591 continue
592 mpath = modules_dir + '/' + mname + '.py'
593 if os.path.exists(mpath):
594 try:
595 m = __import__(mname)
596 mclass = getattr(m, mname)
597 except:
598 raise
599 minstance = mclass(force=self.FORCE,
600 dryrun=self.DRYRUN,
601 nowait=self.NOWAIT,
602 perfmode=self.PERFMODE,
603 cache=self.CACHE,
604 cacheflags=self.CACHE_FLAGS)
605 self.modules[mname] = minstance
606 try:
607 self.module_attrs[mname] = minstance.get_modinfo()
608 except:
609 pass
610 except:
611 raise
612
613 # Assign all modules to query operations
614 self.module_ops['query-checkcurr'] = self.modules.keys()
615 self.module_ops['query-running'] = self.modules.keys()
616 self.module_ops['query-dependency'] = self.modules.keys()
617 self.module_ops['query'] = self.modules.keys()
618 self.module_ops['query-raw'] = self.modules.keys()
619
620
621 def _modules_help(self):
622 """ Prints addon modules supported syntax """
623
624 indent = ' '
625 for m, mdict in self.module_attrs.items():
626 if not mdict:
627 continue
628 print('%s: %s' %(m, mdict.get('mhelp')))
629 attrdict = mdict.get('attrs')
630 if not attrdict:
631 continue
632 try:
633 for attrname, attrvaldict in attrdict.items():
634 if attrvaldict.get('compat', False):
635 continue
636 print('%s%s' %(indent, attrname))
637 print('%shelp: %s' %(indent + ' ',
638 attrvaldict.get('help', '')))
639 print ('%srequired: %s' %(indent + ' ',
640 attrvaldict.get('required', False)))
641 default = attrvaldict.get('default')
642 if default:
643 print('%sdefault: %s' %(indent + ' ', default))
644
645 validrange = attrvaldict.get('validrange')
646 if validrange:
647 print('%svalidrange: %s-%s'
648 %(indent + ' ', validrange[0], validrange[1]))
649
650 validvals = attrvaldict.get('validvals')
651 if validvals:
652 print('%svalidvals: %s'
653 %(indent + ' ', ','.join(validvals)))
654
655 examples = attrvaldict.get('example')
656 if not examples:
657 continue
658
659 print '%sexample:' %(indent + ' ')
660 for e in examples:
661 print '%s%s' %(indent + ' ', e)
662 except:
663 pass
664 print ''
665
666 def load_scripts(self, modules_dir):
667 """ loading user modules from /etc/network/.
668
669 Note that previously loaded python modules override modules found
670 under /etc/network if any
671
672 """
673
674 self.logger.info('looking for user scripts under %s' %modules_dir)
675 for op, mlist in self.script_ops.items():
676 msubdir = modules_dir + '/if-%s.d' %op
677 self.logger.info('loading scripts under %s ...' %msubdir)
678 try:
679 module_list = os.listdir(msubdir)
680 for module in module_list:
681 if self.modules.get(module) is not None:
682 continue
683 self.script_ops[op].append(
684 msubdir + '/' + module)
685 except:
686 # continue reading
687 pass
688
689 def _sched_ifaces(self, ifacenames, ops, skipupperifaces=False,
690 followdependents=True):
691 self.logger.debug('scheduling \'%s\' for %s'
692 %(str(ops), str(ifacenames)))
693 self._pretty_print_ordered_dict('dependency graph',
694 self.dependency_graph)
695 return ifaceScheduler.sched_ifaces(self, ifacenames, ops,
696 dependency_graph=self.dependency_graph,
697 order=ifaceSchedulerFlags.INORDER
698 if 'down' in ops[0]
699 else ifaceSchedulerFlags.POSTORDER,
700 followdependents=followdependents,
701 skipupperifaces=skipupperifaces)
702
703 def _render_ifacename(self, ifacename):
704 new_ifacenames = []
705 vlan_match = re.match("^([\d]+)-([\d]+)", ifacename)
706 if vlan_match:
707 vlan_groups = vlan_match.groups()
708 if vlan_groups[0] and vlan_groups[1]:
709 [new_ifacenames.append('%d' %v)
710 for v in range(int(vlan_groups[0]),
711 int(vlan_groups[1])+1)]
712 return new_ifacenames
713
714 def _preprocess_ifacenames(self, ifacenames):
715 """ validates interface list for config existance.
716
717 returns -1 if one or more interface not found. else, returns 0
718
719 """
720 new_ifacenames = []
721 err_iface = ''
722 for i in ifacenames:
723 ifaceobjs = self.get_ifaceobjs(i)
724 if not ifaceobjs:
725 # if name not available, render interface name and check again
726 rendered_ifacenames = utils.expand_iface_range(i)
727 if rendered_ifacenames:
728 for ri in rendered_ifacenames:
729 ifaceobjs = self.get_ifaceobjs(ri)
730 if not ifaceobjs:
731 err_iface += ' ' + ri
732 else:
733 new_ifacenames.append(ri)
734 else:
735 err_iface += ' ' + i
736 else:
737 new_ifacenames.append(i)
738 if err_iface:
739 raise Exception('cannot find interfaces:%s' %err_iface)
740 return new_ifacenames
741
742 def _iface_whitelisted(self, auto, allow_classes, excludepats, ifacename):
743 """ Checks if interface is whitelisted depending on set of parameters.
744
745 interfaces are checked against the allow_classes and auto lists.
746
747 """
748 if excludepats:
749 for e in excludepats:
750 if re.search(e, ifacename):
751 return False
752 ifaceobjs = self.get_ifaceobjs(ifacename)
753 if not ifaceobjs:
754 self.logger.debug('iface %s' %ifacename + ' not found')
755 return False
756 # We check classes first
757 if allow_classes:
758 for i in ifaceobjs:
759 if i.classes:
760 common = Set([allow_classes]).intersection(
761 Set(i.classes))
762 if common:
763 return True
764 return False
765 if auto:
766 for i in ifaceobjs:
767 if i.auto:
768 return True
769 return False
770 return True
771
772 def _compat_conv_op_to_mode(self, op):
773 """ Returns old op name to work with existing scripts """
774 if op == 'pre-up':
775 return 'start'
776 elif op == 'pre-down':
777 return 'stop'
778 else:
779 return op
780
781 def generate_running_env(self, ifaceobj, op):
782 """ Generates a dictionary with env variables required for
783 an interface. Used to support script execution for interfaces.
784 """
785
786 cenv = None
787 iface_env = ifaceobj.env
788 if iface_env:
789 cenv = os.environ
790 if cenv:
791 cenv.update(iface_env)
792 else:
793 cenv = iface_env
794 cenv['MODE'] = self._compat_conv_op_to_mode(op)
795 return cenv
796
797 def _save_state(self):
798 if not self.STATEMANAGER_ENABLE or not self.STATEMANAGER_UPDATE:
799 return
800 try:
801 # Update persistant iface states
802 self.statemanager.save_state()
803 except Exception, e:
804 if self.logger.isEnabledFor(logging.DEBUG):
805 t = sys.exc_info()[2]
806 traceback.print_tb(t)
807 self.logger.warning('error saving state (%s)' %str(e))
808
809 def set_type(self, type):
810 if type == 'iface':
811 self.type = ifaceType.IFACE
812 elif type == 'vlan':
813 self.type = ifaceType.BRIDGE_VLAN
814 else:
815 self.type = ifaceType.UNKNOWN
816
817 def _process_delay_admin_state_queue(self, op):
818 if not self._delay_admin_state_iface_queue:
819 return
820 if op == 'up':
821 func = self.link_up
822 elif op == 'down':
823 func = self.link_down
824 else:
825 return
826 for i in self._delay_admin_state_iface_queue:
827 try:
828 if self.link_exists(i):
829 func(i)
830 except Exception, e:
831 self.logger.warn(str(e))
832 pass
833
834 def up(self, ops, auto=False, allow_classes=None, ifacenames=None,
835 excludepats=None, printdependency=None, syntaxcheck=False,
836 type=None, skipupperifaces=False):
837 """This brings the interface(s) up
838
839 Args:
840 ops (list): list of ops to perform on the interface(s).
841 Eg: ['pre-up', 'up', 'post-up'
842
843 Kwargs:
844 auto (bool): act on interfaces marked auto
845 allow_classes (list): act on interfaces belonging to classes in the list
846 ifacenames (list): act on interfaces specified in this list
847 excludepats (list): list of patterns of interfaces to exclude
848 syntaxcheck (bool): only perform syntax check
849 """
850
851 self.set_type(type)
852
853 if allow_classes:
854 self.IFACE_CLASS = True
855 if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False
856 if auto:
857 self.ALL = True
858 self.WITH_DEPENDS = True
859 try:
860 self.read_iface_config()
861 except Exception:
862 raise
863
864 # If only syntax check was requested, return here
865 if syntaxcheck:
866 return
867
868 if ifacenames:
869 ifacenames = self._preprocess_ifacenames(ifacenames)
870
871 # if iface list not given by user, assume all from config file
872 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
873
874 # filter interfaces based on auto and allow classes
875 filtered_ifacenames = [i for i in ifacenames
876 if self._iface_whitelisted(auto, allow_classes,
877 excludepats, i)]
878 if not filtered_ifacenames:
879 raise Exception('no ifaces found matching given allow lists')
880
881 if printdependency:
882 self.populate_dependency_info(ops, filtered_ifacenames)
883 self.print_dependency(filtered_ifacenames, printdependency)
884 return
885 else:
886 self.populate_dependency_info(ops)
887
888 try:
889 self._sched_ifaces(filtered_ifacenames, ops,
890 skipupperifaces=skipupperifaces,
891 followdependents=True if self.WITH_DEPENDS else False)
892 finally:
893 self._process_delay_admin_state_queue('up')
894 if not self.DRYRUN and self.ADDONS_ENABLE:
895 self._save_state()
896
897 def down(self, ops, auto=False, allow_classes=None, ifacenames=None,
898 excludepats=None, printdependency=None, usecurrentconfig=False,
899 type=None):
900 """ down an interface """
901
902 self.set_type(type)
903
904 if allow_classes:
905 self.IFACE_CLASS = True
906 if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False
907 if auto:
908 self.ALL = True
909 self.WITH_DEPENDS = True
910 # For down we need to look at old state, unless usecurrentconfig
911 # is set
912 if (not usecurrentconfig and self.STATEMANAGER_ENABLE and
913 self.statemanager.ifaceobjdict):
914 # Since we are using state manager objects,
915 # skip the updating of state manager objects
916 self.logger.debug('Looking at old state ..')
917 self.read_old_iface_config()
918 else:
919 # If no old state available
920 try:
921 self.read_iface_config()
922 except Exception, e:
923 raise Exception('error reading iface config (%s)' %str(e))
924 if ifacenames:
925 # If iface list is given by the caller, always check if iface
926 # is present
927 try:
928 ifacenames = self._preprocess_ifacenames(ifacenames)
929 except Exception, e:
930 raise Exception('%s' %str(e) +
931 ' (interface was probably never up ?)')
932
933 # if iface list not given by user, assume all from config file
934 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
935
936 # filter interfaces based on auto and allow classes
937 filtered_ifacenames = [i for i in ifacenames
938 if self._iface_whitelisted(auto, allow_classes,
939 excludepats, i)]
940 if not filtered_ifacenames:
941 raise Exception('no ifaces found matching given allow lists ' +
942 '(or interfaces were probably never up ?)')
943
944 if printdependency:
945 self.populate_dependency_info(ops, filtered_ifacenames)
946 self.print_dependency(filtered_ifacenames, printdependency)
947 return
948 else:
949 self.populate_dependency_info(ops)
950
951 try:
952 self._sched_ifaces(filtered_ifacenames, ops,
953 followdependents=True if self.WITH_DEPENDS else False)
954 finally:
955 self._process_delay_admin_state_queue('down')
956 if not self.DRYRUN and self.ADDONS_ENABLE:
957 self._save_state()
958
959 def query(self, ops, auto=False, allow_classes=None, ifacenames=None,
960 excludepats=None, printdependency=None,
961 format='native', type=None):
962 """ query an interface """
963
964 self.set_type(type)
965
966 if allow_classes:
967 self.IFACE_CLASS = True
968 if self.STATEMANAGER_ENABLE and ops[0] == 'query-savedstate':
969 return self.statemanager.dump_pretty(ifacenames)
970 self.STATEMANAGER_UPDATE = False
971 if auto:
972 self.logger.debug('setting flag ALL')
973 self.ALL = True
974 self.WITH_DEPENDS = True
975
976 if ops[0] == 'query-syntax':
977 self._modules_help()
978 return
979 elif ops[0] == 'query-running':
980 # create fake devices to all dependents that dont have config
981 map(lambda i: self.create_n_save_ifaceobj(i, self.NOCONFIG),
982 ifacenames)
983 else:
984 try:
985 self.read_iface_config()
986 except Exception:
987 raise
988
989 if ifacenames and ops[0] != 'query-running':
990 # If iface list is given, always check if iface is present
991 ifacenames = self._preprocess_ifacenames(ifacenames)
992
993 # if iface list not given by user, assume all from config file
994 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
995
996 # filter interfaces based on auto and allow classes
997 if ops[0] == 'query-running':
998 filtered_ifacenames = ifacenames
999 else:
1000 filtered_ifacenames = [i for i in ifacenames
1001 if self._iface_whitelisted(auto, allow_classes,
1002 excludepats, i)]
1003 if not filtered_ifacenames:
1004 raise Exception('no ifaces found matching ' +
1005 'given allow lists')
1006
1007 self.populate_dependency_info(ops)
1008 if ops[0] == 'query-dependency' and printdependency:
1009 self.print_dependency(filtered_ifacenames, printdependency)
1010 return
1011
1012 if ops[0] == 'query':
1013 return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
1014 elif ops[0] == 'query-raw':
1015 return self.print_ifaceobjs_raw(filtered_ifacenames)
1016
1017 self._sched_ifaces(filtered_ifacenames, ops,
1018 followdependents=True if self.WITH_DEPENDS else False)
1019
1020 if ops[0] == 'query-checkcurr':
1021 ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames, format)
1022 if ret != 0:
1023 # if any of the object has an error, signal that silently
1024 raise Exception('')
1025 elif ops[0] == 'query-running':
1026 self.print_ifaceobjsrunning_pretty(filtered_ifacenames, format)
1027 return
1028
1029 def _reload_currentlyup(self, upops, downops, auto=True, allow=None,
1030 ifacenames=None, excludepats=None, usecurrentconfig=False,
1031 **extra_args):
1032 """ reload currently up interfaces """
1033 allow_classes = []
1034 new_ifaceobjdict = {}
1035
1036 # Override auto to true
1037 auto = True
1038 if auto:
1039 self.ALL = True
1040 self.WITH_DEPENDS = True
1041 try:
1042 self.read_iface_config()
1043 except:
1044 raise
1045 if not self.ifaceobjdict:
1046 self.logger.warn("nothing to reload ..exiting.")
1047 return
1048 already_up_ifacenames = []
1049 # generate dependency graph of interfaces
1050 self.populate_dependency_info(upops)
1051 if (not usecurrentconfig and self.STATEMANAGER_ENABLE
1052 and self.statemanager.ifaceobjdict):
1053 already_up_ifacenames = self.statemanager.ifaceobjdict.keys()
1054
1055 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1056 filtered_ifacenames = [i for i in ifacenames
1057 if self._iface_whitelisted(auto, allow_classes,
1058 excludepats, i)]
1059
1060 # Get already up interfaces that still exist in the interfaces file
1061 already_up_ifacenames_not_present = Set(
1062 already_up_ifacenames).difference(ifacenames)
1063 already_up_ifacenames_still_present = Set(
1064 already_up_ifacenames).difference(
1065 already_up_ifacenames_not_present)
1066 interfaces_to_up = Set(already_up_ifacenames_still_present).union(
1067 filtered_ifacenames)
1068
1069 if (already_up_ifacenames_not_present and
1070 self.config.get('ifreload_currentlyup_down_notpresent') == '1'):
1071 self.logger.info('reload: schedule down on interfaces: %s'
1072 %str(already_up_ifacenames_not_present))
1073
1074 # Save a copy of new iface objects and dependency_graph
1075 new_ifaceobjdict = dict(self.ifaceobjdict)
1076 new_dependency_graph = dict(self.dependency_graph)
1077
1078 # old interface config is read into self.ifaceobjdict
1079 self.read_old_iface_config()
1080
1081 # reinitialize dependency graph
1082 self.dependency_graph = OrderedDict({})
1083 self.populate_dependency_info(downops,
1084 already_up_ifacenames_not_present)
1085 self._sched_ifaces(already_up_ifacenames_not_present, downops,
1086 followdependents=True if self.WITH_DEPENDS else False)
1087 else:
1088 self.logger.debug('no interfaces to down ..')
1089
1090 # Now, run 'up' with new config dict
1091 # reset statemanager update flag to default
1092 if new_ifaceobjdict:
1093 self.ifaceobjdict = new_ifaceobjdict
1094 self.dependency_graph = new_dependency_graph
1095
1096 if not self.ifaceobjdict:
1097 return
1098 self.logger.info('reload: scheduling up on interfaces: %s'
1099 %str(interfaces_to_up))
1100 self._sched_ifaces(interfaces_to_up, upops,
1101 followdependents=True if self.WITH_DEPENDS else False)
1102 if self.DRYRUN:
1103 return
1104 self._save_state()
1105
1106 def _reload_default(self, upops, downops, auto=False, allow=None,
1107 ifacenames=None, excludepats=None, usecurrentconfig=False,
1108 **extra_args):
1109 """ reload interface config """
1110 allow_classes = []
1111 new_ifaceobjdict = {}
1112
1113 if auto:
1114 self.ALL = True
1115 self.WITH_DEPENDS = True
1116 try:
1117 self.read_iface_config()
1118 except:
1119 raise
1120
1121 if not self.ifaceobjdict:
1122 self.logger.warn("nothing to reload ..exiting.")
1123 return
1124 # generate dependency graph of interfaces
1125 self.populate_dependency_info(upops)
1126 if (not usecurrentconfig and self.STATEMANAGER_ENABLE
1127 and self.statemanager.ifaceobjdict):
1128 # Save a copy of new iface objects and dependency_graph
1129 new_ifaceobjdict = dict(self.ifaceobjdict)
1130 new_dependency_graph = dict(self.dependency_graph)
1131
1132 # if old state is present, read old state and mark op for 'down'
1133 # followed by 'up' aka: reload
1134 # old interface config is read into self.ifaceobjdict
1135 self.read_old_iface_config()
1136 op = 'reload'
1137 else:
1138 # oldconfig not available, continue with 'up' with new config
1139 op = 'up'
1140
1141 if not ifacenames: ifacenames = self.ifaceobjdict.keys()
1142 if op == 'reload' and ifacenames:
1143 filtered_ifacenames = [i for i in ifacenames
1144 if self._iface_whitelisted(auto, allow_classes,
1145 excludepats, i)]
1146 # Generate the interface down list
1147 # Interfaces that go into the down list:
1148 # - interfaces that were present in last config and are not
1149 # present in the new config
1150 # - interfaces that were changed between the last and current
1151 # config
1152 #
1153 ifacedownlist = []
1154 for ifname in filtered_ifacenames:
1155 lastifaceobjlist = self.ifaceobjdict.get(ifname)
1156 objidx = 0
1157 # If interface is not present in the new file
1158 # append it to the down list
1159 newifaceobjlist = new_ifaceobjdict.get(ifname)
1160 if not newifaceobjlist:
1161 ifacedownlist.append(ifname)
1162 continue
1163 # If interface has changed between the current file
1164 # and the last installed append it to the down list
1165 if len(newifaceobjlist) != len(lastifaceobjlist):
1166 ifacedownlist.append(ifname)
1167 continue
1168 # compare object list
1169 for objidx in range(0, len(lastifaceobjlist)):
1170 oldobj = lastifaceobjlist[objidx]
1171 newobj = newifaceobjlist[objidx]
1172 if not newobj.compare(oldobj):
1173 ifacedownlist.append(ifname)
1174 continue
1175
1176 if ifacedownlist:
1177 self.logger.info('reload: scheduling down on interfaces: %s'
1178 %str(ifacedownlist))
1179 # reinitialize dependency graph
1180 self.dependency_graph = OrderedDict({})
1181 # Generate dependency info for old config
1182 self.populate_dependency_info(downops, ifacedownlist)
1183 try:
1184 self._sched_ifaces(ifacedownlist, downops,
1185 followdependents=False)
1186 except Exception, e:
1187 self.logger.error(str(e))
1188 pass
1189 finally:
1190 self._process_delay_admin_state_queue('down')
1191 else:
1192 self.logger.debug('no interfaces to down ..')
1193
1194 # Now, run 'up' with new config dict
1195 # reset statemanager update flag to default
1196 if not new_ifaceobjdict:
1197 return
1198 self.ifaceobjdict = new_ifaceobjdict
1199 self.dependency_graph = new_dependency_graph
1200 ifacenames = self.ifaceobjdict.keys()
1201 filtered_ifacenames = [i for i in ifacenames
1202 if self._iface_whitelisted(auto, allow_classes,
1203 excludepats, i)]
1204
1205 self.logger.info('reload: scheduling up on interfaces: %s'
1206 %str(filtered_ifacenames))
1207 try:
1208 self._sched_ifaces(filtered_ifacenames, upops,
1209 followdependents=True if self.WITH_DEPENDS else False)
1210 except Exception, e:
1211 self.logger.error(str(e))
1212 pass
1213 finally:
1214 self._process_delay_admin_state_queue('up')
1215 if self.DRYRUN:
1216 return
1217 self._save_state()
1218
1219 def reload(self, *args, **kargs):
1220 """ reload interface config """
1221 self.logger.debug('reloading interface config ..')
1222 if kargs.get('currentlyup', False):
1223 self._reload_currentlyup(*args, **kargs)
1224 else:
1225 self._reload_default(*args, **kargs)
1226
1227 def _pretty_print_ordered_dict(self, prefix, argdict):
1228 outbuf = prefix + ' {\n'
1229 for k, vlist in argdict.items():
1230 outbuf += '\t%s : %s\n' %(k, str(vlist))
1231 self.logger.debug(outbuf + '}')
1232
1233 def print_dependency(self, ifacenames, format):
1234 """ prints iface dependency information """
1235
1236 if not ifacenames:
1237 ifacenames = self.ifaceobjdict.keys()
1238 if format == 'list':
1239 for k,v in self.dependency_graph.items():
1240 print '%s : %s' %(k, str(v))
1241 elif format == 'dot':
1242 indegrees = {}
1243 map(lambda i: indegrees.update({i :
1244 self.get_iface_refcnt(i)}),
1245 self.dependency_graph.keys())
1246 graph.generate_dots(self.dependency_graph, indegrees)
1247
1248 def print_ifaceobjs_raw(self, ifacenames):
1249 """ prints raw lines for ifaces from config file """
1250
1251 for i in ifacenames:
1252 for ifaceobj in self.get_ifaceobjs(i):
1253 if (self.is_ifaceobj_builtin(ifaceobj) or
1254 not ifaceobj.is_config_present()):
1255 continue
1256 ifaceobj.dump_raw(self.logger)
1257 print '\n'
1258 if self.WITH_DEPENDS and not self.ALL:
1259 dlist = ifaceobj.lowerifaces
1260 if not dlist: continue
1261 self.print_ifaceobjs_raw(dlist)
1262
1263 def _get_ifaceobjs_pretty(self, ifacenames, ifaceobjs, running=False):
1264 """ returns iface obj list """
1265
1266 for i in ifacenames:
1267 for ifaceobj in self.get_ifaceobjs(i):
1268 if ((not running and self.is_ifaceobj_noconfig(ifaceobj)) or
1269 (running and not ifaceobj.is_config_present())):
1270 continue
1271 ifaceobjs.append(ifaceobj)
1272 if self.WITH_DEPENDS and not self.ALL:
1273 dlist = ifaceobj.lowerifaces
1274 if not dlist: continue
1275 self._get_ifaceobjs_pretty(dlist, ifaceobjs, running)
1276
1277 def print_ifaceobjs_pretty(self, ifacenames, format='native'):
1278 """ pretty prints iface in format given by keyword arg format """
1279
1280 ifaceobjs = []
1281 self._get_ifaceobjs_pretty(ifacenames, ifaceobjs)
1282 if not ifaceobjs: return
1283 if format == 'json':
1284 print json.dumps(ifaceobjs, cls=ifaceJsonEncoder,
1285 indent=4, separators=(',', ': '))
1286 else:
1287 expand = int(self.config.get('ifquery_ifacename_expand_range', '0'))
1288 for i in ifaceobjs:
1289 if not expand and (i.flags & iface.IFACERANGE_ENTRY):
1290 # print only the first one
1291 if i.flags & iface.IFACERANGE_START:
1292 i.dump_pretty(use_realname=True)
1293 else:
1294 i.dump_pretty()
1295
1296 def _get_ifaceobjscurr_pretty(self, ifacenames, ifaceobjs):
1297 ret = 0
1298 for i in ifacenames:
1299 ifaceobjscurr = self.get_ifaceobjcurr(i)
1300 if not ifaceobjscurr: continue
1301 for ifaceobj in ifaceobjscurr:
1302 if (ifaceobj.status == ifaceStatus.NOTFOUND or
1303 ifaceobj.status == ifaceStatus.ERROR):
1304 ret = 1
1305 if self.is_ifaceobj_noconfig(ifaceobj):
1306 continue
1307 ifaceobjs.append(ifaceobj)
1308 if self.WITH_DEPENDS and not self.ALL:
1309 dlist = ifaceobj.lowerifaces
1310 if not dlist: continue
1311 dret = self._get_ifaceobjscurr_pretty(dlist, ifaceobjs)
1312 if dret: ret = 1
1313 return ret
1314
1315 def print_ifaceobjscurr_pretty(self, ifacenames, format='native'):
1316 """ pretty prints current running state of interfaces with status.
1317
1318 returns 1 if any of the interface has an error,
1319 else returns 0
1320 """
1321
1322 ifaceobjs = []
1323 ret = self._get_ifaceobjscurr_pretty(ifacenames, ifaceobjs)
1324 if not ifaceobjs: return
1325 if format == 'json':
1326 print json.dumps(ifaceobjs, cls=ifaceJsonEncoder, indent=2,
1327 separators=(',', ': '))
1328 else:
1329 map(lambda i: i.dump_pretty(with_status=True,
1330 successstr=self.config.get('ifquery_check_success_str',
1331 _success_sym),
1332 errorstr=self.config.get('ifquery_check_error_str', _error_sym),
1333 unknownstr=self.config.get('ifquery_check_unknown_str', '')),
1334 ifaceobjs)
1335 return ret
1336
1337 def print_ifaceobjsrunning_pretty(self, ifacenames, format='native'):
1338 """ pretty prints iface running state """
1339
1340 ifaceobjs = []
1341 self._get_ifaceobjs_pretty(ifacenames, ifaceobjs, running=True)
1342 if not ifaceobjs: return
1343 if format == 'json':
1344 print json.dumps(ifaceobjs, cls=ifaceJsonEncoder, indent=2,
1345 separators=(',', ': '))
1346 else:
1347 map(lambda i: i.dump_pretty(), ifaceobjs)
1348
1349 def _dump(self):
1350 print 'ifupdown main object dump'
1351 print self.pp.pprint(self.modules)
1352 print self.pp.pprint(self.ifaceobjdict)
1353
1354 def _dump_ifaceobjs(self, ifacenames):
1355 for i in ifacenames:
1356 ifaceobjs = self.get_ifaceobjs(i)
1357 for i in ifaceobjs:
1358 i.dump(self.logger)
1359 print '\n'