diff --git a/dashboard/client/api/endpoints/cluster.api.ts b/dashboard/client/api/endpoints/cluster.api.ts index 1f772d57bf..e602340219 100644 --- a/dashboard/client/api/endpoints/cluster.api.ts +++ b/dashboard/client/api/endpoints/cluster.api.ts @@ -5,37 +5,21 @@ import { KubeApi } from "../kube-api"; export class ClusterApi extends KubeApi { async getMetrics(nodeNames: string[], params?: IMetricsReqParams): Promise { 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); } } diff --git a/dashboard/client/api/endpoints/ingress.api.ts b/dashboard/client/api/endpoints/ingress.api.ts index 4105f484a9..dc277af04b 100644 --- a/dashboard/client/api/endpoints/ingress.api.ts +++ b/dashboard/client/api/endpoints/ingress.api.ts @@ -5,17 +5,12 @@ import { KubeApi } from "../kube-api"; export class IngressApi extends KubeApi { getMetrics(ingress: string, namespace: string): Promise { - 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, }); diff --git a/dashboard/client/api/endpoints/nodes.api.ts b/dashboard/client/api/endpoints/nodes.api.ts index 862fd831ba..23b42100bb 100644 --- a/dashboard/client/api/endpoints/nodes.api.ts +++ b/dashboard/client/api/endpoints/nodes.api.ts @@ -5,24 +5,15 @@ import { KubeApi } from "../kube-api"; export class NodesApi extends KubeApi { getMetrics(): Promise { - 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 }); } } diff --git a/dashboard/client/api/endpoints/persistent-volume-claims.api.ts b/dashboard/client/api/endpoints/persistent-volume-claims.api.ts index 3f6dafd6b8..f6464cdf67 100644 --- a/dashboard/client/api/endpoints/persistent-volume-claims.api.ts +++ b/dashboard/client/api/endpoints/persistent-volume-claims.api.ts @@ -6,12 +6,9 @@ import { KubeApi } from "../kube-api"; export class PersistentVolumeClaimsApi extends KubeApi { getMetrics(pvcName: string, namespace: string): Promise { - 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 }); diff --git a/dashboard/client/api/endpoints/pods.api.ts b/dashboard/client/api/endpoints/pods.api.ts index 8025d611d1..de0f6e81f5 100644 --- a/dashboard/client/api/endpoints/pods.api.ts +++ b/dashboard/client/api/endpoints/pods.api.ts @@ -11,26 +11,18 @@ export class PodsApi extends KubeApi { getMetrics(pods: Pod[], namespace: string, selector = "pod, namespace"): Promise { 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, }); diff --git a/dashboard/server/common/metrics.ts b/dashboard/server/common/metrics.ts index 6bfd78d52d..60233e420b 100644 --- a/dashboard/server/common/metrics.ts +++ b/dashboard/server/common/metrics.ts @@ -1,4 +1,4 @@ export type IMetricsQuery = string | string[] | { - [metricName: string]: string; + [metricName: string]: string | object; } diff --git a/src/common/prometheus-providers.ts b/src/common/prometheus-providers.ts new file mode 100644 index 0000000000..87f081b94e --- /dev/null +++ b/src/common/prometheus-providers.ts @@ -0,0 +1,11 @@ +import { PrometheusLens } from "../main/prometheus/lens"; +import { PrometheusHelm } from "../main/prometheus/helm"; +import { PrometheusOperator } from "../main/prometheus/operator"; +import { PrometheusProviderRegistry } from "../main/prometheus/provider-registry"; + +[PrometheusLens, PrometheusHelm, PrometheusOperator].forEach(providerClass => { + const provider = new providerClass() + PrometheusProviderRegistry.registerProvider(provider.id, provider) +}); + +export const prometheusProviders = PrometheusProviderRegistry.getProviders() \ No newline at end of file diff --git a/src/main/cluster.ts b/src/main/cluster.ts index cb603e6272..b6323c0a0d 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -47,6 +47,9 @@ export type ClusterPreferences = { service: string; port: number; }; + prometheusProvider?: { + type: string; + }; icon?: string; httpsProxy?: string; } diff --git a/src/main/index.ts b/src/main/index.ts index ec30792bd1..700b44a4e3 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -15,7 +15,7 @@ import { shellSync } from "./shell-sync" import { getFreePort } from "./port" import { mangleProxyEnv } from "./proxy-env" import { findMainWebContents } from "./webcontents" -import { helmCli } from "./helm-cli" +import "../common/prometheus-providers" mangleProxyEnv() if (app.commandLine.getSwitchValue("proxy-server") !== "") { diff --git a/src/main/prometheus/helm.ts b/src/main/prometheus/helm.ts new file mode 100644 index 0000000000..c69df755d5 --- /dev/null +++ b/src/main/prometheus/helm.ts @@ -0,0 +1,10 @@ +import { PrometheusLens } from "./lens" + +export class PrometheusHelm extends PrometheusLens { + constructor() { + super() + this.id = "helm" + this.name = "Helm" + this.rateAccuracy = "5m" + } +} \ No newline at end of file diff --git a/src/main/prometheus/lens.ts b/src/main/prometheus/lens.ts new file mode 100644 index 0000000000..f278000731 --- /dev/null +++ b/src/main/prometheus/lens.ts @@ -0,0 +1,66 @@ +import { PrometheusProvider, PrometheusQueryOpts, PrometheusClusterQuery, PrometheusNodeQuery, PrometheusPodQuery, PrometheusPvcQuery, PrometheusIngressQuery } from "./provider-registry"; + +export class PrometheusLens implements PrometheusProvider { + id = "lens" + name = "Lens" + rateAccuracy = "1m" + + public getQueries(opts: PrometheusQueryOpts): PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery { + switch(opts.category) { + case 'cluster': + return { + 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=~"${opts.nodes}"}`), + memoryRequests: `sum(kube_pod_container_resource_requests{node=~"${opts.nodes}", resource="memory"}) by (component)`, + memoryLimits: `sum(kube_pod_container_resource_limits{node=~"${opts.nodes}", resource="memory"}) by (component)`, + memoryCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="memory"}) by (component)`, + cpuUsage: `sum(rate(node_cpu_seconds_total{kubernetes_node=~"${opts.nodes}", mode=~"user|system"}[${this.rateAccuracy}]))`, + cpuRequests:`sum(kube_pod_container_resource_requests{node=~"${opts.nodes}", resource="cpu"}) by (component)`, + cpuLimits: `sum(kube_pod_container_resource_limits{node=~"${opts.nodes}", resource="cpu"}) by (component)`, + cpuCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="cpu"}) by (component)`, + podUsage: `sum(kubelet_running_pod_count{instance=~"${opts.nodes}"})`, + podCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="pods"}) by (component)`, + fsSize: `sum(node_filesystem_size_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"}) by (kubernetes_node)`, + fsUsage: `sum(node_filesystem_size_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"} - node_filesystem_avail_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"}) by (kubernetes_node)` + } + case 'nodes': + return { + memoryUsage: `sum (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (kubernetes_node)`, + memoryCapacity: `sum(kube_node_status_capacity{resource="memory"}) by (node)`, + cpuUsage: `sum(rate(node_cpu_seconds_total{mode=~"user|system"}[${this.rateAccuracy}])) by(kubernetes_node)`, + cpuCapacity: `sum(kube_node_status_allocatable{resource="cpu"}) by (node)`, + fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"}) by (kubernetes_node)`, + fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) by (kubernetes_node)` + } + case 'pods': + return { + cpuUsage: `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, + cpuRequests: `sum(kube_pod_container_resource_requests{pod=~"${opts.pods}",resource="cpu",namespace="${opts.namespace}"}) by (${opts.selector})`, + cpuLimits: `sum(kube_pod_container_resource_limits{pod=~"${opts.pods}",resource="cpu",namespace="${opts.namespace}"}) by (${opts.selector})`, + memoryUsage: `sum(container_memory_working_set_bytes{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}) by (${opts.selector})`, + memoryRequests: `sum(kube_pod_container_resource_requests{pod=~"${opts.pods}",resource="memory",namespace="${opts.namespace}"}) by (${opts.selector})`, + memoryLimits: `sum(kube_pod_container_resource_limits{pod=~"${opts.pods}",resource="memory",namespace="${opts.namespace}"}) by (${opts.selector})`, + fsUsage: `sum(container_fs_usage_bytes{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}) by (${opts.selector})`, + networkReceive: `sum(rate(container_network_receive_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, + networkTransit: `sum(rate(container_network_transmit_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})` + } + case 'pvc': + return { + diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`, + diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)` + } + case 'ingress': + const bytesSent = (ingress: string, statuses: string) => + `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)` + return { + bytesSentSuccess: bytesSent(opts.igress, "^2\\\\d*"), + bytesSentFailure: bytesSent(opts.ingres, "^5\\\\d*"), + requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`, + responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)` + } + } + } +} \ No newline at end of file diff --git a/src/main/prometheus/operator.ts b/src/main/prometheus/operator.ts new file mode 100644 index 0000000000..a44abbe72f --- /dev/null +++ b/src/main/prometheus/operator.ts @@ -0,0 +1,66 @@ +import { PrometheusProvider, PrometheusQueryOpts, PrometheusClusterQuery, PrometheusNodeQuery, PrometheusPodQuery, PrometheusPvcQuery, PrometheusIngressQuery } from "./provider-registry"; + +export class PrometheusOperator implements PrometheusProvider { + rateAccuracy = "1m" + id = "operator" + name = "Prometheus Operator" + + public getQueries(opts: PrometheusQueryOpts): PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery { + switch(opts.category) { + case 'cluster': + return { + memoryUsage: ` + sum( + node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes) + ) by (node) + `.replace(/_bytes/g, `_bytes * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"}`), + memoryRequests: `sum(kube_pod_container_resource_requests{node=~"${opts.nodes}", resource="memory"}) by (component)`, + memoryLimits: `sum(kube_pod_container_resource_limits{node=~"${opts.nodes}", resource="memory"}) by (component)`, + memoryCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="memory"}) by (component)`, + cpuUsage: `sum(rate(node_cpu_seconds_total{mode=~"user|system"}[${this.rateAccuracy}])* on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"}) by (node)`, + cpuRequests:`sum(kube_pod_container_resource_requests{node=~"${opts.nodes}", resource="cpu"}) by (component)`, + cpuLimits: `sum(kube_pod_container_resource_limits{node=~"${opts.nodes}", resource="cpu"}) by (component)`, + cpuCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="cpu"}) by (component)`, + podUsage: `sum(kubelet_running_pod_count{node=~"${opts.nodes}"})`, + podCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="pods"}) by (component)`, + fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"}) by (node)`, + fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"} - node_filesystem_avail_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"}) by (node)` + } + case 'nodes': + return { + memoryUsage: `sum((node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) * on (pod,namespace) group_left(node) kube_pod_info) by (node)`, + memoryCapacity: `sum(kube_node_status_capacity{resource="memory"}) by (node)`, + cpuUsage: `sum(rate(node_cpu_seconds_total{mode=~"user|system"}[${this.rateAccuracy}]) * on (pod,namespace) group_left(node) kube_pod_info) by (node)`, + cpuCapacity: `sum(kube_node_status_allocatable{resource="cpu"}) by (node)`, + fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info) by (node)`, + fsUsage: `sum((node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) * on (pod,namespace) group_left(node) kube_pod_info) by (node)` + } + case 'pods': + return { + cpuUsage: `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, + cpuRequests: `sum(kube_pod_container_resource_requests{pod=~"${opts.pods}",resource="cpu",namespace="${opts.namespace}"}) by (${opts.selector})`, + cpuLimits: `sum(kube_pod_container_resource_limits{pod=~"${opts.pods}",resource="cpu",namespace="${opts.namespace}"}) by (${opts.selector})`, + memoryUsage: `sum(container_memory_working_set_bytes{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}) by (${opts.selector})`, + memoryRequests: `sum(kube_pod_container_resource_requests{pod=~"${opts.pods}",resource="memory",namespace="${opts.namespace}"}) by (${opts.selector})`, + memoryLimits: `sum(kube_pod_container_resource_limits{pod=~"${opts.pods}",resource="memory",namespace="${opts.namespace}"}) by (${opts.selector})`, + fsUsage: `sum(container_fs_usage_bytes{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}) by (${opts.selector})`, + networkReceive: `sum(rate(container_network_receive_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, + networkTransit: `sum(rate(container_network_transmit_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})` + } + case 'pvc': + return { + diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`, + diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)` + } + case 'ingress': + const bytesSent = (ingress: string, statuses: string) => + `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`; + return { + bytesSentSuccess: bytesSent(opts.igress, "^2\\\\d*"), + bytesSentFailure: bytesSent(opts.ingres, "^5\\\\d*"), + requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`, + responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)` + } + } + } +} \ No newline at end of file diff --git a/src/main/prometheus/provider-registry.ts b/src/main/prometheus/provider-registry.ts new file mode 100644 index 0000000000..d02feb1ab5 --- /dev/null +++ b/src/main/prometheus/provider-registry.ts @@ -0,0 +1,76 @@ +export type PrometheusClusterQuery = { + memoryUsage: string; + memoryRequests: string; + memoryLimits: string; + memoryCapacity: string; + cpuUsage: string; + cpuRequests: string; + cpuLimits: string; + cpuCapacity: string; + podUsage: string; + podCapacity: string; +} + +export type PrometheusNodeQuery = { + memoryUsage: string; + memoryCapacity: string; + cpuUsage: string; + cpuCapacity: string; + fsSize: string; + fsUsage: string; +} + +export type PrometheusPodQuery = { + memoryUsage: string; + memoryRequests: string; + memoryLimits: string; + cpuUsage: string; + cpuRequests: string; + cpuLimits: string; + fsUsage: string; + networkReceive: string; + networkTransit: string; +} + +export type PrometheusPvcQuery = { + diskUsage: string; + diskCapacity: string; +} + +export type PrometheusIngressQuery = { + bytesSentSuccess: string; + bytesSentFailure: string; + requestDurationSeconds: string; + responseDurationSeconds: string; +} + +export type PrometheusQueryOpts = { + [key: string]: string | any; +}; + +export interface PrometheusProvider { + getQueries(opts: PrometheusQueryOpts): PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery; +} + +export type PrometheusProviderList = { + [key: string]: PrometheusProvider; +} + +export class PrometheusProviderRegistry { + private static prometheusProviders: PrometheusProviderList = {} + + static getProvider(type: string): PrometheusProvider { + if (!this.prometheusProviders[type]) { + throw "Unknown Prometheus provider"; + } + return this.prometheusProviders[type] + } + + static registerProvider(key: string, provider: PrometheusProvider) { + this.prometheusProviders[key] = provider + } + + static getProviders(): PrometheusProvider[] { + return Object.values(this.prometheusProviders) + } +} \ No newline at end of file diff --git a/src/main/routes/metrics.ts b/src/main/routes/metrics.ts index 90eecb6685..b7b1a030b0 100644 --- a/src/main/routes/metrics.ts +++ b/src/main/routes/metrics.ts @@ -1,6 +1,7 @@ import { LensApiRequest } from "../router" import { LensApi } from "../lens-api" import * as requestPromise from "request-promise-native" +import { PrometheusProviderRegistry, PrometheusProvider, PrometheusNodeQuery, PrometheusClusterQuery, PrometheusPodQuery, PrometheusPvcQuery, PrometheusIngressQuery, PrometheusQueryOpts} from "../prometheus/provider-registry" type MetricsQuery = string | string[] | { [metricName: string]: string; @@ -22,6 +23,14 @@ class MetricsRoute extends LensApi { queryParams[key] = value }) + const prometheusInstallationSource = cluster.preferences.prometheusProvider?.type || "lens" + let prometheusProvider: PrometheusProvider + try { + prometheusProvider = PrometheusProviderRegistry.getProvider(prometheusInstallationSource) + } catch { + this.respondJson(response, {}) + return + } // prometheus metrics loader const attempts: { [query: string]: number } = {}; const maxAttempts = 5; @@ -61,7 +70,13 @@ class MetricsRoute extends LensApi { else { data = {}; const result = await Promise.all( - Object.values(query).map(loadMetrics) + Object.entries(query).map((queryEntry: any) => { + const queryName: string = queryEntry[0] + const queryOpts: PrometheusQueryOpts = queryEntry[1] + const queries = prometheusProvider.getQueries(queryOpts) + const q = queries[queryName as keyof (PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery)] + return loadMetrics(q) + }) ); Object.keys(query).forEach((metricName, index) => { data[metricName] = result[index]; diff --git a/src/renderer/components/ClusterSettings/Preferences/index.vue b/src/renderer/components/ClusterSettings/Preferences/index.vue index 9753fafb6c..108b6ad207 100644 --- a/src/renderer/components/ClusterSettings/Preferences/index.vue +++ b/src/renderer/components/ClusterSettings/Preferences/index.vue @@ -31,6 +31,16 @@ @blur="onPrometheusSave" /> + + +
@@ -57,6 +67,8 @@