Skip to content

Commit 07d80c8

Browse files
sagor999roboquat
authored andcommitted
add support for aborting workspaces
1 parent 5e16a2d commit 07d80c8

File tree

9 files changed

+355
-275
lines changed

9 files changed

+355
-275
lines changed

components/ws-manager-api/core.proto

+4
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ message StopWorkspaceRequest {
121121
enum StopWorkspacePolicy {
122122
NORMALLY = 0;
123123
IMMEDIATELY = 1;
124+
ABORT = 2;
124125
}
125126

126127
// StopWorkspaceResponse is the answer to a stop workspace request
@@ -423,6 +424,9 @@ message WorkspaceConditions {
423424

424425
// volume_snapshot contains info about volume snapshot that was used to save persistent volume
425426
VolumeSnapshotInfo volume_snapshot = 12;
427+
428+
// aborted is true if StopWorkspace was called with StopWorkspacePolicy set to ABORT
429+
WorkspaceConditionBool aborted = 13;
426430
}
427431

428432
// WorkspaceConditionBool is a trinary bool: true/false/empty

components/ws-manager-api/go/core.pb.go

+290-273
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/ws-manager-api/typescript/src/core_pb.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,8 @@ export class WorkspaceConditions extends jspb.Message {
840840
clearVolumeSnapshot(): void;
841841
getVolumeSnapshot(): VolumeSnapshotInfo | undefined;
842842
setVolumeSnapshot(value?: VolumeSnapshotInfo): WorkspaceConditions;
843+
getAborted(): WorkspaceConditionBool;
844+
setAborted(value: WorkspaceConditionBool): WorkspaceConditions;
843845

844846
serializeBinary(): Uint8Array;
845847
toObject(includeInstance?: boolean): WorkspaceConditions.AsObject;
@@ -864,6 +866,7 @@ export namespace WorkspaceConditions {
864866
headlessTaskFailed: string,
865867
stoppedByRequest: WorkspaceConditionBool,
866868
volumeSnapshot?: VolumeSnapshotInfo.AsObject,
869+
aborted: WorkspaceConditionBool,
867870
}
868871
}
869872

@@ -1227,6 +1230,7 @@ export namespace WorkspaceClass {
12271230
export enum StopWorkspacePolicy {
12281231
NORMALLY = 0,
12291232
IMMEDIATELY = 1,
1233+
ABORT = 2,
12301234
}
12311235

12321236
export enum AdmissionLevel {

components/ws-manager-api/typescript/src/core_pb.js

+33-2
Original file line numberDiff line numberDiff line change
@@ -6666,7 +6666,8 @@ proto.wsman.WorkspaceConditions.toObject = function(includeInstance, msg) {
66666666
firstUserActivity: (f = msg.getFirstUserActivity()) && google_protobuf_timestamp_pb.Timestamp.toObject(includeInstance, f),
66676667
headlessTaskFailed: jspb.Message.getFieldWithDefault(msg, 10, ""),
66686668
stoppedByRequest: jspb.Message.getFieldWithDefault(msg, 11, 0),
6669-
volumeSnapshot: (f = msg.getVolumeSnapshot()) && proto.wsman.VolumeSnapshotInfo.toObject(includeInstance, f)
6669+
volumeSnapshot: (f = msg.getVolumeSnapshot()) && proto.wsman.VolumeSnapshotInfo.toObject(includeInstance, f),
6670+
aborted: jspb.Message.getFieldWithDefault(msg, 13, 0)
66706671
};
66716672

66726673
if (includeInstance) {
@@ -6749,6 +6750,10 @@ proto.wsman.WorkspaceConditions.deserializeBinaryFromReader = function(msg, read
67496750
reader.readMessage(value,proto.wsman.VolumeSnapshotInfo.deserializeBinaryFromReader);
67506751
msg.setVolumeSnapshot(value);
67516752
break;
6753+
case 13:
6754+
var value = /** @type {!proto.wsman.WorkspaceConditionBool} */ (reader.readEnum());
6755+
msg.setAborted(value);
6756+
break;
67526757
default:
67536758
reader.skipField();
67546759
break;
@@ -6857,6 +6862,13 @@ proto.wsman.WorkspaceConditions.serializeBinaryToWriter = function(message, writ
68576862
proto.wsman.VolumeSnapshotInfo.serializeBinaryToWriter
68586863
);
68596864
}
6865+
f = message.getAborted();
6866+
if (f !== 0.0) {
6867+
writer.writeEnum(
6868+
13,
6869+
f
6870+
);
6871+
}
68606872
};
68616873

68626874

@@ -7096,6 +7108,24 @@ proto.wsman.WorkspaceConditions.prototype.hasVolumeSnapshot = function() {
70967108
};
70977109

70987110

7111+
/**
7112+
* optional WorkspaceConditionBool aborted = 13;
7113+
* @return {!proto.wsman.WorkspaceConditionBool}
7114+
*/
7115+
proto.wsman.WorkspaceConditions.prototype.getAborted = function() {
7116+
return /** @type {!proto.wsman.WorkspaceConditionBool} */ (jspb.Message.getFieldWithDefault(this, 13, 0));
7117+
};
7118+
7119+
7120+
/**
7121+
* @param {!proto.wsman.WorkspaceConditionBool} value
7122+
* @return {!proto.wsman.WorkspaceConditions} returns this
7123+
*/
7124+
proto.wsman.WorkspaceConditions.prototype.setAborted = function(value) {
7125+
return jspb.Message.setProto3EnumField(this, 13, value);
7126+
};
7127+
7128+
70997129

71007130

71017131

@@ -9756,7 +9786,8 @@ proto.wsman.WorkspaceClass.prototype.setDisplayname = function(value) {
97569786
*/
97579787
proto.wsman.StopWorkspacePolicy = {
97589788
NORMALLY: 0,
9759-
IMMEDIATELY: 1
9789+
IMMEDIATELY: 1,
9790+
ABORT: 2
97609791
};
97619792

97629793
/**

components/ws-manager/pkg/manager/annotations.go

+3
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ const (
8080
// stoppedByRequestAnnotation is set on a pod when it was requested to stop using a StopWorkspace call
8181
stoppedByRequestAnnotation = "gitpod.io/stoppedByRequest"
8282

83+
// abortRequestAnnotation is set if StopWorkspace was called with ABORT StopWorkspacePolicy
84+
abortRequestAnnotation = "gitpod.io/abortRequest"
85+
8386
// attemptingToCreatePodAnnotation is set when ws-manager is trying to create pod and is removed when pod is successfully scheduled on the node
8487
attemptingToCreatePodAnnotation = "gitpod.io/attemptingToCreate"
8588
)

components/ws-manager/pkg/manager/manager.go

+7
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import (
4343
wsk8s "github.com/gitpod-io/gitpod/common-go/kubernetes"
4444
"github.com/gitpod-io/gitpod/common-go/log"
4545
"github.com/gitpod-io/gitpod/common-go/tracing"
46+
"github.com/gitpod-io/gitpod/common-go/util"
4647
csapi "github.com/gitpod-io/gitpod/content-service/api"
4748
"github.com/gitpod-io/gitpod/content-service/pkg/layer"
4849
regapi "github.com/gitpod-io/gitpod/registry-facade/api"
@@ -733,6 +734,12 @@ func (m *Manager) StopWorkspace(ctx context.Context, req *api.StopWorkspaceReque
733734
gracePeriod := stopWorkspaceNormallyGracePeriod
734735
if req.Policy == api.StopWorkspacePolicy_IMMEDIATELY {
735736
gracePeriod = stopWorkspaceImmediatelyGracePeriod
737+
} else if req.Policy == api.StopWorkspacePolicy_ABORT {
738+
gracePeriod = stopWorkspaceImmediatelyGracePeriod
739+
err = m.markWorkspace(ctx, req.Id, addMark(abortRequestAnnotation, util.BooleanTrueString))
740+
if err != nil {
741+
clog.WithError(err).Error("failed to mark workspace for abort")
742+
}
736743
}
737744

738745
err = m.markWorkspace(ctx, req.Id, addMark(stoppedByRequestAnnotation, gracePeriod.String()))

components/ws-manager/pkg/manager/metrics.go

+2
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ func (m *metrics) OnChange(status *api.WorkspaceStatus) {
265265
reason = "tab-closed"
266266
} else if strings.Contains(status.Message, "workspace timed out") {
267267
reason = "timeout"
268+
} else if status.Conditions.Aborted == api.WorkspaceConditionBool_TRUE {
269+
reason = "aborted"
268270
} else if status.Conditions.Failed != "" {
269271
reason = "failed"
270272
} else {

components/ws-manager/pkg/manager/monitor.go

+9
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@ func actOnPodEvent(ctx context.Context, m actingManager, manager *Manager, statu
493493
span.LogKV("disposalStatusAnnotation", ds)
494494
if terminated && !ds.Status.IsDisposed() {
495495
if wso.Pod.Annotations[workspaceFailedBeforeStoppingAnnotation] == util.BooleanTrueString && wso.Pod.Annotations[workspaceNeverReadyAnnotation] == util.BooleanTrueString {
496+
span.LogKV("event", "failed before stopping and never ready")
496497
// The workspace is never ready, so there is no need for a finalizer.
497498
if _, ok := pod.Annotations[workspaceExplicitFailAnnotation]; !ok {
498499
failMessage := status.Conditions.Failed
@@ -511,6 +512,14 @@ func actOnPodEvent(ctx context.Context, m actingManager, manager *Manager, statu
511512
return err
512513
}
513514
return m.modifyFinalizer(ctx, workspaceID, gitpodFinalizerName, false)
515+
} else if wso.Pod.Annotations[abortRequestAnnotation] == util.BooleanTrueString {
516+
span.LogKV("event", "workspace was aborted")
517+
// The workspace is aborted, so there is no need to finalize content
518+
if err = manager.deleteWorkspacePVC(ctx, pod.Name); err != nil {
519+
log.Error(err)
520+
return err
521+
}
522+
return m.modifyFinalizer(ctx, workspaceID, gitpodFinalizerName, false)
514523
} else {
515524
// We start finalizing the workspace content only after the container is gone. This way we ensure there's
516525
// no process modifying the workspace content as we create the backup.

components/ws-manager/pkg/manager/status.go

+3
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,9 @@ func (m *Manager) extractStatusFromPod(result *api.WorkspaceStatus, wso workspac
330330
if _, sbr := pod.Annotations[stoppedByRequestAnnotation]; sbr {
331331
result.Conditions.StoppedByRequest = api.WorkspaceConditionBool_TRUE
332332
}
333+
if _, abr := pod.Annotations[abortRequestAnnotation]; abr {
334+
result.Conditions.Aborted = api.WorkspaceConditionBool_TRUE
335+
}
333336
if wso.IsWorkspaceHeadless() {
334337
for _, cs := range pod.Status.ContainerStatuses {
335338
if cs.State.Terminated != nil && cs.State.Terminated.Message != "" {

0 commit comments

Comments
 (0)