Skip to content

Commit

Permalink
[server] Allow options on ws start
Browse files Browse the repository at this point in the history
introduces IDE and workspace class arguments on WS Start
  • Loading branch information
svenefftinge authored and roboquat committed Dec 16, 2022
1 parent f9b429b commit 0605514
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 23 deletions.
4 changes: 3 additions & 1 deletion components/gitpod-protocol/go/gitpod-service.go
Original file line number Diff line number Diff line change
Expand Up @@ -1899,7 +1899,9 @@ type WorkspaceInstanceStatus struct {

// StartWorkspaceOptions is the StartWorkspaceOptions message type
type StartWorkspaceOptions struct {
ForceDefaultImage bool `json:"forceDefaultImage,omitempty"`
ForceDefaultImage bool `json:"forceDefaultImage,omitempty"`
WorkspaceClass string `json:"workspaceClass,omitempty"`
IdeSettings *IDESettings `json:"ideSettings,omitempty"`
}

// GetWorkspaceTimeoutResult is the GetWorkspaceTimeoutResult message type
Expand Down
9 changes: 7 additions & 2 deletions components/gitpod-protocol/src/gitpod-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
PrebuiltWorkspace,
UserSSHPublicKeyValue,
SSHPublicKeyValue,
IDESettings,
} from "./protocol";
import {
Team,
Expand Down Expand Up @@ -414,16 +415,20 @@ export namespace GitpodServer {
export interface GetAccountStatementOptions {
date?: string;
}
export interface CreateWorkspaceOptions {
export interface CreateWorkspaceOptions extends StartWorkspaceOptions {
contextUrl: string;

// whether running workspaces on the same context should be ignored. If false (default) users will be asked.
ignoreRunningWorkspaceOnSameCommit?: boolean;
ignoreRunningPrebuild?: boolean;
allowUsingPreviousPrebuilds?: boolean;
forceDefaultConfig?: boolean;
}

export interface StartWorkspaceOptions {
forceDefaultImage: boolean;
forceDefaultImage?: boolean;
workspaceClass?: string;
ideSettings?: IDESettings;
}
export interface TakeSnapshotOptions {
workspaceId: string;
Expand Down
23 changes: 18 additions & 5 deletions components/server/src/ide-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,18 +84,28 @@ export class IDEService {
return newIDESettings;
}

async resolveWorkspaceConfig(workspace: Workspace, user: User): Promise<ResolveWorkspaceConfigResponse> {
async resolveWorkspaceConfig(
workspace: Workspace,
user: User,
userSelectedIdeSettings?: IDESettings,
): Promise<ResolveWorkspaceConfigResponse> {
const use = await this.configCatClientFactory().getValueAsync("use_IDEService_ResolveWorkspaceConfig", false, {
user,
});
if (use) {
return this.doResolveWorkspaceConfig(workspace, user);
return this.doResolveWorkspaceConfig(
workspace,
userSelectedIdeSettings || user.additionalData?.ideSettings,
);
}

const deprecated = await this.resolveDeprecated(workspace, user);
// assert against ide-service
(async () => {
const config = await this.doResolveWorkspaceConfig(workspace, user);
const config = await this.doResolveWorkspaceConfig(
workspace,
userSelectedIdeSettings || user.additionalData?.ideSettings,
);
const { tasks: configTasks, ...newConfig } = config;
const { tasks: deprecatedTasks, ...newDeprecated } = deprecated;
// we omit tasks because we're going to rewrite them soon and the deepEqual was failing
Expand All @@ -104,14 +114,17 @@ export class IDEService {
return deprecated;
}

private async doResolveWorkspaceConfig(workspace: Workspace, user: User): Promise<ResolveWorkspaceConfigResponse> {
private async doResolveWorkspaceConfig(
workspace: Workspace,
userSelectedIdeSettings?: IDESettings,
): Promise<ResolveWorkspaceConfigResponse> {
const workspaceType =
workspace.type === "prebuild" ? IdeServiceApi.WorkspaceType.PREBUILD : IdeServiceApi.WorkspaceType.REGULAR;

const req: IdeServiceApi.ResolveWorkspaceConfigRequest = {
type: workspaceType,
context: JSON.stringify(workspace.context),
ideSettings: JSON.stringify(user.additionalData?.ideSettings),
ideSettings: JSON.stringify(userSelectedIdeSettings),
workspaceConfig: JSON.stringify(workspace.config),
};
for (let attempt = 0; attempt < 15; attempt++) {
Expand Down
5 changes: 2 additions & 3 deletions components/server/src/workspace/gitpod-server-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -734,9 +734,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
await projectPromise,
await userEnvVars,
await projectEnvVarsPromise,
{
forceDefaultImage: !!options.forceDefaultImage,
},
options,
);
traceWI(ctx, { instanceId: result.instanceID });
return result;
Expand Down Expand Up @@ -1207,6 +1205,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
project,
await envVars,
await projectEnvVarsPromise,
options,
);
ctx.span?.log({ event: "startWorkspaceComplete", ...startWorkspaceResult });

Expand Down
44 changes: 32 additions & 12 deletions components/server/src/workspace/workspace-starter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ import {
EnvVarWithValue,
BillingTier,
Project,
GitpodServer,
IDESettings,
} from "@gitpod/gitpod-protocol";
import { IAnalyticsWriter } from "@gitpod/gitpod-protocol/lib/analytics";
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
Expand Down Expand Up @@ -127,9 +129,8 @@ import { AttributionId } from "@gitpod/gitpod-protocol/lib/attribution";
import { LogContext } from "@gitpod/gitpod-protocol/lib/util/logging";
import { repeat } from "@gitpod/gitpod-protocol/lib/util/repeat";

export interface StartWorkspaceOptions {
export interface StartWorkspaceOptions extends GitpodServer.StartWorkspaceOptions {
rethrow?: boolean;
forceDefaultImage?: boolean;
excludeFeatureFlags?: NamedWorkspaceFeatureFlag[];
}

Expand All @@ -139,21 +140,31 @@ const INSTANCE_START_RETRY_INTERVAL_SECONDS = 2;
export async function getWorkspaceClassForInstance(
ctx: TraceContext,
workspace: Workspace,
previousInstance: WorkspaceInstance | undefined,
user: User,
project: Project | undefined,
workspaceClassOverride: string | undefined,
entitlementService: EntitlementService,
config: WorkspaceClassesConfig,
): Promise<string> {
const span = TraceContext.startSpan("getWorkspaceClassForInstance", ctx);
try {
let workspaceClass: string | undefined;
switch (workspace.type) {
case "prebuild":
workspaceClass = project?.settings?.workspaceClasses?.prebuild;
break;
case "regular":
workspaceClass = project?.settings?.workspaceClasses?.regular;
break;
if (workspaceClassOverride) {
workspaceClass = workspaceClassOverride;
}
if (!workspaceClass && previousInstance) {
workspaceClass = previousInstance.workspaceClass;
}
if (!workspaceClass) {
switch (workspace.type) {
case "prebuild":
workspaceClass = project?.settings?.workspaceClasses?.prebuild;
break;
case "regular":
workspaceClass = project?.settings?.workspaceClasses?.regular;
break;
}
}
if (!workspaceClass && (await entitlementService.userGetsMoreResources(user))) {
workspaceClass = config.find((c) => !!c.marker?.moreResources)?.id;
Expand Down Expand Up @@ -269,7 +280,7 @@ export class WorkspaceStarter {
}
}

const ideConfig = await this.resolveIDEConfiguration(ctx, workspace, user);
const ideConfig = await this.resolveIDEConfiguration(ctx, workspace, user, options.ideSettings);

// create and store instance
let instance = await this.workspaceDb
Expand All @@ -283,6 +294,7 @@ export class WorkspaceStarter {
project,
options.excludeFeatureFlags || [],
ideConfig,
options.workspaceClass,
),
);
span.log({ newInstance: instance.id });
Expand Down Expand Up @@ -350,15 +362,20 @@ export class WorkspaceStarter {
}
}

private async resolveIDEConfiguration(ctx: TraceContext, workspace: Workspace, user: User) {
private async resolveIDEConfiguration(
ctx: TraceContext,
workspace: Workspace,
user: User,
userSelectedIdeSettings?: IDESettings,
) {
const span = TraceContext.startSpan("resolveIDEConfiguration", ctx);
try {
const migrated = this.ideService.migrateSettings(user);
if (user.additionalData?.ideSettings && migrated) {
user.additionalData.ideSettings = migrated;
}

const resp = await this.ideService.resolveWorkspaceConfig(workspace, user);
const resp = await this.ideService.resolveWorkspaceConfig(workspace, user, userSelectedIdeSettings);
if (!user.additionalData?.ideSettings && resp.refererIde) {
// A user does not have IDE settings configured yet configure it with a referrer ide as default.
const additionalData = user?.additionalData || {};
Expand Down Expand Up @@ -770,6 +787,7 @@ export class WorkspaceStarter {
project: Project | undefined,
excludeFeatureFlags: NamedWorkspaceFeatureFlag[],
ideConfig: IdeServiceApi.ResolveWorkspaceConfigResponse,
workspaceClassOverride?: string,
): Promise<WorkspaceInstance> {
const span = TraceContext.startSpan("newInstance", ctx);
try {
Expand Down Expand Up @@ -814,8 +832,10 @@ export class WorkspaceStarter {
let workspaceClass = await getWorkspaceClassForInstance(
ctx,
workspace,
previousInstance,
user,
project,
workspaceClassOverride,
this.entitlementService,
this.config.workspaceClasses,
);
Expand Down

0 comments on commit 0605514

Please sign in to comment.