Merge "Don't lazy-load flavor.projects during destroy()"
This commit is contained in:
commit
28ace935cd
@ -17,7 +17,7 @@
|
|||||||
"vcpu_weight": 0,
|
"vcpu_weight": 0,
|
||||||
"flavorid": "a22d5517-147c-4147-a0d1-e698df5cd4e3",
|
"flavorid": "a22d5517-147c-4147-a0d1-e698df5cd4e3",
|
||||||
"extra_specs": null,
|
"extra_specs": null,
|
||||||
"projects": []
|
"projects": null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"event_type": "flavor.delete",
|
"event_type": "flavor.delete",
|
||||||
|
@ -614,7 +614,12 @@ class Flavor(base.NovaPersistentObject, base.NovaObject,
|
|||||||
# lazy-load projects (which is a problem for instance-bound
|
# lazy-load projects (which is a problem for instance-bound
|
||||||
# flavors and compute-cell operations), just load them here.
|
# flavors and compute-cell operations), just load them here.
|
||||||
if 'projects' not in self:
|
if 'projects' not in self:
|
||||||
self._load_projects()
|
# If the flavor is deleted we can't lazy-load projects.
|
||||||
|
# FlavorPayload will orphan the flavor which will make the
|
||||||
|
# NotificationPayloadBase set projects=None in the notification
|
||||||
|
# payload.
|
||||||
|
if action != fields.NotificationAction.DELETE:
|
||||||
|
self._load_projects()
|
||||||
notification_type = flavor_notification.FlavorNotification
|
notification_type = flavor_notification.FlavorNotification
|
||||||
payload_type = flavor_notification.FlavorPayload
|
payload_type = flavor_notification.FlavorPayload
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@ from nova.objects import fields
|
|||||||
from nova import test
|
from nova import test
|
||||||
from nova.tests.unit.objects.test_flavor import fake_flavor
|
from nova.tests.unit.objects.test_flavor import fake_flavor
|
||||||
|
|
||||||
|
PROJECTS_SENTINEL = object()
|
||||||
|
|
||||||
|
|
||||||
class TestFlavorNotification(test.TestCase):
|
class TestFlavorNotification(test.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -29,7 +31,8 @@ class TestFlavorNotification(test.TestCase):
|
|||||||
|
|
||||||
@mock.patch('nova.notifications.objects.flavor.FlavorNotification')
|
@mock.patch('nova.notifications.objects.flavor.FlavorNotification')
|
||||||
def _verify_notification(self, flavor_obj, flavor, action,
|
def _verify_notification(self, flavor_obj, flavor, action,
|
||||||
mock_notification, project_id=None):
|
mock_notification, project_id=None,
|
||||||
|
expected_projects=PROJECTS_SENTINEL):
|
||||||
notification = mock_notification
|
notification = mock_notification
|
||||||
if action == "CREATE":
|
if action == "CREATE":
|
||||||
flavor_obj.create()
|
flavor_obj.create()
|
||||||
@ -61,8 +64,12 @@ class TestFlavorNotification(test.TestCase):
|
|||||||
|
|
||||||
schema = flavor_notification.FlavorPayload.SCHEMA
|
schema = flavor_notification.FlavorPayload.SCHEMA
|
||||||
for field in schema:
|
for field in schema:
|
||||||
if field in flavor:
|
if field == 'projects' and expected_projects != PROJECTS_SENTINEL:
|
||||||
self.assertEqual(flavor[field], getattr(payload, field))
|
self.assertEqual(expected_projects, getattr(payload, field))
|
||||||
|
elif field in flavor_obj:
|
||||||
|
self.assertEqual(flavor_obj[field], getattr(payload, field))
|
||||||
|
else:
|
||||||
|
self.fail('Missing check for field %s in flavor_obj.' % field)
|
||||||
|
|
||||||
@mock.patch('nova.objects.Flavor._flavor_create')
|
@mock.patch('nova.objects.Flavor._flavor_create')
|
||||||
def test_flavor_create_with_notification(self, mock_create):
|
def test_flavor_create_with_notification(self, mock_create):
|
||||||
@ -117,6 +124,26 @@ class TestFlavorNotification(test.TestCase):
|
|||||||
mock_destroy.return_value = flavor
|
mock_destroy.return_value = flavor
|
||||||
flavor_obj = objects.Flavor(context=self.ctxt, **flavor)
|
flavor_obj = objects.Flavor(context=self.ctxt, **flavor)
|
||||||
flavor_obj.obj_reset_changes()
|
flavor_obj.obj_reset_changes()
|
||||||
|
self.assertNotIn('projects', flavor_obj)
|
||||||
|
# We specifically expect there to not be any projects as we don't want
|
||||||
|
# to try and lazy-load them from the main database and end up with [].
|
||||||
|
self._verify_notification(flavor_obj, flavor, "DELETE",
|
||||||
|
expected_projects=None)
|
||||||
|
|
||||||
|
@mock.patch('nova.objects.Flavor._flavor_destroy')
|
||||||
|
def test_flavor_destroy_with_notification_and_projects(self, mock_destroy):
|
||||||
|
"""Tests the flavor-delete notification with flavor.projects loaded."""
|
||||||
|
flavor = copy.deepcopy(fake_flavor)
|
||||||
|
flavorid = '1'
|
||||||
|
flavor['flavorid'] = flavorid
|
||||||
|
flavor['id'] = flavorid
|
||||||
|
mock_destroy.return_value = flavor
|
||||||
|
flavor_obj = objects.Flavor(
|
||||||
|
context=self.ctxt, projects=['foo'], **flavor)
|
||||||
|
flavor_obj.obj_reset_changes()
|
||||||
|
self.assertIn('projects', flavor_obj)
|
||||||
|
self.assertEqual(['foo'], flavor_obj.projects)
|
||||||
|
# Since projects is loaded we shouldn't try to lazy-load it.
|
||||||
self._verify_notification(flavor_obj, flavor, "DELETE")
|
self._verify_notification(flavor_obj, flavor, "DELETE")
|
||||||
|
|
||||||
def test_obj_make_compatible(self):
|
def test_obj_make_compatible(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user