package main import ( "context" "encoding/json" "flag" "fmt" "io" "log" "net/http" "os" "strconv" "strings" "gcy_hpc_server/internal/mockserver" "gcy_hpc_server/internal/model" "gcy_hpc_server/internal/slurm" ) func main() { defaultPort := 8080 if v := os.Getenv("MOCK_PORT"); v != "" { if p, err := strconv.Atoi(v); err == nil { defaultPort = p } } port := flag.Int("port", defaultPort, "listen port") seed := flag.Bool("seed", true, "inject seed data") flag.Parse() srv, err := mockserver.New(mockserver.WithPort(*port)) if err != nil { log.Fatalf("failed to create server: %v", err) } if *seed { injectSeedData(srv) } if err := srv.Run(); err != nil { log.Fatalf("server error: %v", err) } } func injectSeedData(srv *mockserver.Server) { client := srv.MockSlurmHTTPClient() baseURL := srv.MockSlurmURL() type jobDef struct { name string partition string states []string } jobs := []jobDef{ {"gpu-training-job", "gpu", nil}, {"data-processing", "normal", []string{"RUNNING"}}, {"benchmark-test", "normal", []string{"RUNNING"}}, {"model-evaluation", "gpu", []string{"RUNNING", "COMPLETED"}}, {"failed-script", "normal", []string{"RUNNING", "FAILED"}}, {"cancelled-job", "gpu", []string{"RUNNING", "CANCELLED"}}, } mockSlurm := srv.MockSlurm() for _, j := range jobs { id, err := submitJob(client, baseURL, j.name, j.partition) if err != nil { log.Printf("warning: failed to submit job %q: %v", j.name, err) continue } for _, state := range j.states { mockSlurm.SetJobState(id, state) } } appSvc := srv.ApplicationService() ctx := context.Background() apps := []model.CreateApplicationRequest{ { Name: "图像分类训练", Description: "基于ResNet的图像分类模型训练", ScriptTemplate: "#!/bin/bash\n#SBATCH --job-name={{.Name}}\necho 'Running {{.Name}}'", }, { Name: "数据处理流水线", Description: "ETL数据处理脚本", ScriptTemplate: "#!/bin/bash\necho 'Processing data'", }, } for _, app := range apps { if _, err := appSvc.CreateApplication(ctx, &app); err != nil { log.Printf("warning: failed to create application %q: %v", app.Name, err) } } log.Println("Seeded 6 jobs (1 PENDING, 2 RUNNING, 1 COMPLETED, 1 FAILED, 1 CANCELLED) and 2 applications") } func submitJob(client *http.Client, baseURL, name, partition string) (int32, error) { body := fmt.Sprintf( `{"script":"#!/bin/bash\necho %s","job":{"name":"%s","partition":"%s"}}`, name, name, partition, ) req, err := http.NewRequest("POST", baseURL+"/slurm/v0.0.40/job/submit", strings.NewReader(body)) if err != nil { return 0, fmt.Errorf("create request: %w", err) } req.Header.Set("Content-Type", "application/json") resp, err := client.Do(req) if err != nil { return 0, fmt.Errorf("do request: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { b, _ := io.ReadAll(resp.Body) return 0, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, b) } var result slurm.OpenapiJobSubmitResponse if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return 0, fmt.Errorf("decode response: %w", err) } if result.JobID == nil { return 0, fmt.Errorf("no job_id in response") } return *result.JobID, nil }