Skip to content

Commit

Permalink
feat: logic to remove resources from file/cluster
Browse files Browse the repository at this point in the history
  • Loading branch information
devcatalin committed Sep 9, 2021
1 parent da8ddeb commit 27cf32c
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 3 deletions.
5 changes: 5 additions & 0 deletions src/kindhandlers/ConfigMap.handler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as k8s from '@kubernetes/client-node';
import {ResourceKindHandler} from '@models/resourcekindhandler';
import {NAV_K8S_RESOURCES, SECTION_CONFIGURATION} from '@constants/navigator';
import {K8sResource} from '@models/k8sresource';

const ConfigMapHandler: ResourceKindHandler = {
kind: 'ConfigMap',
Expand All @@ -18,6 +19,10 @@ const ConfigMapHandler: ResourceKindHandler = {
const response = await k8sCoreV1Api.listConfigMapForAllNamespaces();
return response.body.items;
},
async deleteResourceInCluster(kubeconfig: k8s.KubeConfig, resource: K8sResource) {
const k8sCoreV1Api = kubeconfig.makeApiClient(k8s.CoreV1Api);
await k8sCoreV1Api.deleteNamespacedConfigMap(resource.name, resource.namespace || 'default');
},
};

export default ConfigMapHandler;
3 changes: 3 additions & 0 deletions src/models/resourcekindhandler.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as k8s from '@kubernetes/client-node';
import {monaco} from 'react-monaco-editor';
import {K8sResource} from './k8sresource';

interface SymbolMatcher {
isMatch?(symbols: monaco.languages.DocumentSymbol[]): boolean;
Expand Down Expand Up @@ -53,6 +54,8 @@ interface ResourceKindHandler {

listResourcesInCluster(kubeconfig: k8s.KubeConfig): Promise<any[]>;

deleteResourceInCluster?: (kubeconfig: k8s.KubeConfig, resource: K8sResource) => Promise<any>;

/**
* optional outgoing RefMappers to use for resolving refs in resources of this type
*/
Expand Down
29 changes: 29 additions & 0 deletions src/redux/reducers/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {PREVIEW_PREFIX, ROOT_FILE_ENTRY} from '@constants/constants';
import {AppConfig} from '@models/appconfig';
import {AppState, FileMapType, HelmChartMapType, HelmValuesMapType, ResourceMapType} from '@models/appstate';
import {parseDocument} from 'yaml';
import * as k8s from '@kubernetes/client-node';
import fs from 'fs';
import {previewKustomization} from '@redux/thunks/previewKustomization';
import {previewCluster, repreviewCluster} from '@redux/thunks/previewCluster';
Expand All @@ -16,6 +17,7 @@ import {saveUnsavedResource} from '@redux/thunks/saveUnsavedResource';
import {resetSelectionHistory} from '@redux/services/selectionHistory';
import {K8sResource} from '@models/k8sresource';
import {AlertType} from '@models/alert';
import {getResourceKindHandler} from '@src/kindhandlers';
import initialState from '../initialState';
import {clearResourceSelections, highlightChildrenResources, updateSelectionAndHighlights} from '../services/selection';
import {
Expand All @@ -31,6 +33,7 @@ import {
extractK8sResources,
isFileResource,
recalculateResourceRanges,
removeResourceFromFile,
reprocessResources,
saveResource,
} from '../services/resource';
Expand Down Expand Up @@ -201,6 +204,31 @@ export const mainSlice = createSlice({
return original(state);
}
},
removeResource: (state: Draft<AppState>, action: PayloadAction<string>) => {
const resourceId = action.payload;
const resource = state.resourceMap[resourceId];
if (!resource) {
return;
}
if (isFileResource(resource)) {
removeResourceFromFile(resource, state.fileMap, state.resourceMap);
return;
}
if (state.previewType === 'cluster' && state.previewResourceId) {
try {
const kubeConfig = new k8s.KubeConfig();
kubeConfig.loadFromFile(state.previewResourceId);
const kindHandler = getResourceKindHandler(resource.kind);
if (kindHandler?.deleteResourceInCluster) {
kindHandler.deleteResourceInCluster(kubeConfig, resource);
delete state.resourceMap[resource.id];
}
} catch (err) {
log.error(err);
return original(state);
}
}
},
/**
* Marks the specified resource as selected and highlights all related resources
*/
Expand Down Expand Up @@ -452,5 +480,6 @@ export const {
clearPreviewAndSelectionHistory,
startPreviewLoader,
stopPreviewLoader,
removeResource,
} = mainSlice.actions;
export default mainSlice.reducer;
8 changes: 5 additions & 3 deletions src/redux/services/fileEntry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,13 +380,15 @@ export function addPath(absolutePath: string, state: AppState, appConfig: AppCon
* Removes the specified fileEntry and its resources from the provided state
*/

function removeFile(fileEntry: FileEntry, state: AppState, removalSideEffect: PathRemovalSideEffect) {
export function removeFile(fileEntry: FileEntry, state: AppState, removalSideEffect?: PathRemovalSideEffect) {
log.info(`removing file ${fileEntry.filePath}`);
getResourcesForPath(fileEntry.filePath, state.resourceMap).forEach(resource => {
if (state.selectedResourceId === resource.id) {
updateSelectionAndHighlights(state, resource);
}
removalSideEffect.removedResources.push(resource);
if (removalSideEffect) {
removalSideEffect.removedResources.push(resource);
}
delete state.resourceMap[resource.id];
});
}
Expand All @@ -395,7 +397,7 @@ function removeFile(fileEntry: FileEntry, state: AppState, removalSideEffect: Pa
* Removes the specified fileEntry and its resources from the provided state
*/

function removeFolder(fileEntry: FileEntry, state: AppState, removalSideEffect: PathRemovalSideEffect) {
function removeFolder(fileEntry: FileEntry, state: AppState, removalSideEffect?: PathRemovalSideEffect) {
log.info(`removing folder ${fileEntry.filePath}`);
fileEntry.children?.forEach(child => {
const childEntry = state.fileMap[path.join(fileEntry.filePath, child)];
Expand Down
53 changes: 53 additions & 0 deletions src/redux/services/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,59 @@ export function recalculateResourceRanges(resource: K8sResource, state: AppState
}
}

export function removeResourceFromFile(
removedResource: K8sResource,
fileMap: FileMapType,
resourceMap: ResourceMapType
) {
const fileEntry = fileMap[removedResource.filePath];
if (!fileEntry) {
throw new Error(`Failed to find fileEntry for resource with path ${removedResource.filePath}`);
}
const absoluteFilePath = getAbsoluteResourcePath(removedResource, fileMap);

if (!removedResource.range) {
fs.unlinkSync(absoluteFilePath);
return;
}

// get list of resourceIds in file sorted by startPosition
const resourceIds = getResourcesForPath(removedResource.filePath, resourceMap)
.sort((a, b) => {
return a.range && b.range ? a.range.start - b.range.start : 0;
})
.map(r => r.id);

// recalculate ranges for resources below the removed resource
let newRangeStart = 0;
let passedRemovedResource = false;
resourceIds.forEach(resourceId => {
const resource = resourceMap[resourceId];
if (resourceId === removedResource.id) {
passedRemovedResource = true;
newRangeStart = resource.range?.start || newRangeStart;
return;
}
if (!passedRemovedResource) {
return;
}
if (resource.range) {
resource.range.start = newRangeStart;
newRangeStart = resource.range.start + resource.range.length;
}
});

const content = fs.readFileSync(absoluteFilePath, 'utf8');
fs.writeFileSync(
absoluteFilePath,
content.substr(0, removedResource.range.start) +
content.substr(removedResource.range.start + removedResource.range.length)
);
fileEntry.timestamp = fs.statSync(absoluteFilePath).mtime.getTime();

delete resourceMap[removedResource.id];
}

/**
* Extracts all resources from the specified text content (must be yaml)
*/
Expand Down

0 comments on commit 27cf32c

Please sign in to comment.