mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Allow to select Prometheus query style
Signed-off-by: Lauri Nevala <lauri.nevala@gmail.com>
This commit is contained in:
parent
8c666116a3
commit
7476e169b9
@ -5,37 +5,21 @@ import { KubeApi } from "../kube-api";
|
||||
export class ClusterApi extends KubeApi<Cluster> {
|
||||
async getMetrics(nodeNames: string[], params?: IMetricsReqParams): Promise<IClusterMetrics> {
|
||||
const nodes = nodeNames.join("|");
|
||||
const memoryUsage = `
|
||||
sum(
|
||||
node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)
|
||||
) by (kubernetes_name)
|
||||
`.replace(/_bytes/g, `_bytes{kubernetes_node=~"${nodes}"}`);
|
||||
|
||||
const memoryRequests = `sum(kube_pod_container_resource_requests{node=~"${nodes}", resource="memory"}) by (component)`;
|
||||
const memoryLimits = `sum(kube_pod_container_resource_limits{node=~"${nodes}", resource="memory"}) by (component)`;
|
||||
const memoryCapacity = `sum(kube_node_status_capacity{node=~"${nodes}", resource="memory"}) by (component)`;
|
||||
const cpuUsage = `sum(rate(node_cpu_seconds_total{kubernetes_node=~"${nodes}", mode=~"user|system"}[1m]))`;
|
||||
const cpuRequests = `sum(kube_pod_container_resource_requests{node=~"${nodes}", resource="cpu"}) by (component)`;
|
||||
const cpuLimits = `sum(kube_pod_container_resource_limits{node=~"${nodes}", resource="cpu"}) by (component)`;
|
||||
const cpuCapacity = `sum(kube_node_status_capacity{node=~"${nodes}", resource="cpu"}) by (component)`;
|
||||
const podUsage = `sum(kubelet_running_pod_count{instance=~"${nodes}"})`;
|
||||
const podCapacity = `sum(kube_node_status_capacity{node=~"${nodes}", resource="pods"}) by (component)`;
|
||||
const fsSize = `sum(node_filesystem_size_bytes{kubernetes_node=~"${nodes}", mountpoint="/"}) by (kubernetes_node)`;
|
||||
const fsUsage = `sum(node_filesystem_size_bytes{kubernetes_node=~"${nodes}", mountpoint="/"} - node_filesystem_avail_bytes{kubernetes_node=~"${nodes}", mountpoint="/"}) by (kubernetes_node)`;
|
||||
const opts = { category: "cluster", nodes: nodes }
|
||||
|
||||
return metricsApi.getMetrics({
|
||||
memoryUsage,
|
||||
memoryRequests,
|
||||
memoryLimits,
|
||||
memoryCapacity,
|
||||
cpuUsage,
|
||||
cpuRequests,
|
||||
cpuLimits,
|
||||
cpuCapacity,
|
||||
podUsage,
|
||||
podCapacity,
|
||||
fsSize,
|
||||
fsUsage
|
||||
memoryUsage: opts,
|
||||
memoryRequests: opts,
|
||||
memoryLimits: opts,
|
||||
memoryCapacity: opts,
|
||||
cpuUsage: opts,
|
||||
cpuRequests: opts,
|
||||
cpuLimits: opts,
|
||||
cpuCapacity: opts,
|
||||
podUsage: opts,
|
||||
podCapacity: opts,
|
||||
fsSize: opts,
|
||||
fsUsage: opts
|
||||
}, params);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,17 +5,12 @@ import { KubeApi } from "../kube-api";
|
||||
|
||||
export class IngressApi extends KubeApi<Ingress> {
|
||||
getMetrics(ingress: string, namespace: string): Promise<IIngressMetrics> {
|
||||
const bytesSent = (statuses: string) =>
|
||||
`sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[1m])) by (ingress)`;
|
||||
const bytesSentSuccess = bytesSent("^2\\\\d*"); // Requests with status 2**
|
||||
const bytesSentFailure = bytesSent("^5\\\\d*"); // Requests with status 5**
|
||||
const requestDurationSeconds = `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${ingress}"}[1m])) by (ingress)`;
|
||||
const responseDurationSeconds = `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${ingress}"}[1m])) by (ingress)`;
|
||||
const opts = { category: "ingress", ingress }
|
||||
return metricsApi.getMetrics({
|
||||
bytesSentSuccess,
|
||||
bytesSentFailure,
|
||||
requestDurationSeconds,
|
||||
responseDurationSeconds
|
||||
bytesSentSuccess: opts,
|
||||
bytesSentFailure: opts,
|
||||
requestDurationSeconds: opts,
|
||||
responseDurationSeconds: opts
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
|
||||
@ -5,24 +5,15 @@ import { KubeApi } from "../kube-api";
|
||||
|
||||
export class NodesApi extends KubeApi<Node> {
|
||||
getMetrics(): Promise<INodeMetrics> {
|
||||
const memoryUsage = `
|
||||
sum (
|
||||
node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)
|
||||
) by (kubernetes_node)
|
||||
`;
|
||||
const memoryCapacity = `sum(kube_node_status_capacity{resource="memory"}) by (node)`;
|
||||
const cpuUsage = `sum(rate(node_cpu_seconds_total{mode=~"user|system"}[1m])) by(kubernetes_node)`;
|
||||
const cpuCapacity = `sum(kube_node_status_allocatable{resource="cpu"}) by (node)`;
|
||||
const fsSize = `sum(node_filesystem_size_bytes{mountpoint="/"}) by (kubernetes_node)`;
|
||||
const fsUsage = `sum(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) by (kubernetes_node)`;
|
||||
const opts = { category: "nodes"}
|
||||
|
||||
return metricsApi.getMetrics({
|
||||
memoryUsage,
|
||||
memoryCapacity,
|
||||
cpuUsage,
|
||||
cpuCapacity,
|
||||
fsSize,
|
||||
fsUsage
|
||||
memoryUsage: opts,
|
||||
memoryCapacity: opts,
|
||||
cpuUsage: opts,
|
||||
cpuCapacity: opts,
|
||||
fsSize: opts,
|
||||
fsUsage: opts
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,12 +6,9 @@ import { KubeApi } from "../kube-api";
|
||||
|
||||
export class PersistentVolumeClaimsApi extends KubeApi<PersistentVolumeClaim> {
|
||||
getMetrics(pvcName: string, namespace: string): Promise<IPvcMetrics> {
|
||||
const diskUsage = `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${pvcName}"}) by (persistentvolumeclaim, namespace)`;
|
||||
const diskCapacity = `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${pvcName}"}) by (persistentvolumeclaim, namespace)`;
|
||||
|
||||
return metricsApi.getMetrics({
|
||||
diskUsage,
|
||||
diskCapacity
|
||||
diskUsage: { category: 'pvc', pvc: pvcName },
|
||||
diskCapacity: { category: 'pvc', pvc: pvcName }
|
||||
}, {
|
||||
namespace
|
||||
});
|
||||
|
||||
@ -11,26 +11,18 @@ export class PodsApi extends KubeApi<Pod> {
|
||||
|
||||
getMetrics(pods: Pod[], namespace: string, selector = "pod, namespace"): Promise<IPodMetrics> {
|
||||
const podSelector = pods.map(pod => pod.getName()).join("|");
|
||||
const cpuUsage = `sum(rate(container_cpu_usage_seconds_total{container_name!="POD",container_name!="",pod_name=~"${podSelector}",namespace="${namespace}"}[1m])) by (${selector})`;
|
||||
const cpuRequests = `sum(kube_pod_container_resource_requests{pod=~"${podSelector}",resource="cpu",namespace="${namespace}"}) by (${selector})`;
|
||||
const cpuLimits = `sum(kube_pod_container_resource_limits{pod=~"${podSelector}",resource="cpu",namespace="${namespace}"}) by (${selector})`;
|
||||
const memoryUsage = `sum(container_memory_working_set_bytes{container_name!="POD",container_name!="",pod_name=~"${podSelector}",namespace="${namespace}"}) by (${selector})`;
|
||||
const memoryRequests = `sum(kube_pod_container_resource_requests{pod=~"${podSelector}",resource="memory",namespace="${namespace}"}) by (${selector})`;
|
||||
const memoryLimits = `sum(kube_pod_container_resource_limits{pod=~"${podSelector}",resource="memory",namespace="${namespace}"}) by (${selector})`;
|
||||
const fsUsage = `sum(container_fs_usage_bytes{container_name!="POD",container_name!="",pod_name=~"${podSelector}",namespace="${namespace}"}) by (${selector})`;
|
||||
const networkReceive = `sum(rate(container_network_receive_bytes_total{pod_name=~"${podSelector}",namespace="${namespace}"}[1m])) by (${selector})`;
|
||||
const networkTransit = `sum(rate(container_network_transmit_bytes_total{pod_name=~"${podSelector}",namespace="${namespace}"}[1m])) by (${selector})`;
|
||||
const opts = { category: "pods", pods: podSelector, namespace, selector }
|
||||
|
||||
return metricsApi.getMetrics({
|
||||
cpuUsage,
|
||||
cpuRequests,
|
||||
cpuLimits,
|
||||
memoryUsage,
|
||||
memoryRequests,
|
||||
memoryLimits,
|
||||
fsUsage,
|
||||
networkReceive,
|
||||
networkTransit,
|
||||
cpuUsage: opts,
|
||||
cpuRequests: opts,
|
||||
cpuLimits: opts,
|
||||
memoryUsage: opts,
|
||||
memoryRequests: opts,
|
||||
memoryLimits: opts,
|
||||
fsUsage: opts,
|
||||
networkReceive: opts,
|
||||
networkTransit: opts,
|
||||
}, {
|
||||
namespace,
|
||||
});
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
|
||||
export type IMetricsQuery = string | string[] | {
|
||||
[metricName: string]: string;
|
||||
[metricName: string]: string | object;
|
||||
}
|
||||
|
||||
@ -47,6 +47,7 @@ export type ClusterPreferences = {
|
||||
service: string;
|
||||
port: number;
|
||||
};
|
||||
prometheusSource?: string;
|
||||
icon?: string;
|
||||
httpsProxy?: string;
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import { LensApiRequest } from "../router"
|
||||
import { LensApi } from "../lens-api"
|
||||
import * as requestPromise from "request-promise-native"
|
||||
import logger from "../logger"
|
||||
import { PrometheusProviderFactory} from "../prometheus/provider"
|
||||
|
||||
type MetricsQuery = string | string[] | {
|
||||
[metricName: string]: string;
|
||||
@ -22,10 +24,12 @@ class MetricsRoute extends LensApi {
|
||||
queryParams[key] = value
|
||||
})
|
||||
|
||||
const prometheusInstallationSource = cluster.preferences.prometheusSource || "lens"
|
||||
// prometheus metrics loader
|
||||
const attempts: { [query: string]: number } = {};
|
||||
const maxAttempts = 5;
|
||||
const loadMetrics = (orgQuery: string): Promise<any> => {
|
||||
logger.info(orgQuery)
|
||||
const query = orgQuery.trim()
|
||||
const attempt = attempts[query] = (attempts[query] || 0) + 1;
|
||||
return requestPromise(metricsUrl, {
|
||||
@ -61,8 +65,15 @@ class MetricsRoute extends LensApi {
|
||||
else {
|
||||
data = {};
|
||||
const result = await Promise.all(
|
||||
Object.values(query).map(loadMetrics)
|
||||
Object.entries(query).map((objectArr: any) => {
|
||||
const queryName = objectArr[0]
|
||||
const queryOpts = objectArr[1]
|
||||
logger.info(prometheusInstallationSource)
|
||||
const q = PrometheusProviderFactory.createProvider(prometheusInstallationSource).getQueries(queryOpts)[queryName]
|
||||
return loadMetrics(q)
|
||||
})
|
||||
);
|
||||
logger.info(JSON.stringify(result))
|
||||
Object.keys(query).forEach((metricName, index) => {
|
||||
data[metricName] = result[index];
|
||||
});
|
||||
|
||||
@ -31,6 +31,16 @@
|
||||
@blur="onPrometheusSave"
|
||||
/>
|
||||
</b-form-group>
|
||||
<b-form-group
|
||||
label="Prometheus installation method."
|
||||
description="What query format is used to fetch metrics from Prometheus"
|
||||
>
|
||||
<b-form-select
|
||||
v-model="prometheusSource"
|
||||
:options="prometheusSources"
|
||||
@change="onPrometheusSourceSave"
|
||||
/>
|
||||
</b-form-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
@ -57,6 +67,7 @@
|
||||
|
||||
<script>
|
||||
import { lstatSync } from "fs"
|
||||
import { logger } from 'handlebars';
|
||||
export default {
|
||||
name: 'ClusterSettingsPreferences',
|
||||
props: {
|
||||
@ -70,18 +81,32 @@ export default {
|
||||
errors: {
|
||||
terminalcwd: null
|
||||
},
|
||||
prometheusPath: ""
|
||||
prometheusPath: "",
|
||||
prometheusSource: "",
|
||||
prometheusSources: [
|
||||
{ text: "Lens", value: "lens"},
|
||||
{ text: "Helm", value: "helm"},
|
||||
{ text: "Prometheus Operator", value: "operator"}
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted: function() {
|
||||
if (this.cluster.preferences.prometheus) {
|
||||
const prom = this.cluster.preferences.prometheus;
|
||||
this.prometheusPath = `${prom.namespace}/${prom.service}:${prom.port}`
|
||||
}
|
||||
this.updateValues()
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
methods: {
|
||||
updateValues: function(){
|
||||
if (this.cluster.preferences.prometheus) {
|
||||
const prom = this.cluster.preferences.prometheus;
|
||||
this.prometheusPath = `${prom.namespace}/${prom.service}:${prom.port}`
|
||||
} else {
|
||||
this.prometheusPath = ""
|
||||
}
|
||||
|
||||
this.prometheusSource = this.cluster.preferences.prometheusSource || "lens"
|
||||
console.log(this.prometheusSource)
|
||||
},
|
||||
parsePrometheusPath: function(path) {
|
||||
let parsed = path.split(/\/|:/)
|
||||
return {
|
||||
@ -121,10 +146,21 @@ export default {
|
||||
}
|
||||
this.$store.dispatch("storeCluster", this.cluster);
|
||||
},
|
||||
onPrometheusSourceSave: function() {
|
||||
if (this.prometheusSource === "") {
|
||||
this.cluster.preferences.prometheusSource = null;
|
||||
} else {
|
||||
this.cluster.preferences.prometheusSource = this.prometheusSource
|
||||
}
|
||||
this.$store.dispatch("storeCluster", this.cluster);
|
||||
},
|
||||
onTerminalCwdSave: function() {
|
||||
if(this.cluster.preferences.terminalCWD === "") this.cluster.preferences.terminalCWD = null
|
||||
this.$store.dispatch("storeCluster", this.cluster);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
"cluster": "updateValues",
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user