mirror of https://github.com/k3s-io/k3s
237 lines
8.9 KiB
Go
237 lines
8.9 KiB
Go
/*
|
|
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/kubernetes/pkg/runtime"
|
|
"k8s.io/kubernetes/pkg/runtime/schema"
|
|
"k8s.io/kubernetes/pkg/runtime/serializer/json"
|
|
"k8s.io/kubernetes/pkg/runtime/serializer/recognizer"
|
|
"k8s.io/kubernetes/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. gv is ignored.
|
|
func (f DirectCodecFactory) EncoderForVersion(serializer runtime.Encoder, _ runtime.GroupVersioner) runtime.Encoder {
|
|
return versioning.DirectEncoder{
|
|
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,
|
|
}
|
|
}
|