From b0d6e82ec5ac328a685c87f05c016029f4994bb8 Mon Sep 17 00:00:00 2001 From: astaroverov Date: Thu, 4 May 2017 18:00:42 +0300 Subject: [PATCH] Move required-api-versions validator to '../validators.py' Change-Id: Ib7e006ddbcdfd51454502f4ccd0ca7da445c1059 --- rally/plugins/openstack/validators.py | 49 ++++++++ rally/task/validation.py | 36 +----- .../unit/plugins/openstack/test_validators.py | 105 +++++++++++++++++- tests/unit/task/test_validation.py | 77 ------------- 4 files changed, 155 insertions(+), 112 deletions(-) diff --git a/rally/plugins/openstack/validators.py b/rally/plugins/openstack/validators.py index 8552c563e9..6746e91026 100644 --- a/rally/plugins/openstack/validators.py +++ b/rally/plugins/openstack/validators.py @@ -469,3 +469,52 @@ class RequiredCinderServicesValidator(validation.Validator): msg = ("%s service is not available") % self.services return self.fail(msg) + + +@validation.add("required_platform", platform="openstack", users=True) +@validation.configure(name="required_api_versions", + namespace="openstack") +class RequiredAPIVersionsValidator(validation.Validator): + + def __init__(self, component, versions): + """Validator checks component API versions. + + :param component: name of required component + :param versions: version of required component + """ + super(RequiredAPIVersionsValidator, self).__init__() + self.component = component + self.versions = versions + + def validate(self, config, credentials, plugin_cls, plugin_cfg): + versions = [str(v) for v in self.versions] + versions_str = ", ".join(versions) + msg = ("Task was designed to be used with %(component)s " + "V%(version)s, but V%(found_version)s is " + "selected.") + for user in credentials["openstack"]["users"]: + clients = user["credential"].clients() + if self.component == "keystone": + if "2.0" not in versions and hasattr( + clients.keystone(), "tenants"): + return self.fail(msg % {"component": self.component, + "version": versions_str, + "found_version": "2.0"}) + if "3" not in versions and hasattr( + clients.keystone(), "projects"): + return self.fail(msg % {"component": self.component, + "version": versions_str, + "found_version": "3"}) + else: + used_version = config.get( + "context", {}).get( + "api_versions", {}).get( + self.component, {}).get( + "version", getattr( + clients, self.component).choose_version()) + if not used_version: + return self.fail("Unable to determine the API version.") + if str(used_version) not in versions: + return self.fail(msg % {"component": self.component, + "version": versions_str, + "found_version": used_version}) diff --git a/rally/task/validation.py b/rally/task/validation.py index 33f9fbf7ab..efd2ea7a8b 100755 --- a/rally/task/validation.py +++ b/rally/task/validation.py @@ -355,37 +355,6 @@ def required_param_or_context(config, clients, deployment, return ValidationResult(False, message) -@validator -def required_api_versions(config, clients, deployment, component, versions): - """Validator checks component API versions.""" - versions = [str(v) for v in versions] - versions_str = ", ".join(versions) - msg = _("Task was designed to be used with %(component)s " - "V%(version)s, but V%(found_version)s is " - "selected.") - if component == "keystone": - if "2.0" not in versions and hasattr(clients.keystone(), "tenants"): - return ValidationResult(False, msg % {"component": component, - "version": versions_str, - "found_version": "2.0"}) - if "3" not in versions and hasattr(clients.keystone(), "projects"): - return ValidationResult(False, msg % {"component": component, - "version": versions_str, - "found_version": "3"}) - else: - used_version = config.get("context", {}).get("api_versions", {}).get( - component, {}).get("version", - getattr(clients, component).choose_version()) - if not used_version: - return ValidationResult( - False, _("Unable to determine the API version.")) - if str(used_version) not in versions: - return ValidationResult( - False, msg % {"component": component, - "version": versions_str, - "found_version": used_version}) - - @validator def volume_type_exists(config, clients, deployment, param_name): """Returns validator for volume types. @@ -478,6 +447,7 @@ required_services = deprecated_validator("required_services", validate_heat_template = deprecated_validator("validate_heat_template", "validate_heat_template", "0.10.0") + restricted_parameters = deprecated_validator("restricted_parameters", "restricted_parameters", "0.10.0") @@ -485,3 +455,7 @@ restricted_parameters = deprecated_validator("restricted_parameters", required_cinder_services = deprecated_validator("required_cinder_services", "required_cinder_services", "0.10.0") + +required_api_versions = deprecated_validator("required_api_versions", + "required_api_versions", + "0.10.0") diff --git a/tests/unit/plugins/openstack/test_validators.py b/tests/unit/plugins/openstack/test_validators.py index 0faa313a10..57e1a580ce 100644 --- a/tests/unit/plugins/openstack/test_validators.py +++ b/tests/unit/plugins/openstack/test_validators.py @@ -53,8 +53,8 @@ class ImageExistsValidatorTestCase(test.TestCase): def setUp(self): super(ImageExistsValidatorTestCase, self).setUp() self.validator = validators.ImageExistsValidator("image", True) - self.config = config - self.credentials = credentials + self.config = copy.deepcopy(config) + self.credentials = copy.deepcopy(credentials) @ddt.unpack @ddt.data( @@ -115,7 +115,8 @@ class ImageExistsValidatorTestCase(test.TestCase): for ex in exs: clients.glance().images.get.side_effect = ex - result = self.validator.validate(config, credentials, None, None) + result = self.validator.validate(config, self.credentials, + None, None) self.assertEqual("Image 'fake_image' not found", result.msg) @@ -187,7 +188,7 @@ class RequiredNeutronExtensionsValidatorTestCase(test.TestCase): clients.neutron().list_extensions.return_value = { "extensions": [{"alias": "existing_extension"}]} - result = validator.validate({}, self.credentials, {}, None) + result = validator.validate({}, self.credentials, None, None) if err_msg: self.assertTrue(result) @@ -683,3 +684,99 @@ class RequiredCinderServicesValidatorTestCase(test.TestCase): self.assertTrue(result) self.assertEqual("cinder_service service is not available", result.msg) + + +@ddt.ddt +class RequiredAPIVersionsValidatorTestCase(test.TestCase): + + def setUp(self): + super(RequiredAPIVersionsValidatorTestCase, self).setUp() + self.config = copy.deepcopy(config) + self.credentials = copy.deepcopy(credentials) + + def _get_keystone_v2_mock_client(self): + keystone = mock.Mock() + del keystone.projects + keystone.tenants = mock.Mock() + return keystone + + def _get_keystone_v3_mock_client(self): + keystone = mock.Mock() + del keystone.tenants + keystone.projects = mock.Mock() + return keystone + + @ddt.unpack + @ddt.data( + {"versions": [2.0], "err_msg": "Task was designed to be used with" + " keystone V2.0, but V3 is selected."}, + {"versions": [3], "err_msg": "Task was designed to be used with" + " keystone V3, but V2.0 is selected."}, + {"versions": [2.0, 3], "err_msg": None} + ) + def test_validate_keystone(self, versions, err_msg): + validator = validators.RequiredAPIVersionsValidator("keystone", + versions) + + clients = self.credentials["openstack"]["users"][0][ + "credential"].clients() + + clients.keystone.return_value = self._get_keystone_v3_mock_client() + result = validator.validate(self.config, self.credentials, None, None) + + if result: + self.assertEqual(err_msg, result.msg) + + clients.keystone.return_value = self._get_keystone_v2_mock_client() + result = validator.validate(self.config, self.credentials, None, None) + + if result: + self.assertEqual(err_msg, result.msg) + + @ddt.unpack + @ddt.data( + {"nova": 2, "versions": [2], "err_msg": None}, + {"nova": 3, "versions": [2], + "err_msg": "Task was designed to be used with nova V2, " + "but V3 is selected."}, + {"nova": None, "versions": [2], + "err_msg": "Unable to determine the API version."}, + {"nova": 2, "versions": [2, 3], "err_msg": None}, + {"nova": 4, "versions": [2, 3], + "err_msg": "Task was designed to be used with nova V2, 3, " + "but V4 is selected."} + ) + def test_validate_nova(self, nova, versions, err_msg): + validator = validators.RequiredAPIVersionsValidator("nova", + versions) + + clients = self.credentials["openstack"]["users"][0][ + "credential"].clients() + + clients.nova.choose_version.return_value = nova + + result = validator.validate(self.config, self.credentials, None, None) + + if err_msg: + self.assertIsNotNone(result) + self.assertEqual(err_msg, result.msg) + else: + self.assertIsNone(result) + + @ddt.unpack + @ddt.data({"version": 2, "err_msg": None}, + {"version": 3, "err_msg": "Task was designed to be used with " + "nova V3, but V2 is selected."}) + def test_validate_context(self, version, err_msg): + validator = validators.RequiredAPIVersionsValidator("nova", + [version]) + + config = {"context": {"api_versions": {"nova": {"version": 2}}}} + + result = validator.validate(config, self.credentials, None, None) + + if err_msg: + self.assertIsNotNone(result) + self.assertEqual(err_msg, result.msg) + else: + self.assertIsNone(result) diff --git a/tests/unit/task/test_validation.py b/tests/unit/task/test_validation.py index f07c4b941b..d699c35ffe 100755 --- a/tests/unit/task/test_validation.py +++ b/tests/unit/task/test_validation.py @@ -571,83 +571,6 @@ class ValidatorsTestCase(test.TestCase): result = validator(context, clients, mock.MagicMock()) self.assertFalse(result.is_valid, result.msg) - def _get_keystone_v2_mock_client(self): - keystone = mock.Mock() - del keystone.projects - keystone.tenants = mock.Mock() - return keystone - - def _get_keystone_v3_mock_client(self): - keystone = mock.Mock() - del keystone.tenants - keystone.projects = mock.Mock() - return keystone - - def test_required_api_versions_keystonev2(self): - validator = self._unwrap_validator( - validation.required_api_versions, component="keystone", - versions=[2.0]) - clients = mock.MagicMock() - clients.keystone.return_value = self._get_keystone_v3_mock_client() - self.assertFalse(validator({}, clients, None).is_valid) - - clients.keystone.return_value = self._get_keystone_v2_mock_client() - self.assertTrue(validator({}, clients, None).is_valid) - - def test_required_api_versions_keystonev3(self): - validator = self._unwrap_validator( - validation.required_api_versions, component="keystone", - versions=[3]) - clients = mock.MagicMock() - - clients.keystone.return_value = self._get_keystone_v2_mock_client() - self.assertFalse(validator({}, clients, None).is_valid) - - clients.keystone.return_value = self._get_keystone_v3_mock_client() - self.assertTrue(validator({}, clients, None).is_valid) - - def test_required_api_versions_keystone_all_versions(self): - validator = self._unwrap_validator( - validation.required_api_versions, component="keystone", - versions=[2.0, 3]) - clients = mock.MagicMock() - - clients.keystone.return_value = self._get_keystone_v3_mock_client() - self.assertTrue(validator({}, clients, None).is_valid) - - clients.keystone.return_value = self._get_keystone_v2_mock_client() - self.assertTrue(validator({}, clients, None).is_valid) - - @ddt.data({"nova_version": 2, "required_versions": [2], "valid": True}, - {"nova_version": 3, "required_versions": [2], "valid": False}, - {"nova_version": None, "required_versions": [2], "valid": False}, - {"nova_version": 2, "required_versions": [2, 3], "valid": True}, - {"nova_version": 4, "required_versions": [2, 3], "valid": False}) - @ddt.unpack - def test_required_api_versions_choose_version(self, nova_version=None, - required_versions=(2,), - valid=False): - validator = self._unwrap_validator( - validation.required_api_versions, component="nova", - versions=required_versions) - clients = mock.MagicMock() - clients.nova.choose_version.return_value = nova_version - self.assertEqual(validator({}, clients, None).is_valid, - valid) - - @ddt.data({"required_version": 2, "valid": True}, - {"required_version": 3, "valid": False}) - @ddt.unpack - def test_required_api_versions_context(self, required_version=None, - valid=False): - validator = self._unwrap_validator( - validation.required_api_versions, component="nova", - versions=[required_version]) - clients = mock.MagicMock() - config = {"context": {"api_versions": {"nova": {"version": 2}}}} - self.assertEqual(validator(config, clients, None).is_valid, - valid) - @mock.patch( "rally.common.yamlutils.safe_load", return_value={