1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Add links for ingresses

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-01-05 10:08:35 -05:00
parent a76fc6df84
commit d8a50bc0ec
3 changed files with 89 additions and 71 deletions

View File

@ -4,7 +4,7 @@
*/ */
import { KubeObject } from "../kube-object"; import { KubeObject } from "../kube-object";
import { autoBind } from "../../utils"; import { autoBind, iter } from "../../utils";
import { IMetrics, metricsApi } from "./metrics.api"; import { IMetrics, metricsApi } from "./metrics.api";
import { KubeApi } from "../kube-api"; import { KubeApi } from "../kube-api";
import type { KubeJsonApiData } from "../kube-json-api"; import type { KubeJsonApiData } from "../kube-json-api";
@ -61,23 +61,30 @@ export interface IIngressService {
}; };
} }
export const getBackendServiceNamePort = (backend: IIngressBackend) => { /**
* Format an ingress backend into the name of the service and port
* @param backend The ingress target
*/
export function getBackendServiceNamePort(backend: IIngressBackend): string {
// .service is available with networking.k8s.io/v1, otherwise using extensions/v1beta1 interface // .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 }; if ("service" in backend) {
}; const { name, port } = backend.service;
return `${name}:${port.number ?? port.name}`;
}
return `${backend.serviceName}:${backend.servicePort}`;
}
export interface Ingress { export interface Ingress {
spec: { spec: {
tls: { tls?: {
secretName: string; secretName: string;
}[]; }[];
rules?: { rules?: {
host?: string; host?: string;
http: { http?: {
paths: { paths: {
path?: string; path?: string;
backend: IIngressBackend; backend: IIngressBackend;
@ -106,6 +113,11 @@ export interface Ingress {
}; };
} }
export interface ComputedIngressRoute {
url: string;
service: string;
}
export class Ingress extends KubeObject { export class Ingress extends KubeObject {
static kind = "Ingress"; static kind = "Ingress";
static namespaced = true; static namespaced = true;
@ -116,30 +128,22 @@ export class Ingress extends KubeObject {
autoBind(this); autoBind(this);
} }
getRoutes() { getRoutes(): string[] {
const { spec: { tls, rules }} = this; return this.getRouteDecls().map(({ url, service }) => `${url}${service}`);
}
if (!rules) return []; getRouteDecls(): ComputedIngressRoute[] {
const { spec: { tls = [], rules = [] }} = this;
const protocol = tls.length === 0
? "http"
: "https";
let protocol = "http"; return rules.flatMap(({ host = "*", http: { paths } = { paths: [] }}) => (
const routes: string[] = []; paths.map(({ path = "/", backend }) => ({
url: `${protocol}://${host}${path}`,
if (tls && tls.length > 0) { service: getBackendServiceNamePort(backend),
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 { getServiceNamePort(): IExtensionsBackend {
@ -155,11 +159,9 @@ export class Ingress extends KubeObject {
} }
getHosts() { getHosts() {
const { spec: { rules }} = this; const { spec: { rules = [] }} = this;
if (!rules) return []; return [...iter.filterMap(rules, rule => rule.host)];
return rules.filter(rule => rule.host).map(rule => rule.host);
} }
getPorts() { getPorts() {

View File

@ -49,44 +49,51 @@ export class IngressDetails extends React.Component<IngressDetailsProps> {
} }
renderPaths(ingress: Ingress) { renderPaths(ingress: Ingress) {
const { spec: { rules }} = ingress; const { spec: { rules = [], tls = [] }} = ingress;
const protocol = tls.length === 0
? "http"
: "https";
if (!rules || !rules.length) return null; return rules.map((rule, index) => (
<div className="rules" key={index}>
return rules.map((rule, index) => { {rule.host && (
return ( <div className="host-title">
<div className="rules" key={index}> <>Host: {rule.host}</>
{rule.host && ( </div>
<div className="host-title"> )}
<>Host: {rule.host}</> {rule.http && (
</div> <Table className="paths">
)} <TableHead>
{rule.http && ( <TableCell className="path">Path</TableCell>
<Table className="paths"> <TableCell className="link">Link</TableCell>
<TableHead> <TableCell className="backends">Backends</TableCell>
<TableCell className="path">Path</TableCell> </TableHead>
<TableCell className="backends">Backends</TableCell> {
</TableHead> rule.http.paths
{ .map(({ path = "/", backend }, index) => {
rule.http.paths.map((path, index) => { const link = `${protocol}://${rule.host || "*"}${path}`;
const { serviceName, servicePort } = getBackendServiceNamePort(path.backend);
const backend = `${serviceName}:${servicePort}`;
return ( return (
<TableRow key={index}> <TableRow key={index}>
<TableCell className="path">{path.path || ""}</TableCell> <TableCell className="path">{path}</TableCell>
<TableCell className="backends"> <TableCell className="link">
<p key={backend}>{backend}</p> <a
href={link}
rel="noreferrer"
target="_blank"
>
{link}
</a>
</TableCell> </TableCell>
<TableCell className="backends">{getBackendServiceNamePort(backend)}</TableCell>
</TableRow> </TableRow>
); );
}) })
} }
</Table> </Table>
)} )}
</div> </div>
); ));
});
} }
renderIngressPoints(ingressPoints: ILoadBalancerIngress[]) { renderIngressPoints(ingressPoints: ILoadBalancerIngress[]) {
@ -99,15 +106,14 @@ export class IngressDetails extends React.Component<IngressDetailsProps> {
<TableCell className="name">Hostname</TableCell> <TableCell className="name">Hostname</TableCell>
<TableCell className="ingresspoints">IP</TableCell> <TableCell className="ingresspoints">IP</TableCell>
</TableHead> </TableHead>
{ingressPoints.map(({ hostname, ip }, index) => { {
return ( ingressPoints.map(({ hostname, ip }, index) => (
<TableRow key={index}> <TableRow key={index}>
<TableCell className="name">{hostname ? hostname : "-"}</TableCell> <TableCell className="name">{hostname ? hostname : "-"}</TableCell>
<TableCell className="ingresspoints">{ip ? ip : "-"}</TableCell> <TableCell className="ingresspoints">{ip ? ip : "-"}</TableCell>
</TableRow> </TableRow>
); ))
}) }
})
</Table> </Table>
</div> </div>
); );

View File

@ -56,7 +56,17 @@ export class Ingresses extends React.Component<IngressesProps> {
<KubeObjectStatusIcon key="icon" object={ingress} />, <KubeObjectStatusIcon key="icon" object={ingress} />,
ingress.getNs(), ingress.getNs(),
ingress.getLoadBalancers().map(lb => <p key={lb}>{lb}</p>), ingress.getLoadBalancers().map(lb => <p key={lb}>{lb}</p>),
ingress.getRoutes().map(route => <p key={route}>{route}</p>), ingress.getRouteDecls().map(route => (
<a
key={route.url}
href={route.url}
rel="noreferrer"
target="_blank"
onClick={e => e.stopPropagation()}
>
{route.url}
</a>
)),
<KubeObjectAge key="age" object={ingress} />, <KubeObjectAge key="age" object={ingress} />,
]} ]}
tableProps={{ tableProps={{