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