]> git.proxmox.com Git - mirror_ifupdown2.git/commitdiff
more fixes + cleanup + support for --exclude argument
authorroopa <roopa@cumulusnetworks.com>
Thu, 14 Nov 2013 00:07:15 +0000 (16:07 -0800)
committerroopa <roopa@cumulusnetworks.com>
Thu, 14 Nov 2013 00:07:15 +0000 (16:07 -0800)
Ticket: CM-1438
Reviewed By:
Testing Done:

16 files changed:
KNOWN_ISSUES
TODO
debian/python-ifupdown2.postrm
init.d/networking
pkg/exceptions.py
pkg/graph.py
pkg/iface.py
pkg/ifupdown_main.py [deleted file]
pkg/ifupdownbase.py
pkg/ifupdownmain.py [new file with mode: 0644]
pkg/log.py [deleted file]
pkg/networkinterfaces.py
pkg/scheduler.py
pkg/statemanager.py
sbin/ifupdown
setup.py

index eeae802fd17cd57d7ef6a3cdd12bc84d031275fb..f1bbff94feca0b1114503468d67518777d6f7748 100644 (file)
@@ -1,4 +1,4 @@
-- Some state issues if multiple interfaces for the same interface config blocks are present for the same interface
+- There is a state issue if multiple configuration blocks are present for the same interface in the interfaces file
 - `ifquery -r` can give wrong result if dhclient is running + static addresses are configured
 - `ifquery -r` status is success for success case and also for cases where there
 is no support for query yet
diff --git a/TODO b/TODO
index 053fb5491e272de778d7b6b460db5bde98effced..e58ab08bda1763981cbfd11ae3a178b878f4de99 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,5 +1,9 @@
 TODO:
 ====
+- update man-pages with new options. Convert them to rst
+- ifup hotplug support (basically needs some testing and fixing broken things)
+- syslog support
+- -q quiet option
 - support for /etc/networking.defaults
 - implement legacy ifupdown mapping feature
 - support for the following ifupdown options:
index 19028b2c1748a1e6436fa77c5cb69b1d1b0e20c7..42651bcc4955fd662490142c3322171d5b95b0db 100644 (file)
@@ -2,6 +2,8 @@
 
 set -e
 
+rm -f /sbin/ifup /sbin/ifdown /sbin/ifquery
+
 case "$1" in
   purge)
     # Note: We don't remove /etc/network/interfaces
index 79278aab27b5a66463e5037d9a5c8b51cb194ac9..b412f5684309f7ffda90ca1b3d8840162ee0e37b 100644 (file)
@@ -96,7 +96,7 @@ check_network_swap() {
 ifup_hotplug () {
     if [ -d /sys/class/net ]
     then
-           ifaces=$(for iface in $(ifquery --list --allow=hotplug)
+           ifaces=$(for iface in $(ifquery --list --allow=hotplug 2>/dev/null)
                            do
                                    link=${iface##:*}
                                    link=${link##.*}
@@ -170,7 +170,7 @@ force-reload|restart)
        fi
        process_options
 
-       log_warning_msg "Running $0 $1 is deprecated because it may not re-enable some interfaces"
+       #log_warning_msg "Running $0 $1 is deprecated because it may not re-enable some interfaces"
        log_action_begin_msg "Reconfiguring network interfaces"
        ifdown -a --exclude=lo $verbose || true
        set -f
index b870273241a8f3e71999f890ce48340188c82215..2d4e0b2330b3a626638dd59e0ca4a771833ac614 100644 (file)
@@ -1,5 +1,11 @@
 #!/usr/bin/python
-
+#
+# Copyright 2013.  Cumulus Networks, Inc.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# ifupdown --
+#    exceptions
+#
 
 class Error(Exception):
     """Base class for exceptions in ifupdown"""
index 5026e4d8464767873eb9d0f83cc59d518133bb30..8a784bb41647471b0b8a33d1f5903931232b7810 100644 (file)
@@ -1,4 +1,11 @@
 #!/usr/bin/python
+#
+# Copyright 2013.  Cumulus Networks, Inc.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# graph --
+#    graph helper module for ifupdown
+#
 
 import logging
 from collections import deque
@@ -38,6 +45,7 @@ class graph():
         # If some indegrees are non zero, we have a cycle
         for ifname,indegree in indegrees.items():
             if indegree != 0:
-                raise Exception('cycle found involving iface %s' %ifname)
+                raise Exception('cycle found involving iface %s' %ifname +
+                                ' (indegree %d)' %indegree)
 
         return S
index e6a56028e11e5bdb117442be888e462c88b62ae3..5840306f9d6e06eda6dbd348285083e7ec66e225 100644 (file)
@@ -1,4 +1,11 @@
 #!/usr/bin/python
+#
+# Copyright 2013.  Cumulus Networks, Inc.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# iface --
+#    interface object
+#
 
 import logging
 
@@ -158,7 +165,12 @@ class iface():
     def get_classes(self):
         return self.classes
 
-    def set_classes(self, classname):
+    def set_classes(self, classes):
+        """ sets interface class list to the one passed as arg """
+        self.classes = classes
+
+    def set_class(self, classname):
+        """ Appends a class to the list """
         self.classes.append(classname)
 
     def belongs_to_class(self, intfclass):
@@ -209,49 +221,6 @@ class iface():
     def get_linkstate(self):
         return self.linkstate
 
-    def run_children(self, stage, module_list, force=0):
-
-        if (self.is_flag_on(ifaceFlags.FOLLOW_DEPENDENTS)
-                == False):
-            return
-
-        for c in self.children:
-            self.set_flag(
-                ifaceFlags.FOLLOW_DEPENDENTS)
-            ret = c.run(stage, module_list, force)
-            self.clear_flag(
-                ifaceFlags.FOLLOW_DEPENDENTS)
-
-            if ret != 0:
-                self.set_state(stage, ret)
-                if force == 0:
-                    break
-
-        return ret
-
-    def run(self, stage, module_list, force=0):
-        ret = 0
-        err = 0
-
-        ret = self.run_children()
-
-        if ret != 0 and force == 0:
-            return ret
-            
-        for m in module_list:
-            ret = m.run(self, stage, force)
-            if ret != 0:
-                self.set_state(stage, ret)
-
-                # If no force, return!
-                if force == 0:
-                    return -1
-                err += 1
-            else:
-                self.set_state(stage, ret)
-
-        return ret
-
     def get_attr_value(self, attr_name):
         config = self.get_config()
 
diff --git a/pkg/ifupdown_main.py b/pkg/ifupdown_main.py
deleted file mode 100644 (file)
index 335e792..0000000
+++ /dev/null
@@ -1,695 +0,0 @@
-#!/usr/bin/python
-
-import os
-import re
-from statemanager import *
-from networkinterfaces import *
-from iface import *
-from scheduler import *
-from collections import deque
-from collections import OrderedDict
-import imp
-import pprint
-import logging
-from graph import *
-import sys, traceback
-
-class ifupdown_main():
-
-    # Flags
-    NODEPENDS = False
-    ALL = False
-    STATE_CHECK = False
-
-    modules_dir='/etc/network'
-    builtin_modules_dir='/usr/share/ifupdownaddons'
-
-    # iface dictionary in the below format:
-    # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
-    # eg:
-    # { 'swp1' : [<ifaceobject1>, <ifaceobject2> ..] }
-    #
-    # Each ifaceobject corresponds to a configuration block for
-    # that interface
-    ifaceobjdict = OrderedDict()
-
-
-    # iface dictionary representing the curr running state of an iface
-    # in the below format:
-    # {'<ifacename>' : <ifaceobject>}
-    ifaceobjcurrdict = OrderedDict()
-
-    # Dictionary representing operation, sub operation and modules
-    # for every sub operation
-    operations = { 'up' :
-                    OrderedDict([('pre-up', OrderedDict({})),
-                                 ('up' , OrderedDict({})),
-                                 ('post-up' , OrderedDict({}))]),
-                   'down' :
-                    OrderedDict([('pre-down', OrderedDict({})),
-                                 ('down' , OrderedDict({})),
-                                 ('post-down' , OrderedDict({}))])}
-
-
-    def __init__(self, force=False, dryrun=False, nowait=False,
-                 perfmode=False, nodepends=False, njobs=1):
-        self.logger = logging.getLogger('ifupdown')
-
-        self.FORCE = force
-        self.DRYRUN = dryrun
-        self.NOWAIT = nowait
-        self.PERFMODE = perfmode
-        self.NODEPENDS = nodepends
-
-        self.ifaces = OrderedDict()
-        self.njobs = njobs
-        self.pp = pprint.PrettyPrinter(indent=4)
-        self.load_modules_builtin(self.builtin_modules_dir)
-        self.load_modules(self.modules_dir)
-
-        try:
-            self.statemanager = stateManager()
-            self.statemanager.read_saved_state()
-        except Exception, e:
-            # XXX Maybe we should continue by ignoring old state
-            self.logger.warning('error reading state (%s)' %str(e))
-            raise
-
-    def get_subops(self, op):
-        """ Returns sub-operation list """
-        return self.operations.get(op).keys()
-
-    def compat_conv_op_to_mode(self, op):
-        """ Returns old op name to work with existing scripts """
-        if op == 'up':
-            return 'start'
-        elif op == '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):
-        """ return force flag. """
-        return self.FORCE
-
-    def set_dryrun(self, dryrun):
-        if dryrun == True:
-            self.logger.debug('setting dryrun to true')
-        self.DRYRUN = dryrun
-
-    def get_dryrun(self):
-        return self.DRYRUN
-
-    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):
-        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 ignore_error(self, errmsg):
-        if (self.FORCE == True or re.search(r'exists', errmsg,
-            re.IGNORECASE | re.MULTILINE) is not None):
-            return True
-        return False
-
-    def get_nodepends(self):
-        return self.NODEPENDS
-
-    def set_nodepends(self, nodepends):
-        self.logger.debug('setting nodepends to true')
-        self.NODEPENDS = nodepends
-
-    def set_iface_state(self, ifaceobj, state, status):
-        ifaceobj.set_state(state)
-        ifaceobj.set_status(status)
-        self.statemanager.update_iface_state(ifaceobj)
-
-    def get_iface_objs(self, ifacename):
-        return self.ifaceobjdict.get(ifacename)
-
-    def get_iface_obj_first(self, ifacename):
-        ifaceobjs = self.get_iface_objs(ifacename)
-        if ifaceobjs is not None:
-            return ifaceobjs[0]
-        return None
-
-    def get_iface_obj_last(self, ifacename):
-        return self.ifaceobjdict.get(ifacename)[-1]
-
-    def create_ifaceobjcurr(self, ifacename):
-        ifaceobj = self.get_ifaceobjcurr(ifacename)
-        if ifaceobj is not None:
-            return ifaceobj
-
-        ifaceobj = iface()
-        ifaceobj.set_name(ifacename)
-        self.ifaceobjcurrdict[ifacename] = ifaceobj
-
-        return ifaceobj
-
-    def get_ifaceobjcurr(self, ifacename):
-        return self.ifaceobjcurrdict.get(ifacename)
-
-    def get_iface_status(self, ifacename):
-        ifaceobjs = self.get_iface_objs(ifacename)
-        for i in ifaceobjs:
-            if i.get_status() != ifaceStatus.SUCCESS:
-                return i.get_status()
-
-        return ifaceStatus.SUCCESS
-
-    def get_iface_refcnt(self, ifacename):
-        max = 0
-        ifaceobjs = self.get_iface_objs(ifacename)
-        for i in ifaceobjs:
-            if i.get_refcnt() > max:
-                max = i.get_refcnt()
-        return max
-
-    def create_fake_vlan_iface(self, vlan_ifname, op):
-        """ creates and returns a fake vlan iface object.
-
-        This was added to support creation of simple vlan devices without any
-        user specified configuration.
-
-        """
-
-        # XXX: Ideally this should be a call-back into the vlan module.
-        vlan_iface_obj = iface()
-        vlan_iface_obj.set_name(vlan_ifname)
-        vlan_iface_obj.set_dependents(self.get_dependents(vlan_iface_obj, op))
-
-        return vlan_iface_obj
-
-    def is_vlan_device(self, ifacename):
-        """ Returns true if iface name is a vlan interface.
-        
-        only supports vlan interfaces of the format <ifacename>.<vlanid>
-        
-        """
-        if (re.search(r'\.', ifacename, 0) is not None):
-            return True
-        return False
-
-    def preprocess_dependency_list(self, dlist, op):
-        del_list = []
-
-        self.logger.debug('pre-processing dependency list: %s' %list(dlist))
-        for d in dlist:
-            dilist = self.get_iface_objs(d)
-            if dilist == None:
-                if self.is_vlan_device(d) == True:
-                    vlan_iface_obj = self.create_fake_vlan_iface(d, op)
-
-                    # Add face vlan device to ifaceobjdict dict
-                    vlan_iface_obj.inc_refcnt()
-                    self.save_iface(vlan_iface_obj)
-                else:
-                    # Remove the device from the list
-                    del_list.append(d)
-            else:
-                for di in dilist:
-                    di.inc_refcnt()
-
-        for d in del_list:
-            dlist.remove(d)
-
-        self.logger.debug('After Processing dependency list: %s'
-            %list(dlist))
-
-
-    def get_dependents(self, ifaceobj, op):
-        """ Gets iface dependents by calling into respective modules """
-        dlist = None
-
-        self.logger.debug('%s: ' %ifaceobj.get_name() + 'getting dependency')
-
-        # Get dependents for interface by querying respective modules
-        subopdict = self.operations.get(op)
-        for subop, mdict in subopdict.items():
-            for mname, mdata  in mdict.items():
-                if mdata.get('ftype') == 'pmodule':
-                    module = mdata.get('module')
-                    if (hasattr(module,
-                        'get_dependent_ifacenames') == False):
-                        continue
-                    dlist = module.get_dependent_ifacenames(ifaceobj,
-                                    self.ifaceobjdict.keys())
-                    if dlist:
-                        self.logger.debug('%s: ' %ifaceobj.get_name() +
-                                'got dependency list: %s' %str(dlist))
-                        break
-
-        return dlist
-
-    
-    def generate_dependency_info(self, ifacenames, dependency_graph, op):
-        """ recursive function to generate iface dependency info """
-
-        self.logger.debug('generating dependency info for %s' %str(ifacenames))
-
-        for i in ifacenames:
-            # Go through all modules and find dependent ifaces
-            dlist = None
-            ifaceobj = self.get_iface_obj_first(i)
-            if ifaceobj is None: 
-                continue
-
-            dlist = ifaceobj.get_dependents()
-            if dlist is None:
-                dlist = self.get_dependents(ifaceobj, op)
-
-            if dlist is not None:
-                self.preprocess_dependency_list(dlist, op)
-                ifaceobj.set_dependents(dlist)
-
-            if dependency_graph.get(i) is None:
-                dependency_graph[i] = dlist
-
-            if dlist is not None:
-                self.generate_dependency_info(dlist,
-                         dependency_graph, op)
-
-
-    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:
-            self.ifaceobjdict[ifaceobj.get_name()] = [ifaceobj]
-        else:
-            self.ifaceobjdict[ifaceobj.get_name()].append(ifaceobj)
-
-    def read_default_iface_config(self):
-        """ Reads default network interface config /etc/network/interfaces. """
-        nifaces = networkInterfaces()
-        nifaces.subscribe('iface_found', self.save_iface)
-        nifaces.load()
-
-    def read_iface_config(self):
-        return self.read_default_iface_config()
-
-    def read_old_iface_config(self):
-        """ Reads the saved iface config instead of default iface config. """
-
-        # Read it from the statemanager
-        self.ifaceobjdict = self.statemanager.get_ifaceobjdict()
-
-
-    def 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)
-        
-        """
-
-        mmetadata = self.operations[mkind][msubkind].get(mname)
-        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_modules_builtin(self, modules_dir):
-        """ load python modules from modules_dir
-
-        Default modules_dir is /usr/share/ifupdownmodules
-
-        """
-
-        self.logger.info('loading builtin modules from %s' %modules_dir)
-
-        if not modules_dir in sys.path:
-                sys.path.append(modules_dir)
-        try:
-            module_list = os.listdir(modules_dir)
-            for module in module_list:
-                if re.search('.*\.pyc', module, 0) != None:
-                    continue
-
-                mname, mext = os.path.splitext(module)
-                if mext is not None and mext == '.py':
-                    self.logger.info('loading ' + modules_dir + '/' + module)
-                    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())
-                    ops = minstance.get_ops()
-                    for op in ops:
-                        if re.search('up', op) is not None:
-                            self.save_module('up', op, mname, 'pmodule',
-                                             minstance)
-                        else:
-                            self.save_module('down', op, mname, 'pmodule',
-                                             minstance)
-        except: 
-            raise
-
-
-    def load_modules(self, modules_dir):
-        """ loading user modules from /etc/network/.
-
-        Note that previously loaded python modules override modules found
-        under /etc/network if any
-
-        """
-
-        self.logger.info('loading user modules from %s' %modules_dir)
-        for op, subops in self.operations.items():
-            for subop in subops.keys():
-                msubdir = modules_dir + '/if-%s.d' %subop
-                self.logger.info('loading modules under %s ...' %msubdir)
-                try:
-                    module_list = os.listdir(msubdir)
-                    for module in module_list:
-                        if re.search('.*\.pyc', module, 0) != None:
-                            continue
-
-                        mname, mext = os.path.splitext(module)
-                        if mext is not None and mext == '.py':
-                            self.logger.debug('loading ' + msubdir + '/' + module)
-                            try:
-                                m = imp.load_source(module,
-                                        msubdir + '/' + module)
-                                mclass = getattr(m, mname)
-                            except:
-                                raise
-                            minstance = mclass()
-                            self.save_module(op, subop, mname, 'pmodule',
-                                                minstance)
-                        else:
-                            self.save_module(op, subop, mname, 'script',
-                                    msubdir + '/' + module)
-                except: 
-                    raise
-
-        #self.logger.debug('modules ...')
-        #self.pp.pprint(self.operations)
-
-        # For query, we add a special entry, basically use all 'up' modules
-        self.operations['query'] = self.operations.get('up')
-
-
-    def conv_iface_namelist_to_objlist(self, intf_list):
-        for intf in intf_list:
-            iface_obj = self.get_iface(intf)
-            if iface_obj == None:
-                raise ifupdownInvalidValue('no iface %s', intf)
-
-            iface_objs.append(iface_obj)
-
-        return iface_objs
-
-
-    def run_without_dependents(self, op, ifacenames):
-        ifaceSched = ifaceScheduler()
-
-        self.logger.debug('run_without_dependents for op %s' %op +
-                ' for %s' %str(ifacenames))
-
-        if ifacenames == None:
-            raise ifupdownInvalidValue('no interfaces found')
-
-        return ifaceSched.run_iface_list(self, ifacenames, op)
-
-
-    def run_with_dependents(self, op, ifacenames):
-        dependency_graph = {}
-        ret = 0
-        self.logger.debug('run_with_dependents for op %s'
-                          %op + ' for %s' %str(ifacenames))
-
-        ifaceSched = ifaceScheduler()
-
-        if ifacenames is None:
-            ifacenames = self.ifaceobjdict.keys()
-
-        # generate dependency graph of interfaces
-        self.generate_dependency_info(ifacenames, dependency_graph, op)
-
-        if self.logger.isEnabledFor(logging.DEBUG) == True:
-            self.logger.debug('dependency graph:')
-            self.pp.pprint(dependency_graph)
-
-        if self.njobs > 1:
-            ret = ifaceSched.run_iface_dependency_graph_parallel(self,
-                        dependency_graph, op)
-        else:
-            ret = ifaceSched.run_iface_dependency_graph(self, dependency_graph,
-                        op)
-
-        return ret
-
-
-    def validate_ifaces(self, ifacenames):
-        """ validates interface list for config existance.
-       
-        returns -1 if one or more interface not found. else, returns 0
-
-        """
-
-        err_iface = ''
-        for i in ifacenames:
-            ifaceobjs = self.get_iface_objs(i)
-            if ifaceobjs is None:
-                err_iface += ' ' + i
-
-        if len(err_iface) != 0:
-            self.logger.error('did not find interfaces: %s' %err_iface)
-            return -1
-
-        return 0
-
-
-    def iface_whitelisted(self, auto, allow_classes, ifacename):
-        """ Checks if interface is whitelisted depending on set of parameters.
-
-
-        interfaces are checked against the allow_classes and auto lists.
-
-        """
-
-        self.logger.debug('checking if iface %s' %ifacename +
-                ' is whitelisted')
-
-        ifaceobjs = self.get_iface_objs(ifacename)
-        if ifaceobjs is None:
-            self.logger.debug('iface %s' %ifacename + ' not found')
-            return False
-
-        # We check classes first
-        if allow_classes is not None and len(allow_classes) > 0:
-            for i in ifaceobjs:
-                if (len(i.get_classes()) > 0):
-                    common = Set(allow_classes).intersection(
-                                Set(i.get_classes()))
-                    if len(common) > 0:
-                        return True
-            return False
-
-        if auto == True:
-            for i in ifaceobjs:
-                if i.get_auto() == True:
-                    return True
-            return False
-
-        return True
-
-    def generate_running_env(self, ifaceobj, op):
-        """ Generates a dictionary with env variables required for an interface.
-
-        Used to support script execution for interfaces.
-
-        """
-
-        cenv = None
-        iface_env = ifaceobj.get_env()
-        if iface_env is not None:
-            cenv = os.environ
-            if cenv is not None:
-                cenv.update(iface_env)
-            else:
-                cenv = iface_env
-
-            cenv['MODE'] = self.compat_conv_op_to_mode(op)
-
-        return cenv
-
-
-    def run(self, op, auto=False, allow_classes=None,
-            ifacenames=None, query_state=None):
-        """ main ifupdown run method """
-
-        if auto == True:
-            self.logger.debug('setting flag ALL')
-            self.ALL = True
-
-        # Only read new iface config for 'up'
-        # operations. For 'downs' we only rely on
-        # old state
-        if op == 'up' or op == 'query':
-            try:
-                self.read_iface_config()
-            except Exception, e:
-                raise
-        else:
-            # 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')
-
-
-        if ifacenames is not None:
-            # If iface list is given, always check if iface is present
-           if self.validate_ifaces(ifacenames) != 0:
-               raise Exception('all or some interfaces not found')
-
-        # if iface list not given by user, assume all from config file
-        if ifacenames is None: ifacenames = self.ifaceobjdict.keys()
-
-        # filter interfaces based on auto and allow classes
-        filtered_ifacenames = [i for i in ifacenames
-             if self.iface_whitelisted(auto, allow_classes, i) == True]
-
-        if len(filtered_ifacenames) == 0:
-                raise Exception('no ifaces found matching ' +
-                        'given allow lists')
-
-        if op == 'query':
-            if query_state == None:
-                return self.print_ifaceobjs_pretty(filtered_ifacenames)
-            elif query_state == 'presumed':
-                return self.print_ifaceobjs_saved_state_pretty(
-                                    filtered_ifacenames)
-            elif query_state == 'presumeddetailed':
-                return self.print_ifaceobjs_saved_state_detailed_pretty(
-                                    filtered_ifacenames)
-
-        if op == 'query' or self.NODEPENDS == True:
-            self.run_without_dependents(op, filtered_ifacenames)
-        else:
-            self.run_with_dependents(op, filtered_ifacenames)
-
-        if op == 'query':
-            if query_state == 'curr':
-                # print curr state of all interfaces
-                ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames)
-                if ret != 0:
-                    # if any of the object has an error, signal that silently
-                    raise Exception('')
-            return
-
-        # Update persistant iface states
-        try:
-            if self.ALL == True:
-                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 up(self, auto=False, allow=None, ifacenames=None):
-        return self.run('up', auto, allow, ifacenames)
-
-    def down(self, auto=False, allow=None, ifacenames=None):
-        return self.run('down', auto, allow, ifacenames);
-
-    def query(self, auto=False, allow=None, ifacenames=None,
-              query_state=False):
-        return self.run('query', auto, allow, ifacenames,
-                        query_state=query_state);
-
-    def dump(self):
-        """ all state dump """
-
-        print 'ifupdown object dump'
-        print self.pp.pprint(self.modules)
-        print self.pp.pprint(self.ifaces)
-        self.state_manager.dump()
-
-    def print_state(self, ifacenames=None):
-        self.statemanager.dump(ifacenames)
-
-    def print_ifaceobjs_pretty(self, ifacenames):
-        for i in ifacenames:
-            ifaceobjs = self.get_iface_objs(i)
-            for io in ifaceobjs:
-                io.dump_raw(self.logger)
-                print '\n'
-
-    def print_ifaceobjscurr_pretty(self, ifacenames):
-        """ Dumps current running state of interfaces.
-
-        returns 1 if any of the interface has an error,
-        else returns 0
-
-        """
-
-        ret = 0
-        for i in ifacenames:
-            ifaceobj = self.get_ifaceobjcurr(i)
-            ifaceobj.dump_pretty(self.logger)
-            if ifaceobj.get_status() == ifaceStatus.ERROR:
-                ret = 1
-
-        return ret
-
-    def print_ifaceobjs_saved_state_pretty(self, ifacenames):
-        self.statemanager.print_state_pretty(ifacenames, self.logger)
-
-    def print_ifaceobjs_saved_state_detailed_pretty(self, ifacenames):
-        self.statemanager.print_state_detailed_pretty(ifacenames, self.logger)
index 61abc63b08e0dfb68c489e8bd6737ff3a62acc4e..d1d0d0209da37e354b37bd47fa65de82ba30c3ae 100644 (file)
@@ -1,4 +1,11 @@
 #!/usr/bin/python
+#
+# Copyright 2013.  Cumulus Networks, Inc.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# ifupdownBase --
+#    base object for various ifupdown objects
+#
 
 import logging
 import subprocess
@@ -33,3 +40,23 @@ class ifupdownBase(object):
                 '\n(' + cmdout.strip('\n ') + ')')
 
         return cmdout
+
+    def ignore_error(self, errmsg):
+        if (self.FORCE == True or re.search(r'exists', errmsg,
+            re.IGNORECASE | re.MULTILINE) is not None):
+            return True
+        return False
+
+    def log_warn(self, str):
+        if self.ignore_error(str) == False:
+            if self.logger.getEffectiveLevel() == logging.DEBUG:
+                traceback.print_stack()
+            self.logger.warn(str)
+        pass
+
+    def log_error(self, str):
+        if self.ignore_error(str) == False:
+            raise Exception(str)
+        else:
+            pass
+
diff --git a/pkg/ifupdownmain.py b/pkg/ifupdownmain.py
new file mode 100644 (file)
index 0000000..0c4695f
--- /dev/null
@@ -0,0 +1,701 @@
+#!/usr/bin/python
+#
+# Copyright 2013.  Cumulus Networks, Inc.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# ifupdownMain --
+#    ifupdown main module
+#
+
+import os
+import re
+import imp
+import pprint
+import logging
+import sys, traceback
+from statemanager import *
+from networkinterfaces import *
+from iface import *
+from scheduler import *
+from collections import deque
+from collections import OrderedDict
+from graph import *
+from sets import Set
+
+class ifupdownMain():
+
+    # Flags
+    NODEPENDS = False
+    ALL = False
+    STATE_CHECK = False
+
+    modules_dir='/etc/network'
+    builtin_modules_dir='/usr/share/ifupdownaddons'
+
+    # iface dictionary in the below format:
+    # { '<ifacename>' : [<ifaceobject1>, <ifaceobject2> ..] }
+    # eg:
+    # { 'swp1' : [<ifaceobject1>, <ifaceobject2> ..] }
+    #
+    # Each ifaceobject corresponds to a configuration block for
+    # that interface
+    ifaceobjdict = OrderedDict()
+
+
+    # iface dictionary representing the curr running state of an iface
+    # in the below format:
+    # {'<ifacename>' : <ifaceobject>}
+    ifaceobjcurrdict = OrderedDict()
+
+    # Dictionary representing operation, sub operation and modules
+    # for every sub operation
+    operations = { 'up' :
+                    OrderedDict([('pre-up', OrderedDict({})),
+                                 ('up' , OrderedDict({})),
+                                 ('post-up' , OrderedDict({}))]),
+                   'down' :
+                    OrderedDict([('pre-down', OrderedDict({})),
+                                 ('down' , OrderedDict({})),
+                                 ('post-down' , OrderedDict({}))])}
+
+
+    def __init__(self, force=False, dryrun=False, nowait=False,
+                 perfmode=False, nodepends=False, njobs=1):
+        self.logger = logging.getLogger('ifupdown')
+
+        self.FORCE = force
+        self.DRYRUN = dryrun
+        self.NOWAIT = nowait
+        self.PERFMODE = perfmode
+        self.NODEPENDS = nodepends
+
+        self.ifaces = OrderedDict()
+        self.njobs = njobs
+        self.pp = pprint.PrettyPrinter(indent=4)
+        self.load_modules_builtin(self.builtin_modules_dir)
+        self.load_modules(self.modules_dir)
+
+        try:
+            self.statemanager = stateManager()
+            self.statemanager.read_saved_state()
+        except Exception, e:
+            # XXX Maybe we should continue by ignoring old state
+            self.logger.warning('error reading state (%s)' %str(e))
+            raise
+
+    def get_subops(self, op):
+        """ Returns sub-operation list """
+        return self.operations.get(op).keys()
+
+    def compat_conv_op_to_mode(self, op):
+        """ Returns old op name to work with existing scripts """
+        if op == 'up':
+            return 'start'
+        elif op == '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):
+        """ return force flag. """
+        return self.FORCE
+
+    def set_dryrun(self, dryrun):
+        if dryrun == True:
+            self.logger.debug('setting dryrun to true')
+        self.DRYRUN = dryrun
+
+    def get_dryrun(self):
+        return self.DRYRUN
+
+    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):
+        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_nodepends(self):
+        return self.NODEPENDS
+
+    def set_nodepends(self, nodepends):
+        self.logger.debug('setting nodepends to true')
+        self.NODEPENDS = nodepends
+
+    def set_iface_state(self, ifaceobj, state, status):
+        ifaceobj.set_state(state)
+        ifaceobj.set_status(status)
+        self.statemanager.update_iface_state(ifaceobj)
+
+    def get_iface_objs(self, ifacename):
+        return self.ifaceobjdict.get(ifacename)
+
+    def get_iface_obj_first(self, ifacename):
+        ifaceobjs = self.get_iface_objs(ifacename)
+        if ifaceobjs is not None:
+            return ifaceobjs[0]
+        return None
+
+    def get_iface_obj_last(self, ifacename):
+        return self.ifaceobjdict.get(ifacename)[-1]
+
+    def create_ifaceobjcurr(self, ifacename):
+        ifaceobj = self.get_ifaceobjcurr(ifacename)
+        if ifaceobj is not None:
+            return ifaceobj
+
+        ifaceobj = iface()
+        ifaceobj.set_name(ifacename)
+        self.ifaceobjcurrdict[ifacename] = ifaceobj
+
+        return ifaceobj
+
+    def get_ifaceobjcurr(self, ifacename):
+        return self.ifaceobjcurrdict.get(ifacename)
+
+    def get_iface_status(self, ifacename):
+        ifaceobjs = self.get_iface_objs(ifacename)
+        for i in ifaceobjs:
+            if i.get_status() != ifaceStatus.SUCCESS:
+                return i.get_status()
+
+        return ifaceStatus.SUCCESS
+
+    def get_iface_refcnt(self, ifacename):
+        max = 0
+        ifaceobjs = self.get_iface_objs(ifacename)
+        for i in ifaceobjs:
+            if i.get_refcnt() > max:
+                max = i.get_refcnt()
+        return max
+
+    def create_fake_vlan_iface(self, vlan_ifname, op):
+        """ creates and returns a fake vlan iface object.
+
+        This was added to support creation of simple vlan devices without any
+        user specified configuration.
+
+        """
+
+        # XXX: Ideally this should be a call-back into the vlan module.
+        vlan_iface_obj = iface()
+        vlan_iface_obj.set_name(vlan_ifname)
+        vlan_iface_obj.set_dependents(self.get_dependents(vlan_iface_obj, op))
+
+        return vlan_iface_obj
+
+    def is_vlan_device(self, ifacename):
+        """ Returns true if iface name is a vlan interface.
+        
+        only supports vlan interfaces of the format <ifacename>.<vlanid>
+        
+        """
+        if (re.search(r'\.', ifacename, 0) is not None):
+            return True
+        return False
+
+    def preprocess_dependency_list(self, dlist, op):
+        del_list = []
+
+        self.logger.debug('pre-processing dependency list: %s' %list(dlist))
+        for d in dlist:
+            dilist = self.get_iface_objs(d)
+            if dilist == None:
+                if self.is_vlan_device(d) == True:
+                    vlan_iface_obj = self.create_fake_vlan_iface(d, op)
+
+                    # Add face vlan device to ifaceobjdict dict
+                    vlan_iface_obj.inc_refcnt()
+                    self.save_iface(vlan_iface_obj)
+                else:
+                    # Remove the device from the list
+                    del_list.append(d)
+            else:
+                for di in dilist:
+                    di.inc_refcnt()
+
+        for d in del_list:
+            dlist.remove(d)
+
+        self.logger.debug('After Processing dependency list: %s'
+            %list(dlist))
+
+
+    def get_dependents(self, ifaceobj, op):
+        """ Gets iface dependents by calling into respective modules """
+        dlist = None
+
+        self.logger.debug('%s: ' %ifaceobj.get_name() + 'getting dependency')
+
+        # Get dependents for interface by querying respective modules
+        subopdict = self.operations.get(op)
+        for subop, mdict in subopdict.items():
+            for mname, mdata  in mdict.items():
+                if mdata.get('ftype') == 'pmodule':
+                    module = mdata.get('module')
+                    if (hasattr(module,
+                        'get_dependent_ifacenames') == False):
+                        continue
+                    dlist = module.get_dependent_ifacenames(ifaceobj,
+                                    self.ifaceobjdict.keys())
+                    if dlist:
+                        self.logger.debug('%s: ' %ifaceobj.get_name() +
+                                'got dependency list: %s' %str(dlist))
+                        break
+
+        return dlist
+
+    
+    def generate_dependency_info(self, ifacenames, dependency_graph, op):
+        """ recursive function to generate iface dependency info """
+
+        self.logger.debug('generating dependency info for %s' %str(ifacenames))
+
+        for i in ifacenames:
+            # Go through all modules and find dependent ifaces
+            dlist = None
+            ifaceobj = self.get_iface_obj_first(i)
+            if ifaceobj is None: 
+                continue
+
+            dlist = ifaceobj.get_dependents()
+            if dlist is None:
+                dlist = self.get_dependents(ifaceobj, op)
+            else:
+                # we already have dependency info for this interface
+                continue
+
+            self.preprocess_dependency_list(dlist, op)
+            ifaceobj.set_dependents(dlist)
+
+            if dependency_graph.get(i) is None:
+                dependency_graph[i] = dlist
+
+            self.generate_dependency_info(dlist, dependency_graph, op)
+
+    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:
+            self.ifaceobjdict[ifaceobj.get_name()] = [ifaceobj]
+        else:
+            self.ifaceobjdict[ifaceobj.get_name()].append(ifaceobj)
+
+    def read_default_iface_config(self):
+        """ Reads default network interface config /etc/network/interfaces. """
+        nifaces = networkInterfaces()
+        nifaces.subscribe('iface_found', self.save_iface)
+        nifaces.load()
+
+    def read_iface_config(self):
+        return self.read_default_iface_config()
+
+    def read_old_iface_config(self):
+        """ Reads the saved iface config instead of default iface config. """
+
+        # Read it from the statemanager
+        self.ifaceobjdict = self.statemanager.get_ifaceobjdict()
+
+
+    def 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)
+        
+        """
+
+        mmetadata = self.operations[mkind][msubkind].get(mname)
+        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_modules_builtin(self, modules_dir):
+        """ load python modules from modules_dir
+
+        Default modules_dir is /usr/share/ifupdownmodules
+
+        """
+
+        self.logger.info('loading builtin modules from %s' %modules_dir)
+
+        if not modules_dir in sys.path:
+                sys.path.append(modules_dir)
+        try:
+            module_list = os.listdir(modules_dir)
+            for module in module_list:
+                if re.search('.*\.pyc', module, 0) != None:
+                    continue
+
+                mname, mext = os.path.splitext(module)
+                if mext is not None and mext == '.py':
+                    self.logger.info('loading ' + modules_dir + '/' + module)
+                    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())
+                    ops = minstance.get_ops()
+                    for op in ops:
+                        if re.search('up', op) is not None:
+                            self.save_module('up', op, mname, 'pmodule',
+                                             minstance)
+                        else:
+                            self.save_module('down', op, mname, 'pmodule',
+                                             minstance)
+        except: 
+            raise
+
+
+    def load_modules(self, modules_dir):
+        """ loading user modules from /etc/network/.
+
+        Note that previously loaded python modules override modules found
+        under /etc/network if any
+
+        """
+
+        self.logger.info('loading user modules from %s' %modules_dir)
+        for op, subops in self.operations.items():
+            for subop in subops.keys():
+                msubdir = modules_dir + '/if-%s.d' %subop
+                self.logger.info('loading modules under %s ...' %msubdir)
+                try:
+                    module_list = os.listdir(msubdir)
+                    for module in module_list:
+                        if re.search('.*\.pyc', module, 0) != None:
+                            continue
+
+                        mname, mext = os.path.splitext(module)
+                        if mext is not None and mext == '.py':
+                            self.logger.debug('loading ' + msubdir + '/' + module)
+                            try:
+                                m = imp.load_source(module,
+                                        msubdir + '/' + module)
+                                mclass = getattr(m, mname)
+                            except:
+                                raise
+                            minstance = mclass()
+                            self.save_module(op, subop, mname, 'pmodule',
+                                                minstance)
+                        else:
+                            self.save_module(op, subop, mname, 'script',
+                                    msubdir + '/' + module)
+                except: 
+                    raise
+
+        #self.logger.debug('modules ...')
+        #self.pp.pprint(self.operations)
+
+        # For query, we add a special entry, basically use all 'up' modules
+        self.operations['query'] = self.operations.get('up')
+
+
+    def conv_iface_namelist_to_objlist(self, intf_list):
+        for intf in intf_list:
+            iface_obj = self.get_iface(intf)
+            if iface_obj == None:
+                raise ifupdownInvalidValue('no iface %s', intf)
+
+            iface_objs.append(iface_obj)
+
+        return iface_objs
+
+
+    def run_without_dependents(self, op, ifacenames):
+        ifaceSched = ifaceScheduler(force=self.FORCE)
+
+        self.logger.debug('run_without_dependents for op %s' %op +
+                ' for %s' %str(ifacenames))
+
+        if ifacenames == None:
+            raise ifupdownInvalidValue('no interfaces found')
+
+        return ifaceSched.run_iface_list(self, ifacenames, op)
+
+
+    def run_with_dependents(self, op, ifacenames):
+        dependency_graph = {}
+        ret = 0
+        self.logger.debug('run_with_dependents for op %s'
+                          %op + ' for %s' %str(ifacenames))
+
+        ifaceSched = ifaceScheduler()
+
+        if ifacenames is None:
+            ifacenames = self.ifaceobjdict.keys()
+
+        # generate dependency graph of interfaces
+        self.generate_dependency_info(ifacenames, dependency_graph, op)
+
+        if self.logger.isEnabledFor(logging.DEBUG) == True:
+            self.logger.debug('dependency graph:')
+            self.pp.pprint(dependency_graph)
+
+        if self.njobs > 1:
+            ret = ifaceSched.run_iface_dependency_graph_parallel(self,
+                        dependency_graph, op)
+        else:
+            ret = ifaceSched.run_iface_dependency_graph(self, dependency_graph,
+                        op)
+
+        return ret
+
+
+    def validate_ifaces(self, ifacenames):
+        """ validates interface list for config existance.
+       
+        returns -1 if one or more interface not found. else, returns 0
+
+        """
+
+        err_iface = ''
+        for i in ifacenames:
+            ifaceobjs = self.get_iface_objs(i)
+            if ifaceobjs is None:
+                err_iface += ' ' + i
+
+        if len(err_iface) != 0:
+            self.logger.error('did not find interfaces: %s' %err_iface)
+            return -1
+
+        return 0
+
+
+    def iface_whitelisted(self, auto, allow_classes, excludepats, ifacename):
+        """ Checks if interface is whitelisted depending on set of parameters.
+
+
+        interfaces are checked against the allow_classes and auto lists.
+
+        """
+
+        # If the interface matches
+        if excludepats is not None and len(excludepats) > 0:
+            for e in excludepats:
+                if re.search(e, ifacename) is not None:
+                    return False
+
+        ifaceobjs = self.get_iface_objs(ifacename)
+        if ifaceobjs is None:
+            self.logger.debug('iface %s' %ifacename + ' not found')
+            return False
+
+        # We check classes first
+        if allow_classes is not None and len(allow_classes) > 0:
+            for i in ifaceobjs:
+                if (len(i.get_classes()) > 0):
+                    common = Set([allow_classes]).intersection(
+                                Set(i.get_classes()))
+                    if len(common) > 0:
+                        return True
+            return False
+
+        if auto == True:
+            for i in ifaceobjs:
+                if i.get_auto() == True:
+                    return True
+            return False
+
+        return True
+
+    def generate_running_env(self, ifaceobj, op):
+        """ Generates a dictionary with env variables required for an interface.
+
+        Used to support script execution for interfaces.
+
+        """
+
+        cenv = None
+        iface_env = ifaceobj.get_env()
+        if iface_env is not None:
+            cenv = os.environ
+            if cenv is not None:
+                cenv.update(iface_env)
+            else:
+                cenv = iface_env
+
+            cenv['MODE'] = self.compat_conv_op_to_mode(op)
+
+        return cenv
+
+
+    def run(self, op, auto=False, allow_classes=None,
+            ifacenames=None, query_state=None, excludepats=None):
+        """ main ifupdown run method """
+
+        if auto == True:
+            self.logger.debug('setting flag ALL')
+            self.ALL = True
+
+        # Only read new iface config for 'up'
+        # operations. For 'downs' we only rely on
+        # old state
+        if op == 'up' or op == 'query':
+            try:
+                self.read_iface_config()
+            except Exception, e:
+                raise
+        else:
+            # 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')
+
+
+        if ifacenames is not None:
+            # If iface list is given, always check if iface is present
+           if self.validate_ifaces(ifacenames) != 0:
+               raise Exception('all or some interfaces not found')
+
+        # if iface list not given by user, assume all from config file
+        if ifacenames is None: ifacenames = self.ifaceobjdict.keys()
+
+        # filter interfaces based on auto and allow classes
+        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')
+
+        if op == 'query':
+            if query_state == None:
+                return self.print_ifaceobjs_pretty(filtered_ifacenames)
+            elif query_state == 'presumed':
+                return self.print_ifaceobjs_saved_state_pretty(
+                                    filtered_ifacenames)
+            elif query_state == 'presumeddetailed':
+                return self.print_ifaceobjs_saved_state_detailed_pretty(
+                                    filtered_ifacenames)
+
+        if op == 'query' or self.NODEPENDS == True:
+            self.run_without_dependents(op, filtered_ifacenames)
+        else:
+            self.run_with_dependents(op, filtered_ifacenames)
+
+        if op == 'query':
+            if query_state == 'curr':
+                # print curr state of all interfaces
+                ret = self.print_ifaceobjscurr_pretty(filtered_ifacenames)
+                if ret != 0:
+                    # if any of the object has an error, signal that silently
+                    raise Exception('')
+            return
+
+        # Update persistant iface states
+        try:
+            if self.ALL == True:
+                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 up(self, auto=False, allow=None, ifacenames=None, excludepats=None):
+        return self.run('up', auto, allow, ifacenames, excludepats=excludepats)
+
+    def down(self, auto=False, allow=None, ifacenames=None, excludepats=None):
+        return self.run('down', auto, allow, ifacenames,
+                        excludepats=excludepats);
+
+    def query(self, auto=False, allow=None, ifacenames=None,
+              query_state=False, excludepats=None):
+        return self.run('query', auto, allow, ifacenames,
+                        query_state=query_state, excludepats=excludepats);
+
+    def dump(self):
+        """ all state dump """
+
+        print 'ifupdown object dump'
+        print self.pp.pprint(self.modules)
+        print self.pp.pprint(self.ifaces)
+        self.state_manager.dump()
+
+    def print_state(self, ifacenames=None):
+        self.statemanager.dump(ifacenames)
+
+    def print_ifaceobjs_pretty(self, ifacenames):
+        for i in ifacenames:
+            ifaceobjs = self.get_iface_objs(i)
+            for io in ifaceobjs:
+                io.dump_raw(self.logger)
+                print '\n'
+
+    def print_ifaceobjscurr_pretty(self, ifacenames):
+        """ Dumps current running state of interfaces.
+
+        returns 1 if any of the interface has an error,
+        else returns 0
+
+        """
+
+        ret = 0
+        for i in ifacenames:
+            ifaceobj = self.get_ifaceobjcurr(i)
+            ifaceobj.dump_pretty(self.logger)
+            if ifaceobj.get_status() == ifaceStatus.ERROR:
+                ret = 1
+
+        return ret
+
+    def print_ifaceobjs_saved_state_pretty(self, ifacenames):
+        self.statemanager.print_state_pretty(ifacenames, self.logger)
+
+    def print_ifaceobjs_saved_state_detailed_pretty(self, ifacenames):
+        self.statemanager.print_state_detailed_pretty(ifacenames, self.logger)
diff --git a/pkg/log.py b/pkg/log.py
deleted file mode 100644 (file)
index fbdc3ff..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/python
-
-import logging
-
-
-class log:
-
-    @staticmethod
-    def log_error(obj, prefix, *args, **kwargs):
-        obj.get_logger().logger.log_error(''.join(args))
-
-    @staticmethod
-    def log_warn(obj, *args, **kwargs):
-        msg = ''
-        logger = obj.get_logger()
-        errmsg = obj.get_errmsg()
-        msg += ''.join(args)
-        if errmsg is not None and len(errmsg) > 0:
-            msg += '(%s)' %errmsg
-
-
-    @staticmethod
-    def log(obj, log_prefix, *args, **kwargs):
-        msg = ''
-        logger = obj.get_logger()
-        msg += ''.join(args)
-
-
index e0d0c8dc9139ffb1b7b1f1f40a8e63b6738df40b..16d1bbac4c1a03124345840ae478438a4d0bafda 100644 (file)
@@ -1,10 +1,16 @@
 #!/usr/bin/python
+#
+# Copyright 2013.  Cumulus Networks, Inc.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# networkInterfaces --
+#    ifupdown network interfaces file parser
+#
 
 import collections
-from iface import *
 import logging
 import glob
-
+from iface import *
 
 class networkInterfaces():
 
@@ -38,7 +44,7 @@ class networkInterfaces():
         return 0
 
     def process_allow(self, lines, cur_idx, lineno):
-        allow_line = self.lines[cur_idx]
+        allow_line = lines[cur_idx]
 
         words = allow_line.split()
         if len(words) <= 1:
index 3904b0e8ac64ed9efa1753b5baa5fdd0497e5e12..156b187efc01ed7cf76f7cd424851a1971a28e24 100644 (file)
@@ -1,4 +1,11 @@
 #!/usr/bin/python
+#
+# Copyright 2013.  Cumulus Networks, Inc.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# ifaceScheduler --
+#    interface scheduler
+#
 
 import os
 import re
@@ -23,9 +30,10 @@ class ifaceScheduler(ifupdownBase):
     or dependency graph format.
     """
 
-    def __init__(self):
+    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, mdict, cenv):
         """ Runs sub operation on an interface """
@@ -55,10 +63,7 @@ class ifaceScheduler(ifupdownBase):
                     self.exec_command(m, cmdenv=cenv)
             except Exception, e:
                 err = 1
-                if ifupdownobj.ignore_error(str(e)) == True:
-                    pass
-                else:
-                    raise
+                self.log_error(str(e))
             finally:
                 if op != 'query':
                     if err == 1:
@@ -123,11 +128,7 @@ class ifaceScheduler(ifupdownBase):
             try:
                 self.run_iface(ifupdownobj, ifacename, operation)
             except Exception, e:
-                if (ifupdownobj.ignore_error(str(e)) == True):
-                    pass
-                else:
-                    raise
-
+                self.log_error(str(e))
 
     def run_iface_list_subop(self, ifupdownobj, ifacenames, op, subop, mdict,
                              sorted_by_dependency=False):
@@ -164,11 +165,7 @@ class ifaceScheduler(ifupdownBase):
                     self.run_iface_subop(ifupdownobj, ifaceobj, op, subop,
                                          mdict, cenv)
             except Exception, e:
-                if (ifupdownobj.ignore_error(str(e)) == True):
-                    pass
-                else:
-                    raise
-
+                self.log_error(str(e))
 
     def run_iface_list_stages(self, ifupdownobj, ifacenames, op,
                               sorted_by_dependency=False):
@@ -261,7 +258,7 @@ class ifaceScheduler(ifupdownBase):
                                                  dlist, op)
                     self.accquire_token(ifacename)
                 except Exception, e:
-                    if (ifupdownobj.ignore_error(str(e)) == True):
+                    if (self.ignore_error(str(e)) == True):
                         pass
                     else:
                         # Dont bring the iface up if children did not come up
index 8a66d1a3236dd1ba1cafa46d374f41c4b87760c2..a0ed81116bfa4ce2dbef2af6061200233a7b3ada 100644 (file)
@@ -1,5 +1,11 @@
 #!/usr/bin/python
-
+#
+# Copyright 2013.  Cumulus Networks, Inc.
+# Author: Roopa Prabhu, roopa@cumulusnetworks.com
+#
+# stateManager --
+#    interface state manager
+#
 import cPickle
 from collections import OrderedDict
 from exceptions import *
@@ -65,6 +71,7 @@ class stateManager():
         for ifaceobj in pickling.load(pickle_filename):
             self.save_ifaceobj(ifaceobj)
             ifaceobj.set_refcnt(0)
+            ifaceobj.set_dependents(None)
 
         return 0
 
index bc7b0e099418518442aac4d8b13ee4e26cb0fd88..884e604c79bd7290aecda3c9b9d54ebfbe936631 100755 (executable)
@@ -4,7 +4,7 @@ import sys
 import os
 import re
 import argparse
-from ifupdown.ifupdown_main import *
+from ifupdown.ifupdownmain import *
 
 import logging
 
@@ -17,15 +17,15 @@ def run(args, op):
     try:
         logger.debug('creating ifupdown object ..')
         if op == 'up' or op == 'down':
-            ifupdown_handle = ifupdown_main(force=args.force,
-                                            dryrun=args.noact,
+            ifupdown_handle = ifupdownMain(force=args.force,
                                             nodepends=args.nodepends,
                                             perfmode=args.perfmode,
-                                            njobs=args.jobs)
+                                            njobs=args.jobs,
+                                            dryrun=args.noact)
         elif op == 'query':
-            ifupdown_handle = ifupdown_main(dryrun=args.noact,
-                                            nodepends=args.nodepends,
-                                            perfmode=args.perfmode)
+            ifupdown_handle = ifupdownMain(nodepends=args.nodepends,
+                                            perfmode=args.perfmode,
+                                            njobs=args.jobs)
 
         iflist = args.iflist
         if len(args.iflist) == 0:
@@ -33,9 +33,11 @@ def run(args, op):
 
         logger.debug('calling %s' %op + ' for all interfaces ..')
         if op == 'up':
-            ifupdown_handle.up(args.all, args.CLASS, iflist)
+            ifupdown_handle.up(args.all, args.CLASS, iflist,
+                               excludepats=args.excludepats)
         elif op == 'down':
-            ifupdown_handle.down(args.all, args.CLASS, iflist)
+            ifupdown_handle.down(args.all, args.CLASS, iflist,
+                                 excludepats=args.excludepats)
         elif op == 'query':
             if args.curstate == True:
                 qstate='curr'
@@ -46,7 +48,8 @@ def run(args, op):
             else:
                 qstate=None
             ifupdown_handle.query(args.all, args.CLASS, iflist,
-                                  query_state=qstate)
+                                  query_state=qstate,
+                                  excludepats=args.excludepats)
     except:
         raise
 
@@ -73,14 +76,8 @@ def deinit():
     {}
 
 def update_argparser(argparser):
-
     argparser.add_argument('iflist', metavar='IFACE',
                 nargs='*', help='interfaces list')
-    argparser.add_argument('-a', '--all', action='store_true',
-                help='process all interfaces marked \"auto\"')
-    argparser.add_argument('-n', '--no-act', dest='noact',
-                action='store_true', help='print out what would happen,' +
-                'but don\'t do it')
     argparser.add_argument('-v', '--verbose', dest='verbose',
                 action='store_true', help='verbose')
     argparser.add_argument('-d', '--debug', dest='debug',
@@ -93,16 +90,24 @@ def update_argparser(argparser):
                 help='ignore non-\"allow-CLASS\" interfaces')
     argparser.add_argument('--nodepends', dest='nodepends',
                 action='store_true', help=argparse.SUPPRESS)
-    argparser.add_argument('--performance-mode', dest='perfmode',
+    argparser.add_argument('--perfmode', dest='perfmode',
                 action='store_true', help=argparse.SUPPRESS)
+    argparser.add_argument('-j', '--jobs', dest='jobs', type=int,
+                default=-1, choices=range(1,12), help=argparse.SUPPRESS)
+    argparser.add_argument('-X', '--exclude', dest='excludepats',
+                action='append', help='print out what would happen,' +
+                ' but don\'t do it')
 
 
 def update_ifupdown_argparser(argparser):
+    argparser.add_argument('-a', '--all', action='store_true',
+                help='process all interfaces marked \"auto\"')
     argparser.add_argument('-f', '--force', dest='force',
                 action='store_true',
                 help='force run all operations')
-    argparser.add_argument('-j', '--jobs', dest='jobs', type=int,
-                default=-1, choices=range(1,12), help=argparse.SUPPRESS)
+    argparser.add_argument('-n', '--no-act', dest='noact',
+                action='store_true', help='print out what would happen,' +
+                'but don\'t do it')
 
 def update_ifup_argparser(argparser):
     update_ifupdown_argparser(argparser)
@@ -111,6 +116,8 @@ def update_ifdown_argparser(argparser):
     update_ifupdown_argparser(argparser)
 
 def update_ifquery_argparser(argparser):
+    argparser.add_argument('-l', '--list', action='store_true', dest='all',
+                help='process all interfaces marked \"auto\"')
     group = argparser.add_mutually_exclusive_group(required=False)
     group.add_argument('-r', '--running-state', dest='curstate',
                        action='store_true',
@@ -126,6 +133,7 @@ def update_ifquery_argparser(argparser):
                        dest='presumedstatedetailed',
                        action='store_true', help=argparse.SUPPRESS)
 
+
 def parse_args(argsv, op):
     descr = 'interface management'
 
@@ -158,7 +166,7 @@ def main(argv):
         # Command line arg parser
         args = parse_args(argv[1:], op)
         if len(args.iflist) > 0 and args.all is True:
-            print 'iflist and all are mutually exclusive'
+            print 'interface list and \'-a\' are mutually exclusive'
             exit(1)
 
         init(args)
index 32ff3b742e86b4377135e6791773a38d2e19fdae..436ccdf4477fb618a91f7dae56d8c89d50346209 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -13,7 +13,7 @@ setup(name='ifupdown2',
                       ['man/ifup.8', 'man/ifdown.8', 'man/ifquery.8']),
                   ('/etc/init.d/',
                       ['init.d/networking']),
-                  ('/sbin/ifupdown', ['sbin/ifupdown']),
+                  ('/sbin/', ['sbin/ifupdown']),
                   ('/usr/share/doc/ifupdown/examples/',
                       ['docs/examples/interfaces'])]
       )