Skip to content

Commit 17d51f5

Browse files
sagor999roboquat
authored andcommitted
pass workspace type when deleting volume snapshots
1 parent 9a5e6c4 commit 17d51f5

File tree

7 files changed

+191
-94
lines changed

7 files changed

+191
-94
lines changed

components/gitpod-protocol/src/protocol.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,11 @@ export interface VolumeSnapshot {
659659
volumeHandle: string;
660660
}
661661

662+
export interface VolumeSnapshotWithWSType {
663+
vs: VolumeSnapshot;
664+
wsType: WorkspaceType;
665+
}
666+
662667
export type SnapshotState = "pending" | "available" | "error";
663668

664669
export interface Workspace {

components/server/src/workspace/garbage-collector.ts

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import { injectable, inject } from "inversify";
88
import { ConsensusLeaderQorum } from "../consensus/consensus-leader-quorum";
9-
import { Disposable } from "@gitpod/gitpod-protocol";
9+
import { Disposable, VolumeSnapshotWithWSType } from "@gitpod/gitpod-protocol";
1010
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
1111
import { WorkspaceDeletionService } from "./workspace-deletion-service";
1212
import * as opentracing from "opentracing";
@@ -166,23 +166,36 @@ export class WorkspaceGarbageCollector {
166166
protected async deleteOutdatedVolumeSnapshots() {
167167
const span = opentracing.globalTracer().startSpan("deleteOutdatedVolumeSnapshots");
168168
try {
169-
const workspaces = await this.workspaceDB
169+
const workspaceIds = await this.workspaceDB
170170
.trace({ span })
171171
.findVolumeSnapshotWorkspacesForGC(this.config.workspaceGarbageCollection.chunkLimit);
172-
const volumeSnapshots = await Promise.all(
173-
workspaces.map((ws) =>
172+
const volumeSnapshotsWithWSPromises = workspaceIds.map(async (wsId) => {
173+
const [vss, ws] = await Promise.all([
174174
this.workspaceDB
175175
.trace({ span })
176-
.findVolumeSnapshotForGCByWorkspaceId(ws, this.config.workspaceGarbageCollection.chunkLimit),
177-
),
178-
);
176+
.findVolumeSnapshotForGCByWorkspaceId(wsId, this.config.workspaceGarbageCollection.chunkLimit),
177+
this.workspaceDB.trace({ span }).findById(wsId),
178+
]);
179+
return { wsId, ws, vss };
180+
});
179181

180-
await Promise.all(
181-
volumeSnapshots.map((vss) =>
182+
// We're doing the actual deletion in a sync for-loop tp avoid quadratic explosion of requests
183+
for await (const { wsId, ws, vss } of volumeSnapshotsWithWSPromises) {
184+
if (!ws) {
185+
log.error(`Workspace ${wsId} not found while looking for outdated volume snapshots`);
186+
continue; // Still, continue deleting the others
187+
}
188+
await Promise.all(
182189
// skip the first volume snapshot, as it is most recent, and then pass the rest into deletion
183-
vss.slice(1).map((vs) => this.deletionService.garbageCollectVolumeSnapshot({ span }, vs)),
184-
),
185-
);
190+
vss.slice(1).map((vs) => {
191+
let vswst: VolumeSnapshotWithWSType = {
192+
vs,
193+
wsType: ws?.type,
194+
};
195+
return this.deletionService.garbageCollectVolumeSnapshot({ span }, vswst);
196+
}),
197+
);
198+
}
186199
} catch (err) {
187200
TraceContext.setError({ span }, err);
188201
throw err;

components/server/src/workspace/workspace-deletion-service.ts

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66

77
import { inject, injectable } from "inversify";
8-
import { WorkspaceSoftDeletion, VolumeSnapshot } from "@gitpod/gitpod-protocol";
8+
import { WorkspaceSoftDeletion, VolumeSnapshotWithWSType } from "@gitpod/gitpod-protocol";
99
import {
1010
WorkspaceDB,
1111
WorkspaceAndOwner,
@@ -19,6 +19,7 @@ import { TraceContext } from "@gitpod/gitpod-protocol/lib/util/tracing";
1919
import { WorkspaceManagerClientProvider } from "@gitpod/ws-manager/lib/client-provider";
2020
import { DeleteVolumeSnapshotRequest } from "@gitpod/ws-manager/lib";
2121
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
22+
import { WorkspaceType } from "@gitpod/ws-manager/lib/core_pb";
2223

2324
@injectable()
2425
export class WorkspaceDeletionService {
@@ -121,7 +122,20 @@ export class WorkspaceDeletionService {
121122
let vss = await this.db
122123
.trace({ span })
123124
.findVolumeSnapshotForGCByWorkspaceId(ws.id, this.config.workspaceGarbageCollection.chunkLimit);
124-
await Promise.all(vss.map((vs) => this.garbageCollectVolumeSnapshot({ span }, vs)));
125+
// we need full workspace info here to find its type
126+
let fullWS = await this.db.trace({ span }).findById(ws.id);
127+
if (!fullWS) {
128+
throw new Error(`Workspace ${ws.id} not found while deleting its storage`);
129+
}
130+
let wsType = fullWS.type;
131+
let vssType = vss.map((vs) => {
132+
let vswst: VolumeSnapshotWithWSType = {
133+
vs,
134+
wsType: wsType,
135+
};
136+
return vswst;
137+
});
138+
await Promise.all(vssType.map((vs) => this.garbageCollectVolumeSnapshot({ span }, vs)));
125139
} catch (err) {
126140
TraceContext.setError({ span }, err);
127141
throw err;
@@ -141,7 +155,7 @@ export class WorkspaceDeletionService {
141155
* @param ctx
142156
* @param vs
143157
*/
144-
public async garbageCollectVolumeSnapshot(ctx: TraceContext, vs: VolumeSnapshot): Promise<boolean> {
158+
public async garbageCollectVolumeSnapshot(ctx: TraceContext, vs: VolumeSnapshotWithWSType): Promise<boolean> {
145159
const span = TraceContext.startSpan("garbageCollectVolumeSnapshot", ctx);
146160

147161
try {
@@ -161,8 +175,24 @@ export class WorkspaceDeletionService {
161175
this.config.installationShortname,
162176
);
163177
const req = new DeleteVolumeSnapshotRequest();
164-
req.setId(vs.id);
165-
req.setVolumeHandle(vs.volumeHandle);
178+
req.setId(vs.vs.id);
179+
req.setVolumeHandle(vs.vs.volumeHandle);
180+
let type: WorkspaceType = WorkspaceType.REGULAR;
181+
switch (vs.wsType) {
182+
case "regular": {
183+
type = WorkspaceType.REGULAR;
184+
break;
185+
}
186+
case "prebuild": {
187+
type = WorkspaceType.PREBUILD;
188+
break;
189+
}
190+
default: {
191+
throw new Error(`wds: deleteVolumeSnapshot unknown workspace type '${vs.wsType}' detected`);
192+
break;
193+
}
194+
}
195+
req.setWsType(type);
166196

167197
let softDelete = true;
168198
// if we did not delete volume snapshot yet and this is our last cluster, make sure we perform hard delete
@@ -184,7 +214,7 @@ export class WorkspaceDeletionService {
184214
}
185215
}
186216
if (wasDeleted) {
187-
await this.db.trace({ span }).deleteVolumeSnapshot(vs.id);
217+
await this.db.trace({ span }).deleteVolumeSnapshot(vs.vs.id);
188218
}
189219

190220
return wasDeleted;

components/ws-manager-api/core.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ message DeleteVolumeSnapshotRequest{
232232

233233
// soft_delete controls whether manager should attempt to restore volume snapshot from handle if it doesn't exist in the cluster yet
234234
bool soft_delete = 3;
235+
236+
// ws_type is the type of workspace (prebuild or regular) to which this volume snapshot belongs
237+
WorkspaceType ws_type = 4;
235238
}
236239

237240
message DeleteVolumeSnapshotResponse {

0 commit comments

Comments
 (0)