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  }