Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
189 lines
5.1 KiB
Go
189 lines
5.1 KiB
Go
package slurm
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
// DefaultBaseURL is the default Slurm REST API endpoint.
|
|
DefaultBaseURL = "http://localhost:6820/"
|
|
// DefaultUserAgent is the default User-Agent header value.
|
|
DefaultUserAgent = "slurm-go-sdk"
|
|
)
|
|
|
|
// Client manages communication with the Slurm REST API.
|
|
type Client struct {
|
|
client *http.Client
|
|
baseURL *url.URL
|
|
UserAgent string
|
|
|
|
common service
|
|
|
|
Jobs *JobsService
|
|
Nodes *NodesService
|
|
Partitions *PartitionsService
|
|
Reservations *ReservationsService
|
|
Diag *DiagService
|
|
Ping *PingService
|
|
Licenses *LicensesService
|
|
Reconfigure *ReconfigureService
|
|
Shares *SharesService
|
|
|
|
SlurmdbDiag *SlurmdbDiagService
|
|
SlurmdbConfig *SlurmdbConfigService
|
|
SlurmdbTres *SlurmdbTresService
|
|
SlurmdbQos *SlurmdbQosService
|
|
SlurmdbAssocs *SlurmdbAssocsService
|
|
SlurmdbInstances *SlurmdbInstancesService
|
|
SlurmdbUsers *SlurmdbUsersService
|
|
SlurmdbClusters *SlurmdbClustersService
|
|
SlurmdbWckeys *SlurmdbWckeysService
|
|
SlurmdbAccounts *SlurmdbAccountsService
|
|
SlurmdbJobs *SlurmdbJobsService
|
|
}
|
|
|
|
// service is the base struct for all API services.
|
|
type service struct {
|
|
client *Client
|
|
}
|
|
|
|
type JobsService service
|
|
type NodesService service
|
|
type PartitionsService service
|
|
type ReservationsService service
|
|
type DiagService service
|
|
type PingService service
|
|
type LicensesService service
|
|
type ReconfigureService service
|
|
type SharesService service
|
|
type SlurmdbDiagService service
|
|
type SlurmdbConfigService service
|
|
type SlurmdbTresService service
|
|
type SlurmdbQosService service
|
|
type SlurmdbAssocsService service
|
|
type SlurmdbInstancesService service
|
|
type SlurmdbUsersService service
|
|
type SlurmdbClustersService service
|
|
type SlurmdbWckeysService service
|
|
type SlurmdbAccountsService service
|
|
type SlurmdbJobsService service
|
|
|
|
// Response wraps an http.Response and will later hold Meta/Errors/Warnings
|
|
// fields parsed from Slurm API responses.
|
|
type Response struct {
|
|
*http.Response
|
|
}
|
|
|
|
// NewClient returns a new Slurm API client. If httpClient is nil,
|
|
// http.DefaultClient is used.
|
|
func NewClient(baseURL string, httpClient *http.Client) (*Client, error) {
|
|
if httpClient == nil {
|
|
httpClient = http.DefaultClient
|
|
}
|
|
|
|
parsedURL, err := url.Parse(baseURL)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid base URL %q: %w", baseURL, err)
|
|
}
|
|
if !strings.HasSuffix(parsedURL.Path, "/") {
|
|
parsedURL.Path += "/"
|
|
}
|
|
|
|
c := &Client{
|
|
client: httpClient,
|
|
baseURL: parsedURL,
|
|
UserAgent: DefaultUserAgent,
|
|
}
|
|
c.common.client = c
|
|
|
|
c.Jobs = (*JobsService)(&c.common)
|
|
c.Nodes = (*NodesService)(&c.common)
|
|
c.Partitions = (*PartitionsService)(&c.common)
|
|
c.Reservations = (*ReservationsService)(&c.common)
|
|
c.Diag = (*DiagService)(&c.common)
|
|
c.Ping = (*PingService)(&c.common)
|
|
c.Licenses = (*LicensesService)(&c.common)
|
|
c.Reconfigure = (*ReconfigureService)(&c.common)
|
|
c.Shares = (*SharesService)(&c.common)
|
|
|
|
c.SlurmdbDiag = (*SlurmdbDiagService)(&c.common)
|
|
c.SlurmdbConfig = (*SlurmdbConfigService)(&c.common)
|
|
c.SlurmdbTres = (*SlurmdbTresService)(&c.common)
|
|
c.SlurmdbQos = (*SlurmdbQosService)(&c.common)
|
|
c.SlurmdbAssocs = (*SlurmdbAssocsService)(&c.common)
|
|
c.SlurmdbInstances = (*SlurmdbInstancesService)(&c.common)
|
|
c.SlurmdbUsers = (*SlurmdbUsersService)(&c.common)
|
|
c.SlurmdbClusters = (*SlurmdbClustersService)(&c.common)
|
|
c.SlurmdbWckeys = (*SlurmdbWckeysService)(&c.common)
|
|
c.SlurmdbAccounts = (*SlurmdbAccountsService)(&c.common)
|
|
c.SlurmdbJobs = (*SlurmdbJobsService)(&c.common)
|
|
|
|
return c, nil
|
|
}
|
|
|
|
// NewRequest creates an API request. A relative URL path can be provided in
|
|
// urlStr, which will be resolved against the base URL of the Client.
|
|
// If body is not nil, it will be JSON-encoded and set as the request body.
|
|
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
|
|
u, err := c.baseURL.Parse(urlStr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid relative URL %q: %w", urlStr, err)
|
|
}
|
|
|
|
var buf io.Reader
|
|
if body != nil {
|
|
b, err := json.Marshal(body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to marshal request body: %w", err)
|
|
}
|
|
buf = bytes.NewReader(b)
|
|
}
|
|
|
|
req, err := http.NewRequest(method, u.String(), buf)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create request: %w", err)
|
|
}
|
|
|
|
if body != nil {
|
|
req.Header.Set("Content-Type", "application/json")
|
|
}
|
|
if c.UserAgent != "" {
|
|
req.Header.Set("User-Agent", c.UserAgent)
|
|
}
|
|
|
|
return req, nil
|
|
}
|
|
|
|
// Do sends an API request and returns the API response. The API response is
|
|
// JSON-decoded into the value pointed to by v (if v is not nil).
|
|
func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Response, error) {
|
|
req = req.WithContext(ctx)
|
|
|
|
resp, err := c.client.Do(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("request failed: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if err := CheckResponse(resp); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
response := &Response{Response: resp}
|
|
|
|
if v != nil {
|
|
if err := json.NewDecoder(resp.Body).Decode(v); err != nil {
|
|
return response, fmt.Errorf("failed to decode response: %w", err)
|
|
}
|
|
}
|
|
|
|
return response, nil
|
|
}
|