diff --git a/cli/server_internal_test.go b/cli/server_internal_test.go index 3224059e1ec51..4adb85cc64a7d 100644 --- a/cli/server_internal_test.go +++ b/cli/server_internal_test.go @@ -254,7 +254,7 @@ func TestIsDERPPath(t *testing.T) { //{ // path: "/derp", // expected: true, - //}, + // }, { path: "/derp/", expected: true, diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 095f16d223f22..74537c0f7a483 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -11898,6 +11898,9 @@ const docTemplate = `{ "type": "string", "format": "date-time" }, + "version": { + "type": "string" + }, "wildcard_hostname": { "description": "WildcardHostname is the wildcard hostname for subdomain apps.\nE.g. *.us.example.com\nE.g. *--suffix.au.example.com\nOptional. Does not need to be on the same domain as PathAppURL.", "type": "string" diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 927c9b32e3986..cf00313832900 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -10827,6 +10827,9 @@ "type": "string", "format": "date-time" }, + "version": { + "type": "string" + }, "wildcard_hostname": { "description": "WildcardHostname is the wildcard hostname for subdomain apps.\nE.g. *.us.example.com\nE.g. *--suffix.au.example.com\nOptional. Does not need to be on the same domain as PathAppURL.", "type": "string" diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index 1837c6f2588b5..aaf8914faa273 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -5563,6 +5563,7 @@ func (q *FakeQuerier) RegisterWorkspaceProxy(_ context.Context, arg database.Reg p.WildcardHostname = arg.WildcardHostname p.DerpEnabled = arg.DerpEnabled p.DerpOnly = arg.DerpOnly + p.Version = arg.Version p.UpdatedAt = dbtime.Now() q.workspaceProxies[i] = p return p, nil diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index a475d82f3d805..73340b6f1371a 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -1127,7 +1127,8 @@ CREATE TABLE workspace_proxies ( token_hashed_secret bytea NOT NULL, region_id integer NOT NULL, derp_enabled boolean DEFAULT true NOT NULL, - derp_only boolean DEFAULT false NOT NULL + derp_only boolean DEFAULT false NOT NULL, + version text DEFAULT ''::text NOT NULL ); COMMENT ON COLUMN workspace_proxies.icon IS 'Expects an emoji character. (/emojis/1f1fa-1f1f8.png)'; diff --git a/coderd/database/migrations/000170_workspaceproxy_version.down.sql b/coderd/database/migrations/000170_workspaceproxy_version.down.sql new file mode 100644 index 0000000000000..55810705b0152 --- /dev/null +++ b/coderd/database/migrations/000170_workspaceproxy_version.down.sql @@ -0,0 +1,3 @@ +BEGIN; +ALTER TABLE workspace_proxies DROP COLUMN version; +COMMIT; diff --git a/coderd/database/migrations/000170_workspaceproxy_version.up.sql b/coderd/database/migrations/000170_workspaceproxy_version.up.sql new file mode 100644 index 0000000000000..a7e3519126c2e --- /dev/null +++ b/coderd/database/migrations/000170_workspaceproxy_version.up.sql @@ -0,0 +1,3 @@ +BEGIN; +ALTER TABLE workspace_proxies ADD COLUMN version TEXT DEFAULT ''::TEXT NOT NULL; +COMMIT; diff --git a/coderd/database/models.go b/coderd/database/models.go index 8ab3417dd6406..3170dc2562548 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -2364,7 +2364,8 @@ type WorkspaceProxy struct { RegionID int32 `db:"region_id" json:"region_id"` DerpEnabled bool `db:"derp_enabled" json:"derp_enabled"` // Disables app/terminal proxying for this proxy and only acts as a DERP relay. - DerpOnly bool `db:"derp_only" json:"derp_only"` + DerpOnly bool `db:"derp_only" json:"derp_only"` + Version string `db:"version" json:"version"` } type WorkspaceResource struct { diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 842b05380258e..09f36c69b848b 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -3667,7 +3667,7 @@ func (q *sqlQuerier) UpdateProvisionerJobWithCompleteByID(ctx context.Context, a const getWorkspaceProxies = `-- name: GetWorkspaceProxies :many SELECT - id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only + id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only, version FROM workspace_proxies WHERE @@ -3697,6 +3697,7 @@ func (q *sqlQuerier) GetWorkspaceProxies(ctx context.Context) ([]WorkspaceProxy, &i.RegionID, &i.DerpEnabled, &i.DerpOnly, + &i.Version, ); err != nil { return nil, err } @@ -3713,7 +3714,7 @@ func (q *sqlQuerier) GetWorkspaceProxies(ctx context.Context) ([]WorkspaceProxy, const getWorkspaceProxyByHostname = `-- name: GetWorkspaceProxyByHostname :one SELECT - id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only + id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only, version FROM workspace_proxies WHERE @@ -3772,13 +3773,14 @@ func (q *sqlQuerier) GetWorkspaceProxyByHostname(ctx context.Context, arg GetWor &i.RegionID, &i.DerpEnabled, &i.DerpOnly, + &i.Version, ) return i, err } const getWorkspaceProxyByID = `-- name: GetWorkspaceProxyByID :one SELECT - id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only + id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only, version FROM workspace_proxies WHERE @@ -3804,13 +3806,14 @@ func (q *sqlQuerier) GetWorkspaceProxyByID(ctx context.Context, id uuid.UUID) (W &i.RegionID, &i.DerpEnabled, &i.DerpOnly, + &i.Version, ) return i, err } const getWorkspaceProxyByName = `-- name: GetWorkspaceProxyByName :one SELECT - id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only + id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only, version FROM workspace_proxies WHERE @@ -3837,6 +3840,7 @@ func (q *sqlQuerier) GetWorkspaceProxyByName(ctx context.Context, name string) ( &i.RegionID, &i.DerpEnabled, &i.DerpOnly, + &i.Version, ) return i, err } @@ -3858,7 +3862,7 @@ INSERT INTO deleted ) VALUES - ($1, '', '', $2, $3, $4, $5, $6, $7, $8, $9, false) RETURNING id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only + ($1, '', '', $2, $3, $4, $5, $6, $7, $8, $9, false) RETURNING id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only, version ` type InsertWorkspaceProxyParams struct { @@ -3900,6 +3904,7 @@ func (q *sqlQuerier) InsertWorkspaceProxy(ctx context.Context, arg InsertWorkspa &i.RegionID, &i.DerpEnabled, &i.DerpOnly, + &i.Version, ) return i, err } @@ -3912,10 +3917,11 @@ SET wildcard_hostname = $2 :: text, derp_enabled = $3 :: boolean, derp_only = $4 :: boolean, + version = $5 :: text, updated_at = Now() WHERE - id = $5 -RETURNING id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only + id = $6 +RETURNING id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only, version ` type RegisterWorkspaceProxyParams struct { @@ -3923,6 +3929,7 @@ type RegisterWorkspaceProxyParams struct { WildcardHostname string `db:"wildcard_hostname" json:"wildcard_hostname"` DerpEnabled bool `db:"derp_enabled" json:"derp_enabled"` DerpOnly bool `db:"derp_only" json:"derp_only"` + Version string `db:"version" json:"version"` ID uuid.UUID `db:"id" json:"id"` } @@ -3932,6 +3939,7 @@ func (q *sqlQuerier) RegisterWorkspaceProxy(ctx context.Context, arg RegisterWor arg.WildcardHostname, arg.DerpEnabled, arg.DerpOnly, + arg.Version, arg.ID, ) var i WorkspaceProxy @@ -3949,6 +3957,7 @@ func (q *sqlQuerier) RegisterWorkspaceProxy(ctx context.Context, arg RegisterWor &i.RegionID, &i.DerpEnabled, &i.DerpOnly, + &i.Version, ) return i, err } @@ -3971,7 +3980,7 @@ SET updated_at = Now() WHERE id = $5 -RETURNING id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only +RETURNING id, name, display_name, icon, url, wildcard_hostname, created_at, updated_at, deleted, token_hashed_secret, region_id, derp_enabled, derp_only, version ` type UpdateWorkspaceProxyParams struct { @@ -4006,6 +4015,7 @@ func (q *sqlQuerier) UpdateWorkspaceProxy(ctx context.Context, arg UpdateWorkspa &i.RegionID, &i.DerpEnabled, &i.DerpOnly, + &i.Version, ) return i, err } diff --git a/coderd/database/queries/proxies.sql b/coderd/database/queries/proxies.sql index f43ac6465ca6f..df59d3baf107f 100644 --- a/coderd/database/queries/proxies.sql +++ b/coderd/database/queries/proxies.sql @@ -25,6 +25,7 @@ SET wildcard_hostname = @wildcard_hostname :: text, derp_enabled = @derp_enabled :: boolean, derp_only = @derp_only :: boolean, + version = @version :: text, updated_at = Now() WHERE id = @id diff --git a/codersdk/workspaceproxy.go b/codersdk/workspaceproxy.go index efdc3cc93c57d..0340e2f23f408 100644 --- a/codersdk/workspaceproxy.go +++ b/codersdk/workspaceproxy.go @@ -59,6 +59,7 @@ type WorkspaceProxy struct { CreatedAt time.Time `json:"created_at" format:"date-time" table:"created_at,default_sort"` UpdatedAt time.Time `json:"updated_at" format:"date-time" table:"updated_at"` Deleted bool `json:"deleted" table:"deleted"` + Version string `json:"version" table:"version"` } type CreateWorkspaceProxyRequest struct { diff --git a/docs/admin/audit-logs.md b/docs/admin/audit-logs.md index 69c61ad69deed..09ad0aae5bc80 100644 --- a/docs/admin/audit-logs.md +++ b/docs/admin/audit-logs.md @@ -20,7 +20,7 @@ We track the following resources: | User
create, write, delete |
FieldTracked
avatar_urlfalse
created_atfalse
deletedtrue
emailtrue
hashed_passwordtrue
idtrue
last_seen_atfalse
login_typetrue
quiet_hours_scheduletrue
rbac_rolestrue
statustrue
updated_atfalse
usernametrue
| | Workspace
create, write, delete |
FieldTracked
automatic_updatestrue
autostart_scheduletrue
created_atfalse
deletedfalse
deleting_attrue
dormant_attrue
idtrue
last_used_atfalse
nametrue
organization_idfalse
owner_idtrue
template_idtrue
ttltrue
updated_atfalse
| | WorkspaceBuild
start, stop |
FieldTracked
build_numberfalse
created_atfalse
daily_costfalse
deadlinefalse
idfalse
initiator_by_avatar_urlfalse
initiator_by_usernamefalse
initiator_idfalse
job_idfalse
max_deadlinefalse
provisioner_statefalse
reasonfalse
template_version_idtrue
transitionfalse
updated_atfalse
workspace_idfalse
| -| WorkspaceProxy
|
FieldTracked
created_attrue
deletedfalse
derp_enabledtrue
derp_onlytrue
display_nametrue
icontrue
idtrue
nametrue
region_idtrue
token_hashed_secrettrue
updated_atfalse
urltrue
wildcard_hostnametrue
| +| WorkspaceProxy
|
FieldTracked
created_attrue
deletedfalse
derp_enabledtrue
derp_onlytrue
display_nametrue
icontrue
idtrue
nametrue
region_idtrue
token_hashed_secrettrue
updated_atfalse
urltrue
versiontrue
wildcard_hostnametrue
| diff --git a/docs/api/enterprise.md b/docs/api/enterprise.md index 743fbc19fd532..e25b48aedb34a 100644 --- a/docs/api/enterprise.md +++ b/docs/api/enterprise.md @@ -1513,6 +1513,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaceproxies \ "status": "ok" }, "updated_at": "2019-08-24T14:15:22Z", + "version": "string", "wildcard_hostname": "string" } ] @@ -1551,6 +1552,7 @@ Status Code **200** | `»»»» warnings` | array | false | | Warnings do not prevent the workspace proxy from being healthy, but should be addressed. | | `»»» status` | [codersdk.ProxyHealthStatus](schemas.md#codersdkproxyhealthstatus) | false | | | | `»» updated_at` | string(date-time) | false | | | +| `»» version` | string | false | | | | `»» wildcard_hostname` | string | false | | Wildcard hostname is the wildcard hostname for subdomain apps. E.g. _.us.example.com E.g. _--suffix.au.example.com Optional. Does not need to be on the same domain as PathAppURL. | #### Enumerated Values @@ -1619,6 +1621,7 @@ curl -X POST http://coder-server:8080/api/v2/workspaceproxies \ "status": "ok" }, "updated_at": "2019-08-24T14:15:22Z", + "version": "string", "wildcard_hostname": "string" } ``` @@ -1675,6 +1678,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaceproxies/{workspaceproxy} \ "status": "ok" }, "updated_at": "2019-08-24T14:15:22Z", + "version": "string", "wildcard_hostname": "string" } ``` @@ -1789,6 +1793,7 @@ curl -X PATCH http://coder-server:8080/api/v2/workspaceproxies/{workspaceproxy} "status": "ok" }, "updated_at": "2019-08-24T14:15:22Z", + "version": "string", "wildcard_hostname": "string" } ``` diff --git a/docs/api/schemas.md b/docs/api/schemas.md index c2d31f83c4297..544403777a085 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -4086,6 +4086,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in "status": "ok" }, "updated_at": "2019-08-24T14:15:22Z", + "version": "string", "wildcard_hostname": "string" } ] @@ -6649,6 +6650,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| "status": "ok" }, "updated_at": "2019-08-24T14:15:22Z", + "version": "string", "wildcard_hostname": "string" } ``` @@ -6669,6 +6671,7 @@ If the schedule is empty, the user will be updated to use the default schedule.| | `path_app_url` | string | false | | Path app URL is the URL to the base path for path apps. Optional unless wildcard_hostname is set. E.g. https://us.example.com | | `status` | [codersdk.WorkspaceProxyStatus](#codersdkworkspaceproxystatus) | false | | Status is the latest status check of the proxy. This will be empty for deleted proxies. This value can be used to determine if a workspace proxy is healthy and ready to use. | | `updated_at` | string | false | | | +| `version` | string | false | | | | `wildcard_hostname` | string | false | | Wildcard hostname is the wildcard hostname for subdomain apps. E.g. _.us.example.com E.g. _--suffix.au.example.com Optional. Does not need to be on the same domain as PathAppURL. | ## codersdk.WorkspaceProxyStatus diff --git a/enterprise/audit/table.go b/enterprise/audit/table.go index e49432091d6db..085f4ac581a9e 100644 --- a/enterprise/audit/table.go +++ b/enterprise/audit/table.go @@ -207,6 +207,7 @@ var auditableResourcesTypes = map[any]map[string]Action{ "derp_enabled": ActionTrack, "derp_only": ActionTrack, "region_id": ActionTrack, + "version": ActionTrack, }, } diff --git a/enterprise/coderd/proxyhealth/proxyhealth_test.go b/enterprise/coderd/proxyhealth/proxyhealth_test.go index 6f20c1e48ebef..fad5601bf3a71 100644 --- a/enterprise/coderd/proxyhealth/proxyhealth_test.go +++ b/enterprise/coderd/proxyhealth/proxyhealth_test.go @@ -31,6 +31,7 @@ func insertProxy(t *testing.T, db database.Store, url string) database.Workspace Url: url, WildcardHostname: "", ID: proxy.ID, + Version: `v2.34.5-test+beefcake`, }) require.NoError(t, err, "failed to update proxy") return proxy diff --git a/enterprise/coderd/workspaceproxy.go b/enterprise/coderd/workspaceproxy.go index 49f0849b951b7..eaef17542c6bd 100644 --- a/enterprise/coderd/workspaceproxy.go +++ b/enterprise/coderd/workspaceproxy.go @@ -625,6 +625,7 @@ func (api *API) workspaceProxyRegister(rw http.ResponseWriter, r *http.Request) DerpEnabled: req.DerpEnabled, DerpOnly: req.DerpOnly, WildcardHostname: req.WildcardHostname, + Version: req.Version, }) if err != nil { return xerrors.Errorf("register workspace proxy: %w", err) @@ -951,6 +952,7 @@ func convertProxy(p database.WorkspaceProxy, status proxyhealth.ProxyStatus) cod CreatedAt: p.CreatedAt, UpdatedAt: p.UpdatedAt, Deleted: p.Deleted, + Version: p.Version, Status: codersdk.WorkspaceProxyStatus{ Status: codersdk.ProxyHealthStatus(status.Status), Report: status.Report, diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 27a5687a9db36..51921fd729e26 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1581,6 +1581,7 @@ export interface WorkspaceProxy extends Region { readonly created_at: string; readonly updated_at: string; readonly deleted: boolean; + readonly version: string; } // From codersdk/deployment.go diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index ba8dc0458918a..9aeb3560ce961 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -85,6 +85,7 @@ export const MockPrimaryWorkspaceProxy: TypesGen.WorkspaceProxy = { derp_only: false, created_at: new Date().toISOString(), updated_at: new Date().toISOString(), + version: "v2.34.5-test+primary", deleted: false, status: { status: "ok", @@ -105,6 +106,7 @@ export const MockHealthyWildWorkspaceProxy: TypesGen.WorkspaceProxy = { created_at: new Date().toISOString(), updated_at: new Date().toISOString(), deleted: false, + version: "v2.34.5-test+haswildcard", status: { status: "ok", checked_at: new Date().toISOString(), @@ -123,6 +125,7 @@ export const MockUnhealthyWildWorkspaceProxy: TypesGen.WorkspaceProxy = { derp_only: true, created_at: new Date().toISOString(), updated_at: new Date().toISOString(), + version: "v2.34.5-test+unhealthy", deleted: false, status: { status: "unhealthy", @@ -151,6 +154,7 @@ export const MockWorkspaceProxies: TypesGen.WorkspaceProxy[] = [ created_at: new Date().toISOString(), updated_at: new Date().toISOString(), deleted: false, + version: "v2.34.5-test+nowildcard", status: { status: "ok", checked_at: new Date().toISOString(),