github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/runtime/serializer/codec_factory.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package serializer 18 19 import ( 20 "mime" 21 "strings" 22 23 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime" 24 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/schema" 25 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/serializer/json" 26 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/serializer/protobuf" 27 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/serializer/recognizer" 28 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/serializer/versioning" 29 ) 30 31 // serializerExtensions are for serializers that are conditionally compiled in 32 var serializerExtensions = []func(*runtime.Scheme) (serializerType, bool){} 33 34 type serializerType struct { 35 AcceptContentTypes []string 36 ContentType string 37 FileExtensions []string 38 // EncodesAsText should be true if this content type can be represented safely in UTF-8 39 EncodesAsText bool 40 41 Serializer runtime.Serializer 42 PrettySerializer runtime.Serializer 43 StrictSerializer runtime.Serializer 44 45 AcceptStreamContentTypes []string 46 StreamContentType string 47 48 Framer runtime.Framer 49 StreamSerializer runtime.Serializer 50 } 51 52 func newSerializersForScheme(scheme *runtime.Scheme, mf json.MetaFactory, options CodecFactoryOptions) []serializerType { 53 jsonSerializer := json.NewSerializerWithOptions( 54 mf, scheme, scheme, 55 json.SerializerOptions{Yaml: false, Pretty: false, Strict: options.Strict}, 56 ) 57 jsonSerializerType := serializerType{ 58 AcceptContentTypes: []string{runtime.ContentTypeJSON}, 59 ContentType: runtime.ContentTypeJSON, 60 FileExtensions: []string{"json"}, 61 EncodesAsText: true, 62 Serializer: jsonSerializer, 63 64 Framer: json.Framer, 65 StreamSerializer: jsonSerializer, 66 } 67 if options.Pretty { 68 jsonSerializerType.PrettySerializer = json.NewSerializerWithOptions( 69 mf, scheme, scheme, 70 json.SerializerOptions{Yaml: false, Pretty: true, Strict: options.Strict}, 71 ) 72 } 73 74 strictJSONSerializer := json.NewSerializerWithOptions( 75 mf, scheme, scheme, 76 json.SerializerOptions{Yaml: false, Pretty: false, Strict: true}, 77 ) 78 jsonSerializerType.StrictSerializer = strictJSONSerializer 79 80 yamlSerializer := json.NewSerializerWithOptions( 81 mf, scheme, scheme, 82 json.SerializerOptions{Yaml: true, Pretty: false, Strict: options.Strict}, 83 ) 84 strictYAMLSerializer := json.NewSerializerWithOptions( 85 mf, scheme, scheme, 86 json.SerializerOptions{Yaml: true, Pretty: false, Strict: true}, 87 ) 88 protoSerializer := protobuf.NewSerializer(scheme, scheme) 89 protoRawSerializer := protobuf.NewRawSerializer(scheme, scheme) 90 91 serializers := []serializerType{ 92 jsonSerializerType, 93 { 94 AcceptContentTypes: []string{runtime.ContentTypeYAML}, 95 ContentType: runtime.ContentTypeYAML, 96 FileExtensions: []string{"yaml"}, 97 EncodesAsText: true, 98 Serializer: yamlSerializer, 99 StrictSerializer: strictYAMLSerializer, 100 }, 101 { 102 AcceptContentTypes: []string{runtime.ContentTypeProtobuf}, 103 ContentType: runtime.ContentTypeProtobuf, 104 FileExtensions: []string{"pb"}, 105 Serializer: protoSerializer, 106 // note, strict decoding is unsupported for protobuf, 107 // fall back to regular serializing 108 StrictSerializer: protoSerializer, 109 110 Framer: protobuf.LengthDelimitedFramer, 111 StreamSerializer: protoRawSerializer, 112 }, 113 } 114 115 for _, fn := range serializerExtensions { 116 if serializer, ok := fn(scheme); ok { 117 serializers = append(serializers, serializer) 118 } 119 } 120 return serializers 121 } 122 123 // CodecFactory provides methods for retrieving codecs and serializers for specific 124 // versions and content types. 125 type CodecFactory struct { 126 scheme *runtime.Scheme 127 universal runtime.Decoder 128 accepts []runtime.SerializerInfo 129 130 legacySerializer runtime.Serializer 131 } 132 133 // CodecFactoryOptions holds the options for configuring CodecFactory behavior 134 type CodecFactoryOptions struct { 135 // Strict configures all serializers in strict mode 136 Strict bool 137 // Pretty includes a pretty serializer along with the non-pretty one 138 Pretty bool 139 } 140 141 // CodecFactoryOptionsMutator takes a pointer to an options struct and then modifies it. 142 // Functions implementing this type can be passed to the NewCodecFactory() constructor. 143 type CodecFactoryOptionsMutator func(*CodecFactoryOptions) 144 145 // EnablePretty enables including a pretty serializer along with the non-pretty one 146 func EnablePretty(options *CodecFactoryOptions) { 147 options.Pretty = true 148 } 149 150 // DisablePretty disables including a pretty serializer along with the non-pretty one 151 func DisablePretty(options *CodecFactoryOptions) { 152 options.Pretty = false 153 } 154 155 // EnableStrict enables configuring all serializers in strict mode 156 func EnableStrict(options *CodecFactoryOptions) { 157 options.Strict = true 158 } 159 160 // DisableStrict disables configuring all serializers in strict mode 161 func DisableStrict(options *CodecFactoryOptions) { 162 options.Strict = false 163 } 164 165 // NewCodecFactory provides methods for retrieving serializers for the supported wire formats 166 // and conversion wrappers to define preferred internal and external versions. In the future, 167 // as the internal version is used less, callers may instead use a defaulting serializer and 168 // only convert objects which are shared internally (Status, common API machinery). 169 // 170 // Mutators can be passed to change the CodecFactoryOptions before construction of the factory. 171 // It is recommended to explicitly pass mutators instead of relying on defaults. 172 // By default, Pretty is enabled -- this is conformant with previously supported behavior. 173 // 174 // TODO: allow other codecs to be compiled in? 175 // TODO: accept a scheme interface 176 func NewCodecFactory(scheme *runtime.Scheme, mutators ...CodecFactoryOptionsMutator) CodecFactory { 177 options := CodecFactoryOptions{Pretty: true} 178 for _, fn := range mutators { 179 fn(&options) 180 } 181 182 serializers := newSerializersForScheme(scheme, json.DefaultMetaFactory, options) 183 return newCodecFactory(scheme, serializers) 184 } 185 186 // newCodecFactory is a helper for testing that allows a different metafactory to be specified. 187 func newCodecFactory(scheme *runtime.Scheme, serializers []serializerType) CodecFactory { 188 decoders := make([]runtime.Decoder, 0, len(serializers)) 189 var accepts []runtime.SerializerInfo 190 alreadyAccepted := make(map[string]struct{}) 191 192 var legacySerializer runtime.Serializer 193 for _, d := range serializers { 194 decoders = append(decoders, d.Serializer) 195 for _, mediaType := range d.AcceptContentTypes { 196 if _, ok := alreadyAccepted[mediaType]; ok { 197 continue 198 } 199 alreadyAccepted[mediaType] = struct{}{} 200 info := runtime.SerializerInfo{ 201 MediaType: d.ContentType, 202 EncodesAsText: d.EncodesAsText, 203 Serializer: d.Serializer, 204 PrettySerializer: d.PrettySerializer, 205 StrictSerializer: d.StrictSerializer, 206 } 207 208 mediaType, _, err := mime.ParseMediaType(info.MediaType) 209 if err != nil { 210 panic(err) 211 } 212 parts := strings.SplitN(mediaType, "/", 2) 213 info.MediaTypeType = parts[0] 214 info.MediaTypeSubType = parts[1] 215 216 if d.StreamSerializer != nil { 217 info.StreamSerializer = &runtime.StreamSerializerInfo{ 218 Serializer: d.StreamSerializer, 219 EncodesAsText: d.EncodesAsText, 220 Framer: d.Framer, 221 } 222 } 223 accepts = append(accepts, info) 224 if mediaType == runtime.ContentTypeJSON { 225 legacySerializer = d.Serializer 226 } 227 } 228 } 229 if legacySerializer == nil { 230 legacySerializer = serializers[0].Serializer 231 } 232 233 return CodecFactory{ 234 scheme: scheme, 235 universal: recognizer.NewDecoder(decoders...), 236 237 accepts: accepts, 238 239 legacySerializer: legacySerializer, 240 } 241 } 242 243 // WithoutConversion returns a NegotiatedSerializer that performs no conversion, even if the 244 // caller requests it. 245 func (f CodecFactory) WithoutConversion() runtime.NegotiatedSerializer { 246 return WithoutConversionCodecFactory{f} 247 } 248 249 // SupportedMediaTypes returns the RFC2046 media types that this factory has serializers for. 250 func (f CodecFactory) SupportedMediaTypes() []runtime.SerializerInfo { 251 return f.accepts 252 } 253 254 // LegacyCodec encodes output to a given API versions, and decodes output into the internal form from 255 // any recognized source. The returned codec will always encode output to JSON. If a type is not 256 // found in the list of versions an error will be returned. 257 // 258 // This method is deprecated - clients and servers should negotiate a serializer by mime-type and 259 // invoke CodecForVersions. Callers that need only to read data should use UniversalDecoder(). 260 // 261 // TODO: make this call exist only in pkg/api, and initialize it with the set of default versions. 262 // 263 // All other callers will be forced to request a Codec directly. 264 func (f CodecFactory) LegacyCodec(version ...schema.GroupVersion) runtime.Codec { 265 return versioning.NewDefaultingCodecForScheme(f.scheme, f.legacySerializer, f.universal, schema.GroupVersions(version), runtime.InternalGroupVersioner) 266 } 267 268 // UniversalDeserializer can convert any stored data recognized by this factory into a Go object that satisfies 269 // runtime.Object. It does not perform conversion. It does not perform defaulting. 270 func (f CodecFactory) UniversalDeserializer() runtime.Decoder { 271 return f.universal 272 } 273 274 // UniversalDecoder returns a runtime.Decoder capable of decoding all known API objects in all known formats. Used 275 // by clients that do not need to encode objects but want to deserialize API objects stored on disk. Only decodes 276 // objects in groups registered with the scheme. The GroupVersions passed may be used to select alternate 277 // versions of objects to return - by default, runtime.APIVersionInternal is used. If any versions are specified, 278 // unrecognized groups will be returned in the version they are encoded as (no conversion). This decoder performs 279 // defaulting. 280 // 281 // TODO: the decoder will eventually be removed in favor of dealing with objects in their versioned form 282 // TODO: only accept a group versioner 283 func (f CodecFactory) UniversalDecoder(versions ...schema.GroupVersion) runtime.Decoder { 284 var versioner runtime.GroupVersioner 285 if len(versions) == 0 { 286 versioner = runtime.InternalGroupVersioner 287 } else { 288 versioner = schema.GroupVersions(versions) 289 } 290 return f.CodecForVersions(nil, f.universal, nil, versioner) 291 } 292 293 // CodecForVersions creates a codec with the provided serializer. If an object is decoded and its group is not in the list, 294 // it will default to runtime.APIVersionInternal. If encode is not specified for an object's group, the object is not 295 // converted. If encode or decode are nil, no conversion is performed. 296 func (f CodecFactory) CodecForVersions(encoder runtime.Encoder, decoder runtime.Decoder, encode runtime.GroupVersioner, decode runtime.GroupVersioner) runtime.Codec { 297 // TODO: these are for backcompat, remove them in the future 298 if encode == nil { 299 encode = runtime.DisabledGroupVersioner 300 } 301 if decode == nil { 302 decode = runtime.InternalGroupVersioner 303 } 304 return versioning.NewDefaultingCodecForScheme(f.scheme, encoder, decoder, encode, decode) 305 } 306 307 // DecoderToVersion returns a decoder that targets the provided group version. 308 func (f CodecFactory) DecoderToVersion(decoder runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder { 309 return f.CodecForVersions(nil, decoder, nil, gv) 310 } 311 312 // EncoderForVersion returns an encoder that targets the provided group version. 313 func (f CodecFactory) EncoderForVersion(encoder runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder { 314 return f.CodecForVersions(encoder, nil, gv, nil) 315 } 316 317 // WithoutConversionCodecFactory is a CodecFactory that will explicitly ignore requests to perform conversion. 318 // This wrapper is used while code migrates away from using conversion (such as external clients) and in the future 319 // will be unnecessary when we change the signature of NegotiatedSerializer. 320 type WithoutConversionCodecFactory struct { 321 CodecFactory 322 } 323 324 // EncoderForVersion returns an encoder that does not do conversion, but does set the group version kind of the object 325 // when serialized. 326 func (f WithoutConversionCodecFactory) EncoderForVersion(serializer runtime.Encoder, version runtime.GroupVersioner) runtime.Encoder { 327 return runtime.WithVersionEncoder{ 328 Version: version, 329 Encoder: serializer, 330 ObjectTyper: f.CodecFactory.scheme, 331 } 332 } 333 334 // DecoderToVersion returns an decoder that does not do conversion. 335 func (f WithoutConversionCodecFactory) DecoderToVersion(serializer runtime.Decoder, _ runtime.GroupVersioner) runtime.Decoder { 336 return runtime.WithoutVersionDecoder{ 337 Decoder: serializer, 338 } 339 }