Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
feat: add slug property to app, use in URLs
  • Loading branch information
deansheather committed Oct 16, 2022
commit 688945019ebfbc8da5656e08c90190ca2b385f0a
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.ValidAppNameRegex.MatchString(slug) {
return xerrors.Errorf("app slug %q does not match regex %q", slug, provisioner.ValidAppNameRegex.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