# HG changeset patch # User Pascal Volk # Date 1281325708 0 # Node ID 2ae40cd0d2131cb7f26fd4d135fe518b34639db9 # Parent 22d115376e4dc3a70ae43ce0a6e85f6a6d062f2b VMM/config: Extended configuration check and raise only a ConfigError. Added new settings 'module', 'port', and 'sslmode' to the database section. diff -r 22d115376e4d -r 2ae40cd0d213 VirtualMailManager/config.py --- a/VirtualMailManager/config.py Sat Aug 07 20:01:19 2010 +0000 +++ b/VirtualMailManager/config.py Mon Aug 09 03:48:28 2010 +0000 @@ -11,7 +11,7 @@ from ConfigParser import \ Error, MissingSectionHeaderError, NoOptionError, NoSectionError, \ ParsingError, RawConfigParser -from cStringIO import StringIO# TODO: move interactive stff to cli +from cStringIO import StringIO from VirtualMailManager.common import VERSION_RE, \ exec_ok, expand_path, get_unicode, lisdir, version_hex @@ -20,6 +20,9 @@ from VirtualMailManager.maillocation import known_format from VirtualMailManager.password import verify_scheme as _verify_scheme +DB_MUDULES = ('psycopg2', 'pypgsql') +DB_SSL_MODES = ('allow', 'disabled', 'prefer', 'require', 'verify-ca', + 'verify-full') _ = lambda msg: msg @@ -291,7 +294,7 @@ LazyConfig.__init__(self) self._cfg_filename = filename self._cfg_file = None - self.__missing = {} + self._missing = {} LCO = LazyConfigOption bool_t = self.bool_new @@ -315,8 +318,11 @@ }, 'database': { 'host': LCO(str, 'localhost', self.get), + 'module': LCO(str, 'psycopg2', self.get, check_db_module), 'name': LCO(str, 'mailsys', self.get), 'pass': LCO(str, None, self.get), + 'port': LCO(int, 5432, self.getint), + 'sslmode': LCO(str, 'prefer', self.get, check_db_ssl_mode), 'user': LCO(str, None, self.get), }, 'domain': { @@ -364,22 +370,36 @@ """Performs a configuration check. Raises a ConfigError if settings w/o a default value are missed. - Or a ConfigValueError if 'misc.dovecot_version' has the wrong - format. + Or some settings have a invalid value. """ - # TODO: There are only two settings w/o defaults. - # So there is no need for cStringIO - if not self._chk_cfg(): + def iter_dict(): + for section, options in self._missing.iteritems(): + errmsg.write(_(u'* Section: %s\n') % section) + errmsg.writelines(u' %s\n' % option for option in options) + self._missing.clear() + + errmsg = None + self._chk_non_default() + miss_vers = 'misc' in self._missing and \ + 'dovecot_version' in self._missing['misc'] + if self._missing: errmsg = StringIO() + errmsg.write(_(u'Check of configuration file %s failed.\n') % + self._cfg_filename) errmsg.write(_(u'Missing options, which have no default value.\n')) - errmsg.write(_(u'Using configuration file: %s\n') % - self._cfg_filename) - for section, options in self.__missing.iteritems(): - errmsg.write(_(u'* Section: %s\n') % section) - for option in options: - errmsg.write((u' %s\n') % option) + iter_dict() + self._chk_possible_values(miss_vers) + if self._missing: + if not errmsg: + errmsg = StringIO() + errmsg.write(_(u'Check of configuration file %s failed.\n') % + self._cfg_filename) + errmsg.write(_(u'Invalid configuration values.\n')) + else: + errmsg.write('\n' + _(u'Invalid configuration values.\n')) + iter_dict() + if errmsg: raise ConfigError(errmsg.getvalue(), CONF_ERROR) - check_version_format(self.get('misc', 'dovecot_version')) def hexversion(self, section, option): """Converts the version number (e.g.: 1.2.3) from the *option*'s @@ -391,23 +411,38 @@ to Unicode.""" return get_unicode(self.get(section, option)) - def _chk_cfg(self): + def _chk_non_default(self): """Checks all section's options for settings w/o a default - value. - - Returns `True` if everything is fine, else `False`. + value. Missing items will be stored in _missing. """ - errors = False for section in self._cfg.iterkeys(): missing = [] for option, value in self._cfg[section].iteritems(): if (value.default is None and not RawConfigParser.has_option(self, section, option)): missing.append(option) - errors = True if missing: - self.__missing[section] = missing - return not errors + self._missing[section] = missing + + def _chk_possible_values(self, miss_vers): + """Check settings for which the possible values are known.""" + if not miss_vers: + value = self.get('misc', 'dovecot_version') + if not VERSION_RE.match(value): + self._missing['misc'] = ['version: ' +\ + _(u"Not a valid Dovecot version: '%s'") % value] + db_err = [] + value = self.dget('database.module').lower() + if value not in DB_MUDULES: + db_err.append('module: ' + \ + _(u"Unsupported database module: '%s'") % value) + if value == 'psycopg2': + value = self.dget('database.sslmode') + if value not in DB_SSL_MODES: + db_err.append('sslmode: ' + \ + _(u"Unknown pgsql SSL mode: '%s'") % value) + if db_err: + self._missing['database'] = db_err def is_dir(path): @@ -421,6 +456,22 @@ raise ConfigValueError(_(u"No such directory: %s") % get_unicode(path)) +def check_db_module(module): + """Check if the *module* is a supported pgsql module.""" + if module.lower() in DB_MUDULES: + return module + raise ConfigValueError(_(u"Unsupported database module: '%s'") % + get_unicode(module)) + + +def check_db_ssl_mode(ssl_mode): + """Check if the *ssl_mode* is one of the SSL modes, known by pgsql.""" + if ssl_mode in DB_SSL_MODES: + return ssl_mode + raise ConfigValueError(_(u"Unknown pgsql SSL mode: '%s'") % + get_unicode(ssl_mode)) + + def check_mailbox_format(format): """ Check if the mailbox format *format* is supported. When the *format*