Skip to content

Commit

Permalink
Use runtime.SerializerInfo in place of internal "serializerType".
Browse files Browse the repository at this point in the history
CodecFactory construction uses an unexported struct type named "serializerType" to hold serializer
definitions. There are few differences between it and runtime.SerializerInfo, and they do not appear
to be used anymore. For example, serializerType includes an unused FileExtensions field, and has
distinct ContentType (singular) and AcceptContentTypes (plural) fields instead of
runtime.SerializeInfo's singular MediaType. All remaining uses of serializerType set
AcceptContentTypes to a single-entry slice whose element is equal to its ContentType field.

During construction of a CodecFactory, all serializerType values were already being mechanically
translated into runtime.SerializerInfo values.

Moving to an exported type for serializer definitions makes it easier to expose an option to allow
callers to register their own serializer definitions, which in turn makes it possible to
conditionally include new serializers at runtime (especially behind feature gates).

Kubernetes-commit: 66a14268c591a30090de4f89185b8d880ddbdf18
  • Loading branch information
benluddy authored and k8s-publishing-bot committed Oct 16, 2024
1 parent cfee475 commit 009e863
Showing 1 changed file with 46 additions and 92 deletions.
138 changes: 46 additions & 92 deletions pkg/runtime/serializer/codec_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ limitations under the License.
package serializer

import (
"mime"
"strings"

"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
Expand All @@ -28,41 +25,26 @@ import (
"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
StrictSerializer runtime.Serializer

AcceptStreamContentTypes []string
StreamContentType string

Framer runtime.Framer
StreamSerializer runtime.Serializer
}

func newSerializersForScheme(scheme *runtime.Scheme, mf json.MetaFactory, options CodecFactoryOptions) []serializerType {
func newSerializersForScheme(scheme *runtime.Scheme, mf json.MetaFactory, options CodecFactoryOptions) []runtime.SerializerInfo {
jsonSerializer := json.NewSerializerWithOptions(
mf, scheme, scheme,
json.SerializerOptions{Yaml: false, Pretty: false, Strict: options.Strict},
)
jsonSerializerType := serializerType{
AcceptContentTypes: []string{runtime.ContentTypeJSON},
ContentType: runtime.ContentTypeJSON,
FileExtensions: []string{"json"},
EncodesAsText: true,
Serializer: jsonSerializer,

Framer: json.Framer,
StreamSerializer: jsonSerializer,
jsonSerializerType := runtime.SerializerInfo{
MediaType: runtime.ContentTypeJSON,
MediaTypeType: "application",
MediaTypeSubType: "json",
EncodesAsText: true,
Serializer: jsonSerializer,
StrictSerializer: json.NewSerializerWithOptions(
mf, scheme, scheme,
json.SerializerOptions{Yaml: false, Pretty: false, Strict: true},
),
StreamSerializer: &runtime.StreamSerializerInfo{
EncodesAsText: true,
Serializer: jsonSerializer,
Framer: json.Framer,
},
}
if options.Pretty {
jsonSerializerType.PrettySerializer = json.NewSerializerWithOptions(
Expand All @@ -71,12 +53,6 @@ func newSerializersForScheme(scheme *runtime.Scheme, mf json.MetaFactory, option
)
}

strictJSONSerializer := json.NewSerializerWithOptions(
mf, scheme, scheme,
json.SerializerOptions{Yaml: false, Pretty: false, Strict: true},
)
jsonSerializerType.StrictSerializer = strictJSONSerializer

yamlSerializer := json.NewSerializerWithOptions(
mf, scheme, scheme,
json.SerializerOptions{Yaml: true, Pretty: false, Strict: options.Strict},
Expand All @@ -88,35 +64,31 @@ func newSerializersForScheme(scheme *runtime.Scheme, mf json.MetaFactory, option
protoSerializer := protobuf.NewSerializer(scheme, scheme)
protoRawSerializer := protobuf.NewRawSerializer(scheme, scheme)

serializers := []serializerType{
serializers := []runtime.SerializerInfo{
jsonSerializerType,
{
AcceptContentTypes: []string{runtime.ContentTypeYAML},
ContentType: runtime.ContentTypeYAML,
FileExtensions: []string{"yaml"},
EncodesAsText: true,
Serializer: yamlSerializer,
StrictSerializer: strictYAMLSerializer,
MediaType: runtime.ContentTypeYAML,
MediaTypeType: "application",
MediaTypeSubType: "yaml",
EncodesAsText: true,
Serializer: yamlSerializer,
StrictSerializer: strictYAMLSerializer,
},
{
AcceptContentTypes: []string{runtime.ContentTypeProtobuf},
ContentType: runtime.ContentTypeProtobuf,
FileExtensions: []string{"pb"},
Serializer: protoSerializer,
MediaType: runtime.ContentTypeProtobuf,
MediaTypeType: "application",
MediaTypeSubType: "vnd.kubernetes.protobuf",
Serializer: protoSerializer,
// note, strict decoding is unsupported for protobuf,
// fall back to regular serializing
StrictSerializer: protoSerializer,

Framer: protobuf.LengthDelimitedFramer,
StreamSerializer: protoRawSerializer,
StreamSerializer: &runtime.StreamSerializerInfo{
Serializer: protoRawSerializer,
Framer: protobuf.LengthDelimitedFramer,
},
},
}

for _, fn := range serializerExtensions {
if serializer, ok := fn(scheme); ok {
serializers = append(serializers, serializer)
}
}
return serializers
}

Expand Down Expand Up @@ -184,46 +156,28 @@ func NewCodecFactory(scheme *runtime.Scheme, mutators ...CodecFactoryOptionsMuta
}

// newCodecFactory is a helper for testing that allows a different metafactory to be specified.
func newCodecFactory(scheme *runtime.Scheme, serializers []serializerType) CodecFactory {
func newCodecFactory(scheme *runtime.Scheme, serializers []runtime.SerializerInfo) 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,
StrictSerializer: d.StrictSerializer,
}

mediaType, _, err := mime.ParseMediaType(info.MediaType)
if err != nil {
panic(err)
}
parts := strings.SplitN(mediaType, "/", 2)
info.MediaTypeType = parts[0]
info.MediaTypeSubType = parts[1]

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 _, ok := alreadyAccepted[d.MediaType]; ok {
continue
}
alreadyAccepted[d.MediaType] = struct{}{}

acceptedSerializerShallowCopy := d
if d.StreamSerializer != nil {
cloned := *d.StreamSerializer
acceptedSerializerShallowCopy.StreamSerializer = &cloned
}
accepts = append(accepts, acceptedSerializerShallowCopy)

if d.MediaType == runtime.ContentTypeJSON {
legacySerializer = d.Serializer
}
}
if legacySerializer == nil {
Expand Down

0 comments on commit 009e863

Please sign in to comment.