From e51ff5051fb7cb4c9106fa06e17bfe600d063a17 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 15 Nov 2021 11:16:37 -0500 Subject: [PATCH] Fix crash when finding CRD's preferred version (#4332) --- src/common/k8s-api/__tests__/crd.test.ts | 32 +++++++++++++++++-- src/common/k8s-api/endpoints/crd.api.ts | 6 +--- .../+custom-resources/crd-resources.tsx | 12 +++++++ .../item-object-list/item-list-layout.tsx | 12 +++++-- 4 files changed, 53 insertions(+), 9 deletions(-) diff --git a/src/common/k8s-api/__tests__/crd.test.ts b/src/common/k8s-api/__tests__/crd.test.ts index 7e4d255d15..0eba45e2cd 100644 --- a/src/common/k8s-api/__tests__/crd.test.ts +++ b/src/common/k8s-api/__tests__/crd.test.ts @@ -51,7 +51,7 @@ describe("Crds", () => { expect(() => crd.getVersion()).toThrowError("Failed to find a version for CustomResourceDefinition foo"); }); - it("should should get the version that is both served and stored", () => { + it("should get the version that is both served and stored", () => { const crd = new CustomResourceDefinition({ apiVersion: "apiextensions.k8s.io/v1", kind: "CustomResourceDefinition", @@ -79,7 +79,35 @@ describe("Crds", () => { expect(crd.getVersion()).toBe("123"); }); - it("should should get the version that is both served and stored even with version field", () => { + it("should get the version that is only stored", () => { + const crd = new CustomResourceDefinition({ + apiVersion: "apiextensions.k8s.io/v1", + kind: "CustomResourceDefinition", + metadata: { + name: "foo", + resourceVersion: "12345", + uid: "12345", + }, + spec: { + versions: [ + { + name: "123", + served: false, + storage: true, + }, + { + name: "1234", + served: false, + storage: false, + }, + ], + }, + }); + + expect(crd.getVersion()).toBe("123"); + }); + + it("should get the version that is both served and stored even with version field", () => { const crd = new CustomResourceDefinition({ apiVersion: "apiextensions.k8s.io/v1", kind: "CustomResourceDefinition", diff --git a/src/common/k8s-api/endpoints/crd.api.ts b/src/common/k8s-api/endpoints/crd.api.ts index 1e9044e31a..4e2244d8a8 100644 --- a/src/common/k8s-api/endpoints/crd.api.ts +++ b/src/common/k8s-api/endpoints/crd.api.ts @@ -153,11 +153,7 @@ export class CustomResourceDefinition extends KubeObject { // Prefer the modern `versions` over the legacy `version` if (this.spec.versions) { for (const version of this.spec.versions) { - /** - * If the version is not served then 404 errors will occur - * We should also prefer the storage version - */ - if (version.served && version.storage) { + if (version.storage) { return version; } } diff --git a/src/renderer/components/+custom-resources/crd-resources.tsx b/src/renderer/components/+custom-resources/crd-resources.tsx index e8f5caa21b..d0eb4779c7 100644 --- a/src/renderer/components/+custom-resources/crd-resources.tsx +++ b/src/renderer/components/+custom-resources/crd-resources.tsx @@ -78,6 +78,17 @@ export class CrdResources extends React.Component { sortingCallbacks[column.name] = item => jsonPath.value(item, parseJsonPath(column.jsonPath.slice(1))); }); + const version = crd.getPreferedVersion(); + const loadFailedPrefix =

Failed to load {crd.getPluralName()}

; + const failedToLoadMessage = version.served + ? loadFailedPrefix + : ( + <> + {loadFailedPrefix} +

Prefered version ({crd.getGroup()}/{version.name}) is not served

+ + ); + return ( { }), crdInstance.getAge(), ]} + failedToLoadMessage={failedToLoadMessage} /> ); } diff --git a/src/renderer/components/item-object-list/item-list-layout.tsx b/src/renderer/components/item-object-list/item-list-layout.tsx index d19e9d20c8..7e5123c48f 100644 --- a/src/renderer/components/item-object-list/item-list-layout.tsx +++ b/src/renderer/components/item-object-list/item-list-layout.tsx @@ -98,6 +98,13 @@ export interface ItemListLayoutProps { customizeRemoveDialog?: (selectedItems: I[]) => Partial; renderFooter?: (parent: ItemListLayout) => React.ReactNode; + /** + * Message to display when a store failed to load + * + * @default "Failed to load items" + */ + failedToLoadMessage?: React.ReactNode; + filterCallbacks?: ItemsFilters; } @@ -114,7 +121,8 @@ const defaultProps: Partial> = { hasDetailsView: true, onDetails: noop, virtual: true, - customizeTableRowProps: () => ({} as TableRowProps), + customizeTableRowProps: () => ({}), + failedToLoadMessage: "Failed to load items", }; @observer @@ -322,7 +330,7 @@ export class ItemListLayout extends React.ComponentFailed to load items.; + return {this.props.failedToLoadMessage}; } if (!this.isReady) {