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