Ticket #136: extensible_config_v3.patch
| File extensible_config_v3.patch, 20.6 KB (added by callan@…, 3 years ago) |
|---|
-
config.py
20 20 import copy 21 21 22 22 from twisted.python import log 23 from twisted.python.reflect import namedClass 23 24 24 25 from twistedcaldav.py.plistlib import readPlist 25 26 27 def _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 26 38 defaultConfigFile = "/etc/caldavd/caldavd.plist" 27 39 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 } 40 defaultDirectoryService = \ 41 "twistedcaldav.directory.xmlfile.XMLDirectoryService" 37 42 43 defaultDirectoryServiceParams = \ 44 copy.deepcopy(_loadDirectoryService(defaultDirectoryService).defaultParams) 45 38 46 defaultConfig = { 39 47 # 40 48 # Public network address information … … 75 83 # users, groups, locations and resources) to the server. 76 84 # 77 85 "DirectoryService": { 78 "type": "twistedcaldav.directory.xmlfile.XMLDirectoryService",79 "params": serviceDefaultParams["twistedcaldav.directory.xmlfile.XMLDirectoryService"],86 "type": defaultDirectoryService, 87 "params": defaultDirectoryServiceParams, 80 88 }, 81 89 82 90 # … … 189 197 return str(self._data) 190 198 191 199 def update(self, items): 200 dsData = self._data["DirectoryService"] 192 201 dsType = items.get("DirectoryService", {}).get("type", None) 193 202 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) 205 205 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. 206 222 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)) 209 227 210 228 _mergeData(self._data, items) 211 229 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] 215 235 216 236 self.updateServerCapabilities() 217 237 -
directory/xmlfile.py
39 39 40 40 realmName = None 41 41 42 defaultParams = { 43 "xmlFile": "/etc/caldavd/accounts.xml", 44 } 45 42 46 def __repr__(self): 43 47 return "<%s %r: %r>" % (self.__class__.__name__, self.realmName, self.xmlFile) 44 48 -
directory/sqldb.py
285 285 baseGUID = "8256E464-35E0-4DBB-A99C-F0E30C231675" 286 286 realmName = None 287 287 288 defaultParams = { 289 "dbParentPath": "twistedcaldav/test/data/", 290 "xmlFile": None 291 } 292 288 293 def __repr__(self): 289 294 return "<%s %r: %r>" % (self.__class__.__name__, self.realmName, self.manager.dbpath) 290 295 -
directory/appleopendirectory.py
56 56 """ 57 57 baseGUID = "891F8321-ED02-424C-BA72-89C32F215C1E" 58 58 59 defaultParams = { 60 "node": "/Search", 61 "requireComputerRecord": True, 62 } 63 59 64 def __repr__(self): 60 65 return "<%s %r: %r>" % (self.__class__.__name__, self.realmName, self.node) 61 66 -
directory/idirectory.py
34 34 realmName = Attribute("The name of the authentication realm this service represents.") 35 35 guid = Attribute("A GUID for this service.") 36 36 37 defaultParams = Attribute("Default configuration parameters for this service.") 38 37 39 def recordTypes(): 38 40 """ 39 41 @return: a sequence of strings denoting the record types that are kept -
directory/principal.py
304 304 self.provision() 305 305 if name == "": 306 306 return self 307 # FIXME: Is this really the place for this? -- callan 308 name = unquote(name) 307 309 308 310 if "#" in name: 309 311 # This UID belongs to a sub-principal -
directory/apache.py
37 37 """ 38 38 Abstract Apache-compatible implementation of L{IDirectoryService}. 39 39 """ 40 41 defaultParams = { 42 "realmName": "example.com", 43 "userFile": "/etc/caldavd/basic", 44 "groupFile": None, 45 } 46 40 47 def __repr__(self): 41 48 return "<%s %r: %r %r>" % (self.__class__.__name__, self.realmName, self.userFile, self.groupFile) 42 49 -
test/test_config.py
21 21 from twistedcaldav.py.plistlib import writePlist 22 22 23 23 from twistedcaldav.config import config, defaultConfig, ConfigurationError 24 from twistedcaldav.directory.directory import DirectoryService 24 25 25 26 testConfig = """<?xml version="1.0" encoding="UTF-8"?> 26 27 <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> … … 34 35 </plist> 35 36 """ 36 37 38 XML_DIRECTORY_SERVICE = \ 39 "twistedcaldav.directory.xmlfile.XMLDirectoryService" 40 41 OPEN_DIRECTORY_SERVICE = \ 42 "twistedcaldav.directory.appleopendirectory.OpenDirectoryService" 43 44 SQL_DIRECTORY_SERVICE = \ 45 "twistedcaldav.directory.sqldb.SQLDirectoryService" 46 47 APACHE_BASIC_DIRECTORY_SERVICE = \ 48 "twistedcaldav.directory.apache.BasicDirectoryService" 49 50 APACHE_DIGEST_DIRECTORY_SERVICE = \ 51 "twistedcaldav.directory.apache.DigestDirectoryService" 52 53 SUPER_DUPER_DIRECTORY_SERVICE = \ 54 "twistedcaldav.test.test_config.SuperDuperService" 55 56 class 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 37 70 def _testVerbose(testCase): 38 71 from twistedcaldav.config import config 39 72 testCase.assertEquals(config.Verbose, True) … … 44 77 config.update(defaultConfig) 45 78 self.testConfig = self.mktemp() 46 79 open(self.testConfig, 'w').write(testConfig) 80 self.ds = config.DirectoryService 47 81 48 82 def tearDown(self): 49 83 config.setDefaults(defaultConfig) 50 84 config.loadConfig(None) 51 85 config.reload() 52 86 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 53 151 def testDefaults(self): 54 152 for key, value in defaultConfig.iteritems(): 55 153 self.assertEquals(getattr(config, key), value) … … 121 219 122 220 self.assertEquals(config.MultiProcess["LoadBalancer"]["Enabled"], True) 123 221 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 124 245 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() 128 247 config.update({"DirectoryService": {}}) 248 self._checkXMLDefaults() 129 249 130 self.assertEquals(config.DirectoryService["type"], "twistedcaldav.directory.xmlfile.XMLDirectoryService")131 self.assertEquals(config.DirectoryService["params"]["xmlFile"], "/etc/caldavd/accounts.xml")132 133 250 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() 136 254 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 142 255 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() 145 263 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") 147 313 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") 152 331 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() 156 336 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) 159 348 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 164 349 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 }) 167 356 168 self.assertRaises(ConfigurationError, config.update, {"DirectoryService": {"params": {"requireComputerRecord": False}}})169 170 357 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 }) 173 364 174 config.update({"DirectoryService": {"type": "twistedcaldav.test.test_config.SuperDuperAwesomeService"}})175 176 self.assertEquals(177 config.DirectoryService["params"],178 SuperDuperAwesomeService.defaultParameters179 )180 181 testDirectoryService_unknownType.todo = "unimplemented"182 183 365 def testUpdateDefaults(self): 184 366 self.assertEquals(config.SSLPort, 0) 185 367
