Skip to content

Commit ec9b480

Browse files
authored
fix: use is-dormant instead of dormant_at (#10191)
1 parent 652e1a7 commit ec9b480

File tree

14 files changed

+58
-202
lines changed

14 files changed

+58
-202
lines changed

coderd/database/dbfake/dbfake.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -6818,12 +6818,11 @@ func (q *FakeQuerier) GetAuthorizedWorkspaces(ctx context.Context, arg database.
68186818
}
68196819

68206820
// We omit locked workspaces by default.
6821-
if arg.DormantAt.IsZero() && workspace.DormantAt.Valid {
6821+
if arg.IsDormant == "" && workspace.DormantAt.Valid {
68226822
continue
68236823
}
68246824

6825-
// Filter out workspaces that are locked after the timestamp.
6826-
if !arg.DormantAt.IsZero() && workspace.DormantAt.Time.Before(arg.DormantAt) {
6825+
if arg.IsDormant != "" && !workspace.DormantAt.Valid {
68276826
continue
68286827
}
68296828

coderd/database/modelqueries.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ func (q *sqlQuerier) GetAuthorizedWorkspaces(ctx context.Context, arg GetWorkspa
217217
arg.Name,
218218
arg.HasAgent,
219219
arg.AgentInactiveDisconnectTimeoutSeconds,
220-
arg.DormantAt,
220+
arg.IsDormant,
221221
arg.LastUsedBefore,
222222
arg.LastUsedAfter,
223223
arg.Offset,

coderd/database/queries.sql.go

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

coderd/database/queries/workspaces.sql

+2-2
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,8 @@ WHERE
242242
-- Filter by dormant workspaces. By default we do not return dormant
243243
-- workspaces since they are considered soft-deleted.
244244
AND CASE
245-
WHEN @dormant_at :: timestamptz > '0001-01-01 00:00:00+00'::timestamptz THEN
246-
dormant_at IS NOT NULL AND dormant_at >= @dormant_at
245+
WHEN @is_dormant :: text != '' THEN
246+
dormant_at IS NOT NULL
247247
ELSE
248248
dormant_at IS NULL
249249
END

coderd/externalauth.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ import (
88

99
"golang.org/x/sync/errgroup"
1010

11+
"github.com/sqlc-dev/pqtype"
12+
1113
"github.com/coder/coder/v2/coderd/database"
1214
"github.com/coder/coder/v2/coderd/database/dbtime"
1315
"github.com/coder/coder/v2/coderd/externalauth"
1416
"github.com/coder/coder/v2/coderd/httpapi"
1517
"github.com/coder/coder/v2/coderd/httpmw"
1618
"github.com/coder/coder/v2/codersdk"
17-
"github.com/sqlc-dev/pqtype"
1819
)
1920

2021
// @Summary Get external auth by ID

coderd/searchquery/search.go

+5-21
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212

1313
"github.com/coder/coder/v2/coderd/database"
1414
"github.com/coder/coder/v2/coderd/httpapi"
15-
"github.com/coder/coder/v2/coderd/util/ptr"
1615
"github.com/coder/coder/v2/codersdk"
1716
)
1817

@@ -70,22 +69,16 @@ func Users(query string) (database.GetUsersParams, []codersdk.ValidationError) {
7069
return filter, parser.Errors
7170
}
7271

73-
type PostFilter struct {
74-
DeletingBy *time.Time `json:"deleting_by" format:"date-time"`
75-
}
76-
77-
func Workspaces(query string, page codersdk.Pagination, agentInactiveDisconnectTimeout time.Duration) (database.GetWorkspacesParams, PostFilter, []codersdk.ValidationError) {
72+
func Workspaces(query string, page codersdk.Pagination, agentInactiveDisconnectTimeout time.Duration) (database.GetWorkspacesParams, []codersdk.ValidationError) {
7873
filter := database.GetWorkspacesParams{
7974
AgentInactiveDisconnectTimeoutSeconds: int64(agentInactiveDisconnectTimeout.Seconds()),
8075

8176
Offset: int32(page.Offset),
8277
Limit: int32(page.Limit),
8378
}
8479

85-
var postFilter PostFilter
86-
8780
if query == "" {
88-
return filter, postFilter, nil
81+
return filter, nil
8982
}
9083

9184
// Always lowercase for all searches.
@@ -105,7 +98,7 @@ func Workspaces(query string, page codersdk.Pagination, agentInactiveDisconnectT
10598
return nil
10699
})
107100
if len(errors) > 0 {
108-
return filter, postFilter, errors
101+
return filter, errors
109102
}
110103

111104
parser := httpapi.NewQueryParamParser()
@@ -114,21 +107,12 @@ func Workspaces(query string, page codersdk.Pagination, agentInactiveDisconnectT
114107
filter.Name = parser.String(values, "", "name")
115108
filter.Status = string(httpapi.ParseCustom(parser, values, "", "status", httpapi.ParseEnum[database.WorkspaceStatus]))
116109
filter.HasAgent = parser.String(values, "", "has-agent")
117-
filter.DormantAt = parser.Time(values, time.Time{}, "dormant_at", "2006-01-02")
110+
filter.IsDormant = parser.String(values, "", "is-dormant")
118111
filter.LastUsedAfter = parser.Time3339Nano(values, time.Time{}, "last_used_after")
119112
filter.LastUsedBefore = parser.Time3339Nano(values, time.Time{}, "last_used_before")
120113

121-
if _, ok := values["deleting_by"]; ok {
122-
postFilter.DeletingBy = ptr.Ref(parser.Time(values, time.Time{}, "deleting_by", "2006-01-02"))
123-
// We want to make sure to grab dormant workspaces since they
124-
// are omitted by default.
125-
if filter.DormantAt.IsZero() {
126-
filter.DormantAt = time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC)
127-
}
128-
}
129-
130114
parser.ErrorExcessParams(values)
131-
return filter, postFilter, parser.Errors
115+
return filter, parser.Errors
132116
}
133117

134118
func searchTerms(query string, defaultKey func(term string, values url.Values) error) (url.Values, []codersdk.ValidationError) {

coderd/searchquery/search_test.go

+2-45
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"github.com/coder/coder/v2/coderd/database"
1313
"github.com/coder/coder/v2/coderd/rbac"
1414
"github.com/coder/coder/v2/coderd/searchquery"
15-
"github.com/coder/coder/v2/coderd/util/ptr"
1615
"github.com/coder/coder/v2/codersdk"
1716
)
1817

@@ -150,7 +149,7 @@ func TestSearchWorkspace(t *testing.T) {
150149
c := c
151150
t.Run(c.Name, func(t *testing.T) {
152151
t.Parallel()
153-
values, postFilter, errs := searchquery.Workspaces(c.Query, codersdk.Pagination{}, 0)
152+
values, errs := searchquery.Workspaces(c.Query, codersdk.Pagination{}, 0)
154153
if c.ExpectedErrorContains != "" {
155154
assert.True(t, len(errs) > 0, "expect some errors")
156155
var s strings.Builder
@@ -159,7 +158,6 @@ func TestSearchWorkspace(t *testing.T) {
159158
}
160159
assert.Contains(t, s.String(), c.ExpectedErrorContains)
161160
} else {
162-
assert.Empty(t, postFilter)
163161
assert.Len(t, errs, 0, "expected no error")
164162
assert.Equal(t, c.Expected, values, "expected values")
165163
}
@@ -170,51 +168,10 @@ func TestSearchWorkspace(t *testing.T) {
170168

171169
query := ``
172170
timeout := 1337 * time.Second
173-
values, _, errs := searchquery.Workspaces(query, codersdk.Pagination{}, timeout)
171+
values, errs := searchquery.Workspaces(query, codersdk.Pagination{}, timeout)
174172
require.Empty(t, errs)
175173
require.Equal(t, int64(timeout.Seconds()), values.AgentInactiveDisconnectTimeoutSeconds)
176174
})
177-
178-
t.Run("TestSearchWorkspacePostFilter", func(t *testing.T) {
179-
t.Parallel()
180-
testCases := []struct {
181-
Name string
182-
Query string
183-
Expected searchquery.PostFilter
184-
}{
185-
{
186-
Name: "Empty",
187-
Query: "",
188-
Expected: searchquery.PostFilter{},
189-
},
190-
{
191-
Name: "DeletingBy",
192-
Query: "deleting_by:2023-06-09",
193-
Expected: searchquery.PostFilter{
194-
DeletingBy: ptr.Ref(time.Date(
195-
2023, 6, 9, 0, 0, 0, 0, time.UTC)),
196-
},
197-
},
198-
{
199-
Name: "MultipleParams",
200-
Query: "deleting_by:2023-06-09 name:workspace-name",
201-
Expected: searchquery.PostFilter{
202-
DeletingBy: ptr.Ref(time.Date(
203-
2023, 6, 9, 0, 0, 0, 0, time.UTC)),
204-
},
205-
},
206-
}
207-
208-
for _, c := range testCases {
209-
c := c
210-
t.Run(c.Name, func(t *testing.T) {
211-
t.Parallel()
212-
_, postFilter, errs := searchquery.Workspaces(c.Query, codersdk.Pagination{}, 0)
213-
assert.Len(t, errs, 0, "expected no error")
214-
assert.Equal(t, c.Expected, postFilter, "expected values")
215-
})
216-
}
217-
})
218175
}
219176

220177
func TestSearchAudit(t *testing.T) {

coderd/workspaces.go

+2-20
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ func (api *API) workspaces(rw http.ResponseWriter, r *http.Request) {
131131
}
132132

133133
queryStr := r.URL.Query().Get("q")
134-
filter, postFilter, errs := searchquery.Workspaces(queryStr, page, api.AgentInactiveDisconnectTimeout)
134+
filter, errs := searchquery.Workspaces(queryStr, page, api.AgentInactiveDisconnectTimeout)
135135
if len(errs) > 0 {
136136
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
137137
Message: "Invalid workspace search query.",
@@ -191,26 +191,8 @@ func (api *API) workspaces(rw http.ResponseWriter, r *http.Request) {
191191
return
192192
}
193193

194-
var filteredWorkspaces []codersdk.Workspace
195-
// apply post filters, if they exist
196-
if postFilter.DeletingBy == nil {
197-
filteredWorkspaces = append(filteredWorkspaces, wss...)
198-
} else {
199-
for _, v := range wss {
200-
if v.DeletingAt == nil {
201-
continue
202-
}
203-
// get the beginning of the day on which deletion is scheduled
204-
truncatedDeletionAt := time.Date(v.DeletingAt.Year(), v.DeletingAt.Month(), v.DeletingAt.Day(), 0, 0, 0, 0, v.DeletingAt.Location())
205-
if truncatedDeletionAt.After(*postFilter.DeletingBy) {
206-
continue
207-
}
208-
filteredWorkspaces = append(filteredWorkspaces, v)
209-
}
210-
}
211-
212194
httpapi.Write(ctx, rw, http.StatusOK, codersdk.WorkspacesResponse{
213-
Workspaces: filteredWorkspaces,
195+
Workspaces: wss,
214196
Count: int(workspaceRows[0].Count),
215197
})
216198
}

coderd/workspaces_test.go

+2-59
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"net/http"
1010
"os"
1111
"strings"
12-
"sync/atomic"
1312
"testing"
1413
"time"
1514

@@ -1395,63 +1394,7 @@ func TestWorkspaceFilterManual(t *testing.T) {
13951394
}, testutil.IntervalMedium, "agent status timeout")
13961395
})
13971396

1398-
t.Run("FilterQueryHasDeletingByAndUnlicensed", func(t *testing.T) {
1399-
// this test has a licensed counterpart in enterprise/coderd/workspaces_test.go: FilterQueryHasDeletingByAndLicensed
1400-
t.Parallel()
1401-
inactivityTTL := 1 * 24 * time.Hour
1402-
var setCalled int64
1403-
1404-
client := coderdtest.New(t, &coderdtest.Options{
1405-
IncludeProvisionerDaemon: true,
1406-
TemplateScheduleStore: schedule.MockTemplateScheduleStore{
1407-
SetFn: func(ctx context.Context, db database.Store, template database.Template, options schedule.TemplateScheduleOptions) (database.Template, error) {
1408-
if atomic.AddInt64(&setCalled, 1) == 2 {
1409-
assert.Equal(t, inactivityTTL, options.TimeTilDormant)
1410-
}
1411-
template.TimeTilDormant = int64(options.TimeTilDormant)
1412-
return template, nil
1413-
},
1414-
},
1415-
})
1416-
user := coderdtest.CreateFirstUser(t, client)
1417-
authToken := uuid.NewString()
1418-
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
1419-
Parse: echo.ParseComplete,
1420-
ProvisionPlan: echo.PlanComplete,
1421-
ProvisionApply: echo.ProvisionApplyWithAgent(authToken),
1422-
})
1423-
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
1424-
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
1425-
1426-
// update template with inactivity ttl
1427-
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
1428-
defer cancel()
1429-
1430-
template, err := client.UpdateTemplateMeta(ctx, template.ID, codersdk.UpdateTemplateMeta{
1431-
TimeTilDormantMillis: inactivityTTL.Milliseconds(),
1432-
})
1433-
1434-
assert.NoError(t, err)
1435-
assert.Equal(t, inactivityTTL.Milliseconds(), template.TimeTilDormantMillis)
1436-
1437-
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
1438-
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
1439-
1440-
// stop build so workspace is inactive
1441-
stopBuild := coderdtest.CreateWorkspaceBuild(t, client, workspace, database.WorkspaceTransitionStop)
1442-
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, stopBuild.ID)
1443-
1444-
res, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
1445-
FilterQuery: fmt.Sprintf("deleting_by:%s", time.Now().Add(inactivityTTL).Format("2006-01-02")),
1446-
})
1447-
1448-
assert.NoError(t, err)
1449-
// we are expecting that no workspaces are returned as user is unlicensed
1450-
// and template.TimeTilDormant should be 0
1451-
assert.Len(t, res.Workspaces, 0)
1452-
})
1453-
1454-
t.Run("DormantAt", func(t *testing.T) {
1397+
t.Run("IsDormant", func(t *testing.T) {
14551398
// this test has a licensed counterpart in enterprise/coderd/workspaces_test.go: FilterQueryHasDeletingByAndLicensed
14561399
t.Parallel()
14571400
client := coderdtest.New(t, &coderdtest.Options{
@@ -1484,7 +1427,7 @@ func TestWorkspaceFilterManual(t *testing.T) {
14841427
require.NoError(t, err)
14851428

14861429
res, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
1487-
FilterQuery: fmt.Sprintf("dormant_at:%s", time.Now().Add(-time.Minute).Format("2006-01-02")),
1430+
FilterQuery: "is-dormant:true",
14881431
})
14891432
require.NoError(t, err)
14901433
require.Len(t, res.Workspaces, 1)

0 commit comments

Comments
 (0)