Skip to content

feat: allow specifying devcontainer on agent in terraform #16997

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Mar 20, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: add agent devcontainers from provision
  • Loading branch information
mafredri committed Mar 20, 2025
commit 76bf36bceaeb79dc2edbe83723ca9e0ad973d980
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE workspace_agent_devcontainers;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
CREATE TABLE workspace_agent_devcontainers (
id UUID PRIMARY KEY,
workspace_agent_id UUID NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
workspace_folder TEXT NOT NULL,
config_path TEXT NOT NULL,
FOREIGN KEY (workspace_agent_id) REFERENCES workspace_agents(id) ON DELETE CASCADE
);

COMMENT ON TABLE workspace_agent_devcontainers IS 'Workspace agent devcontainer configuration';
COMMENT ON COLUMN workspace_agent_devcontainers.id IS 'Unique identifier';
COMMENT ON COLUMN workspace_agent_devcontainers.workspace_agent_id IS 'Workspace agent foreign key';
COMMENT ON COLUMN workspace_agent_devcontainers.created_at IS 'Creation timestamp';
COMMENT ON COLUMN workspace_agent_devcontainers.workspace_folder IS 'Workspace folder';
COMMENT ON COLUMN workspace_agent_devcontainers.config_path IS 'Path to devcontainer.json.';
10 changes: 10 additions & 0 deletions coderd/database/queries/workspaceagentdevcontainers.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- name: InsertWorkspaceAgentDevcontainers :many
INSERT INTO
workspace_agent_devcontainers (workspace_agent_id, created_at, id, workspace_folder, config_path)
SELECT
@workspace_agent_id::uuid AS workspace_agent_id,
@created_at::timestamptz AS created_at,
unnest(@id::uuid[]) AS id,
unnest(@workspace_folder::text[]) AS workspace_folder,
unnest(@config_path::text[]) AS config_path
RETURNING workspace_agent_devcontainers.*;
24 changes: 24 additions & 0 deletions coderd/provisionerdserver/provisionerdserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2096,6 +2096,30 @@ func InsertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.
return xerrors.Errorf("insert agent scripts: %w", err)
}

if devcontainers := prAgent.GetDevcontainers(); len(devcontainers) > 0 {
var (
devContainerIDs = make([]uuid.UUID, 0, len(devcontainers))
devContainerWorkspaceFolders = make([]string, 0, len(devcontainers))
devContainerConfigPaths = make([]string, 0, len(devcontainers))
)
for _, dc := range devcontainers {
devContainerIDs = append(devContainerIDs, uuid.New())
devContainerWorkspaceFolders = append(devContainerWorkspaceFolders, dc.WorkspaceFolder)
devContainerConfigPaths = append(devContainerConfigPaths, dc.ConfigPath)
}

_, err = db.InsertWorkspaceAgentDevcontainers(ctx, database.InsertWorkspaceAgentDevcontainersParams{
WorkspaceAgentID: agentID,
CreatedAt: dbtime.Now(),
ID: devContainerIDs,
WorkspaceFolder: devContainerWorkspaceFolders,
ConfigPath: devContainerConfigPaths,
})
if err != nil {
return xerrors.Errorf("insert agent devcontainer: %w", err)
}
}

for _, app := range prAgent.Apps {
// Similar logic is duplicated in terraform/resources.go.
slug := app.Slug
Expand Down
1 change: 1 addition & 0 deletions codersdk/agentsdk/agentsdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ type Manifest struct {
DisableDirectConnections bool `json:"disable_direct_connections"`
Metadata []codersdk.WorkspaceAgentMetadataDescription `json:"metadata"`
Scripts []codersdk.WorkspaceAgentScript `json:"scripts"`
Devcontainers []codersdk.WorkspaceAgentDevcontainer `json:"devcontainers"`
}

type LogSource struct {
Expand Down
8 changes: 8 additions & 0 deletions codersdk/workspaceagents.go
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,14 @@ func (c *Client) WorkspaceAgentListeningPorts(ctx context.Context, agentID uuid.
return listeningPorts, json.NewDecoder(res.Body).Decode(&listeningPorts)
}

// WorkspaceAgentDevcontainer defines the location of a devcontainer
// configuration in a workspace that is visible to the workspace agent.
type WorkspaceAgentDevcontainer struct {
ID uuid.UUID `json:"id" format:"uuid"`
WorkspaceFolder string `json:"workspace_folder"`
ConfigPath string `json:"config_path,omitempty"`
}

// WorkspaceAgentContainer describes a devcontainer of some sort
// that is visible to the workspace agent. This struct is an abstraction
// of potentially multiple implementations, and the fields will be
Expand Down
13 changes: 13 additions & 0 deletions provisioner/terraform/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ type agentAttributes struct {
DisplayApps []agentDisplayAppsAttributes `mapstructure:"display_apps"`
Order int64 `mapstructure:"order"`
ResourcesMonitoring []agentResourcesMonitoring `mapstructure:"resources_monitoring"`
Devcontainers []agentDevcontainer `mapstructure:"devcontainers"`
}

type agentDevcontainer struct {
WorkspaceFolder string `mapstructure:"workspace_folder"`
ConfigPath string `mapstructure:"config_path"`
}

type agentResourcesMonitoring struct {
Expand Down Expand Up @@ -347,6 +353,13 @@ func ConvertState(ctx context.Context, modules []*tfjson.StateModule, rawGraph s
agent.Auth = &proto.Agent_InstanceId{}
}

for _, devcontainer := range attrs.Devcontainers {
agent.Devcontainers = append(agent.Devcontainers, &proto.Devcontainer{
WorkspaceFolder: devcontainer.WorkspaceFolder,
ConfigPath: devcontainer.ConfigPath,
})
}

// The label is used to find the graph node!
agentLabel := convertAddressToLabel(tfResource.Address)

Expand Down
6 changes: 6 additions & 0 deletions provisionersdk/proto/provisioner.proto
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ message Agent {
repeated Env extra_envs = 22;
int64 order = 23;
ResourcesMonitoring resources_monitoring = 24;
repeated Devcontainer devcontainers = 25;
}

enum AppSharingLevel {
Expand Down Expand Up @@ -191,6 +192,11 @@ message Script {
string log_path = 9;
}

message Devcontainer {
string workspace_folder = 1;
string config_path = 2;
}

enum AppOpenIn {
WINDOW = 0 [deprecated = true];
SLIM_WINDOW = 1;
Expand Down