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