mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
remove ClusterFeature
Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
parent
f550018f39
commit
f47e2a8477
@ -2,3 +2,5 @@ apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: lens-metrics
|
||||
labels:
|
||||
app: lens-metrics
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ClusterFeature, Catalog, K8sApi } from "@k8slens/extensions";
|
||||
import { Catalog, K8sApi } from "@k8slens/extensions";
|
||||
import semver from "semver";
|
||||
import * as path from "path";
|
||||
|
||||
@ -27,86 +27,67 @@ export interface MetricsConfiguration {
|
||||
storageClass: string;
|
||||
}
|
||||
|
||||
export class MetricsFeature extends ClusterFeature.Feature {
|
||||
export interface MetricsStatus {
|
||||
installed: boolean;
|
||||
canUpgrade: boolean;
|
||||
}
|
||||
|
||||
export class MetricsFeature {
|
||||
name = "metrics";
|
||||
latestVersion = "v2.19.3-lens1";
|
||||
|
||||
templateContext: MetricsConfiguration = {
|
||||
prometheus: {
|
||||
enabled: false
|
||||
},
|
||||
persistence: {
|
||||
enabled: false,
|
||||
storageClass: null,
|
||||
size: "20G",
|
||||
},
|
||||
nodeExporter: {
|
||||
enabled: false,
|
||||
},
|
||||
retention: {
|
||||
time: "2d",
|
||||
size: "5GB",
|
||||
},
|
||||
kubeStateMetrics: {
|
||||
enabled: false,
|
||||
},
|
||||
alertManagers: null,
|
||||
replicas: 1,
|
||||
storageClass: null,
|
||||
};
|
||||
protected stack: K8sApi.ResourceStack;
|
||||
|
||||
async install(cluster: Catalog.KubernetesCluster): Promise<void> {
|
||||
constructor(protected cluster: Catalog.KubernetesCluster) {
|
||||
this.stack = new K8sApi.ResourceStack(cluster);
|
||||
}
|
||||
|
||||
get resourceFolder() {
|
||||
return path.join(__dirname, "../resources/");
|
||||
}
|
||||
|
||||
async install(config: MetricsConfiguration): Promise<string> {
|
||||
// Check if there are storageclasses
|
||||
const storageClassApi = K8sApi.forCluster(cluster, K8sApi.StorageClass);
|
||||
const storageClassApi = K8sApi.forCluster(this.cluster, K8sApi.StorageClass);
|
||||
const scs = await storageClassApi.list();
|
||||
|
||||
this.templateContext.persistence.enabled = scs.some(sc => (
|
||||
config.persistence.enabled = scs.some(sc => (
|
||||
sc.metadata?.annotations?.["storageclass.kubernetes.io/is-default-class"] === "true" ||
|
||||
sc.metadata?.annotations?.["storageclass.beta.kubernetes.io/is-default-class"] === "true"
|
||||
));
|
||||
|
||||
await super.applyResources(cluster, path.join(__dirname, "../resources/"));
|
||||
return this.stack.kubectlApplyFolder(this.resourceFolder, config);
|
||||
}
|
||||
|
||||
async upgrade(cluster: Catalog.KubernetesCluster): Promise<void> {
|
||||
return this.install(cluster);
|
||||
async upgrade(config: MetricsConfiguration): Promise<string> {
|
||||
return this.install(config);
|
||||
}
|
||||
|
||||
async updateStatus(cluster: Catalog.KubernetesCluster): Promise<ClusterFeature.FeatureStatus> {
|
||||
async getStatus(): Promise<MetricsStatus> {
|
||||
const status: MetricsStatus = { installed: false, canUpgrade: false};
|
||||
|
||||
try {
|
||||
const statefulSet = K8sApi.forCluster(cluster, K8sApi.StatefulSet);
|
||||
const statefulSet = K8sApi.forCluster(this.cluster, K8sApi.StatefulSet);
|
||||
const prometheus = await statefulSet.get({name: "prometheus", namespace: "lens-metrics"});
|
||||
|
||||
if (prometheus?.kind) {
|
||||
this.status.installed = true;
|
||||
this.status.currentVersion = prometheus.spec.template.spec.containers[0].image.split(":")[1];
|
||||
this.status.canUpgrade = semver.lt(this.status.currentVersion, this.latestVersion, true);
|
||||
const currentVersion = prometheus.spec.template.spec.containers[0].image.split(":")[1];
|
||||
|
||||
const pvcTemplate = prometheus.spec.volumeClaimTemplates[0];
|
||||
|
||||
if (pvcTemplate) {
|
||||
this.templateContext.persistence.enabled = true;
|
||||
this.templateContext.persistence.size = pvcTemplate.spec.resources.requests.storage;
|
||||
}
|
||||
status.installed = true;
|
||||
status.canUpgrade = semver.lt(currentVersion, this.latestVersion, true);
|
||||
} else {
|
||||
this.status.installed = false;
|
||||
status.installed = false;
|
||||
}
|
||||
} catch(e) {
|
||||
if (e?.error?.code === 404) {
|
||||
this.status.installed = false;
|
||||
status.installed = false;
|
||||
}
|
||||
}
|
||||
|
||||
return this.status;
|
||||
return status;
|
||||
}
|
||||
|
||||
async uninstall(cluster: Catalog.KubernetesCluster): Promise<void> {
|
||||
const namespaceApi = K8sApi.forCluster(cluster, K8sApi.Namespace);
|
||||
const clusterRoleBindingApi = K8sApi.forCluster(cluster, K8sApi.ClusterRoleBinding);
|
||||
const clusterRoleApi = K8sApi.forCluster(cluster, K8sApi.ClusterRole);
|
||||
|
||||
await namespaceApi.delete({name: "lens-metrics"});
|
||||
await clusterRoleBindingApi.delete({name: "lens-prometheus"});
|
||||
await clusterRoleApi.delete({name: "lens-prometheus"});
|
||||
async uninstall(config: MetricsConfiguration): Promise<string> {
|
||||
return this.stack.kubectlDeleteFolder(this.resourceFolder, config);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,8 @@ import React from "react";
|
||||
import { Component, Catalog, K8sApi } from "@k8slens/extensions";
|
||||
import { observer } from "mobx-react";
|
||||
import { observable } from "mobx";
|
||||
import { MetricsFeature } from "./metrics-feature";
|
||||
import { MetricsFeature, MetricsConfiguration } from "./metrics-feature";
|
||||
|
||||
interface Props {
|
||||
cluster: Catalog.KubernetesCluster;
|
||||
}
|
||||
@ -17,28 +18,42 @@ export class MetricsSettings extends React.Component<Props> {
|
||||
@observable canUpgrade = false;
|
||||
@observable upgrading = false;
|
||||
|
||||
pvcOptions = [
|
||||
{ value: "", label: "Use EmptyDir (no PVC)" },
|
||||
{ value: "5GB", label: "5GB" },
|
||||
{ value: "10GB", label: "10GB" },
|
||||
{ value: "20GB", label: "20GB" },
|
||||
{ value: "40GB", label: "40GB" },
|
||||
{ value: "80GB", label: "80GB" },
|
||||
];
|
||||
|
||||
featureSet: MetricsFeature;
|
||||
config: MetricsConfiguration = {
|
||||
prometheus: {
|
||||
enabled: false
|
||||
},
|
||||
persistence: {
|
||||
enabled: false,
|
||||
storageClass: null,
|
||||
size: "20G",
|
||||
},
|
||||
nodeExporter: {
|
||||
enabled: false,
|
||||
},
|
||||
retention: {
|
||||
time: "2d",
|
||||
size: "5GB",
|
||||
},
|
||||
kubeStateMetrics: {
|
||||
enabled: false,
|
||||
},
|
||||
alertManagers: null,
|
||||
replicas: 1,
|
||||
storageClass: null,
|
||||
};
|
||||
feature: MetricsFeature;
|
||||
|
||||
async componentDidMount() {
|
||||
this.featureSet = new MetricsFeature();
|
||||
this.feature = new MetricsFeature(this.props.cluster);
|
||||
|
||||
await this.updateFeatureStates();
|
||||
}
|
||||
|
||||
async updateFeatureStates() {
|
||||
await this.featureSet.updateStatus(this.props.cluster);
|
||||
this.canUpgrade = this.featureSet.status.canUpgrade;
|
||||
const status = await this.feature.getStatus();
|
||||
|
||||
this.featureStates.prometheus = this.featureSet.status.installed;
|
||||
this.canUpgrade = status.canUpgrade;
|
||||
this.featureStates.prometheus = status.installed;
|
||||
|
||||
const deployment = K8sApi.forCluster(this.props.cluster, K8sApi.Deployment);
|
||||
|
||||
@ -68,24 +83,22 @@ export class MetricsSettings extends React.Component<Props> {
|
||||
}
|
||||
|
||||
async save() {
|
||||
const ctx = this.featureSet.templateContext;
|
||||
this.config.prometheus.enabled = !!this.featureStates.prometheus;
|
||||
this.config.kubeStateMetrics.enabled = !!this.featureStates.kubeStateMetrics;
|
||||
this.config.nodeExporter.enabled = !!this.featureStates.nodeExporter;
|
||||
|
||||
ctx.prometheus.enabled = !!this.featureStates.prometheus;
|
||||
ctx.kubeStateMetrics.enabled = !!this.featureStates.kubeStateMetrics;
|
||||
ctx.nodeExporter.enabled = !!this.featureStates.nodeExporter;
|
||||
console.log(this.config);
|
||||
|
||||
if (!ctx.prometheus.enabled && !ctx.kubeStateMetrics.enabled && !ctx.nodeExporter.enabled) {
|
||||
await this.featureSet.uninstall(this.props.cluster);
|
||||
if (!this.config.prometheus.enabled && !this.config.kubeStateMetrics.enabled && !this.config.nodeExporter.enabled) {
|
||||
await this.feature.uninstall(this.config);
|
||||
} else {
|
||||
await this.featureSet.install(this.props.cluster);
|
||||
await this.feature.install(this.config);
|
||||
}
|
||||
}
|
||||
|
||||
async togglePrometheus(enabled: boolean) {
|
||||
this.featureStates.prometheus = enabled;
|
||||
|
||||
this.featureSet.templateContext.prometheus.enabled = this.featureStates.prometheus;
|
||||
|
||||
try {
|
||||
await this.save();
|
||||
} catch(error) {
|
||||
@ -97,8 +110,6 @@ export class MetricsSettings extends React.Component<Props> {
|
||||
async toggleKubeStateMetrics(enabled: boolean) {
|
||||
this.featureStates.kubeStateMetrics = enabled;
|
||||
|
||||
this.featureSet.templateContext.kubeStateMetrics.enabled = this.featureStates.kubeStateMetrics;
|
||||
|
||||
try {
|
||||
await this.save();
|
||||
} catch(error) {
|
||||
@ -110,8 +121,6 @@ export class MetricsSettings extends React.Component<Props> {
|
||||
async toggleNodeExporter(enabled: boolean) {
|
||||
this.featureStates.nodeExporter = enabled;
|
||||
|
||||
this.featureSet.templateContext.nodeExporter.enabled = this.featureStates.nodeExporter;
|
||||
|
||||
try {
|
||||
await this.save();
|
||||
} catch(error) {
|
||||
|
||||
@ -10,6 +10,7 @@ export const clusterSetFrameIdHandler = "cluster:set-frame-id";
|
||||
export const clusterRefreshHandler = "cluster:refresh";
|
||||
export const clusterDisconnectHandler = "cluster:disconnect";
|
||||
export const clusterKubectlApplyAllHandler = "cluster:kubectl-apply-all";
|
||||
export const clusterKubectlDeleteAllHandler = "cluster:kubectl-delete-all";
|
||||
|
||||
if (ipcMain) {
|
||||
handleRequest(clusterActivateHandler, (event, clusterId: ClusterId, force = false) => {
|
||||
@ -64,4 +65,23 @@ if (ipcMain) {
|
||||
throw `${clusterId} is not a valid cluster id`;
|
||||
}
|
||||
});
|
||||
|
||||
handleRequest(clusterKubectlDeleteAllHandler, async (event, clusterId: ClusterId, resources: string[]) => {
|
||||
appEventBus.emit({name: "cluster", action: "kubectl-delete-all"});
|
||||
const cluster = ClusterStore.getInstance().getById(clusterId);
|
||||
|
||||
if (cluster) {
|
||||
const applier = new ResourceApplier(cluster);
|
||||
|
||||
try {
|
||||
const stdout = await applier.kubectlApplyAll(resources);
|
||||
|
||||
return { stdout };
|
||||
} catch (error: any) {
|
||||
return { stderr: error };
|
||||
}
|
||||
} else {
|
||||
throw `${clusterId} is not a valid cluster id`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
102
src/common/k8s/resource-stack.ts
Normal file
102
src/common/k8s/resource-stack.ts
Normal file
@ -0,0 +1,102 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import hb from "handlebars";
|
||||
import { ResourceApplier } from "../../main/resource-applier";
|
||||
import { KubernetesCluster } from "../catalog-entities";
|
||||
import logger from "../../main/logger";
|
||||
import { app } from "electron";
|
||||
import { requestMain } from "../ipc";
|
||||
import { clusterKubectlApplyAllHandler, clusterKubectlDeleteAllHandler } from "../cluster-ipc";
|
||||
import { ClusterStore } from "../cluster-store";
|
||||
|
||||
export class ResourceStack {
|
||||
/**
|
||||
* this field sets the template parameters that are to be applied to any templated kubernetes resources that are to be installed.
|
||||
* See the renderTemplates() method for more details
|
||||
*/
|
||||
templateContext: any;
|
||||
|
||||
constructor(protected cluster: KubernetesCluster) {}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param folderPath folder path that is searched for files defining kubernetes resources.
|
||||
* @param templateContext sets the template parameters that are to be applied to any templated kubernetes resources that are to be applied.
|
||||
*/
|
||||
async kubectlApplyFolder(folderPath: string, templateContext?: any): Promise<string> {
|
||||
const resources = this.renderTemplates(folderPath, templateContext);
|
||||
|
||||
return this.applyResources(resources);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param folderPath folder path that is searched for files defining kubernetes resources.
|
||||
* @param templateContext sets the template parameters that are to be applied to any templated kubernetes resources that are to be applied.
|
||||
*/
|
||||
async kubectlDeleteFolder(folderPath: string, templateContext?: any): Promise<string> {
|
||||
const resources = this.renderTemplates(folderPath, templateContext);
|
||||
|
||||
return this.deleteResources(resources);
|
||||
}
|
||||
|
||||
protected async applyResources(resources: string[]): Promise<string> {
|
||||
const clusterModel = ClusterStore.getInstance().getById(this.cluster.metadata.uid);
|
||||
|
||||
if (!clusterModel) {
|
||||
throw new Error(`cluster not found`);
|
||||
}
|
||||
|
||||
if (app) {
|
||||
return await new ResourceApplier(clusterModel).kubectlApplyAll(resources);
|
||||
} else {
|
||||
const response = await requestMain(clusterKubectlApplyAllHandler, this.cluster.metadata.uid, resources);
|
||||
|
||||
if (response.stderr) {
|
||||
throw new Error(response.stderr);
|
||||
}
|
||||
|
||||
return response.stdout;
|
||||
}
|
||||
}
|
||||
|
||||
protected async deleteResources(resources: string[]): Promise<string> {
|
||||
const clusterModel = ClusterStore.getInstance().getById(this.cluster.metadata.uid);
|
||||
|
||||
if (!clusterModel) {
|
||||
throw new Error(`cluster not found`);
|
||||
}
|
||||
|
||||
if (app) {
|
||||
return await new ResourceApplier(clusterModel).kubectlDeleteAll(resources);
|
||||
} else {
|
||||
const response = await requestMain(clusterKubectlDeleteAllHandler, this.cluster.metadata.uid, resources);
|
||||
|
||||
if (response.stderr) {
|
||||
throw new Error(response.stderr);
|
||||
}
|
||||
|
||||
return response.stdout;
|
||||
}
|
||||
}
|
||||
|
||||
protected renderTemplates(folderPath: string, templateContext: any): string[] {
|
||||
const resources: string[] = [];
|
||||
|
||||
logger.info(`[RESOURCE-STACK]: render templates from ${folderPath}`);
|
||||
fs.readdirSync(folderPath).forEach(filename => {
|
||||
const file = path.join(folderPath, filename);
|
||||
const raw = fs.readFileSync(file);
|
||||
|
||||
if (filename.endsWith(".hb")) {
|
||||
const template = hb.compile(raw.toString());
|
||||
|
||||
resources.push(template(templateContext));
|
||||
} else {
|
||||
resources.push(raw.toString());
|
||||
}
|
||||
});
|
||||
|
||||
return resources;
|
||||
}
|
||||
}
|
||||
@ -1,135 +0,0 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import hb from "handlebars";
|
||||
import { observable } from "mobx";
|
||||
import { ResourceApplier } from "../main/resource-applier";
|
||||
import { KubernetesCluster } from "./core-api/catalog";
|
||||
import logger from "../main/logger";
|
||||
import { app } from "electron";
|
||||
import { requestMain } from "../common/ipc";
|
||||
import { clusterKubectlApplyAllHandler } from "../common/cluster-ipc";
|
||||
import { ClusterStore } from "../common/cluster-store";
|
||||
|
||||
export interface ClusterFeatureStatus {
|
||||
/** feature's current version, as set by the implementation */
|
||||
currentVersion: string;
|
||||
/** feature's latest version, as set by the implementation */
|
||||
latestVersion: string;
|
||||
/** whether the feature is installed or not, as set by the implementation */
|
||||
installed: boolean;
|
||||
/** whether the feature can be upgraded or not, as set by the implementation */
|
||||
canUpgrade: boolean;
|
||||
}
|
||||
|
||||
export abstract class ClusterFeature {
|
||||
|
||||
/**
|
||||
* this field sets the template parameters that are to be applied to any templated kubernetes resources that are to be installed for the feature.
|
||||
* See the renderTemplates() method for more details
|
||||
*/
|
||||
templateContext: any;
|
||||
|
||||
/**
|
||||
* this field holds the current feature status, is accessed directly by Lens
|
||||
*/
|
||||
@observable status: ClusterFeatureStatus = {
|
||||
currentVersion: null,
|
||||
installed: false,
|
||||
latestVersion: null,
|
||||
canUpgrade: false
|
||||
};
|
||||
|
||||
/**
|
||||
* to be implemented in the derived class, this method is typically called by Lens when a user has indicated that this feature is to be installed. The implementation
|
||||
* of this method should install kubernetes resources using the applyResources() method, or by directly accessing the kubernetes api (K8sApi)
|
||||
*
|
||||
* @param cluster the cluster that the feature is to be installed on
|
||||
*/
|
||||
abstract install(cluster: KubernetesCluster): Promise<void>;
|
||||
|
||||
/**
|
||||
* to be implemented in the derived class, this method is typically called by Lens when a user has indicated that this feature is to be upgraded. The implementation
|
||||
* of this method should upgrade the kubernetes resources already installed, if relevant to the feature
|
||||
*
|
||||
* @param cluster the cluster that the feature is to be upgraded on
|
||||
*/
|
||||
abstract upgrade(cluster: KubernetesCluster): Promise<void>;
|
||||
|
||||
/**
|
||||
* to be implemented in the derived class, this method is typically called by Lens when a user has indicated that this feature is to be uninstalled. The implementation
|
||||
* of this method should uninstall kubernetes resources using the kubernetes api (K8sApi)
|
||||
*
|
||||
* @param cluster the cluster that the feature is to be uninstalled from
|
||||
*/
|
||||
abstract uninstall(cluster: KubernetesCluster): Promise<void>;
|
||||
|
||||
/**
|
||||
* to be implemented in the derived class, this method is called periodically by Lens to determine details about the feature's current status. The implementation
|
||||
* of this method should provide the current status information. The currentVersion and latestVersion fields may be displayed by Lens in describing the feature.
|
||||
* The installed field should be set to true if the feature has been installed, otherwise false. Also, Lens relies on the canUpgrade field to determine if the feature
|
||||
* can be upgraded so the implementation should set the canUpgrade field according to specific rules for the feature, if relevant.
|
||||
*
|
||||
* @param cluster the cluster that the feature may be installed on
|
||||
*
|
||||
* @return a promise, resolved with the updated ClusterFeatureStatus
|
||||
*/
|
||||
abstract updateStatus(cluster: KubernetesCluster): Promise<ClusterFeatureStatus>;
|
||||
|
||||
/**
|
||||
* this is a helper method that conveniently applies kubernetes resources to the cluster.
|
||||
*
|
||||
* @param cluster the cluster that the resources are to be applied to
|
||||
* @param resourceSpec as a string type this is a folder path that is searched for files specifying kubernetes resources. The files are read and if any of the resource
|
||||
* files are templated, the template parameters are filled using the templateContext field (See renderTemplate() method). Finally the resources are applied to the
|
||||
* cluster. As a string[] type resourceSpec is treated as an array of fully formed (not templated) kubernetes resources that are applied to the cluster
|
||||
*/
|
||||
protected async applyResources(cluster: KubernetesCluster, resourceSpec: string | string[]) {
|
||||
let resources: string[];
|
||||
|
||||
const clusterModel = ClusterStore.getInstance().getById(cluster.metadata.uid);
|
||||
|
||||
if (!clusterModel) {
|
||||
throw new Error(`cluster not found`);
|
||||
}
|
||||
|
||||
if ( typeof resourceSpec === "string" ) {
|
||||
resources = this.renderTemplates(resourceSpec);
|
||||
} else {
|
||||
resources = resourceSpec;
|
||||
}
|
||||
|
||||
if (app) {
|
||||
return await new ResourceApplier(clusterModel).kubectlApplyAll(resources);
|
||||
} else {
|
||||
return await requestMain(clusterKubectlApplyAllHandler, cluster.metadata.uid, resources);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* this is a helper method that conveniently reads kubernetes resource files into a string array. It also fills templated resource files with the template parameter values
|
||||
* specified by the templateContext field. Templated files must end with the extension '.hb' and the template syntax must be compatible with handlebars.js
|
||||
*
|
||||
* @param folderPath this is a folder path that is searched for files defining kubernetes resources.
|
||||
*
|
||||
* @return an array of strings, each string being the contents of a resource file found in the folder path. This can be passed directly to applyResources()
|
||||
*/
|
||||
protected renderTemplates(folderPath: string): string[] {
|
||||
const resources: string[] = [];
|
||||
|
||||
logger.info(`[FEATURE]: render templates from ${folderPath}`);
|
||||
fs.readdirSync(folderPath).forEach(filename => {
|
||||
const file = path.join(folderPath, filename);
|
||||
const raw = fs.readFileSync(file);
|
||||
|
||||
if (filename.endsWith(".hb")) {
|
||||
const template = hb.compile(raw.toString());
|
||||
|
||||
resources.push(template(this.templateContext));
|
||||
} else {
|
||||
resources.push(raw.toString());
|
||||
}
|
||||
});
|
||||
|
||||
return resources;
|
||||
}
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
export { ClusterFeature as Feature } from "../cluster-feature";
|
||||
export type { ClusterFeatureStatus as FeatureStatus } from "../cluster-feature";
|
||||
@ -7,7 +7,6 @@ import * as App from "./app";
|
||||
import * as EventBus from "./event-bus";
|
||||
import * as Store from "./stores";
|
||||
import * as Util from "./utils";
|
||||
import * as ClusterFeature from "./cluster-feature";
|
||||
import * as Interface from "../interfaces";
|
||||
import * as Catalog from "./catalog";
|
||||
|
||||
@ -15,7 +14,6 @@ export {
|
||||
App,
|
||||
EventBus,
|
||||
Catalog,
|
||||
ClusterFeature,
|
||||
Interface,
|
||||
Store,
|
||||
Util,
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
export { isAllowedResource } from "../../common/rbac";
|
||||
export { ResourceStack } from "../../common/k8s/resource-stack";
|
||||
export { apiManager } from "../../renderer/api/api-manager";
|
||||
export { KubeObjectStore } from "../../renderer/kube-object.store";
|
||||
export { KubeApi, forCluster, IKubeApiCluster } from "../../renderer/api/kube-api";
|
||||
|
||||
@ -53,6 +53,14 @@ export class ResourceApplier {
|
||||
}
|
||||
|
||||
public async kubectlApplyAll(resources: string[]): Promise<string> {
|
||||
return this.kubectlCmdAll("apply", resources);
|
||||
}
|
||||
|
||||
public async kubectlDeleteAll(resources: string[]): Promise<string> {
|
||||
return this.kubectlCmdAll("delete", resources);
|
||||
}
|
||||
|
||||
protected async kubectlCmdAll(subCmd: string, resources: string[]): Promise<string> {
|
||||
const { kubeCtl } = this.cluster;
|
||||
const kubectlPath = await kubeCtl.getPath();
|
||||
const proxyKubeconfigPath = await this.cluster.getProxyKubeconfigPath();
|
||||
@ -64,17 +72,16 @@ export class ResourceApplier {
|
||||
resources.forEach((resource, index) => {
|
||||
fs.writeFileSync(path.join(tmpDir, `${index}.yaml`), resource);
|
||||
});
|
||||
const cmd = `"${kubectlPath}" apply --kubeconfig "${proxyKubeconfigPath}" -o json -f "${tmpDir}"`;
|
||||
const cmd = `"${kubectlPath}" ${subCmd} --kubeconfig "${proxyKubeconfigPath}" -o json -f "${tmpDir}"`;
|
||||
|
||||
console.log("shooting manifests with:", cmd);
|
||||
exec(cmd, (error, stdout) => {
|
||||
if (error) {
|
||||
const splittedError = error.toString().split(`.yaml": `);
|
||||
|
||||
if (splittedError[1]) {
|
||||
reject(`Error applying manifests: ${splittedError[1]}`);
|
||||
reject(splittedError[1]);
|
||||
} else {
|
||||
reject(`Error applying manifests:${error}`);
|
||||
reject(error);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user