From bca4c2710edc780eeb40c76fa7a922bfeff3f0e6 Mon Sep 17 00:00:00 2001 From: haiqi96 <14502009+haiqi96@users.noreply.github.com> Date: Mon, 29 Jul 2024 13:32:10 -0400 Subject: [PATCH] clp-package: Add support for running package as root (fixes #500). (#464) --- .../clp_package_utils/scripts/start_clp.py | 75 ++++++++++++++++++- 1 file changed, 72 insertions(+), 3 deletions(-) diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index 4d0d461ba..7c6de0200 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -89,6 +89,21 @@ def append_docker_port_settings_for_host_ips( cmd.append(f"{ip}:{host_port}:{container_port}") +def chown_recursively( + path: pathlib.Path, + user_id: int, + group_id: int, +): + """ + Recursively changes the owner of the given path to the given user ID and group ID. + :param path: + :param user_id: + :param group_id: + """ + chown_cmd = ["chown", "--recursive", f"{user_id}:{group_id}", str(path)] + subprocess.run(chown_cmd, stdout=subprocess.DEVNULL, check=True) + + def wait_for_container_cmd(container_name: str, cmd_to_run: [str], timeout: int): container_exec_cmd = ["docker", "exec", container_name] cmd = container_exec_cmd + cmd_to_run @@ -318,6 +333,19 @@ def start_queue(instance_id: str, clp_config: CLPConfig): DockerMount(DockerMountType.BIND, queue_logs_dir, rabbitmq_logs_dir), ] rabbitmq_pid_file_path = pathlib.Path("/") / "tmp" / "rabbitmq.pid" + + host_user_id = os.getuid() + if 0 != host_user_id: + container_user = f"{host_user_id}:{os.getgid()}" + else: + # The host user is `root` so use the container's default user and make this component's + # directories writable by that user. + # NOTE: This doesn't affect the host user's access to the directories since they're `root`. + container_user = "rabbitmq" + default_container_user_id = 999 + default_container_group_id = 999 + chown_recursively(queue_logs_dir, default_container_user_id, default_container_group_id) + # fmt: off cmd = [ "docker", "run", @@ -327,7 +355,7 @@ def start_queue(instance_id: str, clp_config: CLPConfig): # Override RABBITMQ_LOGS since the image sets it to *only* log to stdout "-e", f"RABBITMQ_LOGS={rabbitmq_logs_dir / log_filename}", "-e", f"RABBITMQ_PID_FILE={rabbitmq_pid_file_path}", - "-u", f"{os.getuid()}:{os.getgid()}", + "-u", container_user ] # fmt: on append_docker_port_settings_for_host_ips( @@ -380,13 +408,27 @@ def start_redis(instance_id: str, clp_config: CLPConfig, conf_dir: pathlib.Path) ), DockerMount(DockerMountType.BIND, redis_data_dir, pathlib.Path("/") / "data"), ] + + host_user_id = os.getuid() + if 0 != host_user_id: + container_user = f"{host_user_id}:{os.getgid()}" + else: + # The host user is `root` so use the container's default user and make this component's + # directories writable by that user. + # NOTE: This doesn't affect the host user's access to the directories since they're `root`. + container_user = "redis" + default_container_user_id = 999 + default_container_group_id = 999 + chown_recursively(redis_data_dir, default_container_user_id, default_container_group_id) + chown_recursively(redis_logs_dir, default_container_user_id, default_container_group_id) + # fmt: off cmd = [ "docker", "run", "-d", "--name", container_name, "--log-driver", "local", - "-u", f"{os.getuid()}:{os.getgid()}", + "-u", container_user, ] # fmt: on for mount in mounts: @@ -400,6 +442,19 @@ def start_redis(instance_id: str, clp_config: CLPConfig, conf_dir: pathlib.Path) cmd.append(str(config_file_path)) subprocess.run(cmd, stdout=subprocess.DEVNULL, check=True) + # fmt: off + redis_ping_cmd = [ + "redis-cli", + "-h", "127.0.0.1", + "-p", "6379", + "-a", clp_config.redis.password, + "PING" + ] + # fmt: on + + if not wait_for_container_cmd(container_name, redis_ping_cmd, 30): + raise EnvironmentError(f"{component_name} did not initialize in time") + logger.info(f"Started {component_name}.") @@ -426,13 +481,27 @@ def start_results_cache(instance_id: str, clp_config: CLPConfig, conf_dir: pathl DockerMount(DockerMountType.BIND, data_dir, pathlib.Path("/") / "data" / "db"), DockerMount(DockerMountType.BIND, logs_dir, pathlib.Path("/") / "var" / "log" / "mongodb"), ] + + host_user_id = os.getuid() + if 0 != host_user_id: + container_user = f"{host_user_id}:{os.getgid()}" + else: + # The host user is `root` so use the container's default user and make this component's + # directories writable by that user. + # NOTE: This doesn't affect the host user's access to the directories since they're `root`. + container_user = "mongodb" + default_container_user_id = 999 + default_container_group_id = 999 + chown_recursively(data_dir, default_container_user_id, default_container_group_id) + chown_recursively(logs_dir, default_container_user_id, default_container_group_id) + # fmt: off cmd = [ "docker", "run", "-d", "--name", container_name, "--log-driver", "local", - "-u", f"{os.getuid()}:{os.getgid()}", + "-u", container_user, ] # fmt: on for mount in mounts: