]> git.proxmox.com Git - mirror_ifupdown2.git/blobdiff - pkg/ifupdownmain.py
prefix ethtool attributes with "link-" to be compatible with
[mirror_ifupdown2.git] / pkg / ifupdownmain.py
index a1cbf6a55f6a9988fcdb172ecbd4f73baf9b6945..67c1d81b705921eefd67ac0b060c9c0f948fdb61 100644 (file)
@@ -13,6 +13,8 @@ import imp
 import pprint
 import logging
 import sys, traceback
+import copy
+import json
 from statemanager import *
 from networkinterfaces import *
 from iface import *
@@ -22,14 +24,21 @@ from collections import OrderedDict
 from graph import *
 from sets import Set
 
+_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
-    UPDATE_STATEMANAGER = True
+    STATEMANAGER_ENABLE = True
+    STATEMANAGER_UPDATE = True
+    ADDONS_ENABLE = False
 
     # priv flags to mark iface objects
     BUILTIN = 0x1
@@ -37,18 +46,20 @@ class ifupdownMain(ifupdownBase):
 
     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>}
@@ -78,12 +89,12 @@ class ifupdownMain(ifupdownBase):
 
     # Handlers for ops that ifupdown2 owns
     def run_up(self, ifaceobj):
-        ifacename = ifaceobj.get_name()
+        ifacename = ifaceobj.name
         if self.link_exists(ifacename):
             self.link_up(ifacename)
 
     def run_down(self, ifaceobj):
-        ifacename = ifaceobj.get_name()
+        ifacename = ifaceobj.name
         if self.link_exists(ifacename):
             self.link_down(ifacename)
 
@@ -91,112 +102,63 @@ class ifupdownMain(ifupdownBase):
     ops_handlers = OrderedDict([('up', run_up),
                                 ('down', run_down)])
 
-
-    def run_sched_ifaceobj_posthook(self, ifaceobj):
-        if self.UPDATE_STATEMANAGER:
-            self.statemanager.ifaceobj_sync(ifaceobj)
+    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, force=False, dryrun=False, nowait=False,
+    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)
         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.module_ops.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):
-        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
+            self.STATEMANAGER_UPDATE = False
 
     def get_ifaceobjs(self, ifacename):
         return self.ifaceobjdict.get(ifacename)
@@ -207,60 +169,60 @@ class ifupdownMain(ifupdownBase):
             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:
-            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_lowerifaces(ifaceobj.get_lowerifaces())
-        ifaceobjcurr.set_priv_flags(ifaceobj.get_priv_flags())
-        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_ifaceobjs(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_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]
-
-        return ifaceobj
-
     def is_iface_builtin_byname(self, ifacename):
         """ Returns true if iface name is a builtin interface.
         
@@ -280,7 +242,7 @@ class ifupdownMain(ifupdownBase):
         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
@@ -292,7 +254,6 @@ class ifupdownMain(ifupdownBase):
 
         ifaceobj = self.get_ifaceobj_first(ifacename)
         if not ifaceobj: return True
-
         return self.is_ifaceobj_noconfig(ifaceobj)
 
     def preprocess_dependency_list(self, upperifacename, dlist, ops):
@@ -336,30 +297,34 @@ class ifupdownMain(ifupdownBase):
         dlist = None
 
         # Get dependents for interface by querying respective modules
-        for op in ops:
-            for mname in self.module_ops.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:
-                    self.logger.debug('%s: ' %ifaceobj.get_name() +
-                                'got lowerifaces/dependents: %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 not ifacenames:
             ifacenames = self.ifaceobjdict.keys()
-        self.logger.debug('populating dependency info for %s' %str(ifacenames))
+
         iqueue = deque(ifacenames)
         while iqueue:
             i = iqueue.popleft()
@@ -368,50 +333,78 @@ class ifupdownMain(ifupdownBase):
             ifaceobj = self.get_ifaceobj_first(i)
             if not ifaceobj: 
                 continue
-            dlist = ifaceobj.get_lowerifaces()
+            dlist = ifaceobj.lowerifaces
             if not dlist:
                 dlist = self.query_dependents(ifaceobj, ops)
             else:
                 continue
             if dlist:
-                self.preprocess_dependency_list(ifaceobj.get_name(),
+                self.preprocess_dependency_list(ifaceobj.name,
                                                 dlist, ops)
-                self.logger.debug('%s: lowerifaces/dependents after processing: %s'
-                                  %(i, str(dlist)))
-                ifaceobj.set_lowerifaces(dlist)
+                ifaceobj.lowerifaces = dlist
                 [iqueue.append(d) for d in dlist]
             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:
@@ -427,13 +420,13 @@ class ifupdownMain(ifupdownBase):
 
         """
         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.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):
@@ -446,10 +439,13 @@ class ifupdownMain(ifupdownBase):
                                         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
 
@@ -460,7 +456,10 @@ class ifupdownMain(ifupdownBase):
         self.module_ops['query'] = self.modules.keys()
         self.module_ops['query-raw'] = self.modules.keys()
 
-    def modules_help(self):
+
+    def _modules_help(self):
+        """ Prints addon modules supported syntax """
+
         indent = '  '
         for m, mdict in self.module_attrs.items():
             if not mdict:
@@ -484,8 +483,8 @@ class ifupdownMain(ifupdownBase):
 
                     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:
@@ -526,66 +525,20 @@ class ifupdownMain(ifupdownBase):
                 # 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)))
-
-        ifaceScheduler.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'
+    def _sched_ifaces(self, ifacenames, ops):
+        self.logger.debug('scheduling \'%s\' for %s'
                           %(str(ops), str(ifacenames)))
 
-        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 = ifaceScheduler.run_iface_dependency_graph_parallel(self,
-                        self.dependency_graph, ops)
-        else:
-            ret = ifaceScheduler.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
-
-    def print_dependency(self, ifacenames, format):
-        if ifacenames is None:
-            ifacenames = self.ifaceobjdict.keys()
+                                else ifaceSchedulerFlags.POSTORDER,
+                        followdependents=True if self.WITH_DEPENDS else False)
 
-        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
@@ -597,17 +550,16 @@ class ifupdownMain(ifupdownBase):
             if not ifaceobjs:
                 err_iface += ' ' + i
         if err_iface:
-            self.logger.error('could not find interfaces: %s' %err_iface)
-            return -1
-        return 0
+            raise Exception('cannot find interfaces:%s' %err_iface)
+        return True
 
-    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:
             for e in excludepats:
                 if re.search(e, ifacename):
@@ -619,103 +571,119 @@ class ifupdownMain(ifupdownBase):
         # We check classes first
         if allow_classes:
             for i in ifaceobjs:
-                if i.get_classes():
+                if i.classes:
                     common = Set([allow_classes]).intersection(
-                                Set(i.get_classes()))
+                                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 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 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 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)
-
-        if self.DRYRUN:
-            return
+            self.populate_dependency_info(ops)
 
-        # Update persistant iface states
         try:
-            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))
+            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):
+             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 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.UPDATE_STATEMANAGER = False
+            self.logger.debug('Looking at old state ..')
             self.read_old_iface_config()
         else:
             # If no old state available 
-            self.logger.info('old state not available. ' +
-                'Loading current iface config file')
             try:
                 self.read_iface_config()
             except Exception, e:
@@ -723,50 +691,51 @@ class ifupdownMain(ifupdownBase):
         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 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 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)
-        if self.DRYRUN:
-            return
+            self.populate_dependency_info(ops)
 
-        # Update persistant iface states
         try:
-            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))
+            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.UPDATE_STATEMANAGER = False
+        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
@@ -778,10 +747,9 @@ class ifupdownMain(ifupdownBase):
             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 not ifacenames: ifacenames = self.ifaceobjdict.keys()
@@ -791,13 +759,13 @@ class ifupdownMain(ifupdownBase):
             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 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
@@ -807,10 +775,7 @@ class ifupdownMain(ifupdownBase):
         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)
@@ -821,51 +786,44 @@ class ifupdownMain(ifupdownBase):
             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 self.statemanager.get_ifaceobjdict():
             # 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.UPDATE_STATEMANAGER = False
             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 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
@@ -874,96 +832,78 @@ class ifupdownMain(ifupdownBase):
             #     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:
                 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)
-                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))
+                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)
+        self._sched_ifaces(filtered_ifacenames, upops)
         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))
+        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_ifaceobjs(i):
                 if (self.is_ifaceobj_builtin(ifaceobj) or 
@@ -971,78 +911,98 @@ class ifupdownMain(ifupdownBase):
                     continue
                 ifaceobj.dump_raw(self.logger)
                 print '\n'
-                if self.WITH_DEPENDS:
-                    dlist = ifaceobj.get_lowerifaces()
+                if self.WITH_DEPENDS and not self.ALL:
+                    dlist = ifaceobj.lowerifaces
                     if not dlist: continue
-                    self.print_ifaceobjs_pretty(dlist, format)
+                    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_ifaceobjs(i):
-                if (self.is_ifaceobj_noconfig(ifaceobj)):
+                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()
-                if self.WITH_DEPENDS:
-                    dlist = ifaceobj.get_lowerifaces()
+                ifaceobjs.append(ifaceobj)
+                if self.WITH_DEPENDS and not self.ALL:
+                    dlist = ifaceobj.lowerifaces
                     if not dlist: continue
-                    self.print_ifaceobjs_pretty(dlist, format)
+                    self._get_ifaceobjs_pretty(dlist, ifaceobjs, running)
 
-    def dump_ifaceobjs(self, ifacenames):
+    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 _get_ifaceobjscurr_pretty(self, ifacenames, ifaceobjs):
+        ret = 0
         for i in ifacenames:
-            ifaceobjs = self.get_ifaceobjs(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 %s\n' %(ifaceobj.get_name(),
-                            ifaceStatus.to_str(ifaceStatus.NOTFOUND))
-                ret = 1
-                continue
-            elif ifaceobj.get_status() == ifaceStatus.ERROR:
-                ret = 1
-
-            if (self.is_ifaceobj_noconfig(ifaceobj)):
-                continue
 
-            if format == 'json':
-                ifaceobj.dump_json(with_status=True)
-            else:
-                ifaceobj.dump_pretty(with_status=True)
-
-            if self.WITH_DEPENDS:
-                dlist = ifaceobj.get_lowerifaces()
-                if not 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'):
+        """ 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 _dump(self):
+        print 'ifupdown main object dump'
+        print self.pp.pprint(self.modules)
+        print self.pp.pprint(self.ifaceobjdict)
+
+    def _dump_ifaceobjs(self, ifacenames):
         for i in ifacenames:
-            ifaceobj = self.get_ifaceobj_first(i)
-            if ifaceobj.get_status() == ifaceStatus.NOTFOUND:
-                print 'iface %s' %ifaceobj.get_name() + ' (not found)\n'
-                continue
-            if 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: continue
-                self.print_ifaceobjsrunning_pretty(dlist, format)
-        return
+            ifaceobjs = self.get_ifaceobjs(i)
+            for i in ifaceobjs:
+                i.dump(self.logger)
+                print '\n'