Force etcd2 to use application/json, add base64-wrapper decoder as fallback

Kubernetes-commit: 87e32c75321bad09707683cb15d6a0c41f4b6f0d
This commit is contained in:
Jordan Liggitt 2017-03-15 10:58:15 -04:00 committed by Kubernetes Publisher
parent d720bb7423
commit 0f41d276a9
2 changed files with 22 additions and 8 deletions

View File

@ -68,8 +68,8 @@ func (s *EtcdOptions) AddFlags(fs *pflag.FlagSet) {
"format: group/resource#servers, where servers are http://ip:port, semicolon separated.")
fs.StringVar(&s.DefaultStorageMediaType, "storage-media-type", s.DefaultStorageMediaType, ""+
"The media type to use to store objects in storage. Defaults to application/json. "+
"Some resources may only support a specific media type and will ignore this setting.")
"The media type to use to store objects in storage. "+
"Some resources or storage backends may only support a specific media type and will ignore this setting.")
fs.IntVar(&s.DeleteCollectionWorkers, "delete-collection-workers", s.DeleteCollectionWorkers,
"Number of workers spawned for DeleteCollection call. These are used to speed up namespace cleanup.")

View File

@ -47,18 +47,22 @@ func NewStorageCodec(opts StorageCodecConfig) (runtime.Codec, error) {
if err != nil {
return nil, fmt.Errorf("%q is not a valid mime-type", opts.StorageMediaType)
}
if opts.Config.Type == storagebackend.StorageTypeETCD2 && mediaType != "application/json" {
glog.Warningf(`storage type %q does not support media type %q, using "application/json"`, storagebackend.StorageTypeETCD2, mediaType)
mediaType = "application/json"
}
serializer, ok := runtime.SerializerInfoForMediaType(opts.StorageSerializer.SupportedMediaTypes(), mediaType)
if !ok {
return nil, fmt.Errorf("unable to find serializer for %q", opts.StorageMediaType)
return nil, fmt.Errorf("unable to find serializer for %q", mediaType)
}
s := serializer.Serializer
// etcd2 only supports string data - we must wrap any result before returning
// TODO: storagebackend should return a boolean indicating whether it supports binary data
// make sure the selected encoder supports string data
if !serializer.EncodesAsText && opts.Config.Type == storagebackend.StorageTypeETCD2 {
glog.V(4).Infof("Wrapping the underlying binary storage serializer with a base64 encoding for etcd2")
s = runtime.NewBase64Serializer(s)
return nil, fmt.Errorf("storage type %q does not support binary media type %q", storagebackend.StorageTypeETCD2, mediaType)
}
// 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) {
if opts.EncoderDecoratorFn != nil {
encoder = opts.EncoderDecoratorFn(encoder)
}
decoders := []runtime.Decoder{s, opts.StorageSerializer.UniversalDeserializer()}
decoders := []runtime.Decoder{
// selected decoder as the primary
s,
// universal deserializer as a fallback
opts.StorageSerializer.UniversalDeserializer(),
// base64-wrapped universal deserializer as a last resort.
// this allows reading base64-encoded protobuf, which should only exist if etcd2+protobuf was used at some point.
// data written that way could exist in etcd2, or could have been migrated to etcd3.
// 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
runtime.NewBase64Serializer(nil, opts.StorageSerializer.UniversalDeserializer()),
}
if opts.DecoderDecoratorFn != nil {
decoders = opts.DecoderDecoratorFn(decoders)
}