From af6e77c6caef9953db00e795758909fe06b88c09 Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Fri, 21 Aug 2020 15:02:39 -0500 Subject: [PATCH] Add ability to create new environments and images --- coder-sdk/env.go | 66 ++++++++++++++++++++++++++++++---------------- coder-sdk/image.go | 55 ++++++++++++++++++++++++++++++++++++++ coder-sdk/ws.go | 33 +++++++++++++++++++++++ 3 files changed, 131 insertions(+), 23 deletions(-) create mode 100644 coder-sdk/image.go create mode 100644 coder-sdk/ws.go diff --git a/coder-sdk/env.go b/coder-sdk/env.go index 7f0a6573..c8f346be 100644 --- a/coder-sdk/env.go +++ b/coder-sdk/env.go @@ -34,6 +34,30 @@ type Environment struct { AutoOffThreshold xjson.Duration `json:"auto_off_threshold" tab:"-"` } +// CreateEnvironmentRequest is used to configure a new environment +type CreateEnvironmentRequest struct { + Name string `json:"name"` + ImageID string `json:"image_id"` + ImageTag string `json:"image_tag"` + CPUCores float32 `json:"cpu_cores"` + MemoryGB int `json:"memory_gb"` + DiskGB int `json:"disk_gb"` + GPUs int `json:"gpus"` + Services []string `json:"services"` +} + +// CreateEnvironment sends a request to create an environment. +func (c Client) CreateEnvironment(ctx context.Context, orgID string, req CreateEnvironmentRequest) (*Environment, error) { + var env *Environment + err := c.requestBody( + ctx, + http.MethodPost, "/api/orgs/"+orgID+"/environments", + req, + env, + ) + return env, err +} + // EnvironmentsByOrganization gets the list of environments owned by the given user. func (c Client) EnvironmentsByOrganization(ctx context.Context, userID, orgID string) ([]Environment, error) { var envs []Environment @@ -46,32 +70,28 @@ func (c Client) EnvironmentsByOrganization(ctx context.Context, userID, orgID st return envs, err } +// DeleteEnvironment deletes the environment. +func (c Client) DeleteEnvironment(ctx context.Context, envID string) error { + return c.requestBody( + ctx, + http.MethodDelete, "/api/environments/"+envID, + nil, + nil, + ) +} + // DialWsep dials an environments command execution interface // See github.com/cdr/wsep for details func (c Client) DialWsep(ctx context.Context, env *Environment) (*websocket.Conn, error) { - u := c.copyURL() - if c.BaseURL.Scheme == "https" { - u.Scheme = "wss" - } else { - u.Scheme = "ws" - } - u.Path = "/proxy/environments/" + env.ID + "/wsep" + return c.dialWs(ctx, "/proxy/environments/"+env.ID+"/wsep") +} - ctx, cancel := context.WithTimeout(ctx, time.Second*15) - defer cancel() +// DialEnvironmentBuildLog opens a websocket connection for the environment build log messages +func (c Client) DialEnvironmentBuildLog(ctx context.Context, envID string) (*websocket.Conn, error) { + return c.dialWs(ctx, "/api/environments/"+envID+"/watch-update") +} - conn, resp, err := websocket.Dial(ctx, u.String(), - &websocket.DialOptions{ - HTTPHeader: map[string][]string{ - "Cookie": {"session_token=" + c.Token}, - }, - }, - ) - if err != nil { - if resp != nil { - return nil, bodyError(resp) - } - return nil, err - } - return conn, nil +// DialEnvironmentStats opens a websocket connection for environment stats +func (c Client) DialEnvironmentStats(ctx context.Context, envID string) (*websocket.Conn, error) { + return c.dialWs(ctx, "/api/environments/"+envID+"/watch-stats") } diff --git a/coder-sdk/image.go b/coder-sdk/image.go new file mode 100644 index 00000000..87ad584f --- /dev/null +++ b/coder-sdk/image.go @@ -0,0 +1,55 @@ +package coder + +import ( + "context" + "net/http" +) + +// Image describes a Coder Image +type Image struct { + ID string `json:"id"` + OrganizationID string `json:"organization_id"` + Repository string `json:"repository"` + Description string `json:"description"` + URL string `json:"url"` // user-supplied URL for image + DefaultCPUCores float32 `json:"default_cpu_cores"` + DefaultMemoryGB int `json:"default_memory_gb"` + DefaultDiskGB int `json:"default_disk_gb"` + Deprecated bool `json:"deprecated"` +} + +// NewRegistryRequest describes a docker registry used in importing an image +type NewRegistryRequest struct { + FriendlyName string `json:"friendly_name"` + Registry string `json:"registry"` + Username string `json:"username"` + Password string `json:"password"` +} + +// ImportImageRequest is used to import new images and registries into Coder +type ImportImageRequest struct { + // RegistryID is used to import images to existing registries. + RegistryID *string `json:"registry_id"` + // NewRegistry is used when adding a new registry. + NewRegistry *NewRegistryRequest `json:"new_registry"` + // Repository refers to the image. For example: "codercom/ubuntu". + Repository string `json:"repository"` + Tag string `json:"tag"` + DefaultCPUCores float32 `json:"default_cpu_cores"` + DefaultMemoryGB int `json:"default_memory_gb"` + DefaultDiskGB int `json:"default_disk_gb"` + Description string `json:"description"` + URL string `json:"url"` +} + +// ImportImage creates a new image and optionally a new registry +func (c Client) ImportImage(ctx context.Context, orgID string, req ImportImageRequest) (*Image, error) { + var img *Image + err := c.requestBody( + ctx, + http.MethodPost, "/api/orgs/"+orgID+"/images", + req, + img, + ) + return img, err +} diff --git a/coder-sdk/ws.go b/coder-sdk/ws.go new file mode 100644 index 00000000..d2569377 --- /dev/null +++ b/coder-sdk/ws.go @@ -0,0 +1,33 @@ +package coder + +import ( + "context" + + "nhooyr.io/websocket" +) + +func (c Client) dialWs(ctx context.Context, path string) (*websocket.Conn, error) { + u := c.copyURL() + if c.BaseURL.Scheme == "https" { + u.Scheme = "wss" + } else { + u.Scheme = "ws" + } + u.Path = path + + conn, resp, err := websocket.Dial(ctx, u.String(), + &websocket.DialOptions{ + HTTPHeader: map[string][]string{ + "Session-Token": {c.Token}, + }, + }, + ) + if err != nil { + if resp != nil { + return nil, bodyError(resp) + } + return nil, err + } + + return conn, nil +}