From 83c505c24fbfb669b5eb13314bb560abfd91e5e5 Mon Sep 17 00:00:00 2001 From: Oleksii Orel Date: Thu, 19 Sep 2024 03:34:16 +0300 Subject: [PATCH] fix: getWorkspaceConditions method Signed-off-by: Oleksii Orel --- devfile.yaml | 16 ++--- .../WorkspaceProgress/__tests__/utils.spec.ts | 54 ++++----------- .../components/WorkspaceProgress/index.tsx | 4 +- .../src/components/WorkspaceProgress/utils.ts | 18 +++-- .../contexts/WorkspaceActions/Provider.tsx | 1 - .../devWorkspaces/__tests__/actions.spec.ts | 69 ------------------- .../store/Workspaces/devWorkspaces/index.ts | 7 -- .../store/__mocks__/devWorkspaceBuilder.ts | 8 ++- run/local-run.sh | 2 +- scripts/container_tool.sh | 8 +++ scripts/sed_in_place.sh | 23 +++++++ 11 files changed, 71 insertions(+), 139 deletions(-) create mode 100755 scripts/sed_in_place.sh diff --git a/devfile.yaml b/devfile.yaml index 4805b06f7..ec126f1dd 100644 --- a/devfile.yaml +++ b/devfile.yaml @@ -14,13 +14,13 @@ components: endpoints: - exposure: public name: local-server - protocol: http + protocol: https targetPort: 8080 path: / - exposure: public name: bundle-analyzer path: / - protocol: http + protocol: https targetPort: 8888 env: - name: KUBEDOCK_ENABLED @@ -31,7 +31,7 @@ commands: label: "[UD] install dependencies" component: tools workingDir: ${PROJECT_SOURCE} - commandLine: "yarn install --non-interactive" + commandLine: "yarn install" group: kind: build isDefault: true @@ -40,7 +40,7 @@ commands: label: "[UD] build" component: tools workingDir: ${PROJECT_SOURCE} - commandLine: "yarn install --non-interactive && yarn build" + commandLine: "yarn install && yarn build" group: kind: build - id: watchfrontend @@ -115,11 +115,3 @@ commands: commandLine: "yarn --cwd packages/dashboard-backend build --env bundleAnalyzer=true" group: kind: build - - id: install-requirements - exec: - component: tools - commandLine: "npm i yarn@1.22.18 -g" - label: Install yarn@1.22.18 -events: - postStart: - - "install-requirements" diff --git a/packages/dashboard-frontend/src/components/WorkspaceProgress/__tests__/utils.spec.ts b/packages/dashboard-frontend/src/components/WorkspaceProgress/__tests__/utils.spec.ts index 73ddf02a1..dd703eb81 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceProgress/__tests__/utils.spec.ts +++ b/packages/dashboard-frontend/src/components/WorkspaceProgress/__tests__/utils.spec.ts @@ -10,7 +10,7 @@ * Red Hat, Inc. - initial API and implementation */ -import { getStartWorkspaceConditions } from '@/components/WorkspaceProgress/utils'; +import { getWorkspaceConditions } from '@/components/WorkspaceProgress/utils'; import { DevWorkspaceBuilder } from '@/store/__mocks__/devWorkspaceBuilder'; describe('WorkspaceProgress utils', () => { @@ -20,13 +20,13 @@ describe('WorkspaceProgress utils', () => { jest.clearAllMocks(); }); - describe('getStartWorkspaceCondition', () => { + describe('getWorkspaceCondition', () => { it('should return an empty array as a default value', () => { const devWorkspace = new DevWorkspaceBuilder().build(); expect(devWorkspace.status?.conditions).toBeUndefined(); - const conditions = getStartWorkspaceConditions(devWorkspace); + const conditions = getWorkspaceConditions(devWorkspace); expect(conditions).toEqual([]); }); @@ -43,19 +43,15 @@ describe('WorkspaceProgress utils', () => { }; const devWorkspace = new DevWorkspaceBuilder().withStatus(status).build(); - const conditions = getStartWorkspaceConditions(devWorkspace); + const conditions = getWorkspaceConditions(devWorkspace); expect(conditions).toEqual(status.conditions); }); }); - it('should filter conditions that are not related to the workspace start', () => { + it('should return default value if one of conditions has special type that is shown when workspace start failed', () => { const status = { + phase: 'Starting', conditions: [ - { - message: 'DevWorkspace is starting', - status: 'True', - type: 'Started', - }, { message: 'Resolved plugins and parents from DevWorkspace', status: 'True', @@ -81,39 +77,19 @@ describe('WorkspaceProgress utils', () => { status: 'False', type: 'DeploymentReady', }, + { + message: + 'Error creating DevWorkspace deployment: Container tools has state ImagePullBackOff', + reason: 'InfrastructureFailure', + status: 'True', + type: 'FailedStart', + }, ], }; const devWorkspace = new DevWorkspaceBuilder().withStatus(status).build(); - const conditions = getStartWorkspaceConditions(devWorkspace); + const conditions = getWorkspaceConditions(devWorkspace); - expect(conditions).not.toEqual(status.conditions); - expect(conditions).toEqual([ - { - message: 'DevWorkspace is starting', - status: 'True', - type: 'Started', - }, - { - message: 'Resolved plugins and parents from DevWorkspace', - status: 'True', - type: 'DevWorkspaceResolved', - }, - { - message: 'Storage ready', - status: 'True', - type: 'StorageReady', - }, - { - message: 'Networking ready', - status: 'True', - type: 'RoutingReady', - }, - { - message: 'DevWorkspace serviceaccount ready', - status: 'True', - type: 'ServiceAccountReady', - }, - ]); + expect(conditions).toEqual([]); }); }); diff --git a/packages/dashboard-frontend/src/components/WorkspaceProgress/index.tsx b/packages/dashboard-frontend/src/components/WorkspaceProgress/index.tsx index 57bd1d178..4ac93a99f 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceProgress/index.tsx +++ b/packages/dashboard-frontend/src/components/WorkspaceProgress/index.tsx @@ -32,7 +32,7 @@ import StartingStepStartWorkspace from '@/components/WorkspaceProgress/StartingS import StartingStepWorkspaceConditions from '@/components/WorkspaceProgress/StartingSteps/WorkspaceConditions'; import { ConditionType, - getStartWorkspaceConditions, + getWorkspaceConditions, isWorkspaceStatusCondition, } from '@/components/WorkspaceProgress/utils'; import WorkspaceProgressWizard, { @@ -188,7 +188,7 @@ class Progress extends React.Component { workspace.status === DevWorkspaceStatus.FAILING || workspace.status === DevWorkspaceStatus.FAILED) ) { - const conditions = getStartWorkspaceConditions(workspace.ref); + const conditions = getWorkspaceConditions(workspace.ref); const lastScore = this.scoreConditions(this.state.conditions); const score = this.scoreConditions(conditions); diff --git a/packages/dashboard-frontend/src/components/WorkspaceProgress/utils.ts b/packages/dashboard-frontend/src/components/WorkspaceProgress/utils.ts index a085db491..36140f562 100644 --- a/packages/dashboard-frontend/src/components/WorkspaceProgress/utils.ts +++ b/packages/dashboard-frontend/src/components/WorkspaceProgress/utils.ts @@ -13,6 +13,7 @@ import { V1alpha2DevWorkspaceStatusConditions } from '@devfile/api'; import devfileApi from '@/services/devfileApi'; +import { DevWorkspaceStatus } from '@/services/helpers/types'; export type ConditionType = V1alpha2DevWorkspaceStatusConditions & { status: 'True' | 'False' | 'Unknown'; @@ -39,18 +40,23 @@ export function isConditionReady( ); } -export function getStartWorkspaceConditions( +export function getWorkspaceConditions( workspace: devfileApi.DevWorkspace, ): V1alpha2DevWorkspaceStatusConditions[] { if (!workspace.status?.conditions || workspace.status.conditions.length === 0) { return []; } + const conditions = [...workspace.status.conditions]; - // remove all conditions that are not related to the workspace start - for (let i = conditions.length; i > 0; i--) { - if (conditions[i - 1].type === 'ServiceAccountReady') { - conditions.length = i; - break; + + // if the target workspace has status starting + if (workspace.status.phase === DevWorkspaceStatus.STARTING) { + // if one of conditions has special type that is shown when workspace start failed + const failedStart = conditions.find(condition => condition.type === 'FailedStart'); + // this is a special condition that is shown when workspace start failed + if (failedStart !== undefined) { + // it means that all the conditions are from the previous start + return []; } } diff --git a/packages/dashboard-frontend/src/contexts/WorkspaceActions/Provider.tsx b/packages/dashboard-frontend/src/contexts/WorkspaceActions/Provider.tsx index 6834b15ec..8013f1b09 100644 --- a/packages/dashboard-frontend/src/contexts/WorkspaceActions/Provider.tsx +++ b/packages/dashboard-frontend/src/contexts/WorkspaceActions/Provider.tsx @@ -114,7 +114,6 @@ class WorkspaceActionsProvider extends React.Component { break; } case WorkspaceAction.START_DEBUG_AND_OPEN_LOGS: { - // todo: open a new tab with the DEBUG_WORKSPACE_START parameter instead await this.props.startWorkspace(workspace, { 'debug-workspace-start': true, }); diff --git a/packages/dashboard-frontend/src/store/Workspaces/devWorkspaces/__tests__/actions.spec.ts b/packages/dashboard-frontend/src/store/Workspaces/devWorkspaces/__tests__/actions.spec.ts index 39867c2ce..d82399c65 100644 --- a/packages/dashboard-frontend/src/store/Workspaces/devWorkspaces/__tests__/actions.spec.ts +++ b/packages/dashboard-frontend/src/store/Workspaces/devWorkspaces/__tests__/actions.spec.ts @@ -450,75 +450,6 @@ describe('DevWorkspace store, actions', () => { expect(actions).toStrictEqual(expectedActions); }); - it('should remove all workspace conditions in the store before start a DevWorkspace', async () => { - (checkRunningWorkspacesLimit as jest.Mock).mockImplementation(() => undefined); - (isRunningDevWorkspacesClusterLimitExceeded as jest.Mock).mockReturnValue( - Promise.resolve(true), - ); - - // set a condition with an error message to the devWorkspace - devWorkspace.status = { - devworkspaceId: '1234', - conditions: [ - { - type: 'Stopped', - status: 'False', - reason: 'LimitReached', - message: 'Workspace stopped due to error.', - }, - ], - }; - - const store = storeBuilder.withDevWorkspaces({ workspaces: [devWorkspace] }).build(); - - await store.dispatch(testStore.actionCreators.startWorkspace(devWorkspace)); - - const actions = store.getActions(); - - const expectedDevWorkspaceWithEmptyConditions = Object.assign({}, devWorkspace, { - status: { - devworkspaceId: '1234', - conditions: [], - }, - }); - - const expectedActions: Array< - | testStore.KnownAction - | testDevWorkspaceClusterStore.KnownAction - | ServerConfigStore.KnownAction - > = [ - { - type: testStore.Type.UPDATE_DEVWORKSPACE, - workspace: expectedDevWorkspaceWithEmptyConditions, - }, - { - type: testDevWorkspaceClusterStore.Type.REQUEST_DEVWORKSPACES_CLUSTER, - check: AUTHORIZED, - }, - { - type: testDevWorkspaceClusterStore.Type.RECEIVED_DEVWORKSPACES_CLUSTER, - isRunningDevWorkspacesClusterLimitExceeded: true, - }, - { - type: testStore.Type.REQUEST_DEVWORKSPACE, - check: AUTHORIZED, - }, - { - type: 'REQUEST_DW_SERVER_CONFIG', - }, - { - config: {} as api.IServerConfig, - type: 'RECEIVE_DW_SERVER_CONFIG', - }, - { - type: testStore.Type.UPDATE_DEVWORKSPACE, - workspace: devWorkspace, - }, - ]; - - expect(actions).toStrictEqual(expectedActions); - }); - it('should create REQUEST_DEVWORKSPACE and RECEIVE_DEVWORKSPACE_ERROR when failed to start a DevWorkspace', async () => { (checkRunningWorkspacesLimit as jest.Mock).mockImplementation(() => { throw new Error('Limit reached.'); diff --git a/packages/dashboard-frontend/src/store/Workspaces/devWorkspaces/index.ts b/packages/dashboard-frontend/src/store/Workspaces/devWorkspaces/index.ts index 71631d464..2249bf6df 100644 --- a/packages/dashboard-frontend/src/store/Workspaces/devWorkspaces/index.ts +++ b/packages/dashboard-frontend/src/store/Workspaces/devWorkspaces/index.ts @@ -311,13 +311,6 @@ export const actionCreators: ActionCreators = { console.warn(`Workspace ${_workspace.metadata.name} already started`); return; } - if (workspace.status?.conditions && workspace.status?.conditions?.length > 0) { - workspace.status.conditions = []; - dispatch({ - type: Type.UPDATE_DEVWORKSPACE, - workspace, - }); - } try { await OAuthService.refreshTokenIfProjectExists(workspace); } catch (e: unknown) { diff --git a/packages/dashboard-frontend/src/store/__mocks__/devWorkspaceBuilder.ts b/packages/dashboard-frontend/src/store/__mocks__/devWorkspaceBuilder.ts index fef836dfb..ea6e6163a 100644 --- a/packages/dashboard-frontend/src/store/__mocks__/devWorkspaceBuilder.ts +++ b/packages/dashboard-frontend/src/store/__mocks__/devWorkspaceBuilder.ts @@ -103,7 +103,7 @@ export class DevWorkspaceBuilder { withStatus(status: { conditions?: Array; - phase?: keyof typeof DevWorkspaceStatus; + phase?: keyof typeof DevWorkspaceStatus | string; devworkspaceId?: string; mainUrl?: string; message?: string; @@ -115,7 +115,11 @@ export class DevWorkspaceBuilder { this.workspace.status.conditions = Object.assign([], status.conditions); } if (status.phase) { - this.workspace.status.phase = DevWorkspaceStatus[status.phase]; + if (DevWorkspaceStatus[status.phase]) { + this.workspace.status.phase = DevWorkspaceStatus[status.phase]; + } else { + this.workspace.status.phase = status.phase; + } } if (status.devworkspaceId) { this.workspace.status.devworkspaceId = status.devworkspaceId; diff --git a/run/local-run.sh b/run/local-run.sh index 2fec7bacb..6b85f84a9 100755 --- a/run/local-run.sh +++ b/run/local-run.sh @@ -104,7 +104,7 @@ if [ ! -d $DASHBOARD_FRONTEND/lib/public/dashboard/devfile-registry ]; then -i "packages/devfile-registry/air-gap/index.json" if [ -s "$DASHBOARD_FRONTEND/lib/public/dashboard/devfile-registry/air-gap/index.json" ]; then - sed -i 's|CHE_DASHBOARD_INTERNAL_URL|http://localhost:8080|g' "$DASHBOARD_FRONTEND/lib/public/dashboard/devfile-registry/air-gap/index.json" + scripts/sed_in_place 's|CHE_DASHBOARD_INTERNAL_URL|http://localhost:8080|g' "$DASHBOARD_FRONTEND/lib/public/dashboard/devfile-registry/air-gap/index.json" fi fi diff --git a/scripts/container_tool.sh b/scripts/container_tool.sh index 6a3ff2966..5524eed4d 100755 --- a/scripts/container_tool.sh +++ b/scripts/container_tool.sh @@ -1,4 +1,12 @@ #!/bin/bash +# +# Copyright (c) 2021-2024 Red Hat, Inc. +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# # Function to check if a command is available command_exists() { diff --git a/scripts/sed_in_place.sh b/scripts/sed_in_place.sh new file mode 100755 index 000000000..a16cfeb5e --- /dev/null +++ b/scripts/sed_in_place.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# +# Copyright (c) 2021-2024 Red Hat, Inc. +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# + +set -e + +SHORT_UNAME=$(uname -s) +if [ "$(uname)" == "Darwin" ]; then + sed -i '' "$@" +elif [ "${SHORT_UNAME:0:5}" == "Linux" ]; then + sed -i "$@" +else + echo "Unknown OS" + exit 1 +fi + +exit 0