Skip to content

Commit 5cc2bdc

Browse files
committed
[ws-daemon] Support storage quota per class
1 parent f3b5c4a commit 5cc2bdc

File tree

10 files changed

+92
-20
lines changed

10 files changed

+92
-20
lines changed

components/ws-daemon-api/daemon.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ message InitWorkspaceRequest {
5252
// remote_storage_disabled disables any support for remote storage operations, specifically backups and snapshots.
5353
// When any such operation is attempted, a FAILED_PRECONDITION error will be the result.
5454
bool remote_storage_disabled = 7;
55+
56+
// storage_quota_bytes enforces a storage quate for the workspace if set to a value != 0
57+
int64 storage_quota_bytes = 8;
5558
}
5659

5760
// WorkspaceMetadata is data associated with a workspace that's required for other parts of the system to function

components/ws-daemon-api/go/daemon.pb.go

Lines changed: 13 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/ws-daemon-api/typescript/src/daemon_pb.d.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import * as jspb from "google-protobuf";
1414
import * as content_service_api_initializer_pb from "@gitpod/content-service/lib";
1515

16-
export class InitWorkspaceRequest extends jspb.Message {
16+
export class InitWorkspaceRequest extends jspb.Message {
1717
getId(): string;
1818
setId(value: string): InitWorkspaceRequest;
1919

@@ -34,6 +34,8 @@ export class InitWorkspaceRequest extends jspb.Message {
3434
setContentManifest(value: Uint8Array | string): InitWorkspaceRequest;
3535
getRemoteStorageDisabled(): boolean;
3636
setRemoteStorageDisabled(value: boolean): InitWorkspaceRequest;
37+
getStorageQuotaBytes(): number;
38+
setStorageQuotaBytes(value: number): InitWorkspaceRequest;
3739

3840
serializeBinary(): Uint8Array;
3941
toObject(includeInstance?: boolean): InitWorkspaceRequest.AsObject;
@@ -53,10 +55,11 @@ export namespace InitWorkspaceRequest {
5355
fullWorkspaceBackup: boolean,
5456
contentManifest: Uint8Array | string,
5557
remoteStorageDisabled: boolean,
58+
storageQuotaBytes: number,
5659
}
5760
}
5861

59-
export class WorkspaceMetadata extends jspb.Message {
62+
export class WorkspaceMetadata extends jspb.Message {
6063
getOwner(): string;
6164
setOwner(value: string): WorkspaceMetadata;
6265
getMetaId(): string;
@@ -79,7 +82,7 @@ export namespace WorkspaceMetadata {
7982
}
8083
}
8184

82-
export class InitWorkspaceResponse extends jspb.Message {
85+
export class InitWorkspaceResponse extends jspb.Message {
8386

8487
serializeBinary(): Uint8Array;
8588
toObject(includeInstance?: boolean): InitWorkspaceResponse.AsObject;
@@ -96,7 +99,7 @@ export namespace InitWorkspaceResponse {
9699
}
97100
}
98101

99-
export class WaitForInitRequest extends jspb.Message {
102+
export class WaitForInitRequest extends jspb.Message {
100103
getId(): string;
101104
setId(value: string): WaitForInitRequest;
102105

@@ -116,7 +119,7 @@ export namespace WaitForInitRequest {
116119
}
117120
}
118121

119-
export class WaitForInitResponse extends jspb.Message {
122+
export class WaitForInitResponse extends jspb.Message {
120123

121124
serializeBinary(): Uint8Array;
122125
toObject(includeInstance?: boolean): WaitForInitResponse.AsObject;
@@ -133,7 +136,7 @@ export namespace WaitForInitResponse {
133136
}
134137
}
135138

136-
export class TakeSnapshotRequest extends jspb.Message {
139+
export class TakeSnapshotRequest extends jspb.Message {
137140
getId(): string;
138141
setId(value: string): TakeSnapshotRequest;
139142
getReturnImmediately(): boolean;
@@ -156,7 +159,7 @@ export namespace TakeSnapshotRequest {
156159
}
157160
}
158161

159-
export class TakeSnapshotResponse extends jspb.Message {
162+
export class TakeSnapshotResponse extends jspb.Message {
160163
getUrl(): string;
161164
setUrl(value: string): TakeSnapshotResponse;
162165

@@ -176,7 +179,7 @@ export namespace TakeSnapshotResponse {
176179
}
177180
}
178181

179-
export class DisposeWorkspaceRequest extends jspb.Message {
182+
export class DisposeWorkspaceRequest extends jspb.Message {
180183
getId(): string;
181184
setId(value: string): DisposeWorkspaceRequest;
182185
getBackup(): boolean;
@@ -202,7 +205,7 @@ export namespace DisposeWorkspaceRequest {
202205
}
203206
}
204207

205-
export class DisposeWorkspaceResponse extends jspb.Message {
208+
export class DisposeWorkspaceResponse extends jspb.Message {
206209

207210
hasGitStatus(): boolean;
208211
clearGitStatus(): void;
@@ -225,7 +228,7 @@ export namespace DisposeWorkspaceResponse {
225228
}
226229
}
227230

228-
export class BackupWorkspaceRequest extends jspb.Message {
231+
export class BackupWorkspaceRequest extends jspb.Message {
229232
getId(): string;
230233
setId(value: string): BackupWorkspaceRequest;
231234

@@ -245,7 +248,7 @@ export namespace BackupWorkspaceRequest {
245248
}
246249
}
247250

248-
export class BackupWorkspaceResponse extends jspb.Message {
251+
export class BackupWorkspaceResponse extends jspb.Message {
249252
getUrl(): string;
250253
setUrl(value: string): BackupWorkspaceResponse;
251254

components/ws-daemon-api/typescript/src/daemon_pb.js

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,8 @@ proto.wsdaemon.InitWorkspaceRequest.toObject = function(includeInstance, msg) {
303303
initializer: (f = msg.getInitializer()) && content$service$api_initializer_pb.WorkspaceInitializer.toObject(includeInstance, f),
304304
fullWorkspaceBackup: jspb.Message.getBooleanFieldWithDefault(msg, 4, false),
305305
contentManifest: msg.getContentManifest_asB64(),
306-
remoteStorageDisabled: jspb.Message.getBooleanFieldWithDefault(msg, 7, false)
306+
remoteStorageDisabled: jspb.Message.getBooleanFieldWithDefault(msg, 7, false),
307+
storageQuotaBytes: jspb.Message.getFieldWithDefault(msg, 8, 0)
307308
};
308309

309310
if (includeInstance) {
@@ -366,6 +367,10 @@ proto.wsdaemon.InitWorkspaceRequest.deserializeBinaryFromReader = function(msg,
366367
var value = /** @type {boolean} */ (reader.readBool());
367368
msg.setRemoteStorageDisabled(value);
368369
break;
370+
case 8:
371+
var value = /** @type {number} */ (reader.readInt64());
372+
msg.setStorageQuotaBytes(value);
373+
break;
369374
default:
370375
reader.skipField();
371376
break;
@@ -439,6 +444,13 @@ proto.wsdaemon.InitWorkspaceRequest.serializeBinaryToWriter = function(message,
439444
f
440445
);
441446
}
447+
f = message.getStorageQuotaBytes();
448+
if (f !== 0) {
449+
writer.writeInt64(
450+
8,
451+
f
452+
);
453+
}
442454
};
443455

444456

@@ -612,6 +624,24 @@ proto.wsdaemon.InitWorkspaceRequest.prototype.setRemoteStorageDisabled = functio
612624
};
613625

614626

627+
/**
628+
* optional int64 storage_quota_bytes = 8;
629+
* @return {number}
630+
*/
631+
proto.wsdaemon.InitWorkspaceRequest.prototype.getStorageQuotaBytes = function() {
632+
return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 8, 0));
633+
};
634+
635+
636+
/**
637+
* @param {number} value
638+
* @return {!proto.wsdaemon.InitWorkspaceRequest} returns this
639+
*/
640+
proto.wsdaemon.InitWorkspaceRequest.prototype.setStorageQuotaBytes = function(value) {
641+
return jspb.Message.setProto3IntField(this, 8, value);
642+
};
643+
644+
615645

616646

617647

components/ws-daemon/pkg/content/config.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"github.com/gitpod-io/gitpod/common-go/util"
1212
cntntcfg "github.com/gitpod-io/gitpod/content-service/api/config"
1313
"github.com/gitpod-io/gitpod/ws-daemon/api"
14-
"github.com/gitpod-io/gitpod/ws-daemon/pkg/quota"
1514
"golang.org/x/xerrors"
1615
)
1716

@@ -29,9 +28,6 @@ type Config struct {
2928
// TmpDir is the temp working diretory for creating tar files during upload
3029
TmpDir string `json:"tempDir"`
3130

32-
// Limit limits the size of a sandbox
33-
WorkspaceSizeLimit quota.Size `json:"workspaceSizeLimit"`
34-
3531
// Storage is some form of permanent file store to which we back up workspaces
3632
Storage cntntcfg.StorageConfig `json:"storage"`
3733

components/ws-daemon/pkg/content/hooks.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ func workspaceLifecycleHooks(cfg Config, kubernetesNamespace string, workspaceEx
2828
session.WorkspaceInitializing: {
2929
hookSetupRemoteStorage(cfg),
3030
hookSetupWorkspaceLocation,
31-
hookInstallQuota(xfs, cfg.WorkspaceSizeLimit),
31+
hookInstallQuota(xfs),
3232
startIWS,
3333
},
3434
session.WorkspaceReady: {
3535
hookSetupRemoteStorage(cfg),
36-
hookInstallQuota(xfs, cfg.WorkspaceSizeLimit),
36+
hookInstallQuota(xfs),
3737
startIWS,
3838
},
3939
session.WorkspaceDisposed: {
@@ -93,11 +93,12 @@ func hookSetupWorkspaceLocation(ctx context.Context, ws *session.Workspace) erro
9393
}
9494

9595
// hookInstallQuota enforces filesystem quota on the workspace location (if the filesystem supports it)
96-
func hookInstallQuota(xfs *quota.XFS, size quota.Size) session.WorkspaceLivecycleHook {
96+
func hookInstallQuota(xfs *quota.XFS) session.WorkspaceLivecycleHook {
9797
return func(ctx context.Context, ws *session.Workspace) error {
9898
if xfs == nil {
9999
return nil
100100
}
101+
size := quota.Size(ws.StorageQuota)
101102
if size == 0 {
102103
return nil
103104
}

components/ws-daemon/pkg/content/service.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ func (s *WorkspaceService) creator(req *api.InitWorkspaceRequest) session.Worksp
261261
FullWorkspaceBackup: req.FullWorkspaceBackup,
262262
ContentManifest: req.ContentManifest,
263263
RemoteStorageDisabled: req.RemoteStorageDisabled,
264+
StorageQuota: int(req.StorageQuotaBytes),
264265

265266
ServiceLocDaemon: filepath.Join(s.config.WorkingArea, ServiceDirName(req.Id)),
266267
ServiceLocNode: filepath.Join(s.config.WorkingAreaNode, ServiceDirName(req.Id)),

components/ws-daemon/pkg/internal/session/workspace.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ type Workspace struct {
6868
ServiceLocDaemon string `json:"serviceLocDaemon"`
6969

7070
RemoteStorageDisabled bool `json:"remoteStorageDisabled,omitempty"`
71+
StorageQuota int `json:"storageQuota,omitempty"`
7172

7273
XFSProjectID int `json:"xfsProjectID"`
7374

components/ws-manager-api/go/config/config.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,9 +295,23 @@ var validResourceConfig = validation.By(func(o interface{}) error {
295295
return xerrors.Errorf("cannot parse EphemeralStorage quantity: %w", err)
296296
}
297297
}
298+
if rc.Storage != "" {
299+
_, err := resource.ParseQuantity(rc.Storage)
300+
if err != nil {
301+
return xerrors.Errorf("cannot parse Storage quantity: %w", err)
302+
}
303+
}
298304
return nil
299305
})
300306

307+
func (r *ResourceConfiguration) StorageQuantity() (resource.Quantity, error) {
308+
if r.Storage == "" {
309+
res := resource.NewQuantity(0, resource.BinarySI)
310+
return *res, nil
311+
}
312+
return resource.ParseQuantity(r.Storage)
313+
}
314+
301315
// ResourceList parses the quantities in the resource config
302316
func (r *ResourceConfiguration) ResourceList() (corev1.ResourceList, error) {
303317
if r == nil {
@@ -411,4 +425,5 @@ type ResourceConfiguration struct {
411425
CPU string `json:"cpu"`
412426
Memory string `json:"memory"`
413427
EphemeralStorage string `json:"ephemeral-storage"`
428+
Storage string `json:"storage,omitempty"`
414429
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,15 @@ func (m *Monitor) initializeWorkspaceContent(ctx context.Context, pod *corev1.Po
669669
return xerrors.Errorf("pod %s has no owner", pod.Name)
670670
}
671671

672+
class, ok := m.manager.Config.WorkspaceClasses[pod.Labels[workspaceClassLabel]]
673+
if !ok {
674+
return xerrors.Errorf("pod %s has unknown workspace class", pod.Name, pod.Labels[workspaceClassLabel])
675+
}
676+
storage, err := class.Container.Limits.StorageQuantity()
677+
if !ok {
678+
return xerrors.Errorf("workspace class %s has invalid storage quantity: %w", pod.Labels[workspaceClassLabel], err)
679+
}
680+
672681
var (
673682
initializer csapi.WorkspaceInitializer
674683
snc wsdaemon.WorkspaceContentServiceClient
@@ -746,6 +755,7 @@ func (m *Monitor) initializeWorkspaceContent(ctx context.Context, pod *corev1.Po
746755
FullWorkspaceBackup: fullWorkspaceBackup,
747756
ContentManifest: contentManifest,
748757
RemoteStorageDisabled: shouldDisableRemoteStorage(pod),
758+
StorageQuotaBytes: storage.Value(),
749759
})
750760
return err
751761
})

0 commit comments

Comments
 (0)