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