From f2629f288caced21c97ba1241fdb19f2afd0f194 Mon Sep 17 00:00:00 2001 From: wangqun Date: Tue, 19 Jan 2016 02:40:11 +0000 Subject: [PATCH] Validates baymodel volume_driver requests Instead of allowing any volume_driver value to be accepted by the baymodel API. When creating baymodel, the patch can limit the volume_driver value for the different coe. Kubernetes <=> volume_driver = "cinder" Swarm <=> volume_driver = "rexray" Mesos <=> volume_driver = "rexray" Co-Authored By: Kai Qiang Wu(Kennan) Co-Authored By: Ton Ngo Partially-Implements: blueprint magnum-integrate-with-cinder Depends-On: I52c97e2b04ac636ddac611e3677c4ea3972220eb Change-Id: I25f1cd005a39950c47f31a8b925f664909b79ee3 --- magnum/api/controllers/v1/baymodel.py | 1 + magnum/api/validation.py | 35 +++++++++++++++++++ .../tests/functional/api/v1/test_baymodel.py | 8 +++++ magnum/tests/functional/common/datagen.py | 14 +++++++- .../functional/k8s/test_k8s_python_client.py | 1 + .../mesos/test_mesos_python_client.py | 5 +-- magnum/tests/functional/python_client_base.py | 2 ++ .../swarm/test_swarm_python_client.py | 4 ++- magnum/tests/unit/api/test_validation.py | 30 ++++++++++++++++ 9 files changed, 96 insertions(+), 4 deletions(-) diff --git a/magnum/api/controllers/v1/baymodel.py b/magnum/api/controllers/v1/baymodel.py index 8981552b41..c3d47d64db 100644 --- a/magnum/api/controllers/v1/baymodel.py +++ b/magnum/api/controllers/v1/baymodel.py @@ -302,6 +302,7 @@ class BayModelsController(rest.RestController): @expose.expose(BayModel, body=BayModel, status_code=201) @policy.enforce_wsgi("baymodel", "create") @validation.enforce_network_driver_types_create() + @validation.enforce_volume_driver_types_create() def post(self, baymodel): """Create a new baymodel. diff --git a/magnum/api/validation.py b/magnum/api/validation.py index 53dd6c5f4f..25f9bc9cb1 100644 --- a/magnum/api/validation.py +++ b/magnum/api/validation.py @@ -120,6 +120,23 @@ def _enforce_network_driver_types(baymodel): validator.validate_network_driver(baymodel.network_driver) +def enforce_volume_driver_types_create(): + @decorator.decorator + def wrapper(func, *args, **kwargs): + baymodel = args[1] + _enforce_volume_driver_types(baymodel) + return func(*args, **kwargs) + + return wrapper + + +def _enforce_volume_driver_types(baymodel): + validator = Validator.get_coe_validator(baymodel.coe) + if not baymodel.volume_driver: + return + validator.validate_volume_driver(baymodel.volume_driver) + + class Validator(object): validators = {} @@ -166,12 +183,28 @@ class Validator(object): 'allowed_drivers': '/'.join( cls.allowed_drivers + ['unspecified'])}) + @classmethod + def validate_volume_driver(cls, driver): + cls._validate_volume_driver_supported(driver) + + @classmethod + def _validate_volume_driver_supported(cls, driver): + """Confirm that volume driver is supported by Magnum for this COE.""" + if driver not in cls.supported_volume_driver: + raise exception.InvalidParameterValue(_( + 'Volume driver type %(driver)s is not supported, ' + 'expecting a %(supported_volume_driver)s volume driver.') % { + 'driver': driver, + 'supported_volume_driver': '/'.join( + cls.supported_volume_driver + ['unspecified'])}) + class K8sValidator(Validator): supported_drivers = ['flannel'] allowed_drivers = cfg.CONF.baymodel.kubernetes_allowed_network_drivers default_driver = cfg.CONF.baymodel.kubernetes_default_network_driver + supported_volume_driver = ['cinder'] class SwarmValidator(Validator): @@ -179,6 +212,7 @@ class SwarmValidator(Validator): supported_drivers = ['docker', 'flannel'] allowed_drivers = cfg.CONF.baymodel.swarm_allowed_network_drivers default_driver = cfg.CONF.baymodel.swarm_default_network_driver + supported_volume_driver = ['rexray'] class MesosValidator(Validator): @@ -186,3 +220,4 @@ class MesosValidator(Validator): supported_drivers = ['docker'] allowed_drivers = cfg.CONF.baymodel.mesos_allowed_network_drivers default_driver = cfg.CONF.baymodel.mesos_default_network_driver + supported_volume_driver = ['rexray'] diff --git a/magnum/tests/functional/api/v1/test_baymodel.py b/magnum/tests/functional/api/v1/test_baymodel.py index 1e48cd806f..4df7397b9b 100644 --- a/magnum/tests/functional/api/v1/test_baymodel.py +++ b/magnum/tests/functional/api/v1/test_baymodel.py @@ -176,3 +176,11 @@ class BayModelTest(base.BaseMagnumTest): self.assertRaises( exceptions.BadRequest, self.baymodel_client.post_baymodel, gen_model) + + @testtools.testcase.attr('negative') + def test_create_baymodel_invalid_volume_driver(self): + gen_model = datagen.baymodel_data_with_valid_keypair_and_image_id() + gen_model.volume_driver = 'invalid_volume_driver' + self.assertRaises( + exceptions.BadRequest, + self.baymodel_client.post_baymodel, gen_model) diff --git a/magnum/tests/functional/common/datagen.py b/magnum/tests/functional/common/datagen.py index 89f1ba65ef..f5a122518d 100644 --- a/magnum/tests/functional/common/datagen.py +++ b/magnum/tests/functional/common/datagen.py @@ -38,6 +38,16 @@ def gen_coe_dep_network_driver(coe): return driver_types[random.randrange(0, len(driver_types))] +def gen_coe_dep_volume_driver(coe): + allowed_driver_types = { + 'kubernetes': ['cinder', None], + 'swarm': ['rexray', None], + 'mesos': ['rexray', None], + } + driver_types = allowed_driver_types[coe] + return driver_types[random.randrange(0, len(driver_types))] + + def gen_random_port(): return random_int(49152, 65535) @@ -91,6 +101,7 @@ def baymodel_data(**kwargs): "coe": "swarm", "tls_disabled": False, "network_driver": None, + "volume_driver": None, "docker_volume_size": 3, "labels": {}, "fixed_network": "192.168.0.0/24", @@ -175,7 +186,8 @@ def valid_swarm_baymodel(): docker_volume_size=3, cluster_distro=None, ssh_authorized_key=None, external_network_id="public", http_proxy=None, https_proxy=None, no_proxy=None, - network_driver=None, labels={}, tls_disabled=False) + network_driver=None, volume_driver=None, labels={}, + tls_disabled=False) def bay_data(name=data_utils.rand_name('bay'), diff --git a/magnum/tests/functional/k8s/test_k8s_python_client.py b/magnum/tests/functional/k8s/test_k8s_python_client.py index da24fa5618..e1ea4201e4 100644 --- a/magnum/tests/functional/k8s/test_k8s_python_client.py +++ b/magnum/tests/functional/k8s/test_k8s_python_client.py @@ -41,6 +41,7 @@ class TestKubernetesAPIs(BayAPITLSTest): coe='kubernetes', tls_disabled=False, network_driver='flannel', + volume_driver='cinder', fixed_network='192.168.0.0/24', ) cls.bay = cls._create_bay('testk8sAPI', cls.baymodel.uuid) diff --git a/magnum/tests/functional/mesos/test_mesos_python_client.py b/magnum/tests/functional/mesos/test_mesos_python_client.py index 495223c317..1f5b0b5a32 100644 --- a/magnum/tests/functional/mesos/test_mesos_python_client.py +++ b/magnum/tests/functional/mesos/test_mesos_python_client.py @@ -18,7 +18,8 @@ class TestBayModelResource(BayTest): def test_baymodel_create_and_delete(self): self._test_baymodel_create_and_delete('test_mesos_baymodel', - network_driver='docker') + network_driver='docker', + volume_driver='rexray') class TestBayResource(BayTest): @@ -27,5 +28,5 @@ class TestBayResource(BayTest): def test_bay_create_and_delete(self): baymodel_uuid = self._test_baymodel_create_and_delete( 'test_mesos_baymodel', delete=False, tls_disabled=True, - network_driver='docker') + network_driver='docker', volume_driver='rexray') self._test_bay_create_and_delete('test_mesos_bay', baymodel_uuid) diff --git a/magnum/tests/functional/python_client_base.py b/magnum/tests/functional/python_client_base.py index 154ac66c64..3fed35a868 100644 --- a/magnum/tests/functional/python_client_base.py +++ b/magnum/tests/functional/python_client_base.py @@ -108,6 +108,7 @@ class BaseMagnumClient(base.TestCase): coe = kwargs.pop('coe', 'kubernetes') docker_volume_size = kwargs.pop('docker_volume_size', 3) network_driver = kwargs.pop('network_driver', 'flannel') + volume_driver = kwargs.pop('volume_driver', 'cinder') labels = kwargs.pop('labels', {"K1": "V1", "K2": "V2"}) tls_disabled = kwargs.pop('tls_disabled', False) @@ -120,6 +121,7 @@ class BaseMagnumClient(base.TestCase): master_flavor_id=cls.flavor_id, docker_volume_size=docker_volume_size, network_driver=network_driver, + volume_driver=volume_driver, coe=coe, labels=labels, tls_disabled=tls_disabled, diff --git a/magnum/tests/functional/swarm/test_swarm_python_client.py b/magnum/tests/functional/swarm/test_swarm_python_client.py index 51d07c06e3..7aa812fda0 100644 --- a/magnum/tests/functional/swarm/test_swarm_python_client.py +++ b/magnum/tests/functional/swarm/test_swarm_python_client.py @@ -33,7 +33,8 @@ class TestBayModelResource(BayTest): def test_baymodel_create_and_delete(self): self._test_baymodel_create_and_delete( 'test_swarm_baymodel', - network_driver=None) + network_driver=None, + volume_driver=None) class TestSwarmAPIs(BayAPITLSTest): @@ -51,6 +52,7 @@ class TestSwarmAPIs(BayAPITLSTest): coe='swarm', tls_disabled=False, network_driver=None, + volume_driver=None, docker_volume_size=3, labels={}, fixed_network='192.168.0.0/24', diff --git a/magnum/tests/unit/api/test_validation.py b/magnum/tests/unit/api/test_validation.py index 91e4adcb2f..d094ac89d7 100644 --- a/magnum/tests/unit/api/test_validation.py +++ b/magnum/tests/unit/api/test_validation.py @@ -318,3 +318,33 @@ class TestValidation(base.BaseTestCase): network_driver_type=driver, network_driver_config_dict={ 'kubernetes_allowed_network_drivers': ['all']}) + + def _test_enforce_volume_driver_types_create( + self, + volume_driver_type, + coe='kubernetes', + assert_raised=False): + + @v.enforce_volume_driver_types_create() + def test(self, baymodel): + pass + + baymodel = mock.MagicMock() + baymodel.name = 'test_baymodel' + baymodel.volume_driver = volume_driver_type + baymodel.coe = coe + + if assert_raised: + self.assertRaises(exception.InvalidParameterValue, + test, self, baymodel) + else: + test(self, baymodel) + + def test_enforce_volume_driver_types_valid_create(self): + self._test_enforce_volume_driver_types_create( + volume_driver_type='cinder') + + def test_enforce_volume_driver_types_invalid_create(self): + self._test_enforce_volume_driver_types_create( + volume_driver_type='type', + assert_raised=True)