Improved kubernetes error handling

This commit is contained in:
James Wynn 2022-10-26 10:15:25 -05:00
parent 8887fcc3ee
commit 4fc6db49ca
8 changed files with 205 additions and 124 deletions

View file

@ -2,15 +2,18 @@ import { CoreV1Api, Metrics } from "@kubernetes/client-node";
import getKubeConfig from "../../../../utils/config/kubernetes";
import { parseCpu, parseMemory } from "../../../../utils/kubernetes/kubernetes-utils";
import createLogger from "../../../../utils/logger";
const logger = createLogger("kubernetesStatsService");
export default async function handler(req, res) {
const APP_LABEL = "app.kubernetes.io/name";
const APP_LABEL = "app.kubernetes.io/name";
const { service } = req.query;
const [namespace, appName] = service;
if (!namespace && !appName) {
res.status(400).send({
error: "kubernetes query parameters are required",
error: "kubernetes query parameters are required"
});
return;
}
@ -20,12 +23,23 @@ export default async function handler(req, res) {
const kc = getKubeConfig();
const coreApi = kc.makeApiClient(CoreV1Api);
const metricsApi = new Metrics(kc);
const podsResponse = await coreApi.listNamespacedPod(namespace, null, null, null, null, labelSelector);
const pods = podsResponse.body.items;
const podsResponse = await coreApi.listNamespacedPod(namespace, null, null, null, null, labelSelector)
.then((response) => response.body)
.catch((err) => {
logger.error("Error getting pods: %d %s %s", err.statusCode, err.body, err.response);
return null;
});
if (!podsResponse) {
res.status(500).send({
error: "Error communicating with kubernetes"
});
return;
}
const pods = podsResponse.items;
if (pods.length === 0) {
res.status(200).send({
error: "not found",
res.status(404).send({
error: "not found"
});
return;
}
@ -46,34 +60,43 @@ export default async function handler(req, res) {
const stats = await pods.map(async (pod) => {
let depMem = 0;
let depCpu = 0;
const podMetrics = await metricsApi.getPodMetrics(namespace, pod.metadata.name);
podMetrics.containers.forEach((container) => {
depMem += parseMemory(container.usage.memory);
depCpu += parseCpu(container.usage.cpu);
});
const podMetrics = await metricsApi.getPodMetrics(namespace, pod.metadata.name)
.then((response) => response)
.catch((err) => {
// 404 generally means that the metrics have not been populated yet
if (err.statusCode !== 404) {
logger.error("Error getting pod metrics: %d %s %s", err.statusCode, err.body, err.response);
}
return null;
});
if (podMetrics) {
podMetrics.containers.forEach((container) => {
depMem += parseMemory(container.usage.memory);
depCpu += parseCpu(container.usage.cpu);
});
}
return {
mem: depMem,
cpu: depCpu
}
}).reduce(async (finalStats, podStatPromise) => {
const podStats = await podStatPromise;
return {
mem: finalStats.mem + podStats.mem,
cpu: finalStats.cpu + podStats.cpu
};
});
}).reduce(async (finalStats, podStatPromise) => {
const podStats = await podStatPromise;
return {
mem: finalStats.mem + podStats.mem,
cpu: finalStats.cpu + podStats.cpu
};
});
stats.cpuLimit = cpuLimit;
stats.memLimit = memLimit;
stats.cpuUsage = stats.cpu / cpuLimit;
stats.memUsage = stats.mem / memLimit;
stats.cpuUsage = cpuLimit ? stats.cpu / cpuLimit : 0;
stats.memUsage = memLimit ? stats.mem / memLimit : 0;
res.status(200).json({
stats,
stats
});
} catch (e) {
console.log("error", e);
logger.error(e);
res.status(500).send({
error: "unknown error",
error: "unknown error"
});
}
}