From 3112d8901224b98d14bf49c79201b4a3f280aa86 Mon Sep 17 00:00:00 2001 From: Anatolii Bazko Date: Fri, 13 Oct 2023 17:02:17 +0200 Subject: [PATCH] Revert "chore: Mount kubeconfig into users containers (#950)" This reverts commit 2c0237c0473abe4816621f80069a64f9f144ea50. --- packages/common/src/index.ts | 1 - .../src/constants/schemas.ts | 5 +- .../services/__tests__/kubeConfigApi.spec.ts | 160 +++++++++++----- .../services/kubeConfigApi.ts | 177 ++++++++++++++---- .../src/devworkspaceClient/types/index.ts | 4 +- .../routes/api/__tests__/kubeConfig.spec.ts | 5 +- .../__mocks__/getDevWorkspaceClient.ts | 2 +- .../src/routes/api/kubeConfig.ts | 6 +- .../backend-client/devWorkspaceApi.ts | 10 + .../src/services/bootstrap/index.ts | 10 - .../__mocks__/devWorkspaceSpecTemplates.ts | 12 -- .../devworkspace/devWorkspaceClient.ts | 11 +- .../devWorkspaces/__tests__/actions.spec.ts | 4 - .../store/Workspaces/devWorkspaces/index.ts | 4 +- 14 files changed, 286 insertions(+), 125 deletions(-) diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index bb93a0c53..aa868c430 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -20,7 +20,6 @@ export { helpers, api }; export const FACTORY_LINK_ATTR = 'factoryLink'; export const ERROR_CODE_ATTR = 'error_code'; -export const KUBECONFIG_MOUNT_PATH = '/tmp/.kube'; const common = { helpers, diff --git a/packages/dashboard-backend/src/constants/schemas.ts b/packages/dashboard-backend/src/constants/schemas.ts index 3064fbe44..d2e611610 100644 --- a/packages/dashboard-backend/src/constants/schemas.ts +++ b/packages/dashboard-backend/src/constants/schemas.ts @@ -29,8 +29,11 @@ export const namespacedKubeConfigSchema: JSONSchema7 = { namespace: { type: 'string', }, + devworkspaceId: { + type: 'string', + }, }, - required: ['namespace'], + required: ['namespace', 'devworkspaceId'], }; export const namespacedWorkspaceSchema: JSONSchema7 = { diff --git a/packages/dashboard-backend/src/devworkspaceClient/services/__tests__/kubeConfigApi.spec.ts b/packages/dashboard-backend/src/devworkspaceClient/services/__tests__/kubeConfigApi.spec.ts index 8b89b16ad..85cf644d9 100644 --- a/packages/dashboard-backend/src/devworkspaceClient/services/__tests__/kubeConfigApi.spec.ts +++ b/packages/dashboard-backend/src/devworkspaceClient/services/__tests__/kubeConfigApi.spec.ts @@ -13,67 +13,137 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import * as mockClient from '@kubernetes/client-node'; -import { CoreV1Api, HttpError } from '@kubernetes/client-node'; -import { IncomingMessage } from 'http'; +import { CoreV1Api, V1PodList } from '@kubernetes/client-node'; +import * as helper from '@/devworkspaceClient/services/helpers/exec'; import { KubeConfigApiService } from '@/devworkspaceClient/services/kubeConfigApi'; +const homeUserDir = '/home/user'; +const kubeConfigDir = `${homeUserDir}/.kube`; +const mockExecPrintenvHome = jest.fn().mockReturnValue({ + stdOut: homeUserDir, + stdError: '', +}); +const spyExec = jest + .spyOn(helper, 'exec') + .mockImplementation((...args: Parameters) => { + const [, , , command] = args; + if (command.some(c => c === 'printenv HOME')) { + // directory where to create the kubeconfig + return mockExecPrintenvHome(); + } else if (command.some(c => c.startsWith('mkdir -p'))) { + // crete the directory + return Promise.resolve(); + } else if (command.some(c => c.startsWith(`[ -f ${homeUserDir}`))) { + // sync config + return Promise.resolve(); + } + return Promise.reject({ + stdOut: '', + stdError: 'command executing error', + }); + }); + const namespace = 'user-che'; +const workspaceName = 'workspace-1'; +const containerName = 'container-1'; +const config = JSON.stringify({ + apiVersion: 'v1', + kind: 'Config', + 'current-context': 'logged-user', +}); describe('Kubernetes Config API Service', () => { let kubeConfigService: KubeConfigApiService; - let spyCreateNamespacedSecret: jest.SpyInstance; - let spyReadNamespacedSecret: jest.SpyInstance; - let spyReplaceNamespacedSecret: jest.SpyInstance; - - console.error = jest.fn(); - console.warn = jest.fn(); - - function initMocks(readNamespacedSecretReturnPromise: Promise): void { - const stubCoreV1Api = { - createNamespacedSecret: (_namespace: string, secret: any) => { - return Promise.resolve({ body: secret }); - }, - readNamespacedSecret: () => { - return readNamespacedSecretReturnPromise; - }, - replaceNamespacedSecret: (_name: string, _namespace: string, secret: any) => { - return Promise.resolve({ body: secret }); - }, - } as unknown as CoreV1Api; - - spyCreateNamespacedSecret = jest.spyOn(stubCoreV1Api, 'createNamespacedSecret'); - spyReadNamespacedSecret = jest.spyOn(stubCoreV1Api, 'readNamespacedSecret'); - spyReplaceNamespacedSecret = jest.spyOn(stubCoreV1Api, 'replaceNamespacedSecret'); + beforeEach(() => { const { KubeConfig } = mockClient; const kubeConfig = new KubeConfig(); - kubeConfig.makeApiClient = jest.fn().mockImplementation(_api => stubCoreV1Api); + + kubeConfig.makeApiClient = jest.fn().mockImplementation(_api => { + return { + listNamespacedPod: namespace => { + return Promise.resolve(buildListNamespacedPod()); + }, + } as CoreV1Api; + }); + kubeConfig.exportConfig = jest.fn().mockReturnValue(config); + kubeConfig.getCurrentCluster = jest.fn().mockReturnValue(''); + kubeConfig.applyToRequest = jest.fn(); kubeConfigService = new KubeConfigApiService(kubeConfig); - } + }); afterEach(() => { jest.clearAllMocks(); }); - test('create kubeconfig Secret', async () => { - initMocks(Promise.reject(new HttpError({} as IncomingMessage, undefined, 404))); - - await kubeConfigService.applyKubeConfigSecret(namespace); - - expect(spyReadNamespacedSecret).toBeCalled(); - expect(spyCreateNamespacedSecret).toBeCalled(); - expect(spyReplaceNamespacedSecret).toBeCalledTimes(0); - }); - - test('replace kubeconfig Secret', async () => { - initMocks(Promise.resolve({} as any)); - - await kubeConfigService.applyKubeConfigSecret(namespace); - - expect(spyReadNamespacedSecret).toBeCalled(); - expect(spyCreateNamespacedSecret).toBeCalledTimes(0); - expect(spyReplaceNamespacedSecret).toBeCalled(); + test('injecting kubeconfig', async () => { + // mute output + console.error = jest.fn(); + console.warn = jest.fn(); + + await kubeConfigService.injectKubeConfig(namespace, 'wksp-id'); + expect(spyExec).toHaveBeenCalledTimes(4); + + // should attempt to resolve the KUBECONFIG env variable + expect(spyExec).toHaveBeenNthCalledWith( + 1, + workspaceName, + namespace, + containerName, + ['sh', '-c', 'printenv KUBECONFIG'], + expect.anything(), + ); + + // should attempt to resolve the HOME env variable + expect(spyExec).toHaveBeenNthCalledWith( + 2, + workspaceName, + namespace, + containerName, + ['sh', '-c', 'printenv HOME'], + expect.anything(), + ); + + // should create the directory + expect(spyExec).toHaveBeenNthCalledWith( + 3, + workspaceName, + namespace, + containerName, + ['sh', '-c', `mkdir -p ${kubeConfigDir}`], + expect.anything(), + ); + + // should sync the kubeconfig to the container + expect(spyExec).toHaveBeenNthCalledWith( + 4, + workspaceName, + namespace, + containerName, + ['sh', '-c', `[ -f ${kubeConfigDir}/config ] || echo '${config}' > ${kubeConfigDir}/config`], + expect.anything(), + ); }); }); + +function buildListNamespacedPod(): { body: V1PodList } { + return { + body: { + apiVersion: 'v1', + items: [ + { + metadata: { + name: workspaceName, + namespace, + }, + spec: { + containers: [{ name: containerName }], + }, + }, + ], + kind: 'PodList', + }, + }; +} diff --git a/packages/dashboard-backend/src/devworkspaceClient/services/kubeConfigApi.ts b/packages/dashboard-backend/src/devworkspaceClient/services/kubeConfigApi.ts index 5da95f6c8..b8266c7e2 100644 --- a/packages/dashboard-backend/src/devworkspaceClient/services/kubeConfigApi.ts +++ b/packages/dashboard-backend/src/devworkspaceClient/services/kubeConfigApi.ts @@ -10,18 +10,17 @@ * Red Hat, Inc. - initial API and implementation */ -import { helpers, KUBECONFIG_MOUNT_PATH } from '@eclipse-che/common'; +import { helpers } from '@eclipse-che/common'; import * as k8s from '@kubernetes/client-node'; -import { V1Secret } from '@kubernetes/client-node'; -import { ServerConfig } from '@/devworkspaceClient/services/helpers/exec'; +import { exec, ServerConfig } from '@/devworkspaceClient/services/helpers/exec'; import { CoreV1API, prepareCoreV1API, } from '@/devworkspaceClient/services/helpers/prepareCoreV1API'; import { IKubeConfigApi } from '@/devworkspaceClient/types'; -const KUBECONFIG_SECRET_NAME = 'kubeconfig'; +const EXCLUDED_CONTAINERS = ['che-gateway', 'che-machine-exec']; export class KubeConfigApiService implements IKubeConfigApi { private readonly corev1API: CoreV1API; @@ -40,46 +39,156 @@ export class KubeConfigApiService implements IKubeConfigApi { } /** - * Creates or replaces kubeconfig Secret to be mounted into all containers in a namespace. + * Inject the kubeconfig into all containers with the given name in the namespace * @param namespace The namespace where the pod lives + * @param devworkspaceId The id of the devworkspace */ - async applyKubeConfigSecret(namespace: string): Promise { - const kubeConfig = this.setNamespaceInContext(this.kubeConfig, namespace); - const kubeConfigSecret = { - apiVersion: 'v1', - data: { config: Buffer.from(kubeConfig, 'binary').toString('base64') }, - metadata: { - name: KUBECONFIG_SECRET_NAME, - labels: { - 'controller.devfile.io/mount-to-devworkspace': 'true', - 'controller.devfile.io/watch-secret': 'true', - }, - annotations: { - 'controller.devfile.io/mount-as': 'file', - 'controller.devfile.io/mount-path': KUBECONFIG_MOUNT_PATH, - }, - }, - kind: 'Secret', - } as V1Secret; + async injectKubeConfig(namespace: string, devworkspaceId: string): Promise { + const currentPod = await this.getPodByDevWorkspaceId(namespace, devworkspaceId); + const podName = currentPod.metadata?.name || ''; + const currentPodContainers = currentPod.spec?.containers || []; + let resolved = false; + for (const container of currentPodContainers) { + const containerName = container.name; + if (EXCLUDED_CONTAINERS.indexOf(containerName) !== -1) { + continue; + } + + try { + // find the directory where we should create the kubeconfig + const kubeConfigDirectory = await this.resolveDirectory(podName, namespace, containerName); + if (kubeConfigDirectory === '') { + console.log( + `Could not find appropriate kubeconfig directory for ${namespace}/${podName}/${containerName}`, + ); + continue; + } + + // then create the directory if it doesn't exist + await exec( + podName, + namespace, + containerName, + ['sh', '-c', `mkdir -p ${kubeConfigDirectory}`], + this.getServerConfig(), + ); + + // if -f ${kubeConfigDirectory}/config is not found then sync kubeconfig to the container + const kubeConfig = this.setNamespaceInContext(this.kubeConfig, namespace); + await exec( + podName, + namespace, + containerName, + [ + 'sh', + '-c', + `[ -f ${kubeConfigDirectory}/config ] || echo '${kubeConfig}' > ${kubeConfigDirectory}/config`, + ], + this.getServerConfig(), + ); + + if (!resolved) { + resolved = true; + } + } catch (e) { + console.warn(helpers.errors.getMessage(e)); + } + } + if (!resolved) { + throw new Error(`Could not add kubeconfig into containers in ${namespace}`); + } + } + + /** + * Given a namespace, find a pod that has the label controller.devfile.io/devworkspace_id=${devworkspaceId} + * @param namespace The namespace to look in + * @param devworkspaceId The id of the devworkspace + * @returns The containers for the first pod with given devworkspaceId + */ + private async getPodByDevWorkspaceId( + namespace: string, + devworkspaceId: string, + ): Promise { try { - await this.corev1API.readNamespacedSecret(KUBECONFIG_SECRET_NAME, namespace); - await this.corev1API.replaceNamespacedSecret( - KUBECONFIG_SECRET_NAME, + const resp = await this.corev1API.listNamespacedPod( namespace, - kubeConfigSecret, + undefined, + false, + undefined, + undefined, + `controller.devfile.io/devworkspace_id=${devworkspaceId}`, ); - } catch (error) { - if (helpers.errors.isKubeClientError(error) && error.statusCode === 404) { - await this.corev1API.createNamespacedSecret(namespace, kubeConfigSecret); - return; + if (resp.body.items.length === 0) { + throw new Error( + `Could not find requested devworkspace with id ${devworkspaceId} in ${namespace}`, + ); } - - console.error('Failed to create kubeconfig Secret', error); + return resp.body.items[0]; + } catch (e: any) { throw new Error( - `Could not create ${KUBECONFIG_SECRET_NAME} Secret in ${namespace} namespace`, + `Error occurred when attempting to retrieve pod. ${helpers.errors.getMessage(e)}`, + ); + } + } + + /** + * Resolve the directory where the kubeconfig is going to live. First it looks for the $KUBECONFIG env variable if + * that is found then use that. If that is not found then the default directory is $HOME/.kube + * @param name The name of the pod + * @param namespace The namespace where the pod lives + * @param containerName The name of the container to resolve the directory for + * @returns A promise of the directory where the kubeconfig is going to live + */ + private async resolveDirectory( + name: string, + namespace: string, + containerName: string, + ): Promise { + try { + // attempt to resolve the kubeconfig env variable + const kubeConfigEnvResolver = await exec( + name, + namespace, + containerName, + ['sh', '-c', 'printenv KUBECONFIG'], + this.getServerConfig(), + ); + + if (kubeConfigEnvResolver.stdOut) { + return kubeConfigEnvResolver.stdOut.replace(new RegExp('/config$'), ''); + } + } catch (e) { + const message = helpers.errors.getMessage(e); + console.error( + `Failed to run command 'printenv KUBECONFIG' in '${namespace}/${name}/${containerName}' with message: '${message}'`, + ); + } + + try { + // attempt to resolve the home directory + const homeEnvResolution = await exec( + name, + namespace, + containerName, + ['sh', '-c', 'printenv HOME'], + this.getServerConfig(), + ); + + if (homeEnvResolution.stdOut) { + if (homeEnvResolution.stdOut.substr(-1) === '/') { + return homeEnvResolution.stdOut + '.kube'; + } else { + return homeEnvResolution.stdOut + '/.kube'; + } + } + } catch (e) { + const message = helpers.errors.getMessage(e); + console.error( + `Failed to run command 'printenv HOME' in '${namespace}/${name}/${containerName}' with message: '${message}'`, ); } + return ''; } private setNamespaceInContext(kubeConfig: string, namespace: string): string { diff --git a/packages/dashboard-backend/src/devworkspaceClient/types/index.ts b/packages/dashboard-backend/src/devworkspaceClient/types/index.ts index 00cfe9758..f0819c0df 100644 --- a/packages/dashboard-backend/src/devworkspaceClient/types/index.ts +++ b/packages/dashboard-backend/src/devworkspaceClient/types/index.ts @@ -262,9 +262,9 @@ export interface IServerConfigApi { export interface IKubeConfigApi { /** - * Creates or replaces kubeconfig Secret to be mounted into all containers in a namespace. + * Inject the kubeconfig into all containers with the given devworkspaceId in a namespace. */ - applyKubeConfigSecret(namespace: string): Promise; + injectKubeConfig(namespace: string, devworkspaceId: string): Promise; } export interface IPodmanApi { diff --git a/packages/dashboard-backend/src/routes/api/__tests__/kubeConfig.spec.ts b/packages/dashboard-backend/src/routes/api/__tests__/kubeConfig.spec.ts index 0755f80a1..c44219d34 100644 --- a/packages/dashboard-backend/src/routes/api/__tests__/kubeConfig.spec.ts +++ b/packages/dashboard-backend/src/routes/api/__tests__/kubeConfig.spec.ts @@ -30,10 +30,11 @@ describe('Kube Config Route', () => { teardown(app); }); - test('POST ${baseApiPath}/namespace/:namespace/kubeconfig', async () => { + test('POST ${baseApiPath}/namespace/:namespace/devworkspaceId/:devworkspaceId/kubeconfig', async () => { + const devworkspaceId = 'wksp-id'; const res = await app .inject() - .post(`${baseApiPath}/namespace/${namespace}/kubeconfig`) + .post(`${baseApiPath}/namespace/${namespace}/devworkspaceId/${devworkspaceId}/kubeconfig`) .payload({}); expect(res.statusCode).toEqual(204); diff --git a/packages/dashboard-backend/src/routes/api/helpers/__mocks__/getDevWorkspaceClient.ts b/packages/dashboard-backend/src/routes/api/helpers/__mocks__/getDevWorkspaceClient.ts index 350b7f20b..c7ab9dc5d 100644 --- a/packages/dashboard-backend/src/routes/api/helpers/__mocks__/getDevWorkspaceClient.ts +++ b/packages/dashboard-backend/src/routes/api/helpers/__mocks__/getDevWorkspaceClient.ts @@ -149,7 +149,7 @@ export function getDevWorkspaceClient( update: (_namespace, _dockerCfg) => Promise.resolve(stubDockerConfig), } as IDockerConfigApi, kubeConfigApi: { - applyKubeConfigSecret: _namespace => Promise.resolve(undefined), + injectKubeConfig: (_namespace, _devworkspaceId) => Promise.resolve(undefined), } as IKubeConfigApi, devWorkspaceTemplateApi: { create: _template => Promise.resolve(stubDevWorkspaceTemplate), diff --git a/packages/dashboard-backend/src/routes/api/kubeConfig.ts b/packages/dashboard-backend/src/routes/api/kubeConfig.ts index c91c61761..0b846f7f6 100644 --- a/packages/dashboard-backend/src/routes/api/kubeConfig.ts +++ b/packages/dashboard-backend/src/routes/api/kubeConfig.ts @@ -24,7 +24,7 @@ const tags = ['Kube Config']; export function registerKubeConfigRoute(instance: FastifyInstance) { instance.register(async server => { server.post( - `${baseApiPath}/namespace/:namespace/kubeconfig`, + `${baseApiPath}/namespace/:namespace/devworkspaceId/:devworkspaceId/kubeconfig`, getSchema({ tags, params: namespacedKubeConfigSchema, @@ -38,8 +38,8 @@ export function registerKubeConfigRoute(instance: FastifyInstance) { async function (request: FastifyRequest, reply: FastifyReply) { const token = getToken(request); const { kubeConfigApi } = getDevWorkspaceClient(token); - const { namespace } = request.params as restParams.INamespacedPodParams; - await kubeConfigApi.applyKubeConfigSecret(namespace); + const { namespace, devworkspaceId } = request.params as restParams.INamespacedPodParams; + await kubeConfigApi.injectKubeConfig(namespace, devworkspaceId); reply.code(204); return reply.send(); }, diff --git a/packages/dashboard-frontend/src/services/backend-client/devWorkspaceApi.ts b/packages/dashboard-frontend/src/services/backend-client/devWorkspaceApi.ts index 4c0c5f054..5de88fff9 100644 --- a/packages/dashboard-frontend/src/services/backend-client/devWorkspaceApi.ts +++ b/packages/dashboard-frontend/src/services/backend-client/devWorkspaceApi.ts @@ -123,6 +123,16 @@ export async function putDockerConfig( } } +export async function injectKubeConfig(namespace: string, devworkspaceId: string): Promise { + try { + await AxiosWrapper.createToRetryMissedBearerTokenError().post( + `${dashboardBackendPrefix}/namespace/${namespace}/devworkspaceId/${devworkspaceId}/kubeconfig`, + ); + } catch (e) { + throw new Error(`Failed to inject kubeconfig. ${helpers.errors.getMessage(e)}`); + } +} + export async function podmanLogin(namespace: string, devworkspaceId: string): Promise { try { await AxiosWrapper.createToRetryMissedBearerTokenError().post( diff --git a/packages/dashboard-frontend/src/services/bootstrap/index.ts b/packages/dashboard-frontend/src/services/bootstrap/index.ts index c9351abd7..e8ee3b276 100644 --- a/packages/dashboard-frontend/src/services/bootstrap/index.ts +++ b/packages/dashboard-frontend/src/services/bootstrap/index.ts @@ -14,8 +14,6 @@ import common, { api, ApplicationId } from '@eclipse-che/common'; import { Store } from 'redux'; import { lazyInject } from '@/inversify.config'; -import { AxiosWrapper } from '@/services/backend-client/axiosWrapper'; -import { dashboardBackendPrefix } from '@/services/backend-client/const'; import { WebsocketClient } from '@/services/backend-client/websocketClient'; import { ChannelListener } from '@/services/backend-client/websocketClient/messageHandler'; import { @@ -115,7 +113,6 @@ export default class Bootstrap { this.watchWebSocketPods(); }), this.fetchClusterConfig(), - this.createKubeConfigSecret(), ]); const errors = results @@ -257,13 +254,6 @@ export default class Bootstrap { }); } - private async createKubeConfigSecret(): Promise { - const defaultKubernetesNamespace = selectDefaultNamespace(this.store.getState()); - await AxiosWrapper.createToRetryMissedBearerTokenError().post( - `${dashboardBackendPrefix}/namespace/${defaultKubernetesNamespace.name}/kubeconfig`, - ); - } - private async fetchWorkspaces(): Promise { const { requestWorkspaces } = WorkspacesStore.actionCreators; await requestWorkspaces()(this.store.dispatch, this.store.getState, undefined); diff --git a/packages/dashboard-frontend/src/services/workspace-client/devworkspace/__tests__/__mocks__/devWorkspaceSpecTemplates.ts b/packages/dashboard-frontend/src/services/workspace-client/devworkspace/__tests__/__mocks__/devWorkspaceSpecTemplates.ts index f6c2f4827..a4528bda2 100644 --- a/packages/dashboard-frontend/src/services/workspace-client/devworkspace/__tests__/__mocks__/devWorkspaceSpecTemplates.ts +++ b/packages/dashboard-frontend/src/services/workspace-client/devworkspace/__tests__/__mocks__/devWorkspaceSpecTemplates.ts @@ -44,10 +44,6 @@ const getDevWorkspaceTemplate = (cpuLimit = '1500m') => name: 'CHE_DASHBOARD_URL', value: 'http://localhost', }, - { - name: 'KUBECONFIG', - value: '/tmp/.kube/config', - }, { name: 'CHE_PLUGIN_REGISTRY_URL', value: 'plugin-registry-url', @@ -87,10 +83,6 @@ const getDevWorkspaceTemplate = (cpuLimit = '1500m') => name: 'CHE_DASHBOARD_URL', value: 'http://localhost', }, - { - name: 'KUBECONFIG', - value: '/tmp/.kube/config', - }, { name: 'CHE_PLUGIN_REGISTRY_URL', value: 'plugin-registry-url', @@ -120,10 +112,6 @@ const getDevWorkspaceTemplate = (cpuLimit = '1500m') => name: 'CHE_DASHBOARD_URL', value: 'http://localhost', }, - { - name: 'KUBECONFIG', - value: '/tmp/.kube/config', - }, { name: 'CHE_PLUGIN_REGISTRY_URL', value: 'plugin-registry-url', diff --git a/packages/dashboard-frontend/src/services/workspace-client/devworkspace/devWorkspaceClient.ts b/packages/dashboard-frontend/src/services/workspace-client/devworkspace/devWorkspaceClient.ts index 0adcb9257..006217322 100644 --- a/packages/dashboard-frontend/src/services/workspace-client/devworkspace/devWorkspaceClient.ts +++ b/packages/dashboard-frontend/src/services/workspace-client/devworkspace/devWorkspaceClient.ts @@ -16,7 +16,7 @@ import { V1alpha2DevWorkspaceTemplateSpecComponents, V221DevfileComponentsItemsContainer, } from '@devfile/api'; -import { api, KUBECONFIG_MOUNT_PATH } from '@eclipse-che/common'; +import { api } from '@eclipse-che/common'; import { inject, injectable } from 'inversify'; import { load } from 'js-yaml'; import { cloneDeep, isEqual } from 'lodash'; @@ -85,7 +85,6 @@ export class DevWorkspaceClient { private readonly clusterConsoleTitleEnvName: string; private readonly openVSXUrlEnvName: string; private readonly dashboardUrlEnvName: string; - private readonly kubeconfigEnvName: string; private readonly defaultPluginsHandler: DevWorkspaceDefaultPluginsHandler; constructor( @@ -99,7 +98,6 @@ export class DevWorkspaceClient { this.dashboardUrlEnvName = 'CHE_DASHBOARD_URL'; this.clusterConsoleUrlEnvName = 'CLUSTER_CONSOLE_URL'; this.clusterConsoleTitleEnvName = 'CLUSTER_CONSOLE_TITLE'; - this.kubeconfigEnvName = 'KUBECONFIG'; this.defaultPluginsHandler = defaultPluginsHandler; } @@ -267,17 +265,12 @@ export class DevWorkspaceClient { env.name !== this.pluginRegistryInternalUrlEnvName && env.name !== this.clusterConsoleUrlEnvName && env.name !== this.clusterConsoleTitleEnvName && - env.name !== this.openVSXUrlEnvName && - env.name !== this.kubeconfigEnvName, + env.name !== this.openVSXUrlEnvName, ); envs.push({ name: this.dashboardUrlEnvName, value: dashboardUrl, }); - envs.push({ - name: this.kubeconfigEnvName, - value: `${KUBECONFIG_MOUNT_PATH}/config`, - }); if (pluginRegistryUrl !== undefined) { envs.push({ name: this.pluginRegistryUrlEnvName, 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 75d6b30cd..9a3f884cc 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 @@ -538,10 +538,6 @@ describe('DevWorkspace store, actions', () => { name: 'CHE_DASHBOARD_URL', value: 'http://localhost', }, - { - name: 'KUBECONFIG', - value: '/tmp/.kube/config', - }, { name: 'CHE_PLUGIN_REGISTRY_URL', value: 'https://dummy.registry', diff --git a/packages/dashboard-frontend/src/store/Workspaces/devWorkspaces/index.ts b/packages/dashboard-frontend/src/store/Workspaces/devWorkspaces/index.ts index af08a2d85..adb624cc5 100644 --- a/packages/dashboard-frontend/src/store/Workspaces/devWorkspaces/index.ts +++ b/packages/dashboard-frontend/src/store/Workspaces/devWorkspaces/index.ts @@ -15,7 +15,7 @@ import { dump } from 'js-yaml'; import { Action, Reducer } from 'redux'; import { container } from '@/inversify.config'; -import { podmanLogin } from '@/services/backend-client/devWorkspaceApi'; +import { injectKubeConfig, podmanLogin } from '@/services/backend-client/devWorkspaceApi'; import * as DwApi from '@/services/backend-client/devWorkspaceApi'; import { fetchResources } from '@/services/backend-client/devworkspaceResourcesApi'; import * as DwtApi from '@/services/backend-client/devWorkspaceTemplateApi'; @@ -1015,6 +1015,8 @@ export const actionCreators: ActionCreators = { devworkspaceId !== undefined ) { try { + // inject the kube config + await injectKubeConfig(workspace.metadata.namespace, devworkspaceId); // inject the 'podman login' await podmanLogin(workspace.metadata.namespace, devworkspaceId); } catch (e) {