Projects
Wiki     Timeline     Roadmap     Browse Source     View Tickets     New Ticket     Search

Ticket #136: extensible_config_v2.patch

File extensible_config_v2.patch, 19.2 KB (added by callan@…, 3 years ago)

After being reminded via e-mail by several people of the existence of other DirectoryService instances such as the ApacheDirectoryService I've made sure each of these has defaultParams and a test to ensure that it actually loads correctly.

  • 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/sqldb.py

     
    285285    baseGUID = "8256E464-35E0-4DBB-A99C-F0E30C231675" 
    286286    realmName = None 
    287287 
     288    defaultParams = { 
     289        "dbParentPath": "twistedcaldav/test/data/", 
     290        "xmlFile": None 
     291    } 
     292 
    288293    def __repr__(self): 
    289294        return "<%s %r: %r>" % (self.__class__.__name__, self.realmName, self.manager.dbpath) 
    290295 
  • 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 
  • directory/apache.py

     
    3737    """ 
    3838    Abstract Apache-compatible implementation of L{IDirectoryService}. 
    3939    """ 
     40 
     41    defaultParams = { 
     42        "realmName": "example.com", 
     43        "userFile": "/etc/caldavd/basic", 
     44        "groupFile": None, 
     45    } 
     46 
    4047    def __repr__(self): 
    4148        return "<%s %r: %r %r>" % (self.__class__.__name__, self.realmName, self.userFile, self.groupFile) 
    4249 
  • 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 
     44SQL_DIRECTORY_SERVICE = \ 
     45    "twistedcaldav.directory.sqldb.SQLDirectoryService" 
     46 
     47APACHE_BASIC_DIRECTORY_SERVICE = \ 
     48    "twistedcaldav.directory.apache.BasicDirectoryService" 
     49 
     50APACHE_DIGEST_DIRECTORY_SERVICE = \ 
     51    "twistedcaldav.directory.apache.DigestDirectoryService" 
     52 
     53SUPER_DUPER_DIRECTORY_SERVICE = \ 
     54    "twistedcaldav.test.test_config.SuperDuperService" 
     55 
     56class SuperDuperService(DirectoryService): 
     57    """ 
     58    A super duper directory service that's super duper effective at being 
     59    used for testing but not awesome. 
     60    """ 
     61    defaultParams = { 
     62        "superLevel": "super", 
     63        "duperLevel": "duper", 
     64    } 
     65 
    3766def _testVerbose(testCase): 
    3867    from twistedcaldav.config import config 
    3968    testCase.assertEquals(config.Verbose, True) 
     
    4473        config.update(defaultConfig) 
    4574        self.testConfig = self.mktemp() 
    4675        open(self.testConfig, 'w').write(testConfig) 
     76        self.ds = config.DirectoryService 
    4777 
    4878    def tearDown(self): 
    4979        config.setDefaults(defaultConfig) 
    5080        config.loadConfig(None) 
    5181        config.reload() 
    5282 
     83    def _checkXMLDefaults(self): 
     84        """ 
     85        Checks that the base XML directory service defaults are correct. 
     86        """ 
     87        self.assertEquals(self.ds["type"], XML_DIRECTORY_SERVICE) 
     88        self.assertEquals(self.ds["params"]["xmlFile"], 
     89                          "/etc/caldavd/accounts.xml") 
     90 
     91    def _checkODDefaults(self): 
     92        """ 
     93        Checks that the base Apple open directory service defaults are correct. 
     94        """ 
     95        self.assertEquals(self.ds["type"], OPEN_DIRECTORY_SERVICE) 
     96        self.assertNotIn("xmlFile", self.ds["params"]) 
     97        self.assertEquals(self.ds["params"]["node"], "/Search") 
     98        self.assertEquals(self.ds["params"]["requireComputerRecord"], True) 
     99     
     100    def _checkSQLDefaults(self): 
     101        """ 
     102        Checks that the base SQL directory service defaults are correct. 
     103        """ 
     104        self.assertEquals(self.ds["type"], SQL_DIRECTORY_SERVICE) 
     105        self.assertEquals(self.ds["params"]["dbParentPath"], 
     106                          "twistedcaldav/test/data/") 
     107        self.assertEquals(self.ds["params"]["xmlFile"], None) 
     108 
     109    def _checkApacheBaseDefaults(self): 
     110        """ 
     111        Checks that the base Apache open directory service parameters are correct. 
     112        """ 
     113        self.assertEquals(self.ds["params"]["realmName"], "example.com") 
     114        self.assertEquals(self.ds["params"]["userFile"], "/etc/caldavd/basic") 
     115        self.assertEquals(self.ds["params"]["groupFile"], None) 
     116 
     117    def _checkApacheBasicDefaults(self): 
     118        """ 
     119        Checks that the base Apache basic authentication directory service 
     120        defaults are correct. 
     121        """ 
     122        self.assertEquals(self.ds["type"], APACHE_BASIC_DIRECTORY_SERVICE) 
     123        self.assertNotIn("xmlFile", self.ds["params"]) 
     124        self._checkApacheBaseDefaults() 
     125     
     126    def _checkApacheDigestDefaults(self): 
     127        """ 
     128        Checks that the base Apache digest authentication directory service 
     129        defaults are correct. 
     130        """ 
     131        self.assertEquals(self.ds["type"], APACHE_DIGEST_DIRECTORY_SERVICE) 
     132        self.assertNotIn("xmlFile", self.ds["params"]) 
     133        self._checkApacheBaseDefaults() 
     134 
     135    def _checkSuperDuperDefaults(self): 
     136        """ 
     137        Checks that the base super duper test-only directory service defaults 
     138        are correct. 
     139        """ 
     140        self.assertEquals(self.ds["type"], SUPER_DUPER_DIRECTORY_SERVICE) 
     141        self.assertNotIn("xmlFile", self.ds["params"]) 
     142        self.assertEquals(self.ds["params"]["superLevel"], "super") 
     143        self.assertEquals(self.ds["params"]["duperLevel"], "duper") 
     144 
    53145    def testDefaults(self): 
    54146        for key, value in defaultConfig.iteritems(): 
    55147            self.assertEquals(getattr(config, key), value) 
     
    121213 
    122214        self.assertEquals(config.MultiProcess["LoadBalancer"]["Enabled"], True) 
    123215 
     216    def testDirectoryService_loadSQL(self): 
     217        self._checkXMLDefaults() 
     218        config.update({"DirectoryService": {"type": SQL_DIRECTORY_SERVICE}}) 
     219        self._checkSQLDefaults() 
     220     
     221    def testDirectoryService_loadApacheBasic(self): 
     222        self._checkXMLDefaults() 
     223        config.update({ 
     224            "DirectoryService": { 
     225                "type": APACHE_BASIC_DIRECTORY_SERVICE 
     226            } 
     227        }) 
     228        self._checkApacheBasicDefaults() 
     229 
     230    def testDirectoryService_loadApacheDigest(self): 
     231        self._checkXMLDefaults() 
     232        config.update({ 
     233            "DirectoryService": { 
     234                "type": APACHE_DIGEST_DIRECTORY_SERVICE 
     235            } 
     236        }) 
     237        self._checkApacheDigestDefaults() 
     238 
    124239    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  
     240        self._checkXMLDefaults() 
    128241        config.update({"DirectoryService": {}}) 
     242        self._checkXMLDefaults() 
    129243 
    130         self.assertEquals(config.DirectoryService["type"], "twistedcaldav.directory.xmlfile.XMLDirectoryService") 
    131         self.assertEquals(config.DirectoryService["params"]["xmlFile"], "/etc/caldavd/accounts.xml") 
    132  
    133244    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") 
     245        self._checkXMLDefaults() 
     246        config.update({"DirectoryService": {"type": XML_DIRECTORY_SERVICE}}) 
     247        self._checkXMLDefaults() 
    136248 
    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  
    142249    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") 
     250        self._checkXMLDefaults() 
     251        config.update({ 
     252            "DirectoryService": { 
     253                "type": SUPER_DUPER_DIRECTORY_SERVICE 
     254            } 
     255        }) 
     256        self._checkSuperDuperDefaults() 
    145257 
    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  
    153258    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") 
     259        self._checkXMLDefaults() 
     260        config.update({ 
     261            "DirectoryService": { 
     262                "type": SUPER_DUPER_DIRECTORY_SERVICE 
     263            } 
     264        }) 
     265        config.update({ 
     266            "DirectoryService": { 
     267                "params": {"superLevel": "!super" } 
     268            } 
     269        }) 
     270        self.assertEquals(self.ds["type"], SUPER_DUPER_DIRECTORY_SERVICE) 
     271        self.assertNotIn("xmlFile", self.ds["params"]) 
     272        self.assertEquals(self.ds["params"]["superLevel"], "!super") 
     273        self.assertEquals(self.ds["params"]["duperLevel"], "duper") 
     274     
     275    def testDirectoryService_newBadParam(self): 
     276        self._checkXMLDefaults() 
     277        self.assertRaises(ConfigurationError, config.update, { 
     278            "DirectoryService": { 
     279                "type": SUPER_DUPER_DIRECTORY_SERVICE, 
     280                "params": { 
     281                    "xmlFile": "/etc/caldavd/accounts.xml" 
     282                } 
     283            } 
     284        }) 
     285     
     286    def testDirectoryService_twoNewParams(self): 
     287        self._checkXMLDefaults() 
     288        config.update({ 
     289            "DirectoryService": { 
     290                "type": SUPER_DUPER_DIRECTORY_SERVICE 
     291            } 
     292        }) 
     293        config.update({ 
     294            "DirectoryService": { 
     295                "params": {"superLevel": "!super" } 
     296            } 
     297        }) 
     298        config.update({ 
     299            "DirectoryService": { 
     300                "params": {"duperLevel": "!duper" } 
     301            } 
     302        }) 
     303        self.assertEquals(self.ds["type"], SUPER_DUPER_DIRECTORY_SERVICE) 
     304        self.assertNotIn("xmlFile", self.ds["params"]) 
     305        self.assertEquals(self.ds["params"]["superLevel"], "!super") 
     306        self.assertEquals(self.ds["params"]["duperLevel"], "!duper") 
    156307 
    157         config.update({"DirectoryService": {"type": "twistedcaldav.directory.appleopendirectory.OpenDirectoryService"}}) 
    158         config.update({"DirectoryService": {"params": {"requireComputerRecord": False}}}) 
     308    def testDirectoryService_newTypeOD(self): 
     309        self._checkXMLDefaults() 
     310        config.update({"DirectoryService": {"type": OPEN_DIRECTORY_SERVICE}}) 
     311        self._checkODDefaults() 
    159312 
    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) 
     313    def testDirectoryService_newParamOD(self): 
     314        self._checkXMLDefaults() 
     315        config.update({"DirectoryService": {"type": OPEN_DIRECTORY_SERVICE}}) 
     316        config.update({ 
     317            "DirectoryService": { 
     318                "params": {"requireComputerRecord": False} 
     319            } 
     320        }) 
     321        self.assertEquals(self.ds["type"], OPEN_DIRECTORY_SERVICE) 
     322        self.assertEquals(self.ds["params"]["node"], "/Search") 
     323        self.assertEquals(self.ds["params"]["requireComputerRecord"], False) 
    163324 
    164325    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") 
     326        self._checkXMLDefaults() 
     327        self.assertRaises(ConfigurationError, config.update, { 
     328            "DirectoryService": { 
     329                "params": {"requireComputerRecord": False} 
     330            } 
     331        }) 
    167332 
    168         self.assertRaises(ConfigurationError, config.update, {"DirectoryService": {"params": {"requireComputerRecord": False}}}) 
    169  
    170333    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") 
     334        self._checkXMLDefaults() 
     335        self.assertRaises(ConfigurationError, config.update, { 
     336            "DirectoryService": { 
     337                "type": "twistedcaldav.test.test_config.SuperDuperAwesomeService" 
     338            } 
     339        }) 
    173340 
    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  
    183341    def testUpdateDefaults(self): 
    184342        self.assertEquals(config.SSLPort, 0) 
    185343