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