diff --git a/src/serializer.ts b/src/serializer.ts index 210bde3221..5769fac831 100644 --- a/src/serializer.ts +++ b/src/serializer.ts @@ -1,5 +1,6 @@ import { ObjectSerializer } from './api'; import { V1ObjectMeta } from './gen/model/v1ObjectMeta'; +import { V1ListMeta } from './gen/model/v1ListMeta'; type AttributeType = { name: string; @@ -37,9 +38,52 @@ class KubernetesObject { ]; } +class KubernetesObjectList { + /** + * APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + */ + 'apiVersion'?: string; + /** + * Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + */ + 'kind'?: string; + 'metadata'?: V1ListMeta; + 'items'?: KubernetesObject[]; + + static attributeTypeMap: AttributeType[] = [ + { + name: 'apiVersion', + baseName: 'apiVersion', + type: 'string', + }, + { + name: 'kind', + baseName: 'kind', + type: 'string', + }, + { + name: 'metadata', + baseName: 'metadata', + type: 'V1ListMeta', + }, + ]; +} + const isKubernetesObject = (data: unknown): boolean => !!data && typeof data === 'object' && 'apiVersion' in data && 'kind' in data; +const isKubernetesObjectList = (data: any): boolean => isKubernetesObject(data) && 'items' in data; + +const getClassOfKubernetesInstance = (data: any): any => { + if (!isKubernetesObject(data)) { + return null; + } + if (isKubernetesObjectList(data)) { + return KubernetesObjectList; + } + return KubernetesObject; +}; + /** * Wraps the ObjectSerializer to support custom resources and generic Kubernetes objects. */ @@ -90,12 +134,13 @@ class KubernetesObjectSerializer { return obj; } - if (!isKubernetesObject(data)) { + const kubernetesClass = getClassOfKubernetesInstance(data); + if (!kubernetesClass) { return obj; } - const instance = new KubernetesObject(); - for (const attributeType of KubernetesObject.attributeTypeMap) { + const instance = new kubernetesClass(); + for (const attributeType of kubernetesClass.attributeTypeMap) { instance[attributeType.name] = ObjectSerializer.deserialize( data[attributeType.baseName], attributeType.type, @@ -108,6 +153,10 @@ class KubernetesObjectSerializer { } instance[key] = value; } + if (instance.items) { + instance.items = instance.items.map((item: any) => this.deserialize(item, '')); + } + return instance; } } diff --git a/src/serializer_test.ts b/src/serializer_test.ts index 6023519c25..5c939dc5f0 100644 --- a/src/serializer_test.ts +++ b/src/serializer_test.ts @@ -186,5 +186,66 @@ describe('KubernetesObjectSerializer', () => { const res = KubernetesObjectSerializer.serialize(s, 'unknown'); expect(res).to.deep.equal(s); }); + + it('should deserialize a list of unknown objects', () => { + const s = { + apiVersion: 'v1alpha1', + kind: 'MyCustomResourceList', + metadata: { + resourceVersion: '1', + }, + items: [ + { + apiVersion: 'v1alpha1', + kind: 'MyCustomResource', + metadata: { + name: 'k8s-js-client-test', + namespace: 'default', + creationTimestamp: '2022-01-01T00:00:00.000Z', + }, + data: { + key: 'value', + }, + }, + ], + }; + const res = KubernetesObjectSerializer.deserialize(s, 'v1alpha1MyCustomResource'); + expect(res).to.deep.equal({ + apiVersion: 'v1alpha1', + kind: 'MyCustomResourceList', + metadata: { + _continue: undefined, + remainingItemCount: undefined, + resourceVersion: '1', + selfLink: undefined, + }, + items: [ + { + apiVersion: 'v1alpha1', + kind: 'MyCustomResource', + metadata: { + name: 'k8s-js-client-test', + namespace: 'default', + creationTimestamp: new Date('2022-01-01T00:00:00.000Z'), + uid: undefined, + annotations: undefined, + labels: undefined, + finalizers: undefined, + generateName: undefined, + selfLink: undefined, + resourceVersion: undefined, + generation: undefined, + ownerReferences: undefined, + deletionTimestamp: undefined, + deletionGracePeriodSeconds: undefined, + managedFields: undefined, + }, + data: { + key: 'value', + }, + }, + ], + }); + }); }); });