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