From 4b983ae5bdca1cb7fead62386e28072e36b504b2 Mon Sep 17 00:00:00 2001
From: Jari Kolehmainen
Date: Mon, 17 May 2021 17:06:49 +0300
Subject: [PATCH] dedicated action button
Signed-off-by: Jari Kolehmainen
---
.../{01-namespace.yml => 01-namespace.yml.hb} | 2 +
.../src/metrics-feature.ts | 11 +-
.../src/metrics-settings.tsx | 113 ++++++++++--------
3 files changed, 72 insertions(+), 54 deletions(-)
rename extensions/metrics-cluster-feature/resources/{01-namespace.yml => 01-namespace.yml.hb} (53%)
diff --git a/extensions/metrics-cluster-feature/resources/01-namespace.yml b/extensions/metrics-cluster-feature/resources/01-namespace.yml.hb
similarity index 53%
rename from extensions/metrics-cluster-feature/resources/01-namespace.yml
rename to extensions/metrics-cluster-feature/resources/01-namespace.yml.hb
index 85d13c1046..dd3816fdff 100644
--- a/extensions/metrics-cluster-feature/resources/01-namespace.yml
+++ b/extensions/metrics-cluster-feature/resources/01-namespace.yml.hb
@@ -2,3 +2,5 @@ apiVersion: v1
kind: Namespace
metadata:
name: lens-metrics
+ annotations:
+ extensionVersion: "{{ version }}"
diff --git a/extensions/metrics-cluster-feature/src/metrics-feature.ts b/extensions/metrics-cluster-feature/src/metrics-feature.ts
index c5688f9be5..655c8e60ed 100644
--- a/extensions/metrics-cluster-feature/src/metrics-feature.ts
+++ b/extensions/metrics-cluster-feature/src/metrics-feature.ts
@@ -46,6 +46,7 @@ export interface MetricsConfiguration {
alertManagers: string[];
replicas: number;
storageClass: string;
+ version?: string;
}
export interface MetricsStatus {
@@ -77,6 +78,8 @@ export class MetricsFeature {
sc.metadata?.annotations?.["storageclass.beta.kubernetes.io/is-default-class"] === "true"
));
+ config.version = this.latestVersion;
+
return this.stack.kubectlApplyFolder(this.resourceFolder, config, ["--prune"]);
}
@@ -88,11 +91,11 @@ export class MetricsFeature {
const status: MetricsStatus = { installed: false, canUpgrade: false};
try {
- const statefulSet = K8sApi.forCluster(this.cluster, K8sApi.StatefulSet);
- const prometheus = await statefulSet.get({name: "prometheus", namespace: "lens-metrics"});
+ const namespaceApi = K8sApi.forCluster(this.cluster, K8sApi.Namespace);
+ const namespace = await namespaceApi.get({name: "lens-metrics"});
- if (prometheus?.kind) {
- const currentVersion = prometheus.spec.template.spec.containers[0].image.split(":")[1];
+ if (namespace?.kind) {
+ const currentVersion = namespace.metadata.annotations?.extensionVersion || "0.0.0";
status.installed = true;
status.canUpgrade = semver.lt(currentVersion, this.latestVersion, true);
diff --git a/extensions/metrics-cluster-feature/src/metrics-settings.tsx b/extensions/metrics-cluster-feature/src/metrics-settings.tsx
index 8d9c62d44a..bc1784ca3c 100644
--- a/extensions/metrics-cluster-feature/src/metrics-settings.tsx
+++ b/extensions/metrics-cluster-feature/src/metrics-settings.tsx
@@ -17,6 +17,8 @@ export class MetricsSettings extends React.Component {
};
@observable canUpgrade = false;
@observable upgrading = false;
+ @observable changed = false;
+ @observable inProgress = false;
config: MetricsConfiguration = {
prometheus: {
@@ -44,6 +46,7 @@ export class MetricsSettings extends React.Component {
feature: MetricsFeature;
@computed get isTogglable() {
+ if (this.inProgress) return false;
if (!this.props.cluster.status.active) return false;
if (this.canUpgrade) return false;
if (!this.isActiveMetricsProvider) return false;
@@ -69,7 +72,23 @@ export class MetricsSettings extends React.Component {
const status = await this.feature.getStatus();
this.canUpgrade = status.canUpgrade;
- this.featureStates.prometheus = status.installed;
+
+ if (this.canUpgrade) {
+ this.changed = true;
+ }
+
+ const statefulSet = K8sApi.forCluster(this.props.cluster, K8sApi.StatefulSet);
+
+ try {
+ await statefulSet.get({name: "prometheus", namespace: "lens-metrics"});
+ this.featureStates.prometheus = true;
+ } catch(e) {
+ if (e?.error?.code === 404) {
+ this.featureStates.prometheus = false;
+ } else {
+ this.featureStates.prometheus = undefined;
+ }
+ }
const deployment = K8sApi.forCluster(this.props.cluster, K8sApi.Deployment);
@@ -103,55 +122,47 @@ export class MetricsSettings extends React.Component {
this.config.kubeStateMetrics.enabled = !!this.featureStates.kubeStateMetrics;
this.config.nodeExporter.enabled = !!this.featureStates.nodeExporter;
- if (!this.config.prometheus.enabled && !this.config.kubeStateMetrics.enabled && !this.config.nodeExporter.enabled) {
- await this.feature.uninstall(this.config);
- } else {
- await this.feature.install(this.config);
+ this.inProgress = true;
+
+ try {
+ if (!this.config.prometheus.enabled && !this.config.kubeStateMetrics.enabled && !this.config.nodeExporter.enabled) {
+ await this.feature.uninstall(this.config);
+ } else {
+ await this.feature.install(this.config);
+ }
+ } finally {
+ this.inProgress = false;
+ this.changed = false;
+
+ await this.updateFeatureStates();
}
}
async togglePrometheus(enabled: boolean) {
this.featureStates.prometheus = enabled;
-
- try {
- await this.save();
- } catch(error) {
- this.featureStates.prometheus = !enabled;
- Component.Notifications.error(`Failed to ${enabled ? "enable" : "disable"} Prometheus: ${error}`);
- }
+ this.changed = true;
}
async toggleKubeStateMetrics(enabled: boolean) {
this.featureStates.kubeStateMetrics = enabled;
-
- try {
- await this.save();
- } catch(error) {
- this.featureStates.kubeStateMetrics = !enabled;
- Component.Notifications.error(`Failed to ${enabled ? "enable" : "disable"} kube-state-metrics: ${error}`);
- }
+ this.changed = true;
}
async toggleNodeExporter(enabled: boolean) {
this.featureStates.nodeExporter = enabled;
-
- try {
- await this.save();
- } catch(error) {
- this.featureStates.nodeExporter = !enabled;
- Component.Notifications.error(`Failed to ${enabled ? "enable" : "disable"} node-exporter: ${error}`);
- }
+ this.changed = true;
}
- async updateStack() {
- this.upgrading = true;
+ @computed get buttonLabel() {
+ if (this.inProgress && this.canUpgrade) return "Upgrading ...";
+ if (this.inProgress) return "Applying ...";
+ if (this.canUpgrade) return "Upgrade";
- await this.save();
- setTimeout(() => {
- Component.Notifications.info("Lens Metrics stack updated!", {timeout: 5_000});
- this.upgrading = false;
- this.canUpgrade = false;
- }, 1000);
+ if (this.changed && !this.featureStates.kubeStateMetrics && !this.featureStates.nodeExporter && !this.featureStates.prometheus) {
+ return "Uninstall";
+ }
+
+ return "Apply";
}
render() {
@@ -171,17 +182,6 @@ export class MetricsSettings extends React.Component {
)}
- { this.canUpgrade && (
-
-
-
- this.updateStack() } waiting={this.upgrading} />
-
-
- An update is available for enabled metrics components.
-
-
- )}
{
name="prometheus"
/>
}
- label="Install bundled Prometheus metrics stack"
+ label="Enable bundled Prometheus metrics stack"
/>
Enable timeseries data visualization (Prometheus stack) for your cluster.
@@ -211,11 +211,11 @@ export class MetricsSettings extends React.Component {
name="node-exporter"
/>
}
- label="Install bundled kube-state-metrics stack"
+ label="Enable bundled kube-state-metrics stack"
/>
Enable Kubernetes API object metrics for your cluster.
- Install this only if you don't have existing kube-state-metrics stack installed.
+ Enable this only if you don't have existing kube-state-metrics stack installed.
@@ -230,13 +230,26 @@ export class MetricsSettings extends React.Component {
name="node-exporter"
/>
}
- label="Install bundled node-exporter stack"
+ label="Enable bundled node-exporter stack"
/>
Enable node level metrics for your cluster.
- Install this only if you don't have existing node-exporter stack installed.
+ Enable this only if you don't have existing node-exporter stack installed.
+
+
+ this.save()}
+ primary
+ disabled={!this.changed} />
+
+ {this.canUpgrade && (
+ An update is available for enabled metrics components.
+ )}
+
>
);
}