Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package crmsh for openSUSE:Factory checked in at 2024-08-29 15:44:09 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/crmsh (Old) and /work/SRC/openSUSE:Factory/.crmsh.new.2698 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "crmsh" Thu Aug 29 15:44:09 2024 rev:342 rq:1197372 version:5.0.0+20240829.9e723030 Changes: -------- --- /work/SRC/openSUSE:Factory/crmsh/crmsh.changes 2024-08-20 16:14:23.888653283 +0200 +++ /work/SRC/openSUSE:Factory/.crmsh.new.2698/crmsh.changes 2024-08-29 15:45:02.377399222 +0200 @@ -1,0 +2,25 @@ +Thu Aug 29 08:04:11 UTC 2024 - xli...@suse.com + +- Update to version 5.0.0+20240829.9e723030: + * Dev: behave: Add functional test for previous commit + * Fix: Don't add time units to values for existing CIB (bsc#1228817) + * Dev: unittest: Adjust unit test for previous commit + * Fix: utils: group check failure when os.getgroups() returns empty (bsc#1229030) + +------------------------------------------------------------------- +Mon Aug 26 08:19:08 UTC 2024 - xli...@suse.com + +- Update to version 5.0.0+20240826.84fcb728: + * Dev: unittests: Add unit tests for pickling CommandFailure + * Dev: unittests: Adjust unit test for previous commit + * Dev: sh: Ensure CommandFailure Exception is Picklable Across Processes (bsc#1229686) + * Fix: report: Error output of crm_verify should be recorded in report result (bsc#1229686) + +------------------------------------------------------------------- +Thu Aug 22 14:40:04 UTC 2024 - xli...@suse.com + +- Update to version 5.0.0+20240822.9ee6ca4d: + * Revert "Dev: doc: Add deprecated note for 'crm configure erase'" + * Revert "Dev: ui_configure: Deprecate configure erase sub-command" (bsc#1228713) + +------------------------------------------------------------------- Old: ---- crmsh-5.0.0+20240812.49aeacfa.tar.bz2 New: ---- crmsh-5.0.0+20240829.9e723030.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ crmsh.spec ++++++ --- /var/tmp/diff_new_pack.7iKKvd/_old 2024-08-29 15:45:02.885420315 +0200 +++ /var/tmp/diff_new_pack.7iKKvd/_new 2024-08-29 15:45:02.885420315 +0200 @@ -36,7 +36,7 @@ Summary: High Availability cluster command-line interface License: GPL-2.0-or-later Group: %{pkg_group} -Version: 5.0.0+20240812.49aeacfa +Version: 5.0.0+20240829.9e723030 Release: 0 URL: http://crmsh.github.io Source0: %{name}-%{version}.tar.bz2 ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.7iKKvd/_old 2024-08-29 15:45:02.929422142 +0200 +++ /var/tmp/diff_new_pack.7iKKvd/_new 2024-08-29 15:45:02.933422309 +0200 @@ -9,7 +9,7 @@ </service> <service name="tar_scm"> <param name="url">https://github.com/ClusterLabs/crmsh.git</param> - <param name="changesrevision">697716cd3b27ea6437aaee8e428d785fa6303818</param> + <param name="changesrevision">9e7230304124cdf2541d4ccb08d9f007cad9142c</param> </service> </servicedata> (No newline at EOF) ++++++ crmsh-5.0.0+20240812.49aeacfa.tar.bz2 -> crmsh-5.0.0+20240829.9e723030.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20240812.49aeacfa/crmsh/cibconfig.py new/crmsh-5.0.0+20240829.9e723030/crmsh/cibconfig.py --- old/crmsh-5.0.0+20240812.49aeacfa/crmsh/cibconfig.py 2024-08-12 14:28:46.000000000 +0200 +++ new/crmsh-5.0.0+20240829.9e723030/crmsh/cibconfig.py 2024-08-29 08:44:31.000000000 +0200 @@ -854,7 +854,8 @@ output: XML, obj_type, obj_id """ node = None - advised_op_values = False + # Flag to auto add adviced operation values and time units + auto_add = False default_promotable_meta = False comments = [] if isinstance(cli, str): @@ -864,12 +865,12 @@ else: # should be a pre-tokenized list utils.auto_convert_role = True if len(cli) >= 3 and cli[0] == "primitive" and cli[2].startswith("@"): - advised_op_values = False + auto_add = False default_promotable_meta = False else: - advised_op_values = config.core.add_advised_op_values + auto_add = config.core.add_advised_op_values default_promotable_meta = True - node = parse.parse(cli, comments=comments, ignore_empty=False, add_advised_op_values=advised_op_values) + node = parse.parse(cli, comments=comments, ignore_empty=False, auto_add=auto_add) if node is False: return None, None, None elif node is None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20240812.49aeacfa/crmsh/parse.py new/crmsh-5.0.0+20240829.9e723030/crmsh/parse.py --- old/crmsh-5.0.0+20240812.49aeacfa/crmsh/parse.py 2024-08-12 14:28:46.000000000 +0200 +++ new/crmsh-5.0.0+20240829.9e723030/crmsh/parse.py 2024-08-29 08:44:31.000000000 +0200 @@ -170,13 +170,13 @@ self.begin(cmd, min_args=min_args) return self.match_dispatch(errmsg="Unknown command") - def do_parse(self, cmd, ignore_empty, add_advised_op_values): + def do_parse(self, cmd, ignore_empty, auto_add): """ Called by CliParser. Calls parse() Parsers should pass their return value through this method. """ self.ignore_empty = ignore_empty - self.add_advised_op_values = add_advised_op_values + self.auto_add = auto_add out = self.parse(cmd) if self.has_tokens(): self.err("Unknown arguments: " + ' '.join(self._cmd[self._currtok:])) @@ -661,7 +661,7 @@ """ Add default operation actions advised values """ - if not self.add_advised_op_values or out.tag != "primitive": + if not self.auto_add or out.tag != "primitive": return ra_inst = ra.RAInfo(out.get('class'), out.get('type'), out.get('provider')) ra_actions_dict = ra_inst.actions() @@ -753,7 +753,7 @@ inst_attrs = xmlutil.child(container_node, name) # set meaningful id for port-mapping and storage-mapping # when the bundle is newly created - if self.add_advised_op_values: + if self.auto_add: id_str = f"{bundle_id}_{name.replace('-', '_')}_{index}" inst_attrs.set('id', id_str) child_flag = True @@ -794,7 +794,7 @@ if inst_attrs is not None: self.err(f"Attribute order error: {name} must appear before any instance attribute") value = nvp.get('value') - if name in ('interval', 'timeout'): + if name in ('interval', 'timeout') and self.auto_add: value = add_time_unit_if_needed(value) node.set(name, value) else: @@ -1794,7 +1794,7 @@ return ret -def parse(s, comments=None, ignore_empty=True, add_advised_op_values=False): +def parse(s, comments=None, ignore_empty=True, auto_add=False): ''' Input: a list of tokens (or a CLI format string). Return: a cibobject @@ -1840,7 +1840,7 @@ return False try: - ret = parser.do_parse(s, ignore_empty, add_advised_op_values) + ret = parser.do_parse(s, ignore_empty, auto_add) if ret is not None and len(comments) > 0: if ret.tag in constants.defaults_tags: xmlutil.stuff_comments(ret[0], comments) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20240812.49aeacfa/crmsh/report/collect.py new/crmsh-5.0.0+20240829.9e723030/crmsh/report/collect.py --- old/crmsh-5.0.0+20240812.49aeacfa/crmsh/report/collect.py 2024-08-12 14:28:46.000000000 +0200 +++ new/crmsh-5.0.0+20240829.9e723030/crmsh/report/collect.py 2024-08-29 08:44:31.000000000 +0200 @@ -375,8 +375,9 @@ crmutils.str2file(out, os.path.join(workdir, constants.CONFIGURE_SHOW_F)) cmd = f"crm_verify -V -x {cib_in_workdir}" - out = cluster_shell_inst.get_stdout_or_raise_error(cmd) - crmutils.str2file(out, os.path.join(workdir, constants.CRM_VERIFY_F)) + _, _, err = cluster_shell_inst.get_rc_stdout_stderr_without_input(None, cmd) + if err: + crmutils.str2file(err, os.path.join(workdir, constants.CRM_VERIFY_F)) def collect_config(context: core.Context) -> None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20240812.49aeacfa/crmsh/sh.py new/crmsh-5.0.0+20240829.9e723030/crmsh/sh.py --- old/crmsh-5.0.0+20240812.49aeacfa/crmsh/sh.py 2024-08-12 14:28:46.000000000 +0200 +++ new/crmsh-5.0.0+20240829.9e723030/crmsh/sh.py 2024-08-29 08:44:31.000000000 +0200 @@ -87,6 +87,14 @@ super().__init__("Failed to run command as {}@{}: '{}': {}".format(user, host, cmd, msg), cmd) self.host = host self.user = user + self.cmd = cmd + self.msg = msg + + def __reduce__(self): + ''' + Return a tuple that Python will use for pickling this object + ''' + return CommandFailure, (self.cmd, self.host, self.user, self.msg) class Utils: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20240812.49aeacfa/crmsh/ui_configure.py new/crmsh-5.0.0+20240829.9e723030/crmsh/ui_configure.py --- old/crmsh-5.0.0+20240812.49aeacfa/crmsh/ui_configure.py 2024-08-12 14:28:46.000000000 +0200 +++ new/crmsh-5.0.0+20240829.9e723030/crmsh/ui_configure.py 2024-08-29 08:44:31.000000000 +0200 @@ -885,9 +885,6 @@ @command.completers(compl.choice(['nodes'])) def do_erase(self, context, nodes=None): "usage: erase [nodes]" - if not options.regression_tests: - logger.warning("`crm configure erase` is deprecated. The replacement could be `crm cluster remove [node]`") - return True cib_factory.ensure_cib_updated() if nodes is None: return cib_factory.erase() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20240812.49aeacfa/crmsh/utils.py new/crmsh-5.0.0+20240829.9e723030/crmsh/utils.py --- old/crmsh-5.0.0+20240812.49aeacfa/crmsh/utils.py 2024-08-12 14:28:46.000000000 +0200 +++ new/crmsh-5.0.0+20240829.9e723030/crmsh/utils.py 2024-08-29 08:44:31.000000000 +0200 @@ -19,6 +19,7 @@ import argparse import random import string +import pwd import grp import functools import gzip @@ -466,12 +467,10 @@ if isinstance(user, int): uid = user else: - import pwd uid = pwd.getpwnam(user).pw_uid if isinstance(group, int): gid = group else: - import grp gid = grp.getgrnam(group).gr_gid try: os.chown(path, uid, gid) @@ -2988,7 +2987,7 @@ """ Check if current user is in haclient group """ - return constants.HA_GROUP in [grp.getgrgid(g).gr_name for g in os.getgroups()] + return grp.getgrnam(constants.HA_GROUP).gr_gid in (os.getgroups() + [os.getegid()]) def check_user_access(level_name): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20240812.49aeacfa/doc/crm.8.adoc new/crmsh-5.0.0+20240829.9e723030/doc/crm.8.adoc --- old/crmsh-5.0.0+20240812.49aeacfa/doc/crm.8.adoc 2024-08-12 14:28:46.000000000 +0200 +++ new/crmsh-5.0.0+20240829.9e723030/doc/crm.8.adoc 2024-08-29 08:44:31.000000000 +0200 @@ -2875,12 +2875,6 @@ [[cmdhelp_configure_erase,erase the CIB]] ==== `erase` -.Deprecation note -**************************** -`crm configure erase` is deprecated. -The replacement could be `crm cluster remove [node]` -**************************** - The `erase` clears all configuration. Apart from nodes. To remove nodes, you have to specify an additional keyword `nodes`. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20240812.49aeacfa/test/features/resource_set.feature new/crmsh-5.0.0+20240829.9e723030/test/features/resource_set.feature --- old/crmsh-5.0.0+20240812.49aeacfa/test/features/resource_set.feature 2024-08-12 14:28:46.000000000 +0200 +++ new/crmsh-5.0.0+20240829.9e723030/test/features/resource_set.feature 2024-08-29 08:44:31.000000000 +0200 @@ -193,3 +193,11 @@ When Run "crm configure rsc_template dummy_template ocf:pacemaker:Dummy op monitor interval=12s" on "hanode1" And Try "crm configure primitive d8 @dummy_template params passwd=123" on "hanode1" Then Expected "got no meta-data, does this RA exist" not in stderr + + @clean + Scenario: Don't add time units to values for existing CIB (bsc#1228817) + When Run "crm configure show xml d > /tmp/d.xml" on "hanode1" + And Run "sed -i '/<op name="monitor"/s/timeout="20s"/timeout="20"/' /tmp/d.xml" on "hanode1" + And Run "crm configure load xml update /tmp/d.xml" on "hanode1" + And Try "crm configure show|grep -E "^xml <primitive"" + Then Expected return code is "1" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20240812.49aeacfa/test/unittests/test_report_collect.py new/crmsh-5.0.0+20240829.9e723030/test/unittests/test_report_collect.py --- old/crmsh-5.0.0+20240812.49aeacfa/test/unittests/test_report_collect.py 2024-08-12 14:28:46.000000000 +0200 +++ new/crmsh-5.0.0+20240829.9e723030/test/unittests/test_report_collect.py 2024-08-29 08:44:31.000000000 +0200 @@ -334,16 +334,17 @@ mock_isfile.return_value = True mock_run_inst = mock.Mock() mock_run.return_value = mock_run_inst - mock_run_inst.get_stdout_or_raise_error.side_effect = ["data1", "data2"] + mock_run_inst.get_stdout_or_raise_error.return_value = "data1" + mock_run_inst.get_rc_stdout_stderr_without_input.return_value = (0, "data2", "error") collect.consume_cib_in_workdir("/workdir") mock_isfile.assert_called_once_with(f"/workdir/{constants.CIB_F}") - mock_run_inst.get_stdout_or_raise_error.assert_has_calls([ - mock.call('CIB_file=/workdir/cib.xml crm configure show'), - mock.call('crm_verify -V -x /workdir/cib.xml') - ]) + cmd1 = "CIB_file=/workdir/cib.xml crm configure show" + mock_run_inst.get_stdout_or_raise_error.assert_called_once_with(cmd1) + cmd2 = f"crm_verify -V -x /workdir/cib.xml" + mock_run_inst.get_rc_stdout_stderr_without_input.assert_called_once_with(None, cmd2) mock_str2file.assert_has_calls([ mock.call("data1", f"/workdir/{constants.CONFIGURE_SHOW_F}"), - mock.call("data2", f"/workdir/{constants.CRM_VERIFY_F}") + mock.call("error", f"/workdir/{constants.CRM_VERIFY_F}") ]) @mock.patch('crmsh.report.utils.real_path') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20240812.49aeacfa/test/unittests/test_sh.py new/crmsh-5.0.0+20240829.9e723030/test/unittests/test_sh.py --- old/crmsh-5.0.0+20240812.49aeacfa/test/unittests/test_sh.py 2024-08-12 14:28:46.000000000 +0200 +++ new/crmsh-5.0.0+20240829.9e723030/test/unittests/test_sh.py 2024-08-29 08:44:31.000000000 +0200 @@ -1,5 +1,6 @@ import subprocess import unittest +import pickle from unittest import mock import crmsh.sh @@ -193,3 +194,33 @@ stdin=subprocess.PIPE, ) self.cluster_shell.local_shell.su_subprocess_run.assert_not_called() + + +class TestCommandFailurePickling(unittest.TestCase): + def test_pickling_unpickling(self): + # Create an instance of CommandFailure + original = crmsh.sh.CommandFailure(cmd="ls", host="localhost", user="root", msg="Permission denied") + # Pickle the object + pickled = pickle.dumps(original) + # Unpickle the object + unpickled = pickle.loads(pickled) + + # Assert that the unpickled object retains the same attributes as the original + self.assertEqual(original.cmd, unpickled.cmd) + self.assertEqual(original.host, unpickled.host) + self.assertEqual(original.user, unpickled.user) + self.assertEqual(original.msg, unpickled.msg) + + def test_pickling_unpickling_with_none_values(self): + # Create an instance of CommandFailure with None values for optional parameters + original = crmsh.sh.CommandFailure(cmd="ls", host=None, user=None, msg="No such file or directory") + # Pickle the object + pickled = pickle.dumps(original) + # Unpickle the object + unpickled = pickle.loads(pickled) + + # Assert that the unpickled object retains the same attributes, including None values + self.assertEqual(original.cmd, unpickled.cmd) + self.assertEqual(original.host, unpickled.host) + self.assertEqual(original.user, unpickled.user) + self.assertEqual(original.msg, unpickled.msg) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-5.0.0+20240812.49aeacfa/test/unittests/test_utils.py new/crmsh-5.0.0+20240829.9e723030/test/unittests/test_utils.py --- old/crmsh-5.0.0+20240812.49aeacfa/test/unittests/test_utils.py 2024-08-12 14:28:46.000000000 +0200 +++ new/crmsh-5.0.0+20240829.9e723030/test/unittests/test_utils.py 2024-08-29 08:44:31.000000000 +0200 @@ -1292,15 +1292,16 @@ mock_run.assert_called_once_with("sudo -S -k -n id -u") -@mock.patch('grp.getgrgid') +@mock.patch('grp.getgrnam') +@mock.patch('os.getegid') @mock.patch('os.getgroups') -def test_in_haclient(mock_group, mock_getgrgid): - mock_group.return_value = [90, 100] - mock_getgrgid_inst1 = mock.Mock(gr_name=constants.HA_GROUP) - mock_getgrgid_inst2 = mock.Mock(gr_name="other") - mock_getgrgid.side_effect = [mock_getgrgid_inst1, mock_getgrgid_inst2] +def test_in_haclient(mock_getgroups, mock_getegid, mock_getgrnam): + mock_getgroups.return_value = [90] + mock_getegid.return_value = 90 + mock_getgrnam_inst = mock.Mock(gr_gid=90) + mock_getgrnam.return_value = mock_getgrnam_inst assert utils.in_haclient() is True - mock_group.assert_called_once_with() + mock_getgrnam.assert_called_once_with(constants.HA_GROUP) @mock.patch('crmsh.utils.in_haclient')