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
This commit is contained in:
Boden R 2017-11-14 09:09:40 -07:00
parent cfc0a1ae5b
commit a6617002e7
3 changed files with 34 additions and 214 deletions

View File

@ -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)

View File

@ -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 {}

View File

@ -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'])