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.") "format: group/resource#servers, where servers are http://ip:port, semicolon separated.")
fs.StringVar(&s.DefaultStorageMediaType, "storage-media-type", s.DefaultStorageMediaType, ""+ fs.StringVar(&s.DefaultStorageMediaType, "storage-media-type", s.DefaultStorageMediaType, ""+
"The media type to use to store objects in storage. Defaults to application/json. "+ "The media type to use to store objects in storage. "+
"Some resources may only support a specific media type and will ignore this setting.") "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, fs.IntVar(&s.DeleteCollectionWorkers, "delete-collection-workers", s.DeleteCollectionWorkers,
"Number of workers spawned for DeleteCollection call. These are used to speed up namespace cleanup.") "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 { if err != nil {
return nil, fmt.Errorf("%q is not a valid mime-type", opts.StorageMediaType) 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) serializer, ok := runtime.SerializerInfoForMediaType(opts.StorageSerializer.SupportedMediaTypes(), mediaType)
if !ok { 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 s := serializer.Serializer
// etcd2 only supports string data - we must wrap any result before returning // make sure the selected encoder supports string data
// TODO: storagebackend should return a boolean indicating whether it supports binary data
if !serializer.EncodesAsText && opts.Config.Type == storagebackend.StorageTypeETCD2 { if !serializer.EncodesAsText && opts.Config.Type == storagebackend.StorageTypeETCD2 {
glog.V(4).Infof("Wrapping the underlying binary storage serializer with a base64 encoding for etcd2") return nil, fmt.Errorf("storage type %q does not support binary media type %q", storagebackend.StorageTypeETCD2, mediaType)
s = runtime.NewBase64Serializer(s)
} }
// Give callers the opportunity to wrap encoders and decoders. For decoders, each returned decoder will // 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 { if opts.EncoderDecoratorFn != nil {
encoder = opts.EncoderDecoratorFn(encoder) 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 { if opts.DecoderDecoratorFn != nil {
decoders = opts.DecoderDecoratorFn(decoders) decoders = opts.DecoderDecoratorFn(decoders)
} }