From c049918d25543759872d00314c315f0722c4a28b Mon Sep 17 00:00:00 2001 From: Lauri Nevala Date: Wed, 30 Sep 2020 14:02:18 +0300 Subject: [PATCH] Add support for Docker Enterprise Container Cloud metrics (#998) * Add support for Docker Enterprise Container Cloud metrics Signed-off-by: Lauri Nevala --- src/common/prometheus-providers.ts | 3 +- src/main/prometheus/stacklight.ts | 83 ++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/main/prometheus/stacklight.ts diff --git a/src/common/prometheus-providers.ts b/src/common/prometheus-providers.ts index 87f081b94e..2c6e6fac8e 100644 --- a/src/common/prometheus-providers.ts +++ b/src/common/prometheus-providers.ts @@ -1,9 +1,10 @@ import { PrometheusLens } from "../main/prometheus/lens"; import { PrometheusHelm } from "../main/prometheus/helm"; import { PrometheusOperator } from "../main/prometheus/operator"; +import { PrometheusStacklight } from "../main/prometheus/stacklight"; import { PrometheusProviderRegistry } from "../main/prometheus/provider-registry"; -[PrometheusLens, PrometheusHelm, PrometheusOperator].forEach(providerClass => { +[PrometheusLens, PrometheusHelm, PrometheusOperator, PrometheusStacklight].forEach(providerClass => { const provider = new providerClass() PrometheusProviderRegistry.registerProvider(provider.id, provider) }); diff --git a/src/main/prometheus/stacklight.ts b/src/main/prometheus/stacklight.ts new file mode 100644 index 0000000000..4cb946c81d --- /dev/null +++ b/src/main/prometheus/stacklight.ts @@ -0,0 +1,83 @@ +import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry"; +import { CoreV1Api } from "@kubernetes/client-node"; +import logger from "../logger" + +export class PrometheusStacklight implements PrometheusProvider { + id = "stacklight" + name = "Stacklight" + rateAccuracy = "1m" + + public async getPrometheusService(client: CoreV1Api): Promise { + try { + const resp = await client.readNamespacedService("prometheus-server", "stacklight") + const service = resp.body + return { + id: this.id, + namespace: service.metadata.namespace, + service: service.metadata.name, + port: service.spec.ports[0].port + } + } catch(error) { + logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`) + } + } + + public getQueries(opts: PrometheusQueryOpts): PrometheusQuery { + 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{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{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{node=~"${opts.nodes}", mountpoint="/"}) by (node)`, + fsUsage: `sum(node_filesystem_size_bytes{node=~"${opts.nodes}", mountpoint="/"} - node_filesystem_avail_bytes{node=~"${opts.nodes}", mountpoint="/"}) by (node)` + } + case 'nodes': + return { + memoryUsage: `sum (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (node)`, + memoryCapacity: `sum(kube_node_status_capacity{resource="memory"}) by (node)`, + cpuUsage: `sum(rate(node_cpu_seconds_total{mode=~"user|system"}[${this.rateAccuracy}])) by(node)`, + cpuCapacity: `sum(kube_node_status_allocatable{resource="cpu"}) by (node)`, + fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"}) by (node)`, + fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) 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})`, + networkTransmit: `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)` + } + } + } +}