diff --git a/senlin/drivers/base.py b/senlin/drivers/base.py index 314e0c7e5..97cc9dc42 100644 --- a/senlin/drivers/base.py +++ b/senlin/drivers/base.py @@ -41,3 +41,4 @@ class SenlinDriver(object): # TODO(Yanyan Hu): Use openstack compute driver(nova_v2) # as the start point of using senlin generic driver. self.compute = cloud_backend_plugin.ComputeClient + self.orchestration = cloud_backend_plugin.OrchestrationClient diff --git a/senlin/drivers/openstack/__init__.py b/senlin/drivers/openstack/__init__.py index 6e62b5e77..507a33c43 100644 --- a/senlin/drivers/openstack/__init__.py +++ b/senlin/drivers/openstack/__init__.py @@ -10,8 +10,13 @@ # License for the specific language governing permissions and limitations # under the License. +from senlin.drivers.openstack import heat_v1 from senlin.drivers.openstack import nova_v2 def ComputeClient(params): return nova_v2.NovaClient(params) + + +def OrchestrationClient(params): + return heat_v1.HeatClient(params) diff --git a/senlin/profiles/os/heat/resource.py b/senlin/profiles/os/heat/resource.py index d02b7e3e3..95e34cd52 100644 --- a/senlin/profiles/os/heat/resource.py +++ b/senlin/profiles/os/heat/resource.py @@ -10,7 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -# from senlin.drivers import heat_v1 as heat from senlin.profiles import base __type_name__ = 'os.heat.resource' diff --git a/senlin/profiles/os/heat/stack.py b/senlin/profiles/os/heat/stack.py index 3dbe0871e..67f550202 100644 --- a/senlin/profiles/os/heat/stack.py +++ b/senlin/profiles/os/heat/stack.py @@ -19,7 +19,7 @@ from senlin.common import exception from senlin.common.i18n import _ from senlin.common import schema from senlin.common import utils -from senlin.drivers.openstack import heat_v1 as heatclient +from senlin.drivers import base as driver_base from senlin.engine import scheduler from senlin.profiles import base @@ -87,7 +87,7 @@ class StackProfile(base.Profile): if self.hc: return self.hc params = self._get_connection_params(context.get_current(), obj) - self.hc = heatclient.HeatClient(params) + self.hc = driver_base.SenlinDriver().orchestration(params) return self.hc def do_validate(self, obj): diff --git a/senlin/tests/unit/driver/test_driver.py b/senlin/tests/unit/driver/test_driver.py new file mode 100644 index 000000000..1996a3fa5 --- /dev/null +++ b/senlin/tests/unit/driver/test_driver.py @@ -0,0 +1,46 @@ +# 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. + +import mock +from oslo_config import cfg + +from senlin.drivers import base as driver_base +from senlin.engine import environment +from senlin.tests.unit.common import base + + +class TestSenlinDriver(base.SenlinTestCase): + + def test_init_using_default_cloud_backend(self): + plugin1 = mock.Mock() + plugin1.ComputeClient = 'ComputeClient1' + plugin1.OrchestrationClient = 'OrchestrationClient1' + env = environment.global_env() + env.register_driver('cloud_backend_1', plugin1) + + # Using default cloud backend defined in configure file + cfg.CONF.set_override('cloud_backend', 'cloud_backend_1') + sd = driver_base.SenlinDriver() + self.assertEqual('ComputeClient1', sd.compute) + self.assertEqual('OrchestrationClient1', sd.orchestration) + + def test_init_using_specified_cloud_backend(self): + plugin2 = mock.Mock() + plugin2.ComputeClient = 'ComputeClient2' + plugin2.OrchestrationClient = 'OrchestrationClient2' + env = environment.global_env() + env.register_driver('cloud_backend_2', plugin2) + + # Using specified cloud backend + sd = driver_base.SenlinDriver('cloud_backend_2') + self.assertEqual('ComputeClient2', sd.compute) + self.assertEqual('OrchestrationClient2', sd.orchestration) diff --git a/senlin/tests/unit/profiles/test_heat_stack.py b/senlin/tests/unit/profiles/test_heat_stack.py index 178f29480..eceb3fe1a 100644 --- a/senlin/tests/unit/profiles/test_heat_stack.py +++ b/senlin/tests/unit/profiles/test_heat_stack.py @@ -12,7 +12,7 @@ import mock -from senlin.drivers.openstack import heat_v1 as heatclient +from senlin.drivers import base as driver_base from senlin.profiles.os.heat import stack from senlin.tests.unit.common import base from senlin.tests.unit.common import utils @@ -44,7 +44,14 @@ class TestHeatStackProfile(base.SenlinTestCase): self.assertIsNone(profile.hc) self.assertIsNone(profile.stack_id) - def test_heat_client(self): + @mock.patch.object(driver_base, 'SenlinDriver') + def test_heat_client_create_new_hc(self, mock_senlindriver): + test_stack = mock.Mock() + hc = mock.Mock() + sd = mock.Mock() + sd.orchestration.return_value = hc + mock_senlindriver.return_value = sd + kwargs = { 'spec': self.spec } @@ -52,18 +59,35 @@ class TestHeatStackProfile(base.SenlinTestCase): 'test-profile', **kwargs) - profile.hc = mock.Mock() - test_stack = mock.Mock() - profile.heat(test_stack) - self.assertIsNotNone(profile.hc) + # New hc will be created if no cache is found + profile.hc = None + params = mock.Mock() + mock_param = self.patchobject(profile, '_get_connection_params', + return_value=params) + res = profile.heat(test_stack) + self.assertEqual(hc, res) + self.assertEqual(hc, profile.hc) + mock_param.assert_called_once_with(mock.ANY, test_stack) + sd.orchestration.assert_called_once_with(params) - with mock.patch('senlin.drivers.openstack.heat_v1.HeatClient', - mock.MagicMock()): - profile._get_connection_params = mock.MagicMock() - profile.hc = None - profile.heat(test_stack) - self.assertIsNotNone(profile.hc) - self.assertTrue(heatclient.HeatClient.called) + @mock.patch.object(driver_base, 'SenlinDriver') + def test_heat_client_use_cached_hc(self, mock_senlindriver): + test_stack = mock.Mock() + hc = mock.Mock() + sd = mock.Mock() + sd.orchestration.return_value = hc + mock_senlindriver.return_value = sd + + kwargs = { + 'spec': self.spec + } + profile = stack.StackProfile('os.heat.stack', + 'test-profile', + **kwargs) + + # Cache hc will be used + profile.hc = hc + self.assertEqual(hc, profile.heat(test_stack)) def test_do_validate(self): kwargs = {