From a86efd21242fa99c342f98a33b6c989b26fb69f4 Mon Sep 17 00:00:00 2001 From: Andrew Farries Date: Mon, 18 Jul 2022 11:50:35 +0000 Subject: [PATCH] [usage] Implement GetBilledUsage rpc --- components/dashboard/src/teams/TeamUsage.tsx | 2 +- .../gitpod-protocol/src/gitpod-service.ts | 2 +- .../ee/src/workspace/gitpod-server-impl.ts | 6 +- components/server/src/auth/rate-limiter.ts | 2 +- .../src/workspace/gitpod-server-impl.ts | 2 +- components/usage-api/go/v1/usage.pb.go | 146 +++++++++--------- components/usage-api/go/v1/usage_grpc.pb.go | 32 ++-- .../typescript/src/usage/v1/sugar.ts | 14 +- .../src/usage/v1/usage_grpc_pb.d.ts | 28 ++-- .../typescript/src/usage/v1/usage_grpc_pb.js | 38 ++--- .../typescript/src/usage/v1/usage_pb.d.ts | 32 ++-- .../typescript/src/usage/v1/usage_pb.js | 98 ++++++------ components/usage-api/usage/v1/usage.proto | 8 +- components/usage/pkg/apiv1/usage.go | 45 +++++- components/usage/pkg/apiv1/usage_test.go | 58 ++++--- .../pkg/db/dbtest/workspace_instance_usage.go | 29 ++++ .../usage/pkg/db/workspace_instance_usage.go | 12 ++ .../pkg/db/workspace_instance_usage_test.go | 2 +- components/usage/pkg/server/server.go | 7 +- 19 files changed, 325 insertions(+), 238 deletions(-) create mode 100644 components/usage/pkg/db/dbtest/workspace_instance_usage.go diff --git a/components/dashboard/src/teams/TeamUsage.tsx b/components/dashboard/src/teams/TeamUsage.tsx index eda9aee4b0b14f..91d4c8ac866067 100644 --- a/components/dashboard/src/teams/TeamUsage.tsx +++ b/components/dashboard/src/teams/TeamUsage.tsx @@ -31,7 +31,7 @@ function TeamUsage() { } (async () => { const attributionId = AttributionId.render({ kind: "team", teamId: team.id }); - const billedUsageResult = await getGitpodService().server.getBilledUsage(attributionId); + const billedUsageResult = await getGitpodService().server.listBilledUsage(attributionId); setBilledUsage(billedUsageResult); })(); }, [team]); diff --git a/components/gitpod-protocol/src/gitpod-service.ts b/components/gitpod-protocol/src/gitpod-service.ts index d8adeedc4d4d11..cf2131d0af0551 100644 --- a/components/gitpod-protocol/src/gitpod-service.ts +++ b/components/gitpod-protocol/src/gitpod-service.ts @@ -291,7 +291,7 @@ export interface GitpodServer extends JsonRpcServer, AdminServer, subscribeTeamToStripe(teamId: string, setupIntentId: string, currency: Currency): Promise; getStripePortalUrlForTeam(teamId: string): Promise; - getBilledUsage(attributionId: string): Promise; + listBilledUsage(attributionId: string): Promise; /** * Analytics diff --git a/components/server/ee/src/workspace/gitpod-server-impl.ts b/components/server/ee/src/workspace/gitpod-server-impl.ts index 1b79c57fa9145a..8259354484f7a1 100644 --- a/components/server/ee/src/workspace/gitpod-server-impl.ts +++ b/components/server/ee/src/workspace/gitpod-server-impl.ts @@ -2066,14 +2066,14 @@ export class GitpodServerEEImpl extends GitpodServerImpl { } } - async getBilledUsage(ctx: TraceContext, attributionId: string): Promise { + async listBilledUsage(ctx: TraceContext, attributionId: string): Promise { traceAPIParams(ctx, { attributionId }); - const user = this.checkAndBlockUser("getBilledUsage"); + const user = this.checkAndBlockUser("listBilledUsage"); await this.guardCostCenterAccess(ctx, user.id, attributionId, "get"); const usageClient = this.usageServiceClientProvider.getDefault(); - const response = await usageClient.getBilledUsage(ctx, attributionId); + const response = await usageClient.listBilledUsage(ctx, attributionId); const sessions = response.getSessionsList().map((s) => this.mapBilledSession(s)); return sessions.concat(billableSessionDummyData); // to at least return some data for testing diff --git a/components/server/src/auth/rate-limiter.ts b/components/server/src/auth/rate-limiter.ts index 8a4b5da10427a5..fe5a5624c8eb7c 100644 --- a/components/server/src/auth/rate-limiter.ts +++ b/components/server/src/auth/rate-limiter.ts @@ -210,7 +210,7 @@ function getConfig(config: RateLimiterConfig): RateLimiterConfig { findStripeSubscriptionIdForTeam: { group: "default", points: 1 }, subscribeTeamToStripe: { group: "default", points: 1 }, getStripePortalUrlForTeam: { group: "default", points: 1 }, - getBilledUsage: { group: "default", points: 1 }, + listBilledUsage: { group: "default", points: 1 }, trackEvent: { group: "default", points: 1 }, trackLocation: { group: "default", points: 1 }, identifyUser: { group: "default", points: 1 }, diff --git a/components/server/src/workspace/gitpod-server-impl.ts b/components/server/src/workspace/gitpod-server-impl.ts index 1e5d4cba3f6880..1ae6c4a455f8b2 100644 --- a/components/server/src/workspace/gitpod-server-impl.ts +++ b/components/server/src/workspace/gitpod-server-impl.ts @@ -3191,7 +3191,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable { throw new ResponseError(ErrorCodes.SAAS_FEATURE, `Not implemented in this version`); } - async getBilledUsage(ctx: TraceContext, attributionId: string): Promise { + async listBilledUsage(ctx: TraceContext, attributionId: string): Promise { throw new ResponseError(ErrorCodes.SAAS_FEATURE, `Not implemented in this version`); } diff --git a/components/usage-api/go/v1/usage.pb.go b/components/usage-api/go/v1/usage.pb.go index b3ddb6a942d9e2..7bec82d76ed963 100644 --- a/components/usage-api/go/v1/usage.pb.go +++ b/components/usage-api/go/v1/usage.pb.go @@ -25,7 +25,7 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -type GetBilledUsageRequest struct { +type ListBilledUsageRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -33,8 +33,8 @@ type GetBilledUsageRequest struct { AttributionId string `protobuf:"bytes,1,opt,name=attribution_id,json=attributionId,proto3" json:"attribution_id,omitempty"` } -func (x *GetBilledUsageRequest) Reset() { - *x = GetBilledUsageRequest{} +func (x *ListBilledUsageRequest) Reset() { + *x = ListBilledUsageRequest{} if protoimpl.UnsafeEnabled { mi := &file_usage_v1_usage_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -42,13 +42,13 @@ func (x *GetBilledUsageRequest) Reset() { } } -func (x *GetBilledUsageRequest) String() string { +func (x *ListBilledUsageRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetBilledUsageRequest) ProtoMessage() {} +func (*ListBilledUsageRequest) ProtoMessage() {} -func (x *GetBilledUsageRequest) ProtoReflect() protoreflect.Message { +func (x *ListBilledUsageRequest) ProtoReflect() protoreflect.Message { mi := &file_usage_v1_usage_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -60,19 +60,19 @@ func (x *GetBilledUsageRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetBilledUsageRequest.ProtoReflect.Descriptor instead. -func (*GetBilledUsageRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use ListBilledUsageRequest.ProtoReflect.Descriptor instead. +func (*ListBilledUsageRequest) Descriptor() ([]byte, []int) { return file_usage_v1_usage_proto_rawDescGZIP(), []int{0} } -func (x *GetBilledUsageRequest) GetAttributionId() string { +func (x *ListBilledUsageRequest) GetAttributionId() string { if x != nil { return x.AttributionId } return "" } -type GetBilledUsageResponse struct { +type ListBilledUsageResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -80,8 +80,8 @@ type GetBilledUsageResponse struct { Sessions []*BilledSession `protobuf:"bytes,1,rep,name=sessions,proto3" json:"sessions,omitempty"` } -func (x *GetBilledUsageResponse) Reset() { - *x = GetBilledUsageResponse{} +func (x *ListBilledUsageResponse) Reset() { + *x = ListBilledUsageResponse{} if protoimpl.UnsafeEnabled { mi := &file_usage_v1_usage_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -89,13 +89,13 @@ func (x *GetBilledUsageResponse) Reset() { } } -func (x *GetBilledUsageResponse) String() string { +func (x *ListBilledUsageResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetBilledUsageResponse) ProtoMessage() {} +func (*ListBilledUsageResponse) ProtoMessage() {} -func (x *GetBilledUsageResponse) ProtoReflect() protoreflect.Message { +func (x *ListBilledUsageResponse) ProtoReflect() protoreflect.Message { mi := &file_usage_v1_usage_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -107,12 +107,12 @@ func (x *GetBilledUsageResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetBilledUsageResponse.ProtoReflect.Descriptor instead. -func (*GetBilledUsageResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use ListBilledUsageResponse.ProtoReflect.Descriptor instead. +func (*ListBilledUsageResponse) Descriptor() ([]byte, []int) { return file_usage_v1_usage_proto_rawDescGZIP(), []int{1} } -func (x *GetBilledUsageResponse) GetSessions() []*BilledSession { +func (x *ListBilledUsageResponse) GetSessions() []*BilledSession { if x != nil { return x.Sessions } @@ -253,52 +253,52 @@ var file_usage_v1_usage_proto_rawDesc = []byte{ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0x3e, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x42, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x55, 0x73, - 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x22, 0x4d, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x42, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x55, 0x73, - 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x08, 0x73, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, - 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x22, 0xa7, 0x03, 0x0a, 0x0d, 0x42, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, - 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, - 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x77, - 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, - 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, - 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x39, - 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x65, 0x6e, 0x64, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, - 0x12, 0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x07, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x73, 0x32, 0x65, 0x0a, 0x0c, 0x55, 0x73, - 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x55, 0x0a, 0x0e, 0x47, 0x65, - 0x74, 0x42, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x2e, 0x75, - 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x69, 0x6c, 0x6c, 0x65, - 0x64, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, - 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x69, 0x6c, 0x6c, - 0x65, 0x64, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2d, 0x69, 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, - 0x2f, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2d, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x22, 0x3f, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x55, + 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x61, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x22, 0x4e, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x69, 0x6c, 0x6c, 0x65, 0x64, + 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, + 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x6c, 0x6c, 0x65, + 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x22, 0xa7, 0x03, 0x0a, 0x0d, 0x42, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, + 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, + 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x21, 0x0a, + 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, + 0x12, 0x25, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, + 0x12, 0x39, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x65, + 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x73, 0x18, 0x0b, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x07, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x73, 0x32, 0x68, 0x0a, 0x0c, + 0x55, 0x73, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x0f, + 0x4c, 0x69, 0x73, 0x74, 0x42, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x20, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, + 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x21, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x42, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2d, 0x69, 0x6f, 0x2f, 0x67, + 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2f, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2d, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -315,17 +315,17 @@ func file_usage_v1_usage_proto_rawDescGZIP() []byte { var file_usage_v1_usage_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_usage_v1_usage_proto_goTypes = []interface{}{ - (*GetBilledUsageRequest)(nil), // 0: usage.v1.GetBilledUsageRequest - (*GetBilledUsageResponse)(nil), // 1: usage.v1.GetBilledUsageResponse - (*BilledSession)(nil), // 2: usage.v1.BilledSession - (*timestamppb.Timestamp)(nil), // 3: google.protobuf.Timestamp + (*ListBilledUsageRequest)(nil), // 0: usage.v1.ListBilledUsageRequest + (*ListBilledUsageResponse)(nil), // 1: usage.v1.ListBilledUsageResponse + (*BilledSession)(nil), // 2: usage.v1.BilledSession + (*timestamppb.Timestamp)(nil), // 3: google.protobuf.Timestamp } var file_usage_v1_usage_proto_depIdxs = []int32{ - 2, // 0: usage.v1.GetBilledUsageResponse.sessions:type_name -> usage.v1.BilledSession + 2, // 0: usage.v1.ListBilledUsageResponse.sessions:type_name -> usage.v1.BilledSession 3, // 1: usage.v1.BilledSession.start_time:type_name -> google.protobuf.Timestamp 3, // 2: usage.v1.BilledSession.end_time:type_name -> google.protobuf.Timestamp - 0, // 3: usage.v1.UsageService.GetBilledUsage:input_type -> usage.v1.GetBilledUsageRequest - 1, // 4: usage.v1.UsageService.GetBilledUsage:output_type -> usage.v1.GetBilledUsageResponse + 0, // 3: usage.v1.UsageService.ListBilledUsage:input_type -> usage.v1.ListBilledUsageRequest + 1, // 4: usage.v1.UsageService.ListBilledUsage:output_type -> usage.v1.ListBilledUsageResponse 4, // [4:5] is the sub-list for method output_type 3, // [3:4] is the sub-list for method input_type 3, // [3:3] is the sub-list for extension type_name @@ -340,7 +340,7 @@ func file_usage_v1_usage_proto_init() { } if !protoimpl.UnsafeEnabled { file_usage_v1_usage_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBilledUsageRequest); i { + switch v := v.(*ListBilledUsageRequest); i { case 0: return &v.state case 1: @@ -352,7 +352,7 @@ func file_usage_v1_usage_proto_init() { } } file_usage_v1_usage_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetBilledUsageResponse); i { + switch v := v.(*ListBilledUsageResponse); i { case 0: return &v.state case 1: diff --git a/components/usage-api/go/v1/usage_grpc.pb.go b/components/usage-api/go/v1/usage_grpc.pb.go index 5e08265142aba5..9c53069ac7d8ba 100644 --- a/components/usage-api/go/v1/usage_grpc.pb.go +++ b/components/usage-api/go/v1/usage_grpc.pb.go @@ -26,8 +26,8 @@ const _ = grpc.SupportPackageIsVersion7 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type UsageServiceClient interface { - // GetBilleadUsage retrieves all usage for a team. - GetBilledUsage(ctx context.Context, in *GetBilledUsageRequest, opts ...grpc.CallOption) (*GetBilledUsageResponse, error) + // ListBilledUsage retrieves all usage for the specified attributionId + ListBilledUsage(ctx context.Context, in *ListBilledUsageRequest, opts ...grpc.CallOption) (*ListBilledUsageResponse, error) } type usageServiceClient struct { @@ -38,9 +38,9 @@ func NewUsageServiceClient(cc grpc.ClientConnInterface) UsageServiceClient { return &usageServiceClient{cc} } -func (c *usageServiceClient) GetBilledUsage(ctx context.Context, in *GetBilledUsageRequest, opts ...grpc.CallOption) (*GetBilledUsageResponse, error) { - out := new(GetBilledUsageResponse) - err := c.cc.Invoke(ctx, "/usage.v1.UsageService/GetBilledUsage", in, out, opts...) +func (c *usageServiceClient) ListBilledUsage(ctx context.Context, in *ListBilledUsageRequest, opts ...grpc.CallOption) (*ListBilledUsageResponse, error) { + out := new(ListBilledUsageResponse) + err := c.cc.Invoke(ctx, "/usage.v1.UsageService/ListBilledUsage", in, out, opts...) if err != nil { return nil, err } @@ -51,8 +51,8 @@ func (c *usageServiceClient) GetBilledUsage(ctx context.Context, in *GetBilledUs // All implementations must embed UnimplementedUsageServiceServer // for forward compatibility type UsageServiceServer interface { - // GetBilleadUsage retrieves all usage for a team. - GetBilledUsage(context.Context, *GetBilledUsageRequest) (*GetBilledUsageResponse, error) + // ListBilledUsage retrieves all usage for the specified attributionId + ListBilledUsage(context.Context, *ListBilledUsageRequest) (*ListBilledUsageResponse, error) mustEmbedUnimplementedUsageServiceServer() } @@ -60,8 +60,8 @@ type UsageServiceServer interface { type UnimplementedUsageServiceServer struct { } -func (UnimplementedUsageServiceServer) GetBilledUsage(context.Context, *GetBilledUsageRequest) (*GetBilledUsageResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetBilledUsage not implemented") +func (UnimplementedUsageServiceServer) ListBilledUsage(context.Context, *ListBilledUsageRequest) (*ListBilledUsageResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListBilledUsage not implemented") } func (UnimplementedUsageServiceServer) mustEmbedUnimplementedUsageServiceServer() {} @@ -76,20 +76,20 @@ func RegisterUsageServiceServer(s grpc.ServiceRegistrar, srv UsageServiceServer) s.RegisterService(&UsageService_ServiceDesc, srv) } -func _UsageService_GetBilledUsage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetBilledUsageRequest) +func _UsageService_ListBilledUsage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListBilledUsageRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(UsageServiceServer).GetBilledUsage(ctx, in) + return srv.(UsageServiceServer).ListBilledUsage(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/usage.v1.UsageService/GetBilledUsage", + FullMethod: "/usage.v1.UsageService/ListBilledUsage", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UsageServiceServer).GetBilledUsage(ctx, req.(*GetBilledUsageRequest)) + return srv.(UsageServiceServer).ListBilledUsage(ctx, req.(*ListBilledUsageRequest)) } return interceptor(ctx, in, info, handler) } @@ -102,8 +102,8 @@ var UsageService_ServiceDesc = grpc.ServiceDesc{ HandlerType: (*UsageServiceServer)(nil), Methods: []grpc.MethodDesc{ { - MethodName: "GetBilledUsage", - Handler: _UsageService_GetBilledUsage_Handler, + MethodName: "ListBilledUsage", + Handler: _UsageService_ListBilledUsage_Handler, }, }, Streams: []grpc.StreamDesc{}, diff --git a/components/usage-api/typescript/src/usage/v1/sugar.ts b/components/usage-api/typescript/src/usage/v1/sugar.ts index 26dfc2ec2db09f..42c3b4c5fec701 100644 --- a/components/usage-api/typescript/src/usage/v1/sugar.ts +++ b/components/usage-api/typescript/src/usage/v1/sugar.ts @@ -8,7 +8,7 @@ import { UsageServiceClient } from "./usage_grpc_pb"; import { TraceContext } from "@gitpod/gitpod-protocol/lib/util/tracing"; import * as opentracing from "opentracing"; import { Metadata } from "@grpc/grpc-js"; -import { GetBilledUsageRequest, GetBilledUsageResponse } from "./usage_pb"; +import { ListBilledUsageRequest, ListBilledUsageResponse } from "./usage_pb"; import { injectable, inject } from "inversify"; import * as grpc from "@grpc/grpc-js"; @@ -89,18 +89,18 @@ export class PromisifiedUsageServiceClient { ); } - public async getBilledUsage(_ctx: TraceContext, attributionId: string): Promise { - const ctx = TraceContext.childContext(`/usage-service/getBilledUsage`, _ctx); + public async listBilledUsage(_ctx: TraceContext, attributionId: string): Promise { + const ctx = TraceContext.childContext(`/usage-service/listBilledUsage`, _ctx); try { - const req = new GetBilledUsageRequest(); + const req = new ListBilledUsageRequest(); req.setAttributionId(attributionId); - const response = await new Promise((resolve, reject) => { - this.client.getBilledUsage( + const response = await new Promise((resolve, reject) => { + this.client.listBilledUsage( req, withTracing(ctx), - (err: grpc.ServiceError | null, response: GetBilledUsageResponse) => { + (err: grpc.ServiceError | null, response: ListBilledUsageResponse) => { if (err) { reject(err); return; diff --git a/components/usage-api/typescript/src/usage/v1/usage_grpc_pb.d.ts b/components/usage-api/typescript/src/usage/v1/usage_grpc_pb.d.ts index c8d8f63163a4ed..613d8320273d33 100644 --- a/components/usage-api/typescript/src/usage/v1/usage_grpc_pb.d.ts +++ b/components/usage-api/typescript/src/usage/v1/usage_grpc_pb.d.ts @@ -15,34 +15,34 @@ import * as usage_v1_usage_pb from "../../usage/v1/usage_pb"; import * as google_protobuf_timestamp_pb from "google-protobuf/google/protobuf/timestamp_pb"; interface IUsageServiceService extends grpc.ServiceDefinition { - getBilledUsage: IUsageServiceService_IGetBilledUsage; + listBilledUsage: IUsageServiceService_IListBilledUsage; } -interface IUsageServiceService_IGetBilledUsage extends grpc.MethodDefinition { - path: "/usage.v1.UsageService/GetBilledUsage"; +interface IUsageServiceService_IListBilledUsage extends grpc.MethodDefinition { + path: "/usage.v1.UsageService/ListBilledUsage"; requestStream: false; responseStream: false; - requestSerialize: grpc.serialize; - requestDeserialize: grpc.deserialize; - responseSerialize: grpc.serialize; - responseDeserialize: grpc.deserialize; + requestSerialize: grpc.serialize; + requestDeserialize: grpc.deserialize; + responseSerialize: grpc.serialize; + responseDeserialize: grpc.deserialize; } export const UsageServiceService: IUsageServiceService; export interface IUsageServiceServer extends grpc.UntypedServiceImplementation { - getBilledUsage: grpc.handleUnaryCall; + listBilledUsage: grpc.handleUnaryCall; } export interface IUsageServiceClient { - getBilledUsage(request: usage_v1_usage_pb.GetBilledUsageRequest, callback: (error: grpc.ServiceError | null, response: usage_v1_usage_pb.GetBilledUsageResponse) => void): grpc.ClientUnaryCall; - getBilledUsage(request: usage_v1_usage_pb.GetBilledUsageRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: usage_v1_usage_pb.GetBilledUsageResponse) => void): grpc.ClientUnaryCall; - getBilledUsage(request: usage_v1_usage_pb.GetBilledUsageRequest, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: usage_v1_usage_pb.GetBilledUsageResponse) => void): grpc.ClientUnaryCall; + listBilledUsage(request: usage_v1_usage_pb.ListBilledUsageRequest, callback: (error: grpc.ServiceError | null, response: usage_v1_usage_pb.ListBilledUsageResponse) => void): grpc.ClientUnaryCall; + listBilledUsage(request: usage_v1_usage_pb.ListBilledUsageRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: usage_v1_usage_pb.ListBilledUsageResponse) => void): grpc.ClientUnaryCall; + listBilledUsage(request: usage_v1_usage_pb.ListBilledUsageRequest, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: usage_v1_usage_pb.ListBilledUsageResponse) => void): grpc.ClientUnaryCall; } export class UsageServiceClient extends grpc.Client implements IUsageServiceClient { constructor(address: string, credentials: grpc.ChannelCredentials, options?: Partial); - public getBilledUsage(request: usage_v1_usage_pb.GetBilledUsageRequest, callback: (error: grpc.ServiceError | null, response: usage_v1_usage_pb.GetBilledUsageResponse) => void): grpc.ClientUnaryCall; - public getBilledUsage(request: usage_v1_usage_pb.GetBilledUsageRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: usage_v1_usage_pb.GetBilledUsageResponse) => void): grpc.ClientUnaryCall; - public getBilledUsage(request: usage_v1_usage_pb.GetBilledUsageRequest, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: usage_v1_usage_pb.GetBilledUsageResponse) => void): grpc.ClientUnaryCall; + public listBilledUsage(request: usage_v1_usage_pb.ListBilledUsageRequest, callback: (error: grpc.ServiceError | null, response: usage_v1_usage_pb.ListBilledUsageResponse) => void): grpc.ClientUnaryCall; + public listBilledUsage(request: usage_v1_usage_pb.ListBilledUsageRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: usage_v1_usage_pb.ListBilledUsageResponse) => void): grpc.ClientUnaryCall; + public listBilledUsage(request: usage_v1_usage_pb.ListBilledUsageRequest, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: usage_v1_usage_pb.ListBilledUsageResponse) => void): grpc.ClientUnaryCall; } diff --git a/components/usage-api/typescript/src/usage/v1/usage_grpc_pb.js b/components/usage-api/typescript/src/usage/v1/usage_grpc_pb.js index 609d9a935f2305..f72af7f5c45034 100644 --- a/components/usage-api/typescript/src/usage/v1/usage_grpc_pb.js +++ b/components/usage-api/typescript/src/usage/v1/usage_grpc_pb.js @@ -11,41 +11,41 @@ var grpc = require('@grpc/grpc-js'); var usage_v1_usage_pb = require('../../usage/v1/usage_pb.js'); var google_protobuf_timestamp_pb = require('google-protobuf/google/protobuf/timestamp_pb.js'); -function serialize_usage_v1_GetBilledUsageRequest(arg) { - if (!(arg instanceof usage_v1_usage_pb.GetBilledUsageRequest)) { - throw new Error('Expected argument of type usage.v1.GetBilledUsageRequest'); +function serialize_usage_v1_ListBilledUsageRequest(arg) { + if (!(arg instanceof usage_v1_usage_pb.ListBilledUsageRequest)) { + throw new Error('Expected argument of type usage.v1.ListBilledUsageRequest'); } return Buffer.from(arg.serializeBinary()); } -function deserialize_usage_v1_GetBilledUsageRequest(buffer_arg) { - return usage_v1_usage_pb.GetBilledUsageRequest.deserializeBinary(new Uint8Array(buffer_arg)); +function deserialize_usage_v1_ListBilledUsageRequest(buffer_arg) { + return usage_v1_usage_pb.ListBilledUsageRequest.deserializeBinary(new Uint8Array(buffer_arg)); } -function serialize_usage_v1_GetBilledUsageResponse(arg) { - if (!(arg instanceof usage_v1_usage_pb.GetBilledUsageResponse)) { - throw new Error('Expected argument of type usage.v1.GetBilledUsageResponse'); +function serialize_usage_v1_ListBilledUsageResponse(arg) { + if (!(arg instanceof usage_v1_usage_pb.ListBilledUsageResponse)) { + throw new Error('Expected argument of type usage.v1.ListBilledUsageResponse'); } return Buffer.from(arg.serializeBinary()); } -function deserialize_usage_v1_GetBilledUsageResponse(buffer_arg) { - return usage_v1_usage_pb.GetBilledUsageResponse.deserializeBinary(new Uint8Array(buffer_arg)); +function deserialize_usage_v1_ListBilledUsageResponse(buffer_arg) { + return usage_v1_usage_pb.ListBilledUsageResponse.deserializeBinary(new Uint8Array(buffer_arg)); } var UsageServiceService = exports.UsageServiceService = { - // GetBilleadUsage retrieves all usage for a team. -getBilledUsage: { - path: '/usage.v1.UsageService/GetBilledUsage', + // ListBilledUsage retrieves all usage for the specified attributionId +listBilledUsage: { + path: '/usage.v1.UsageService/ListBilledUsage', requestStream: false, responseStream: false, - requestType: usage_v1_usage_pb.GetBilledUsageRequest, - responseType: usage_v1_usage_pb.GetBilledUsageResponse, - requestSerialize: serialize_usage_v1_GetBilledUsageRequest, - requestDeserialize: deserialize_usage_v1_GetBilledUsageRequest, - responseSerialize: serialize_usage_v1_GetBilledUsageResponse, - responseDeserialize: deserialize_usage_v1_GetBilledUsageResponse, + requestType: usage_v1_usage_pb.ListBilledUsageRequest, + responseType: usage_v1_usage_pb.ListBilledUsageResponse, + requestSerialize: serialize_usage_v1_ListBilledUsageRequest, + requestDeserialize: deserialize_usage_v1_ListBilledUsageRequest, + responseSerialize: serialize_usage_v1_ListBilledUsageResponse, + responseDeserialize: deserialize_usage_v1_ListBilledUsageResponse, }, }; diff --git a/components/usage-api/typescript/src/usage/v1/usage_pb.d.ts b/components/usage-api/typescript/src/usage/v1/usage_pb.d.ts index 96a4a54dbb0cc4..cc54c74e25f5f1 100644 --- a/components/usage-api/typescript/src/usage/v1/usage_pb.d.ts +++ b/components/usage-api/typescript/src/usage/v1/usage_pb.d.ts @@ -13,43 +13,43 @@ import * as jspb from "google-protobuf"; import * as google_protobuf_timestamp_pb from "google-protobuf/google/protobuf/timestamp_pb"; -export class GetBilledUsageRequest extends jspb.Message { +export class ListBilledUsageRequest extends jspb.Message { getAttributionId(): string; - setAttributionId(value: string): GetBilledUsageRequest; + setAttributionId(value: string): ListBilledUsageRequest; serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): GetBilledUsageRequest.AsObject; - static toObject(includeInstance: boolean, msg: GetBilledUsageRequest): GetBilledUsageRequest.AsObject; + toObject(includeInstance?: boolean): ListBilledUsageRequest.AsObject; + static toObject(includeInstance: boolean, msg: ListBilledUsageRequest): ListBilledUsageRequest.AsObject; static extensions: {[key: number]: jspb.ExtensionFieldInfo}; static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; - static serializeBinaryToWriter(message: GetBilledUsageRequest, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): GetBilledUsageRequest; - static deserializeBinaryFromReader(message: GetBilledUsageRequest, reader: jspb.BinaryReader): GetBilledUsageRequest; + static serializeBinaryToWriter(message: ListBilledUsageRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): ListBilledUsageRequest; + static deserializeBinaryFromReader(message: ListBilledUsageRequest, reader: jspb.BinaryReader): ListBilledUsageRequest; } -export namespace GetBilledUsageRequest { +export namespace ListBilledUsageRequest { export type AsObject = { attributionId: string, } } -export class GetBilledUsageResponse extends jspb.Message { +export class ListBilledUsageResponse extends jspb.Message { clearSessionsList(): void; getSessionsList(): Array; - setSessionsList(value: Array): GetBilledUsageResponse; + setSessionsList(value: Array): ListBilledUsageResponse; addSessions(value?: BilledSession, index?: number): BilledSession; serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): GetBilledUsageResponse.AsObject; - static toObject(includeInstance: boolean, msg: GetBilledUsageResponse): GetBilledUsageResponse.AsObject; + toObject(includeInstance?: boolean): ListBilledUsageResponse.AsObject; + static toObject(includeInstance: boolean, msg: ListBilledUsageResponse): ListBilledUsageResponse.AsObject; static extensions: {[key: number]: jspb.ExtensionFieldInfo}; static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; - static serializeBinaryToWriter(message: GetBilledUsageResponse, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): GetBilledUsageResponse; - static deserializeBinaryFromReader(message: GetBilledUsageResponse, reader: jspb.BinaryReader): GetBilledUsageResponse; + static serializeBinaryToWriter(message: ListBilledUsageResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): ListBilledUsageResponse; + static deserializeBinaryFromReader(message: ListBilledUsageResponse, reader: jspb.BinaryReader): ListBilledUsageResponse; } -export namespace GetBilledUsageResponse { +export namespace ListBilledUsageResponse { export type AsObject = { sessionsList: Array, } diff --git a/components/usage-api/typescript/src/usage/v1/usage_pb.js b/components/usage-api/typescript/src/usage/v1/usage_pb.js index 1ccf6c96a7d0fd..ac4a71086e389c 100644 --- a/components/usage-api/typescript/src/usage/v1/usage_pb.js +++ b/components/usage-api/typescript/src/usage/v1/usage_pb.js @@ -24,8 +24,8 @@ var global = (function() { return this || window || global || self || Function(' var google_protobuf_timestamp_pb = require('google-protobuf/google/protobuf/timestamp_pb.js'); goog.object.extend(proto, google_protobuf_timestamp_pb); goog.exportSymbol('proto.usage.v1.BilledSession', null, global); -goog.exportSymbol('proto.usage.v1.GetBilledUsageRequest', null, global); -goog.exportSymbol('proto.usage.v1.GetBilledUsageResponse', null, global); +goog.exportSymbol('proto.usage.v1.ListBilledUsageRequest', null, global); +goog.exportSymbol('proto.usage.v1.ListBilledUsageResponse', null, global); /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a @@ -36,16 +36,16 @@ goog.exportSymbol('proto.usage.v1.GetBilledUsageResponse', null, global); * @extends {jspb.Message} * @constructor */ -proto.usage.v1.GetBilledUsageRequest = function(opt_data) { +proto.usage.v1.ListBilledUsageRequest = function(opt_data) { jspb.Message.initialize(this, opt_data, 0, -1, null, null); }; -goog.inherits(proto.usage.v1.GetBilledUsageRequest, jspb.Message); +goog.inherits(proto.usage.v1.ListBilledUsageRequest, jspb.Message); if (goog.DEBUG && !COMPILED) { /** * @public * @override */ - proto.usage.v1.GetBilledUsageRequest.displayName = 'proto.usage.v1.GetBilledUsageRequest'; + proto.usage.v1.ListBilledUsageRequest.displayName = 'proto.usage.v1.ListBilledUsageRequest'; } /** * Generated by JsPbCodeGenerator. @@ -57,16 +57,16 @@ if (goog.DEBUG && !COMPILED) { * @extends {jspb.Message} * @constructor */ -proto.usage.v1.GetBilledUsageResponse = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, proto.usage.v1.GetBilledUsageResponse.repeatedFields_, null); +proto.usage.v1.ListBilledUsageResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.usage.v1.ListBilledUsageResponse.repeatedFields_, null); }; -goog.inherits(proto.usage.v1.GetBilledUsageResponse, jspb.Message); +goog.inherits(proto.usage.v1.ListBilledUsageResponse, jspb.Message); if (goog.DEBUG && !COMPILED) { /** * @public * @override */ - proto.usage.v1.GetBilledUsageResponse.displayName = 'proto.usage.v1.GetBilledUsageResponse'; + proto.usage.v1.ListBilledUsageResponse.displayName = 'proto.usage.v1.ListBilledUsageResponse'; } /** * Generated by JsPbCodeGenerator. @@ -105,8 +105,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) { * http://goto/soy-param-migration * @return {!Object} */ -proto.usage.v1.GetBilledUsageRequest.prototype.toObject = function(opt_includeInstance) { - return proto.usage.v1.GetBilledUsageRequest.toObject(opt_includeInstance, this); +proto.usage.v1.ListBilledUsageRequest.prototype.toObject = function(opt_includeInstance) { + return proto.usage.v1.ListBilledUsageRequest.toObject(opt_includeInstance, this); }; @@ -115,11 +115,11 @@ proto.usage.v1.GetBilledUsageRequest.prototype.toObject = function(opt_includeIn * @param {boolean|undefined} includeInstance Deprecated. Whether to include * the JSPB instance for transitional soy proto support: * http://goto/soy-param-migration - * @param {!proto.usage.v1.GetBilledUsageRequest} msg The msg instance to transform. + * @param {!proto.usage.v1.ListBilledUsageRequest} msg The msg instance to transform. * @return {!Object} * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.usage.v1.GetBilledUsageRequest.toObject = function(includeInstance, msg) { +proto.usage.v1.ListBilledUsageRequest.toObject = function(includeInstance, msg) { var f, obj = { attributionId: jspb.Message.getFieldWithDefault(msg, 1, "") }; @@ -135,23 +135,23 @@ proto.usage.v1.GetBilledUsageRequest.toObject = function(includeInstance, msg) { /** * Deserializes binary data (in protobuf wire format). * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.usage.v1.GetBilledUsageRequest} + * @return {!proto.usage.v1.ListBilledUsageRequest} */ -proto.usage.v1.GetBilledUsageRequest.deserializeBinary = function(bytes) { +proto.usage.v1.ListBilledUsageRequest.deserializeBinary = function(bytes) { var reader = new jspb.BinaryReader(bytes); - var msg = new proto.usage.v1.GetBilledUsageRequest; - return proto.usage.v1.GetBilledUsageRequest.deserializeBinaryFromReader(msg, reader); + var msg = new proto.usage.v1.ListBilledUsageRequest; + return proto.usage.v1.ListBilledUsageRequest.deserializeBinaryFromReader(msg, reader); }; /** * Deserializes binary data (in protobuf wire format) from the * given reader into the given message object. - * @param {!proto.usage.v1.GetBilledUsageRequest} msg The message object to deserialize into. + * @param {!proto.usage.v1.ListBilledUsageRequest} msg The message object to deserialize into. * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.usage.v1.GetBilledUsageRequest} + * @return {!proto.usage.v1.ListBilledUsageRequest} */ -proto.usage.v1.GetBilledUsageRequest.deserializeBinaryFromReader = function(msg, reader) { +proto.usage.v1.ListBilledUsageRequest.deserializeBinaryFromReader = function(msg, reader) { while (reader.nextField()) { if (reader.isEndGroup()) { break; @@ -175,9 +175,9 @@ proto.usage.v1.GetBilledUsageRequest.deserializeBinaryFromReader = function(msg, * Serializes the message to binary data (in protobuf wire format). * @return {!Uint8Array} */ -proto.usage.v1.GetBilledUsageRequest.prototype.serializeBinary = function() { +proto.usage.v1.ListBilledUsageRequest.prototype.serializeBinary = function() { var writer = new jspb.BinaryWriter(); - proto.usage.v1.GetBilledUsageRequest.serializeBinaryToWriter(this, writer); + proto.usage.v1.ListBilledUsageRequest.serializeBinaryToWriter(this, writer); return writer.getResultBuffer(); }; @@ -185,11 +185,11 @@ proto.usage.v1.GetBilledUsageRequest.prototype.serializeBinary = function() { /** * Serializes the given message to binary data (in protobuf wire * format), writing to the given BinaryWriter. - * @param {!proto.usage.v1.GetBilledUsageRequest} message + * @param {!proto.usage.v1.ListBilledUsageRequest} message * @param {!jspb.BinaryWriter} writer * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.usage.v1.GetBilledUsageRequest.serializeBinaryToWriter = function(message, writer) { +proto.usage.v1.ListBilledUsageRequest.serializeBinaryToWriter = function(message, writer) { var f = undefined; f = message.getAttributionId(); if (f.length > 0) { @@ -205,16 +205,16 @@ proto.usage.v1.GetBilledUsageRequest.serializeBinaryToWriter = function(message, * optional string attribution_id = 1; * @return {string} */ -proto.usage.v1.GetBilledUsageRequest.prototype.getAttributionId = function() { +proto.usage.v1.ListBilledUsageRequest.prototype.getAttributionId = function() { return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); }; /** * @param {string} value - * @return {!proto.usage.v1.GetBilledUsageRequest} returns this + * @return {!proto.usage.v1.ListBilledUsageRequest} returns this */ -proto.usage.v1.GetBilledUsageRequest.prototype.setAttributionId = function(value) { +proto.usage.v1.ListBilledUsageRequest.prototype.setAttributionId = function(value) { return jspb.Message.setProto3StringField(this, 1, value); }; @@ -225,7 +225,7 @@ proto.usage.v1.GetBilledUsageRequest.prototype.setAttributionId = function(value * @private {!Array} * @const */ -proto.usage.v1.GetBilledUsageResponse.repeatedFields_ = [1]; +proto.usage.v1.ListBilledUsageResponse.repeatedFields_ = [1]; @@ -242,8 +242,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) { * http://goto/soy-param-migration * @return {!Object} */ -proto.usage.v1.GetBilledUsageResponse.prototype.toObject = function(opt_includeInstance) { - return proto.usage.v1.GetBilledUsageResponse.toObject(opt_includeInstance, this); +proto.usage.v1.ListBilledUsageResponse.prototype.toObject = function(opt_includeInstance) { + return proto.usage.v1.ListBilledUsageResponse.toObject(opt_includeInstance, this); }; @@ -252,11 +252,11 @@ proto.usage.v1.GetBilledUsageResponse.prototype.toObject = function(opt_includeI * @param {boolean|undefined} includeInstance Deprecated. Whether to include * the JSPB instance for transitional soy proto support: * http://goto/soy-param-migration - * @param {!proto.usage.v1.GetBilledUsageResponse} msg The msg instance to transform. + * @param {!proto.usage.v1.ListBilledUsageResponse} msg The msg instance to transform. * @return {!Object} * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.usage.v1.GetBilledUsageResponse.toObject = function(includeInstance, msg) { +proto.usage.v1.ListBilledUsageResponse.toObject = function(includeInstance, msg) { var f, obj = { sessionsList: jspb.Message.toObjectList(msg.getSessionsList(), proto.usage.v1.BilledSession.toObject, includeInstance) @@ -273,23 +273,23 @@ proto.usage.v1.GetBilledUsageResponse.toObject = function(includeInstance, msg) /** * Deserializes binary data (in protobuf wire format). * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.usage.v1.GetBilledUsageResponse} + * @return {!proto.usage.v1.ListBilledUsageResponse} */ -proto.usage.v1.GetBilledUsageResponse.deserializeBinary = function(bytes) { +proto.usage.v1.ListBilledUsageResponse.deserializeBinary = function(bytes) { var reader = new jspb.BinaryReader(bytes); - var msg = new proto.usage.v1.GetBilledUsageResponse; - return proto.usage.v1.GetBilledUsageResponse.deserializeBinaryFromReader(msg, reader); + var msg = new proto.usage.v1.ListBilledUsageResponse; + return proto.usage.v1.ListBilledUsageResponse.deserializeBinaryFromReader(msg, reader); }; /** * Deserializes binary data (in protobuf wire format) from the * given reader into the given message object. - * @param {!proto.usage.v1.GetBilledUsageResponse} msg The message object to deserialize into. + * @param {!proto.usage.v1.ListBilledUsageResponse} msg The message object to deserialize into. * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.usage.v1.GetBilledUsageResponse} + * @return {!proto.usage.v1.ListBilledUsageResponse} */ -proto.usage.v1.GetBilledUsageResponse.deserializeBinaryFromReader = function(msg, reader) { +proto.usage.v1.ListBilledUsageResponse.deserializeBinaryFromReader = function(msg, reader) { while (reader.nextField()) { if (reader.isEndGroup()) { break; @@ -314,9 +314,9 @@ proto.usage.v1.GetBilledUsageResponse.deserializeBinaryFromReader = function(msg * Serializes the message to binary data (in protobuf wire format). * @return {!Uint8Array} */ -proto.usage.v1.GetBilledUsageResponse.prototype.serializeBinary = function() { +proto.usage.v1.ListBilledUsageResponse.prototype.serializeBinary = function() { var writer = new jspb.BinaryWriter(); - proto.usage.v1.GetBilledUsageResponse.serializeBinaryToWriter(this, writer); + proto.usage.v1.ListBilledUsageResponse.serializeBinaryToWriter(this, writer); return writer.getResultBuffer(); }; @@ -324,11 +324,11 @@ proto.usage.v1.GetBilledUsageResponse.prototype.serializeBinary = function() { /** * Serializes the given message to binary data (in protobuf wire * format), writing to the given BinaryWriter. - * @param {!proto.usage.v1.GetBilledUsageResponse} message + * @param {!proto.usage.v1.ListBilledUsageResponse} message * @param {!jspb.BinaryWriter} writer * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.usage.v1.GetBilledUsageResponse.serializeBinaryToWriter = function(message, writer) { +proto.usage.v1.ListBilledUsageResponse.serializeBinaryToWriter = function(message, writer) { var f = undefined; f = message.getSessionsList(); if (f.length > 0) { @@ -345,7 +345,7 @@ proto.usage.v1.GetBilledUsageResponse.serializeBinaryToWriter = function(message * repeated BilledSession sessions = 1; * @return {!Array} */ -proto.usage.v1.GetBilledUsageResponse.prototype.getSessionsList = function() { +proto.usage.v1.ListBilledUsageResponse.prototype.getSessionsList = function() { return /** @type{!Array} */ ( jspb.Message.getRepeatedWrapperField(this, proto.usage.v1.BilledSession, 1)); }; @@ -353,9 +353,9 @@ proto.usage.v1.GetBilledUsageResponse.prototype.getSessionsList = function() { /** * @param {!Array} value - * @return {!proto.usage.v1.GetBilledUsageResponse} returns this + * @return {!proto.usage.v1.ListBilledUsageResponse} returns this */ -proto.usage.v1.GetBilledUsageResponse.prototype.setSessionsList = function(value) { +proto.usage.v1.ListBilledUsageResponse.prototype.setSessionsList = function(value) { return jspb.Message.setRepeatedWrapperField(this, 1, value); }; @@ -365,16 +365,16 @@ proto.usage.v1.GetBilledUsageResponse.prototype.setSessionsList = function(value * @param {number=} opt_index * @return {!proto.usage.v1.BilledSession} */ -proto.usage.v1.GetBilledUsageResponse.prototype.addSessions = function(opt_value, opt_index) { +proto.usage.v1.ListBilledUsageResponse.prototype.addSessions = function(opt_value, opt_index) { return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.usage.v1.BilledSession, opt_index); }; /** * Clears the list making it empty but non-null. - * @return {!proto.usage.v1.GetBilledUsageResponse} returns this + * @return {!proto.usage.v1.ListBilledUsageResponse} returns this */ -proto.usage.v1.GetBilledUsageResponse.prototype.clearSessionsList = function() { +proto.usage.v1.ListBilledUsageResponse.prototype.clearSessionsList = function() { return this.setSessionsList([]); }; diff --git a/components/usage-api/usage/v1/usage.proto b/components/usage-api/usage/v1/usage.proto index 35e49dfa7e429d..8ab7f36a795e29 100644 --- a/components/usage-api/usage/v1/usage.proto +++ b/components/usage-api/usage/v1/usage.proto @@ -7,15 +7,15 @@ option go_package = "github.com/gitpod-io/gitpod/usage-api/v1"; import "google/protobuf/timestamp.proto"; service UsageService { - // GetBilledUsage retrieves all usage for the specified attributionId - rpc GetBilledUsage(GetBilledUsageRequest) returns (GetBilledUsageResponse) {} + // ListBilledUsage retrieves all usage for the specified attributionId + rpc ListBilledUsage(ListBilledUsageRequest) returns (ListBilledUsageResponse) {} } -message GetBilledUsageRequest { +message ListBilledUsageRequest { string attribution_id = 1; } -message GetBilledUsageResponse { +message ListBilledUsageResponse { repeated BilledSession sessions = 1; } diff --git a/components/usage/pkg/apiv1/usage.go b/components/usage/pkg/apiv1/usage.go index 5d311a2b2958d6..fb0fdf61fad634 100644 --- a/components/usage/pkg/apiv1/usage.go +++ b/components/usage/pkg/apiv1/usage.go @@ -8,20 +8,53 @@ import ( context "context" v1 "github.com/gitpod-io/gitpod/usage-api/v1" + "github.com/gitpod-io/gitpod/usage/pkg/db" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/timestamppb" + "gorm.io/gorm" ) var _ v1.UsageServiceServer = (*UsageService)(nil) type UsageService struct { + conn *gorm.DB v1.UnimplementedUsageServiceServer } -func (us *UsageService) GetBilledUsage(ctx context.Context, in *v1.GetBilledUsageRequest) (*v1.GetBilledUsageResponse, error) { - // TODO(geropl) Dummy data for now - response := v1.GetBilledUsageResponse{} - return &response, nil +func (us *UsageService) ListBilledUsage(ctx context.Context, in *v1.ListBilledUsageRequest) (*v1.ListBilledUsageResponse, error) { + usageRecords, err := db.ListUsage(ctx, us.conn, db.AttributionID(in.GetAttributionId())) + if err != nil { + return nil, status.Error(codes.Internal, "unable to retrieve billed usage") + } + + var billedSessions []*v1.BilledSession + for _, usageRecord := range usageRecords { + var endTime *timestamppb.Timestamp + if usageRecord.StoppedAt.Valid { + endTime = timestamppb.New(usageRecord.StoppedAt.Time) + } + billedSession := &v1.BilledSession{ + AttributionId: string(usageRecord.AttributionID), + UserId: "", + TeamId: "", + WorkspaceId: "", + WorkspaceType: "", + ProjectId: "", + InstanceId: usageRecord.InstanceID.String(), + WorkspaceClass: "", + StartTime: timestamppb.New(usageRecord.StartedAt), + EndTime: endTime, + Credits: int64(usageRecord.CreditsUsed), + } + billedSessions = append(billedSessions, billedSession) + } + + return &v1.ListBilledUsageResponse{ + Sessions: billedSessions, + }, nil } -func NewUsageService() *UsageService { - return &UsageService{} +func NewUsageService(conn *gorm.DB) *UsageService { + return &UsageService{conn: conn} } diff --git a/components/usage/pkg/apiv1/usage_test.go b/components/usage/pkg/apiv1/usage_test.go index 01ec682c66197b..22fcbf1d40139c 100644 --- a/components/usage/pkg/apiv1/usage_test.go +++ b/components/usage/pkg/apiv1/usage_test.go @@ -6,29 +6,29 @@ package apiv1 import ( "context" + "database/sql" "testing" "github.com/gitpod-io/gitpod/common-go/baseserver" v1 "github.com/gitpod-io/gitpod/usage-api/v1" - "github.com/google/go-cmp/cmp" + "github.com/gitpod-io/gitpod/usage/pkg/db" + "github.com/gitpod-io/gitpod/usage/pkg/db/dbtest" + "github.com/google/uuid" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/status" - "google.golang.org/protobuf/testing/protocmp" + "google.golang.org/protobuf/types/known/timestamppb" ) -func TestUsageService_GetBilledUsage(t *testing.T) { - const ( - attributionID = "team:123-456-789" - ) - +func TestUsageService_ListBilledUsage(t *testing.T) { srv := baseserver.NewForTests(t, baseserver.WithGRPC(baseserver.MustUseRandomLocalAddress(t)), ) - v1.RegisterUsageServiceServer(srv.GRPC(), NewUsageService()) + dbconn := dbtest.ConnectForTests(t) + v1.RegisterUsageServiceServer(srv.GRPC(), NewUsageService(dbconn)) baseserver.StartServerForTests(t, srv) conn, err := grpc.Dial(srv.GRPCAddress(), grpc.WithTransportCredentials(insecure.NewCredentials())) @@ -37,9 +37,25 @@ func TestUsageService_GetBilledUsage(t *testing.T) { client := v1.NewUsageServiceClient(conn) ctx := context.Background() + const attributionID = "team:123-456-789" + instanceId := uuid.New() + startedAt := timestamppb.Now() + instanceUsages := []db.WorkspaceInstanceUsage{ + { + InstanceID: instanceId, + AttributionID: attributionID, + StartedAt: startedAt.AsTime(), + StoppedAt: sql.NullTime{}, + CreditsUsed: 0, + GenerationId: 0, + Deleted: false, + }, + } + dbtest.CreateWorkspaceInstanceUsageRecords(t, dbconn, instanceUsages...) + type Expectation struct { - Code codes.Code - Response *v1.GetBilledUsageResponse + Code codes.Code + InstanceIds []string } scenarios := []struct { @@ -48,30 +64,26 @@ func TestUsageService_GetBilledUsage(t *testing.T) { Expect Expectation }{ { - name: "returns a dummy response", + name: "returns one usage record", AttributionID: attributionID, Expect: Expectation{ - Code: codes.OK, - Response: &v1.GetBilledUsageResponse{ - Sessions: []*v1.BilledSession{}, - }, + Code: codes.OK, + InstanceIds: []string{instanceId.String()}, }, }, } for _, scenario := range scenarios { t.Run(scenario.name, func(t *testing.T) { - resp, err := client.GetBilledUsage(ctx, &v1.GetBilledUsageRequest{ + resp, err := client.ListBilledUsage(ctx, &v1.ListBilledUsageRequest{ AttributionId: scenario.AttributionID, }) - if diff := cmp.Diff(scenario.Expect, Expectation{ - Code: status.Code(err), - Response: resp, - }, protocmp.Transform()); diff != "" { - t.Errorf("unexpected difference:\n%v", diff) + var instanceIds []string + for _, billedSession := range resp.Sessions { + instanceIds = append(instanceIds, billedSession.InstanceId) } + require.Equal(t, scenario.Expect.Code, status.Code(err)) + require.Equal(t, scenario.Expect.InstanceIds, instanceIds) }) - } - } diff --git a/components/usage/pkg/db/dbtest/workspace_instance_usage.go b/components/usage/pkg/db/dbtest/workspace_instance_usage.go new file mode 100644 index 00000000000000..6c2483d9d92576 --- /dev/null +++ b/components/usage/pkg/db/dbtest/workspace_instance_usage.go @@ -0,0 +1,29 @@ +// Copyright (c) 2022 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License-AGPL.txt in the project root for license information. + +package dbtest + +import ( + "github.com/gitpod-io/gitpod/usage/pkg/db" + "github.com/stretchr/testify/require" + "gorm.io/gorm" + "testing" +) + +func CreateWorkspaceInstanceUsageRecords(t *testing.T, conn *gorm.DB, instancesUsages ...db.WorkspaceInstanceUsage) []db.WorkspaceInstanceUsage { + t.Helper() + + var ids []string + for _, instanceUsage := range instancesUsages { + ids = append(ids, instanceUsage.InstanceID.String()) + } + + require.NoError(t, conn.CreateInBatches(&instancesUsages, 1000).Error) + + t.Cleanup(func() { + require.NoError(t, conn.Where(ids).Delete(&db.WorkspaceInstanceUsage{}).Error) + }) + + return instancesUsages +} diff --git a/components/usage/pkg/db/workspace_instance_usage.go b/components/usage/pkg/db/workspace_instance_usage.go index 36a51a6b2ed647..8fc73fd74e7ed1 100644 --- a/components/usage/pkg/db/workspace_instance_usage.go +++ b/components/usage/pkg/db/workspace_instance_usage.go @@ -7,6 +7,7 @@ package db import ( "context" "database/sql" + "fmt" "time" "github.com/google/uuid" @@ -37,3 +38,14 @@ func CreateUsageRecords(ctx context.Context, conn *gorm.DB, records []WorkspaceI return db.CreateInBatches(records, 1000).Error } + +func ListUsage(ctx context.Context, conn *gorm.DB, attributionId AttributionID) ([]WorkspaceInstanceUsage, error) { + db := conn.WithContext(ctx) + + var usageRecords []WorkspaceInstanceUsage + result := db.Find(&usageRecords, "attributionId = ?", attributionId) + if result.Error != nil { + return nil, fmt.Errorf("failed to get usage records: %s", result.Error) + } + return usageRecords, nil +} diff --git a/components/usage/pkg/db/workspace_instance_usage_test.go b/components/usage/pkg/db/workspace_instance_usage_test.go index 4c29e51646e653..76496f60c3a407 100644 --- a/components/usage/pkg/db/workspace_instance_usage_test.go +++ b/components/usage/pkg/db/workspace_instance_usage_test.go @@ -52,7 +52,7 @@ func TestCanCreateUsageRecords(t *testing.T) { } } -func TestCanHandleDuplicateRecords(t *testing.T) { +func TestNoErrorOnCreatingDuplicateRecords(t *testing.T) { teamID := uuid.New().String() teamAttributionID := db.NewTeamAttributionID(teamID) instanceID := uuid.New() diff --git a/components/usage/pkg/server/server.go b/components/usage/pkg/server/server.go index 22a9ee95eae952..7250585e8b9acb 100644 --- a/components/usage/pkg/server/server.go +++ b/components/usage/pkg/server/server.go @@ -17,6 +17,7 @@ import ( "github.com/gitpod-io/gitpod/usage/pkg/controller" "github.com/gitpod-io/gitpod/usage/pkg/db" "github.com/gitpod-io/gitpod/usage/pkg/stripe" + "gorm.io/gorm" ) type Config struct { @@ -88,7 +89,7 @@ func Start(cfg Config) error { if err != nil { return fmt.Errorf("failed to initialize usage server: %w", err) } - err = registerGRPCServices(srv) + err = registerGRPCServices(srv, conn) if err != nil { return fmt.Errorf("failed to register gRPC services: %w", err) } @@ -106,7 +107,7 @@ func Start(cfg Config) error { return nil } -func registerGRPCServices(srv *baseserver.Server) error { - v1.RegisterUsageServiceServer(srv.GRPC(), apiv1.NewUsageService()) +func registerGRPCServices(srv *baseserver.Server, conn *gorm.DB) error { + v1.RegisterUsageServiceServer(srv.GRPC(), apiv1.NewUsageService(conn)) return nil }