Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

chore: wire up usage tracking for managed agents#19096

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
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
1 change: 0 additions & 1 deletioncli/delete_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -111,7 +111,6 @@ func TestDelete(t *testing.T) {
// The API checks if the user has any workspaces, so we cannot delete a user
// this way.
ctx := testutil.Context(t, testutil.WaitShort)
// nolint:gocritic // Unit test
err := api.Database.UpdateUserDeletedByID(dbauthz.AsSystemRestricted(ctx), deleteMeUser.ID)
require.NoError(t, err)

Expand Down
1 change: 0 additions & 1 deletioncli/provisioners_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,7 +31,6 @@ func TestProvisioners_Golden(t *testing.T) {
// Replace UUIDs with predictable values for golden files.
replace := make(map[string]string)
updateReplaceUUIDs := func(coderdAPI *coderd.API) {
//nolint:gocritic // This is a test.
systemCtx := dbauthz.AsSystemRestricted(context.Background())
provisioners, err := coderdAPI.Database.GetProvisionerDaemons(systemCtx)
require.NoError(t, err)
Expand Down
26 changes: 13 additions & 13 deletionscoderd/agentapi/subagent_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -163,7 +163,7 @@ func TestSubAgentAPI(t *testing.T) {
agentID, err := uuid.FromBytes(createResp.Agent.Id)
require.NoError(t, err)

agent, err := api.Database.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), agentID) //nolint:gocritic // this is a test.
agent, err := api.Database.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), agentID)
require.NoError(t, err)

assert.Equal(t, tt.agentName, agent.Name)
Expand DownExpand Up@@ -621,7 +621,7 @@ func TestSubAgentAPI(t *testing.T) {
agentID, err := uuid.FromBytes(createResp.Agent.Id)
require.NoError(t, err)

apps, err := api.Database.GetWorkspaceAppsByAgentID(dbauthz.AsSystemRestricted(ctx), agentID) //nolint:gocritic // this is a test.
apps, err := api.Database.GetWorkspaceAppsByAgentID(dbauthz.AsSystemRestricted(ctx), agentID)
require.NoError(t, err)

// Sort the apps for determinism
Expand DownExpand Up@@ -751,7 +751,7 @@ func TestSubAgentAPI(t *testing.T) {
agentID, err := uuid.FromBytes(createResp.Agent.Id)
require.NoError(t, err)

apps, err := db.GetWorkspaceAppsByAgentID(dbauthz.AsSystemRestricted(ctx), agentID) //nolint:gocritic // this is a test.
apps, err := db.GetWorkspaceAppsByAgentID(dbauthz.AsSystemRestricted(ctx), agentID)
require.NoError(t, err)
require.Len(t, apps, 1)
require.Equal(t, "k5jd7a99-duplicate-slug", apps[0].Slug)
Expand DownExpand Up@@ -789,7 +789,7 @@ func TestSubAgentAPI(t *testing.T) {
require.NoError(t, err)

// Then: It is deleted.
_, err = db.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), childAgent.ID) //nolint:gocritic // this is a test.
_, err = db.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), childAgent.ID)
require.ErrorIs(t, err, sql.ErrNoRows)
})

Expand DownExpand Up@@ -830,10 +830,10 @@ func TestSubAgentAPI(t *testing.T) {
require.NoError(t, err)

// Then: The correct one is deleted.
_, err = api.Database.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), childAgentOne.ID) //nolint:gocritic // this is a test.
_, err = api.Database.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), childAgentOne.ID)
require.ErrorIs(t, err, sql.ErrNoRows)

_, err = api.Database.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), childAgentTwo.ID) //nolint:gocritic // this is a test.
_, err = api.Database.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), childAgentTwo.ID)
require.NoError(t, err)
})

Expand DownExpand Up@@ -871,7 +871,7 @@ func TestSubAgentAPI(t *testing.T) {
var notAuthorizedError dbauthz.NotAuthorizedError
require.ErrorAs(t, err, &notAuthorizedError)

_, err = db.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), childAgentOne.ID) //nolint:gocritic // this is a test.
_, err = db.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), childAgentOne.ID)
require.NoError(t, err)
})

Expand DownExpand Up@@ -912,7 +912,7 @@ func TestSubAgentAPI(t *testing.T) {
require.NoError(t, err)

// Verify that the apps were created
apps, err := api.Database.GetWorkspaceAppsByAgentID(dbauthz.AsSystemRestricted(ctx), subAgentID) //nolint:gocritic // this is a test.
apps, err := api.Database.GetWorkspaceAppsByAgentID(dbauthz.AsSystemRestricted(ctx), subAgentID)
require.NoError(t, err)
require.Len(t, apps, 2)

Expand All@@ -923,7 +923,7 @@ func TestSubAgentAPI(t *testing.T) {
require.NoError(t, err)

// Then: The agent is deleted
_, err = api.Database.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), subAgentID) //nolint:gocritic // this is a test.
_, err = api.Database.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), subAgentID)
require.ErrorIs(t, err, sql.ErrNoRows)

// And: The apps are *retained* to avoid causing issues
Expand DownExpand Up@@ -1068,7 +1068,7 @@ func TestSubAgentAPI(t *testing.T) {
agentID, err := uuid.FromBytes(createResp.Agent.Id)
require.NoError(t, err)

subAgent, err := api.Database.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), agentID) //nolint:gocritic // this is a test.
subAgent, err := api.Database.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), agentID)
require.NoError(t, err)

require.Equal(t, len(tt.expectedApps), len(subAgent.DisplayApps), "display apps count mismatch")
Expand DownExpand Up@@ -1118,14 +1118,14 @@ func TestSubAgentAPI(t *testing.T) {
require.NoError(t, err)

// Verify display apps
subAgent, err := api.Database.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), agentID) //nolint:gocritic // this is a test.
subAgent, err := api.Database.GetWorkspaceAgentByID(dbauthz.AsSystemRestricted(ctx), agentID)
require.NoError(t, err)
require.Len(t, subAgent.DisplayApps, 2)
require.Equal(t, database.DisplayAppVscode, subAgent.DisplayApps[0])
require.Equal(t, database.DisplayAppWebTerminal, subAgent.DisplayApps[1])

// Verify regular apps
apps, err := api.Database.GetWorkspaceAppsByAgentID(dbauthz.AsSystemRestricted(ctx), agentID) //nolint:gocritic // this is a test.
apps, err := api.Database.GetWorkspaceAppsByAgentID(dbauthz.AsSystemRestricted(ctx), agentID)
require.NoError(t, err)
require.Len(t, apps, 1)
require.Equal(t, "v4qhkq17-custom-app", apps[0].Slug)
Expand DownExpand Up@@ -1190,7 +1190,7 @@ func TestSubAgentAPI(t *testing.T) {
})

// When: We list the sub agents.
listResp, err := api.ListSubAgents(ctx, &proto.ListSubAgentsRequest{}) //nolint:gocritic // this is a test.
listResp, err := api.ListSubAgents(ctx, &proto.ListSubAgentsRequest{})
require.NoError(t, err)

listedChildAgents := listResp.Agents
Expand Down
14 changes: 14 additions & 0 deletionscoderd/coderd.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,6 +23,7 @@ import (
"github.com/coder/coder/v2/coderd/oauth2provider"
"github.com/coder/coder/v2/coderd/pproflabel"
"github.com/coder/coder/v2/coderd/prebuilds"
"github.com/coder/coder/v2/coderd/usage"
"github.com/coder/coder/v2/coderd/wsbuilder"

"github.com/andybalholm/brotli"
Expand DownExpand Up@@ -200,6 +201,7 @@ type Options struct {
TemplateScheduleStore *atomic.Pointer[schedule.TemplateScheduleStore]
UserQuietHoursScheduleStore *atomic.Pointer[schedule.UserQuietHoursScheduleStore]
AccessControlStore *atomic.Pointer[dbauthz.AccessControlStore]
UsageInserter *atomic.Pointer[usage.Inserter]
// CoordinatorResumeTokenProvider is used to provide and validate resume
// tokens issued by and passed to the coordinator DRPC API.
CoordinatorResumeTokenProvider tailnet.ResumeTokenProvider
Expand DownExpand Up@@ -428,6 +430,13 @@ func New(options *Options) *API {
v := schedule.NewAGPLUserQuietHoursScheduleStore()
options.UserQuietHoursScheduleStore.Store(&v)
}
if options.UsageInserter == nil {
options.UsageInserter = &atomic.Pointer[usage.Inserter]{}
}
if options.UsageInserter.Load() == nil {
inserter := usage.NewAGPLInserter()
options.UsageInserter.Store(&inserter)
}
if options.OneTimePasscodeValidityPeriod == 0 {
options.OneTimePasscodeValidityPeriod = 20 * time.Minute
}
Expand DownExpand Up@@ -590,6 +599,7 @@ func New(options *Options) *API {
UserQuietHoursScheduleStore: options.UserQuietHoursScheduleStore,
AccessControlStore: options.AccessControlStore,
BuildUsageChecker: &buildUsageChecker,
UsageInserter: options.UsageInserter,
FileCache: files.New(options.PrometheusRegistry, options.Authorizer),
Experiments: experiments,
WebpushDispatcher: options.WebPushDispatcher,
Expand DownExpand Up@@ -1690,6 +1700,9 @@ type API struct {
// BuildUsageChecker is a pointer as it's passed around to multiple
// components.
BuildUsageChecker *atomic.Pointer[wsbuilder.UsageChecker]
// UsageInserter is a pointer to an atomic pointer because it is passed to
// multiple components.
UsageInserter *atomic.Pointer[usage.Inserter]

UpdatesProvider tailnet.WorkspaceUpdatesProvider

Expand DownExpand Up@@ -1905,6 +1918,7 @@ func (api *API) CreateInMemoryTaggedProvisionerDaemon(dialCtx context.Context, n
&api.Auditor,
api.TemplateScheduleStore,
api.UserQuietHoursScheduleStore,
api.UsageInserter,
api.DeploymentValues,
provisionerdserver.Options{
OIDCConfig: api.OIDCConfig,
Expand Down
28 changes: 16 additions & 12 deletionscoderd/database/dbauthz/dbauthz.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -213,6 +213,8 @@ var (
// Provisionerd creates workspaces resources monitor
rbac.ResourceWorkspaceAgentResourceMonitor.Type: {policy.ActionCreate},
rbac.ResourceWorkspaceAgentDevcontainers.Type: {policy.ActionCreate},
// Provisionerd creates usage events
rbac.ResourceUsageEvent.Type: {policy.ActionCreate},
}),
Org: map[string][]rbac.Permission{},
User: []rbac.Permission{},
Expand DownExpand Up@@ -510,17 +512,19 @@ var (
Scope: rbac.ScopeAll,
}.WithCachedASTValue()

subjectUsageTracker = rbac.Subject{
Type: rbac.SubjectTypeUsageTracker,
FriendlyName: "UsageTracker",
subjectUsagePublisher = rbac.Subject{
Type: rbac.SubjectTypeUsagePublisher,
FriendlyName: "UsagePublisher",
ID: uuid.Nil.String(),
Roles: rbac.Roles([]rbac.Role{
{
Identifier: rbac.RoleIdentifier{Name: "usage-tracker"},
DisplayName: "UsageTracker",
Identifier: rbac.RoleIdentifier{Name: "usage-publisher"},
DisplayName: "UsagePublisher",
Site: rbac.Permissions(map[string][]policy.Action{
rbac.ResourceLicense.Type: {policy.ActionRead},
rbac.ResourceUsageEvent.Type: {policy.ActionCreate, policy.ActionRead, policy.ActionUpdate},
rbac.ResourceLicense.Type: {policy.ActionRead},
// The usage publisher doesn't create events, just
// reads/processes them.
rbac.ResourceUsageEvent.Type: {policy.ActionRead, policy.ActionUpdate},
}),
Org: map[string][]rbac.Permission{},
User: []rbac.Permission{},
Expand DownExpand Up@@ -604,10 +608,10 @@ func AsFileReader(ctx context.Context) context.Context {
return As(ctx, subjectFileReader)
}

//AsUsageTracker returns a context with an actor that has permissions required
// for creating, reading, and updating usage events.
funcAsUsageTracker(ctx context.Context) context.Context {
return As(ctx,subjectUsageTracker)
//AsUsagePublisher returns a context with an actor that has permissions
//requiredfor creating, reading, and updating usage events.
funcAsUsagePublisher(ctx context.Context) context.Context {
return As(ctx,subjectUsagePublisher)
}

var AsRemoveActor = rbac.Subject{
Expand DownExpand Up@@ -3038,7 +3042,7 @@ func (q *querier) GetTemplatesWithFilter(ctx context.Context, arg database.GetTe
}

func (q *querier) GetUnexpiredLicenses(ctx context.Context) ([]database.License, error) {
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil {
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceLicense); err != nil {
return nil, err
}
return q.db.GetUnexpiredLicenses(ctx)
Expand Down
15 changes: 12 additions & 3 deletionscoderd/database/dbauthz/dbauthz_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -758,6 +758,18 @@ func (s *MethodTestSuite) TestLicense() {
check.Args().Asserts(l, policy.ActionRead).
Returns([]database.License{l})
}))
s.Run("GetUnexpiredLicenses", s.Mocked(func(db *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
l := database.License{
ID: 1,
Exp: time.Now().Add(time.Hour * 24 * 30),
UUID: uuid.New(),
}
db.EXPECT().GetUnexpiredLicenses(gomock.Any()).
Return([]database.License{l}, nil).
AnyTimes()
check.Args().Asserts(rbac.ResourceLicense, policy.ActionRead).
Returns([]database.License{l})
}))
s.Run("InsertLicense", s.Subtest(func(db database.Store, check *expects) {
check.Args(database.InsertLicenseParams{}).
Asserts(rbac.ResourceLicense, policy.ActionCreate)
Expand DownExpand Up@@ -3770,9 +3782,6 @@ func (s *MethodTestSuite) TestSystemFunctions() {
s.Run("GetActiveUserCount", s.Subtest(func(db database.Store, check *expects) {
check.Args(false).Asserts(rbac.ResourceSystem, policy.ActionRead).Returns(int64(0))
}))
s.Run("GetUnexpiredLicenses", s.Subtest(func(db database.Store, check *expects) {
check.Args().Asserts(rbac.ResourceSystem, policy.ActionRead)
}))
s.Run("GetAuthorizationUserRoles", s.Subtest(func(db database.Store, check *expects) {
u := dbgen.User(s.T(), db, database.User{})
check.Args(u.ID).Asserts(rbac.ResourceSystem, policy.ActionRead)
Expand Down
1 change: 0 additions & 1 deletioncoderd/externalauth/externalauth_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -337,7 +337,6 @@ func TestRefreshToken(t *testing.T) {
require.Equal(t, 1, validateCalls, "token is validated")
require.Equal(t, 1, refreshCalls, "token is refreshed")
require.NotEqualf(t, link.OAuthAccessToken, updated.OAuthAccessToken, "token is updated")
//nolint:gocritic // testing
dbLink, err := db.GetExternalAuthLink(dbauthz.AsSystemRestricted(context.Background()), database.GetExternalAuthLinkParams{
ProviderID: link.ProviderID,
UserID: link.UserID,
Expand Down
6 changes: 0 additions & 6 deletionscoderd/files/cache_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,7 +45,6 @@ func TestCancelledFetch(t *testing.T) {
cache := files.New(prometheus.NewRegistry(), &coderdtest.FakeAuthorizer{})

// Cancel the context for the first call; should fail.
//nolint:gocritic // Unit testing
ctx, cancel := context.WithCancel(dbauthz.AsFileReader(testutil.Context(t, testutil.WaitShort)))
cancel()
_, err := cache.Acquire(ctx, dbM, fileID)
Expand All@@ -71,7 +70,6 @@ func TestCancelledConcurrentFetch(t *testing.T) {

cache := files.LeakCache{Cache: files.New(prometheus.NewRegistry(), &coderdtest.FakeAuthorizer{})}

//nolint:gocritic // Unit testing
ctx := dbauthz.AsFileReader(testutil.Context(t, testutil.WaitShort))

// Cancel the context for the first call; should fail.
Expand DownExpand Up@@ -99,7 +97,6 @@ func TestConcurrentFetch(t *testing.T) {
})

cache := files.New(prometheus.NewRegistry(), &coderdtest.FakeAuthorizer{})
//nolint:gocritic // Unit testing
ctx := dbauthz.AsFileReader(testutil.Context(t, testutil.WaitShort))

// Expect 2 calls to Acquire before we continue the test
Expand DownExpand Up@@ -151,7 +148,6 @@ func TestCacheRBAC(t *testing.T) {
Scope: rbac.ScopeAll,
})

//nolint:gocritic // Unit testing
cacheReader := dbauthz.AsFileReader(ctx)

t.Run("NoRolesOpen", func(t *testing.T) {
Expand DownExpand Up@@ -207,7 +203,6 @@ func cachePromMetricName(metric string) string {

func TestConcurrency(t *testing.T) {
t.Parallel()
//nolint:gocritic // Unit testing
ctx := dbauthz.AsFileReader(t.Context())

const fileSize = 10
Expand DownExpand Up@@ -268,7 +263,6 @@ func TestConcurrency(t *testing.T) {

func TestRelease(t *testing.T) {
t.Parallel()
//nolint:gocritic // Unit testing
ctx := dbauthz.AsFileReader(t.Context())

const fileSize = 10
Expand Down
2 changes: 0 additions & 2 deletionscoderd/idpsync/group_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -328,7 +328,6 @@ func TestGroupSyncTable(t *testing.T) {
},
}

//nolint:gocritic // testing
defOrg, err := db.GetDefaultOrganization(dbauthz.AsSystemRestricted(ctx))
require.NoError(t, err)
SetupOrganization(t, s, db, user, defOrg.ID, def)
Expand DownExpand Up@@ -527,7 +526,6 @@ func TestApplyGroupDifference(t *testing.T) {
db, _ := dbtestutil.NewDB(t)

ctx := testutil.Context(t, testutil.WaitMedium)
//nolint:gocritic // testing
ctx = dbauthz.AsSystemRestricted(ctx)

org := dbgen.Organization(t, db, database.Organization{})
Expand Down
1 change: 0 additions & 1 deletioncoderd/idpsync/role_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -273,7 +273,6 @@ func TestRoleSyncTable(t *testing.T) {
}

// Also assert site wide roles
//nolint:gocritic // unit testing assertions
allRoles, err := db.GetAuthorizationUserRoles(dbauthz.AsSystemRestricted(ctx), user.ID)
require.NoError(t, err)

Expand Down
2 changes: 0 additions & 2 deletionscoderd/insights_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -754,7 +754,6 @@ func TestTemplateInsights_Golden(t *testing.T) {
Database: db,
AppStatBatchSize: workspaceapps.DefaultStatsDBReporterBatchSize,
})
//nolint:gocritic // This is a test.
err = reporter.ReportAppStats(dbauthz.AsSystemRestricted(ctx), stats)
require.NoError(t, err, "want no error inserting app stats")

Expand DownExpand Up@@ -1646,7 +1645,6 @@ func TestUserActivityInsights_Golden(t *testing.T) {
Database: db,
AppStatBatchSize: workspaceapps.DefaultStatsDBReporterBatchSize,
})
//nolint:gocritic // This is a test.
err = reporter.ReportAppStats(dbauthz.AsSystemRestricted(ctx), stats)
require.NoError(t, err, "want no error inserting app stats")

Expand Down
4 changes: 0 additions & 4 deletionscoderd/notifications/manager_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,7 +31,6 @@ func TestBufferedUpdates(t *testing.T) {

// setup

// nolint:gocritic // Unit test.
ctx := dbauthz.AsSystemRestricted(testutil.Context(t, testutil.WaitSuperLong))
store, ps := dbtestutil.NewDB(t)
logger := testutil.Logger(t)
Expand DownExpand Up@@ -108,7 +107,6 @@ func TestBuildPayload(t *testing.T) {

// SETUP

// nolint:gocritic // Unit test.
ctx := dbauthz.AsSystemRestricted(testutil.Context(t, testutil.WaitSuperLong))
store, _ := dbtestutil.NewDB(t)
logger := testutil.Logger(t)
Expand DownExpand Up@@ -166,7 +164,6 @@ func TestStopBeforeRun(t *testing.T) {

// SETUP

// nolint:gocritic // Unit test.
ctx := dbauthz.AsSystemRestricted(testutil.Context(t, testutil.WaitSuperLong))
store, ps := dbtestutil.NewDB(t)
logger := testutil.Logger(t)
Expand All@@ -187,7 +184,6 @@ func TestRunStopRace(t *testing.T) {

// SETUP

// nolint:gocritic // Unit test.
ctx := dbauthz.AsSystemRestricted(testutil.Context(t, testutil.WaitMedium))
store, ps := dbtestutil.NewDB(t)
logger := testutil.Logger(t)
Expand Down
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp