Subversion Repositories HomeAutomation

Rev

Rev 751 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. ###########################################################
  2. #
  3. # Daemon configuration
  4. #
  5. ###########################################################
  6. import logging as log
  7. import pickle
  8. import hashlib
  9. import os
  10. import imp
  11. import re
  12. from ConfigParser import ConfigParser
  13. import filters
  14. import statespaces
  15. from CanPktHandlerBase import CanPktHandlerBase
  16. from CanPktHandler1 import CanPktHandler1
  17.  
  18. from NodeIfSerial import NodeIfSerial
  19. from NodeIfTCP import NodeIfTCP
  20. from NodeIfUDP import NodeIfUDP
  21. from NodeIfTCPTLS import NodeIfTCPTLS
  22. from NodeIfCanStim import NodeIfCanStim
  23.  
  24. from TCPServer1 import TCPServer1
  25. from TCPTLSServer import TCPTLSServer
  26. from CanCtldServer import CanCtldServer
  27.  
  28. class DynamicModuleCfg:
  29.     """Dynamic module manager"""
  30.  
  31.     modSubDir = None
  32.     CHECKSUM_FILE = 'checksums'
  33.     CHECKSUM_SECTION = 'SHA-1_CHECKSUMS'
  34.    
  35.     def __init__(self, modSubDir):
  36.         self.modSubDir = modSubDir
  37.         self.checkSumFile = modSubDir + '/' + self.CHECKSUM_FILE
  38.         if not os.path.exists(self.checkSumFile):
  39.             self.__createCsumsFile()
  40.    
  41.     def loadModule(self, className):
  42.         pFileName = os.getcwd() + '/' + self.modSubDir + '/' + className + '.p'
  43.         log.debug('Reading from ' + pFileName)
  44.         fp = open(pFileName, 'r')
  45.         p = pickle.Unpickler(fp)
  46.         loadedMod = p.load()
  47.         fp.close()
  48.         if not self.__verifyCheckSum(className, pFileName):
  49.             print 'Invalid checksum'
  50.             return None
  51.         else:
  52.             return loadedMod
  53.        
  54.        
  55.     def loadModules(self, config = None):
  56.         subDirFiles = os.listdir(os.getcwd() + '/' + self.modSubDir)
  57.         p = re.compile('.p$', re.IGNORECASE)
  58.         modFiles = [elem for elem in subDirFiles if p.search(elem) is not None]
  59.         modNames = []
  60.         for mfName in modFiles:
  61.             modNames.append(mfName.split('.')[0])
  62.         log.debug('Found modules: ' + str(modNames))
  63.         myMods = {}
  64.         for mName in modNames:
  65.             classObj = self.loadModule(mName)
  66.             if classObj is not None:
  67.                 myMods[mName] = classObj
  68.         return myMods
  69.  
  70.    
  71.     def saveModule(self, className, classObj):
  72.         pFileName = os.getcwd() + '/' + self.modSubDir + '/' + className + '.p'
  73.         log.debug('Writing to ' + pFileName)
  74.         fp = open(pFileName, 'w')
  75.         p = pickle.Pickler(fp)
  76.         p.dump(classObj)
  77.         fp.close()
  78.         self.__writeCheckSum(className, pFileName)
  79.    
  80.    
  81.     def __doCheckSum(self, filename):
  82.         f = open(filename, 'r')
  83.         data = f.read()
  84.         f.close()
  85.         hasher = hashlib.sha1()
  86.         hasher.update(data)
  87.         digest = hasher.hexdigest()
  88.         return digest
  89.    
  90.    
  91.     def __createCsumsFile(self):
  92.          csumsfile = open(self.checkSumFile, 'w')
  93.          csumsfile.write('[' + self.CHECKSUM_SECTION + ']\n')
  94.          csumsfile.close()
  95.    
  96.    
  97.     def __writeCheckSum(self, entryname, filename):
  98.         csumsfile = open(self.checkSumFile, 'r+')
  99.         csumcfg = ConfigParser()
  100.         csumcfg.readfp(csumsfile)
  101.         digest = self.__doCheckSum(filename)
  102.         csumcfg.set(self.CHECKSUM_SECTION, entryname, digest)
  103.         csumsfile.seek(0)
  104.         csumcfg.write(csumsfile)
  105.        
  106.        
  107.     def __verifyCheckSum(self, entryname, filename):
  108.         csumsfile = open(self.checkSumFile, 'r')
  109.         csumcfg = ConfigParser()
  110.         csumcfg.readfp(csumsfile)
  111.         digest = csumcfg.get(self.CHECKSUM_SECTION, entryname)
  112.         cur_digest = self.__doCheckSum(filename)
  113.         log.debug('Old checksum ' + digest + '\nNew checksum: ' + cur_digest)
  114.         if cur_digest == digest:
  115.             return True
  116.         return False
  117.    
  118.    
  119.     def importModule(self, className, requiredAttributes):
  120.         """Imports a given class from the module with the same name """
  121.  
  122.         codeFile = os.getcwd() + '/' + self.modSubDir + '/' + className + '.py'
  123.         mod = imp.load_source(self.modSubDir + '.' + className, codeFile)
  124.         newClass = eval('mod.' + className)()
  125.        
  126.         for ra in requiredAttributes:
  127.             if not hasattr(newClass, ra):
  128.                 print className, ': missing required symbol \"' + ra + '\"'
  129.                 return None
  130.        
  131.         self.saveModule(className, newClass)
  132.         return newClass
  133.  
  134.  
  135. class FilterCfg:
  136.     """Filter resource manager"""
  137.    
  138.     REQUIRED_ATTRIBUTES = ['ASSOCIATED_SPACES', 'DESCRIPTIVE_NAME',
  139.                            'attach', 'detach', 'filter']
  140.    
  141.     dynamicModuleCfg = None
  142.     FILTER_SUBDIR = 'filters'
  143.     filterModules = {}
  144.    
  145.     def __init__(self):
  146.         self.dynamicModuleCfg = DynamicModuleCfg(self.FILTER_SUBDIR)
  147.    
  148.     def loadFilter(self, name):
  149.         newFilt = self.dynamicModuleCfg.loadModule(name)
  150.         if newFilt is not None:
  151.             self.filterModules[name] = newFilt
  152.             return True
  153.         else:
  154.             return False
  155.  
  156.     def loadFilters(self, config = None):
  157.         self.filterModules = self.dynamicModuleCfg.loadModules()
  158.         for fM in self.filterModules:
  159.             log.debug(fM)
  160.  
  161.     def __saveFilter(self, className, classObj):
  162.         self.dynamicModuleCfg.saveModule(className, classObj)
  163.  
  164.     def saveFilters(self):
  165.         for className in self.filterModules:
  166.             self.__saveFilter(className, self.filterModules[className])
  167.        
  168.     def importFilter(self, className):
  169.         """Imports a given filter definition """
  170.         classObj = self.dynamicModuleCfg.importModule(className, self.REQUIRED_ATTRIBUTES)
  171.         if classObj is not None:
  172.             print 'Imported: ' + classObj.DESCRIPTIVE_NAME
  173.             return True
  174.         else:
  175.             return False
  176.        
  177.  
  178. class StateSpaceCfg:
  179.     """State space resource manager"""
  180.    
  181.     REQUIRED_ATTRIBUTES = ['DESCRIPTIVE_NAME', 'RELATED_SPACES'
  182.                            'load', 'reset', 'run', 'unload']
  183.    
  184.     dynamicModuleCfg = None
  185.     FILTER_SUBDIR = 'statespaces'
  186.     spaceModules = {}
  187.    
  188.     def __init__(self):
  189.         self.dynamicModuleCfg = DynamicModuleCfg(self.FILTER_SUBDIR)
  190.    
  191.     def loadSpace(self, name):
  192.         newSpace = self.dynamicModuleCfg.loadModule(name)
  193.         if newSpace is not None:
  194.             self.spaceModules[name] = newFilt
  195.             return True
  196.         else:
  197.             return False
  198.  
  199.     def loadSpaces(self, config = None):
  200.         self.spaceModules = self.dynamicModuleCfg.loadModules()
  201.         for sM in self.spaceModules:
  202.             log.debug(sM)
  203.  
  204.     def __saveSpace(self, className, classObj):
  205.         self.dynamicModuleCfg.saveModule(className, classObj)
  206.  
  207.     def saveSpaces(self):
  208.         for className in self.spaceModules:
  209.             self.__saveSpace(className, self.spaceModules[className])
  210.    
  211.     def importSpace(self, name):
  212.         """Imports a given state space definition file """
  213.         classObj = self.dynamicModuleCfg.importModule(name, self.REQUIRED_ATTRIBUTES)
  214.         if classObj is not None:
  215.             print 'Imported: ' + classObj.DESCRIPTIVE_NAME
  216.             return True
  217.         else:
  218.             return False
  219.  
  220. class DaemonConfig:
  221.    
  222.     stateSpaceCfg = None
  223.     filterCfg = None
  224.     pktHandler = None
  225.    
  226.     filterChain = []
  227.     nodeInterfaces = []
  228.     nodeInterfaceMap = {}
  229.    
  230.     serverDaemons = []
  231.    
  232.     INTERFACE_TYPES = {'serial' : NodeIfSerial, 'tcp' : NodeIfTCP,
  233.                        'udp' : NodeIfUDP, 'sim' : NodeIfCanStim,
  234.                        'tcptls' : NodeIfTCPTLS}
  235.    
  236.     SERVER_TYPES = {'tcpd' : TCPServer1, 'tcptlsd' : TCPTLSServer,
  237.                     'canctld' : CanCtldServer}
  238.  
  239.     def __init__ (self):
  240.         self.filterCfg = FilterCfg()
  241.         self.stateSpaceCfg = StateSpaceCfg()
  242.         self.pktHandler = CanPktHandler1(self)
  243.        
  244.     def load(self):
  245.         self.stateSpaceCfg.loadSpaces()
  246.         self.filterCfg.loadFilters()
  247.         self.__setupFilterBindings()
  248.         self.__setupStateSpaceRelations()
  249.         self.__setupFilterChain()
  250.  
  251.     def save(self):
  252.         self.stateSpaceCfg.saveSpaces()
  253.         self.filterCfg.saveFilters()
  254.        
  255.     def addInterface(self, type, cfg = None):
  256.         """ addInterface
  257.        type - a valid interface type name
  258.        cfg - interface configuration
  259.        returns: True on success, False otherwise """
  260.        
  261.         if not self.INTERFACE_TYPES.has_key(type):
  262.             log.debug('addInterface called with invalid interface type')
  263.             return False
  264.        
  265.         if cfg is None:
  266.             cfg = self.INTERFACE_TYPES[type].DEFAULT_CONFIG
  267.        
  268.         nodeIf = self.INTERFACE_TYPES[type](self.pktHandler, cfg)
  269.         self.nodeInterfaces.append(nodeIf)
  270.         return True
  271.    
  272.     def remInterface(self, name):
  273.         pass
  274.    
  275.     def addServerDaemon(self, type, cfg = None):
  276.        
  277.         if not self.SERVER_TYPES.has_key(type):
  278.             log.debug('addServerDaemon called with invalid daemon type')
  279.             return False
  280.        
  281.         if cfg is None:
  282.             cfg = self.SERVER_TYPES[type].DEFAULT_CONFIG
  283.        
  284.         serverd = self.SERVER_TYPES[type](self.pktHandler, cfg) # actung!
  285.         self.serverDaemons.append(serverd)
  286.         return True
  287.    
  288.     def remServerDaemon(self, name):
  289.         pass
  290.        
  291.     def __setupFilterChain(self):
  292.         self.filterChain = ['DefaultFilter']
  293.    
  294.     def __setupFilterBindings(self):
  295.         for f in self.filterCfg.filterModules.values():
  296.             assocSpaces = []
  297.             for s in f.ASSOCIATED_SPACES:
  298.                 if self.stateSpaceCfg.spaceModules.has_key(s):
  299.                     assocSpaces.append(self.stateSpaceCfg.spaceModules[s])
  300.                 else:
  301.                     print 'WARNING: Reference to undefined state space: ' + s
  302.             setattr(f, '__ASSOCIATED_SPACES__', assocSpaces)
  303.  
  304.     def __setupStateSpaceRelations(self):
  305.         for sm in self.stateSpaceCfg.spaceModules:
  306.             relatedSpaceNames = self.stateSpaceCfg.spaceModules[sm].RELATED_SPACES
  307.             relatedSpaces = {}
  308.             for rsname in relatedSpaceNames:
  309.                 relatedSpaces[rsname] = self.stateSpaceCfg.spaceModules[rsname]
  310.             setattr(self.stateSpaceCfg.spaceModules[sm], '__RELATED_SPACES__', relatedSpaces)
  311.  
  312.