diff --git a/senlin/api/openstack/v1/policy_types.py b/senlin/api/openstack/v1/policy_types.py index 799dd643b..ffe7e45ef 100644 --- a/senlin/api/openstack/v1/policy_types.py +++ b/senlin/api/openstack/v1/policy_types.py @@ -15,6 +15,7 @@ Policy type endpoint for Senlin v1 ReST API. """ from senlin.api.common import util +from senlin.api.common import version_request as vr from senlin.api.common import wsgi @@ -30,7 +31,12 @@ class PolicyTypeController(wsgi.Controller): obj = util.parse_request('PolicyTypeListRequest', req, {}) types = self.rpc_client.call(req.context, 'policy_type_list', obj) - return {'policy_types': types} + result = types + if req.version_request <= vr.APIVersionRequest("1.4"): + # we return only policy name before microversion 1.5 + result = [{'name': '-'.join((t['name'], t['version']))} + for t in types] + return {'policy_types': result} @util.policy_enforce def get(self, req, type_name): diff --git a/senlin/api/openstack/v1/profile_types.py b/senlin/api/openstack/v1/profile_types.py index 45ba95b0b..27121ead8 100644 --- a/senlin/api/openstack/v1/profile_types.py +++ b/senlin/api/openstack/v1/profile_types.py @@ -15,6 +15,7 @@ Profile type endpoint for Senlin v1 ReST API. """ from senlin.api.common import util +from senlin.api.common import version_request as vr from senlin.api.common import wsgi @@ -29,7 +30,12 @@ class ProfileTypeController(wsgi.Controller): obj = util.parse_request('ProfileTypeListRequest', req, {}) types = self.rpc_client.call(req.context, 'profile_type_list', obj) - return {'profile_types': types} + result = types + if req.version_request <= vr.APIVersionRequest("1.4"): + # We return only profile type name before 1.5 + result = [{'name': '-'.join((t['name'], t['version']))} + for t in types] + return {'profile_types': result} @util.policy_enforce def get(self, req, type_name): diff --git a/senlin/engine/registry.py b/senlin/engine/registry.py index 27b7d89c5..0d5ba1ac3 100644 --- a/senlin/engine/registry.py +++ b/senlin/engine/registry.py @@ -133,4 +133,11 @@ class Registry(object): def get_types(self): '''Return a list of valid plugin types.''' - return [{'name': name} for name in self._registry.keys()] + return [ + { + 'name': name.split('-')[0] if '-' in name else name, + 'version': name.split('-')[1] if '-' in name else '', + 'support_status': pi.plugin.VERSIONS + } + for name, pi in self._registry.items() + ] diff --git a/senlin/tests/unit/api/openstack/v1/test_policy_types.py b/senlin/tests/unit/api/openstack/v1/test_policy_types.py index 8ca82cedc..0e49dea2f 100644 --- a/senlin/tests/unit/api/openstack/v1/test_policy_types.py +++ b/senlin/tests/unit/api/openstack/v1/test_policy_types.py @@ -37,12 +37,72 @@ class PolicyTypeControllerTest(shared.ControllerTest, base.SenlinTestCase): @mock.patch.object(util, 'parse_request') @mock.patch.object(rpc_client.EngineClient, 'call') - def test_policy_type_list(self, mock_call, mock_parse, mock_enforce): + def test_list(self, mock_call, mock_parse, mock_enforce): self._mock_enforce_setup(mock_enforce, 'index', True) req = self._get('/policy_types') - engine_response = [{'name': 'os.heat.stack'}, - {'name': 'os.nova.server'}] + engine_response = [ + {'name': 'senlin.policy.p1', 'version': '1.0', 'attr': 'v1'}, + {'name': 'senlin.policy.p2', 'version': '1.0', 'attr': 'v2'} + ] + + mock_call.return_value = engine_response + obj = mock.Mock() + mock_parse.return_value = obj + + response = self.controller.index(req) + + self.assertEqual( + [ + {'name': 'senlin.policy.p1-1.0'}, + {'name': 'senlin.policy.p2-1.0'}, + ], + response['policy_types'] + ) + mock_parse.assert_called_once_with( + 'PolicyTypeListRequest', req, {}) + mock_call.assert_called_once_with( + req.context, 'policy_type_list', mock.ANY) + + @mock.patch.object(util, 'parse_request') + @mock.patch.object(rpc_client.EngineClient, 'call') + def test_list_old_version(self, mock_call, mock_parse, mock_enforce): + self._mock_enforce_setup(mock_enforce, 'index', True) + req = self._get('/policy_types', version='1.3') + + engine_response = [ + {'name': 'senlin.policy.p1', 'version': '1.0'}, + {'name': 'senlin.policy.p2', 'version': '1.1'} + ] + + mock_call.return_value = engine_response + obj = mock.Mock() + mock_parse.return_value = obj + + response = self.controller.index(req) + + self.assertEqual( + [ + {'name': 'senlin.policy.p1-1.0'}, + {'name': 'senlin.policy.p2-1.1'} + ], + response['policy_types'] + ) + mock_parse.assert_called_once_with( + 'PolicyTypeListRequest', req, {}) + mock_call.assert_called_once_with( + req.context, 'policy_type_list', mock.ANY) + + @mock.patch.object(util, 'parse_request') + @mock.patch.object(rpc_client.EngineClient, 'call') + def test_list_new_version(self, mock_call, mock_parse, mock_enforce): + self._mock_enforce_setup(mock_enforce, 'index', True) + req = self._get('/policy_types', version='1.5') + + engine_response = [ + {'name': 'senlin.policy.p1', 'version': '1.0', 'a1': 'v1'}, + {'name': 'senlin.policy.p2', 'version': '1.1', 'a2': 'v2'} + ] mock_call.return_value = engine_response obj = mock.Mock() @@ -56,7 +116,7 @@ class PolicyTypeControllerTest(shared.ControllerTest, base.SenlinTestCase): mock_call.assert_called_once_with( req.context, 'policy_type_list', mock.ANY) - def test_policy_type_list_err_denied_policy(self, mock_enforce): + def test_list_err_denied_policy(self, mock_enforce): self._mock_enforce_setup(mock_enforce, 'index', False) req = self._get('/policy_types') resp = shared.request_with_middleware(fault.FaultWrapper, diff --git a/senlin/tests/unit/api/openstack/v1/test_profile_types.py b/senlin/tests/unit/api/openstack/v1/test_profile_types.py index b3bd36693..9ff59e35d 100644 --- a/senlin/tests/unit/api/openstack/v1/test_profile_types.py +++ b/senlin/tests/unit/api/openstack/v1/test_profile_types.py @@ -37,12 +37,63 @@ class ProfileTypeControllerTest(shared.ControllerTest, base.SenlinTestCase): @mock.patch.object(util, 'parse_request') @mock.patch.object(rpc_client.EngineClient, 'call') - def test_profile_type_list(self, mock_call, mock_parse, mock_enforce): + def test_list(self, mock_call, mock_parse, mock_enforce): self._mock_enforce_setup(mock_enforce, 'index', True) req = self._get('/profile_types') - engine_response = [{'name': 'os.heat.stack'}, - {'name': 'os.nova.server'}] + engine_response = [ + {'name': 'os.heat.stack', 'version': '1.0'}, + {'name': 'os.nova.server', 'version': '1.0'} + ] + + mock_call.return_value = engine_response + obj = mock.Mock() + mock_parse.return_value = obj + + response = self.controller.index(req) + + self.assertEqual( + [{'name': 'os.heat.stack-1.0'}, {'name': 'os.nova.server-1.0'}], + response['profile_types']) + mock_parse.assert_called_once_with('ProfileTypeListRequest', req, {}) + mock_call.assert_called_once_with( + req.context, 'profile_type_list', mock.ANY) + + @mock.patch.object(util, 'parse_request') + @mock.patch.object(rpc_client.EngineClient, 'call') + def test_list_old_version(self, mock_call, mock_parse, mock_enforce): + self._mock_enforce_setup(mock_enforce, 'index', True) + req = self._get('/profile_types', version='1.3') + + engine_response = [ + {'name': 'os.heat.stack', 'version': '1.0', 'attr': 'bar'}, + {'name': 'os.nova.server', 'version': '1.0', 'attr': 'foo'}, + ] + + mock_call.return_value = engine_response + obj = mock.Mock() + mock_parse.return_value = obj + + response = self.controller.index(req) + + self.assertEqual( + [{'name': 'os.heat.stack-1.0'}, {'name': 'os.nova.server-1.0'}], + response['profile_types'] + ) + mock_parse.assert_called_once_with('ProfileTypeListRequest', req, {}) + mock_call.assert_called_once_with( + req.context, 'profile_type_list', mock.ANY) + + @mock.patch.object(util, 'parse_request') + @mock.patch.object(rpc_client.EngineClient, 'call') + def test_list_new_version(self, mock_call, mock_parse, mock_enforce): + self._mock_enforce_setup(mock_enforce, 'index', True) + req = self._get('/profile_types', version='1.5') + + engine_response = [ + {'name': 'os.heat.stack', 'version': '1.0', 'attr': 'bar'}, + {'name': 'os.nova.server', 'version': '1.0', 'attr': 'foo'}, + ] mock_call.return_value = engine_response obj = mock.Mock() diff --git a/senlin/tests/unit/engine/test_environment.py b/senlin/tests/unit/engine/test_environment.py index ad01ed468..672488dee 100644 --- a/senlin/tests/unit/engine/test_environment.py +++ b/senlin/tests/unit/engine/test_environment.py @@ -177,14 +177,18 @@ class TestEnvironment(base.SenlinTestCase): def test_get_profile_types(self): env = environment.Environment() - plugin1 = mock.Mock() - env.register_profile('foo', plugin1) - plugin2 = mock.Mock() - env.register_profile('bar', plugin2) + plugin1 = mock.Mock(VERSIONS={'k': 'v'}) + env.register_profile('foo-1.0', plugin1) + plugin2 = mock.Mock(VERSIONS={'k': 'v1'}) + env.register_profile('bar-1.2', plugin2) actual = env.get_profile_types() - self.assertIn({'name': 'foo'}, actual) - self.assertIn({'name': 'bar'}, actual) + self.assertIn( + {'name': 'foo', 'version': '1.0', 'support_status': {'k': 'v'}}, + actual) + self.assertIn( + {'name': 'bar', 'version': '1.2', 'support_status': {'k': 'v1'}}, + actual) def test_register_and_get_policy(self): plugin = mock.Mock() @@ -200,14 +204,18 @@ class TestEnvironment(base.SenlinTestCase): def test_get_policy_types(self): env = environment.Environment() - plugin1 = mock.Mock() - env.register_policy('foo', plugin1) - plugin2 = mock.Mock() - env.register_policy('bar', plugin2) + plugin1 = mock.Mock(VERSIONS={'k': 'v'}) + env.register_policy('foo-0.1', plugin1) + plugin2 = mock.Mock(VERSIONS={'k': 'v1'}) + env.register_policy('bar-0.2', plugin2) actual = env.get_policy_types() - self.assertIn({'name': 'foo'}, actual) - self.assertIn({'name': 'bar'}, actual) + self.assertIn( + {'name': 'foo', 'version': '0.1', 'support_status': {'k': 'v'}}, + actual) + self.assertIn( + {'name': 'bar', 'version': '0.2', 'support_status': {'k': 'v1'}}, + actual) def test_register_and_get_driver_types(self): plugin = mock.Mock() @@ -223,14 +231,18 @@ class TestEnvironment(base.SenlinTestCase): def test_get_driver_types(self): env = environment.Environment() - plugin1 = mock.Mock() + plugin1 = mock.Mock(VERSIONS={}) env.register_driver('foo', plugin1) - plugin2 = mock.Mock() + plugin2 = mock.Mock(VERSIONS={}) env.register_driver('bar', plugin2) actual = env.get_driver_types() - self.assertIn({'name': 'foo'}, actual) - self.assertIn({'name': 'bar'}, actual) + self.assertIn( + {'name': 'foo', 'version': '', 'support_status': {}}, + actual) + self.assertIn( + {'name': 'bar', 'version': '', 'support_status': {}}, + actual) def test_read_global_environment(self): mock_dir = self.patchobject(glob, 'glob') diff --git a/senlin/tests/unit/engine/test_registry.py b/senlin/tests/unit/engine/test_registry.py index 84e642433..464223233 100644 --- a/senlin/tests/unit/engine/test_registry.py +++ b/senlin/tests/unit/engine/test_registry.py @@ -200,10 +200,22 @@ class RegistryTest(base.SenlinTestCase): def test_get_types(self): reg = registry.Registry('GLOBAL', None) - plugin1 = mock.Mock() - reg.register_plugin('FOO', plugin1) - plugin2 = mock.Mock() - reg.register_plugin('BAR', plugin2) + plugin1 = mock.Mock(VERSIONS={'foo': 'bar'}) + reg.register_plugin('FOO-1.0', plugin1) + plugin2 = mock.Mock(VERSIONS={'zoo': 'car'}) + reg.register_plugin('BAR-1.1', plugin2) - self.assertIn({'name': 'FOO'}, reg.get_types()) - self.assertIn({'name': 'BAR'}, reg.get_types()) + self.assertIn( + { + 'name': 'FOO', + 'version': '1.0', + 'support_status': {'foo': 'bar'} + }, + reg.get_types()) + self.assertIn( + { + 'name': 'BAR', + 'version': '1.1', + 'support_status': {'zoo': 'car'} + }, + reg.get_types())