mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
211 lines
5.1 KiB
TypeScript
211 lines
5.1 KiB
TypeScript
/**
|
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
*/
|
|
|
|
import { KubeObject } from "../kube-object";
|
|
import { autoBind } from "../../utils";
|
|
import { IMetrics, metricsApi } from "./metrics.api";
|
|
import { KubeApi } from "../kube-api";
|
|
import type { KubeJsonApiData } from "../kube-json-api";
|
|
import { isClusterPageContext } from "../../utils/cluster-id-url-parsing";
|
|
import type { RequireExactlyOne } from "type-fest";
|
|
|
|
export class IngressApi extends KubeApi<Ingress> {
|
|
}
|
|
|
|
export function getMetricsForIngress(ingress: string, namespace: string): Promise<IIngressMetrics> {
|
|
const opts = { category: "ingress", ingress, namespace };
|
|
|
|
return metricsApi.getMetrics({
|
|
bytesSentSuccess: opts,
|
|
bytesSentFailure: opts,
|
|
requestDurationSeconds: opts,
|
|
responseDurationSeconds: opts,
|
|
}, {
|
|
namespace,
|
|
});
|
|
}
|
|
|
|
export interface IIngressMetrics<T = IMetrics> {
|
|
[metric: string]: T;
|
|
bytesSentSuccess: T;
|
|
bytesSentFailure: T;
|
|
requestDurationSeconds: T;
|
|
responseDurationSeconds: T;
|
|
}
|
|
|
|
export interface ILoadBalancerIngress {
|
|
hostname?: string;
|
|
ip?: string;
|
|
}
|
|
|
|
// extensions/v1beta1
|
|
interface IExtensionsBackend {
|
|
serviceName: string;
|
|
servicePort: number | string;
|
|
}
|
|
|
|
// networking.k8s.io/v1
|
|
interface INetworkingBackend {
|
|
service: IIngressService;
|
|
}
|
|
|
|
export type IIngressBackend = IExtensionsBackend | INetworkingBackend;
|
|
|
|
export interface IIngressService {
|
|
name: string;
|
|
port: {
|
|
name?: string;
|
|
number?: number;
|
|
};
|
|
}
|
|
|
|
export const getBackendServiceNamePort = (backend: IIngressBackend) => {
|
|
// .service is available with networking.k8s.io/v1, otherwise using extensions/v1beta1 interface
|
|
const serviceName = "service" in backend ? backend.service.name : backend.serviceName;
|
|
// Port is specified either with a number or name
|
|
const servicePort = "service" in backend ? backend.service.port.number ?? backend.service.port.name : backend.servicePort;
|
|
|
|
return { serviceName, servicePort };
|
|
};
|
|
|
|
export interface Ingress {
|
|
spec: {
|
|
tls: {
|
|
secretName: string;
|
|
}[];
|
|
rules?: {
|
|
host?: string;
|
|
http: {
|
|
paths: {
|
|
path?: string;
|
|
backend: IIngressBackend;
|
|
}[];
|
|
};
|
|
}[];
|
|
// extensions/v1beta1
|
|
backend?: IExtensionsBackend;
|
|
/**
|
|
* The default backend which is exactly on of:
|
|
* - service
|
|
* - resource
|
|
*/
|
|
defaultBackend?: RequireExactlyOne<INetworkingBackend & {
|
|
resource: {
|
|
apiGroup: string;
|
|
kind: string;
|
|
name: string;
|
|
};
|
|
}>;
|
|
};
|
|
status: {
|
|
loadBalancer: {
|
|
ingress: ILoadBalancerIngress[];
|
|
};
|
|
};
|
|
}
|
|
|
|
export class Ingress extends KubeObject {
|
|
static kind = "Ingress";
|
|
static namespaced = true;
|
|
static apiBase = "/apis/networking.k8s.io/v1/ingresses";
|
|
|
|
constructor(data: KubeJsonApiData) {
|
|
super(data);
|
|
autoBind(this);
|
|
}
|
|
|
|
getRoutes() {
|
|
const { spec: { tls, rules }} = this;
|
|
|
|
if (!rules) return [];
|
|
|
|
let protocol = "http";
|
|
const routes: string[] = [];
|
|
|
|
if (tls && tls.length > 0) {
|
|
protocol += "s";
|
|
}
|
|
rules.map(rule => {
|
|
const host = rule.host ? rule.host : "*";
|
|
|
|
if (rule.http && rule.http.paths) {
|
|
rule.http.paths.forEach(path => {
|
|
const { serviceName, servicePort } = getBackendServiceNamePort(path.backend);
|
|
|
|
routes.push(`${protocol}://${host}${path.path || "/"} ⇢ ${serviceName}:${servicePort}`);
|
|
});
|
|
}
|
|
});
|
|
|
|
return routes;
|
|
}
|
|
|
|
getServiceNamePort(): IExtensionsBackend {
|
|
const { spec: { backend, defaultBackend } = {}} = this;
|
|
|
|
const serviceName = defaultBackend?.service?.name ?? backend?.serviceName;
|
|
const servicePort = defaultBackend?.service?.port.number ?? defaultBackend?.service?.port.name ?? backend?.servicePort;
|
|
|
|
return {
|
|
serviceName,
|
|
servicePort,
|
|
};
|
|
}
|
|
|
|
getHosts() {
|
|
const { spec: { rules }} = this;
|
|
|
|
if (!rules) return [];
|
|
|
|
return rules.filter(rule => rule.host).map(rule => rule.host);
|
|
}
|
|
|
|
getPorts() {
|
|
const ports: number[] = [];
|
|
const { spec: { tls, rules, backend, defaultBackend }} = this;
|
|
const httpPort = 80;
|
|
const tlsPort = 443;
|
|
// Note: not using the port name (string)
|
|
const servicePort = defaultBackend?.service.port.number ?? backend?.servicePort;
|
|
|
|
if (rules && rules.length > 0) {
|
|
if (rules.some(rule => Object.prototype.hasOwnProperty.call(rule, "http"))) {
|
|
ports.push(httpPort);
|
|
}
|
|
} else if (servicePort !== undefined) {
|
|
ports.push(Number(servicePort));
|
|
}
|
|
|
|
if (tls && tls.length > 0) {
|
|
ports.push(tlsPort);
|
|
}
|
|
|
|
return ports.join(", ");
|
|
}
|
|
|
|
getLoadBalancers() {
|
|
const { status: { loadBalancer = { ingress: [] }}} = this;
|
|
|
|
return (loadBalancer.ingress ?? []).map(address => (
|
|
address.hostname || address.ip
|
|
));
|
|
}
|
|
}
|
|
|
|
let ingressApi: IngressApi;
|
|
|
|
if (isClusterPageContext()) {
|
|
ingressApi = new IngressApi({
|
|
objectConstructor: Ingress,
|
|
// Add fallback for Kubernetes <1.19
|
|
checkPreferredVersion: true,
|
|
fallbackApiBases: ["/apis/extensions/v1beta1/ingresses"],
|
|
});
|
|
}
|
|
|
|
export {
|
|
ingressApi,
|
|
};
|