diff --git a/.gitignore b/.gitignore index e660fd9..66c8265 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ bin/ +app.log \ No newline at end of file diff --git a/cli/api/api_client.go b/cli/api/api_client.go new file mode 100644 index 0000000..ab8b453 --- /dev/null +++ b/cli/api/api_client.go @@ -0,0 +1,117 @@ +package cli + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" +) + +type APIClient struct { + BaseURL string +} + +// Make new API client +func NewAPIClient(baseURL string) *APIClient{ + return &APIClient{BaseURL: baseURL} +} + +func (c *APIClient) SubmitJob(script string, compute string) (string, error) { + payload := map[string]string{ + "script": script, + "compute": compute, + } + + bodyBytes, err := json.Marshal(payload) + if err != nil { + return "", err + } + + url := c.BaseURL + "/jobs" + resp, err := http.Post(url, "application.json", bytes.NewBuffer(bodyBytes)) + + if err != nil { + return "", err + } + defer resp.Body.Close() + + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + + return string(respBody), nil +} + +func (c *APIClient) GetJobStatus(jobID string) (string, error){ + url := fmt.Sprintf("%s/jobs/status?id=%s", c.BaseURL, jobID) + + resp, err := http.Get(url) + if err != nil { + return "", err + } + + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + + if resp.StatusCode != http.StatusOK{ + return "", fmt.Errorf("server return %s: %s", resp.Status, body) + } + + return string(body), nil +} + +func (c *APIClient) GetSupervisors(active bool) (string, error){ + url := c.BaseURL + "/supervisors" + if active { + url += "?active=true" + } + + resp, err := http.Get(url) + if err != nil { + return "", err + } + + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + return string(body), nil +} + +func (c * APIClient) GetAllSupervisorsStatuses() (string, error) { + url := c.BaseURL + "/supervisors/status" + + resp, err := http.Get(url) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + return string(body), nil +} + +func (c * APIClient) GetSupervisorStatusByID(id string) (string, error) { + url := fmt.Sprintf("%s/supervisors/status/%s", c.BaseURL, id) + resp, err := http.Get(url) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + return string(body), nil +} \ No newline at end of file diff --git a/cli/cmd/job_cancel_test.go b/cli/cmd/job_cancel_test.go index eff91c6..487b2c0 100644 --- a/cli/cmd/job_cancel_test.go +++ b/cli/cmd/job_cancel_test.go @@ -2,7 +2,7 @@ package cmd import ( "testing" - "fmt" + // "fmt" ) diff --git a/cli/cmd/job_status.go b/cli/cmd/job_status.go index cff9187..27a78df 100644 --- a/cli/cmd/job_status.go +++ b/cli/cmd/job_status.go @@ -2,9 +2,10 @@ package cmd import ( "fmt" - "os" - "text/tabwriter" - "time" + // "os" + // "text/tabwriter" + // "time" + "mist/cli/api" ) type JobStatusCmd struct { @@ -12,36 +13,51 @@ type JobStatusCmd struct { } func (j *JobStatusCmd) Run() error { - // Mock data - pull from API in real implementation - jobs := []Job{{ - ID: "ID:1", - Name: "docker_container_name_1", - Status: "Running", - GPUType: "AMD", - CreatedAt: time.Now(), - }} - - job, err := findJobByID(jobs, j.ID) + // Mock data implementatino + // jobs := []Job{{ + // ID: "ID:1", + // Name: "docker_container_name_1", + // Status: "Running", + // GPUType: "AMD", + // CreatedAt: time.Now(), + // }} + + // job, err := findJobByID(jobs, j.ID) + // if err != nil { + // fmt.Printf("%s does not exist in your jobs.\n", j.ID) + // fmt.Printf("Use the command \"job list\" for your list of jobs.") + // return nil + // } + + // println("Checking status for job ID:", j.ID) + // w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) + // fmt.Fprintln(w, "Job ID\tName\tStatus\tGPU Type\tCreated At") + // fmt.Fprintln(w, "--------------------------------------------------------------") + + // fmt.Fprintf( + // w, + // "%s\t%s\t%s\t%s\t%s\n", + // job.ID, + // job.Name, + // job.Status, + // job.GPUType, + // job.CreatedAt.Format(time.RFC1123), + // ) + // w.Flush() + // return nil + + client := cli.NewAPIClient("http://localhost:3000") + + fmt.Println("Checking status for job ID: ", j.ID) + status, err := client.GetJobStatus(j.ID) + if err != nil { - fmt.Printf("%s does not exist in your jobs.\n", j.ID) - fmt.Printf("Use the command \"job list\" for your list of jobs.") - return nil + fmt.Println("Error fetching job status:", err) + return nil } - println("Checking status for job ID:", j.ID) - w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) - fmt.Fprintln(w, "Job ID\tName\tStatus\tGPU Type\tCreated At") - fmt.Fprintln(w, "--------------------------------------------------------------") - - fmt.Fprintf( - w, - "%s\t%s\t%s\t%s\t%s\n", - job.ID, - job.Name, - job.Status, - job.GPUType, - job.CreatedAt.Format(time.RFC1123), - ) - w.Flush() - return nil + fmt.Println("Server response:") + fmt.Println(status) + + return nil } diff --git a/cli/cmd/job_submit.go b/cli/cmd/job_submit.go index d090934..818a1a2 100644 --- a/cli/cmd/job_submit.go +++ b/cli/cmd/job_submit.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "strings" + "mist/cli/api" ) type JobSubmitCmd struct { @@ -47,10 +48,23 @@ func (j *JobSubmitCmd) Run() error { if input == "y" || input == "yes" { fmt.Println("Confirmed, proceeding...") + // Using API Client + client := cli.NewAPIClient("http://localhost:3000") + resp, err := client.SubmitJob(j.Script, j.Compute) + if err != nil { + fmt.Println("Error submitting job:", err) + return err + } + + // CONFIRMED LOGIC - fmt.Println("Submitting job with script:", j.Script) - fmt.Println("Requested GPU type:", j.Compute) - println("Job submitted successfully with ID: job_12345") + // fmt.Println("Submitting job with script:", j.Script) + // fmt.Println("Requested GPU type:", j.Compute) + // println("Job submitted successfully with ID: job_12345") + + // CONFIRMED JOB SUBMISSION + fmt.Println("Job submitted successfully!!!") + fmt.Println("Server response:", resp) return nil diff --git a/cli/cmd/root.go b/cli/cmd/root.go index dc03e11..9456e18 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -11,6 +11,7 @@ type CLI struct { // Config ConfigCmd `cmd:"" help:"Configuration commands"` Help HelpCmd `cmd:"" help:"Show help information"` Config ConfigCmd `cmd:"" help: "Display Cluster Configuration"` + Supervisor SupervisorCmd `cmd:"" help:"Supervisor commands"` } func Main() { diff --git a/cli/cmd/supervisor.go b/cli/cmd/supervisor.go new file mode 100644 index 0000000..f42e830 --- /dev/null +++ b/cli/cmd/supervisor.go @@ -0,0 +1,10 @@ +package cmd + +type SupervisorCmd struct { + List SupervisorListCmd `cmd:"" help:"List all supervisors"` + Status SupervisorStatusCmd `cmd:"" help:"View supervisor status"` +} + +func(s *SupervisorCmd) Run() error{ + return nil +} \ No newline at end of file diff --git a/cli/cmd/supervisor_list.go b/cli/cmd/supervisor_list.go new file mode 100644 index 0000000..ae3f159 --- /dev/null +++ b/cli/cmd/supervisor_list.go @@ -0,0 +1,26 @@ +package cmd +import ( + // "encoding/json" + "fmt" + // "strings" + "mist/cli/api" +) + +type SupervisorListCmd struct { + // --active flag + Active bool "help: Show only active supervisors" +} + +func (s *SupervisorListCmd) Run() error { + client := cli.NewAPIClient("http://localhost:3000") + + raw, err := client.GetSupervisors(s.Active) + if err != nil { + fmt.Println("Error: ", err) + return nil + } + + fmt.Println("Supervisor List Response: ", raw) + return nil + // We can pretty this up later, hence raw +} \ No newline at end of file diff --git a/cli/cmd/supervisor_list_test.go b/cli/cmd/supervisor_list_test.go new file mode 100644 index 0000000..82c7729 --- /dev/null +++ b/cli/cmd/supervisor_list_test.go @@ -0,0 +1,19 @@ +package cmd + +import ( + "testing" + // "fmt" +) + +// Right now supervisors should be empty! Add more in the future. +func TestSupervisorDoesNotExist(t *testing.T){ + cmd := &SupervisorListCmd{Active: true} + output := CaptureOutput( func() { + _ = cmd.Run() + }) + + want := "Supervisor List Response: {\"active_only\":true,\"count\":0,\"supervisors\":null}\n\n" + if !contains(output, want){ + t.Errorf("expected output to contain %q, got %q", want, output) + } +} diff --git a/cli/cmd/supervisor_status.go b/cli/cmd/supervisor_status.go new file mode 100644 index 0000000..41535aa --- /dev/null +++ b/cli/cmd/supervisor_status.go @@ -0,0 +1,37 @@ +package cmd +import ( + "fmt" + "mist/cli/api" + // "strings" +) + +// Support both /status and /status/ID endpoints +type SupervisorStatusCmd struct { + ID string `arg:"" optional help: "Supervisor ID (optional)"` +} + +func(s *SupervisorStatusCmd) Run() error { + client := cli.NewAPIClient("http://localhost:3000") + + if s.ID == "" { + raw, err := client.GetAllSupervisorsStatuses() + if err != nil { + fmt.Println("Error: ", err) + return nil + } + + fmt.Println("All Supervisor Status Response: ", raw) + return nil + } + + raw, err := client.GetSupervisorStatusByID(s.ID) + if err != nil { + fmt.Println("Error: ", err) + return nil + } + + fmt.Println("Supervisor Status by ID Response: ", raw) + return nil + + // We can pretty this up later, most likely to JSON format, hence raw +} \ No newline at end of file diff --git a/cli/cmd/supervisor_status_test.go b/cli/cmd/supervisor_status_test.go new file mode 100644 index 0000000..b9ddde4 --- /dev/null +++ b/cli/cmd/supervisor_status_test.go @@ -0,0 +1,32 @@ +package cmd + +import ( + "testing" + // "fmt" +) + +// Should return nothing for now...? No supervisors are being made + +func TestGetAllSupervisorsStatusesEmpty(t * testing.T){ + cmd := &SupervisorStatusCmd{} + output := CaptureOutput( func() { + _ = cmd.Run() + }) + + want := "All Supervisor Status Response: {\"count\":0,\"supervisors\":null}\n\n" + if !contains(output, want){ + t.Errorf("expected output to contain %q, got %q", want, output) + } +} + +func TestGetSupervisorByIDEmpty(t * testing.T){ + cmd := &SupervisorStatusCmd{ID: "123"} + output := CaptureOutput( func() { + _ = cmd.Run() + }) + + want := "Supervisor Status by ID Response: supervisor not found\n\n" + if !contains(output, want){ + t.Errorf("expected output to contain %q, got %q", want, output) + } +} \ No newline at end of file