Unverified Commit d5e1f454 authored by Janne Savolainen's avatar Janne Savolainen
Browse files

Introduce healthy abstraction between back-end routes and route handlers

Signed-off-by: default avatarJanne Savolainen <janne.savolainen@live.fi>
parent bd23876a
Showing with 296 additions and 212 deletions
+296 -212
......@@ -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,7 @@
import Call from "@hapi/call";
import Subtext from "@hapi/subtext";
import type http from "http";
import { toPairs } from "lodash/fp";
import path from "path";
import type { Cluster } from "../common/cluster/cluster";
......@@ -39,6 +40,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();
protected static rootPath = path.resolve(__static);
......@@ -46,7 +135,37 @@ 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 = {},
} = result;
const headerNameValuePairs = toPairs<string>(headers);
headerNameValuePairs.forEach(([key, value]) => {
request.response.setHeader(key, value);
});
contentType.respond(error || response, statusCode, request.response);
});
});
}
......@@ -90,8 +209,20 @@ 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 };
}
export interface Route {
path: string;
method: "get" | "post" | "put" | "patch" | "delete";
handler: (request: LensApiRequest) => Promise<void>;
handler: (request: LensApiRequest) => 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)) {
const data = await loadMetrics(payload, cluster, prometheusPath, queryParams);
return { response: data };
}
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]]));
if (Array.isArray(payload)) {
const data = await loadMetrics(payload, cluster, prometheusPath, queryParams);
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,
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment