Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bdfa61a

Browse files
committed
feat: Add app support
This adds apps as a property to a workspace agent. The resource is added to the Terraform provider here: coder/terraform-provider-coder#17 Apps will be opened in the dashboard or via the CLI with `coder open <name>`. If `command` is specified, a terminal will appear locally and in the web. If `target` is specified, the browser will open to an exposed instance of that target.
1 parent 914a2f4 commit bdfa61a

23 files changed

+791
-214
lines changed

.vscode/settings.json

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"coderdtest",
88
"codersdk",
99
"devel",
10+
"apps",
1011
"drpc",
1112
"drpcconn",
1213
"drpcmux",

coderd/database/databasefake/databasefake.go

+54
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ func New() database.Store {
3434
templateVersions: make([]database.TemplateVersion, 0),
3535
templates: make([]database.Template, 0),
3636
workspaceBuilds: make([]database.WorkspaceBuild, 0),
37+
workspaceApps: make([]database.WorkspaceApp, 0),
3738
workspaces: make([]database.Workspace, 0),
3839
}
3940
}
@@ -62,6 +63,7 @@ type fakeQuerier struct {
6263
templateVersions []database.TemplateVersion
6364
templates []database.Template
6465
workspaceBuilds []database.WorkspaceBuild
66+
workspaceApps []database.WorkspaceApp
6567
workspaces []database.Workspace
6668
}
6769

@@ -328,6 +330,41 @@ func (q *fakeQuerier) GetWorkspaceByOwnerIDAndName(_ context.Context, arg databa
328330
return database.Workspace{}, sql.ErrNoRows
329331
}
330332

333+
func (q *fakeQuerier) GetWorkspaceAppsByAgentID(_ context.Context, id uuid.UUID) ([]database.WorkspaceApp, error) {
334+
q.mutex.RLock()
335+
defer q.mutex.RUnlock()
336+
337+
apps := make([]database.WorkspaceApp, 0)
338+
for _, app := range q.workspaceApps {
339+
if app.AgentID == id {
340+
apps = append(apps, app)
341+
}
342+
}
343+
if len(apps) == 0 {
344+
return nil, sql.ErrNoRows
345+
}
346+
return apps, nil
347+
}
348+
349+
func (q *fakeQuerier) GetWorkspaceAppsByAgentIDs(_ context.Context, ids []uuid.UUID) ([]database.WorkspaceApp, error) {
350+
q.mutex.RLock()
351+
defer q.mutex.RUnlock()
352+
353+
apps := make([]database.WorkspaceApp, 0)
354+
for _, app := range q.workspaceApps {
355+
for _, id := range ids {
356+
if app.AgentID.String() == id.String() {
357+
apps = append(apps, app)
358+
break
359+
}
360+
}
361+
}
362+
if len(apps) == 0 {
363+
return nil, sql.ErrNoRows
364+
}
365+
return apps, nil
366+
}
367+
331368
func (q *fakeQuerier) GetWorkspaceOwnerCountsByTemplateIDs(_ context.Context, templateIDs []uuid.UUID) ([]database.GetWorkspaceOwnerCountsByTemplateIDsRow, error) {
332369
q.mutex.RLock()
333370
defer q.mutex.RUnlock()
@@ -1353,6 +1390,23 @@ func (q *fakeQuerier) InsertWorkspaceBuild(_ context.Context, arg database.Inser
13531390
return workspaceBuild, nil
13541391
}
13551392

1393+
func (q *fakeQuerier) InsertWorkspaceApp(_ context.Context, arg database.InsertWorkspaceAppParams) (database.WorkspaceApp, error) {
1394+
q.mutex.Lock()
1395+
defer q.mutex.Unlock()
1396+
1397+
workspaceApp := database.WorkspaceApp{
1398+
ID: arg.ID,
1399+
AgentID: arg.AgentID,
1400+
CreatedAt: arg.CreatedAt,
1401+
Name: arg.Name,
1402+
Icon: arg.Icon,
1403+
Command: arg.Command,
1404+
Target: arg.Target,
1405+
}
1406+
q.workspaceApps = append(q.workspaceApps, workspaceApp)
1407+
return workspaceApp, nil
1408+
}
1409+
13561410
func (q *fakeQuerier) UpdateAPIKeyByID(_ context.Context, arg database.UpdateAPIKeyByIDParams) error {
13571411
q.mutex.Lock()
13581412
defer q.mutex.Unlock()

coderd/database/dump.sql

+19
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DROP TABLE workspace_apps;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CREATE TABLE workspace_apps (
2+
id uuid NOT NULL,
3+
created_at timestamp with time zone NOT NULL,
4+
agent_id uuid NOT NULL REFERENCES workspace_agents (id) ON DELETE CASCADE,
5+
name varchar(64) NOT NULL,
6+
icon varchar(256) NOT NULL,
7+
-- A command to run when opened.
8+
command varchar(65534),
9+
-- A URL or port to target.
10+
target varchar(65534),
11+
PRIMARY KEY (id),
12+
UNIQUE(agent_id, name)
13+
);

coderd/database/models.go

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/querier.go

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

+118
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-- name: GetWorkspaceAppsByAgentID :many
2+
SELECT * FROM workspace_apps WHERE agent_id = $1;
3+
4+
-- name: GetWorkspaceAppsByAgentIDs :many
5+
SELECT * FROM workspace_apps WHERE agent_id = ANY(@ids :: uuid [ ]);
6+
7+
-- name: InsertWorkspaceApp :one
8+
INSERT INTO
9+
workspace_apps (
10+
id,
11+
created_at,
12+
agent_id,
13+
name,
14+
icon,
15+
command,
16+
target
17+
)
18+
VALUES
19+
($1, $2, $3, $4, $5, $6, $7) RETURNING *;

coderd/provisionerdaemons.go

+22-1
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ func insertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.
625625
}
626626
}
627627

628-
_, err := db.InsertWorkspaceAgent(ctx, database.InsertWorkspaceAgentParams{
628+
dbAgent, err := db.InsertWorkspaceAgent(ctx, database.InsertWorkspaceAgentParams{
629629
ID: uuid.New(),
630630
CreatedAt: database.Now(),
631631
UpdatedAt: database.Now(),
@@ -645,6 +645,27 @@ func insertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.
645645
if err != nil {
646646
return xerrors.Errorf("insert agent: %w", err)
647647
}
648+
649+
for _, app := range agent.Apps {
650+
_, err := db.InsertWorkspaceApp(ctx, database.InsertWorkspaceAppParams{
651+
ID: uuid.New(),
652+
CreatedAt: database.Now(),
653+
AgentID: dbAgent.ID,
654+
Name: app.Name,
655+
Icon: app.Icon,
656+
Command: sql.NullString{
657+
String: app.Command,
658+
Valid: app.Command != "",
659+
},
660+
Target: sql.NullString{
661+
String: app.Target,
662+
Valid: app.Target != "",
663+
},
664+
})
665+
if err != nil {
666+
return xerrors.Errorf("insert app: %w", err)
667+
}
668+
}
648669
}
649670
return nil
650671
}

coderd/provisionerjobs.go

+22-1
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,20 @@ func (api *api) provisionerJobResources(rw http.ResponseWriter, r *http.Request,
209209
})
210210
return
211211
}
212+
resourceAgentIDs := make([]uuid.UUID, 0)
213+
for _, agent := range resourceAgents {
214+
resourceAgentIDs = append(resourceAgentIDs, agent.ID)
215+
}
216+
apps, err := api.Database.GetWorkspaceAppsByAgentIDs(r.Context(), resourceAgentIDs)
217+
if errors.Is(err, sql.ErrNoRows) {
218+
err = nil
219+
}
220+
if err != nil {
221+
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
222+
Message: fmt.Sprintf("get workspace apps: %s", err),
223+
})
224+
return
225+
}
212226

213227
apiResources := make([]codersdk.WorkspaceResource, 0)
214228
for _, resource := range resources {
@@ -217,7 +231,14 @@ func (api *api) provisionerJobResources(rw http.ResponseWriter, r *http.Request,
217231
if agent.ResourceID != resource.ID {
218232
continue
219233
}
220-
apiAgent, err := convertWorkspaceAgent(agent, api.AgentConnectionUpdateFrequency)
234+
dbApps := make([]database.WorkspaceApp, 0)
235+
for _, app := range apps {
236+
if app.AgentID == agent.ID {
237+
dbApps = append(dbApps, app)
238+
}
239+
}
240+
241+
apiAgent, err := convertWorkspaceAgent(agent, convertApps(dbApps), api.AgentConnectionUpdateFrequency)
221242
if err != nil {
222243
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
223244
Message: fmt.Sprintf("convert provisioner job agent: %s", err),

0 commit comments

Comments
 (0)