Explicit checking for supported and unsupported types, add test

This commit is contained in:
Richa Banker
2026-01-06 20:00:58 -08:00
parent e179f38cb8
commit a9dec0cfdd
4 changed files with 113 additions and 27 deletions

View File

@@ -46,6 +46,7 @@ const (
// from the supported media types list, so error messages only show actually supported types.
type flagzCodecFactory struct {
serializer.CodecFactory
supportedMediaTypes []runtime.SerializerInfo
}
type mux interface {
@@ -64,9 +65,19 @@ func Install(m mux, componentName string, flagReader Reader, opts ...Option) {
scheme := runtime.NewScheme()
utilruntime.Must(v1alpha1.AddToScheme(scheme))
filteredCodecFactory, err := newFlagzCodecFactory(scheme, componentName, reg.reader)
if err != nil {
utilruntime.HandleError(err)
}
m.Handle(DefaultFlagzPath, handleFlagz(componentName, reg, filteredCodecFactory, negotiate.FlagzEndpointRestrictions{}))
}
// newFlagzCodecFactory creates a codec factory with the standard serializers for flagz,
// filtering out unsupported media types (e.g., protobuf).
func newFlagzCodecFactory(scheme *runtime.Scheme, componentName string, flagReader Reader) (*flagzCodecFactory, error) {
codecFactoryOpts := []serializer.CodecFactoryOptionsMutator{
serializer.WithSerializer(func(_ runtime.ObjectCreater, _ runtime.ObjectTyper) runtime.SerializerInfo {
textSerializer := flagzTextSerializer{componentName, reg.reader}
textSerializer := flagzTextSerializer{componentName, flagReader}
return runtime.SerializerInfo{
MediaType: "text/plain",
MediaTypeType: "text",
@@ -83,21 +94,36 @@ func Install(m mux, componentName string, flagReader Reader, opts ...Option) {
}
codecFactory := serializer.NewCodecFactory(scheme, codecFactoryOpts...)
// Wrap to filter out unsupported media types (e.g., protobuf)
filteredCodecFactory := &flagzCodecFactory{codecFactory}
m.Handle(DefaultFlagzPath, handleFlagz(componentName, reg, filteredCodecFactory, negotiate.FlagzEndpointRestrictions{}))
allTypes := codecFactory.SupportedMediaTypes()
filtered := make([]runtime.SerializerInfo, 0, len(allTypes))
var unknownTypes []string
for _, info := range allTypes {
switch info.MediaType {
// Supported media types
case "text/plain", runtime.ContentTypeJSON, runtime.ContentTypeYAML, runtime.ContentTypeCBOR:
filtered = append(filtered, info)
// Unsupported media types
case runtime.ContentTypeProtobuf:
continue
default:
unknownTypes = append(unknownTypes, info.MediaType)
}
}
var err error
if len(unknownTypes) > 0 {
err = fmt.Errorf("flagz: unknown media type(s) %v, excluding from supported types", unknownTypes)
}
return &flagzCodecFactory{
CodecFactory: codecFactory,
supportedMediaTypes: filtered,
}, err
}
func (f *flagzCodecFactory) SupportedMediaTypes() []runtime.SerializerInfo {
allTypes := f.CodecFactory.SupportedMediaTypes()
filtered := make([]runtime.SerializerInfo, 0, len(allTypes))
for _, info := range allTypes {
if info.MediaType == runtime.ContentTypeProtobuf {
continue
}
filtered = append(filtered, info)
}
return filtered
return f.supportedMediaTypes
}
func handleFlagz(componentName string, reg *registry, serializer runtime.NegotiatedSerializer, restrictions negotiate.FlagzEndpointRestrictions) http.HandlerFunc {

View File

@@ -27,7 +27,9 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/spf13/pflag"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
cbor "k8s.io/apimachinery/pkg/runtime/serializer/cbor/direct"
"k8s.io/apimachinery/pkg/runtime"
cbordirect "k8s.io/apimachinery/pkg/runtime/serializer/cbor/direct"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apiserver/pkg/features"
v1alpha1 "k8s.io/apiserver/pkg/server/flagz/api/v1alpha1"
utilfeature "k8s.io/apiserver/pkg/util/feature"
@@ -306,7 +308,7 @@ func unmarshalResponse(t *testing.T, contentType string, body []byte, got *v1alp
t.Fatalf("unexpected error while unmarshalling YAML response: %v", err)
}
case strings.Contains(contentType, "application/cbor"):
if err := cbor.Unmarshal(body, got); err != nil {
if err := cbordirect.Unmarshal(body, got); err != nil {
t.Fatalf("unexpected error while unmarshalling CBOR response: %v", err)
}
default:
@@ -360,3 +362,18 @@ func TestCache(t *testing.T) {
t.Errorf("Unexpected diff on cached response (-want,+got):\n%s", diff)
}
}
// TestNewFlagzCodecFactory ensures all media types in the codec factory
// are explicitly handled. If this test fails, a new media type was added
// to the codec factory and needs to be explicitly added to the supported
// or unsupported list in newFlagzCodecFactory.
func TestNewFlagzCodecFactory(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CBORServingAndStorage, true)
scheme := runtime.NewScheme()
utilruntime.Must(v1alpha1.AddToScheme(scheme))
_, err := newFlagzCodecFactory(scheme, "", nil)
if err != nil {
t.Fatalf("unknown media type(s) detected - update newFlagzCodecFactory to explicitly handle them: %v", err)
}
}

View File

@@ -67,6 +67,7 @@ Warning: This endpoint is not meant to be machine parseable, has no formatting c
// from the supported media types list, so error messages only show actually supported types.
type statuszCodecFactory struct {
serializer.CodecFactory
supportedMediaTypes []runtime.SerializerInfo
}
type mux interface {
@@ -89,6 +90,16 @@ func NewRegistry(effectiveVersion compatibility.EffectiveVersion, opts ...Option
func Install(m mux, componentName string, reg statuszRegistry) {
scheme := runtime.NewScheme()
utilruntime.Must(v1alpha1.AddToScheme(scheme))
filteredCodecFactory, err := newStatuszCodecFactory(scheme, componentName, reg)
if err != nil {
utilruntime.HandleError(err)
}
m.Handle(DefaultStatuszPath, handleStatusz(componentName, reg, filteredCodecFactory, negotiate.StatuszEndpointRestrictions{}))
}
// newStatuszCodecFactory creates a codec factory with the standard serializers for statusz,
// filtering out unsupported media types (e.g., protobuf).
func newStatuszCodecFactory(scheme *runtime.Scheme, componentName string, reg statuszRegistry) (*statuszCodecFactory, error) {
codecFactoryOpts := []serializer.CodecFactoryOptionsMutator{
serializer.WithSerializer(func(_ runtime.ObjectCreater, _ runtime.ObjectTyper) runtime.SerializerInfo {
textSerializer := statuszTextSerializer{componentName, reg}
@@ -108,21 +119,36 @@ func Install(m mux, componentName string, reg statuszRegistry) {
}
codecFactory := serializer.NewCodecFactory(scheme, codecFactoryOpts...)
// Wrap to filter out unsupported media types (e.g., protobuf)
filteredCodecFactory := &statuszCodecFactory{codecFactory}
m.Handle(DefaultStatuszPath, handleStatusz(componentName, reg, filteredCodecFactory, negotiate.StatuszEndpointRestrictions{}))
allTypes := codecFactory.SupportedMediaTypes()
filtered := make([]runtime.SerializerInfo, 0, len(allTypes))
var unknownTypes []string
for _, info := range allTypes {
switch info.MediaType {
// Supported media types
case "text/plain", runtime.ContentTypeJSON, runtime.ContentTypeYAML, runtime.ContentTypeCBOR:
filtered = append(filtered, info)
// Unsupported media types
case runtime.ContentTypeProtobuf:
continue
default:
unknownTypes = append(unknownTypes, info.MediaType)
}
}
var err error
if len(unknownTypes) > 0 {
err = fmt.Errorf("statusz: unknown media type(s) %v, excluding from supported types", unknownTypes)
}
return &statuszCodecFactory{
CodecFactory: codecFactory,
supportedMediaTypes: filtered,
}, err
}
func (f *statuszCodecFactory) SupportedMediaTypes() []runtime.SerializerInfo {
allTypes := f.CodecFactory.SupportedMediaTypes()
filtered := make([]runtime.SerializerInfo, 0, len(allTypes))
for _, info := range allTypes {
if info.MediaType == runtime.ContentTypeProtobuf {
continue
}
filtered = append(filtered, info)
}
return filtered
return f.supportedMediaTypes
}
func handleStatusz(componentName string, reg statuszRegistry, serializer runtime.NegotiatedSerializer, restrictions negotiate.StatuszEndpointRestrictions) http.HandlerFunc {

View File

@@ -27,7 +27,9 @@ import (
"github.com/google/go-cmp/cmp"
"k8s.io/apimachinery/pkg/runtime"
cbor "k8s.io/apimachinery/pkg/runtime/serializer/cbor/direct"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/version"
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/apiserver/pkg/features"
@@ -443,3 +445,18 @@ func timeEqual() cmp.Option {
return expectedTime.Truncate(time.Second).Equal(actualTime.Truncate(time.Second))
})
}
// TestNewStatuszCodecFactory ensures all media types in the codec factory
// are explicitly handled. If this test fails, a new media type was added
// to the codec factory and needs to be explicitly added to the supported
// or unsupported list in newStatuszCodecFactory.
func TestNewStatuszCodecFactory(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CBORServingAndStorage, true)
scheme := runtime.NewScheme()
utilruntime.Must(v1alpha1.AddToScheme(scheme))
_, err := newStatuszCodecFactory(scheme, "", nil)
if err != nil {
t.Fatalf("unknown media type(s) detected - update newStatuszCodecFactory to explicitly handle them: %v", err)
}
}