First step of integrating gateway-api with homepage.

This commit is contained in:
djeinstine 2024-11-06 11:15:52 +00:00
parent f7810cb67a
commit a15b5bd692
3 changed files with 305 additions and 100 deletions

View File

@ -11,13 +11,31 @@ const extractKubeData = (config) => {
//kubeconfig
const kc = new KubeConfig();
kc.loadFromCluster()
//route
let route="ingress";
if (config?.route=="gateway"){
route="gateway";
}
//traefik
let traefik=true;
if (config?.traefik=="disable"){
traefik=false;
}
//traefik
let metrics=true;
if (config?.metrics=="disable"){
metrics=false;
}
//return
return {"config":kc,
"route":route};
"route":route,
"traefik":traefik,
"metrics":metrics
};
}
export default function getKubeArguments() {

View File

@ -3,12 +3,12 @@ import path from "path";
import yaml from "js-yaml";
import Docker from "dockerode";
import { CustomObjectsApi, NetworkingV1Api, ApiextensionsV1Api } from "@kubernetes/client-node";
import { ApiextensionsV1Api } from "@kubernetes/client-node";
import createLogger from "utils/logger";
import checkAndCopyConfig, { CONF_DIR, getSettings, substituteEnvironmentVars } from "utils/config/config";
import getDockerArguments from "utils/config/docker";
import getKubeArguments from "utils/config/kubernetes";
import {getUrlSchema,getRouteList} from "utils/kubernetes/kubernetes-routes";
import * as shvl from "utils/config/shvl";
const logger = createLogger("service-helpers");
@ -151,12 +151,12 @@ export async function servicesFromDocker() {
return mappedServiceGroups;
}
function getUrlFromIngress(ingress) {
const urlHost = ingress.spec.rules[0].host;
const urlPath = ingress.spec.rules[0].http.paths[0].path;
const urlSchema = ingress.spec.tls ? "https" : "http";
return `${urlSchema}://${urlHost}${urlPath}`;
}
// function getUrlFromroute(route) {
// const urlHost = route.spec.rules[0].host;
// const urlPath = route.spec.rules[0].http.paths[0].path;
// const urlSchema = route.spec.tls ? "https" : "http";
// return `${urlSchema}://${urlHost}${urlPath}`;
// }
export async function checkCRD(kc, name) {
const apiExtensions = kc.makeApiClient(ApiextensionsV1Api);
@ -186,115 +186,122 @@ export async function servicesFromKubernetes() {
checkAndCopyConfig("kubernetes.yaml");
try {
const kc = getKubeArguments().config;
if (!kc) {
// const kc = getKubeArguments().config;
// if (!kc) {
// return [];
// }
// const networking = kc.makeApiClient(NetworkingV1Api);
// const crd = kc.makeApiClient(CustomObjectsApi);
// const routeList = await networking
// .listrouteForAllNamespaces(null, null, null, null)
// .then((response) => response.body)
// .catch((error) => {
// logger.error("Error getting routees: %d %s %s", error.statusCode, error.body, error.response);
// logger.debug(error);
// return null;
// });
// const traefikContainoExists = await checkCRD(kc, "routeroutes.traefik.containo.us");
// const traefikExists = await checkCRD(kc, "routeroutes.traefik.io");
// const traefikrouteListContaino = await crd
// .listClusterCustomObject("traefik.containo.us", "v1alpha1", "routeroutes")
// .then((response) => response.body)
// .catch(async (error) => {
// if (traefikContainoExists) {
// logger.error(
// "Error getting traefik routees from traefik.containo.us: %d %s %s",
// error.statusCode,
// error.body,
// error.response,
// );
// logger.debug(error);
// }
// return [];
// });
// const traefikrouteListIo = await crd
// .listClusterCustomObject("traefik.io", "v1alpha1", "routeroutes")
// .then((response) => response.body)
// .catch(async (error) => {
// if (traefikExists) {
// logger.error(
// "Error getting traefik routees from traefik.io: %d %s %s",
// error.statusCode,
// error.body,
// error.response,
// );
// logger.debug(error);
// }
// return [];
// });
// const traefikrouteList = [...(traefikrouteListContaino?.items ?? []), ...(traefikrouteListIo?.items ?? [])];
// if (traefikrouteList.length > 0) {
// const traefikServices = traefikrouteList.filter(
// (route) => route.metadata.annotations && route.metadata.annotations[`${ANNOTATION_BASE}/href`],
// );
// routeList.items.push(...traefikServices);
// }
// if (!routeList) {
// return [];
// }
const routeList = await getRouteList();
if (!routeList) {
return [];
}
const networking = kc.makeApiClient(NetworkingV1Api);
const crd = kc.makeApiClient(CustomObjectsApi);
const ingressList = await networking
.listIngressForAllNamespaces(null, null, null, null)
.then((response) => response.body)
.catch((error) => {
logger.error("Error getting ingresses: %d %s %s", error.statusCode, error.body, error.response);
logger.debug(error);
return null;
});
const traefikContainoExists = await checkCRD(kc, "ingressroutes.traefik.containo.us");
const traefikExists = await checkCRD(kc, "ingressroutes.traefik.io");
const traefikIngressListContaino = await crd
.listClusterCustomObject("traefik.containo.us", "v1alpha1", "ingressroutes")
.then((response) => response.body)
.catch(async (error) => {
if (traefikContainoExists) {
logger.error(
"Error getting traefik ingresses from traefik.containo.us: %d %s %s",
error.statusCode,
error.body,
error.response,
);
logger.debug(error);
}
return [];
});
const traefikIngressListIo = await crd
.listClusterCustomObject("traefik.io", "v1alpha1", "ingressroutes")
.then((response) => response.body)
.catch(async (error) => {
if (traefikExists) {
logger.error(
"Error getting traefik ingresses from traefik.io: %d %s %s",
error.statusCode,
error.body,
error.response,
);
logger.debug(error);
}
return [];
});
const traefikIngressList = [...(traefikIngressListContaino?.items ?? []), ...(traefikIngressListIo?.items ?? [])];
if (traefikIngressList.length > 0) {
const traefikServices = traefikIngressList.filter(
(ingress) => ingress.metadata.annotations && ingress.metadata.annotations[`${ANNOTATION_BASE}/href`],
);
ingressList.items.push(...traefikServices);
}
if (!ingressList) {
return [];
}
const services = ingressList.items
const services = routeList
.filter(
(ingress) =>
ingress.metadata.annotations &&
ingress.metadata.annotations[`${ANNOTATION_BASE}/enabled`] === "true" &&
(!ingress.metadata.annotations[`${ANNOTATION_BASE}/instance`] ||
ingress.metadata.annotations[`${ANNOTATION_BASE}/instance`] === instanceName ||
`${ANNOTATION_BASE}/instance.${instanceName}` in ingress.metadata.annotations),
(route) =>
route.metadata.annotations &&
route.metadata.annotations[`${ANNOTATION_BASE}/enabled`] === "true" &&
(!route.metadata.annotations[`${ANNOTATION_BASE}/instance`] ||
route.metadata.annotations[`${ANNOTATION_BASE}/instance`] === instanceName ||
`${ANNOTATION_BASE}/instance.${instanceName}` in route.metadata.annotations),
)
.map((ingress) => {
.map((route) => {
let constructedService = {
app: ingress.metadata.annotations[`${ANNOTATION_BASE}/app`] || ingress.metadata.name,
namespace: ingress.metadata.namespace,
href: ingress.metadata.annotations[`${ANNOTATION_BASE}/href`] || getUrlFromIngress(ingress),
name: ingress.metadata.annotations[`${ANNOTATION_BASE}/name`] || ingress.metadata.name,
group: ingress.metadata.annotations[`${ANNOTATION_BASE}/group`] || "Kubernetes",
weight: ingress.metadata.annotations[`${ANNOTATION_BASE}/weight`] || "0",
icon: ingress.metadata.annotations[`${ANNOTATION_BASE}/icon`] || "",
description: ingress.metadata.annotations[`${ANNOTATION_BASE}/description`] || "",
app: route.metadata.annotations[`${ANNOTATION_BASE}/app`] || route.metadata.name,
namespace: route.metadata.namespace,
href: route.metadata.annotations[`${ANNOTATION_BASE}/href`] || getUrlSchema(route),
name: route.metadata.annotations[`${ANNOTATION_BASE}/name`] || route.metadata.name,
group: route.metadata.annotations[`${ANNOTATION_BASE}/group`] || "Kubernetes",
weight: route.metadata.annotations[`${ANNOTATION_BASE}/weight`] || "0",
icon: route.metadata.annotations[`${ANNOTATION_BASE}/icon`] || "",
description: route.metadata.annotations[`${ANNOTATION_BASE}/description`] || "",
external: false,
type: "service",
};
if (ingress.metadata.annotations[`${ANNOTATION_BASE}/external`]) {
console.log("href is ",constructedService.href);
if (route.metadata.annotations[`${ANNOTATION_BASE}/external`]) {
constructedService.external =
String(ingress.metadata.annotations[`${ANNOTATION_BASE}/external`]).toLowerCase() === "true";
String(route.metadata.annotations[`${ANNOTATION_BASE}/external`]).toLowerCase() === "true";
}
if (ingress.metadata.annotations[`${ANNOTATION_BASE}/pod-selector`] !== undefined) {
constructedService.podSelector = ingress.metadata.annotations[`${ANNOTATION_BASE}/pod-selector`];
if (route.metadata.annotations[`${ANNOTATION_BASE}/pod-selector`] !== undefined) {
constructedService.podSelector = route.metadata.annotations[`${ANNOTATION_BASE}/pod-selector`];
}
if (ingress.metadata.annotations[`${ANNOTATION_BASE}/ping`]) {
constructedService.ping = ingress.metadata.annotations[`${ANNOTATION_BASE}/ping`];
if (route.metadata.annotations[`${ANNOTATION_BASE}/ping`]) {
constructedService.ping = route.metadata.annotations[`${ANNOTATION_BASE}/ping`];
}
if (ingress.metadata.annotations[`${ANNOTATION_BASE}/siteMonitor`]) {
constructedService.siteMonitor = ingress.metadata.annotations[`${ANNOTATION_BASE}/siteMonitor`];
if (route.metadata.annotations[`${ANNOTATION_BASE}/siteMonitor`]) {
constructedService.siteMonitor = route.metadata.annotations[`${ANNOTATION_BASE}/siteMonitor`];
}
if (ingress.metadata.annotations[`${ANNOTATION_BASE}/statusStyle`]) {
constructedService.statusStyle = ingress.metadata.annotations[`${ANNOTATION_BASE}/statusStyle`];
if (route.metadata.annotations[`${ANNOTATION_BASE}/statusStyle`]) {
constructedService.statusStyle = route.metadata.annotations[`${ANNOTATION_BASE}/statusStyle`];
}
Object.keys(ingress.metadata.annotations).forEach((annotation) => {
Object.keys(route.metadata.annotations).forEach((annotation) => {
if (annotation.startsWith(ANNOTATION_WIDGET_BASE)) {
shvl.set(
constructedService,
annotation.replace(`${ANNOTATION_BASE}/`, ""),
ingress.metadata.annotations[annotation],
route.metadata.annotations[annotation],
);
}
});
@ -305,7 +312,7 @@ export async function servicesFromKubernetes() {
logger.error("Error attempting k8s environment variable substitution.");
logger.debug(e);
}
console.log(constructedService)
return constructedService;
});

View File

@ -0,0 +1,180 @@
import { CustomObjectsApi, NetworkingV1Api, CoreV1Api } from "@kubernetes/client-node";
import getKubeArguments from "utils/config/kubernetes";
const kubeArguments = getKubeArguments();
const kc = kubeArguments.config;
const apiGroup = 'gateway.networking.k8s.io';
const version = 'v1';
let crd;
let core;
let networking;
let routingType;
let traefik;
const getSchemaFromGateway = async (gatewayRef) => {
try {
const gateway = await crd.getNamespacedCustomObject(apiGroup, version, gatewayRef.namespace,"gateways",gatewayRef.name);
const listener = gateway.body.spec.listeners.filter((listener)=>listener.name==gatewayRef.sectionName)[0];
return listener.protocol.toLowerCase();
} catch (err) {
console.error(err);
}
};
function getUrlFromHttpRoute(ingress) {
const urlHost = ingress.spec.hostnames[0];
const urlPath = ingress.spec.rules[0].matches[0].path.value;
//const urlSchema = await getSchemaFromGateway(ingress.spec.parentRefs[0]) ? "https" : "http";
const urlSchema = "https"
return `${urlSchema}://${urlHost}${urlPath}`;
}
function getUrlFromIngress(ingress) {
const urlHost = ingress.spec.rules[0].host;
const urlPath = ingress.spec.rules[0].http.paths[0].path;
const urlSchema = ingress.spec.tls ? "https" : "http";
return `${urlSchema}://${urlHost}${urlPath}`;
}
async function getHttpRouteList(){
const httpRouteList = new Array();
const namespaces = await core.listNamespace()
.then((response) => response.body.items.map(ns => ns.metadata.name))
.catch((error) => {
logger.error("Error getting namespaces: %d %s %s", error.statusCode, error.body, error.response);
logger.debug(error);
return null;
})
if (namespaces){
// Iterate over each namespace
for (const namespace of namespaces) {
try {
// Fetch the httproute from one namespaces
const customObject = await crd.listNamespacedCustomObject(apiGroup,version,namespace,'httproutes');
if (customObject.body.items.length !== 0){
httpRouteList.push(customObject.body.items[0]);
}
} catch (err) {
console.error(`Error fetching httproutes objects in namespace "${namespace}":`, err.body || err.message);
}
}
}
return httpRouteList;
}
async function getIngressList(){
const ingressList = await networking
.listIngressForAllNamespaces(null, null, null, null)
.then((response) => response.body)
.catch((error) => {
logger.error("Error getting ingresses: %d %s %s", error.statusCode, error.body, error.response);
logger.debug(error);
return null;
});
if (traefik){
const traefikContainoExists = await checkCRD(kc, "ingressroutes.traefik.containo.us");
const traefikExists = await checkCRD(kc, "ingressroutes.traefik.io");
const traefikIngressListContaino = await crd
.listClusterCustomObject("traefik.containo.us", "v1alpha1", "ingressroutes")
.then((response) => response.body)
.catch(async (error) => {
if (traefikContainoExists) {
logger.error(
"Error getting traefik ingresses from traefik.containo.us: %d %s %s",
error.statusCode,
error.body,
error.response,
);
logger.debug(error);
}
return [];
});
const traefikIngressListIo = await crd
.listClusterCustomObject("traefik.io", "v1alpha1", "ingressroutes")
.then((response) => response.body)
.catch(async (error) => {
if (traefikExists) {
logger.error(
"Error getting traefik ingresses from traefik.io: %d %s %s",
error.statusCode,
error.body,
error.response,
);
logger.debug(error);
}
return [];
});
const traefikIngressList = [...(traefikIngressListContaino?.items ?? []), ...(traefikIngressListIo?.items ?? [])];
if (traefikIngressList.length > 0) {
const traefikServices = traefikIngressList.filter(
(ingress) => ingress.metadata.annotations && ingress.metadata.annotations[`${ANNOTATION_BASE}/href`],
);
ingressList.items.push(...traefikServices);
}
}
return ingressList.items;
}
export async function getRouteList(){
let routeList = new Array();
if (!kc) {
return [];
}
crd = kc.makeApiClient(CustomObjectsApi);
core = kc.makeApiClient(CoreV1Api);
networking = kc.makeApiClient(NetworkingV1Api);
routingType = kubeArguments.route;
traefik = kubeArguments.traefik;
switch (routingType) {
case "ingress":
routeList = await getIngressList();
break;
case "gateway":
routeList = await getHttpRouteList();
break;
default:
routeList = await getIngressList();
}
return routeList;
}
export function getUrlSchema(route) {
let urlSchema;
switch (routingType) {
case "ingress":
urlSchema = getUrlFromIngress(route);
break;
case "gateway":
urlSchema = getUrlFromHttpRoute(route);
break;
default:
urlSchema = getUrlFromIngress(route);
}
return urlSchema;
}