Projects
Wiki     Timeline     Roadmap     Browse Source     View Tickets     New Ticket     Search

Ticket #136: extensible_config_v3.patch

File extensible_config_v3.patch, 20.6 KB (added by callan@…, 3 years ago)

Updated patch with test cases covering the possibility of dictionary based parameters

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

     
    304304        self.provision() 
    305305        if name == "": 
    306306            return self 
     307        # FIXME: Is this really the place for this? -- callan 
     308        name = unquote(name) 
    307309 
    308310        if "#" in name: 
    309311            # This UID belongs to a sub-principal 
  • 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        "dictParam": { 
     65            "keyA": "valueA", 
     66            "keyB": "valueB", 
     67        } 
     68    } 
     69 
    3770def _testVerbose(testCase): 
    3871    from twistedcaldav.config import config 
    3972    testCase.assertEquals(config.Verbose, True) 
     
    4477        config.update(defaultConfig) 
    4578        self.testConfig = self.mktemp() 
    4679        open(self.testConfig, 'w').write(testConfig) 
     80        self.ds = config.DirectoryService 
    4781 
    4882    def tearDown(self): 
    4983        config.setDefaults(defaultConfig) 
    5084        config.loadConfig(None) 
    5185        config.reload() 
    5286 
     87    def _checkXMLDefaults(self): 
     88        """ 
     89        Checks that the base XML directory service defaults are correct. 
     90        """ 
     91        self.assertEquals(self.ds["type"], XML_DIRECTORY_SERVICE) 
     92        self.assertEquals(self.ds["params"]["xmlFile"], 
     93                          "/etc/caldavd/accounts.xml") 
     94 
     95    def _checkODDefaults(self): 
     96        """ 
     97        Checks that the base Apple open directory service defaults are correct. 
     98        """ 
     99        self.assertEquals(self.ds["type"], OPEN_DIRECTORY_SERVICE) 
     100        self.assertNotIn("xmlFile", self.ds["params"]) 
     101        self.assertEquals(self.ds["params"]["node"], "/Search") 
     102        self.assertEquals(self.ds["params"]["requireComputerRecord"], True) 
     103     
     104    def _checkSQLDefaults(self): 
     105        """ 
     106        Checks that the base SQL directory service defaults are correct. 
     107        """ 
     108        self.assertEquals(self.ds["type"], SQL_DIRECTORY_SERVICE) 
     109        self.assertEquals(self.ds["params"]["dbParentPath"], 
     110                          "twistedcaldav/test/data/") 
     111        self.assertEquals(self.ds["params"]["xmlFile"], None) 
     112 
     113    def _checkApacheBaseDefaults(self): 
     114        """ 
     115        Checks that the base Apache open directory service parameters are correct. 
     116        """ 
     117        self.assertEquals(self.ds["params"]["realmName"], "example.com") 
     118        self.assertEquals(self.ds["params"]["userFile"], "/etc/caldavd/basic") 
     119        self.assertEquals(self.ds["params"]["groupFile"], None) 
     120 
     121    def _checkApacheBasicDefaults(self): 
     122        """ 
     123        Checks that the base Apache basic authentication directory service 
     124        defaults are correct. 
     125        """ 
     126        self.assertEquals(self.ds["type"], APACHE_BASIC_DIRECTORY_SERVICE) 
     127        self.assertNotIn("xmlFile", self.ds["params"]) 
     128        self._checkApacheBaseDefaults() 
     129     
     130    def _checkApacheDigestDefaults(self): 
     131        """ 
     132        Checks that the base Apache digest authentication directory service 
     133        defaults are correct. 
     134        """ 
     135        self.assertEquals(self.ds["type"], APACHE_DIGEST_DIRECTORY_SERVICE) 
     136        self.assertNotIn("xmlFile", self.ds["params"]) 
     137        self._checkApacheBaseDefaults() 
     138 
     139    def _checkSuperDuperDefaults(self): 
     140        """ 
     141        Checks that the base super duper test-only directory service defaults 
     142        are correct. 
     143        """ 
     144        self.assertEquals(self.ds["type"], SUPER_DUPER_DIRECTORY_SERVICE) 
     145        self.assertNotIn("xmlFile", self.ds["params"]) 
     146        self.assertEquals(self.ds["params"]["superLevel"], "super") 
     147        self.assertEquals(self.ds["params"]["duperLevel"], "duper") 
     148        self.assertEquals(self.ds["params"]["dictParam"]["keyA"], "valueA") 
     149        self.assertEquals(self.ds["params"]["dictParam"]["keyB"], "valueB") 
     150 
    53151    def testDefaults(self): 
    54152        for key, value in defaultConfig.iteritems(): 
    55153            self.assertEquals(getattr(config, key), value) 
     
    121219 
    122220        self.assertEquals(config.MultiProcess["LoadBalancer"]["Enabled"], True) 
    123221 
     222    def testDirectoryService_loadSQL(self): 
     223        self._checkXMLDefaults() 
     224        config.update({"DirectoryService": {"type": SQL_DIRECTORY_SERVICE}}) 
     225        self._checkSQLDefaults() 
     226     
     227    def testDirectoryService_loadApacheBasic(self): 
     228        self._checkXMLDefaults() 
     229        config.update({ 
     230            "DirectoryService": { 
     231                "type": APACHE_BASIC_DIRECTORY_SERVICE 
     232            } 
     233        }) 
     234        self._checkApacheBasicDefaults() 
     235 
     236    def testDirectoryService_loadApacheDigest(self): 
     237        self._checkXMLDefaults() 
     238        config.update({ 
     239            "DirectoryService": { 
     240                "type": APACHE_DIGEST_DIRECTORY_SERVICE 
     241            } 
     242        }) 
     243        self._checkApacheDigestDefaults() 
     244 
    124245    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  
     246        self._checkXMLDefaults() 
    128247        config.update({"DirectoryService": {}}) 
     248        self._checkXMLDefaults() 
    129249 
    130         self.assertEquals(config.DirectoryService["type"], "twistedcaldav.directory.xmlfile.XMLDirectoryService") 
    131         self.assertEquals(config.DirectoryService["params"]["xmlFile"], "/etc/caldavd/accounts.xml") 
    132  
    133250    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") 
     251        self._checkXMLDefaults() 
     252        config.update({"DirectoryService": {"type": XML_DIRECTORY_SERVICE}}) 
     253        self._checkXMLDefaults() 
    136254 
    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  
    142255    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") 
     256        self._checkXMLDefaults() 
     257        config.update({ 
     258            "DirectoryService": { 
     259                "type": SUPER_DUPER_DIRECTORY_SERVICE 
     260            } 
     261        }) 
     262        self._checkSuperDuperDefaults() 
    145263 
    146         config.update({"DirectoryService": {"type": "twistedcaldav.directory.appleopendirectory.OpenDirectoryService"}}) 
     264    def testDirectoryService_newParam(self): 
     265        self._checkXMLDefaults() 
     266        config.update({ 
     267            "DirectoryService": { 
     268                "type": SUPER_DUPER_DIRECTORY_SERVICE 
     269            } 
     270        }) 
     271        config.update({ 
     272            "DirectoryService": { 
     273                "params": {"superLevel": "!super" } 
     274            } 
     275        }) 
     276        self.assertEquals(self.ds["type"], SUPER_DUPER_DIRECTORY_SERVICE) 
     277        self.assertNotIn("xmlFile", self.ds["params"]) 
     278        self.assertEquals(self.ds["params"]["superLevel"], "!super") 
     279        self.assertEquals(self.ds["params"]["duperLevel"], "duper") 
     280     
     281    def testDirectoryService_newBadParam(self): 
     282        self._checkXMLDefaults() 
     283        self.assertRaises(ConfigurationError, config.update, { 
     284            "DirectoryService": { 
     285                "type": SUPER_DUPER_DIRECTORY_SERVICE, 
     286                "params": { 
     287                    "xmlFile": "/etc/caldavd/accounts.xml" 
     288                } 
     289            } 
     290        }) 
     291     
     292    def testDirectoryService_twoNewParams(self): 
     293        self._checkXMLDefaults() 
     294        config.update({ 
     295            "DirectoryService": { 
     296                "type": SUPER_DUPER_DIRECTORY_SERVICE 
     297            } 
     298        }) 
     299        config.update({ 
     300            "DirectoryService": { 
     301                "params": {"superLevel": "!super" } 
     302            } 
     303        }) 
     304        config.update({ 
     305            "DirectoryService": { 
     306                "params": {"duperLevel": "!duper" } 
     307            } 
     308        }) 
     309        self.assertEquals(self.ds["type"], SUPER_DUPER_DIRECTORY_SERVICE) 
     310        self.assertNotIn("xmlFile", self.ds["params"]) 
     311        self.assertEquals(self.ds["params"]["superLevel"], "!super") 
     312        self.assertEquals(self.ds["params"]["duperLevel"], "!duper") 
    147313 
    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) 
     314    def testDirectoryService_newDictParam(self): 
     315        self._checkXMLDefaults() 
     316        config.update({ 
     317            "DirectoryService": { 
     318                "type": SUPER_DUPER_DIRECTORY_SERVICE 
     319            } 
     320        }) 
     321        config.update({ 
     322            "DirectoryService": { 
     323                "params": { 
     324                    "dictParam": {"keyB": "!valueB"} 
     325                } 
     326            } 
     327        }) 
     328        self.assertEquals(self.ds["type"], SUPER_DUPER_DIRECTORY_SERVICE) 
     329        self.assertNotIn("xmlFile", self.ds["params"]) 
     330        self.assertEquals(self.ds["params"]["dictParam"]["keyB"], "!valueB") 
    152331 
    153     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") 
     332    def testDirectoryService_newTypeOD(self): 
     333        self._checkXMLDefaults() 
     334        config.update({"DirectoryService": {"type": OPEN_DIRECTORY_SERVICE}}) 
     335        self._checkODDefaults() 
    156336 
    157         config.update({"DirectoryService": {"type": "twistedcaldav.directory.appleopendirectory.OpenDirectoryService"}}) 
    158         config.update({"DirectoryService": {"params": {"requireComputerRecord": False}}}) 
     337    def testDirectoryService_newParamOD(self): 
     338        self._checkXMLDefaults() 
     339        config.update({"DirectoryService": {"type": OPEN_DIRECTORY_SERVICE}}) 
     340        config.update({ 
     341            "DirectoryService": { 
     342                "params": {"requireComputerRecord": False} 
     343            } 
     344        }) 
     345        self.assertEquals(self.ds["type"], OPEN_DIRECTORY_SERVICE) 
     346        self.assertEquals(self.ds["params"]["node"], "/Search") 
     347        self.assertEquals(self.ds["params"]["requireComputerRecord"], False) 
    159348 
    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) 
    163  
    164349    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") 
     350        self._checkXMLDefaults() 
     351        self.assertRaises(ConfigurationError, config.update, { 
     352            "DirectoryService": { 
     353                "params": {"requireComputerRecord": False} 
     354            } 
     355        }) 
    167356 
    168         self.assertRaises(ConfigurationError, config.update, {"DirectoryService": {"params": {"requireComputerRecord": False}}}) 
    169  
    170357    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") 
     358        self._checkXMLDefaults() 
     359        self.assertRaises(ConfigurationError, config.update, { 
     360            "DirectoryService": { 
     361                "type": "twistedcaldav.test.test_config.SuperDuperAwesomeService" 
     362            } 
     363        }) 
    173364 
    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  
    183365    def testUpdateDefaults(self): 
    184366        self.assertEquals(config.SSLPort, 0) 
    185367