Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CA-405381 Mpath Info Does Not Automatically Refresh in XC After Disabling and Enabling Multipath #730

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions drivers/mpathcount.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import xs_errors
import mpath_cli
import json
import subprocess

supported = ['iscsi', 'lvmoiscsi', 'rawhba', 'lvmohba', 'ocfsohba', 'ocfsoiscsi', 'netapp', 'gfs2']

Expand All @@ -35,6 +36,7 @@
match_bySCSIid = False
mpath_enabled = True
SCSIid = 'NOTSUPPLIED'
XAPI_HEALTH_CHECK = '/opt/xensource/libexec/xapi-health-check'

cached_DM_maj = None

Expand Down Expand Up @@ -199,13 +201,31 @@ def check_devconfig(devconfig, sm_config, config, remove, add, mpath_status=None
else:
update_config(key, i, config[key], remove, add, mpath_status)


def check_xapi_is_enabled(session, hostref):
host = session.xenapi.host.get_record(hostref)
if not host['enabled']:
util.SMlog("Xapi is not enabled, exiting")
mpc_exit(session, 0)

def check_xapi_is_enabled():
"""Check XAPI health status"""
def _run_command(command, timeout):
try:
process = subprocess.Popen(
command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True
)
try:
stdout, stderr = process.communicate(timeout=timeout)
return process.returncode, stdout, stderr
except subprocess.TimeoutExpired:
process.kill()
util.SMlog(f"Command execution timeout after {timeout}s: {' '.join(command)}")
return -1, "", "Timeout"
except Exception as e:
util.SMlog(f"Error executing command: {e}")
return -1, "", str(e)

returncode, _, stderr = _run_command([XAPI_HEALTH_CHECK], timeout=120)
if returncode != 0:
util.SMlog(f"XAPI health check failed: {stderr}")
return returncode == 0

if __name__ == '__main__':
try:
Expand All @@ -215,7 +235,7 @@ def check_xapi_is_enabled(session, hostref):
sys.exit(-1)

localhost = session.xenapi.host.get_by_uuid(get_localhost_uuid())
check_xapi_is_enabled(session, localhost)
check_xapi_is_enabled()
# Check whether multipathing is enabled (either for root dev or SRs)
try:
if get_root_dev_major() != get_dm_major():
Expand Down
32 changes: 21 additions & 11 deletions tests/test_mpathcount.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,27 +211,37 @@ def test_exit_log_out_error(self, mock_exit):
session.xenapi.session.logout.assert_called_once()

@mock.patch('mpathcount.sys.exit', autospec=True)
def test_check_xapi_enabled_yes(self, mock_exit):
@mock.patch('mpathcount.util.SMlog', autospec=True)
@mock.patch('mpathcount.subprocess.Popen', autospec=True)
def test_check_xapi_enabled_yes(self, mock_popen, mock_smlog, mock_exit):
# Arrange
session = mock.MagicMock()
session.xenapi.host.get_record.return_value = {'enabled': True}
hostref = mock.MagicMock()
process_mock = mock.Mock()
attrs = {'communicate.return_value': ('output', ''), 'returncode': 0}
process_mock.configure_mock(**attrs)
mock_popen.return_value = process_mock

# Act
mpathcount.check_xapi_is_enabled(session, hostref)
result = mpathcount.check_xapi_is_enabled()

# Assert
self.assertTrue(result)
mock_exit.assert_not_called()
mock_smlog.assert_not_called()

@mock.patch('mpathcount.sys.exit', autospec=True)
def test_check_xapi_enabled_no(self, mock_exit):
@mock.patch('mpathcount.util.SMlog', autospec=True)
@mock.patch('mpathcount.subprocess.Popen', autospec=True)
def test_check_xapi_enabled_no(self, mock_popen, mock_smlog, mock_exit):
# Arrange
session = mock.MagicMock()
session.xenapi.host.get_record.return_value = {'enabled': False}
hostref = mock.MagicMock()
process_mock = mock.Mock()
attrs = {'communicate.return_value': ('', 'error'), 'returncode': 1}
process_mock.configure_mock(**attrs)
mock_popen.return_value = process_mock

# Act
mpathcount.check_xapi_is_enabled(session, hostref)
result = mpathcount.check_xapi_is_enabled()

# Assert
mock_exit.assert_called_once_with(0)
self.assertFalse(result)
mock_exit.assert_not_called()
mock_smlog.assert_called_once_with('XAPI health check failed: error')