mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Restructure to monorepo (#6907)
* wip: restructure to monorepo Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * refactor create-release-pr to a package Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * build fixes Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * github workflow fixes Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix typo Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * add webpack-env types to core Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix github workflows Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * refactor/fix integration tests Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * lint fix Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * yarn run dev Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * eslint settings for vscode Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * move templates to right package Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * open-lens build fixes Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * integration test fix Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix nx task dependencies Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * use bash shell for unit tests in test workflow Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix test:unit for windows Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix win-ca webpack error in open-lens Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix win-ca webpack error in open-lens Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix build:app on windows Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * remove ELECTRON_BUILDER_EXTRA_ARGS Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * sync src/ from master Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * remove Makefile from core Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
1 parent
0066ca4ea2
commit
2657df2293
3321 files changed
+28699
-11447
No files matched your search
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import httpProxy from "http-proxy";
|
||||
import { webpackDevServerPort } from "../../../../webpack/vars";
|
||||
import { publicPath } from "../../../common/vars";
|
||||
import type { LensApiRequest, RouteResponse } from "../../router/route";
|
||||
|
||||
const devStaticFileRouteHandlerInjectable = getInjectable({
|
||||
id: "dev-static-file-route-handler",
|
||||
instantiate: () => {
|
||||
const proxy = httpProxy.createProxy();
|
||||
const proxyTarget = `http://127.0.0.1:${webpackDevServerPort}`;
|
||||
|
||||
return async ({ raw: { req, res }}: LensApiRequest<"/{path*}">): Promise<RouteResponse<Buffer>> => {
|
||||
if (req.url === "/" || !req.url || !req.url.startsWith(publicPath)) {
|
||||
req.url = `${publicPath}/index.html`;
|
||||
}
|
||||
|
||||
proxy.web(req, res, { target: proxyTarget });
|
||||
|
||||
return { proxy };
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default devStaticFileRouteHandlerInjectable;
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import readFileBufferInjectable from "../../../common/fs/read-file-buffer.injectable";
|
||||
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
|
||||
import staticFilesDirectoryInjectable from "../../../common/vars/static-files-directory.injectable";
|
||||
import type { LensApiRequest } from "../../router/route";
|
||||
import path from "path";
|
||||
import type { SupportedFileExtension } from "../../router/router-content-types";
|
||||
import { contentTypes } from "../../router/router-content-types";
|
||||
import loggerInjectable from "../../../common/logger.injectable";
|
||||
import { publicPath } from "../../../common/vars";
|
||||
|
||||
const prodStaticFileRouteHandlerInjectable = getInjectable({
|
||||
id: "prod-static-file-route-handler",
|
||||
instantiate: (di) => {
|
||||
const readFileBuffer = di.inject(readFileBufferInjectable);
|
||||
const joinPaths = di.inject(joinPathsInjectable);
|
||||
const staticFilesDirectory = di.inject(staticFilesDirectoryInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return async ({ params }: LensApiRequest<"/{path*}">) => {
|
||||
let filePath = params.path;
|
||||
|
||||
|
||||
for (let retryCount = 0; retryCount < 5; retryCount += 1) {
|
||||
const assetFilePath = joinPaths(staticFilesDirectory, filePath);
|
||||
|
||||
if (!assetFilePath.startsWith(staticFilesDirectory)) {
|
||||
return { statusCode: 404 };
|
||||
}
|
||||
|
||||
try {
|
||||
const fileExtension = path
|
||||
.extname(assetFilePath)
|
||||
.slice(1) as SupportedFileExtension;
|
||||
|
||||
const contentType = contentTypes[fileExtension] || contentTypes.txt;
|
||||
|
||||
return { response: await readFileBuffer(assetFilePath), contentType };
|
||||
} catch (err) {
|
||||
if (retryCount > 5) {
|
||||
logger.error("handleStaticFile:", String(err));
|
||||
|
||||
return { statusCode: 404 };
|
||||
}
|
||||
|
||||
filePath = `${publicPath}/index.html`;
|
||||
}
|
||||
}
|
||||
|
||||
return { statusCode: 404 };
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default prodStaticFileRouteHandlerInjectable;
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getRouteInjectable } from "../../router/router.injectable";
|
||||
import isDevelopmentInjectable from "../../../common/vars/is-development.injectable";
|
||||
import { route } from "../../router/route";
|
||||
import prodStaticFileRouteHandlerInjectable from "./production.injectable";
|
||||
import devStaticFileRouteHandlerInjectable from "./development.injectable";
|
||||
|
||||
const staticFileRouteInjectable = getRouteInjectable({
|
||||
id: "static-file-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const isDevelopment = di.inject(isDevelopmentInjectable);
|
||||
|
||||
return route({
|
||||
method: "get",
|
||||
path: `/{path*}`,
|
||||
})(
|
||||
isDevelopment
|
||||
? di.inject(devStaticFileRouteHandlerInjectable)
|
||||
: di.inject(prodStaticFileRouteHandlerInjectable),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default staticFileRouteInjectable;
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import { route } from "../../../router/route";
|
||||
import getHelmChartReadmeInjectable from "../../../helm/helm-service/get-helm-chart-readme.injectable";
|
||||
|
||||
const getHelmChartReadmeRouteInjectable = getRouteInjectable({
|
||||
id: "get-helm-chart-readme-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const getHelmChartReadme = di.inject(getHelmChartReadmeInjectable);
|
||||
|
||||
return route({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/v2/charts/{repo}/{chart}/readme`,
|
||||
})(async ({ params, query }) => {
|
||||
const { repo, chart } = params;
|
||||
|
||||
return {
|
||||
response: await getHelmChartReadme(
|
||||
repo,
|
||||
chart,
|
||||
query.get("version") ?? undefined,
|
||||
),
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default getHelmChartReadmeRouteInjectable;
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import { route } from "../../../router/route";
|
||||
import getHelmChartValuesInjectable from "../../../helm/helm-service/get-helm-chart-values.injectable";
|
||||
|
||||
const getHelmChartRouteValuesInjectable = getRouteInjectable({
|
||||
id: "get-helm-chart-values-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const getHelmChartValues = di.inject(getHelmChartValuesInjectable);
|
||||
|
||||
return route({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/v2/charts/{repo}/{chart}/values`,
|
||||
})(async ({ params, query }) => ({
|
||||
response: await getHelmChartValues(
|
||||
params.repo,
|
||||
params.chart,
|
||||
query.get("version") ?? undefined,
|
||||
),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default getHelmChartRouteValuesInjectable;
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import { route } from "../../../router/route";
|
||||
import getHelmChartVersionsInjectable from "../../../helm/helm-service/get-helm-chart-versions.injectable";
|
||||
|
||||
const getHelmChartVersionsRouteInjectable = getRouteInjectable({
|
||||
id: "get-helm-chart-versions-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const getHelmChartVersions = di.inject(getHelmChartVersionsInjectable);
|
||||
|
||||
return route({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/v2/charts/{repo}/{chart}/versions`,
|
||||
})(async ({ params: { repo, chart }}) => ({
|
||||
response: await getHelmChartVersions(repo, chart),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default getHelmChartVersionsRouteInjectable;
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import { route } from "../../../router/route";
|
||||
import listHelmChartsInjectable from "../../../helm/helm-service/list-helm-charts.injectable";
|
||||
|
||||
const listHelmChartsRouteInjectable = getRouteInjectable({
|
||||
id: "list-helm-charts-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const listHelmCharts = di.inject(listHelmChartsInjectable);
|
||||
|
||||
return route({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/v2/charts`,
|
||||
})(async () => ({
|
||||
response: await listHelmCharts(),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default listHelmChartsRouteInjectable;
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import { clusterRoute } from "../../../router/route";
|
||||
import deleteClusterHelmReleaseInjectable from "../../../helm/helm-service/delete-helm-release.injectable";
|
||||
|
||||
const deleteReleaseRouteInjectable = getRouteInjectable({
|
||||
id: "delete-release-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const deleteHelmRelease = di.inject(deleteClusterHelmReleaseInjectable);
|
||||
|
||||
return clusterRoute({
|
||||
method: "delete",
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{name}`,
|
||||
})(async ({ cluster, params }) => ({
|
||||
response: await deleteHelmRelease(cluster, params),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default deleteReleaseRouteInjectable;
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import { clusterRoute } from "../../../router/route";
|
||||
import getClusterHelmReleaseHistoryInjectable from "../../../helm/helm-service/get-helm-release-history.injectable";
|
||||
|
||||
const getReleaseRouteHistoryInjectable = getRouteInjectable({
|
||||
id: "get-release-history-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const getHelmReleaseHistory = di.inject(getClusterHelmReleaseHistoryInjectable);
|
||||
|
||||
return clusterRoute({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{name}/history`,
|
||||
})(async ({ cluster, params }) => ({
|
||||
response: await getHelmReleaseHistory(cluster, params),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default getReleaseRouteHistoryInjectable;
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import { clusterRoute } from "../../../router/route";
|
||||
import getHelmReleaseInjectable from "../../../helm/helm-service/get-helm-release.injectable";
|
||||
|
||||
const getReleaseRouteInjectable = getRouteInjectable({
|
||||
id: "get-release-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const getHelmRelease = di.inject(getHelmReleaseInjectable);
|
||||
|
||||
return clusterRoute({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{release}`,
|
||||
})(async ({ cluster, params }) => ({
|
||||
response: await getHelmRelease(
|
||||
cluster,
|
||||
params.release,
|
||||
params.namespace,
|
||||
),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default getReleaseRouteInjectable;
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import { getBoolean } from "../../../utils/parse-query";
|
||||
import { contentTypes } from "../../../router/router-content-types";
|
||||
import { clusterRoute } from "../../../router/route";
|
||||
import getClusterHelmReleaseValuesInjectable from "../../../helm/helm-service/get-helm-release-values.injectable";
|
||||
|
||||
const getReleaseRouteValuesInjectable = getRouteInjectable({
|
||||
id: "get-release-values-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const getClusterHelmReleaseValues = di.inject(getClusterHelmReleaseValuesInjectable);
|
||||
|
||||
return clusterRoute({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{name}/values`,
|
||||
})(async ({ cluster, params: { namespace, name }, query }) => ({
|
||||
response: await getClusterHelmReleaseValues(cluster, {
|
||||
name,
|
||||
namespace,
|
||||
all: getBoolean(query, "all"),
|
||||
}),
|
||||
|
||||
contentType: contentTypes.txt,
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default getReleaseRouteValuesInjectable;
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import Joi from "joi";
|
||||
import { payloadValidatedClusterRoute } from "../../../router/route";
|
||||
import type { InstallChartArgs } from "../../../helm/helm-service/install-helm-chart.injectable";
|
||||
import installClusterHelmChartInjectable from "../../../helm/helm-service/install-helm-chart.injectable";
|
||||
|
||||
const installChartArgsValidator = Joi.object<InstallChartArgs, true, InstallChartArgs>({
|
||||
chart: Joi
|
||||
.string()
|
||||
.required(),
|
||||
values: Joi
|
||||
.object()
|
||||
.required()
|
||||
.unknown(true),
|
||||
name: Joi
|
||||
.string(),
|
||||
namespace: Joi
|
||||
.string()
|
||||
.required(),
|
||||
version: Joi
|
||||
.string()
|
||||
.required(),
|
||||
});
|
||||
|
||||
const installChartRouteInjectable = getRouteInjectable({
|
||||
id: "install-chart-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const installHelmChart = di.inject(installClusterHelmChartInjectable);
|
||||
|
||||
return payloadValidatedClusterRoute({
|
||||
method: "post",
|
||||
path: `${apiPrefix}/v2/releases`,
|
||||
payloadValidator: installChartArgsValidator,
|
||||
})(async ({ payload, cluster }) => ({
|
||||
response: await installHelmChart(cluster, payload),
|
||||
statusCode: 201,
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default installChartRouteInjectable;
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import { clusterRoute } from "../../../router/route";
|
||||
import listClusterHelmReleasesInjectable from "../../../helm/helm-service/list-helm-releases.injectable";
|
||||
|
||||
const listReleasesRouteInjectable = getRouteInjectable({
|
||||
id: "list-releases-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const listHelmReleases = di.inject(listClusterHelmReleasesInjectable);
|
||||
|
||||
return clusterRoute({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/v2/releases/{namespace?}`,
|
||||
})(async ({ cluster, params }) => ({
|
||||
response: await listHelmReleases(cluster, params.namespace),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default listReleasesRouteInjectable;
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import Joi from "joi";
|
||||
import { payloadValidatedClusterRoute } from "../../../router/route";
|
||||
import rollbackClusterHelmReleaseInjectable from "../../../helm/helm-service/rollback-helm-release.injectable";
|
||||
|
||||
interface RollbackReleasePayload {
|
||||
revision: number;
|
||||
}
|
||||
|
||||
const rollbackReleasePayloadValidator = Joi.object<RollbackReleasePayload, true, RollbackReleasePayload>({
|
||||
revision: Joi
|
||||
.number()
|
||||
.required(),
|
||||
});
|
||||
|
||||
const rollbackReleaseRouteInjectable = getRouteInjectable({
|
||||
id: "rollback-release-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const rollbackRelease = di.inject(rollbackClusterHelmReleaseInjectable);
|
||||
|
||||
return payloadValidatedClusterRoute({
|
||||
method: "put",
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{name}/rollback`,
|
||||
payloadValidator: rollbackReleasePayloadValidator,
|
||||
})(async ({ cluster, params, payload }) => {
|
||||
await rollbackRelease(cluster, { ...params, ...payload });
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default rollbackReleaseRouteInjectable;
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { apiPrefix } from "../../../../common/vars";
|
||||
import { getRouteInjectable } from "../../../router/router.injectable";
|
||||
import { payloadValidatedClusterRoute } from "../../../router/route";
|
||||
import Joi from "joi";
|
||||
import type { UpdateChartArgs } from "../../../helm/helm-service/update-helm-release.injectable";
|
||||
import updateHelmReleaseInjectable from "../../../helm/helm-service/update-helm-release.injectable";
|
||||
|
||||
const updateChartArgsValidator = Joi.object<UpdateChartArgs, true, UpdateChartArgs>({
|
||||
chart: Joi
|
||||
.string()
|
||||
.required(),
|
||||
version: Joi
|
||||
.string()
|
||||
.required(),
|
||||
values: Joi
|
||||
.string()
|
||||
.required(),
|
||||
});
|
||||
|
||||
const updateReleaseRouteInjectable = getRouteInjectable({
|
||||
id: "update-release-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const updateRelease = di.inject(updateHelmReleaseInjectable);
|
||||
|
||||
return payloadValidatedClusterRoute({
|
||||
method: "put",
|
||||
path: `${apiPrefix}/v2/releases/{namespace}/{release}`,
|
||||
payloadValidator: updateChartArgsValidator,
|
||||
})(async ({ cluster, params, payload }) => ({
|
||||
response: await updateRelease(
|
||||
cluster,
|
||||
params.release,
|
||||
params.namespace,
|
||||
payload,
|
||||
),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default updateReleaseRouteInjectable;
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import { getRouteInjectable } from "../../router/router.injectable";
|
||||
import type { Cluster } from "../../../common/cluster/cluster";
|
||||
import type { V1Secret } from "@kubernetes/client-node";
|
||||
import { CoreV1Api } from "@kubernetes/client-node";
|
||||
import { clusterRoute } from "../../router/route";
|
||||
import { dump } from "js-yaml";
|
||||
|
||||
const getServiceAccountRouteInjectable = getRouteInjectable({
|
||||
id: "get-service-account-route",
|
||||
|
||||
instantiate: () => clusterRoute({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}`,
|
||||
})(async ({ params, cluster }) => {
|
||||
const client = (await cluster.getProxyKubeconfig()).makeApiClient(CoreV1Api);
|
||||
const secretList = await client.listNamespacedSecret(params.namespace);
|
||||
|
||||
const secret = secretList.body.items.find(secret => {
|
||||
const { annotations } = secret.metadata ?? {};
|
||||
|
||||
return annotations?.["kubernetes.io/service-account.name"] === params.account;
|
||||
});
|
||||
|
||||
if (!secret) {
|
||||
return {
|
||||
error: "No secret found",
|
||||
statusCode: 404,
|
||||
};
|
||||
}
|
||||
|
||||
const kubeconfig = generateKubeConfig(params.account, secret, cluster);
|
||||
|
||||
if (!kubeconfig) {
|
||||
return {
|
||||
error: "No secret found",
|
||||
statusCode: 404,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
response: kubeconfig,
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
||||
export default getServiceAccountRouteInjectable;
|
||||
|
||||
function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster): string | undefined {
|
||||
if (!secret.data || !secret.metadata) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const { token, "ca.crt": caCrt } = secret.data;
|
||||
const tokenData = Buffer.from(token, "base64");
|
||||
|
||||
return dump({
|
||||
"apiVersion": "v1",
|
||||
"kind": "Config",
|
||||
"clusters": [
|
||||
{
|
||||
"name": cluster.contextName,
|
||||
"cluster": {
|
||||
"server": cluster.apiUrl,
|
||||
"certificate-authority-data": caCrt,
|
||||
},
|
||||
},
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"name": username,
|
||||
"user": {
|
||||
"token": tokenData.toString("utf8"),
|
||||
},
|
||||
},
|
||||
],
|
||||
"contexts": [
|
||||
{
|
||||
"name": cluster.contextName,
|
||||
"context": {
|
||||
"user": username,
|
||||
"cluster": cluster.contextName,
|
||||
"namespace": secret.metadata.namespace,
|
||||
},
|
||||
},
|
||||
],
|
||||
"current-context": cluster.contextName,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import { getRouteInjectable } from "../../router/router.injectable";
|
||||
import type { ClusterPrometheusMetadata } from "../../../common/cluster-types";
|
||||
import { ClusterMetadataKey } from "../../../common/cluster-types";
|
||||
import type { Cluster } from "../../../common/cluster/cluster";
|
||||
import { clusterRoute } from "../../router/route";
|
||||
import { isObject } from "lodash";
|
||||
import { isRequestError, object } from "../../../common/utils";
|
||||
import type { GetMetrics } from "../../get-metrics.injectable";
|
||||
import getMetricsInjectable from "../../get-metrics.injectable";
|
||||
import loggerInjectable from "../../../common/logger.injectable";
|
||||
|
||||
// This is used for backoff retry tracking.
|
||||
const ATTEMPTS = [false, false, false, false, true];
|
||||
|
||||
const loadMetricsFor = (getMetrics: GetMetrics) => async (promQueries: string[], cluster: Cluster, prometheusPath: string, queryParams: Partial<Record<string, string>>): Promise<any[]> => {
|
||||
const queries = promQueries.map(p => p.trim());
|
||||
const loaders = new Map<string, Promise<any>>();
|
||||
|
||||
async function loadMetric(query: string): Promise<any> {
|
||||
async function loadMetricHelper(): Promise<any> {
|
||||
for (const [attempt, lastAttempt] of ATTEMPTS.entries()) { // retry
|
||||
try {
|
||||
return await getMetrics(cluster, prometheusPath, { query, ...queryParams });
|
||||
} catch (error) {
|
||||
if (
|
||||
!isRequestError(error)
|
||||
|| lastAttempt
|
||||
|| (
|
||||
!lastAttempt && (
|
||||
typeof error.statusCode === "number" &&
|
||||
400 <= error.statusCode && error.statusCode < 500
|
||||
)
|
||||
)
|
||||
) {
|
||||
throw new Error("Metrics not available", { cause: error });
|
||||
}
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, (attempt + 1) * 1000)); // add delay before repeating request
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loaders.get(query) ?? loaders.set(query, loadMetricHelper()).get(query);
|
||||
}
|
||||
|
||||
return Promise.all(queries.map(loadMetric));
|
||||
};
|
||||
|
||||
const addMetricsRouteInjectable = getRouteInjectable({
|
||||
id: "add-metrics-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const getMetrics = di.inject(getMetricsInjectable);
|
||||
const loadMetrics = loadMetricsFor(getMetrics);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return clusterRoute({
|
||||
method: "post",
|
||||
path: `${apiPrefix}/metrics`,
|
||||
})(async ({ cluster, payload, query }) => {
|
||||
const queryParams: Partial<Record<string, string>> = Object.fromEntries(query.entries());
|
||||
const prometheusMetadata: ClusterPrometheusMetadata = {};
|
||||
|
||||
try {
|
||||
const { prometheusPath, provider } = await cluster.contextHandler.getPrometheusDetails();
|
||||
|
||||
prometheusMetadata.provider = provider?.kind;
|
||||
prometheusMetadata.autoDetected = !cluster.preferences.prometheusProvider?.type;
|
||||
|
||||
if (!prometheusPath) {
|
||||
prometheusMetadata.success = false;
|
||||
|
||||
return { response: {}};
|
||||
}
|
||||
|
||||
// return data in same structure as query
|
||||
if (typeof payload === "string") {
|
||||
const [data] = await loadMetrics([payload], cluster, prometheusPath, queryParams);
|
||||
|
||||
return { response: data };
|
||||
}
|
||||
|
||||
if (Array.isArray(payload)) {
|
||||
const data = await loadMetrics(payload, cluster, prometheusPath, queryParams);
|
||||
|
||||
return { response: data };
|
||||
}
|
||||
|
||||
if (isObject(payload)) {
|
||||
const data = payload as Record<string, Record<string, string>>;
|
||||
const queries = object.entries(data)
|
||||
.map(([queryName, queryOpts]) => (
|
||||
provider.getQuery(queryOpts, queryName)
|
||||
));
|
||||
|
||||
const result = await loadMetrics(queries, cluster, prometheusPath, queryParams);
|
||||
const response = object.fromEntries(object.keys(data).map((metricName, i) => [metricName, result[i]]));
|
||||
|
||||
prometheusMetadata.success = true;
|
||||
|
||||
return { response };
|
||||
}
|
||||
|
||||
return { response: {}};
|
||||
} catch (error) {
|
||||
prometheusMetadata.success = false;
|
||||
|
||||
logger.warn(`[METRICS-ROUTE]: failed to get metrics for clusterId=${cluster.id}:`, error);
|
||||
|
||||
return { response: {}};
|
||||
} finally {
|
||||
cluster.metadata[ClusterMetadataKey.PROMETHEUS] = prometheusMetadata;
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default addMetricsRouteInjectable;
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import { getRouteInjectable } from "../../router/router.injectable";
|
||||
import { route } from "../../router/route";
|
||||
import prometheusProvidersInjectable from "../../prometheus/providers.injectable";
|
||||
|
||||
const getMetricProvidersRouteInjectable = getRouteInjectable({
|
||||
id: "get-metric-providers-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const prometheusProviders = di.inject(prometheusProvidersInjectable);
|
||||
|
||||
return route({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/metrics/providers`,
|
||||
})(() => ({
|
||||
response: (
|
||||
prometheusProviders
|
||||
.get()
|
||||
.map(({ name, kind: id, isConfigurable }) => ({ name, id, isConfigurable }))
|
||||
),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default getMetricProvidersRouteInjectable;
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { PortForwardArgs, PortForwardDependencies } from "./port-forward";
|
||||
import { PortForward } from "./port-forward";
|
||||
import bundledKubectlInjectable from "../../../kubectl/bundled-kubectl.injectable";
|
||||
import getPortFromStreamInjectable from "../../../utils/get-port-from-stream.injectable";
|
||||
import loggerInjectable from "../../../../common/logger.injectable";
|
||||
|
||||
export type CreatePortForward = (pathToKubeConfig: string, args: PortForwardArgs) => PortForward;
|
||||
|
||||
const createPortForwardInjectable = getInjectable({
|
||||
id: "create-port-forward",
|
||||
|
||||
instantiate: (di): CreatePortForward => {
|
||||
const dependencies: PortForwardDependencies = {
|
||||
getKubectlBinPath: di.inject(bundledKubectlInjectable).getPath,
|
||||
getPortFromStream: di.inject(getPortFromStreamInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
};
|
||||
|
||||
return (pathToKubeConfig, args) => new PortForward(dependencies, pathToKubeConfig, args);
|
||||
},
|
||||
});
|
||||
|
||||
export default createPortForwardInjectable;
|
||||
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { GetPortFromStream } from "../../../utils/get-port-from-stream.injectable";
|
||||
import type { ChildProcessWithoutNullStreams } from "child_process";
|
||||
import { spawn } from "child_process";
|
||||
import * as tcpPortUsed from "tcp-port-used";
|
||||
import { TypedRegEx } from "typed-regex";
|
||||
import type { Logger } from "../../../../common/logger";
|
||||
|
||||
const internalPortMatcher = "^forwarding from (?<address>.+) ->";
|
||||
const internalPortRegex = Object.assign(TypedRegEx(internalPortMatcher, "i"), {
|
||||
rawMatcher: internalPortMatcher,
|
||||
});
|
||||
|
||||
export interface PortForwardArgs {
|
||||
clusterId: string;
|
||||
kind: string;
|
||||
namespace: string;
|
||||
name: string;
|
||||
port: number;
|
||||
forwardPort: number;
|
||||
}
|
||||
|
||||
export interface PortForwardDependencies {
|
||||
readonly logger: Logger;
|
||||
getKubectlBinPath: (bundled: boolean) => Promise<string>;
|
||||
getPortFromStream: GetPortFromStream;
|
||||
}
|
||||
|
||||
export class PortForward {
|
||||
public static portForwards: PortForward[] = [];
|
||||
|
||||
static getPortforward(forward: PortForwardArgs) {
|
||||
return PortForward.portForwards.find((pf) => (
|
||||
pf.clusterId == forward.clusterId &&
|
||||
pf.kind == forward.kind &&
|
||||
pf.name == forward.name &&
|
||||
pf.namespace == forward.namespace &&
|
||||
pf.port == forward.port
|
||||
));
|
||||
}
|
||||
|
||||
public process?: ChildProcessWithoutNullStreams;
|
||||
public clusterId: string;
|
||||
public kind: string;
|
||||
public namespace: string;
|
||||
public name: string;
|
||||
public port: number;
|
||||
public forwardPort: number;
|
||||
|
||||
constructor(private dependencies: PortForwardDependencies, public pathToKubeConfig: string, args: PortForwardArgs) {
|
||||
this.clusterId = args.clusterId;
|
||||
this.kind = args.kind;
|
||||
this.namespace = args.namespace;
|
||||
this.name = args.name;
|
||||
this.port = args.port;
|
||||
this.forwardPort = args.forwardPort;
|
||||
}
|
||||
|
||||
public async start() {
|
||||
const kubectlBin = await this.dependencies.getKubectlBinPath(true);
|
||||
const args = [
|
||||
"--kubeconfig", this.pathToKubeConfig,
|
||||
"port-forward",
|
||||
"-n", this.namespace,
|
||||
`${this.kind}/${this.name}`,
|
||||
`${this.forwardPort ?? ""}:${this.port}`,
|
||||
];
|
||||
|
||||
this.process = spawn(kubectlBin, args, {
|
||||
env: process.env,
|
||||
});
|
||||
PortForward.portForwards.push(this);
|
||||
this.process.on("exit", () => {
|
||||
const index = PortForward.portForwards.indexOf(this);
|
||||
|
||||
if (index > -1) {
|
||||
PortForward.portForwards.splice(index, 1);
|
||||
}
|
||||
});
|
||||
|
||||
this.process.stderr.on("data", (data) => {
|
||||
this.dependencies.logger.debug(`[PORT-FORWARD-ROUTE]: kubectl port-forward process stderr: ${data}`);
|
||||
});
|
||||
|
||||
const internalPort = await this.dependencies.getPortFromStream(this.process.stdout, {
|
||||
lineRegex: internalPortRegex,
|
||||
});
|
||||
|
||||
try {
|
||||
await tcpPortUsed.waitUntilUsed(internalPort, 500, 15000);
|
||||
|
||||
// make sure this.forwardPort is set to the actual port used (if it was 0 then an available port is found by 'kubectl port-forward')
|
||||
this.forwardPort = internalPort;
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
this.process.kill();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async stop() {
|
||||
this.process?.kill();
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getRouteInjectable } from "../../router/router.injectable";
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import { PortForward } from "./functionality/port-forward";
|
||||
import { clusterRoute } from "../../router/route";
|
||||
|
||||
const getCurrentPortForwardRouteInjectable = getRouteInjectable({
|
||||
id: "get-current-port-forward-route",
|
||||
|
||||
instantiate: () => clusterRoute({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/pods/port-forward/{namespace}/{resourceType}/{resourceName}`,
|
||||
})(async ({ params, query, cluster }) => {
|
||||
const { namespace, resourceType, resourceName } = params;
|
||||
const port = Number(query.get("port"));
|
||||
const forwardPort = Number(query.get("forwardPort"));
|
||||
|
||||
const portForward = PortForward.getPortforward({
|
||||
clusterId: cluster.id, kind: resourceType, name: resourceName,
|
||||
namespace, port, forwardPort,
|
||||
});
|
||||
|
||||
return {
|
||||
response: {
|
||||
port: portForward?.forwardPort ?? null,
|
||||
},
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
||||
export default getCurrentPortForwardRouteInjectable;
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getRouteInjectable } from "../../router/router.injectable";
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import { PortForward } from "./functionality/port-forward";
|
||||
import createPortForwardInjectable from "./functionality/create-port-forward.injectable";
|
||||
import { clusterRoute } from "../../router/route";
|
||||
import loggerInjectable from "../../../common/logger.injectable";
|
||||
|
||||
const startPortForwardRouteInjectable = getRouteInjectable({
|
||||
id: "start-current-port-forward-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const createPortForward = di.inject(createPortForwardInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return clusterRoute({
|
||||
method: "post",
|
||||
path: `${apiPrefix}/pods/port-forward/{namespace}/{resourceType}/{resourceName}`,
|
||||
})(async ({ params, query, cluster }) => {
|
||||
const { namespace, resourceType, resourceName } = params;
|
||||
const port = Number(query.get("port"));
|
||||
const forwardPort = Number(query.get("forwardPort"));
|
||||
|
||||
try {
|
||||
let portForward = PortForward.getPortforward({
|
||||
clusterId: cluster.id,
|
||||
kind: resourceType,
|
||||
name: resourceName,
|
||||
namespace,
|
||||
port,
|
||||
forwardPort,
|
||||
});
|
||||
|
||||
if (!portForward) {
|
||||
logger.info(
|
||||
`Creating a new port-forward ${namespace}/${resourceType}/${resourceName}:${port}`,
|
||||
);
|
||||
|
||||
const thePort = 0 < forwardPort && forwardPort < 65536
|
||||
? forwardPort
|
||||
: 0;
|
||||
|
||||
portForward = createPortForward(await cluster.getProxyKubeconfigPath(), {
|
||||
clusterId: cluster.id,
|
||||
kind: resourceType,
|
||||
namespace,
|
||||
name: resourceName,
|
||||
port,
|
||||
forwardPort: thePort,
|
||||
});
|
||||
|
||||
const started = await portForward.start();
|
||||
|
||||
if (!started) {
|
||||
logger.error("[PORT-FORWARD-ROUTE]: failed to start a port-forward", {
|
||||
namespace,
|
||||
port,
|
||||
resourceType,
|
||||
resourceName,
|
||||
});
|
||||
|
||||
return {
|
||||
error: {
|
||||
message: `Failed to forward port ${port} to ${
|
||||
thePort ? forwardPort : "random port"
|
||||
}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return { response: { port: portForward.forwardPort }};
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
`[PORT-FORWARD-ROUTE]: failed to open a port-forward: ${error}`,
|
||||
{ namespace, port, resourceType, resourceName },
|
||||
);
|
||||
|
||||
return {
|
||||
error: {
|
||||
message: `Failed to forward port ${port}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default startPortForwardRouteInjectable;
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getRouteInjectable } from "../../router/router.injectable";
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import { PortForward } from "./functionality/port-forward";
|
||||
import { clusterRoute } from "../../router/route";
|
||||
import loggerInjectable from "../../../common/logger.injectable";
|
||||
|
||||
const stopCurrentPortForwardRouteInjectable = getRouteInjectable({
|
||||
id: "stop-current-port-forward-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return clusterRoute({
|
||||
method: "delete",
|
||||
path: `${apiPrefix}/pods/port-forward/{namespace}/{resourceType}/{resourceName}`,
|
||||
})(async ({ params, query, cluster }) => {
|
||||
const { namespace, resourceType, resourceName } = params;
|
||||
const port = Number(query.get("port"));
|
||||
const forwardPort = Number(query.get("forwardPort"));
|
||||
const portForward = PortForward.getPortforward({
|
||||
clusterId: cluster.id, kind: resourceType, name: resourceName,
|
||||
namespace, port, forwardPort,
|
||||
});
|
||||
|
||||
try {
|
||||
await portForward?.stop();
|
||||
|
||||
return { response: { status: true }};
|
||||
} catch (error) {
|
||||
logger.error("[PORT-FORWARD-ROUTE]: error stopping a port-forward", { namespace, port, forwardPort, resourceType, resourceName });
|
||||
|
||||
return {
|
||||
error: {
|
||||
message: `error stopping a forward port ${port}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default stopCurrentPortForwardRouteInjectable;
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getRouteInjectable } from "../../router/router.injectable";
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import { payloadValidatedClusterRoute } from "../../router/route";
|
||||
import Joi from "joi";
|
||||
import createResourceApplierInjectable from "../../resource-applier/create-resource-applier.injectable";
|
||||
|
||||
const createResourceRouteInjectable = getRouteInjectable({
|
||||
id: "create-resource-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const createResourceApplier = di.inject(createResourceApplierInjectable);
|
||||
|
||||
return payloadValidatedClusterRoute({
|
||||
method: "post",
|
||||
path: `${apiPrefix}/stack`,
|
||||
payloadValidator: Joi.string(),
|
||||
})(async ({ cluster, payload }) => ({
|
||||
response: await createResourceApplier(cluster).create(payload),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default createResourceRouteInjectable;
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getRouteInjectable } from "../../router/router.injectable";
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import { payloadValidatedClusterRoute } from "../../router/route";
|
||||
import Joi from "joi";
|
||||
import type { Patch } from "rfc6902";
|
||||
import createResourceApplierInjectable from "../../resource-applier/create-resource-applier.injectable";
|
||||
|
||||
interface PatchResourcePayload {
|
||||
name: string;
|
||||
kind: string;
|
||||
patch: Patch;
|
||||
ns?: string;
|
||||
}
|
||||
|
||||
const patchResourcePayloadValidator = Joi.object<PatchResourcePayload, true, PatchResourcePayload>({
|
||||
name: Joi
|
||||
.string()
|
||||
.required(),
|
||||
kind: Joi
|
||||
.string()
|
||||
.required(),
|
||||
ns: Joi
|
||||
.string()
|
||||
.optional(),
|
||||
patch: Joi
|
||||
.array()
|
||||
.allow(
|
||||
Joi.object({
|
||||
op: Joi
|
||||
.string()
|
||||
.required(),
|
||||
}).unknown(true),
|
||||
),
|
||||
});
|
||||
|
||||
const patchResourceRouteInjectable = getRouteInjectable({
|
||||
id: "patch-resource-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const createResourceApplier = di.inject(createResourceApplierInjectable);
|
||||
|
||||
return payloadValidatedClusterRoute({
|
||||
method: "patch",
|
||||
path: `${apiPrefix}/stack`,
|
||||
payloadValidator: patchResourcePayloadValidator,
|
||||
})(async ({ cluster, payload }) => ({
|
||||
response: await createResourceApplier(cluster).patch(
|
||||
payload.name,
|
||||
payload.kind,
|
||||
payload.patch,
|
||||
payload.ns,
|
||||
),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default patchResourceRouteInjectable;
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getRouteInjectable } from "../../router/router.injectable";
|
||||
import { route } from "../../router/route";
|
||||
import buildVersionInjectable from "../../vars/build-version/build-version.injectable";
|
||||
|
||||
const getVersionRouteInjectable = getRouteInjectable({
|
||||
id: "get-version-route",
|
||||
|
||||
instantiate: (di) => {
|
||||
const buildVersion = di.inject(buildVersionInjectable);
|
||||
|
||||
return route({
|
||||
method: "get",
|
||||
path: `/version`,
|
||||
})(() => ({
|
||||
response: {
|
||||
version: buildVersion.get(),
|
||||
},
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default getVersionRouteInjectable;
|
||||
Reference in new issue
Block a user