[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/ceph/ceph-devstack/main/ceph_devstack/resources/container.py [Back]  [Original]

import asyncio
import json
import os

from typing import Dict, List, Optional

from ceph_devstack import config, logger
from ceph_devstack.resources import PodmanResource


class Container(PodmanResource):
    network: str
    secret: List[str]
    cmd_vars: List[str] = ["name", "image", "image_name", "image_tag"]
    build_cmd: List[str] = [
        "podman",
        "build",
        "-t",
        "{image_name}:{image_tag}",
        ".",
    ]
    create_cmd: List[str] = ["podman", "container", "create", "{name}"]
    remove_cmd: List[str] = ["podman", "container", "rm", "-f", "{name}"]
    start_cmd: List[str] = ["podman", "container", "start", "{name}"]
    stop_cmd: List[str] = ["podman", "container", "stop", "{name}"]
    exists_cmd: List[str] = ["podman", "container", "inspect", "{name}"]
    pull_cmd: List[str] = ["podman", "pull", "{image}"]
    wait_cmd: List[str] = ["podman", "wait", "{name}"]
    env_vars: Dict[str, Optional[str]] = {}
    _image_name: str | None = None

    def __init__(self, name: str = ""):
        super().__init__(name)
        self.env_vars = {**self.__class__.env_vars}
        for key in self.env_vars:
            if os.environ.get(key):
                self.env_vars[key] = os.environ[key]

    def add_env_to_args(self, args: List):
        args = super().format_cmd(args)
        for key, value in self.env_vars.items():
            if not value:
                continue
            args.insert(-1, "-e")
            args.insert(-1, f"{key}={value}")
        return args

    @property
    def config(self):
        return config["containers"].get(self.__class__.__name__.lower(), {})

    @property
    def image_name(self) -> str:
        if self._image_name is not None:
            return self._image_name
        return self.__class__.__name__.lower()

    @property
    def image(self):
        if self.repo:
            return f"localhost/{self.image_name}"
        return self.config["image"]

    @property
    def image_tag(self):
        if ":" not in self.image:
            return "latest"
        return self.image.split(":")[-1]

    @property
    def repo(self):
        repo = self.config.get("repo", "")
        try:
            return repo.expanduser()
        except AttributeError:
            return os.path.expanduser(repo)

    @property
    def cwd(self):
        return self.repo or "."

    async def pull(self):
        if not getattr(self, "pull_cmd", None):
            return
        if self.image.startswith("localhost/"):
            return
        logger.debug(f"{self.name}: pulling from: {self.image}")
        await self.cmd(
            self.format_cmd(self.pull_cmd),
            check=True,
            stream_output=True,
        )

    async def build(self):
        if not getattr(self, "repo", None):
            return
        logger.debug(f"{self.name}: building from repo: {self.repo}")
        await self.cmd(
            self.format_cmd(self.build_cmd),
            check=True,
            stream_output=True,
        )
        logger.debug(f"{self.name}: built")

    async def create(self):
        if not getattr(self, "create_cmd", None):
            return
        if await self.exists():
            return
        args = self.add_env_to_args(self.format_cmd(self.create_cmd))
        logger.debug(f"{self.name}: creating")
        await self.cmd(
            args,
            check=True,
            stream_output=True,
        )
        logger.debug(f"{self.name}: created")

    async def start(self):
        if not getattr(self, "start_cmd", None):
            return
        logger.debug(f"{self.name}: starting")
        await self.cmd(
            self.format_cmd(self.start_cmd),
            check=True,
            stream_output=True,
        )
        if "--health-cmd" in self.create_cmd or "--healthcheck-cmd" in self.create_cmd:
            rc = None
            while rc != 0:
                proc = await self.cmd(
                    self.format_cmd(["podman", "healthcheck", "run", "{name}"]),
                )
                rc = await proc.wait()
                await asyncio.sleep(1)
        logger.debug(f"{self.name}: started")

    async def stop(self):
        if not getattr(self, "stop_cmd", None):
            return
        logger.debug(f"{self.name}: stopping")
        await self.cmd(
            self.format_cmd(self.stop_cmd),
            stream_output=True,
        )
        logger.debug(f"{self.name}: stopping")

    async def remove(self):
        if not getattr(self, "remove_cmd", None):
            return
        logger.debug(f"{self.name}: removing")
        await super().remove()
        logger.debug(f"{self.name}: removed")

    async def is_running(self):
        proc = await self.cmd(self.format_cmd(self.exists_cmd))
        assert proc.stdout is not None
        if not await self.exists():
            return False
        result = json.loads(await proc.stdout.read())
        if not result:
            return False
        return result[0]["State"]["Status"].lower() == "running"

    async def wait(self) -> Optional[int]:
        proc = await self.cmd(self.format_cmd(self.wait_cmd))
        out, err = await proc.communicate()
        if proc.returncode:
            logger.error(f"Could not wait for {self.name}: {err.decode().strip()}")
            return proc.returncode
        return int(out.decode().strip())

Web Proxy Viewer  |  New URL  |  Original Page