Commit Graph
32 Commits
Author SHA1 Message Date
Claude ff9dea0ba7 feat: log MCP tool list + descriptions on startup
main.py lifespan now enumerates every MCP tool with its description at
startup so operators can see at a glance what the server exposes.

The auto-generated '### Responses:' suffix that fastapi-mcp appends to
each tool description is truncated before logging to keep the startup
log scannable.

Docstrings added to all 12 route handlers in server.py so the MCP tool
descriptions are meaningful (without them, fastapi-mcp would emit empty
descriptions). Each route now carries a summary + description used by
the auto-generated OpenAPI schema.
2026-06-24 17:50:30 +08:00
Claude 093e51a9c2 feat: update Dockerfile mirror 2026-06-24 17:49:12 +08:00
Claude 33294af477 fix(Dockerfile): install openjdk-17-jre-headless for spark-submit
Spark 4.1.2 requires Java 17 at runtime (it boots a JVM via the
bin/spark-submit shell script). The previous Dockerfile only installed
curl, ca-certificates, and tar — leaving spark-submit unable to find
the 'java' binary.

A JRE is sufficient (not the full JDK) because spark-submit does not
compile Java at runtime — it loads pre-built JARs from $SPARK_HOME/jars/.
JRE-only keeps the image ~160 MB smaller than JDK-headless.

Sets JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 and prepends it to
PATH so spark-submit (which checks JAVA_HOME) finds the right JVM.

Combined with the prior yarn-REST rewrite, the runtime image now needs
exactly three things in addition to python:3.12-slim:
  - uv (from ghcr.io/astral-sh/uv)
  - openjdk-17-jre-headless
  - Spark 4.1.2 from Tsinghua mirror
2026-06-24 17:37:44 +08:00
Claude bfdf4fd1ff feat: update Dockerfile 2026-06-24 17:36:14 +08:00
Claude b3564737f7 refactor: replace yarn CLI shell-out with YARN REST API
yarn_client.py no longer invokes the 'yarn' binary via subprocess; it uses
httpx against /ws/v1/cluster/apps/* endpoints. This means the runtime image
no longer needs the Hadoop client installation — the only YARN-side
dependency left in the container is the config dir consumed by
spark-submit itself.

New model field:
  - Job.yarn_rm_url: str | None
  - PendingSubmission.yarn_rm_url: str | None (snapshotted at prepare)

prepare_submit_job snapshots Connection.yarn_rm_url into the pending
record (consistent with the existing master/deploy_mode/spark_conf
snapshot pattern); confirm_submit_job copies it onto the Job so
status/logs/kill can use it without re-looking-up the connection.

Resolution order for the RM URL at runtime:
  1. Job.yarn_rm_url (preferred — survives connection edits/deletes)
  2. Connection.yarn_rm_url fallback (if a future tool is added that
     doesn't go through a Job)
  3. YARN_RESOURCE_MANAGER_URL env var

Errors:
  - YarnConfigError (HTTP 4xx semantics) when URL is missing/malformed
  - YarnError for HTTP 4xx/5xx from the RM, network failures, missing
    state field, or unparseable log responses

10 new tests in test_yarn_client.py cover the REST surface:
success, 404, 5xx, missing state field, env-var fallback, malformed
URL, log 404 with log-aggregation hint, kill PUT body shape, and
httpx connection-error wrapping.
2026-06-24 17:33:36 +08:00
Claude 0d7b1d1ec3 feat: add Dockerfile 2026-06-24 17:07:23 +08:00
Claude 80df978206 feat: add requirements.txt 2026-06-24 16:53:47 +08:00
Claude 475c64cb69 feat: update spark executor title 2026-06-24 15:42:50 +08:00
Claude ce2eeb4bac feat: update memory 2026-06-24 15:20:29 +08:00
Claude b3eabe1fb6 feat: logging to file 2026-06-24 15:09:59 +08:00
Claude 5c7dcf57cc feat: structured DEBUG/INFO logging via loguru
- common/logging.py: improve format to timestamp|LEVEL|module:func:line - message
- core/ layer: DEBUG log every subprocess invocation (cmd, rc, byte counts),
  JSON load/dump events, parsed application_id. ERROR log on failures.
- tools/ layer: DEBUG log every public tool entry with key parameters,
  INFO log on business outcomes (saved/submitted/killed/...).
- New tests/unit/test_logging.py: capture loguru output via in-memory sink
  and assert DEBUG + INFO messages are emitted for representative flows.
2026-06-24 15:02:54 +08:00
Claude fad296591c fix: map KeyError->404 and ValueError->400 for MCP clients
Tool functions raise KeyError for unknown ids and ValueError for invalid
state transitions. Without handlers, FastAPI returned a bare 500
"Internal Server Error" to MCP clients — useless for an agent that needs
to know whether the id was wrong vs the cluster was down.

KeyError -> 404 with the message ("Unknown job_id: foo").
ValueError -> 400 with the message (e.g. "pending_id p_xyz is in status
'CANCELLED', not PENDING").
2026-06-24 14:59:00 +08:00
Claude 6b9f278294 fix: switch FastAPI routes to Pydantic body models for MCP tools/call
The plan's route signatures used query parameters, which worked for direct
HTTP callers and unit tests, but fastapi-mcp's HTTP transport passes
tools/call arguments as a JSON body. dict-typed parameters like
spark_conf arrived as a string and the route returned 422.

Refactor each route to take a single Pydantic body model (saved in
spark_executor/tools/requests.py). Underlying tool functions unchanged.

Integration tests in tests/integration/test_mcp_routes.py now exercise
the full body-based roundtrip (save_connection with spark_conf, prepare
→ list → get, list_connections with empty body).
2026-06-24 14:56:31 +08:00
Claude cc7eafaa16 feat: register 12 MCP tools on FastAPI app 2026-06-24 14:50:51 +08:00
Claude 0d60f9b246 feat: add kill_job tool 2026-06-24 14:44:10 +08:00
Claude 1cd3128522 feat: add get_job_logs tool with tail 2026-06-24 14:43:56 +08:00
Claude e443f96756 feat: add get_job_status tool 2026-06-24 14:43:41 +08:00
Claude 63dcae8d75 test: cover cancel_pending_job 2026-06-24 14:43:26 +08:00
Claude c734823e79 feat: add list_pending_jobs and get_pending_job 2026-06-24 14:40:54 +08:00
Claude 2f57c98aa6 feat: add confirm_submit_job (two-step submit flow) 2026-06-24 14:40:33 +08:00
Claude 7f08f0590a feat: add prepare_submit_job (no spark-submit invocation) 2026-06-24 14:40:01 +08:00
Claude 0aa3c1eaf5 feat: add JSON-backed PendingStore 2026-06-24 14:39:13 +08:00
Claude 82dafd357f test: cover delete_connection 2026-06-24 14:38:06 +08:00
Claude 3a08702c06 test: cover get_connection 2026-06-24 14:38:06 +08:00
Claude 1450ad1779 test: cover list_connections 2026-06-24 14:38:06 +08:00
Claude 00592f5cf8 feat: add save_connection tool 2026-06-24 14:37:58 +08:00
Claude 8dd39367ed feat: add JSON-backed ConnectionStore 2026-06-24 14:37:09 +08:00
Claude 31d28baace feat: add in-memory JobStore 2026-06-24 14:36:05 +08:00
Claude a9f64d9942 feat: add yarn client (status, logs, kill) 2026-06-24 14:35:30 +08:00
Claude b4b2ad534a feat: add spark-submit command builder and runner 2026-06-24 14:35:07 +08:00
Claude e6902b00a0 feat: add spark-submit output parser 2026-06-24 14:34:40 +08:00
Claude 864093f1fb chore: add pytest dev-deps and pydantic models (Job, Connection, PendingSubmission) 2026-06-24 14:34:09 +08:00