Skip to content

Commit

Permalink
feat: add external attributes to workspaces
Browse files Browse the repository at this point in the history
Allows for injecting storage-type and external config attributes into devworkspaces

Signed-off-by: Andrew Obuchowicz <[email protected]>
  • Loading branch information
AObuchow committed Sep 19, 2022
1 parent e440a14 commit bcf9e4f
Show file tree
Hide file tree
Showing 12 changed files with 129 additions and 33 deletions.
16 changes: 16 additions & 0 deletions packages/common/src/dto/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
* Red Hat, Inc. - initial API and implementation
*/

import { V220DevfileComponents } from '@devfile/api';

export interface IPatch {
op: string;
path: string;
Expand All @@ -25,3 +27,17 @@ export interface IWorkspacesDefaultPlugins {
editor: string;
plugins: string[];
}

export interface IServerConfig {
defaults: {
editor: string | undefined;
components: V220DevfileComponents[];
plugins: IWorkspacesDefaultPlugins[];
pvcStrategy: string | undefined;
};
timeouts: {
inactivityTimeout: number;
runTimeout: number;
};
cheNamespace: string;
}
10 changes: 9 additions & 1 deletion packages/dashboard-backend/src/api/serverConfigApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { baseApiPath } from '../constants/config';
import { getDevWorkspaceClient, getServiceAccountToken } from './helper';
import { getSchema } from '../services/helpers';

const CHECLUSTER_CR_NAMESPACE = process.env.CHECLUSTER_CR_NAMESPACE as string;

const tags = ['Server Config'];

export function registerServerConfigApi(server: FastifyInstance) {
Expand All @@ -28,16 +30,22 @@ export function registerServerConfigApi(server: FastifyInstance) {
const components = serverConfigApi.getDefaultComponents(cheCustomResource);
const inactivityTimeout = serverConfigApi.getWorkspaceInactivityTimeout(cheCustomResource);
const runTimeout = serverConfigApi.getWorkspaceRunTimeout(cheCustomResource);
return {
const pvcStrategy = serverConfigApi.getPvcStrategy(cheCustomResource);
const serverConfig: api.IServerConfig = {

defaults: {
editor,
plugins,
components,
pvcStrategy,
},
timeouts: {
inactivityTimeout,
runTimeout,
},
pluginRegistry: {
openVSXURL,
},
};
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ export class ServerConfigApi implements IServerConfigApi {
return cheCustomResource.spec.server.workspaceDefaultComponents || [];
}

getPvcStrategy(cheCustomResource: { [key: string]: any }): string | undefined {
return cheCustomResource.spec.devEnvironments.storage.pvcStrategy;
}

getDashboardWarning(cheCustomResource: { [key: string]: any }): string | undefined {
return cheCustomResource.spec.dashboard?.warning;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,13 @@ export interface IServerConfigApi {
* These default components are meant to be used when a Devfile does not contain any components.
*/
getDefaultComponents(cheCustomResource: { [key: string]: any }): V220DevfileComponents[];

/**
* Returns the PVC strategy if it is defined.
*/
getPvcStrategy(cheCustomResource: { [key: string]: any }): string | undefined;
/**
* Returns a maintenance warning
* Returns a maintenance warning.
*/
getDashboardWarning(cheCustomResource: { [key: string]: any }): string | undefined;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,12 @@ import { V220DevfileComponents } from '@devfile/api';
* default plug-ins for the specified editor,
* default editor and default components
*/
export async function getServerConfig(): Promise<{
defaults: {
plugins: api.IWorkspacesDefaultPlugins[];
components: V220DevfileComponents[];
editor: string | undefined;
};
timeouts: {
inactivityTimeout: number;
runTimeout: number;
};
}> {
export async function getServerConfig(): Promise<api.IServerConfig> {
const url = `${prefix}/server-config`;
try {
const response = await axios.get(url);
return response.data ? response.data : [];
} catch (e) {
throw `Failed to fetch default plugins. ${common.helpers.errors.getMessage(e)}`;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ export const DEVWORKSPACE_NEXT_START_ANNOTATION = 'che.eclipse.org/next-start-cf

export const DEVWORKSPACE_DEBUG_START_ANNOTATION = 'controller.devfile.io/debug-start';

export const DEVWORKSPACE_CONFIG_ANNOTATION = 'controller.devfile.io/devworkspace-config';

export const DEVWORKSPACE_STORAGE_TYPE = 'controller.devfile.io/storage-type';

export const DEVWORKSPACE_DEVFILE_SOURCE = 'che.eclipse.org/devfile-source';

export const DEVWORKSPACE_METADATA_ANNOTATION = 'dw.metadata.annotations';
Expand Down Expand Up @@ -721,6 +725,70 @@ export class DevWorkspaceClient extends WorkspaceClient {
return workspace.metadata.annotations?.[DEVWORKSPACE_DEBUG_START_ANNOTATION] === 'true';
}

async updateConfigData(
workspace: devfileApi.DevWorkspace,
config: api.IServerConfig,
): Promise<devfileApi.DevWorkspace> {
const patch: api.IPatch[] = [];

const cheNamespace = config.cheNamespace;
if (cheNamespace) {
const devworkspaceConfig = { name: 'devworkspace-config', namespace: cheNamespace };
const devworkspaceConfigPath = `/spec/template/attributes/${this.escape(
DEVWORKSPACE_CONFIG_ANNOTATION,
)}`;
if (workspace.spec.template.attributes) {
if (workspace.spec.template.attributes[DEVWORKSPACE_CONFIG_ANNOTATION]) {
if (
workspace.spec.template.attributes[DEVWORKSPACE_CONFIG_ANNOTATION] !==
devworkspaceConfig
) {
patch.push({ op: 'replace', path: devworkspaceConfigPath, value: devworkspaceConfig });
}
} else {
patch.push({ op: 'add', path: devworkspaceConfigPath, value: devworkspaceConfig });
}
} else {
patch.push({
op: 'add',
path: '/spec/template/attributes',
value: { 'controller.devfile.io/devworkspace-config': devworkspaceConfig },
});
}
}

const currentPvcStrategy = config.defaults.pvcStrategy;
if (currentPvcStrategy) {
const devworkspaceStorageTypePath = `/spec/template/attributes/${this.escape(
DEVWORKSPACE_STORAGE_TYPE,
)}`;

if (workspace.spec.template.attributes) {
if (workspace.spec.template.attributes[DEVWORKSPACE_STORAGE_TYPE] !== currentPvcStrategy) {
patch.push({
op: 'replace',
path: devworkspaceStorageTypePath,
value: currentPvcStrategy,
});
} else {
patch.push({ op: 'add', path: devworkspaceStorageTypePath, value: currentPvcStrategy });
}
} else {
patch.push({
op: 'add',
path: '/spec/template/attributes',
value: { 'controller.devfile.io/storage-type': currentPvcStrategy },
});
}
}

if (patch.length === 0) {
return workspace;
}

return await DwApi.patchWorkspace(workspace.metadata.namespace, workspace.metadata.name, patch);
}

async updateDebugMode(
workspace: devfileApi.DevWorkspace,
debugMode: boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,11 +316,13 @@ describe('dwPlugins store', () => {
plugins: ['https://test.com/devfile.yaml'],
},
],
pvcStrategy: 'per-workspace',
},
timeouts: {
inactivityTimeout: -1,
runTimeout: -1,
},
cheNamespace: 'eclipse-che',
})
.build() as MockStoreEnhanced<
AppState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,13 @@ describe('dwPlugins store', () => {
plugins: ['https://test.com/devfile.yaml'],
},
],
pvcStrategy: 'per-workspace',
},
timeouts: {
inactivityTimeout: -1,
runTimeout: -1,
},
cheNamespace: 'eclipse-che',
},
});

Expand Down Expand Up @@ -85,11 +87,13 @@ describe('dwPlugins store', () => {
plugins: ['https://test.com/devfile.yaml'],
},
],
pvcStrategy: 'per-workspace',
},
timeouts: {
inactivityTimeout: -1,
runTimeout: -1,
},
cheNamespace: 'eclipse-che',
},
},
];
Expand Down
19 changes: 4 additions & 15 deletions packages/dashboard-frontend/src/store/ServerConfig/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,10 @@ import common, { api } from '@eclipse-che/common';
import { AppThunk } from '../';
import { createObject } from '../helpers';
import * as ServerConfigApi from '../../services/dashboard-backend-client/serverConfigApi';
import { V220DevfileComponents } from '@devfile/api';

export interface ServerConfig {
defaults: {
editor: string | undefined;
components: V220DevfileComponents[];
plugins: api.IWorkspacesDefaultPlugins[];
};
timeouts: {
inactivityTimeout: number;
runTimeout: number;
};
}

export interface State {
isLoading: boolean;
config: ServerConfig;
config: api.IServerConfig;
error?: string;
}

Expand All @@ -41,7 +28,7 @@ export interface RequestDwServerConfigAction {

export interface ReceiveDwServerConfigAction {
type: 'RECEIVE_DW_SERVER_CONFIG';
config: ServerConfig;
config: api.IServerConfig;
}

export interface ReceiveDwServerConfigErrorAction {
Expand Down Expand Up @@ -88,11 +75,13 @@ const unloadedState: State = {
editor: undefined,
components: [],
plugins: [],
pvcStrategy: '',
},
timeouts: {
inactivityTimeout: -1,
runTimeout: -1,
},
cheNamespace: '',
},
error: undefined,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,8 @@ export const selectDefaultPlugins = createSelector(
state => state.config.defaults?.plugins || [],
);

export const selectPvcStrategy = createSelector(
selectState,
state => state.config.defaults.pvcStrategy,
);
export const selectServerConfigError = createSelector(selectState, state => state.error);
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { injectKubeConfig } from '../../../services/dashboard-backend-client/dev
import { selectRunningWorkspacesLimit } from '../../ClusterConfig/selectors';
import { cloneDeep } from 'lodash';
import { delay } from '../../../services/helpers/delay';
import * as DwServerConfigStore from '../../ServerConfig';

const devWorkspaceClient = container.get(DevWorkspaceClient);

Expand Down Expand Up @@ -292,6 +293,9 @@ export const actionCreators: ActionCreators = {
throw new Error('You are not allowed to start more workspaces.');
}
await devWorkspaceClient.updateDebugMode(workspace, debugWorkspace);
await dispatch(DwServerConfigStore.actionCreators.requestServerConfig());
const config = getState().dwServerConfig.config;
await devWorkspaceClient.updateConfigData(workspace, config);
let updatedWorkspace: devfileApi.DevWorkspace;
const workspaceUID = workspace.metadata.uid;
dispatch({
Expand Down
10 changes: 6 additions & 4 deletions packages/dashboard-frontend/src/store/__mocks__/storeBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ import { State as UserState } from '../User';
import { State as UserProfileState } from '../UserProfile';
import mockThunk from './thunk';
import devfileApi from '../../services/devfileApi';
import { ClusterConfig, ClusterInfo } from '@eclipse-che/common';
import { api as dashboardBackendApi, ClusterConfig, ClusterInfo } from '@eclipse-che/common';
import { WorkspacesLogs } from '../../services/helpers/types';
import { ServerConfig } from '../ServerConfig';


export class FakeStoreBuilder {
private state: AppState = {
Expand All @@ -47,12 +47,14 @@ export class FakeStoreBuilder {
editor: undefined,
components: [],
plugins: [],
pvcStrategy: '',
},
timeouts: {
inactivityTimeout: -1,
runTimeout: -1,
},
} as ServerConfig,
cheNamespace: '',
} as dashboardBackendApi.IServerConfig,
},
clusterInfo: {
isLoading: false,
Expand Down Expand Up @@ -135,7 +137,7 @@ export class FakeStoreBuilder {
},
};

public withDwServerConfig(config: ServerConfig): FakeStoreBuilder {
public withDwServerConfig(config: dashboardBackendApi.IServerConfig): FakeStoreBuilder {
this.state.dwServerConfig = {
isLoading: false,
config,
Expand Down

0 comments on commit bcf9e4f

Please sign in to comment.