Skip to content

Commit

Permalink
Merge pull request #1306 from kubeshop/olelensmar/fix/pass-env-to-kub…
Browse files Browse the repository at this point in the history
…eclient-exec-auth

fix: ensured passing of main process env to kubeclient exec authenticator
  • Loading branch information
olensmar authored Feb 7, 2022
2 parents 67b79ce + dc0381b commit aec0290
Show file tree
Hide file tree
Showing 13 changed files with 115 additions and 62 deletions.
5 changes: 2 additions & 3 deletions electron/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ ipcMain.on('get-user-home-dir', event => {
event.returnValue = userHomeDir;
});


ipcMain.on(DOWNLOAD_PLUGIN, async (event, pluginUrl: string) => {
try {
const pluginExtension = await downloadPlugin(pluginUrl, pluginsDir);
Expand Down Expand Up @@ -344,7 +343,8 @@ export const createWindow = (givenPath?: string) => {
};
dispatchToWindow(win, setAlert(alert));
}
win.webContents.send('executed-from', {path: givenPath});
win.webContents.send('executed-from', {path: givenPath });
win.webContents.send('set-main-process-env', {mainProcessEnv: PROCESS_ENV });

const pluginMap = await loadPluginMap(pluginsDir);
const uniquePluginNames = Object.values(pluginMap).map((plugin) => `${plugin.repository.owner}-${plugin.repository.name}`);
Expand All @@ -365,7 +365,6 @@ export const createWindow = (givenPath?: string) => {
dispatch(setTemplatePackMap(templatePackMap));
dispatch(setTemplateMap(templateMap));
convertRecentFilesToRecentProjects(dispatch);

});

return win;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
},
"dependencies": {
"@ant-design/icons": "4.7.0",
"@kubernetes/client-node": "0.16.1",
"@kubernetes/client-node": "0.16.2",
"@reduxjs/toolkit": "1.7.1",
"@rjsf/antd": "3.2.1",
"@rjsf/core": "3.2.1",
Expand Down
13 changes: 13 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import FileExplorer from '@components/atoms/FileExplorer';

import {useFileExplorer} from '@hooks/useFileExplorer';

import {setMainProcessEnv} from '@utils/env';
import {getFileStats} from '@utils/files';
import {useWindowSize} from '@utils/hooks';

Expand Down Expand Up @@ -152,6 +153,18 @@ const App = () => {
};
}, [onOpenProjectFolderFromMainThread]);

const onSetMainProcessEnv = useCallback((_: any, args: any) => {
setMainProcessEnv(args.mainProcessEnv);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
ipcRenderer.on('set-main-process-env', onSetMainProcessEnv);
return () => {
ipcRenderer.removeListener('set-main-process-env', onSetMainProcessEnv);
};
}, [onSetMainProcessEnv]);

useDebounce(
() => {
loadContexts(kubeConfigPath, dispatch, kubeConfigContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {kubeConfigContextSelector, kubeConfigPathSelector} from '@redux/selector

import {useTargetClusterNamespaces} from '@hooks/useTargetClusterNamespaces';

import {createKubeClient} from '@utils/kubeclient';
import {getDefaultNamespaceForApply} from '@utils/resources';

import Colors from '@styles/Colors';
Expand Down Expand Up @@ -60,6 +61,7 @@ const ModalConfirmWithNamespaceSelect: React.FC<IProps> = props => {
const kubeConfigPath = useAppSelector(kubeConfigPathSelector);
const kubeConfigContext = useAppSelector(kubeConfigContextSelector);

const configState = useAppSelector(state => state.config);
const {defaultNamespace, defaultOption} = getDefaultNamespaceForApply(resources);
const [namespaces] = useTargetClusterNamespaces();

Expand All @@ -74,10 +76,8 @@ const ModalConfirmWithNamespaceSelect: React.FC<IProps> = props => {
setErrorMessage('Namespace name must not be empty!');
return;
}
const kc = new k8s.KubeConfig();
kc.loadFromFile(kubeConfigPath);
kc.setCurrentContext(kubeConfigContext);

const kc = createKubeClient(configState);
const k8sCoreV1Api = kc.makeApiClient(k8s.CoreV1Api);

k8sCoreV1Api
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import * as k8s from '@kubernetes/client-node';

import {LegacyRef, useEffect, useMemo, useState} from 'react';
import {MonacoDiffEditor} from 'react-monaco-editor';
import {ResizableBox} from 'react-resizable';
Expand All @@ -26,6 +24,7 @@ import Icon from '@components/atoms/Icon';
import ModalConfirmWithNamespaceSelect from '@components/molecules/ModalConfirmWithNamespaceSelect';

import {useWindowSize} from '@utils/hooks';
import {createKubeClient} from '@utils/kubeclient';
import {KUBESHOP_MONACO_THEME} from '@utils/monaco';
import {removeIgnoredPathsFromResourceContent} from '@utils/resources';

Expand Down Expand Up @@ -61,6 +60,7 @@ const DiffModal = () => {
const [shouldDiffIgnorePaths, setShouldDiffIgnorePaths] = useState<boolean>(true);
const [selectedMatchingResourceId, setSelectedMathingResourceId] = useState<string>();
const [targetResourceText, setTargetResourceText] = useState<string>();
const configState = useAppSelector(state => state.config);

const windowSize = useWindowSize();

Expand Down Expand Up @@ -186,9 +186,7 @@ const DiffModal = () => {
}

const getClusterResources = async () => {
const kc = new k8s.KubeConfig();
kc.loadFromFile(kubeConfigPath);
kc.setCurrentContext(kubeConfigContext);
const kc = createKubeClient(configState);

const resourceKindHandler = getResourceKindHandler(targetResource.kind);
const resourcesFromCluster =
Expand Down
7 changes: 3 additions & 4 deletions src/redux/reducers/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {setRootFolder} from '@redux/thunks/setRootFolder';

import electronStore from '@utils/electronStore';
import {getFileStats, getFileTimestamp} from '@utils/files';
import {createKubeClient} from '@utils/kubeclient';
import {makeResourceNameKindNamespaceIdentifier} from '@utils/resources';

import {getKnownResourceKinds, getResourceKindHandler} from '@src/kindhandlers';
Expand Down Expand Up @@ -437,13 +438,11 @@ export const mainSlice = createSlice({
}
if (state.previewType === 'cluster' && state.previewKubeConfigPath && state.previewKubeConfigContext) {
try {
const kubeConfig = new k8s.KubeConfig();
kubeConfig.loadFromFile(state.previewKubeConfigPath);
kubeConfig.setCurrentContext(state.previewKubeConfigContext);
const kubeClient = createKubeClient(state.previewKubeConfigPath, state.previewKubeConfigContext);

const kindHandler = getResourceKindHandler(resource.kind);
if (kindHandler?.deleteResourceInCluster) {
kindHandler.deleteResourceInCluster(kubeConfig, resource);
kindHandler.deleteResourceInCluster(kubeClient, resource);
deleteResource(resource, state.resourceMap);
}
} catch (err) {
Expand Down
8 changes: 2 additions & 6 deletions src/redux/services/getClusterObjects.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import * as k8s from '@kubernetes/client-node';
import {KubeConfig} from '@kubernetes/client-node';

import {getK8sObjectsAsYaml} from '@redux/thunks/utils';

import {getRegisteredKindHandlers} from '@src/kindhandlers';

const getClusterObjects = (configPath: string, currentContext: string) => {
const kc = new k8s.KubeConfig();
kc.loadFromFile(configPath);
kc.setCurrentContext(currentContext);

const getClusterObjects = async (kc: KubeConfig) => {
return Promise.allSettled(
getRegisteredKindHandlers().map(resourceKindHandler =>
resourceKindHandler
Expand Down
10 changes: 3 additions & 7 deletions src/redux/services/resource.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import * as k8s from '@kubernetes/client-node';

import fs from 'fs';
import log from 'loglevel';
import path from 'path';
Expand All @@ -23,6 +21,7 @@ import {isKustomizationPatch, isKustomizationResource, processKustomizations} fr
import {clearRefNodesCache, isUnsatisfiedRef, refMapperMatchesKind} from '@redux/services/resourceRefs';

import {getFileTimestamp} from '@utils/files';
import {createKubeClient} from '@utils/kubeclient';

import {
getDependentResourceKinds,
Expand Down Expand Up @@ -274,11 +273,8 @@ export function getNamespaces(resourceMap: ResourceMapType) {
}

export async function getTargetClusterNamespaces(kubeconfigPath: string, context: string) {
const kc = new k8s.KubeConfig();
kc.loadFromFile(kubeconfigPath);
kc.setCurrentContext(context);

const namespaces = await NamespaceHandler.listResourcesInCluster(kc);
const kubeClient = createKubeClient(kubeconfigPath, context);
const namespaces = await NamespaceHandler.listResourcesInCluster(kubeClient);

const ns: string[] = [];
namespaces.forEach(namespace => {
Expand Down
13 changes: 5 additions & 8 deletions src/redux/thunks/loadClusterDiff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {RootState} from '@models/rootstate';
import getClusterObjects from '@redux/services/getClusterObjects';
import {extractK8sResources} from '@redux/services/resource';

import {createKubeClient} from '@utils/kubeclient';

import {createRejectionWithAlert} from './utils';

export type LoadClusterDiffPayload = {
Expand All @@ -28,17 +30,12 @@ export const loadClusterDiff = createAsyncThunk<
}
>('main/loadClusterDiff', async (_, thunkAPI) => {
const state = thunkAPI.getState();
const currentContext =
state.config.projectConfig?.kubeConfig?.currentContext || state.config.kubeConfig?.currentContext;
if (!state.ui.isClusterDiffVisible) {
return;
}
if (!currentContext) {
return createRejectionWithAlert(thunkAPI, CLUSTER_DIFF_FAILED, 'Could not find current kubeconfig context.');
}
try {
const kubeConfigPath = state.config.projectConfig?.kubeConfig?.path || state.config.kubeConfig.path;
return getClusterObjects(String(kubeConfigPath), currentContext).then(
const kc = createKubeClient(state.config);
return getClusterObjects(kc).then(
results => {
const fulfilledResults = results.filter(r => r.status === 'fulfilled' && r.value);

Expand All @@ -53,7 +50,7 @@ export const loadClusterDiff = createAsyncThunk<

// @ts-ignore
const allYaml = fulfilledResults.map(r => r.value).join(YAML_DOCUMENT_DELIMITER_NEW_LINE);
const resources = extractK8sResources(allYaml, CLUSTER_DIFF_PREFIX + String(kubeConfigPath));
const resources = extractK8sResources(allYaml, CLUSTER_DIFF_PREFIX + String(kc.currentContext));
const resourceMap = resources.reduce((rm: ResourceMapType, r) => {
rm[r.id] = r;
return rm;
Expand Down
19 changes: 8 additions & 11 deletions src/redux/thunks/previewCluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,14 @@ import {SetPreviewDataPayload} from '@redux/reducers/main';
import {extractK8sResources, processParsedResources} from '@redux/services/resource';
import {createPreviewResult, createRejectionWithAlert, getK8sObjectsAsYaml} from '@redux/thunks/utils';

import {createKubeClient} from '@utils/kubeclient';

import {getRegisteredKindHandlers, getResourceKindHandler} from '@src/kindhandlers';

const previewClusterHandler = async (configPath: string, thunkAPI: any) => {
const previewClusterHandler = async (context: string, thunkAPI: any) => {
const resourceRefsProcessingOptions = thunkAPI.getState().main.resourceRefsProcessingOptions;
try {
const kc = new k8s.KubeConfig();
const currentContext =
thunkAPI.getState().config.projectConfig?.kubeConfig?.currentContext ||
thunkAPI.getState().config.kubeConfig.currentContext;
kc.loadFromFile(configPath);
kc.setCurrentContext(currentContext);
const kc = createKubeClient(thunkAPI.getState().config, context);

const results = await Promise.allSettled(
getRegisteredKindHandlers()
Expand All @@ -53,11 +50,11 @@ const previewClusterHandler = async (configPath: string, thunkAPI: any) => {

const previewResult = createPreviewResult(
allYaml,
configPath,
context,
'Get Cluster Resources',
resourceRefsProcessingOptions,
configPath,
currentContext
context,
kc.currentContext
);

// if the cluster contains CRDs we need to check if there any corresponding resources also
Expand All @@ -70,7 +67,7 @@ const previewClusterHandler = async (configPath: string, thunkAPI: any) => {
// if any were found we need to merge them into the preview-result
if (customResourceObjects.length > 0) {
const customResourcesYaml = customResourceObjects.join(YAML_DOCUMENT_DELIMITER_NEW_LINE);
const customResources = extractK8sResources(customResourcesYaml, PREVIEW_PREFIX + configPath);
const customResources = extractK8sResources(customResourcesYaml, PREVIEW_PREFIX + context);
customResources.forEach(r => {
previewResult.previewResources[r.id] = r;
});
Expand Down
20 changes: 6 additions & 14 deletions src/redux/thunks/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {K8sResource} from '@models/k8sresource';

import {extractK8sResources, processParsedResources} from '@redux/services/resource';

import {createKubeClient} from '@utils/kubeclient';

import {getResourceKindHandler} from '@src/kindhandlers';

/**
Expand Down Expand Up @@ -80,24 +82,14 @@ export async function getResourceFromCluster(resource: K8sResource, kubeconfigPa
const resourceKindHandler = getResourceKindHandler(resource.kind);

if (resource && resource.text && resourceKindHandler) {
const kc = new k8s.KubeConfig();
kc.loadFromFile(kubeconfigPath);
if (context && context.length > 0) {
kc.setCurrentContext(context);
}

const resourceFromCluster = await resourceKindHandler.getResourceFromCluster(kc, resource);
const kubeClient = createKubeClient(kubeconfigPath, context);
const resourceFromCluster = await resourceKindHandler.getResourceFromCluster(kubeClient, resource);
return resourceFromCluster;
}
}

export async function removeNamespaceFromCluster(namespace: string, kubeconfigPath: string, context?: string) {
const kc = new k8s.KubeConfig();
kc.loadFromFile(kubeconfigPath);
if (context && context.length > 0) {
kc.setCurrentContext(context);
}

const k8sCoreV1Api = kc.makeApiClient(k8s.CoreV1Api);
const kubeClient = createKubeClient(kubeconfigPath, context);
const k8sCoreV1Api = kubeClient.makeApiClient(k8s.CoreV1Api);
await k8sCoreV1Api.deleteNamespace(namespace);
}
11 changes: 11 additions & 0 deletions src/utils/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,16 @@ function shellEnvSync() {
}
}
}

let mainProcessEnv: any | undefined;

export function getMainProcessEnv() {
return mainProcessEnv;
}

export function setMainProcessEnv(env: any) {
mainProcessEnv = env;
}

export const PROCESS_ENV: any = shellEnvSync();
export const RESOURCES_PATH = process.resourcesPath;
55 changes: 55 additions & 0 deletions src/utils/kubeclient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import * as k8s from '@kubernetes/client-node';

import log from 'loglevel';

import {AppConfig} from '@models/appconfig';

import {getMainProcessEnv} from '@utils/env';

export function createKubeClient(config: string | AppConfig, context?: string) {
const kc = new k8s.KubeConfig();

const path = typeof config === 'string' ? config : config.projectConfig?.kubeConfig?.path || config.kubeConfig.path;
if (!path) {
throw new Error('Missing path to kubeconfing');
}

kc.loadFromFile(path);
let currentContext =
typeof config === 'string'
? context
: config.projectConfig?.kubeConfig?.currentContext || config.kubeConfig.currentContext;

if (!currentContext) {
currentContext = kc.currentContext;
log.warn(`Missing currentContext, using default in kubeconfig: ${currentContext}`);
} else {
kc.setCurrentContext(currentContext);
}

// find the context
const ctxt = kc.contexts.find(c => c.name === currentContext);
if (ctxt) {
// find the user
const user = kc.users.find(usr => usr.name === ctxt.user);

// does the user use the ExecAuthenticator? -> apply process env
if (user?.exec) {
const mainProcessEnv = getMainProcessEnv();
if (mainProcessEnv) {
const envValues = Object.keys(mainProcessEnv).map(k => {
return {name: k, value: mainProcessEnv[k]};
});
if (user.exec.env) {
envValues.push(...user.exec.env);
}

user.exec.env = envValues;
}
}
} else {
throw new Error(`Selected context ${currentContext} not found in kubeconfig at ${path}`);
}

return kc;
}

0 comments on commit aec0290

Please sign in to comment.