Merge "Stable compute uuid functional tests"
This commit is contained in:
@@ -10,8 +10,12 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import functools
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
import fixtures
|
||||||
|
from oslo_utils.fixture import uuidsentinel as uuids
|
||||||
|
|
||||||
from nova import context as nova_context
|
from nova import context as nova_context
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova.objects import service
|
from nova.objects import service
|
||||||
@@ -19,6 +23,7 @@ from nova import test
|
|||||||
from nova.tests import fixtures as nova_fixtures
|
from nova.tests import fixtures as nova_fixtures
|
||||||
from nova.tests.functional import fixtures as func_fixtures
|
from nova.tests.functional import fixtures as func_fixtures
|
||||||
from nova.tests.functional import integrated_helpers
|
from nova.tests.functional import integrated_helpers
|
||||||
|
from nova.virt import node
|
||||||
|
|
||||||
|
|
||||||
class ServiceTestCase(test.TestCase,
|
class ServiceTestCase(test.TestCase,
|
||||||
@@ -137,3 +142,83 @@ class TestOldComputeCheck(
|
|||||||
return_value=old_version):
|
return_value=old_version):
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exception.TooOldComputeService, self._start_compute, 'host1')
|
exception.TooOldComputeService, self._start_compute, 'host1')
|
||||||
|
|
||||||
|
|
||||||
|
class TestComputeStartupChecks(test.TestCase):
|
||||||
|
STUB_COMPUTE_ID = False
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.useFixture(nova_fixtures.RealPolicyFixture())
|
||||||
|
self.useFixture(nova_fixtures.NeutronFixture(self))
|
||||||
|
self.useFixture(nova_fixtures.GlanceFixture(self))
|
||||||
|
self.useFixture(func_fixtures.PlacementFixture())
|
||||||
|
|
||||||
|
self._local_uuid = str(uuids.node)
|
||||||
|
|
||||||
|
self.useFixture(fixtures.MockPatch(
|
||||||
|
'nova.virt.node.get_local_node_uuid',
|
||||||
|
functools.partial(self.local_uuid, True)))
|
||||||
|
self.useFixture(fixtures.MockPatch(
|
||||||
|
'nova.virt.node.read_local_node_uuid',
|
||||||
|
self.local_uuid))
|
||||||
|
self.useFixture(fixtures.MockPatch(
|
||||||
|
'nova.virt.node.write_local_node_uuid',
|
||||||
|
mock.DEFAULT))
|
||||||
|
self.flags(compute_driver='fake.FakeDriverWithoutFakeNodes')
|
||||||
|
|
||||||
|
def local_uuid(self, get=False):
|
||||||
|
if get and not self._local_uuid:
|
||||||
|
# Simulate the get_local_node_uuid behavior of calling write once
|
||||||
|
self._local_uuid = str(uuids.node)
|
||||||
|
node.write_local_node_uuid(self._local_uuid)
|
||||||
|
return self._local_uuid
|
||||||
|
|
||||||
|
def test_compute_node_identity_greenfield(self):
|
||||||
|
# Level-set test case to show that starting and re-starting without
|
||||||
|
# any error cases works as expected.
|
||||||
|
|
||||||
|
# Start with no local compute_id
|
||||||
|
self._local_uuid = None
|
||||||
|
self.start_service('compute')
|
||||||
|
|
||||||
|
# Start should have generated and written a compute id
|
||||||
|
node.write_local_node_uuid.assert_called_once_with(str(uuids.node))
|
||||||
|
|
||||||
|
# Starting again should succeed and not cause another write
|
||||||
|
self.start_service('compute')
|
||||||
|
node.write_local_node_uuid.assert_called_once_with(str(uuids.node))
|
||||||
|
|
||||||
|
def test_compute_node_identity_deleted(self):
|
||||||
|
self.start_service('compute')
|
||||||
|
|
||||||
|
# Simulate the compute_id file being deleted
|
||||||
|
self._local_uuid = None
|
||||||
|
|
||||||
|
# Should refuse to start because it's not our first time and the file
|
||||||
|
# being missing is a hard error.
|
||||||
|
exc = self.assertRaises(exception.InvalidConfiguration,
|
||||||
|
self.start_service, 'compute')
|
||||||
|
self.assertIn('lost that state', str(exc))
|
||||||
|
|
||||||
|
def test_compute_node_hostname_changed(self):
|
||||||
|
# Start our compute once to create the node record
|
||||||
|
self.start_service('compute')
|
||||||
|
|
||||||
|
# Starting with a different hostname should trigger the abort
|
||||||
|
exc = self.assertRaises(exception.InvalidConfiguration,
|
||||||
|
self.start_service, 'compute', host='other')
|
||||||
|
self.assertIn('hypervisor_hostname', str(exc))
|
||||||
|
|
||||||
|
def test_compute_node_uuid_changed(self):
|
||||||
|
# Start our compute once to create the node record
|
||||||
|
self.start_service('compute')
|
||||||
|
|
||||||
|
# Simulate a changed local compute_id file
|
||||||
|
self._local_uuid = str(uuids.othernode)
|
||||||
|
|
||||||
|
# We should fail to create the compute node record again, but with a
|
||||||
|
# useful error message about why.
|
||||||
|
exc = self.assertRaises(exception.InvalidConfiguration,
|
||||||
|
self.start_service, 'compute')
|
||||||
|
self.assertIn('Duplicate compute node record', str(exc))
|
||||||
|
@@ -49,6 +49,7 @@ from nova.objects import migrate_data
|
|||||||
from nova.virt import driver
|
from nova.virt import driver
|
||||||
from nova.virt import hardware
|
from nova.virt import hardware
|
||||||
from nova.virt.ironic import driver as ironic
|
from nova.virt.ironic import driver as ironic
|
||||||
|
import nova.virt.node
|
||||||
from nova.virt import virtapi
|
from nova.virt import virtapi
|
||||||
|
|
||||||
CONF = nova.conf.CONF
|
CONF = nova.conf.CONF
|
||||||
@@ -1130,3 +1131,22 @@ class EphEncryptionDriverPLAIN(MediumFakeDriver):
|
|||||||
FakeDriver.capabilities,
|
FakeDriver.capabilities,
|
||||||
supports_ephemeral_encryption=True,
|
supports_ephemeral_encryption=True,
|
||||||
supports_ephemeral_encryption_plain=True)
|
supports_ephemeral_encryption_plain=True)
|
||||||
|
|
||||||
|
|
||||||
|
class FakeDriverWithoutFakeNodes(FakeDriver):
|
||||||
|
"""FakeDriver that behaves like a real single-node driver.
|
||||||
|
|
||||||
|
This behaves like a real virt driver from the perspective of its
|
||||||
|
nodes, with a stable nodename and use of the global node identity
|
||||||
|
stuff to provide a stable node UUID.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_available_resource(self, nodename):
|
||||||
|
resources = super().get_available_resource(nodename)
|
||||||
|
resources['uuid'] = nova.virt.node.get_local_node_uuid()
|
||||||
|
return resources
|
||||||
|
|
||||||
|
def get_nodenames_by_uuid(self, refresh=False):
|
||||||
|
return {
|
||||||
|
nova.virt.node.get_local_node_uuid(): self.get_available_nodes()[0]
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user