Projects
Wiki     Timeline     Roadmap     Browse Source     View Tickets     New Ticket     Search

Ticket #136: extensible_config.patch

File extensible_config.patch, 15.7 KB (added by callan@…, 3 years ago)

More ambitious patch extending the extensible configuration logic throught

  • config.py

     
    2020import copy 
    2121 
    2222from twisted.python import log 
     23from twisted.python.reflect import namedClass 
    2324 
    2425from twistedcaldav.py.plistlib import readPlist 
    2526 
     27def _loadDirectoryService(klass): 
     28    """ 
     29    Loads a directory service class at runtime, raising a ConfigurationError 
     30    on failure. 
     31    """ 
     32    try: 
     33        return namedClass(klass) 
     34    except (ImportError, AttributeError): 
     35        raise ConfigurationError( 
     36            "Unable to load directory service %s" % klass) 
     37 
    2638defaultConfigFile = "/etc/caldavd/caldavd.plist" 
    2739 
    28 serviceDefaultParams = { 
    29     "twistedcaldav.directory.xmlfile.XMLDirectoryService": { 
    30         "xmlFile": "/etc/caldavd/accounts.xml", 
    31     }, 
    32     "twistedcaldav.directory.appleopendirectory.OpenDirectoryService": { 
    33         "node": "/Search", 
    34         "requireComputerRecord": True, 
    35     }, 
    36 } 
     40defaultDirectoryService = \ 
     41    "twistedcaldav.directory.xmlfile.XMLDirectoryService" 
    3742 
     43defaultDirectoryServiceParams = \ 
     44    copy.deepcopy(_loadDirectoryService(defaultDirectoryService).defaultParams) 
     45 
    3846defaultConfig = { 
    3947    # 
    4048    # Public network address information 
     
    7583    #    users, groups, locations and resources) to the server. 
    7684    # 
    7785    "DirectoryService": { 
    78         "type": "twistedcaldav.directory.xmlfile.XMLDirectoryService", 
    79         "params": serviceDefaultParams["twistedcaldav.directory.xmlfile.XMLDirectoryService"], 
     86        "type": defaultDirectoryService, 
     87        "params": defaultDirectoryServiceParams, 
    8088    }, 
    8189 
    8290    # 
     
    189197        return str(self._data) 
    190198 
    191199    def update(self, items): 
     200        dsData = self._data["DirectoryService"] 
    192201        dsType = items.get("DirectoryService", {}).get("type", None) 
    193202        if dsType is None: 
    194             dsType = self._data["DirectoryService"]["type"] 
    195         else: 
    196             if dsType == self._data["DirectoryService"]["type"]: 
    197                 oldParams = self._data["DirectoryService"]["params"] 
    198                 newParams = items["DirectoryService"].get("params", {}) 
    199                 _mergeData(oldParams, newParams) 
    200             else: 
    201                 if dsType in serviceDefaultParams: 
    202                     self._data["DirectoryService"]["params"] = copy.deepcopy(serviceDefaultParams[dsType]) 
    203                 else: 
    204                     self._data["DirectoryService"]["params"] = {} 
     203            dsType = dsData["type"] 
     204        dsClass = _loadDirectoryService(dsType) 
    205205 
     206        # Copy the default parameters from the directory service class, if the 
     207        # directory service we've been given is different than the one we 
     208        # already have. This ensures that at the very least the directory  
     209        # service is configured using the specified defaults and that the 
     210        # update method may be called more than once with specific parameters 
     211        # for configuration. 
     212        try: 
     213            if dsData["type"] != dsType: 
     214                dsData["type"] = dsType 
     215                dsData["params"] = copy.deepcopy(dsClass.defaultParams) 
     216        except AttributeError: 
     217            raise ConfigurationError( 
     218                "Default service parameters must be specified in %s " \ 
     219                "using the 'defaultParams' class variable." % dsType) 
     220        # Ensure that the parameters defined in the configuration file are 
     221        # acceptable for the directory service. 
    206222        for param in items.get("DirectoryService", {}).get("params", {}): 
    207             if param not in serviceDefaultParams[dsType]: 
    208                 raise ConfigurationError("Parameter %s is not supported by service %s" % (param, dsType)) 
     223            if param not in dsClass.defaultParams: 
     224                raise ConfigurationError( 
     225                    "Parameter %s is not supported by service %s" % \ 
     226                    (param, dsType)) 
    209227 
    210228        _mergeData(self._data, items) 
    211229 
    212         for param in tuple(self._data["DirectoryService"]["params"]): 
    213             if param not in serviceDefaultParams[self._data["DirectoryService"]["type"]]: 
    214                 del self._data["DirectoryService"]["params"][param] 
     230        # Cleeanup parameters which may have been left around after a switch 
     231        # in directory service type. 
     232        for param in tuple(dsData["params"]): 
     233            if param not in dsClass.defaultParams: 
     234                del dsData["params"][param] 
    215235 
    216236        self.updateServerCapabilities() 
    217237 
  • directory/xmlfile.py

     
    3939 
    4040    realmName = None 
    4141 
     42    defaultParams = { 
     43        "xmlFile": "/etc/caldavd/accounts.xml", 
     44    } 
     45 
    4246    def __repr__(self): 
    4347        return "<%s %r: %r>" % (self.__class__.__name__, self.realmName, self.xmlFile) 
    4448 
  • directory/appleopendirectory.py

     
    5656    """ 
    5757    baseGUID = "891F8321-ED02-424C-BA72-89C32F215C1E" 
    5858 
     59    defaultParams = { 
     60        "node": "/Search", 
     61        "requireComputerRecord": True, 
     62    } 
     63 
    5964    def __repr__(self): 
    6065        return "<%s %r: %r>" % (self.__class__.__name__, self.realmName, self.node) 
    6166 
  • directory/idirectory.py

     
    3434    realmName = Attribute("The name of the authentication realm this service represents.") 
    3535    guid = Attribute("A GUID for this service.") 
    3636 
     37    defaultParams = Attribute("Default configuration parameters for this service.") 
     38 
    3739    def recordTypes(): 
    3840        """ 
    3941        @return: a sequence of strings denoting the record types that are kept 
  • test/test_config.py

     
    2121from twistedcaldav.py.plistlib import writePlist 
    2222 
    2323from twistedcaldav.config import config, defaultConfig, ConfigurationError 
     24from twistedcaldav.directory.directory import DirectoryService 
    2425 
    2526testConfig = """<?xml version="1.0" encoding="UTF-8"?> 
    2627<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 
     
    3435</plist> 
    3536""" 
    3637 
     38XML_DIRECTORY_SERVICE = \ 
     39    "twistedcaldav.directory.xmlfile.XMLDirectoryService" 
     40 
     41OPEN_DIRECTORY_SERVICE = \ 
     42    "twistedcaldav.directory.appleopendirectory.OpenDirectoryService" 
     43 
     44SUPER_DUPER_DIRECTORY_SERVICE = \ 
     45    "twistedcaldav.test.test_config.SuperDuperService" 
     46 
     47class SuperDuperService(DirectoryService): 
     48    """ 
     49    A super duper directory service that's super duper effective at being 
     50    used for testing but not awesome. 
     51    """ 
     52    defaultParams = { 
     53        "superLevel": "super", 
     54        "duperLevel": "duper", 
     55    } 
     56 
    3757def _testVerbose(testCase): 
    3858    from twistedcaldav.config import config 
    3959    testCase.assertEquals(config.Verbose, True) 
     
    4464        config.update(defaultConfig) 
    4565        self.testConfig = self.mktemp() 
    4666        open(self.testConfig, 'w').write(testConfig) 
     67        self.ds = config.DirectoryService 
    4768 
    4869    def tearDown(self): 
    4970        config.setDefaults(defaultConfig) 
    5071        config.loadConfig(None) 
    5172        config.reload() 
    5273 
     74    def _checkXMLDefaults(self): 
     75        """ 
     76        Checks that the base XML directory service defaults are correct. 
     77        """ 
     78        self.assertEquals(self.ds["type"], XML_DIRECTORY_SERVICE) 
     79        self.assertEquals(self.ds["params"]["xmlFile"], 
     80                          "/etc/caldavd/accounts.xml") 
     81 
     82    def _checkODDefaults(self): 
     83        """ 
     84        Checks that the base Apple open directory service defaults are correct. 
     85        """ 
     86        self.assertEquals(self.ds["type"], OPEN_DIRECTORY_SERVICE) 
     87        self.assertNotIn("xmlFile", self.ds["params"]) 
     88        self.assertEquals(self.ds["params"]["node"], "/Search") 
     89        self.assertEquals(self.ds["params"]["requireComputerRecord"], True) 
     90 
     91    def _checkSuperDuperDefaults(self): 
     92        """ 
     93        Checks that the base super duper test-only directory service defaults 
     94        are correct. 
     95        """ 
     96        self.assertEquals(self.ds["type"], SUPER_DUPER_DIRECTORY_SERVICE) 
     97        self.assertNotIn("xmlFile", self.ds["params"]) 
     98        self.assertEquals(self.ds["params"]["superLevel"], "super") 
     99        self.assertEquals(self.ds["params"]["duperLevel"], "duper") 
     100 
     101 
    53102    def testDefaults(self): 
    54103        for key, value in defaultConfig.iteritems(): 
    55104            self.assertEquals(getattr(config, key), value) 
     
    122171        self.assertEquals(config.MultiProcess["LoadBalancer"]["Enabled"], True) 
    123172 
    124173    def testDirectoryService_noChange(self): 
    125         self.assertEquals(config.DirectoryService["type"], "twistedcaldav.directory.xmlfile.XMLDirectoryService") 
    126         self.assertEquals(config.DirectoryService["params"]["xmlFile"], "/etc/caldavd/accounts.xml") 
    127  
     174        self._checkXMLDefaults() 
    128175        config.update({"DirectoryService": {}}) 
     176        self._checkXMLDefaults() 
    129177 
    130         self.assertEquals(config.DirectoryService["type"], "twistedcaldav.directory.xmlfile.XMLDirectoryService") 
    131         self.assertEquals(config.DirectoryService["params"]["xmlFile"], "/etc/caldavd/accounts.xml") 
    132  
    133178    def testDirectoryService_sameType(self): 
    134         self.assertEquals(config.DirectoryService["type"], "twistedcaldav.directory.xmlfile.XMLDirectoryService") 
    135         self.assertEquals(config.DirectoryService["params"]["xmlFile"], "/etc/caldavd/accounts.xml") 
     179        self._checkXMLDefaults() 
     180        config.update({"DirectoryService": {"type": XML_DIRECTORY_SERVICE}}) 
     181        self._checkXMLDefaults() 
    136182 
    137         config.update({"DirectoryService": {"type": "twistedcaldav.directory.xmlfile.XMLDirectoryService"}}) 
    138  
    139         self.assertEquals(config.DirectoryService["type"], "twistedcaldav.directory.xmlfile.XMLDirectoryService") 
    140         self.assertEquals(config.DirectoryService["params"]["xmlFile"], "/etc/caldavd/accounts.xml") 
    141  
    142183    def testDirectoryService_newType(self): 
    143         self.assertEquals(config.DirectoryService["type"], "twistedcaldav.directory.xmlfile.XMLDirectoryService") 
    144         self.assertEquals(config.DirectoryService["params"]["xmlFile"], "/etc/caldavd/accounts.xml") 
     184        self._checkXMLDefaults() 
     185        config.update({ 
     186            "DirectoryService": { 
     187                "type": SUPER_DUPER_DIRECTORY_SERVICE 
     188            } 
     189        }) 
     190        self._checkSuperDuperDefaults() 
    145191 
    146         config.update({"DirectoryService": {"type": "twistedcaldav.directory.appleopendirectory.OpenDirectoryService"}}) 
    147  
    148         self.assertEquals(config.DirectoryService["type"], "twistedcaldav.directory.appleopendirectory.OpenDirectoryService") 
    149         self.assertNotIn("xmlFile", config.DirectoryService["params"]) 
    150         self.assertEquals(config.DirectoryService["params"]["node"], "/Search") 
    151         self.assertEquals(config.DirectoryService["params"]["requireComputerRecord"], True) 
    152  
    153192    def testDirectoryService_newParam(self): 
    154         self.assertEquals(config.DirectoryService["type"], "twistedcaldav.directory.xmlfile.XMLDirectoryService") 
    155         self.assertEquals(config.DirectoryService["params"]["xmlFile"], "/etc/caldavd/accounts.xml") 
     193        self._checkXMLDefaults() 
     194        config.update({ 
     195            "DirectoryService": { 
     196                "type": SUPER_DUPER_DIRECTORY_SERVICE 
     197            } 
     198        }) 
     199        config.update({ 
     200            "DirectoryService": { 
     201                "params": {"superLevel": "!super" } 
     202            } 
     203        }) 
     204        self.assertEquals(self.ds["type"], SUPER_DUPER_DIRECTORY_SERVICE) 
     205        self.assertNotIn("xmlFile", self.ds["params"]) 
     206        self.assertEquals(self.ds["params"]["superLevel"], "!super") 
     207        self.assertEquals(self.ds["params"]["duperLevel"], "duper") 
     208     
     209    def testDirectoryService_newBadParam(self): 
     210        self._checkXMLDefaults() 
     211        self.assertRaises(ConfigurationError, config.update, { 
     212            "DirectoryService": { 
     213                "type": SUPER_DUPER_DIRECTORY_SERVICE, 
     214                "params": { 
     215                    "xmlFile": "/etc/caldavd/accounts.xml" 
     216                } 
     217            } 
     218        }) 
     219     
     220    def testDirectoryService_twoNewParams(self): 
     221        self._checkXMLDefaults() 
     222        config.update({ 
     223            "DirectoryService": { 
     224                "type": SUPER_DUPER_DIRECTORY_SERVICE 
     225            } 
     226        }) 
     227        config.update({ 
     228            "DirectoryService": { 
     229                "params": {"superLevel": "!super" } 
     230            } 
     231        }) 
     232        config.update({ 
     233            "DirectoryService": { 
     234                "params": {"duperLevel": "!duper" } 
     235            } 
     236        }) 
     237        self.assertEquals(self.ds["type"], SUPER_DUPER_DIRECTORY_SERVICE) 
     238        self.assertNotIn("xmlFile", self.ds["params"]) 
     239        self.assertEquals(self.ds["params"]["superLevel"], "!super") 
     240        self.assertEquals(self.ds["params"]["duperLevel"], "!duper") 
    156241 
    157         config.update({"DirectoryService": {"type": "twistedcaldav.directory.appleopendirectory.OpenDirectoryService"}}) 
    158         config.update({"DirectoryService": {"params": {"requireComputerRecord": False}}}) 
     242    def testDirectoryService_newTypeOD(self): 
     243        self._checkXMLDefaults() 
     244        config.update({"DirectoryService": {"type": OPEN_DIRECTORY_SERVICE}}) 
     245        self._checkODDefaults() 
    159246 
    160         self.assertEquals(config.DirectoryService["type"], "twistedcaldav.directory.appleopendirectory.OpenDirectoryService") 
    161         self.assertEquals(config.DirectoryService["params"]["node"], "/Search") 
    162         self.assertEquals(config.DirectoryService["params"]["requireComputerRecord"], False) 
     247    def testDirectoryService_newParamOD(self): 
     248        self._checkXMLDefaults() 
     249        config.update({"DirectoryService": {"type": OPEN_DIRECTORY_SERVICE}}) 
     250        config.update({ 
     251            "DirectoryService": { 
     252                "params": {"requireComputerRecord": False} 
     253            } 
     254        }) 
     255        self.assertEquals(self.ds["type"], OPEN_DIRECTORY_SERVICE) 
     256        self.assertEquals(self.ds["params"]["node"], "/Search") 
     257        self.assertEquals(self.ds["params"]["requireComputerRecord"], False) 
    163258 
    164259    def testDirectoryService_badParam(self): 
    165         self.assertEquals(config.DirectoryService["type"], "twistedcaldav.directory.xmlfile.XMLDirectoryService") 
    166         self.assertEquals(config.DirectoryService["params"]["xmlFile"], "/etc/caldavd/accounts.xml") 
     260        self._checkXMLDefaults() 
     261        self.assertRaises(ConfigurationError, config.update, { 
     262            "DirectoryService": { 
     263                "params": {"requireComputerRecord": False} 
     264            } 
     265        }) 
    167266 
    168         self.assertRaises(ConfigurationError, config.update, {"DirectoryService": {"params": {"requireComputerRecord": False}}}) 
    169  
    170267    def testDirectoryService_unknownType(self): 
    171         self.assertEquals(config.DirectoryService["type"], "twistedcaldav.directory.xmlfile.XMLDirectoryService") 
    172         self.assertEquals(config.DirectoryService["params"]["xmlFile"], "/etc/caldavd/accounts.xml") 
     268        self._checkXMLDefaults() 
     269        self.assertRaises(ConfigurationError, config.update, { 
     270            "DirectoryService": { 
     271                "type": "twistedcaldav.test.test_config.SuperDuperAwesomeService" 
     272            } 
     273        }) 
    173274 
    174         config.update({"DirectoryService": {"type": "twistedcaldav.test.test_config.SuperDuperAwesomeService"}}) 
    175  
    176         self.assertEquals( 
    177             config.DirectoryService["params"], 
    178             SuperDuperAwesomeService.defaultParameters 
    179         ) 
    180  
    181     testDirectoryService_unknownType.todo = "unimplemented" 
    182  
    183275    def testUpdateDefaults(self): 
    184276        self.assertEquals(config.SSLPort, 0) 
    185277