mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
auto-detect prometheus installation
Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
parent
6412d73a5a
commit
e23c8cfb6b
@ -95,7 +95,6 @@ export class Cluster implements ClusterInfo {
|
||||
this.contextName = kc.currentContext
|
||||
this.url = this.contextHandler.url
|
||||
this.apiUrl = kc.getCurrentCluster().server
|
||||
await this.contextHandler.init()
|
||||
}
|
||||
|
||||
public stopServer() {
|
||||
@ -120,7 +119,7 @@ export class Cluster implements ClusterInfo {
|
||||
|
||||
public async refreshCluster() {
|
||||
clusterStore.reloadCluster(this)
|
||||
this.contextHandler.setClusterPreferences(this.preferences)
|
||||
await this.contextHandler.setClusterPreferences(this.preferences)
|
||||
|
||||
const connectionStatus = await this.getConnectionStatus()
|
||||
if (connectionStatus == ClusterStatus.AccessGranted) {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { KubeConfig } from "@kubernetes/client-node"
|
||||
import { KubeConfig, CoreV1Api } from "@kubernetes/client-node"
|
||||
import { readFileSync } from "fs"
|
||||
import * as http from "http"
|
||||
import { ServerOptions } from "http-proxy"
|
||||
@ -7,6 +7,8 @@ import logger from "./logger"
|
||||
import { getFreePort } from "./port"
|
||||
import { KubeAuthProxy } from "./kube-auth-proxy"
|
||||
import { Cluster, ClusterPreferences } from "./cluster"
|
||||
import { prometheusProviders } from "../common/prometheus-providers"
|
||||
import { PrometheusService, PrometheusProvider } from "./prometheus/provider-registry"
|
||||
|
||||
export class ContextHandler {
|
||||
public contextName: string
|
||||
@ -56,7 +58,6 @@ export class ContextHandler {
|
||||
this.defaultNamespace = kc.getContextObject(kc.currentContext).namespace
|
||||
this.url = `http://${this.id}.localhost:${cluster.port}/`
|
||||
this.kubernetesApi = `http://127.0.0.1:${cluster.port}/${this.id}`
|
||||
this.setClusterPreferences(cluster.preferences)
|
||||
this.kc.clusters = [
|
||||
{
|
||||
name: kc.getCurrentCluster().name,
|
||||
@ -64,14 +65,16 @@ export class ContextHandler {
|
||||
skipTLSVerify: true
|
||||
}
|
||||
]
|
||||
this.setClusterPreferences(cluster.preferences)
|
||||
}
|
||||
|
||||
public setClusterPreferences(clusterPreferences?: ClusterPreferences) {
|
||||
public async setClusterPreferences(clusterPreferences?: ClusterPreferences) {
|
||||
if (clusterPreferences && clusterPreferences.prometheus) {
|
||||
const prom = clusterPreferences.prometheus
|
||||
this.prometheusPath = `${prom.namespace}/services/${prom.service}:${prom.port}`
|
||||
} else {
|
||||
this.prometheusPath = "lens-metrics/services/prometheus:80"
|
||||
const path = await this.resolvePrometheusPath(clusterPreferences.prometheusProvider?.type)
|
||||
this.prometheusPath = path ? path : "lens-metrics/services/prometheus:80"
|
||||
}
|
||||
if(clusterPreferences && clusterPreferences.clusterName) {
|
||||
this.clusterName = clusterPreferences.clusterName;
|
||||
@ -80,26 +83,22 @@ export class ContextHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public getPrometheusPath() {
|
||||
return this.prometheusPath
|
||||
protected async resolvePrometheusPath(providerId: string): Promise<string> {
|
||||
const apiClient = this.kc.makeApiClient(CoreV1Api)
|
||||
const providers = providerId ? prometheusProviders.filter((p, _) => p.id == providerId) : prometheusProviders
|
||||
const prometheusPromises: Promise<PrometheusService>[] = providers.map(async (provider: PrometheusProvider): Promise<PrometheusService> => {
|
||||
return await provider.getPrometheusService(apiClient)
|
||||
})
|
||||
const resolvedPrometheusServices = await Promise.all(prometheusPromises)
|
||||
const service = resolvedPrometheusServices.filter(n => n)[0]
|
||||
console.log(service)
|
||||
if (service) {
|
||||
return `${service.namespace}/services/${service.service}:${service.port}`
|
||||
}
|
||||
}
|
||||
|
||||
public async init() {
|
||||
const currentCluster = this.kc.getCurrentCluster()
|
||||
if (currentCluster.caFile) {
|
||||
this.certData = readFileSync(currentCluster.caFile).toString()
|
||||
} else if (currentCluster.caData) {
|
||||
this.certData = Buffer.from(currentCluster.caData, "base64").toString("ascii")
|
||||
}
|
||||
const user = this.kc.getCurrentUser()
|
||||
if (user.authProvider && user.authProvider.name === "oidc") {
|
||||
const authConfig = user.authProvider.config
|
||||
if (authConfig["idp-certificate-authority"]) {
|
||||
this.authCertData = readFileSync(authConfig["idp-certificate-authority"]).toString()
|
||||
} else if (authConfig["idp-certificate-authority-data"]) {
|
||||
this.authCertData = Buffer.from(authConfig["idp-certificate-authority-data"], "base64").toString("ascii")
|
||||
}
|
||||
}
|
||||
public getPrometheusPath() {
|
||||
return this.prometheusPath
|
||||
}
|
||||
|
||||
public async getApiTarget(isWatchRequest = false) {
|
||||
|
||||
@ -1,10 +1,29 @@
|
||||
import { PrometheusLens } from "./lens"
|
||||
import { CoreV1Api } from "@kubernetes/client-node"
|
||||
import { PrometheusService } from "./provider-registry";
|
||||
import logger from "../logger"
|
||||
|
||||
export class PrometheusHelm extends PrometheusLens {
|
||||
constructor() {
|
||||
super()
|
||||
this.id = "helm"
|
||||
this.name = "Helm"
|
||||
this.rateAccuracy = "5m"
|
||||
id = "helm"
|
||||
name = "helm"
|
||||
rateAccuracy = "5m"
|
||||
|
||||
public async getPrometheusService(client: CoreV1Api): Promise<PrometheusService> {
|
||||
const labelSelector = "app=prometheus,component=server,heritage=Helm"
|
||||
try {
|
||||
const serviceList = await client.listServiceForAllNamespaces(false, "", null, labelSelector)
|
||||
const service = serviceList.body.items[0]
|
||||
if (!service) return
|
||||
|
||||
return {
|
||||
id: this.id,
|
||||
namespace: service.metadata.namespace,
|
||||
service: service.metadata.name,
|
||||
port: service.spec.ports[0].port
|
||||
}
|
||||
} catch(error) {
|
||||
logger.warn(`failed to list services: ${error.toString()}`)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,21 @@
|
||||
import { PrometheusProvider, PrometheusQueryOpts, PrometheusClusterQuery, PrometheusNodeQuery, PrometheusPodQuery, PrometheusPvcQuery, PrometheusIngressQuery } from "./provider-registry";
|
||||
import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry";
|
||||
import { CoreV1Api } from "@kubernetes/client-node";
|
||||
|
||||
export class PrometheusLens implements PrometheusProvider {
|
||||
id = "lens"
|
||||
name = "Lens"
|
||||
rateAccuracy = "1m"
|
||||
|
||||
public getQueries(opts: PrometheusQueryOpts): PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery {
|
||||
public async getPrometheusService(client: CoreV1Api): Promise<PrometheusService> {
|
||||
return {
|
||||
id: this.id,
|
||||
namespace: "lens-metrics",
|
||||
service: "prometheus",
|
||||
port: 80
|
||||
}
|
||||
}
|
||||
|
||||
public getQueries(opts: PrometheusQueryOpts): PrometheusQuery {
|
||||
switch(opts.category) {
|
||||
case 'cluster':
|
||||
return {
|
||||
@ -63,4 +73,4 @@ export class PrometheusLens implements PrometheusProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,33 @@
|
||||
import { PrometheusProvider, PrometheusQueryOpts, PrometheusClusterQuery, PrometheusNodeQuery, PrometheusPodQuery, PrometheusPvcQuery, PrometheusIngressQuery } from "./provider-registry";
|
||||
import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry";
|
||||
import { CoreV1Api } from "@kubernetes/client-node";
|
||||
import logger from "../logger";
|
||||
|
||||
export class PrometheusOperator implements PrometheusProvider {
|
||||
rateAccuracy = "1m"
|
||||
id = "operator"
|
||||
name = "Prometheus Operator"
|
||||
|
||||
public getQueries(opts: PrometheusQueryOpts): PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery {
|
||||
public async getPrometheusService(client: CoreV1Api): Promise<PrometheusService> {
|
||||
const labelSelector = "operated-prometheus==true"
|
||||
try {
|
||||
const serviceList = await client.listServiceForAllNamespaces(false, "", null, labelSelector)
|
||||
const service = serviceList.body.items[0]
|
||||
if (!service) return
|
||||
|
||||
return {
|
||||
id: this.id,
|
||||
namespace: service.metadata.namespace,
|
||||
service: service.metadata.name,
|
||||
port: service.spec.ports[0].port
|
||||
}
|
||||
} catch(error) {
|
||||
console.error(error)
|
||||
logger.warn(`failed to list services: ${error.toString()}`)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
public getQueries(opts: PrometheusQueryOpts): PrometheusQuery {
|
||||
switch(opts.category) {
|
||||
case 'cluster':
|
||||
return {
|
||||
@ -63,4 +85,4 @@ export class PrometheusOperator implements PrometheusProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { CoreV1Api } from "@kubernetes/client-node"
|
||||
|
||||
export type PrometheusClusterQuery = {
|
||||
memoryUsage: string;
|
||||
memoryRequests: string;
|
||||
@ -48,8 +50,20 @@ export type PrometheusQueryOpts = {
|
||||
[key: string]: string | any;
|
||||
};
|
||||
|
||||
export type PrometheusQuery = PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery
|
||||
|
||||
export type PrometheusService = {
|
||||
id: string;
|
||||
namespace: string;
|
||||
service: string;
|
||||
port: number;
|
||||
}
|
||||
|
||||
export interface PrometheusProvider {
|
||||
getQueries(opts: PrometheusQueryOpts): PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery;
|
||||
id: string;
|
||||
name: string;
|
||||
getQueries(opts: PrometheusQueryOpts): PrometheusQuery;
|
||||
getPrometheusService(client: CoreV1Api): Promise<PrometheusService>;
|
||||
}
|
||||
|
||||
export type PrometheusProviderList = {
|
||||
@ -73,4 +87,4 @@ export class PrometheusProviderRegistry {
|
||||
static getProviders(): PrometheusProvider[] {
|
||||
return Object.values(this.prometheusProviders)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,17 +20,7 @@
|
||||
<div class="cluster-settings-section">
|
||||
<b>Prometheus</b>
|
||||
<p>Use pre-installed Prometheus service for metrics. Please refer to the <a href="https://github.com/lensapp/lens/blob/master/troubleshooting/custom-prometheus.md">guide</a> for possible configuration changes.</p>
|
||||
<b-form-group
|
||||
label="Prometheus service address."
|
||||
description="A path to an existing Prometheus installation (<namespace>/<service>:<port>)."
|
||||
>
|
||||
<b-form-input
|
||||
v-model="prometheusPath"
|
||||
placeholder="lens-metrics/prometheus:80"
|
||||
id="input-prometheuspath"
|
||||
@blur="onPrometheusSave"
|
||||
/>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group
|
||||
label="Prometheus installation method."
|
||||
description="What query format is used to fetch metrics from Prometheus"
|
||||
@ -41,6 +31,18 @@
|
||||
@change="onPrometheusProviderSave"
|
||||
/>
|
||||
</b-form-group>
|
||||
<b-form-group
|
||||
label="Prometheus service address."
|
||||
description="A path to an existing Prometheus installation (<namespace>/<service>:<port>)."
|
||||
v-if="canEditPrometheusPath"
|
||||
>
|
||||
<b-form-input
|
||||
v-model="prometheusPath"
|
||||
placeholder="lens-metrics/prometheus:80"
|
||||
id="input-prometheuspath"
|
||||
@blur="onPrometheusSave"
|
||||
/>
|
||||
</b-form-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
@ -84,13 +86,25 @@ export default {
|
||||
},
|
||||
prometheusPath: "",
|
||||
prometheusProvider: "",
|
||||
prometheusProviders: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
prometheusProviders: function() {
|
||||
const providers = prometheusProviders.map((provider) => {
|
||||
return { text: provider.name, value: provider.id }
|
||||
})
|
||||
providers.unshift({text: "Auto detect", value: ""})
|
||||
|
||||
return providers;
|
||||
},
|
||||
canEditPrometheusPath: function() {
|
||||
if (this.prometheusProvider === "") return false
|
||||
if (this.prometheusProvider === "lens") return false
|
||||
|
||||
return true
|
||||
}
|
||||
},
|
||||
mounted: async function() {
|
||||
this.prometheusProviders = prometheusProviders.map((provider) => {
|
||||
return { text: provider.name, value: provider.id }
|
||||
})
|
||||
this.updateValues()
|
||||
},
|
||||
methods: {
|
||||
@ -104,7 +118,7 @@ export default {
|
||||
if (this.cluster.preferences.prometheusProvider) {
|
||||
this.prometheusProvider = this.cluster.preferences.prometheusProvider.type
|
||||
} else {
|
||||
this.prometheusProvider = "lens"
|
||||
this.prometheusProvider = ""
|
||||
}
|
||||
},
|
||||
parsePrometheusPath: function(path) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user