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

[crmsh-4.6] Dev: completers: Add online_nodes and standby_nodes #1270

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
6 changes: 3 additions & 3 deletions crmsh/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ def wait_for_resource(message, resource, timeout_ms=WAIT_TIMEOUT_MS_DEFAULT):
with logger_utils.status_long(message) as progress_bar:
start_time = int(time.clock_gettime(time.CLOCK_MONOTONIC) * 1000)
while True:
if xmlutil.CrmMonXmlParser.is_resource_started(resource):
if xmlutil.CrmMonXmlParser().is_resource_started(resource):
break
status_progress(progress_bar)
if 0 < timeout_ms <= (int(time.clock_gettime(time.CLOCK_MONOTONIC) * 1000) - start_time):
Expand Down Expand Up @@ -471,7 +471,7 @@ def is_online():
Check whether local node is online
Besides that, in join process, check whether init node is online
"""
if not xmlutil.CrmMonXmlParser.is_node_online(utils.this_node()):
if not xmlutil.CrmMonXmlParser().is_node_online(utils.this_node()):
return False

# if peer_node is None, this is in the init process
Expand All @@ -482,7 +482,7 @@ def is_online():
# The communication IP maybe mis-configured
user, cluster_node = _parse_user_at_host(_context.cluster_node, None)
cluster_node = get_node_canonical_hostname(cluster_node)
if not xmlutil.CrmMonXmlParser.is_node_online(cluster_node):
if not xmlutil.CrmMonXmlParser().is_node_online(cluster_node):
shutil.copy(COROSYNC_CONF_ORIG, corosync.conf())
sync_file(corosync.conf())
ServiceManager(sh.ClusterShellAdaptorForLocalShell(sh.LocalShell())).stop_service("corosync")
Expand Down
2 changes: 2 additions & 0 deletions crmsh/completers.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ def primitives(args):


nodes = call(xmlutil.listnodes)
online_nodes = call(xmlutil.CrmMonXmlParser().get_node_list, "online")
standby_nodes = call(xmlutil.CrmMonXmlParser().get_node_list, "standby")

shadows = call(xmlutil.listshadows)

Expand Down
2 changes: 1 addition & 1 deletion crmsh/ocfs2.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@
if not target:
return
with logger_utils.status_long("Verify OCFS2 environment"):
use_cluster_lvm2 = xmlutil.CrmMonXmlParser.is_resource_configured(constants.LVMLOCKD_RA, peer)
use_cluster_lvm2 = xmlutil.CrmMonXmlParser(peer).is_resource_configured(constants.LVMLOCKD_RA)

Check warning on line 335 in crmsh/ocfs2.py

View check run for this annotation

Codecov / codecov/patch

crmsh/ocfs2.py#L335

Added line #L335 was not covered by tests
self._verify_packages(use_cluster_lvm2)
if utils.is_dev_a_plain_raw_disk_or_partition(target, peer):
utils.compare_uuid_with_peer_dev([target], peer)
Expand Down
2 changes: 1 addition & 1 deletion crmsh/qdevice.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def evaluate_qdevice_quorum_effect(mode, diskless_sbd=False, is_stage=False):
elif mode == QDEVICE_ADD and not is_stage:
# Add qdevice from init process, safe to restart
return QdevicePolicy.QDEVICE_RESTART
elif xmlutil.CrmMonXmlParser.is_any_resource_running():
elif xmlutil.CrmMonXmlParser().is_any_resource_running():
# will lose quorum, and with RA running
# no reload, no restart cluster service
# just leave a warning
Expand Down
10 changes: 5 additions & 5 deletions crmsh/sbd.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@
"""
Try to configure sbd resource, restart cluster on needed
"""
if not xmlutil.CrmMonXmlParser.is_any_resource_running():
if not xmlutil.CrmMonXmlParser().is_any_resource_running():

Check warning on line 459 in crmsh/sbd.py

View check run for this annotation

Codecov / codecov/patch

crmsh/sbd.py#L459

Added line #L459 was not covered by tests
logger.info("Restarting cluster service")
utils.cluster_run_cmd("crm cluster restart")
bootstrap.wait_for_cluster()
Expand Down Expand Up @@ -523,7 +523,7 @@
"""
if not utils.package_is_installed("sbd") or \
not ServiceManager().service_is_enabled("sbd.service") or \
xmlutil.CrmMonXmlParser.is_resource_configured(self.SBD_RA):
xmlutil.CrmMonXmlParser().is_resource_configured(self.SBD_RA):
return
shell = sh.cluster_shell()

Expand Down Expand Up @@ -625,9 +625,9 @@


def clean_up_existing_sbd_resource():
if xmlutil.CrmMonXmlParser.is_resource_configured(SBDManager.SBD_RA):
sbd_id_list = xmlutil.CrmMonXmlParser.get_resource_id_list_via_type(SBDManager.SBD_RA)
if xmlutil.CrmMonXmlParser.is_resource_started(SBDManager.SBD_RA):
if xmlutil.CrmMonXmlParser().is_resource_configured(SBDManager.SBD_RA):
sbd_id_list = xmlutil.CrmMonXmlParser().get_resource_id_list_via_type(SBDManager.SBD_RA)
if xmlutil.CrmMonXmlParser().is_resource_started(SBDManager.SBD_RA):

Check warning on line 630 in crmsh/sbd.py

View check run for this annotation

Codecov / codecov/patch

crmsh/sbd.py#L628-L630

Added lines #L628 - L630 were not covered by tests
for sbd_id in sbd_id_list:
utils.ext_cmd("crm resource stop {}".format(sbd_id))
utils.ext_cmd("crm configure delete {}".format(' '.join(sbd_id_list)))
4 changes: 2 additions & 2 deletions crmsh/ui_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ def do_print(uname):
return True

@command.wait
@command.completers(compl.nodes)
@command.completers(compl.online_nodes)
def do_standby(self, context, *args):
"""
usage: standby [<node>] [<lifetime>]
Expand Down Expand Up @@ -422,7 +422,7 @@ def do_standby(self, context, *args):
logger.info("standby node %s", node)

@command.wait
@command.completers(compl.nodes)
@command.completers(compl.standby_nodes)
def do_online(self, context, *args):
"""
usage: online [<node>]
Expand Down
4 changes: 2 additions & 2 deletions crmsh/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2866,15 +2866,15 @@ def is_dlm_running():
Check if dlm ra controld is running
"""
from . import xmlutil
return xmlutil.CrmMonXmlParser.is_resource_started(constants.DLM_CONTROLD_RA)
return xmlutil.CrmMonXmlParser().is_resource_started(constants.DLM_CONTROLD_RA)


def is_dlm_configured():
"""
Check if dlm configured
"""
from . import xmlutil
return xmlutil.CrmMonXmlParser.is_resource_configured(constants.DLM_CONTROLD_RA)
return xmlutil.CrmMonXmlParser().is_resource_configured(constants.DLM_CONTROLD_RA)


def is_quorate():
Expand Down
73 changes: 31 additions & 42 deletions crmsh/xmlutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -1515,72 +1515,61 @@
Init function
when peer set, parse peer node's results
"""
self.xml_elem = None
self.peer = peer
self.xml_elem = self._load()

def _load(self):
"""
Load xml output of crm_mon
"""
rc, output, stderr = sh.cluster_shell().get_rc_stdout_stderr_without_input(self.peer, constants.CRM_MON_XML_OUTPUT)
self.xml_elem = text2elem(output)
_, output, _ = sh.cluster_shell().get_rc_stdout_stderr_without_input(self.peer, constants.CRM_MON_XML_OUTPUT)
return text2elem(output)

@classmethod
def is_node_online(cls, node):
def is_node_online(self, node):
"""
Check if node online
Check if a node is online
"""
cls_inst = cls()
cls_inst._load()
elem_list = cls_inst.xml_elem.xpath('//node[@name="{}" and @online="true"]'.format(node))
return len(elem_list) != 0
xpath = f'//node[@name="{node}" and @online="true"]'
return bool(self.xml_elem.xpath(xpath))

@classmethod
def is_resource_configured(cls, ra_type, peer=None):
def get_node_list(self, attr=None):
"""
Check if the RA configured
Get a list of nodes based on the given attribute
"""
cls_inst = cls(peer=peer)
cls_inst._load()
elem_list = cls_inst.xml_elem.xpath('//resource[@resource_agent="{}"]'.format(ra_type))
return len(elem_list) != 0
attr_dict = {

Check warning on line 1539 in crmsh/xmlutil.py

View check run for this annotation

Codecov / codecov/patch

crmsh/xmlutil.py#L1539

Added line #L1539 was not covered by tests
'standby': '[@standby="true"]',
'online': '[@standby="false"]'
}
xpath_str = f'//node{attr_dict.get(attr, "")}'
return [e.get('name') for e in self.xml_elem.xpath(xpath_str)]

Check warning on line 1544 in crmsh/xmlutil.py

View check run for this annotation

Codecov / codecov/patch

crmsh/xmlutil.py#L1543-L1544

Added lines #L1543 - L1544 were not covered by tests

def is_resource_configured(self, ra_type):
"""
Check if the RA is configured
"""
xpath = f'//resource[@resource_agent="{ra_type}"]'
return bool(self.xml_elem.xpath(xpath))

@classmethod
def is_any_resource_running(cls, peer=None):
def is_any_resource_running(self):
"""
Check if any RA is running
"""
cls_inst = cls(peer=peer)
cls_inst._load()
elem_list = cls_inst.xml_elem.xpath('//resource[@active="true"]')
return len(elem_list) != 0
xpath = '//resource[@active="true"]'
return bool(self.xml_elem.xpath(xpath))

@classmethod
def is_resource_started(cls, ra, peer=None):
def is_resource_started(self, ra):
"""
Check if the RA started(in all clone instances if configured as clone)

@ra could be resource id or resource type
"""
cls_inst = cls(peer=peer)
cls_inst._load()
elem_list = cls_inst.xml_elem.xpath('//resource[(@id="{ra}" or @resource_agent="{ra}") and @active="true"]'.format(ra=ra))
# Stopped or not exist
if not elem_list:
return False
# Starting will return False
return all([True if elem.get('role') == 'Started' else False for elem in elem_list])
xpath = f'//resource[(@id="{ra}" or @resource_agent="{ra}") and @active="true" and @role="Started"]'
return bool(self.xml_elem.xpath(xpath))

@classmethod
def get_resource_id_list_via_type(cls, ra_type, peer=None):
def get_resource_id_list_via_type(self, ra_type):
"""
Given configured ra type, get the ra id list
"""
id_list = []
cls_inst = cls(peer=peer)
cls_inst._load()
elem_list = cls_inst.xml_elem.xpath('//resource[@resource_agent="{ra_type}"]'.format(ra_type=ra_type))
if not elem_list:
return id_list
return [elem.get('id') for elem in elem_list]
xpath = f'//resource[@resource_agent="{ra_type}"]'
return [elem.get('id') for elem in self.xml_elem.xpath(xpath)]

Check warning on line 1574 in crmsh/xmlutil.py

View check run for this annotation

Codecov / codecov/patch

crmsh/xmlutil.py#L1573-L1574

Added lines #L1573 - L1574 were not covered by tests
# vim:ts=4:sw=4:et:
7 changes: 3 additions & 4 deletions test/unittests/test_ocfs2.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,16 +445,15 @@ def test_join_ocfs2_return(self, mock_find):
@mock.patch('crmsh.utils.compare_uuid_with_peer_dev')
@mock.patch('crmsh.utils.is_dev_a_plain_raw_disk_or_partition')
@mock.patch('crmsh.ocfs2.OCFS2Manager._verify_packages')
@mock.patch('crmsh.xmlutil.CrmMonXmlParser.is_resource_configured')
@mock.patch('crmsh.xmlutil.CrmMonXmlParser')
@mock.patch('crmsh.log.LoggerUtils.status_long')
@mock.patch('crmsh.ocfs2.OCFS2Manager._find_target_on_join')
def test_join_ocfs2(self, mock_find, mock_long, mock_configured, mock_verify_packages, mock_is_mapper, mock_compare):
def test_join_ocfs2(self, mock_find, mock_long, mock_parser, mock_verify_packages, mock_is_mapper, mock_compare):
mock_find.return_value = "/dev/sda2"
mock_configured.return_value = False
mock_parser("node1").is_resource_configured.return_value = False
mock_is_mapper.return_value = True
self.ocfs2_inst3.join_ocfs2("node1")
mock_find.assert_called_once_with("node1")
mock_configured.assert_called_once_with(constants.LVMLOCKD_RA, "node1")
mock_verify_packages.assert_called_once_with(False)
mock_is_mapper.assert_called_once_with("/dev/sda2", "node1")
mock_compare.assert_called_once_with(["/dev/sda2"], "node1")
Expand Down
14 changes: 6 additions & 8 deletions test/unittests/test_qdevice.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,32 +38,30 @@ def test_evaluate_qdevice_quorum_effect_reload(mock_get_dict, mock_quorate):
mock_quorate.assert_called_once_with(3, 2)


@mock.patch('crmsh.xmlutil.CrmMonXmlParser.is_any_resource_running')
@mock.patch('crmsh.xmlutil.CrmMonXmlParser')
@mock.patch('crmsh.utils.calculate_quorate_status')
@mock.patch('crmsh.utils.get_quorum_votes_dict')
def test_evaluate_qdevice_quorum_effect_later(mock_get_dict, mock_quorate, mock_ra_running):
def test_evaluate_qdevice_quorum_effect_later(mock_get_dict, mock_quorate, mock_parser):
mock_get_dict.return_value = {'Expected': '2', 'Total': '2'}
mock_quorate.return_value = False
mock_ra_running.return_value = True
mock_parser().is_any_resource_running.return_value = True
res = qdevice.evaluate_qdevice_quorum_effect(qdevice.QDEVICE_REMOVE)
assert res == qdevice.QdevicePolicy.QDEVICE_RESTART_LATER
mock_get_dict.assert_called_once_with()
mock_quorate.assert_called_once_with(2, 1)
mock_ra_running.assert_called_once_with()


@mock.patch('crmsh.xmlutil.CrmMonXmlParser.is_any_resource_running')
@mock.patch('crmsh.xmlutil.CrmMonXmlParser')
@mock.patch('crmsh.utils.calculate_quorate_status')
@mock.patch('crmsh.utils.get_quorum_votes_dict')
def test_evaluate_qdevice_quorum_effect(mock_get_dict, mock_quorate, mock_ra_running):
def test_evaluate_qdevice_quorum_effect(mock_get_dict, mock_quorate, mock_parser):
mock_get_dict.return_value = {'Expected': '2', 'Total': '2'}
mock_quorate.return_value = False
mock_ra_running.return_value = False
mock_parser().is_any_resource_running.return_value = False
res = qdevice.evaluate_qdevice_quorum_effect(qdevice.QDEVICE_REMOVE)
assert res == qdevice.QdevicePolicy.QDEVICE_RESTART
mock_get_dict.assert_called_once_with()
mock_quorate.assert_called_once_with(2, 1)
mock_ra_running.assert_called_once_with()


@mock.patch('crmsh.lock.RemoteLock')
Expand Down
26 changes: 12 additions & 14 deletions test/unittests/test_sbd.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,9 +618,9 @@ def test_sbd_init(self, mock_package, mock_watchdog, mock_get_device, mock_initi
@mock.patch('crmsh.bootstrap.wait_for_cluster')
@mock.patch('crmsh.utils.cluster_run_cmd')
@mock.patch('logging.Logger.info')
@mock.patch('crmsh.xmlutil.CrmMonXmlParser.is_any_resource_running')
def test_restart_cluster_on_needed_no_ra_running(self, mock_ra_running, mock_status, mock_cluster_run, mock_wait, mock_config_sbd_ra):
mock_ra_running.return_value = False
@mock.patch('crmsh.xmlutil.CrmMonXmlParser')
def test_restart_cluster_on_needed_no_ra_running(self, mock_parser, mock_status, mock_cluster_run, mock_wait, mock_config_sbd_ra):
mock_parser().is_any_resource_running.return_value = False
self.sbd_inst._restart_cluster_and_configure_sbd_ra()
mock_status.assert_called_once_with("Restarting cluster service")
mock_cluster_run.assert_called_once_with("crm cluster restart")
Expand All @@ -629,9 +629,9 @@ def test_restart_cluster_on_needed_no_ra_running(self, mock_ra_running, mock_sta

@mock.patch('crmsh.sbd.SBDTimeout.get_stonith_timeout')
@mock.patch('logging.Logger.warning')
@mock.patch('crmsh.xmlutil.CrmMonXmlParser.is_any_resource_running')
def test_restart_cluster_on_needed_diskless(self, mock_ra_running, mock_warn, mock_get_timeout):
mock_ra_running.return_value = True
@mock.patch('crmsh.xmlutil.CrmMonXmlParser')
def test_restart_cluster_on_needed_diskless(self, mock_parser, mock_warn, mock_get_timeout):
mock_parser().is_any_resource_running.return_value = True
mock_get_timeout.return_value = 60
self.sbd_inst_diskless.timeout_inst = mock.Mock(stonith_watchdog_timeout=-1)
self.sbd_inst_diskless._restart_cluster_and_configure_sbd_ra()
Expand All @@ -642,14 +642,13 @@ def test_restart_cluster_on_needed_diskless(self, mock_ra_running, mock_warn, mo

@mock.patch('crmsh.sbd.SBDManager.configure_sbd_resource_and_properties')
@mock.patch('logging.Logger.warning')
@mock.patch('crmsh.xmlutil.CrmMonXmlParser.is_any_resource_running')
def test_restart_cluster_on_needed(self, mock_ra_running, mock_warn, mock_config_sbd_ra):
mock_ra_running.return_value = True
@mock.patch('crmsh.xmlutil.CrmMonXmlParser')
def test_restart_cluster_on_needed(self, mock_parser, mock_warn, mock_config_sbd_ra):
mock_parser().is_any_resource_running.return_value = True
self.sbd_inst._restart_cluster_and_configure_sbd_ra()
mock_warn.assert_has_calls([
mock.call("To start sbd.service, need to restart cluster service manually on each node"),
])
mock_config_sbd_ra.assert_called_once_with()

@mock.patch('crmsh.bootstrap.invoke')
def test_enable_sbd_service_init(self, mock_invoke):
Expand Down Expand Up @@ -677,16 +676,16 @@ def test_configure_sbd_resource_and_properties_not_installed(self, mock_package)
@mock.patch('crmsh.sbd.SBDTimeout.adjust_sbd_timeout_related_cluster_configuration')
@mock.patch('crmsh.utils.set_property')
@mock.patch('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
@mock.patch('crmsh.xmlutil.CrmMonXmlParser.is_resource_configured')
@mock.patch('crmsh.xmlutil.CrmMonXmlParser')
@mock.patch('crmsh.service_manager.ServiceManager.service_is_enabled')
@mock.patch('crmsh.utils.package_is_installed')
def test_configure_sbd_resource_and_properties(
self,
mock_package, mock_enabled, mock_configured, mock_run, mock_set_property, sbd_adjust, mock_is_active,
mock_package, mock_enabled, mock_parser, mock_run, mock_set_property, sbd_adjust, mock_is_active,
):
mock_package.return_value = True
mock_enabled.return_value = True
mock_configured.return_value = False
mock_parser().is_resource_configured.return_value = False
mock_is_active.return_value = False
self.sbd_inst._context = mock.Mock(cluster_is_running=True)
self.sbd_inst._get_sbd_device_from_config = mock.Mock()
Expand All @@ -696,7 +695,6 @@ def test_configure_sbd_resource_and_properties(

mock_package.assert_called_once_with("sbd")
mock_enabled.assert_called_once_with("sbd.service")
mock_configured.assert_called_once_with(sbd.SBDManager.SBD_RA)
mock_run.assert_called_once_with("crm configure primitive {} {}".format(sbd.SBDManager.SBD_RA_ID, sbd.SBDManager.SBD_RA))
mock_set_property.assert_called_once_with("stonith-enabled", "true")

Expand Down
8 changes: 4 additions & 4 deletions test/unittests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1327,11 +1327,11 @@ def test_set_dlm_option(mock_get_dict, mock_run):
mock_run.assert_called_once_with('dlm_tool set_config "key2=test"')


@mock.patch('crmsh.xmlutil.CrmMonXmlParser.is_resource_configured')
def test_is_dlm_configured(mock_configured):
mock_configured.return_value = True
@mock.patch('crmsh.xmlutil.CrmMonXmlParser')
def test_is_dlm_configured(mock_parser):
mock_parser().is_resource_configured.return_value = True
assert utils.is_dlm_configured() is True
mock_configured.assert_called_once_with(constants.DLM_CONTROLD_RA)
mock_parser().is_resource_configured.assert_called_once_with(constants.DLM_CONTROLD_RA)


@mock.patch('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
Expand Down
Loading