Skip to content

Commit 0af7d1e

Browse files
committed
[usage] wiring ListUsage through server
1 parent cb94f2d commit 0af7d1e

File tree

5 files changed

+153
-5
lines changed

5 files changed

+153
-5
lines changed

components/gitpod-protocol/src/gitpod-service.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ import {
6060
import { RemotePageMessage, RemoteTrackMessage, RemoteIdentifyMessage } from "./analytics";
6161
import { IDEServer } from "./ide-protocol";
6262
import { InstallationAdminSettings, TelemetryData } from "./installation-admin-protocol";
63-
import { ListBilledUsageResponse, ListBilledUsageRequest } from "./usage";
63+
import { ListBilledUsageResponse, ListBilledUsageRequest, ListUsageRequest, ListUsageResponse } from "./usage";
6464
import { SupportedWorkspaceClass } from "./workspace-class";
6565
import { BillingMode } from "./billing-mode";
6666

@@ -298,6 +298,7 @@ export interface GitpodServer extends JsonRpcServer<GitpodClient>, AdminServer,
298298
setSpendingLimitForTeam(teamId: string, spendingLimit: number): Promise<void>;
299299

300300
listBilledUsage(req: ListBilledUsageRequest): Promise<ListBilledUsageResponse>;
301+
listUsage(req: ListUsageRequest): Promise<ListUsageResponse>;
301302

302303
setUsageAttribution(usageAttribution: string): Promise<void>;
303304

components/gitpod-protocol/src/usage.ts

+65
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,68 @@ export interface ListBilledUsageResponse {
6161
}
6262

6363
export type BillableWorkspaceType = WorkspaceType;
64+
65+
// types below are copied over from components/usage-api/typescript/src/usage/v1/usage_pb.d.ts
66+
67+
export interface ListUsageRequest {
68+
attributionId: string;
69+
from?: number;
70+
to?: number;
71+
order: Ordering;
72+
pagination?: PaginationRequest;
73+
}
74+
75+
export enum Ordering {
76+
ORDERING_DESCENDING = 0,
77+
ORDERING_ASCENDING = 1,
78+
}
79+
80+
export interface PaginationRequest {
81+
perPage: number;
82+
page: number;
83+
}
84+
85+
export interface ListUsageResponse {
86+
usageEntriesList: Usage[];
87+
pagination?: PaginationResponse;
88+
creditBalanceAtStart: number;
89+
creditBalanceAtEnd: number;
90+
}
91+
92+
export interface PaginationResponse {
93+
perPage: number;
94+
totalPages: number;
95+
total: number;
96+
page: number;
97+
}
98+
99+
export type UsageKind = "workspaceinstance" | "invoice";
100+
export interface Usage {
101+
id: string;
102+
attributionId: string;
103+
description: string;
104+
credits: number;
105+
effectiveTime?: number;
106+
kind: UsageKind;
107+
workspaceInstanceId: string;
108+
draft: boolean;
109+
metadata: WorkspaceInstanceUsageData | InvoiceUsageData;
110+
}
111+
112+
// the equivalent golang shape is maintained in `/workspace/gitpod/`components/usage/pkg/db/usage.go`
113+
export interface WorkspaceInstanceUsageData {
114+
workspaceid: string;
115+
workspaceType: WorkspaceType;
116+
workspaceClass: string;
117+
contextURL: string;
118+
startTime: string;
119+
endTime?: string;
120+
userName: string;
121+
userAvatarURL: string;
122+
}
123+
124+
export interface InvoiceUsageData {
125+
invoiceId: string;
126+
startDate: string;
127+
endDate: string;
128+
}

components/server/ee/src/workspace/gitpod-server-impl.ts

+63-3
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,13 @@ import { BlockedRepository } from "@gitpod/gitpod-protocol/lib/blocked-repositor
7171
import { EligibilityService } from "../user/eligibility-service";
7272
import { AccountStatementProvider } from "../user/account-statement-provider";
7373
import { GithubUpgradeURL, PlanCoupon } from "@gitpod/gitpod-protocol/lib/payment-protocol";
74-
import { ListBilledUsageRequest, ListBilledUsageResponse } from "@gitpod/gitpod-protocol/lib/usage";
75-
import { ListBilledUsageRequest as ListBilledUsage } from "@gitpod/usage-api/lib/usage/v1/usage_pb";
74+
import {
75+
ListBilledUsageRequest,
76+
ListBilledUsageResponse,
77+
ListUsageRequest,
78+
ListUsageResponse,
79+
} from "@gitpod/gitpod-protocol/lib/usage";
80+
import * as usage_grpc from "@gitpod/usage-api/lib/usage/v1/usage_pb";
7681
import {
7782
AssigneeIdentityIdentifier,
7883
TeamSubscription,
@@ -114,6 +119,7 @@ import { BillingMode } from "@gitpod/gitpod-protocol/lib/billing-mode";
114119
import { BillingModes } from "../billing/billing-mode";
115120
import { getExperimentsClientForBackend } from "@gitpod/gitpod-protocol/lib/experiments/configcat-server";
116121
import { BillingService } from "../billing/billing-service";
122+
import { restEndpointMethods } from "@octokit/plugin-rest-endpoint-methods";
117123

118124
@injectable()
119125
export class GitpodServerEEImpl extends GitpodServerImpl {
@@ -2182,6 +2188,60 @@ export class GitpodServerEEImpl extends GitpodServerImpl {
21822188
return result;
21832189
}
21842190

2191+
async listUsage(ctx: TraceContext, req: ListUsageRequest): Promise<ListUsageResponse> {
2192+
const { attributionId, from, to } = req;
2193+
traceAPIParams(ctx, { attributionId });
2194+
const user = this.checkAndBlockUser("listBilledUsage");
2195+
2196+
await this.guardCostCenterAccess(ctx, user.id, attributionId, "get");
2197+
2198+
const timestampFrom = from ? Timestamp.fromDate(new Date(from)) : undefined;
2199+
const timestampTo = to ? Timestamp.fromDate(new Date(to)) : undefined;
2200+
2201+
const usageClient = this.usageServiceClientProvider.getDefault();
2202+
const request = new usage_grpc.ListBilledUsageRequest();
2203+
request.setAttributionId(attributionId);
2204+
request.setFrom(timestampFrom);
2205+
if (to) {
2206+
request.setTo(timestampTo);
2207+
}
2208+
request.setOrder(req.order);
2209+
if (req.pagination) {
2210+
const paginatedRequest = new usage_grpc.PaginatedRequest();
2211+
paginatedRequest.setPage(req.pagination.page);
2212+
paginatedRequest.setPerPage(req.pagination.perPage);
2213+
request.setPagination(paginatedRequest);
2214+
}
2215+
const response = await usageClient.listUsage(ctx, request);
2216+
const pagination = response.getPagination();
2217+
return {
2218+
usageEntriesList: response.getUsageEntriesList().map((u) => {
2219+
return {
2220+
id: u.getId(),
2221+
attributionId: u.getAttributionId(),
2222+
effectiveTime: u.getEffectiveTime()!.toDate().getTime(),
2223+
credits: u.getCredits(),
2224+
description: u.getDescription(),
2225+
draft: u.getDraft(),
2226+
workspaceInstanceId: u.getWorkspaceInstanceId(),
2227+
kind:
2228+
u.getKind() === usage_grpc.Usage.Kind.KIND_WORKSPACE_INSTANCE ? "workspaceinstance" : "invoice",
2229+
metadata: JSON.parse(u.getMetadata()),
2230+
};
2231+
}),
2232+
pagination: pagination
2233+
? {
2234+
page: pagination.getPage(),
2235+
perPage: pagination.getPerPage(),
2236+
total: pagination.getTotal(),
2237+
totalPages: pagination.getTotalPages(),
2238+
}
2239+
: undefined,
2240+
creditBalanceAtEnd: response.getCreditBalanceAtEnd(),
2241+
creditBalanceAtStart: response.getCreditBalanceAtStart(),
2242+
};
2243+
}
2244+
21852245
async listBilledUsage(ctx: TraceContext, req: ListBilledUsageRequest): Promise<ListBilledUsageResponse> {
21862246
const { attributionId, fromDate, toDate, perPage, page } = req;
21872247
traceAPIParams(ctx, { attributionId });
@@ -2201,7 +2261,7 @@ export class GitpodServerEEImpl extends GitpodServerImpl {
22012261
const response = await usageClient.listBilledUsage(
22022262
ctx,
22032263
attributionId,
2204-
ListBilledUsage.Ordering.ORDERING_DESCENDING,
2264+
usage_grpc.ListBilledUsageRequest.Ordering.ORDERING_DESCENDING,
22052265
perPage,
22062266
page,
22072267
timestampFrom,

components/server/src/workspace/gitpod-server-impl.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,12 @@ import { InstallationAdminTelemetryDataProvider } from "../installation-admin/te
172172
import { LicenseEvaluator } from "@gitpod/licensor/lib";
173173
import { Feature } from "@gitpod/licensor/lib/api";
174174
import { getExperimentsClientForBackend } from "@gitpod/gitpod-protocol/lib/experiments/configcat-server";
175-
import { ListBilledUsageRequest, ListBilledUsageResponse } from "@gitpod/gitpod-protocol/lib/usage";
175+
import {
176+
ListBilledUsageRequest,
177+
ListBilledUsageResponse,
178+
ListUsageRequest,
179+
ListUsageResponse,
180+
} from "@gitpod/gitpod-protocol/lib/usage";
176181
import { WorkspaceClusterImagebuilderClientProvider } from "./workspace-cluster-imagebuilder-client-provider";
177182
import { VerificationService } from "../auth/verification-service";
178183
import { BillingMode } from "@gitpod/gitpod-protocol/lib/billing-mode";
@@ -3232,6 +3237,10 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
32323237
throw new ResponseError(ErrorCodes.SAAS_FEATURE, `Not implemented in this version`);
32333238
}
32343239

3240+
async listUsage(ctx: TraceContext, req: ListUsageRequest): Promise<ListUsageResponse> {
3241+
throw new ResponseError(ErrorCodes.SAAS_FEATURE, `Not implemented in this version`);
3242+
}
3243+
32353244
async getSpendingLimitForTeam(ctx: TraceContext, teamId: string): Promise<number | undefined> {
32363245
throw new ResponseError(ErrorCodes.SAAS_FEATURE, `Not implemented in this version`);
32373246
}

components/usage/pkg/db/usage.go

+13
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,19 @@ type Usage struct {
3535
Metadata datatypes.JSON `gorm:"column:metadata;type:text;size:65535" json:"metadata"`
3636
}
3737

38+
// WorkspaceInstanceUsageData represents the shape for usage entry of kind "workspaceinstance"
39+
// the equivalent TypeScript definition is maintained in `components/gitpod-protocol/src/usage.ts“
40+
type WorkspaceInstanceUsageData struct {
41+
WorkspaceId string
42+
WorkspaceType WorkspaceType
43+
WorkspaceClass string
44+
ContextURL string
45+
StartTime string
46+
EndTime string
47+
UserName string
48+
UserAvatarURL string
49+
}
50+
3851
type FindUsageResult struct {
3952
UsageEntries []Usage
4053
}

0 commit comments

Comments
 (0)