libvirt: manage COMPUTE_STATUS_DISABLED for hypervisor connection
The libvirt driver has a callback method for when the hypervisor connection drops and is re-connected which mirrors those changes in the related compute Service record's "disabled" field. This builds on that by hooking back into the ComputeVirtAPI update_compute_provider_status method when the Service.disabled value changes so the COMPUTE_STATUS_DISABLED trait can be added to or removed from the related compute node resource provider. Part of blueprint pre-filter-disabled-computes Change-Id: Ifabbb543aab62b917394eefe48126231df7cd503
This commit is contained in:
parent
b7ad974723
commit
9b99be44cd
@ -1583,7 +1583,11 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||||
svc = self._create_service(host='fake-mini')
|
svc = self._create_service(host='fake-mini')
|
||||||
mock_svc.return_value = svc
|
mock_svc.return_value = svc
|
||||||
|
with mock.patch.object(
|
||||||
|
drvr, '_update_compute_provider_status') as ucps:
|
||||||
drvr._set_host_enabled(False)
|
drvr._set_host_enabled(False)
|
||||||
|
ucps.assert_called_once_with(
|
||||||
|
test.MatchType(context.RequestContext), svc)
|
||||||
self.assertTrue(svc.disabled)
|
self.assertTrue(svc.disabled)
|
||||||
mock_save.assert_called_once_with()
|
mock_save.assert_called_once_with()
|
||||||
|
|
||||||
@ -1594,7 +1598,10 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||||
svc = self._create_service(disabled=True, host='fake-mini')
|
svc = self._create_service(disabled=True, host='fake-mini')
|
||||||
mock_svc.return_value = svc
|
mock_svc.return_value = svc
|
||||||
|
with mock.patch.object(
|
||||||
|
drvr, '_update_compute_provider_status') as ucps:
|
||||||
drvr._set_host_enabled(True)
|
drvr._set_host_enabled(True)
|
||||||
|
ucps.assert_not_called()
|
||||||
# since disabled_reason is not set and not prefixed with "AUTO:",
|
# since disabled_reason is not set and not prefixed with "AUTO:",
|
||||||
# service should not be enabled.
|
# service should not be enabled.
|
||||||
mock_save.assert_not_called()
|
mock_save.assert_not_called()
|
||||||
@ -1608,7 +1615,10 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||||
svc = self._create_service(disabled=False, host='fake-mini')
|
svc = self._create_service(disabled=False, host='fake-mini')
|
||||||
mock_svc.return_value = svc
|
mock_svc.return_value = svc
|
||||||
|
with mock.patch.object(
|
||||||
|
drvr, '_update_compute_provider_status') as ucps:
|
||||||
drvr._set_host_enabled(True)
|
drvr._set_host_enabled(True)
|
||||||
|
ucps.assert_not_called()
|
||||||
self.assertFalse(svc.disabled)
|
self.assertFalse(svc.disabled)
|
||||||
mock_save.assert_not_called()
|
mock_save.assert_not_called()
|
||||||
|
|
||||||
@ -1620,7 +1630,10 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||||
svc = self._create_service(disabled=True, host='fake-mini')
|
svc = self._create_service(disabled=True, host='fake-mini')
|
||||||
mock_svc.return_value = svc
|
mock_svc.return_value = svc
|
||||||
|
with mock.patch.object(
|
||||||
|
drvr, '_update_compute_provider_status') as ucps:
|
||||||
drvr._set_host_enabled(False)
|
drvr._set_host_enabled(False)
|
||||||
|
ucps.assert_not_called()
|
||||||
mock_save.assert_not_called()
|
mock_save.assert_not_called()
|
||||||
self.assertTrue(svc.disabled)
|
self.assertTrue(svc.disabled)
|
||||||
|
|
||||||
@ -1635,6 +1648,47 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||||||
db_mock.side_effect = exception.NovaException
|
db_mock.side_effect = exception.NovaException
|
||||||
drvr._set_host_enabled(False)
|
drvr._set_host_enabled(False)
|
||||||
|
|
||||||
|
def test_update_compute_provider_status(self):
|
||||||
|
"""Tests happy path of calling _update_compute_provider_status"""
|
||||||
|
virtapi = mock.Mock()
|
||||||
|
drvr = libvirt_driver.LibvirtDriver(virtapi, read_only=True)
|
||||||
|
ctxt = context.get_admin_context()
|
||||||
|
service = self._create_service()
|
||||||
|
service.compute_node = objects.ComputeNode(uuid=uuids.rp_uuid)
|
||||||
|
drvr._update_compute_provider_status(ctxt, service)
|
||||||
|
virtapi.update_compute_provider_status.assert_called_once_with(
|
||||||
|
ctxt, uuids.rp_uuid, enabled=not service.disabled)
|
||||||
|
|
||||||
|
def test_update_compute_provider_status_swallows_exceptions(self):
|
||||||
|
"""Tests error path handling in _update_compute_provider_status"""
|
||||||
|
# First we'll make Service.compute_node loading raise an exception
|
||||||
|
# by not setting the field and we cannot lazy-load it from an orphaned
|
||||||
|
# Service object.
|
||||||
|
virtapi = mock.Mock()
|
||||||
|
drvr = libvirt_driver.LibvirtDriver(virtapi, read_only=True)
|
||||||
|
ctxt = context.get_admin_context()
|
||||||
|
service = self._create_service(host='fake-host', disabled=True)
|
||||||
|
drvr._update_compute_provider_status(ctxt, service)
|
||||||
|
virtapi.update_compute_provider_status.assert_not_called()
|
||||||
|
self.assertIn('An error occurred while updating compute node resource '
|
||||||
|
'provider status to "disabled" for provider: fake-host',
|
||||||
|
self.stdlog.logger.output)
|
||||||
|
|
||||||
|
# Now fix Service.compute_node loading but make the VirtAPI call fail.
|
||||||
|
service.compute_node = objects.ComputeNode(uuid=uuids.rp_uuid)
|
||||||
|
service.disabled = False # make sure the log message logic works
|
||||||
|
error = exception.TraitRetrievalFailed(error='oops')
|
||||||
|
virtapi.update_compute_provider_status.side_effect = error
|
||||||
|
drvr._update_compute_provider_status(ctxt, service)
|
||||||
|
virtapi.update_compute_provider_status.assert_called_once_with(
|
||||||
|
ctxt, uuids.rp_uuid, enabled=True)
|
||||||
|
log_output = self.stdlog.logger.output
|
||||||
|
self.assertIn('An error occurred while updating compute node resource '
|
||||||
|
'provider status to "enabled" for provider: %s' %
|
||||||
|
uuids.rp_uuid, log_output)
|
||||||
|
# The error should have been logged as well.
|
||||||
|
self.assertIn(six.text_type(error), log_output)
|
||||||
|
|
||||||
@mock.patch.object(fakelibvirt.virConnect, "nodeDeviceLookupByName")
|
@mock.patch.object(fakelibvirt.virConnect, "nodeDeviceLookupByName")
|
||||||
def test_prepare_pci_device(self, mock_lookup):
|
def test_prepare_pci_device(self, mock_lookup):
|
||||||
|
|
||||||
|
@ -3902,6 +3902,25 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||||||
if pci_dev.address in direct_passthrough_pci_addresses])
|
if pci_dev.address in direct_passthrough_pci_addresses])
|
||||||
self._detach_pci_devices(guest, direct_passthrough_pci_addresses)
|
self._detach_pci_devices(guest, direct_passthrough_pci_addresses)
|
||||||
|
|
||||||
|
def _update_compute_provider_status(self, context, service):
|
||||||
|
"""Calls the ComputeVirtAPI.update_compute_provider_status method
|
||||||
|
|
||||||
|
:param context: nova auth RequestContext
|
||||||
|
:param service: nova.objects.Service record for this host which is
|
||||||
|
expected to only manage a single ComputeNode
|
||||||
|
"""
|
||||||
|
rp_uuid = None
|
||||||
|
try:
|
||||||
|
rp_uuid = service.compute_node.uuid
|
||||||
|
self.virtapi.update_compute_provider_status(
|
||||||
|
context, rp_uuid, enabled=not service.disabled)
|
||||||
|
except Exception:
|
||||||
|
LOG.warning(
|
||||||
|
'An error occurred while updating compute node '
|
||||||
|
'resource provider status to "%s" for provider: %s',
|
||||||
|
'disabled' if service.disabled else 'enabled',
|
||||||
|
rp_uuid or service.host, exc_info=True)
|
||||||
|
|
||||||
def _set_host_enabled(self, enabled,
|
def _set_host_enabled(self, enabled,
|
||||||
disable_reason=DISABLE_REASON_UNDEFINED):
|
disable_reason=DISABLE_REASON_UNDEFINED):
|
||||||
"""Enables / Disables the compute service on this host.
|
"""Enables / Disables the compute service on this host.
|
||||||
@ -3938,6 +3957,9 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||||||
service.save()
|
service.save()
|
||||||
LOG.debug('Updating compute service status to %s',
|
LOG.debug('Updating compute service status to %s',
|
||||||
status_name[disable_service])
|
status_name[disable_service])
|
||||||
|
# Update the disabled trait status on the corresponding
|
||||||
|
# compute node resource provider in placement.
|
||||||
|
self._update_compute_provider_status(ctx, service)
|
||||||
else:
|
else:
|
||||||
LOG.debug('Not overriding manual compute service '
|
LOG.debug('Not overriding manual compute service '
|
||||||
'status with: %s',
|
'status with: %s',
|
||||||
|
Loading…
Reference in New Issue
Block a user