Skip to content

Commit ab11df3

Browse files
committed
[usage] more workspace instance fetch methods
1 parent f6d86c6 commit ab11df3

File tree

5 files changed

+259
-71
lines changed

5 files changed

+259
-71
lines changed

components/usage/pkg/apiv1/report-generator.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ package apiv1
77
import (
88
"context"
99
"fmt"
10-
"github.com/gitpod-io/gitpod/usage/pkg/contentservice"
1110
"time"
1211

12+
"github.com/gitpod-io/gitpod/usage/pkg/contentservice"
13+
1314
"github.com/gitpod-io/gitpod/common-go/log"
1415
"github.com/gitpod-io/gitpod/usage/pkg/db"
1516
"google.golang.org/grpc/codes"
@@ -76,15 +77,15 @@ func validateInstances(instances []db.WorkspaceInstanceForUsage) (valid []db.Wor
7677
instance := i
7778

7879
// Each instance must have a start time, without it, we do not have a baseline for usage computation.
79-
if !instance.CreationTime.IsSet() {
80+
if !instance.StartedTime.IsSet() {
8081
invalid = append(invalid, contentservice.InvalidSession{
81-
Reason: "missing creation time",
82+
Reason: "missing started time",
8283
Session: instance,
8384
})
8485
continue
8586
}
8687

87-
start := instance.CreationTime.Time()
88+
start := instance.StartedTime.Time()
8889

8990
// Currently running instances do not have a stopped time set, so we ignore these.
9091
if instance.StoppingTime.IsSet() {

components/usage/pkg/apiv1/usage_test.go

+2-9
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ package apiv1
77
import (
88
"context"
99
"database/sql"
10-
"github.com/gitpod-io/gitpod/usage/pkg/contentservice"
1110
"reflect"
1211
"testing"
1312
"time"
1413

14+
"github.com/gitpod-io/gitpod/usage/pkg/contentservice"
15+
1516
"github.com/gitpod-io/gitpod/common-go/baseserver"
1617
v1 "github.com/gitpod-io/gitpod/usage-api/v1"
1718
"github.com/gitpod-io/gitpod/usage/pkg/db"
@@ -104,7 +105,6 @@ func TestUsageService_ListBilledUsage(t *testing.T) {
104105
start := time.Date(2022, 07, 1, 13, 0, 0, 0, time.UTC)
105106
attrID := db.NewTeamAttributionID(uuid.New().String())
106107
var instances []db.WorkspaceInstanceUsage
107-
var instanceIDs []string
108108
for i := 0; i < 3; i++ {
109109
instance := dbtest.NewWorkspaceInstanceUsage(t, db.WorkspaceInstanceUsage{
110110
AttributionID: attrID,
@@ -115,8 +115,6 @@ func TestUsageService_ListBilledUsage(t *testing.T) {
115115
},
116116
})
117117
instances = append(instances, instance)
118-
119-
instanceIDs = append(instanceIDs, instance.InstanceID.String())
120118
}
121119

122120
return Scenario{
@@ -395,25 +393,20 @@ func TestReportGenerator_GenerateUsageReport(t *testing.T) {
395393
dbtest.NewWorkspaceInstance(t, db.WorkspaceInstance{
396394
ID: uuid.New(),
397395
UsageAttributionID: db.NewTeamAttributionID(teamID.String()),
398-
CreationTime: db.NewVarcharTime(time.Date(2022, 05, 1, 00, 00, 00, 00, time.UTC)),
399396
StartedTime: db.NewVarcharTime(time.Date(2022, 05, 1, 00, 01, 00, 00, time.UTC)),
400397
StoppingTime: db.NewVarcharTime(time.Date(2022, 06, 1, 1, 0, 0, 0, time.UTC)),
401-
StoppedTime: db.NewVarcharTime(time.Date(2022, 06, 1, 1, 1, 0, 0, time.UTC)),
402398
}),
403399
// Still running
404400
dbtest.NewWorkspaceInstance(t, db.WorkspaceInstance{
405401
ID: uuid.New(),
406402
UsageAttributionID: db.NewTeamAttributionID(teamID.String()),
407-
CreationTime: db.NewVarcharTime(time.Date(2022, 05, 30, 00, 00, 00, 00, time.UTC)),
408403
StartedTime: db.NewVarcharTime(time.Date(2022, 05, 30, 00, 01, 00, 00, time.UTC)),
409404
}),
410405
// No creation time, invalid record
411406
dbtest.NewWorkspaceInstance(t, db.WorkspaceInstance{
412407
ID: uuid.New(),
413408
UsageAttributionID: db.NewTeamAttributionID(teamID.String()),
414-
StartedTime: db.NewVarcharTime(time.Date(2022, 06, 1, 1, 1, 0, 0, time.UTC)),
415409
StoppingTime: db.NewVarcharTime(time.Date(2022, 06, 1, 1, 0, 0, 0, time.UTC)),
416-
StoppedTime: db.NewVarcharTime(time.Date(2022, 06, 1, 1, 1, 0, 0, time.UTC)),
417410
}),
418411
}
419412

components/usage/pkg/db/dbtest/workspace_instance.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ package dbtest
66

77
import (
88
"database/sql"
9+
"testing"
10+
"time"
11+
912
"github.com/gitpod-io/gitpod/usage/pkg/db"
1013
"github.com/google/uuid"
1114
"github.com/stretchr/testify/require"
1215
"gorm.io/gorm"
13-
"testing"
14-
"time"
1516
)
1617

1718
var (
@@ -34,6 +35,8 @@ func NewWorkspaceInstance(t *testing.T, instance db.WorkspaceInstance) db.Worksp
3435
creationTime := db.VarcharTime{}
3536
if instance.CreationTime.IsSet() {
3637
creationTime = instance.CreationTime
38+
} else if instance.StartedTime.IsSet() {
39+
creationTime = instance.StartedTime
3740
}
3841

3942
startedTime := db.VarcharTime{}
@@ -49,6 +52,8 @@ func NewWorkspaceInstance(t *testing.T, instance db.WorkspaceInstance) db.Worksp
4952
stoppedTime := db.VarcharTime{}
5053
if instance.StoppedTime.IsSet() {
5154
stoppedTime = instance.StoppedTime
55+
} else if instance.StoppingTime.IsSet() {
56+
creationTime = instance.StoppingTime
5257
}
5358

5459
stoppingTime := db.VarcharTime{}

components/usage/pkg/db/workspace_instance.go

+79-17
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,65 @@ func (i *WorkspaceInstance) TableName() string {
5151
return "d_b_workspace_instance"
5252
}
5353

54+
// FindStoppedWorkspaceInstancesInRange finds WorkspaceInstanceForUsage that have been stopped between from (inclusive) and to (exclusive).
55+
func FindStoppedWorkspaceInstancesInRange(ctx context.Context, conn *gorm.DB, from, to time.Time) ([]WorkspaceInstanceForUsage, error) {
56+
var instances []WorkspaceInstanceForUsage
57+
var instancesInBatch []WorkspaceInstanceForUsage
58+
59+
tx := queryWorkspaceInstanceForUsage(ctx, conn).
60+
Where("wsi.stoppingTime >= ?", TimeToISO8601(from)).
61+
Where("wsi.stoppingTime < ?", TimeToISO8601(to)).
62+
Where("wsi.stoppingTime != ?", "").
63+
Where("wsi.usageAttributionId != ?", "").
64+
FindInBatches(&instancesInBatch, 1000, func(_ *gorm.DB, _ int) error {
65+
instances = append(instances, instancesInBatch...)
66+
return nil
67+
})
68+
if tx.Error != nil {
69+
return nil, fmt.Errorf("failed to list workspace instances: %w", tx.Error)
70+
}
71+
72+
return instances, nil
73+
}
74+
75+
// FindRunningWorkspaceInstances finds WorkspaceInstanceForUsage that are running at the point in time the querty is executed.
76+
func FindRunningWorkspaceInstances(ctx context.Context, conn *gorm.DB) ([]WorkspaceInstanceForUsage, error) {
77+
var instances []WorkspaceInstanceForUsage
78+
var instancesInBatch []WorkspaceInstanceForUsage
79+
80+
tx := queryWorkspaceInstanceForUsage(ctx, conn).
81+
Where("wsi.stoppingTime = ?", "").
82+
Where("wsi.usageAttributionId != ?", "").
83+
FindInBatches(&instancesInBatch, 1000, func(_ *gorm.DB, _ int) error {
84+
instances = append(instances, instancesInBatch...)
85+
return nil
86+
})
87+
if tx.Error != nil {
88+
return nil, fmt.Errorf("failed to list workspace instances: %w", tx.Error)
89+
}
90+
91+
return instances, nil
92+
}
93+
94+
// FindWorkspaceInstancesByIds finds WorkspaceInstanceForUsage by Id.
95+
func FindWorkspaceInstancesByIds(ctx context.Context, conn *gorm.DB, workspaceInstanceIds []uuid.UUID) ([]WorkspaceInstanceForUsage, error) {
96+
var instances []WorkspaceInstanceForUsage
97+
var instancesInBatch []WorkspaceInstanceForUsage
98+
99+
tx := queryWorkspaceInstanceForUsage(ctx, conn).
100+
Where("wsi.id in ?", workspaceInstanceIds).
101+
Where("wsi.usageAttributionId != ?", "").
102+
FindInBatches(&instancesInBatch, 1000, func(_ *gorm.DB, _ int) error {
103+
instances = append(instances, instancesInBatch...)
104+
return nil
105+
})
106+
if tx.Error != nil {
107+
return nil, fmt.Errorf("failed to list workspace instances: %w", tx.Error)
108+
}
109+
110+
return instances, nil
111+
}
112+
54113
// ListWorkspaceInstancesInRange lists WorkspaceInstances between from (inclusive) and to (exclusive).
55114
// This results in all instances which have existed in the specified period, regardless of their current status, this includes:
56115
// - terminated
@@ -61,26 +120,11 @@ func ListWorkspaceInstancesInRange(ctx context.Context, conn *gorm.DB, from, to
61120
var instances []WorkspaceInstanceForUsage
62121
var instancesInBatch []WorkspaceInstanceForUsage
63122

64-
tx := conn.WithContext(ctx).
65-
Table(fmt.Sprintf("%s as wsi", (&WorkspaceInstance{}).TableName())).
66-
Select("wsi.id as id, "+
67-
"ws.projectId as projectId, "+
68-
"ws.type as workspaceType, "+
69-
"wsi.workspaceClass as workspaceClass, "+
70-
"wsi.usageAttributionId as usageAttributionId, "+
71-
"wsi.creationTime as creationTime, "+
72-
"wsi.startedTime as startedTime, "+
73-
"wsi.stoppingTime as stoppingTime, "+
74-
"wsi.stoppedTime as stoppedTime, "+
75-
"ws.ownerId as ownerId, "+
76-
"ws.id as workspaceId",
77-
).
78-
Joins(fmt.Sprintf("LEFT JOIN %s AS ws ON wsi.workspaceId = ws.id", (&Workspace{}).TableName())).
123+
tx := queryWorkspaceInstanceForUsage(ctx, conn).
79124
Where(
80125
conn.Where("wsi.stoppingTime >= ?", TimeToISO8601(from)).Or("wsi.stoppingTime = ?", ""),
81126
).
82-
Where("wsi.creationTime < ?", TimeToISO8601(to)).
83-
Where("wsi.startedTime != ?", "").
127+
Where("wsi.startedTime < ?", TimeToISO8601(to)).
84128
Where("wsi.usageAttributionId != ?", "").
85129
FindInBatches(&instancesInBatch, 1000, func(_ *gorm.DB, _ int) error {
86130
instances = append(instances, instancesInBatch...)
@@ -93,6 +137,24 @@ func ListWorkspaceInstancesInRange(ctx context.Context, conn *gorm.DB, from, to
93137
return instances, nil
94138
}
95139

140+
func queryWorkspaceInstanceForUsage(ctx context.Context, conn *gorm.DB) *gorm.DB {
141+
return conn.WithContext(ctx).
142+
Table(fmt.Sprintf("%s as wsi", (&WorkspaceInstance{}).TableName())).
143+
Select("wsi.id as id, " +
144+
"ws.projectId as projectId, " +
145+
"ws.type as workspaceType, " +
146+
"wsi.workspaceClass as workspaceClass, " +
147+
"wsi.usageAttributionId as usageAttributionId, " +
148+
"wsi.creationTime as creationTime, " +
149+
"wsi.startedTime as startedTime, " +
150+
"wsi.stoppingTime as stoppingTime, " +
151+
"wsi.stoppedTime as stoppedTime, " +
152+
"ws.ownerId as ownerId, " +
153+
"ws.id as workspaceId",
154+
).
155+
Joins(fmt.Sprintf("LEFT JOIN %s AS ws ON wsi.workspaceId = ws.id", (&Workspace{}).TableName()))
156+
}
157+
96158
const (
97159
AttributionEntity_User = "user"
98160
AttributionEntity_Team = "team"

0 commit comments

Comments
 (0)