mirror of
https://github.com/gethomepage/homepage.git
synced 2026-09-29 07:21:16 -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 { getKubeConfig, getKubernetes, HTTPROUTE_API_GROUP, HTTPROUTE_API_VERSION } from "utils/config/kubernetes";
|
||||||
import createLogger from "utils/logger";
|
import createLogger from "utils/logger";
|
||||||
@@ -7,49 +7,28 @@ const logger = createLogger("httproute-list");
|
|||||||
const kc = getKubeConfig();
|
const kc = getKubeConfig();
|
||||||
|
|
||||||
export default async function listHttpRoute() {
|
export default async function listHttpRoute() {
|
||||||
const crd = kc.makeApiClient(CustomObjectsApi);
|
|
||||||
const core = kc.makeApiClient(CoreV1Api);
|
|
||||||
const { gateway } = getKubernetes();
|
const { gateway } = getKubernetes();
|
||||||
let httpRouteList = [];
|
|
||||||
|
|
||||||
if (gateway) {
|
if (gateway) {
|
||||||
// httproutes
|
const crd = kc.makeApiClient(CustomObjectsApi);
|
||||||
const getHttpRoutes = async (namespace) =>
|
|
||||||
crd
|
const httpRoutes = await crd
|
||||||
.listNamespacedCustomObject({
|
.listClusterCustomObject({
|
||||||
group: HTTPROUTE_API_GROUP,
|
group: HTTPROUTE_API_GROUP,
|
||||||
version: HTTPROUTE_API_VERSION,
|
version: HTTPROUTE_API_VERSION,
|
||||||
namespace,
|
plural: "httproutes",
|
||||||
plural: "httproutes",
|
})
|
||||||
})
|
.then((response) => {
|
||||||
.then((response) => {
|
return response?.items ?? [];
|
||||||
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))
|
|
||||||
.catch((error) => {
|
.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);
|
logger.debug(error);
|
||||||
return null;
|
return [];
|
||||||
});
|
});
|
||||||
|
|
||||||
if (namespaces) {
|
return httpRoutes;
|
||||||
const httpRouteListUnfiltered = await Promise.all(
|
|
||||||
namespaces.map(async (namespace) => {
|
|
||||||
const httpRoutes = await getHttpRoutes(namespace);
|
|
||||||
return httpRoutes;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
httpRouteList = httpRouteListUnfiltered.flat().filter((httpRoute) => httpRoute);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return httpRouteList;
|
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,19 +3,12 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
|||||||
const { state, getKubernetes, getKubeConfig, logger } = vi.hoisted(() => {
|
const { state, getKubernetes, getKubeConfig, logger } = vi.hoisted(() => {
|
||||||
const state = {
|
const state = {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
namespaces: ["a", "b"],
|
items: [{ metadata: { name: "r1" } }, { metadata: { name: "r2" } }],
|
||||||
routesByNs: {
|
|
||||||
a: [{ metadata: { name: "r1" } }],
|
|
||||||
b: [{ metadata: { name: "r2" } }],
|
|
||||||
},
|
|
||||||
crd: {
|
crd: {
|
||||||
listNamespacedCustomObject: vi.fn(async ({ namespace }) => ({ items: state.routesByNs[namespace] ?? [] })),
|
listClusterCustomObject: vi.fn(async () => ({ items: state.items })),
|
||||||
},
|
|
||||||
core: {
|
|
||||||
listNamespace: vi.fn(async () => ({ items: state.namespaces.map((n) => ({ metadata: { name: n } })) })),
|
|
||||||
},
|
},
|
||||||
kc: {
|
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", () => ({
|
vi.mock("@kubernetes/client-node", () => ({
|
||||||
CoreV1Api: class CoreV1Api {},
|
|
||||||
CustomObjectsApi: class CustomObjectsApi {},
|
CustomObjectsApi: class CustomObjectsApi {},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -47,11 +39,7 @@ describe("utils/kubernetes/httproute-list", () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
state.enabled = true;
|
state.enabled = true;
|
||||||
state.namespaces = ["a", "b"];
|
state.items = [{ metadata: { name: "r1" } }, { metadata: { name: "r2" } }];
|
||||||
state.routesByNs = {
|
|
||||||
a: [{ metadata: { name: "r1" } }],
|
|
||||||
b: [{ metadata: { name: "r2" } }],
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns an empty list when gateway discovery is disabled", async () => {
|
it("returns an empty list when gateway discovery is disabled", async () => {
|
||||||
@@ -64,19 +52,18 @@ describe("utils/kubernetes/httproute-list", () => {
|
|||||||
expect(result).toEqual([]);
|
expect(result).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("lists namespaces and aggregates httproutes", async () => {
|
it("lists httproutes", async () => {
|
||||||
vi.resetModules();
|
vi.resetModules();
|
||||||
const listHttpRoute = (await import("./httproute-list")).default;
|
const listHttpRoute = (await import("./httproute-list")).default;
|
||||||
|
|
||||||
const result = await listHttpRoute();
|
const result = await listHttpRoute();
|
||||||
|
|
||||||
expect(result.map((r) => r.metadata.name)).toEqual(["r1", "r2"]);
|
expect(result.map((r) => r.metadata.name)).toEqual(["r1", "r2"]);
|
||||||
expect(state.core.listNamespace).toHaveBeenCalled();
|
expect(state.crd.listClusterCustomObject).toHaveBeenCalled();
|
||||||
expect(state.crd.listNamespacedCustomObject).toHaveBeenCalledTimes(2);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("logs and returns [] when namespace listing fails", async () => {
|
it("logs and returns [] when cluster listing fails", async () => {
|
||||||
state.core.listNamespace.mockRejectedValueOnce({ statusCode: 500, body: "boom", response: "resp" });
|
state.crd.listClusterCustomObject.mockRejectedValueOnce({ statusCode: 500, body: "boom", response: "resp" });
|
||||||
|
|
||||||
vi.resetModules();
|
vi.resetModules();
|
||||||
const listHttpRoute = (await import("./httproute-list")).default;
|
const listHttpRoute = (await import("./httproute-list")).default;
|
||||||
@@ -87,20 +74,4 @@ describe("utils/kubernetes/httproute-list", () => {
|
|||||||
expect(logger.error).toHaveBeenCalled();
|
expect(logger.error).toHaveBeenCalled();
|
||||||
expect(logger.debug).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