Skip to content

Commit aeba354

Browse files
committed
[usage] Implement CollectUsage
1 parent a52e8a7 commit aeba354

File tree

3 files changed

+62
-9
lines changed

3 files changed

+62
-9
lines changed

components/usage/pkg/apiv1/usage.go

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package apiv1
77
import (
88
context "context"
99
"github.com/gitpod-io/gitpod/common-go/log"
10+
"github.com/gitpod-io/gitpod/usage/pkg/controller"
1011
"time"
1112

1213
v1 "github.com/gitpod-io/gitpod/usage-api/v1"
@@ -21,12 +22,15 @@ var _ v1.UsageServiceServer = (*UsageService)(nil)
2122

2223
type UsageService struct {
2324
conn *gorm.DB
25+
26+
usageCtrl *controller.UsageReconciler
27+
2428
v1.UnimplementedUsageServiceServer
2529
}
2630

2731
const maxQuerySize = 31 * 24 * time.Hour
2832

29-
func (us *UsageService) ListBilledUsage(ctx context.Context, in *v1.ListBilledUsageRequest) (*v1.ListBilledUsageResponse, error) {
33+
func (s *UsageService) ListBilledUsage(ctx context.Context, in *v1.ListBilledUsageRequest) (*v1.ListBilledUsageResponse, error) {
3034
to := time.Now()
3135
if in.To != nil {
3236
to = in.To.AsTime()
@@ -52,7 +56,7 @@ func (us *UsageService) ListBilledUsage(ctx context.Context, in *v1.ListBilledUs
5256
order = db.DescendingOrder
5357
}
5458

55-
usageRecords, err := db.ListUsage(ctx, us.conn, db.AttributionID(in.GetAttributionId()), from, to, order)
59+
usageRecords, err := db.ListUsage(ctx, s.conn, db.AttributionID(in.GetAttributionId()), from, to, order)
5660
if err != nil {
5761
log.Log.
5862
WithField("attribution_id", in.AttributionId).
@@ -88,6 +92,54 @@ func (us *UsageService) ListBilledUsage(ctx context.Context, in *v1.ListBilledUs
8892
}, nil
8993
}
9094

91-
func NewUsageService(conn *gorm.DB) *UsageService {
92-
return &UsageService{conn: conn}
95+
func (s *UsageService) CollectUsage(ctx context.Context, req *v1.CollectUsageRequest) (*v1.CollectUsageResponse, error) {
96+
from := req.GetStartTime().AsTime()
97+
to := req.GetEndTime().AsTime()
98+
99+
if from.Before(to) {
100+
return nil, status.Errorf(codes.InvalidArgument, "End time must be after start time")
101+
}
102+
103+
_, report, err := s.usageCtrl.ReconcileTimeRange(ctx, from, to)
104+
if err != nil {
105+
log.Log.WithError(err).Error("Failed to reconcile time range.")
106+
return nil, status.Error(codes.Internal, "failed to reconcile time range")
107+
}
108+
109+
var sessions []*v1.BilledSession
110+
for _, instance := range report {
111+
sessions = append(sessions, usageRecordToBilledUsageProto(instance))
112+
}
113+
114+
return &v1.CollectUsageResponse{
115+
Sessions: sessions,
116+
}, nil
117+
118+
}
119+
120+
func NewUsageService(conn *gorm.DB, usageCtrl *controller.UsageReconciler) *UsageService {
121+
return &UsageService{
122+
conn: conn,
123+
usageCtrl: usageCtrl,
124+
}
125+
}
126+
127+
func usageRecordToBilledUsageProto(usageRecord db.WorkspaceInstanceUsage) *v1.BilledSession {
128+
var endTime *timestamppb.Timestamp
129+
if usageRecord.StoppedAt.Valid {
130+
endTime = timestamppb.New(usageRecord.StoppedAt.Time)
131+
}
132+
return &v1.BilledSession{
133+
AttributionId: string(usageRecord.AttributionID),
134+
UserId: usageRecord.UserID.String(),
135+
WorkspaceId: usageRecord.WorkspaceID,
136+
TeamId: "",
137+
WorkspaceType: string(usageRecord.WorkspaceType),
138+
ProjectId: usageRecord.ProjectID,
139+
InstanceId: usageRecord.InstanceID.String(),
140+
WorkspaceClass: usageRecord.WorkspaceClass,
141+
StartTime: timestamppb.New(usageRecord.StartedAt),
142+
EndTime: endTime,
143+
Credits: usageRecord.CreditsUsed,
144+
}
93145
}

components/usage/pkg/apiv1/usage_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ func TestUsageService_ListBilledUsage(t *testing.T) {
142142
baseserver.WithGRPC(baseserver.MustUseRandomLocalAddress(t)),
143143
)
144144

145-
v1.RegisterUsageServiceServer(srv.GRPC(), NewUsageService(dbconn))
145+
v1.RegisterUsageServiceServer(srv.GRPC(), NewUsageService(dbconn, nil))
146146
baseserver.StartServerForTests(t, srv)
147147

148148
conn, err := grpc.Dial(srv.GRPCAddress(), grpc.WithTransportCredentials(insecure.NewCredentials()))

components/usage/pkg/server/server.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ func Start(cfg Config) error {
9393
contentService = contentservice.New(cfg.ContentServiceAddress)
9494
}
9595

96-
ctrl, err := controller.New(schedule, controller.NewUsageReconciler(conn, pricer, v1.NewBillingServiceClient(selfConnection), contentService))
96+
usageCtrl := controller.NewUsageReconciler(conn, pricer, v1.NewBillingServiceClient(selfConnection), contentService)
97+
ctrl, err := controller.New(schedule, usageCtrl)
9798
if err != nil {
9899
return fmt.Errorf("failed to initialize usage controller: %w", err)
99100
}
@@ -104,7 +105,7 @@ func Start(cfg Config) error {
104105
}
105106
defer ctrl.Stop()
106107

107-
err = registerGRPCServices(srv, conn, stripeClient)
108+
err = registerGRPCServices(srv, conn, stripeClient, usageCtrl)
108109
if err != nil {
109110
return fmt.Errorf("failed to register gRPC services: %w", err)
110111
}
@@ -122,8 +123,8 @@ func Start(cfg Config) error {
122123
return nil
123124
}
124125

125-
func registerGRPCServices(srv *baseserver.Server, conn *gorm.DB, stripeClient *stripe.Client) error {
126-
v1.RegisterUsageServiceServer(srv.GRPC(), apiv1.NewUsageService(conn))
126+
func registerGRPCServices(srv *baseserver.Server, conn *gorm.DB, stripeClient *stripe.Client, usageCtrl *controller.UsageReconciler) error {
127+
v1.RegisterUsageServiceServer(srv.GRPC(), apiv1.NewUsageService(conn, usageCtrl))
127128
if stripeClient == nil {
128129
v1.RegisterBillingServiceServer(srv.GRPC(), &apiv1.BillingServiceNoop{})
129130
} else {

0 commit comments

Comments
 (0)