mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Store prometheus metadata for clusters based on metrics requests
Signed-off-by: Lauri Nevala <lauri.nevala@gmail.com>
This commit is contained in:
parent
04517148c0
commit
2e568d3413
@ -21,7 +21,13 @@ export interface ClusterIconUpload {
|
||||
}
|
||||
|
||||
export interface ClusterMetadata {
|
||||
[key: string]: string | number | boolean;
|
||||
[key: string]: string | number | boolean | object;
|
||||
}
|
||||
|
||||
export type ClusterPrometheusMetadata = {
|
||||
success?: boolean;
|
||||
provider?: string;
|
||||
autoDetected?: boolean;
|
||||
}
|
||||
|
||||
export interface ClusterStoreModel {
|
||||
|
||||
@ -139,6 +139,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
if (ipcMain) {
|
||||
this.eventDisposers.push(
|
||||
reaction(() => this.getState(), () => this.pushState()),
|
||||
reaction(() => this.preferences, () => this.contextHandler.setupPrometheus(this.preferences)),
|
||||
() => {
|
||||
clearInterval(refreshTimer)
|
||||
clearInterval(refreshMetadataTimer)
|
||||
|
||||
@ -22,7 +22,7 @@ export class ContextHandler {
|
||||
this.setupPrometheus(cluster.preferences);
|
||||
}
|
||||
|
||||
protected setupPrometheus(preferences: ClusterPreferences = {}) {
|
||||
public setupPrometheus(preferences: ClusterPreferences = {}) {
|
||||
this.prometheusProvider = preferences.prometheusProvider?.type;
|
||||
this.prometheusPath = null;
|
||||
if (preferences.prometheus) {
|
||||
@ -32,13 +32,18 @@ export class ContextHandler {
|
||||
}
|
||||
|
||||
protected async resolvePrometheusPath(): Promise<string> {
|
||||
const { service, namespace, port } = await this.getPrometheusService()
|
||||
const prometheusService = await this.getPrometheusService()
|
||||
if (!prometheusService) return null
|
||||
const { service, namespace, port } = prometheusService
|
||||
return `${namespace}/services/${service}:${port}`
|
||||
}
|
||||
|
||||
async getPrometheusProvider() {
|
||||
if (!this.prometheusProvider) {
|
||||
const service = await this.getPrometheusService()
|
||||
if (!service) {
|
||||
return null
|
||||
}
|
||||
logger.info(`using ${service.id} as prometheus provider`)
|
||||
this.prometheusProvider = service.id
|
||||
}
|
||||
@ -52,13 +57,7 @@ export class ContextHandler {
|
||||
return await provider.getPrometheusService(apiClient)
|
||||
})
|
||||
const resolvedPrometheusServices = await Promise.all(prometheusPromises)
|
||||
const service = resolvedPrometheusServices.filter(n => n)[0];
|
||||
return service || {
|
||||
id: "lens",
|
||||
namespace: "lens-metrics",
|
||||
service: "prometheus",
|
||||
port: 80
|
||||
}
|
||||
return resolvedPrometheusServices.filter(n => n)[0];
|
||||
}
|
||||
|
||||
async getPrometheusPath(): Promise<string> {
|
||||
|
||||
@ -2,6 +2,7 @@ import { LensApiRequest } from "../router"
|
||||
import { LensApi } from "../lens-api"
|
||||
import { Cluster } from "../cluster"
|
||||
import _ from "lodash"
|
||||
import { ClusterPrometheusMetadata } from "../../common/cluster-store"
|
||||
|
||||
export type IMetricsQuery = string | string[] | {
|
||||
[metricName: string]: string;
|
||||
@ -22,11 +23,8 @@ async function loadMetrics(promQueries: string[], cluster: Cluster, prometheusPa
|
||||
try {
|
||||
return await cluster.getMetrics(prometheusPath, { query, ...queryParams })
|
||||
} catch (error) {
|
||||
if (lastAttempt || error?.statusCode === 404) {
|
||||
return {
|
||||
status: error.toString(),
|
||||
data: { result: [] },
|
||||
}
|
||||
if (lastAttempt || (error?.statusCode >= 400 && error?.statusCode < 500)) {
|
||||
throw new Error("Metrics not available");
|
||||
}
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, (attempt + 1) * 1000)); // add delay before repeating request
|
||||
@ -36,20 +34,25 @@ async function loadMetrics(promQueries: string[], cluster: Cluster, prometheusPa
|
||||
|
||||
return loaders.get(query) ?? loaders.set(query, loadMetricHelper()).get(query)
|
||||
}
|
||||
|
||||
return Promise.all(queries.map(loadMetric))
|
||||
}
|
||||
|
||||
class MetricsRoute extends LensApi {
|
||||
async routeMetrics({ response, cluster, payload, query }: LensApiRequest) {
|
||||
const queryParams: IMetricsQuery = Object.fromEntries(query.entries())
|
||||
|
||||
const prometheusMetadata: ClusterPrometheusMetadata = {}
|
||||
try {
|
||||
const [prometheusPath, prometheusProvider] = await Promise.all([
|
||||
cluster.contextHandler.getPrometheusPath(),
|
||||
cluster.contextHandler.getPrometheusProvider()
|
||||
])
|
||||
|
||||
prometheusMetadata["provider"] = prometheusProvider?.id
|
||||
prometheusMetadata["autoDetected"] = !cluster.preferences.prometheusProvider?.type
|
||||
if (!prometheusPath) {
|
||||
prometheusMetadata["success"] = false
|
||||
this.respondJson(response, {})
|
||||
return
|
||||
}
|
||||
// return data in same structure as query
|
||||
if (typeof payload === "string") {
|
||||
const [data] = await loadMetrics([payload], cluster, prometheusPath, queryParams)
|
||||
@ -65,8 +68,12 @@ class MetricsRoute extends LensApi {
|
||||
const data = Object.fromEntries(Object.keys(payload).map((metricName, i) => [metricName, result[i]]))
|
||||
this.respondJson(response, data)
|
||||
}
|
||||
prometheusMetadata["success"] = true
|
||||
} catch {
|
||||
prometheusMetadata["success"] = false
|
||||
this.respondJson(response, {})
|
||||
} finally {
|
||||
cluster.metadata["prometheus"] = prometheusMetadata
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user