225 lines
6.4 KiB
Python
225 lines
6.4 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from core.tools.base import BaseTool, ToolContext
|
|
from core.tools.registry import registry
|
|
from core.events import bus
|
|
from core.subprocess import run_command
|
|
|
|
|
|
class DockerTool(BaseTool):
|
|
name = "docker"
|
|
description = "Docker container and image management"
|
|
|
|
# =========================================================
|
|
# EXECUTE ROUTER
|
|
# =========================================================
|
|
|
|
def execute(self, payload: dict[str, Any], ctx: ToolContext):
|
|
action = str(payload.get("action", "")).strip()
|
|
|
|
bus.log(
|
|
"DOCKER",
|
|
"docker_execute",
|
|
"INFO",
|
|
{"action": action}
|
|
)
|
|
|
|
match action:
|
|
case "ps":
|
|
return self.ps(payload)
|
|
|
|
case "run":
|
|
return self.run_container(payload, ctx)
|
|
|
|
case "stop":
|
|
return self.stop_container(payload)
|
|
|
|
case "start":
|
|
return self.start_container(payload)
|
|
|
|
case "restart":
|
|
return self.restart_container(payload)
|
|
|
|
case "logs":
|
|
return self.logs(payload)
|
|
|
|
case "images":
|
|
return self.images(payload)
|
|
|
|
case "build":
|
|
return self.build_image(payload, ctx)
|
|
|
|
case _:
|
|
raise ValueError(f"Unknown docker action: {action}")
|
|
|
|
# =========================================================
|
|
# CONTAINERS LIST
|
|
# =========================================================
|
|
|
|
def ps(self, payload: dict[str, Any]):
|
|
all_containers = payload.get("all", False)
|
|
|
|
cmd = ["docker", "ps"]
|
|
if all_containers:
|
|
cmd.append("-a")
|
|
|
|
result = run_command(cmd=cmd)
|
|
|
|
return {
|
|
"action": "ps",
|
|
"status": "ok" if result.get("return_code") == 0 else "error",
|
|
"output": result.get("stdout", ""),
|
|
"error": result.get("stderr", "")
|
|
}
|
|
|
|
# =========================================================
|
|
# RUN CONTAINER
|
|
# =========================================================
|
|
|
|
def run_container(self, payload: dict[str, Any], ctx: ToolContext):
|
|
image = payload.get("image")
|
|
name = payload.get("name")
|
|
args = payload.get("args", [])
|
|
|
|
if not isinstance(image, str):
|
|
raise ValueError("image must be string")
|
|
|
|
if not isinstance(args, list):
|
|
raise ValueError("args must be list")
|
|
|
|
cmd = ["docker", "run"]
|
|
|
|
if name:
|
|
if not isinstance(name, str):
|
|
raise ValueError("name must be string")
|
|
cmd += ["--name", name]
|
|
|
|
cmd += args
|
|
cmd.append(image)
|
|
|
|
if ctx.dry_run:
|
|
return {
|
|
"dry_run": True,
|
|
"command": cmd
|
|
}
|
|
|
|
result = run_command(cmd=cmd)
|
|
|
|
return {
|
|
"action": "run",
|
|
"image": image,
|
|
"status": "ok" if result.get("return_code") == 0 else "error",
|
|
"stdout": result.get("stdout", ""),
|
|
"stderr": result.get("stderr", "")
|
|
}
|
|
|
|
# =========================================================
|
|
# STOP / START / RESTART
|
|
# =========================================================
|
|
|
|
def stop_container(self, payload: dict[str, Any]):
|
|
return self._simple_container_action("stop", payload)
|
|
|
|
def start_container(self, payload: dict[str, Any]):
|
|
return self._simple_container_action("start", payload)
|
|
|
|
def restart_container(self, payload: dict[str, Any]):
|
|
return self._simple_container_action("restart", payload)
|
|
|
|
def _simple_container_action(self, action: str, payload: dict[str, Any]):
|
|
container = payload.get("container")
|
|
|
|
if not isinstance(container, str):
|
|
raise ValueError("container must be string")
|
|
|
|
result = run_command(
|
|
cmd=["docker", action, container]
|
|
)
|
|
|
|
return {
|
|
"action": action,
|
|
"container": container,
|
|
"status": "ok" if result.get("return_code") == 0 else "error",
|
|
"stdout": result.get("stdout", ""),
|
|
"stderr": result.get("stderr", "")
|
|
}
|
|
|
|
# =========================================================
|
|
# LOGS
|
|
# =========================================================
|
|
|
|
def logs(self, payload: dict[str, Any]):
|
|
container = payload.get("container")
|
|
tail = payload.get("tail", 100)
|
|
|
|
if not isinstance(container, str):
|
|
raise ValueError("container must be string")
|
|
|
|
cmd = ["docker", "logs", "--tail", str(tail), container]
|
|
|
|
result = run_command(cmd=cmd)
|
|
|
|
return {
|
|
"action": "logs",
|
|
"container": container,
|
|
"output": result.get("stdout", ""),
|
|
"error": result.get("stderr", "")
|
|
}
|
|
|
|
# =========================================================
|
|
# IMAGES
|
|
# =========================================================
|
|
|
|
def images(self, payload: dict[str, Any]):
|
|
result = run_command(cmd=["docker", "images"])
|
|
|
|
return {
|
|
"action": "images",
|
|
"output": result.get("stdout", ""),
|
|
"error": result.get("stderr", "")
|
|
}
|
|
|
|
# =========================================================
|
|
# BUILD IMAGE
|
|
# =========================================================
|
|
|
|
def build_image(self, payload: dict[str, Any], ctx: ToolContext):
|
|
path = payload.get("path", ".")
|
|
tag = payload.get("tag")
|
|
|
|
if not isinstance(path, str):
|
|
raise ValueError("path must be string")
|
|
|
|
cmd = ["docker", "build", "-t"]
|
|
|
|
if isinstance(tag, str):
|
|
cmd.append(tag)
|
|
else:
|
|
cmd.append("untagged-image")
|
|
|
|
cmd.append(path)
|
|
|
|
if ctx.dry_run:
|
|
return {
|
|
"dry_run": True,
|
|
"command": cmd
|
|
}
|
|
|
|
result = run_command(cmd=cmd)
|
|
|
|
return {
|
|
"action": "build",
|
|
"path": path,
|
|
"status": "ok" if result.get("return_code") == 0 else "error",
|
|
"stdout": result.get("stdout", ""),
|
|
"stderr": result.get("stderr", "")
|
|
}
|
|
|
|
|
|
# =========================================================
|
|
# REGISTER TOOL
|
|
# =========================================================
|
|
|
|
registry.register(DockerTool()) |
