123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- /*
- Copyright 2014 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package serializer
- import (
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/apimachinery/pkg/runtime/serializer/json"
- "k8s.io/apimachinery/pkg/runtime/serializer/recognizer"
- "k8s.io/apimachinery/pkg/runtime/serializer/versioning"
- )
- // serializerExtensions are for serializers that are conditionally compiled in
- var serializerExtensions = []func(*runtime.Scheme) (serializerType, bool){}
- type serializerType struct {
- AcceptContentTypes []string
- ContentType string
- FileExtensions []string
- // EncodesAsText should be true if this content type can be represented safely in UTF-8
- EncodesAsText bool
- Serializer runtime.Serializer
- PrettySerializer runtime.Serializer
- AcceptStreamContentTypes []string
- StreamContentType string
- Framer runtime.Framer
- StreamSerializer runtime.Serializer
- }
- func newSerializersForScheme(scheme *runtime.Scheme, mf json.MetaFactory) []serializerType {
- jsonSerializer := json.NewSerializer(mf, scheme, scheme, false)
- jsonPrettySerializer := json.NewSerializer(mf, scheme, scheme, true)
- yamlSerializer := json.NewYAMLSerializer(mf, scheme, scheme)
- serializers := []serializerType{
- {
- AcceptContentTypes: []string{"application/json"},
- ContentType: "application/json",
- FileExtensions: []string{"json"},
- EncodesAsText: true,
- Serializer: jsonSerializer,
- PrettySerializer: jsonPrettySerializer,
- Framer: json.Framer,
- StreamSerializer: jsonSerializer,
- },
- {
- AcceptContentTypes: []string{"application/yaml"},
- ContentType: "application/yaml",
- FileExtensions: []string{"yaml"},
- EncodesAsText: true,
- Serializer: yamlSerializer,
- },
- }
- for _, fn := range serializerExtensions {
- if serializer, ok := fn(scheme); ok {
- serializers = append(serializers, serializer)
- }
- }
- return serializers
- }
- // CodecFactory provides methods for retrieving codecs and serializers for specific
- // versions and content types.
- type CodecFactory struct {
- scheme *runtime.Scheme
- serializers []serializerType
- universal runtime.Decoder
- accepts []runtime.SerializerInfo
- legacySerializer runtime.Serializer
- }
- // NewCodecFactory provides methods for retrieving serializers for the supported wire formats
- // and conversion wrappers to define preferred internal and external versions. In the future,
- // as the internal version is used less, callers may instead use a defaulting serializer and
- // only convert objects which are shared internally (Status, common API machinery).
- // TODO: allow other codecs to be compiled in?
- // TODO: accept a scheme interface
- func NewCodecFactory(scheme *runtime.Scheme) CodecFactory {
- serializers := newSerializersForScheme(scheme, json.DefaultMetaFactory)
- return newCodecFactory(scheme, serializers)
- }
- // newCodecFactory is a helper for testing that allows a different metafactory to be specified.
- func newCodecFactory(scheme *runtime.Scheme, serializers []serializerType) CodecFactory {
- decoders := make([]runtime.Decoder, 0, len(serializers))
- var accepts []runtime.SerializerInfo
- alreadyAccepted := make(map[string]struct{})
- var legacySerializer runtime.Serializer
- for _, d := range serializers {
- decoders = append(decoders, d.Serializer)
- for _, mediaType := range d.AcceptContentTypes {
- if _, ok := alreadyAccepted[mediaType]; ok {
- continue
- }
- alreadyAccepted[mediaType] = struct{}{}
- info := runtime.SerializerInfo{
- MediaType: d.ContentType,
- EncodesAsText: d.EncodesAsText,
- Serializer: d.Serializer,
- PrettySerializer: d.PrettySerializer,
- }
- if d.StreamSerializer != nil {
- info.StreamSerializer = &runtime.StreamSerializerInfo{
- Serializer: d.StreamSerializer,
- EncodesAsText: d.EncodesAsText,
- Framer: d.Framer,
- }
- }
- accepts = append(accepts, info)
- if mediaType == runtime.ContentTypeJSON {
- legacySerializer = d.Serializer
- }
- }
- }
- if legacySerializer == nil {
- legacySerializer = serializers[0].Serializer
- }
- return CodecFactory{
- scheme: scheme,
- serializers: serializers,
- universal: recognizer.NewDecoder(decoders...),
- accepts: accepts,
- legacySerializer: legacySerializer,
- }
- }
- // SupportedMediaTypes returns the RFC2046 media types that this factory has serializers for.
- func (f CodecFactory) SupportedMediaTypes() []runtime.SerializerInfo {
- return f.accepts
- }
- // LegacyCodec encodes output to a given API versions, and decodes output into the internal form from
- // any recognized source. The returned codec will always encode output to JSON. If a type is not
- // found in the list of versions an error will be returned.
- //
- // This method is deprecated - clients and servers should negotiate a serializer by mime-type and
- // invoke CodecForVersions. Callers that need only to read data should use UniversalDecoder().
- //
- // TODO: make this call exist only in pkg/api, and initialize it with the set of default versions.
- // All other callers will be forced to request a Codec directly.
- func (f CodecFactory) LegacyCodec(version ...schema.GroupVersion) runtime.Codec {
- return versioning.NewDefaultingCodecForScheme(f.scheme, f.legacySerializer, f.universal, schema.GroupVersions(version), runtime.InternalGroupVersioner)
- }
- // UniversalDeserializer can convert any stored data recognized by this factory into a Go object that satisfies
- // runtime.Object. It does not perform conversion. It does not perform defaulting.
- func (f CodecFactory) UniversalDeserializer() runtime.Decoder {
- return f.universal
- }
- // UniversalDecoder returns a runtime.Decoder capable of decoding all known API objects in all known formats. Used
- // by clients that do not need to encode objects but want to deserialize API objects stored on disk. Only decodes
- // objects in groups registered with the scheme. The GroupVersions passed may be used to select alternate
- // versions of objects to return - by default, runtime.APIVersionInternal is used. If any versions are specified,
- // unrecognized groups will be returned in the version they are encoded as (no conversion). This decoder performs
- // defaulting.
- //
- // TODO: the decoder will eventually be removed in favor of dealing with objects in their versioned form
- // TODO: only accept a group versioner
- func (f CodecFactory) UniversalDecoder(versions ...schema.GroupVersion) runtime.Decoder {
- var versioner runtime.GroupVersioner
- if len(versions) == 0 {
- versioner = runtime.InternalGroupVersioner
- } else {
- versioner = schema.GroupVersions(versions)
- }
- return f.CodecForVersions(nil, f.universal, nil, versioner)
- }
- // CodecForVersions creates a codec with the provided serializer. If an object is decoded and its group is not in the list,
- // it will default to runtime.APIVersionInternal. If encode is not specified for an object's group, the object is not
- // converted. If encode or decode are nil, no conversion is performed.
- func (f CodecFactory) CodecForVersions(encoder runtime.Encoder, decoder runtime.Decoder, encode runtime.GroupVersioner, decode runtime.GroupVersioner) runtime.Codec {
- // TODO: these are for backcompat, remove them in the future
- if encode == nil {
- encode = runtime.DisabledGroupVersioner
- }
- if decode == nil {
- decode = runtime.InternalGroupVersioner
- }
- return versioning.NewDefaultingCodecForScheme(f.scheme, encoder, decoder, encode, decode)
- }
- // DecoderToVersion returns a decoder that targets the provided group version.
- func (f CodecFactory) DecoderToVersion(decoder runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder {
- return f.CodecForVersions(nil, decoder, nil, gv)
- }
- // EncoderForVersion returns an encoder that targets the provided group version.
- func (f CodecFactory) EncoderForVersion(encoder runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder {
- return f.CodecForVersions(encoder, nil, gv, nil)
- }
- // DirectCodecFactory provides methods for retrieving "DirectCodec"s, which do not do conversion.
- type DirectCodecFactory struct {
- CodecFactory
- }
- // EncoderForVersion returns an encoder that does not do conversion.
- func (f DirectCodecFactory) EncoderForVersion(serializer runtime.Encoder, version runtime.GroupVersioner) runtime.Encoder {
- return versioning.DirectEncoder{
- Version: version,
- Encoder: serializer,
- ObjectTyper: f.CodecFactory.scheme,
- }
- }
- // DecoderToVersion returns an decoder that does not do conversion. gv is ignored.
- func (f DirectCodecFactory) DecoderToVersion(serializer runtime.Decoder, _ runtime.GroupVersioner) runtime.Decoder {
- return versioning.DirectDecoder{
- Decoder: serializer,
- }
- }
|