From a6617002e7bab0ca7d393cbff373c49fde638a4a Mon Sep 17 00:00:00 2001 From: Boden R Date: Tue, 14 Nov 2017 09:09:40 -0700 Subject: [PATCH] use flavors api def from neutron-lib The flavors extension's API definition was rehomed into neutron-lib with commit I0229a80bb168bac8dc0fa17fb2b06f1b140d27b4 This patch consumes it by: - Removing the rehomed code and using neutron-lib's implementation instead. - Using the APIExtensionDescriptor for the extensions parent class. NeutronLibImpact Change-Id: I265ac1c0596d0fb0acaf99eeb7cfe9501732476f --- neutron/db/flavors_db.py | 26 +-- neutron/extensions/flavors.py | 201 +----------------- neutron/tests/unit/extensions/test_flavors.py | 21 +- 3 files changed, 34 insertions(+), 214 deletions(-) diff --git a/neutron/db/flavors_db.py b/neutron/db/flavors_db.py index 6738b5d8a58..544f1dab1e2 100644 --- a/neutron/db/flavors_db.py +++ b/neutron/db/flavors_db.py @@ -12,6 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. +from neutron_lib.exceptions import flavors as flav_exc from oslo_db import exception as db_exc from oslo_log import log as logging @@ -19,7 +20,6 @@ from neutron.db import _utils as db_utils from neutron.db import api as db_api from neutron.db import common_db_mixin from neutron.db import servicetype_db as sdb -from neutron.extensions import flavors as ext_flavors from neutron.objects import base as base_obj from neutron.objects import flavor as obj_flavor @@ -34,14 +34,14 @@ class FlavorsDbMixin(common_db_mixin.CommonDbMixin): def _get_flavor(self, context, flavor_id): flavor = obj_flavor.Flavor.get_object(context, id=flavor_id) if not flavor: - raise ext_flavors.FlavorNotFound(flavor_id=flavor_id) + raise flav_exc.FlavorNotFound(flavor_id=flavor_id) return flavor def _get_service_profile(self, context, sp_id): service_profile = obj_flavor.ServiceProfile.get_object( context, id=sp_id) if not service_profile: - raise ext_flavors.ServiceProfileNotFound(sp_id=sp_id) + raise flav_exc.ServiceProfileNotFound(sp_id=sp_id) return service_profile @staticmethod @@ -80,7 +80,7 @@ class FlavorsDbMixin(common_db_mixin.CommonDbMixin): """Ensures no current bindings to flavors exist.""" if obj_flavor.FlavorServiceProfileBinding.objects_exist( context, service_profile_id=sp_id): - raise ext_flavors.ServiceProfileInUse(sp_id=sp_id) + raise flav_exc.ServiceProfileInUse(sp_id=sp_id) def _validate_driver(self, context, driver): """Confirms a non-empty driver is a valid provider.""" @@ -90,7 +90,7 @@ class FlavorsDbMixin(common_db_mixin.CommonDbMixin): filters={'driver': driver}) if not providers: - raise ext_flavors.ServiceProfileDriverNotFound(driver=driver) + raise flav_exc.ServiceProfileDriverNotFound(driver=driver) def create_flavor(self, context, flavor): fl = flavor['flavor'] @@ -122,7 +122,7 @@ class FlavorsDbMixin(common_db_mixin.CommonDbMixin): self._ensure_flavor_not_in_use(context, flavor_id) self._get_flavor(context, flavor_id).delete() except db_exc.DBReferenceError: - raise ext_flavors.FlavorInUse(flavor_id=flavor_id) + raise flav_exc.FlavorInUse(flavor_id=flavor_id) def get_flavors(self, context, filters=None, fields=None, sorts=None, limit=None, marker=None, page_reverse=False): @@ -139,7 +139,7 @@ class FlavorsDbMixin(common_db_mixin.CommonDbMixin): with db_api.context_manager.writer.using(context): if obj_flavor.FlavorServiceProfileBinding.objects_exist( context, service_profile_id=sp['id'], flavor_id=flavor_id): - raise ext_flavors.FlavorServiceProfileBindingExists( + raise flav_exc.FlavorServiceProfileBindingExists( sp_id=sp['id'], fl_id=flavor_id) obj_flavor.FlavorServiceProfileBinding( context, service_profile_id=sp['id'], @@ -152,7 +152,7 @@ class FlavorsDbMixin(common_db_mixin.CommonDbMixin): if (obj_flavor.FlavorServiceProfileBinding.delete_objects( context, service_profile_id=service_profile_id, flavor_id=flavor_id) == 0): - raise ext_flavors.FlavorServiceProfileBindingNotFound( + raise flav_exc.FlavorServiceProfileBindingNotFound( sp_id=service_profile_id, fl_id=flavor_id) @staticmethod @@ -161,7 +161,7 @@ class FlavorsDbMixin(common_db_mixin.CommonDbMixin): if not obj_flavor.FlavorServiceProfileBinding.objects_exist( context, service_profile_id=service_profile_id, flavor_id=flavor_id): - raise ext_flavors.FlavorServiceProfileBindingNotFound( + raise flav_exc.FlavorServiceProfileBindingNotFound( sp_id=service_profile_id, fl_id=flavor_id) res = {'service_profile_id': service_profile_id, 'flavor_id': flavor_id} @@ -174,7 +174,7 @@ class FlavorsDbMixin(common_db_mixin.CommonDbMixin): self._validate_driver(context, sp['driver']) else: if not sp['metainfo']: - raise ext_flavors.ServiceProfileEmpty() + raise flav_exc.ServiceProfileEmpty() obj = obj_flavor.ServiceProfile( context, description=sp['description'], driver=sp['driver'], @@ -225,14 +225,14 @@ class FlavorsDbMixin(common_db_mixin.CommonDbMixin): objs = obj_flavor.FlavorServiceProfileBinding.get_objects(context, flavor_id=flavor_id) if not objs: - raise ext_flavors.FlavorServiceProfileBindingNotFound( + raise flav_exc.FlavorServiceProfileBindingNotFound( sp_id='', fl_id=flavor_id) # Get the service profile from the first binding # TODO(jwarendt) Should become a scheduling framework instead sp_obj = self._get_service_profile(context, objs[0].service_profile_id) if not sp_obj.enabled: - raise ext_flavors.ServiceProfileDisabled() + raise flav_exc.ServiceProfileDisabled() LOG.debug("Found driver %s.", sp_obj.driver) @@ -242,7 +242,7 @@ class FlavorsDbMixin(common_db_mixin.CommonDbMixin): filters={'driver': sp_obj.driver}) if not providers: - raise ext_flavors.ServiceProfileDriverNotFound( + raise flav_exc.ServiceProfileDriverNotFound( driver=sp_obj.driver) LOG.debug("Found providers %s.", providers) diff --git a/neutron/extensions/flavors.py b/neutron/extensions/flavors.py index 16c929378a6..4f819a7a272 100644 --- a/neutron/extensions/flavors.py +++ b/neutron/extensions/flavors.py @@ -12,208 +12,37 @@ # License for the specific language governing permissions and limitations # under the License. -from neutron_lib.api import converters +from neutron_lib.api.definitions import flavors as apidef from neutron_lib.api import extensions as api_extensions -from neutron_lib.api import validators -from neutron_lib.db import constants as db_const -from neutron_lib import exceptions as nexception from neutron_lib.plugins import constants from neutron_lib.plugins import directory -from neutron._i18n import _ from neutron.api import extensions from neutron.api.v2 import base from neutron.api.v2 import resource_helper -# Flavor Exceptions -class FlavorNotFound(nexception.NotFound): - message = _("Flavor %(flavor_id)s could not be found.") +class Flavors(api_extensions.APIExtensionDescriptor): - -class FlavorInUse(nexception.InUse): - message = _("Flavor %(flavor_id)s is used by some service instance.") - - -class ServiceProfileNotFound(nexception.NotFound): - message = _("Service Profile %(sp_id)s could not be found.") - - -class ServiceProfileInUse(nexception.InUse): - message = _("Service Profile %(sp_id)s is used by some service instance.") - - -class FlavorServiceProfileBindingExists(nexception.Conflict): - message = _("Service Profile %(sp_id)s is already associated " - "with flavor %(fl_id)s.") - - -class FlavorServiceProfileBindingNotFound(nexception.NotFound): - message = _("Service Profile %(sp_id)s is not associated " - "with flavor %(fl_id)s.") - - -class ServiceProfileDriverNotFound(nexception.NotFound): - message = _("Service Profile driver %(driver)s could not be found.") - - -class ServiceProfileEmpty(nexception.InvalidInput): - message = _("Service Profile needs either a driver or metainfo.") - - -class FlavorDisabled(nexception.ServiceUnavailable): - message = _("Flavor is not enabled.") - - -class ServiceProfileDisabled(nexception.ServiceUnavailable): - message = _("Service Profile is not enabled.") - - -class InvalidFlavorServiceType(nexception.InvalidInput): - message = _("Invalid service type %(service_type)s.") - - -def _validate_flavor_service_type(validate_type, valid_values=None): - """Ensure requested flavor service type plugin is loaded.""" - if not directory.get_plugin(validate_type): - raise InvalidFlavorServiceType(service_type=validate_type) - -validators.add_validator('validate_flavor_service_type', - _validate_flavor_service_type) - -FLAVORS = 'flavors' -SERVICE_PROFILES = 'service_profiles' -FLAVORS_PREFIX = "" - -RESOURCE_ATTRIBUTE_MAP = { - FLAVORS: { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'name': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': db_const.NAME_FIELD_SIZE}, - 'is_visible': True, 'default': ''}, - 'description': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string_or_none': - db_const.LONG_DESCRIPTION_FIELD_SIZE}, - 'is_visible': True, 'default': ''}, - 'service_type': {'allow_post': True, 'allow_put': False, - 'validate': - {'type:validate_flavor_service_type': None}, - 'is_visible': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'required_by_policy': True, - 'validate': { - 'type:string': db_const.PROJECT_ID_FIELD_SIZE}, - 'is_visible': True}, - 'service_profiles': {'allow_post': True, 'allow_put': True, - 'validate': {'type:uuid_list': None}, - 'is_visible': True, 'default': []}, - 'enabled': {'allow_post': True, 'allow_put': True, - 'convert_to': converters.convert_to_boolean_if_not_none, - 'default': True, - 'is_visible': True}, - }, - SERVICE_PROFILES: { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'description': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string_or_none': - db_const.LONG_DESCRIPTION_FIELD_SIZE}, - 'is_visible': True, 'default': ''}, - 'driver': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': - db_const.LONG_DESCRIPTION_FIELD_SIZE}, - 'is_visible': True, - 'default': ''}, - 'metainfo': {'allow_post': True, 'allow_put': True, - 'is_visible': True, - 'default': ''}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'required_by_policy': True, - 'validate': { - 'type:string': db_const.PROJECT_ID_FIELD_SIZE}, - 'is_visible': True}, - 'enabled': {'allow_post': True, 'allow_put': True, - 'convert_to': converters.convert_to_boolean_if_not_none, - 'is_visible': True, 'default': True}, - }, -} - - -SUB_RESOURCE_ATTRIBUTE_MAP = { - 'next_providers': { - 'parent': {'collection_name': 'flavors', - 'member_name': 'flavor'}, - 'parameters': {'provider': {'allow_post': False, - 'allow_put': False, - 'is_visible': True}, - 'driver': {'allow_post': False, - 'allow_put': False, - 'is_visible': True}, - 'metainfo': {'allow_post': False, - 'allow_put': False, - 'is_visible': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'required_by_policy': True, - 'validate': { - 'type:string': - db_const.PROJECT_ID_FIELD_SIZE}, - 'is_visible': True}} - }, - 'service_profiles': { - 'parent': {'collection_name': 'flavors', - 'member_name': 'flavor'}, - 'parameters': {'id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'required_by_policy': True, - 'validate': { - 'type:string': - db_const.PROJECT_ID_FIELD_SIZE}, - 'is_visible': True}} - } -} - - -class Flavors(api_extensions.ExtensionDescriptor): - - @classmethod - def get_name(cls): - return "Neutron Service Flavors" - - @classmethod - def get_alias(cls): - return "flavors" - - @classmethod - def get_description(cls): - return "Flavor specification for Neutron advanced services" - - @classmethod - def get_updated(cls): - return "2015-09-17T10:00:00-00:00" + api_definition = apidef @classmethod def get_resources(cls): """Returns Ext Resources.""" plural_mappings = resource_helper.build_plural_mappings( - {}, RESOURCE_ATTRIBUTE_MAP) + {}, apidef.RESOURCE_ATTRIBUTE_MAP) resources = resource_helper.build_resource_info( plural_mappings, - RESOURCE_ATTRIBUTE_MAP, + apidef.RESOURCE_ATTRIBUTE_MAP, constants.FLAVORS) plugin = directory.get_plugin(constants.FLAVORS) - for collection_name in SUB_RESOURCE_ATTRIBUTE_MAP: + for collection_name in apidef.SUB_RESOURCE_ATTRIBUTE_MAP: # Special handling needed for sub-resources with 'y' ending # (e.g. proxies -> proxy) resource_name = collection_name[:-1] - parent = SUB_RESOURCE_ATTRIBUTE_MAP[collection_name].get('parent') - params = SUB_RESOURCE_ATTRIBUTE_MAP[collection_name].get( + parent = apidef.SUB_RESOURCE_ATTRIBUTE_MAP[collection_name].get( + 'parent') + params = apidef.SUB_RESOURCE_ATTRIBUTE_MAP[collection_name].get( 'parameters') controller = base.create_resource(collection_name, resource_name, @@ -224,18 +53,8 @@ class Flavors(api_extensions.ExtensionDescriptor): resource = extensions.ResourceExtension( collection_name, controller, parent, - path_prefix=FLAVORS_PREFIX, + path_prefix=apidef.API_PREFIX, attr_map=params) resources.append(resource) return resources - - def update_attributes_map(self, attributes): - super(Flavors, self).update_attributes_map( - attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP) - - def get_extended_resources(self, version): - if version == "2.0": - return RESOURCE_ATTRIBUTE_MAP - else: - return {} diff --git a/neutron/tests/unit/extensions/test_flavors.py b/neutron/tests/unit/extensions/test_flavors.py index fea9f2b3820..f90912b0198 100644 --- a/neutron/tests/unit/extensions/test_flavors.py +++ b/neutron/tests/unit/extensions/test_flavors.py @@ -19,6 +19,7 @@ import fixtures import mock from neutron_lib import context from neutron_lib.db import constants as db_const +from neutron_lib.exceptions import flavors as flav_exc from neutron_lib.plugins import constants from oslo_config import cfg from oslo_utils import uuidutils @@ -53,7 +54,7 @@ class FlavorExtensionTestCase(extension.ExtensionTestCase): super(FlavorExtensionTestCase, self).setUp() self._setUpExtension( 'neutron.services.flavors.flavors_plugin.FlavorsPlugin', - constants.FLAVORS, flavors.RESOURCE_ATTRIBUTE_MAP, + constants.FLAVORS, {}, flavors.Flavors, '', supported_extension_aliases='flavors') def test_create_flavor(self): @@ -538,7 +539,7 @@ class FlavorPluginTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase, 'driver': "Broken", 'enabled': True, 'metainfo': '{"data": "value"}'}} - self.assertRaises(flavors.ServiceProfileDriverNotFound, + self.assertRaises(flav_exc.ServiceProfileDriverNotFound, self.plugin.create_service_profile, self.ctx, data) @@ -549,7 +550,7 @@ class FlavorPluginTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase, 'driver': '', 'enabled': True, 'metainfo': ''}} - self.assertRaises(flavors.ServiceProfileEmpty, + self.assertRaises(flav_exc.ServiceProfileEmpty, self.plugin.create_service_profile, self.ctx, data) @@ -616,7 +617,7 @@ class FlavorPluginTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase, self.ctx, {'service_profile': {'id': sp['id']}}, fl['id']) - self.assertRaises(flavors.FlavorServiceProfileBindingExists, + self.assertRaises(flav_exc.FlavorServiceProfileBindingExists, self.plugin.create_flavor_service_profile, self.ctx, {'service_profile': {'id': sp['id']}}, @@ -636,7 +637,7 @@ class FlavorPluginTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase, flavor_obj.FlavorServiceProfileBinding.objects_exist(self.ctx)) self.assertRaises( - flavors.FlavorServiceProfileBindingNotFound, + flav_exc.FlavorServiceProfileBindingNotFound, self.plugin.delete_flavor_service_profile, self.ctx, sp['id'], fl['id']) @@ -648,7 +649,7 @@ class FlavorPluginTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase, {'service_profile': {'id': sp['id']}}, fl['id']) self.assertRaises( - flavors.ServiceProfileInUse, + flav_exc.ServiceProfileInUse, self.plugin.delete_service_profile, self.ctx, sp['id']) @@ -659,7 +660,7 @@ class FlavorPluginTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase, with self.ctx.session.begin(): self.ctx.session.add(l3_models.Router(flavor_id=fl['id'])) self.assertRaises( - flavors.FlavorInUse, + flav_exc.FlavorInUse, self.plugin.delete_flavor, self.ctx, fl['id']) @@ -667,7 +668,7 @@ class FlavorPluginTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase, def test_get_flavor_next_provider_no_binding(self): fl, data = self._create_flavor() self.assertRaises( - flavors.FlavorServiceProfileBindingNotFound, + flav_exc.FlavorServiceProfileBindingNotFound, self.plugin.get_flavor_next_provider, self.ctx, fl['id']) @@ -686,7 +687,7 @@ class FlavorPluginTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase, {'service_profile': {'id': sp['id']}}, fl['id']) self.assertRaises( - flavors.ServiceProfileDisabled, + flav_exc.ServiceProfileDisabled, self.plugin.get_flavor_next_provider, self.ctx, fl['id']) @@ -705,7 +706,7 @@ class FlavorPluginTestCase(test_db_base_plugin_v2.NeutronDbPluginV2TestCase, {'service_profile': {'id': sp['id']}}, fl['id']) self.assertRaises( - flavors.ServiceProfileDriverNotFound, + flav_exc.ServiceProfileDriverNotFound, self.plugin.get_flavor_next_provider, self.ctx, fl['id'])