From 312c1860e8b39d012e7eff4de68d5cc0bb21a5cc Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 3 Jun 2026 23:39:27 +0800 Subject: [PATCH] Add minimal strategy demo --- .dockerignore | 4 +++ Dockerfile | 21 ++++++++++++++ README.md | 46 ++++++++++++++++++++++++++++++ main.py | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 1 + 5 files changed, 145 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 main.py create mode 100644 requirements.txt diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..33c31f5 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +.git +__pycache__/ +*.pyc +.pytest_cache/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..05ce8e3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +FROM python:3.11-slim + +ARG TASK_TYPE +ARG GPU_TYPE +ARG FRAMEWORK + +ENV TASK_TYPE=${TASK_TYPE} +ENV GPU_TYPE=${GPU_TYPE} +ENV FRAMEWORK=${FRAMEWORK} +ENV PYTHONUNBUFFERED=1 + +WORKDIR /app + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +EXPOSE 8080 + +CMD ["python", "main.py"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..855532d --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +# Strategy Platform Demo Repo + +Minimal strategy repository for testing the platform Kaniko build and deployment flow. + +It satisfies the runtime contract from the parent README: + +- Root-level `Dockerfile` +- Listens on port `8080` +- Exposes `GET /health` +- Reads `TASK_TYPE`, `GPU_TYPE`, `FRAMEWORK`, and `EXTERNAL_SERVICE_TOKEN` +- Handles `SIGTERM` for graceful shutdown + +## Local Run + +```bash +python main.py +curl http://localhost:8080/health +curl http://localhost:8080/ +``` + +## Build Locally + +```bash +docker build \ + --build-arg TASK_TYPE=validation \ + --build-arg GPU_TYPE=amd64 \ + --build-arg FRAMEWORK=pytorch \ + -t strategy-demo:v1.0.0 . + +docker run --rm -p 8080:8080 strategy-demo:v1.0.0 +``` + +## Platform Test + +Push this directory to Gitea and keep the `v1.0.0` tag. Then create a strategy with: + +```json +{ + "name": "strategy-demo", + "repo_url": "https:////strategy-demo", + "tag": "v1.0.0", + "task_type": "validation", + "gpu_type": "amd64", + "framework": "pytorch" +} +``` diff --git a/main.py b/main.py new file mode 100644 index 0000000..ce54ed3 --- /dev/null +++ b/main.py @@ -0,0 +1,73 @@ +import json +import os +import signal +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer + + +HOST = "0.0.0.0" +PORT = 8080 +shutdown_requested = False + + +def _config() -> dict: + token = os.getenv("EXTERNAL_SERVICE_TOKEN", "") + return { + "task_type": os.getenv("TASK_TYPE", ""), + "gpu_type": os.getenv("GPU_TYPE", ""), + "framework": os.getenv("FRAMEWORK", ""), + "external_service_token_present": bool(token), + } + + +class Handler(BaseHTTPRequestHandler): + def do_GET(self) -> None: + if self.path == "/health": + self._send_json({"status": "ok"}) + return + + if self.path == "/": + self._send_json( + { + "name": "strategy-demo", + "status": "running", + "config": _config(), + } + ) + return + + self._send_json({"error": "not found"}, status=404) + + def log_message(self, fmt: str, *args: object) -> None: + print(f"{self.address_string()} - {fmt % args}", flush=True) + + def _send_json(self, body: dict, status: int = 200) -> None: + payload = json.dumps(body).encode() + self.send_response(status) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", str(len(payload))) + self.end_headers() + self.wfile.write(payload) + + +def _handle_signal(signum: int, _frame: object) -> None: + global shutdown_requested + shutdown_requested = True + print(f"received signal {signum}, shutting down", flush=True) + + +def main() -> None: + signal.signal(signal.SIGTERM, _handle_signal) + signal.signal(signal.SIGINT, _handle_signal) + + server = ThreadingHTTPServer((HOST, PORT), Handler) + server.timeout = 1 + print(f"strategy-demo listening on {HOST}:{PORT}", flush=True) + + while not shutdown_requested: + server.handle_request() + + server.server_close() + + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +