mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
fix: Do not crash when opening details of a helm release
- Switch to using RequestChannel instead of LensProxy for better type safety Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
b7ac14df73
commit
40af0d31c5
@ -4,14 +4,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { ItemObject } from "@k8slens/list-layout";
|
import type { ItemObject } from "@k8slens/list-layout";
|
||||||
import type { HelmReleaseDetails } from "./helm-releases.api/request-details.injectable";
|
import type { HelmReleaseData } from "../../../features/helm-releases/common/channels";
|
||||||
|
|
||||||
export interface HelmReleaseUpdateDetails {
|
export interface HelmReleaseUpdateDetails {
|
||||||
log: string;
|
log: string;
|
||||||
release: HelmReleaseDetails;
|
release: HelmReleaseData;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HelmReleaseDto {
|
export interface HelmRelease extends ItemObject {
|
||||||
appVersion: string;
|
appVersion: string;
|
||||||
name: string;
|
name: string;
|
||||||
namespace: string;
|
namespace: string;
|
||||||
@ -19,14 +19,10 @@ export interface HelmReleaseDto {
|
|||||||
status: string;
|
status: string;
|
||||||
updated: string;
|
updated: string;
|
||||||
revision: string;
|
revision: string;
|
||||||
}
|
|
||||||
|
|
||||||
export interface HelmRelease extends HelmReleaseDto, ItemObject {
|
|
||||||
getNs: () => string;
|
getNs: () => string;
|
||||||
getChart: (withVersion?: boolean) => string;
|
getChart: (withVersion?: boolean) => string;
|
||||||
getRevision: () => number;
|
getRevision: () => number;
|
||||||
getStatus: () => string;
|
getStatus: () => string;
|
||||||
getVersion: () => string;
|
getVersion: () => string;
|
||||||
getUpdated: (humanize?: boolean, compact?: boolean) => string | number;
|
getUpdated: (humanize?: boolean, compact?: boolean) => string | number;
|
||||||
getRepo: () => Promise<string>;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,41 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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 { KubeJsonApiData } from "@k8slens/kube-object";
|
|
||||||
import { urlBuilderFor } from "@k8slens/utilities";
|
|
||||||
import apiBaseInjectable from "../../api-base.injectable";
|
|
||||||
|
|
||||||
export interface HelmReleaseDetails {
|
|
||||||
resources: KubeJsonApiData[];
|
|
||||||
name: string;
|
|
||||||
namespace: string;
|
|
||||||
version: string;
|
|
||||||
config: string; // release values
|
|
||||||
manifest: string;
|
|
||||||
info: {
|
|
||||||
deleted: string;
|
|
||||||
description: string;
|
|
||||||
first_deployed: string;
|
|
||||||
last_deployed: string;
|
|
||||||
notes: string;
|
|
||||||
status: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CallForHelmReleaseDetails = (name: string, namespace: string) => Promise<HelmReleaseDetails>;
|
|
||||||
|
|
||||||
const requestDetailsEndpoint = urlBuilderFor("/v2/releases/:namespace/:name");
|
|
||||||
|
|
||||||
const requestHelmReleaseDetailsInjectable = getInjectable({
|
|
||||||
id: "call-for-helm-release-details",
|
|
||||||
|
|
||||||
instantiate: (di): CallForHelmReleaseDetails => {
|
|
||||||
const apiBase = di.inject(apiBaseInjectable);
|
|
||||||
|
|
||||||
return (name, namespace) => apiBase.get(requestDetailsEndpoint.compile({ name, namespace }));
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default requestHelmReleaseDetailsInjectable;
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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 { urlBuilderFor } from "@k8slens/utilities";
|
|
||||||
import apiBaseInjectable from "../../api-base.injectable";
|
|
||||||
import type { HelmReleaseDto } from "../helm-releases.api";
|
|
||||||
|
|
||||||
export type RequestHelmReleases = (namespace?: string) => Promise<HelmReleaseDto[]>;
|
|
||||||
|
|
||||||
const requestHelmReleasesEndpoint = urlBuilderFor("/v2/releases/:namespace?");
|
|
||||||
|
|
||||||
const requestHelmReleasesInjectable = getInjectable({
|
|
||||||
id: "request-helm-releases",
|
|
||||||
|
|
||||||
instantiate: (di): RequestHelmReleases => {
|
|
||||||
const apiBase = di.inject(apiBaseInjectable);
|
|
||||||
|
|
||||||
return (namespace) => apiBase.get(requestHelmReleasesEndpoint.compile({ namespace }));
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default requestHelmReleasesInjectable;
|
|
||||||
@ -28,9 +28,9 @@ import requestHelmChartReadmeInjectable from "../../../common/k8s-api/endpoints/
|
|||||||
import requestHelmChartValuesInjectable from "../../../common/k8s-api/endpoints/helm-charts.api/request-values.injectable";
|
import requestHelmChartValuesInjectable from "../../../common/k8s-api/endpoints/helm-charts.api/request-values.injectable";
|
||||||
import type { RequestDetailedHelmRelease } from "../../../renderer/components/helm-releases/release-details/release-details-model/request-detailed-helm-release.injectable";
|
import type { RequestDetailedHelmRelease } from "../../../renderer/components/helm-releases/release-details/release-details-model/request-detailed-helm-release.injectable";
|
||||||
import requestDetailedHelmReleaseInjectable from "../../../renderer/components/helm-releases/release-details/release-details-model/request-detailed-helm-release.injectable";
|
import requestDetailedHelmReleaseInjectable from "../../../renderer/components/helm-releases/release-details/release-details-model/request-detailed-helm-release.injectable";
|
||||||
import type { RequestHelmReleases } from "../../../common/k8s-api/endpoints/helm-releases.api/request-releases.injectable";
|
|
||||||
import requestHelmReleasesInjectable from "../../../common/k8s-api/endpoints/helm-releases.api/request-releases.injectable";
|
|
||||||
import { flushPromises } from "@k8slens/test-utils";
|
import { flushPromises } from "@k8slens/test-utils";
|
||||||
|
import type { ListClusterHelmReleases } from "../../../main/helm/helm-service/list-helm-releases.injectable";
|
||||||
|
import listClusterHelmReleasesInjectable from "../../../main/helm/helm-service/list-helm-releases.injectable";
|
||||||
|
|
||||||
describe("installing helm chart from new tab", () => {
|
describe("installing helm chart from new tab", () => {
|
||||||
let builder: ApplicationBuilder;
|
let builder: ApplicationBuilder;
|
||||||
@ -40,7 +40,7 @@ describe("installing helm chart from new tab", () => {
|
|||||||
let requestHelmChartReadmeMock: AsyncFnMock<RequestHelmChartReadme>;
|
let requestHelmChartReadmeMock: AsyncFnMock<RequestHelmChartReadme>;
|
||||||
let requestHelmChartValuesMock: AsyncFnMock<RequestHelmChartValues>;
|
let requestHelmChartValuesMock: AsyncFnMock<RequestHelmChartValues>;
|
||||||
let requestCreateHelmReleaseMock: AsyncFnMock<RequestCreateHelmRelease>;
|
let requestCreateHelmReleaseMock: AsyncFnMock<RequestCreateHelmRelease>;
|
||||||
let requestHelmReleasesMock: AsyncFnMock<RequestHelmReleases>;
|
let listClusterHelmReleasesMock: AsyncFnMock<ListClusterHelmReleases>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
builder = getApplicationBuilder();
|
builder = getApplicationBuilder();
|
||||||
@ -53,7 +53,6 @@ describe("installing helm chart from new tab", () => {
|
|||||||
requestHelmChartReadmeMock = asyncFn();
|
requestHelmChartReadmeMock = asyncFn();
|
||||||
requestHelmChartValuesMock = asyncFn();
|
requestHelmChartValuesMock = asyncFn();
|
||||||
requestCreateHelmReleaseMock = asyncFn();
|
requestCreateHelmReleaseMock = asyncFn();
|
||||||
requestHelmReleasesMock = asyncFn();
|
|
||||||
|
|
||||||
builder.beforeWindowStart(({ windowDi }) => {
|
builder.beforeWindowStart(({ windowDi }) => {
|
||||||
windowDi.override(directoryForLensLocalStorageInjectable, () => "/some-directory-for-lens-local-storage");
|
windowDi.override(directoryForLensLocalStorageInjectable, () => "/some-directory-for-lens-local-storage");
|
||||||
@ -63,7 +62,6 @@ describe("installing helm chart from new tab", () => {
|
|||||||
windowDi.override(requestHelmChartReadmeInjectable, () => requestHelmChartReadmeMock);
|
windowDi.override(requestHelmChartReadmeInjectable, () => requestHelmChartReadmeMock);
|
||||||
windowDi.override(requestHelmChartValuesInjectable, () => requestHelmChartValuesMock);
|
windowDi.override(requestHelmChartValuesInjectable, () => requestHelmChartValuesMock);
|
||||||
windowDi.override(requestCreateHelmReleaseInjectable, () => requestCreateHelmReleaseMock);
|
windowDi.override(requestCreateHelmReleaseInjectable, () => requestCreateHelmReleaseMock);
|
||||||
windowDi.override(requestHelmReleasesInjectable, () => requestHelmReleasesMock);
|
|
||||||
|
|
||||||
windowDi.override(getRandomInstallChartTabIdInjectable, () =>
|
windowDi.override(getRandomInstallChartTabIdInjectable, () =>
|
||||||
jest
|
jest
|
||||||
@ -73,6 +71,11 @@ describe("installing helm chart from new tab", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
builder.beforeApplicationStart(({ mainDi }) => {
|
||||||
|
listClusterHelmReleasesMock = asyncFn();
|
||||||
|
mainDi.override(listClusterHelmReleasesInjectable, () => listClusterHelmReleasesMock);
|
||||||
|
});
|
||||||
|
|
||||||
builder.namespaces.add("default");
|
builder.namespaces.add("default");
|
||||||
builder.namespaces.add("some-other-namespace");
|
builder.namespaces.add("some-other-namespace");
|
||||||
});
|
});
|
||||||
@ -360,11 +363,10 @@ describe("installing helm chart from new tab", () => {
|
|||||||
log: "some-execution-output",
|
log: "some-execution-output",
|
||||||
|
|
||||||
release: {
|
release: {
|
||||||
resources: [],
|
|
||||||
name: "some-release",
|
name: "some-release",
|
||||||
namespace: "default",
|
namespace: "default",
|
||||||
version: "some-version",
|
version: 1,
|
||||||
config: "some-config",
|
config: {},
|
||||||
manifest: "some-manifest",
|
manifest: "some-manifest",
|
||||||
|
|
||||||
info: {
|
info: {
|
||||||
@ -400,7 +402,10 @@ describe("installing helm chart from new tab", () => {
|
|||||||
fireEvent.click(releaseButton);
|
fireEvent.click(releaseButton);
|
||||||
|
|
||||||
await flushPromises();
|
await flushPromises();
|
||||||
await requestHelmReleasesMock.resolve([]);
|
await listClusterHelmReleasesMock.resolve({
|
||||||
|
callWasSuccessful: true,
|
||||||
|
response: [],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders", () => {
|
it("renders", () => {
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
import type { AsyncFnMock } from "@async-fn/jest";
|
import type { AsyncFnMock } from "@async-fn/jest";
|
||||||
import asyncFn from "@async-fn/jest";
|
import asyncFn from "@async-fn/jest";
|
||||||
import type { RenderResult } from "@testing-library/react";
|
import type { RenderResult } from "@testing-library/react";
|
||||||
|
import { anyObject } from "jest-mock-extended";
|
||||||
import type { NavigateToHelmReleases } from "../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable";
|
import type { NavigateToHelmReleases } from "../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable";
|
||||||
import navigateToHelmReleasesInjectable from "../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable";
|
import navigateToHelmReleasesInjectable from "../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable";
|
||||||
import { HelmChart } from "../../../common/k8s-api/endpoints/helm-charts.api";
|
import { HelmChart } from "../../../common/k8s-api/endpoints/helm-charts.api";
|
||||||
@ -15,8 +16,8 @@ import type { RequestHelmChartVersions } from "../../../common/k8s-api/endpoints
|
|||||||
import requestHelmChartVersionsInjectable from "../../../common/k8s-api/endpoints/helm-charts.api/request-versions.injectable";
|
import requestHelmChartVersionsInjectable from "../../../common/k8s-api/endpoints/helm-charts.api/request-versions.injectable";
|
||||||
import type { RequestHelmReleaseConfiguration } from "../../../common/k8s-api/endpoints/helm-releases.api/request-configuration.injectable";
|
import type { RequestHelmReleaseConfiguration } from "../../../common/k8s-api/endpoints/helm-releases.api/request-configuration.injectable";
|
||||||
import requestHelmReleaseConfigurationInjectable from "../../../common/k8s-api/endpoints/helm-releases.api/request-configuration.injectable";
|
import requestHelmReleaseConfigurationInjectable from "../../../common/k8s-api/endpoints/helm-releases.api/request-configuration.injectable";
|
||||||
import type { RequestHelmReleases } from "../../../common/k8s-api/endpoints/helm-releases.api/request-releases.injectable";
|
import type { ListClusterHelmReleases } from "../../../main/helm/helm-service/list-helm-releases.injectable";
|
||||||
import requestHelmReleasesInjectable from "../../../common/k8s-api/endpoints/helm-releases.api/request-releases.injectable";
|
import listClusterHelmReleasesInjectable from "../../../main/helm/helm-service/list-helm-releases.injectable";
|
||||||
import dockStoreInjectable from "../../../renderer/components/dock/dock/store.injectable";
|
import dockStoreInjectable from "../../../renderer/components/dock/dock/store.injectable";
|
||||||
import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
||||||
import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
||||||
@ -26,9 +27,9 @@ describe("New Upgrade Helm Chart Dock Tab", () => {
|
|||||||
let builder: ApplicationBuilder;
|
let builder: ApplicationBuilder;
|
||||||
let renderResult: RenderResult;
|
let renderResult: RenderResult;
|
||||||
let requestHelmReleaseConfigurationMock: AsyncFnMock<RequestHelmReleaseConfiguration>;
|
let requestHelmReleaseConfigurationMock: AsyncFnMock<RequestHelmReleaseConfiguration>;
|
||||||
let requestHelmReleasesMock: AsyncFnMock<RequestHelmReleases>;
|
|
||||||
let requestHelmChartsMock: AsyncFnMock<RequestHelmCharts>;
|
let requestHelmChartsMock: AsyncFnMock<RequestHelmCharts>;
|
||||||
let requestHelmChartVersionsMock: AsyncFnMock<RequestHelmChartVersions>;
|
let requestHelmChartVersionsMock: AsyncFnMock<RequestHelmChartVersions>;
|
||||||
|
let listClusterHelmReleasesMock: AsyncFnMock<ListClusterHelmReleases>;
|
||||||
let navigateToHelmReleases: NavigateToHelmReleases;
|
let navigateToHelmReleases: NavigateToHelmReleases;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
@ -39,9 +40,6 @@ describe("New Upgrade Helm Chart Dock Tab", () => {
|
|||||||
requestHelmReleaseConfigurationMock = asyncFn();
|
requestHelmReleaseConfigurationMock = asyncFn();
|
||||||
windowDi.override(requestHelmReleaseConfigurationInjectable, () => requestHelmReleaseConfigurationMock);
|
windowDi.override(requestHelmReleaseConfigurationInjectable, () => requestHelmReleaseConfigurationMock);
|
||||||
|
|
||||||
requestHelmReleasesMock = asyncFn();
|
|
||||||
windowDi.override(requestHelmReleasesInjectable, () => requestHelmReleasesMock);
|
|
||||||
|
|
||||||
requestHelmChartsMock = asyncFn();
|
requestHelmChartsMock = asyncFn();
|
||||||
windowDi.override(requestHelmChartsInjectable, () => requestHelmChartsMock);
|
windowDi.override(requestHelmChartsInjectable, () => requestHelmChartsMock);
|
||||||
|
|
||||||
@ -51,6 +49,11 @@ describe("New Upgrade Helm Chart Dock Tab", () => {
|
|||||||
navigateToHelmReleases = windowDi.inject(navigateToHelmReleasesInjectable);
|
navigateToHelmReleases = windowDi.inject(navigateToHelmReleasesInjectable);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
builder.beforeApplicationStart(({ mainDi }) => {
|
||||||
|
listClusterHelmReleasesMock = asyncFn();
|
||||||
|
mainDi.override(listClusterHelmReleasesInjectable, () => listClusterHelmReleasesMock);
|
||||||
|
});
|
||||||
|
|
||||||
testUsingFakeTime("2020-01-12 12:00:00");
|
testUsingFakeTime("2020-01-12 12:00:00");
|
||||||
|
|
||||||
builder.namespaces.add("my-first-namespace");
|
builder.namespaces.add("my-first-namespace");
|
||||||
@ -79,14 +82,16 @@ describe("New Upgrade Helm Chart Dock Tab", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("requests helm releases for the selected namespace", () => {
|
it("requests helm releases for the selected namespace", () => {
|
||||||
expect(requestHelmReleasesMock).toBeCalledWith("my-second-namespace");
|
expect(listClusterHelmReleasesMock).toBeCalledWith(anyObject({ id: "some-cluster-id" }), "my-second-namespace");
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when helm releases resolves", () => {
|
describe("when helm releases resolves", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await requestHelmReleasesMock.resolve([
|
await listClusterHelmReleasesMock.resolve({
|
||||||
|
callWasSuccessful: true,
|
||||||
|
response: [
|
||||||
{
|
{
|
||||||
appVersion: "some-app-version",
|
app_version: "some-app-version",
|
||||||
name: "some-name",
|
name: "some-name",
|
||||||
namespace: "my-second-namespace",
|
namespace: "my-second-namespace",
|
||||||
chart: "some-chart-1.0.0",
|
chart: "some-chart-1.0.0",
|
||||||
@ -94,7 +99,8 @@ describe("New Upgrade Helm Chart Dock Tab", () => {
|
|||||||
updated: "some-updated",
|
updated: "some-updated",
|
||||||
revision: "some-revision",
|
revision: "some-revision",
|
||||||
},
|
},
|
||||||
]);
|
],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders", () => {
|
it("renders", () => {
|
||||||
|
|||||||
59
packages/core/src/features/helm-releases/common/channels.ts
Normal file
59
packages/core/src/features/helm-releases/common/channels.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { getRequestChannel } from "@k8slens/messaging";
|
||||||
|
import type { Result } from "@k8slens/utilities";
|
||||||
|
import type { KubeJsonApiData } from "@k8slens/kube-object";
|
||||||
|
|
||||||
|
export interface GetHelmReleaseArgs {
|
||||||
|
clusterId: string;
|
||||||
|
releaseName: string;
|
||||||
|
namespace: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HelmReleaseInfo {
|
||||||
|
first_deployed: string;
|
||||||
|
last_deployed: string;
|
||||||
|
deleted: string;
|
||||||
|
description: string;
|
||||||
|
status: string;
|
||||||
|
notes: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HelmReleaseDataWithResources extends HelmReleaseData {
|
||||||
|
resources: KubeJsonApiData[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HelmReleaseData {
|
||||||
|
name: string;
|
||||||
|
info: HelmReleaseInfo;
|
||||||
|
config: Record<string, unknown>;
|
||||||
|
manifest: string;
|
||||||
|
version: number;
|
||||||
|
namespace: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GetHelmReleaseResponse = Result<HelmReleaseDataWithResources, string>;
|
||||||
|
|
||||||
|
export const getHelmReleaseChannel = getRequestChannel<GetHelmReleaseArgs, GetHelmReleaseResponse>("get-helm-release");
|
||||||
|
|
||||||
|
export interface ListedHelmRelease {
|
||||||
|
name: string;
|
||||||
|
namespace: string;
|
||||||
|
revision: string;
|
||||||
|
updated: string;
|
||||||
|
status: string;
|
||||||
|
chart: string;
|
||||||
|
app_version: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ListHelmReleasesArgs {
|
||||||
|
namespace?: string;
|
||||||
|
clusterId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ListHelmReleasesResponse = Result<ListedHelmRelease[], string>;
|
||||||
|
|
||||||
|
export const listHelmReleasesChannel = getRequestChannel<ListHelmReleasesArgs, ListHelmReleasesResponse>("list-helm-releases");
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getRequestChannelListenerInjectable } from "@k8slens/messaging";
|
||||||
|
import getHelmReleaseInjectable from "../../../main/helm/helm-service/get-helm-release.injectable";
|
||||||
|
import getClusterByIdInjectable from "../../cluster/storage/common/get-by-id.injectable";
|
||||||
|
import { getHelmReleaseChannel } from "../common/channels";
|
||||||
|
|
||||||
|
const handleGetHelmReleaseInjectable = getRequestChannelListenerInjectable({
|
||||||
|
channel: getHelmReleaseChannel,
|
||||||
|
getHandler: (di) => {
|
||||||
|
const getHelmRelease = di.inject(getHelmReleaseInjectable);
|
||||||
|
const getClusterById = di.inject(getClusterByIdInjectable);
|
||||||
|
|
||||||
|
return async ({ clusterId, ...args }) => {
|
||||||
|
const cluster = getClusterById(clusterId);
|
||||||
|
|
||||||
|
if (!cluster) {
|
||||||
|
return {
|
||||||
|
callWasSuccessful: false,
|
||||||
|
error: `Cluster with id "${clusterId}" not found`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return getHelmRelease({
|
||||||
|
cluster,
|
||||||
|
...args,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
},
|
||||||
|
id: "handle-get-helm-release",
|
||||||
|
});
|
||||||
|
|
||||||
|
export default handleGetHelmReleaseInjectable;
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { getRequestChannelListenerInjectable } from "@k8slens/messaging";
|
||||||
|
import listClusterHelmReleasesInjectable from "../../../main/helm/helm-service/list-helm-releases.injectable";
|
||||||
|
import getClusterByIdInjectable from "../../cluster/storage/common/get-by-id.injectable";
|
||||||
|
import { listHelmReleasesChannel } from "../common/channels";
|
||||||
|
|
||||||
|
const handleListHelmReleasesInjectable = getRequestChannelListenerInjectable({
|
||||||
|
channel: listHelmReleasesChannel,
|
||||||
|
id: "handle-list-helm-releases",
|
||||||
|
getHandler: (di) => {
|
||||||
|
const listClusterHelmReleases = di.inject(listClusterHelmReleasesInjectable);
|
||||||
|
const getClusterById = di.inject(getClusterByIdInjectable);
|
||||||
|
|
||||||
|
return async ({ clusterId, namespace }) => {
|
||||||
|
const cluster = getClusterById(clusterId);
|
||||||
|
|
||||||
|
if (!cluster) {
|
||||||
|
return {
|
||||||
|
callWasSuccessful: false,
|
||||||
|
error: `Cluster with id "${clusterId}" not found`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return listClusterHelmReleases(cluster, namespace);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default handleListHelmReleasesInjectable;
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import type { ChannelRequester } from "@k8slens/messaging";
|
||||||
|
import { requestFromChannelInjectionToken } from "@k8slens/messaging";
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { listHelmReleasesChannel } from "../common/channels";
|
||||||
|
|
||||||
|
export type RequestListHelmReleases = ChannelRequester<typeof listHelmReleasesChannel>;
|
||||||
|
|
||||||
|
const requestListHelmReleasesInjectable = getInjectable({
|
||||||
|
id: "request-list-helm-releases",
|
||||||
|
instantiate: (di): RequestListHelmReleases => {
|
||||||
|
const requestFromChannel = di.inject(requestFromChannelInjectionToken);
|
||||||
|
|
||||||
|
return (args) => requestFromChannel(listHelmReleasesChannel, args);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default requestListHelmReleasesInjectable;
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { ChannelRequester } from "@k8slens/messaging";
|
||||||
|
import { requestFromChannelInjectionToken } from "@k8slens/messaging";
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { getHelmReleaseChannel } from "../common/channels";
|
||||||
|
|
||||||
|
export type RequestHelmRelease = ChannelRequester<typeof getHelmReleaseChannel>;
|
||||||
|
|
||||||
|
const requestHelmReleaseInjectable = getInjectable({
|
||||||
|
id: "request-helm-release",
|
||||||
|
instantiate: (di): RequestHelmRelease => {
|
||||||
|
const requestFromChannel = di.inject(requestFromChannelInjectionToken);
|
||||||
|
|
||||||
|
return (args) => requestFromChannel(getHelmReleaseChannel, args);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default requestHelmReleaseInjectable;
|
||||||
@ -9,8 +9,6 @@ import type { RenderResult } from "@testing-library/react";
|
|||||||
import { fireEvent } from "@testing-library/react";
|
import { fireEvent } from "@testing-library/react";
|
||||||
import type { AsyncFnMock } from "@async-fn/jest";
|
import type { AsyncFnMock } from "@async-fn/jest";
|
||||||
import asyncFn from "@async-fn/jest";
|
import asyncFn from "@async-fn/jest";
|
||||||
import type { RequestHelmReleases } from "../../common/k8s-api/endpoints/helm-releases.api/request-releases.injectable";
|
|
||||||
import requestHelmReleasesInjectable from "../../common/k8s-api/endpoints/helm-releases.api/request-releases.injectable";
|
|
||||||
import type { RequestHelmReleaseConfiguration } from "../../common/k8s-api/endpoints/helm-releases.api/request-configuration.injectable";
|
import type { RequestHelmReleaseConfiguration } from "../../common/k8s-api/endpoints/helm-releases.api/request-configuration.injectable";
|
||||||
import requestHelmReleaseConfigurationInjectable from "../../common/k8s-api/endpoints/helm-releases.api/request-configuration.injectable";
|
import requestHelmReleaseConfigurationInjectable from "../../common/k8s-api/endpoints/helm-releases.api/request-configuration.injectable";
|
||||||
import type { RequestHelmReleaseUpdate } from "../../common/k8s-api/endpoints/helm-releases.api/request-update.injectable";
|
import type { RequestHelmReleaseUpdate } from "../../common/k8s-api/endpoints/helm-releases.api/request-update.injectable";
|
||||||
@ -30,10 +28,13 @@ import requestHelmChartReadmeInjectable from "../../common/k8s-api/endpoints/hel
|
|||||||
import requestHelmChartValuesInjectable from "../../common/k8s-api/endpoints/helm-charts.api/request-values.injectable";
|
import requestHelmChartValuesInjectable from "../../common/k8s-api/endpoints/helm-charts.api/request-values.injectable";
|
||||||
import { HelmChart } from "../../common/k8s-api/endpoints/helm-charts.api";
|
import { HelmChart } from "../../common/k8s-api/endpoints/helm-charts.api";
|
||||||
import { testUsingFakeTime } from "../../test-utils/use-fake-time";
|
import { testUsingFakeTime } from "../../test-utils/use-fake-time";
|
||||||
|
import type { ListClusterHelmReleases } from "../../main/helm/helm-service/list-helm-releases.injectable";
|
||||||
|
import listClusterHelmReleasesInjectable from "../../main/helm/helm-service/list-helm-releases.injectable";
|
||||||
|
import { anyObject } from "jest-mock-extended";
|
||||||
|
import { toHelmRelease } from "../../renderer/components/helm-releases/to-helm-release";
|
||||||
|
|
||||||
describe("showing details for helm release", () => {
|
describe("showing details for helm release", () => {
|
||||||
let builder: ApplicationBuilder;
|
let builder: ApplicationBuilder;
|
||||||
let requestHelmReleasesMock: AsyncFnMock<RequestHelmReleases>;
|
|
||||||
let requestDetailedHelmReleaseMock: AsyncFnMock<RequestDetailedHelmRelease>;
|
let requestDetailedHelmReleaseMock: AsyncFnMock<RequestDetailedHelmRelease>;
|
||||||
let requestHelmReleaseConfigurationMock: AsyncFnMock<RequestHelmReleaseConfiguration>;
|
let requestHelmReleaseConfigurationMock: AsyncFnMock<RequestHelmReleaseConfiguration>;
|
||||||
let requestHelmReleaseUpdateMock: AsyncFnMock<RequestHelmReleaseUpdate>;
|
let requestHelmReleaseUpdateMock: AsyncFnMock<RequestHelmReleaseUpdate>;
|
||||||
@ -43,6 +44,7 @@ describe("showing details for helm release", () => {
|
|||||||
let requestHelmChartValuesMock: AsyncFnMock<RequestHelmChartValues>;
|
let requestHelmChartValuesMock: AsyncFnMock<RequestHelmChartValues>;
|
||||||
let showSuccessNotificationMock: jest.Mock;
|
let showSuccessNotificationMock: jest.Mock;
|
||||||
let showCheckedErrorNotificationMock: jest.Mock;
|
let showCheckedErrorNotificationMock: jest.Mock;
|
||||||
|
let listClusterHelmReleasesMock: AsyncFnMock<ListClusterHelmReleases>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
testUsingFakeTime("2015-10-21T07:28:00Z");
|
testUsingFakeTime("2015-10-21T07:28:00Z");
|
||||||
@ -51,7 +53,6 @@ describe("showing details for helm release", () => {
|
|||||||
|
|
||||||
builder.setEnvironmentToClusterFrame();
|
builder.setEnvironmentToClusterFrame();
|
||||||
|
|
||||||
requestHelmReleasesMock = asyncFn();
|
|
||||||
requestDetailedHelmReleaseMock = asyncFn();
|
requestDetailedHelmReleaseMock = asyncFn();
|
||||||
requestHelmReleaseConfigurationMock = asyncFn();
|
requestHelmReleaseConfigurationMock = asyncFn();
|
||||||
requestHelmReleaseUpdateMock = asyncFn();
|
requestHelmReleaseUpdateMock = asyncFn();
|
||||||
@ -67,7 +68,6 @@ describe("showing details for helm release", () => {
|
|||||||
windowDi.override(getRandomUpgradeChartTabIdInjectable, () => () => "some-tab-id");
|
windowDi.override(getRandomUpgradeChartTabIdInjectable, () => () => "some-tab-id");
|
||||||
windowDi.override(showSuccessNotificationInjectable, () => showSuccessNotificationMock);
|
windowDi.override(showSuccessNotificationInjectable, () => showSuccessNotificationMock);
|
||||||
windowDi.override(showCheckedErrorInjectable, () => showCheckedErrorNotificationMock);
|
windowDi.override(showCheckedErrorInjectable, () => showCheckedErrorNotificationMock);
|
||||||
windowDi.override(requestHelmReleasesInjectable, () => requestHelmReleasesMock);
|
|
||||||
windowDi.override(requestDetailedHelmReleaseInjectable, () => requestDetailedHelmReleaseMock);
|
windowDi.override(requestDetailedHelmReleaseInjectable, () => requestDetailedHelmReleaseMock);
|
||||||
windowDi.override(requestHelmReleaseConfigurationInjectable, () => requestHelmReleaseConfigurationMock);
|
windowDi.override(requestHelmReleaseConfigurationInjectable, () => requestHelmReleaseConfigurationMock);
|
||||||
windowDi.override(requestHelmReleaseUpdateInjectable, () => requestHelmReleaseUpdateMock);
|
windowDi.override(requestHelmReleaseUpdateInjectable, () => requestHelmReleaseUpdateMock);
|
||||||
@ -77,6 +77,11 @@ describe("showing details for helm release", () => {
|
|||||||
windowDi.override(requestHelmChartValuesInjectable, () => requestHelmChartValuesMock);
|
windowDi.override(requestHelmChartValuesInjectable, () => requestHelmChartValuesMock);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
builder.beforeApplicationStart(({ mainDi }) => {
|
||||||
|
listClusterHelmReleasesMock = asyncFn();
|
||||||
|
mainDi.override(listClusterHelmReleasesInjectable, () => listClusterHelmReleasesMock);
|
||||||
|
});
|
||||||
|
|
||||||
builder.namespaces.add("some-namespace");
|
builder.namespaces.add("some-namespace");
|
||||||
builder.namespaces.add("some-other-namespace");
|
builder.namespaces.add("some-other-namespace");
|
||||||
builder.namespaces.add("some-third-namespace");
|
builder.namespaces.add("some-third-namespace");
|
||||||
@ -110,9 +115,9 @@ describe("showing details for helm release", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("calls for releases for each selected namespace", () => {
|
it("calls for releases for each selected namespace", () => {
|
||||||
expect(requestHelmReleasesMock).toBeCalledTimes(2);
|
expect(listClusterHelmReleasesMock).toBeCalledTimes(2);
|
||||||
expect(requestHelmReleasesMock).toBeCalledWith("some-namespace");
|
expect(listClusterHelmReleasesMock).toBeCalledWith(anyObject({ id: "some-cluster-id" }), "some-namespace");
|
||||||
expect(requestHelmReleasesMock).toBeCalledWith("some-other-namespace");
|
expect(listClusterHelmReleasesMock).toBeCalledWith(anyObject({ id: "some-cluster-id" }), "some-other-namespace");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows spinner", () => {
|
it("shows spinner", () => {
|
||||||
@ -122,19 +127,27 @@ describe("showing details for helm release", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("when releases resolve but there is none, renders", async () => {
|
it("when releases resolve but there is none, renders", async () => {
|
||||||
await requestHelmReleasesMock.resolve([]);
|
await listClusterHelmReleasesMock.resolve({
|
||||||
await requestHelmReleasesMock.resolve([]);
|
callWasSuccessful: true,
|
||||||
|
response: [],
|
||||||
|
});
|
||||||
|
await listClusterHelmReleasesMock.resolve({
|
||||||
|
callWasSuccessful: true,
|
||||||
|
response: [],
|
||||||
|
});
|
||||||
|
|
||||||
expect(rendered.baseElement).toMatchSnapshot();
|
expect(rendered.baseElement).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when releases resolve", () => {
|
describe("when releases resolve", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await requestHelmReleasesMock.resolveSpecific(
|
await listClusterHelmReleasesMock.resolveSpecific(
|
||||||
([namespace]) => namespace === "some-namespace",
|
([, namespace]) => namespace === "some-namespace",
|
||||||
[
|
|
||||||
{
|
{
|
||||||
appVersion: "some-app-version",
|
callWasSuccessful: true,
|
||||||
|
response: [
|
||||||
|
{
|
||||||
|
app_version: "some-app-version",
|
||||||
name: "some-name",
|
name: "some-name",
|
||||||
namespace: "some-namespace",
|
namespace: "some-namespace",
|
||||||
chart: "some-chart-1.0.0",
|
chart: "some-chart-1.0.0",
|
||||||
@ -143,13 +156,16 @@ describe("showing details for helm release", () => {
|
|||||||
revision: "some-revision",
|
revision: "some-revision",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
await requestHelmReleasesMock.resolveSpecific(
|
await listClusterHelmReleasesMock.resolveSpecific(
|
||||||
([namespace]) => namespace === "some-other-namespace",
|
([, namespace]) => namespace === "some-other-namespace",
|
||||||
[
|
|
||||||
{
|
{
|
||||||
appVersion: "some-other-app-version",
|
callWasSuccessful: true,
|
||||||
|
response: [
|
||||||
|
{
|
||||||
|
app_version: "some-other-app-version",
|
||||||
name: "some-other-name",
|
name: "some-other-name",
|
||||||
namespace: "some-other-namespace",
|
namespace: "some-other-namespace",
|
||||||
chart: "some-other-chart-2.0.0",
|
chart: "some-other-chart-2.0.0",
|
||||||
@ -158,6 +174,7 @@ describe("showing details for helm release", () => {
|
|||||||
revision: "some-other-revision",
|
revision: "some-other-revision",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -191,10 +208,11 @@ describe("showing details for helm release", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("calls for release", () => {
|
it("calls for release", () => {
|
||||||
expect(requestDetailedHelmReleaseMock).toHaveBeenCalledWith(
|
expect(requestDetailedHelmReleaseMock).toHaveBeenCalledWith({
|
||||||
"some-name",
|
clusterId: "some-cluster-id",
|
||||||
"some-namespace",
|
namespace: "some-namespace",
|
||||||
);
|
releaseName: "some-name",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows spinner", () => {
|
it("shows spinner", () => {
|
||||||
@ -219,10 +237,11 @@ describe("showing details for helm release", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("calls for another release", () => {
|
it("calls for another release", () => {
|
||||||
expect(requestDetailedHelmReleaseMock).toHaveBeenCalledWith(
|
expect(requestDetailedHelmReleaseMock).toHaveBeenCalledWith({
|
||||||
"some-other-name",
|
clusterId: "some-cluster-id",
|
||||||
"some-other-namespace",
|
namespace: "some-other-namespace",
|
||||||
);
|
releaseName: "some-other-name",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("closes details for first release", () => {
|
it("closes details for first release", () => {
|
||||||
@ -252,21 +271,21 @@ describe("showing details for helm release", () => {
|
|||||||
await requestDetailedHelmReleaseMock.resolve({
|
await requestDetailedHelmReleaseMock.resolve({
|
||||||
callWasSuccessful: true,
|
callWasSuccessful: true,
|
||||||
response: {
|
response: {
|
||||||
release: {
|
release: toHelmRelease({
|
||||||
appVersion: "some-app-version",
|
app_version: "some-app-version",
|
||||||
chart: "some-chart-1.0.0",
|
chart: "some-chart-1.0.0",
|
||||||
status: "some-status",
|
status: "some-status",
|
||||||
updated: "some-updated",
|
updated: "some-updated",
|
||||||
revision: "some-revision",
|
revision: "some-revision",
|
||||||
name: "some-other-name",
|
name: "some-other-name",
|
||||||
namespace: "some-other-namespace",
|
namespace: "some-other-namespace",
|
||||||
},
|
}),
|
||||||
|
|
||||||
details: {
|
details: {
|
||||||
name: "some-other-name",
|
name: "some-other-name",
|
||||||
namespace: "some-other-namespace",
|
namespace: "some-other-namespace",
|
||||||
version: "some-version",
|
version: 1,
|
||||||
config: "some-config",
|
config: {},
|
||||||
manifest: "some-manifest",
|
manifest: "some-manifest",
|
||||||
|
|
||||||
info: {
|
info: {
|
||||||
@ -393,21 +412,21 @@ describe("showing details for helm release", () => {
|
|||||||
await requestDetailedHelmReleaseMock.resolve({
|
await requestDetailedHelmReleaseMock.resolve({
|
||||||
callWasSuccessful: true,
|
callWasSuccessful: true,
|
||||||
response: {
|
response: {
|
||||||
release: {
|
release: toHelmRelease({
|
||||||
appVersion: "some-app-version",
|
app_version: "some-app-version",
|
||||||
chart: "some-chart-1.0.0",
|
chart: "some-chart-1.0.0",
|
||||||
status: "some-status",
|
status: "some-status",
|
||||||
updated: "some-updated",
|
updated: "some-updated",
|
||||||
revision: "some-revision",
|
revision: "some-revision",
|
||||||
name: "some-name",
|
name: "some-name",
|
||||||
namespace: "some-namespace",
|
namespace: "some-namespace",
|
||||||
},
|
}),
|
||||||
|
|
||||||
details: {
|
details: {
|
||||||
name: "some-name",
|
name: "some-name",
|
||||||
namespace: "some-namespace",
|
namespace: "some-namespace",
|
||||||
version: "some-version",
|
version: 1,
|
||||||
config: "some-config",
|
config: {},
|
||||||
manifest: "some-manifest",
|
manifest: "some-manifest",
|
||||||
|
|
||||||
info: {
|
info: {
|
||||||
@ -632,7 +651,7 @@ describe("showing details for helm release", () => {
|
|||||||
|
|
||||||
describe("when update resolves with success", () => {
|
describe("when update resolves with success", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
requestHelmReleasesMock.mockClear();
|
listClusterHelmReleasesMock.mockClear();
|
||||||
requestHelmReleaseConfigurationMock.mockClear();
|
requestHelmReleaseConfigurationMock.mockClear();
|
||||||
|
|
||||||
await requestHelmReleaseUpdateMock.resolve({
|
await requestHelmReleaseUpdateMock.resolve({
|
||||||
@ -671,7 +690,7 @@ describe("showing details for helm release", () => {
|
|||||||
|
|
||||||
describe("when update resolves with failure", () => {
|
describe("when update resolves with failure", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
requestHelmReleasesMock.mockClear();
|
listClusterHelmReleasesMock.mockClear();
|
||||||
requestHelmReleaseConfigurationMock.mockClear();
|
requestHelmReleaseConfigurationMock.mockClear();
|
||||||
|
|
||||||
await requestHelmReleaseUpdateMock.resolve({
|
await requestHelmReleaseUpdateMock.resolve({
|
||||||
|
|||||||
@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import type { AsyncResult } from "@k8slens/utilities";
|
||||||
|
import { isObject, json } from "@k8slens/utilities";
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import type { HelmReleaseData } from "../../../features/helm-releases/common/channels";
|
||||||
|
import execHelmInjectable from "../exec-helm/exec-helm.injectable";
|
||||||
|
|
||||||
|
export type GetHelmReleaseData = (
|
||||||
|
name: string,
|
||||||
|
namespace: string,
|
||||||
|
kubeconfigPath: string,
|
||||||
|
) => AsyncResult<HelmReleaseData, string>;
|
||||||
|
|
||||||
|
const getHelmReleaseDataInjectable = getInjectable({
|
||||||
|
id: "get-helm-release-data",
|
||||||
|
instantiate: (di): GetHelmReleaseData => {
|
||||||
|
const execHelm = di.inject(execHelmInjectable);
|
||||||
|
|
||||||
|
return async (releaseName, namespace, proxyKubeconfigPath) => {
|
||||||
|
const result = await execHelm([
|
||||||
|
"status",
|
||||||
|
releaseName,
|
||||||
|
"--namespace",
|
||||||
|
namespace,
|
||||||
|
"--kubeconfig",
|
||||||
|
proxyKubeconfigPath,
|
||||||
|
"--output",
|
||||||
|
"json",
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!result.callWasSuccessful) {
|
||||||
|
return {
|
||||||
|
callWasSuccessful: false,
|
||||||
|
error: `Failed to execute helm: ${result.error}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseResult = json.parse(result.response);
|
||||||
|
|
||||||
|
if (!parseResult.callWasSuccessful) {
|
||||||
|
return {
|
||||||
|
callWasSuccessful: false,
|
||||||
|
error: `Failed to parse helm response: ${parseResult.error}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const release = parseResult.response;
|
||||||
|
|
||||||
|
if (!isObject(release) || Array.isArray(release)) {
|
||||||
|
return {
|
||||||
|
callWasSuccessful: false,
|
||||||
|
error: `Helm response is not an object: ${JSON.stringify(release)}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
callWasSuccessful: true,
|
||||||
|
response: release as unknown as HelmReleaseData,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default getHelmReleaseDataInjectable;
|
||||||
@ -4,12 +4,13 @@
|
|||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import type { AsyncResult } from "@k8slens/utilities";
|
import type { AsyncResult } from "@k8slens/utilities";
|
||||||
|
import { isObject } from "@k8slens/utilities";
|
||||||
import execHelmInjectable from "../../../exec-helm/exec-helm.injectable";
|
import execHelmInjectable from "../../../exec-helm/exec-helm.injectable";
|
||||||
import yaml from "js-yaml";
|
import yaml from "js-yaml";
|
||||||
import type { KubeJsonApiData, KubeJsonApiDataList } from "@k8slens/kube-object";
|
import type { KubeJsonApiData, KubeJsonApiDataList } from "@k8slens/kube-object";
|
||||||
|
|
||||||
const callForHelmManifestInjectable = getInjectable({
|
const requestHelmManifestInjectable = getInjectable({
|
||||||
id: "call-for-helm-manifest",
|
id: "request-helm-manifest",
|
||||||
|
|
||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
const execHelm = di.inject(execHelmInjectable);
|
const execHelm = di.inject(execHelmInjectable);
|
||||||
@ -37,11 +38,11 @@ const callForHelmManifestInjectable = getInjectable({
|
|||||||
callWasSuccessful: true,
|
callWasSuccessful: true,
|
||||||
response: yaml
|
response: yaml
|
||||||
.loadAll(result.response)
|
.loadAll(result.response)
|
||||||
.filter((manifest) => !!manifest) as KubeJsonApiData[],
|
.filter(isObject) as unknown as KubeJsonApiData[],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default callForHelmManifestInjectable;
|
export default requestHelmManifestInjectable;
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import callForHelmManifestInjectable from "./call-for-helm-manifest/call-for-helm-manifest.injectable";
|
import requestHelmManifestInjectable from "./call-for-helm-manifest/call-for-helm-manifest.injectable";
|
||||||
import type { KubeJsonApiData, KubeJsonApiDataList } from "@k8slens/kube-object";
|
import type { KubeJsonApiData, KubeJsonApiDataList } from "@k8slens/kube-object";
|
||||||
import type { AsyncResult } from "@k8slens/utilities";
|
import type { AsyncResult } from "@k8slens/utilities";
|
||||||
|
|
||||||
@ -17,10 +17,10 @@ const getHelmReleaseResourcesInjectable = getInjectable({
|
|||||||
id: "get-helm-release-resources",
|
id: "get-helm-release-resources",
|
||||||
|
|
||||||
instantiate: (di): GetHelmReleaseResources => {
|
instantiate: (di): GetHelmReleaseResources => {
|
||||||
const callForHelmManifest = di.inject(callForHelmManifestInjectable);
|
const requestHelmManifest = di.inject(requestHelmManifestInjectable);
|
||||||
|
|
||||||
return async (name, namespace, kubeconfigPath) => {
|
return async (name, namespace, kubeconfigPath) => {
|
||||||
const result = await callForHelmManifest(name, namespace, kubeconfigPath);
|
const result = await requestHelmManifest(name, namespace, kubeconfigPath);
|
||||||
|
|
||||||
if (!result.callWasSuccessful) {
|
if (!result.callWasSuccessful) {
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@ -4,47 +4,42 @@
|
|||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import type { Cluster } from "../../../common/cluster/cluster";
|
import type { Cluster } from "../../../common/cluster/cluster";
|
||||||
import { loggerInjectionToken } from "@k8slens/logger";
|
|
||||||
import kubeconfigManagerInjectable from "../../kubeconfig-manager/kubeconfig-manager.injectable";
|
import kubeconfigManagerInjectable from "../../kubeconfig-manager/kubeconfig-manager.injectable";
|
||||||
import { isObject, json } from "@k8slens/utilities";
|
import type { AsyncResult } from "@k8slens/utilities";
|
||||||
import execHelmInjectable from "../exec-helm/exec-helm.injectable";
|
|
||||||
import getHelmReleaseResourcesInjectable from "./get-helm-release-resources/get-helm-release-resources.injectable";
|
import getHelmReleaseResourcesInjectable from "./get-helm-release-resources/get-helm-release-resources.injectable";
|
||||||
|
import type { HelmReleaseDataWithResources } from "../../../features/helm-releases/common/channels";
|
||||||
|
import getHelmReleaseDataInjectable from "./get-helm-release-data.injectable";
|
||||||
|
|
||||||
|
export interface GetHelmReleaseArgs {
|
||||||
|
cluster: Cluster;
|
||||||
|
releaseName: string;
|
||||||
|
namespace: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GetHelmRelease = (args: GetHelmReleaseArgs) => AsyncResult<HelmReleaseDataWithResources, string>;
|
||||||
|
|
||||||
const getHelmReleaseInjectable = getInjectable({
|
const getHelmReleaseInjectable = getInjectable({
|
||||||
id: "get-helm-release",
|
id: "get-helm-release",
|
||||||
|
|
||||||
instantiate: (di) => {
|
instantiate: (di): GetHelmRelease => {
|
||||||
const logger = di.inject(loggerInjectionToken);
|
const getHelmReleaseData = di.inject(getHelmReleaseDataInjectable);
|
||||||
const execHelm = di.inject(execHelmInjectable);
|
|
||||||
const getHelmReleaseResources = di.inject(getHelmReleaseResourcesInjectable);
|
const getHelmReleaseResources = di.inject(getHelmReleaseResourcesInjectable);
|
||||||
|
|
||||||
return async (cluster: Cluster, releaseName: string, namespace: string) => {
|
return async ({ cluster, namespace, releaseName }) => {
|
||||||
const proxyKubeconfigManager = di.inject(kubeconfigManagerInjectable, cluster);
|
const proxyKubeconfigManager = di.inject(kubeconfigManagerInjectable, cluster);
|
||||||
const proxyKubeconfigPath = await proxyKubeconfigManager.ensurePath();
|
const proxyKubeconfigPath = await proxyKubeconfigManager.ensurePath();
|
||||||
|
|
||||||
logger.debug("Fetch release");
|
const releaseResult = await getHelmReleaseData(
|
||||||
|
|
||||||
const result = await execHelm([
|
|
||||||
"status",
|
|
||||||
releaseName,
|
releaseName,
|
||||||
"--namespace",
|
|
||||||
namespace,
|
namespace,
|
||||||
"--kubeconfig",
|
|
||||||
proxyKubeconfigPath,
|
proxyKubeconfigPath,
|
||||||
"--output",
|
);
|
||||||
"json",
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!result.callWasSuccessful) {
|
if (!releaseResult.callWasSuccessful) {
|
||||||
logger.warn(`Failed to exectute helm: ${result.error}`);
|
return {
|
||||||
|
callWasSuccessful: false,
|
||||||
return undefined;
|
error: `Failed to get helm release data: ${releaseResult.error}`,
|
||||||
}
|
};
|
||||||
|
|
||||||
const release = json.parse(result.response);
|
|
||||||
|
|
||||||
if (!isObject(release) || Array.isArray(release)) {
|
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const resourcesResult = await getHelmReleaseResources(
|
const resourcesResult = await getHelmReleaseResources(
|
||||||
@ -54,14 +49,18 @@ const getHelmReleaseInjectable = getInjectable({
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!resourcesResult.callWasSuccessful) {
|
if (!resourcesResult.callWasSuccessful) {
|
||||||
logger.warn(`Failed to get helm release resources: ${resourcesResult.error}`);
|
return {
|
||||||
|
callWasSuccessful: false,
|
||||||
return undefined;
|
error: `Failed to get helm release resources: ${resourcesResult.error}`,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...release,
|
callWasSuccessful: true,
|
||||||
|
response: {
|
||||||
|
...releaseResult.response,
|
||||||
resources: resourcesResult.response,
|
resources: resourcesResult.response,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@ -7,15 +7,19 @@ import type { Cluster } from "../../../common/cluster/cluster";
|
|||||||
import { loggerInjectionToken } from "@k8slens/logger";
|
import { loggerInjectionToken } from "@k8slens/logger";
|
||||||
import kubeconfigManagerInjectable from "../../kubeconfig-manager/kubeconfig-manager.injectable";
|
import kubeconfigManagerInjectable from "../../kubeconfig-manager/kubeconfig-manager.injectable";
|
||||||
import listHelmReleasesInjectable from "../list-helm-releases.injectable";
|
import listHelmReleasesInjectable from "../list-helm-releases.injectable";
|
||||||
|
import type { AsyncResult } from "@k8slens/utilities";
|
||||||
|
import type { ListedHelmRelease } from "../../../features/helm-releases/common/channels";
|
||||||
|
|
||||||
|
export type ListClusterHelmReleases = (cluster: Cluster, namespace?: string) => AsyncResult<ListedHelmRelease[], string>;
|
||||||
|
|
||||||
const listClusterHelmReleasesInjectable = getInjectable({
|
const listClusterHelmReleasesInjectable = getInjectable({
|
||||||
id: "list-cluster-helm-releases",
|
id: "list-cluster-helm-releases",
|
||||||
|
|
||||||
instantiate: (di) => {
|
instantiate: (di): ListClusterHelmReleases => {
|
||||||
const logger = di.inject(loggerInjectionToken);
|
const logger = di.inject(loggerInjectionToken);
|
||||||
const listHelmReleases = di.inject(listHelmReleasesInjectable);
|
const listHelmReleases = di.inject(listHelmReleasesInjectable);
|
||||||
|
|
||||||
return async (cluster: Cluster, namespace?: string) => {
|
return async (cluster, namespace) => {
|
||||||
const proxyKubeconfigManager = di.inject(kubeconfigManagerInjectable, cluster);
|
const proxyKubeconfigManager = di.inject(kubeconfigManagerInjectable, cluster);
|
||||||
const proxyKubeconfigPath = await proxyKubeconfigManager.ensurePath();
|
const proxyKubeconfigPath = await proxyKubeconfigManager.ensurePath();
|
||||||
|
|
||||||
|
|||||||
@ -52,9 +52,15 @@ const updateHelmReleaseInjectable = getInjectable({
|
|||||||
throw result.error; // keep the same interface
|
throw result.error; // keep the same interface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const releaseResult = await getHelmRelease({ cluster, releaseName, namespace });
|
||||||
|
|
||||||
|
if (!releaseResult.callWasSuccessful) {
|
||||||
|
throw releaseResult.error; // keep the same interface
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
log: result.response,
|
log: result.response,
|
||||||
release: await getHelmRelease(cluster, releaseName, namespace),
|
release: releaseResult.response,
|
||||||
};
|
};
|
||||||
} finally {
|
} finally {
|
||||||
await removePath(valuesFilePath);
|
await removePath(valuesFilePath);
|
||||||
|
|||||||
@ -4,9 +4,11 @@
|
|||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import execHelmInjectable from "./exec-helm/exec-helm.injectable";
|
import execHelmInjectable from "./exec-helm/exec-helm.injectable";
|
||||||
import { toCamelCase, isObject } from "@k8slens/utilities";
|
import type { AsyncResult } from "@k8slens/utilities";
|
||||||
|
import { isObject } from "@k8slens/utilities";
|
||||||
|
import type { ListedHelmRelease } from "../../features/helm-releases/common/channels";
|
||||||
|
|
||||||
export type ListHelmReleases = (pathToKubeconfig: string, namespace?: string) => Promise<Record<string, any>[]>;
|
export type ListHelmReleases = (pathToKubeconfig: string, namespace?: string) => AsyncResult<ListedHelmRelease[], string>;
|
||||||
|
|
||||||
const listHelmReleasesInjectable = getInjectable({
|
const listHelmReleasesInjectable = getInjectable({
|
||||||
id: "list-helm-releases",
|
id: "list-helm-releases",
|
||||||
@ -33,16 +35,21 @@ const listHelmReleasesInjectable = getInjectable({
|
|||||||
const result = await execHelm(args);
|
const result = await execHelm(args);
|
||||||
|
|
||||||
if (!result.callWasSuccessful) {
|
if (!result.callWasSuccessful) {
|
||||||
throw result.error;
|
return {
|
||||||
|
callWasSuccessful: false,
|
||||||
|
error: `Failed to list helm releases: ${result.error}`,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const output = JSON.parse(result.response);
|
const rawOutput = JSON.parse(result.response);
|
||||||
|
const output = Array.isArray(rawOutput)
|
||||||
|
? rawOutput.filter(isObject)
|
||||||
|
: [];
|
||||||
|
|
||||||
if (!Array.isArray(output) || output.length == 0) {
|
return {
|
||||||
return [];
|
callWasSuccessful: true,
|
||||||
}
|
response: output as unknown as ListedHelmRelease[],
|
||||||
|
};
|
||||||
return output.filter(isObject).map(toCamelCase);
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,29 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
@ -26,7 +26,7 @@ const helmChartVersionsInjectable = getInjectable({
|
|||||||
},
|
},
|
||||||
|
|
||||||
lifecycle: lifecycleEnum.keyedSingleton({
|
lifecycle: lifecycleEnum.keyedSingleton({
|
||||||
getInstanceKey: (di, release: HelmRelease) => release.getName(),
|
getInstanceKey: (di, release: HelmRelease) => `${release.namespace}/${release.name}}`,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
|
import { asyncComputed } from "@ogre-tools/injectable-react";
|
||||||
|
import { when } from "mobx";
|
||||||
|
import type { HelmRelease } from "../../../common/k8s-api/endpoints/helm-releases.api";
|
||||||
|
import helmChartVersionsInjectable from "../helm-charts/helm-charts/versions.injectable";
|
||||||
|
|
||||||
|
const helmChartRepoInjectable = getInjectable({
|
||||||
|
id: "helm-chart-repo",
|
||||||
|
instantiate: (di, release) => {
|
||||||
|
const chartVersions = di.inject(helmChartVersionsInjectable, release);
|
||||||
|
|
||||||
|
return asyncComputed({
|
||||||
|
getValueFromObservedPromise: async () => {
|
||||||
|
await when(() => !chartVersions.pending.get());
|
||||||
|
|
||||||
|
const version = release.getVersion();
|
||||||
|
|
||||||
|
return chartVersions.value
|
||||||
|
.get()
|
||||||
|
.find((chartVersion) => chartVersion.version === version)?.repo;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
lifecycle: lifecycleEnum.keyedSingleton({
|
||||||
|
getInstanceKey: (di, release: HelmRelease) => `${release.namespace}/${release.name}`,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default helmChartRepoInjectable;
|
||||||
@ -29,17 +29,24 @@ import type { NavigateToHelmReleases } from "../../../../../common/front-end-rou
|
|||||||
import navigateToHelmReleasesInjectable from "../../../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable";
|
import navigateToHelmReleasesInjectable from "../../../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable";
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import activeThemeInjectable from "../../../../themes/active.injectable";
|
import activeThemeInjectable from "../../../../themes/active.injectable";
|
||||||
import type { ToHelmRelease } from "../../to-helm-release.injectable";
|
import hostedClusterIdInjectable from "../../../../cluster-frame-context/hosted-cluster-id.injectable";
|
||||||
import toHelmReleaseInjectable from "../../to-helm-release.injectable";
|
import helmChartRepoInjectable from "../../helm-chart-repo.injectable";
|
||||||
|
import type { IAsyncComputed } from "@ogre-tools/injectable-react";
|
||||||
|
import { waitUntilDefined } from "@k8slens/utilities";
|
||||||
|
|
||||||
const releaseDetailsModelInjectable = getInjectable({
|
const releaseDetailsModelInjectable = getInjectable({
|
||||||
id: "release-details-model",
|
id: "release-details-model",
|
||||||
|
|
||||||
instantiate: async (di, targetRelease: TargetHelmRelease) => {
|
instantiate: async (di, targetRelease: TargetHelmRelease) => {
|
||||||
|
const clusterId = di.inject(hostedClusterIdInjectable);
|
||||||
|
|
||||||
|
assert(clusterId, "Cluster id is required");
|
||||||
|
|
||||||
const model = new ReleaseDetailsModel({
|
const model = new ReleaseDetailsModel({
|
||||||
requestDetailedHelmRelease: di.inject(requestDetailedHelmReleaseInjectable),
|
requestDetailedHelmRelease: di.inject(requestDetailedHelmReleaseInjectable),
|
||||||
targetRelease,
|
targetRelease,
|
||||||
activeTheme: di.inject(activeThemeInjectable),
|
activeTheme: di.inject(activeThemeInjectable),
|
||||||
|
clusterId,
|
||||||
requestHelmReleaseConfiguration: di.inject(requestHelmReleaseConfigurationInjectable),
|
requestHelmReleaseConfiguration: di.inject(requestHelmReleaseConfigurationInjectable),
|
||||||
getResourceDetailsUrl: di.inject(getResourceDetailsUrlInjectable),
|
getResourceDetailsUrl: di.inject(getResourceDetailsUrlInjectable),
|
||||||
updateRelease: di.inject(updateReleaseInjectable),
|
updateRelease: di.inject(updateReleaseInjectable),
|
||||||
@ -47,7 +54,7 @@ const releaseDetailsModelInjectable = getInjectable({
|
|||||||
showSuccessNotification: di.inject(showSuccessNotificationInjectable),
|
showSuccessNotification: di.inject(showSuccessNotificationInjectable),
|
||||||
createUpgradeChartTab: di.inject(createUpgradeChartTabInjectable),
|
createUpgradeChartTab: di.inject(createUpgradeChartTabInjectable),
|
||||||
navigateToHelmReleases: di.inject(navigateToHelmReleasesInjectable),
|
navigateToHelmReleases: di.inject(navigateToHelmReleasesInjectable),
|
||||||
toHelmRelease: di.inject(toHelmReleaseInjectable),
|
helmChartRepo: di.injectFactory(helmChartRepoInjectable),
|
||||||
});
|
});
|
||||||
|
|
||||||
await model.load();
|
await model.load();
|
||||||
@ -78,6 +85,7 @@ export interface ConfigurationInput {
|
|||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
readonly targetRelease: TargetHelmRelease;
|
readonly targetRelease: TargetHelmRelease;
|
||||||
readonly activeTheme: IComputedValue<LensTheme>;
|
readonly activeTheme: IComputedValue<LensTheme>;
|
||||||
|
readonly clusterId: string;
|
||||||
requestDetailedHelmRelease: RequestDetailedHelmRelease;
|
requestDetailedHelmRelease: RequestDetailedHelmRelease;
|
||||||
requestHelmReleaseConfiguration: RequestHelmReleaseConfiguration;
|
requestHelmReleaseConfiguration: RequestHelmReleaseConfiguration;
|
||||||
getResourceDetailsUrl: GetResourceDetailsUrl;
|
getResourceDetailsUrl: GetResourceDetailsUrl;
|
||||||
@ -86,7 +94,7 @@ interface Dependencies {
|
|||||||
showSuccessNotification: ShowNotification;
|
showSuccessNotification: ShowNotification;
|
||||||
createUpgradeChartTab: (release: HelmRelease) => string;
|
createUpgradeChartTab: (release: HelmRelease) => string;
|
||||||
navigateToHelmReleases: NavigateToHelmReleases;
|
navigateToHelmReleases: NavigateToHelmReleases;
|
||||||
toHelmRelease: ToHelmRelease;
|
helmChartRepo: (release: HelmRelease) => IAsyncComputed<string | undefined>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ReleaseDetailsModel {
|
export class ReleaseDetailsModel {
|
||||||
@ -114,10 +122,12 @@ export class ReleaseDetailsModel {
|
|||||||
|
|
||||||
const name = this.release.getName();
|
const name = this.release.getName();
|
||||||
const namespace = this.release.getNs();
|
const namespace = this.release.getNs();
|
||||||
|
const helmChartRepo = this.dependencies.helmChartRepo(this.release);
|
||||||
|
const repo = await waitUntilDefined(helmChartRepo.value);
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
chart: this.release.getChart(),
|
chart: this.release.getChart(),
|
||||||
repo: await this.release.getRepo(),
|
repo,
|
||||||
version: this.release.getVersion(),
|
version: this.release.getVersion(),
|
||||||
values: this.configuration.nonSavedValue.get(),
|
values: this.configuration.nonSavedValue.get(),
|
||||||
};
|
};
|
||||||
@ -165,10 +175,11 @@ export class ReleaseDetailsModel {
|
|||||||
load = async () => {
|
load = async () => {
|
||||||
const { name, namespace } = this.dependencies.targetRelease;
|
const { name, namespace } = this.dependencies.targetRelease;
|
||||||
|
|
||||||
const result = await this.dependencies.requestDetailedHelmRelease(
|
const result = await this.dependencies.requestDetailedHelmRelease({
|
||||||
name,
|
releaseName: name,
|
||||||
namespace,
|
namespace,
|
||||||
);
|
clusterId: this.dependencies.clusterId,
|
||||||
|
});
|
||||||
|
|
||||||
if (!result.callWasSuccessful) {
|
if (!result.callWasSuccessful) {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
@ -210,7 +221,7 @@ export class ReleaseDetailsModel {
|
|||||||
|
|
||||||
assert(detailedRelease, "Tried to access release before load");
|
assert(detailedRelease, "Tried to access release before load");
|
||||||
|
|
||||||
return this.dependencies.toHelmRelease(detailedRelease.release);
|
return detailedRelease.release;
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed private get details() {
|
@computed private get details() {
|
||||||
@ -227,7 +238,7 @@ export class ReleaseDetailsModel {
|
|||||||
|
|
||||||
@computed get groupedResources(): MinimalResourceGroup[] {
|
@computed get groupedResources(): MinimalResourceGroup[] {
|
||||||
return pipeline(
|
return pipeline(
|
||||||
this.details?.resources ?? [],
|
this.details.resources ?? [],
|
||||||
groupBy((resource) => resource.kind),
|
groupBy((resource) => resource.kind),
|
||||||
(grouped) => Object.entries(grouped),
|
(grouped) => Object.entries(grouped),
|
||||||
|
|
||||||
|
|||||||
@ -3,47 +3,57 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import type { HelmReleaseDto } from "../../../../../common/k8s-api/endpoints/helm-releases.api";
|
|
||||||
import requestHelmReleasesInjectable from "../../../../../common/k8s-api/endpoints/helm-releases.api/request-releases.injectable";
|
|
||||||
import type { HelmReleaseDetails } from "../../../../../common/k8s-api/endpoints/helm-releases.api/request-details.injectable";
|
|
||||||
import requestHelmReleaseDetailsInjectable from "../../../../../common/k8s-api/endpoints/helm-releases.api/request-details.injectable";
|
|
||||||
import type { AsyncResult } from "@k8slens/utilities";
|
import type { AsyncResult } from "@k8slens/utilities";
|
||||||
|
import requestHelmReleaseInjectable from "../../../../../features/helm-releases/renderer/request–helm-release.injectable";
|
||||||
|
import type { GetHelmReleaseArgs, HelmReleaseDataWithResources } from "../../../../../features/helm-releases/common/channels";
|
||||||
|
import requestListHelmReleasesInjectable from "../../../../../features/helm-releases/renderer/request-list-helm-releases.injectable";
|
||||||
|
import type { HelmRelease } from "../../../../../common/k8s-api/endpoints/helm-releases.api";
|
||||||
|
import { toHelmRelease } from "../../to-helm-release";
|
||||||
|
|
||||||
export interface DetailedHelmRelease {
|
export interface DetailedHelmRelease {
|
||||||
release: HelmReleaseDto;
|
release: HelmRelease;
|
||||||
details?: HelmReleaseDetails;
|
details: HelmReleaseDataWithResources;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RequestDetailedHelmRelease = (
|
export type RequestDetailedHelmRelease = (args: GetHelmReleaseArgs) => AsyncResult<DetailedHelmRelease>;
|
||||||
name: string,
|
|
||||||
namespace: string
|
|
||||||
) => AsyncResult<DetailedHelmRelease>;
|
|
||||||
|
|
||||||
const requestDetailedHelmReleaseInjectable = getInjectable({
|
const requestDetailedHelmReleaseInjectable = getInjectable({
|
||||||
id: "request-detailed-helm-release",
|
id: "request-detailed-helm-release",
|
||||||
|
|
||||||
instantiate: (di): RequestDetailedHelmRelease => {
|
instantiate: (di): RequestDetailedHelmRelease => {
|
||||||
const requestHelmReleases = di.inject(requestHelmReleasesInjectable);
|
const requestListHelmReleases = di.inject(requestListHelmReleasesInjectable);
|
||||||
const requestHelmReleaseDetails = di.inject(requestHelmReleaseDetailsInjectable);
|
const requestHelmRelease = di.inject(requestHelmReleaseInjectable);
|
||||||
|
|
||||||
return async (name, namespace) => {
|
return async ({ clusterId, namespace, releaseName }) => {
|
||||||
const [releases, details] = await Promise.all([
|
const listReleasesResult = await requestListHelmReleases({ clusterId, namespace });
|
||||||
requestHelmReleases(namespace),
|
const detailsResult = await requestHelmRelease({ clusterId, releaseName, namespace });
|
||||||
requestHelmReleaseDetails(name, namespace),
|
|
||||||
]);
|
|
||||||
|
|
||||||
const release = releases.find(
|
if (!listReleasesResult.callWasSuccessful) {
|
||||||
(rel) => rel.name === name && rel.namespace === namespace,
|
return listReleasesResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
const release = listReleasesResult.response.find(
|
||||||
|
(rel) => rel.name === releaseName && rel.namespace === namespace,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!release) {
|
if (!release) {
|
||||||
return {
|
return {
|
||||||
callWasSuccessful: false,
|
callWasSuccessful: false,
|
||||||
error: `Release ${name} didn't exist in ${namespace} namespace.`,
|
error: `Release ${releaseName} didn't exist in ${namespace} namespace.`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return { callWasSuccessful: true, response: { release, details }};
|
if (!detailsResult.callWasSuccessful) {
|
||||||
|
return detailsResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
callWasSuccessful: true,
|
||||||
|
response: {
|
||||||
|
release: toHelmRelease(release),
|
||||||
|
details: detailsResult.response,
|
||||||
|
},
|
||||||
|
};
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -6,31 +6,49 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import { asyncComputed } from "@ogre-tools/injectable-react";
|
import { asyncComputed } from "@ogre-tools/injectable-react";
|
||||||
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
|
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
|
||||||
import releaseSecretsInjectable from "./release-secrets.injectable";
|
import releaseSecretsInjectable from "./release-secrets.injectable";
|
||||||
import requestHelmReleasesInjectable from "../../../common/k8s-api/endpoints/helm-releases.api/request-releases.injectable";
|
import requestListHelmReleasesInjectable from "../../../features/helm-releases/renderer/request-list-helm-releases.injectable";
|
||||||
import toHelmReleaseInjectable from "./to-helm-release.injectable";
|
import hostedClusterIdInjectable from "../../cluster-frame-context/hosted-cluster-id.injectable";
|
||||||
|
import assert from "assert";
|
||||||
|
import { iter } from "@k8slens/utilities";
|
||||||
|
import { prefixedLoggerInjectable } from "@k8slens/logger";
|
||||||
|
import { toHelmRelease } from "./to-helm-release";
|
||||||
|
|
||||||
const releasesInjectable = getInjectable({
|
const releasesInjectable = getInjectable({
|
||||||
id: "releases",
|
id: "releases",
|
||||||
|
|
||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
const clusterContext = di.inject(clusterFrameContextForNamespacedResourcesInjectable);
|
const clusterContext = di.inject(clusterFrameContextForNamespacedResourcesInjectable);
|
||||||
|
const hostedClusterId = di.inject(hostedClusterIdInjectable);
|
||||||
const releaseSecrets = di.inject(releaseSecretsInjectable);
|
const releaseSecrets = di.inject(releaseSecretsInjectable);
|
||||||
const requestHelmReleases = di.inject(requestHelmReleasesInjectable);
|
const requestListHelmReleases = di.inject(requestListHelmReleasesInjectable);
|
||||||
const toHelmRelease = di.inject(toHelmReleaseInjectable);
|
const logger = di.inject(prefixedLoggerInjectable, "HELM-RELEASES");
|
||||||
|
|
||||||
|
assert(hostedClusterId, "hostedClusterId is required");
|
||||||
|
|
||||||
return asyncComputed({
|
return asyncComputed({
|
||||||
getValueFromObservedPromise: async () => {
|
getValueFromObservedPromise: async () => {
|
||||||
void releaseSecrets.get();
|
void releaseSecrets.get();
|
||||||
|
|
||||||
const releaseArrays = await (
|
const releaseResults = await (
|
||||||
clusterContext.hasSelectedAll
|
clusterContext.hasSelectedAll
|
||||||
? requestHelmReleases()
|
? requestListHelmReleases({ clusterId: hostedClusterId })
|
||||||
: Promise.all(clusterContext.contextNamespaces.map((namespace) => requestHelmReleases(namespace)))
|
: Promise.all(clusterContext.contextNamespaces.map((namespace) => requestListHelmReleases({ clusterId: hostedClusterId, namespace })))
|
||||||
);
|
);
|
||||||
|
|
||||||
return releaseArrays.flat().map(toHelmRelease);
|
return iter.chain([releaseResults].flat().values())
|
||||||
},
|
.filterMap((result) => {
|
||||||
|
if (result.callWasSuccessful) {
|
||||||
|
return result.response;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.warn("Failed to list helm releases", { error: result.error });
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
})
|
||||||
|
.flatMap((releases) => releases)
|
||||||
|
.map(toHelmRelease)
|
||||||
|
.toArray();
|
||||||
|
},
|
||||||
valueWhenPending: [],
|
valueWhenPending: [],
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,90 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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 { capitalize } from "lodash";
|
|
||||||
import { when } from "mobx";
|
|
||||||
import helmChartVersionsInjectable from "../helm-charts/helm-charts/versions.injectable";
|
|
||||||
import type { HelmRelease, HelmReleaseDto } from "../../../common/k8s-api/endpoints/helm-releases.api";
|
|
||||||
import { getMillisecondsFromUnixEpoch } from "../../../common/utils/date/get-current-date-time";
|
|
||||||
import { formatDuration } from "@k8slens/utilities";
|
|
||||||
|
|
||||||
export type ToHelmRelease = (release: HelmReleaseDto) => HelmRelease;
|
|
||||||
|
|
||||||
const toHelmReleaseInjectable = getInjectable({
|
|
||||||
id: "to-helm-release",
|
|
||||||
instantiate: (di): ToHelmRelease => {
|
|
||||||
const helmChartVersions = (release: HelmRelease) => di.inject(helmChartVersionsInjectable, release);
|
|
||||||
|
|
||||||
return (release) => ({
|
|
||||||
...release,
|
|
||||||
|
|
||||||
getId() {
|
|
||||||
return `${this.namespace}/${this.name}`;
|
|
||||||
},
|
|
||||||
|
|
||||||
getName() {
|
|
||||||
return this.name;
|
|
||||||
},
|
|
||||||
|
|
||||||
getNs() {
|
|
||||||
return this.namespace;
|
|
||||||
},
|
|
||||||
|
|
||||||
getChart(withVersion = false) {
|
|
||||||
let chart = this.chart;
|
|
||||||
|
|
||||||
if (!withVersion && this.getVersion() != "") {
|
|
||||||
const search = new RegExp(`-${this.getVersion()}`);
|
|
||||||
|
|
||||||
chart = chart.replace(search, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
return chart;
|
|
||||||
},
|
|
||||||
|
|
||||||
getRevision() {
|
|
||||||
return parseInt(this.revision, 10);
|
|
||||||
},
|
|
||||||
|
|
||||||
getStatus() {
|
|
||||||
return capitalize(this.status);
|
|
||||||
},
|
|
||||||
|
|
||||||
getVersion() {
|
|
||||||
const versions = this.chart.match(/(?<=-)(v?\d+)[^-].*$/);
|
|
||||||
|
|
||||||
return versions?.[0] ?? "";
|
|
||||||
},
|
|
||||||
|
|
||||||
getUpdated(humanize = true, compact = true) {
|
|
||||||
const updated = this.updated.replace(/\s\w*$/, ""); // 2019-11-26 10:58:09 +0300 MSK -> 2019-11-26 10:58:09 +0300 to pass into Date()
|
|
||||||
const updatedDate = new Date(updated).getTime();
|
|
||||||
const diff = getMillisecondsFromUnixEpoch() - updatedDate;
|
|
||||||
|
|
||||||
if (humanize) {
|
|
||||||
return formatDuration(diff, compact);
|
|
||||||
}
|
|
||||||
|
|
||||||
return diff;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Helm does not store from what repository the release is installed,
|
|
||||||
// so we have to try to guess it by searching charts
|
|
||||||
async getRepo() {
|
|
||||||
const versionsComputed = helmChartVersions(this);
|
|
||||||
const version = this.getVersion();
|
|
||||||
|
|
||||||
await when(() => !versionsComputed.pending.get());
|
|
||||||
|
|
||||||
return versionsComputed.value
|
|
||||||
.get()
|
|
||||||
.find((chartVersion) => chartVersion.version === version)?.repo
|
|
||||||
?? "";
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default toHelmReleaseInjectable;
|
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { capitalize } from "lodash";
|
||||||
|
import type { HelmRelease } from "../../../common/k8s-api/endpoints/helm-releases.api";
|
||||||
|
import { getMillisecondsFromUnixEpoch } from "../../../common/utils/date/get-current-date-time";
|
||||||
|
import { formatDuration } from "@k8slens/utilities";
|
||||||
|
import type { ListedHelmRelease } from "../../../features/helm-releases/common/channels";
|
||||||
|
|
||||||
|
export const toHelmRelease = (release: ListedHelmRelease): HelmRelease => ({
|
||||||
|
appVersion: release.app_version,
|
||||||
|
chart: release.chart,
|
||||||
|
namespace: release.namespace,
|
||||||
|
revision: release.revision,
|
||||||
|
status: release.status,
|
||||||
|
name: release.name,
|
||||||
|
updated: release.updated,
|
||||||
|
|
||||||
|
getId() {
|
||||||
|
return `${this.namespace}/${this.name}`;
|
||||||
|
},
|
||||||
|
|
||||||
|
getName() {
|
||||||
|
return this.name;
|
||||||
|
},
|
||||||
|
|
||||||
|
getNs() {
|
||||||
|
return this.namespace;
|
||||||
|
},
|
||||||
|
|
||||||
|
getChart(withVersion = false) {
|
||||||
|
let chart = this.chart;
|
||||||
|
|
||||||
|
if (!withVersion && this.getVersion() != "") {
|
||||||
|
const search = new RegExp(`-${this.getVersion()}`);
|
||||||
|
|
||||||
|
chart = chart.replace(search, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return chart;
|
||||||
|
},
|
||||||
|
|
||||||
|
getRevision() {
|
||||||
|
return parseInt(this.revision, 10);
|
||||||
|
},
|
||||||
|
|
||||||
|
getStatus() {
|
||||||
|
return capitalize(this.status);
|
||||||
|
},
|
||||||
|
|
||||||
|
getVersion() {
|
||||||
|
const versions = this.chart.match(/(?<=-)(v?\d+)[^-].*$/);
|
||||||
|
|
||||||
|
return versions?.[0] ?? "";
|
||||||
|
},
|
||||||
|
|
||||||
|
getUpdated(humanize = true, compact = true) {
|
||||||
|
const updated = this.updated.replace(/\s\w*$/, ""); // 2019-11-26 10:58:09 +0300 MSK -> 2019-11-26 10:58:09 +0300 to pass into Date()
|
||||||
|
const updatedDate = new Date(updated).getTime();
|
||||||
|
const diff = getMillisecondsFromUnixEpoch() - updatedDate;
|
||||||
|
|
||||||
|
if (humanize) {
|
||||||
|
return formatDuration(diff, compact);
|
||||||
|
}
|
||||||
|
|
||||||
|
return diff;
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -71,6 +71,7 @@ import { testUsingFakeTime } from "../../../test-utils/use-fake-time";
|
|||||||
import { sendMessageToChannelInjectionToken } from "@k8slens/messaging";
|
import { sendMessageToChannelInjectionToken } from "@k8slens/messaging";
|
||||||
import { getMessageBridgeFake } from "@k8slens/messaging-fake-bridge";
|
import { getMessageBridgeFake } from "@k8slens/messaging-fake-bridge";
|
||||||
import { historyInjectionToken } from "@k8slens/routing";
|
import { historyInjectionToken } from "@k8slens/routing";
|
||||||
|
import writeJsonSyncInjectable from "../../../common/fs/write-json-sync.injectable";
|
||||||
|
|
||||||
type MainDiCallback = (container: { mainDi: DiContainer }) => void | Promise<void>;
|
type MainDiCallback = (container: { mainDi: DiContainer }) => void | Promise<void>;
|
||||||
type WindowDiCallback = (container: { windowDi: DiContainer }) => void | Promise<void>;
|
type WindowDiCallback = (container: { windowDi: DiContainer }) => void | Promise<void>;
|
||||||
@ -240,7 +241,7 @@ export const getApplicationBuilder = () => {
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const windowHelpers = new Map<string, { di: DiContainer; getRendered: () => RenderResult }>();
|
const windowHelpers: ApplicationWindowHelpers = new Map();
|
||||||
|
|
||||||
const createElectronWindowFake: CreateElectronWindow = (configuration) => {
|
const createElectronWindowFake: CreateElectronWindow = (configuration) => {
|
||||||
const windowId = configuration.id;
|
const windowId = configuration.id;
|
||||||
@ -273,7 +274,10 @@ export const getApplicationBuilder = () => {
|
|||||||
|
|
||||||
let rendered: RenderResult;
|
let rendered: RenderResult;
|
||||||
|
|
||||||
windowHelpers.set(windowId, { di: windowDi, getRendered: () => rendered });
|
windowHelpers.set(windowId, {
|
||||||
|
di: windowDi,
|
||||||
|
getRendered: () => rendered,
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
show: () => {},
|
show: () => {},
|
||||||
@ -321,9 +325,10 @@ export const getApplicationBuilder = () => {
|
|||||||
|
|
||||||
const namespaceItems = observable.array<Namespace>();
|
const namespaceItems = observable.array<Namespace>();
|
||||||
const selectedNamespaces = observable.set<string>();
|
const selectedNamespaces = observable.set<string>();
|
||||||
const startApplication = mainDi.inject(startApplicationInjectionToken);
|
|
||||||
|
|
||||||
const startApp = async ({ shouldStartHidden }: { shouldStartHidden: boolean }) => {
|
const startApp = async ({ shouldStartHidden }: { shouldStartHidden: boolean }) => {
|
||||||
|
const startApplication = mainDi.inject(startApplicationInjectionToken);
|
||||||
|
|
||||||
mainDi.inject(lensProxyPortInjectable).set(42);
|
mainDi.inject(lensProxyPortInjectable).set(42);
|
||||||
|
|
||||||
for (const callback of beforeApplicationStartCallbacks) {
|
for (const callback of beforeApplicationStartCallbacks) {
|
||||||
@ -545,19 +550,17 @@ export const getApplicationBuilder = () => {
|
|||||||
setEnvironmentToClusterFrame: () => {
|
setEnvironmentToClusterFrame: () => {
|
||||||
environment = environments.clusterFrame;
|
environment = environments.clusterFrame;
|
||||||
|
|
||||||
builder.beforeWindowStart(({ windowDi }) => {
|
|
||||||
const cluster = new Cluster({
|
const cluster = new Cluster({
|
||||||
id: "some-cluster-id",
|
id: "some-cluster-id",
|
||||||
contextName: "some-context-name",
|
contextName: "some-context-name",
|
||||||
kubeConfigPath: "/some-path-to-kube-config",
|
kubeConfigPath: "/some-path-to-kube-config",
|
||||||
});
|
});
|
||||||
|
|
||||||
windowDi.override(activeKubernetesClusterInjectable, () =>
|
builder.beforeWindowStart(({ windowDi }) => {
|
||||||
computed(() => catalogEntityFromCluster(cluster)),
|
|
||||||
);
|
|
||||||
|
|
||||||
windowDi.override(hostedClusterIdInjectable, () => cluster.id);
|
windowDi.override(hostedClusterIdInjectable, () => cluster.id);
|
||||||
windowDi.override(hostedClusterInjectable, () => cluster);
|
|
||||||
|
// TODO: Remove this once we moved catalog to new IPC injectables
|
||||||
|
windowDi.override(activeKubernetesClusterInjectable, () => computed(() => catalogEntityFromCluster(cluster)));
|
||||||
|
|
||||||
// TODO: Figure out a way to remove this stub.
|
// TODO: Figure out a way to remove this stub.
|
||||||
windowDi.override(namespaceStoreInjectable, () => ({
|
windowDi.override(namespaceStoreInjectable, () => ({
|
||||||
@ -581,6 +584,43 @@ export const getApplicationBuilder = () => {
|
|||||||
} as Partial<NamespaceStore> as NamespaceStore));
|
} as Partial<NamespaceStore> as NamespaceStore));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
builder.beforeApplicationStart(({ mainDi }) => {
|
||||||
|
const writeJsonSync = mainDi.inject(writeJsonSyncInjectable);
|
||||||
|
|
||||||
|
writeJsonSync("/some-path-to-kube-config", {
|
||||||
|
clusters: [
|
||||||
|
{
|
||||||
|
name: cluster.contextName,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
users: [
|
||||||
|
{
|
||||||
|
name: "some-user-name",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
contexts: [
|
||||||
|
{
|
||||||
|
name: cluster.contextName,
|
||||||
|
context: {
|
||||||
|
cluster: cluster.contextName,
|
||||||
|
user: "some-user-name",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"current-context": cluster.contextName,
|
||||||
|
});
|
||||||
|
writeJsonSync("/some-directory-for-app-data/some-product-name/lens-cluster-store.json", {
|
||||||
|
clusters: [
|
||||||
|
{
|
||||||
|
id: cluster.id,
|
||||||
|
kubeConfigPath: "/some-path-to-kube-config",
|
||||||
|
contextName: cluster.contextName,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
__internal__: { migrations: { version: "6.4.0" }},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -774,17 +814,13 @@ const findExtensionInstance = <T extends LensExtension> (di: DiContainer, inject
|
|||||||
type ApplicationWindowHelpers = Map<string, { di: DiContainer; getRendered: () => RenderResult }>;
|
type ApplicationWindowHelpers = Map<string, { di: DiContainer; getRendered: () => RenderResult }>;
|
||||||
|
|
||||||
const toWindowWithHelpersFor =
|
const toWindowWithHelpersFor =
|
||||||
(windowHelpers: ApplicationWindowHelpers) => (applicationWindow: LensWindow) => ({
|
(windowHelpers: ApplicationWindowHelpers) => (applicationWindow: LensWindow): LensWindowWithHelpers => ({
|
||||||
...applicationWindow,
|
...applicationWindow,
|
||||||
|
|
||||||
get rendered() {
|
get rendered() {
|
||||||
const helpers = windowHelpers.get(applicationWindow.id);
|
const helpers = windowHelpers.get(applicationWindow.id);
|
||||||
|
|
||||||
if (!helpers) {
|
assert(helpers, `Tried to get rendered for application window "${applicationWindow.id}" before it was started.`);
|
||||||
throw new Error(
|
|
||||||
`Tried to get rendered for application window "${applicationWindow.id}" before it was started.`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return helpers.getRendered();
|
return helpers.getRendered();
|
||||||
},
|
},
|
||||||
@ -792,11 +828,7 @@ const toWindowWithHelpersFor =
|
|||||||
get di() {
|
get di() {
|
||||||
const helpers = windowHelpers.get(applicationWindow.id);
|
const helpers = windowHelpers.get(applicationWindow.id);
|
||||||
|
|
||||||
if (!helpers) {
|
assert(helpers, `Tried to get rendered for application window "${applicationWindow.id}" before it was started.`);
|
||||||
throw new Error(
|
|
||||||
`Tried to get di for application window "${applicationWindow.id}" before it was started.`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return helpers.di;
|
return helpers.di;
|
||||||
},
|
},
|
||||||
|
|||||||
@ -49,7 +49,7 @@ const webpackLensMain = (): webpack.Configuration => {
|
|||||||
use: "node-loader",
|
use: "node-loader",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.ts$/,
|
test: (modulePath) => modulePath.endsWith(".ts") && !modulePath.endsWith(".test.ts"),
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
use: {
|
use: {
|
||||||
loader: "ts-loader",
|
loader: "ts-loader",
|
||||||
|
|||||||
@ -62,7 +62,10 @@ export function webpackLensRenderer(): webpack.Configuration {
|
|||||||
use: "node-loader",
|
use: "node-loader",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.tsx?$/,
|
test: (modulePath) => (
|
||||||
|
(modulePath.endsWith(".ts") && !modulePath.endsWith(".test.ts"))
|
||||||
|
|| (modulePath.endsWith(".tsx") && !modulePath.endsWith(".test.tsx"))
|
||||||
|
),
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
use: {
|
use: {
|
||||||
loader: "ts-loader",
|
loader: "ts-loader",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user