diff --git a/components/clp-package-utils/clp_package_utils/controller.py b/components/clp-package-utils/clp_package_utils/controller.py index 740767b26f..b0ec72fb45 100644 --- a/components/clp-package-utils/clp_package_utils/controller.py +++ b/components/clp-package-utils/clp_package_utils/controller.py @@ -87,22 +87,22 @@ def __init__(self, clp_config: CLPConfig) -> None: self._conf_dir = self._clp_home / "etc" @abstractmethod - def start(self) -> None: + def set_up_env(self) -> None: """ - Starts the components. + Sets up all components to run by preparing environment variables, directories, and + configuration files. """ @abstractmethod - def stop(self) -> None: + def start(self) -> None: """ - Stops the components. + Starts the components. """ @abstractmethod - def _set_up_env(self) -> None: + def stop(self) -> None: """ - Sets up all components to run by preparing environment variables, directories, and - configuration files. + Stops the components. """ def _set_up_env_for_database(self) -> EnvVarsDict: @@ -642,75 +642,7 @@ def __init__(self, clp_config: CLPConfig, instance_id: str) -> None: self._project_name = f"clp-package-{instance_id}" super().__init__(clp_config) - def start(self) -> None: - """ - Starts CLP's components using Docker Compose. - - :raise: Propagates `check_docker_dependencies`'s exceptions. - :raise: Propagates `subprocess.run`'s exceptions. - """ - check_docker_dependencies( - should_compose_project_be_running=False, project_name=self._project_name - ) - self._set_up_env() - - deployment_type = self._clp_config.get_deployment_type() - logger.info(f"Starting CLP using Docker Compose ({deployment_type} deployment)...") - - cmd = ["docker", "compose", "--project-name", self._project_name] - if deployment_type == DeploymentType.BASE: - cmd += ["--file", "docker-compose.base.yaml"] - if self._clp_config.mcp_server is not None: - cmd += ["--profile", "mcp"] - cmd += ["up", "--detach", "--wait"] - subprocess.run( - cmd, - cwd=self._clp_home, - check=True, - ) - logger.info("Started CLP.") - - def stop(self) -> None: - """ - Stops CLP components deployed via Docker Compose. - - :raise: Propagates `subprocess.run`'s exceptions. - """ - try: - check_docker_dependencies( - should_compose_project_be_running=True, project_name=self._project_name - ) - except DockerComposeProjectNotRunningError: - logger.info( - "Docker Compose project '%s' is not running. Nothing to stop.", - self._project_name, - ) - return - except DockerDependencyError as e: - logger.warning( - 'Docker dependencies check failed: "%s". Attempting to stop CLP containers ' - "anyway...", - e, - ) - else: - logger.info("Stopping all CLP containers using Docker Compose...") - - subprocess.run( - ["docker", "compose", "--project-name", self._project_name, "down"], - cwd=self._clp_home, - check=True, - ) - logger.info("Stopped CLP.") - - @staticmethod - def _get_num_workers() -> int: - """ - :return: Number of worker processes to run. - """ - # This will change when we move from single to multi-container workers. See y-scope/clp#1424 - return multiprocessing.cpu_count() // 2 - - def _set_up_env(self) -> None: + def set_up_env(self) -> None: # Generate container-specific config. container_clp_config = generate_docker_compose_container_config(self._clp_config) num_workers = self._get_num_workers() @@ -796,6 +728,73 @@ def _set_up_env(self) -> None: continue env_file.write(f"{key}={value}\n") + def start(self) -> None: + """ + Starts CLP's components using Docker Compose. + + :raise: Propagates `check_docker_dependencies`'s exceptions. + :raise: Propagates `subprocess.run`'s exceptions. + """ + check_docker_dependencies( + should_compose_project_be_running=False, project_name=self._project_name + ) + + deployment_type = self._clp_config.get_deployment_type() + logger.info(f"Starting CLP using Docker Compose ({deployment_type} deployment)...") + + cmd = ["docker", "compose", "--project-name", self._project_name] + if deployment_type == DeploymentType.BASE: + cmd += ["--file", "docker-compose.base.yaml"] + if self._clp_config.mcp_server is not None: + cmd += ["--profile", "mcp"] + cmd += ["up", "--detach", "--wait"] + subprocess.run( + cmd, + cwd=self._clp_home, + check=True, + ) + logger.info("Started CLP.") + + def stop(self) -> None: + """ + Stops CLP components deployed via Docker Compose. + + :raise: Propagates `subprocess.run`'s exceptions. + """ + try: + check_docker_dependencies( + should_compose_project_be_running=True, project_name=self._project_name + ) + except DockerComposeProjectNotRunningError: + logger.info( + "Docker Compose project '%s' is not running. Nothing to stop.", + self._project_name, + ) + return + except DockerDependencyError as e: + logger.warning( + 'Docker dependencies check failed: "%s". Attempting to stop CLP containers ' + "anyway...", + e, + ) + else: + logger.info("Stopping all CLP containers using Docker Compose...") + + subprocess.run( + ["docker", "compose", "--project-name", self._project_name, "down"], + cwd=self._clp_home, + check=True, + ) + logger.info("Stopped CLP.") + + @staticmethod + def _get_num_workers() -> int: + """ + :return: Number of worker processes to run. + """ + # This will change when we move from single to multi-container workers. See y-scope/clp#1424 + return multiprocessing.cpu_count() // 2 + def get_or_create_instance_id(clp_config: CLPConfig) -> str: """ 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 89ddf2f56b..15a44b7458 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 @@ -37,6 +37,11 @@ def main(argv): action="store_true", help="Enable debug logging.", ) + args_parser.add_argument( + "--setup-only", + action="store_true", + help="Validate configuration and prepare directories without starting services.", + ) parsed_args = args_parser.parse_args(argv[1:]) @@ -79,6 +84,12 @@ def main(argv): try: instance_id = get_or_create_instance_id(clp_config) controller = DockerComposeController(clp_config, instance_id) + controller.set_up_env() + if parsed_args.setup_only: + logger.info( + "Completed setup. Services not started because `--setup-only` was specified." + ) + return 0 controller.start() except Exception as ex: if type(ex) == ValueError: diff --git a/docs/src/user-docs/quick-start/clp-json.md b/docs/src/user-docs/quick-start/clp-json.md index 7f080a3d87..a2f0f67567 100644 --- a/docs/src/user-docs/quick-start/clp-json.md +++ b/docs/src/user-docs/quick-start/clp-json.md @@ -17,6 +17,11 @@ To start CLP, run: sbin/start-clp.sh ``` +:::{tip} +To validate configuration and prepare directories without launching services, add the +`--setup-only` flag (e.g., `sbin/start-clp.sh --setup-only`). +::: + :::{note} If CLP fails to start (e.g., due to a port conflict), try adjusting the settings in `etc/clp-config.yml` and then run the start command again. diff --git a/docs/src/user-docs/quick-start/clp-text.md b/docs/src/user-docs/quick-start/clp-text.md index 89af511003..bc5d51719e 100644 --- a/docs/src/user-docs/quick-start/clp-text.md +++ b/docs/src/user-docs/quick-start/clp-text.md @@ -19,6 +19,11 @@ To start CLP, run: sbin/start-clp.sh ``` +:::{tip} +To validate configuration and prepare directories without launching services, add the +`--setup-only` flag (e.g., `sbin/start-clp.sh --setup-only`). +::: + :::{note} If CLP fails to start (e.g., due to a port conflict), try adjusting the settings in `etc/clp-config.yml` and then run the start command again.