diff --git a/.packit.yml b/.packit.yml index c8fb697bfd..e4c71ed266 100644 --- a/.packit.yml +++ b/.packit.yml @@ -50,13 +50,14 @@ jobs: - standard env: INSTALL_DEPS: "yes" + LOG_LEVEL: "debug" targets: # Run integration tests on Fedora using CS9 containers, because running integrations tests on CS9 using CS9 # containers is very flaky # # This can be set to fedora-rawhide as soon as the following issue gets resolved: # https://github.com/containers/podman/issues/22422 - - fedora-latest-stable-x86_64 + - fedora-39-x86_64 - job: tests trigger: pull_request diff --git a/tests/bluechi_machine_lib/util.py b/tests/bluechi_machine_lib/util.py new file mode 100644 index 0000000000..72720bb19f --- /dev/null +++ b/tests/bluechi_machine_lib/util.py @@ -0,0 +1,42 @@ +# +# Copyright Contributors to the Eclipse BlueChi project +# +# SPDX-License-Identifier: LGPL-2.1-or-later + +import signal +import subprocess +from typing import Tuple + + +def run_command(command: str) -> Tuple[int, str, str]: + process = subprocess.Popen( + command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True + ) + print(f"Executing of command '{process.args}' started") + out, err = process.communicate() + + out = out.decode("utf-8").strip() + err = err.decode("utf-8").strip() + + print( + f"Executing of command '{process.args}' finished with result '{process.returncode}', " + f"stdout '{out}', stderr '{err}'" + ) + + return process.returncode, out.strip(), err + + +class Timeout: + def __init__(self, seconds=1, error_message="Timeout"): + self.seconds = seconds + self.error_message = error_message + + def handle_timeout(self, signum, frame): + raise TimeoutError(self.error_message) + + def __enter__(self): + signal.signal(signal.SIGALRM, self.handle_timeout) + signal.alarm(self.seconds) + + def __exit__(self, type, value, traceback): + signal.alarm(0) diff --git a/tests/bluechi_test/machine.py b/tests/bluechi_test/machine.py index a45f62d004..fdc9d92d78 100644 --- a/tests/bluechi_test/machine.py +++ b/tests/bluechi_test/machine.py @@ -219,7 +219,7 @@ def enable_valgrind(self) -> None: self.systemctl.daemon_reload() def run_python( - self, python_script_path: str + self, python_script_path: str, as_user: str = None ) -> Tuple[Optional[int], Union[Iterator[bytes], Any, Tuple[bytes, bytes]]]: target_file_dir = os.path.join("/", "tmp") @@ -231,8 +231,15 @@ def run_python( self.client.create_file(target_file_dir, target_file_name, content) target_file_path = os.path.join(target_file_dir, target_file_name) - LOGGER.debug(f"Executing python script '{target_file_path}'") - result, output = self.client.exec_run(f"python3 {target_file_path}") + cmd = f"python3 {target_file_path}" + if as_user: + cmd = f"runuser -l {as_user} -c '{cmd}'" + LOGGER.debug( + f"Executing python script '{target_file_path}'" + f" as user {as_user}" + if as_user + else "" + ) + result, output = self.client.exec_run(cmd) LOGGER.debug( f"Execute python script '{target_file_path}' finished with result '{result}' \ and output:\n{output}" @@ -300,6 +307,7 @@ def __init__( self.create_file( self.config.get_confd_dir(), self.config.file_name, self.config.serialize() ) + self.copy_machine_lib() class BluechiControllerMachine(BluechiMachine): diff --git a/tests/bluechi_test/service.py b/tests/bluechi_test/service.py index 67506455ca..3c156604a6 100644 --- a/tests/bluechi_test/service.py +++ b/tests/bluechi_test/service.py @@ -41,6 +41,8 @@ class Option(enum.Enum): ExecStartPre = "ExecStartPre" RemainAfterExit = "RemainAfterExit" Type = "Type" + User = "User" + Group = "Group" # Available options for Install section can be found at # https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html#%5BInstall%5D%20Section%20Options diff --git a/tests/tests/tier0/bluechi-agent-user-bus/main.fmf b/tests/tests/tier0/bluechi-agent-user-bus/main.fmf new file mode 100644 index 0000000000..0e1ea7a877 --- /dev/null +++ b/tests/tests/tier0/bluechi-agent-user-bus/main.fmf @@ -0,0 +1,2 @@ +summary: Test agent connecting to user bus +id: 6886e7c8-7548-4cf7-8dd4-d2d46b125fd3 diff --git a/tests/tests/tier0/bluechi-agent-user-bus/python/start_agent_as_user.py b/tests/tests/tier0/bluechi-agent-user-bus/python/start_agent_as_user.py new file mode 100644 index 0000000000..341a6e1011 --- /dev/null +++ b/tests/tests/tier0/bluechi-agent-user-bus/python/start_agent_as_user.py @@ -0,0 +1,36 @@ +# +# Copyright Contributors to the Eclipse BlueChi project +# +# SPDX-License-Identifier: LGPL-2.1-or-later + +import time +import unittest + +from bluechi_machine_lib.util import Timeout, run_command + +service = "org.eclipse.bluechi.Agent" +object = "/org/eclipse/bluechi" +interface = "org.eclipse.bluechi.Agent" + + +class TestAgentStartAsUser(unittest.TestCase): + + def test_agent_start_as_user(self): + result, _, _ = run_command("systemctl --user start bluechi-agent") + assert result == 0 + + with Timeout(5, "Timeout waiting for agent to connect to user bus"): + while True: + result, output, _ = run_command( + f"busctl --user get-property {service} {object} {interface} Status" + ) + if output == 's "offline"': + break + time.sleep(0.5) + + result, _, _ = run_command("systemctl --user stop bluechi-agent") + assert result == 0 + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/tests/tier0/bluechi-agent-user-bus/test_bluechi_agent_user_bus.py b/tests/tests/tier0/bluechi-agent-user-bus/test_bluechi_agent_user_bus.py new file mode 100644 index 0000000000..e8b48f14a9 --- /dev/null +++ b/tests/tests/tier0/bluechi-agent-user-bus/test_bluechi_agent_user_bus.py @@ -0,0 +1,58 @@ +# +# Copyright Contributors to the Eclipse BlueChi project +# +# SPDX-License-Identifier: LGPL-2.1-or-later + +import logging +import os +from typing import Dict + +from bluechi_test.config import BluechiAgentConfig, BluechiControllerConfig +from bluechi_test.machine import BluechiAgentMachine, BluechiControllerMachine +from bluechi_test.service import Option, Section +from bluechi_test.test import BluechiTest + +LOGGER = logging.getLogger(__name__) + +NODE_FOO = "node-foo" + + +def exec(ctrl: BluechiControllerMachine, nodes: Dict[str, BluechiAgentMachine]): + os.system("cat /etc/redhat-release") + bluechi_user = "bluechiuser" + node_foo = nodes[NODE_FOO] + node_foo.exec_run("cat /etc/redhat-release") + node_foo.systemctl.stop_unit("bluechi-agent") + ctrl.systemctl.stop_unit("bluechi-controller") + assert node_foo.wait_for_unit_state_to_be("bluechi-agent", "inactive") + + bc_agent = node_foo.load_systemd_service( + directory="/usr/lib/systemd/system", name="bluechi-agent.service" + ) + exec_start = bc_agent.get_option(Section.Service, Option.ExecStart) + bc_agent.set_option(Section.Service, Option.ExecStart, exec_start + " -u") + bc_agent.set_option(Section.Service, Option.User, bluechi_user) + node_foo.install_systemd_service(bc_agent, restart=False) + + node_foo.exec_run(f"useradd {bluechi_user}") + node_foo.exec_run("chmod -R 777 /var/tmp/bluechi-coverage") + result, _ = node_foo.run_python( + os.path.join("python", "start_agent_as_user.py"), bluechi_user + ) + assert result == 0 + + +def test_monitor_node_disconnect( + bluechi_test: BluechiTest, + bluechi_ctrl_default_config: BluechiControllerConfig, + bluechi_node_default_config: BluechiAgentConfig, +): + node_foo_cfg = bluechi_node_default_config.deep_copy() + node_foo_cfg.node_name = NODE_FOO + + bluechi_test.add_bluechi_agent_config(node_foo_cfg) + + bluechi_ctrl_default_config.allowed_node_names = [NODE_FOO] + bluechi_test.set_bluechi_controller_config(bluechi_ctrl_default_config) + + bluechi_test.run(exec)