Report libvirt failures as IPMI-retryable

It seems that at times of high concurrency, libvirt
occassionally fails on supposedly some race condition
what leads to client failure (e.g. Ironic). This change
is to tell Ironic that it should try some more times rather
than bailing out right away.

Change-Id: I5848d721305c887fb7803ca4b302565aa4b83c88
Story: #2001798
Task: #15076
This commit is contained in:
Ilya Etingof 2018-04-27 13:19:55 +02:00
parent b06dc796c9
commit 72f873d9f4
2 changed files with 23 additions and 23 deletions

View File

@ -103,7 +103,7 @@ class VirtualBMCTestCase(base.TestCase):
mock_libvirt_open): mock_libvirt_open):
mock_libvirt_domain.side_effect = libvirt.libvirtError('boom') mock_libvirt_domain.side_effect = libvirt.libvirtError('boom')
ret = self.vbmc.set_boot_device('network') ret = self.vbmc.set_boot_device('network')
self.assertEqual(0xd5, ret) self.assertEqual(0xc0, ret)
self._assert_libvirt_calls(mock_libvirt_domain, mock_libvirt_open) self._assert_libvirt_calls(mock_libvirt_domain, mock_libvirt_open)
def test_set_boot_device_unkown_device_error(self, mock_libvirt_domain, def test_set_boot_device_unkown_device_error(self, mock_libvirt_domain,
@ -135,7 +135,7 @@ class VirtualBMCTestCase(base.TestCase):
mock_libvirt_open): mock_libvirt_open):
mock_libvirt_domain.side_effect = libvirt.libvirtError('boom') mock_libvirt_domain.side_effect = libvirt.libvirtError('boom')
ret = self.vbmc.get_power_state() ret = self.vbmc.get_power_state()
self.assertEqual(0xd5, ret) self.assertEqual(0xC0, ret)
self._assert_libvirt_calls(mock_libvirt_domain, mock_libvirt_open, self._assert_libvirt_calls(mock_libvirt_domain, mock_libvirt_open,
readonly=True) readonly=True)
@ -159,7 +159,7 @@ class VirtualBMCTestCase(base.TestCase):
def test_pulse_diag_error(self, mock_libvirt_domain, mock_libvirt_open): def test_pulse_diag_error(self, mock_libvirt_domain, mock_libvirt_open):
mock_libvirt_domain.side_effect = libvirt.libvirtError('boom') mock_libvirt_domain.side_effect = libvirt.libvirtError('boom')
ret = self.vbmc.pulse_diag() ret = self.vbmc.pulse_diag()
self.assertEqual(0xd5, ret) self.assertEqual(0xC0, ret)
mock_libvirt_domain.return_value.injectNMI.assert_not_called() mock_libvirt_domain.return_value.injectNMI.assert_not_called()
self._assert_libvirt_calls(mock_libvirt_domain, mock_libvirt_open) self._assert_libvirt_calls(mock_libvirt_domain, mock_libvirt_open)
@ -183,7 +183,7 @@ class VirtualBMCTestCase(base.TestCase):
def test_power_off_error(self, mock_libvirt_domain, mock_libvirt_open): def test_power_off_error(self, mock_libvirt_domain, mock_libvirt_open):
mock_libvirt_domain.side_effect = libvirt.libvirtError('boom') mock_libvirt_domain.side_effect = libvirt.libvirtError('boom')
ret = self.vbmc.power_off() ret = self.vbmc.power_off()
self.assertEqual(0xd5, ret) self.assertEqual(0xC0, ret)
mock_libvirt_domain.return_value.destroy.assert_not_called() mock_libvirt_domain.return_value.destroy.assert_not_called()
self._assert_libvirt_calls(mock_libvirt_domain, mock_libvirt_open) self._assert_libvirt_calls(mock_libvirt_domain, mock_libvirt_open)
@ -207,7 +207,7 @@ class VirtualBMCTestCase(base.TestCase):
def test_power_reset_error(self, mock_libvirt_domain, mock_libvirt_open): def test_power_reset_error(self, mock_libvirt_domain, mock_libvirt_open):
mock_libvirt_domain.side_effect = libvirt.libvirtError('boom') mock_libvirt_domain.side_effect = libvirt.libvirtError('boom')
ret = self.vbmc.power_reset() ret = self.vbmc.power_reset()
self.assertEqual(0xd5, ret) self.assertEqual(0xC0, ret)
mock_libvirt_domain.return_value.reset.assert_not_called() mock_libvirt_domain.return_value.reset.assert_not_called()
self._assert_libvirt_calls(mock_libvirt_domain, mock_libvirt_open) self._assert_libvirt_calls(mock_libvirt_domain, mock_libvirt_open)
@ -234,7 +234,7 @@ class VirtualBMCTestCase(base.TestCase):
mock_libvirt_open): mock_libvirt_open):
mock_libvirt_domain.side_effect = libvirt.libvirtError('boom') mock_libvirt_domain.side_effect = libvirt.libvirtError('boom')
ret = self.vbmc.power_shutdown() ret = self.vbmc.power_shutdown()
self.assertEqual(0xd5, ret) self.assertEqual(0xC0, ret)
mock_libvirt_domain.return_value.shutdown.assert_not_called() mock_libvirt_domain.return_value.shutdown.assert_not_called()
self._assert_libvirt_calls(mock_libvirt_domain, mock_libvirt_open) self._assert_libvirt_calls(mock_libvirt_domain, mock_libvirt_open)
@ -258,7 +258,7 @@ class VirtualBMCTestCase(base.TestCase):
def test_power_on_error(self, mock_libvirt_domain, mock_libvirt_open): def test_power_on_error(self, mock_libvirt_domain, mock_libvirt_open):
mock_libvirt_domain.side_effect = libvirt.libvirtError('boom') mock_libvirt_domain.side_effect = libvirt.libvirtError('boom')
ret = self.vbmc.power_on() ret = self.vbmc.power_on()
self.assertEqual(0xd5, ret) self.assertEqual(0xC0, ret)
self.assertFalse(mock_libvirt_domain.return_value.create.called) self.assertFalse(mock_libvirt_domain.return_value.create.called)
self._assert_libvirt_calls(mock_libvirt_domain, mock_libvirt_open) self._assert_libvirt_calls(mock_libvirt_domain, mock_libvirt_open)

View File

@ -29,8 +29,8 @@ POWERON = 1
# Second Generation v2.0 Document Revision 1.1 October 1, 2013 # Second Generation v2.0 Document Revision 1.1 October 1, 2013
# https://www.intel.com/content/dam/www/public/us/en/documents/product-briefs/ipmi-second-gen-interface-spec-v2-rev1-1.pdf # https://www.intel.com/content/dam/www/public/us/en/documents/product-briefs/ipmi-second-gen-interface-spec-v2-rev1-1.pdf
# #
# Command not supported in present state # Command failed and can be retried
IPMI_COMMAND_NOT_SUPPORTED = 0xd5 IPMI_COMMAND_NODE_BUSY = 0xC0
# Invalid data field in request # Invalid data field in request
IPMI_INVALID_DATA = 0xcc IPMI_INVALID_DATA = 0xcc
@ -138,8 +138,8 @@ class VirtualBMC(bmc.Bmc):
LOG.error('Failed setting the boot device %(bootdev)s for ' LOG.error('Failed setting the boot device %(bootdev)s for '
'domain %(domain)s', {'bootdev': device, 'domain %(domain)s', {'bootdev': device,
'domain': self.domain_name}) 'domain': self.domain_name})
# Command not supported in present state # Command failed, but let client to retry
return IPMI_COMMAND_NOT_SUPPORTED return IPMI_COMMAND_NODE_BUSY
def get_power_state(self): def get_power_state(self):
LOG.debug('Get power state called for domain %s', self.domain_name) LOG.debug('Get power state called for domain %s', self.domain_name)
@ -152,8 +152,8 @@ class VirtualBMC(bmc.Bmc):
LOG.error('Error getting the power state of domain %(domain)s. ' LOG.error('Error getting the power state of domain %(domain)s. '
'Error: %(error)s', {'domain': self.domain_name, 'Error: %(error)s', {'domain': self.domain_name,
'error': e}) 'error': e})
# Command not supported in present state # Command failed, but let client to retry
return IPMI_COMMAND_NOT_SUPPORTED return IPMI_COMMAND_NODE_BUSY
return POWEROFF return POWEROFF
@ -168,8 +168,8 @@ class VirtualBMC(bmc.Bmc):
LOG.error('Error powering diag the domain %(domain)s. ' LOG.error('Error powering diag the domain %(domain)s. '
'Error: %(error)s' % {'domain': self.domain_name, 'Error: %(error)s' % {'domain': self.domain_name,
'error': e}) 'error': e})
# Command not supported in present state # Command failed, but let client to retry
return IPMI_COMMAND_NOT_SUPPORTED return IPMI_COMMAND_NODE_BUSY
def power_off(self): def power_off(self):
LOG.debug('Power off called for domain %s', self.domain_name) LOG.debug('Power off called for domain %s', self.domain_name)
@ -182,8 +182,8 @@ class VirtualBMC(bmc.Bmc):
LOG.error('Error powering off the domain %(domain)s. ' LOG.error('Error powering off the domain %(domain)s. '
'Error: %(error)s' % {'domain': self.domain_name, 'Error: %(error)s' % {'domain': self.domain_name,
'error': e}) 'error': e})
# Command not supported in present state # Command failed, but let client to retry
return IPMI_COMMAND_NOT_SUPPORTED return IPMI_COMMAND_NODE_BUSY
def power_on(self): def power_on(self):
LOG.debug('Power on called for domain %s', self.domain_name) LOG.debug('Power on called for domain %s', self.domain_name)
@ -196,8 +196,8 @@ class VirtualBMC(bmc.Bmc):
LOG.error('Error powering on the domain %(domain)s. ' LOG.error('Error powering on the domain %(domain)s. '
'Error: %(error)s' % {'domain': self.domain_name, 'Error: %(error)s' % {'domain': self.domain_name,
'error': e}) 'error': e})
# Command not supported in present state # Command failed, but let client to retry
return IPMI_COMMAND_NOT_SUPPORTED return IPMI_COMMAND_NODE_BUSY
def power_shutdown(self): def power_shutdown(self):
LOG.debug('Soft power off called for domain %s', self.domain_name) LOG.debug('Soft power off called for domain %s', self.domain_name)
@ -210,8 +210,8 @@ class VirtualBMC(bmc.Bmc):
LOG.error('Error soft powering off the domain %(domain)s. ' LOG.error('Error soft powering off the domain %(domain)s. '
'Error: %(error)s' % {'domain': self.domain_name, 'Error: %(error)s' % {'domain': self.domain_name,
'error': e}) 'error': e})
# Command not supported in present state # Command failed, but let client to retry
return IPMI_COMMAND_NOT_SUPPORTED return IPMI_COMMAND_NODE_BUSY
def power_reset(self): def power_reset(self):
LOG.debug('Power reset called for domain %s', self.domain_name) LOG.debug('Power reset called for domain %s', self.domain_name)
@ -224,8 +224,8 @@ class VirtualBMC(bmc.Bmc):
LOG.error('Error reseting the domain %(domain)s. ' LOG.error('Error reseting the domain %(domain)s. '
'Error: %(error)s' % {'domain': self.domain_name, 'Error: %(error)s' % {'domain': self.domain_name,
'error': e}) 'error': e})
# Command not supported in present state # Command failed, but let client to retry
return IPMI_COMMAND_NOT_SUPPORTED return IPMI_COMMAND_NODE_BUSY
def is_active(self): def is_active(self):
try: try: