tools: persist spark_submit calls to SubmissionRepo
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -6,10 +6,12 @@ import (
|
||||
"log/slog"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
|
||||
"spark-mcp-go/internal/executor"
|
||||
"spark-mcp-go/internal/storage"
|
||||
)
|
||||
|
||||
const SparkSubmitName = "spark_submit"
|
||||
@@ -98,7 +100,8 @@ func (d *Deps) SparkSubmitHandler(ctx context.Context, req mcp.CallToolRequest)
|
||||
// letting spark-submit produce a confusing FileNotFoundException later.
|
||||
// Placed after all required-string parses so error messages surface in
|
||||
// field order (cluster_id, master, ..., script_path, queue, ...).
|
||||
if _, err := d.UploadStore.Validate(scriptPath); err != nil {
|
||||
fileID, err := d.UploadStore.Validate(scriptPath)
|
||||
if err != nil {
|
||||
if d.Logger != nil {
|
||||
d.Logger.Warn("spark_submit.unminted_path_rejected", slog.String("path", scriptPath), slog.String("err", err.Error()))
|
||||
}
|
||||
@@ -173,35 +176,58 @@ func (d *Deps) SparkSubmitHandler(ctx context.Context, req mcp.CallToolRequest)
|
||||
})
|
||||
if err != nil {
|
||||
callLog.WithError(err)
|
||||
// Even on error, result carries ExitCode/Stderr for the LLM.
|
||||
if result != nil {
|
||||
callLog.WithResult(map[string]any{
|
||||
"binary": binary,
|
||||
"argv": cmd,
|
||||
"app_id": result.AppID,
|
||||
"exit_code": result.ExitCode,
|
||||
"duration_ms": result.DurationMS,
|
||||
})
|
||||
callLog.WithResult(sparkSubmitResultLog(binary, cmd, result))
|
||||
return textResult(encodeJSON(map[string]any{
|
||||
"app_id": result.AppID,
|
||||
"exit_code": result.ExitCode,
|
||||
"stdout_tail": result.StdoutTail,
|
||||
"stderr_tail": result.StderrTail,
|
||||
"duration_ms": result.DurationMS,
|
||||
"error": err.Error(),
|
||||
"app_id": result.AppID,
|
||||
"tracking_url": result.TrackingURL,
|
||||
"exit_code": result.ExitCode,
|
||||
"stdout_tail": result.StdoutTail,
|
||||
"stderr_tail": result.StderrTail,
|
||||
"duration_ms": result.DurationMS,
|
||||
"error": err.Error(),
|
||||
})), nil
|
||||
}
|
||||
return errResult("spark_submit: " + err.Error()), nil
|
||||
}
|
||||
|
||||
callLog.WithResult(map[string]any{
|
||||
if result.AppID != "" && d.SubmissionRepo != nil {
|
||||
sub := storage.Submission{
|
||||
FileID: fileID,
|
||||
AppID: result.AppID,
|
||||
TrackingURL: result.TrackingURL,
|
||||
ClusterID: clusterID,
|
||||
ExitCode: result.ExitCode,
|
||||
DurationMS: result.DurationMS,
|
||||
SubmittedAt: time.Now(),
|
||||
}
|
||||
if createErr := d.SubmissionRepo.Create(ctx, sub); createErr != nil {
|
||||
if d.Logger != nil {
|
||||
d.Logger.Warn("spark_submit.persist_failed", slog.String("file_id", fileID), slog.String("app_id", result.AppID), slog.String("err", createErr.Error()))
|
||||
} else {
|
||||
slog.Default().Warn("spark_submit.persist_failed", slog.String("file_id", fileID), slog.String("app_id", result.AppID), slog.String("err", createErr.Error()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
callLog.WithResult(sparkSubmitResultLog(binary, cmd, result))
|
||||
return textResult(encodeJSON(result)), nil
|
||||
}
|
||||
|
||||
// sparkSubmitResultLog builds the standard result map used for both logging
|
||||
// and the admin audit trail.
|
||||
func sparkSubmitResultLog(binary string, cmd []string, result *executor.Result) map[string]any {
|
||||
m := map[string]any{
|
||||
"binary": binary,
|
||||
"argv": cmd,
|
||||
"app_id": result.AppID,
|
||||
"exit_code": result.ExitCode,
|
||||
"duration_ms": result.DurationMS,
|
||||
})
|
||||
return textResult(encodeJSON(result)), nil
|
||||
}
|
||||
if result.TrackingURL != "" {
|
||||
m["tracking_url"] = result.TrackingURL
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// SparkSubmitCommandOpts holds the structured arguments used to build the
|
||||
|
||||
Reference in New Issue
Block a user