Skip to content

Commit 9e73691

Browse files
[installer] Allow to set default workspace timeout
1 parent 4a90fc6 commit 9e73691

File tree

11 files changed

+112
-20
lines changed

11 files changed

+112
-20
lines changed

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,16 @@ export interface ClientHeaderFields {
306306
clientRegion?: string;
307307
}
308308

309-
export const WorkspaceTimeoutValues = ["30m", "60m", "180m"] as const;
309+
export const WORKSPACE_TIMEOUT_DEFAULT_SHORT = "short";
310+
export const WORKSPACE_TIMEOUT_DEFAULT_LONG = "long";
311+
export const WORKSPACE_TIMEOUT_EXTENDED = "extended";
312+
export const WORKSPACE_TIMEOUT_EXTENDED_ALT = "180m"; // for backwards compatibility since the IDE uses this
313+
export const WorkspaceTimeoutValues = [
314+
WORKSPACE_TIMEOUT_DEFAULT_SHORT,
315+
WORKSPACE_TIMEOUT_DEFAULT_LONG,
316+
WORKSPACE_TIMEOUT_EXTENDED,
317+
WORKSPACE_TIMEOUT_EXTENDED_ALT,
318+
] as const;
310319

311320
export const createServiceMock = function <C extends GitpodClient, S extends GitpodServer>(methods: Partial<JsonRpcProxy<S>>): GitpodServiceImpl<C, S> {
312321
return new GitpodServiceImpl<C, S>(createServerMock(methods));

components/server/ee/src/user/eligibility-service.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import { inject, injectable } from "inversify";
88
import { TeamSubscriptionDB, UserDB } from "@gitpod/gitpod-db/lib";
99
import { TokenProvider } from "../../../src/user/token-provider";
10-
import { User, WorkspaceTimeoutDuration, WorkspaceInstance } from "@gitpod/gitpod-protocol";
10+
import { User, WorkspaceTimeoutDuration, WorkspaceInstance, WORKSPACE_TIMEOUT_DEFAULT_LONG, WORKSPACE_TIMEOUT_DEFAULT_SHORT } from "@gitpod/gitpod-protocol";
1111
import { RemainingHours } from "@gitpod/gitpod-protocol/lib/accounting-protocol";
1212
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
1313
import { Plans, MAX_PARALLEL_WORKSPACES } from "@gitpod/gitpod-protocol/lib/plans";
@@ -230,9 +230,9 @@ export class EligibilityService {
230230
*/
231231
async getDefaultWorkspaceTimeout(user: User, date: Date = new Date()): Promise<WorkspaceTimeoutDuration> {
232232
if (await this.maySetTimeout(user, date)) {
233-
return "60m";
233+
return WORKSPACE_TIMEOUT_DEFAULT_LONG;
234234
} else {
235-
return "30m";
235+
return WORKSPACE_TIMEOUT_DEFAULT_SHORT;
236236
}
237237
}
238238

components/server/ee/src/user/user-service.ts

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

77
import { UserService, CheckSignUpParams, CheckTermsParams } from "../../../src/user/user-service";
8-
import { User, WorkspaceTimeoutDuration } from "@gitpod/gitpod-protocol";
8+
import { User, WorkspaceTimeoutDuration, WORKSPACE_TIMEOUT_EXTENDED, WORKSPACE_TIMEOUT_EXTENDED_ALT, WORKSPACE_TIMEOUT_DEFAULT_LONG, WORKSPACE_TIMEOUT_DEFAULT_SHORT } from "@gitpod/gitpod-protocol";
99
import { inject } from "inversify";
1010
import { LicenseEvaluator } from "@gitpod/licensor/lib";
1111
import { Feature } from "@gitpod/licensor/lib/api";
@@ -14,13 +14,15 @@ import { EligibilityService } from "./eligibility-service";
1414
import { SubscriptionService } from "@gitpod/gitpod-payment-endpoint/lib/accounting";
1515
import { OssAllowListDB } from "@gitpod/gitpod-db/lib/oss-allowlist-db";
1616
import { HostContextProvider } from "../../../src/auth/host-context-provider";
17+
import { Config } from "../../../src/config";
1718

1819
export class UserServiceEE extends UserService {
1920
@inject(LicenseEvaluator) protected readonly licenseEvaluator: LicenseEvaluator;
2021
@inject(EligibilityService) protected readonly eligibilityService: EligibilityService;
2122
@inject(SubscriptionService) protected readonly subscriptionService: SubscriptionService;
2223
@inject(OssAllowListDB) protected readonly OssAllowListDb: OssAllowListDB;
2324
@inject(HostContextProvider) protected readonly hostContextProvider: HostContextProvider;
25+
@inject(Config) protected readonly config: Config;
2426

2527
async getDefaultWorkspaceTimeout(user: User, date: Date): Promise<WorkspaceTimeoutDuration> {
2628
if (this.config.enablePayment) {
@@ -30,10 +32,35 @@ export class UserServiceEE extends UserService {
3032

3133
// the self-hosted case
3234
if (!this.licenseEvaluator.isEnabled(Feature.FeatureSetTimeout)) {
33-
return "30m";
35+
return WORKSPACE_TIMEOUT_DEFAULT_SHORT;
3436
}
3537

36-
return "60m";
38+
return WORKSPACE_TIMEOUT_DEFAULT_LONG;
39+
}
40+
41+
public workspaceTimeoutToDuration(timeout: WorkspaceTimeoutDuration): string {
42+
switch (timeout) {
43+
case WORKSPACE_TIMEOUT_DEFAULT_SHORT:
44+
return "30m";
45+
case WORKSPACE_TIMEOUT_DEFAULT_LONG:
46+
return this.config.workspaceDefaults.timeoutDefault || "60m";
47+
case WORKSPACE_TIMEOUT_EXTENDED:
48+
case WORKSPACE_TIMEOUT_EXTENDED_ALT:
49+
return this.config.workspaceDefaults.timeoutExtended || "180m";
50+
}
51+
}
52+
53+
public durationToWorkspaceTimeout(duration: string): WorkspaceTimeoutDuration {
54+
switch (duration) {
55+
case "30m":
56+
return WORKSPACE_TIMEOUT_DEFAULT_SHORT;
57+
case this.config.workspaceDefaults.timeoutDefault || "60m":
58+
return WORKSPACE_TIMEOUT_DEFAULT_LONG;
59+
case this.config.workspaceDefaults.timeoutExtended || "180m":
60+
return WORKSPACE_TIMEOUT_EXTENDED_ALT;
61+
default:
62+
return WORKSPACE_TIMEOUT_DEFAULT_SHORT;
63+
}
3764
}
3865

3966
async userGetsMoreResources(user: User): Promise<boolean> {

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import { injectable, inject } from "inversify";
88
import { GitpodServerImpl, traceAPIParams, traceWI, censor } from "../../../src/workspace/gitpod-server-impl";
99
import { TraceContext } from "@gitpod/gitpod-protocol/lib/util/tracing";
10-
import { GitpodServer, GitpodClient, AdminGetListRequest, User, Team, TeamMemberInfo, AdminGetListResult, Permission, AdminBlockUserRequest, AdminModifyRoleOrPermissionRequest, RoleOrPermission, AdminModifyPermanentWorkspaceFeatureFlagRequest, UserFeatureSettings, AdminGetWorkspacesRequest, WorkspaceAndInstance, GetWorkspaceTimeoutResult, WorkspaceTimeoutDuration, WorkspaceTimeoutValues, SetWorkspaceTimeoutResult, WorkspaceContext, CreateWorkspaceMode, WorkspaceCreationResult, PrebuiltWorkspaceContext, CommitContext, PrebuiltWorkspace, WorkspaceInstance, EduEmailDomain, ProviderRepository, Queue, PrebuildWithStatus, CreateProjectParams, Project, StartPrebuildResult, ClientHeaderFields, Workspace, FindPrebuildsParams, TeamMemberRole } from "@gitpod/gitpod-protocol";
10+
import { GitpodServer, GitpodClient, AdminGetListRequest, User, Team, TeamMemberInfo, AdminGetListResult, Permission, AdminBlockUserRequest, AdminModifyRoleOrPermissionRequest, RoleOrPermission, AdminModifyPermanentWorkspaceFeatureFlagRequest, UserFeatureSettings, AdminGetWorkspacesRequest, WorkspaceAndInstance, GetWorkspaceTimeoutResult, WorkspaceTimeoutDuration, WorkspaceTimeoutValues, SetWorkspaceTimeoutResult, WorkspaceContext, CreateWorkspaceMode, WorkspaceCreationResult, PrebuiltWorkspaceContext, CommitContext, PrebuiltWorkspace, WorkspaceInstance, EduEmailDomain, ProviderRepository, Queue, PrebuildWithStatus, CreateProjectParams, Project, StartPrebuildResult, ClientHeaderFields, Workspace, FindPrebuildsParams, TeamMemberRole, WORKSPACE_TIMEOUT_DEFAULT_SHORT } from "@gitpod/gitpod-protocol";
1111
import { ResponseError } from "vscode-jsonrpc";
1212
import { TakeSnapshotRequest, AdmissionLevel, ControlAdmissionRequest, StopWorkspacePolicy, DescribeWorkspaceRequest, SetTimeoutRequest } from "@gitpod/ws-manager/lib";
1313
import { ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error";
@@ -27,7 +27,7 @@ import { AssigneeIdentityIdentifier, TeamSubscription, TeamSubscriptionSlot, Tea
2727
import { Plans } from "@gitpod/gitpod-protocol/lib/plans";
2828
import * as pThrottle from "p-throttle";
2929
import { formatDate } from "@gitpod/gitpod-protocol/lib/util/date-time";
30-
import { FindUserByIdentityStrResult } from "../../../src/user/user-service";
30+
import { FindUserByIdentityStrResult, UserService } from "../../../src/user/user-service";
3131
import { Accounting, AccountService, SubscriptionService, TeamSubscriptionService } from "@gitpod/gitpod-payment-endpoint/lib/accounting";
3232
import { AccountingDB, TeamSubscriptionDB, EduEmailDomainDB } from "@gitpod/gitpod-db/lib";
3333
import { ChargebeeProvider, UpgradeHelper } from "@gitpod/gitpod-payment-endpoint/lib/chargebee";
@@ -75,6 +75,8 @@ export class GitpodServerEEImpl extends GitpodServerImpl {
7575

7676
@inject(SnapshotService) protected readonly snapshotService: SnapshotService;
7777

78+
@inject(UserService) protected readonly userService: UserService;
79+
7880
initialize(client: GitpodClient | undefined, user: User | undefined, accessGuard: ResourceAccessGuard, clientMetadata: ClientMetadata, connectionCtx: TraceContext | undefined, clientHeaderFields: ClientHeaderFields): void {
7981
super.initialize(client, user, accessGuard, clientMetadata, connectionCtx, clientHeaderFields);
8082

@@ -211,14 +213,14 @@ export class GitpodServerEEImpl extends GitpodServerImpl {
211213
await Promise.all(instancesWithReset.map(i => {
212214
const req = new SetTimeoutRequest();
213215
req.setId(i.id);
214-
req.setDuration(defaultTimeout);
216+
req.setDuration(this.userService.workspaceTimeoutToDuration(defaultTimeout));
215217

216218
return client.setTimeout(ctx, req);
217219
}));
218220

219221
const req = new SetTimeoutRequest();
220222
req.setId(runningInstance.id);
221-
req.setDuration(duration);
223+
req.setDuration(this.userService.workspaceTimeoutToDuration(duration));
222224
await client.setTimeout(ctx, req);
223225

224226
return {
@@ -241,7 +243,7 @@ export class GitpodServerEEImpl extends GitpodServerImpl {
241243
const runningInstance = await this.workspaceDb.trace(ctx).findRunningInstance(workspaceId);
242244
if (!runningInstance) {
243245
log.warn({ userId: user.id, workspaceId }, 'Can only get keep-alive for running workspaces');
244-
return { duration: "30m", canChange };
246+
return { duration: WORKSPACE_TIMEOUT_DEFAULT_SHORT, canChange };
245247
}
246248
await this.guardAccess({ kind: "workspaceInstance", subject: runningInstance, workspace: workspace }, "get");
247249

@@ -250,11 +252,10 @@ export class GitpodServerEEImpl extends GitpodServerImpl {
250252

251253
const client = await this.workspaceManagerClientProvider.get(runningInstance.region);
252254
const desc = await client.describeWorkspace(ctx, req);
253-
const duration = desc.getStatus()!.getSpec()!.getTimeout() as WorkspaceTimeoutDuration;
255+
const duration = this.userService.durationToWorkspaceTimeout(desc.getStatus()!.getSpec()!.getTimeout());
254256
return { duration, canChange };
255257
}
256258

257-
258259
public async isPrebuildDone(ctx: TraceContext, pwsId: string): Promise<boolean> {
259260
traceAPIParams(ctx, { pwsId });
260261

components/server/src/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ export interface WorkspaceDefaults {
2929
workspaceImage: string;
3030
previewFeatureFlags: NamedWorkspaceFeatureFlag[];
3131
defaultFeatureFlags: NamedWorkspaceFeatureFlag[];
32+
timeoutDefault?: string;
33+
timeoutExtended?: string;
3234
}
3335

3436
export interface WorkspaceGarbageCollection {

components/server/src/user/user-service.ts

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

77
import { injectable, inject } from "inversify";
8-
import { User, Identity, WorkspaceTimeoutDuration, UserEnvVarValue, Token } from "@gitpod/gitpod-protocol";
8+
import { User, Identity, WorkspaceTimeoutDuration, UserEnvVarValue, Token, WORKSPACE_TIMEOUT_DEFAULT_SHORT, WORKSPACE_TIMEOUT_DEFAULT_LONG, WORKSPACE_TIMEOUT_EXTENDED, WORKSPACE_TIMEOUT_EXTENDED_ALT } from "@gitpod/gitpod-protocol";
99
import { TermsAcceptanceDB, UserDB } from "@gitpod/gitpod-db/lib";
1010
import { HostContextProvider } from "../auth/host-context-provider";
1111
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
@@ -155,7 +155,32 @@ export class UserService {
155155
* @param date The date for which we want to know the default workspace timeout
156156
*/
157157
async getDefaultWorkspaceTimeout(user: User, date: Date = new Date()): Promise<WorkspaceTimeoutDuration> {
158-
return "30m";
158+
return WORKSPACE_TIMEOUT_DEFAULT_SHORT;
159+
}
160+
161+
public workspaceTimeoutToDuration(timeout: WorkspaceTimeoutDuration): string {
162+
switch (timeout) {
163+
case WORKSPACE_TIMEOUT_DEFAULT_SHORT:
164+
return "30m";
165+
case WORKSPACE_TIMEOUT_DEFAULT_LONG:
166+
return "60m";
167+
case WORKSPACE_TIMEOUT_EXTENDED:
168+
case WORKSPACE_TIMEOUT_EXTENDED_ALT:
169+
return "180m";
170+
}
171+
}
172+
173+
public durationToWorkspaceTimeout(duration: string): WorkspaceTimeoutDuration {
174+
switch (duration) {
175+
case "30m":
176+
return WORKSPACE_TIMEOUT_DEFAULT_SHORT;
177+
case "60m":
178+
return WORKSPACE_TIMEOUT_DEFAULT_LONG;
179+
case "180m":
180+
return WORKSPACE_TIMEOUT_EXTENDED_ALT;
181+
default:
182+
return WORKSPACE_TIMEOUT_DEFAULT_SHORT;
183+
}
159184
}
160185

161186
/**

components/server/src/workspace/workspace-starter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -907,7 +907,7 @@ export class WorkspaceStarter {
907907
spec.setWorkspaceLocation(workspace.config.workspaceLocation || spec.getCheckoutLocation());
908908
spec.setFeatureFlagsList(this.toWorkspaceFeatureFlags(featureFlags));
909909
if (workspace.type === 'regular') {
910-
spec.setTimeout(await userTimeoutPromise);
910+
spec.setTimeout(this.userService.workspaceTimeoutToDuration(await userTimeoutPromise));
911911
}
912912
spec.setAdmission(admissionLevel);
913913
return spec;

install/installer/pkg/components/server/configmap.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) {
4040
WorkspaceImage: common.ImageName(common.ThirdPartyContainerRepo(ctx.Config.Repository, ""), workspace.DefaultWorkspaceImage, workspace.DefaultWorkspaceImageVersion),
4141
PreviewFeatureFlags: []NamedWorkspaceFeatureFlag{},
4242
DefaultFeatureFlags: []NamedWorkspaceFeatureFlag{},
43+
TimeoutDefault: ctx.Config.Workspace.TimeoutDefault,
44+
TimeoutExtended: ctx.Config.Workspace.TimeoutExtended,
4345
},
4446
Session: Session{
4547
MaxAgeMs: 259200000,

install/installer/pkg/components/server/types.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44

55
package server
66

7-
import "github.com/gitpod-io/gitpod/installer/pkg/config/v1"
7+
import (
8+
"github.com/gitpod-io/gitpod/common-go/util"
9+
"github.com/gitpod-io/gitpod/installer/pkg/config/v1"
10+
)
811

912
// These types are from TypeScript files
1013

@@ -120,6 +123,8 @@ type WorkspaceDefaults struct {
120123
WorkspaceImage string `json:"workspaceImage"`
121124
PreviewFeatureFlags []NamedWorkspaceFeatureFlag `json:"previewFeatureFlags"`
122125
DefaultFeatureFlags []NamedWorkspaceFeatureFlag `json:"defaultFeatureFlags"`
126+
TimeoutDefault *util.Duration `json:"timeoutDefault,omitempty"`
127+
TimeoutExtended *util.Duration `json:"timeoutExtended,omitempty"`
123128
}
124129

125130
type NamedWorkspaceFeatureFlag string

install/installer/pkg/components/ws-manager/configmap.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) {
3838
return (&q).String()
3939
}
4040

41+
timeoutAfterClose := util.Duration(2 * time.Minute)
42+
if ctx.Config.Workspace.TimeoutAfterClose != nil {
43+
timeoutAfterClose = *ctx.Config.Workspace.TimeoutAfterClose
44+
}
45+
4146
wsmcfg := config.ServiceConfiguration{
4247
Manager: config.Configuration{
4348
Namespace: ctx.Namespace,
@@ -81,11 +86,11 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) {
8186
WorkspaceHostPath: wsdaemon.HostWorkingArea,
8287
WorkspacePodTemplate: templatesCfg,
8388
Timeouts: config.WorkspaceTimeoutConfiguration{
84-
AfterClose: util.Duration(2 * time.Minute),
89+
AfterClose: timeoutAfterClose,
8590
HeadlessWorkspace: util.Duration(1 * time.Hour),
8691
Initialization: util.Duration(30 * time.Minute),
8792
RegularWorkspace: util.Duration(30 * time.Minute),
88-
MaxLifetime: util.Duration(36 * time.Hour),
93+
MaxLifetime: ctx.Config.Workspace.MaxLifetime,
8994
TotalStartup: util.Duration(1 * time.Hour),
9095
ContentFinalization: util.Duration(1 * time.Hour),
9196
Stopping: util.Duration(1 * time.Hour),

0 commit comments

Comments
 (0)