Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

Commit 40e39c7

Browse files
committed
Add ability to create new environments and images
1 parent 2d52bb3 commit 40e39c7

File tree

2 files changed

+182
-0
lines changed

2 files changed

+182
-0
lines changed

coder-sdk/env.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ package coder
22

33
import (
44
"context"
5+
"fmt"
56
"net/http"
67
"time"
78

9+
"nhooyr.io/websocket/wsjson"
10+
811
"cdr.dev/coder-cli/internal/x/xjson"
912
"nhooyr.io/websocket"
1013
)
@@ -75,3 +78,127 @@ func (c Client) DialWsep(ctx context.Context, env *Environment) (*websocket.Conn
7578
}
7679
return conn, nil
7780
}
81+
82+
// CreateEnvironmentRequest is used to configure a new environment
83+
type CreateEnvironmentRequest struct {
84+
Name string `json:"name"`
85+
ImageID string `json:"image_id"`
86+
ImageTag string `json:"image_tag"`
87+
CPUCores float32 `json:"cpu_cores"`
88+
MemoryGB int `json:"memory_gb"`
89+
DiskGB int `json:"disk_gb"`
90+
GPUs int `json:"gpus"`
91+
Services []string `json:"services"`
92+
}
93+
94+
// CreateEnvironment sends a request to create an environment.
95+
func (c Client) CreateEnvironment(ctx context.Context, orgID string, req CreateEnvironmentRequest) (Environment, error) {
96+
var env Environment
97+
err := c.requestBody(
98+
ctx,
99+
http.MethodPost, "/api/orgs/"+orgID+"/environments",
100+
req,
101+
&env,
102+
)
103+
return env, err
104+
}
105+
106+
type envUpdate struct {
107+
Type string `json:"type"`
108+
}
109+
110+
// WaitForEnvironmentReady watches the environment update websocket and waits for the "done" message type before returning.
111+
func (c Client) WaitForEnvironmentReady(ctx context.Context, envID string) error {
112+
u := c.copyURL()
113+
if c.BaseURL.Scheme == "https" {
114+
u.Scheme = "wss"
115+
} else {
116+
u.Scheme = "ws"
117+
}
118+
u.Path = "/api/environments/" + envID + "/watch-update"
119+
120+
conn, resp, err := websocket.Dial(ctx, u.String(),
121+
&websocket.DialOptions{
122+
HTTPHeader: map[string][]string{
123+
"Cookie": {"session_token=" + c.Token},
124+
},
125+
},
126+
)
127+
if err != nil {
128+
if resp != nil {
129+
return bodyError(resp)
130+
}
131+
return err
132+
}
133+
134+
for {
135+
m := envUpdate{}
136+
err = wsjson.Read(ctx, conn, &m)
137+
if err != nil {
138+
return fmt.Errorf("read ws json msg: %w", err)
139+
}
140+
if m.Type == "done" {
141+
break
142+
}
143+
}
144+
145+
return nil
146+
}
147+
148+
type stats struct {
149+
ContainerStatus string `json:"container_status"`
150+
StatError string `json:"stat_error"`
151+
Time string `json:"time"`
152+
}
153+
154+
// WatchEnvironmentStats watches the environment update websocket for a given duration.
155+
func (c Client) WatchEnvironmentStats(ctx context.Context, envID string, duration time.Duration) error {
156+
u := c.copyURL()
157+
if c.BaseURL.Scheme == "https" {
158+
u.Scheme = "wss"
159+
} else {
160+
u.Scheme = "ws"
161+
}
162+
u.Path = "/api/environments/" + envID + "/watch-stats"
163+
164+
conn, resp, err := websocket.Dial(ctx, u.String(),
165+
&websocket.DialOptions{
166+
HTTPHeader: map[string][]string{
167+
"Cookie": {"session_token=" + c.Token},
168+
},
169+
},
170+
)
171+
if err != nil {
172+
if resp != nil {
173+
return bodyError(resp)
174+
}
175+
return err
176+
}
177+
178+
statsCtx, statsCancel := context.WithTimeout(ctx, duration)
179+
defer statsCancel()
180+
181+
for {
182+
select {
183+
case <-statsCtx.Done():
184+
return nil
185+
default:
186+
m := stats{}
187+
err = wsjson.Read(ctx, conn, &m)
188+
if err != nil {
189+
return fmt.Errorf("read ws json msg: %w", err)
190+
}
191+
}
192+
}
193+
}
194+
195+
// DeleteEnvironment deletes the environment.
196+
func (c Client) DeleteEnvironment(ctx context.Context, envID string) error {
197+
err := c.requestBody(
198+
ctx,
199+
http.MethodDelete, "/api/environments/"+envID,
200+
nil,
201+
nil,
202+
)
203+
return err
204+
}

coder-sdk/image.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package coder
2+
3+
import (
4+
"context"
5+
"net/http"
6+
)
7+
8+
// Image describes a Coder Image
9+
type Image struct {
10+
ID string `json:"id"`
11+
OrganizationID string `json:"organization_id"`
12+
Repository string `json:"repository"`
13+
Description string `json:"description"`
14+
URL string `json:"url"` // user-supplied URL for image
15+
DefaultCPUCores float32 `json:"default_cpu_cores"`
16+
DefaultMemoryGB int `json:"default_memory_gb"`
17+
DefaultDiskGB int `json:"default_disk_gb"`
18+
Deprecated bool `json:"deprecated"`
19+
}
20+
21+
// NewRegistryRequest describes a docker registry used in importing an image
22+
type NewRegistryRequest struct {
23+
FriendlyName string `json:"friendly_name"`
24+
Registry string `json:"registry"`
25+
Username string `json:"username"`
26+
Password string `json:"password"`
27+
}
28+
29+
// ImportImageRequest is used to import new images and registries into Coder
30+
type ImportImageRequest struct {
31+
// RegistryID is used to import images to existing registries.
32+
RegistryID *string `json:"registry_id"`
33+
// NewRegistry is used when adding a new registry.
34+
NewRegistry *NewRegistryRequest `json:"new_registry"`
35+
// Repository refers to the image. For example: "codercom/ubuntu".
36+
Repository string `json:"repository"`
37+
Tag string `json:"tag"`
38+
DefaultCPUCores float32 `json:"default_cpu_cores"`
39+
DefaultMemoryGB int `json:"default_memory_gb"`
40+
DefaultDiskGB int `json:"default_disk_gb"`
41+
Description string `json:"description"`
42+
URL string `json:"url"`
43+
}
44+
45+
// ImportImage creates a new image and optionally a new registry
46+
func (c Client) ImportImage(ctx context.Context, orgID string, req ImportImageRequest) (Image, error) {
47+
var img Image
48+
err := c.requestBody(
49+
ctx,
50+
http.MethodPost, "/api/orgs/"+orgID+"/images",
51+
req,
52+
&img,
53+
)
54+
return img, err
55+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy