Nova shelve creates duplicated images in cells
Calling super method in cells_api.py causes duplicated method call in nova-api and nova-cell. I found the problem in shelve and unshelve, so fix about them. (Nova cell v1 may have similar problems) Change-Id: I8030b6ffc1710bca733e38a9a6fb0d7de5f24268 Closes-bug: #1588657
This commit is contained in:
@@ -24,6 +24,7 @@ from nova.cells import rpcapi as cells_rpcapi
|
|||||||
from nova.cells import utils as cells_utils
|
from nova.cells import utils as cells_utils
|
||||||
from nova.compute import api as compute_api
|
from nova.compute import api as compute_api
|
||||||
from nova.compute import rpcapi as compute_rpcapi
|
from nova.compute import rpcapi as compute_rpcapi
|
||||||
|
from nova.compute import vm_states
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import objects
|
from nova import objects
|
||||||
from nova.objects import base as obj_base
|
from nova.objects import base as obj_base
|
||||||
@@ -348,10 +349,10 @@ class ComputeCellsAPI(compute_api.API):
|
|||||||
self._cast_to_cells(context, instance, 'unrescue')
|
self._cast_to_cells(context, instance, 'unrescue')
|
||||||
|
|
||||||
@check_instance_cell
|
@check_instance_cell
|
||||||
|
@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED,
|
||||||
|
vm_states.PAUSED, vm_states.SUSPENDED])
|
||||||
def shelve(self, context, instance, clean_shutdown=True):
|
def shelve(self, context, instance, clean_shutdown=True):
|
||||||
"""Shelve the given instance."""
|
"""Shelve the given instance."""
|
||||||
super(ComputeCellsAPI, self).shelve(context, instance,
|
|
||||||
clean_shutdown=clean_shutdown)
|
|
||||||
self._cast_to_cells(context, instance, 'shelve',
|
self._cast_to_cells(context, instance, 'shelve',
|
||||||
clean_shutdown=clean_shutdown)
|
clean_shutdown=clean_shutdown)
|
||||||
|
|
||||||
@@ -364,9 +365,10 @@ class ComputeCellsAPI(compute_api.API):
|
|||||||
clean_shutdown=clean_shutdown)
|
clean_shutdown=clean_shutdown)
|
||||||
|
|
||||||
@check_instance_cell
|
@check_instance_cell
|
||||||
|
@check_instance_state(vm_state=[vm_states.SHELVED,
|
||||||
|
vm_states.SHELVED_OFFLOADED])
|
||||||
def unshelve(self, context, instance):
|
def unshelve(self, context, instance):
|
||||||
"""Unshelve the given instance."""
|
"""Unshelve the given instance."""
|
||||||
super(ComputeCellsAPI, self).unshelve(context, instance)
|
|
||||||
self._cast_to_cells(context, instance, 'unshelve')
|
self._cast_to_cells(context, instance, 'unshelve')
|
||||||
|
|
||||||
@check_instance_cell
|
@check_instance_cell
|
||||||
|
@@ -4526,6 +4526,20 @@ class ComputeAPIAPICellUnitTestCase(_ComputeAPIUnitTestMixIn,
|
|||||||
self.context, requested_networks, 5)
|
self.context, requested_networks, 5)
|
||||||
self.assertEqual(5, count)
|
self.assertEqual(5, count)
|
||||||
|
|
||||||
|
def _test_shelve(self, vm_state=vm_states.ACTIVE,
|
||||||
|
boot_from_volume=False, clean_shutdown=True):
|
||||||
|
params = dict(task_state=None, vm_state=vm_state,
|
||||||
|
display_name='fake-name')
|
||||||
|
instance = self._create_instance_obj(params=params)
|
||||||
|
with mock.patch.object(self.compute_api,
|
||||||
|
'_cast_to_cells') as cast_to_cells:
|
||||||
|
self.compute_api.shelve(self.context, instance,
|
||||||
|
clean_shutdown=clean_shutdown)
|
||||||
|
cast_to_cells.assert_called_once_with(self.context,
|
||||||
|
instance, 'shelve',
|
||||||
|
clean_shutdown=clean_shutdown
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ComputeAPIComputeCellUnitTestCase(_ComputeAPIUnitTestMixIn,
|
class ComputeAPIComputeCellUnitTestCase(_ComputeAPIUnitTestMixIn,
|
||||||
test.NoDBTestCase):
|
test.NoDBTestCase):
|
||||||
|
@@ -28,6 +28,7 @@ from nova.cells import manager
|
|||||||
from nova.compute import api as compute_api
|
from nova.compute import api as compute_api
|
||||||
from nova.compute import cells_api as compute_cells_api
|
from nova.compute import cells_api as compute_cells_api
|
||||||
from nova.compute import flavors
|
from nova.compute import flavors
|
||||||
|
from nova.compute import task_states
|
||||||
from nova.compute import utils as compute_utils
|
from nova.compute import utils as compute_utils
|
||||||
from nova.compute import vm_states
|
from nova.compute import vm_states
|
||||||
import nova.conf
|
import nova.conf
|
||||||
@@ -38,6 +39,7 @@ from nova import objects
|
|||||||
from nova import quota
|
from nova import quota
|
||||||
from nova import test
|
from nova import test
|
||||||
from nova.tests.unit.compute import test_compute
|
from nova.tests.unit.compute import test_compute
|
||||||
|
from nova.tests.unit.compute import test_shelve
|
||||||
from nova.tests.unit import fake_instance
|
from nova.tests.unit import fake_instance
|
||||||
from nova.tests.unit.objects import test_flavor
|
from nova.tests.unit.objects import test_flavor
|
||||||
from nova.tests import uuidsentinel as uuids
|
from nova.tests import uuidsentinel as uuids
|
||||||
@@ -425,6 +427,49 @@ class CellsComputeAPITestCase(test_compute.ComputeAPITestCase):
|
|||||||
cells_enabled=True)
|
cells_enabled=True)
|
||||||
|
|
||||||
|
|
||||||
|
class CellsShelveComputeAPITestCase(test_shelve.ShelveComputeAPITestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(CellsShelveComputeAPITestCase, self).setUp()
|
||||||
|
global ORIG_COMPUTE_API
|
||||||
|
ORIG_COMPUTE_API = self.compute_api
|
||||||
|
self.compute_api = compute_cells_api.ComputeCellsAPI()
|
||||||
|
|
||||||
|
def _fake_validate_cell(*args, **kwargs):
|
||||||
|
return
|
||||||
|
|
||||||
|
def _fake_cast_to_cells(self, context, instance, method,
|
||||||
|
*args, **kwargs):
|
||||||
|
fn = getattr(ORIG_COMPUTE_API, method)
|
||||||
|
fn(context, instance, *args, **kwargs)
|
||||||
|
|
||||||
|
self.stub_out('nova.compute.api.API._validate_cell',
|
||||||
|
_fake_validate_cell)
|
||||||
|
self.stub_out('nova.compute.cells_api.ComputeCellsAPI._cast_to_cells',
|
||||||
|
_fake_cast_to_cells)
|
||||||
|
|
||||||
|
def test_unshelve(self):
|
||||||
|
# Ensure instance can be unshelved on cell environment.
|
||||||
|
# The super class tests nova-shelve.
|
||||||
|
instance = self._create_fake_instance_obj()
|
||||||
|
|
||||||
|
self.assertIsNone(instance['task_state'])
|
||||||
|
|
||||||
|
self.compute_api.shelve(self.context, instance)
|
||||||
|
|
||||||
|
instance.task_state = None
|
||||||
|
instance.vm_state = vm_states.SHELVED
|
||||||
|
instance.save()
|
||||||
|
|
||||||
|
self.compute_api.unshelve(self.context, instance)
|
||||||
|
|
||||||
|
self.assertEqual(task_states.UNSHELVING, instance.task_state)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
global ORIG_COMPUTE_API
|
||||||
|
self.compute_api = ORIG_COMPUTE_API
|
||||||
|
super(CellsShelveComputeAPITestCase, self).tearDown()
|
||||||
|
|
||||||
|
|
||||||
class CellsConductorAPIRPCRedirect(test.NoDBTestCase):
|
class CellsConductorAPIRPCRedirect(test.NoDBTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(CellsConductorAPIRPCRedirect, self).setUp()
|
super(CellsConductorAPIRPCRedirect, self).setUp()
|
||||||
|
Reference in New Issue
Block a user