From 812f1803a6d55a6574bc37525b5541e165c62d3c Mon Sep 17 00:00:00 2001 From: Daryl Mowrer Date: Thu, 18 Feb 2016 18:21:56 -0600 Subject: [PATCH] Add Mistral action pack This patch adds support for calling Mistral v2 APIs as actions in Mistral. There will be at least two more patch sets for this blueprint to fully support these changes. Change-Id: I0226482ddee1573232663e124837deb8a1985df8 Implements: blueprint mistral-mistral-actions --- mistral/actions/generator_factory.py | 3 +- mistral/actions/openstack/actions.py | 35 +++++++++++ mistral/actions/openstack/mapping.json | 58 +++++++++++++++++++ .../unit/actions/openstack/test_generator.py | 1 + .../openstack/test_openstack_actions.py | 12 ++++ requirements.txt | 1 + tools/get_action_list.py | 13 ++++- 7 files changed, 120 insertions(+), 3 deletions(-) diff --git a/mistral/actions/generator_factory.py b/mistral/actions/generator_factory.py index 2cb4a114..1a071c9e 100644 --- a/mistral/actions/generator_factory.py +++ b/mistral/actions/generator_factory.py @@ -19,7 +19,8 @@ from mistral.actions.openstack.action_generator import base SUPPORTED_MODULES = [ 'Nova', 'Glance', 'Keystone', 'Heat', 'Neutron', 'Cinder', 'Ceilometer', - 'Trove', 'Ironic', 'Baremetal Introspection', 'Swift', 'Zaqar', 'Barbican' + 'Trove', 'Ironic', 'Baremetal Introspection', 'Swift', 'Zaqar', 'Barbican', + 'Mistral' ] diff --git a/mistral/actions/openstack/actions.py b/mistral/actions/openstack/actions.py index a7e7c37a..d4026e43 100644 --- a/mistral/actions/openstack/actions.py +++ b/mistral/actions/openstack/actions.py @@ -24,6 +24,7 @@ from ironicclient.v1 import client as ironicclient from keystoneclient.auth import identity from keystoneclient import httpclient from keystoneclient.v3 import client as keystoneclient +from mistralclient.api.v2 import client as mistralclient from neutronclient.v2_0 import client as neutronclient from novaclient import client as novaclient from oslo_config import cfg @@ -243,6 +244,40 @@ class CinderAction(base.OpenStackAction): return cls._client_class() +class MistralAction(base.OpenStackAction): + _client_class = mistralclient.Client + + def _get_client(self): + ctx = context.ctx() + + LOG.debug("Mistral action security context: %s" % ctx) + + # Check for trust scope token. This may occur if the action is + # called from a workflow triggered by a Mistral cron trigger. + if ctx.is_trust_scoped: + auth_url = None + mistral_endpoint = keystone_utils.get_endpoint_for_project( + 'mistral' + ) + mistral_url = mistral_endpoint.url + else: + keystone_endpoint = keystone_utils.get_keystone_endpoint_v2() + auth_url = keystone_endpoint.url + mistral_url = None + + return self._client_class( + mistral_url=mistral_url, + auth_token=ctx.auth_token, + project_id=ctx.project_id, + user_id=ctx.user_id, + auth_url=auth_url + ) + + @classmethod + def _get_fake_client(cls): + return cls._client_class() + + class TroveAction(base.OpenStackAction): _client_class = troveclient.Client diff --git a/mistral/actions/openstack/mapping.json b/mistral/actions/openstack/mapping.json index b2a62c29..4b487c34 100644 --- a/mistral/actions/openstack/mapping.json +++ b/mistral/actions/openstack/mapping.json @@ -965,5 +965,63 @@ "orders_delete": "orders.delete", "orders_list": "orders.list", "secrets_store": "secrets_store" + }, + "mistral": { + "_comment": "It uses mistralclient.v2.", + "action_executions_create": "action_executions.create", + "action_executions_delete": "action_executions.delete", + "action_executions_find": "action_executions.find", + "action_executions_get": "action_executions.get", + "action_executions_list": "action_executions.list", + "action_executions_update": "action_executions.update", + "actions_create": "actions.create", + "actions_delete": "actions.delete", + "actions_find": "actions.find", + "actions_get": "actions.get", + "actions_list": "actions.list", + "actions_update": "actions.update", + "cron_triggers_create": "cron_triggers.create", + "cron_triggers_delete": "cron_triggers.delete", + "cron_triggers_find": "cron_triggers.find", + "cron_triggers_get": "cron_triggers.get", + "cron_triggers_list": "cron_triggers.list", + "environments_create": "environments.create", + "environments_delete": "environments.delete", + "environments_find": "environments.find", + "environments_get": "environments.get", + "environments_list": "environments.list", + "environments_update": "environments.update", + "executions_create": "executions.create", + "executions_delete": "executions.delete", + "executions_find": "executions.find", + "executions_get": "executions.get", + "executions_list": "executions.list", + "executions_update": "executions.update", + "members_create": "members.create", + "members_delete": "members.delete", + "members_find": "members.find", + "members_get": "members.get", + "members_list": "members.list", + "members_update": "members.update", + "services_find": "services.find", + "services_list": "services.list", + "tasks_find": "tasks.find", + "tasks_get": "tasks.get", + "tasks_list": "tasks.list", + "tasks_rerun": "tasks.rerun", + "workbooks_create": "workbooks.create", + "workbooks_delete": "workbooks.delete", + "workbooks_find": "workbooks.find", + "workbooks_get": "workbooks.get", + "workbooks_list": "workbooks.list", + "workbooks_update": "workbooks.update", + "workbooks_validate": "workbooks.validate", + "workflows_create": "workflows.create", + "workflows_delete": "workflows.delete", + "workflows_find": "workflows.find", + "workflows_get": "workflows.get", + "workflows_list": "workflows.list", + "workflows_update": "workflows.update", + "workflows_validate": "workflows.validate" } } diff --git a/mistral/tests/unit/actions/openstack/test_generator.py b/mistral/tests/unit/actions/openstack/test_generator.py index 5aab7a4f..719d062d 100644 --- a/mistral/tests/unit/actions/openstack/test_generator.py +++ b/mistral/tests/unit/actions/openstack/test_generator.py @@ -31,6 +31,7 @@ MODULE_MAPPING = { 'swift': ['swift.head_account', actions.SwiftAction], 'zaqar': ['zaqar.queue_messages', actions.ZaqarAction], 'barbican': ['barbican.orders_list', actions.BarbicanAction], + 'mistral': ['mistral.workflows_get', actions.MistralAction], } EXTRA_MODULES = ['neutron', 'swift', 'zaqar'] diff --git a/mistral/tests/unit/actions/openstack/test_openstack_actions.py b/mistral/tests/unit/actions/openstack/test_openstack_actions.py index 37638fb4..3bc65ba5 100644 --- a/mistral/tests/unit/actions/openstack/test_openstack_actions.py +++ b/mistral/tests/unit/actions/openstack/test_openstack_actions.py @@ -139,6 +139,18 @@ class OpenStackActionTest(base.BaseTestCase): self.assertTrue(mocked().get_status.called) mocked().get_status.assert_called_once_with(uuid="1234") + @mock.patch.object(actions.MistralAction, '_get_client') + def test_mistral_action(self, mocked): + method_name = "workflows.get" + action_class = actions.MistralAction + action_class.client_method_name = method_name + params = {'name': '1234-abcd'} + action = action_class(**params) + action.run() + + self.assertTrue(mocked().workflows.get.called) + mocked().workflows.get.assert_called_once_with(name="1234-abcd") + @mock.patch.object(actions.SwiftAction, '_get_client') def test_swift_action(self, mocked): method_name = "get_object" diff --git a/requirements.txt b/requirements.txt index f0f33bb0..49b09d07 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,6 +28,7 @@ python-cinderclient>=1.3.1 # Apache-2.0 python-glanceclient>=1.2.0 # Apache-2.0 python-heatclient>=0.6.0 # Apache-2.0 python-keystoneclient!=1.8.0,!=2.1.0,>=1.6.0 # Apache-2.0 +python-mistralclient>=1.0.0 # Apache-2.0 python-neutronclient>=2.6.0 # Apache-2.0 python-novaclient!=2.33.0,>=2.29.0 # Apache-2.0 python-swiftclient>=2.2.0 # Apache-2.0 diff --git a/tools/get_action_list.py b/tools/get_action_list.py index 88ba7d33..96915516 100644 --- a/tools/get_action_list.py +++ b/tools/get_action_list.py @@ -21,7 +21,7 @@ import os from barbicanclient import base as barbican_base from barbicanclient import client as barbicanclient from ceilometerclient.v2 import client as ceilometerclient -from cinderclient import utils as cinder_base +from cinderclient.openstack.common.apiclient import base as cinder_base from cinderclient.v2 import client as cinderclient from glanceclient.v2 import client as glanceclient from heatclient.openstack.common.apiclient import base as heat_base @@ -30,8 +30,10 @@ from ironicclient.common import base as ironic_base from ironicclient.v1 import client as ironicclient from keystoneclient import base as keystone_base from keystoneclient.v3 import client as keystoneclient +from mistralclient.api import base as mistral_base +from mistralclient.api.v2 import client as mistralclient +from novaclient import base as nova_base from novaclient import client as novaclient -from novaclient.openstack.common.apiclient import base as nova_base from troveclient import base as trove_base from troveclient.v1 import client as troveclient @@ -71,6 +73,7 @@ BASE_HEAT_MANAGER = heat_base.HookableMixin BASE_NOVA_MANAGER = nova_base.HookableMixin BASE_KEYSTONE_MANAGER = keystone_base.Manager BASE_CINDER_MANAGER = cinder_base.HookableMixin +BASE_MISTRAL_MANAGER = mistral_base.ResourceManager BASE_TROVE_MANAGER = trove_base.Manager BASE_IRONIC_MANAGER = ironic_base.Manager BASE_BARBICAN_MANAGER = barbican_base.BaseEntityManager @@ -149,6 +152,10 @@ def get_cinder_client(**kwargs): return cinderclient.Client() +def get_mistral_client(**kwargs): + return mistralclient.Client() + + def get_trove_client(**kwargs): return troveclient.Client('username', 'password') @@ -174,6 +181,7 @@ CLIENTS = { 'trove': get_trove_client, 'ironic': get_ironic_client, 'barbican': get_barbican_client, + 'mistral': get_mistral_client, # 'neutron': get_nova_client # 'baremetal_introspection': ... # 'swift': ... @@ -189,6 +197,7 @@ BASE_MANAGERS = { 'trove': BASE_TROVE_MANAGER, 'ironic': BASE_IRONIC_MANAGER, 'barbican': BASE_BARBICAN_MANAGER, + 'mistral': BASE_MISTRAL_MANAGER, # 'neutron': BASE_NOVA_MANAGER # 'baremetal_introspection': ... # 'swift': ...