Skip to content

Commit 38304a7

Browse files
authored
Merge pull request #1270 from liangxin1300/20231101_node_standby_online_completer_crmsh46
[crmsh-4.6] Dev: completers: Add online_nodes and standby_nodes
2 parents 779324d + c8137e5 commit 38304a7

File tree

13 files changed

+108
-153
lines changed

13 files changed

+108
-153
lines changed

crmsh/bootstrap.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ def wait_for_resource(message, resource, timeout_ms=WAIT_TIMEOUT_MS_DEFAULT):
436436
with logger_utils.status_long(message) as progress_bar:
437437
start_time = int(time.clock_gettime(time.CLOCK_MONOTONIC) * 1000)
438438
while True:
439-
if xmlutil.CrmMonXmlParser.is_resource_started(resource):
439+
if xmlutil.CrmMonXmlParser().is_resource_started(resource):
440440
break
441441
status_progress(progress_bar)
442442
if 0 < timeout_ms <= (int(time.clock_gettime(time.CLOCK_MONOTONIC) * 1000) - start_time):
@@ -471,7 +471,7 @@ def is_online():
471471
Check whether local node is online
472472
Besides that, in join process, check whether init node is online
473473
"""
474-
if not xmlutil.CrmMonXmlParser.is_node_online(utils.this_node()):
474+
if not xmlutil.CrmMonXmlParser().is_node_online(utils.this_node()):
475475
return False
476476

477477
# if peer_node is None, this is in the init process
@@ -482,7 +482,7 @@ def is_online():
482482
# The communication IP maybe mis-configured
483483
user, cluster_node = _parse_user_at_host(_context.cluster_node, None)
484484
cluster_node = get_node_canonical_hostname(cluster_node)
485-
if not xmlutil.CrmMonXmlParser.is_node_online(cluster_node):
485+
if not xmlutil.CrmMonXmlParser().is_node_online(cluster_node):
486486
shutil.copy(COROSYNC_CONF_ORIG, corosync.conf())
487487
sync_file(corosync.conf())
488488
ServiceManager(sh.ClusterShellAdaptorForLocalShell(sh.LocalShell())).stop_service("corosync")

crmsh/completers.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ def primitives(args):
7676

7777

7878
nodes = call(xmlutil.listnodes)
79+
online_nodes = call(xmlutil.CrmMonXmlParser().get_node_list, "online")
80+
standby_nodes = call(xmlutil.CrmMonXmlParser().get_node_list, "standby")
7981

8082
shadows = call(xmlutil.listshadows)
8183

crmsh/ocfs2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ def join_ocfs2(self, peer):
332332
if not target:
333333
return
334334
with logger_utils.status_long("Verify OCFS2 environment"):
335-
use_cluster_lvm2 = xmlutil.CrmMonXmlParser.is_resource_configured(constants.LVMLOCKD_RA, peer)
335+
use_cluster_lvm2 = xmlutil.CrmMonXmlParser(peer).is_resource_configured(constants.LVMLOCKD_RA)
336336
self._verify_packages(use_cluster_lvm2)
337337
if utils.is_dev_a_plain_raw_disk_or_partition(target, peer):
338338
utils.compare_uuid_with_peer_dev([target], peer)

crmsh/qdevice.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def evaluate_qdevice_quorum_effect(mode, diskless_sbd=False, is_stage=False):
5252
elif mode == QDEVICE_ADD and not is_stage:
5353
# Add qdevice from init process, safe to restart
5454
return QdevicePolicy.QDEVICE_RESTART
55-
elif xmlutil.CrmMonXmlParser.is_any_resource_running():
55+
elif xmlutil.CrmMonXmlParser().is_any_resource_running():
5656
# will lose quorum, and with RA running
5757
# no reload, no restart cluster service
5858
# just leave a warning

crmsh/sbd.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ def _restart_cluster_and_configure_sbd_ra(self):
456456
"""
457457
Try to configure sbd resource, restart cluster on needed
458458
"""
459-
if not xmlutil.CrmMonXmlParser.is_any_resource_running():
459+
if not xmlutil.CrmMonXmlParser().is_any_resource_running():
460460
logger.info("Restarting cluster service")
461461
utils.cluster_run_cmd("crm cluster restart")
462462
bootstrap.wait_for_cluster()
@@ -523,7 +523,7 @@ def configure_sbd_resource_and_properties(self):
523523
"""
524524
if not utils.package_is_installed("sbd") or \
525525
not ServiceManager().service_is_enabled("sbd.service") or \
526-
xmlutil.CrmMonXmlParser.is_resource_configured(self.SBD_RA):
526+
xmlutil.CrmMonXmlParser().is_resource_configured(self.SBD_RA):
527527
return
528528
shell = sh.cluster_shell()
529529

@@ -625,9 +625,9 @@ def has_sbd_device_already_initialized(dev):
625625

626626

627627
def clean_up_existing_sbd_resource():
628-
if xmlutil.CrmMonXmlParser.is_resource_configured(SBDManager.SBD_RA):
629-
sbd_id_list = xmlutil.CrmMonXmlParser.get_resource_id_list_via_type(SBDManager.SBD_RA)
630-
if xmlutil.CrmMonXmlParser.is_resource_started(SBDManager.SBD_RA):
628+
if xmlutil.CrmMonXmlParser().is_resource_configured(SBDManager.SBD_RA):
629+
sbd_id_list = xmlutil.CrmMonXmlParser().get_resource_id_list_via_type(SBDManager.SBD_RA)
630+
if xmlutil.CrmMonXmlParser().is_resource_started(SBDManager.SBD_RA):
631631
for sbd_id in sbd_id_list:
632632
utils.ext_cmd("crm resource stop {}".format(sbd_id))
633633
utils.ext_cmd("crm configure delete {}".format(' '.join(sbd_id_list)))

crmsh/ui_node.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ def do_print(uname):
347347
return True
348348

349349
@command.wait
350-
@command.completers(compl.nodes)
350+
@command.completers(compl.online_nodes)
351351
def do_standby(self, context, *args):
352352
"""
353353
usage: standby [<node>] [<lifetime>]
@@ -422,7 +422,7 @@ def do_standby(self, context, *args):
422422
logger.info("standby node %s", node)
423423

424424
@command.wait
425-
@command.completers(compl.nodes)
425+
@command.completers(compl.standby_nodes)
426426
def do_online(self, context, *args):
427427
"""
428428
usage: online [<node>]

crmsh/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2866,15 +2866,15 @@ def is_dlm_running():
28662866
Check if dlm ra controld is running
28672867
"""
28682868
from . import xmlutil
2869-
return xmlutil.CrmMonXmlParser.is_resource_started(constants.DLM_CONTROLD_RA)
2869+
return xmlutil.CrmMonXmlParser().is_resource_started(constants.DLM_CONTROLD_RA)
28702870

28712871

28722872
def is_dlm_configured():
28732873
"""
28742874
Check if dlm configured
28752875
"""
28762876
from . import xmlutil
2877-
return xmlutil.CrmMonXmlParser.is_resource_configured(constants.DLM_CONTROLD_RA)
2877+
return xmlutil.CrmMonXmlParser().is_resource_configured(constants.DLM_CONTROLD_RA)
28782878

28792879

28802880
def is_quorate():

crmsh/xmlutil.py

Lines changed: 31 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,72 +1515,61 @@ def __init__(self, peer=None):
15151515
Init function
15161516
when peer set, parse peer node's results
15171517
"""
1518-
self.xml_elem = None
15191518
self.peer = peer
1519+
self.xml_elem = self._load()
15201520

15211521
def _load(self):
15221522
"""
15231523
Load xml output of crm_mon
15241524
"""
1525-
rc, output, stderr = sh.cluster_shell().get_rc_stdout_stderr_without_input(self.peer, constants.CRM_MON_XML_OUTPUT)
1526-
self.xml_elem = text2elem(output)
1525+
_, output, _ = sh.cluster_shell().get_rc_stdout_stderr_without_input(self.peer, constants.CRM_MON_XML_OUTPUT)
1526+
return text2elem(output)
15271527

1528-
@classmethod
1529-
def is_node_online(cls, node):
1528+
def is_node_online(self, node):
15301529
"""
1531-
Check if node online
1530+
Check if a node is online
15321531
"""
1533-
cls_inst = cls()
1534-
cls_inst._load()
1535-
elem_list = cls_inst.xml_elem.xpath('//node[@name="{}" and @online="true"]'.format(node))
1536-
return len(elem_list) != 0
1532+
xpath = f'//node[@name="{node}" and @online="true"]'
1533+
return bool(self.xml_elem.xpath(xpath))
15371534

1538-
@classmethod
1539-
def is_resource_configured(cls, ra_type, peer=None):
1535+
def get_node_list(self, attr=None):
15401536
"""
1541-
Check if the RA configured
1537+
Get a list of nodes based on the given attribute
15421538
"""
1543-
cls_inst = cls(peer=peer)
1544-
cls_inst._load()
1545-
elem_list = cls_inst.xml_elem.xpath('//resource[@resource_agent="{}"]'.format(ra_type))
1546-
return len(elem_list) != 0
1539+
attr_dict = {
1540+
'standby': '[@standby="true"]',
1541+
'online': '[@standby="false"]'
1542+
}
1543+
xpath_str = f'//node{attr_dict.get(attr, "")}'
1544+
return [e.get('name') for e in self.xml_elem.xpath(xpath_str)]
1545+
1546+
def is_resource_configured(self, ra_type):
1547+
"""
1548+
Check if the RA is configured
1549+
"""
1550+
xpath = f'//resource[@resource_agent="{ra_type}"]'
1551+
return bool(self.xml_elem.xpath(xpath))
15471552

1548-
@classmethod
1549-
def is_any_resource_running(cls, peer=None):
1553+
def is_any_resource_running(self):
15501554
"""
15511555
Check if any RA is running
15521556
"""
1553-
cls_inst = cls(peer=peer)
1554-
cls_inst._load()
1555-
elem_list = cls_inst.xml_elem.xpath('//resource[@active="true"]')
1556-
return len(elem_list) != 0
1557+
xpath = '//resource[@active="true"]'
1558+
return bool(self.xml_elem.xpath(xpath))
15571559

1558-
@classmethod
1559-
def is_resource_started(cls, ra, peer=None):
1560+
def is_resource_started(self, ra):
15601561
"""
15611562
Check if the RA started(in all clone instances if configured as clone)
15621563
15631564
@ra could be resource id or resource type
15641565
"""
1565-
cls_inst = cls(peer=peer)
1566-
cls_inst._load()
1567-
elem_list = cls_inst.xml_elem.xpath('//resource[(@id="{ra}" or @resource_agent="{ra}") and @active="true"]'.format(ra=ra))
1568-
# Stopped or not exist
1569-
if not elem_list:
1570-
return False
1571-
# Starting will return False
1572-
return all([True if elem.get('role') == 'Started' else False for elem in elem_list])
1566+
xpath = f'//resource[(@id="{ra}" or @resource_agent="{ra}") and @active="true" and @role="Started"]'
1567+
return bool(self.xml_elem.xpath(xpath))
15731568

1574-
@classmethod
1575-
def get_resource_id_list_via_type(cls, ra_type, peer=None):
1569+
def get_resource_id_list_via_type(self, ra_type):
15761570
"""
15771571
Given configured ra type, get the ra id list
15781572
"""
1579-
id_list = []
1580-
cls_inst = cls(peer=peer)
1581-
cls_inst._load()
1582-
elem_list = cls_inst.xml_elem.xpath('//resource[@resource_agent="{ra_type}"]'.format(ra_type=ra_type))
1583-
if not elem_list:
1584-
return id_list
1585-
return [elem.get('id') for elem in elem_list]
1573+
xpath = f'//resource[@resource_agent="{ra_type}"]'
1574+
return [elem.get('id') for elem in self.xml_elem.xpath(xpath)]
15861575
# vim:ts=4:sw=4:et:

test/unittests/test_ocfs2.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -445,16 +445,15 @@ def test_join_ocfs2_return(self, mock_find):
445445
@mock.patch('crmsh.utils.compare_uuid_with_peer_dev')
446446
@mock.patch('crmsh.utils.is_dev_a_plain_raw_disk_or_partition')
447447
@mock.patch('crmsh.ocfs2.OCFS2Manager._verify_packages')
448-
@mock.patch('crmsh.xmlutil.CrmMonXmlParser.is_resource_configured')
448+
@mock.patch('crmsh.xmlutil.CrmMonXmlParser')
449449
@mock.patch('crmsh.log.LoggerUtils.status_long')
450450
@mock.patch('crmsh.ocfs2.OCFS2Manager._find_target_on_join')
451-
def test_join_ocfs2(self, mock_find, mock_long, mock_configured, mock_verify_packages, mock_is_mapper, mock_compare):
451+
def test_join_ocfs2(self, mock_find, mock_long, mock_parser, mock_verify_packages, mock_is_mapper, mock_compare):
452452
mock_find.return_value = "/dev/sda2"
453-
mock_configured.return_value = False
453+
mock_parser("node1").is_resource_configured.return_value = False
454454
mock_is_mapper.return_value = True
455455
self.ocfs2_inst3.join_ocfs2("node1")
456456
mock_find.assert_called_once_with("node1")
457-
mock_configured.assert_called_once_with(constants.LVMLOCKD_RA, "node1")
458457
mock_verify_packages.assert_called_once_with(False)
459458
mock_is_mapper.assert_called_once_with("/dev/sda2", "node1")
460459
mock_compare.assert_called_once_with(["/dev/sda2"], "node1")

test/unittests/test_qdevice.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,32 +38,30 @@ def test_evaluate_qdevice_quorum_effect_reload(mock_get_dict, mock_quorate):
3838
mock_quorate.assert_called_once_with(3, 2)
3939

4040

41-
@mock.patch('crmsh.xmlutil.CrmMonXmlParser.is_any_resource_running')
41+
@mock.patch('crmsh.xmlutil.CrmMonXmlParser')
4242
@mock.patch('crmsh.utils.calculate_quorate_status')
4343
@mock.patch('crmsh.utils.get_quorum_votes_dict')
44-
def test_evaluate_qdevice_quorum_effect_later(mock_get_dict, mock_quorate, mock_ra_running):
44+
def test_evaluate_qdevice_quorum_effect_later(mock_get_dict, mock_quorate, mock_parser):
4545
mock_get_dict.return_value = {'Expected': '2', 'Total': '2'}
4646
mock_quorate.return_value = False
47-
mock_ra_running.return_value = True
47+
mock_parser().is_any_resource_running.return_value = True
4848
res = qdevice.evaluate_qdevice_quorum_effect(qdevice.QDEVICE_REMOVE)
4949
assert res == qdevice.QdevicePolicy.QDEVICE_RESTART_LATER
5050
mock_get_dict.assert_called_once_with()
5151
mock_quorate.assert_called_once_with(2, 1)
52-
mock_ra_running.assert_called_once_with()
5352

5453

55-
@mock.patch('crmsh.xmlutil.CrmMonXmlParser.is_any_resource_running')
54+
@mock.patch('crmsh.xmlutil.CrmMonXmlParser')
5655
@mock.patch('crmsh.utils.calculate_quorate_status')
5756
@mock.patch('crmsh.utils.get_quorum_votes_dict')
58-
def test_evaluate_qdevice_quorum_effect(mock_get_dict, mock_quorate, mock_ra_running):
57+
def test_evaluate_qdevice_quorum_effect(mock_get_dict, mock_quorate, mock_parser):
5958
mock_get_dict.return_value = {'Expected': '2', 'Total': '2'}
6059
mock_quorate.return_value = False
61-
mock_ra_running.return_value = False
60+
mock_parser().is_any_resource_running.return_value = False
6261
res = qdevice.evaluate_qdevice_quorum_effect(qdevice.QDEVICE_REMOVE)
6362
assert res == qdevice.QdevicePolicy.QDEVICE_RESTART
6463
mock_get_dict.assert_called_once_with()
6564
mock_quorate.assert_called_once_with(2, 1)
66-
mock_ra_running.assert_called_once_with()
6765

6866

6967
@mock.patch('crmsh.lock.RemoteLock')

0 commit comments

Comments
 (0)