feat: add list_applications tool for YARN application enumeration
Add a new MCP tool that queries YARN's /ws/v1/cluster/apps endpoint
through a named Connection, returning a list of ApplicationSummary
records. Bypasses the local JobStore — useful for enumerating apps
that were not submitted through this service.
API:
list_applications(
connection_name: str, # required, which YARN cluster
state: str | None = None, # YARN state filter: NEW/NEW_SAVING/
# SUBMITTED/ACCEPTED/RUNNING/
# FINISHED/FAILED/KILLED
queue: str | None = None, # YARN queue filter
limit: int = 100, # cap on returned apps (YARN has no
# offset-based pagination; combine
# state/queue filters for big clusters)
) -> list[ApplicationSummary]
Implementation:
- yarn_client.list_applications(config, *, state, queue, limit) -> list[dict]
Returns raw YARN app dicts; raises YarnError on 4xx/5xx; returns
[] on 404 (no apps match). Uses the existing _request helper,
which now accepts a "params" kwarg for query strings (one-line
additive change).
- external_jobs.list_applications(connection_name, state, queue, limit)
-> list[ApplicationSummary]. Looks up the Connection, builds the
YarnClientConfig, calls the yarn_client function, maps each raw
YARN dict to ApplicationSummary (mirroring the manual field-mapping
style of get_job_result). The yarn_client function is imported
as "list_applications_yarn" to avoid name collision.
- ApplicationSummary: 12-field Pydantic model with snake_case names
(application_id, name, user, queue, state, final_status,
application_type, application_tags, started_time, finished_time,
tracking_url, progress). Unused YARN fields (memorySeconds,
vcoreSeconds, preemptedResource*, etc.) are not exposed.
- ListApplicationsRequest: Pydantic body model with Field(description=)
for LLM-facing schema.
- /list_applications route registered with operation_id=
"list_applications", placed next to the other external YARN tools.
Tests:
- 8 new unit tests in test_external_jobs.py (happy path, state/queue/
limit pass-through, default limit, empty list, missing connection,
full field mapping).
- test_mcp_routes.py: assert 23 tool routes.
- README: list_applications row added to the Spark Executor table.
Tests: 390 passed (was 382, +8 net).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,7 @@ from spark_executor.tools.external_jobs import (
|
||||
get_external_job_logs,
|
||||
get_external_job_status,
|
||||
get_external_job_result,
|
||||
list_applications,
|
||||
)
|
||||
from spark_executor.tools.fetch_url import fetch_url
|
||||
from spark_executor.tools.requests import (
|
||||
@@ -30,6 +31,7 @@ from spark_executor.tools.requests import (
|
||||
ExternalJobLogsRequest,
|
||||
ExternalJobStatusRequest,
|
||||
ExternalJobResultRequest,
|
||||
ListApplicationsRequest,
|
||||
FetchUrlRequest,
|
||||
GetJobLogsRequest,
|
||||
JobIdRequest,
|
||||
@@ -346,6 +348,34 @@ def _get_external_job_result(req: ExternalJobResultRequest):
|
||||
return get_external_job_result(req.application_id, req.connection_name)
|
||||
|
||||
|
||||
@app.post(
|
||||
"/list_applications",
|
||||
operation_id="list_applications",
|
||||
summary="List YARN applications on a cluster, optionally filtered",
|
||||
description=(
|
||||
"Query YARN's /ws/v1/cluster/apps endpoint through the named "
|
||||
"Connection, returning a list of ApplicationSummary records. "
|
||||
"Bypasses the local JobStore — useful for enumerating apps that "
|
||||
"were not submitted through this service.\n\n"
|
||||
"**Filters:** state (YARN state, e.g. 'RUNNING', 'FINISHED', "
|
||||
"'FAILED'), queue (YARN queue name), limit (default 100, max ~10000). "
|
||||
"YARN has no offset-based pagination, so for large clusters combine "
|
||||
"state/queue filters to scope the result. The `FINISHED` state "
|
||||
"covers SUCCEEDED/FAILED/KILLED.\n\n"
|
||||
"Returns an empty list if no apps match. The Connection's auth_type "
|
||||
"/ auth_user / auth_password / ssl_verify / ssl_ca_bundle are reused "
|
||||
"for the request."
|
||||
),
|
||||
)
|
||||
def _list_applications(req: ListApplicationsRequest):
|
||||
return list_applications(
|
||||
req.connection_name,
|
||||
state=req.state,
|
||||
queue=req.queue,
|
||||
limit=req.limit,
|
||||
)
|
||||
|
||||
|
||||
# --- Connection management tools ---
|
||||
|
||||
@app.post(
|
||||
|
||||
Reference in New Issue
Block a user