Skip to content

Commit

Permalink
Add support for risk-averse users
Browse files Browse the repository at this point in the history
  • Loading branch information
csweichel committed Jul 14, 2022
1 parent ff507c2 commit 1795acd
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 25 deletions.
1 change: 1 addition & 0 deletions components/gitpod-protocol/src/permission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const Permissions = {
"admin-api": undefined,
"ide-settings": undefined,
"new-workspace-cluster": undefined,
"mature-workspace-cluster": undefined,
};
export type PermissionName = keyof typeof Permissions;
export const Roles = { devops: undefined, viewer: undefined, admin: undefined };
Expand Down
4 changes: 2 additions & 2 deletions components/ws-manager-api/typescript/src/client-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
WorkspaceManagerClientProviderCompositeSource,
WorkspaceManagerClientProviderSource,
} from "./client-provider-source";
import { ExtendedUser, workspaceClusterSetsAuthorized } from "./constraints";
import { ExtendedUser, workspaceClusterSets } from "./constraints";
import { WorkspaceManagerClient } from "./core_grpc_pb";
import { linearBackoffStrategy, PromisifiedWorkspaceManagerClient } from "./promisified-client";

Expand Down Expand Up @@ -56,7 +56,7 @@ export class WorkspaceManagerClientProvider implements Disposable {
const allClusters = await this.source.getAllWorkspaceClusters();
const availableClusters = allClusters.filter((c) => c.score > 0 && c.state === "available");

const sets = workspaceClusterSetsAuthorized
const sets = workspaceClusterSets
.map((constraints) => {
const r = constraints.constraint(availableClusters, user, workspace, instance);
if (!r) {
Expand Down
86 changes: 63 additions & 23 deletions components/ws-manager-api/typescript/src/constraints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
*/

import { PermissionName, RolesOrPermissions, User, Workspace, WorkspaceInstance } from "@gitpod/gitpod-protocol";
import { AdmissionConstraint, WorkspaceClusterWoTLS } from "@gitpod/gitpod-protocol/lib/workspace-cluster";
import {
AdmissionConstraint,
ClusterMaturityLevel,
WorkspaceClusterWoTLS,
} from "@gitpod/gitpod-protocol/lib/workspace-cluster";

/**
* ExtendedUser adds additional attributes to a user which are helpful
Expand All @@ -22,28 +26,37 @@ export interface WorkspaceClusterConstraintSet {
* workspaceClusterSets defines an order of preference in which we'll select
* workspace cluster when starting a workspace.
*/
const workspaceClusterSets: WorkspaceClusterConstraintSet[] = [
{
name: "new workspace cluster",
constraint: constraintHasPermissions("new-workspace-cluster"),
},
{
name: "regional",
constraint: intersect(constraintRegional),
},
{
name: "non-regional",
constraint: intersect(invert(constraintRegional)),
},
];

/**
* workspaceClusterSetsAuthorized applies the constraint "is user authorized" to all workspaceClusterSets
*/
export const workspaceClusterSetsAuthorized = workspaceClusterSets.map((set) => ({
...set,
constraint: intersect(set.constraint, constraintUserIsAuthorized),
}));
export const workspaceClusterSets: WorkspaceClusterConstraintSet[] = multiply(
[
{
name: "new workspace cluster",
constraint: constraintHasPermissions("new-workspace-cluster"),
},
{
name: "higly mature",
constraint: intersect(
userConstraintHasPermission("mature-workspace-cluster"),
constraintMaturityLevelClustersOnly("high"),
),
},
{
name: "regional",
constraint: constraintRegional,
},
{
name: "non-regional",
constraint: invert(constraintRegional),
},
],
constraintUserIsAuthorized,
);

function multiply(s: WorkspaceClusterConstraintSet[], ...constraints: Constraint[]): WorkspaceClusterConstraintSet[] {
return s.map((set) => ({
...set,
constraint: intersect(set.constraint, ...constraints),
}));
}

export type Constraint = (
all: WorkspaceClusterWoTLS[],
Expand Down Expand Up @@ -78,6 +91,12 @@ function hasPermissionConstraint(cluster: WorkspaceClusterWoTLS, permission: Per
);
}

function hasMaturityLevel(cluster: WorkspaceClusterWoTLS, level: ClusterMaturityLevel): boolean {
return !!cluster.admissionConstraints?.find(
(constraint) => constraint.type === "has-maturity-level" && constraint.level === level,
);
}

/**
* The returned Constraint _filters out_ all clusters that require _any_ of the given permissions
* @param permissions
Expand All @@ -100,6 +119,27 @@ export function constraintHasPermissions(...permissions: PermissionName[]): Cons
};
}

/**
* The returned Constraint returns all clusters that have exactly the given maturity level
* @param level
* @returns
*/
export function constraintMaturityLevelClustersOnly(level: ClusterMaturityLevel): Constraint {
return (all: WorkspaceClusterWoTLS[], user: ExtendedUser, workspace: Workspace, instance: WorkspaceInstance) => {
return all.filter((cluster) => hasMaturityLevel(cluster, level));
};
}

function userConstraintHasPermission(permission: PermissionName): Constraint {
return (all: WorkspaceClusterWoTLS[], user: ExtendedUser, workspace: Workspace, instance: WorkspaceInstance) => {
if (user.rolesOrPermissions?.includes(permission)) {
return all;
}

return [];
};
}

export function constraintRegional(
all: WorkspaceClusterWoTLS[],
user: ExtendedUser,
Expand Down

0 comments on commit 1795acd

Please sign in to comment.