From 72f873d9f47bece235e8c46a738bc6e31ce7bc6b Mon Sep 17 00:00:00 2001 From: Ilya Etingof Date: Fri, 27 Apr 2018 13:19:55 +0200 Subject: [PATCH] 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 --- virtualbmc/tests/unit/test_vbmc.py | 14 ++++++------- virtualbmc/vbmc.py | 32 +++++++++++++++--------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/virtualbmc/tests/unit/test_vbmc.py b/virtualbmc/tests/unit/test_vbmc.py index 95848e1..dec32f4 100644 --- a/virtualbmc/tests/unit/test_vbmc.py +++ b/virtualbmc/tests/unit/test_vbmc.py @@ -103,7 +103,7 @@ class VirtualBMCTestCase(base.TestCase): mock_libvirt_open): mock_libvirt_domain.side_effect = libvirt.libvirtError('boom') 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) 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_domain.side_effect = libvirt.libvirtError('boom') ret = self.vbmc.get_power_state() - self.assertEqual(0xd5, ret) + self.assertEqual(0xC0, ret) self._assert_libvirt_calls(mock_libvirt_domain, mock_libvirt_open, readonly=True) @@ -159,7 +159,7 @@ class VirtualBMCTestCase(base.TestCase): def test_pulse_diag_error(self, mock_libvirt_domain, mock_libvirt_open): mock_libvirt_domain.side_effect = libvirt.libvirtError('boom') ret = self.vbmc.pulse_diag() - self.assertEqual(0xd5, ret) + self.assertEqual(0xC0, ret) mock_libvirt_domain.return_value.injectNMI.assert_not_called() 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): mock_libvirt_domain.side_effect = libvirt.libvirtError('boom') ret = self.vbmc.power_off() - self.assertEqual(0xd5, ret) + self.assertEqual(0xC0, ret) mock_libvirt_domain.return_value.destroy.assert_not_called() 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): mock_libvirt_domain.side_effect = libvirt.libvirtError('boom') ret = self.vbmc.power_reset() - self.assertEqual(0xd5, ret) + self.assertEqual(0xC0, ret) mock_libvirt_domain.return_value.reset.assert_not_called() self._assert_libvirt_calls(mock_libvirt_domain, mock_libvirt_open) @@ -234,7 +234,7 @@ class VirtualBMCTestCase(base.TestCase): mock_libvirt_open): mock_libvirt_domain.side_effect = libvirt.libvirtError('boom') ret = self.vbmc.power_shutdown() - self.assertEqual(0xd5, ret) + self.assertEqual(0xC0, ret) mock_libvirt_domain.return_value.shutdown.assert_not_called() 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): mock_libvirt_domain.side_effect = libvirt.libvirtError('boom') ret = self.vbmc.power_on() - self.assertEqual(0xd5, ret) + self.assertEqual(0xC0, ret) self.assertFalse(mock_libvirt_domain.return_value.create.called) self._assert_libvirt_calls(mock_libvirt_domain, mock_libvirt_open) diff --git a/virtualbmc/vbmc.py b/virtualbmc/vbmc.py index 58f0d3e..18f700c 100644 --- a/virtualbmc/vbmc.py +++ b/virtualbmc/vbmc.py @@ -29,8 +29,8 @@ POWERON = 1 # 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 # -# Command not supported in present state -IPMI_COMMAND_NOT_SUPPORTED = 0xd5 +# Command failed and can be retried +IPMI_COMMAND_NODE_BUSY = 0xC0 # Invalid data field in request IPMI_INVALID_DATA = 0xcc @@ -138,8 +138,8 @@ class VirtualBMC(bmc.Bmc): LOG.error('Failed setting the boot device %(bootdev)s for ' 'domain %(domain)s', {'bootdev': device, 'domain': self.domain_name}) - # Command not supported in present state - return IPMI_COMMAND_NOT_SUPPORTED + # Command failed, but let client to retry + return IPMI_COMMAND_NODE_BUSY def get_power_state(self): 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. ' 'Error: %(error)s', {'domain': self.domain_name, 'error': e}) - # Command not supported in present state - return IPMI_COMMAND_NOT_SUPPORTED + # Command failed, but let client to retry + return IPMI_COMMAND_NODE_BUSY return POWEROFF @@ -168,8 +168,8 @@ class VirtualBMC(bmc.Bmc): LOG.error('Error powering diag the domain %(domain)s. ' 'Error: %(error)s' % {'domain': self.domain_name, 'error': e}) - # Command not supported in present state - return IPMI_COMMAND_NOT_SUPPORTED + # Command failed, but let client to retry + return IPMI_COMMAND_NODE_BUSY def power_off(self): 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. ' 'Error: %(error)s' % {'domain': self.domain_name, 'error': e}) - # Command not supported in present state - return IPMI_COMMAND_NOT_SUPPORTED + # Command failed, but let client to retry + return IPMI_COMMAND_NODE_BUSY def power_on(self): 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. ' 'Error: %(error)s' % {'domain': self.domain_name, 'error': e}) - # Command not supported in present state - return IPMI_COMMAND_NOT_SUPPORTED + # Command failed, but let client to retry + return IPMI_COMMAND_NODE_BUSY def power_shutdown(self): 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. ' 'Error: %(error)s' % {'domain': self.domain_name, 'error': e}) - # Command not supported in present state - return IPMI_COMMAND_NOT_SUPPORTED + # Command failed, but let client to retry + return IPMI_COMMAND_NODE_BUSY def power_reset(self): 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. ' 'Error: %(error)s' % {'domain': self.domain_name, 'error': e}) - # Command not supported in present state - return IPMI_COMMAND_NOT_SUPPORTED + # Command failed, but let client to retry + return IPMI_COMMAND_NODE_BUSY def is_active(self): try: