Source code for platform.docker.compose_runner

# Copyright 2021 Curtin University
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Author: James Diprose

import dataclasses
import os
import subprocess
from subprocess import Popen
from typing import Dict, List

from observatory.platform.docker.builder import Builder, rendered_file_name
from observatory.platform.utils.proc_utils import stream_process


@dataclasses.dataclass
[docs]class ProcessOutput: """Output from a process :param output: the process std out. :param error: the process std error. :param return_code: the process return code. """
[docs] output: str
[docs] error: str
[docs] return_code: int
[docs]class ComposeRunner(Builder):
[docs] COMPOSE_ARGS_PREFIX = ["docker", "compose", "-f"]
[docs] COMPOSE_BUILD_ARGS = ["build"]
[docs] COMPOSE_START_ARGS = ["up", "-d"]
[docs] COMPOSE_STOP_ARGS = ["down"]
def __init__( self, *, compose_template_path: str, build_path: str, compose_template_kwargs: Dict = None, debug: bool = False ): """Docker Compose runner constructor. :param compose_template_path: the path to the Docker Compose Jinja2 template file. :param build_path: the path where Docker will build. :param compose_template_kwargs: the kwargs to use when rendering the Docker Compose Jinja2 template file. :param debug: whether to run in debug mode or not. """ super().__init__(build_path=build_path) if compose_template_kwargs is None: compose_template_kwargs = dict() self.debug = debug self.compose_template_path = compose_template_path self.add_template(path=compose_template_path, **compose_template_kwargs)
[docs] def make_environment(self) -> Dict: """Make the environment variables. :return: environment dictionary. """ return os.environ.copy()
@property
[docs] def compose_file_name(self): """Return the file name for the rendered Docker Compose template. :return: Docker Compose file name. """ return rendered_file_name(self.compose_template_path)
[docs] def build(self) -> ProcessOutput: """Build the Docker containers. :return: output and error stream results and proc return code. """ return self.__run_docker_compose_cmd(self.COMPOSE_BUILD_ARGS)
[docs] def start(self) -> ProcessOutput: """Start the Docker containers. :return: output and error stream results and proc return code. """ return self.__run_docker_compose_cmd(self.COMPOSE_START_ARGS)
[docs] def stop(self) -> ProcessOutput: """Stop the Docker containers. :return: output and error stream results and proc return code. """ return self.__run_docker_compose_cmd(self.COMPOSE_STOP_ARGS)
[docs] def __run_docker_compose_cmd(self, args: List) -> ProcessOutput: """Run a set of Docker Compose arguments. :param args: the list of arguments. :return: output and error stream results and proc return code. """ # Make environment env = self.make_environment() # Make files self.make_files() # Build the containers first proc: Popen = subprocess.Popen( self.COMPOSE_ARGS_PREFIX + [self.compose_file_name] + args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env, cwd=self.build_path, ) # Wait for results output, error = stream_process(proc, self.debug) return ProcessOutput(output, error, proc.returncode)