[placement] Fix resource provider delete

Due to foreign key constraints for the
resource_provider.root_provider_id in mysql and the way of column
filling it is impossible to delete newly created RP now.

Patch sets root_provider_id to NULL before deletion
if root_provider_id == id.

Closes-Bug: #1739571
Co-Authored-by: Andrey Volkov <avolkov@mirantis.com>
Change-Id: I256c901fdc02b1f764ea9f8d1a1a708e82cc369a
This commit is contained in:
Yikun Jiang 2017-12-21 16:11:37 +08:00 committed by Yikun Jiang (Kero)
parent 459353eec2
commit 4dd1406289
2 changed files with 37 additions and 3 deletions

@ -644,6 +644,13 @@ def _provider_ids_from_uuid(context, uuid):
return ProviderIds(**dict(res))
@db_api.api_context_manager.writer
def _delete_rp_record(context, _id):
return context.session.query(models.ResourceProvider).\
filter(models.ResourceProvider.id == _id).\
delete(synchronize_session=False)
@base.NovaObjectRegistry.register_if(False)
class ResourceProvider(base.NovaObject, base.NovaTimestampObject):
SETTABLE_FIELDS = ('name', 'parent_provider_uuid')
@ -841,11 +848,14 @@ class ResourceProvider(base.NovaObject, base.NovaTimestampObject):
RPT_model = models.ResourceProviderTrait
context.session.query(RPT_model).\
filter(RPT_model.resource_provider_id == _id).delete()
# set root_provider_id to null to make deletion possible
context.session.query(models.ResourceProvider).\
filter(models.ResourceProvider.id == _id,
models.ResourceProvider.root_provider_id == _id).\
update({'root_provider_id': None})
# Now delete the RP record
try:
result = context.session.query(models.ResourceProvider).\
filter(models.ResourceProvider.id == _id).\
delete(synchronize_session=False)
result = _delete_rp_record(context, _id)
except sqla_exc.IntegrityError:
# NOTE(jaypipes): Another thread snuck in and parented this
# resource provider in between the above check for

@ -17,6 +17,7 @@ from oslo_utils import timeutils
import nova
from nova import context
from nova.db.sqlalchemy import api_models as models
from nova import exception
from nova.objects import fields
from nova.objects import resource_provider
@ -219,6 +220,29 @@ class TestResourceProvider(test_objects._LocalTest):
resource_provider.ResourceProvider.get_by_uuid,
self.context, uuids.rp)
def test_destroy(self):
def emulate_rp_mysql_delete(func):
def wrapped(context, _id):
rp = context.session.query(
models.ResourceProvider).\
filter(
models.ResourceProvider.id == _id).first()
self.assertIsNone(rp.root_provider_id)
return func(context, _id)
return wrapped
emulated = emulate_rp_mysql_delete(resource_provider._delete_rp_record)
rp = resource_provider.ResourceProvider(
self.context, uuid=_RESOURCE_PROVIDER_UUID,
name=_RESOURCE_PROVIDER_NAME)
rp.create()
with mock.patch.object(
resource_provider, '_delete_rp_record', emulated):
rp.destroy()
class TestInventoryNoDB(test_objects._LocalTest):
USES_DB = False