From 54d38f40bb4b1da705bf6744c57eeadb5d52712b Mon Sep 17 00:00:00 2001 From: Jason Dunsmore Date: Wed, 25 Jan 2017 11:36:22 -0600 Subject: [PATCH] Don't create clusters of an unsupported type Return a 400 error if the cluster type is unsupported (ie. no drivers are installed that will create a cluster of that particular server type, cluster distro, and COE combination). Partial-Bug: #1646215 Change-Id: I26d9881cfc530132e1aa88d01194c6496bc527f4 --- magnum/api/controllers/v1/cluster.py | 5 ++- magnum/api/validation.py | 16 ++++++++ magnum/common/exception.py | 2 +- magnum/tests/unit/api/test_validation.py | 51 ++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 3 deletions(-) diff --git a/magnum/api/controllers/v1/cluster.py b/magnum/api/controllers/v1/cluster.py index 19818a9ac8..e6ad47f44d 100644 --- a/magnum/api/controllers/v1/cluster.py +++ b/magnum/api/controllers/v1/cluster.py @@ -28,7 +28,7 @@ from magnum.api.controllers.v1 import collection from magnum.api.controllers.v1 import types from magnum.api import expose from magnum.api import utils as api_utils -from magnum.api.validation import validate_cluster_properties +from magnum.api import validation from magnum.common import clients from magnum.common import exception from magnum.common import name_generator @@ -375,6 +375,7 @@ class ClustersController(base.Controller): raise exception.ResourceLimitExceeded(msg=msg) @expose.expose(ClusterID, body=Cluster, status_code=202) + @validation.enforce_cluster_type_supported() def post(self, cluster): """Create a new cluster. @@ -473,7 +474,7 @@ class ClustersController(base.Controller): delta = cluster.obj_what_changed() - validate_cluster_properties(delta) + validation.validate_cluster_properties(delta) return cluster @expose.expose(None, types.uuid_or_name, status_code=204) diff --git a/magnum/api/validation.py b/magnum/api/validation.py index 23da2d05f2..234bba8ba1 100644 --- a/magnum/api/validation.py +++ b/magnum/api/validation.py @@ -20,6 +20,7 @@ import pecan from magnum.api import utils as api_utils from magnum.common import exception import magnum.conf +from magnum.drivers.common import driver from magnum.i18n import _ from magnum import objects @@ -28,6 +29,21 @@ CONF = magnum.conf.CONF cluster_update_allowed_properties = set(['node_count']) +def enforce_cluster_type_supported(): + @decorator.decorator + def wrapper(func, *args, **kwargs): + cluster = args[1] + cluster_template = objects.ClusterTemplate.get_by_uuid( + pecan.request.context, cluster.cluster_template_id) + cluster_type = (cluster_template.server_type, + cluster_template.cluster_distro, + cluster_template.coe) + driver.Driver.get_driver(*cluster_type) + return func(*args, **kwargs) + + return wrapper + + def enforce_network_driver_types_create(): @decorator.decorator def wrapper(func, *args, **kwargs): diff --git a/magnum/common/exception.py b/magnum/common/exception.py index 9a8c347bd9..d3986494b1 100644 --- a/magnum/common/exception.py +++ b/magnum/common/exception.py @@ -260,7 +260,7 @@ class NotSupported(MagnumException): code = 400 -class ClusterTypeNotSupported(MagnumException): +class ClusterTypeNotSupported(NotSupported): message = _("Cluster type (%(server_type)s, %(os)s, %(coe)s)" " not supported.") diff --git a/magnum/tests/unit/api/test_validation.py b/magnum/tests/unit/api/test_validation.py index d6e05d080c..b1c1149a64 100644 --- a/magnum/tests/unit/api/test_validation.py +++ b/magnum/tests/unit/api/test_validation.py @@ -28,6 +28,57 @@ CONF = magnum.conf.CONF class TestValidation(base.BaseTestCase): + def _test_enforce_cluster_type_supported( + self, mock_cluster_template_get_by_uuid, mock_cluster_get_by_uuid, + mock_pecan_request, cluster_type, assert_raised=False): + + @v.enforce_cluster_type_supported() + def test(self, cluster): + pass + + server_type, cluster_distro, coe = cluster_type + cluster_template = obj_utils.get_test_cluster_template( + mock_pecan_request.context, uuid='cluster_template_id', + coe=coe, cluster_distro=cluster_distro, server_type=server_type) + mock_cluster_template_get_by_uuid.return_value = cluster_template + + cluster = mock.MagicMock() + cluster.cluster_template_id = 'cluster_template_id' + cluster.cluster_template = cluster_template + mock_cluster_get_by_uuid.return_value = cluster + + if assert_raised: + return self.assertRaises( + exception.ClusterTypeNotSupported, test, self, cluster) + else: + self.assertIsNone(test(self, cluster)) + + @mock.patch('pecan.request') + @mock.patch('magnum.objects.Cluster.get_by_uuid') + @mock.patch('magnum.objects.ClusterTemplate.get_by_uuid') + def test_enforce_cluster_type_supported( + self, mock_cluster_template_get_by_uuid, mock_cluster_get_by_uuid, + mock_pecan_request): + + cluster_type = ('vm', 'fedora-atomic', 'kubernetes') + self._test_enforce_cluster_type_supported( + mock_cluster_template_get_by_uuid, mock_cluster_get_by_uuid, + mock_pecan_request, cluster_type) + + @mock.patch('pecan.request') + @mock.patch('magnum.objects.Cluster.get_by_uuid') + @mock.patch('magnum.objects.ClusterTemplate.get_by_uuid') + def test_enforce_cluster_type_not_supported( + self, mock_cluster_template_get_by_uuid, mock_cluster_get_by_uuid, + mock_pecan_request): + + cluster_type = ('vm', 'foo', 'kubernetes') + exc = self._test_enforce_cluster_type_supported( + mock_cluster_template_get_by_uuid, mock_cluster_get_by_uuid, + mock_pecan_request, cluster_type, assert_raised=True) + self.assertEqual('Cluster type (vm, foo, kubernetes) not supported.', + exc.message) + def _test_enforce_network_driver_types_create( self, network_driver_type,