diff options
-rw-r--r-- | ipalib/cli.py | 4 | ||||
-rw-r--r-- | ipalib/constants.py | 4 | ||||
-rw-r--r-- | ipalib/errors2.py | 32 | ||||
-rw-r--r-- | ipalib/frontend.py | 22 | ||||
-rw-r--r-- | ipalib/parameters.py | 5 | ||||
-rw-r--r-- | ipalib/plugins/misc.py | 2 | ||||
-rw-r--r-- | ipaserver/rpcserver.py | 4 | ||||
-rw-r--r-- | tests/test_ipalib/test_frontend.py | 4 |
8 files changed, 55 insertions, 22 deletions
diff --git a/ipalib/cli.py b/ipalib/cli.py index 6b3ab7e5b..0afe09c46 100644 --- a/ipalib/cli.py +++ b/ipalib/cli.py @@ -36,7 +36,7 @@ import frontend import backend import plugable import util -from errors2 import PublicError, CommandError +from errors2 import PublicError, CommandError, HelpError from constants import CLI_TAB from parameters import Password, Bytes @@ -398,7 +398,7 @@ class help(frontend.Application): return key = str(command) if key not in self.application: - raise errors.UnknownHelpError(key) + raise HelpError(topic=key) cmd = self.application[key] print 'Purpose: %s' % cmd.doc self.application.build_parser(cmd).print_help() diff --git a/ipalib/constants.py b/ipalib/constants.py index 14f7f25d4..13a60f2ba 100644 --- a/ipalib/constants.py +++ b/ipalib/constants.py @@ -61,10 +61,10 @@ FORMAT_STDERR = ': '.join([ # Log format for log file: FORMAT_FILE = '\t'.join([ '%(created)f', - '%(levelname)s', - '%(message)r', # Using %r for repr() so message is a single line '%(process)d', '%(threadName)s', + '%(levelname)s', + '%(message)r', # Using %r for repr() so message is a single line ]) diff --git a/ipalib/errors2.py b/ipalib/errors2.py index 042580936..91b231159 100644 --- a/ipalib/errors2.py +++ b/ipalib/errors2.py @@ -85,7 +85,9 @@ current block assignments: - **4001 - 4099** Open for general execution errors - - **4100 - 4199** `LDAPError` and its subclasses + - **4100 - 4199** `BuiltinError` and its subclasses + + - **4200 - 4299** `LDAPError` and its subclasses - **4300 - 4999** *Reserved for future use* @@ -581,14 +583,38 @@ class ExecutionError(PublicError): errno = 4000 -class LDAPError(ExecutionError): +class BuiltinError(ExecutionError): """ - **4100** Base class for LDAP execution errors (*4100 - 4199*). + **4100** Base class for builtin execution errors (*4100 - 4199*). """ errno = 4100 +class HelpError(BuiltinError): + """ + **4101** Raised when requesting help for an unknown topic. + + For example: + + >>> raise HelpError(topic='newfeature') + Traceback (most recent call last): + ... + HelpError: no command nor help topic 'newfeature' + """ + + errno = 4101 + format = _('no command nor help topic %(topic)r') + + +class LDAPError(ExecutionError): + """ + **4200** Base class for LDAP execution errors (*4200 - 4299*). + """ + + errno = 4200 + + ############################################################################## # 5000 - 5999: Generic errors diff --git a/ipalib/frontend.py b/ipalib/frontend.py index 6efccbb4d..565060b5d 100644 --- a/ipalib/frontend.py +++ b/ipalib/frontend.py @@ -97,17 +97,28 @@ class Command(plugable.Plugin): XML-RPC and the executed an the nearest IPA server. """ params = self.args_options_2_params(*args, **options) + self.info( + '%s(%s)', self.name, ', '.join(self.__repr_iter(params)) + ) params = self.normalize(**params) params = self.convert(**params) params.update(self.get_default(**params)) self.validate(**params) (args, options) = self.params_2_args_options(**params) - # FIXME: don't log passords! - self.info(make_repr(self.name, *args, **options)) result = self.run(*args, **options) - self.debug('%s result: %r', self.name, result) + self.debug('result from %s(): %r', self.name, result) return result + def __repr_iter(self, params): + for arg in self.args(): + value = params.get(arg.name, None) + yield '%r' % (arg.safe_value(value),) + for option in self.options(): + if option.name not in params: + continue + value = params[option.name] + yield '%s=%r' % (option.name, option.safe_value(value)) + def args_options_2_params(self, *args, **options): """ Merge (args, options) into params. @@ -245,10 +256,7 @@ class Command(plugable.Plugin): """ for param in self.params(): value = kw.get(param.name, None) - if value is not None: - param.validate(value) - elif param.required: - raise errors.RequirementError(param.name) + param.validate(value) def run(self, *args, **options): """ diff --git a/ipalib/parameters.py b/ipalib/parameters.py index fc6880747..0cf6a1f75 100644 --- a/ipalib/parameters.py +++ b/ipalib/parameters.py @@ -353,6 +353,11 @@ class Param(ReadOnly): self.validate(value) return value + def safe_value(self, value): + if isinstance(self, Password) and value is not None: + return u'********' + return value + def clone(self, **overrides): """ Return a new `Param` instance similar to this one. diff --git a/ipalib/plugins/misc.py b/ipalib/plugins/misc.py index 327e52b56..a2f0fa4e4 100644 --- a/ipalib/plugins/misc.py +++ b/ipalib/plugins/misc.py @@ -22,7 +22,7 @@ Misc frontend plugins. """ import re -from ipalib import api, LocalOrRemote, Bytes +from ipalib import api, LocalOrRemote diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py index 7bc57751d..5e886abca 100644 --- a/ipaserver/rpcserver.py +++ b/ipaserver/rpcserver.py @@ -48,11 +48,7 @@ class xmlserver(Backend): self.debug('Received RPC call to %r', method) if method not in self.Command: raise CommandError(name=method) - self.info('params = %r', params) (args, options) = params_2_args_options(params) - self.info('args = %r', args) - self.info('options = %r', options) - self.debug(make_repr(method, *args, **options)) result = self.Command[method](*args, **options) return (result,) # Must wrap XML-RPC response in a tuple singleton diff --git a/tests/test_ipalib/test_frontend.py b/tests/test_ipalib/test_frontend.py index 72fc889e6..91fc83558 100644 --- a/tests/test_ipalib/test_frontend.py +++ b/tests/test_ipalib/test_frontend.py @@ -285,10 +285,8 @@ class test_Command(ClassChecker): # Check with a missing required arg fail = dict(okay) fail.pop('option1') - e = raises(errors.RequirementError, sub.validate, **fail) + e = raises(errors2.RequirementError, sub.validate, **fail) assert e.name == 'option1' - assert e.value is None - assert e.index is None def test_execute(self): """ |