mirror of https://github.com/coder/coder.git
feat: add deleted_at field to workspace model (#7475)
* added impending_deletion workspace field * gen docs * update golden files * added test * PR comments
This commit is contained in:
parent
fe0e94ece9
commit
ae3473dc1b
|
@ -20,6 +20,8 @@
|
|||
"codersdk",
|
||||
"cronstrue",
|
||||
"databasefake",
|
||||
"dbfake",
|
||||
"dbgen",
|
||||
"dbtype",
|
||||
"DERP",
|
||||
"derphttp",
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
"name": "test-workspace",
|
||||
"autostart_schedule": "CRON_TZ=US/Central 30 9 * * 1-5",
|
||||
"ttl_ms": 28800000,
|
||||
"last_used_at": "[timestamp]"
|
||||
"last_used_at": "[timestamp]",
|
||||
"deleting_at": null
|
||||
}
|
||||
]
|
||||
|
|
|
@ -9455,6 +9455,11 @@ const docTemplate = `{
|
|||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"deleting_at": {
|
||||
"description": "DeletingAt indicates the time of the upcoming workspace deletion, if applicable; otherwise it is nil.\nWorkspaces may have impending deletions if Template.InactivityTTL feature is turned on and the workspace is inactive.",
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
|
|
|
@ -8499,6 +8499,11 @@
|
|||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"deleting_at": {
|
||||
"description": "DeletingAt indicates the time of the upcoming workspace deletion, if applicable; otherwise it is nil.\nWorkspaces may have impending deletions if Template.InactivityTTL feature is turned on and the workspace is inactive.",
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
|
|
|
@ -1169,7 +1169,10 @@ func convertWorkspace(
|
|||
autostartSchedule = &workspace.AutostartSchedule.String
|
||||
}
|
||||
|
||||
ttlMillis := convertWorkspaceTTLMillis(workspace.Ttl)
|
||||
var (
|
||||
ttlMillis = convertWorkspaceTTLMillis(workspace.Ttl)
|
||||
deletingAt = calculateDeletingAt(workspace, template)
|
||||
)
|
||||
return codersdk.Workspace{
|
||||
ID: workspace.ID,
|
||||
CreatedAt: workspace.CreatedAt,
|
||||
|
@ -1188,6 +1191,7 @@ func convertWorkspace(
|
|||
AutostartSchedule: autostartSchedule,
|
||||
TTLMillis: ttlMillis,
|
||||
LastUsedAt: workspace.LastUsedAt,
|
||||
DeletingAt: deletingAt,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1200,6 +1204,22 @@ func convertWorkspaceTTLMillis(i sql.NullInt64) *int64 {
|
|||
return &millis
|
||||
}
|
||||
|
||||
// Calculate the time of the upcoming workspace deletion, if applicable; otherwise, return nil.
|
||||
// Workspaces may have impending deletions if InactivityTTL feature is turned on and the workspace is inactive.
|
||||
func calculateDeletingAt(workspace database.Workspace, template database.Template) *time.Time {
|
||||
var (
|
||||
year, month, day = time.Now().Date()
|
||||
beginningOfToday = time.Date(year, month, day, 0, 0, 0, 0, time.Now().Location())
|
||||
)
|
||||
// If InactivityTTL is turned off (set to 0), if the workspace has already been deleted,
|
||||
// or if the workspace was used sometime within the last day, there is no impending deletion
|
||||
if template.InactivityTTL == 0 || workspace.Deleted || workspace.LastUsedAt.After(beginningOfToday) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return ptr.Ref(workspace.LastUsedAt.Add(time.Duration(template.InactivityTTL) * time.Nanosecond))
|
||||
}
|
||||
|
||||
func validWorkspaceTTLMillis(millis *int64, templateDefault, templateMax time.Duration) (sql.NullInt64, error) {
|
||||
if templateDefault == 0 && templateMax != 0 || (templateMax > 0 && templateDefault > templateMax) {
|
||||
templateDefault = templateMax
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
package coderd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/coderd/database"
|
||||
"github.com/coder/coder/coderd/util/ptr"
|
||||
)
|
||||
|
||||
func Test_calculateDeletingAt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
workspace database.Workspace
|
||||
template database.Template
|
||||
expected *time.Time
|
||||
}{
|
||||
{
|
||||
name: "DeletingAt",
|
||||
workspace: database.Workspace{
|
||||
Deleted: false,
|
||||
LastUsedAt: time.Now().Add(time.Duration(-10) * time.Hour * 24), // 10 days ago
|
||||
},
|
||||
template: database.Template{
|
||||
InactivityTTL: int64(9 * 24 * time.Hour), // 9 days
|
||||
},
|
||||
expected: ptr.Ref(time.Now().Add(time.Duration(-1) * time.Hour * 24)), // yesterday
|
||||
},
|
||||
{
|
||||
name: "InactivityTTLUnset",
|
||||
workspace: database.Workspace{
|
||||
Deleted: false,
|
||||
LastUsedAt: time.Now().Add(time.Duration(-10) * time.Hour * 24),
|
||||
},
|
||||
template: database.Template{
|
||||
InactivityTTL: 0,
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "DeletedWorkspace",
|
||||
workspace: database.Workspace{
|
||||
Deleted: true,
|
||||
LastUsedAt: time.Now().Add(time.Duration(-10) * time.Hour * 24),
|
||||
},
|
||||
template: database.Template{
|
||||
InactivityTTL: int64(9 * 24 * time.Hour),
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "ActiveWorkspace",
|
||||
workspace: database.Workspace{
|
||||
Deleted: true,
|
||||
LastUsedAt: time.Now().Add(time.Duration(-5) * time.Hour), // 5 hours ago
|
||||
},
|
||||
template: database.Template{
|
||||
InactivityTTL: int64(1 * 24 * time.Hour), // 1 day
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
found := calculateDeletingAt(tc.workspace, tc.template)
|
||||
if tc.expected == nil {
|
||||
require.Nil(t, found, "impending deletion should be nil")
|
||||
} else {
|
||||
require.NotNil(t, found)
|
||||
require.WithinDuration(t, *tc.expected, *found, time.Second, "incorrect impending deletion")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -34,6 +34,10 @@ type Workspace struct {
|
|||
AutostartSchedule *string `json:"autostart_schedule,omitempty"`
|
||||
TTLMillis *int64 `json:"ttl_ms,omitempty"`
|
||||
LastUsedAt time.Time `json:"last_used_at" format:"date-time"`
|
||||
|
||||
// DeletingAt 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.
|
||||
DeletingAt *time.Time `json:"deleting_at" format:"date-time"`
|
||||
}
|
||||
|
||||
type WorkspacesRequest struct {
|
||||
|
|
|
@ -4594,6 +4594,7 @@ Parameter represents a set value for the scope.
|
|||
{
|
||||
"autostart_schedule": "string",
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"deleting_at": "2019-08-24T14:15:22Z",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"last_used_at": "2019-08-24T14:15:22Z",
|
||||
"latest_build": {
|
||||
|
@ -4731,25 +4732,26 @@ Parameter represents a set value for the scope.
|
|||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ------------------------------------------- | -------------------------------------------------- | -------- | ------------ | ----------- |
|
||||
| `autostart_schedule` | string | false | | |
|
||||
| `created_at` | string | false | | |
|
||||
| `id` | string | false | | |
|
||||
| `last_used_at` | string | false | | |
|
||||
| `latest_build` | [codersdk.WorkspaceBuild](#codersdkworkspacebuild) | false | | |
|
||||
| `name` | string | false | | |
|
||||
| `organization_id` | string | false | | |
|
||||
| `outdated` | boolean | false | | |
|
||||
| `owner_id` | string | false | | |
|
||||
| `owner_name` | string | false | | |
|
||||
| `template_allow_user_cancel_workspace_jobs` | boolean | false | | |
|
||||
| `template_display_name` | string | false | | |
|
||||
| `template_icon` | string | false | | |
|
||||
| `template_id` | string | false | | |
|
||||
| `template_name` | string | false | | |
|
||||
| `ttl_ms` | integer | false | | |
|
||||
| `updated_at` | string | false | | |
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ------------------------------------------- | -------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `autostart_schedule` | string | false | | |
|
||||
| `created_at` | string | false | | |
|
||||
| `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. |
|
||||
| `id` | string | false | | |
|
||||
| `last_used_at` | string | false | | |
|
||||
| `latest_build` | [codersdk.WorkspaceBuild](#codersdkworkspacebuild) | false | | |
|
||||
| `name` | string | false | | |
|
||||
| `organization_id` | string | false | | |
|
||||
| `outdated` | boolean | false | | |
|
||||
| `owner_id` | string | false | | |
|
||||
| `owner_name` | string | false | | |
|
||||
| `template_allow_user_cancel_workspace_jobs` | boolean | false | | |
|
||||
| `template_display_name` | string | false | | |
|
||||
| `template_icon` | string | false | | |
|
||||
| `template_id` | string | false | | |
|
||||
| `template_name` | string | false | | |
|
||||
| `ttl_ms` | integer | false | | |
|
||||
| `updated_at` | string | false | | |
|
||||
|
||||
## codersdk.WorkspaceAgent
|
||||
|
||||
|
@ -5596,6 +5598,7 @@ Parameter represents a set value for the scope.
|
|||
{
|
||||
"autostart_schedule": "string",
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"deleting_at": "2019-08-24T14:15:22Z",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"last_used_at": "2019-08-24T14:15:22Z",
|
||||
"latest_build": {
|
||||
|
|
|
@ -56,6 +56,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/member
|
|||
{
|
||||
"autostart_schedule": "string",
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"deleting_at": "2019-08-24T14:15:22Z",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"last_used_at": "2019-08-24T14:15:22Z",
|
||||
"latest_build": {
|
||||
|
@ -228,6 +229,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam
|
|||
{
|
||||
"autostart_schedule": "string",
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"deleting_at": "2019-08-24T14:15:22Z",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"last_used_at": "2019-08-24T14:15:22Z",
|
||||
"latest_build": {
|
||||
|
@ -423,6 +425,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces \
|
|||
{
|
||||
"autostart_schedule": "string",
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"deleting_at": "2019-08-24T14:15:22Z",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"last_used_at": "2019-08-24T14:15:22Z",
|
||||
"latest_build": {
|
||||
|
@ -592,6 +595,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace} \
|
|||
{
|
||||
"autostart_schedule": "string",
|
||||
"created_at": "2019-08-24T14:15:22Z",
|
||||
"deleting_at": "2019-08-24T14:15:22Z",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"last_used_at": "2019-08-24T14:15:22Z",
|
||||
"latest_build": {
|
||||
|
|
|
@ -1113,6 +1113,7 @@ export interface Workspace {
|
|||
readonly autostart_schedule?: string
|
||||
readonly ttl_ms?: number
|
||||
readonly last_used_at: string
|
||||
readonly deleting_at?: string
|
||||
}
|
||||
|
||||
// From codersdk/workspaceagents.go
|
||||
|
|
|
@ -721,6 +721,7 @@ export const MockWorkspace: TypesGen.Workspace = {
|
|||
ttl_ms: 2 * 60 * 60 * 1000,
|
||||
latest_build: MockWorkspaceBuild,
|
||||
last_used_at: "2022-05-16T15:29:10.302441433Z",
|
||||
deleting_at: "0001-01-01T00:00:00Z",
|
||||
}
|
||||
|
||||
export const MockStoppedWorkspace: TypesGen.Workspace = {
|
||||
|
|
Loading…
Reference in New Issue