diff options
author | Petr Viktorin <pviktori@redhat.com> | 2012-12-07 10:54:07 -0500 |
---|---|---|
committer | Martin Kosek <mkosek@redhat.com> | 2013-02-21 16:26:09 +0100 |
commit | 24bca144a8049cea8683afd699d2e0e158b5f164 (patch) | |
tree | 9314443e230d79cb8c7930ce73842036b3b8c054 /ipalib/frontend.py | |
parent | 8af5369cba1ff0e6d8baae90f3d93b40e91e85d6 (diff) | |
download | freeipa-24bca144a8049cea8683afd699d2e0e158b5f164.tar.gz freeipa-24bca144a8049cea8683afd699d2e0e158b5f164.tar.xz freeipa-24bca144a8049cea8683afd699d2e0e158b5f164.zip |
Add client capabilities, enable messages
The API version the client sends can now be used to check what the client
expects or is capable of.
All version tests IPA does will be be named and listed in one module,
ipalib.capabilities, which includes a function to test a specific capability
against an API version.
Similarly to Python's __future__ module, capabilities.py also serves as
documentation of backwards-incompatible changes to the API.
The first capability to be defined is "messages". Recent enough clients can
accept a list of warnings or other info under the "messages" key in the
result dict.
If a JSON client does not send the API version, it is assumed this is a testing
client (e.g. curl from the command line). Such a client "has" all capabilities,
but it will always receive a warning mentioning that forward compatibility
is not guaranteed.
If a XML client does not send the API version, it is assumed it uses the API
version before capabilities were introduced. (This is to keep backwards
compatibility with clients containing bug https://fedorahosted.org/freeipa/ticket/3294)
Whenever a capability is added, the API version must be incremented.
To ensure that, capabilities are written to API.txt and checked by
`makeapi --validate`.
Design page: http://freeipa.org/page/V3/Messages
Ticket: https://fedorahosted.org/freeipa/ticket/2732
Diffstat (limited to 'ipalib/frontend.py')
-rw-r--r-- | ipalib/frontend.py | 40 |
1 files changed, 32 insertions, 8 deletions
diff --git a/ipalib/frontend.py b/ipalib/frontend.py index c27ff1389..06259823c 100644 --- a/ipalib/frontend.py +++ b/ipalib/frontend.py @@ -23,18 +23,19 @@ Base classes for all front-end plugins. import re import inspect +from distutils import version + +from ipapython.version import API_VERSION +from ipapython.ipa_log_manager import root_logger from base import lock, check_name, NameSpace from plugable import Plugin, is_production_mode from parameters import create_param, parse_param_spec, Param, Str, Flag, Password from output import Output, Entry, ListOfEntries from text import _, ngettext - from errors import (ZeroArgumentError, MaxArgumentError, OverlapError, - RequiresRoot, VersionError, RequirementError, OptionError) -from errors import InvocationError + RequiresRoot, VersionError, RequirementError, OptionError, InvocationError) from constants import TYPE_ERROR -from ipapython.version import API_VERSION -from distutils import version +from ipalib import messages RULE_FLAG = 'validation_rule' @@ -740,11 +741,17 @@ class Command(HasParam): performs is executed remotely. """ if self.api.env.in_server: - if 'version' in options: + version_provided = 'version' in options + if version_provided: self.verify_client_version(options['version']) else: options['version'] = API_VERSION - return self.execute(*args, **options) + result = self.execute(*args, **options) + if not version_provided: + messages.add_message( + API_VERSION, result, + messages.VersionMissing(server_version=API_VERSION)) + return result return self.forward(*args, **options) def execute(self, *args, **kw): @@ -914,7 +921,7 @@ class Command(HasParam): nice, dict, type(output), output) ) expected_set = set(self.output) - actual_set = set(output) + actual_set = set(output) - set(['messages']) if expected_set != actual_set: missing = expected_set - actual_set if missing: @@ -945,6 +952,21 @@ class Command(HasParam): continue yield param + def log_messages(self, output, logger): + logger_functions = dict( + debug=logger.debug, + info=logger.info, + warning=logger.warning, + error=logger.error, + ) + for message in output.get('messages', ()): + try: + function = logger_functions[message['type']] + except KeyError: + logger.error('Server sent a message with a wrong type') + function = logger.error + function(message.get('message')) + def output_for_cli(self, textui, output, *args, **options): """ Generic output method. Prints values the output argument according @@ -963,6 +985,8 @@ class Command(HasParam): rv = 0 + self.log_messages(output, root_logger) + order = [p.name for p in self.output_params()] if options.get('all', False): order.insert(0, 'dn') |