From c31a9533fa3718c0712cf59530a66f0aeb291958 Mon Sep 17 00:00:00 2001 From: Miguel Grinberg Date: Wed, 3 Jun 2015 22:45:35 -0700 Subject: [PATCH] Move mistral resources in-tree This change relocates the mistral resources from the contrib area into the main resource tree. It was originally added to contrib/ because of the project's incubation status, and more specifically because the client is not in the global-requirements.txt file. However, when this was discussed at the summit in Vancouver, the decision was to move the resources to main tree but skip registration if the client is not installed. This will save users from the trouble of installing it as a plugin. Change-Id: I6eeef5fa2b080df610e52620d2b935450d8d49e3 --- contrib/heat_mistral/README.md | 18 ------- .../heat_mistral/resources/__init__.py | 0 .../heat_mistral/tests/__init__.py | 0 contrib/heat_mistral/requirements.txt | 1 - contrib/heat_mistral/setup.cfg | 34 ------------- contrib/heat_mistral/setup.py | 29 ----------- .../engine/clients/os/mistral.py | 4 ++ .../resources/openstack/mistral}/__init__.py | 0 .../openstack/mistral}/cron_trigger.py | 8 +++ .../resources/openstack/mistral}/workflow.py | 0 heat/tests/test_mistral_client.py | 32 ++++++++++++ .../tests/test_mistral_cron_trigger.py | 21 ++++++-- .../tests/test_mistral_workflow.py | 49 +++++++++++++++---- setup.cfg | 1 + 14 files changed, 102 insertions(+), 95 deletions(-) delete mode 100644 contrib/heat_mistral/README.md delete mode 100644 contrib/heat_mistral/heat_mistral/resources/__init__.py delete mode 100644 contrib/heat_mistral/heat_mistral/tests/__init__.py delete mode 100644 contrib/heat_mistral/requirements.txt delete mode 100644 contrib/heat_mistral/setup.cfg delete mode 100644 contrib/heat_mistral/setup.py rename contrib/heat_mistral/heat_mistral/client.py => heat/engine/clients/os/mistral.py (95%) rename {contrib/heat_mistral/heat_mistral => heat/engine/resources/openstack/mistral}/__init__.py (100%) rename {contrib/heat_mistral/heat_mistral/resources => heat/engine/resources/openstack/mistral}/cron_trigger.py (96%) rename {contrib/heat_mistral/heat_mistral/resources => heat/engine/resources/openstack/mistral}/workflow.py (100%) create mode 100644 heat/tests/test_mistral_client.py rename contrib/heat_mistral/heat_mistral/tests/test_cron_trigger.py => heat/tests/test_mistral_cron_trigger.py (82%) rename contrib/heat_mistral/heat_mistral/tests/test_workflow.py => heat/tests/test_mistral_workflow.py (91%) diff --git a/contrib/heat_mistral/README.md b/contrib/heat_mistral/README.md deleted file mode 100644 index 61c5bdfde6..0000000000 --- a/contrib/heat_mistral/README.md +++ /dev/null @@ -1,18 +0,0 @@ -Mistral plugin for OpenStack Heat -================================ - -This plugin enables using Mistral resources in a Heat template. - - -### 1. Install the Mistral plugin in Heat - -NOTE: These instructions assume the value of heat.conf plugin_dirs includes the -default directory /usr/lib/heat. - -To install the plugin, from this directory run: - sudo python ./setup.py install - -### 2. Restart heat - -Only the process "heat-engine" needs to be restarted to load the newly installed -plugin. diff --git a/contrib/heat_mistral/heat_mistral/resources/__init__.py b/contrib/heat_mistral/heat_mistral/resources/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/contrib/heat_mistral/heat_mistral/tests/__init__.py b/contrib/heat_mistral/heat_mistral/tests/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/contrib/heat_mistral/requirements.txt b/contrib/heat_mistral/requirements.txt deleted file mode 100644 index 60e8a95278..0000000000 --- a/contrib/heat_mistral/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -python-mistralclient diff --git a/contrib/heat_mistral/setup.cfg b/contrib/heat_mistral/setup.cfg deleted file mode 100644 index 7862b51d77..0000000000 --- a/contrib/heat_mistral/setup.cfg +++ /dev/null @@ -1,34 +0,0 @@ -[metadata] -name = heat-contrib-mistral -summary = Heat resources for Mistral -description-file = - README.md -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = http://www.openstack.org/ -classifier = - Environment :: OpenStack - Intended Audience :: Information Technology - Intended Audience :: System Administrators - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 2.6 - -[files] -packages = - heat_mistral - -# Copy to /usr/lib/heat for plugin loading -data_files = - lib/heat/mistral = heat_mistral/resources/* - -[entry_points] -heat.clients = - mistral = heat_mistral.client:MistralClientPlugin - -[global] -setup-hooks = - pbr.hooks.setup_hook diff --git a/contrib/heat_mistral/setup.py b/contrib/heat_mistral/setup.py deleted file mode 100644 index 62f38a592f..0000000000 --- a/contrib/heat_mistral/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr'], - pbr=True) diff --git a/contrib/heat_mistral/heat_mistral/client.py b/heat/engine/clients/os/mistral.py similarity index 95% rename from contrib/heat_mistral/heat_mistral/client.py rename to heat/engine/clients/os/mistral.py index 22131d3208..f754d40519 100644 --- a/contrib/heat_mistral/heat_mistral/client.py +++ b/heat/engine/clients/os/mistral.py @@ -21,6 +21,10 @@ mistral_client = importutils.try_import('mistralclient.api.client') class MistralClientPlugin(client_plugin.ClientPlugin): + @staticmethod + def is_available(): + return mistral_base is not None + def _create(self): endpoint_type = self._get_client_option('mistral', 'endpoint_type') endpoint = self.url_for(service_type='workflowv2', diff --git a/contrib/heat_mistral/heat_mistral/__init__.py b/heat/engine/resources/openstack/mistral/__init__.py similarity index 100% rename from contrib/heat_mistral/heat_mistral/__init__.py rename to heat/engine/resources/openstack/mistral/__init__.py diff --git a/contrib/heat_mistral/heat_mistral/resources/cron_trigger.py b/heat/engine/resources/openstack/mistral/cron_trigger.py similarity index 96% rename from contrib/heat_mistral/heat_mistral/resources/cron_trigger.py rename to heat/engine/resources/openstack/mistral/cron_trigger.py index 5a69877326..ba6527b3e4 100644 --- a/contrib/heat_mistral/heat_mistral/resources/cron_trigger.py +++ b/heat/engine/resources/openstack/mistral/cron_trigger.py @@ -13,6 +13,7 @@ from heat.common.i18n import _ from heat.engine import attributes +from heat.engine import clients from heat.engine import properties from heat.engine import resource from heat.engine import support @@ -126,3 +127,10 @@ def resource_mapping(): return { 'OS::Mistral::CronTrigger': CronTrigger, } + + +def available_resource_mapping(): + if not clients.has_client('mistral'): + return {} + + return resource_mapping() diff --git a/contrib/heat_mistral/heat_mistral/resources/workflow.py b/heat/engine/resources/openstack/mistral/workflow.py similarity index 100% rename from contrib/heat_mistral/heat_mistral/resources/workflow.py rename to heat/engine/resources/openstack/mistral/workflow.py diff --git a/heat/tests/test_mistral_client.py b/heat/tests/test_mistral_client.py new file mode 100644 index 0000000000..270fd28512 --- /dev/null +++ b/heat/tests/test_mistral_client.py @@ -0,0 +1,32 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from oslo_utils import importutils +import testtools + +from heat.tests import common +from heat.tests import utils + +mistral_client = importutils.try_import('mistralclient.api.base') + + +class MistralClientPluginTests(common.HeatTestCase): + + @testtools.skipIf(mistral_client is None, 'Tests the mistral client') + def test_create(self): + context = utils.dummy_context() + plugin = context.clients.client_plugin('mistral') + client = plugin.client() + self.assertIsNotNone(client.workflows) + self.assertEqual('http://server.test:5000/v3', + client.http_client.base_url) diff --git a/contrib/heat_mistral/heat_mistral/tests/test_cron_trigger.py b/heat/tests/test_mistral_cron_trigger.py similarity index 82% rename from contrib/heat_mistral/heat_mistral/tests/test_cron_trigger.py rename to heat/tests/test_mistral_cron_trigger.py index e9f09c1b3e..c6aadf47f4 100644 --- a/contrib/heat_mistral/heat_mistral/tests/test_cron_trigger.py +++ b/heat/tests/test_mistral_cron_trigger.py @@ -12,13 +12,20 @@ # under the License. import mock +from oslo_utils import importutils +import testtools +from heat.common import exception from heat.common import template_format +from heat.engine import resources +from heat.engine.resources.openstack.mistral import cron_trigger from heat.engine import scheduler +from heat.engine import stack as stack_parser +from heat.engine import template from heat.tests import common from heat.tests import utils -from ..resources import cron_trigger # noqa +mistral_client = importutils.try_import('mistralclient.api.base') stack_template = ''' heat_template_version: 2013-05-23 @@ -43,10 +50,11 @@ class FakeCronTrigger(object): self.remaining_executions = 3 -class CronTriggerTest(common.HeatTestCase): +class MistralCronTriggerTest(common.HeatTestCase): def setUp(self): - super(CronTriggerTest, self).setUp() + super(MistralCronTriggerTest, self).setUp() + resources.initialise() utils.setup_dummy_db() self.ctx = utils.dummy_context() @@ -107,3 +115,10 @@ class CronTriggerTest(common.HeatTestCase): self.assertEqual((ct.DELETE, ct.COMPLETE), ct.state) self.client.cron_triggers.delete.assert_called_once_with( ct.resource_id) + + @testtools.skipIf(mistral_client is not None, + 'Tests mistral client not installed') + def test_no_client(self): + tmpl = template.Template((template_format.parse(stack_template))) + stack = stack_parser.Stack(utils.dummy_context(), 'foo', tmpl) + self.assertRaises(exception.ResourceTypeNotFound, stack.validate) diff --git a/contrib/heat_mistral/heat_mistral/tests/test_workflow.py b/heat/tests/test_mistral_workflow.py similarity index 91% rename from contrib/heat_mistral/heat_mistral/tests/test_workflow.py rename to heat/tests/test_mistral_workflow.py index 3eb58b2ad6..7b42789093 100644 --- a/contrib/heat_mistral/heat_mistral/tests/test_workflow.py +++ b/heat/tests/test_mistral_workflow.py @@ -12,21 +12,26 @@ # under the License. import mock +from oslo_utils import importutils import six +import testtools from heat.common import exception from heat.common import template_format +from heat.engine.clients.os import mistral as client from heat.engine import resource +from heat.engine import resources +from heat.engine.resources.openstack.mistral import workflow from heat.engine.resources import signal_responder from heat.engine.resources import stack_user from heat.engine import scheduler +from heat.engine import stack as stack_parser from heat.engine import template from heat.tests import common from heat.tests import utils -from mistralclient.api.v2 import executions -from .. import client # noqa -from ..resources import workflow # noqa +mistral_client = importutils.try_import('mistralclient.api.base') +executions = importutils.try_import('mistralclient.api.v2.executions') workflow_template = """ heat_template_version: 2013-05-23 @@ -174,9 +179,11 @@ class FakeWorkflow(object): self.name = name -class TestWorkflow(common.HeatTestCase): +class TestMistralWorkflow(common.HeatTestCase): + def setUp(self): - super(TestWorkflow, self).setUp() + super(TestMistralWorkflow, self).setUp() + resources.initialise() utils.setup_dummy_db() self.ctx = utils.dummy_context() tmpl = template_format.parse(workflow_template) @@ -188,13 +195,26 @@ class TestWorkflow(common.HeatTestCase): self.mistral = mock.Mock() self.patchobject(workflow.Workflow, 'mistral', return_value=self.mistral) - mock.patch.object(stack_user.StackUser, '_create_user').start() - mock.patch.object(signal_responder.SignalResponder, - '_create_keypair').start() - mock.patch.object(client, 'mistral_base').start() - mock.patch.object(client.MistralClientPlugin, '_create').start() + + self.patches = [] + self.patches.append(mock.patch.object(stack_user.StackUser, + '_create_user')) + self.patches.append(mock.patch.object(signal_responder.SignalResponder, + '_create_keypair')) + self.patches.append(mock.patch.object(client, + 'mistral_base')) + self.patches.append(mock.patch.object(client.MistralClientPlugin, + '_create')) + for patch in self.patches: + patch.start() + self.client = client.MistralClientPlugin(self.ctx) + def tearDown(self): + super(TestMistralWorkflow, self).tearDown() + for patch in self.patches: + patch.stop() + def _create_resource(self, name, snippet, stack): wf = workflow.Workflow(name, snippet, stack) self.mistral.workflows.create.return_value = [ @@ -404,6 +424,8 @@ class TestWorkflow(common.HeatTestCase): " Unknown input 1") self.assertEqual(error_message, six.text_type(err)) + @testtools.skipIf(executions is None, + 'Uses the actual mistral client') def test_signal_and_delete_with_executions(self): tmpl = template_format.parse(workflow_template_full) stack = utils.parse_stack(tmpl) @@ -478,3 +500,10 @@ class TestWorkflow(common.HeatTestCase): execution = mock.Mock() execution.id = '12345' return execution + + @testtools.skipIf(mistral_client is not None, + 'Tests mistral client not installed') + def test_no_client(self): + tmpl = template.Template((template_format.parse(workflow_template))) + stack = stack_parser.Stack(utils.dummy_context(), 'foo', tmpl) + self.assertRaises(exception.ResourceTypeNotFound, stack.validate) diff --git a/setup.cfg b/setup.cfg index 7c7b5f30e6..2275d2a194 100644 --- a/setup.cfg +++ b/setup.cfg @@ -53,6 +53,7 @@ heat.clients = heat = heat.engine.clients.os.heat_plugin:HeatClientPlugin keystone = heat.engine.clients.os.keystone:KeystoneClientPlugin manila = heat.engine.clients.os.manila:ManilaClientPlugin + mistral = heat.engine.clients.os.mistral:MistralClientPlugin nova = heat.engine.clients.os.nova:NovaClientPlugin neutron = heat.engine.clients.os.neutron:NeutronClientPlugin swift = heat.engine.clients.os.swift:SwiftClientPlugin