From 984cec85470e9256398808d79cbfae4976737f2e Mon Sep 17 00:00:00 2001 From: Daryl Mowrer Date: Fri, 19 Feb 2016 12:40:30 -0600 Subject: [PATCH] Change for synchronous Mistral actions from CLI This patch allows the Mistral actions to be run synchronously from the Mistral CLI. When a Mistral action is run synchronously using the Mistral CLI 'run-action' command, it does not complete successfully. This is due to the Mistral API server handling requests on a single thread. The 'run-action' command performs a REST POST call to the ActionExecution RestController in the API server. That in turn calls back into the python-mistralclient which then performs another REST call back to the appropriate REST controller to actually run the action requested. That call hangs since the requests are handled on a single thread because the first POST has not completed yet. Eventually the RPC call between the engine and the executor servers times out, and the 'run-action' command fails. This patch changes the Mistral API server so that requests are handled in separate threads. Added a new functional test to the tempest test package to test synchronous action execution of a mistral action from within mistral. Change-Id: I8e06d3ef6aab4b2009a8fff4aa4d1acc118eee3f Implements: blueprint mistral-mistral-actions --- mistral/cmd/launch.py | 15 ++++++++++++++- .../tests/api/v2/test_mistral_basic_v2.py | 15 +++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/mistral/cmd/launch.py b/mistral/cmd/launch.py index 83d0a440d..4b7cce1ac 100755 --- a/mistral/cmd/launch.py +++ b/mistral/cmd/launch.py @@ -25,6 +25,7 @@ eventlet.monkey_patch( time=True) import os +import six import time # If ../mistral/__init__.py exists, add ../ to Python search path, so that @@ -38,7 +39,14 @@ if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'mistral', '__init__.py')): from oslo_config import cfg from oslo_log import log as logging import oslo_messaging as messaging + +if six.PY3 is True: + import socketserver +else: + import SocketServer as socketserver + from wsgiref import simple_server +from wsgiref.simple_server import WSGIServer from mistral.api import app from mistral import config @@ -128,6 +136,10 @@ def launch_engine(transport): server.wait() +class ThreadingWSGIServer(socketserver.ThreadingMixIn, WSGIServer): + pass + + def launch_api(transport): host = cfg.CONF.api.host port = cfg.CONF.api.port @@ -135,7 +147,8 @@ def launch_api(transport): server = simple_server.make_server( host, port, - app.setup_app() + app.setup_app(), + ThreadingWSGIServer ) LOG.info("Mistral API is serving on http://%s:%s (PID=%s)" % diff --git a/mistral_tempest_tests/tests/api/v2/test_mistral_basic_v2.py b/mistral_tempest_tests/tests/api/v2/test_mistral_basic_v2.py index be60cf6b3..95ab5aa12 100644 --- a/mistral_tempest_tests/tests/api/v2/test_mistral_basic_v2.py +++ b/mistral_tempest_tests/tests/api/v2/test_mistral_basic_v2.py @@ -1167,3 +1167,18 @@ class ActionExecutionTestsV2(base.TestCase): 'action_executions', 'nonexist' ) + + @test.attr(type='sanity') + def test_create_action_execution_sync(self): + token = self.client.auth_provider.get_token() + resp, body = self.client.create_action_execution( + { + 'name': 'std.http', + 'input': '{{"url": "http://localhost:8989/v2/workflows",\ + "headers": {{"X-Auth-Token": "{}"}}}}'.format(token) + } + ) + + self.assertEqual(201, resp.status) + output = json.loads(body['output']) + self.assertEqual(200, output['result']['status'])