|
# retoor <retoor@molodetz.nl>
|
|
|
|
from __future__ import annotations
|
|
|
|
from devplacepy.services.containers.backend.base import (
|
|
Backend,
|
|
BuildResult,
|
|
ExecResult,
|
|
PsRow,
|
|
RunSpec,
|
|
StatsSample,
|
|
)
|
|
|
|
|
|
class FakeBackend(Backend):
|
|
def __init__(self) -> None:
|
|
self.containers: dict = {}
|
|
self.built_images: list = []
|
|
self.removed: list = []
|
|
self.removed_images: list = []
|
|
self.pruned = 0
|
|
self._counter = 0
|
|
self.fail_build = False
|
|
|
|
async def build(self, *, context_dir, dockerfile_text, tags, on_log=None, network="") -> BuildResult:
|
|
if on_log is not None:
|
|
await on_log(f"FAKE build {tags} net={network}")
|
|
if self.fail_build:
|
|
return BuildResult(success=False, error="fake build failure")
|
|
self.built_images.append(list(tags))
|
|
return BuildResult(success=True, image_id=f"sha256:fake{len(self.built_images)}")
|
|
|
|
async def run(self, spec: RunSpec) -> str:
|
|
self._counter += 1
|
|
cid = f"fake{self._counter:012d}"
|
|
self.containers[cid] = {
|
|
"name": spec.name, "state": "running", "labels": dict(spec.labels),
|
|
"exit_code": None, "image": spec.image, "spec": spec,
|
|
}
|
|
return cid
|
|
|
|
def _set_state(self, cid: str, state: str, exit_code=None) -> None:
|
|
if cid in self.containers:
|
|
self.containers[cid]["state"] = state
|
|
if exit_code is not None:
|
|
self.containers[cid]["exit_code"] = exit_code
|
|
|
|
async def start(self, cid: str) -> None:
|
|
self._set_state(cid, "running")
|
|
|
|
async def stop(self, cid: str, timeout: int = 10) -> None:
|
|
self._set_state(cid, "exited", exit_code=0)
|
|
|
|
async def restart(self, cid: str) -> None:
|
|
self._set_state(cid, "running")
|
|
|
|
async def pause(self, cid: str) -> None:
|
|
self._set_state(cid, "paused")
|
|
|
|
async def unpause(self, cid: str) -> None:
|
|
self._set_state(cid, "running")
|
|
|
|
async def rm(self, cid: str, force: bool = False) -> None:
|
|
self.removed.append(cid)
|
|
self.containers.pop(cid, None)
|
|
|
|
async def exec(self, cid, cmd, *, tty=False, on_log=None) -> ExecResult:
|
|
line = f"FAKE exec {' '.join(cmd)}"
|
|
if on_log is not None:
|
|
await on_log(line)
|
|
return ExecResult(exit_code=0, output=line)
|
|
|
|
async def logs(self, cid, *, follow=False, tail=200, on_log=None) -> None:
|
|
if on_log is not None:
|
|
await on_log(f"FAKE logs for {cid}")
|
|
|
|
async def stats_once(self, cids: list) -> dict:
|
|
return {self.containers[cid]["name"]: StatsSample(cpu_pct=1.0, mem_bytes=1024)
|
|
for cid in cids if cid in self.containers}
|
|
|
|
async def ps(self, *, label_filter: str = "devplace.instance") -> list:
|
|
key, _, value = label_filter.partition("=")
|
|
rows = []
|
|
for cid, data in self.containers.items():
|
|
labels = data["labels"]
|
|
if key not in labels:
|
|
continue
|
|
if value and labels.get(key) != value:
|
|
continue
|
|
rows.append(PsRow(
|
|
container_id=cid, name=data["name"], state=data["state"],
|
|
status=data["state"], exit_code=data["exit_code"], labels=labels,
|
|
))
|
|
return rows
|
|
|
|
async def inspect(self, cid: str) -> dict:
|
|
return self.containers.get(cid, {})
|
|
|
|
async def image_prune(self) -> None:
|
|
self.pruned += 1
|
|
|
|
async def remove_image(self, ref: str, force: bool = False) -> None:
|
|
self.removed_images.append(ref)
|
|
|
|
async def image_exists(self, ref: str) -> bool:
|
|
return True
|