import pprint
import logging
import sys, traceback
+import copy
+import json
from statemanager import *
from networkinterfaces import *
from iface import *
from graph import *
from sets import Set
-class ifupdownMain():
+_tickmark = u'\u2713'
+_crossmark = u'\u2717'
+_success_sym = _tickmark
+_error_sym = _crossmark
+
+class ifupdownMain(ifupdownBase):
+ """ ifupdown2 main class """
# Flags
WITH_DEPENDS = False
ALL = False
- STATE_CHECK = False
+ COMPAT_EXEC_SCRIPTS = False
+ STATEMANAGER_ENABLE = True
+ STATEMANAGER_UPDATE = True
+ ADDONS_ENABLE = False
# priv flags to mark iface objects
BUILTIN = 0x1
scripts_dir='/etc/network'
addon_modules_dir='/usr/share/ifupdownaddons'
- addon_modules_configfile='/etc/network/.addons.conf'
+ addon_modules_configfile='/var/lib/ifupdownaddons/addons.conf'
# iface dictionary in the below format:
# { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
# eg:
- # { 'swp1' : [<ifaceobject1>, <ifaceobject2> ..] }
+ # { 'swp1' : [<iface swp1>, <iface swp2> ..] }
#
# Each ifaceobject corresponds to a configuration block for
# that interface
+ # The value in the dictionary is a list because the network
+ # interface configuration file supports more than one iface section
+ # in the interfaces file
ifaceobjdict = OrderedDict()
-
# iface dictionary representing the curr running state of an iface
# in the below format:
# {'<ifacename>' : <ifaceobject>}
ifaceobjcurrdict = OrderedDict()
- # Dictionary representing operation, sub operation and modules
- # for every sub operation
- operations = OrderedDict([('pre-up', []),
+ # Dictionary representing operation and modules
+ # for every operation
+ module_ops = OrderedDict([('pre-up', []),
('up' , []),
('post-up' , []),
('query-checkcurr', []),
('post-down' , [])])
# For old style /etc/network/ bash scripts
- operations_compat = OrderedDict([('pre-up', []),
+ script_ops = OrderedDict([('pre-up', []),
('up' , []),
('post-up' , []),
('pre-down', []),
('down' , []),
('post-down' , [])])
+ # Handlers for ops that ifupdown2 owns
+ def run_up(self, ifaceobj):
+ ifacename = ifaceobj.name
+ if self.link_exists(ifacename):
+ self.link_up(ifacename)
+
+ def run_down(self, ifaceobj):
+ ifacename = ifaceobj.name
+ if self.link_exists(ifacename):
+ self.link_down(ifacename)
- def __init__(self, force=False, dryrun=False, nowait=False,
+ # ifupdown object interface operation handlers
+ ops_handlers = OrderedDict([('up', run_up),
+ ('down', run_down)])
+
+ def run_sched_ifaceobj_posthook(self, ifaceobj, op):
+ if ((ifaceobj.priv_flags & self.BUILTIN) or
+ (ifaceobj.priv_flags & self.NOCONFIG)):
+ return
+ if self.STATEMANAGER_UPDATE:
+ self.statemanager.ifaceobj_sync(ifaceobj, op)
+
+ # ifupdown object interface scheduler pre and posthooks
+ sched_hooks = {'posthook' : run_sched_ifaceobj_posthook}
+
+ def __init__(self, config={},
+ force=False, dryrun=False, nowait=False,
perfmode=False, withdepends=False, njobs=1,
- cache=False):
+ cache=False, addons_enable=True, statemanager_enable=True,
+ interfacesfile='/etc/network/interfaces',
+ interfacesfileiobuf=None,
+ interfacesfileformat='native'):
self.logger = logging.getLogger('ifupdown')
-
self.FORCE = force
self.DRYRUN = dryrun
self.NOWAIT = nowait
self.PERFMODE = perfmode
self.WITH_DEPENDS = withdepends
+ self.STATEMANAGER_ENABLE = statemanager_enable
self.CACHE = cache
+ self.interfacesfile = interfacesfile
+ self.interfacesfileiobuf = interfacesfileiobuf
+ self.interfacesfileformat = interfacesfileformat
+ self.config = config
+ self.logger.debug(self.config)
+
+ # Can be used to provide hints for caching
+ self.CACHE_FLAGS = 0x0
self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
+ self.ADDONS_ENABLE = addons_enable
self.ifaces = OrderedDict()
self.njobs = njobs
self.pp = pprint.PrettyPrinter(indent=4)
self.modules = OrderedDict({})
self.module_attrs = {}
+
self.load_addon_modules(self.addon_modules_dir)
- self.load_scripts(self.scripts_dir)
+ if self.COMPAT_EXEC_SCRIPTS:
+ self.load_scripts(self.scripts_dir)
self.dependency_graph = OrderedDict({})
- try:
- self.statemanager = stateManager()
- self.statemanager.read_saved_state()
- except Exception, e:
- # XXX Maybe we should continue by ignoring old state
- self.logger.warning('error reading state (%s)' %str(e))
- raise
-
- def get_subops(self, op):
- """ Returns sub-operation list """
- return self.operations.get(op).keys()
-
- def compat_conv_op_to_mode(self, op):
- """ Returns old op name to work with existing scripts """
- if op == 'pre-up':
- return 'start'
- elif op == 'pre-down':
- return 'stop'
+ if self.STATEMANAGER_ENABLE:
+ try:
+ self.statemanager = stateManager()
+ self.statemanager.read_saved_state()
+ except Exception, e:
+ # XXX Maybe we should continue by ignoring old state
+ self.logger.warning('error reading state (%s)' %str(e))
+ raise
else:
- return op
-
- def set_force(self, force):
- """ Set force flag. """
- self.FORCE = force
-
- def get_force(self):
- """ return force flag. """
- return self.FORCE
-
- def set_dryrun(self, dryrun):
- self.DRYRUN = dryrun
-
- def get_dryrun(self):
- return self.DRYRUN
-
- def get_cache(self):
- return self.CACHE
-
- def get_ifaceobjdict(self):
- return self.ifaceobjdict
-
- def set_ifaceobjdict(self, ifaceobjdict):
- del self.ifaceobjdict
- self.ifaceobjdict = ifaceobjdict
-
- def set_dependency_graph(self, dependency_graph):
- self.dependency_graph = dependency_graph
+ self.STATEMANAGER_UPDATE = False
- def get_dependency_graph(self):
- return self.dependency_graph
-
- def set_perfmode(self, perfmode):
- self.PERFMODE = perfmode
-
- def get_perfmode(self):
- return self.PERFMODE
-
- def set_nowait(self, nowait):
- self.NOWAIT = nowait
-
- def get_nowait(self):
- return self.NOWAIT
-
- def set_njobs(self, njobs):
- self.logger.debug('setting njobs to %d' %njobs)
- self.njobs = njobs
-
- def get_njobs(self):
- return self.njobs
-
- def get_withdepends(self):
- return self.WITH_DEPENDS
-
- def set_withdepends(self, withdepends):
- self.logger.debug('setting withdepends to true')
- self.WITH_DEPENDS = withdepends
-
- def set_iface_state(self, ifaceobj, state, status):
- ifaceobj.set_state(state)
- ifaceobj.set_status(status)
- self.statemanager.update_iface_state(ifaceobj)
-
- def get_iface_objs(self, ifacename):
+ def get_ifaceobjs(self, ifacename):
return self.ifaceobjdict.get(ifacename)
- def get_iface_obj_first(self, ifacename):
- ifaceobjs = self.get_iface_objs(ifacename)
- if ifaceobjs is not None:
+ def get_ifaceobj_first(self, ifacename):
+ ifaceobjs = self.get_ifaceobjs(ifacename)
+ if ifaceobjs:
return ifaceobjs[0]
return None
+ def get_ifacenames(self):
+ return self.ifaceobjdict.keys()
+
def get_iface_obj_last(self, ifacename):
return self.ifaceobjdict.get(ifacename)[-1]
- def create_n_save_ifaceobjcurr(self, ifaceobj):
- ifacename = ifaceobj.get_name()
- ifaceobjcurr = self.get_ifaceobjcurr(ifacename)
- if ifaceobjcurr is not None:
- return ifaceobjcurr
+ def create_n_save_ifaceobj(self, ifacename, priv_flags=None,
+ increfcnt=False):
+ """ creates a iface object and adds it to the iface dictionary """
+ ifaceobj = iface()
+ ifaceobj.name = ifacename
+ ifaceobj.priv_flags = priv_flags
+ ifaceobj.auto = True
+ if increfcnt:
+ ifaceobj.inc_refcnt()
+ self.ifaceobjdict[ifacename] = [ifaceobj]
+ return ifaceobj
+ def create_n_save_ifaceobjcurr(self, ifaceobj):
+ """ creates a copy of iface object and adds it to the iface
+ dict containing current iface objects
+ """
ifaceobjcurr = iface()
- ifaceobjcurr.set_name(ifacename)
- ifaceobjcurr.set_dependents(ifaceobj.get_dependents())
- self.ifaceobjcurrdict[ifacename] = ifaceobjcurr
-
+ ifaceobjcurr.name = ifaceobj.name
+ ifaceobjcurr.lowerifaces = ifaceobj.lowerifaces
+ ifaceobjcurr.priv_flags = ifaceobj.priv_flags
+ ifaceobjcurr.auto = ifaceobj.auto
+ self.ifaceobjcurrdict.setdefault(ifaceobj.name,
+ []).append(ifaceobjcurr)
return ifaceobjcurr
- def get_ifaceobjcurr(self, ifacename):
- return self.ifaceobjcurrdict.get(ifacename)
+ def get_ifaceobjcurr(self, ifacename, idx=0):
+ ifaceobjlist = self.ifaceobjcurrdict.get(ifacename)
+ if not ifaceobjlist:
+ return None
+ if not idx:
+ return ifaceobjlist
+ else:
+ return ifaceobjlist[idx]
def get_ifaceobjrunning(self, ifacename):
return self.ifaceobjrunningdict.get(ifacename)
- def get_iface_status(self, ifacename):
- ifaceobjs = self.get_iface_objs(ifacename)
- for i in ifaceobjs:
- if i.get_status() != ifaceStatus.SUCCESS:
- return i.get_status()
-
- return ifaceStatus.SUCCESS
-
def get_iface_refcnt(self, ifacename):
+ """ Return iface ref count """
max = 0
- ifaceobjs = self.get_iface_objs(ifacename)
+ ifaceobjs = self.get_ifaceobjs(ifacename)
+ if not ifaceobjs:
+ return 0
for i in ifaceobjs:
- if i.get_refcnt() > max:
- max = i.get_refcnt()
+ if i.refcnt > max:
+ max = i.refcnt
return max
- def create_n_save_ifaceobj(self, ifacename, priv_flags=None,
- increfcnt=False):
- """ creates and returns a fake vlan iface object.
- This was added to support creation of simple vlan
- devices without any user specified configuration.
- """
- ifaceobj = iface()
- ifaceobj.set_name(ifacename)
- ifaceobj.priv_flags = priv_flags
- ifaceobj.set_auto()
- if increfcnt:
- ifaceobj.inc_refcnt()
- self.ifaceobjdict[ifacename] = [ifaceobj]
-
def is_iface_builtin_byname(self, ifacename):
""" Returns true if iface name is a builtin interface.
return (ifaceobj.priv_flags & self.BUILTIN)
def is_ifaceobj_noconfig(self, ifaceobj):
- """ Returns true if iface name did not have a user defined config.
+ """ Returns true if iface object did not have a user defined config.
These interfaces appear only when they are dependents of interfaces
which have user defined config
def is_iface_noconfig(self, ifacename):
""" Returns true if iface has no config """
- ifaceobj = self.get_iface_obj_first(ifacename)
+ ifaceobj = self.get_ifaceobj_first(ifacename)
if not ifaceobj: return True
-
return self.is_ifaceobj_noconfig(ifaceobj)
- def preprocess_dependency_list(self, dlist, ops):
+ def preprocess_dependency_list(self, upperifacename, dlist, ops):
""" We go through the dependency list and
delete or add interfaces from the interfaces dict by
applying the following rules:
del_list = []
for d in dlist:
- dilist = self.get_iface_objs(d)
+ dilist = self.get_ifaceobjs(d)
if not dilist:
if self.is_iface_builtin_byname(d):
- self.create_n_save_ifaceobj(d,
- self.BUILTIN | self.NOCONFIG, True),
- elif self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG == False:
- # create fake devices to all dependents that dont
- # have config
- self.create_n_save_ifaceobj(d, self.NOCONFIG, True),
+ self.create_n_save_ifaceobj(d, self.BUILTIN | self.NOCONFIG,
+ True).add_to_upperifaces(upperifacename)
+ elif not self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG:
+ self.create_n_save_ifaceobj(d, self.NOCONFIG,
+ True).add_to_upperifaces(upperifacename)
else:
del_list.append(d)
else:
for di in dilist:
di.inc_refcnt()
+ di.add_to_upperifaces(upperifacename)
for d in del_list:
dlist.remove(d)
dlist = None
# Get dependents for interface by querying respective modules
- for op in ops:
- for mname in self.operations.get(op):
- module = self.modules.get(mname)
- if op == 'query-running':
- if (hasattr(module,
- 'get_dependent_ifacenames_running') == False):
+ for mname, module in self.modules.items():
+ module = self.modules.get(mname)
+ try:
+ if ops[0] == 'query-running':
+ if (not hasattr(module,
+ 'get_dependent_ifacenames_running')):
continue
dlist = module.get_dependent_ifacenames_running(ifaceobj)
else:
- if (hasattr(module, 'get_dependent_ifacenames') == False):
+ if (not hasattr(module, 'get_dependent_ifacenames')):
continue
dlist = module.get_dependent_ifacenames(ifaceobj,
self.ifaceobjdict.keys())
- if dlist and len(dlist):
- ifaceobj.set_realdev_dependents(dlist[:])
- self.logger.debug('%s: ' %ifaceobj.get_name() +
- 'got dependency list: %s' %str(dlist))
- break
+ except Exception, e:
+ self.logger.warn('%s: error getting dependent interfaces (%s)'
+ %(ifaceobj.name, str(e)))
+ dlist = None
+ pass
+ if dlist:
+ break
return dlist
- def populate_dependency_info(self, ifacenames, ops):
+ def populate_dependency_info(self, ops, ifacenames=None):
""" recursive function to generate iface dependency info """
- if ifacenames is None:
+ if not ifacenames:
ifacenames = self.ifaceobjdict.keys()
- self.logger.debug('populating dependency info for %s' %str(ifacenames))
-
iqueue = deque(ifacenames)
while iqueue:
i = iqueue.popleft()
-
# Go through all modules and find dependent ifaces
dlist = None
- ifaceobj = self.get_iface_obj_first(i)
- if ifaceobj is None:
+ ifaceobj = self.get_ifaceobj_first(i)
+ if not ifaceobj:
continue
-
- dlist = ifaceobj.get_dependents()
- if dlist is None:
+ dlist = ifaceobj.lowerifaces
+ if not dlist:
dlist = self.query_dependents(ifaceobj, ops)
else:
continue
-
- if dlist is not None:
- self.preprocess_dependency_list(dlist, ops)
- self.logger.debug('%s: dependency list after processing: %s'
- %(i, str(dlist)))
- ifaceobj.set_dependents(dlist)
+ if dlist:
+ self.preprocess_dependency_list(ifaceobj.name,
+ dlist, ops)
+ ifaceobj.lowerifaces = dlist
[iqueue.append(d) for d in dlist]
-
- if self.dependency_graph.get(i) is None:
+ if not self.dependency_graph.get(i):
self.dependency_graph[i] = dlist
def _save_iface(self, ifaceobj):
- if not self.ifaceobjdict.get(ifaceobj.get_name()):
- self.ifaceobjdict[ifaceobj.get_name()] = [ifaceobj]
- else:
- self.ifaceobjdict[ifaceobj.get_name()].append(ifaceobj)
+ currentifaceobjlist = self.ifaceobjdict.get(ifaceobj.name)
+ if not currentifaceobjlist:
+ self.ifaceobjdict[ifaceobj.name]= [ifaceobj]
+ return
+ if ifaceobj.compare(currentifaceobjlist[0]):
+ self.logger.warn('duplicate interface %s found' %ifaceobj.name)
+ return
+ currentifaceobjlist[0].flags |= iface.HAS_SIBLINGS
+ ifaceobj.flags |= iface.HAS_SIBLINGS
+ self.ifaceobjdict[ifaceobj.name].append(ifaceobj)
- def _module_syntax_checker(self, attrname, attrval):
+ def _iface_configattr_syntax_checker(self, attrname, attrval):
for m, mdict in self.module_attrs.items():
+ if not mdict:
+ continue
attrsdict = mdict.get('attrs')
- if attrsdict and attrname in attrsdict.keys(): return True
+ try:
+ if attrsdict.get(attrname):
+ return True
+ except AttributeError:
+ pass
return False
- def read_default_iface_config(self):
+ def _ifaceobj_syntax_checker(self, ifaceobj):
+ err = False
+ for attrname in ifaceobj.config:
+ found = False
+ for k, v in self.module_attrs.items():
+ if v and v.get('attrs', {}).get(attrname):
+ found = True
+ break
+ if not found:
+ err = True
+ self.logger.warn('%s: unsupported attribute \'%s\'' %attrname)
+ continue
+ return err
+
+ def read_iface_config(self):
""" Reads default network interface config /etc/network/interfaces. """
- nifaces = networkInterfaces()
+ nifaces = networkInterfaces(self.interfacesfile,
+ self.interfacesfileiobuf,
+ self.interfacesfileformat,
+ template_engine=self.config.get('template_engine'),
+ template_lookuppath=self.config.get('template_lookuppath'))
nifaces.subscribe('iface_found', self._save_iface)
- nifaces.subscribe('validate', self._module_syntax_checker)
+ nifaces.subscribe('validateifaceattr',
+ self._iface_configattr_syntax_checker)
+ nifaces.subscribe('validateifaceobj', self._ifaceobj_syntax_checker)
nifaces.load()
- def read_iface_config(self):
- return self.read_default_iface_config()
-
def read_old_iface_config(self):
- """ Reads the saved iface config instead of default iface config. """
+ """ Reads the saved iface config instead of default iface config.
+ And saved iface config is already read by the statemanager """
+ self.ifaceobjdict = copy.deepcopy(self.statemanager.ifaceobjdict)
- # Read it from the statemanager
- self.ifaceobjdict = self.statemanager.get_ifaceobjdict()
+ def _load_addon_modules_config(self):
+ """ Load addon modules config file """
- def load_addon_modules_config(self):
with open(self.addon_modules_configfile, 'r') as f:
lines = f.readlines()
for l in lines:
litems = l.rstrip(' \n').split(',')
operation = litems[0]
mname = litems[1]
- self.operations[operation].append(mname)
+ self.module_ops[operation].append(mname)
def load_addon_modules(self, modules_dir):
""" load python modules from modules_dir
"""
self.logger.info('loading builtin modules from %s' %modules_dir)
- self.load_addon_modules_config()
+ self._load_addon_modules_config()
if not modules_dir in sys.path:
sys.path.append(modules_dir)
try:
- for op, mlist in self.operations.items():
+ for op, mlist in self.module_ops.items():
for mname in mlist:
- if self.modules.get(mname) is not None:
+ if self.modules.get(mname):
continue
mpath = modules_dir + '/' + mname + '.py'
if os.path.exists(mpath):
dryrun=self.DRYRUN,
nowait=self.NOWAIT,
perfmode=self.PERFMODE,
- cache=self.CACHE)
+ cache=self.CACHE,
+ cacheflags=self.CACHE_FLAGS)
self.modules[mname] = minstance
- if hasattr(minstance, 'get_modinfo'):
+ try:
self.module_attrs[mname] = minstance.get_modinfo()
+ except:
+ pass
except:
raise
# Assign all modules to query operations
- self.operations['query-checkcurr'] = self.modules.keys()
- self.operations['query-running'] = self.modules.keys()
- self.operations['query-dependency'] = self.modules.keys()
- self.operations['query'] = self.modules.keys()
- self.operations['query-raw'] = self.modules.keys()
+ self.module_ops['query-checkcurr'] = self.modules.keys()
+ self.module_ops['query-running'] = self.modules.keys()
+ self.module_ops['query-dependency'] = self.modules.keys()
+ self.module_ops['query'] = self.modules.keys()
+ self.module_ops['query-raw'] = self.modules.keys()
+
+
+ def _modules_help(self):
+ """ Prints addon modules supported syntax """
- def modules_help(self):
indent = ' '
for m, mdict in self.module_attrs.items():
if not mdict:
validrange = attrvaldict.get('validrange')
if validrange:
- print('%svalidrange: %s'
- %(indent + ' ', '-'.join(validrange)))
+ print('%svalidrange: %s-%s'
+ %(indent + ' ', validrange[0], validrange[1]))
validvals = attrvaldict.get('validvals')
if validvals:
"""
self.logger.info('looking for user scripts under %s' %modules_dir)
- for op, mlist in self.operations_compat.items():
+ for op, mlist in self.script_ops.items():
msubdir = modules_dir + '/if-%s.d' %op
self.logger.info('loading scripts under %s ...' %msubdir)
try:
for module in module_list:
if self.modules.get(module) is not None:
continue
- self.operations_compat[op].append(
+ self.script_ops[op].append(
msubdir + '/' + module)
except:
- raise
-
- def conv_iface_namelist_to_objlist(self, intf_list):
- for intf in intf_list:
- iface_obj = self.get_iface(intf)
- if not iface_obj:
- raise ifupdownInvalidValue('no iface %s', intf)
- iface_objs.append(iface_obj)
- return iface_objs
-
-
- def run_without_dependents(self, ops, ifacenames):
- """ Run interface list without their dependents """
- if not ifacenames:
- raise ifupdownInvalidValue('no interfaces found')
-
- self.logger.debug('run_without_dependents for ops %s for %s'
- %(str(ops), str(ifacenames)))
-
- ifaceSched = ifaceScheduler(force=self.FORCE)
- ifaceSched.run_iface_list(self, ifacenames, ops,
- order=ifaceSchedulerFlags.INORDER
- if 'down' in ops[0]
- else ifaceSchedulerFlags.POSTORDER,
- followdependents=False)
+ # continue reading
+ pass
- def run_with_dependents(self, ops, ifacenames):
- ret = 0
- self.logger.debug('running \'%s\' with dependents for %s'
+ def _sched_ifaces(self, ifacenames, ops):
+ self.logger.debug('scheduling \'%s\' for %s'
%(str(ops), str(ifacenames)))
- ifaceSched = ifaceScheduler()
- if ifacenames is None:
- ifacenames = self.ifaceobjdict.keys()
-
- if self.logger.isEnabledFor(logging.DEBUG):
- self.logger.debug('dependency graph:')
- self.logger.debug(self.pp.pformat(self.dependency_graph))
-
- if self.njobs > 1:
- ret = ifaceSched.run_iface_dependency_graph_parallel(self,
- self.dependency_graph, ops)
- else:
- ret = ifaceSched.run_iface_dependency_graphs(self,
- self.dependency_graph, ops,
+ self._pretty_print_ordered_dict('dependency graph',
+ self.dependency_graph)
+ return ifaceScheduler.sched_ifaces(self, ifacenames, ops,
+ dependency_graph=self.dependency_graph,
order=ifaceSchedulerFlags.INORDER
if 'down' in ops[0]
- else ifaceSchedulerFlags.POSTORDER)
- return ret
+ else ifaceSchedulerFlags.POSTORDER,
+ followdependents=True if self.WITH_DEPENDS else False)
- def print_dependency(self, ifacenames, format):
- if ifacenames is None:
- ifacenames = self.ifaceobjdict.keys()
-
- if format == 'list':
- for k,v in self.dependency_graph.items():
- print '%s : %s' %(k, str(v))
- elif format == 'dot':
- indegrees = {}
- map(lambda i: indegrees.update({i :
- self.get_iface_refcnt(i)}),
- self.dependency_graph.keys())
- graph.generate_dots(self.dependency_graph, indegrees)
-
- def validate_ifaces(self, ifacenames):
+ def _validate_ifaces(self, ifacenames):
""" validates interface list for config existance.
returns -1 if one or more interface not found. else, returns 0
"""
-
err_iface = ''
for i in ifacenames:
- ifaceobjs = self.get_iface_objs(i)
- if ifaceobjs is None:
+ ifaceobjs = self.get_ifaceobjs(i)
+ if not ifaceobjs:
err_iface += ' ' + i
+ if err_iface:
+ raise Exception('cannot find interfaces:%s' %err_iface)
+ return True
- if len(err_iface):
- self.logger.error('could not find interfaces: %s' %err_iface)
- return -1
-
- return 0
-
-
- def iface_whitelisted(self, auto, allow_classes, excludepats, ifacename):
+ def _iface_whitelisted(self, auto, allow_classes, excludepats, ifacename):
""" Checks if interface is whitelisted depending on set of parameters.
-
interfaces are checked against the allow_classes and auto lists.
"""
- # If the interface matches
- if excludepats and len(excludepats):
+
+ if excludepats:
for e in excludepats:
if re.search(e, ifacename):
return False
-
- ifaceobjs = self.get_iface_objs(ifacename)
- if ifaceobjs is None:
+ ifaceobjs = self.get_ifaceobjs(ifacename)
+ if not ifaceobjs:
self.logger.debug('iface %s' %ifacename + ' not found')
return False
-
# We check classes first
- if allow_classes and len(allow_classes):
+ if allow_classes:
for i in ifaceobjs:
- if len(i.get_classes()):
+ if i.classes:
common = Set([allow_classes]).intersection(
- Set(i.get_classes()))
- if len(common):
+ Set(i.classes))
+ if common:
return True
return False
-
if auto:
for i in ifaceobjs:
- if i.get_auto():
+ if i.auto:
return True
return False
-
return True
+ def _compat_conv_op_to_mode(self, op):
+ """ Returns old op name to work with existing scripts """
+ if op == 'pre-up':
+ return 'start'
+ elif op == 'pre-down':
+ return 'stop'
+ else:
+ return op
+
def generate_running_env(self, ifaceobj, op):
""" Generates a dictionary with env variables required for
an interface. Used to support script execution for interfaces.
"""
cenv = None
- iface_env = ifaceobj.get_env()
- if iface_env is not None:
+ iface_env = ifaceobj.env
+ if iface_env:
cenv = os.environ
if cenv:
cenv.update(iface_env)
else:
cenv = iface_env
-
- cenv['MODE'] = self.compat_conv_op_to_mode(op)
-
+ cenv['MODE'] = self._compat_conv_op_to_mode(op)
return cenv
+ def _save_state(self):
+ if not self.STATEMANAGER_ENABLE or not self.STATEMANAGER_UPDATE:
+ return
+ try:
+ # Update persistant iface states
+ self.statemanager.save_state()
+ except Exception, e:
+ if self.logger.isEnabledFor(logging.DEBUG):
+ t = sys.exc_info()[2]
+ traceback.print_tb(t)
+ self.logger.warning('error saving state (%s)' %str(e))
+
def up(self, ops, auto=False, allow_classes=None, ifacenames=None,
- excludepats=None, printdependency=None):
+ excludepats=None, printdependency=None, syntaxcheck=False):
+ """ up an interface """
+
+ if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False
if auto:
self.ALL = True
self.WITH_DEPENDS = True
-
try:
self.read_iface_config()
- except Exception, e:
+ except Exception:
raise
- if ifacenames is not None:
+ # If only syntax check was requested, return here
+ if syntaxcheck:
+ return
+
+ if ifacenames:
# If iface list is given by the caller, always check if iface
# is present
- if self.validate_ifaces(ifacenames) != 0:
- raise Exception('all or some interfaces not found')
+ self._validate_ifaces(ifacenames)
# if iface list not given by user, assume all from config file
- if ifacenames is None: ifacenames = self.ifaceobjdict.keys()
+ if not ifacenames: ifacenames = self.ifaceobjdict.keys()
# filter interfaces based on auto and allow classes
filtered_ifacenames = [i for i in ifacenames
- if self.iface_whitelisted(auto, allow_classes,
+ if self._iface_whitelisted(auto, allow_classes,
excludepats, i)]
- if not len(filtered_ifacenames):
+ if not filtered_ifacenames:
raise Exception('no ifaces found matching given allow lists')
- self.populate_dependency_info(filtered_ifacenames, ops)
-
- if printdependency is not None:
+ if printdependency:
+ self.populate_dependency_info(ops, filtered_ifacenames)
self.print_dependency(filtered_ifacenames, printdependency)
return
-
- if self.WITH_DEPENDS:
- self.run_with_dependents(ops, filtered_ifacenames)
else:
- self.run_without_dependents(ops, filtered_ifacenames)
+ self.populate_dependency_info(ops)
- # Update persistant iface states
try:
- if self.ALL:
- self.statemanager.flush_state(self.ifaceobjdict)
- else:
- self.statemanager.flush_state()
- except Exception, e:
- if self.logger.isEnabledFor(logging.DEBUG):
- t = sys.exc_info()[2]
- traceback.print_tb(t)
- self.logger.warning('error saving state (%s)' %str(e))
+ self._sched_ifaces(filtered_ifacenames, ops)
+ finally:
+ if not self.DRYRUN and self.ADDONS_ENABLE:
+ self._save_state()
def down(self, ops, auto=False, allow_classes=None, ifacenames=None,
- excludepats=None, printdependency=None):
- loaded_newconfig = False
+ excludepats=None, printdependency=None, usecurrentconfig=False):
+ """ down an interface """
+
+ if not self.ADDONS_ENABLE: self.STATEMANAGER_UPDATE = False
if auto:
self.ALL = True
self.WITH_DEPENDS = True
-
- # for down we need to look at old state
- self.logger.debug('Looking at old state ..')
-
- if len(self.statemanager.get_ifaceobjdict()):
+ # For down we need to look at old state, unless usecurrentconfig
+ # is set
+ if (not usecurrentconfig and self.STATEMANAGER_ENABLE and
+ self.statemanager.ifaceobjdict):
+ # Since we are using state manager objects,
+ # skip the updating of state manager objects
+ self.logger.debug('Looking at old state ..')
self.read_old_iface_config()
- elif self.FORCE:
+ else:
# If no old state available
- self.logger.info('old state not available. ' +
- 'Force option set. Loading new iface config file')
try:
self.read_iface_config()
except Exception, e:
raise Exception('error reading iface config (%s)' %str(e))
- loaded_newconfig = True
- else:
- raise Exception('old state not available...aborting.' +
- ' try running with --force option')
-
if ifacenames:
# If iface list is given by the caller, always check if iface
# is present
- if self.validate_ifaces(ifacenames) != 0:
- raise Exception('all or some interfaces not found')
+ try:
+ self._validate_ifaces(ifacenames)
+ except Exception, e:
+ raise Exception('%s' %str(e) +
+ ' (interface was probably never up ?)')
# if iface list not given by user, assume all from config file
- if ifacenames is None: ifacenames = self.ifaceobjdict.keys()
+ if not ifacenames: ifacenames = self.ifaceobjdict.keys()
# filter interfaces based on auto and allow classes
filtered_ifacenames = [i for i in ifacenames
- if self.iface_whitelisted(auto, allow_classes,
+ if self._iface_whitelisted(auto, allow_classes,
excludepats, i)]
- if not len(filtered_ifacenames):
+ if not filtered_ifacenames:
raise Exception('no ifaces found matching given allow lists')
- self.populate_dependency_info(filtered_ifacenames, ops)
if printdependency:
+ self.populate_dependency_info(ops, filtered_ifacenames)
self.print_dependency(filtered_ifacenames, printdependency)
return
-
- if self.WITH_DEPENDS:
- self.run_with_dependents(ops, filtered_ifacenames)
else:
- self.run_without_dependents(ops, filtered_ifacenames)
+ self.populate_dependency_info(ops)
- if loaded_newconfig:
- # Update persistant iface states
- try:
- if self.ALL:
- self.statemanager.flush_state(self.ifaceobjdict)
- else:
- self.statemanager.flush_state()
- except Exception, e:
- if self.logger.isEnabledFor(logging.DEBUG):
- t = sys.exc_info()[2]
- traceback.print_tb(t)
- self.logger.warning('error saving state (%s)' %str(e))
+ try:
+ self._sched_ifaces(filtered_ifacenames, ops)
+ finally:
+ if not self.DRYRUN and self.ADDONS_ENABLE:
+ self._save_state()
def query(self, ops, auto=False, allow_classes=None, ifacenames=None,
excludepats=None, printdependency=None,
format='native'):
+ """ query an interface """
+
+ if self.STATEMANAGER_ENABLE and ops[0] == 'query-savedstate':
+ return self.statemanager.dump_pretty(ifacenames)
+
+ self.STATEMANAGER_UPDATE = False
if auto:
self.logger.debug('setting flag ALL')
self.ALL = True
self.WITH_DEPENDS = True
if ops[0] == 'query-syntax':
- self.modules_help()
+ self._modules_help()
return
elif ops[0] == 'query-running':
# create fake devices to all dependents that dont have config
except Exception:
raise
- if ifacenames is not None and ops[0] != 'query-running':
+ if ifacenames and ops[0] != 'query-running':
# If iface list is given, always check if iface is present
- if self.validate_ifaces(ifacenames) != 0:
- raise Exception('all or some interfaces not found')
+ self._validate_ifaces(ifacenames)
# if iface list not given by user, assume all from config file
- if ifacenames is None: ifacenames = self.ifaceobjdict.keys()
+ if not ifacenames: ifacenames = self.ifaceobjdict.keys()
# filter interfaces based on auto and allow classes
if ops[0] == 'query-running':
filtered_ifacenames = ifacenames
else:
filtered_ifacenames = [i for i in ifacenames
- if self.iface_whitelisted(auto, allow_classes,
+ if self._iface_whitelisted(auto, allow_classes,
excludepats, i)]
- if len(filtered_ifacenames) == 0:
+ if not filtered_ifacenames:
raise Exception('no ifaces found matching ' +
'given allow lists')
- self.populate_dependency_info(filtered_ifacenames, ops)
+ self.populate_dependency_info(ops, filtered_ifacenames)
if ops[0] == 'query-dependency' and printdependency:
self.print_dependency(filtered_ifacenames, printdependency)
return
elif ops[0] == 'query-raw':
return self.print_ifaceobjs_raw(filtered_ifacenames)
- if self.WITH_DEPENDS:
- self.run_with_dependents(ops, filtered_ifacenames)
- else:
- self.run_without_dependents(ops, filtered_ifacenames)
+ self._sched_ifaces(filtered_ifacenames, ops)
if ops[0] == 'query-checkcurr':
ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames, format)
self.print_ifaceobjsrunning_pretty(filtered_ifacenames, format)
return
- def reload(self, auto=False, allow=None,
- ifacenames=None, excludepats=None, downchangediface=False):
- """ main ifupdown run method """
+ def reload(self, upops, downops, auto=False, allow=None,
+ ifacenames=None, excludepats=None, usecurrentconfig=False):
+ """ reload interface config """
+
allow_classes = []
- upops = ['pre-up', 'up', 'post-up']
- downops = ['pre-down', 'down', 'post-down']
self.logger.debug('reloading interface config ..')
-
if auto:
self.ALL = True
self.WITH_DEPENDS = True
try:
- # Read the current interface config
self.read_iface_config()
- except Exception, e:
+ except:
raise
# generate dependency graph of interfaces
- self.populate_dependency_info(ifacenames, upops)
+ self.populate_dependency_info(upops)
+ if (not usecurrentconfig and self.STATEMANAGER_ENABLE
+ and self.statemanager.ifaceobjdict):
+ # Save a copy of new iface objects and dependency_graph
+ new_ifaceobjdict = dict(self.ifaceobjdict)
+ new_dependency_graph = dict(self.dependency_graph)
- # Save a copy of new iface objects and dependency_graph
- new_ifaceobjdict = dict(self.get_ifaceobjdict())
- new_dependency_graph = dict(self.get_dependency_graph())
-
- if len(self.statemanager.get_ifaceobjdict()) > 0:
# if old state is present, read old state and mark op for 'down'
# followed by 'up' aka: reload
# old interface config is read into self.ifaceobjdict
- #
self.read_old_iface_config()
op = 'reload'
else:
# oldconfig not available, continue with 'up' with new config
op = 'up'
- if ifacenames is None: ifacenames = self.ifaceobjdict.keys()
-
- if (op == 'reload' and ifacenames is not None and
- len(ifacenames) != 0):
+ if not ifacenames: ifacenames = self.ifaceobjdict.keys()
+ if op == 'reload' and ifacenames:
filtered_ifacenames = [i for i in ifacenames
- if self.iface_whitelisted(auto, allow_classes,
+ if self._iface_whitelisted(auto, allow_classes,
excludepats, i)]
-
# Generate the interface down list
# Interfaces that go into the down list:
# - interfaces that were present in last config and are not
# config
#
ifacedownlist = []
- for ifname, lastifobjlist in self.ifaceobjdict.items():
+ for ifname, lastifaceobjlist in self.ifaceobjdict.items():
objidx = 0
-
# If interface is not present in the new file
# append it to the down list
- newifobjlist = new_ifaceobjdict.get(ifname)
- if newifobjlist == None:
+ newifaceobjlist = new_ifaceobjdict.get(ifname)
+ if not newifaceobjlist:
ifacedownlist.append(ifname)
continue
-
- if downchangediface == False:
- continue
-
# If interface has changed between the current file
# and the last installed append it to the down list
- if len(newifobjlist) != len(lastifobjlist):
+ if len(newifaceobjlist) != len(lastifaceobjlist):
ifacedownlist.append(ifname)
continue
-
# compare object list
- for objidx in range(0, len(lastifobjlist)):
- oldobj = lastifobjlist[objidx]
- newobj = newifobjlist[objidx]
- if newobj.is_different(oldobj):
+ for objidx in range(0, len(lastifaceobjlist)):
+ oldobj = lastifaceobjlist[objidx]
+ newobj = newifaceobjlist[objidx]
+ if not newobj.compare(oldobj):
ifacedownlist.append(ifname)
continue
-
- if ifacedownlist is not None and len(ifacedownlist) > 0:
+ if ifacedownlist:
self.logger.info('Executing down on interfaces: %s'
%str(ifacedownlist))
+ # reinitialize dependency graph
+ self.dependency_graph = OrderedDict({})
# Generate dependency info for old config
- self.populate_dependency_info(ifacedownlist, downops)
- if len(ifacedownlist) == len(self.ifaceobjdict):
- # if you are downing all interfaces, its better run
- # with dependents
- self.run_with_dependents(downops, ifacedownlist)
- else:
- # if not, down only the interfaces that we have in the
- # down list
- self.run_without_dependents(downops, ifacedownlist)
- # Update persistant iface states
- try:
- if self.ALL:
- self.statemanager.flush_state(self.ifaceobjdict)
- else:
- self.statemanager.flush_state()
- except Exception, e:
- if self.logger.isEnabledFor(logging.DEBUG):
- t = sys.exc_info()[2]
- traceback.print_tb(t)
- self.logger.warning('error saving state (%s)' %str(e))
+ self.populate_dependency_info(downops, ifacedownlist)
+ self._sched_ifaces(ifacedownlist, downops)
else:
self.logger.debug('no interfaces to down ..')
- # Now, run up with new config dict
- self.set_ifaceobjdict(new_ifaceobjdict)
- self.set_dependency_graph(new_dependency_graph)
-
+ # Now, run 'up' with new config dict
+ # reset statemanager update flag to default
+ self.ifaceobjdict = new_ifaceobjdict
+ self.dependency_graph = new_dependency_graph
ifacenames = self.ifaceobjdict.keys()
filtered_ifacenames = [i for i in ifacenames
- if self.iface_whitelisted(auto, allow_classes,
+ if self._iface_whitelisted(auto, allow_classes,
excludepats, i)]
- self.logger.info('Executing up on interfaces: %s'
+ self.logger.info('Scheduling up on interfaces: %s'
%str(filtered_ifacenames))
- if self.WITH_DEPENDS:
- self.run_with_dependents(upops, filtered_ifacenames)
- else:
- self.run_without_dependents(upops, filtered_ifacenames)
-
- # Update persistant iface states
- try:
- if self.ALL:
- self.statemanager.flush_state(self.get_ifaceobjdict())
- else:
- self.statemanager.flush_state()
- except Exception, e:
- if self.logger.isEnabledFor(logging.DEBUG):
- t = sys.exc_info()[2]
- traceback.print_tb(t)
- self.logger.warning('error saving state (%s)' %str(e))
+ self._sched_ifaces(filtered_ifacenames, upops)
+ if self.DRYRUN:
+ return
+ self._save_state()
- def dump(self):
- """ all state dump """
+ def _pretty_print_ordered_dict(self, prefix, argdict):
+ outbuf = prefix + ' {\n'
+ for k, vlist in argdict.items():
+ outbuf += '\t%s : %s\n' %(k, str(vlist))
+ self.logger.debug(outbuf + '}')
- print 'ifupdown object dump'
- print self.pp.pprint(self.modules)
- print self.pp.pprint(self.ifaces)
- self.state_manager.dump()
+ def print_dependency(self, ifacenames, format):
+ """ prints iface dependency information """
- def print_state(self, ifacenames=None):
- self.statemanager.dump(ifacenames)
+ if not ifacenames:
+ ifacenames = self.ifaceobjdict.keys()
+ if format == 'list':
+ for k,v in self.dependency_graph.items():
+ print '%s : %s' %(k, str(v))
+ elif format == 'dot':
+ indegrees = {}
+ map(lambda i: indegrees.update({i :
+ self.get_iface_refcnt(i)}),
+ self.dependency_graph.keys())
+ graph.generate_dots(self.dependency_graph, indegrees)
def print_ifaceobjs_raw(self, ifacenames):
+ """ prints raw lines for ifaces from config file """
+
for i in ifacenames:
- for ifaceobj in self.get_iface_objs(i):
+ for ifaceobj in self.get_ifaceobjs(i):
if (self.is_ifaceobj_builtin(ifaceobj) or
not ifaceobj.is_config_present()):
continue
ifaceobj.dump_raw(self.logger)
print '\n'
- if self.WITH_DEPENDS:
- dlist = ifaceobj.get_dependents()
- if not dlist or not len(dlist): continue
- self.print_ifaceobjs_pretty(dlist, format)
+ if self.WITH_DEPENDS and not self.ALL:
+ dlist = ifaceobj.lowerifaces
+ if not dlist: continue
+ self.print_ifaceobjs_raw(dlist)
+
+ def _get_ifaceobjs_pretty(self, ifacenames, ifaceobjs, running=False):
+ """ returns iface obj list """
- def print_ifaceobjs_pretty(self, ifacenames, format='native'):
for i in ifacenames:
- for ifaceobj in self.get_iface_objs(i):
- if (self.is_ifaceobj_builtin(ifaceobj) or
- not ifaceobj.is_config_present()):
+ for ifaceobj in self.get_ifaceobjs(i):
+ if ((not running and self.is_ifaceobj_noconfig(ifaceobj)) or
+ (running and not ifaceobj.is_config_present())):
continue
- if format == 'json':
- ifaceobj.dump_json()
- else:
- ifaceobj.dump_pretty()
+ ifaceobjs.append(ifaceobj)
+ if self.WITH_DEPENDS and not self.ALL:
+ dlist = ifaceobj.lowerifaces
+ if not dlist: continue
+ self._get_ifaceobjs_pretty(dlist, ifaceobjs, running)
- if self.WITH_DEPENDS:
- dlist = ifaceobj.get_dependents()
- if not dlist or not len(dlist): continue
- self.print_ifaceobjs_pretty(dlist, format)
+ def print_ifaceobjs_pretty(self, ifacenames, format='native'):
+ """ pretty prints iface in format given by keyword arg format """
+
+ ifaceobjs = []
+ self._get_ifaceobjs_pretty(ifacenames, ifaceobjs)
+ if not ifaceobjs: return
+ if format == 'json':
+ print json.dumps(ifaceobjs, cls=ifaceJsonEncoder,
+ indent=4, separators=(',', ': '))
+ else:
+ map(lambda i: i.dump_pretty(), ifaceobjs)
- def dump_ifaceobjs(self, ifacenames):
+ def _get_ifaceobjscurr_pretty(self, ifacenames, ifaceobjs):
+ ret = 0
for i in ifacenames:
- ifaceobjs = self.get_iface_objs(i)
- for i in ifaceobjs:
- i.dump(self.logger)
- print '\n'
+ ifaceobjscurr = self.get_ifaceobjcurr(i)
+ if not ifaceobjscurr: continue
+ for ifaceobj in ifaceobjscurr:
+ if (ifaceobj.status == ifaceStatus.NOTFOUND or
+ ifaceobj.status == ifaceStatus.ERROR):
+ ret = 1
+ if self.is_ifaceobj_noconfig(ifaceobj):
+ continue
+ ifaceobjs.append(ifaceobj)
+ if self.WITH_DEPENDS and not self.ALL:
+ dlist = ifaceobj.lowerifaces
+ if not dlist: continue
+ dret = self._get_ifaceobjscurr_pretty(dlist, ifaceobjs)
+ if dret: ret = 1
+ return ret
def print_ifaceobjscurr_pretty(self, ifacenames, format='native'):
- """ Dumps current running state of interfaces.
+ """ pretty prints current running state of interfaces with status.
returns 1 if any of the interface has an error,
else returns 0
"""
- ret = 0
- for i in ifacenames:
- ifaceobj = self.get_ifaceobjcurr(i)
- if not ifaceobj: continue
- if ifaceobj.get_status() == ifaceStatus.NOTFOUND:
- print 'iface %s' %ifaceobj.get_name() + ' (not found)\n'
- ret = 1
- continue
- elif ifaceobj.get_status() == ifaceStatus.ERROR:
- ret = 1
-
- if (self.is_ifaceobj_builtin(ifaceobj) or
- ifaceobj.is_config_present() == False):
- continue
-
- if format == 'json':
- ifaceobj.dump_json()
- else:
- ifaceobj.dump_pretty()
-
- if self.WITH_DEPENDS:
- dlist = ifaceobj.get_dependents()
- if not dlist or not len(dlist): continue
- self.print_ifaceobjscurr_pretty(dlist, format)
+ ifaceobjs = []
+ ret = self._get_ifaceobjscurr_pretty(ifacenames, ifaceobjs)
+ if not ifaceobjs: return
+ self.logger.debug(ifaceobjs)
+ if format == 'json':
+ print json.dumps(ifaceobjs, cls=ifaceJsonEncoder, indent=2,
+ separators=(',', ': '))
+ else:
+ map(lambda i: i.dump_pretty(with_status=True,
+ successstr=self.config.get('check_success_str',
+ _success_sym),
+ errorstr=self.config.get('check_error_str', _error_sym)),
+ ifaceobjs)
return ret
def print_ifaceobjsrunning_pretty(self, ifacenames, format='native'):
- for i in ifacenames:
- ifaceobj = self.get_iface_obj_first(i)
- if ifaceobj.get_status() == ifaceStatus.NOTFOUND:
- print 'iface %s' %ifaceobj.get_name() + ' (not found)\n'
- continue
-
- if ifaceobj.is_config_present() == False:
- continue
-
- if format == 'json':
- ifaceobj.dump_json()
- else:
- ifaceobj.dump_pretty()
-
- if self.WITH_DEPENDS:
- dlist = ifaceobj.get_dependents()
- if dlist is None or len(dlist) == 0: continue
- self.print_ifaceobjsrunning_pretty(dlist, format)
- return
+ """ pretty prints iface running state """
+
+ ifaceobjs = []
+ self._get_ifaceobjs_pretty(ifacenames, ifaceobjs, running=True)
+ if not ifaceobjs: return
+ if format == 'json':
+ print json.dumps(ifaceobjs, cls=ifaceJsonEncoder, indent=2,
+ separators=(',', ': '))
+ else:
+ map(lambda i: i.dump_pretty(), ifaceobjs)
- def print_ifaceobjs_saved_state_pretty(self, ifacenames):
- self.statemanager.print_state_pretty(ifacenames, self.logger)
+ def _dump(self):
+ print 'ifupdown main object dump'
+ print self.pp.pprint(self.modules)
+ print self.pp.pprint(self.ifaceobjdict)
- def print_ifaceobjs_saved_state_detailed_pretty(self, ifacenames):
- self.statemanager.print_state_detailed_pretty(ifacenames, self.logger)
+ def _dump_ifaceobjs(self, ifacenames):
+ for i in ifacenames:
+ ifaceobjs = self.get_ifaceobjs(i)
+ for i in ifaceobjs:
+ i.dump(self.logger)
+ print '\n'