mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Merge branch 'master' into feature/prometheus-api-prefix
Signed-off-by: Lauri Nevala <lauri.nevala@gmail.com>
This commit is contained in:
commit
85f2f43cf7
@ -86,6 +86,9 @@ export class EndpointSubset implements IEndpointSubset {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return this.addresses.map(address => {
|
return this.addresses.map(address => {
|
||||||
|
if (!this.ports) {
|
||||||
|
return address.ip
|
||||||
|
}
|
||||||
return this.ports.map(port => {
|
return this.ports.map(port => {
|
||||||
return `${address.ip}:${port.port}`
|
return `${address.ip}:${port.port}`
|
||||||
}).join(", ")
|
}).join(", ")
|
||||||
|
|||||||
@ -170,7 +170,12 @@ export class HelmRelease implements ItemObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getVersion() {
|
getVersion() {
|
||||||
return this.chart.match(/(\d+)[^-]*$/)[0];
|
const versions = this.chart.match(/(\d+)[^-]*$/)
|
||||||
|
if (versions) {
|
||||||
|
return versions[0]
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getUpdated(humanize = true, compact = true) {
|
getUpdated(humanize = true, compact = true) {
|
||||||
|
|||||||
@ -2,13 +2,10 @@ import { EventEmitter } from 'events'
|
|||||||
|
|
||||||
class MockServer extends EventEmitter {
|
class MockServer extends EventEmitter {
|
||||||
listen = jest.fn((obj) => {
|
listen = jest.fn((obj) => {
|
||||||
if(obj.port < 9003) {
|
|
||||||
this.emit('error', new Error("fail!"))
|
|
||||||
} else {
|
|
||||||
this.emit('listening', {})
|
this.emit('listening', {})
|
||||||
}
|
|
||||||
return this
|
return this
|
||||||
})
|
})
|
||||||
|
address = () => { return { port: 12345 }}
|
||||||
unref = jest.fn()
|
unref = jest.fn()
|
||||||
close = jest.fn((cb) => {
|
close = jest.fn((cb) => {
|
||||||
cb()
|
cb()
|
||||||
@ -29,11 +26,7 @@ describe("getFreePort", () => {
|
|||||||
jest.clearAllMocks()
|
jest.clearAllMocks()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("fails for an invalid range", async () => {
|
|
||||||
return expect(port.getFreePort(1, 2)).rejects.toMatch('free port')
|
|
||||||
})
|
|
||||||
|
|
||||||
it("finds the next free port", async () => {
|
it("finds the next free port", async () => {
|
||||||
return expect(port.getFreePort(9000, 9005)).resolves.toBe(9003)
|
return expect(port.getFreePort()).resolves.toEqual(expect.any(Number))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -96,7 +96,6 @@ export class Cluster implements ClusterInfo {
|
|||||||
this.contextName = kc.currentContext
|
this.contextName = kc.currentContext
|
||||||
this.url = this.contextHandler.url
|
this.url = this.contextHandler.url
|
||||||
this.apiUrl = kc.getCurrentCluster().server
|
this.apiUrl = kc.getCurrentCluster().server
|
||||||
await this.contextHandler.init()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public stopServer() {
|
public stopServer() {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { KubeConfig } from "@kubernetes/client-node"
|
import { KubeConfig, CoreV1Api } from "@kubernetes/client-node"
|
||||||
import { readFileSync } from "fs"
|
import { readFileSync } from "fs"
|
||||||
import * as http from "http"
|
import * as http from "http"
|
||||||
import { ServerOptions } from "http-proxy"
|
import { ServerOptions } from "http-proxy"
|
||||||
@ -7,6 +7,9 @@ import logger from "./logger"
|
|||||||
import { getFreePort } from "./port"
|
import { getFreePort } from "./port"
|
||||||
import { KubeAuthProxy } from "./kube-auth-proxy"
|
import { KubeAuthProxy } from "./kube-auth-proxy"
|
||||||
import { Cluster, ClusterPreferences } from "./cluster"
|
import { Cluster, ClusterPreferences } from "./cluster"
|
||||||
|
import { prometheusProviders } from "../common/prometheus-providers"
|
||||||
|
import { PrometheusService, PrometheusProvider } from "./prometheus/provider-registry"
|
||||||
|
import { PrometheusLens } from "./prometheus/lens"
|
||||||
|
|
||||||
export class ContextHandler {
|
export class ContextHandler {
|
||||||
public contextName: string
|
public contextName: string
|
||||||
@ -28,6 +31,7 @@ export class ContextHandler {
|
|||||||
protected defaultNamespace: string
|
protected defaultNamespace: string
|
||||||
protected proxyPort: number
|
protected proxyPort: number
|
||||||
protected kubernetesApi: string
|
protected kubernetesApi: string
|
||||||
|
protected prometheusProvider: string
|
||||||
protected prometheusPath: string
|
protected prometheusPath: string
|
||||||
protected clusterName: string
|
protected clusterName: string
|
||||||
|
|
||||||
@ -56,7 +60,6 @@ export class ContextHandler {
|
|||||||
this.defaultNamespace = kc.getContextObject(kc.currentContext).namespace
|
this.defaultNamespace = kc.getContextObject(kc.currentContext).namespace
|
||||||
this.url = `http://${this.id}.localhost:${cluster.port}/`
|
this.url = `http://${this.id}.localhost:${cluster.port}/`
|
||||||
this.kubernetesApi = `http://127.0.0.1:${cluster.port}/${this.id}`
|
this.kubernetesApi = `http://127.0.0.1:${cluster.port}/${this.id}`
|
||||||
this.setClusterPreferences(cluster.preferences)
|
|
||||||
this.kc.clusters = [
|
this.kc.clusters = [
|
||||||
{
|
{
|
||||||
name: kc.getCurrentCluster().name,
|
name: kc.getCurrentCluster().name,
|
||||||
@ -64,14 +67,17 @@ export class ContextHandler {
|
|||||||
skipTLSVerify: true
|
skipTLSVerify: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
this.setClusterPreferences(cluster.preferences)
|
||||||
}
|
}
|
||||||
|
|
||||||
public setClusterPreferences(clusterPreferences?: ClusterPreferences) {
|
public setClusterPreferences(clusterPreferences?: ClusterPreferences) {
|
||||||
|
this.prometheusProvider = clusterPreferences.prometheusProvider?.type
|
||||||
|
|
||||||
if (clusterPreferences && clusterPreferences.prometheus) {
|
if (clusterPreferences && clusterPreferences.prometheus) {
|
||||||
const prom = clusterPreferences.prometheus
|
const prom = clusterPreferences.prometheus
|
||||||
this.prometheusPath = `${prom.namespace}/services/${prom.service}:${prom.port}`
|
this.prometheusPath = `${prom.namespace}/services/${prom.service}:${prom.port}`
|
||||||
} else {
|
} else {
|
||||||
this.prometheusPath = "lens-metrics/services/prometheus:80"
|
this.prometheusPath = null
|
||||||
}
|
}
|
||||||
if(clusterPreferences && clusterPreferences.clusterName) {
|
if(clusterPreferences && clusterPreferences.clusterName) {
|
||||||
this.clusterName = clusterPreferences.clusterName;
|
this.clusterName = clusterPreferences.clusterName;
|
||||||
@ -80,28 +86,48 @@ export class ContextHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPrometheusPath() {
|
protected async resolvePrometheusPath(): Promise<string> {
|
||||||
return this.prometheusPath
|
const service = await this.getPrometheusService()
|
||||||
|
return `${service.namespace}/services/${service.service}:${service.port}`
|
||||||
}
|
}
|
||||||
|
|
||||||
public async init() {
|
public async getPrometheusProvider() {
|
||||||
const currentCluster = this.kc.getCurrentCluster()
|
if (!this.prometheusProvider) {
|
||||||
if (currentCluster.caFile) {
|
const service = await this.getPrometheusService()
|
||||||
this.certData = readFileSync(currentCluster.caFile).toString()
|
logger.info(`using ${service.id} as prometheus provider`)
|
||||||
} else if (currentCluster.caData) {
|
this.prometheusProvider = service.id
|
||||||
this.certData = Buffer.from(currentCluster.caData, "base64").toString("ascii")
|
|
||||||
}
|
}
|
||||||
const user = this.kc.getCurrentUser()
|
return prometheusProviders.find(p => p.id === this.prometheusProvider)
|
||||||
if (user.authProvider && user.authProvider.name === "oidc") {
|
}
|
||||||
const authConfig = user.authProvider.config
|
|
||||||
if (authConfig["idp-certificate-authority"]) {
|
public async getPrometheusService(): Promise<PrometheusService> {
|
||||||
this.authCertData = readFileSync(authConfig["idp-certificate-authority"]).toString()
|
const providers = this.prometheusProvider ? prometheusProviders.filter((p, _) => p.id == this.prometheusProvider) : prometheusProviders
|
||||||
} else if (authConfig["idp-certificate-authority-data"]) {
|
const prometheusPromises: Promise<PrometheusService>[] = providers.map(async (provider: PrometheusProvider): Promise<PrometheusService> => {
|
||||||
this.authCertData = Buffer.from(authConfig["idp-certificate-authority-data"], "base64").toString("ascii")
|
const apiClient = this.kc.makeApiClient(CoreV1Api)
|
||||||
|
return await provider.getPrometheusService(apiClient)
|
||||||
|
})
|
||||||
|
const resolvedPrometheusServices = await Promise.all(prometheusPromises)
|
||||||
|
const service = resolvedPrometheusServices.filter(n => n)[0]
|
||||||
|
if (service) {
|
||||||
|
return service
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
id: "lens",
|
||||||
|
namespace: "lens-metrics",
|
||||||
|
service: "prometheus",
|
||||||
|
port: 80
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getPrometheusPath(): Promise<string> {
|
||||||
|
if (this.prometheusPath) return this.prometheusPath
|
||||||
|
|
||||||
|
this.prometheusPath = await this.resolvePrometheusPath()
|
||||||
|
|
||||||
|
return this.prometheusPath
|
||||||
|
}
|
||||||
|
|
||||||
public async getApiTarget(isWatchRequest = false) {
|
public async getApiTarget(isWatchRequest = false) {
|
||||||
if (this.apiTarget && !isWatchRequest) {
|
if (this.apiTarget && !isWatchRequest) {
|
||||||
return this.apiTarget
|
return this.apiTarget
|
||||||
@ -135,7 +161,7 @@ export class ContextHandler {
|
|||||||
|
|
||||||
let serverPort: number = null
|
let serverPort: number = null
|
||||||
try {
|
try {
|
||||||
serverPort = await getFreePort(49901, 65535)
|
serverPort = await getFreePort()
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
logger.error(error)
|
logger.error(error)
|
||||||
throw(error)
|
throw(error)
|
||||||
|
|||||||
@ -48,7 +48,7 @@ async function main() {
|
|||||||
let port: number = null
|
let port: number = null
|
||||||
// find free port
|
// find free port
|
||||||
try {
|
try {
|
||||||
port = await getFreePort(49152, 65535)
|
port = await getFreePort()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error)
|
logger.error(error)
|
||||||
await dialog.showErrorBox("Lens Error", "Could not find a free port for the cluster proxy")
|
await dialog.showErrorBox("Lens Error", "Could not find a free port for the cluster proxy")
|
||||||
|
|||||||
@ -1,27 +1,30 @@
|
|||||||
import logger from "./logger"
|
import logger from "./logger"
|
||||||
import { createServer } from "net"
|
import { createServer } from "net"
|
||||||
|
import { AddressInfo } from "net"
|
||||||
|
|
||||||
// Adapted from https://gist.github.com/mikeal/1840641#gistcomment-2896667
|
const getNextAvailablePort = () => {
|
||||||
function checkPort(port: number) {
|
logger.debug("getNextAvailablePort() start")
|
||||||
const server = createServer()
|
const server = createServer()
|
||||||
server.unref()
|
server.unref()
|
||||||
return new Promise((resolve, reject) =>
|
return new Promise<number>((resolve, reject) =>
|
||||||
server
|
server
|
||||||
.on('error', error => reject(error))
|
.on('error', (error: any) => reject(error))
|
||||||
.on('listening', () => server.close(() => resolve(port)))
|
.on('listening', () => {
|
||||||
.listen({host: "127.0.0.1", port: port}))
|
logger.debug("*** server listening event ***")
|
||||||
|
const _port = (server.address() as AddressInfo).port
|
||||||
|
server.close(() => resolve(_port))
|
||||||
|
})
|
||||||
|
.listen({host: "127.0.0.1", port: 0}))
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getFreePort(firstPort: number, lastPort: number): Promise<number> {
|
export const getFreePort = async () => {
|
||||||
let port = firstPort
|
logger.debug("getFreePort() start")
|
||||||
|
let freePort: number = null
|
||||||
while(true) {
|
|
||||||
try {
|
try {
|
||||||
logger.debug("Checking port " + port + " availability ...")
|
freePort = await getNextAvailablePort()
|
||||||
await checkPort(port)
|
logger.debug("got port : " + freePort)
|
||||||
return(port)
|
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
if(++port > lastPort) throw("Could not find a free port")
|
throw("getNextAvailablePort() threw: '" + error + "'")
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return freePort
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,29 @@
|
|||||||
import { PrometheusLens } from "./lens"
|
import { PrometheusLens } from "./lens"
|
||||||
|
import { CoreV1Api } from "@kubernetes/client-node"
|
||||||
|
import { PrometheusService } from "./provider-registry";
|
||||||
|
import logger from "../logger"
|
||||||
|
|
||||||
export class PrometheusHelm extends PrometheusLens {
|
export class PrometheusHelm extends PrometheusLens {
|
||||||
constructor() {
|
id = "helm"
|
||||||
super()
|
name = "Helm"
|
||||||
this.id = "helm"
|
rateAccuracy = "5m"
|
||||||
this.name = "Helm"
|
|
||||||
this.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(`PrometheusHelm: failed to list services: ${error.toString()}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,11 +1,28 @@
|
|||||||
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 PrometheusLens implements PrometheusProvider {
|
export class PrometheusLens implements PrometheusProvider {
|
||||||
id = "lens"
|
id = "lens"
|
||||||
name = "Lens"
|
name = "Lens"
|
||||||
rateAccuracy = "1m"
|
rateAccuracy = "1m"
|
||||||
|
|
||||||
public getQueries(opts: PrometheusQueryOpts): PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery {
|
public async getPrometheusService(client: CoreV1Api): Promise<PrometheusService> {
|
||||||
|
try {
|
||||||
|
const resp = await client.readNamespacedService("prometheus", "lens-metrics")
|
||||||
|
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.toString()}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getQueries(opts: PrometheusQueryOpts): PrometheusQuery {
|
||||||
switch(opts.category) {
|
switch(opts.category) {
|
||||||
case 'cluster':
|
case 'cluster':
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,11 +1,36 @@
|
|||||||
import { PrometheusProvider, PrometheusQueryOpts, PrometheusClusterQuery, PrometheusNodeQuery, PrometheusPodQuery, PrometheusPvcQuery, PrometheusIngressQuery } from "./provider-registry";
|
import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry";
|
||||||
|
import { CoreV1Api, V1Service } from "@kubernetes/client-node";
|
||||||
|
import logger from "../logger";
|
||||||
|
|
||||||
export class PrometheusOperator implements PrometheusProvider {
|
export class PrometheusOperator implements PrometheusProvider {
|
||||||
rateAccuracy = "1m"
|
rateAccuracy = "1m"
|
||||||
id = "operator"
|
id = "operator"
|
||||||
name = "Prometheus Operator"
|
name = "Prometheus Operator"
|
||||||
|
|
||||||
public getQueries(opts: PrometheusQueryOpts): PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery {
|
public async getPrometheusService(client: CoreV1Api): Promise<PrometheusService> {
|
||||||
|
try {
|
||||||
|
let service: V1Service
|
||||||
|
for (const labelSelector of ["operated-prometheus=true", "self-monitor=true"]) {
|
||||||
|
if (!service) {
|
||||||
|
const serviceList = await client.listServiceForAllNamespaces(null, null, null, labelSelector)
|
||||||
|
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(`PrometheusOperator: failed to list services: ${error.toString()}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getQueries(opts: PrometheusQueryOpts): PrometheusQuery {
|
||||||
switch(opts.category) {
|
switch(opts.category) {
|
||||||
case 'cluster':
|
case 'cluster':
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { CoreV1Api } from "@kubernetes/client-node"
|
||||||
|
|
||||||
export type PrometheusClusterQuery = {
|
export type PrometheusClusterQuery = {
|
||||||
memoryUsage: string;
|
memoryUsage: string;
|
||||||
memoryRequests: string;
|
memoryRequests: string;
|
||||||
@ -48,8 +50,20 @@ export type PrometheusQueryOpts = {
|
|||||||
[key: string]: string | any;
|
[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 {
|
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 = {
|
export type PrometheusProviderList = {
|
||||||
|
|||||||
@ -83,8 +83,6 @@ export class LensProxy {
|
|||||||
}, (250 * retryCount))
|
}, (250 * retryCount))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//return
|
|
||||||
}
|
}
|
||||||
res.writeHead(500, {
|
res.writeHead(500, {
|
||||||
'Content-Type': 'text/plain'
|
'Content-Type': 'text/plain'
|
||||||
|
|||||||
@ -13,7 +13,6 @@ class MetricsRoute extends LensApi {
|
|||||||
const { response, cluster} = request
|
const { response, cluster} = request
|
||||||
const query: MetricsQuery = request.payload;
|
const query: MetricsQuery = request.payload;
|
||||||
const serverUrl = `http://127.0.0.1:${cluster.port}/api-kube`
|
const serverUrl = `http://127.0.0.1:${cluster.port}/api-kube`
|
||||||
const metricsUrl = `${serverUrl}/api/v1/namespaces/${cluster.contextHandler.getPrometheusPath()}/proxy${cluster.getPrometheusApiPrefix()}/api/v1/query_range`
|
|
||||||
const headers = {
|
const headers = {
|
||||||
"Host": `${cluster.id}.localhost:${cluster.port}`,
|
"Host": `${cluster.id}.localhost:${cluster.port}`,
|
||||||
"Content-type": "application/json",
|
"Content-type": "application/json",
|
||||||
@ -23,10 +22,12 @@ class MetricsRoute extends LensApi {
|
|||||||
queryParams[key] = value
|
queryParams[key] = value
|
||||||
})
|
})
|
||||||
|
|
||||||
const prometheusInstallationSource = cluster.preferences.prometheusProvider?.type || "lens"
|
let metricsUrl: string
|
||||||
let prometheusProvider: PrometheusProvider
|
let prometheusProvider: PrometheusProvider
|
||||||
try {
|
try {
|
||||||
prometheusProvider = PrometheusProviderRegistry.getProvider(prometheusInstallationSource)
|
const prometheusPath = await cluster.contextHandler.getPrometheusPath()
|
||||||
|
metricsUrl = `${serverUrl}/api/v1/namespaces/${prometheusPath}/proxy${cluster.getPrometheusApiPrefix()}/api/v1/query_range`
|
||||||
|
prometheusProvider = await cluster.contextHandler.getPrometheusProvider()
|
||||||
} catch {
|
} catch {
|
||||||
this.respondJson(response, {})
|
this.respondJson(response, {})
|
||||||
return
|
return
|
||||||
|
|||||||
@ -36,7 +36,7 @@ class PortForward {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async start() {
|
public async start() {
|
||||||
this.localPort = await getFreePort(8000, 9999)
|
this.localPort = await getFreePort()
|
||||||
const kubectlBin = await bundledKubectl.kubectlPath()
|
const kubectlBin = await bundledKubectl.kubectlPath()
|
||||||
const args = [
|
const args = [
|
||||||
"--kubeconfig", this.kubeConfig,
|
"--kubeconfig", this.kubeConfig,
|
||||||
|
|||||||
@ -20,17 +20,7 @@
|
|||||||
<div class="cluster-settings-section">
|
<div class="cluster-settings-section">
|
||||||
<b>Prometheus</b>
|
<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>
|
<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
|
<b-form-group
|
||||||
label="Prometheus installation method."
|
label="Prometheus installation method."
|
||||||
description="What query format is used to fetch metrics from Prometheus"
|
description="What query format is used to fetch metrics from Prometheus"
|
||||||
@ -41,6 +31,18 @@
|
|||||||
@change="onPrometheusProviderSave"
|
@change="onPrometheusProviderSave"
|
||||||
/>
|
/>
|
||||||
</b-form-group>
|
</b-form-group>
|
||||||
|
<b-form-group
|
||||||
|
label="Prometheus service address."
|
||||||
|
description="An address to an existing Prometheus installation (<namespace>/<service>:<port>). Lens tries to auto-detect address if left empty."
|
||||||
|
v-if="canEditPrometheusPath"
|
||||||
|
>
|
||||||
|
<b-form-input
|
||||||
|
v-model="prometheusPath"
|
||||||
|
placeholder="<namespace>/<service>:<port>"
|
||||||
|
id="input-prometheuspath"
|
||||||
|
@blur="onPrometheusSave"
|
||||||
|
/>
|
||||||
|
</b-form-group>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
@ -86,10 +88,23 @@ export default {
|
|||||||
prometheusProvider: "",
|
prometheusProvider: "",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted: async function() {
|
computed: {
|
||||||
this.prometheusProviders = prometheusProviders.map((provider) => {
|
prometheusProviders: function() {
|
||||||
|
const providers = prometheusProviders.map((provider) => {
|
||||||
return { text: provider.name, value: provider.id }
|
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.updateValues()
|
this.updateValues()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -103,7 +118,7 @@ export default {
|
|||||||
if (this.cluster.preferences.prometheusProvider) {
|
if (this.cluster.preferences.prometheusProvider) {
|
||||||
this.prometheusProvider = this.cluster.preferences.prometheusProvider.type
|
this.prometheusProvider = this.cluster.preferences.prometheusProvider.type
|
||||||
} else {
|
} else {
|
||||||
this.prometheusProvider = "lens"
|
this.prometheusProvider = ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
parsePrometheusPath: function(path) {
|
parsePrometheusPath: function(path) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user