chore: implement oom/ood processing component (#16436)

Implements the processing logic as set out in the OOM/OOD RFC.
This commit is contained in:
Danielle Maywood
2025-02-17 16:56:52 +00:00
committed by GitHub
parent b5329ae1cd
commit d6b9806098
26 changed files with 1823 additions and 113 deletions
+40
View File
@@ -289,6 +289,24 @@ var (
Scope: rbac.ScopeAll,
}.WithCachedASTValue()
subjectResourceMonitor = rbac.Subject{
FriendlyName: "Resource Monitor",
ID: uuid.Nil.String(),
Roles: rbac.Roles([]rbac.Role{
{
Identifier: rbac.RoleIdentifier{Name: "resourcemonitor"},
DisplayName: "Resource Monitor",
Site: rbac.Permissions(map[string][]policy.Action{
// The workspace monitor needs to be able to update monitors
rbac.ResourceWorkspaceAgentResourceMonitor.Type: {policy.ActionUpdate},
}),
Org: map[string][]rbac.Permission{},
User: []rbac.Permission{},
},
}),
Scope: rbac.ScopeAll,
}.WithCachedASTValue()
subjectSystemRestricted = rbac.Subject{
FriendlyName: "System",
ID: uuid.Nil.String(),
@@ -376,6 +394,12 @@ func AsNotifier(ctx context.Context) context.Context {
return context.WithValue(ctx, authContextKey{}, subjectNotifier)
}
// AsResourceMonitor returns a context with an actor that has permissions required for
// updating resource monitors.
func AsResourceMonitor(ctx context.Context) context.Context {
return context.WithValue(ctx, authContextKey{}, subjectResourceMonitor)
}
// AsSystemRestricted returns a context with an actor that has permissions
// required for various system operations (login, logout, metrics cache).
func AsSystemRestricted(ctx context.Context) context.Context {
@@ -3677,6 +3701,14 @@ func (q *querier) UpdateMemberRoles(ctx context.Context, arg database.UpdateMemb
return q.db.UpdateMemberRoles(ctx, arg)
}
func (q *querier) UpdateMemoryResourceMonitor(ctx context.Context, arg database.UpdateMemoryResourceMonitorParams) error {
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceWorkspaceAgentResourceMonitor); err != nil {
return err
}
return q.db.UpdateMemoryResourceMonitor(ctx, arg)
}
func (q *querier) UpdateNotificationTemplateMethodByID(ctx context.Context, arg database.UpdateNotificationTemplateMethodByIDParams) (database.NotificationTemplate, error) {
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceNotificationTemplate); err != nil {
return database.NotificationTemplate{}, err
@@ -4073,6 +4105,14 @@ func (q *querier) UpdateUserStatus(ctx context.Context, arg database.UpdateUserS
return updateWithReturn(q.log, q.auth, fetch, q.db.UpdateUserStatus)(ctx, arg)
}
func (q *querier) UpdateVolumeResourceMonitor(ctx context.Context, arg database.UpdateVolumeResourceMonitorParams) error {
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceWorkspaceAgentResourceMonitor); err != nil {
return err
}
return q.db.UpdateVolumeResourceMonitor(ctx, arg)
}
func (q *querier) UpdateWorkspace(ctx context.Context, arg database.UpdateWorkspaceParams) (database.WorkspaceTable, error) {
fetch := func(ctx context.Context, arg database.UpdateWorkspaceParams) (database.WorkspaceTable, error) {
w, err := q.db.GetWorkspaceByID(ctx, arg.ID)
+56 -45
View File
@@ -4725,43 +4725,78 @@ func (s *MethodTestSuite) TestOAuth2ProviderAppTokens() {
}
func (s *MethodTestSuite) TestResourcesMonitor() {
s.Run("InsertMemoryResourceMonitor", s.Subtest(func(db database.Store, check *expects) {
dbtestutil.DisableForeignKeysAndTriggers(s.T(), db)
check.Args(database.InsertMemoryResourceMonitorParams{}).Asserts(rbac.ResourceWorkspaceAgentResourceMonitor, policy.ActionCreate)
}))
createAgent := func(t *testing.T, db database.Store) (database.WorkspaceAgent, database.WorkspaceTable) {
t.Helper()
s.Run("InsertVolumeResourceMonitor", s.Subtest(func(db database.Store, check *expects) {
dbtestutil.DisableForeignKeysAndTriggers(s.T(), db)
check.Args(database.InsertVolumeResourceMonitorParams{}).Asserts(rbac.ResourceWorkspaceAgentResourceMonitor, policy.ActionCreate)
}))
s.Run("FetchMemoryResourceMonitorsByAgentID", s.Subtest(func(db database.Store, check *expects) {
u := dbgen.User(s.T(), db, database.User{})
o := dbgen.Organization(s.T(), db, database.Organization{})
tpl := dbgen.Template(s.T(), db, database.Template{
u := dbgen.User(t, db, database.User{})
o := dbgen.Organization(t, db, database.Organization{})
tpl := dbgen.Template(t, db, database.Template{
OrganizationID: o.ID,
CreatedBy: u.ID,
})
tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{
tv := dbgen.TemplateVersion(t, db, database.TemplateVersion{
TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true},
OrganizationID: o.ID,
CreatedBy: u.ID,
})
w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{
w := dbgen.Workspace(t, db, database.WorkspaceTable{
TemplateID: tpl.ID,
OrganizationID: o.ID,
OwnerID: u.ID,
})
j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{
j := dbgen.ProvisionerJob(t, db, nil, database.ProvisionerJob{
Type: database.ProvisionerJobTypeWorkspaceBuild,
})
b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{
b := dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{
JobID: j.ID,
WorkspaceID: w.ID,
TemplateVersionID: tv.ID,
})
res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: b.JobID})
agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID})
res := dbgen.WorkspaceResource(t, db, database.WorkspaceResource{JobID: b.JobID})
agt := dbgen.WorkspaceAgent(t, db, database.WorkspaceAgent{ResourceID: res.ID})
return agt, w
}
s.Run("InsertMemoryResourceMonitor", s.Subtest(func(db database.Store, check *expects) {
agt, _ := createAgent(s.T(), db)
check.Args(database.InsertMemoryResourceMonitorParams{
AgentID: agt.ID,
State: database.WorkspaceAgentMonitorStateOK,
}).Asserts(rbac.ResourceWorkspaceAgentResourceMonitor, policy.ActionCreate)
}))
s.Run("InsertVolumeResourceMonitor", s.Subtest(func(db database.Store, check *expects) {
agt, _ := createAgent(s.T(), db)
check.Args(database.InsertVolumeResourceMonitorParams{
AgentID: agt.ID,
State: database.WorkspaceAgentMonitorStateOK,
}).Asserts(rbac.ResourceWorkspaceAgentResourceMonitor, policy.ActionCreate)
}))
s.Run("UpdateMemoryResourceMonitor", s.Subtest(func(db database.Store, check *expects) {
agt, _ := createAgent(s.T(), db)
check.Args(database.UpdateMemoryResourceMonitorParams{
AgentID: agt.ID,
State: database.WorkspaceAgentMonitorStateOK,
}).Asserts(rbac.ResourceWorkspaceAgentResourceMonitor, policy.ActionUpdate)
}))
s.Run("UpdateVolumeResourceMonitor", s.Subtest(func(db database.Store, check *expects) {
agt, _ := createAgent(s.T(), db)
check.Args(database.UpdateVolumeResourceMonitorParams{
AgentID: agt.ID,
State: database.WorkspaceAgentMonitorStateOK,
}).Asserts(rbac.ResourceWorkspaceAgentResourceMonitor, policy.ActionUpdate)
}))
s.Run("FetchMemoryResourceMonitorsByAgentID", s.Subtest(func(db database.Store, check *expects) {
agt, w := createAgent(s.T(), db)
dbgen.WorkspaceAgentMemoryResourceMonitor(s.T(), db, database.WorkspaceAgentMemoryResourceMonitor{
AgentID: agt.ID,
Enabled: true,
@@ -4776,32 +4811,8 @@ func (s *MethodTestSuite) TestResourcesMonitor() {
}))
s.Run("FetchVolumesResourceMonitorsByAgentID", s.Subtest(func(db database.Store, check *expects) {
u := dbgen.User(s.T(), db, database.User{})
o := dbgen.Organization(s.T(), db, database.Organization{})
tpl := dbgen.Template(s.T(), db, database.Template{
OrganizationID: o.ID,
CreatedBy: u.ID,
})
tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{
TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true},
OrganizationID: o.ID,
CreatedBy: u.ID,
})
w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{
TemplateID: tpl.ID,
OrganizationID: o.ID,
OwnerID: u.ID,
})
j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{
Type: database.ProvisionerJobTypeWorkspaceBuild,
})
b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{
JobID: j.ID,
WorkspaceID: w.ID,
TemplateVersionID: tv.ID,
})
res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: b.JobID})
agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID})
agt, w := createAgent(s.T(), db)
dbgen.WorkspaceAgentVolumeResourceMonitor(s.T(), db, database.WorkspaceAgentVolumeResourceMonitor{
AgentID: agt.ID,
Path: "/var/lib",
+15 -9
View File
@@ -1038,10 +1038,13 @@ func OAuth2ProviderAppToken(t testing.TB, db database.Store, seed database.OAuth
func WorkspaceAgentMemoryResourceMonitor(t testing.TB, db database.Store, seed database.WorkspaceAgentMemoryResourceMonitor) database.WorkspaceAgentMemoryResourceMonitor {
monitor, err := db.InsertMemoryResourceMonitor(genCtx, database.InsertMemoryResourceMonitorParams{
AgentID: takeFirst(seed.AgentID, uuid.New()),
Enabled: takeFirst(seed.Enabled, true),
Threshold: takeFirst(seed.Threshold, 100),
CreatedAt: takeFirst(seed.CreatedAt, dbtime.Now()),
AgentID: takeFirst(seed.AgentID, uuid.New()),
Enabled: takeFirst(seed.Enabled, true),
State: takeFirst(seed.State, database.WorkspaceAgentMonitorStateOK),
Threshold: takeFirst(seed.Threshold, 100),
CreatedAt: takeFirst(seed.CreatedAt, dbtime.Now()),
UpdatedAt: takeFirst(seed.UpdatedAt, dbtime.Now()),
DebouncedUntil: takeFirst(seed.DebouncedUntil, time.Time{}),
})
require.NoError(t, err, "insert workspace agent memory resource monitor")
return monitor
@@ -1049,11 +1052,14 @@ func WorkspaceAgentMemoryResourceMonitor(t testing.TB, db database.Store, seed d
func WorkspaceAgentVolumeResourceMonitor(t testing.TB, db database.Store, seed database.WorkspaceAgentVolumeResourceMonitor) database.WorkspaceAgentVolumeResourceMonitor {
monitor, err := db.InsertVolumeResourceMonitor(genCtx, database.InsertVolumeResourceMonitorParams{
AgentID: takeFirst(seed.AgentID, uuid.New()),
Path: takeFirst(seed.Path, "/"),
Enabled: takeFirst(seed.Enabled, true),
Threshold: takeFirst(seed.Threshold, 100),
CreatedAt: takeFirst(seed.CreatedAt, dbtime.Now()),
AgentID: takeFirst(seed.AgentID, uuid.New()),
Path: takeFirst(seed.Path, "/"),
Enabled: takeFirst(seed.Enabled, true),
State: takeFirst(seed.State, database.WorkspaceAgentMonitorStateOK),
Threshold: takeFirst(seed.Threshold, 100),
CreatedAt: takeFirst(seed.CreatedAt, dbtime.Now()),
UpdatedAt: takeFirst(seed.UpdatedAt, dbtime.Now()),
DebouncedUntil: takeFirst(seed.DebouncedUntil, time.Time{}),
})
require.NoError(t, err, "insert workspace agent volume resource monitor")
return monitor
+66 -6
View File
@@ -7989,7 +7989,16 @@ func (q *FakeQuerier) InsertMemoryResourceMonitor(_ context.Context, arg databas
q.mutex.Lock()
defer q.mutex.Unlock()
monitor := database.WorkspaceAgentMemoryResourceMonitor(arg)
//nolint:unconvert // The structs field-order differs so this is needed.
monitor := database.WorkspaceAgentMemoryResourceMonitor(database.WorkspaceAgentMemoryResourceMonitor{
AgentID: arg.AgentID,
Enabled: arg.Enabled,
State: arg.State,
Threshold: arg.Threshold,
CreatedAt: arg.CreatedAt,
UpdatedAt: arg.UpdatedAt,
DebouncedUntil: arg.DebouncedUntil,
})
q.workspaceAgentMemoryResourceMonitors = append(q.workspaceAgentMemoryResourceMonitors, monitor)
return monitor, nil
@@ -8676,11 +8685,14 @@ func (q *FakeQuerier) InsertVolumeResourceMonitor(_ context.Context, arg databas
defer q.mutex.Unlock()
monitor := database.WorkspaceAgentVolumeResourceMonitor{
AgentID: arg.AgentID,
Path: arg.Path,
Enabled: arg.Enabled,
Threshold: arg.Threshold,
CreatedAt: arg.CreatedAt,
AgentID: arg.AgentID,
Path: arg.Path,
Enabled: arg.Enabled,
State: arg.State,
Threshold: arg.Threshold,
CreatedAt: arg.CreatedAt,
UpdatedAt: arg.UpdatedAt,
DebouncedUntil: arg.DebouncedUntil,
}
q.workspaceAgentVolumeResourceMonitors = append(q.workspaceAgentVolumeResourceMonitors, monitor)
@@ -9691,6 +9703,30 @@ func (q *FakeQuerier) UpdateMemberRoles(_ context.Context, arg database.UpdateMe
return database.OrganizationMember{}, sql.ErrNoRows
}
func (q *FakeQuerier) UpdateMemoryResourceMonitor(_ context.Context, arg database.UpdateMemoryResourceMonitorParams) error {
err := validateDatabaseType(arg)
if err != nil {
return err
}
q.mutex.Lock()
defer q.mutex.Unlock()
for i, monitor := range q.workspaceAgentMemoryResourceMonitors {
if monitor.AgentID != arg.AgentID {
continue
}
monitor.State = arg.State
monitor.UpdatedAt = arg.UpdatedAt
monitor.DebouncedUntil = arg.DebouncedUntil
q.workspaceAgentMemoryResourceMonitors[i] = monitor
return nil
}
return nil
}
func (*FakeQuerier) UpdateNotificationTemplateMethodByID(_ context.Context, _ database.UpdateNotificationTemplateMethodByIDParams) (database.NotificationTemplate, error) {
// Not implementing this function because it relies on state in the database which is created with migrations.
// We could consider using code-generation to align the database state and dbmem, but it's not worth it right now.
@@ -10469,6 +10505,30 @@ func (q *FakeQuerier) UpdateUserStatus(_ context.Context, arg database.UpdateUse
return database.User{}, sql.ErrNoRows
}
func (q *FakeQuerier) UpdateVolumeResourceMonitor(_ context.Context, arg database.UpdateVolumeResourceMonitorParams) error {
err := validateDatabaseType(arg)
if err != nil {
return err
}
q.mutex.Lock()
defer q.mutex.Unlock()
for i, monitor := range q.workspaceAgentVolumeResourceMonitors {
if monitor.AgentID != arg.AgentID || monitor.Path != arg.Path {
continue
}
monitor.State = arg.State
monitor.UpdatedAt = arg.UpdatedAt
monitor.DebouncedUntil = arg.DebouncedUntil
q.workspaceAgentVolumeResourceMonitors[i] = monitor
return nil
}
return nil
}
func (q *FakeQuerier) UpdateWorkspace(_ context.Context, arg database.UpdateWorkspaceParams) (database.WorkspaceTable, error) {
if err := validateDatabaseType(arg); err != nil {
return database.WorkspaceTable{}, err
+14
View File
@@ -2331,6 +2331,13 @@ func (m queryMetricsStore) UpdateMemberRoles(ctx context.Context, arg database.U
return member, err
}
func (m queryMetricsStore) UpdateMemoryResourceMonitor(ctx context.Context, arg database.UpdateMemoryResourceMonitorParams) error {
start := time.Now()
r0 := m.s.UpdateMemoryResourceMonitor(ctx, arg)
m.queryLatencies.WithLabelValues("UpdateMemoryResourceMonitor").Observe(time.Since(start).Seconds())
return r0
}
func (m queryMetricsStore) UpdateNotificationTemplateMethodByID(ctx context.Context, arg database.UpdateNotificationTemplateMethodByIDParams) (database.NotificationTemplate, error) {
start := time.Now()
r0, r1 := m.s.UpdateNotificationTemplateMethodByID(ctx, arg)
@@ -2569,6 +2576,13 @@ func (m queryMetricsStore) UpdateUserStatus(ctx context.Context, arg database.Up
return user, err
}
func (m queryMetricsStore) UpdateVolumeResourceMonitor(ctx context.Context, arg database.UpdateVolumeResourceMonitorParams) error {
start := time.Now()
r0 := m.s.UpdateVolumeResourceMonitor(ctx, arg)
m.queryLatencies.WithLabelValues("UpdateVolumeResourceMonitor").Observe(time.Since(start).Seconds())
return r0
}
func (m queryMetricsStore) UpdateWorkspace(ctx context.Context, arg database.UpdateWorkspaceParams) (database.WorkspaceTable, error) {
start := time.Now()
workspace, err := m.s.UpdateWorkspace(ctx, arg)
+28
View File
@@ -4965,6 +4965,20 @@ func (mr *MockStoreMockRecorder) UpdateMemberRoles(ctx, arg any) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateMemberRoles", reflect.TypeOf((*MockStore)(nil).UpdateMemberRoles), ctx, arg)
}
// UpdateMemoryResourceMonitor mocks base method.
func (m *MockStore) UpdateMemoryResourceMonitor(ctx context.Context, arg database.UpdateMemoryResourceMonitorParams) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UpdateMemoryResourceMonitor", ctx, arg)
ret0, _ := ret[0].(error)
return ret0
}
// UpdateMemoryResourceMonitor indicates an expected call of UpdateMemoryResourceMonitor.
func (mr *MockStoreMockRecorder) UpdateMemoryResourceMonitor(ctx, arg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateMemoryResourceMonitor", reflect.TypeOf((*MockStore)(nil).UpdateMemoryResourceMonitor), ctx, arg)
}
// UpdateNotificationTemplateMethodByID mocks base method.
func (m *MockStore) UpdateNotificationTemplateMethodByID(ctx context.Context, arg database.UpdateNotificationTemplateMethodByIDParams) (database.NotificationTemplate, error) {
m.ctrl.T.Helper()
@@ -5456,6 +5470,20 @@ func (mr *MockStoreMockRecorder) UpdateUserStatus(ctx, arg any) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserStatus", reflect.TypeOf((*MockStore)(nil).UpdateUserStatus), ctx, arg)
}
// UpdateVolumeResourceMonitor mocks base method.
func (m *MockStore) UpdateVolumeResourceMonitor(ctx context.Context, arg database.UpdateVolumeResourceMonitorParams) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UpdateVolumeResourceMonitor", ctx, arg)
ret0, _ := ret[0].(error)
return ret0
}
// UpdateVolumeResourceMonitor indicates an expected call of UpdateVolumeResourceMonitor.
func (mr *MockStoreMockRecorder) UpdateVolumeResourceMonitor(ctx, arg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateVolumeResourceMonitor", reflect.TypeOf((*MockStore)(nil).UpdateVolumeResourceMonitor), ctx, arg)
}
// UpdateWorkspace mocks base method.
func (m *MockStore) UpdateWorkspace(ctx context.Context, arg database.UpdateWorkspaceParams) (database.WorkspaceTable, error) {
m.ctrl.T.Helper()
+13 -2
View File
@@ -244,6 +244,11 @@ CREATE TYPE workspace_agent_lifecycle_state AS ENUM (
'off'
);
CREATE TYPE workspace_agent_monitor_state AS ENUM (
'OK',
'NOK'
);
CREATE TYPE workspace_agent_script_timing_stage AS ENUM (
'start',
'stop',
@@ -1510,7 +1515,10 @@ CREATE TABLE workspace_agent_memory_resource_monitors (
agent_id uuid NOT NULL,
enabled boolean NOT NULL,
threshold integer NOT NULL,
created_at timestamp with time zone NOT NULL
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
state workspace_agent_monitor_state DEFAULT 'OK'::workspace_agent_monitor_state NOT NULL,
debounced_until timestamp with time zone DEFAULT '0001-01-01 00:00:00+00'::timestamp with time zone NOT NULL
);
CREATE UNLOGGED TABLE workspace_agent_metadata (
@@ -1595,7 +1603,10 @@ CREATE TABLE workspace_agent_volume_resource_monitors (
enabled boolean NOT NULL,
threshold integer NOT NULL,
path text NOT NULL,
created_at timestamp with time zone NOT NULL
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
state workspace_agent_monitor_state DEFAULT 'OK'::workspace_agent_monitor_state NOT NULL,
debounced_until timestamp with time zone DEFAULT '0001-01-01 00:00:00+00'::timestamp with time zone NOT NULL
);
CREATE TABLE workspace_agents (
@@ -0,0 +1,11 @@
ALTER TABLE workspace_agent_volume_resource_monitors
DROP COLUMN updated_at,
DROP COLUMN state,
DROP COLUMN debounced_until;
ALTER TABLE workspace_agent_memory_resource_monitors
DROP COLUMN updated_at,
DROP COLUMN state,
DROP COLUMN debounced_until;
DROP TYPE workspace_agent_monitor_state;
@@ -0,0 +1,14 @@
CREATE TYPE workspace_agent_monitor_state AS ENUM (
'OK',
'NOK'
);
ALTER TABLE workspace_agent_memory_resource_monitors
ADD COLUMN updated_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
ADD COLUMN state workspace_agent_monitor_state NOT NULL DEFAULT 'OK',
ADD COLUMN debounced_until timestamp with time zone NOT NULL DEFAULT '0001-01-01 00:00:00'::timestamptz;
ALTER TABLE workspace_agent_volume_resource_monitors
ADD COLUMN updated_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
ADD COLUMN state workspace_agent_monitor_state NOT NULL DEFAULT 'OK',
ADD COLUMN debounced_until timestamp with time zone NOT NULL DEFAULT '0001-01-01 00:00:00'::timestamptz;
+28
View File
@@ -527,3 +527,31 @@ func (k CryptoKey) CanVerify(now time.Time) bool {
func (r GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerRow) RBACObject() rbac.Object {
return r.ProvisionerJob.RBACObject()
}
func (m WorkspaceAgentMemoryResourceMonitor) Debounce(
by time.Duration,
now time.Time,
oldState, newState WorkspaceAgentMonitorState,
) (time.Time, bool) {
if now.After(m.DebouncedUntil) &&
oldState == WorkspaceAgentMonitorStateOK &&
newState == WorkspaceAgentMonitorStateNOK {
return now.Add(by), true
}
return m.DebouncedUntil, false
}
func (m WorkspaceAgentVolumeResourceMonitor) Debounce(
by time.Duration,
now time.Time,
oldState, newState WorkspaceAgentMonitorState,
) (debouncedUntil time.Time, shouldNotify bool) {
if now.After(m.DebouncedUntil) &&
oldState == WorkspaceAgentMonitorStateOK &&
newState == WorkspaceAgentMonitorStateNOK {
return now.Add(by), true
}
return m.DebouncedUntil, false
}
+73 -9
View File
@@ -1976,6 +1976,64 @@ func AllWorkspaceAgentLifecycleStateValues() []WorkspaceAgentLifecycleState {
}
}
type WorkspaceAgentMonitorState string
const (
WorkspaceAgentMonitorStateOK WorkspaceAgentMonitorState = "OK"
WorkspaceAgentMonitorStateNOK WorkspaceAgentMonitorState = "NOK"
)
func (e *WorkspaceAgentMonitorState) Scan(src interface{}) error {
switch s := src.(type) {
case []byte:
*e = WorkspaceAgentMonitorState(s)
case string:
*e = WorkspaceAgentMonitorState(s)
default:
return fmt.Errorf("unsupported scan type for WorkspaceAgentMonitorState: %T", src)
}
return nil
}
type NullWorkspaceAgentMonitorState struct {
WorkspaceAgentMonitorState WorkspaceAgentMonitorState `json:"workspace_agent_monitor_state"`
Valid bool `json:"valid"` // Valid is true if WorkspaceAgentMonitorState is not NULL
}
// Scan implements the Scanner interface.
func (ns *NullWorkspaceAgentMonitorState) Scan(value interface{}) error {
if value == nil {
ns.WorkspaceAgentMonitorState, ns.Valid = "", false
return nil
}
ns.Valid = true
return ns.WorkspaceAgentMonitorState.Scan(value)
}
// Value implements the driver Valuer interface.
func (ns NullWorkspaceAgentMonitorState) Value() (driver.Value, error) {
if !ns.Valid {
return nil, nil
}
return string(ns.WorkspaceAgentMonitorState), nil
}
func (e WorkspaceAgentMonitorState) Valid() bool {
switch e {
case WorkspaceAgentMonitorStateOK,
WorkspaceAgentMonitorStateNOK:
return true
}
return false
}
func AllWorkspaceAgentMonitorStateValues() []WorkspaceAgentMonitorState {
return []WorkspaceAgentMonitorState{
WorkspaceAgentMonitorStateOK,
WorkspaceAgentMonitorStateNOK,
}
}
// What stage the script was ran in.
type WorkspaceAgentScriptTimingStage string
@@ -3185,10 +3243,13 @@ type WorkspaceAgentLogSource struct {
}
type WorkspaceAgentMemoryResourceMonitor struct {
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
Enabled bool `db:"enabled" json:"enabled"`
Threshold int32 `db:"threshold" json:"threshold"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
Enabled bool `db:"enabled" json:"enabled"`
Threshold int32 `db:"threshold" json:"threshold"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
State WorkspaceAgentMonitorState `db:"state" json:"state"`
DebouncedUntil time.Time `db:"debounced_until" json:"debounced_until"`
}
type WorkspaceAgentMetadatum struct {
@@ -3259,11 +3320,14 @@ type WorkspaceAgentStat struct {
}
type WorkspaceAgentVolumeResourceMonitor struct {
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
Enabled bool `db:"enabled" json:"enabled"`
Threshold int32 `db:"threshold" json:"threshold"`
Path string `db:"path" json:"path"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
Enabled bool `db:"enabled" json:"enabled"`
Threshold int32 `db:"threshold" json:"threshold"`
Path string `db:"path" json:"path"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
State WorkspaceAgentMonitorState `db:"state" json:"state"`
DebouncedUntil time.Time `db:"debounced_until" json:"debounced_until"`
}
type WorkspaceApp struct {
+2
View File
@@ -480,6 +480,7 @@ type sqlcQuerier interface {
UpdateGroupByID(ctx context.Context, arg UpdateGroupByIDParams) (Group, error)
UpdateInactiveUsersToDormant(ctx context.Context, arg UpdateInactiveUsersToDormantParams) ([]UpdateInactiveUsersToDormantRow, error)
UpdateMemberRoles(ctx context.Context, arg UpdateMemberRolesParams) (OrganizationMember, error)
UpdateMemoryResourceMonitor(ctx context.Context, arg UpdateMemoryResourceMonitorParams) error
UpdateNotificationTemplateMethodByID(ctx context.Context, arg UpdateNotificationTemplateMethodByIDParams) (NotificationTemplate, error)
UpdateOAuth2ProviderAppByID(ctx context.Context, arg UpdateOAuth2ProviderAppByIDParams) (OAuth2ProviderApp, error)
UpdateOAuth2ProviderAppSecretByID(ctx context.Context, arg UpdateOAuth2ProviderAppSecretByIDParams) (OAuth2ProviderAppSecret, error)
@@ -514,6 +515,7 @@ type sqlcQuerier interface {
UpdateUserQuietHoursSchedule(ctx context.Context, arg UpdateUserQuietHoursScheduleParams) (User, error)
UpdateUserRoles(ctx context.Context, arg UpdateUserRolesParams) (User, error)
UpdateUserStatus(ctx context.Context, arg UpdateUserStatusParams) (User, error)
UpdateVolumeResourceMonitor(ctx context.Context, arg UpdateVolumeResourceMonitorParams) error
UpdateWorkspace(ctx context.Context, arg UpdateWorkspaceParams) (WorkspaceTable, error)
UpdateWorkspaceAgentConnectionByID(ctx context.Context, arg UpdateWorkspaceAgentConnectionByIDParams) error
UpdateWorkspaceAgentLifecycleStateByID(ctx context.Context, arg UpdateWorkspaceAgentLifecycleStateByIDParams) error
+101 -15
View File
@@ -12044,7 +12044,7 @@ func (q *sqlQuerier) UpsertWorkspaceAgentPortShare(ctx context.Context, arg Upse
const fetchMemoryResourceMonitorsByAgentID = `-- name: FetchMemoryResourceMonitorsByAgentID :one
SELECT
agent_id, enabled, threshold, created_at
agent_id, enabled, threshold, created_at, updated_at, state, debounced_until
FROM
workspace_agent_memory_resource_monitors
WHERE
@@ -12059,13 +12059,16 @@ func (q *sqlQuerier) FetchMemoryResourceMonitorsByAgentID(ctx context.Context, a
&i.Enabled,
&i.Threshold,
&i.CreatedAt,
&i.UpdatedAt,
&i.State,
&i.DebouncedUntil,
)
return i, err
}
const fetchVolumesResourceMonitorsByAgentID = `-- name: FetchVolumesResourceMonitorsByAgentID :many
SELECT
agent_id, enabled, threshold, path, created_at
agent_id, enabled, threshold, path, created_at, updated_at, state, debounced_until
FROM
workspace_agent_volume_resource_monitors
WHERE
@@ -12087,6 +12090,9 @@ func (q *sqlQuerier) FetchVolumesResourceMonitorsByAgentID(ctx context.Context,
&i.Threshold,
&i.Path,
&i.CreatedAt,
&i.UpdatedAt,
&i.State,
&i.DebouncedUntil,
); err != nil {
return nil, err
}
@@ -12106,26 +12112,35 @@ INSERT INTO
workspace_agent_memory_resource_monitors (
agent_id,
enabled,
state,
threshold,
created_at
created_at,
updated_at,
debounced_until
)
VALUES
($1, $2, $3, $4) RETURNING agent_id, enabled, threshold, created_at
($1, $2, $3, $4, $5, $6, $7) RETURNING agent_id, enabled, threshold, created_at, updated_at, state, debounced_until
`
type InsertMemoryResourceMonitorParams struct {
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
Enabled bool `db:"enabled" json:"enabled"`
Threshold int32 `db:"threshold" json:"threshold"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
Enabled bool `db:"enabled" json:"enabled"`
State WorkspaceAgentMonitorState `db:"state" json:"state"`
Threshold int32 `db:"threshold" json:"threshold"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
DebouncedUntil time.Time `db:"debounced_until" json:"debounced_until"`
}
func (q *sqlQuerier) InsertMemoryResourceMonitor(ctx context.Context, arg InsertMemoryResourceMonitorParams) (WorkspaceAgentMemoryResourceMonitor, error) {
row := q.db.QueryRowContext(ctx, insertMemoryResourceMonitor,
arg.AgentID,
arg.Enabled,
arg.State,
arg.Threshold,
arg.CreatedAt,
arg.UpdatedAt,
arg.DebouncedUntil,
)
var i WorkspaceAgentMemoryResourceMonitor
err := row.Scan(
@@ -12133,6 +12148,9 @@ func (q *sqlQuerier) InsertMemoryResourceMonitor(ctx context.Context, arg Insert
&i.Enabled,
&i.Threshold,
&i.CreatedAt,
&i.UpdatedAt,
&i.State,
&i.DebouncedUntil,
)
return i, err
}
@@ -12143,19 +12161,25 @@ INSERT INTO
agent_id,
path,
enabled,
state,
threshold,
created_at
created_at,
updated_at,
debounced_until
)
VALUES
($1, $2, $3, $4, $5) RETURNING agent_id, enabled, threshold, path, created_at
($1, $2, $3, $4, $5, $6, $7, $8) RETURNING agent_id, enabled, threshold, path, created_at, updated_at, state, debounced_until
`
type InsertVolumeResourceMonitorParams struct {
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
Path string `db:"path" json:"path"`
Enabled bool `db:"enabled" json:"enabled"`
Threshold int32 `db:"threshold" json:"threshold"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
Path string `db:"path" json:"path"`
Enabled bool `db:"enabled" json:"enabled"`
State WorkspaceAgentMonitorState `db:"state" json:"state"`
Threshold int32 `db:"threshold" json:"threshold"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
DebouncedUntil time.Time `db:"debounced_until" json:"debounced_until"`
}
func (q *sqlQuerier) InsertVolumeResourceMonitor(ctx context.Context, arg InsertVolumeResourceMonitorParams) (WorkspaceAgentVolumeResourceMonitor, error) {
@@ -12163,8 +12187,11 @@ func (q *sqlQuerier) InsertVolumeResourceMonitor(ctx context.Context, arg Insert
arg.AgentID,
arg.Path,
arg.Enabled,
arg.State,
arg.Threshold,
arg.CreatedAt,
arg.UpdatedAt,
arg.DebouncedUntil,
)
var i WorkspaceAgentVolumeResourceMonitor
err := row.Scan(
@@ -12173,10 +12200,69 @@ func (q *sqlQuerier) InsertVolumeResourceMonitor(ctx context.Context, arg Insert
&i.Threshold,
&i.Path,
&i.CreatedAt,
&i.UpdatedAt,
&i.State,
&i.DebouncedUntil,
)
return i, err
}
const updateMemoryResourceMonitor = `-- name: UpdateMemoryResourceMonitor :exec
UPDATE workspace_agent_memory_resource_monitors
SET
updated_at = $2,
state = $3,
debounced_until = $4
WHERE
agent_id = $1
`
type UpdateMemoryResourceMonitorParams struct {
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
State WorkspaceAgentMonitorState `db:"state" json:"state"`
DebouncedUntil time.Time `db:"debounced_until" json:"debounced_until"`
}
func (q *sqlQuerier) UpdateMemoryResourceMonitor(ctx context.Context, arg UpdateMemoryResourceMonitorParams) error {
_, err := q.db.ExecContext(ctx, updateMemoryResourceMonitor,
arg.AgentID,
arg.UpdatedAt,
arg.State,
arg.DebouncedUntil,
)
return err
}
const updateVolumeResourceMonitor = `-- name: UpdateVolumeResourceMonitor :exec
UPDATE workspace_agent_volume_resource_monitors
SET
updated_at = $3,
state = $4,
debounced_until = $5
WHERE
agent_id = $1 AND path = $2
`
type UpdateVolumeResourceMonitorParams struct {
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
Path string `db:"path" json:"path"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
State WorkspaceAgentMonitorState `db:"state" json:"state"`
DebouncedUntil time.Time `db:"debounced_until" json:"debounced_until"`
}
func (q *sqlQuerier) UpdateVolumeResourceMonitor(ctx context.Context, arg UpdateVolumeResourceMonitorParams) error {
_, err := q.db.ExecContext(ctx, updateVolumeResourceMonitor,
arg.AgentID,
arg.Path,
arg.UpdatedAt,
arg.State,
arg.DebouncedUntil,
)
return err
}
const deleteOldWorkspaceAgentLogs = `-- name: DeleteOldWorkspaceAgentLogs :exec
WITH
latest_builds AS (
@@ -19,11 +19,14 @@ INSERT INTO
workspace_agent_memory_resource_monitors (
agent_id,
enabled,
state,
threshold,
created_at
created_at,
updated_at,
debounced_until
)
VALUES
($1, $2, $3, $4) RETURNING *;
($1, $2, $3, $4, $5, $6, $7) RETURNING *;
-- name: InsertVolumeResourceMonitor :one
INSERT INTO
@@ -31,8 +34,29 @@ INSERT INTO
agent_id,
path,
enabled,
state,
threshold,
created_at
created_at,
updated_at,
debounced_until
)
VALUES
($1, $2, $3, $4, $5) RETURNING *;
($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *;
-- name: UpdateMemoryResourceMonitor :exec
UPDATE workspace_agent_memory_resource_monitors
SET
updated_at = $2,
state = $3,
debounced_until = $4
WHERE
agent_id = $1;
-- name: UpdateVolumeResourceMonitor :exec
UPDATE workspace_agent_volume_resource_monitors
SET
updated_at = $3,
state = $4,
debounced_until = $5
WHERE
agent_id = $1 AND path = $2;