Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
9a398e7
feat(coderd): notify when workspace is marked as dormant
BrunoQuaresma Jul 10, 2024
fbf99be
Fix role
BrunoQuaresma Jul 10, 2024
40e5801
Apply Danny suggestions
BrunoQuaresma Jul 11, 2024
9a35cbb
Notify dormant workspace on lifecycle executor
BrunoQuaresma Jul 11, 2024
0701572
Notify dormancy on template schedule
BrunoQuaresma Jul 11, 2024
64cf76b
Apply Danny review suggestions
BrunoQuaresma Jul 12, 2024
b2f9180
Fix mismatch usage
BrunoQuaresma Jul 12, 2024
a445c4c
Resolve migration conflict
BrunoQuaresma Jul 12, 2024
bdc08d6
Merge branch 'main' of https://github.com/coder/coder into bq/impleme…
BrunoQuaresma Jul 12, 2024
ee7d542
Return error instead of receiving the logger
BrunoQuaresma Jul 12, 2024
f6db3c7
Improve verbiage
BrunoQuaresma Jul 12, 2024
95c784a
Merge branch 'main' of github.com:/coder/coder into bq/implement-noti…
dannykopping Jul 15, 2024
68bcfb0
Merge branch 'main' of github.com:/coder/coder into bq/implement-noti…
dannykopping Jul 16, 2024
467a797
Possible implementation simplification
dannykopping Jul 16, 2024
853e59e
Merge branch 'main' of https://github.com/coder/coder into bq/impleme…
BrunoQuaresma Jul 17, 2024
bbcb28e
Apply fmt
BrunoQuaresma Jul 17, 2024
e3c6f49
Notify after executor is done
BrunoQuaresma Jul 17, 2024
20a8766
Revert refactoring mistake
dannykopping Jul 18, 2024
e087172
Add workspace name to the log
BrunoQuaresma Jul 18, 2024
4b99061
Set a fake enqueuer on coderdtest options
BrunoQuaresma Jul 18, 2024
1932168
Merge branch 'bq/implement-notifications' of https://github.com/coder…
BrunoQuaresma Jul 18, 2024
36c043c
Fix migration
BrunoQuaresma Jul 18, 2024
d07f9d8
Fix migration sql
BrunoQuaresma Jul 18, 2024
21f7c35
Merge branch 'main' of https://github.com/coder/coder into bq/impleme…
BrunoQuaresma Jul 18, 2024
72da82d
Fix typo
BrunoQuaresma Jul 18, 2024
b49cd08
Fix migration number
BrunoQuaresma Jul 18, 2024
6f61f9f
Merge branch 'main' of https://github.com/coder/coder into bq/impleme…
BrunoQuaresma Jul 18, 2024
281b545
Apply Marcin comments
BrunoQuaresma Jul 18, 2024
7f73d90
Fix lint
BrunoQuaresma Jul 18, 2024
7c5de97
Update coderd/autobuild/lifecycle_executor.go
BrunoQuaresma Jul 18, 2024
299cd7f
Apply dannys comment
BrunoQuaresma Jul 18, 2024
16a3c19
Simplify dormancy template
BrunoQuaresma Jul 22, 2024
cf9eaec
Merge branch 'main' of https://github.com/coder/coder into bq/impleme…
BrunoQuaresma Jul 22, 2024
aea55aa
Add test to verify dormancy in lifecycle executor
BrunoQuaresma Jul 22, 2024
6d47c04
Add placeholder
BrunoQuaresma Jul 22, 2024
7b4ae29
make test pass
sreya Jul 23, 2024
308bd69
fix: lint
mtojek Jul 23, 2024
10ff6cf
Merge branch 'main' of https://github.com/coder/coder into bq/impleme…
BrunoQuaresma Jul 23, 2024
48ad269
Add test to verify notification in lifecycle executor
BrunoQuaresma Jul 23, 2024
0226fdf
Add notification for marked as deletion
BrunoQuaresma Jul 23, 2024
4d71c94
Apply Dannys review comments
BrunoQuaresma Jul 24, 2024
e1d5fec
Fix SQL
BrunoQuaresma Jul 24, 2024
a2023a1
Rollback dormant at test
BrunoQuaresma Jul 24, 2024
bae985c
Fix template
BrunoQuaresma Jul 24, 2024
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
Prev Previous commit
Next Next commit
Apply Dannys review comments
  • Loading branch information
BrunoQuaresma committed Jul 24, 2024
commit 4d71c946c8ba5c8e5e41d8508b0dad9a78cb45cc
4 changes: 1 addition & 3 deletions coderd/autobuild/lifecycle_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ func (e *Executor) runOnce(t time.Time) Stats {
nextBuildReason = string(nextBuild.Reason)
}

if _, err := e.notificationsEnqueuer.Enqueue(e.ctx, ws.OwnerID, notifications.WorkspaceAutoUpdated,
if _, err := e.notificationsEnqueuer.Enqueue(e.ctx, ws.OwnerID, notifications.TemplateWorkspaceAutoUpdated,
map[string]string{
"name": ws.Name,
"initiator": "autobuild",
Expand Down Expand Up @@ -334,8 +334,6 @@ func (e *Executor) runOnce(t time.Time) Stats {
if err != nil {
log.Warn(e.ctx, "failed to notify of workspace marked as dormant", slog.Error(err), slog.F("workspace_id", dormantNotification.Workspace.ID))
}
} else {
log.Warn(e.ctx, "no dormant notification to send", slog.F("workspace_id", wsID))
}
return nil
}()
Expand Down
6 changes: 4 additions & 2 deletions coderd/autobuild/lifecycle_executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/coder/coder/v2/coderd/coderdtest"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbauthz"
"github.com/coder/coder/v2/coderd/notifications"
"github.com/coder/coder/v2/coderd/schedule"
"github.com/coder/coder/v2/coderd/schedule/cron"
"github.com/coder/coder/v2/coderd/util/ptr"
Expand Down Expand Up @@ -1107,15 +1108,16 @@ func TestNotifications(t *testing.T) {

// Wait for workspace to become dormant
ticker <- workspace.LastUsedAt.Add(timeTilDormant * 3)
<-statCh
_ = testutil.RequireRecvCtx(testutil.Context(t, testutil.WaitShort), t, statCh)

// Check that the workspace is dormant
workspace = coderdtest.MustWorkspace(t, client, workspace.ID)
require.NotNil(t, workspace.DormantAt)
require.Equal(t, workspace.DormantAt, workspace.LastUsedAt.Add(timeTilDormant))

// Check that a notification was enqueued
require.Len(t, notifyEnq.Sent, 1)
require.Equal(t, notifyEnq.Sent[0].UserID, workspace.OwnerID)
require.Equal(t, notifyEnq.Sent[0].TemplateID, notifications.TemplateWorkspaceDormant)
require.Contains(t, notifyEnq.Sent[0].Targets, template.ID)
require.Contains(t, notifyEnq.Sent[0].Targets, workspace.ID)
require.Contains(t, notifyEnq.Sent[0].Targets, workspace.OrganizationID)
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
DELETE FROM notification_templates WHERE id = '0ea69165-ec14-4314-91f1-69566ac3c5a0';
DELETE FROM notification_templates
WHERE
id = '0ea69165-ec14-4314-91f1-69566ac3c5a0';

DELETE FROM notification_templates
WHERE
id = '51ce2fdf-c9ca-4be1-8d70-628674f9bc42';
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,18 @@ VALUES (
"label": "View workspace",
"url": "{{ base_url }}/@{{.UserName}}/{{.Labels.name}}"
}
]'::jsonb,
),
(
'51ce2fdf-c9ca-4be1-8d70-628674f9bc42',
'Workspace Marked for Deletion',
E'Workspace "{{.Labels.name}}" marked for deletion',
E'Hi {{.UserName}}\n\n' || E'Your workspace **{{.Labels.name}}** has been marked for **deletion** after {{.Labels.dormancyHours}} hours of dormancy.\n' || E'The specified reason was "**{{.Labels.reason}}{{end}}**\n\n' || E'Dormancy refers to a workspace being unused for a defined length of time, and after it exceeds {{.Labels.dormancyHours}} hours of dormancy it will be deleted.\n' || E'To prevent your workspace from being deleted, simply use it as normal.',
'Workspace Events',
'[
{
"label": "View workspace",
"url": "{{ base_url }}/@{{.UserName}}/{{.Labels.name}}"
}
]'::jsonb
);

This file was deleted.

This file was deleted.

7 changes: 3 additions & 4 deletions coderd/dormancy/notifications.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,13 @@ func NotifyWorkspaceMarkedForDeletion(
notification WorkspaceMarkedForDeletionNotification,
) (id *uuid.UUID, err error) {
labels := map[string]string{
"name": notification.Workspace.Name,
"initiator": "autobuild",
"reason": notification.Reason,
"name": notification.Workspace.Name,
"reason": notification.Reason,
}
return enqueuer.Enqueue(
ctx,
notification.Workspace.OwnerID,
notifications.TemplateWorkspaceDormant,
notifications.TemplateWorkspaceMarkedForDeletion,
labels,
notification.CreatedBy,
// Associate this notification with all the related entities.
Expand Down
4 changes: 2 additions & 2 deletions coderd/notifications/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import "github.com/google/uuid"
// Workspace-related events.
var (
TemplateWorkspaceDeleted = uuid.MustParse("f517da0b-cdc9-410f-ab89-a86107c420ed")
WorkspaceAutobuildFailed = uuid.MustParse("381df2a9-c0c0-4749-420f-80a9280c66f9")
TemplateWorkspaceAutobuildFailed = uuid.MustParse("381df2a9-c0c0-4749-420f-80a9280c66f9")
TemplateWorkspaceDormant = uuid.MustParse("0ea69165-ec14-4314-91f1-69566ac3c5a0")
WorkspaceAutoUpdated = uuid.MustParse("c34a0c09-0704-4cac-bd1c-0c0146811c2b")
TemplateWorkspaceAutoUpdated = uuid.MustParse("c34a0c09-0704-4cac-bd1c-0c0146811c2b")
TemplateWorkspaceMarkedForDeletion = uuid.MustParse("51ce2fdf-c9ca-4be1-8d70-628674f9bc42")
)
2 changes: 1 addition & 1 deletion coderd/provisionerdserver/provisionerdserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -1103,7 +1103,7 @@ func (s *server) notifyWorkspaceBuildFailed(ctx context.Context, workspace datab
reason = string(build.Reason)
initiator := "autobuild"

if _, err := s.NotificationsEnqueuer.Enqueue(ctx, workspace.OwnerID, notifications.WorkspaceAutobuildFailed,
if _, err := s.NotificationsEnqueuer.Enqueue(ctx, workspace.OwnerID, notifications.TemplateWorkspaceAutobuildFailed,
map[string]string{
"name": workspace.Name,
"initiator": initiator,
Expand Down
2 changes: 2 additions & 0 deletions coderd/workspaces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/coder/coder/v2/coderd/database/dbgen"
"github.com/coder/coder/v2/coderd/database/dbtestutil"
"github.com/coder/coder/v2/coderd/database/dbtime"
"github.com/coder/coder/v2/coderd/notifications"
"github.com/coder/coder/v2/coderd/rbac"
"github.com/coder/coder/v2/coderd/rbac/policy"
"github.com/coder/coder/v2/coderd/render"
Expand Down Expand Up @@ -3541,6 +3542,7 @@ func TestNotifications(t *testing.T) {
// Then
require.NoError(t, err, "mark workspace as dormant")
require.Len(t, notifyEnq.Sent, 1)
require.Equal(t, notifyEnq.Sent[0].TemplateID, notifications.TemplateWorkspaceDormant)
require.Equal(t, notifyEnq.Sent[0].UserID, workspace.OwnerID)
require.Contains(t, notifyEnq.Sent[0].Targets, template.ID)
require.Contains(t, notifyEnq.Sent[0].Targets, workspace.ID)
Expand Down
2 changes: 1 addition & 1 deletion enterprise/coderd/schedule/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ func (s *EnterpriseTemplateScheduleStore) Set(ctx context.Context, db database.S
},
)
if err != nil {
s.logger.Warn(ctx, "failed to notify of workspace marked for deletion", slog.Error(err))
s.logger.Warn(ctx, "failed to notify of workspace marked for deletion", slog.Error(err), slog.F("workspace_id", workspace.ID))
}
}

Expand Down
13 changes: 11 additions & 2 deletions enterprise/coderd/schedule/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -683,15 +683,24 @@ func TestNotifications(t *testing.T) {
templateScheduleStore := schedule.NewEnterpriseTemplateScheduleStore(userQuietHoursStorePtr, &notifyEnq, logger)
templateScheduleStore.TimeNowFn = time.Now

// Update dormancy TTL for a lower value
// Lower the dormancy TTL to ensure the schedule recalculates deadlines and
// triggers notifications.
_, err = templateScheduleStore.Set(ctx, db, template, agplschedule.TemplateScheduleOptions{
TimeTilDormant: timeTilDormant / 2,
TimeTilDormantAutoDelete: timeTilDormant / 2,
})
require.NoError(t, err)

// We should expect two notifications. One for each dormant workspace.
// We should expect a notification for each dormant workspace.
require.Len(t, notifyEnq.Sent, len(dormantWorkspaces))
for i, dormantWs := range dormantWorkspaces {
require.Equal(t, notifyEnq.Sent[i].UserID, dormantWs.OwnerID)
require.Equal(t, notifyEnq.Sent[i].TemplateID, notifications.TemplateWorkspaceMarkedForDeletion)
require.Contains(t, notifyEnq.Sent[i].Targets, template.ID)
require.Contains(t, notifyEnq.Sent[i].Targets, dormantWs.ID)
require.Contains(t, notifyEnq.Sent[i].Targets, dormantWs.OrganizationID)
require.Contains(t, notifyEnq.Sent[i].Targets, dormantWs.OwnerID)
}
})
}

Expand Down
Loading