move metrics api to main

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
Jari Kolehmainen committed 2020-03-23 17:54:55 +02:00
1 parent 47d82e4d62
commit c0fb808365
6 files changed
+84 -143

No files matched your search

-59
View File
@@ -1,59 +0,0 @@
// Get namespaces
import config from "../config";
import { KubeJsonApiDataList } from "../../client/api/kube-json-api";
import { IKubeRequestParams, kubeRequest } from "./kube-request";
import { reviewResourceAccess } from "./review-resource-access";
import { getServiceAccountToken } from "./get-service-account-token"
export async function getNamespaces(params: Partial<IKubeRequestParams> = {}) {
return kubeRequest<KubeJsonApiDataList>({
...params,
path: "/api/v1/namespaces",
});
}
export async function getAllowedNamespaces(
params: Partial<IKubeRequestParams>,
fallbackNs = config.KUBERNETES_NAMESPACE,
): Promise<string[]> {
try {
const allNamespaces = await getNamespaces(params);
const nsAccessStatuses = await Promise.all(
allNamespaces.items.map(ns => {
const { name } = ns.metadata;
return reviewResourceAccess(params, {
namespace: name,
resource: "pods",
verb: "list",
});
})
);
return allNamespaces.items
.filter((ns, i) => nsAccessStatuses[i].allowed)
.map(ns => ns.metadata.name);
} catch (e) {
const serviceToken = await getServiceAccountToken();
if (!serviceToken) {
return fallbackNs ? [fallbackNs] : [];
}
// fetch namespaces with service-account token (cluster-wide)
// and for every namespace make additional request to check if namespace available for user-token
const allNamespaces = await getNamespaces({
authHeader: `Bearer ${serviceToken}`
});
const nsAccessStatuses = await Promise.all(
allNamespaces.items.map(ns => {
const { name } = ns.metadata;
return reviewResourceAccess(params, {
namespace: name,
resource: "pods",
verb: "list",
});
})
);
return allNamespaces.items
.filter((ns, i) => nsAccessStatuses[i].allowed)
.map(ns => ns.metadata.name);
}
}
+1 -2
View File
@@ -8,7 +8,7 @@ import compression from "compression"
import helmet from "helmet"
import morgan from "morgan"
import { logger } from "../server/utils/logger"
import { kubewatchRoute, metricsRoute, readyStateRoute } from "../server/routes";
import { kubewatchRoute, readyStateRoute } from "../server/routes";
import { useRequestHeaderToken } from "../server/middlewares";
const {
@@ -25,7 +25,6 @@ app.set('trust proxy', 1); // trust first proxy
localApis.use(
readyStateRoute(),
kubewatchRoute(),
metricsRoute()
);
// https://github.com/expressjs/cookie-session
-82
View File
@@ -1,82 +0,0 @@
//-- Metrics
// https://prometheus.io/docs/prometheus/latest/querying/api/
import { Router } from "express";
import config from "../config";
import { kubeRequest } from "../api/kube-request";
import { userSession } from "../user-session";
import { AxiosError } from "axios";
import { IMetrics } from "../../client/api/endpoints/metrics.api";
import { IMetricsQuery } from "../common/metrics"
export function metricsRoute() {
const router = Router();
router.post("/metrics", async (req, res, next) => {
const { authHeader } = userSession.get(req);
const { namespace, ...queryParams } = req.query;
const query: IMetricsQuery = req.body;
/*eslint-disable */
// add default namespace for rbac-proxy validation
if (!queryParams.kubernetes_namespace) {
queryParams.kubernetes_namespace = config.STATS_NAMESPACE;
}
/*eslint-enble */
// prometheus metrics loader
const attempts: { [query: string]: number } = {};
const maxAttempts = 5;
const loadMetrics = (query: string): Promise<IMetrics> => {
const attempt = attempts[query] = (attempts[query] || 0) + 1;
return kubeRequest<IMetrics>({
url: config.KUBE_METRICS_URL,
path: "/api/v1/query_range",
authHeader: authHeader,
params: {
query: query,
...queryParams,
},
}).catch(async (err: AxiosError) => {
// https://github.com/axios/axios#handling-errors
if (!err.response && attempt < maxAttempts) {
await new Promise(resolve => setTimeout(resolve, attempt * 1000)); // add delay before repeating request
return loadMetrics(query);
}
return {
status: err.toString(),
data: {
result: []
},
} as IMetrics;
})
};
// return data in same structure as query
let data: any;
try {
if (typeof query === "string") {
data = await loadMetrics(query)
}
else if (Array.isArray(query)) {
data = await Promise.all(query.map(loadMetrics));
}
else {
data = {};
const result = await Promise.all(
Object.values(query).map(loadMetrics)
);
Object.keys(query).forEach((metricName, index) => {
data[metricName] = result[index];
});
}
res.json(data);
} catch (err) {
next(err);
}
});
return router;
}