/** * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ import type { CoreV1Api } from "@kubernetes/client-node"; import { getInjectionToken } from "@ogre-tools/injectable"; import { isRequestError } from "@k8slens/utilities"; export interface PrometheusService extends PrometheusServiceInfo { kind: string; } export interface PrometheusServiceInfo { namespace: string; service: string; port: number; } export interface PrometheusProvider { readonly kind: string; readonly name: string; readonly isConfigurable: boolean; getQuery(opts: Record, queryName: string): string; getPrometheusService(client: CoreV1Api): Promise; } export interface CreatePrometheusProviderOpts { readonly kind: string; readonly name: string; readonly isConfigurable: boolean; getQuery(opts: Record, queryName: string): string; getService(client: CoreV1Api): Promise; } export const createPrometheusProvider = ({ getService, ...opts }: CreatePrometheusProviderOpts): PrometheusProvider => ({ ...opts, getPrometheusService: async (client) => { try { return { kind: opts.kind, ...await getService(client), }; } catch (error) { throw new Error(`Failed to find Prometheus provider for "${opts.name}"`, { cause: error }); } }, }); export async function findFirstNamespacedService(client: CoreV1Api, ...selectors: string[]): Promise { try { for (const selector of selectors) { const { items: [service] } = await client.listServiceForAllNamespaces({ labelSelector: selector, }); if (service?.metadata?.namespace && service.metadata.name && service.spec?.ports) { return { namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port, }; } } } catch (error) { throw new Error(`Failed to list services in all namespaces: ${isRequestError(error) ? error.response?.body.message : error}`); } throw new Error(`No service found from any namespace`); } export async function findNamespacedService(client: CoreV1Api, name: string, namespace: string): Promise { try { const service = await client.readNamespacedService({ name, namespace }); if (!service.metadata?.namespace || !service.metadata.name || !service.spec?.ports) { throw new Error(`Service found in namespace="${namespace}" did not have required information`); } return { namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port, }; } catch(error) { throw new Error(`Failed to list services in namespace="${namespace}": ${isRequestError(error) ? error.response?.body.message : error}`); } } export interface BytesSentArgs { rateAccuracy: string; ingress: string; namespace: string; statuses: string; } export function bytesSent({ rateAccuracy, ingress, namespace, statuses }: BytesSentArgs): string { return `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}",namespace="${namespace}",status=~"${statuses}"}[${rateAccuracy}])) by (ingress, namespace)`; } export const prometheusProviderInjectionToken = getInjectionToken({ id: "prometheus-provider", });