1
1
import { ObjectSerializer as InternalSerializer , V1ObjectMeta } from './gen/models/ObjectSerializer.js' ;
2
2
3
+ type KubernetesObjectHeader = {
4
+ apiVersion : string ;
5
+ kind : string ;
6
+ } ;
7
+
8
+ const isKubernetesObject = ( data : unknown ) : data is KubernetesObjectHeader =>
9
+ ! ! data && typeof data === 'object' && 'apiVersion' in data && 'kind' in data ;
10
+
3
11
type AttributeType = {
4
12
name : string ;
5
13
baseName : string ;
@@ -38,30 +46,38 @@ class KubernetesObject {
38
46
format : '' ,
39
47
} ,
40
48
] ;
41
- }
42
-
43
- const isKubernetesObject = ( data : unknown ) : boolean =>
44
- ! ! data && typeof data === 'object' && 'apiVersion' in data && 'kind' in data ;
45
49
46
- /**
47
- * Wraps the ObjectSerializer to support custom resources and generic Kubernetes objects.
48
- */
49
- export class ObjectSerializer extends InternalSerializer {
50
- public static serialize ( data : any , type : string , format : string = '' ) : any {
51
- const obj = InternalSerializer . serialize ( data , type , format ) ;
52
- if ( obj !== data ) {
53
- return obj ;
50
+ public serialize ( ) : any {
51
+ const instance : Record < string , any > = { } ;
52
+ for ( const attributeType of KubernetesObject . attributeTypeMap ) {
53
+ const value = this [ attributeType . baseName ] ;
54
+ if ( value !== undefined ) {
55
+ instance [ attributeType . name ] = InternalSerializer . serialize (
56
+ this [ attributeType . baseName ] ,
57
+ attributeType . type ,
58
+ attributeType . format ,
59
+ ) ;
60
+ }
61
+ }
62
+ // add all unknown properties as is.
63
+ for ( const [ key , value ] of Object . entries ( this ) ) {
64
+ if ( KubernetesObject . attributeTypeMap . find ( ( t ) => t . name === key ) ) {
65
+ continue ;
66
+ }
67
+ instance [ key ] = value ;
54
68
}
69
+ return instance ;
70
+ }
55
71
72
+ public static fromUnknown ( data : unknown ) : KubernetesObject {
56
73
if ( ! isKubernetesObject ( data ) ) {
57
- return obj ;
74
+ throw new Error ( `Unable to deseriliaze non-Kubernetes object ${ data } .` ) ;
58
75
}
59
-
60
- const instance : Record < string , any > = { } ;
76
+ const instance = new KubernetesObject ( ) ;
61
77
for ( const attributeType of KubernetesObject . attributeTypeMap ) {
62
78
const value = data [ attributeType . baseName ] ;
63
79
if ( value !== undefined ) {
64
- instance [ attributeType . name ] = InternalSerializer . serialize (
80
+ instance [ attributeType . name ] = InternalSerializer . deserialize (
65
81
data [ attributeType . baseName ] ,
66
82
attributeType . type ,
67
83
attributeType . format ,
@@ -77,23 +93,114 @@ export class ObjectSerializer extends InternalSerializer {
77
93
}
78
94
return instance ;
79
95
}
96
+ }
80
97
81
- public static deserialize ( data : any , type : string , format : string = '' ) : any {
82
- const obj = InternalSerializer . deserialize ( data , type , format ) ;
98
+ export interface Serializer {
99
+ serialize ( data : any , type : string , format ?: string ) : any ;
100
+ deserialize ( data : any , type : string , format ?) : any ;
101
+ }
102
+
103
+ export type GroupVersionKind = {
104
+ group : string ;
105
+ version : string ;
106
+ kind : string ;
107
+ } ;
108
+
109
+ type ModelRegistry = {
110
+ [ gv : string ] : {
111
+ [ kind : string ] : Serializer ;
112
+ } ;
113
+ } ;
114
+
115
+ const gvString = ( { group, version } : GroupVersionKind ) : string => [ group , version ] . join ( '/' ) ;
116
+
117
+ const gvkFromObject = ( obj : KubernetesObjectHeader ) : GroupVersionKind => {
118
+ const [ g , v ] = obj . apiVersion . split ( '/' ) ;
119
+ return {
120
+ kind : obj . kind ,
121
+ group : v ? g : '' ,
122
+ version : v ? v : g ,
123
+ } ;
124
+ } ;
125
+
126
+ /**
127
+ * Default serializer that uses the KubernetesObject to serialize and deserialize
128
+ * any object using only the minimum required attributes.
129
+ */
130
+ export const defaultSerializer : Serializer = {
131
+ serialize : ( data : any , type : string , format ?: string ) : any => {
132
+ if ( data instanceof KubernetesObject ) {
133
+ return data . serialize ( ) ;
134
+ }
135
+ return KubernetesObject . fromUnknown ( data ) . serialize ( ) ;
136
+ } ,
137
+ deserialize : ( data : any , type : string , format ?) : any => {
138
+ return KubernetesObject . fromUnknown ( data ) ;
139
+ } ,
140
+ } ;
141
+
142
+ /**
143
+ * Wraps the ObjectSerializer to support custom resources and generic Kubernetes objects.
144
+ *
145
+ * CustomResources that are unknown to the ObjectSerializer can be registered
146
+ * by using ObjectSerializer.registerModel().
147
+ */
148
+ export class ObjectSerializer extends InternalSerializer {
149
+ private static modelRegistry : ModelRegistry = { } ;
150
+
151
+ /**
152
+ * Adds a dedicated seriliazer for a Kubernetes resource.
153
+ * Every resource is uniquly identified using its group, version and kind.
154
+ * @param gvk
155
+ * @param serializer
156
+ */
157
+ public static registerModel ( gvk : GroupVersionKind , serializer : Serializer ) {
158
+ const gv = gvString ( gvk ) ;
159
+ const kinds = ( this . modelRegistry [ gv ] ??= { } ) ;
160
+ if ( kinds [ gvk . kind ] ) {
161
+ throw new Error ( `Kind ${ gvk . kind } of ${ gv } is already defined` ) ;
162
+ }
163
+ kinds [ gvk . kind ] = serializer ;
164
+ }
165
+
166
+ /**
167
+ * Removes all registered models from the registry.
168
+ */
169
+ public static clearModelRegistry ( ) : void {
170
+ this . modelRegistry = { } ;
171
+ }
172
+
173
+ private static getSerializerForObject ( obj : unknown ) : undefined | Serializer {
174
+ if ( ! isKubernetesObject ( obj ) ) {
175
+ return undefined ;
176
+ }
177
+ const gvk = gvkFromObject ( obj ) ;
178
+ return ObjectSerializer . modelRegistry [ gvString ( gvk ) ] ?. [ gvk . kind ] ;
179
+ }
180
+
181
+ public static serialize ( data : any , type : string , format : string = '' ) : any {
182
+ const serializer = ObjectSerializer . getSerializerForObject ( data ) ;
183
+ if ( serializer ) {
184
+ return serializer . serialize ( data , type , format ) ;
185
+ }
186
+ if ( data instanceof KubernetesObject ) {
187
+ return data . serialize ( ) ;
188
+ }
189
+
190
+ const obj = InternalSerializer . serialize ( data , type , format ) ;
83
191
if ( obj !== data ) {
84
- // the serializer knows the type and already deserialized it.
85
192
return obj ;
86
193
}
87
194
88
195
if ( ! isKubernetesObject ( data ) ) {
89
196
return obj ;
90
197
}
91
198
92
- const instance = new KubernetesObject ( ) ;
199
+ const instance : Record < string , any > = { } ;
93
200
for ( const attributeType of KubernetesObject . attributeTypeMap ) {
94
201
const value = data [ attributeType . baseName ] ;
95
202
if ( value !== undefined ) {
96
- instance [ attributeType . name ] = InternalSerializer . deserialize (
203
+ instance [ attributeType . name ] = InternalSerializer . serialize (
97
204
data [ attributeType . baseName ] ,
98
205
attributeType . type ,
99
206
attributeType . format ,
@@ -109,4 +216,22 @@ export class ObjectSerializer extends InternalSerializer {
109
216
}
110
217
return instance ;
111
218
}
219
+
220
+ public static deserialize ( data : any , type : string , format : string = '' ) : any {
221
+ const serializer = ObjectSerializer . getSerializerForObject ( data ) ;
222
+ if ( serializer ) {
223
+ return serializer . deserialize ( data , type , format ) ;
224
+ }
225
+ const obj = InternalSerializer . deserialize ( data , type , format ) ;
226
+ if ( obj !== data ) {
227
+ // the serializer knows the type and already deserialized it.
228
+ return obj ;
229
+ }
230
+
231
+ if ( ! isKubernetesObject ( data ) ) {
232
+ return obj ;
233
+ }
234
+
235
+ return KubernetesObject . fromUnknown ( data ) ;
236
+ }
112
237
}
0 commit comments