diff --git a/package-lock.json b/package-lock.json index a51f3e5..c7feb1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "chart.js": "^4.4.4", "color-hash": "^2.0.2", "daisyui": "^4.6.0", + "deepmerge": "^4.3.1", "echarts": "^5.5.1", "humanize-duration": "^3.32.1", "mongoose-zod": "^0.1.1", @@ -27,7 +28,7 @@ "solid-supabase": "^0.5.0", "tailwindcss": "^3.3.3", "vinxi": "^0.4.1", - "zod": "^3.20.6" + "zod": "^3.23.8" }, "devDependencies": { "@types/color-hash": "^2.0.0", @@ -4882,6 +4883,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -10513,6 +10515,7 @@ "version": "3.23.8", "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 2a1bff2..53cdf1f 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "chart.js": "^4.4.4", "color-hash": "^2.0.2", "daisyui": "^4.6.0", + "deepmerge": "^4.3.1", "echarts": "^5.5.1", "humanize-duration": "^3.32.1", "mongoose-zod": "^0.1.1", @@ -33,7 +34,7 @@ "solid-supabase": "^0.5.0", "tailwindcss": "^3.3.3", "vinxi": "^0.4.1", - "zod": "^3.20.6" + "zod": "^3.23.8" }, "engines": { "node": ">=18" diff --git a/src/k8s.ts b/src/k8s.ts index 26ea87e..6b3ede7 100644 --- a/src/k8s.ts +++ b/src/k8s.ts @@ -1,14 +1,15 @@ import k8s from "@kubernetes/client-node"; import { Knative } from "./knative"; +import { config } from "./lib/config"; const kc = new k8s.KubeConfig(); -if (typeof process.env.DEPLOYCAT_KUBECONFIG_PATH === "string") { +if (config.kubeconfig?.path) { console.log("load kubeconfig from file"); - kc.loadFromFile(process.env.DEPLOYCAT_KUBECONFIG_PATH); -} else if (typeof process.env.DEPLOYCAT_KUBECONFIG === "string") { + kc.loadFromFile(config.kubeconfig.path); +} else if (config.kubeconfig?.base64) { console.log("load kubeconfig from env (base64 encoded)"); - kc.loadFromString(atob(process.env.DEPLOYCAT_KUBECONFIG)); -} else if (process.env.DEPLOYCAT_KUBECONFIG_FROM_CLUSTER) { + kc.loadFromString(atob(config.kubeconfig?.base64)); +} else if (config.kubeconfig?.fromcluster) { console.log("load kubeconfig from cluster"); kc.loadFromCluster(); } else { diff --git a/src/lib/config.ts b/src/lib/config.ts new file mode 100644 index 0000000..9c4f97d --- /dev/null +++ b/src/lib/config.ts @@ -0,0 +1,57 @@ +import { z } from "zod"; +import fs from "fs/promises"; +import merge from "deepmerge"; + +const configPath = `${process.cwd()}/config.json`; + +const schemaConfig = z.object({ + database: z.object({ + url: z.string(), + }), + kubeconfig: z + .object({ + base64: z.string().optional(), + path: z.string().optional(), + fromcluster: z.boolean().optional(), + }) + .optional(), + prometheus: z.object({ + url: z.string(), + }), +}); + +const parseEnv = ({ prefix = "", envs = process.env } = {}) => { + const parsed = {} as any; + Object.entries(envs).forEach(([key, value]) => { + const seq = (obj: any, arr: Array, v: string | undefined) => { + if (typeof obj === "string") return; + if (arr.length > 1) { + const [pos] = arr.splice(0, 1); + if (!obj[pos]) obj[pos] = {}; + seq(obj[pos], arr, v); + } else { + obj[arr[0]] = v; + } + }; + const keyArr = key.split("_").map((e) => e.toLocaleLowerCase()); + seq(parsed, keyArr, value); + }); + return prefix !== "" ? parsed?.[prefix] : parsed; +}; + +const parseJSON = async () => { + try { + return JSON.parse((await fs.readFile(configPath)).toString()); + } catch (e) { + console.info("no json config found, get config only from envs"); + return {}; + } +}; + +const getConfig = async () => { + const config = merge(await parseJSON(), parseEnv({ prefix: "deploycat" })); + console.log("config:", config); + return config; +}; + +export const config = schemaConfig.parse(await getConfig()); diff --git a/src/lib/prometheus.ts b/src/lib/prometheus.ts index 983b674..589dbba 100644 --- a/src/lib/prometheus.ts +++ b/src/lib/prometheus.ts @@ -1,8 +1,9 @@ import { cache } from "@solidjs/router"; import { getUser } from "./server"; import { knative } from "~/k8s"; +import { config } from "./config"; -const baseUrl = `${process.env.DEPLOYCAT_PROMETHEUS_URL}/api/v1`; +const baseUrl = `${config.prometheus.url}/api/v1`; export const rangeQuery = async ({ query,