12
12
*/
13
13
package io .kubernetes .client .util ;
14
14
15
+ import com .google .common .base .Objects ;
15
16
import com .google .common .collect .ImmutableMap ;
16
17
import com .google .common .reflect .ClassPath ;
18
+ import io .kubernetes .client .Discovery ;
19
+ import io .kubernetes .client .common .KubernetesListObject ;
20
+ import io .kubernetes .client .common .KubernetesObject ;
21
+ import io .kubernetes .client .openapi .ApiException ;
17
22
import java .io .IOException ;
18
23
import java .util .ArrayList ;
19
24
import java .util .HashMap ;
31
36
*/
32
37
public class ModelMapper {
33
38
34
- private static Map <String , Class <?>> classes = new HashMap <>();
39
+ private static final Logger logger = LoggerFactory .getLogger (ModelMapper .class );
40
+
41
+ private static Map <GroupVersionKind , Class <?>> classes = new HashMap <>();
42
+ // Model's api-group prefix to kubernetes api-group
35
43
private static Map <String , String > apiGroups = new HashMap <>();
44
+ // Model's api-version midfix to kubernetes api-version
36
45
private static List <String > apiVersions = new ArrayList <>();
37
46
38
- private static final Logger logger = LoggerFactory .getLogger (ModelMapper .class );
39
-
40
47
static {
41
48
try {
42
49
initModelMap ();
@@ -46,30 +53,114 @@ public class ModelMapper {
46
53
}
47
54
48
55
/**
49
- * Add a mapping from API Group/version/kind to a Class to use when calling <code>load(...)
50
- * </code> .
56
+ * Registering concrete model classes by its apiGroupVersion (e.g. "apps/v1") and kind (e.g.
57
+ * "Deployment") .
51
58
*
52
- * <p>Shouldn't really be needed as most API Group/Version/Kind are loaded dynamically at startup.
59
+ * <p>Note that the the so-called apiGroupVersion equals to the "apiVersion" in the kubenretes
60
+ * resource yamls.
53
61
*/
54
62
public static void addModelMap (String apiGroupVersion , String kind , Class <?> clazz ) {
55
- classes .put (apiGroupVersion + "/" + kind , clazz );
63
+ String [] parts = apiGroupVersion .split ("/" );
64
+ if (parts .length == 1 ) {
65
+ String version = apiGroupVersion ;
66
+ addModelMap ("" , version , kind , clazz );
67
+ }
68
+ addModelMap (parts [0 ], parts [1 ], kind , clazz );
56
69
}
57
70
58
- public static Class <?> getApiTypeClass (String apiVersion , String kind ) {
59
- Class <?> clazz = (Class <?>) classes .get (apiVersion + "/" + kind );
60
- if (clazz == null ) {
61
- // Attempt to detect class from version and kind alone
62
- if (apiVersion .contains ("/" )) {
63
- clazz = (Class <?>) classes .get (apiVersion .split ("/" )[1 ] + "/" + kind );
64
- }
71
+ /**
72
+ * Registering concrete model classes by its group, version and kind (e.g. "apps", "v1",
73
+ * "Deployment")
74
+ *
75
+ * @param group the group
76
+ * @param version the version
77
+ * @param kind the kind
78
+ * @param clazz the clazz
79
+ */
80
+ public static void addModelMap (String group , String version , String kind , Class <?> clazz ) {
81
+ classes .put (new GroupVersionKind (group , version , kind ), clazz );
82
+ }
83
+
84
+ /**
85
+ * Gets the model classes by given apiGroupVersion (e.g. "apps/v1") and kind (e.g. "Deployment").
86
+ *
87
+ * @param apiGroupVersion the api version
88
+ * @param kind the kind
89
+ * @return the api type class
90
+ */
91
+ public static Class <?> getApiTypeClass (String apiGroupVersion , String kind ) {
92
+ String [] parts = apiGroupVersion .split ("/" );
93
+ if (parts .length == 1 ) {
94
+ // legacy group
95
+ return getApiTypeClass ("" , apiGroupVersion , kind );
65
96
}
66
- return clazz ;
97
+ return getApiTypeClass ( parts [ 0 ], parts [ 1 ], kind ) ;
67
98
}
68
99
69
- public static Map <String , Class <?>> getAllKnownClasses () {
100
+ /**
101
+ * Gets the model classes by given group, version and kind (e.g. "apps", ""v1", "Deployment").
102
+ *
103
+ * @param group the group
104
+ * @param version the version
105
+ * @param kind the kind
106
+ * @return the api type class
107
+ */
108
+ public static Class <?> getApiTypeClass (String group , String version , String kind ) {
109
+ Class <?> clazz = classes .get (new GroupVersionKind (group , version , kind ));
110
+ if (clazz != null ) {
111
+ return clazz ;
112
+ }
113
+ return classes .get (new GroupVersionKind (null , version , kind ));
114
+ }
115
+
116
+ /**
117
+ * Returns all the registered model classes.
118
+ *
119
+ * @return the all known classes
120
+ */
121
+ public static Map <GroupVersionKind , Class <?>> getAllKnownClasses () {
70
122
return ImmutableMap .copyOf (classes );
71
123
}
72
124
125
+ /**
126
+ * Gets the GVK by the given model class.
127
+ *
128
+ * <p>Note: This method will run a loop over the registered models, consider use {@link
129
+ * ModelMapper#getAllKnownClasses} and build your own index for faster queries.
130
+ *
131
+ * @param clazz the clazz
132
+ * @return the group version kind by class
133
+ */
134
+ public static GroupVersionKind getGroupVersionKindByClass (Class <?> clazz ) {
135
+ return classes .entrySet ().stream ()
136
+ .filter (e -> clazz .equals (e .getValue ()))
137
+ .map (e -> e .getKey ())
138
+ .findFirst ()
139
+ .get ();
140
+ }
141
+
142
+ /**
143
+ * Refreshes the model mapping by syncing up w/the api discovery info from the kubernetes
144
+ * apiserver.
145
+ *
146
+ * @param discovery the discovery
147
+ * @throws ApiException the api exception
148
+ */
149
+ public static void refresh (Discovery discovery ) throws ApiException {
150
+ // TODO(yue9944882): integration test it
151
+ for (Discovery .APIResource apiResource : discovery .findAll ()) {
152
+ for (String version : apiResource .getVersions ()) {
153
+ Class <?> clazz = getApiTypeClass (apiResource .getGroup (), version , apiResource .getKind ());
154
+ if (clazz == null ) {
155
+ continue ;
156
+ }
157
+ // sync up w/ the latest api discovery
158
+ classes .remove (getGroupVersionKindByClass (clazz ));
159
+ addModelMap (apiResource .getGroup (), version , apiResource .getKind (), clazz );
160
+ }
161
+ }
162
+ }
163
+
73
164
private static void initApiGroupMap () {
74
165
apiGroups .put ("Admissionregistration" , "admissionregistration.k8s.io" );
75
166
apiGroups .put ("Apiextensions" , "apiextensions.k8s.io" );
@@ -87,6 +178,7 @@ private static void initApiGroupMap() {
87
178
apiGroups .put ("Scheduling" , "scheduling.k8s.io" );
88
179
apiGroups .put ("Settings" , "settings.k8s.io" );
89
180
apiGroups .put ("Storage" , "storage.k8s.io" );
181
+ apiGroups .put ("FlowControl" , "flowcontrol.apiserver.k8s.io" );
90
182
}
91
183
92
184
private static void initApiVersionList () {
@@ -100,20 +192,6 @@ private static void initApiVersionList() {
100
192
apiVersions .add ("V1" );
101
193
}
102
194
103
- private static Pair <String , String > getApiVersion (String name ) {
104
- MutablePair <String , String > parts = new MutablePair <>();
105
- for (String version : apiVersions ) {
106
- if (name .startsWith (version )) {
107
- parts .left = version .toLowerCase ();
108
- parts .right = name .substring (version .length ());
109
- break ;
110
- }
111
- }
112
- if (parts .left == null ) parts .right = name ;
113
-
114
- return parts ;
115
- }
116
-
117
195
private static void initModelMap () throws IOException {
118
196
initApiGroupMap ();
119
197
initApiVersionList ();
@@ -122,29 +200,80 @@ private static void initModelMap() throws IOException {
122
200
Set <ClassPath .ClassInfo > allClasses =
123
201
cp .getTopLevelClasses ("io.kubernetes.client.openapi.models" );
124
202
125
- for (ClassPath .ClassInfo clazz : allClasses ) {
126
- String modelName = "" ;
127
- Pair <String , String > nameParts = getApiGroup (clazz .getSimpleName ());
128
- modelName += nameParts .getLeft () == null ? "" : nameParts .getLeft () + "/" ;
203
+ for (ClassPath .ClassInfo classInfo : allClasses ) {
204
+ Class clazz = classInfo .load ();
205
+ if (!KubernetesObject .class .isAssignableFrom (clazz )
206
+ && !KubernetesListObject .class .isAssignableFrom (clazz )) {
207
+ continue ;
208
+ }
209
+
210
+ Pair <String , String > groupAndOther = getApiGroup (clazz .getSimpleName ());
211
+ Pair <String , String > versionAndOther = getApiVersion (groupAndOther .getRight ());
129
212
130
- nameParts = getApiVersion ( nameParts . getRight () );
131
- modelName += nameParts . getLeft () == null ? "" : nameParts .getLeft () + "/" ;
132
- modelName += nameParts .getRight ();
213
+ String group = groupAndOther . getLeft ( );
214
+ String version = versionAndOther .getLeft ();
215
+ String kind = versionAndOther .getRight ();
133
216
134
- classes .put (modelName , clazz . load () );
217
+ classes .put (new GroupVersionKind ( group , version , kind ), clazz );
135
218
}
136
219
}
137
220
138
221
private static Pair <String , String > getApiGroup (String name ) {
139
- MutablePair <String , String > parts = new MutablePair <>();
140
- for (Map .Entry <String , String > entry : apiGroups .entrySet ()) {
141
- if (name .startsWith (entry .getKey ())) {
142
- parts .left = entry .getValue ();
143
- parts .right = name .substring (entry .getKey ().length ());
144
- break ;
145
- }
222
+ return apiGroups .entrySet ().stream ()
223
+ .filter (e -> name .startsWith (e .getKey ()))
224
+ .map (e -> new MutablePair (e .getValue (), name .substring (e .getKey ().length ())))
225
+ .findFirst ()
226
+ .orElse (new MutablePair (null , name ));
227
+ }
228
+
229
+ private static Pair <String , String > getApiVersion (String name ) {
230
+ return apiVersions .stream ()
231
+ .filter (v -> name .startsWith (v ))
232
+ .map (v -> new MutablePair (v .toLowerCase (), name .substring (v .length ())))
233
+ .findFirst ()
234
+ .orElse (new MutablePair (null , name ));
235
+ }
236
+
237
+ public static class GroupVersionKind {
238
+
239
+ public GroupVersionKind (String group , String version , String kind ) {
240
+ this .group = group ;
241
+ this .version = version ;
242
+ this .kind = kind ;
243
+ }
244
+
245
+ private String group ;
246
+ private String version ;
247
+ private String kind ;
248
+
249
+ @ Override
250
+ public boolean equals (Object o ) {
251
+ if (this == o ) return true ;
252
+ if (o == null || getClass () != o .getClass ()) return false ;
253
+ GroupVersionKind that = (GroupVersionKind ) o ;
254
+ return Objects .equal (group , that .group )
255
+ && Objects .equal (version , that .version )
256
+ && Objects .equal (kind , that .kind );
257
+ }
258
+
259
+ @ Override
260
+ public int hashCode () {
261
+ return Objects .hashCode (group , version , kind );
262
+ }
263
+
264
+ @ Override
265
+ public String toString () {
266
+ return "GroupVersionKind{"
267
+ + "group='"
268
+ + group
269
+ + '\''
270
+ + ", version='"
271
+ + version
272
+ + '\''
273
+ + ", kind='"
274
+ + kind
275
+ + '\''
276
+ + '}' ;
146
277
}
147
- if (parts .left == null ) parts .right = name ;
148
- return parts ;
149
278
}
150
279
}
0 commit comments