Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package crmsh for openSUSE:Factory checked in at 2023-03-22 22:31:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/crmsh (Old) and /work/SRC/openSUSE:Factory/.crmsh.new.31432 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "crmsh" Wed Mar 22 22:31:48 2023 rev:287 rq:1073807 version:4.5.0+20230321.97bd51bb Changes: -------- --- /work/SRC/openSUSE:Factory/crmsh/crmsh.changes 2023-03-21 17:42:57.870242491 +0100 +++ /work/SRC/openSUSE:Factory/.crmsh.new.31432/crmsh.changes 2023-03-22 22:32:36.478786759 +0100 @@ -1,0 +2,18 @@ +Tue Mar 21 15:30:12 UTC 2023 - xli...@suse.com + +- Update to version 4.5.0+20230321.97bd51bb: + * Dev: behave: Split the time cost case into two cases + * Dev: unittest: Adjust unit test for previous changes + * Dev: remove 'sudo' prefix internally + +------------------------------------------------------------------- +Tue Mar 21 13:34:38 UTC 2023 - xli...@suse.com + +- Update to version 4.5.0+20230321.eda6d2d9: + * Dev: workflows: Disable resource_failcount.feature temporarily + * Dev: behave: Add test case for 'Passwordless for root, not for sudoer(bsc#1209193)' + * Dev: behave: check user shell after init and join, without upgrading + * Dev: bootstrap: Change user shell for hacluster on remote node, in init_ssh_impl function + * Dev: behave: Add functional test to check user shell for hacluster + +------------------------------------------------------------------- Old: ---- crmsh-4.5.0+20230320.5e777809.tar.bz2 New: ---- crmsh-4.5.0+20230321.97bd51bb.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ crmsh.spec ++++++ --- /var/tmp/diff_new_pack.aSrJAW/_old 2023-03-22 22:32:36.982789295 +0100 +++ /var/tmp/diff_new_pack.aSrJAW/_new 2023-03-22 22:32:36.986789315 +0100 @@ -36,7 +36,7 @@ Summary: High Availability cluster command-line interface License: GPL-2.0-or-later Group: %{pkg_group} -Version: 4.5.0+20230320.5e777809 +Version: 4.5.0+20230321.97bd51bb Release: 0 URL: http://crmsh.github.io Source0: %{name}-%{version}.tar.bz2 ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.aSrJAW/_old 2023-03-22 22:32:37.030789536 +0100 +++ /var/tmp/diff_new_pack.aSrJAW/_new 2023-03-22 22:32:37.030789536 +0100 @@ -9,7 +9,7 @@ </service> <service name="tar_scm"> <param name="url">https://github.com/ClusterLabs/crmsh.git</param> - <param name="changesrevision">4697fb58457de1acf83640116e145612d97e593f</param> + <param name="changesrevision">e751cc863b8189ee541fd84a72bf1584d163ffcf</param> </service> </servicedata> (No newline at EOF) ++++++ crmsh-4.5.0+20230320.5e777809.tar.bz2 -> crmsh-4.5.0+20230321.97bd51bb.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.5.0+20230320.5e777809/.github/workflows/crmsh-ci.yml new/crmsh-4.5.0+20230321.97bd51bb/.github/workflows/crmsh-ci.yml --- old/crmsh-4.5.0+20230320.5e777809/.github/workflows/crmsh-ci.yml 2023-03-20 08:49:02.000000000 +0100 +++ new/crmsh-4.5.0+20230321.97bd51bb/.github/workflows/crmsh-ci.yml 2023-03-21 16:02:58.000000000 +0100 @@ -74,7 +74,19 @@ echo '{ "exec-opts": ["native.cgroupdriver=systemd"] }' | sudo tee /etc/docker/daemon.json sudo systemctl restart docker.service index=`$GET_INDEX_OF bootstrap_bugs` - $DOCKER_SCRIPT $index && $DOCKER_SCRIPT -d && $DOCKER_SCRIPT $index -u + $DOCKER_SCRIPT $index + + functional_test_bootstrap_bugs_non_root: + runs-on: ubuntu-20.04 + timeout-minutes: 40 + steps: + - uses: actions/checkout@v3 + - name: functional test for bootstrap bugs, under non root user + run: | + echo '{ "exec-opts": ["native.cgroupdriver=systemd"] }' | sudo tee /etc/docker/daemon.json + sudo systemctl restart docker.service + index=`$GET_INDEX_OF bootstrap_bugs` + $DOCKER_SCRIPT $index -u functional_test_bootstrap_common: runs-on: ubuntu-20.04 @@ -86,7 +98,19 @@ echo '{ "exec-opts": ["native.cgroupdriver=systemd"] }' | sudo tee /etc/docker/daemon.json sudo systemctl restart docker.service index=`$GET_INDEX_OF bootstrap_init_join_remove` - $DOCKER_SCRIPT $index && $DOCKER_SCRIPT -d && $DOCKER_SCRIPT $index -u + $DOCKER_SCRIPT $index + + functional_test_bootstrap_common_non_root: + runs-on: ubuntu-20.04 + timeout-minutes: 40 + steps: + - uses: actions/checkout@v3 + - name: functional test for bootstrap common, under non root user + run: | + echo '{ "exec-opts": ["native.cgroupdriver=systemd"] }' | sudo tee /etc/docker/daemon.json + sudo systemctl restart docker.service + index=`$GET_INDEX_OF bootstrap_init_join_remove` + $DOCKER_SCRIPT $index -u functional_test_bootstrap_options: runs-on: ubuntu-20.04 @@ -110,7 +134,19 @@ echo '{ "exec-opts": ["native.cgroupdriver=systemd"] }' | sudo tee /etc/docker/daemon.json sudo systemctl restart docker.service index=`$GET_INDEX_OF qdevice_setup_remove` - $DOCKER_SCRIPT $index && $DOCKER_SCRIPT -d && $DOCKER_SCRIPT $index -u + $DOCKER_SCRIPT $index + + functional_test_qdevice_setup_remove_non_root: + runs-on: ubuntu-20.04 + timeout-minutes: 40 + steps: + - uses: actions/checkout@v3 + - name: functional test for qdevice setup and remove, under non root user + run: | + echo '{ "exec-opts": ["native.cgroupdriver=systemd"] }' | sudo tee /etc/docker/daemon.json + sudo systemctl restart docker.service + index=`$GET_INDEX_OF qdevice_setup_remove` + $DOCKER_SCRIPT $index -u functional_test_qdevice_options: runs-on: ubuntu-20.04 @@ -157,7 +193,7 @@ run: | echo '{ "exec-opts": ["native.cgroupdriver=systemd"] }' | sudo tee /etc/docker/daemon.json sudo systemctl restart docker.service - index=`$GET_INDEX_OF resource_failcount resource_set` + index=`$GET_INDEX_OF resource_set` $DOCKER_SCRIPT $index && $DOCKER_SCRIPT -d && $DOCKER_SCRIPT $index -u functional_test_configure_sublevel: @@ -244,9 +280,12 @@ unit_test, functional_test_crm_report_bugs, functional_test_bootstrap_bugs, + functional_test_bootstrap_bugs_non_root, functional_test_bootstrap_common, + functional_test_bootstrap_common_non_root, functional_test_bootstrap_options, functional_test_qdevice_setup_remove, + functional_test_qdevice_setup_remove_non_root, functional_test_qdevice_options, functional_test_qdevice_validate, functional_test_qdevice_user_case, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.5.0+20230320.5e777809/crmsh/bootstrap.py new/crmsh-4.5.0+20230321.97bd51bb/crmsh/bootstrap.py --- old/crmsh-4.5.0+20230320.5e777809/crmsh/bootstrap.py 2023-03-20 08:49:02.000000000 +0100 +++ new/crmsh-4.5.0+20230321.97bd51bb/crmsh/bootstrap.py 2023-03-21 16:02:58.000000000 +0100 @@ -695,7 +695,6 @@ def init_firewall_firewalld(tcp, udp): has_firewalld = utils.service_is_active("firewalld") cmdbase = 'firewall-cmd --zone=public --permanent ' if has_firewalld else 'firewall-offline-cmd --zone=public ' - cmdbase = 'sudo ' + cmdbase def cmd(args): if not invokerc(cmdbase + args): @@ -708,7 +707,7 @@ cmd("--add-port={}/udp".format(p)) if has_firewalld: - if not invokerc("sudo firewall-cmd --reload"): + if not invokerc("firewall-cmd --reload"): utils.fatal("Failed to reload firewall configuration.") def init_firewall_ufw(tcp, udp): @@ -766,7 +765,7 @@ # reset password, but only if it's not already set # (We still need the hacluster for the hawk). - _rc, outp = utils.get_stdout("sudo passwd -S hacluster") + _rc, outp = utils.get_stdout("passwd -S hacluster") ps = outp.strip().split()[1] pass_msg = "" if ps not in ("P", "PS"): @@ -778,7 +777,7 @@ pass_msg = ", password 'linux'" # evil, but necessary - invoke("sudo rm -f /var/lib/heartbeat/crm/* /var/lib/pacemaker/cib/*") + invoke("rm -f /var/lib/heartbeat/crm/* /var/lib/pacemaker/cib/*") # only try to start hawk if hawk is installed if utils.service_is_available("hawk.service"): @@ -837,9 +836,10 @@ def append(fromfile, tofile, remote=None): - cmd = "sudo bash -c 'cat {} >> {}'".format(fromfile, tofile) + cmd = "cat {} >> {}".format(fromfile, tofile) utils.get_stdout_or_raise_error(cmd, remote=remote) + def append_unique(fromfile, tofile, user=None, remote=None, from_local=False): """ Append unique content from fromfile to tofile @@ -889,6 +889,7 @@ # After this, login to remote_node is passwordless public_key_list.append(swap_public_ssh_key(node, local_user, remote_user, local_user, remote_user, add=True)) hacluster_public_key_list.append(swap_public_ssh_key(node, 'hacluster', 'hacluster', local_user, remote_user, add=True)) + change_user_shell('hacluster', node) if len(node_list) > 1: shell_script = _merge_authorized_keys(public_key_list) hacluster_shell_script = _merge_authorized_keys(hacluster_public_key_list) @@ -981,7 +982,7 @@ return rc == 0 else: with open(passwd_file) as f: - return re.search(pattern, f.read()) + return re.search(pattern, f.read()) is not None def change_user_shell(user, remote=None): @@ -1132,9 +1133,9 @@ if not confirm("csync2 is already configured - overwrite?"): return - invoke("sudo rm", "-f", CSYNC2_KEY) + invoke("rm", "-f", CSYNC2_KEY) logger.debug("Generating csync2 shared key") - if not invokerc("sudo csync2", "-k", CSYNC2_KEY): + if not invokerc("csync2", "-k", CSYNC2_KEY): utils.fatal("Can't create csync2 key {}".format(CSYNC2_KEY)) csync2_file_list = "" @@ -1166,7 +1167,7 @@ if _context.skip_csync2: csync2_update("/") else: - invoke("sudo csync2", "-cr", "/") + invoke("csync2", "-cr", "/") def csync2_update(path): @@ -1175,11 +1176,11 @@ If there was a conflict, use '-f' to force this side to win ''' - invoke("sudo csync2 -rm {}".format(path)) - if invokerc("sudo csync2 -rxv {}".format(path)): + invoke("csync2 -rm {}".format(path)) + if invokerc("csync2 -rxv {}".format(path)): return - invoke("sudo csync2 -rf {}".format(path)) - if not invokerc("sudo csync2 -rxv {}".format(path)): + invoke("csync2 -rf {}".format(path)) + if not invokerc("csync2 -rxv {}".format(path)): logger.warning("{} was not synced".format(path)) @@ -1222,7 +1223,7 @@ if not confirm("%s already exists - overwrite?" % (COROSYNC_AUTH)): return utils.rmfile(COROSYNC_AUTH) - invoke("sudo corosync-keygen -l -k {}".format(COROSYNC_AUTH)) + invoke("corosync-keygen -l -k {}".format(COROSYNC_AUTH)) def init_remote_auth(): @@ -1236,7 +1237,7 @@ pcmk_remote_dir = os.path.dirname(PCMK_REMOTE_AUTH) utils.mkdirs_owned(pcmk_remote_dir, mode=0o750, gid="haclient") - if not invokerc("sudo dd if=/dev/urandom of={} bs=4096 count=1".format(PCMK_REMOTE_AUTH)): + if not invokerc("dd if=/dev/urandom of={} bs=4096 count=1".format(PCMK_REMOTE_AUTH)): logger.warning("Failed to create pacemaker authkey: {}".format(PCMK_REMOTE_AUTH)) utils.chown(PCMK_REMOTE_AUTH, _context.current_user, "haclient") utils.chmod(PCMK_REMOTE_AUTH, 0o640) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.5.0+20230320.5e777809/crmsh/sbd.py new/crmsh-4.5.0+20230321.97bd51bb/crmsh/sbd.py --- old/crmsh-4.5.0+20230320.5e777809/crmsh/sbd.py 2023-03-20 08:49:02.000000000 +0100 +++ new/crmsh-4.5.0+20230321.97bd51bb/crmsh/sbd.py 2023-03-21 16:02:58.000000000 +0100 @@ -90,7 +90,7 @@ """ Get msgwait for sbd device """ - out = utils.get_stdout_or_raise_error("sudo sbd -d {} dump".format(dev)) + out = utils.get_stdout_or_raise_error("sbd -d {} dump".format(dev)) # Format like "Timeout (msgwait) : 30" res = re.search("\(msgwait\)\s+:\s+(\d+)", out) if not res: @@ -292,7 +292,7 @@ """ Get UUID for specific device and node """ - out = utils.get_stdout_or_raise_error("sudo sbd -d {} dump".format(dev), remote=node) + out = utils.get_stdout_or_raise_error("sbd -d {} dump".format(dev), remote=node) res = re.search("UUID\s*:\s*(.*)\n", out) if not res: raise ValueError("Cannot find sbd device UUID for {}".format(dev)) @@ -419,7 +419,7 @@ for dev in self._sbd_devices: if dev in self.no_overwrite_map and self.no_overwrite_map[dev]: continue - rc, _, err = bootstrap.invoke("sudo sbd {} -d {} create".format(opt, dev)) + rc, _, err = bootstrap.invoke("sbd {} -d {} create".format(opt, dev)) if not rc: utils.fatal("Failed to initialize SBD device {}: {}".format(dev, err)) @@ -478,7 +478,7 @@ self._restart_cluster_and_configure_sbd_ra() else: # in init process - bootstrap.invoke("sudo systemctl enable sbd.service") + bootstrap.invoke("systemctl enable sbd.service") def _warn_diskless_sbd(self, peer=None): """ @@ -509,7 +509,7 @@ self._watchdog_inst.init_watchdog() self._get_sbd_device() if not self._sbd_devices and not self.diskless_sbd: - bootstrap.invoke("sudo systemctl disable sbd.service") + bootstrap.invoke("systemctl disable sbd.service") return self._warn_diskless_sbd() self._initialize_sbd() @@ -552,7 +552,7 @@ if not utils.package_is_installed("sbd"): return if not os.path.exists(SYSCONFIG_SBD) or not utils.service_is_enabled("sbd.service", peer_host): - bootstrap.invoke("sudo systemctl disable sbd.service") + bootstrap.invoke("systemctl disable sbd.service") return self._watchdog_inst = Watchdog(remote_user=remote_user, peer_host=peer_host) self._watchdog_inst.join_watchdog() @@ -562,7 +562,7 @@ else: self._warn_diskless_sbd(peer_host) logger.info("Got {}SBD configuration".format("" if dev_list else "diskless ")) - bootstrap.invoke("sudo systemctl enable sbd.service") + bootstrap.invoke("systemctl enable sbd.service") @classmethod def verify_sbd_device(cls): @@ -617,6 +617,6 @@ """ Check if sbd device already initialized """ - cmd = "sudo sbd -d {} dump".format(dev) + cmd = "sbd -d {} dump".format(dev) rc, _, _ = utils.get_stdout_stderr(cmd) return rc == 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.5.0+20230320.5e777809/crmsh/utils.py new/crmsh-4.5.0+20230321.97bd51bb/crmsh/utils.py --- old/crmsh-4.5.0+20230320.5e777809/crmsh/utils.py 2023-03-20 08:49:02.000000000 +0100 +++ new/crmsh-4.5.0+20230321.97bd51bb/crmsh/utils.py 2023-03-21 16:02:58.000000000 +0100 @@ -2253,9 +2253,9 @@ Detect if in AWS """ # will match on xen instances - xen_test = get_stdout_or_raise_error("sudo dmidecode -s system-version").lower() + xen_test = get_stdout_or_raise_error("dmidecode -s system-version").lower() # will match on nitro/kvm instances - kvm_test = get_stdout_or_raise_error("sudo dmidecode -s system-manufacturer").lower() + kvm_test = get_stdout_or_raise_error("dmidecode -s system-manufacturer").lower() if "amazon" in xen_test or "amazon" in kvm_test: return True return False @@ -2270,8 +2270,8 @@ # might return American Megatrends Inc. instead of Microsoft Corporation in Azure. # The better way is to check the result of dmidecode -s chassis-asset-tag is # 7783-7084-3265-9085-8269-3286-77, aka. the ascii code of MSFT AZURE VM - system_manufacturer = get_stdout_or_raise_error("sudo dmidecode -s system-manufacturer") - chassis_asset_tag = get_stdout_or_raise_error("sudo dmidecode -s chassis-asset-tag") + system_manufacturer = get_stdout_or_raise_error("dmidecode -s system-manufacturer") + chassis_asset_tag = get_stdout_or_raise_error("dmidecode -s chassis-asset-tag") if "microsoft corporation" in system_manufacturer.lower() or \ ''.join([chr(int(n)) for n in re.findall("\d\d", chassis_asset_tag)]) == "MSFT AZURE VM": # To detect azure we also need to make an API request @@ -2287,7 +2287,7 @@ """ Detect if in GCP """ - bios_vendor = get_stdout_or_raise_error("sudo dmidecode -s bios-vendor") + bios_vendor = get_stdout_or_raise_error("dmidecode -s bios-vendor") if "Google" in bios_vendor: # To detect GCP we also need to make an API request result = _cloud_metadata_request( @@ -2742,9 +2742,9 @@ if not detect_file(target_file, remote=remote): return False - cmd = "sudo cat {}".format(target_file) + cmd = "cat {}".format(target_file) target_data = get_stdout_or_raise_error(cmd, remote=remote) - cmd = "sudo cat {}".format(source_file) + cmd = "cat {}".format(source_file) source_data = get_stdout_or_raise_error(cmd, remote=None if source_local else remote) return source_data in target_data @@ -3423,7 +3423,7 @@ """ rc = False if not remote: - cmd = "sudo test -f {}".format(_file) + cmd = "test -f {}".format(_file) else: # FIXME cmd = "ssh {} {}@{} 'test -f {}'".format(SSH_OPTION, user_of(remote), remote, _file) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.5.0+20230320.5e777809/crmsh/watchdog.py new/crmsh-4.5.0+20230321.97bd51bb/crmsh/watchdog.py --- old/crmsh-4.5.0+20230320.5e777809/crmsh/watchdog.py 2023-03-20 08:49:02.000000000 +0100 +++ new/crmsh-4.5.0+20230321.97bd51bb/crmsh/watchdog.py 2023-03-21 16:02:58.000000000 +0100 @@ -30,7 +30,7 @@ """ Use wdctl to verify watchdog device """ - rc, _, err = utils.get_stdout_stderr("sudo wdctl {}".format(dev)) + rc, _, err = utils.get_stdout_stderr("wdctl {}".format(dev)) if rc != 0: if ignore_error: return False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.5.0+20230320.5e777809/test/features/bootstrap_bugs.feature new/crmsh-4.5.0+20230321.97bd51bb/test/features/bootstrap_bugs.feature --- old/crmsh-4.5.0+20230320.5e777809/test/features/bootstrap_bugs.feature 2023-03-20 08:49:02.000000000 +0100 +++ new/crmsh-4.5.0+20230321.97bd51bb/test/features/bootstrap_bugs.feature 2023-03-21 16:02:58.000000000 +0100 @@ -136,3 +136,22 @@ Then Service "corosync" is "started" on "hanode1" When Run "crm cluster stop" on "hanode1" Then Service "corosync" is "stopped" on "hanode1" + + @clean + @skip_non_root + Scenario: Passwordless for root, not for sudoer(bsc#1209193) + Given Cluster service is "stopped" on "hanode1" + And Cluster service is "stopped" on "hanode2" + When Run "crm cluster init -y" on "hanode1" + Then Cluster service is "started" on "hanode1" + When Run "crm cluster join -c hanode1 -y" on "hanode2" + Then Cluster service is "started" on "hanode2" + When Run "useradd -m -s /bin/bash xin" on "hanode1" + When Run "echo "xin ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/xin" on "hanode1" + When Run "rm -f /root/.config/crm/crm.conf" on "hanode1" + When Run "useradd -m -s /bin/bash xin" on "hanode2" + When Run "echo "xin ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/xin" on "hanode2" + When Run "rm -f /root/.config/crm/crm.conf" on "hanode2" + When Run "su xin -c "sudo crm cluster run 'touch /tmp/1209193'"" on "hanode1" + And Run "test -f /tmp/1209193" on "hanode1" + And Run "test -f /tmp/1209193" on "hanode2" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.5.0+20230320.5e777809/test/features/bootstrap_init_join_remove.feature new/crmsh-4.5.0+20230321.97bd51bb/test/features/bootstrap_init_join_remove.feature --- old/crmsh-4.5.0+20230320.5e777809/test/features/bootstrap_init_join_remove.feature 2023-03-20 08:49:02.000000000 +0100 +++ new/crmsh-4.5.0+20230321.97bd51bb/test/features/bootstrap_init_join_remove.feature 2023-03-21 16:02:58.000000000 +0100 @@ -152,6 +152,7 @@ Then Directory "/var/lib/corosync/" is empty on "hanode1" Scenario: Check hacluster's passwordless configuration on 2 nodes + Then Check user shell for hacluster between "hanode1 hanode2" Then Check passwordless for hacluster between "hanode1 hanode2" Scenario: Check hacluster's passwordless configuration in old cluster, 2 nodes @@ -171,6 +172,7 @@ When Run "crm cluster join -c hanode1 -y" on "hanode3" Then Cluster service is "started" on "hanode3" And Online nodes are "hanode1 hanode2 hanode3" + And Check user shell for hacluster between "hanode1 hanode2 hanode3" And Check passwordless for hacluster between "hanode1 hanode2 hanode3" Scenario: Check hacluster's passwordless configuration in old cluster, 3 nodes @@ -181,3 +183,21 @@ Then Cluster service is "started" on "hanode3" And Online nodes are "hanode1 hanode2 hanode3" And Check passwordless for hacluster between "hanode1 hanode2 hanode3" + + Scenario: Check hacluster's user shell + Given Cluster service is "stopped" on "hanode3" + When Run "crm cluster join -c hanode1 -y" on "hanode3" + Then Cluster service is "started" on "hanode3" + And Online nodes are "hanode1 hanode2 hanode3" + When Run "rm -rf /var/lib/heartbeat/cores/hacluster/.ssh" on "hanode1" + And Run "rm -rf /var/lib/heartbeat/cores/hacluster/.ssh" on "hanode2" + And Run "rm -rf /var/lib/heartbeat/cores/hacluster/.ssh" on "hanode3" + And Run "usermod -s /usr/sbin/nologin hacluster" on "hanode1" + And Run "usermod -s /usr/sbin/nologin hacluster" on "hanode2" + And Run "usermod -s /usr/sbin/nologin hacluster" on "hanode3" + And Run "rm -f /var/lib/crmsh/upgrade_seq" on "hanode1" + And Run "rm -f /var/lib/crmsh/upgrade_seq" on "hanode2" + And Run "rm -f /var/lib/crmsh/upgrade_seq" on "hanode3" + And Run "crm status" on "hanode1" + Then Check user shell for hacluster between "hanode1 hanode2 hanode3" + Then Check passwordless for hacluster between "hanode1 hanode2 hanode3" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.5.0+20230320.5e777809/test/features/environment.py new/crmsh-4.5.0+20230321.97bd51bb/test/features/environment.py --- old/crmsh-4.5.0+20230320.5e777809/test/features/environment.py 2023-03-20 08:49:02.000000000 +0100 +++ new/crmsh-4.5.0+20230321.97bd51bb/test/features/environment.py 2023-03-21 16:02:58.000000000 +0100 @@ -1,6 +1,6 @@ import logging import re -from crmsh import utils, parallax +from crmsh import utils, parallax, userdir import time @@ -32,3 +32,7 @@ if utils.get_dc(): break utils.get_stdout_or_raise_error("sudo crm cluster stop --all") + if tag == "skip_non_root": + sudoer = userdir.get_sudoer() + if sudoer or userdir.getuser() != 'root': + context.scenario.skip() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.5.0+20230320.5e777809/test/features/steps/step_implementation.py new/crmsh-4.5.0+20230321.97bd51bb/test/features/steps/step_implementation.py --- old/crmsh-4.5.0+20230320.5e777809/test/features/steps/step_implementation.py 2023-03-20 08:49:02.000000000 +0100 +++ new/crmsh-4.5.0+20230321.97bd51bb/test/features/steps/step_implementation.py 2023-03-21 16:02:58.000000000 +0100 @@ -6,7 +6,7 @@ import behave from behave import given, when, then -from crmsh import corosync, parallax, sbd, userdir +from crmsh import corosync, parallax, sbd, userdir, bootstrap from crmsh import utils as crmutils from utils import check_cluster_state, check_service_state, online, run_command, me, \ run_command_local_or_remote, file_in_archive, \ @@ -494,3 +494,13 @@ cmd = f"ssh {node} \"{cmd}\"" context.logger.info(f"\nRun cmd: {cmd}") run_command(context, cmd) + +@then('Check user shell for hacluster between "{nodelist}"') +def step_impl(context, nodelist): + if userdir.getuser() != 'root' or userdir.get_sudoer(): + return True + for node in nodelist.split(): + if node == me(): + assert bootstrap.is_nologin('hacluster') is False + else: + assert bootstrap.is_nologin('hacluster', node) is False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.5.0+20230320.5e777809/test/unittests/test_bootstrap.py new/crmsh-4.5.0+20230321.97bd51bb/test/unittests/test_bootstrap.py --- old/crmsh-4.5.0+20230320.5e777809/test/unittests/test_bootstrap.py 2023-03-20 08:49:02.000000000 +0100 +++ new/crmsh-4.5.0+20230321.97bd51bb/test/unittests/test_bootstrap.py 2023-03-21 16:02:58.000000000 +0100 @@ -756,8 +756,8 @@ def test_csync2_update_no_conflicts(self, mock_invoke, mock_invokerc): mock_invokerc.return_value = True bootstrap.csync2_update("/etc/corosync.conf") - mock_invoke.assert_called_once_with("sudo csync2 -rm /etc/corosync.conf") - mock_invokerc.assert_called_once_with("sudo csync2 -rxv /etc/corosync.conf") + mock_invoke.assert_called_once_with("csync2 -rm /etc/corosync.conf") + mock_invokerc.assert_called_once_with("csync2 -rxv /etc/corosync.conf") @mock.patch('logging.Logger.warning') @mock.patch('crmsh.bootstrap.invokerc') @@ -766,12 +766,12 @@ mock_invokerc.side_effect = [False, False] bootstrap.csync2_update("/etc/corosync.conf") mock_invoke.assert_has_calls([ - mock.call("sudo csync2 -rm /etc/corosync.conf"), - mock.call("sudo csync2 -rf /etc/corosync.conf") + mock.call("csync2 -rm /etc/corosync.conf"), + mock.call("csync2 -rf /etc/corosync.conf") ]) mock_invokerc.assert_has_calls([ - mock.call("sudo csync2 -rxv /etc/corosync.conf"), - mock.call("sudo csync2 -rxv /etc/corosync.conf") + mock.call("csync2 -rxv /etc/corosync.conf"), + mock.call("csync2 -rxv /etc/corosync.conf") ]) mock_warn.assert_called_once_with("/etc/corosync.conf was not synced") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.5.0+20230320.5e777809/test/unittests/test_sbd.py new/crmsh-4.5.0+20230321.97bd51bb/test/unittests/test_sbd.py --- old/crmsh-4.5.0+20230320.5e777809/test/unittests/test_sbd.py 2023-03-20 08:49:02.000000000 +0100 +++ new/crmsh-4.5.0+20230321.97bd51bb/test/unittests/test_sbd.py 2023-03-21 16:02:58.000000000 +0100 @@ -87,7 +87,7 @@ with self.assertRaises(ValueError) as err: sbd.SBDTimeout.get_sbd_msgwait("/dev/sda1") self.assertEqual("Cannot get sbd msgwait for /dev/sda1", str(err.exception)) - mock_run.assert_called_once_with("sudo sbd -d /dev/sda1 dump") + mock_run.assert_called_once_with("sbd -d /dev/sda1 dump") @mock.patch('crmsh.utils.get_stdout_or_raise_error') def test_get_sbd_msgwait(self, mock_run): @@ -98,7 +98,7 @@ """ res = sbd.SBDTimeout.get_sbd_msgwait("/dev/sda1") assert res == 10 - mock_run.assert_called_once_with("sudo sbd -d /dev/sda1 dump") + mock_run.assert_called_once_with("sbd -d /dev/sda1 dump") @mock.patch('crmsh.sbd.SBDManager.get_sbd_value_from_config') def test_get_sbd_watchdog_timeout_exception(self, mock_get): @@ -500,8 +500,8 @@ self.sbd_inst._initialize_sbd() mock_invoke.assert_has_calls([ - mock.call("sudo sbd -4 10 -1 5 -d /dev/sdb1 create"), - mock.call("sudo sbd -4 10 -1 5 -d /dev/sdc1 create") + mock.call("sbd -4 10 -1 5 -d /dev/sdb1 create"), + mock.call("sbd -4 10 -1 5 -d /dev/sdc1 create") ]) mock_error.assert_called_once_with("Failed to initialize SBD device /dev/sdc1: error") @@ -591,7 +591,7 @@ mock_update.assert_not_called() mock_watchdog.assert_called_once_with(_input=None) mock_watchdog_inst.init_watchdog.assert_called_once_with() - mock_invoke.assert_called_once_with("sudo systemctl disable sbd.service") + mock_invoke.assert_called_once_with("systemctl disable sbd.service") @mock.patch('crmsh.sbd.SBDManager._enable_sbd_service') @mock.patch('crmsh.sbd.SBDManager._warn_diskless_sbd') @@ -658,7 +658,7 @@ def test_enable_sbd_service_init(self, mock_invoke): self.sbd_inst._context = mock.Mock(cluster_is_running=False) self.sbd_inst._enable_sbd_service() - mock_invoke.assert_called_once_with("sudo systemctl enable sbd.service") + mock_invoke.assert_called_once_with("systemctl enable sbd.service") @mock.patch('crmsh.sbd.SBDManager._restart_cluster_and_configure_sbd_ra') @mock.patch('crmsh.utils.cluster_run_cmd') @@ -713,7 +713,7 @@ self.sbd_inst.join_sbd("alice", "node1") mock_package.assert_called_once_with("sbd") mock_exists.assert_called_once_with("/etc/sysconfig/sbd") - mock_invoke.assert_called_once_with("sudo systemctl disable sbd.service") + mock_invoke.assert_called_once_with("systemctl disable sbd.service") @mock.patch('crmsh.bootstrap.invoke') @mock.patch('crmsh.utils.service_is_enabled') @@ -728,7 +728,7 @@ mock_package.assert_called_once_with("sbd") mock_exists.assert_called_once_with("/etc/sysconfig/sbd") - mock_invoke.assert_called_once_with("sudo systemctl disable sbd.service") + mock_invoke.assert_called_once_with("systemctl disable sbd.service") mock_enabled.assert_called_once_with("sbd.service", "node1") @mock.patch('logging.Logger.info') @@ -752,7 +752,7 @@ mock_package.assert_called_once_with("sbd") mock_exists.assert_called_once_with("/etc/sysconfig/sbd") - mock_invoke.assert_called_once_with("sudo systemctl enable sbd.service") + mock_invoke.assert_called_once_with("systemctl enable sbd.service") mock_get_device.assert_called_once_with() mock_verify.assert_called_once_with(["/dev/sdb1"], ["node1"]) mock_enabled.assert_called_once_with("sbd.service", "node1") @@ -782,7 +782,7 @@ mock_package.assert_called_once_with("sbd") mock_exists.assert_called_once_with("/etc/sysconfig/sbd") - mock_invoke.assert_called_once_with("sudo systemctl enable sbd.service") + mock_invoke.assert_called_once_with("systemctl enable sbd.service") mock_get_device.assert_called_once_with() mock_warn.assert_called_once_with("node1") mock_enabled.assert_called_once_with("sbd.service", "node1") @@ -827,7 +827,7 @@ with self.assertRaises(ValueError) as err: self.sbd_inst._get_device_uuid("/dev/sdb1") self.assertEqual("Cannot find sbd device UUID for /dev/sdb1", str(err.exception)) - mock_run.assert_called_once_with("sudo sbd -d /dev/sdb1 dump", remote=None) + mock_run.assert_called_once_with("sbd -d /dev/sdb1 dump", remote=None) @mock.patch('crmsh.utils.get_stdout_or_raise_error') def test_get_device_uuid(self, mock_run): @@ -846,7 +846,7 @@ mock_run.return_value = output res = self.sbd_inst._get_device_uuid("/dev/sda1", node="node1") self.assertEqual(res, "a2e9a92c-cc72-4ef9-ac55-ccc342f3546b") - mock_run.assert_called_once_with("sudo sbd -d /dev/sda1 dump", remote="node1") + mock_run.assert_called_once_with("sbd -d /dev/sda1 dump", remote="node1") @mock.patch('crmsh.sbd.SBDManager._get_sbd_device_from_config') @mock.patch('crmsh.utils.service_is_active') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.5.0+20230320.5e777809/test/unittests/test_utils.py new/crmsh-4.5.0+20230321.97bd51bb/test/unittests/test_utils.py --- old/crmsh-4.5.0+20230320.5e777809/test/unittests/test_utils.py 2023-03-20 08:49:02.000000000 +0100 +++ new/crmsh-4.5.0+20230321.97bd51bb/test/unittests/test_utils.py 2023-03-21 16:02:58.000000000 +0100 @@ -67,8 +67,8 @@ mock.call("file2", remote=None) ]) mock_run.assert_has_calls([ - mock.call("sudo cat file2", remote=None), - mock.call("sudo cat file1", remote=None) + mock.call("cat file2", remote=None), + mock.call("cat file1", remote=None) ]) @@ -491,8 +491,8 @@ mock_run.side_effect = ["test", "test"] assert utils.detect_aws() is False mock_run.assert_has_calls([ - mock.call("sudo dmidecode -s system-version"), - mock.call("sudo dmidecode -s system-manufacturer") + mock.call("dmidecode -s system-version"), + mock.call("dmidecode -s system-manufacturer") ]) @mock.patch("crmsh.utils.get_stdout_or_raise_error") @@ -500,8 +500,8 @@ mock_run.side_effect = ["4.2.amazon", "Xen"] assert utils.detect_aws() is True mock_run.assert_has_calls([ - mock.call("sudo dmidecode -s system-version"), - mock.call("sudo dmidecode -s system-manufacturer") + mock.call("dmidecode -s system-version"), + mock.call("dmidecode -s system-manufacturer") ]) @mock.patch("crmsh.utils.get_stdout_or_raise_error") @@ -509,8 +509,8 @@ mock_run.side_effect = ["Not Specified", "Amazon EC2"] assert utils.detect_aws() is True mock_run.assert_has_calls([ - mock.call("sudo dmidecode -s system-version"), - mock.call("sudo dmidecode -s system-manufacturer") + mock.call("dmidecode -s system-version"), + mock.call("dmidecode -s system-manufacturer") ]) @mock.patch("crmsh.utils.get_stdout_or_raise_error") @@ -518,8 +518,8 @@ mock_run.side_effect = ["test", "test"] assert utils.detect_azure() is False mock_run.assert_has_calls([ - mock.call("sudo dmidecode -s system-manufacturer"), - mock.call("sudo dmidecode -s chassis-asset-tag") + mock.call("dmidecode -s system-manufacturer"), + mock.call("dmidecode -s chassis-asset-tag") ]) @mock.patch("crmsh.utils._cloud_metadata_request") @@ -529,8 +529,8 @@ mock_request.return_value = "data" assert utils.detect_azure() is True mock_run.assert_has_calls([ - mock.call("sudo dmidecode -s system-manufacturer"), - mock.call("sudo dmidecode -s chassis-asset-tag") + mock.call("dmidecode -s system-manufacturer"), + mock.call("dmidecode -s chassis-asset-tag") ]) @mock.patch("crmsh.utils._cloud_metadata_request") @@ -540,15 +540,15 @@ mock_request.return_value = "data" assert utils.detect_azure() is True mock_run.assert_has_calls([ - mock.call("sudo dmidecode -s system-manufacturer"), - mock.call("sudo dmidecode -s chassis-asset-tag") + mock.call("dmidecode -s system-manufacturer"), + mock.call("dmidecode -s chassis-asset-tag") ]) @mock.patch("crmsh.utils.get_stdout_or_raise_error") def test_detect_gcp_false(mock_run): mock_run.return_value = "test" assert utils.detect_gcp() is False - mock_run.assert_called_once_with("sudo dmidecode -s bios-vendor") + mock_run.assert_called_once_with("dmidecode -s bios-vendor") @mock.patch("crmsh.utils._cloud_metadata_request") @mock.patch("crmsh.utils.get_stdout_or_raise_error") @@ -556,7 +556,7 @@ mock_run.return_value = "Google instance" mock_request.return_value = "data" assert utils.detect_gcp() is True - mock_run.assert_called_once_with("sudo dmidecode -s bios-vendor") + mock_run.assert_called_once_with("dmidecode -s bios-vendor") @mock.patch("crmsh.utils.is_program") def test_detect_cloud_no_cmd(mock_is_program): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.5.0+20230320.5e777809/test/unittests/test_watchdog.py new/crmsh-4.5.0+20230321.97bd51bb/test/unittests/test_watchdog.py --- old/crmsh-4.5.0+20230320.5e777809/test/unittests/test_watchdog.py 2023-03-20 08:49:02.000000000 +0100 +++ new/crmsh-4.5.0+20230321.97bd51bb/test/unittests/test_watchdog.py 2023-03-21 16:02:58.000000000 +0100 @@ -48,7 +48,7 @@ mock_run.return_value = (1, None, "error") res = self.watchdog_inst._verify_watchdog_device("/dev/watchdog", True) self.assertEqual(res, False) - mock_run.assert_called_once_with("sudo wdctl /dev/watchdog") + mock_run.assert_called_once_with("wdctl /dev/watchdog") @mock.patch('crmsh.utils.fatal') @mock.patch('crmsh.utils.get_stdout_stderr') @@ -58,7 +58,7 @@ with self.assertRaises(ValueError) as err: self.watchdog_inst._verify_watchdog_device("/dev/watchdog") mock_error.assert_called_once_with("Invalid watchdog device /dev/watchdog: error") - mock_run.assert_called_once_with("sudo wdctl /dev/watchdog") + mock_run.assert_called_once_with("wdctl /dev/watchdog") @mock.patch('crmsh.utils.get_stdout_stderr') def test_verify_watchdog_device(self, mock_run):