Skip to content

Commit 87e32c7

Browse files
committed
Force etcd2 to use application/json, add base64-wrapper decoder as fallback
1 parent a19210f commit 87e32c7

File tree

5 files changed

+30
-15
lines changed

5 files changed

+30
-15
lines changed

pkg/api/testapi/testapi.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ func (g TestGroup) StorageCodec() runtime.Codec {
349349
// etcd2 only supports string data - we must wrap any result before returning
350350
// TODO: remove for etcd3 / make parameterizable
351351
if !storageSerializer.EncodesAsText {
352-
s = runtime.NewBase64Serializer(s)
352+
s = runtime.NewBase64Serializer(s, s)
353353
}
354354
ds := recognizer.NewDecoder(s, api.Codecs.UniversalDeserializer())
355355

staging/src/k8s.io/apimachinery/pkg/api/testing/codec.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func TestStorageCodec(codecs runtimeserializer.CodecFactory, gvs ...schema.Group
5858
// TODO: remove for etcd3 / make parameterizable
5959
serializer := serializerInfo.Serializer
6060
if !serializerInfo.EncodesAsText {
61-
serializer = runtime.NewBase64Serializer(serializer)
61+
serializer = runtime.NewBase64Serializer(serializer, serializer)
6262
}
6363

6464
decoder := recognizer.NewDecoder(serializer, codecs.UniversalDeserializer())

staging/src/k8s.io/apimachinery/pkg/runtime/codec.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,16 +195,17 @@ func (c *parameterCodec) EncodeParameters(obj Object, to schema.GroupVersion) (u
195195
}
196196

197197
type base64Serializer struct {
198-
Serializer
198+
Encoder
199+
Decoder
199200
}
200201

201-
func NewBase64Serializer(s Serializer) Serializer {
202-
return &base64Serializer{s}
202+
func NewBase64Serializer(e Encoder, d Decoder) Serializer {
203+
return &base64Serializer{e, d}
203204
}
204205

205206
func (s base64Serializer) Encode(obj Object, stream io.Writer) error {
206207
e := base64.NewEncoder(base64.StdEncoding, stream)
207-
err := s.Serializer.Encode(obj, e)
208+
err := s.Encoder.Encode(obj, e)
208209
e.Close()
209210
return err
210211
}
@@ -215,7 +216,7 @@ func (s base64Serializer) Decode(data []byte, defaults *schema.GroupVersionKind,
215216
if err != nil {
216217
return nil, nil, err
217218
}
218-
return s.Serializer.Decode(out[:n], defaults, into)
219+
return s.Decoder.Decode(out[:n], defaults, into)
219220
}
220221

221222
// SerializerInfoForMediaType returns the first info in types that has a matching media type (which cannot

staging/src/k8s.io/apiserver/pkg/server/options/etcd.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ func (s *EtcdOptions) AddFlags(fs *pflag.FlagSet) {
6868
"format: group/resource#servers, where servers are http://ip:port, semicolon separated.")
6969

7070
fs.StringVar(&s.DefaultStorageMediaType, "storage-media-type", s.DefaultStorageMediaType, ""+
71-
"The media type to use to store objects in storage. Defaults to application/json. "+
72-
"Some resources may only support a specific media type and will ignore this setting.")
71+
"The media type to use to store objects in storage. "+
72+
"Some resources or storage backends may only support a specific media type and will ignore this setting.")
7373
fs.IntVar(&s.DeleteCollectionWorkers, "delete-collection-workers", s.DeleteCollectionWorkers,
7474
"Number of workers spawned for DeleteCollection call. These are used to speed up namespace cleanup.")
7575

staging/src/k8s.io/apiserver/pkg/server/storage/storage_codec.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,22 @@ func NewStorageCodec(opts StorageCodecConfig) (runtime.Codec, error) {
4747
if err != nil {
4848
return nil, fmt.Errorf("%q is not a valid mime-type", opts.StorageMediaType)
4949
}
50+
51+
if opts.Config.Type == storagebackend.StorageTypeETCD2 && mediaType != "application/json" {
52+
glog.Warningf(`storage type %q does not support media type %q, using "application/json"`, storagebackend.StorageTypeETCD2, mediaType)
53+
mediaType = "application/json"
54+
}
55+
5056
serializer, ok := runtime.SerializerInfoForMediaType(opts.StorageSerializer.SupportedMediaTypes(), mediaType)
5157
if !ok {
52-
return nil, fmt.Errorf("unable to find serializer for %q", opts.StorageMediaType)
58+
return nil, fmt.Errorf("unable to find serializer for %q", mediaType)
5359
}
5460

5561
s := serializer.Serializer
5662

57-
// etcd2 only supports string data - we must wrap any result before returning
58-
// TODO: storagebackend should return a boolean indicating whether it supports binary data
63+
// make sure the selected encoder supports string data
5964
if !serializer.EncodesAsText && opts.Config.Type == storagebackend.StorageTypeETCD2 {
60-
glog.V(4).Infof("Wrapping the underlying binary storage serializer with a base64 encoding for etcd2")
61-
s = runtime.NewBase64Serializer(s)
65+
return nil, fmt.Errorf("storage type %q does not support binary media type %q", storagebackend.StorageTypeETCD2, mediaType)
6266
}
6367

6468
// Give callers the opportunity to wrap encoders and decoders. For decoders, each returned decoder will
@@ -67,7 +71,17 @@ func NewStorageCodec(opts StorageCodecConfig) (runtime.Codec, error) {
6771
if opts.EncoderDecoratorFn != nil {
6872
encoder = opts.EncoderDecoratorFn(encoder)
6973
}
70-
decoders := []runtime.Decoder{s, opts.StorageSerializer.UniversalDeserializer()}
74+
decoders := []runtime.Decoder{
75+
// selected decoder as the primary
76+
s,
77+
// universal deserializer as a fallback
78+
opts.StorageSerializer.UniversalDeserializer(),
79+
// base64-wrapped universal deserializer as a last resort.
80+
// this allows reading base64-encoded protobuf, which should only exist if etcd2+protobuf was used at some point.
81+
// data written that way could exist in etcd2, or could have been migrated to etcd3.
82+
// TODO: flag this type of data if we encounter it, require migration (read to decode, write to persist using a supported encoder), and remove in 1.8
83+
runtime.NewBase64Serializer(nil, opts.StorageSerializer.UniversalDeserializer()),
84+
}
7185
if opts.DecoderDecoratorFn != nil {
7286
decoders = opts.DecoderDecoratorFn(decoders)
7387
}

0 commit comments

Comments
 (0)