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