mirror of
https://github.com/CumulusNetworks/ifupdown2.git
synced 2024-05-06 15:54:50 +00:00
Ticket: CM-1438 Reviewed By: Testing Done: There are a few known issues listed in the TODO and KNOWN_ISSUES files
1074 lines
38 KiB
Python
1074 lines
38 KiB
Python
#!/usr/bin/python
|
|
#
|
|
# Copyright 2013. Cumulus Networks, Inc.
|
|
# Author: Roopa Prabhu, roopa@cumulusnetworks.com
|
|
#
|
|
# ifupdownMain --
|
|
# ifupdown main module
|
|
#
|
|
|
|
import os
|
|
import re
|
|
import imp
|
|
import pprint
|
|
import logging
|
|
import sys, traceback
|
|
from statemanager import *
|
|
from networkinterfaces import *
|
|
from iface import *
|
|
from scheduler import *
|
|
from collections import deque
|
|
from collections import OrderedDict
|
|
from graph import *
|
|
from sets import Set
|
|
|
|
class ifupdownMain():
|
|
|
|
# Flags
|
|
WITH_DEPENDS = False
|
|
ALL = False
|
|
STATE_CHECK = False
|
|
|
|
# priv flags to mark iface objects
|
|
BUILTIN = 0x1
|
|
NOCONFIG = 0x2
|
|
|
|
scripts_dir='/etc/network'
|
|
addon_modules_dir='/usr/share/ifupdownaddons'
|
|
addon_modules_configfile='/etc/network/.addons.conf'
|
|
|
|
# iface dictionary in the below format:
|
|
# { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
|
|
# eg:
|
|
# { 'swp1' : [<ifaceobject1>, <ifaceobject2> ..] }
|
|
#
|
|
# Each ifaceobject corresponds to a configuration block for
|
|
# that interface
|
|
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', []),
|
|
('up' , []),
|
|
('post-up' , []),
|
|
('query-checkcurr', []),
|
|
('query-running', []),
|
|
('query-dependency', []),
|
|
('query', []),
|
|
('query-raw', []),
|
|
('pre-down', []),
|
|
('down' , []),
|
|
('post-down' , [])])
|
|
|
|
# For old style /etc/network/ bash scripts
|
|
operations_compat = OrderedDict([('pre-up', []),
|
|
('up' , []),
|
|
('post-up' , []),
|
|
('pre-down', []),
|
|
('down' , []),
|
|
('post-down' , [])])
|
|
|
|
|
|
def __init__(self, force=False, dryrun=False, nowait=False,
|
|
perfmode=False, withdepends=False, njobs=1,
|
|
cache=False):
|
|
self.logger = logging.getLogger('ifupdown')
|
|
|
|
self.FORCE = force
|
|
self.DRYRUN = dryrun
|
|
self.NOWAIT = nowait
|
|
self.PERFMODE = perfmode
|
|
self.WITH_DEPENDS = withdepends
|
|
self.CACHE = cache
|
|
self._DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False
|
|
|
|
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)
|
|
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'
|
|
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):
|
|
self.ifaceobjdict = ifaceobjdict
|
|
|
|
def set_dependency_graph(self, dependency_graph):
|
|
self.dependency_graph = dependency_graph
|
|
|
|
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):
|
|
return self.ifaceobjdict.get(ifacename)
|
|
|
|
def get_iface_obj_first(self, ifacename):
|
|
ifaceobjs = self.get_iface_objs(ifacename)
|
|
if ifaceobjs is not None:
|
|
return ifaceobjs[0]
|
|
return None
|
|
|
|
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
|
|
|
|
ifaceobjcurr = iface()
|
|
ifaceobjcurr.set_name(ifacename)
|
|
ifaceobjcurr.set_lowerifaces(ifaceobj.get_lowerifaces())
|
|
self.ifaceobjcurrdict[ifacename] = ifaceobjcurr
|
|
|
|
return ifaceobjcurr
|
|
|
|
def get_ifaceobjcurr(self, ifacename):
|
|
return self.ifaceobjcurrdict.get(ifacename)
|
|
|
|
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):
|
|
max = 0
|
|
ifaceobjs = self.get_iface_objs(ifacename)
|
|
for i in ifaceobjs:
|
|
if i.get_refcnt() > max:
|
|
max = i.get_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]
|
|
|
|
return ifaceobj
|
|
|
|
def is_iface_builtin_byname(self, ifacename):
|
|
""" Returns true if iface name is a builtin interface.
|
|
|
|
A builtin interface is an interface which ifupdown understands.
|
|
The following are currently considered builtin ifaces:
|
|
- vlan interfaces in the format <ifacename>.<vlanid>
|
|
"""
|
|
return '.' in ifacename
|
|
|
|
def is_ifaceobj_builtin(self, ifaceobj):
|
|
""" Returns true if iface name is a builtin interface.
|
|
|
|
A builtin interface is an interface which ifupdown understands.
|
|
The following are currently considered builtin ifaces:
|
|
- vlan interfaces in the format <ifacename>.<vlanid>
|
|
"""
|
|
return (ifaceobj.priv_flags & self.BUILTIN)
|
|
|
|
def is_ifaceobj_noconfig(self, ifaceobj):
|
|
""" Returns true if iface name did not have a user defined config.
|
|
|
|
These interfaces appear only when they are dependents of interfaces
|
|
which have user defined config
|
|
"""
|
|
return (ifaceobj.priv_flags & self.NOCONFIG)
|
|
|
|
def is_iface_noconfig(self, ifacename):
|
|
""" Returns true if iface has no config """
|
|
|
|
ifaceobj = self.get_iface_obj_first(ifacename)
|
|
if not ifaceobj: return True
|
|
|
|
return self.is_ifaceobj_noconfig(ifaceobj)
|
|
|
|
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:
|
|
if flag _DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is True:
|
|
we only consider devices whose configuration was
|
|
specified in the network interfaces file. We delete
|
|
any interface whose config was not specified except
|
|
for vlan devices. vlan devices get special treatment.
|
|
Even if they are not present they are created and added
|
|
to the ifacesdict
|
|
elif flag _DELETE_DEPENDENT_IFACES_WITH_NOCONFIG is False:
|
|
we create objects for all dependent devices that are not
|
|
present in the ifacesdict
|
|
"""
|
|
del_list = []
|
|
|
|
for d in dlist:
|
|
dilist = self.get_iface_objs(d)
|
|
if not dilist:
|
|
if self.is_iface_builtin_byname(d):
|
|
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)
|
|
|
|
def query_dependents(self, ifaceobj, ops):
|
|
""" Gets iface dependents by calling into respective modules """
|
|
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):
|
|
continue
|
|
dlist = module.get_dependent_ifacenames_running(ifaceobj)
|
|
else:
|
|
if (hasattr(module, 'get_dependent_ifacenames') == False):
|
|
continue
|
|
dlist = module.get_dependent_ifacenames(ifaceobj,
|
|
self.ifaceobjdict.keys())
|
|
if dlist and len(dlist):
|
|
self.logger.debug('%s: ' %ifaceobj.get_name() +
|
|
'got lowerifaces/dependents: %s' %str(dlist))
|
|
break
|
|
return dlist
|
|
|
|
def populate_dependency_info(self, ifacenames, ops):
|
|
""" recursive function to generate iface dependency info """
|
|
|
|
if ifacenames is None:
|
|
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:
|
|
continue
|
|
|
|
dlist = ifaceobj.get_lowerifaces()
|
|
if dlist is None:
|
|
dlist = self.query_dependents(ifaceobj, ops)
|
|
else:
|
|
continue
|
|
|
|
if dlist is not None:
|
|
self.preprocess_dependency_list(ifaceobj.get_name(),
|
|
dlist, ops)
|
|
self.logger.debug('%s: lowerifaces/dependents after processing: %s'
|
|
%(i, str(dlist)))
|
|
ifaceobj.set_lowerifaces(dlist)
|
|
[iqueue.append(d) for d in dlist]
|
|
|
|
if self.dependency_graph.get(i) is None:
|
|
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)
|
|
|
|
def _module_syntax_checker(self, attrname, attrval):
|
|
for m, mdict in self.module_attrs.items():
|
|
attrsdict = mdict.get('attrs')
|
|
if attrsdict and attrname in attrsdict.keys(): return True
|
|
return False
|
|
|
|
def read_default_iface_config(self):
|
|
""" Reads default network interface config /etc/network/interfaces. """
|
|
nifaces = networkInterfaces()
|
|
nifaces.subscribe('iface_found', self._save_iface)
|
|
nifaces.subscribe('validate', self._module_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. """
|
|
|
|
# Read it from the statemanager
|
|
self.ifaceobjdict = self.statemanager.get_ifaceobjdict()
|
|
|
|
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)
|
|
|
|
def load_addon_modules(self, modules_dir):
|
|
""" load python modules from modules_dir
|
|
|
|
Default modules_dir is /usr/share/ifupdownmodules
|
|
|
|
"""
|
|
self.logger.info('loading builtin modules from %s' %modules_dir)
|
|
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 mname in mlist:
|
|
if self.modules.get(mname) is not None:
|
|
continue
|
|
mpath = modules_dir + '/' + mname + '.py'
|
|
if os.path.exists(mpath):
|
|
try:
|
|
m = __import__(mname)
|
|
mclass = getattr(m, mname)
|
|
except:
|
|
raise
|
|
minstance = mclass(force=self.FORCE,
|
|
dryrun=self.DRYRUN,
|
|
nowait=self.NOWAIT,
|
|
perfmode=self.PERFMODE,
|
|
cache=self.CACHE)
|
|
self.modules[mname] = minstance
|
|
if hasattr(minstance, 'get_modinfo'):
|
|
self.module_attrs[mname] = minstance.get_modinfo()
|
|
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()
|
|
|
|
def modules_help(self):
|
|
indent = ' '
|
|
for m, mdict in self.module_attrs.items():
|
|
if not mdict:
|
|
continue
|
|
print('%s: %s' %(m, mdict.get('mhelp')))
|
|
attrdict = mdict.get('attrs')
|
|
if not attrdict:
|
|
continue
|
|
try:
|
|
for attrname, attrvaldict in attrdict.items():
|
|
if attrvaldict.get('compat', False):
|
|
continue
|
|
print('%s%s' %(indent, attrname))
|
|
print('%shelp: %s' %(indent + ' ',
|
|
attrvaldict.get('help', '')))
|
|
print ('%srequired: %s' %(indent + ' ',
|
|
attrvaldict.get('required', False)))
|
|
default = attrvaldict.get('default')
|
|
if default:
|
|
print('%sdefault: %s' %(indent + ' ', default))
|
|
|
|
validrange = attrvaldict.get('validrange')
|
|
if validrange:
|
|
print('%svalidrange: %s'
|
|
%(indent + ' ', '-'.join(validrange)))
|
|
|
|
validvals = attrvaldict.get('validvals')
|
|
if validvals:
|
|
print('%svalidvals: %s'
|
|
%(indent + ' ', ','.join(validvals)))
|
|
|
|
examples = attrvaldict.get('example')
|
|
if not examples:
|
|
continue
|
|
|
|
print '%sexample:' %(indent + ' ')
|
|
for e in examples:
|
|
print '%s%s' %(indent + ' ', e)
|
|
except:
|
|
pass
|
|
print ''
|
|
|
|
def load_scripts(self, modules_dir):
|
|
""" loading user modules from /etc/network/.
|
|
|
|
Note that previously loaded python modules override modules found
|
|
under /etc/network if any
|
|
|
|
"""
|
|
|
|
self.logger.info('looking for user scripts under %s' %modules_dir)
|
|
for op, mlist in self.operations_compat.items():
|
|
msubdir = modules_dir + '/if-%s.d' %op
|
|
self.logger.info('loading scripts under %s ...' %msubdir)
|
|
try:
|
|
module_list = os.listdir(msubdir)
|
|
for module in module_list:
|
|
if self.modules.get(module) is not None:
|
|
continue
|
|
self.operations_compat[op].append(
|
|
msubdir + '/' + module)
|
|
except:
|
|
# continue reading
|
|
pass
|
|
|
|
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, parent=None,
|
|
order=ifaceSchedulerFlags.INORDER
|
|
if 'down' in ops[0]
|
|
else ifaceSchedulerFlags.POSTORDER,
|
|
followdependents=False)
|
|
|
|
def run_with_dependents(self, ops, ifacenames):
|
|
ret = 0
|
|
self.logger.debug('running \'%s\' with dependents for %s'
|
|
%(str(ops), str(ifacenames)))
|
|
|
|
ifaceSched = ifaceScheduler()
|
|
if ifacenames is None:
|
|
ifacenames = self.ifaceobjdict.keys()
|
|
|
|
self.logger.info('dependency graph:')
|
|
self.logger.info(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,
|
|
order=ifaceSchedulerFlags.INORDER
|
|
if 'down' in ops[0]
|
|
else ifaceSchedulerFlags.POSTORDER)
|
|
return ret
|
|
|
|
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):
|
|
""" 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:
|
|
err_iface += ' ' + i
|
|
|
|
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):
|
|
""" 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):
|
|
for e in excludepats:
|
|
if re.search(e, ifacename):
|
|
return False
|
|
|
|
ifaceobjs = self.get_iface_objs(ifacename)
|
|
if ifaceobjs is None:
|
|
self.logger.debug('iface %s' %ifacename + ' not found')
|
|
return False
|
|
|
|
# We check classes first
|
|
if allow_classes and len(allow_classes):
|
|
for i in ifaceobjs:
|
|
if len(i.get_classes()):
|
|
common = Set([allow_classes]).intersection(
|
|
Set(i.get_classes()))
|
|
if len(common):
|
|
return True
|
|
return False
|
|
|
|
if auto:
|
|
for i in ifaceobjs:
|
|
if i.get_auto():
|
|
return True
|
|
return False
|
|
|
|
return True
|
|
|
|
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:
|
|
cenv = os.environ
|
|
if cenv:
|
|
cenv.update(iface_env)
|
|
else:
|
|
cenv = iface_env
|
|
|
|
cenv['MODE'] = self.compat_conv_op_to_mode(op)
|
|
|
|
return cenv
|
|
|
|
def up(self, ops, auto=False, allow_classes=None, ifacenames=None,
|
|
excludepats=None, printdependency=None):
|
|
if auto:
|
|
self.ALL = True
|
|
self.WITH_DEPENDS = True
|
|
|
|
try:
|
|
self.read_iface_config()
|
|
except Exception, e:
|
|
raise
|
|
|
|
if ifacenames is not None:
|
|
# 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')
|
|
|
|
# if iface list not given by user, assume all from config file
|
|
if ifacenames is None: 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,
|
|
excludepats, i)]
|
|
if not len(filtered_ifacenames):
|
|
raise Exception('no ifaces found matching given allow lists')
|
|
|
|
self.populate_dependency_info(filtered_ifacenames, ops)
|
|
|
|
if printdependency is not None:
|
|
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)
|
|
|
|
if self.DRYRUN:
|
|
return
|
|
|
|
# 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))
|
|
|
|
def down(self, ops, auto=False, allow_classes=None, ifacenames=None,
|
|
excludepats=None, printdependency=None):
|
|
loaded_newconfig = 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()):
|
|
self.read_old_iface_config()
|
|
elif self.FORCE:
|
|
# 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')
|
|
|
|
# if iface list not given by user, assume all from config file
|
|
if ifacenames is None: 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,
|
|
excludepats, i)]
|
|
if not len(filtered_ifacenames):
|
|
raise Exception('no ifaces found matching given allow lists')
|
|
|
|
self.populate_dependency_info(filtered_ifacenames, ops)
|
|
if printdependency:
|
|
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)
|
|
|
|
if self.DRYRUN:
|
|
return
|
|
|
|
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))
|
|
|
|
def query(self, ops, auto=False, allow_classes=None, ifacenames=None,
|
|
excludepats=None, printdependency=None,
|
|
format='native'):
|
|
if auto:
|
|
self.logger.debug('setting flag ALL')
|
|
self.ALL = True
|
|
self.WITH_DEPENDS = True
|
|
|
|
if ops[0] == 'query-syntax':
|
|
self.modules_help()
|
|
return
|
|
elif ops[0] == 'query-running':
|
|
# create fake devices to all dependents that dont have config
|
|
map(lambda i: self.create_n_save_ifaceobj(i, self.NOCONFIG),
|
|
ifacenames)
|
|
else:
|
|
try:
|
|
self.read_iface_config()
|
|
except Exception:
|
|
raise
|
|
|
|
if ifacenames is not None 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')
|
|
|
|
# if iface list not given by user, assume all from config file
|
|
if ifacenames is None: 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,
|
|
excludepats, i)]
|
|
if len(filtered_ifacenames) == 0:
|
|
raise Exception('no ifaces found matching ' +
|
|
'given allow lists')
|
|
|
|
self.populate_dependency_info(filtered_ifacenames, ops)
|
|
if ops[0] == 'query-dependency' and printdependency:
|
|
self.print_dependency(filtered_ifacenames, printdependency)
|
|
return
|
|
|
|
if ops[0] == 'query':
|
|
return self.print_ifaceobjs_pretty(filtered_ifacenames, format)
|
|
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)
|
|
|
|
if ops[0] == 'query-checkcurr':
|
|
ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames, format)
|
|
if ret != 0:
|
|
# if any of the object has an error, signal that silently
|
|
raise Exception('')
|
|
elif ops[0] == 'query-running':
|
|
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 """
|
|
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:
|
|
raise
|
|
|
|
# generate dependency graph of interfaces
|
|
self.populate_dependency_info(ifacenames, upops)
|
|
|
|
# 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):
|
|
filtered_ifacenames = [i for i in ifacenames
|
|
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
|
|
# present in the new config
|
|
# - interfaces that were changed between the last and current
|
|
# config
|
|
#
|
|
ifacedownlist = []
|
|
for ifname, lastifobjlist 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:
|
|
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):
|
|
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):
|
|
ifacedownlist.append(ifname)
|
|
continue
|
|
|
|
|
|
if ifacedownlist is not None and len(ifacedownlist) > 0:
|
|
self.logger.info('Executing down on interfaces: %s'
|
|
%str(ifacedownlist))
|
|
# Generate dependency info for old config
|
|
self.populate_dependency_info(ifacedownlist, downops)
|
|
self.run_with_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))
|
|
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)
|
|
|
|
ifacenames = self.ifaceobjdict.keys()
|
|
filtered_ifacenames = [i for i in ifacenames
|
|
if self.iface_whitelisted(auto, allow_classes,
|
|
excludepats, i)]
|
|
|
|
self.logger.info('Executing 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)
|
|
|
|
if self.DRYRUN:
|
|
return
|
|
|
|
# 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))
|
|
|
|
def dump(self):
|
|
""" all state dump """
|
|
|
|
print 'ifupdown object dump'
|
|
print self.pp.pprint(self.modules)
|
|
print self.pp.pprint(self.ifaces)
|
|
self.state_manager.dump()
|
|
|
|
def print_state(self, ifacenames=None):
|
|
self.statemanager.dump(ifacenames)
|
|
|
|
def print_ifaceobjs_raw(self, ifacenames):
|
|
for i in ifacenames:
|
|
for ifaceobj in self.get_iface_objs(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_lowerifaces()
|
|
if not dlist or not len(dlist): continue
|
|
self.print_ifaceobjs_pretty(dlist, format)
|
|
|
|
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()):
|
|
continue
|
|
if format == 'json':
|
|
ifaceobj.dump_json()
|
|
else:
|
|
ifaceobj.dump_pretty()
|
|
|
|
if self.WITH_DEPENDS:
|
|
dlist = ifaceobj.get_lowerifaces()
|
|
if not dlist or not len(dlist): continue
|
|
self.print_ifaceobjs_pretty(dlist, format)
|
|
|
|
def dump_ifaceobjs(self, ifacenames):
|
|
for i in ifacenames:
|
|
ifaceobjs = self.get_iface_objs(i)
|
|
for i in ifaceobjs:
|
|
i.dump(self.logger)
|
|
print '\n'
|
|
|
|
def print_ifaceobjscurr_pretty(self, ifacenames, format='native'):
|
|
""" Dumps current running state of interfaces.
|
|
|
|
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_lowerifaces()
|
|
if not dlist or not len(dlist): continue
|
|
self.print_ifaceobjscurr_pretty(dlist, format)
|
|
|
|
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_lowerifaces()
|
|
if dlist is None or len(dlist) == 0: continue
|
|
self.print_ifaceobjsrunning_pretty(dlist, format)
|
|
return
|
|
|
|
def print_ifaceobjs_saved_state_pretty(self, ifacenames):
|
|
self.statemanager.print_state_pretty(ifacenames, self.logger)
|
|
|
|
def print_ifaceobjs_saved_state_detailed_pretty(self, ifacenames):
|
|
self.statemanager.print_state_detailed_pretty(ifacenames, self.logger)
|