Skip to content

Commit 11bd719

Browse files
Kira-Pilotpull[bot]
authored andcommitted
feat: add deleted_at field to workspace model (coder#7475)
* added impending_deletion workspace field * gen docs * update golden files * added test * PR comments
1 parent 3dadbe8 commit 11bd719

File tree

11 files changed

+149
-21
lines changed

11 files changed

+149
-21
lines changed

.vscode/settings.json

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
"codersdk",
2121
"cronstrue",
2222
"databasefake",
23+
"dbfake",
24+
"dbgen",
2325
"dbtype",
2426
"DERP",
2527
"derphttp",

cli/testdata/coder_list_--output_json.golden

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"name": "test-workspace",
4949
"autostart_schedule": "CRON_TZ=US/Central 30 9 * * 1-5",
5050
"ttl_ms": 28800000,
51-
"last_used_at": "[timestamp]"
51+
"last_used_at": "[timestamp]",
52+
"deleting_at": null
5253
}
5354
]

coderd/apidoc/docs.go

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

coderd/apidoc/swagger.json

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

coderd/workspaces.go

+21-1
Original file line numberDiff line numberDiff line change
@@ -1169,7 +1169,10 @@ func convertWorkspace(
11691169
autostartSchedule = &workspace.AutostartSchedule.String
11701170
}
11711171

1172-
ttlMillis := convertWorkspaceTTLMillis(workspace.Ttl)
1172+
var (
1173+
ttlMillis = convertWorkspaceTTLMillis(workspace.Ttl)
1174+
deletingAt = calculateDeletingAt(workspace, template)
1175+
)
11731176
return codersdk.Workspace{
11741177
ID: workspace.ID,
11751178
CreatedAt: workspace.CreatedAt,
@@ -1188,6 +1191,7 @@ func convertWorkspace(
11881191
AutostartSchedule: autostartSchedule,
11891192
TTLMillis: ttlMillis,
11901193
LastUsedAt: workspace.LastUsedAt,
1194+
DeletingAt: deletingAt,
11911195
}
11921196
}
11931197

@@ -1200,6 +1204,22 @@ func convertWorkspaceTTLMillis(i sql.NullInt64) *int64 {
12001204
return &millis
12011205
}
12021206

1207+
// Calculate the time of the upcoming workspace deletion, if applicable; otherwise, return nil.
1208+
// Workspaces may have impending deletions if InactivityTTL feature is turned on and the workspace is inactive.
1209+
func calculateDeletingAt(workspace database.Workspace, template database.Template) *time.Time {
1210+
var (
1211+
year, month, day = time.Now().Date()
1212+
beginningOfToday = time.Date(year, month, day, 0, 0, 0, 0, time.Now().Location())
1213+
)
1214+
// If InactivityTTL is turned off (set to 0), if the workspace has already been deleted,
1215+
// or if the workspace was used sometime within the last day, there is no impending deletion
1216+
if template.InactivityTTL == 0 || workspace.Deleted || workspace.LastUsedAt.After(beginningOfToday) {
1217+
return nil
1218+
}
1219+
1220+
return ptr.Ref(workspace.LastUsedAt.Add(time.Duration(template.InactivityTTL) * time.Nanosecond))
1221+
}
1222+
12031223
func validWorkspaceTTLMillis(millis *int64, templateDefault, templateMax time.Duration) (sql.NullInt64, error) {
12041224
if templateDefault == 0 && templateMax != 0 || (templateMax > 0 && templateDefault > templateMax) {
12051225
templateDefault = templateMax

coderd/workspaces_internal_test.go

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package coderd
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/stretchr/testify/require"
8+
9+
"github.com/coder/coder/coderd/database"
10+
"github.com/coder/coder/coderd/util/ptr"
11+
)
12+
13+
func Test_calculateDeletingAt(t *testing.T) {
14+
t.Parallel()
15+
16+
testCases := []struct {
17+
name string
18+
workspace database.Workspace
19+
template database.Template
20+
expected *time.Time
21+
}{
22+
{
23+
name: "DeletingAt",
24+
workspace: database.Workspace{
25+
Deleted: false,
26+
LastUsedAt: time.Now().Add(time.Duration(-10) * time.Hour * 24), // 10 days ago
27+
},
28+
template: database.Template{
29+
InactivityTTL: int64(9 * 24 * time.Hour), // 9 days
30+
},
31+
expected: ptr.Ref(time.Now().Add(time.Duration(-1) * time.Hour * 24)), // yesterday
32+
},
33+
{
34+
name: "InactivityTTLUnset",
35+
workspace: database.Workspace{
36+
Deleted: false,
37+
LastUsedAt: time.Now().Add(time.Duration(-10) * time.Hour * 24),
38+
},
39+
template: database.Template{
40+
InactivityTTL: 0,
41+
},
42+
expected: nil,
43+
},
44+
{
45+
name: "DeletedWorkspace",
46+
workspace: database.Workspace{
47+
Deleted: true,
48+
LastUsedAt: time.Now().Add(time.Duration(-10) * time.Hour * 24),
49+
},
50+
template: database.Template{
51+
InactivityTTL: int64(9 * 24 * time.Hour),
52+
},
53+
expected: nil,
54+
},
55+
{
56+
name: "ActiveWorkspace",
57+
workspace: database.Workspace{
58+
Deleted: true,
59+
LastUsedAt: time.Now().Add(time.Duration(-5) * time.Hour), // 5 hours ago
60+
},
61+
template: database.Template{
62+
InactivityTTL: int64(1 * 24 * time.Hour), // 1 day
63+
},
64+
expected: nil,
65+
},
66+
}
67+
68+
for _, tc := range testCases {
69+
tc := tc
70+
t.Run(tc.name, func(t *testing.T) {
71+
t.Parallel()
72+
73+
found := calculateDeletingAt(tc.workspace, tc.template)
74+
if tc.expected == nil {
75+
require.Nil(t, found, "impending deletion should be nil")
76+
} else {
77+
require.NotNil(t, found)
78+
require.WithinDuration(t, *tc.expected, *found, time.Second, "incorrect impending deletion")
79+
}
80+
})
81+
}
82+
}

codersdk/workspaces.go

+4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ type Workspace struct {
3434
AutostartSchedule *string `json:"autostart_schedule,omitempty"`
3535
TTLMillis *int64 `json:"ttl_ms,omitempty"`
3636
LastUsedAt time.Time `json:"last_used_at" format:"date-time"`
37+
38+
// DeletingAt indicates the time of the upcoming workspace deletion, if applicable; otherwise it is nil.
39+
// Workspaces may have impending deletions if Template.InactivityTTL feature is turned on and the workspace is inactive.
40+
DeletingAt *time.Time `json:"deleting_at" format:"date-time"`
3741
}
3842

3943
type WorkspacesRequest struct {

docs/api/schemas.md

+22-19
Original file line numberDiff line numberDiff line change
@@ -4594,6 +4594,7 @@ Parameter represents a set value for the scope.
45944594
{
45954595
"autostart_schedule": "string",
45964596
"created_at": "2019-08-24T14:15:22Z",
4597+
"deleting_at": "2019-08-24T14:15:22Z",
45974598
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
45984599
"last_used_at": "2019-08-24T14:15:22Z",
45994600
"latest_build": {
@@ -4731,25 +4732,26 @@ Parameter represents a set value for the scope.
47314732

47324733
### Properties
47334734

4734-
| Name | Type | Required | Restrictions | Description |
4735-
| ------------------------------------------- | -------------------------------------------------- | -------- | ------------ | ----------- |
4736-
| `autostart_schedule` | string | false | | |
4737-
| `created_at` | string | false | | |
4738-
| `id` | string | false | | |
4739-
| `last_used_at` | string | false | | |
4740-
| `latest_build` | [codersdk.WorkspaceBuild](#codersdkworkspacebuild) | false | | |
4741-
| `name` | string | false | | |
4742-
| `organization_id` | string | false | | |
4743-
| `outdated` | boolean | false | | |
4744-
| `owner_id` | string | false | | |
4745-
| `owner_name` | string | false | | |
4746-
| `template_allow_user_cancel_workspace_jobs` | boolean | false | | |
4747-
| `template_display_name` | string | false | | |
4748-
| `template_icon` | string | false | | |
4749-
| `template_id` | string | false | | |
4750-
| `template_name` | string | false | | |
4751-
| `ttl_ms` | integer | false | | |
4752-
| `updated_at` | string | false | | |
4735+
| Name | Type | Required | Restrictions | Description |
4736+
| ------------------------------------------- | -------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
4737+
| `autostart_schedule` | string | false | | |
4738+
| `created_at` | string | false | | |
4739+
| `deleting_at` | string | false | | Deleting at indicates the time of the upcoming workspace deletion, if applicable; otherwise it is nil. Workspaces may have impending deletions if Template.InactivityTTL feature is turned on and the workspace is inactive. |
4740+
| `id` | string | false | | |
4741+
| `last_used_at` | string | false | | |
4742+
| `latest_build` | [codersdk.WorkspaceBuild](#codersdkworkspacebuild) | false | | |
4743+
| `name` | string | false | | |
4744+
| `organization_id` | string | false | | |
4745+
| `outdated` | boolean | false | | |
4746+
| `owner_id` | string | false | | |
4747+
| `owner_name` | string | false | | |
4748+
| `template_allow_user_cancel_workspace_jobs` | boolean | false | | |
4749+
| `template_display_name` | string | false | | |
4750+
| `template_icon` | string | false | | |
4751+
| `template_id` | string | false | | |
4752+
| `template_name` | string | false | | |
4753+
| `ttl_ms` | integer | false | | |
4754+
| `updated_at` | string | false | | |
47534755

47544756
## codersdk.WorkspaceAgent
47554757

@@ -5596,6 +5598,7 @@ Parameter represents a set value for the scope.
55965598
{
55975599
"autostart_schedule": "string",
55985600
"created_at": "2019-08-24T14:15:22Z",
5601+
"deleting_at": "2019-08-24T14:15:22Z",
55995602
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
56005603
"last_used_at": "2019-08-24T14:15:22Z",
56015604
"latest_build": {

docs/api/workspaces.md

+4
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/member
5656
{
5757
"autostart_schedule": "string",
5858
"created_at": "2019-08-24T14:15:22Z",
59+
"deleting_at": "2019-08-24T14:15:22Z",
5960
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
6061
"last_used_at": "2019-08-24T14:15:22Z",
6162
"latest_build": {
@@ -228,6 +229,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam
228229
{
229230
"autostart_schedule": "string",
230231
"created_at": "2019-08-24T14:15:22Z",
232+
"deleting_at": "2019-08-24T14:15:22Z",
231233
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
232234
"last_used_at": "2019-08-24T14:15:22Z",
233235
"latest_build": {
@@ -423,6 +425,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces \
423425
{
424426
"autostart_schedule": "string",
425427
"created_at": "2019-08-24T14:15:22Z",
428+
"deleting_at": "2019-08-24T14:15:22Z",
426429
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
427430
"last_used_at": "2019-08-24T14:15:22Z",
428431
"latest_build": {
@@ -592,6 +595,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace} \
592595
{
593596
"autostart_schedule": "string",
594597
"created_at": "2019-08-24T14:15:22Z",
598+
"deleting_at": "2019-08-24T14:15:22Z",
595599
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
596600
"last_used_at": "2019-08-24T14:15:22Z",
597601
"latest_build": {

site/src/api/typesGenerated.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,7 @@ export interface Workspace {
11131113
readonly autostart_schedule?: string
11141114
readonly ttl_ms?: number
11151115
readonly last_used_at: string
1116+
readonly deleting_at?: string
11161117
}
11171118

11181119
// From codersdk/workspaceagents.go

site/src/testHelpers/entities.ts

+1
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,7 @@ export const MockWorkspace: TypesGen.Workspace = {
721721
ttl_ms: 2 * 60 * 60 * 1000,
722722
latest_build: MockWorkspaceBuild,
723723
last_used_at: "2022-05-16T15:29:10.302441433Z",
724+
deleting_at: "0001-01-01T00:00:00Z",
724725
}
725726

726727
export const MockStoppedWorkspace: TypesGen.Workspace = {

0 commit comments

Comments
 (0)