957eca96f4
The functionality within neutron.db.common_db_mixin is available via neutron-lib APIs. This patch removes common_db_mixin and updates any uses of it to use neutron-lib instead. Depends-On: https://review.openstack.org/#/c/636159/ NeutronLibImpact Change-Id: I2388f90b37abb09408809dda8c21da551bcd94bb
253 lines
11 KiB
Python
253 lines
11 KiB
Python
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from neutron_lib.db import api as db_api
|
|
from neutron_lib.db import utils as db_utils
|
|
from neutron_lib.exceptions import flavors as flav_exc
|
|
from oslo_db import exception as db_exc
|
|
from oslo_log import log as logging
|
|
|
|
from neutron.db import servicetype_db as sdb
|
|
from neutron.objects import base as base_obj
|
|
from neutron.objects import flavor as obj_flavor
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class FlavorsDbMixin(object):
|
|
|
|
"""Class to support flavors and service profiles."""
|
|
|
|
def _get_flavor(self, context, flavor_id):
|
|
flavor = obj_flavor.Flavor.get_object(context, id=flavor_id)
|
|
if not flavor:
|
|
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 flav_exc.ServiceProfileNotFound(sp_id=sp_id)
|
|
return service_profile
|
|
|
|
@staticmethod
|
|
def _make_flavor_dict(flavor_obj, fields=None):
|
|
res = {'id': flavor_obj['id'],
|
|
'name': flavor_obj['name'],
|
|
'description': flavor_obj['description'],
|
|
'service_type': flavor_obj['service_type'],
|
|
'enabled': flavor_obj['enabled'],
|
|
'service_profiles': list(flavor_obj['service_profile_ids'])}
|
|
|
|
return db_utils.resource_fields(res, fields)
|
|
|
|
@staticmethod
|
|
def _make_service_profile_dict(sp_obj, fields=None):
|
|
res = {'id': sp_obj['id'],
|
|
'description': sp_obj['description'],
|
|
'driver': sp_obj['driver'],
|
|
'enabled': sp_obj['enabled'],
|
|
'metainfo': sp_obj['metainfo'],
|
|
'flavors': list(sp_obj['flavor_ids'])}
|
|
return db_utils.resource_fields(res, fields)
|
|
|
|
def _ensure_flavor_not_in_use(self, context, flavor_id):
|
|
"""Checks that flavor is not associated with service instance."""
|
|
# Future TODO(enikanorov): check that there is no binding to
|
|
# instances. Shall address in future upon getting the right
|
|
# flavor supported driver
|
|
# NOTE(kevinbenton): sqlalchemy utils has a cool dependent
|
|
# objects function we can use to quickly query all tables
|
|
# that have a foreign key ref to flavors. Or we could replace
|
|
# the call to this with callback events.
|
|
pass
|
|
|
|
def _ensure_service_profile_not_in_use(self, context, sp_id):
|
|
"""Ensures no current bindings to flavors exist."""
|
|
if obj_flavor.FlavorServiceProfileBinding.objects_exist(
|
|
context, service_profile_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."""
|
|
service_type_manager = sdb.ServiceTypeManager.get_instance()
|
|
providers = service_type_manager.get_service_providers(
|
|
context,
|
|
filters={'driver': driver})
|
|
|
|
if not providers:
|
|
raise flav_exc.ServiceProfileDriverNotFound(driver=driver)
|
|
|
|
def create_flavor(self, context, flavor):
|
|
fl = flavor['flavor']
|
|
obj = obj_flavor.Flavor(
|
|
context, name=fl['name'], description=fl['description'],
|
|
service_type=fl['service_type'], enabled=fl['enabled'])
|
|
obj.create()
|
|
return self._make_flavor_dict(obj)
|
|
|
|
def update_flavor(self, context, flavor_id, flavor):
|
|
with db_api.CONTEXT_WRITER.using(context):
|
|
self._ensure_flavor_not_in_use(context, flavor_id)
|
|
fl_obj = self._get_flavor(context, flavor_id)
|
|
fl_obj.update_fields(flavor['flavor'])
|
|
fl_obj.update()
|
|
return self._make_flavor_dict(fl_obj)
|
|
|
|
def get_flavor(self, context, flavor_id, fields=None):
|
|
fl = self._get_flavor(context, flavor_id)
|
|
return self._make_flavor_dict(fl, fields)
|
|
|
|
def delete_flavor(self, context, flavor_id):
|
|
# NOTE(kevinbenton): we need to fix _ensure_flavor_not_in_use,
|
|
# but the fix is non-trivial since multiple services can use
|
|
# flavors so for now we just capture the foreign key violation
|
|
# to detect if it's in use.
|
|
try:
|
|
with db_api.CONTEXT_WRITER.using(context):
|
|
self._ensure_flavor_not_in_use(context, flavor_id)
|
|
self._get_flavor(context, flavor_id).delete()
|
|
except db_exc.DBReferenceError:
|
|
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):
|
|
pager = base_obj.Pager(sorts, limit, page_reverse, marker)
|
|
filters = filters or {}
|
|
flavor_objs = obj_flavor.Flavor.get_objects(context, _pager=pager,
|
|
**filters)
|
|
return [self._make_flavor_dict(flavor_object, fields)
|
|
for flavor_object in flavor_objs]
|
|
|
|
def create_flavor_service_profile(self, context,
|
|
service_profile, flavor_id):
|
|
sp = service_profile['service_profile']
|
|
with db_api.CONTEXT_WRITER.using(context):
|
|
if obj_flavor.FlavorServiceProfileBinding.objects_exist(
|
|
context, service_profile_id=sp['id'], flavor_id=flavor_id):
|
|
raise flav_exc.FlavorServiceProfileBindingExists(
|
|
sp_id=sp['id'], fl_id=flavor_id)
|
|
obj_flavor.FlavorServiceProfileBinding(
|
|
context, service_profile_id=sp['id'],
|
|
flavor_id=flavor_id).create()
|
|
fl_obj = self._get_flavor(context, flavor_id)
|
|
return self._make_flavor_dict(fl_obj)
|
|
|
|
def delete_flavor_service_profile(self, context,
|
|
service_profile_id, flavor_id):
|
|
if (obj_flavor.FlavorServiceProfileBinding.delete_objects(
|
|
context, service_profile_id=service_profile_id,
|
|
flavor_id=flavor_id) == 0):
|
|
raise flav_exc.FlavorServiceProfileBindingNotFound(
|
|
sp_id=service_profile_id, fl_id=flavor_id)
|
|
|
|
@staticmethod
|
|
def get_flavor_service_profile(context,
|
|
service_profile_id, flavor_id, fields=None):
|
|
if not obj_flavor.FlavorServiceProfileBinding.objects_exist(
|
|
context, service_profile_id=service_profile_id,
|
|
flavor_id=flavor_id):
|
|
raise flav_exc.FlavorServiceProfileBindingNotFound(
|
|
sp_id=service_profile_id, fl_id=flavor_id)
|
|
res = {'service_profile_id': service_profile_id,
|
|
'flavor_id': flavor_id}
|
|
return db_utils.resource_fields(res, fields)
|
|
|
|
def create_service_profile(self, context, service_profile):
|
|
sp = service_profile['service_profile']
|
|
|
|
if sp['driver']:
|
|
self._validate_driver(context, sp['driver'])
|
|
else:
|
|
if not sp['metainfo']:
|
|
raise flav_exc.ServiceProfileEmpty()
|
|
|
|
obj = obj_flavor.ServiceProfile(
|
|
context, description=sp['description'], driver=sp['driver'],
|
|
enabled=sp['enabled'], metainfo=sp['metainfo'])
|
|
obj.create()
|
|
return self._make_service_profile_dict(obj)
|
|
|
|
def update_service_profile(self, context,
|
|
service_profile_id, service_profile):
|
|
sp = service_profile['service_profile']
|
|
|
|
if sp.get('driver'):
|
|
self._validate_driver(context, sp['driver'])
|
|
|
|
with db_api.CONTEXT_WRITER.using(context):
|
|
self._ensure_service_profile_not_in_use(context,
|
|
service_profile_id)
|
|
sp_obj = self._get_service_profile(context, service_profile_id)
|
|
sp_obj.update_fields(sp)
|
|
sp_obj.update()
|
|
return self._make_service_profile_dict(sp_obj)
|
|
|
|
def get_service_profile(self, context, sp_id, fields=None):
|
|
sp_db = self._get_service_profile(context, sp_id)
|
|
return self._make_service_profile_dict(sp_db, fields)
|
|
|
|
def delete_service_profile(self, context, sp_id):
|
|
with db_api.CONTEXT_WRITER.using(context):
|
|
self._ensure_service_profile_not_in_use(context, sp_id)
|
|
self._get_service_profile(context, sp_id).delete()
|
|
|
|
def get_service_profiles(self, context, filters=None, fields=None,
|
|
sorts=None, limit=None, marker=None,
|
|
page_reverse=False):
|
|
pager = base_obj.Pager(sorts, limit, page_reverse, marker)
|
|
filters = filters or {}
|
|
sp_objs = obj_flavor.ServiceProfile.get_objects(context, _pager=pager,
|
|
**filters)
|
|
return [self._make_service_profile_dict(sp_obj, fields)
|
|
for sp_obj in sp_objs]
|
|
|
|
def get_flavor_next_provider(self, context, flavor_id,
|
|
filters=None, fields=None,
|
|
sorts=None, limit=None,
|
|
marker=None, page_reverse=False):
|
|
"""From flavor, choose service profile and find provider for driver."""
|
|
|
|
objs = obj_flavor.FlavorServiceProfileBinding.get_objects(
|
|
context, flavor_id=flavor_id)
|
|
if not objs:
|
|
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 flav_exc.ServiceProfileDisabled()
|
|
|
|
LOG.debug("Found driver %s.", sp_obj.driver)
|
|
|
|
service_type_manager = sdb.ServiceTypeManager.get_instance()
|
|
providers = service_type_manager.get_service_providers(
|
|
context,
|
|
filters={'driver': sp_obj.driver})
|
|
|
|
if not providers:
|
|
raise flav_exc.ServiceProfileDriverNotFound(
|
|
driver=sp_obj.driver)
|
|
|
|
LOG.debug("Found providers %s.", providers)
|
|
|
|
res = {'driver': sp_obj.driver,
|
|
'provider': providers[0].get('name')}
|
|
|
|
return [db_utils.resource_fields(res, fields)]
|