# 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