Improve detection of multipathd running

There is a case where `multipathd show status` should fail, yet it
doesn't exit with an error code. Instead it returns 0. Error is printed
to stdout as "error receiving packet".

This means that enforce will not work as expected.

The multipathd error got fixed here:
https://www.redhat.com/archives/dm-devel/2015-March/msg00136.html

But that patch is missing in some packages, so this patch adds a
workaround to detect the error base on the stdout of the multipathd show
status command.

Closes-Bug: #1789699
Change-Id: I1cb29782541e3fe53b0b1744ab36f56464cd2135
(cherry picked from commit 028af871de)
(cherry picked from commit f2fed213f6)
This commit is contained in:
Gorka Eguileor 2018-08-29 19:16:58 +02:00 committed by Jay S. Bryant
parent 44a0486d05
commit ce72e77959
3 changed files with 24 additions and 10 deletions

View File

@ -168,8 +168,13 @@ class LinuxSCSI(executor.Executor):
try:
if execute is None:
execute = priv_rootwrap.execute
execute('multipathd', 'show', 'status',
run_as_root=True, root_helper=root_helper)
cmd = ('multipathd', 'show', 'status')
out, _err = execute(*cmd, run_as_root=True,
root_helper=root_helper)
# There was a bug in multipathd where it didn't return an error
# code and just printed the error message in stdout.
if out and out.startswith('error receiving packet'):
raise putils.ProcessExecutionError('', out, 1, cmd, None)
except putils.ProcessExecutionError as err:
LOG.error('multipathd is not running: exit code %(err)s',
{'err': err.exit_code})

View File

@ -89,7 +89,7 @@ class ConnectorUtilsTestCase(test_base.TestCase):
def test_brick_get_connector_properties(self):
self._test_brick_get_connector_properties(False, False, False)
@mock.patch.object(priv_rootwrap, 'execute')
@mock.patch.object(priv_rootwrap, 'execute', return_value=('', ''))
def test_brick_get_connector_properties_multipath(self, mock_execute):
self._test_brick_get_connector_properties(True, True, True)
mock_execute.assert_called_once_with('multipathd', 'show', 'status',
@ -149,7 +149,7 @@ class ConnectorTestCase(test_base.TestCase):
def test_get_connector_properties(self):
with mock.patch.object(priv_rootwrap, 'execute') as mock_exec:
mock_exec.return_value = True
mock_exec.return_value = ('', '')
multipath = True
enforce_multipath = True
props = base.BaseLinuxConnector.get_connector_properties(

View File

@ -19,6 +19,7 @@ import time
import ddt
import mock
from oslo_concurrency import processutils as putils
from oslo_log import log as logging
from os_brick import exception
@ -829,12 +830,20 @@ loop0 0"""
expected = 13
self.assertEqual(expected, result)
@mock.patch('os_brick.privileged.rootwrap')
def test_is_multipath_running_default_executor(self, mock_rootwrap):
self.assertTrue(
linuxscsi.LinuxSCSI.is_multipath_running(
False, None, mock_rootwrap.execute))
mock_rootwrap.execute.assert_called_once_with(
@mock.patch('os_brick.privileged.rootwrap.execute', return_value=('', ''))
def test_is_multipath_running_default_executor(self, mock_exec):
res = linuxscsi.LinuxSCSI.is_multipath_running(False, None, mock_exec)
self.assertTrue(res)
mock_exec.assert_called_once_with(
'multipathd', 'show', 'status', run_as_root=True, root_helper=None)
@mock.patch('os_brick.privileged.rootwrap.execute')
def test_is_multipath_running_failure_exit_code_0(self, mock_exec):
mock_exec.return_value = ('error receiving packet', '')
self.assertRaises(putils.ProcessExecutionError,
linuxscsi.LinuxSCSI.is_multipath_running,
True, None, mock_exec)
mock_exec.assert_called_once_with(
'multipathd', 'show', 'status', run_as_root=True, root_helper=None)
@mock.patch('glob.glob')