Skip to content

Commit 44a76a8

Browse files
authored
Release 6.4.9 (#7400)
* Fix behaviour of auto generated CRD KubeApis and KubeObjectStores (#7384) * Simplify CRD KubeApi registrations - Switch to auto injectable registrations Signed-off-by: Sebastian Malton <sebastian@malton.name> * Make sure that stores can still be retrieved Signed-off-by: Sebastian Malton <sebastian@malton.name> * Cleanup get extension fake to simplify impl Signed-off-by: Sebastian Malton <sebastian@malton.name> * Simplify logic for extensionInjectable Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix test in differencing registrator Signed-off-by: Sebastian Malton <sebastian@malton.name> * Cleanup code style Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix some tests Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix HPA details tests Signed-off-by: Sebastian Malton <sebastian@malton.name> --------- Signed-off-by: Sebastian Malton <sebastian@malton.name> * Release 6.4.9 Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix lint Signed-off-by: Sebastian Malton <sebastian@malton.name> --------- Signed-off-by: Sebastian Malton <sebastian@malton.name>
1 parent 42b2a33 commit 44a76a8

21 files changed

Lines changed: 322 additions & 195 deletions

lerna.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"packages": [
55
"packages/*"
66
],
7-
"version": "6.4.8",
7+
"version": "6.4.9",
88
"npmClient": "yarn",
99
"npmClientArgs": [
1010
"--network-timeout=100000"

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"productName": "",
44
"description": "Lens Desktop Core",
55
"homepage": "https://github.com/lensapp/lens",
6-
"version": "6.4.8",
6+
"version": "6.4.9",
77
"repository": {
88
"type": "git",
99
"url": "git+https://github.com/lensapp/lens.git"

packages/core/src/common/k8s-api/__tests__/api-manager.test.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import type { DiContainer } from "@ogre-tools/injectable";
77
import createClusterInjectable from "../../../main/create-cluster/create-cluster.injectable";
8+
import { getInjectable } from "@ogre-tools/injectable";
89
import clusterFrameContextForNamespacedResourcesInjectable from "../../../renderer/cluster-frame-context/for-namespaced-resources.injectable";
910
import hostedClusterInjectable from "../../../renderer/cluster-frame-context/hosted-cluster.injectable";
1011
import { getDiForUnitTesting } from "../../../renderer/getDiForUnitTesting";
@@ -21,6 +22,9 @@ import maybeKubeApiInjectable from "../maybe-kube-api.injectable";
2122

2223
// eslint-disable-next-line no-restricted-imports
2324
import { KubeApi as ExternalKubeApi } from "../../../extensions/common-api/k8s-api";
25+
import { runInAction } from "mobx";
26+
import { customResourceDefinitionApiInjectionToken } from "../api-manager/crd-api-token";
27+
import assert from "assert";
2428

2529
class TestApi extends KubeApi<KubeObject> {
2630
protected async checkPreferredVersion() {
@@ -119,4 +123,90 @@ describe("ApiManager", () => {
119123
});
120124
});
121125
});
126+
127+
describe("given than a CRD has a default KubeApi registered for it", () => {
128+
const apiBase = "/apis/aquasecurity.github.io/v1alpha1/vulnerabilityreports";
129+
130+
beforeEach(() => {
131+
runInAction(() => {
132+
di.register(getInjectable({
133+
id: `default-kube-api-for-custom-resource-definition-${apiBase}`,
134+
instantiate: (di) => {
135+
const objectConstructor = class extends KubeObject {
136+
static readonly kind = "VulnerabilityReport";
137+
static readonly namespaced = true;
138+
static readonly apiBase = apiBase;
139+
};
140+
141+
return Object.assign(
142+
new KubeApi({
143+
logger: di.inject(loggerInjectable),
144+
maybeKubeApi: di.inject(maybeKubeApiInjectable),
145+
}, { objectConstructor }),
146+
{
147+
myField: 1,
148+
},
149+
);
150+
},
151+
injectionToken: customResourceDefinitionApiInjectionToken,
152+
}));
153+
});
154+
});
155+
156+
it("can be retrieved from apiManager", () => {
157+
expect(apiManager.getApi(apiBase)).toMatchObject({
158+
myField: 1,
159+
});
160+
});
161+
162+
it("can have a default KubeObjectStore instance retrieved for it", () => {
163+
expect(apiManager.getStore(apiBase)).toBeInstanceOf(KubeObjectStore);
164+
});
165+
166+
describe("given that an extension registers an api with the same apibase", () => {
167+
beforeEach(() => {
168+
void Object.assign(new ExternalKubeApi({
169+
objectConstructor: KubeObject,
170+
apiBase,
171+
kind: "VulnerabilityReport",
172+
}), {
173+
myField: 2,
174+
});
175+
});
176+
177+
it("the extension's instance is retrievable instead from apiManager", () => {
178+
expect(apiManager.getApi(apiBase)).toMatchObject({
179+
myField: 2,
180+
});
181+
});
182+
183+
it("can have a default KubeObjectStore instance retrieved for it", () => {
184+
expect(apiManager.getStore(apiBase)).toBeInstanceOf(KubeObjectStore);
185+
});
186+
187+
describe("given that an extension registers a store for the same apibase", () => {
188+
beforeEach(() => {
189+
const api = apiManager.getApi(apiBase);
190+
191+
assert(api);
192+
193+
apiManager.registerStore(Object.assign(
194+
new KubeObjectStore({
195+
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
196+
logger: di.inject(loggerInjectable),
197+
}, api),
198+
{
199+
someField: 2,
200+
},
201+
));
202+
});
203+
204+
it("can gets the custom KubeObjectStore instance instead", () => {
205+
expect(apiManager.getStore(apiBase)).toMatchObject({
206+
someField: 2,
207+
});
208+
});
209+
});
210+
});
211+
});
122212
});

packages/core/src/common/k8s-api/api-manager/api-manager.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import type { KubeApi } from "../kube-api";
1111
import type { KubeObject, ObjectReference } from "../kube-object";
1212
import { parseKubeApi, createKubeApiURL } from "../kube-api-parse";
1313
import { chain, find } from "../../utils/iter";
14+
import type { CreateCustomResourceStore } from "./create-custom-resource-store.injectable";
15+
import { getOrInsertWith, iter } from "../../utils";
1416

1517
export type RegisterableStore<Store> = Store extends KubeObjectStore<any, any, any>
1618
? Store
@@ -26,13 +28,15 @@ export type FindApiCallback = (api: KubeApi<KubeObject>) => boolean;
2628

2729
interface Dependencies {
2830
readonly apis: IComputedValue<KubeApi[]>;
31+
readonly crdApis: IComputedValue<KubeApi[]>;
2932
readonly stores: IComputedValue<KubeObjectStore[]>;
33+
createCustomResourceStore: CreateCustomResourceStore;
3034
}
3135

3236
export class ApiManager {
3337
private readonly externalApis = observable.array<KubeApi>();
3438
private readonly externalStores = observable.array<KubeObjectStore>();
35-
39+
private readonly defaultCrdStores = observable.map<string, KubeObjectStore>();
3640
private readonly apis = observable.map<string, KubeApi>();
3741

3842
constructor(private readonly dependencies: Dependencies) {
@@ -56,6 +60,12 @@ export class ApiManager {
5660
}
5761
}
5862

63+
for (const crdApi of this.dependencies.crdApis.get()) {
64+
if (!newState.has(crdApi.apiBase)) {
65+
newState.set(crdApi.apiBase, crdApi);
66+
}
67+
}
68+
5969
this.apis.replace(newState);
6070
});
6171
}
@@ -110,6 +120,16 @@ export class ApiManager {
110120
this.externalStores.push(store);
111121
}
112122

123+
private apiIsDefaultCrdApi(api: KubeApi): boolean {
124+
for (const crdApi of this.dependencies.crdApis.get()) {
125+
if (crdApi.apiBase === api.apiBase) {
126+
return true;
127+
}
128+
}
129+
130+
return false;
131+
}
132+
113133
getStore(api: string | undefined): KubeObjectStore | undefined;
114134
getStore<Api>(api: RegisterableApi<Api>): KubeObjectStoreFrom<Api> | undefined;
115135
/**
@@ -130,9 +150,19 @@ export class ApiManager {
130150
return undefined;
131151
}
132152

133-
return chain(this.dependencies.stores.get().values())
153+
const defaultResult = iter.chain(this.dependencies.stores.get().values())
134154
.concat(this.externalStores.values())
135155
.find(store => store.api.apiBase === api.apiBase);
156+
157+
if (defaultResult) {
158+
return defaultResult;
159+
}
160+
161+
if (this.apiIsDefaultCrdApi(api)) {
162+
return getOrInsertWith(this.defaultCrdStores, api.apiBase, () => this.dependencies.createCustomResourceStore(api));
163+
}
164+
165+
return undefined;
136166
}
137167

138168
lookupApiLink(ref: ObjectReference, parentObject?: KubeObject): string {

packages/core/src/common/k8s-api/api-manager/auto-registration-emitter.injectable.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,9 @@
55
import { getInjectable } from "@ogre-tools/injectable";
66
import EventEmitter from "events";
77
import type TypedEventEmitter from "typed-emitter";
8-
import type { CustomResourceDefinition } from "../endpoints";
98
import type { KubeApi } from "../kube-api";
109

1110
export interface LegacyAutoRegistration {
12-
customResourceDefinition: (crd: CustomResourceDefinition) => void;
1311
kubeApi: (api: KubeApi<any, any>) => void;
1412
}
1513

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* Copyright (c) OpenLens Authors. All rights reserved.
3+
* Licensed under MIT License. See LICENSE in root directory for more information.
4+
*/
5+
6+
import { getInjectionToken } from "@ogre-tools/injectable";
7+
import type { KubeApi } from "../kube-api";
8+
9+
export const customResourceDefinitionApiInjectionToken = getInjectionToken<KubeApi>({
10+
id: "custom-resource-definition-api-token",
11+
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Copyright (c) OpenLens Authors. All rights reserved.
3+
* Licensed under MIT License. See LICENSE in root directory for more information.
4+
*/
5+
import { getInjectable } from "@ogre-tools/injectable";
6+
import clusterFrameContextForNamespacedResourcesInjectable from "../../../renderer/cluster-frame-context/for-namespaced-resources.injectable";
7+
import loggerInjectable from "../../logger.injectable";
8+
import type { KubeApi } from "../kube-api";
9+
import type { KubeObject } from "../kube-object";
10+
import type { KubeObjectStoreDependencies } from "../kube-object.store";
11+
import { CustomResourceStore } from "./resource.store";
12+
13+
export type CreateCustomResourceStore = <K extends KubeObject>(api: KubeApi<K>) => CustomResourceStore<K>;
14+
15+
const createCustomResourceStoreInjectable = getInjectable({
16+
id: "create-custom-resource-store",
17+
instantiate: (di): CreateCustomResourceStore => {
18+
const deps: KubeObjectStoreDependencies = {
19+
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
20+
logger: di.inject(loggerInjectable),
21+
};
22+
23+
return (api) => new CustomResourceStore(deps, api);
24+
},
25+
});
26+
27+
export default createCustomResourceStoreInjectable;

packages/core/src/common/k8s-api/api-manager/manager.injectable.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-f
99
import { kubeObjectStoreInjectionToken } from "./kube-object-store-token";
1010
import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token";
1111
import { computed } from "mobx";
12+
import { customResourceDefinitionApiInjectionToken } from "./crd-api-token";
13+
import createCustomResourceStoreInjectable from "./create-custom-resource-store.injectable";
1214

1315
const apiManagerInjectable = getInjectable({
1416
id: "api-manager",
@@ -23,6 +25,10 @@ const apiManagerInjectable = getInjectable({
2325
stores: storesAndApisCanBeCreated
2426
? computedInjectMany(kubeObjectStoreInjectionToken)
2527
: computed(() => []),
28+
crdApis: storesAndApisCanBeCreated
29+
? computedInjectMany(customResourceDefinitionApiInjectionToken)
30+
: computed(() => []),
31+
createCustomResourceStore: di.inject(createCustomResourceStoreInjectable),
2632
});
2733
},
2834
});

packages/core/src/common/k8s-api/kube-object.store.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export interface KubeObjectStoreDependencies {
8989
readonly logger: Logger;
9090
}
9191

92-
export abstract class KubeObjectStore<
92+
export class KubeObjectStore<
9393
K extends KubeObject = KubeObject,
9494
A extends KubeApi<K, D> = KubeApi<K, KubeJsonApiDataFor<K>>,
9595
D extends KubeJsonApiDataFor<K> = KubeApiDataFrom<K, A>,
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* Copyright (c) OpenLens Authors. All rights reserved.
3+
* Licensed under MIT License. See LICENSE in root directory for more information.
4+
*/
5+
6+
import * as iter from "./iter";
7+
import type { DiContainerForInjection, Injectable } from "@ogre-tools/injectable";
8+
9+
// Register new injectables and deregister removed injectables by id
10+
11+
export const injectableDifferencingRegistratorWith = (di: DiContainerForInjection) => (
12+
(rawCurrent: Injectable<any, any, any>[], rawPrevious: Injectable<any, any, any>[] = []) => {
13+
const current = new Map(rawCurrent.map(inj => [inj.id, inj]));
14+
const previous = new Map(rawPrevious.map(inj => [inj.id, inj]));
15+
const toAdd = iter.chain(current.entries())
16+
.filter(([id]) => !previous.has(id))
17+
.collect(entries => new Map(entries));
18+
const toRemove = iter.chain(previous.entries())
19+
.filter(([id]) => !current.has(id))
20+
.collect(entries => new Map(entries));
21+
22+
di.deregister(...toRemove.values());
23+
di.register(...toAdd.values());
24+
}
25+
);

0 commit comments

Comments
 (0)