@@ -18,7 +18,6 @@ package etcd
18
18
19
19
import (
20
20
"context"
21
- "encoding/json"
22
21
"fmt"
23
22
"path/filepath"
24
23
"reflect"
@@ -33,10 +32,17 @@ import (
33
32
"k8s.io/apimachinery/pkg/api/meta"
34
33
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
35
34
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
35
+ "k8s.io/apimachinery/pkg/runtime"
36
36
"k8s.io/apimachinery/pkg/runtime/schema"
37
+ "k8s.io/apimachinery/pkg/runtime/serializer/cbor"
38
+ "k8s.io/apimachinery/pkg/runtime/serializer/json"
39
+ "k8s.io/apimachinery/pkg/runtime/serializer/recognizer"
40
+ utiljson "k8s.io/apimachinery/pkg/util/json"
37
41
"k8s.io/apimachinery/pkg/util/sets"
38
42
"k8s.io/apiserver/pkg/util/feature"
39
43
"k8s.io/client-go/dynamic"
44
+ clientfeatures "k8s.io/client-go/features"
45
+ clientfeaturestesting "k8s.io/client-go/features/testing"
40
46
featuregatetesting "k8s.io/component-base/featuregate/testing"
41
47
)
42
48
@@ -77,6 +83,9 @@ func TestEtcdStoragePath(t *testing.T) {
77
83
featuregatetesting .SetFeatureGateDuringTest (t , feature .DefaultFeatureGate , "AllAlpha" , true )
78
84
featuregatetesting .SetFeatureGateDuringTest (t , feature .DefaultFeatureGate , "AllBeta" , true )
79
85
86
+ // TODO: Remove this override when the codecs used for serving all built-in APIs are wired to the apiserver feature gate.
87
+ clientfeaturestesting .SetFeatureDuringTest (t , clientfeatures .ClientsPreferCBOR , false )
88
+
80
89
apiServer := StartRealAPIServerOrDie (t )
81
90
defer apiServer .Cleanup ()
82
91
defer dumpEtcdKVOnFailure (t , apiServer .KV )
@@ -124,7 +133,8 @@ func TestEtcdStoragePath(t *testing.T) {
124
133
err error
125
134
)
126
135
if shouldCreate {
127
- if input , err = jsonToMetaObject ([]byte (testData .Stub )); err != nil || input .isEmpty () {
136
+ input = new (metaObject )
137
+ if err = utiljson .Unmarshal ([]byte (testData .Stub ), input ); err != nil || input .isEmpty () {
128
138
t .Fatalf ("invalid test data for %s: %v" , gvResource , err )
129
139
}
130
140
// unset type meta fields - we only set these in the CRD test data and it makes
@@ -152,7 +162,20 @@ func TestEtcdStoragePath(t *testing.T) {
152
162
}
153
163
}
154
164
155
- output , err := getFromEtcd (apiServer .KV , testData .ExpectedEtcdPath )
165
+ // Build a decoder that can decode JSON and CBOR from storage.
166
+ scheme := runtime .NewScheme ()
167
+ if testData .ExpectedGVK != nil {
168
+ scheme .AddKnownTypeWithName (* testData .ExpectedGVK , & metaObject {})
169
+ } else {
170
+ scheme .AddKnownTypeWithName (gvk , & metaObject {})
171
+
172
+ }
173
+ decoder := recognizer .NewDecoder (
174
+ cbor .NewSerializer (scheme , scheme ),
175
+ json .NewSerializerWithOptions (json .DefaultMetaFactory , scheme , scheme , json.SerializerOptions {}),
176
+ )
177
+
178
+ output , err := getFromEtcd (decoder , apiServer .KV , testData .ExpectedEtcdPath )
156
179
if err != nil {
157
180
t .Fatalf ("failed to get from etcd for %s: %#v" , gvResource , err )
158
181
}
@@ -208,7 +231,7 @@ func TestEtcdStoragePath(t *testing.T) {
208
231
)
209
232
}
210
233
211
- actualGVK := output .getGVK ()
234
+ actualGVK := output .GroupVersionKind ()
212
235
if actualGVK != expectedGVK {
213
236
t .Errorf ("GVK for %s does not match, expected %s got %s" , kind , expectedGVK , actualGVK )
214
237
}
@@ -289,9 +312,7 @@ func getEtcdBucket(path string) string {
289
312
290
313
// stable fields to compare as a sanity check
291
314
type metaObject struct {
292
- // all of type meta
293
- Kind string `json:"kind,omitempty"`
294
- APIVersion string `json:"apiVersion,omitempty"`
315
+ metav1.TypeMeta `json:",inline"`
295
316
296
317
// parts of object meta
297
318
Metadata struct {
@@ -300,8 +321,10 @@ type metaObject struct {
300
321
} `json:"metadata,omitempty"`
301
322
}
302
323
303
- func (obj * metaObject ) getGVK () schema.GroupVersionKind {
304
- return schema .FromAPIVersionAndKind (obj .APIVersion , obj .Kind )
324
+ var _ runtime.Object = & metaObject {}
325
+
326
+ func (* metaObject ) DeepCopyObject () runtime.Object {
327
+ panic ("unimplemented" )
305
328
}
306
329
307
330
func (obj * metaObject ) isEmpty () bool {
@@ -315,14 +338,6 @@ type cleanupData struct {
315
338
resource schema.GroupVersionResource
316
339
}
317
340
318
- func jsonToMetaObject (stub []byte ) (* metaObject , error ) {
319
- obj := & metaObject {}
320
- if err := json .Unmarshal (stub , obj ); err != nil {
321
- return nil , err
322
- }
323
- return obj , nil
324
- }
325
-
326
341
func keyStringer (i interface {}) string {
327
342
base := "\n \t "
328
343
switch key := i .(type ) {
@@ -386,15 +401,19 @@ func (c *allClient) createPrerequisites(mapper meta.RESTMapper, ns string, prere
386
401
return nil
387
402
}
388
403
389
- func getFromEtcd (keys clientv3.KV , path string ) (* metaObject , error ) {
404
+ func getFromEtcd (decoder runtime. Decoder , keys clientv3.KV , path string ) (* metaObject , error ) {
390
405
response , err := keys .Get (context .Background (), path )
391
406
if err != nil {
392
407
return nil , err
393
408
}
394
409
if response .More || response .Count != 1 || len (response .Kvs ) != 1 {
395
410
return nil , fmt .Errorf ("Invalid etcd response (not found == %v): %#v" , response .Count == 0 , response )
396
411
}
397
- return jsonToMetaObject (response .Kvs [0 ].Value )
412
+ var obj metaObject
413
+ if err := runtime .DecodeInto (decoder , response .Kvs [0 ].Value , & obj ); err != nil {
414
+ return nil , err
415
+ }
416
+ return & obj , nil
398
417
}
399
418
400
419
func diffMaps (a , b interface {}) ([]string , []string ) {
0 commit comments