From bf13ef79f464a1271f7ae0e56a71a8c502a1184e Mon Sep 17 00:00:00 2001 From: djeinstine Date: Mon, 10 Feb 2025 15:36:08 +0000 Subject: [PATCH] refactored code to seperate kubernetes resources --- src/utils/config/kubernetes.js | 4 +- src/utils/config/service-helpers.js | 92 +------- .../kubernetes/kubernetes-httproute-list.js | 3 +- src/utils/kubernetes/kubernetes-routes.js | 222 ------------------ src/utils/kubernetes/resource-helpers.js | 66 +++++- 5 files changed, 70 insertions(+), 317 deletions(-) delete mode 100644 src/utils/kubernetes/kubernetes-routes.js diff --git a/src/utils/config/kubernetes.js b/src/utils/config/kubernetes.js index 6cb215835..9ebda3a31 100644 --- a/src/utils/config/kubernetes.js +++ b/src/utils/config/kubernetes.js @@ -76,4 +76,6 @@ export async function checkCRD(name,kc,logger) { } export const ANNOTATION_BASE = "gethomepage.dev"; -export const ANNOTATION_WIDGET_BASE = `${ANNOTATION_BASE}/widget.`; \ No newline at end of file +export const ANNOTATION_WIDGET_BASE = `${ANNOTATION_BASE}/widget.`; +export const HTTPROUTE_API_GROUP = "gateway.networking.k8s.io"; +export const HTTPROUTE_API_VERSION = "v1"; \ No newline at end of file diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js index 82b1162b2..2e036f5bd 100644 --- a/src/utils/config/service-helpers.js +++ b/src/utils/config/service-helpers.js @@ -9,8 +9,6 @@ import checkAndCopyConfig, { CONF_DIR, getSettings, substituteEnvironmentVars } import getDockerArguments from "utils/config/docker"; import kubernetes from "utils/kubernetes/kubernetes-export"; import getKubeArguments from "utils/config/kubernetes"; -// import { getUrlSchema, getRouteList } from "utils/kubernetes/kubernetes-routes"; -// import { ANNOTATION_BASE, ANNOTATION_WIDGET_BASE } from "utils/config/kubernetes"; import * as shvl from "utils/config/shvl"; const logger = createLogger("service-helpers"); @@ -180,6 +178,7 @@ export async function servicesFromKubernetes() { return []; } + //resource lists const [ingressList, traefikIngressList, httpRouteList] = await Promise.all([ kubernetes.listIngress(kubeArguments), kubernetes.listTraefikIngress(kubeArguments), @@ -195,6 +194,7 @@ export async function servicesFromKubernetes() { .filter(resource => kubernetes.isDiscoverable(resource, instanceName)) .map(async (resource) => kubernetes.constructedServiceFromResource(resource))); + //map service groups const mappedServiceGroups = services.reduce((groups, serverService) => { let serverGroup = groups.find(group => group.name === serverService.group); @@ -216,94 +216,6 @@ export async function servicesFromKubernetes() { return groups; }, []); - - // console.log(mappedServiceGroups); - // const routeList = await getRouteList(ANNOTATION_BASE); - - // if (!routeList) { - // return []; - // } - - // const services = await Promise.all( - // routeList - // .filter( - // (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(async (route) => { - // let constructedService = { - // app: route.metadata.annotations[`${ANNOTATION_BASE}/app`] || route.metadata.name, - // namespace: route.metadata.namespace, - // href: route.metadata.annotations[`${ANNOTATION_BASE}/href`] || (await 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 (route.metadata.annotations[`${ANNOTATION_BASE}/external`]) { - // constructedService.external = - // String(route.metadata.annotations[`${ANNOTATION_BASE}/external`]).toLowerCase() === "true"; - // } - // if (route.metadata.annotations[`${ANNOTATION_BASE}/pod-selector`] !== undefined) { - // constructedService.podSelector = route.metadata.annotations[`${ANNOTATION_BASE}/pod-selector`]; - // } - // if (route.metadata.annotations[`${ANNOTATION_BASE}/ping`]) { - // constructedService.ping = route.metadata.annotations[`${ANNOTATION_BASE}/ping`]; - // } - // if (route.metadata.annotations[`${ANNOTATION_BASE}/siteMonitor`]) { - // constructedService.siteMonitor = route.metadata.annotations[`${ANNOTATION_BASE}/siteMonitor`]; - // } - // if (route.metadata.annotations[`${ANNOTATION_BASE}/statusStyle`]) { - // constructedService.statusStyle = route.metadata.annotations[`${ANNOTATION_BASE}/statusStyle`]; - // } - // Object.keys(route.metadata.annotations).forEach((annotation) => { - // if (annotation.startsWith(ANNOTATION_WIDGET_BASE)) { - // shvl.set( - // constructedService, - // annotation.replace(`${ANNOTATION_BASE}/`, ""), - // route.metadata.annotations[annotation], - // ); - // } - // }); - - // try { - // constructedService = JSON.parse(substituteEnvironmentVars(JSON.stringify(constructedService))); - // } catch (e) { - // logger.error("Error attempting k8s environment variable substitution."); - // logger.debug(e); - // } - // return constructedService; - // }), - // ); - - // const mappedServiceGroups = []; - - // services.forEach((serverService) => { - // let serverGroup = mappedServiceGroups.find((searchedGroup) => searchedGroup.name === serverService.group); - // if (!serverGroup) { - // mappedServiceGroups.push({ - // name: serverService.group, - // services: [], - // }); - // serverGroup = mappedServiceGroups[mappedServiceGroups.length - 1]; - // } - - // const { name: serviceName, group: serverServiceGroup, ...pushedService } = serverService; - // const result = { - // name: serviceName, - // ...pushedService, - // }; - - // serverGroup.services.push(result); - // }); - return mappedServiceGroups; } catch (e) { if (e) logger.error(e); diff --git a/src/utils/kubernetes/kubernetes-httproute-list.js b/src/utils/kubernetes/kubernetes-httproute-list.js index 66e19b98e..c915b2b43 100644 --- a/src/utils/kubernetes/kubernetes-httproute-list.js +++ b/src/utils/kubernetes/kubernetes-httproute-list.js @@ -1,11 +1,10 @@ import { CustomObjectsApi, CoreV1Api } from "@kubernetes/client-node"; +import { HTTPROUTE_API_GROUP,HTTPROUTE_API_VERSION } from "utils/config/kubernetes"; import createLogger from "utils/logger"; const logger = createLogger("kubernetes-httproute-list"); -const HTTPROUTE_API_GROUP = "gateway.networking.k8s.io"; -const HTTPROUTE_API_VERSION = "v1"; export default async function listHttpRoute(kubeArguments) { diff --git a/src/utils/kubernetes/kubernetes-routes.js b/src/utils/kubernetes/kubernetes-routes.js deleted file mode 100644 index 875956eed..000000000 --- a/src/utils/kubernetes/kubernetes-routes.js +++ /dev/null @@ -1,222 +0,0 @@ -import { CustomObjectsApi } from "@kubernetes/client-node"; - -import getKubeArguments from "utils/config/kubernetes"; -import createLogger from "utils/logger"; - -const logger = createLogger("service-helpers"); - -const kubeArguments = getKubeArguments(); -const kc = kubeArguments.config; - -const apiGroup = "gateway.networking.k8s.io"; -const version = "v1"; - -const getSchemaFromGateway = async (gatewayRef) => { - const crd = kc.makeApiClient(CustomObjectsApi); - const schema = await crd - .getNamespacedCustomObject(apiGroup, version, gatewayRef.namespace, "gateways", gatewayRef.name) - .then((response) => { - const listner = response.body.spec.listeners.filter((listener) => listener.name === gatewayRef.sectionName)[0]; - return listner.protocol.toLowerCase(); - }) - .catch((error) => { - logger.error("Error getting gateways: %d %s %s", error.statusCode, error.body, error.response); - logger.debug(error); - return ""; - }); - return schema; -}; - -async function getUrlFromHttpRoute(resource) { - let url = null; - const hasHostName = resource.spec?.hostnames; - const isHttpRoute = resource.kind === "HTTPRoute"; - - if (isHttpRoute && hasHostName) { - if (resource.spec.rules[0].matches[0].path.type!=="RegularExpression"){ - const urlHost = resource.spec.hostnames[0]; - const urlPath = resource.spec.rules[0].matches[0].path.value; - const urlSchema = (await getSchemaFromGateway(resource.spec.parentRefs[0])) ? "https" : "http"; - url = `${urlSchema}://${urlHost}${urlPath}`; - } - } - return url; -} - -function getUrlFromIngress(resource) { - const isNotHttpRoute = resource.kind !== "HTTPRoute"; - let url = null - - if (isNotHttpRoute){ - const urlHost = resource.spec.rules[0].host; - const urlPath = resource.spec.rules[0].http.paths[0].path; - const urlSchema = resource.spec.tls ? "https" : "http"; - url = `${urlSchema}://${urlHost}${urlPath}`; -} - return url; -} - -// async function getHttpRouteList() { - -// const crd = kc.makeApiClient(CustomObjectsApi); -// const core = kc.makeApiClient(CoreV1Api); - -// // httproutes -// const getHttpRoute = async (namespace) => -// crd -// .listNamespacedCustomObject(apiGroup, version, namespace, "httproutes") -// .then((response) => { -// const [httpRoute] = response.body.items; -// return httpRoute; -// }) -// .catch((error) => { -// logger.error("Error getting httproutes: %d %s %s", error.statusCode, error.body, error.response); -// logger.debug(error); -// return null; -// }); - -// // namespaces -// 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; -// }); - -// let httpRouteList = []; -// if (namespaces) { -// const httpRouteListUnfiltered = await Promise.all( -// namespaces.map(async (namespace) => { -// const httpRoute = await getHttpRoute(namespace); -// return httpRoute; -// }), -// ); - -// httpRouteList = httpRouteListUnfiltered.filter((httpRoute) => httpRoute !== undefined); -// } -// return httpRouteList; -// } - -// async function getIngressList(annotationBase) { - -// const { traefik } = kubeArguments; -// const networking = kc.makeApiClient(NetworkingV1Api); - -// 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 crd = kc.makeApiClient(CustomObjectsApi); -// const traefikContainoExists = await checkCRD("ingressroutes.traefik.containo.us",kc,logger); -// const traefikExists = await checkCRD("ingressroutes.traefik.io",kc,logger); - -// 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[`${annotationBase}/href`], -// ); -// ingressList.items.push(...traefikServices); -// } -// } - -// return ingressList.items; -// } - -// export async function getRouteList(annotationBase) { -// let routeList = []; - -// if (!kc) { -// return []; -// } - -// if (kubeArguments.ingress){ -// routeList = await getIngressList(annotationBase); -// }else if (kubeArguments.gateway) { -// routeList = await getHttpRouteList(); -// }else{ -// routeList = await getIngressList(annotationBase); -// } - -// // const routingType = kubeArguments.route; - -// // switch (routingType) { -// // case "ingress": -// // routeList = await getIngressList(annotationBase); -// // break; -// // case "gateway": -// // routeList = await getHttpRouteList(); -// // break; -// // default: -// // routeList = await getIngressList(annotationBase); -// // } - -// return routeList; -// } - -export default async function getUrlSchema(resource) { - let urlSchema; - - if (kubeArguments.ingress){ - urlSchema = getUrlFromIngress(resource); - }else if (kubeArguments.gateway){ - urlSchema = await getUrlFromHttpRoute(resource); - }else{ - urlSchema = getUrlFromIngress(resource); - } - - // const routingType = kubeArguments.route; - // switch (routingType) { - // case "ingress": - // urlSchema = getUrlFromIngress(route); - // break; - // case "gateway": - // urlSchema = await getUrlFromHttpRoute(route); - // break; - // default: - // urlSchema = getUrlFromIngress(route); - // } - return urlSchema; -} diff --git a/src/utils/kubernetes/resource-helpers.js b/src/utils/kubernetes/resource-helpers.js index 565393b10..dae86d11a 100644 --- a/src/utils/kubernetes/resource-helpers.js +++ b/src/utils/kubernetes/resource-helpers.js @@ -1,10 +1,72 @@ -import getUrlSchema from "utils/kubernetes/kubernetes-routes"; +import { CustomObjectsApi } from "@kubernetes/client-node"; + +import getKubeArguments,{ ANNOTATION_BASE,ANNOTATION_WIDGET_BASE,HTTPROUTE_API_GROUP,HTTPROUTE_API_VERSION } from "utils/config/kubernetes"; import { substituteEnvironmentVars } from "utils/config/config"; -import { ANNOTATION_BASE,ANNOTATION_WIDGET_BASE } from "utils/config/kubernetes"; import createLogger from "utils/logger"; import * as shvl from "utils/config/shvl"; const logger = createLogger("resource-helpers"); +const kubeArguments = getKubeArguments(); +const kc = kubeArguments.config; + +const getSchemaFromGateway = async (gatewayRef) => { + const crd = kc.makeApiClient(CustomObjectsApi); + const schema = await crd + .getNamespacedCustomObject(HTTPROUTE_API_GROUP, HTTPROUTE_API_VERSION, gatewayRef.namespace, "gateways", gatewayRef.name) + .then((response) => { + const listner = response.body.spec.listeners.filter((listener) => listener.name === gatewayRef.sectionName)[0]; + return listner.protocol.toLowerCase(); + }) + .catch((error) => { + logger.error("Error getting gateways: %d %s %s", error.statusCode, error.body, error.response); + logger.debug(error); + return ""; + }); + return schema; + }; + + async function getUrlFromHttpRoute(resource) { + let url = null; + const hasHostName = resource.spec?.hostnames; + const isHttpRoute = resource.kind === "HTTPRoute"; + + if (isHttpRoute && hasHostName) { + if (resource.spec.rules[0].matches[0].path.type!=="RegularExpression"){ + const urlHost = resource.spec.hostnames[0]; + const urlPath = resource.spec.rules[0].matches[0].path.value; + const urlSchema = (await getSchemaFromGateway(resource.spec.parentRefs[0])) ? "https" : "http"; + url = `${urlSchema}://${urlHost}${urlPath}`; + } + } + return url; + } + + function getUrlFromIngress(resource) { + const isNotHttpRoute = resource.kind !== "HTTPRoute"; + let url = null + + if (isNotHttpRoute){ + const urlHost = resource.spec.rules[0].host; + const urlPath = resource.spec.rules[0].http.paths[0].path; + const urlSchema = resource.spec.tls ? "https" : "http"; + url = `${urlSchema}://${urlHost}${urlPath}`; + } + return url; + } + + async function getUrlSchema(resource) { + let urlSchema; + + if (kubeArguments.ingress){ + urlSchema = getUrlFromIngress(resource); + }else if (kubeArguments.gateway){ + urlSchema = await getUrlFromHttpRoute(resource); + }else{ + urlSchema = getUrlFromIngress(resource); + } + + return urlSchema; + } export function isDiscoverable(resource,instanceName) { return resource.metadata.annotations &&