def ExecuteDockerCommand(command): """Executes Docker CLI commands in subprocess. Just calls local_util.ExecuteCommand(cmd,...) and raises error for non-zero exit code. Args: command: (List[str]) Strings to send in as the command. Raises: ValueError: The input command is not a docker command. DockerError: An error occurred when executing the given docker command. """ command_str = " ".join(command) if not command_str.startswith("docker"): raise ValueError("`{}` is not a Docker command".format("docker")) log.info("Running command: {}".format(command_str)) return_code = local_util.ExecuteCommand(command) if return_code != 0: error_msg = """ Docker failed with error code {code}. Command: {cmd} """.format( code=return_code, cmd=command_str) raise errors.DockerError(error_msg, command, return_code)
def RunContainer(image, enable_gpu=False, run_args=None, user_args=None): """Calls `docker run` on a given image with specified arguments. Args: image: (Image) Represents the image to run, containing info like image name, home directory, entrypoint etc. enable_gpu: (bool) Whether to use GPU run_args: (List[str]) Extra custom options to apply to `docker run` after our defaults. user_args: (List[str]) Extra user defined arguments to supply to the entrypoint. Raises: DockerError: An error occurred when executing `docker run` """ # TODO(b/177787660): add interactive mode option if run_args is None: run_args = [] if user_args is None: user_args = [] run_opts = _DockerRunOptions(enable_gpu, image.default_home, run_args) command = ["docker", "run"] + run_opts + [image.name] + user_args command_str = " ".join(command) log.info("Running command: {}".format(command_str)) return_code = local_util.ExecuteCommand(command) if return_code != 0: error_msg = """ Docker failed with error code {code}. Command: {cmd} """.format(code=return_code, cmd=command_str) raise errors.DockerError(error_msg, command, return_code)
def BuildImage(base_image, host_workdir, main_script, output_image_name, python_module=None, requirements=None, extra_packages=None, container_workdir=None, container_home=None, no_cache=True, **kwargs): """Builds a Docker image. Generates a Dockerfile and passes it to `docker build` via stdin. All output from the `docker build` process prints to stdout. Args: base_image: (str) ID or name of the base image to initialize the build stage. host_workdir: (str) A path indicating where all the required sources locates. main_script: (str) A string that identifies the executable script under the working directory. output_image_name: (str) Name of the built image. python_module: (str) Represents the executable main_script in form of a python module, if applicable. requirements: (List[str]) Required dependencies to install from PyPI. extra_packages: (List[str]) User custom dependency packages to install. container_workdir: (str) Working directory in the container. container_home: (str) the $HOME directory in the container. no_cache: (bool) Do not use cache when building the image. **kwargs: Other arguments to pass to underlying method that generates the Dockerfile. Returns: A Image class that contains info of the built image. Raises: DockerError: An error occurred when executing `docker build` """ tag_options = ["-t", output_image_name] cache_args = ["--no-cache"] if no_cache else [] command = ["docker", "build" ] + cache_args + tag_options + ["--rm", "-f-", host_workdir] setup_path = _DEFAULT_SETUP_PATH if os.path.exists( _DEFAULT_SETUP_PATH) else None requirments_path = _DEFAULT_REQUIREMENTS_PATH if os.path.exists( _DEFAULT_REQUIREMENTS_PATH) else None home_dir = container_home or _DEFAULT_HOME work_dir = container_workdir or _DEFAULT_WORKDIR # The package will be used in Docker, thus norm it to POSIX path format. main_package = Package( script=main_script.replace(os.sep, posixpath.sep), package_path=host_workdir.replace(os.sep, posixpath.sep), python_module=python_module) dockerfile = _MakeDockerfile( base_image, main_package=main_package, container_home=home_dir, container_workdir=work_dir, requirements_path=requirments_path, setup_path=setup_path, extra_requirements=requirements, extra_packages=extra_packages, **kwargs) joined_command = " ".join(command) log.info("Running command: {}".format(joined_command)) return_code = local_util.ExecuteCommand(command, input_str=dockerfile) if return_code == 0: return Image(output_image_name, home_dir, work_dir) else: error_msg = textwrap.dedent(""" Docker failed with error code {code}. Command: {cmd} """.format(code=return_code, cmd=joined_command)) raise errors.DockerError(error_msg, command, return_code)