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