Ticket #136: extensible_config.patch
| File extensible_config.patch, 15.7 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/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 -
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 SUPER_DUPER_DIRECTORY_SERVICE = \ 45 "twistedcaldav.test.test_config.SuperDuperService" 46 47 class 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 37 57 def _testVerbose(testCase): 38 58 from twistedcaldav.config import config 39 59 testCase.assertEquals(config.Verbose, True) … … 44 64 config.update(defaultConfig) 45 65 self.testConfig = self.mktemp() 46 66 open(self.testConfig, 'w').write(testConfig) 67 self.ds = config.DirectoryService 47 68 48 69 def tearDown(self): 49 70 config.setDefaults(defaultConfig) 50 71 config.loadConfig(None) 51 72 config.reload() 52 73 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 53 102 def testDefaults(self): 54 103 for key, value in defaultConfig.iteritems(): 55 104 self.assertEquals(getattr(config, key), value) … … 122 171 self.assertEquals(config.MultiProcess["LoadBalancer"]["Enabled"], True) 123 172 124 173 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() 128 175 config.update({"DirectoryService": {}}) 176 self._checkXMLDefaults() 129 177 130 self.assertEquals(config.DirectoryService["type"], "twistedcaldav.directory.xmlfile.XMLDirectoryService")131 self.assertEquals(config.DirectoryService["params"]["xmlFile"], "/etc/caldavd/accounts.xml")132 133 178 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() 136 182 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 183 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() 145 191 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 153 192 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") 156 241 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() 159 246 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) 163 258 164 259 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 }) 167 266 168 self.assertRaises(ConfigurationError, config.update, {"DirectoryService": {"params": {"requireComputerRecord": False}}})169 170 267 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 }) 173 274 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 275 def testUpdateDefaults(self): 184 276 self.assertEquals(config.SSLPort, 0) 185 277
