Hi,

these patches are for master only, see commit messages for details.

Honza

--
Jan Cholasta
From 49f3e365dc56ccda7d8aec7cf9d8e2d98791b031 Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jchol...@redhat.com>
Date: Wed, 2 Mar 2016 11:00:23 +0100
Subject: [PATCH 1/2] ipalib: provide per-call command context

Add context which is valid for the duration of command call. The context
is accessible using the `context` attribute of Command and Object plugins.
---
 ipalib/frontend.py | 10 ++++++++++
 ipalib/request.py  | 21 +++++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/ipalib/frontend.py b/ipalib/frontend.py
index 5b730b1..e91660d 100644
--- a/ipalib/frontend.py
+++ b/ipalib/frontend.py
@@ -38,6 +38,7 @@ from ipalib.errors import (ZeroArgumentError, MaxArgumentError, OverlapError,
     VersionError, OptionError, InvocationError,
     ValidationError, ConversionError)
 from ipalib import messages
+from ipalib.request import context, context_frame
 from ipalib.util import json_serialize
 
 if six.PY3:
@@ -370,6 +371,10 @@ class HasParam(Plugin):
                 check(namespace)
         setattr(self, name, namespace)
 
+    @property
+    def context(self):
+        return context.current_frame
+
 
 class Command(HasParam):
     """
@@ -424,6 +429,11 @@ class Command(HasParam):
         XML-RPC and the executed an the nearest IPA server.
         """
         self.ensure_finalized()
+        with context_frame():
+            self.context.principal = getattr(context, 'principal', None)
+            return self.__do_call(*args, **options)
+
+    def __do_call(self, *args, **options):
         version_provided = 'version' in options
         if version_provided:
             self.verify_client_version(unicode(options['version']))
diff --git a/ipalib/request.py b/ipalib/request.py
index 9484be5..d851ba8 100644
--- a/ipalib/request.py
+++ b/ipalib/request.py
@@ -22,6 +22,7 @@
 Per-request thread-local data.
 """
 
+import contextlib
 import threading
 
 from ipalib.base import ReadOnly, lock
@@ -32,6 +33,26 @@ from ipalib.constants import CALLABLE_ERROR
 context = threading.local()
 
 
+class _FrameContext(object):
+    pass
+
+
+@contextlib.contextmanager
+def context_frame():
+    try:
+        frame_back = context.current_frame
+    except AttributeError:
+        pass
+    context.current_frame = _FrameContext()
+    try:
+        yield
+    finally:
+        try:
+            context.current_frame = frame_back
+        except UnboundLocalError:
+            del context.current_frame
+
+
 class Connection(ReadOnly):
     """
     Base class for connection objects stored on `request.context`.
-- 
2.5.0

From 8ca33656a7ebb7819af9a8101befb20396d2bd75 Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jchol...@redhat.com>
Date: Wed, 2 Mar 2016 12:44:15 +0100
Subject: [PATCH 2/2] ipalib: add convenient Command method for adding messages

Call the add_message() method of Command from anywhere in the implementation
of a command to add a message to the result of the command.
---
 ipalib/frontend.py | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/ipalib/frontend.py b/ipalib/frontend.py
index e91660d..ba830f2 100644
--- a/ipalib/frontend.py
+++ b/ipalib/frontend.py
@@ -434,13 +434,17 @@ class Command(HasParam):
             return self.__do_call(*args, **options)
 
     def __do_call(self, *args, **options):
-        version_provided = 'version' in options
-        if version_provided:
+        self.context.__messages = []
+        if 'version' in options:
             self.verify_client_version(unicode(options['version']))
         elif self.api.env.skip_version_check and not self.api.env.in_server:
             options['version'] = u'2.0'
         else:
             options['version'] = API_VERSION
+            if self.api.env.in_server:
+                # add message only on server side
+                self.add_message(
+                    messages.VersionMissing(server_version=API_VERSION))
         params = self.args_options_2_params(*args, **options)
         self.debug(
             'raw: %s(%s)', self.name, ', '.join(self._repr_iter(**params))
@@ -454,12 +458,9 @@ class Command(HasParam):
         self.validate(**params)
         (args, options) = self.params_2_args_options(**params)
         ret = self.run(*args, **options)
-        if (not version_provided and isinstance(ret, dict) and
-                self.api.env.in_server):
-            # add message only on server side
-            messages.add_message(
-                API_VERSION, ret,
-                messages.VersionMissing(server_version=API_VERSION))
+        if isinstance(ret, dict):
+            for message in self.context.__messages:
+                messages.add_message(options['version'], ret, message)
         if (
             isinstance(ret, dict)
             and 'summary' in self.output
@@ -470,6 +471,9 @@ class Command(HasParam):
             self.validate_output(ret, options['version'])
         return ret
 
+    def add_message(self, message):
+        self.context.__messages.append(message)
+
     def soft_validate(self, values):
         errors = dict()
         for p in self.params():
-- 
2.5.0

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to