mirror of
https://github.com/gethomepage/homepage.git
synced 2026-09-25 05:25:52 -07:00
Performance: reduce calls to kubernetes api-server (#6963)
Docker CI / Docker Build & Push (push) Has been cancelled
Lint / Linting Checks (push) Has been cancelled
Release Drafter / Update Release Draft (push) Has been cancelled
Release Drafter / Auto Label PR (push) Has been cancelled
Tests / vitest (1) (push) Has been cancelled
Tests / vitest (2) (push) Has been cancelled
Tests / vitest (3) (push) Has been cancelled
Tests / vitest (4) (push) Has been cancelled
Docker CI / Docker Build & Push (push) Has been cancelled
Lint / Linting Checks (push) Has been cancelled
Release Drafter / Update Release Draft (push) Has been cancelled
Release Drafter / Auto Label PR (push) Has been cancelled
Tests / vitest (1) (push) Has been cancelled
Tests / vitest (2) (push) Has been cancelled
Tests / vitest (3) (push) Has been cancelled
Tests / vitest (4) (push) Has been cancelled
Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { CoreV1Api, CustomObjectsApi } from "@kubernetes/client-node";
|
||||
import { CustomObjectsApi } from "@kubernetes/client-node";
|
||||
|
||||
import { getKubeConfig, getKubernetes, HTTPROUTE_API_GROUP, HTTPROUTE_API_VERSION } from "utils/config/kubernetes";
|
||||
import createLogger from "utils/logger";
|
||||
@@ -7,49 +7,28 @@ const logger = createLogger("httproute-list");
|
||||
const kc = getKubeConfig();
|
||||
|
||||
export default async function listHttpRoute() {
|
||||
const crd = kc.makeApiClient(CustomObjectsApi);
|
||||
const core = kc.makeApiClient(CoreV1Api);
|
||||
const { gateway } = getKubernetes();
|
||||
let httpRouteList = [];
|
||||
|
||||
if (gateway) {
|
||||
// httproutes
|
||||
const getHttpRoutes = async (namespace) =>
|
||||
crd
|
||||
.listNamespacedCustomObject({
|
||||
group: HTTPROUTE_API_GROUP,
|
||||
version: HTTPROUTE_API_VERSION,
|
||||
namespace,
|
||||
plural: "httproutes",
|
||||
})
|
||||
.then((response) => {
|
||||
return response.items;
|
||||
})
|
||||
.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.items.map((ns) => ns.metadata.name))
|
||||
const crd = kc.makeApiClient(CustomObjectsApi);
|
||||
|
||||
const httpRoutes = await crd
|
||||
.listClusterCustomObject({
|
||||
group: HTTPROUTE_API_GROUP,
|
||||
version: HTTPROUTE_API_VERSION,
|
||||
plural: "httproutes",
|
||||
})
|
||||
.then((response) => {
|
||||
return response?.items ?? [];
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error("Error getting namespaces: %d %s %s", error.statusCode, error.body, error.response);
|
||||
logger.error("Error getting httproutes: %d %s %s", error.statusCode, error.body, error.response);
|
||||
logger.debug(error);
|
||||
return null;
|
||||
return [];
|
||||
});
|
||||
|
||||
if (namespaces) {
|
||||
const httpRouteListUnfiltered = await Promise.all(
|
||||
namespaces.map(async (namespace) => {
|
||||
const httpRoutes = await getHttpRoutes(namespace);
|
||||
return httpRoutes;
|
||||
}),
|
||||
);
|
||||
|
||||
httpRouteList = httpRouteListUnfiltered.flat().filter((httpRoute) => httpRoute);
|
||||
}
|
||||
return httpRoutes;
|
||||
}
|
||||
return httpRouteList;
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -3,19 +3,12 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
const { state, getKubernetes, getKubeConfig, logger } = vi.hoisted(() => {
|
||||
const state = {
|
||||
enabled: true,
|
||||
namespaces: ["a", "b"],
|
||||
routesByNs: {
|
||||
a: [{ metadata: { name: "r1" } }],
|
||||
b: [{ metadata: { name: "r2" } }],
|
||||
},
|
||||
items: [{ metadata: { name: "r1" } }, { metadata: { name: "r2" } }],
|
||||
crd: {
|
||||
listNamespacedCustomObject: vi.fn(async ({ namespace }) => ({ items: state.routesByNs[namespace] ?? [] })),
|
||||
},
|
||||
core: {
|
||||
listNamespace: vi.fn(async () => ({ items: state.namespaces.map((n) => ({ metadata: { name: n } })) })),
|
||||
listClusterCustomObject: vi.fn(async () => ({ items: state.items })),
|
||||
},
|
||||
kc: {
|
||||
makeApiClient: vi.fn((Api) => (Api.name === "CoreV1Api" ? state.core : state.crd)),
|
||||
makeApiClient: vi.fn(() => state.crd),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -28,7 +21,6 @@ const { state, getKubernetes, getKubeConfig, logger } = vi.hoisted(() => {
|
||||
});
|
||||
|
||||
vi.mock("@kubernetes/client-node", () => ({
|
||||
CoreV1Api: class CoreV1Api {},
|
||||
CustomObjectsApi: class CustomObjectsApi {},
|
||||
}));
|
||||
|
||||
@@ -47,11 +39,7 @@ describe("utils/kubernetes/httproute-list", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
state.enabled = true;
|
||||
state.namespaces = ["a", "b"];
|
||||
state.routesByNs = {
|
||||
a: [{ metadata: { name: "r1" } }],
|
||||
b: [{ metadata: { name: "r2" } }],
|
||||
};
|
||||
state.items = [{ metadata: { name: "r1" } }, { metadata: { name: "r2" } }];
|
||||
});
|
||||
|
||||
it("returns an empty list when gateway discovery is disabled", async () => {
|
||||
@@ -64,19 +52,18 @@ describe("utils/kubernetes/httproute-list", () => {
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it("lists namespaces and aggregates httproutes", async () => {
|
||||
it("lists httproutes", async () => {
|
||||
vi.resetModules();
|
||||
const listHttpRoute = (await import("./httproute-list")).default;
|
||||
|
||||
const result = await listHttpRoute();
|
||||
|
||||
expect(result.map((r) => r.metadata.name)).toEqual(["r1", "r2"]);
|
||||
expect(state.core.listNamespace).toHaveBeenCalled();
|
||||
expect(state.crd.listNamespacedCustomObject).toHaveBeenCalledTimes(2);
|
||||
expect(state.crd.listClusterCustomObject).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("logs and returns [] when namespace listing fails", async () => {
|
||||
state.core.listNamespace.mockRejectedValueOnce({ statusCode: 500, body: "boom", response: "resp" });
|
||||
it("logs and returns [] when cluster listing fails", async () => {
|
||||
state.crd.listClusterCustomObject.mockRejectedValueOnce({ statusCode: 500, body: "boom", response: "resp" });
|
||||
|
||||
vi.resetModules();
|
||||
const listHttpRoute = (await import("./httproute-list")).default;
|
||||
@@ -87,20 +74,4 @@ describe("utils/kubernetes/httproute-list", () => {
|
||||
expect(logger.error).toHaveBeenCalled();
|
||||
expect(logger.debug).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("skips namespaces whose httproute queries fail", async () => {
|
||||
state.crd.listNamespacedCustomObject.mockImplementation(async ({ namespace }) => {
|
||||
if (namespace === "b") throw { statusCode: 500, body: "boom", response: "resp" };
|
||||
return { items: state.routesByNs[namespace] ?? [] };
|
||||
});
|
||||
|
||||
vi.resetModules();
|
||||
const listHttpRoute = (await import("./httproute-list")).default;
|
||||
|
||||
const result = await listHttpRoute();
|
||||
|
||||
expect(result.map((r) => r.metadata.name)).toEqual(["r1"]);
|
||||
expect(logger.error).toHaveBeenCalled();
|
||||
expect(logger.debug).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user