From d08d5f547870cf9e8f8d1b6deabacba125a72bab Mon Sep 17 00:00:00 2001 From: roopa Date: Sat, 8 Feb 2014 09:05:32 -0800 Subject: [PATCH] More fixes and cleanup Ticket: CM-1438 Reviewed By: Testing Done: --- TODO | 6 +- pkg/graph.py | 1 - pkg/iface.py | 88 ++++-- pkg/ifupdownmain.py | 621 +++++++++++++++++++-------------------- pkg/networkinterfaces.py | 19 +- pkg/scheduler.py | 290 ++++++++++-------- pkg/statemanager.py | 4 +- sbin/ifupdown | 95 +++--- 8 files changed, 587 insertions(+), 537 deletions(-) diff --git a/TODO b/TODO index 93f4dc8..5dcf921 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,9 @@ TODO: ==== -- fix service networking reload to use ifreload -- the --print-dependency=dot option currently assumes gvgen module is installed. +- dry-run improvement: It skips the cache completely. Which means It tells you the commands it would execute if the system is clean. Its not smart enought to say what it will really execute given the state of the system + +- included gvgen in the package. Need to check if there are any license issues +- bash completion for options - Ifquery does not report link status, mainly because it reports only in terms of /etc/network/interfaces attributes. Plan to fix that - update man-pages with new options. Convert them to rst - Documentation diff --git a/pkg/graph.py b/pkg/graph.py index 30538ab..bfbc957 100644 --- a/pkg/graph.py +++ b/pkg/graph.py @@ -139,6 +139,5 @@ class graph(): roots = [k for k, v in indegrees.items() if v == 0] if roots is None: return - print roots map(lambda r: cls.generate_dot(dependency_graph, r), roots) diff --git a/pkg/iface.py b/pkg/iface.py index 98cd587..07d3858 100644 --- a/pkg/iface.py +++ b/pkg/iface.py @@ -6,18 +6,19 @@ # iface -- # interface object # - from collections import OrderedDict -import logging +#from json import * import json +import logging + +tickmark = ' (' + u'\u2713'.encode('utf8') + ')' +crossmark = ' (' + u'\u2717'.encode('utf8') + ')' class ifaceFlags(): - NONE = 0x1 FOLLOW_DEPENDENTS = 0x2 class ifaceStatus(): - """iface status """ UNKNOWN = 0x1 SUCCESS = 0x2 @@ -56,6 +57,10 @@ class ifaceState(): DOWN = 0x7 POST_DOWN = 0x8 + # Pseudo states + QUERY_CHECKCURR = 0x9 + QUERY_RUNNING = 0xa + @classmethod def to_str(cls, state): if state == cls.UNKNOWN: @@ -70,8 +75,14 @@ class ifaceState(): return 'post-up' elif state == cls.PRE_DOWN: return 'pre-down' + elif state == cls.DOWN: + return 'down' elif state == cls.POST_DOWN: return 'post-down' + elif state == cls.QUERY_CHECKCURR: + return 'query-checkcurr' + elif state == cls.QUERY_RUNNING: + return 'query-running' @classmethod def from_str(cls, state_str): @@ -87,10 +98,23 @@ class ifaceState(): return cls.POST_UP elif state_str == 'pre-down': return cls.PRE_DOWN + elif state_str == 'down': + return cls.DOWN elif state_str == 'post-down': return cls.POST_DOWN + elif state_str == 'query-checkcurr': + return cls.QUERY_CHECKCURR + elif state_str == 'query-running': + return cls.QUERY_RUNNING +class ifaceJsonEncoder(json.JSONEncoder): + def default(self, o): + return {'addr_method' : o.addr_method, + 'addr_family' : o.addr_family, + 'auto' : o.auto, + 'config' : o.config} + class iface(): """ config flags """ AUTO = 0x1 @@ -98,15 +122,14 @@ class iface(): version = '0.1' - def __init__(self): self.name = None self.addr_family = None self.addr_method = None self.config = OrderedDict() - self.children = [] self.state = ifaceState.NEW self.status = ifaceStatus.UNKNOWN + self.errstr = '' self.flags = 0x0 self.priv_flags = 0x0 self.refcnt = 0 @@ -203,9 +226,6 @@ class iface(): return False - def add_child(self, child_iface_obj): - self.children.append(child_iface_obj) - def get_state(self): return self.state @@ -258,11 +278,9 @@ class iface(): def get_attr_value_first(self, attr_name): config = self.get_config() - attr_value_list = config.get(attr_name) if attr_value_list is not None: return attr_value_list[0] - return None def get_attr_value_n(self, attr_name, attr_index): @@ -308,26 +326,17 @@ class iface(): def update_config_with_status(self, attr_name, attr_value, attr_status=0): if attr_value is None: attr_value = '' - - if attr_status != 0: + if attr_status: self.set_status(ifaceStatus.ERROR) + new_attr_value = '%s (%s)' %(attr_value, crossmark) else: + new_attr_value = '%s (%s)' %(attr_value, tickmark) if self.get_status() != ifaceStatus.ERROR: self.set_status(ifaceStatus.SUCCESS) if self.config.get(attr_name) is not None: - self.config[attr_name].append(attr_value) + self.config[attr_name].append(new_attr_value) else: - self.config[attr_name] = [attr_value] - - """ XXX: If status needs to be encoded in the query string - if attr_status == 0: - self.set_status(attr - attr_status_str = '' - elif attr_status == 0: - attr_status_str = ' (success)' - elif attr_status != 0: - attr_status_str = ' (error)' - self.config[attr_name] = attr_value + attr_status_str """ + self.config[attr_name] = [new_attr_value] def is_different(self, dstiface): if self.name != dstiface.name: return True @@ -342,8 +351,26 @@ class iface(): if any(True for k,v in self.config.items() if v != dstiface.config.get(k)): return True - return False + + def __getstate__(self): + odict = self.__dict__.copy() + del odict['state'] + del odict['status'] + del odict['dependents'] + del odict['realdev_dependents'] + del odict['refcnt'] + + return odict + + def __setstate__(self, dict): + self.__dict__.update(dict) + self.state = ifaceState.NEW + self.status = ifaceStatus.UNKNOWN + self.refcnt = 0 + self.dependents = None + self.realdev_dependents = None + self.linkstate = None def dump_raw(self, logger): indent = ' ' @@ -376,7 +403,7 @@ class iface(): logger.info(indent + indent + str(config)) logger.info('}') - def dump_pretty(self, logger): + def dump_pretty(self): indent = '\t' outbuf = '' if self.get_auto(): @@ -396,10 +423,7 @@ class iface(): for cv in cvaluelist: outbuf += indent + '%s' %cname + ' %s\n' %cv - #outbuf += ('%s' %indent + '%s' %self.get_state_str() + - # ' %s' %self.get_status_str()) - print outbuf - def dump_json(self, logger): - json.dumps(self) + def dump_json(self): + print json.dumps(self, cls=ifaceJsonEncoder) diff --git a/pkg/ifupdownmain.py b/pkg/ifupdownmain.py index 8730e85..d27b407 100644 --- a/pkg/ifupdownmain.py +++ b/pkg/ifupdownmain.py @@ -54,36 +54,28 @@ class ifupdownMain(): # Dictionary representing operation, sub operation and modules # for every sub operation - operations = { 'up' : - OrderedDict([('pre-up', []), - ('up' , []), - ('post-up' , [])]), - 'query-checkcurr' : - OrderedDict([('query-checkcurr', [])]), - - 'query-running' : - OrderedDict([('query-running', [])]), - - 'down' : - OrderedDict([('pre-down', []), - ('down' , []), - ('post-down' , [])])} + operations = OrderedDict([('pre-up', []), + ('up' , []), + ('post-up' , []), + ('query-checkcurr', []), + ('query-running', []), + ('query-dependency', []), + ('pre-down', []), + ('down' , []), + ('post-down' , [])]) # For old style /etc/network/ bash scripts - operations_compat = { 'up' : - OrderedDict([('pre-up', []), - ('up' , []), - ('post-up' , [])]), - 'down' : - OrderedDict([('pre-down', []), - ('down' , []), - ('post-down' , [])])} - + 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, - format='nwifaces', cache=False): + cache=False): self.logger = logging.getLogger('ifupdown') self.FORCE = force @@ -98,10 +90,11 @@ class ifupdownMain(): self.njobs = njobs self.pp = pprint.PrettyPrinter(indent=4) self.modules = OrderedDict({}) + self.module_attrs = {} self.load_addon_modules_config() self.load_addon_modules(self.addon_modules_dir) self.load_scripts(self.scripts_dir) - self.dependency_graph = {} + self.dependency_graph = OrderedDict({}) try: self.statemanager = stateManager() @@ -117,17 +110,15 @@ class ifupdownMain(): def compat_conv_op_to_mode(self, op): """ Returns old op name to work with existing scripts """ - if op == 'up': + if op == 'pre-up': return 'start' - elif op == 'down': + elif op == 'pre-down': return 'stop' else: return op def set_force(self, force): """ Set force flag. """ - if force == True: - self.logger.debug('setting force to true') self.FORCE = force def get_force(self): @@ -157,16 +148,12 @@ class ifupdownMain(): return self.dependency_graph def set_perfmode(self, perfmode): - if perfmode == True: - self.logger.debug('setting perfmode to true') self.PERFMODE = perfmode def get_perfmode(self): return self.PERFMODE def set_nowait(self, nowait): - if nowait == True: - self.logger.debug('setting dryrun to true') self.NOWAIT = nowait def get_nowait(self): @@ -203,7 +190,7 @@ class ifupdownMain(): def get_iface_obj_last(self, ifacename): return self.ifaceobjdict.get(ifacename)[-1] - def create_ifaceobjcurr(self, ifaceobj): + def create_n_save_ifaceobjcurr(self, ifaceobj): ifacename = ifaceobj.get_name() ifaceobjcurr = self.get_ifaceobjcurr(ifacename) if ifaceobjcurr is not None: @@ -214,7 +201,7 @@ class ifupdownMain(): ifaceobjcurr.set_dependents(ifaceobj.get_dependents()) self.ifaceobjcurrdict[ifacename] = ifaceobjcurr - return ifaceobj + return ifaceobjcurr def get_ifaceobjcurr(self, ifacename): return self.ifaceobjcurrdict.get(ifacename) @@ -248,20 +235,18 @@ class ifupdownMain(): ifaceobj.set_name(ifacename) ifaceobj.priv_flags = priv_flags ifaceobj.set_auto() - if increfcnt == True: + if increfcnt: ifaceobj.inc_refcnt() self.ifaceobjdict[ifacename] = [ifaceobj] - def is_iface_builtin(self, ifacename): + 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 . """ - if re.search(r'\.', ifacename, 0) is not None: - return True - return False + return '.' in ifacename def is_ifaceobj_builtin(self, ifaceobj): """ Returns true if iface name is a builtin interface. @@ -270,11 +255,7 @@ class ifupdownMain(): The following are currently considered builtin ifaces: - vlan interfaces in the format . """ - - if (ifaceobj.priv_flags & self.BUILTIN) != 0: - return True - - return False + return (ifaceobj.priv_flags & self.BUILTIN) def is_ifaceobj_noconfig(self, ifaceobj): """ Returns true if iface name did not have a user defined config. @@ -282,13 +263,17 @@ class ifupdownMain(): These interfaces appear only when they are dependents of interfaces which have user defined config """ + return (ifaceobj.priv_flags & self.NOCONFIG) - if (ifaceobj.priv_flags & self.NOCONFIG) != 0: - return True + def is_iface_noconfig(self, ifacename): + """ Returns true if iface has no config """ - return False + ifaceobj = self.get_iface_obj_first(ifacename) + if not ifaceobj: return True - def preprocess_dependency_list(self, dlist, op): + return self.is_ifaceobj_noconfig(ifaceobj) + + def preprocess_dependency_list(self, dlist, ops): """ We go through the dependency list and delete or add interfaces from the interfaces dict by applying the following rules: @@ -307,9 +292,10 @@ class ifupdownMain(): for d in dlist: dilist = self.get_iface_objs(d) - if dilist == None: - if self.is_iface_builtin(d) == True: - self.create_n_save_ifaceobj(d, self.BUILTIN, True), + 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 @@ -323,14 +309,13 @@ class ifupdownMain(): for d in del_list: dlist.remove(d) - def get_dependents(self, ifaceobj, op): + def query_dependents(self, ifaceobj, ops): """ Gets iface dependents by calling into respective modules """ dlist = None # Get dependents for interface by querying respective modules - subopdict = self.operations.get(op) - for subop, mlist in subopdict.items(): - for mname in mlist: + for op in ops: + for mname in self.operations.get(op): module = self.modules.get(mname) if op == 'query-running': if (hasattr(module, @@ -342,15 +327,14 @@ class ifupdownMain(): continue dlist = module.get_dependent_ifacenames(ifaceobj, self.ifaceobjdict.keys()) - if dlist is not None and len(dlist) > 0: + if dlist and len(dlist): ifaceobj.set_realdev_dependents(dlist[:]) self.logger.debug('%s: ' %ifaceobj.get_name() + 'got dependency list: %s' %str(dlist)) break - return dlist - def populate_dependency_info(self, ifacenames, op): + def populate_dependency_info(self, ifacenames, ops): """ recursive function to generate iface dependency info """ if ifacenames is None: @@ -370,12 +354,12 @@ class ifupdownMain(): dlist = ifaceobj.get_dependents() if dlist is None: - dlist = self.get_dependents(ifaceobj, op) + dlist = self.query_dependents(ifaceobj, ops) else: continue if dlist is not None: - self.preprocess_dependency_list(dlist, op) + self.preprocess_dependency_list(dlist, ops) self.logger.debug('%s: dependency list after processing: %s' %(i, str(dlist))) ifaceobj.set_dependents(dlist) @@ -384,20 +368,23 @@ class ifupdownMain(): if self.dependency_graph.get(i) is None: self.dependency_graph[i] = dlist - def is_valid_state_transition(self, ifname, to_be_state): - return self.statemanager.is_valid_state_transition(ifname, - to_be_state) - - def save_iface(self, ifaceobj): - if self.ifaceobjdict.get(ifaceobj.get_name()) is None: + 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('iface_found', self._save_iface) + nifaces.subscribe('validate', self._module_syntax_checker) nifaces.load() def read_iface_config(self): @@ -409,34 +396,6 @@ class ifupdownMain(): # Read it from the statemanager self.ifaceobjdict = self.statemanager.get_ifaceobjdict() - - def save_module(self, mkind, msubkind, mname, mftype, module): - """ saves a module into internal module dict for later use. - - mtype - pre-up.d, post-up.d and so on - mftype - pmodule (python module), bashscript (bash script) - - """ - - try: - mmetadata = self.operations[mkind][msubkind].get(mname) - except KeyError: - self.logger.warn('unsupported module type %s' %mname) - return - - if mmetadata is None or mmetadata.get('ftype') != 'pmodule': - mmetadata = {} - mmetadata['ftype'] = mftype - mmetadata['module'] = module - self.operations[mkind][msubkind][mname] = mmetadata - - self.logger.debug('saved module %s' %mkind + - ' %s' %mname + ' %s' %mftype) - else: - self.logger.info('ignoring module %s' %mkind + ' %s' %msubkind + - ' %s' %mname + ' of type %s' %mftype) - - def load_addon_modules_config(self): with open(self.addon_modules_configfile, 'r') as f: lines = f.readlines() @@ -444,10 +403,7 @@ class ifupdownMain(): litems = l.rstrip(' \n').split(',') operation = litems[0] mname = litems[1] - if operation.find('up') != -1: - self.operations['up'][operation].append(mname) - elif operation.find('down') != -1: - self.operations['down'][operation].append(mname) + self.operations[operation].append(mname) def load_addon_modules(self, modules_dir): """ load python modules from modules_dir @@ -460,32 +416,76 @@ class ifupdownMain(): if not modules_dir in sys.path: sys.path.append(modules_dir) try: - for op, opdict in self.operations.items(): - for subop, mlist in opdict.items(): - for mname in mlist: - if self.modules.get(mname) is not None: - continue - mpath = modules_dir + '/' + mname + '.py' - if os.path.exists(mpath) == True: - try: - m = __import__(mname) - mclass = getattr(m, mname) - except: - raise - - minstance = mclass(force=self.get_force(), - dryrun=self.get_dryrun(), - nowait=self.get_nowait(), - perfmode=self.get_perfmode(), - cache=self.get_cache()) - self.modules[mname] = minstance + 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']['query-checkcurr'] = self.modules.keys() - self.operations['query-running']['query-running'] = self.modules.keys() + self.operations['query-checkcurr'] = self.modules.keys() + self.operations['query-running'] = self.modules.keys() + self.operations['query-dependency'] = 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/. @@ -495,108 +495,74 @@ class ifupdownMain(): """ self.logger.info('looking for user scripts under %s' %modules_dir) - for op, subops in self.operations_compat.items(): - for subop in subops.keys(): - msubdir = modules_dir + '/if-%s.d' %subop - 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][subop].append( + 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: - raise + except: + raise def conv_iface_namelist_to_objlist(self, intf_list): for intf in intf_list: iface_obj = self.get_iface(intf) - if iface_obj == None: + if not iface_obj: raise ifupdownInvalidValue('no iface %s', intf) - iface_objs.append(iface_obj) - return iface_objs - def run_without_dependents(self, op, ifacenames): - """ Run interfaces without executing their dependents. - - Even though we are running without dependents here, we will have - to cover the builtin dependents. Because the only way builtin - devices are operated on is when they are seen as dependents. - So we include them. And also we need to execute the user provided - interface names in order of their dependencies. - So, we created a special dependency_graph with interfaces matching - the above constraints here - - if self.ALL is True you are better off using the default - dependency graph self.dependency_graph that carries all dependents - """ - - if ifacenames == None: + 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 op %s' %op + - ' for %s' %str(ifacenames)) + self.logger.debug('run_without_dependents for ops %s for %s' + %(str(ops), str(ifacenames))) - dependency_graph = {} - indegrees = {} 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) - for i in ifacenames: - if dependency_graph.get(i) is not None: - continue - - dependency_graph[i] = [] - indegrees[i] = 0 - ifaceobj = self.get_iface_obj_first(i) - dlist = ifaceobj.get_dependents() - if dlist is None: - continue - - for d in dlist: - ifaceobj = self.get_iface_obj_first(d) - if (self.is_ifaceobj_builtin(ifaceobj) == True or - self.is_ifaceobj_noconfig(ifaceobj) == True or - d in ifacenames): - dependency_graph[i].append(d) - dependency_graph[d] = None - indegrees[d] = 1 - - self.logger.debug('dependency graph: %s' %str(dependency_graph)) - ifaceSched.run_iface_dependency_graph(self, dependency_graph, op, - indegrees, - graphsortall=True) - - def run_with_dependents(self, op, ifacenames): + def run_with_dependents(self, ops, ifacenames): ret = 0 self.logger.debug('running \'%s\' with dependents for %s' - %(op, str(ifacenames))) + %(str(ops), str(ifacenames))) ifaceSched = ifaceScheduler() if ifacenames is None: ifacenames = self.ifaceobjdict.keys() - if self.logger.isEnabledFor(logging.DEBUG) == True: + 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, op) + self.dependency_graph, ops) else: - ret = ifaceSched.run_iface_dependency_graph(self, - self.dependency_graph, op) + 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, op, ifacenames, format): + def print_dependency(self, ifacenames, format): if ifacenames is None: ifacenames = self.ifaceobjdict.keys() if format == 'list': - self.pp.pprint(self.dependency_graph) + for k,v in self.dependency_graph.items(): + print '%s : %s' %(k, str(v)) elif format == 'dot': indegrees = {} map(lambda i: indegrees.update({i : @@ -617,7 +583,7 @@ class ifupdownMain(): if ifaceobjs is None: err_iface += ' ' + i - if len(err_iface) != 0: + if len(err_iface): self.logger.error('could not find interfaces: %s' %err_iface) return -1 @@ -631,11 +597,10 @@ class ifupdownMain(): interfaces are checked against the allow_classes and auto lists. """ - # If the interface matches - if excludepats is not None and len(excludepats) > 0: + if excludepats and len(excludepats): for e in excludepats: - if re.search(e, ifacename) is not None: + if re.search(e, ifacename): return False ifaceobjs = self.get_iface_objs(ifacename) @@ -644,18 +609,18 @@ class ifupdownMain(): return False # We check classes first - if allow_classes is not None and len(allow_classes) > 0: + if allow_classes and len(allow_classes): for i in ifaceobjs: - if (len(i.get_classes()) > 0): + if len(i.get_classes()): common = Set([allow_classes]).intersection( Set(i.get_classes())) - if len(common) > 0: + if len(common): return True return False - if auto == True: + if auto: for i in ifaceobjs: - if i.get_auto() == True: + if i.get_auto(): return True return False @@ -670,7 +635,7 @@ class ifupdownMain(): iface_env = ifaceobj.get_env() if iface_env is not None: cenv = os.environ - if cenv is not None: + if cenv: cenv.update(iface_env) else: cenv = iface_env @@ -679,42 +644,16 @@ class ifupdownMain(): return cenv - def run(self, op, auto=False, allow_classes=None, - ifacenames=None, excludepats=None, - format=None, printdependency=None): - """ main ifupdown run method """ - - if auto == True: + def up(self, ops, auto=False, allow_classes=None, ifacenames=None, + excludepats=None, printdependency=None): + if auto: self.ALL = True self.WITH_DEPENDS = True - # Only read new iface config for 'up' - # operations. For 'downs' we only rely on - # old state - if op == 'up': - try: - self.read_iface_config() - except Exception, e: - raise - elif op == 'down': - # for down we need to look at old state - self.logger.debug('down op, looking at old state ..') - - if len(self.statemanager.get_ifaceobjdict()) > 0: - self.read_old_iface_config() - elif self.FORCE == True: - # 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)) - else: - raise Exception('old state not available...aborting.' + - ' try running with --force option') - + 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 @@ -728,25 +667,24 @@ class ifupdownMain(): # filter interfaces based on auto and allow classes filtered_ifacenames = [i for i in ifacenames if self.iface_whitelisted(auto, allow_classes, - excludepats, i) == True] - if len(filtered_ifacenames) == 0: - raise Exception('no ifaces found matching ' + - 'given allow lists') + excludepats, i)] + if not len(filtered_ifacenames): + raise Exception('no ifaces found matching given allow lists') - self.populate_dependency_info(filtered_ifacenames, op) + self.populate_dependency_info(filtered_ifacenames, ops) if printdependency is not None: - self.print_dependency(op, filtered_ifacenames, printdependency) + self.print_dependency(filtered_ifacenames, printdependency) return - if self.WITH_DEPENDS == True: - self.run_with_dependents(op, filtered_ifacenames) + if self.WITH_DEPENDS: + self.run_with_dependents(ops, filtered_ifacenames) else: - self.run_without_dependents(op, filtered_ifacenames) + self.run_without_dependents(ops, filtered_ifacenames) # Update persistant iface states try: - if self.ALL == True: + if self.ALL: self.statemanager.flush_state(self.ifaceobjdict) else: self.statemanager.flush_state() @@ -756,26 +694,82 @@ class ifupdownMain(): traceback.print_tb(t) self.logger.warning('error saving state (%s)' %str(e)) - def up(self, auto=False, allow=None, ifacenames=None, - excludepats=None, printdependency=None): - return self.run('up', auto, allow, ifacenames, - excludepats=excludepats, - printdependency=printdependency) + 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 - def down(self, auto=False, allow=None, ifacenames=None, excludepats=None): - return self.run('down', auto, allow, ifacenames, - excludepats=excludepats); + # for down we need to look at old state + self.logger.debug('Looking at old state ..') - def query(self, op, auto=False, allow_classes=None, ifacenames=None, + 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 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=None): - """ main ifupdown run method """ - if auto == True: + format='native'): + if auto: self.logger.debug('setting flag ALL') self.ALL = True self.WITH_DEPENDS = True - if op == 'query-running': + 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) @@ -785,7 +779,7 @@ class ifupdownMain(): except Exception: raise - if ifacenames is not None and op != 'query-running': + 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') @@ -794,58 +788,49 @@ class ifupdownMain(): if ifacenames is None: ifacenames = self.ifaceobjdict.keys() # filter interfaces based on auto and allow classes - if op == 'query-running': + 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) == True] - + excludepats, i)] if len(filtered_ifacenames) == 0: raise Exception('no ifaces found matching ' + 'given allow lists') - - if op == 'query': + if ops[0] == 'query': + return self.print_ifaceobjs_pretty(filtered_ifacenames, format) + elif ops[0] == 'query-raw': return self.print_ifaceobjs_raw(filtered_ifacenames) - elif op == 'query-pretty': - return self.print_ifaceobjs_pretty(filtered_ifacenames) - elif op == 'query-presumed': - return self.print_ifaceobjs_saved_state_pretty( - filtered_ifacenames) - elif op == 'query-presumeddetailed': - return self.print_ifaceobjs_saved_state_detailed_pretty( - filtered_ifacenames) + self.populate_dependency_info(filtered_ifacenames, ops) + if ops[0] == 'query-dependency' and printdependency: + self.print_dependency(filtered_ifacenames, printdependency) + return - self.populate_dependency_info(filtered_ifacenames, op) - - #if printdependency is not None: - # self.print_dependency(op, filtered_ifacenames, printdependency) - # return - - if self.WITH_DEPENDS == True: - self.run_with_dependents(op, filtered_ifacenames) + if self.WITH_DEPENDS: + self.run_with_dependents(ops, filtered_ifacenames) else: - self.run_without_dependents(op, filtered_ifacenames) + self.run_without_dependents(ops, filtered_ifacenames) - if op == 'query-checkcurr': - ret = self.print_ifaceobjscurr_pretty(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 op == 'query-running': - self.print_ifaceobjsrunning_pretty(filtered_ifacenames) + 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 == True: + if auto: self.ALL = True self.WITH_DEPENDS = True @@ -856,11 +841,11 @@ class ifupdownMain(): raise # generate dependency graph of interfaces - self.populate_dependency_info(ifacenames, 'up') + self.populate_dependency_info(ifacenames, upops) # Save a copy of new iface objects and dependency_graph - new_ifaceobjdict = self.get_ifaceobjdict() - new_dependency_graph = self.get_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' @@ -879,7 +864,7 @@ class ifupdownMain(): len(ifacenames) != 0): filtered_ifacenames = [i for i in ifacenames if self.iface_whitelisted(auto, allow_classes, - excludepats, i) == True] + excludepats, i)] # Generate the interface down list # Interfaces that go into the down list: @@ -888,7 +873,6 @@ class ifupdownMain(): # - interfaces that were changed between the last and current # config # - ifacedownlist = [] for ifname, lastifobjlist in self.ifaceobjdict.items(): objidx = 0 @@ -913,32 +897,27 @@ class ifupdownMain(): for objidx in range(0, len(lastifobjlist)): oldobj = lastifobjlist[objidx] newobj = newifobjlist[objidx] - if newobj.is_different(oldobj) == True: + if newobj.is_different(oldobj): ifacedownlist.append(ifname) continue - #ifacedownlist = Set(filtered_ifacenames).difference( - # Set(new_ifaceobjdict.keys())) 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, 'down') - + 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('down', ifacedownlist) + self.run_with_dependents(downops, ifacedownlist) else: # if not, down only the interfaces that we have in the # down list - self.run_without_dependents('down', ifacedownlist) - + self.run_without_dependents(downops, ifacedownlist) # Update persistant iface states try: - if self.ALL == True: + if self.ALL: self.statemanager.flush_state(self.ifaceobjdict) else: self.statemanager.flush_state() @@ -957,18 +936,18 @@ class ifupdownMain(): ifacenames = self.ifaceobjdict.keys() filtered_ifacenames = [i for i in ifacenames if self.iface_whitelisted(auto, allow_classes, - excludepats, i) == True] + excludepats, i)] self.logger.info('Executing up on interfaces: %s' %str(filtered_ifacenames)) - if self.WITH_DEPENDS == True: - self.run_with_dependents('up', filtered_ifacenames) + if self.WITH_DEPENDS: + self.run_with_dependents(upops, filtered_ifacenames) else: - self.run_without_dependents('up', filtered_ifacenames) + self.run_without_dependents(upops, filtered_ifacenames) # Update persistant iface states try: - if self.ALL == True: + if self.ALL: self.statemanager.flush_state(self.get_ifaceobjdict()) else: self.statemanager.flush_state() @@ -996,9 +975,13 @@ class ifupdownMain(): i.dump_raw(self.logger) print '\n' - def print_ifaceobjs_pretty(self, ifacenames): + def print_ifaceobjs_pretty(self, ifacenames, format='native'): for i in ifacenames: - [ j.dump_pretty(self.logger) + if format == 'json': + [ j.dump_json() + for j in self.get_iface_objs(i)] + else: + [ j.dump_pretty() for j in self.get_iface_objs(i)] def dump_ifaceobjs(self, ifacenames): @@ -1008,7 +991,7 @@ class ifupdownMain(): i.dump(self.logger) print '\n' - def print_ifaceobjscurr_pretty(self, ifacenames, format=None): + def print_ifaceobjscurr_pretty(self, ifacenames, format='native'): """ Dumps current running state of interfaces. returns 1 if any of the interface has an error, @@ -1017,7 +1000,7 @@ class ifupdownMain(): ret = 0 for i in ifacenames: ifaceobj = self.get_ifaceobjcurr(i) - if ifaceobj is None: continue + if not ifaceobj: continue if ifaceobj.get_status() == ifaceStatus.NOTFOUND: print 'iface %s' %ifaceobj.get_name() + ' (not found)\n' ret = 1 @@ -1025,38 +1008,36 @@ class ifupdownMain(): elif ifaceobj.get_status() == ifaceStatus.ERROR: ret = 1 - if (self.is_iface_builtin(i) or + if (self.is_ifaceobj_builtin(ifaceobj) or ifaceobj.is_config_present() == False): continue - if format is None or format == 'nwifaces': - ifaceobj.dump_pretty(self.logger) + if format == 'json': + ifaceobj.dump_json() else: - ifaceobj.dump_json(self.logger) + ifaceobj.dump_pretty() if self.ALL == False or self.WITH_DEPENDS: dlist = ifaceobj.get_dependents() - if dlist is None or len(dlist) == 0: continue + if not dlist or not len(dlist): continue self.print_ifaceobjscurr_pretty(dlist, format) return ret - def print_ifaceobjsrunning_pretty(self, ifacenames, format=None): + 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 (self.is_iface_builtin(i) and - # ifaceobj.is_config_present() == False): if ifaceobj.is_config_present() == False: continue - if format is None or format == 'nwifaces': - ifaceobj.dump_pretty(self.logger) - elif format == 'json': - ifaceobj.dump_json(self.logger) + if format == 'json': + ifaceobj.dump_json() + else: + ifaceobj.dump_pretty() if self.ALL == False or self.WITH_DEPENDS: dlist = ifaceobj.get_dependents() diff --git a/pkg/networkinterfaces.py b/pkg/networkinterfaces.py index b4e591f..f8ad212 100644 --- a/pkg/networkinterfaces.py +++ b/pkg/networkinterfaces.py @@ -24,7 +24,8 @@ class networkInterfaces(): def __init__(self): self.logger = logging.getLogger('ifupdown.' + self.__class__.__name__) - self.callbacks = {'iface_found' : None} + self.callbacks = {'iface_found' : None, + 'validate' : None} self.allow_classes = {} @@ -118,11 +119,18 @@ class networkInterfaces(): if len(attrs) < 2: self.logger.warn('invalid syntax at line %d' %(line_idx + 1)) continue - - if iface_config.get(attrs[0]) == None: - iface_config[attrs[0]] = [attrs[1].strip(' ')] + attrname = attrs[0] + attrval = attrs[1].strip(' ') + try: + if not self.callbacks.get('validate')(attrname, attrval): + self.logger.warn('unsupported keyword (%s) at line %d' + %(l, line_idx + 1)) + except: + pass + if not iface_config.get(attrname): + iface_config[attrname] = [attrval] else: - iface_config[attrs[0]].append(attrs[1].strip(' ')) + iface_config[attrname].append(attrval) lines_consumed = line_idx - cur_idx @@ -148,7 +156,6 @@ class networkInterfaces(): ifaceobj.set_class(c) # Call iface found callback - #self.logger.debug('saving interface %s' %ifaceobj.get_name()) self.callbacks.get('iface_found')(ifaceobj) return lines_consumed # Return next index diff --git a/pkg/scheduler.py b/pkg/scheduler.py index ad77fca..fe5bbec 100644 --- a/pkg/scheduler.py +++ b/pkg/scheduler.py @@ -7,21 +7,22 @@ # interface scheduler # -import os -import re from statemanager import * from iface import * from graph import * from collections import deque from collections import OrderedDict -import imp -import pprint import logging +import traceback from graph import * from collections import deque from threading import * from ifupdownbase import * +class ifaceSchedulerFlags(): + INORDER = 1 + POSTORDER = 2 + class ifaceScheduler(ifupdownBase): """ scheduler to schedule configuration of interfaces. @@ -30,132 +31,206 @@ class ifaceScheduler(ifupdownBase): or dependency graph format. """ + def __init__(self, force=False): self.logger = logging.getLogger('ifupdown.' + self.__class__.__name__) self.FORCE = force - def run_iface_subop(self, ifupdownobj, ifaceobj, op, subop, mlist, cenv): + def run_iface_op(self, ifupdownobj, ifaceobj, op, cenv): """ Runs sub operation on an interface """ + ifacename = ifaceobj.get_name() - self.logger.debug('%s: ' %ifaceobj.get_name() + 'op %s' %op + - ' subop = %s' %subop) + if (ifaceobj.get_state() >= ifaceState.from_str(op) and + ifaceobj.get_status() == ifaceStatus.SUCCESS): + self.logger.debug('%s: already in state %s' %(ifacename, op)) + return - for mname in mlist: + for mname in ifupdownobj.operations.get(op): m = ifupdownobj.modules.get(mname) err = 0 try: - if hasattr(m, 'run') == True: + if hasattr(m, 'run'): self.logger.debug('%s: %s : running module %s' - %(ifaceobj.get_name(), subop, mname)) + %(ifacename, op, mname)) if op == 'query-checkcurr': - # Dont check state if the interface object was + # Dont check curr if the interface object was # auto generated - if ((ifaceobj.priv_flags & ifupdownobj.BUILTIN) != 0 or - (ifaceobj.priv_flags & ifupdownobj.NOCONFIG) != 0): + if (ifaceobj.priv_flags & ifupdownobj.NOCONFIG): continue - m.run(ifaceobj, subop, - query_ifaceobj=ifupdownobj.create_ifaceobjcurr( - ifaceobj)) + m.run(ifaceobj, op, + query_ifaceobj=ifupdownobj.create_n_save_ifaceobjcurr(ifaceobj)) else: - m.run(ifaceobj, subop) + m.run(ifaceobj, op) except Exception, e: err = 1 self.log_error(str(e)) finally: - if op[:5] != 'query': - if err == 1: - ifupdownobj.set_iface_state(ifaceobj, - ifaceState.from_str(subop), + if err == 1: + ifupdownobj.set_iface_state(ifaceobj, + ifaceState.from_str(op), ifaceStatus.ERROR) - else: - ifupdownobj.set_iface_state(ifaceobj, - ifaceState.from_str(subop), + else: + ifupdownobj.set_iface_state(ifaceobj, + ifaceState.from_str(op), ifaceStatus.SUCCESS) # execute /etc/network/ scripts - subop_dict = ifupdownobj.operations_compat.get(op) - if subop_dict is None: return - for mname in subop_dict.get(subop): + mlist = ifupdownobj.operations_compat.get(op) + if not mlist: + return + for mname in mlist: self.logger.debug('%s: %s : running script %s' - %(ifaceobj.get_name(), subop, mname)) + %(ifacename, op, mname)) try: self.exec_command(mname, cmdenv=cenv) except Exception, e: err = 1 self.log_error(str(e)) - def run_iface_subops(self, ifupdownobj, ifaceobj, op): + + def run_iface_ops(self, ifupdownobj, ifaceobj, ops): """ Runs all sub operations on an interface """ # For backward compatibility execute scripts with # environent set - cenv = ifupdownobj.generate_running_env(ifaceobj, op) + cenv = ifupdownobj.generate_running_env(ifaceobj, ops[0]) # Each sub operation has a module list - subopdict = ifupdownobj.operations.get(op) - for subop, mlist in subopdict.items(): - self.run_iface_subop(ifupdownobj, ifaceobj, op, subop, mlist, cenv) + [self.run_iface_op(ifupdownobj, ifaceobj, op, cenv) + for op in ops] + + def run_iface_graph(self, ifupdownobj, ifacename, ops, + order=ifaceSchedulerFlags.POSTORDER, + followdependents=True): + """ runs interface by traversing its dependents first """ + + # Each ifacename can have a list of iface objects + ifaceobjs = ifupdownobj.get_iface_objs(ifacename) + if ifaceobjs is None: + raise Exception('%s: not found' %ifacename) - def run_iface(self, ifupdownobj, ifacename, op): + for ifaceobj in ifaceobjs: + if order == ifaceSchedulerFlags.INORDER: + # Run all sub operations sequentially + try: + self.run_iface_ops(ifupdownobj, ifaceobj, ops) + except Exception, e: + raise Exception(str(e)) + # Run dependents + dlist = ifaceobj.get_dependents() + if dlist and len(dlist): + self.logger.debug('%s:' %ifacename + + ' found dependents: %s' %str(dlist)) + try: + if not followdependents: + # XXX: this is yet another extra step, + # but is needed for interfaces that are + # implicit dependents + # up without dependents, but + new_dlist = [d for d in dlist + if ifupdownobj.is_iface_noconfig(d)] + if not new_dlist: continue + self.run_iface_list(ifupdownobj, new_dlist, ops, + order, followdependents) + else: + self.run_iface_list(ifupdownobj, dlist, ops, + order, followdependents) + except Exception, e: + if (self.ignore_error(str(e))): + pass + else: + # Dont bring the iface up if children did not come up + ifaceobj.set_state(ifaceState.NEW) + ifaceobj.set_status(ifaceStatus.ERROR) + raise + + if order == ifaceSchedulerFlags.POSTORDER: + try: + self.run_iface_ops(ifupdownobj, ifaceobj, ops) + except Exception, e: + raise Exception(str(e)) + + def run_iface_list(self, ifupdownobj, ifacenames, + ops, order=ifaceSchedulerFlags.POSTORDER, + followdependents=True): + """ Runs interface list """ + + for ifacename in ifacenames: + try: + self.run_iface_graph(ifupdownobj, ifacename, ops, + order, followdependents) + except Exception, e: + if (self.ignore_error(str(e))): + pass + else: + traceback.print_stack() + raise Exception('error running iface %s (%s)' + %(ifacename, str(e))) + + def run_iface_dependency_graphs(self, ifupdownobj, + dependency_graph, ops, indegrees=None, + order=ifaceSchedulerFlags.POSTORDER, + followdependents=True): + """ Runs iface dependeny graph by visiting all the nodes + + Parameters: + ----------- + ifupdownobj : ifupdown object (used for getting and updating iface + object state) + dependency_graph : dependency graph in adjacency list + format (contains more than one dependency graph) + ops : list of operations to perform eg ['pre-up', 'up', 'post-up'] + + indegrees : indegree array if present is used to determine roots + of the graphs in the dependency_graph + """ + + self.logger.debug('running dependency graph serially ..') + + run_queue = [] + # Build a list of ifaces that dont have any dependencies + if indegrees: + # use indegrees array if specified + for ifacename, degree in indegrees.items(): + if not indegrees.get(ifacename): + run_queue.append(ifacename) + else: + for ifacename in dependency_graph.keys(): + if not ifupdownobj.get_iface_refcnt(ifacename): + run_queue.append(ifacename) + + self.logger.debug('graph roots (interfaces that dont have ' + 'dependents):' + ' %s' %str(run_queue)) + + return self.run_iface_list(ifupdownobj, run_queue, ops, order, + followdependents) + + + def run_iface(self, ifupdownobj, ifacename, ops): """ Runs operation on an interface """ ifaceobjs = ifupdownobj.get_iface_objs(ifacename) for i in ifaceobjs: - if (op != 'query' and ifupdownobj.STATE_CHECK == True and - ifupdownobj.is_valid_state_transition(i, op) == False and - ifupdownobj.FORCE == False): - self.logger.warning('%s' %ifacename + - ' already %s' %op) - continue + self.run_iface_ops(ifupdownobj, i, ops) - self.run_iface_subops(ifupdownobj, i, op) - - - def run_iface_list(self, ifupdownobj, ifacenames, operation, - sorted_by_dependency=False): - """ Runs interface list serially executing all sub operations on - each interface at a time. """ - - self.logger.debug('run_iface_list: running interface list for ' + - 'operation %s' %operation) - - iface_run_queue = deque(ifacenames) - for i in range(0, len(iface_run_queue)): - if operation == 'up': - # XXX: simplify this - if sorted_by_dependency == True: - ifacename = iface_run_queue.pop() - else: - ifacename = iface_run_queue.popleft() - else: - if sorted_by_dependency == True: - ifacename = iface_run_queue.popleft() - else: - ifacename = iface_run_queue.pop() - - try: - self.run_iface(ifupdownobj, ifacename, operation) - except Exception, e: - self.log_error(str(e)) - - def run_iface_list_subop(self, ifupdownobj, ifacenames, op, subop, mdict, + def run_iface_list_op(self, ifupdownobj, ifacenames, op, sorted_by_dependency=False): """ Runs interface list through sub operation handler. """ - self.logger.debug('running sub operation %s on all given interfaces' - %subop) + self.logger.debug('running operation %s on all given interfaces' + %op) iface_run_queue = deque(ifacenames) for i in range(0, len(iface_run_queue)): - if op == 'up': + if op.endswith('up'): # XXX: simplify this - if sorted_by_dependency == True: + if sorted_by_dependency: ifacename = iface_run_queue.pop() else: ifacename = iface_run_queue.popleft() else: - if sorted_by_dependency == True: + if sorted_by_dependency: ifacename = iface_run_queue.popleft() else: ifacename = iface_run_queue.pop() @@ -163,21 +238,12 @@ class ifaceScheduler(ifupdownBase): try: ifaceobjs = ifupdownobj.get_iface_objs(ifacename) for ifaceobj in ifaceobjs: - if (op != 'query' and ifupdownobj.STATE_CHECK == True and - ifupdownobj.is_valid_state_transition(ifaceobj, - op) == False and ifupdownobj.FORCE == False): - if subop == 'post-down' or subop == 'post-up': - self.logger.warning('%s: ' %ifacename + - ' already %s' %op) - continue - cenv = ifupdownobj.generate_running_env(ifaceobj, op) - self.run_iface_subop(ifupdownobj, ifaceobj, op, subop, - mdict, cenv) + self.run_iface_op(ifupdownobj, ifaceobj, op, cenv) except Exception, e: self.log_error(str(e)) - def run_iface_list_stages(self, ifupdownobj, ifacenames, op, + def run_iface_list_ops(self, ifupdownobj, ifacenames, ops, sorted_by_dependency=False): """ Runs interface list through sub operations handler @@ -188,30 +254,27 @@ class ifaceScheduler(ifupdownBase): """ # Each sub operation has a module list - subopdict = ifupdownobj.operations.get(op) - for subop, mdict in subopdict.items(): - self.run_iface_list_subop(ifupdownobj, ifacenames, op, subop, mdict, - sorted_by_dependency) + [self.run_iface_list_op(ifupdownobj, ifacenames, op, + sorted_by_dependency) for op in ops] - - def run_iface_dependency_graph(self, ifupdownobj, dependency_graphs, - operation, indegrees=None, + def run_iface_dependency_graphs_sorted(self, ifupdownobj, + dependency_graphs, + ops, indegrees=None, graphsortall=False): - """ runs interface dependency graph """ - + """ runs interface dependency graph by topologically sorting the interfaces """ if indegrees is None: indegrees = OrderedDict() for ifacename in dependency_graphs.keys(): indegrees[ifacename] = ifupdownobj.get_iface_refcnt(ifacename) - if self.logger.isEnabledFor(logging.DEBUG) == True: + if self.logger.isEnabledFor(logging.DEBUG): self.logger.debug('indegree array :') self.logger.debug(ifupdownobj.pp.pformat(indegrees)) try: self.logger.debug('calling topological sort on the graph ...') - if graphsortall == True: + if graphsortall: sorted_ifacenames = graph.topological_sort_graphs_all( dependency_graphs, indegrees) else: @@ -221,14 +284,11 @@ class ifaceScheduler(ifupdownBase): raise self.logger.debug('sorted iface list = %s' %sorted_ifacenames) - - #self.run_iface_list(ifupdownobj, sorted_ifacenames, operation, - # sorted_by_dependency=True) - - self.run_iface_list_stages(ifupdownobj, sorted_ifacenames, operation, - sorted_by_dependency=True) + self.run_iface_list_ops(ifupdownobj, sorted_ifacenames, ops, + sorted_by_dependency=True) + """ Methods to execute interfaces in parallel """ def init_tokens(self, count): self.token_pool = BoundedSemaphore(count) self.logger.debug('initialized bounded semaphore with %d' %count) @@ -270,7 +330,7 @@ class ifaceScheduler(ifupdownBase): dlist, op) self.accquire_token(ifacename) except Exception, e: - if (self.ignore_error(str(e)) == True): + if self.ignore_error(str(e)): pass else: # Dont bring the iface up if children did not come up @@ -278,22 +338,14 @@ class ifaceScheduler(ifupdownBase): ' there was an error bringing %s' %op + ' dependents (%s)', str(e)) ifupdownobj.set_iface_state(ifaceobj, - ifaceState.from_str( - ifupdownobj.get_subops(op)[0]), + ifaceState.from_str(ops[0]), ifaceStatus.ERROR) return -1 - if (op != 'query' and ifupdownobj.STATE_CHECK == True and - ifupdownobj.is_valid_state_transition(ifaceobj, - op) == False and ifupdownobj.FORCE == False): - self.logger.warning('%s:' %ifacename + ' already %s' %op) - continue - - # Run all sub operations sequentially try: self.logger.debug('%s:' %ifacename + ' running sub-operations') - self.run_iface_subops(ifupdownobj, ifaceobj, op) + self.run_iface_ops(ifupdownobj, ifaceobj, op) except Exception, e: self.logger.error('%s:' %ifacename + ' error running sub operations (%s)' %str(e)) @@ -317,7 +369,7 @@ class ifaceScheduler(ifupdownBase): self.release_token(parent) except Exception, e: self.release_token(parent) - if (ifupdownobj.ignore_error(str(e)) == True): + if ifupdownobj.ignore_error(str(e)): pass else: raise Exception('error starting thread for iface %s' @@ -348,7 +400,7 @@ class ifaceScheduler(ifupdownBase): self.release_graph_token(parent) except Exception, e: self.release_graph_token(parent) - if (ifupdownobj.ignore_error(str(e)) == True): + if ifupdownobj.ignore_error(str(e)): pass else: raise Exception('error starting thread for iface %s' @@ -385,8 +437,8 @@ class ifaceScheduler(ifupdownBase): if ifupdownobj.get_iface_refcnt(ifacename) == 0: run_queue.append(ifacename) - self.logger.debug('graph roots (interfaces that dont have dependents):' + - ' %s' %str(run_queue)) + self.logger.debug('graph roots (interfaces that dont' + ' have dependents):' + ' %s' %str(run_queue)) self.init_tokens(ifupdownobj.get_njobs()) diff --git a/pkg/statemanager.py b/pkg/statemanager.py index a0ed811..5b5c174 100644 --- a/pkg/statemanager.py +++ b/pkg/statemanager.py @@ -70,8 +70,8 @@ class stateManager(): # Read all ifaces from file for ifaceobj in pickling.load(pickle_filename): self.save_ifaceobj(ifaceobj) - ifaceobj.set_refcnt(0) - ifaceobj.set_dependents(None) + #ifaceobj.set_refcnt(0) + #ifaceobj.set_dependents(None) return 0 diff --git a/sbin/ifupdown b/sbin/ifupdown index 9fc4087..4a880a5 100755 --- a/sbin/ifupdown +++ b/sbin/ifupdown @@ -18,14 +18,11 @@ def run(args, op): iflist = args.iflist if len(args.iflist) == 0: iflist = None - - cachearg=(False if (iflist is not None or - args.nocache == True or - args.perfmode == True) - else True) - logger.debug('creating ifupdown object ..') if op == 'up' or op == 'down' or op == 'reload': + cachearg=(False if (iflist or args.nocache or + args.perfmode or args.noact) + else True) ifupdown_handle = ifupdownMain(force=args.force, withdepends=args.withdepends, perfmode=args.perfmode, @@ -33,40 +30,45 @@ def run(args, op): dryrun=args.noact, cache=cachearg) elif op == 'query': + cachearg=(False if (iflist or args.nocache or + args.perfmode or args.syntaxhelp) else True) ifupdown_handle = ifupdownMain(withdepends=args.withdepends, perfmode=args.perfmode, njobs=args.jobs, - format=args.format, cache=cachearg) logger.debug('calling \'%s\'' %op + ' for all interfaces ..') if op == 'up': - ifupdown_handle.up(args.all, args.CLASS, iflist, + ifupdown_handle.up(['pre-up', 'up', 'post-up'], + args.all, args.CLASS, iflist, excludepats=args.excludepats, printdependency=args.printdependency) elif op == 'down': - ifupdown_handle.down(args.all, args.CLASS, iflist, - excludepats=args.excludepats) + ifupdown_handle.down(['pre-down', 'down', 'post-down'], + args.all, args.CLASS, iflist, + excludepats=args.excludepats, + printdependency=args.printdependency) elif op == 'query': - if args.checkcurstate == True: - qtype='query-checkcurr' - elif args.presumedstate == True: - qtype='query-presumed' - elif args.presumedstatedetailed == True: - qtype='query-presumeddetailed' - elif args.runningstate == True: + if args.checkcurstate: + qop='query-checkcurr' + elif args.runningstate: if iflist is None: iflist = [i for i in os.listdir('/sys/class/net/') - if os.path.isdir('/sys/class/net/%s' %i) == True] - qtype='query-running' - elif args.pretty == True: - qtype='query-pretty' + if os.path.isdir('/sys/class/net/%s' %i)] + qop='query-running' + elif args.raw: + qop='query-raw' + elif args.syntaxhelp: + qop = 'query-syntax' + elif args.printdependency: + qop = 'query-dependency' else: - qtype='query' + qop='query' - ifupdown_handle.query(qtype, args.all, args.CLASS, iflist, + ifupdown_handle.query([qop], args.all, args.CLASS, iflist, excludepats=args.excludepats, - printdependency=args.printdependency) + printdependency=args.printdependency, + format=args.format) elif op == 'reload': if iflist is not None: raise Exception('iflist is currently not supported with reload') @@ -157,34 +159,22 @@ def update_ifquery_argparser(argparser): group.add_argument('-r', '--running-state', dest='runningstate', action='store_true', help='query running state of an interface') - group.add_argument('-c', '--check-state', dest='checkcurstate', action='store_true', help='check running against config of an interface') - - # presumed-state is state maintained by ifupdown - group.add_argument('--presumed-state', dest='presumedstate', - action='store_true', help=argparse.SUPPRESS) - - # presumed-state-detailed prints all details about the object stored - # by ifupdown - group.add_argument('--presumed-state-detailed', - dest='presumedstatedetailed', - action='store_true', help=argparse.SUPPRESS) - - group.add_argument('--format', dest='format', default='nwifaces', - choices=['nwifaces', 'json'], help=argparse.SUPPRESS) - - group.add_argument('--pretty', action='store_true', dest='pretty', - help='pretty print config file entries') - + group.add_argument('--raw', action='store_true', dest='raw', + help='print raw config file entries') + argparser.add_argument('--format', dest='format', default='native', + choices=['native', 'json'], help=argparse.SUPPRESS) argparser.add_argument('--print-dependency', - dest='printdependency', choices=['list', 'dot'], - help=argparse.SUPPRESS) + dest='printdependency', choices=['list', 'dot'], + help='print interface dependency') + argparser.add_argument('--syntax-help', action='store_true', + dest='syntaxhelp', + help='print supported interface config syntax') def update_ifreload_argparser(argparser): update_ifupdown_argparser(argparser) - argparser.add_argument('--down-changediface', dest='downchangediface', action='store_true', help='down interfaces that have changed before bringing them up') @@ -194,7 +184,6 @@ def parse_args(argsv, op): descr = 'query interfaces (all or interface list)' else: descr = 'interface management' - argparser = argparse.ArgumentParser(description=descr) update_argparser(argparser) if op == 'up': @@ -205,7 +194,6 @@ def parse_args(argsv, op): update_ifquery_argparser(argparser) elif op == 'reload': update_ifreload_argparser(argparser) - return argparser.parse_args(argsv) def main(argv): @@ -224,28 +212,25 @@ def main(argv): print ('Unexpected executable.' + ' Should be \'ifup\' or \'ifdown\' or \'ifquery\'') exit(1) - # Command line arg parser args = parse_args(argv[1:], op) - if len(args.iflist) == 0 and args.all == False: + if not len(args.iflist) and not args.all and not args.syntaxhelp: print '\'-a\' option or interface list are required' exit(1) - - if len(args.iflist) > 0 and args.all is True: + if len(args.iflist) and args.all: print '\'-a\' option and interface list are mutually exclusive' exit(1) - init(args) run(args, op) except Exception, e: if str(e) == '': exit(1) - - if args.debug == True: + if args.debug: raise else: logger.error(str(e)) - print '\nRerun the command with \'-d\' for a detailed errormsg' + if not args.debug: + print '\nRerun the command with \'-d\' for a detailed errormsg' exit(1) finally: deinit()