Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
3 changes: 2 additions & 1 deletion coderd/coderdtest/authorize.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ func NewAuthTester(ctx context.Context, t *testing.T, client *codersdk.Client, a
Id: "something",
Auth: &proto.Agent_Token{},
Apps: []*proto.App{{
Slug: "testapp",
Name: "testapp",
Url: "http://localhost:3000",
}},
Expand Down Expand Up @@ -371,7 +372,7 @@ func NewAuthTester(ctx context.Context, t *testing.T, client *codersdk.Client, a
"{template}": template.ID.String(),
"{fileID}": file.ID.String(),
"{workspaceresource}": workspace.LatestBuild.Resources[0].ID.String(),
"{workspaceapp}": workspace.LatestBuild.Resources[0].Agents[0].Apps[0].Name,
"{workspaceapp}": workspace.LatestBuild.Resources[0].Agents[0].Apps[0].Slug,
"{templateversion}": version.ID.String(),
"{jobID}": templateVersionDryRun.ID.String(),
"{templatename}": template.Name,
Expand Down
5 changes: 3 additions & 2 deletions coderd/database/databasefake/databasefake.go
Original file line number Diff line number Diff line change
Expand Up @@ -1705,15 +1705,15 @@ func (q *fakeQuerier) GetWorkspaceAgentsCreatedAfter(_ context.Context, after ti
return workspaceAgents, nil
}

func (q *fakeQuerier) GetWorkspaceAppByAgentIDAndName(_ context.Context, arg database.GetWorkspaceAppByAgentIDAndNameParams) (database.WorkspaceApp, error) {
func (q *fakeQuerier) GetWorkspaceAppByAgentIDAndSlug(_ context.Context, arg database.GetWorkspaceAppByAgentIDAndSlugParams) (database.WorkspaceApp, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()

for _, app := range q.workspaceApps {
if app.AgentID != arg.AgentID {
continue
}
if app.Name != arg.Name {
if app.Slug != arg.Slug {
continue
}
return app, nil
Expand Down Expand Up @@ -2362,6 +2362,7 @@ func (q *fakeQuerier) InsertWorkspaceApp(_ context.Context, arg database.InsertW
ID: arg.ID,
AgentID: arg.AgentID,
CreatedAt: arg.CreatedAt,
Slug: arg.Slug,
Name: arg.Name,
Icon: arg.Icon,
Command: arg.Command,
Expand Down
3 changes: 2 additions & 1 deletion coderd/database/dump.sql

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions coderd/database/migrations/000061_app_slug.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- drop "slug" column from "workspace_apps" table
ALTER TABLE "workspace_apps" DROP COLUMN "slug";
9 changes: 9 additions & 0 deletions coderd/database/migrations/000061_app_slug.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- add "slug" column to "workspace_apps" table
ALTER TABLE "workspace_apps" ADD COLUMN "slug" text DEFAULT '';

-- copy the "name" column for each workspace app to the "slug" column
UPDATE "workspace_apps" SET "slug" = "name";

-- make "slug" column not nullable and remove default
ALTER TABLE "workspace_apps" ALTER COLUMN "slug" SET NOT NULL;
ALTER TABLE "workspace_apps" ALTER COLUMN "slug" DROP DEFAULT;
1 change: 1 addition & 0 deletions coderd/database/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion coderd/database/querier.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 18 additions & 10 deletions coderd/database/queries.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 7 additions & 6 deletions coderd/database/queries/workspaceapps.sql
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
-- name: GetWorkspaceAppsByAgentID :many
SELECT * FROM workspace_apps WHERE agent_id = $1 ORDER BY name ASC;
SELECT * FROM workspace_apps WHERE agent_id = $1 ORDER BY slug ASC;

-- name: GetWorkspaceAppsByAgentIDs :many
SELECT * FROM workspace_apps WHERE agent_id = ANY(@ids :: uuid [ ]) ORDER BY name ASC;
SELECT * FROM workspace_apps WHERE agent_id = ANY(@ids :: uuid [ ]) ORDER BY slug ASC;

-- name: GetWorkspaceAppByAgentIDAndName :one
SELECT * FROM workspace_apps WHERE agent_id = $1 AND name = $2;
-- name: GetWorkspaceAppByAgentIDAndSlug :one
SELECT * FROM workspace_apps WHERE agent_id = $1 AND slug = $2;

-- name: GetWorkspaceAppsCreatedAfter :many
SELECT * FROM workspace_apps WHERE created_at > $1 ORDER BY name ASC;
SELECT * FROM workspace_apps WHERE created_at > $1 ORDER BY slug ASC;

-- name: InsertWorkspaceApp :one
INSERT INTO
workspace_apps (
id,
created_at,
agent_id,
slug,
name,
icon,
command,
Expand All @@ -28,7 +29,7 @@ INSERT INTO
health
)
VALUES
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING *;
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) RETURNING *;

-- name: UpdateWorkspaceAppHealthByID :exec
UPDATE
Expand Down
22 changes: 11 additions & 11 deletions coderd/httpapi/url.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ var (
// Remove the "starts with" and "ends with" regex components.
nameRegex = strings.Trim(UsernameValidRegex.String(), "^$")
appURL = regexp.MustCompile(fmt.Sprintf(
// {PORT/APP_NAME}--{AGENT_NAME}--{WORKSPACE_NAME}--{USERNAME}
`^(?P<AppName>%[1]s)--(?P<AgentName>%[1]s)--(?P<WorkspaceName>%[1]s)--(?P<Username>%[1]s)$`,
// {PORT/APP_SLUG}--{AGENT_NAME}--{WORKSPACE_NAME}--{USERNAME}
`^(?P<AppSlug>%[1]s)--(?P<AgentName>%[1]s)--(?P<WorkspaceName>%[1]s)--(?P<Username>%[1]s)$`,
nameRegex))

validHostnameLabelRegex = regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?$`)
)

// ApplicationURL is a parsed application URL hostname.
type ApplicationURL struct {
// Only one of AppName or Port will be set.
AppName string
// Only one of AppSlug or Port will be set.
AppSlug string
Port uint16
AgentName string
WorkspaceName string
Expand All @@ -34,12 +34,12 @@ type ApplicationURL struct {
// String returns the application URL hostname without scheme. You will likely
// want to append a period and the base hostname.
func (a ApplicationURL) String() string {
appNameOrPort := a.AppName
appSlugOrPort := a.AppSlug
if a.Port != 0 {
appNameOrPort = strconv.Itoa(int(a.Port))
appSlugOrPort = strconv.Itoa(int(a.Port))
}

return fmt.Sprintf("%s--%s--%s--%s", appNameOrPort, a.AgentName, a.WorkspaceName, a.Username)
return fmt.Sprintf("%s--%s--%s--%s", appSlugOrPort, a.AgentName, a.WorkspaceName, a.Username)
}

// ParseSubdomainAppURL parses an ApplicationURL from the given subdomain. If
Expand All @@ -60,19 +60,19 @@ func ParseSubdomainAppURL(subdomain string) (ApplicationURL, error) {
}
matchGroup := matches[0]

appName, port := AppNameOrPort(matchGroup[appURL.SubexpIndex("AppName")])
appSlug, port := AppSlugOrPort(matchGroup[appURL.SubexpIndex("AppSlug")])
return ApplicationURL{
AppName: appName,
AppSlug: appSlug,
Port: port,
AgentName: matchGroup[appURL.SubexpIndex("AgentName")],
WorkspaceName: matchGroup[appURL.SubexpIndex("WorkspaceName")],
Username: matchGroup[appURL.SubexpIndex("Username")],
}, nil
}

// AppNameOrPort takes a string and returns either the input string or a port
// AppSlugOrPort takes a string and returns either the input string or a port
// number.
func AppNameOrPort(val string) (string, uint16) {
func AppSlugOrPort(val string) (string, uint16) {
port, err := strconv.ParseUint(val, 10, 16)
if err != nil || port == 0 {
port = 0
Expand Down
12 changes: 6 additions & 6 deletions coderd/httpapi/url_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func TestApplicationURLString(t *testing.T) {
{
Name: "AppName",
URL: httpapi.ApplicationURL{
AppName: "app",
AppSlug: "app",
Port: 0,
AgentName: "agent",
WorkspaceName: "workspace",
Expand All @@ -36,7 +36,7 @@ func TestApplicationURLString(t *testing.T) {
{
Name: "Port",
URL: httpapi.ApplicationURL{
AppName: "",
AppSlug: "",
Port: 8080,
AgentName: "agent",
WorkspaceName: "workspace",
Expand All @@ -47,7 +47,7 @@ func TestApplicationURLString(t *testing.T) {
{
Name: "Both",
URL: httpapi.ApplicationURL{
AppName: "app",
AppSlug: "app",
Port: 8080,
AgentName: "agent",
WorkspaceName: "workspace",
Expand Down Expand Up @@ -111,7 +111,7 @@ func TestParseSubdomainAppURL(t *testing.T) {
Name: "AppName--Agent--Workspace--User",
Subdomain: "app--agent--workspace--user",
Expected: httpapi.ApplicationURL{
AppName: "app",
AppSlug: "app",
Port: 0,
AgentName: "agent",
WorkspaceName: "workspace",
Expand All @@ -122,7 +122,7 @@ func TestParseSubdomainAppURL(t *testing.T) {
Name: "Port--Agent--Workspace--User",
Subdomain: "8080--agent--workspace--user",
Expected: httpapi.ApplicationURL{
AppName: "",
AppSlug: "",
Port: 8080,
AgentName: "agent",
WorkspaceName: "workspace",
Expand All @@ -133,7 +133,7 @@ func TestParseSubdomainAppURL(t *testing.T) {
Name: "HyphenatedNames",
Subdomain: "app-name--agent-name--workspace-name--user-name",
Expected: httpapi.ApplicationURL{
AppName: "app-name",
AppSlug: "app-name",
Port: 0,
AgentName: "agent-name",
WorkspaceName: "workspace-name",
Expand Down
13 changes: 13 additions & 0 deletions coderd/provisionerdaemons.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/coder/coder/coderd/rbac"
"github.com/coder/coder/coderd/telemetry"
"github.com/coder/coder/codersdk"
"github.com/coder/coder/provisioner"
"github.com/coder/coder/provisionerd/proto"
"github.com/coder/coder/provisionersdk"
sdkproto "github.com/coder/coder/provisionersdk/proto"
Expand Down Expand Up @@ -806,6 +807,17 @@ func insertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.
snapshot.WorkspaceAgents = append(snapshot.WorkspaceAgents, telemetry.ConvertWorkspaceAgent(dbAgent))

for _, app := range prAgent.Apps {
slug := app.Slug
if slug == "" {
slug = app.Name
}
if slug == "" {
return xerrors.Errorf("app must have a slug or name set")
}
if !provisioner.ValidAppSlugRegex.MatchString(slug) {
return xerrors.Errorf("app slug %q does not match regex %q", slug, provisioner.ValidAppSlugRegex.String())
}

health := database.WorkspaceAppHealthDisabled
if app.Healthcheck == nil {
app.Healthcheck = &sdkproto.Healthcheck{}
Expand All @@ -826,6 +838,7 @@ func insertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.
ID: uuid.New(),
CreatedAt: database.Now(),
AgentID: dbAgent.ID,
Slug: slug,
Name: app.Name,
Icon: app.Icon,
Command: sql.NullString{
Expand Down
1 change: 1 addition & 0 deletions coderd/workspaceagents.go
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,7 @@ func convertApps(dbApps []database.WorkspaceApp) []codersdk.WorkspaceApp {
for _, dbApp := range dbApps {
apps = append(apps, codersdk.WorkspaceApp{
ID: dbApp.ID,
Slug: dbApp.Slug,
Name: dbApp.Name,
Command: dbApp.Command.String,
Icon: dbApp.Icon,
Expand Down
Loading