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: populate connectionlog count using a separate query#18629

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

Draft
ethanndickson wants to merge1 commit intoethan/connection-logs-api
base:ethan/connection-logs-api
Choose a base branch
Loading
fromethan/populate-connection-log-count
Draft
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
19 changes: 19 additions & 0 deletionscoderd/database/dbauthz/dbauthz.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1323,6 +1323,21 @@ func (q *querier) CleanTailnetTunnels(ctx context.Context) error {
returnq.db.CleanTailnetTunnels(ctx)
}

func (q*querier)CountConnectionLogs(ctx context.Context,arg database.CountConnectionLogsParams) (int64,error) {
// Just like the actual query, shortcut if the user is an owner.
err:=q.authorizeContext(ctx,policy.ActionRead,rbac.ResourceConnectionLog)
iferr==nil {
returnq.db.CountConnectionLogs(ctx,arg)
}

prep,err:=prepareSQLFilter(ctx,q.auth,policy.ActionRead,rbac.ResourceConnectionLog.Type)
iferr!=nil {
return0,xerrors.Errorf("(dev error) prepare sql filter: %w",err)
}

returnq.db.CountAuthorizedConnectionLogs(ctx,arg,prep)
}

func (q*querier)CountInProgressPrebuilds(ctx context.Context) ([]database.CountInProgressPrebuildsRow,error) {
iferr:=q.authorizeContext(ctx,policy.ActionRead,rbac.ResourceWorkspace.All());err!=nil {
returnnil,err
Expand DownExpand Up@@ -5301,3 +5316,7 @@ func (q *querier) GetAuthorizedAuditLogsOffset(ctx context.Context, arg database
func (q*querier)GetAuthorizedConnectionLogsOffset(ctx context.Context,arg database.GetConnectionLogsOffsetParams,_ rbac.PreparedAuthorized) ([]database.GetConnectionLogsOffsetRow,error) {
returnq.GetConnectionLogsOffset(ctx,arg)
}

func (q*querier)CountAuthorizedConnectionLogs(ctx context.Context,arg database.CountConnectionLogsParams,_ rbac.PreparedAuthorized) (int64,error) {
returnq.CountConnectionLogs(ctx,arg)
}
36 changes: 36 additions & 0 deletionscoderd/database/dbauthz/dbauthz_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -391,6 +391,42 @@ func (s *MethodTestSuite) TestConnectionLogs() {
LimitOpt:10,
},emptyPreparedAuthorized{}).Asserts(rbac.ResourceConnectionLog,policy.ActionRead)
}))
s.Run("CountConnectionLogs",s.Subtest(func(db database.Store,check*expects) {
ws:=createWorkspace(s.T(),db)
_=dbgen.ConnectionLog(s.T(),db, database.UpsertConnectionLogParams{
Type:database.ConnectionTypeSsh,
WorkspaceID:ws.ID,
OrganizationID:ws.OrganizationID,
WorkspaceOwnerID:ws.OwnerID,
})
_=dbgen.ConnectionLog(s.T(),db, database.UpsertConnectionLogParams{
Type:database.ConnectionTypeSsh,
WorkspaceID:ws.ID,
OrganizationID:ws.OrganizationID,
WorkspaceOwnerID:ws.OwnerID,
})
check.Args(database.CountConnectionLogsParams{}).Asserts(
rbac.ResourceConnectionLog,policy.ActionRead,
).WithNotAuthorized("nil")
}))
s.Run("CountAuthorizedConnectionLogs",s.Subtest(func(db database.Store,check*expects) {
ws:=createWorkspace(s.T(),db)
_=dbgen.ConnectionLog(s.T(),db, database.UpsertConnectionLogParams{
Type:database.ConnectionTypeSsh,
WorkspaceID:ws.ID,
OrganizationID:ws.OrganizationID,
WorkspaceOwnerID:ws.OwnerID,
})
_=dbgen.ConnectionLog(s.T(),db, database.UpsertConnectionLogParams{
Type:database.ConnectionTypeSsh,
WorkspaceID:ws.ID,
OrganizationID:ws.OrganizationID,
WorkspaceOwnerID:ws.OwnerID,
})
check.Args(database.CountConnectionLogsParams{},emptyPreparedAuthorized{}).Asserts(
rbac.ResourceConnectionLog,policy.ActionRead,
)
}))
}

func (s*MethodTestSuite)TestFile() {
Expand Down
13 changes: 10 additions & 3 deletionscoderd/database/dbauthz/setup_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -271,7 +271,7 @@ func (s *MethodTestSuite) NotAuthorizedErrorTest(ctx context.Context, az *coderd

// This is unfortunate, but if we are using `Filter` the error returned will be nil. So filter out
// any case where the error is nil and the response is an empty slice.
iferr!=nil||!hasEmptySliceResponse(resp) {
iferr!=nil||!hasEmptyResponse(resp) {
// Expect the default error
iftestCase.notAuthorizedExpect=="" {
s.ErrorContainsf(err,"unauthorized","error string should have a good message")
Expand All@@ -297,7 +297,7 @@ func (s *MethodTestSuite) NotAuthorizedErrorTest(ctx context.Context, az *coderd

// This is unfortunate, but if we are using `Filter` the error returned will be nil. So filter out
// any case where the error is nil and the response is an empty slice.
iferr!=nil||!hasEmptySliceResponse(resp) {
iferr!=nil||!hasEmptyResponse(resp) {
iftestCase.cancelledCtxExpect=="" {
s.Errorf(err,"method should an error with cancellation")
s.ErrorIsf(err,context.Canceled,"error should match context.Canceled")
Expand All@@ -308,13 +308,20 @@ func (s *MethodTestSuite) NotAuthorizedErrorTest(ctx context.Context, az *coderd
})
}

funchasEmptySliceResponse(values []reflect.Value)bool {
funchasEmptyResponse(values []reflect.Value)bool {
for_,r:=rangevalues {
ifr.Kind()==reflect.Slice||r.Kind()==reflect.Array {
ifr.Len()==0 {
returntrue
}
}

// Special case for int64, as it's the return type for count queries.
ifr.Kind()==reflect.Int64 {
ifr.Int()==0 {
returntrue
}
}
}
returnfalse
}
Expand Down
94 changes: 94 additions & 0 deletionscoderd/database/dbmem/dbmem.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1780,6 +1780,10 @@ func (*FakeQuerier) CleanTailnetTunnels(context.Context) error {
returnErrUnimplemented
}

func (q*FakeQuerier)CountConnectionLogs(ctx context.Context,arg database.CountConnectionLogsParams) (int64,error) {
returnq.CountAuthorizedConnectionLogs(ctx,arg,nil)
}

func (q*FakeQuerier)CountInProgressPrebuilds(ctx context.Context) ([]database.CountInProgressPrebuildsRow,error) {
returnnil,ErrUnimplemented
}
Expand DownExpand Up@@ -14156,3 +14160,93 @@ func (q *FakeQuerier) GetAuthorizedConnectionLogsOffset(ctx context.Context, arg

returnlogs,nil
}

func (q*FakeQuerier)CountAuthorizedConnectionLogs(ctx context.Context,arg database.CountConnectionLogsParams,prepared rbac.PreparedAuthorized) (int64,error) {
iferr:=validateDatabaseType(arg);err!=nil {
return0,err
}

// Call this to match the same function calls as the SQL implementation.
// It functionally does nothing for filtering.
ifprepared!=nil {
_,err:=prepared.CompileToSQL(ctx, regosql.ConvertConfig{
VariableConverter:regosql.ConnectionLogConverter(),
})
iferr!=nil {
return0,err
}
}

q.mutex.RLock()
deferq.mutex.RUnlock()

varcountint64

for_,clog:=rangeq.connectionLogs {
ifarg.OrganizationID!=uuid.Nil&&clog.OrganizationID!=arg.OrganizationID {
continue
}
ifarg.WorkspaceOwner!="" {
workspaceOwner,err:=q.getUserByIDNoLock(clog.WorkspaceOwnerID)
iferr==nil&&!strings.EqualFold(arg.WorkspaceOwner,workspaceOwner.Username) {
continue
}
}
ifarg.Type!=""&&string(clog.Type)!=arg.Type {
continue
}
ifarg.UserID!=uuid.Nil&& (!clog.UserID.Valid||clog.UserID.UUID!=arg.UserID) {
continue
}
ifarg.Username!="" {
if!clog.UserID.Valid {
continue
}
user,err:=q.getUserByIDNoLock(clog.UserID.UUID)
iferr!=nil||user.Username!=arg.Username {
continue
}
}
ifarg.Email!="" {
if!clog.UserID.Valid {
continue
}
user,err:=q.getUserByIDNoLock(clog.UserID.UUID)
iferr!=nil||user.Email!=arg.Email {
continue
}
}
if!arg.StartedAfter.IsZero()&&clog.Time.Before(arg.StartedAfter) {
continue
}
if!arg.StartedBefore.IsZero()&&clog.Time.After(arg.StartedBefore) {
continue
}
if!arg.ClosedAfter.IsZero()&& (!clog.CloseTime.Valid||clog.CloseTime.Time.Before(arg.ClosedAfter)) {
continue
}
if!arg.ClosedBefore.IsZero()&& (!clog.CloseTime.Valid||clog.CloseTime.Time.After(arg.ClosedBefore)) {
continue
}
ifarg.WorkspaceID!=uuid.Nil&&clog.WorkspaceID!=arg.WorkspaceID {
continue
}
ifarg.ConnectionID!=uuid.Nil&& (!clog.ConnectionID.Valid||clog.ConnectionID.UUID!=arg.ConnectionID) {
continue
}
ifarg.Status!="" {
isConnected:=!clog.CloseTime.Valid
if (arg.Status=="connected"&&!isConnected)|| (arg.Status=="disconnected"&&isConnected) {
continue
}
}

ifprepared!=nil&&prepared.Authorize(ctx,clog.RBACObject())!=nil {
continue
}

count++
}

returncount,nil
}
14 changes: 14 additions & 0 deletionscoderd/database/dbmetrics/querymetrics.go
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

30 changes: 30 additions & 0 deletionscoderd/database/dbmock/dbmock.go
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

48 changes: 48 additions & 0 deletionscoderd/database/modelqueries.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -566,6 +566,7 @@ func (q *sqlQuerier) GetAuthorizedAuditLogsOffset(ctx context.Context, arg GetAu

typeconnectionLogQuerierinterface {
GetAuthorizedConnectionLogsOffset(ctx context.Context,argGetConnectionLogsOffsetParams,prepared rbac.PreparedAuthorized) ([]GetConnectionLogsOffsetRow,error)
CountAuthorizedConnectionLogs(ctx context.Context,argCountConnectionLogsParams,prepared rbac.PreparedAuthorized) (int64,error)
}

func (q*sqlQuerier)GetAuthorizedConnectionLogsOffset(ctx context.Context,argGetConnectionLogsOffsetParams,prepared rbac.PreparedAuthorized) ([]GetConnectionLogsOffsetRow,error) {
Expand DownExpand Up@@ -653,6 +654,53 @@ func (q *sqlQuerier) GetAuthorizedConnectionLogsOffset(ctx context.Context, arg
returnitems,nil
}

func (q*sqlQuerier)CountAuthorizedConnectionLogs(ctx context.Context,argCountConnectionLogsParams,prepared rbac.PreparedAuthorized) (int64,error) {
authorizedFilter,err:=prepared.CompileToSQL(ctx, regosql.ConvertConfig{
VariableConverter:regosql.ConnectionLogConverter(),
})
iferr!=nil {
return0,xerrors.Errorf("compile authorized filter: %w",err)
}
filtered,err:=insertAuthorizedFilter(countConnectionLogs,fmt.Sprintf(" AND %s",authorizedFilter))
iferr!=nil {
return0,xerrors.Errorf("insert authorized filter: %w",err)
}

query:=fmt.Sprintf("-- name: CountAuthorizedConnectionLogs :one\n%s",filtered)
rows,err:=q.db.QueryContext(ctx,query,
arg.OrganizationID,
arg.WorkspaceOwner,
arg.Type,
arg.UserID,
arg.Username,
arg.Email,
arg.StartedAfter,
arg.StartedBefore,
arg.ClosedAfter,
arg.ClosedBefore,
arg.WorkspaceID,
arg.ConnectionID,
arg.Status,
)
iferr!=nil {
return0,err
}
deferrows.Close()
varcountint64
forrows.Next() {
iferr:=rows.Scan(&count);err!=nil {
return0,err
}
}
iferr:=rows.Close();err!=nil {
return0,err
}
iferr:=rows.Err();err!=nil {
return0,err
}
returncount,nil
}

funcinsertAuthorizedFilter(querystring,replaceWithstring) (string,error) {
if!strings.Contains(query,authorizedQueryPlaceholder) {
return"",xerrors.Errorf("query does not contain authorized replace string, this is not an authorized query")
Expand Down
34 changes: 34 additions & 0 deletionscoderd/database/modelqueries_internal_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
package database

import (
"regexp"
"strings"
"testing"
"time"

Expand DownExpand Up@@ -54,3 +56,35 @@ func TestWorkspaceTableConvert(t *testing.T) {
"'workspace.WorkspaceTable()' is not missing at least 1 field when converting to 'WorkspaceTable'. "+
"To resolve this, go to the 'func (w Workspace) WorkspaceTable()' and ensure all fields are converted.")
}

funcTestConnectionLogsQueryConsistency(t*testing.T) {
t.Parallel()

getWhereClause:=extractWhereClause(getConnectionLogsOffset)
require.NotEmpty(t,getWhereClause,"getConnectionLogsOffset query should have a WHERE clause")

countWhereClause:=extractWhereClause(countConnectionLogs)
require.NotEmpty(t,countWhereClause,"countConnectionLogs query should have a WHERE clause")

require.Equal(t,getWhereClause,countWhereClause,"getConnectionLogsOffset and countConnectionLogs queries should have the same WHERE clause")
}

// extractWhereClause extracts the WHERE clause from a SQL query string
funcextractWhereClause(querystring)string {
// Find WHERE and get everything after it
wherePattern:=regexp.MustCompile(`(?is)WHERE\s+(.*)`)
whereMatches:=wherePattern.FindStringSubmatch(query)
iflen(whereMatches)<2 {
return""
}

whereClause:=whereMatches[1]

// Remove ORDER BY, LIMIT, OFFSET clauses from the end
whereClause=regexp.MustCompile(`(?is)\s+(ORDER BY|LIMIT|OFFSET).*$`).ReplaceAllString(whereClause,"")

// Remove SQL comments
whereClause=regexp.MustCompile(`(?m)--.*$`).ReplaceAllString(whereClause,"")

returnstrings.TrimSpace(whereClause)
}
1 change: 1 addition & 0 deletionscoderd/database/querier.go
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp