mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Introduce healthy abstraction between back-end routes and route handlers
Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
parent
d099256c9a
commit
4b76327489
@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { LensApiRequest } from "../router";
|
||||
import type { LensApiRequest, LensApiResult } from "../router";
|
||||
import staticFileRouteInjectable from "../routes/static-file-route.injectable";
|
||||
import { getDiForUnitTesting } from "../getDiForUnitTesting";
|
||||
|
||||
@ -24,7 +24,7 @@ jest.mock("electron", () => ({
|
||||
}));
|
||||
|
||||
describe("Router", () => {
|
||||
let handleStaticFile: (request: LensApiRequest) => Promise<void>;
|
||||
let handleStaticFile: (request: LensApiRequest) => Promise<LensApiResult>;
|
||||
|
||||
beforeEach(async () => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
@ -6,6 +6,8 @@
|
||||
import Call from "@hapi/call";
|
||||
import Subtext from "@hapi/subtext";
|
||||
import type http from "http";
|
||||
import type httpProxy from "http-proxy";
|
||||
import { toPairs } from "lodash/fp";
|
||||
import path from "path";
|
||||
import type { Cluster } from "../common/cluster/cluster";
|
||||
|
||||
@ -40,6 +42,94 @@ export interface LensApiRequest<P = any> {
|
||||
};
|
||||
}
|
||||
|
||||
const respondFor =
|
||||
(contentType: string) =>
|
||||
(
|
||||
content: any,
|
||||
statusCode: number,
|
||||
response: http.ServerResponse,
|
||||
) => {
|
||||
response.statusCode = statusCode;
|
||||
response.setHeader("Content-Type", contentType);
|
||||
|
||||
if (content instanceof Buffer) {
|
||||
response.write(content);
|
||||
|
||||
response.end();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
response.end(content);
|
||||
};
|
||||
|
||||
export type SupportedFileExtension = "json" | "txt" | "html" | "css" | "gif" | "jpg" | "png" | "svg" | "js" | "woff2" | "ttf";
|
||||
|
||||
export const contentTypes: Record<SupportedFileExtension, LensApiResultContentType> = {
|
||||
json: {
|
||||
respond: (
|
||||
content: any,
|
||||
statusCode: number,
|
||||
response: http.ServerResponse,
|
||||
) => {
|
||||
response.statusCode = statusCode;
|
||||
response.setHeader("Content-Type", "application/json");
|
||||
|
||||
if (content instanceof Buffer) {
|
||||
response.write(content);
|
||||
response.end();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const normalizedContent =
|
||||
typeof content === "object" ? JSON.stringify(content) : content;
|
||||
|
||||
response.end(normalizedContent);
|
||||
},
|
||||
},
|
||||
|
||||
txt: {
|
||||
respond: respondFor("text/plain"),
|
||||
},
|
||||
|
||||
html: {
|
||||
respond: respondFor("text/html"),
|
||||
},
|
||||
|
||||
css: {
|
||||
respond: respondFor("text/css"),
|
||||
},
|
||||
|
||||
gif: {
|
||||
respond: respondFor("image/gif"),
|
||||
},
|
||||
|
||||
jpg: {
|
||||
respond: respondFor("image/jpeg"),
|
||||
},
|
||||
|
||||
png: {
|
||||
respond: respondFor("image/png"),
|
||||
},
|
||||
|
||||
svg: {
|
||||
respond: respondFor("image/svg+xml"),
|
||||
},
|
||||
|
||||
js: {
|
||||
respond: respondFor("application/javascript"),
|
||||
},
|
||||
|
||||
woff2: {
|
||||
respond: respondFor("font/woff2"),
|
||||
},
|
||||
|
||||
ttf: {
|
||||
respond: respondFor("font/ttf"),
|
||||
},
|
||||
};
|
||||
|
||||
export class Router {
|
||||
protected router = new Call.Router();
|
||||
static rootPath = path.resolve(__static);
|
||||
@ -47,7 +137,42 @@ export class Router {
|
||||
constructor(routes: Route[]) {
|
||||
routes.forEach(route => {
|
||||
this.router.add({ method: route.method, path: route.path }, async (request: LensApiRequest) => {
|
||||
await route.handler(request);
|
||||
let result: LensApiResult | void;
|
||||
|
||||
try {
|
||||
result = await route.handler(request);
|
||||
} catch(error) {
|
||||
contentTypes.txt.respond(error.toString(), 422, request.response);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
contentTypes.txt.respond(null, 204, request.response);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
response,
|
||||
error,
|
||||
statusCode = error ? 400 : 200,
|
||||
contentType = contentTypes.json,
|
||||
headers = {},
|
||||
proxy,
|
||||
} = result;
|
||||
|
||||
if (proxy) {
|
||||
return;
|
||||
}
|
||||
|
||||
const headerNameValuePairs = toPairs<string>(headers);
|
||||
|
||||
headerNameValuePairs.forEach(([key, value]) => {
|
||||
request.response.setHeader(key, value);
|
||||
});
|
||||
|
||||
contentType.respond(error || response, statusCode, request.response);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -91,8 +216,21 @@ export class Router {
|
||||
}
|
||||
}
|
||||
|
||||
interface LensApiResultContentType {
|
||||
respond: (content: any, statusCode: number, response: http.ServerResponse) => void;
|
||||
}
|
||||
|
||||
export interface LensApiResult {
|
||||
statusCode?: number;
|
||||
response?: any;
|
||||
error?: any;
|
||||
contentType?: LensApiResultContentType;
|
||||
headers?: { Location: string };
|
||||
proxy?: httpProxy;
|
||||
}
|
||||
|
||||
export interface Route {
|
||||
path: string;
|
||||
method: "get" | "post" | "put" | "patch" | "delete";
|
||||
handler: (request: LensApiRequest) => void | Promise<void>;
|
||||
handler: (request: LensApiRequest) => LensApiResult | Promise<LensApiResult>;
|
||||
}
|
||||
|
||||
@ -4,9 +4,8 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { routeInjectionToken } from "../../../router/router.injectable";
|
||||
import type { LensApiRequest } from "../../../router";
|
||||
import type { LensApiRequest, LensApiResult } from "../../../router";
|
||||
import { helmService } from "../../../helm/helm-service";
|
||||
import { respondJson, respondText } from "../../../utils/http-responses";
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
|
||||
const getChartRouteInjectable = getInjectable({
|
||||
@ -16,17 +15,16 @@ const getChartRouteInjectable = getInjectable({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/v2/charts/{repo}/{chart}`,
|
||||
|
||||
handler: async (request: LensApiRequest) => {
|
||||
const { params, query, response } = request;
|
||||
|
||||
try {
|
||||
const chart = await helmService.getChart(params.repo, params.chart, query.get("version"));
|
||||
|
||||
respondJson(response, chart);
|
||||
} catch (error) {
|
||||
respondText(response, error?.toString() || "Error getting chart", 422);
|
||||
}
|
||||
},
|
||||
handler: async ({
|
||||
params,
|
||||
query,
|
||||
}: LensApiRequest): Promise<LensApiResult> => ({
|
||||
response: await helmService.getChart(
|
||||
params.repo,
|
||||
params.chart,
|
||||
query.get("version"),
|
||||
),
|
||||
}),
|
||||
}),
|
||||
|
||||
injectionToken: routeInjectionToken,
|
||||
|
||||
@ -4,9 +4,8 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { routeInjectionToken } from "../../../router/router.injectable";
|
||||
import type { LensApiRequest } from "../../../router";
|
||||
import type { LensApiRequest, LensApiResult } from "../../../router";
|
||||
import { helmService } from "../../../helm/helm-service";
|
||||
import { respondJson, respondText } from "../../../utils/http-responses";
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
|
||||
const getChartRouteValuesInjectable = getInjectable({
|
||||
@ -16,17 +15,16 @@ const getChartRouteValuesInjectable = getInjectable({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/v2/charts/{repo}/{chart}/values`,
|
||||
|
||||
handler: async (request: LensApiRequest) => {
|
||||
const { params, query, response } = request;
|
||||
|
||||
try {
|
||||
const values = await helmService.getChartValues(params.repo, params.chart, query.get("version"));
|
||||
|
||||
respondJson(response, values);
|
||||
} catch (error) {
|
||||
respondText(response, error?.toString() || "Error getting chart values", 422);
|
||||
}
|
||||
},
|
||||
handler: async ({
|
||||
params,
|
||||
query,
|
||||
}: LensApiRequest): Promise<LensApiResult> => ({
|
||||
response: await helmService.getChartValues(
|
||||
params.repo,
|
||||
params.chart,
|
||||
query.get("version"),
|
||||
),
|
||||
}),
|
||||
}),
|
||||
|
||||
injectionToken: routeInjectionToken,
|
||||
|
||||
@ -4,9 +4,8 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { routeInjectionToken } from "../../../router/router.injectable";
|
||||
import type { LensApiRequest } from "../../../router";
|
||||
import type { LensApiRequest, LensApiResult } from "../../../router";
|
||||
import { helmService } from "../../../helm/helm-service";
|
||||
import { respondJson } from "../../../utils/http-responses";
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
|
||||
const listChartsRouteInjectable = getInjectable({
|
||||
@ -16,12 +15,10 @@ const listChartsRouteInjectable = getInjectable({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/v2/charts`,
|
||||
|
||||
handler: async (request: LensApiRequest) => {
|
||||
const { response } = request;
|
||||
const charts = await helmService.listCharts();
|
||||
|
||||
respondJson(response, charts);
|
||||
},
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars-ts
|
||||
handler: async (request: LensApiRequest): Promise<LensApiResult> => ({
|
||||
response: await helmService.listCharts(),
|
||||
}),
|
||||
}),
|
||||
|
||||
injectionToken: routeInjectionToken,
|
||||
|
||||
@ -3,12 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import type { LensApiRequest } from "../../../router";
|
||||
import type { LensApiRequest, LensApiResult } from "../../../router";
|
||||
import { helmService } from "../../../helm/helm-service";
|
||||
import { respondJson, respondText } from "../../../utils/http-responses";
|
||||
import { routeInjectionToken } from "../../../router/router.injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import logger from "../../../logger";
|
||||
|
||||
const deleteReleaseRouteInjectable = getInjectable({
|
||||
id: "delete-release-route",
|
||||
@ -17,17 +15,16 @@ const deleteReleaseRouteInjectable = getInjectable({
|
||||
method: "delete",
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{release}`,
|
||||
|
||||
handler: async (request: LensApiRequest) => {
|
||||
const { cluster, params, response } = request;
|
||||
handler: async (request: LensApiRequest): Promise<LensApiResult> => {
|
||||
const { cluster, params } = request;
|
||||
|
||||
try {
|
||||
const result = await helmService.deleteRelease(cluster, params.release, params.namespace);
|
||||
|
||||
respondJson(response, result);
|
||||
} catch (error) {
|
||||
logger.debug(error);
|
||||
respondText(response, error?.toString() || "Error deleting release", 422);
|
||||
}
|
||||
return {
|
||||
response: await helmService.deleteRelease(
|
||||
cluster,
|
||||
params.release,
|
||||
params.namespace,
|
||||
),
|
||||
};
|
||||
},
|
||||
}),
|
||||
|
||||
|
||||
@ -3,12 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import type { LensApiRequest } from "../../../router";
|
||||
import type { LensApiRequest, LensApiResult } from "../../../router";
|
||||
import { helmService } from "../../../helm/helm-service";
|
||||
import { respondJson, respondText } from "../../../utils/http-responses";
|
||||
import { routeInjectionToken } from "../../../router/router.injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import logger from "../../../logger";
|
||||
|
||||
const getReleaseRouteHistoryInjectable = getInjectable({
|
||||
id: "get-release-history-route",
|
||||
@ -17,17 +15,16 @@ const getReleaseRouteHistoryInjectable = getInjectable({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{release}/history`,
|
||||
|
||||
handler: async (request: LensApiRequest) => {
|
||||
const { cluster, params, response } = request;
|
||||
handler: async (request: LensApiRequest): Promise<LensApiResult> => {
|
||||
const { cluster, params } = request;
|
||||
|
||||
try {
|
||||
const result = await helmService.getReleaseHistory(cluster, params.release, params.namespace);
|
||||
|
||||
respondJson(response, result);
|
||||
} catch (error) {
|
||||
logger.debug(error);
|
||||
respondText(response, error?.toString() || "Error getting release history", 422);
|
||||
}
|
||||
return {
|
||||
response: await helmService.getReleaseHistory(
|
||||
cluster,
|
||||
params.release,
|
||||
params.namespace,
|
||||
),
|
||||
};
|
||||
},
|
||||
}),
|
||||
|
||||
|
||||
@ -3,12 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import type { LensApiRequest } from "../../../router";
|
||||
import type { LensApiRequest, LensApiResult } from "../../../router";
|
||||
import { helmService } from "../../../helm/helm-service";
|
||||
import { respondJson, respondText } from "../../../utils/http-responses";
|
||||
import { routeInjectionToken } from "../../../router/router.injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import logger from "../../../logger";
|
||||
|
||||
const getReleaseRouteInjectable = getInjectable({
|
||||
id: "get-release-route",
|
||||
@ -17,17 +15,16 @@ const getReleaseRouteInjectable = getInjectable({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{release}`,
|
||||
|
||||
handler: async (request: LensApiRequest) => {
|
||||
const { cluster, params, response } = request;
|
||||
handler: async (request: LensApiRequest): Promise<LensApiResult> => {
|
||||
const { cluster, params } = request;
|
||||
|
||||
try {
|
||||
const result = await helmService.getRelease(cluster, params.release, params.namespace);
|
||||
|
||||
respondJson(response, result);
|
||||
} catch (error) {
|
||||
logger.debug(error);
|
||||
respondText(response, error?.toString() || "Error getting release", 422);
|
||||
}
|
||||
return {
|
||||
response: await helmService.getRelease(
|
||||
cluster,
|
||||
params.release,
|
||||
params.namespace,
|
||||
),
|
||||
};
|
||||
},
|
||||
}),
|
||||
|
||||
|
||||
@ -3,13 +3,12 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import type { LensApiRequest } from "../../../router";
|
||||
import type { LensApiRequest, LensApiResult } from "../../../router";
|
||||
import { helmService } from "../../../helm/helm-service";
|
||||
import { respondText } from "../../../utils/http-responses";
|
||||
import { routeInjectionToken } from "../../../router/router.injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import logger from "../../../logger";
|
||||
import { getBoolean } from "../../../utils/parse-query";
|
||||
import { contentTypes } from "../../../router";
|
||||
|
||||
const getReleaseRouteValuesInjectable = getInjectable({
|
||||
id: "get-release-values-route",
|
||||
@ -18,18 +17,19 @@ const getReleaseRouteValuesInjectable = getInjectable({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{release}/values`,
|
||||
|
||||
handler: async (request: LensApiRequest) => {
|
||||
const { cluster, params: { namespace, release }, response, query } = request;
|
||||
handler: async (request: LensApiRequest): Promise<LensApiResult> => {
|
||||
const { cluster, params: { namespace, release }, query } = request;
|
||||
const all = getBoolean(query, "all");
|
||||
|
||||
try {
|
||||
const result = await helmService.getReleaseValues(release, { cluster, namespace, all });
|
||||
return {
|
||||
response: await helmService.getReleaseValues(release, {
|
||||
cluster,
|
||||
namespace,
|
||||
all,
|
||||
}),
|
||||
|
||||
respondText(response, result);
|
||||
} catch (error) {
|
||||
logger.debug(error);
|
||||
respondText(response, error?.toString() || "Error getting release values", 422);
|
||||
}
|
||||
contentType: contentTypes.txt,
|
||||
};
|
||||
},
|
||||
}),
|
||||
|
||||
|
||||
@ -3,12 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import type { LensApiRequest } from "../../../router";
|
||||
import type { LensApiRequest, LensApiResult } from "../../../router";
|
||||
import { helmService } from "../../../helm/helm-service";
|
||||
import { respondJson, respondText } from "../../../utils/http-responses";
|
||||
import { routeInjectionToken } from "../../../router/router.injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import logger from "../../../logger";
|
||||
|
||||
const installChartRouteInjectable = getInjectable({
|
||||
id: "install-chart-route",
|
||||
@ -17,17 +15,13 @@ const installChartRouteInjectable = getInjectable({
|
||||
method: "post",
|
||||
path: `${apiPrefix}/v2/releases`,
|
||||
|
||||
handler: async (request: LensApiRequest) => {
|
||||
const { payload, cluster, response } = request;
|
||||
handler: async (request: LensApiRequest): Promise<LensApiResult> => {
|
||||
const { payload, cluster } = request;
|
||||
|
||||
try {
|
||||
const result = await helmService.installChart(cluster, payload);
|
||||
|
||||
respondJson(response, result, 201);
|
||||
} catch (error) {
|
||||
logger.debug(error);
|
||||
respondText(response, error?.toString() || "Error installing chart", 422);
|
||||
}
|
||||
return {
|
||||
response: await helmService.installChart(cluster, payload),
|
||||
statusCode: 201,
|
||||
};
|
||||
},
|
||||
}),
|
||||
|
||||
|
||||
@ -3,12 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import type { LensApiRequest } from "../../../router";
|
||||
import type { LensApiRequest, LensApiResult } from "../../../router";
|
||||
import { helmService } from "../../../helm/helm-service";
|
||||
import { respondJson, respondText } from "../../../utils/http-responses";
|
||||
import { routeInjectionToken } from "../../../router/router.injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import logger from "../../../logger";
|
||||
|
||||
const listReleasesRouteInjectable = getInjectable({
|
||||
id: "list-releases-route",
|
||||
@ -17,17 +15,12 @@ const listReleasesRouteInjectable = getInjectable({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/v2/releases/{namespace?}`,
|
||||
|
||||
handler: async (request: LensApiRequest) => {
|
||||
const { cluster, params, response } = request;
|
||||
handler: async (request: LensApiRequest): Promise<LensApiResult> => {
|
||||
const { cluster, params } = request;
|
||||
|
||||
try {
|
||||
const result = await helmService.listReleases(cluster, params.namespace);
|
||||
|
||||
respondJson(response, result);
|
||||
} catch(error) {
|
||||
logger.debug(error);
|
||||
respondText(response, error?.toString() || "Error listing release", 422);
|
||||
}
|
||||
return {
|
||||
response: await helmService.listReleases(cluster, params.namespace),
|
||||
};
|
||||
},
|
||||
}),
|
||||
|
||||
|
||||
@ -5,10 +5,8 @@
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import type { LensApiRequest } from "../../../router";
|
||||
import { helmService } from "../../../helm/helm-service";
|
||||
import { respondText } from "../../../utils/http-responses";
|
||||
import { routeInjectionToken } from "../../../router/router.injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import logger from "../../../logger";
|
||||
|
||||
const rollbackReleaseRouteInjectable = getInjectable({
|
||||
id: "rollback-release-route",
|
||||
@ -17,20 +15,14 @@ const rollbackReleaseRouteInjectable = getInjectable({
|
||||
method: "put",
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{release}/rollback`,
|
||||
|
||||
handler: async (request: LensApiRequest) => {
|
||||
const { cluster, params, payload, response } = request;
|
||||
handler: async (request: LensApiRequest): Promise<void> => {
|
||||
const { cluster, params, payload } = request;
|
||||
|
||||
try {
|
||||
await helmService.rollback(cluster, params.release, params.namespace, payload.revision);
|
||||
|
||||
response.end();
|
||||
} catch (error) {
|
||||
logger.debug(error);
|
||||
respondText(response, error?.toString() || "Error rolling back chart", 422);
|
||||
}
|
||||
await helmService.rollback(cluster, params.release, params.namespace, payload.revision);
|
||||
},
|
||||
}),
|
||||
|
||||
// @ts-ignore
|
||||
injectionToken: routeInjectionToken,
|
||||
});
|
||||
|
||||
|
||||
@ -3,12 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import type { LensApiRequest } from "../../../router";
|
||||
import type { LensApiRequest, LensApiResult } from "../../../router";
|
||||
import { helmService } from "../../../helm/helm-service";
|
||||
import { respondJson, respondText } from "../../../utils/http-responses";
|
||||
import { routeInjectionToken } from "../../../router/router.injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import logger from "../../../logger";
|
||||
|
||||
const updateReleaseRouteInjectable = getInjectable({
|
||||
id: "update-release-route",
|
||||
@ -17,18 +15,18 @@ const updateReleaseRouteInjectable = getInjectable({
|
||||
method: "put",
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{release}`,
|
||||
|
||||
handler: async (request: LensApiRequest) => {
|
||||
const { cluster, params, payload, response } = request;
|
||||
|
||||
try {
|
||||
const result = await helmService.updateRelease(cluster, params.release, params.namespace, payload );
|
||||
|
||||
respondJson(response, result);
|
||||
} catch (error) {
|
||||
logger.debug(error);
|
||||
respondText(response, error?.toString() || "Error updating chart", 422);
|
||||
}
|
||||
},
|
||||
handler: async ({
|
||||
cluster,
|
||||
params,
|
||||
payload,
|
||||
}: LensApiRequest): Promise<LensApiResult> => ({
|
||||
response: await helmService.updateRelease(
|
||||
cluster,
|
||||
params.release,
|
||||
params.namespace,
|
||||
payload,
|
||||
),
|
||||
}),
|
||||
}),
|
||||
|
||||
injectionToken: routeInjectionToken,
|
||||
|
||||
@ -5,13 +5,11 @@
|
||||
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import type { LensApiRequest } from "../../router";
|
||||
import { respondJson } from "../../utils/http-responses";
|
||||
import type { LensApiRequest, LensApiResult } from "../../router";
|
||||
import { routeInjectionToken } from "../../router/router.injectable";
|
||||
import type { Cluster } from "../../../common/cluster/cluster";
|
||||
import { CoreV1Api, V1Secret } from "@kubernetes/client-node";
|
||||
|
||||
|
||||
const getServiceAccountRouteInjectable = getInjectable({
|
||||
id: "get-service-account-route",
|
||||
|
||||
@ -19,8 +17,8 @@ const getServiceAccountRouteInjectable = getInjectable({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}`,
|
||||
|
||||
handler: async (request: LensApiRequest) => {
|
||||
const { params, response, cluster } = request;
|
||||
handler: async (request: LensApiRequest): Promise<LensApiResult> => {
|
||||
const { params, cluster } = request;
|
||||
const client = (await cluster.getProxyKubeconfig()).makeApiClient(CoreV1Api);
|
||||
const secretList = await client.listNamespacedSecret(params.namespace);
|
||||
|
||||
@ -30,9 +28,7 @@ const getServiceAccountRouteInjectable = getInjectable({
|
||||
return annotations && annotations["kubernetes.io/service-account.name"] == params.account;
|
||||
});
|
||||
|
||||
const data = generateKubeConfig(params.account, secret, cluster);
|
||||
|
||||
respondJson(response, data);
|
||||
return { response: generateKubeConfig(params.account, secret, cluster) };
|
||||
},
|
||||
}),
|
||||
|
||||
|
||||
@ -5,8 +5,7 @@
|
||||
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import type { LensApiRequest } from "../../router";
|
||||
import { respondJson } from "../../utils/http-responses";
|
||||
import type { LensApiRequest, LensApiResult } from "../../router";
|
||||
import { routeInjectionToken } from "../../router/router.injectable";
|
||||
import { ClusterMetadataKey, ClusterPrometheusMetadata } from "../../../common/cluster-types";
|
||||
import logger from "../../logger";
|
||||
@ -43,7 +42,7 @@ async function loadMetrics(promQueries: string[], cluster: Cluster, prometheusPa
|
||||
return Promise.all(queries.map(loadMetric));
|
||||
}
|
||||
|
||||
const addMetricsRoute = async ({ response, cluster, payload, query }: LensApiRequest) => {
|
||||
const addMetricsRoute = async ({ cluster, payload, query }: LensApiRequest): Promise<LensApiResult> => {
|
||||
const queryParams: IMetricsQuery = Object.fromEntries(query.entries());
|
||||
const prometheusMetadata: ClusterPrometheusMetadata = {};
|
||||
|
||||
@ -56,33 +55,39 @@ const addMetricsRoute = async ({ response, cluster, payload, query }: LensApiReq
|
||||
if (!prometheusPath) {
|
||||
prometheusMetadata.success = false;
|
||||
|
||||
return respondJson(response, {});
|
||||
return { response: {}};
|
||||
}
|
||||
|
||||
// return data in same structure as query
|
||||
if (typeof payload === "string") {
|
||||
const [data] = await loadMetrics([payload], cluster, prometheusPath, queryParams);
|
||||
|
||||
respondJson(response, data);
|
||||
} else if (Array.isArray(payload)) {
|
||||
return { response: data };
|
||||
}
|
||||
|
||||
if (Array.isArray(payload)) {
|
||||
const data = await loadMetrics(payload, cluster, prometheusPath, queryParams);
|
||||
|
||||
respondJson(response, data);
|
||||
} else {
|
||||
const queries = Object.entries<Record<string, string>>(payload)
|
||||
.map(([queryName, queryOpts]) => (
|
||||
provider.getQuery(queryOpts, queryName)
|
||||
));
|
||||
const result = await loadMetrics(queries, cluster, prometheusPath, queryParams);
|
||||
const data = Object.fromEntries(Object.keys(payload).map((metricName, i) => [metricName, result[i]]));
|
||||
|
||||
respondJson(response, data);
|
||||
return { response: data };
|
||||
}
|
||||
|
||||
const queries = Object.entries<Record<string, string>>(payload)
|
||||
.map(([queryName, queryOpts]) => (
|
||||
provider.getQuery(queryOpts, queryName)
|
||||
));
|
||||
|
||||
const result = await loadMetrics(queries, cluster, prometheusPath, queryParams);
|
||||
const data = Object.fromEntries(Object.keys(payload).map((metricName, i) => [metricName, result[i]]));
|
||||
|
||||
prometheusMetadata.success = true;
|
||||
|
||||
return { response: data };
|
||||
} catch (error) {
|
||||
prometheusMetadata.success = false;
|
||||
respondJson(response, {});
|
||||
|
||||
logger.warn(`[METRICS-ROUTE]: failed to get metrics for clusterId=${cluster.id}:`, error);
|
||||
|
||||
return { response: {}};
|
||||
} finally {
|
||||
cluster.metadata[ClusterMetadataKey.PROMETHEUS] = prometheusMetadata;
|
||||
}
|
||||
|
||||
@ -5,8 +5,7 @@
|
||||
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import type { LensApiRequest } from "../../router";
|
||||
import { respondJson } from "../../utils/http-responses";
|
||||
import type { LensApiRequest, LensApiResult } from "../../router";
|
||||
import { routeInjectionToken } from "../../router/router.injectable";
|
||||
import { PrometheusProviderRegistry } from "../../prometheus";
|
||||
import type { MetricProviderInfo } from "../../../common/k8s-api/endpoints/metrics.api";
|
||||
@ -18,14 +17,15 @@ const getMetricProvidersRouteInjectable = getInjectable({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/metrics/providers`,
|
||||
|
||||
handler: async (request: LensApiRequest) => {
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars-ts
|
||||
handler: async (request: LensApiRequest) : Promise<LensApiResult> => {
|
||||
const providers: MetricProviderInfo[] = [];
|
||||
|
||||
for (const { name, id, isConfigurable } of PrometheusProviderRegistry.getInstance().providers.values()) {
|
||||
providers.push({ name, id, isConfigurable });
|
||||
}
|
||||
|
||||
respondJson(request.response, providers);
|
||||
return { response: providers };
|
||||
},
|
||||
}),
|
||||
|
||||
|
||||
@ -4,13 +4,12 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { routeInjectionToken } from "../../router/router.injectable";
|
||||
import type { LensApiRequest } from "../../router";
|
||||
import type { LensApiRequest, LensApiResult } from "../../router";
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import { respondJson } from "../../utils/http-responses";
|
||||
import { PortForward } from "./functionality/port-forward";
|
||||
|
||||
const getCurrentPortForward = async (request: LensApiRequest) => {
|
||||
const { params, query, response, cluster } = request;
|
||||
const getCurrentPortForward = async (request: LensApiRequest): Promise<LensApiResult> => {
|
||||
const { params, query, cluster } = request;
|
||||
const { namespace, resourceType, resourceName } = params;
|
||||
const port = Number(query.get("port"));
|
||||
const forwardPort = Number(query.get("forwardPort"));
|
||||
@ -20,7 +19,7 @@ const getCurrentPortForward = async (request: LensApiRequest) => {
|
||||
namespace, port, forwardPort,
|
||||
});
|
||||
|
||||
respondJson(response, { port: portForward?.forwardPort ?? null });
|
||||
return { response: { port: portForward?.forwardPort ?? null }};
|
||||
};
|
||||
|
||||
const getCurrentPortForwardRouteInjectable = getInjectable({
|
||||
|
||||
@ -4,19 +4,18 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { routeInjectionToken } from "../../router/router.injectable";
|
||||
import type { LensApiRequest } from "../../router";
|
||||
import type { LensApiRequest, LensApiResult } from "../../router";
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import { PortForward, PortForwardArgs } from "./functionality/port-forward";
|
||||
import logger from "../../logger";
|
||||
import { respondJson } from "../../utils/http-responses";
|
||||
import createPortForwardInjectable from "./functionality/create-port-forward.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
createPortForward: (pathToKubeConfig: string, args: PortForwardArgs) => PortForward;
|
||||
}
|
||||
|
||||
const startPortForward = ({ createPortForward }: Dependencies) => async (request: LensApiRequest) => {
|
||||
const { params, query, response, cluster } = request;
|
||||
const startPortForward = ({ createPortForward }: Dependencies) => async (request: LensApiRequest): Promise<LensApiResult> => {
|
||||
const { params, query, cluster } = request;
|
||||
const { namespace, resourceType, resourceName } = params;
|
||||
const port = Number(query.get("port"));
|
||||
const forwardPort = Number(query.get("forwardPort"));
|
||||
@ -58,32 +57,28 @@ const startPortForward = ({ createPortForward }: Dependencies) => async (request
|
||||
resourceName,
|
||||
});
|
||||
|
||||
return respondJson(
|
||||
response,
|
||||
{
|
||||
return {
|
||||
error: {
|
||||
message: `Failed to forward port ${port} to ${
|
||||
thePort ? forwardPort : "random port"
|
||||
}`,
|
||||
},
|
||||
400,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
respondJson(response, { port: portForward.forwardPort });
|
||||
return { response: { port: portForward.forwardPort }};
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
`[PORT-FORWARD-ROUTE]: failed to open a port-forward: ${error}`,
|
||||
{ namespace, port, resourceType, resourceName },
|
||||
);
|
||||
|
||||
return respondJson(
|
||||
response,
|
||||
{
|
||||
return {
|
||||
error: {
|
||||
message: `Failed to forward port ${port}`,
|
||||
},
|
||||
400,
|
||||
);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -4,14 +4,13 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { routeInjectionToken } from "../../router/router.injectable";
|
||||
import type { LensApiRequest } from "../../router";
|
||||
import type { LensApiRequest, LensApiResult } from "../../router";
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import { respondJson } from "../../utils/http-responses";
|
||||
import { PortForward } from "./functionality/port-forward";
|
||||
import logger from "../../logger";
|
||||
|
||||
const stopCurrentPortForward = async (request: LensApiRequest) => {
|
||||
const { params, query, response, cluster } = request;
|
||||
const stopCurrentPortForward = async (request: LensApiRequest): Promise<LensApiResult> => {
|
||||
const { params, query, cluster } = request;
|
||||
const { namespace, resourceType, resourceName } = params;
|
||||
const port = Number(query.get("port"));
|
||||
const forwardPort = Number(query.get("forwardPort"));
|
||||
@ -23,13 +22,17 @@ const stopCurrentPortForward = async (request: LensApiRequest) => {
|
||||
|
||||
try {
|
||||
await portForward.stop();
|
||||
respondJson(response, { status: true });
|
||||
|
||||
return { response: { status: true }};
|
||||
} catch (error) {
|
||||
logger.error("[PORT-FORWARD-ROUTE]: error stopping a port-forward", { namespace, port, forwardPort, resourceType, resourceName });
|
||||
|
||||
return respondJson(response, {
|
||||
message: `error stopping a forward port ${port}`,
|
||||
}, 400);
|
||||
return {
|
||||
error: {
|
||||
message: `error stopping a forward port ${port}`,
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -4,10 +4,9 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { routeInjectionToken } from "../../router/router.injectable";
|
||||
import type { LensApiRequest } from "../../router";
|
||||
import type { LensApiRequest, LensApiResult } from "../../router";
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import { ResourceApplier } from "../../resource-applier";
|
||||
import { respondJson, respondText } from "../../utils/http-responses";
|
||||
|
||||
const applyResourceRouteInjectable = getInjectable({
|
||||
id: "apply-resource-route",
|
||||
@ -16,17 +15,12 @@ const applyResourceRouteInjectable = getInjectable({
|
||||
method: "post",
|
||||
path: `${apiPrefix}/stack`,
|
||||
|
||||
handler: async (request: LensApiRequest) => {
|
||||
const { response, cluster, payload } = request;
|
||||
|
||||
try {
|
||||
const resource = await new ResourceApplier(cluster).apply(payload);
|
||||
|
||||
respondJson(response, resource, 200);
|
||||
} catch (error) {
|
||||
respondText(response, error, 422);
|
||||
}
|
||||
},
|
||||
handler: async ({
|
||||
cluster,
|
||||
payload,
|
||||
}: LensApiRequest): Promise<LensApiResult> => ({
|
||||
response: await new ResourceApplier(cluster).apply(payload),
|
||||
}),
|
||||
}),
|
||||
|
||||
injectionToken: routeInjectionToken,
|
||||
|
||||
@ -4,10 +4,9 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { routeInjectionToken } from "../../router/router.injectable";
|
||||
import type { LensApiRequest } from "../../router";
|
||||
import type { LensApiRequest, LensApiResult } from "../../router";
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import { ResourceApplier } from "../../resource-applier";
|
||||
import { respondJson, respondText } from "../../utils/http-responses";
|
||||
|
||||
const patchResourceRouteInjectable = getInjectable({
|
||||
id: "patch-resource-route",
|
||||
@ -16,17 +15,17 @@ const patchResourceRouteInjectable = getInjectable({
|
||||
method: "patch",
|
||||
path: `${apiPrefix}/stack`,
|
||||
|
||||
handler: async (request: LensApiRequest) => {
|
||||
const { response, cluster, payload } = request;
|
||||
|
||||
try {
|
||||
const resource = await new ResourceApplier(cluster).patch(payload.name, payload.kind, payload.patch, payload.ns);
|
||||
|
||||
respondJson(response, resource, 200);
|
||||
} catch (error) {
|
||||
respondText(response, error, 422);
|
||||
}
|
||||
},
|
||||
handler: async ({
|
||||
cluster,
|
||||
payload,
|
||||
}: LensApiRequest): Promise<LensApiResult> => ({
|
||||
response: await new ResourceApplier(cluster).patch(
|
||||
payload.name,
|
||||
payload.kind,
|
||||
payload.patch,
|
||||
payload.ns,
|
||||
),
|
||||
}),
|
||||
}),
|
||||
|
||||
injectionToken: routeInjectionToken,
|
||||
|
||||
@ -3,35 +3,15 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { LensApiRequest, Route } from "../router";
|
||||
import type { LensApiRequest, LensApiResult, SupportedFileExtension, Route } from "../router";
|
||||
import { contentTypes } from "../router";
|
||||
import logger from "../logger";
|
||||
import { routeInjectionToken } from "../router/router.injectable";
|
||||
import {
|
||||
appName,
|
||||
publicPath,
|
||||
} from "../../common/vars";
|
||||
import { appName, publicPath } from "../../common/vars";
|
||||
import path from "path";
|
||||
import readFileInjectable from "../../common/fs/read-file.injectable";
|
||||
import isDevelopmentInjectable from "../../common/vars/is-development.injectable";
|
||||
import httpProxy from "http-proxy";
|
||||
import { Router } from "../router";
|
||||
|
||||
function getMimeType(filename: string) {
|
||||
const mimeTypes: Record<string, string> = {
|
||||
html: "text/html",
|
||||
txt: "text/plain",
|
||||
css: "text/css",
|
||||
gif: "image/gif",
|
||||
jpg: "image/jpeg",
|
||||
png: "image/png",
|
||||
svg: "image/svg+xml",
|
||||
js: "application/javascript",
|
||||
woff2: "font/woff2",
|
||||
ttf: "font/ttf",
|
||||
};
|
||||
|
||||
return mimeTypes[path.extname(filename).slice(1)] || "text/plain";
|
||||
}
|
||||
|
||||
interface ProductionDependencies {
|
||||
readFile: (path: string) => Promise<Buffer>;
|
||||
@ -39,36 +19,38 @@ interface ProductionDependencies {
|
||||
|
||||
const handleStaticFileInProduction =
|
||||
({ readFile }: ProductionDependencies) =>
|
||||
async ({ params, response }: LensApiRequest): Promise<void> => {
|
||||
async ({ params }: LensApiRequest): Promise<LensApiResult> => {
|
||||
const staticPath = path.resolve(__static);
|
||||
let filePath = params.path;
|
||||
|
||||
for (let retryCount = 0; retryCount < 5; retryCount += 1) {
|
||||
const asset = path.join(Router.rootPath, filePath);
|
||||
const asset = path.join(staticPath, filePath);
|
||||
const normalizedFilePath = path.resolve(asset);
|
||||
|
||||
if (!normalizedFilePath.startsWith(Router.rootPath)) {
|
||||
response.statusCode = 404;
|
||||
|
||||
return response.end();
|
||||
if (!normalizedFilePath.startsWith(staticPath)) {
|
||||
return { statusCode: 404 };
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await readFile(asset);
|
||||
const fileExtension = path
|
||||
.extname(asset)
|
||||
.slice(1) as SupportedFileExtension;
|
||||
|
||||
response.setHeader("Content-Type", getMimeType(asset));
|
||||
response.write(data);
|
||||
response.end();
|
||||
const contentType = contentTypes[fileExtension] || contentTypes.txt;
|
||||
|
||||
return { response: await readFile(asset), contentType };
|
||||
} catch (err) {
|
||||
if (retryCount > 5) {
|
||||
logger.error("handleStaticFile:", err.toString());
|
||||
response.statusCode = 404;
|
||||
|
||||
return response.end();
|
||||
return { statusCode: 404 };
|
||||
}
|
||||
|
||||
filePath = `${publicPath}/${appName}.html`;
|
||||
}
|
||||
}
|
||||
|
||||
return { statusCode: 404 };
|
||||
};
|
||||
|
||||
interface DevelopmentDependencies {
|
||||
@ -87,6 +69,8 @@ const handleStaticFileInDevelopment =
|
||||
proxy.web(req, res, {
|
||||
target: "http://127.0.0.1:8080",
|
||||
});
|
||||
|
||||
return { proxy };
|
||||
};
|
||||
|
||||
const staticFileRouteInjectable = getInjectable({
|
||||
|
||||
@ -3,8 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { LensApiRequest } from "../../router";
|
||||
import { respondJson } from "../../utils/http-responses";
|
||||
import type { LensApiRequest, LensApiResult } from "../../router";
|
||||
import { routeInjectionToken } from "../../router/router.injectable";
|
||||
import { getAppVersion } from "../../../common/utils";
|
||||
|
||||
@ -15,10 +14,9 @@ const getVersionRouteInjectable = getInjectable({
|
||||
method: "get",
|
||||
path: `/version`,
|
||||
|
||||
handler: async (request: LensApiRequest) => {
|
||||
const { response } = request;
|
||||
|
||||
respondJson(response, { version: getAppVersion() }, 200);
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars-ts
|
||||
handler: async (request: LensApiRequest): Promise<LensApiResult> => {
|
||||
return { response: { version: getAppVersion() }};
|
||||
},
|
||||
}),
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user