Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨add CodecFactoryOptionsMutators for codecfactory #3048

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions pkg/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ type Options struct {
// Scheme is the scheme to use for mapping objects to GroupVersionKinds
Scheme *runtime.Scheme

// CodecFactoryOptionsByObject are used to indicate whether enable strict/pretty mode of codecFactory for specific object
CodecFactoryOptionsByObject map[client.Object]client.CodecFactoryOptions

// Mapper is the RESTMapper to use for mapping GroupVersionKinds to Resources
Mapper meta.RESTMapper

Expand Down Expand Up @@ -420,11 +423,12 @@ func newCache(restConfig *rest.Config, opts Options) newCacheFunc {
return &informerCache{
scheme: opts.Scheme,
Informers: internal.NewInformers(restConfig, &internal.InformersOpts{
HTTPClient: opts.HTTPClient,
Scheme: opts.Scheme,
Mapper: opts.Mapper,
ResyncPeriod: *opts.SyncPeriod,
Namespace: namespace,
HTTPClient: opts.HTTPClient,
Scheme: opts.Scheme,
CodecFactoryOptionsByObject: opts.CodecFactoryOptionsByObject,
Mapper: opts.Mapper,
ResyncPeriod: *opts.SyncPeriod,
Namespace: namespace,
Selector: internal.Selector{
Label: config.LabelSelector,
Field: config.FieldSelector,
Expand Down
58 changes: 43 additions & 15 deletions pkg/cache/internal/informers.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,25 @@ import (
"k8s.io/client-go/metadata"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
"sigs.k8s.io/controller-runtime/pkg/internal/syncs"
)

// InformersOpts configures an InformerMap.
type InformersOpts struct {
HTTPClient *http.Client
Scheme *runtime.Scheme
Mapper meta.RESTMapper
ResyncPeriod time.Duration
Namespace string
NewInformer func(cache.ListerWatcher, runtime.Object, time.Duration, cache.Indexers) cache.SharedIndexInformer
Selector Selector
Transform cache.TransformFunc
UnsafeDisableDeepCopy bool
EnableWatchBookmarks bool
WatchErrorHandler cache.WatchErrorHandler
HTTPClient *http.Client
Scheme *runtime.Scheme
CodecFactoryOptionsByObject map[client.Object]client.CodecFactoryOptions
Mapper meta.RESTMapper
ResyncPeriod time.Duration
Namespace string
NewInformer func(cache.ListerWatcher, runtime.Object, time.Duration, cache.Indexers) cache.SharedIndexInformer
Selector Selector
Transform cache.TransformFunc
UnsafeDisableDeepCopy bool
EnableWatchBookmarks bool
WatchErrorHandler cache.WatchErrorHandler
}

// NewInformers creates a new InformersMap that can create informers under the hood.
Expand All @@ -61,6 +63,23 @@ func NewInformers(config *rest.Config, options *InformersOpts) *Informers {
if options.NewInformer != nil {
newInformer = options.NewInformer
}

codecFactories := make(map[schema.GroupVersionKind]serializer.CodecFactory)
for obj, codecFactoryOptions := range options.CodecFactoryOptionsByObject {
gvk, err := apiutil.GVKForObject(obj, options.Scheme)
if err != nil {
continue
}
var mutators []serializer.CodecFactoryOptionsMutator
if codecFactoryOptions.Strict {
mutators = append(mutators, serializer.EnableStrict)
}
if codecFactoryOptions.Pretty {
mutators = append(mutators, serializer.EnablePretty)
}
codecFactories[gvk] = serializer.NewCodecFactory(options.Scheme, mutators...)
}

return &Informers{
config: config,
httpClient: options.HTTPClient,
Expand All @@ -71,7 +90,8 @@ func NewInformers(config *rest.Config, options *InformersOpts) *Informers {
Unstructured: make(map[schema.GroupVersionKind]*Cache),
Metadata: make(map[schema.GroupVersionKind]*Cache),
},
codecs: serializer.NewCodecFactory(options.Scheme),
defaultCodecs: serializer.NewCodecFactory(options.Scheme),
codecsByObject: codecFactories,
paramCodec: runtime.NewParameterCodec(options.Scheme),
resync: options.ResyncPeriod,
startWait: make(chan struct{}),
Expand Down Expand Up @@ -139,8 +159,11 @@ type Informers struct {
// tracker tracks informers keyed by their type and groupVersionKind
tracker tracker

// codecs is used to create a new REST client
codecs serializer.CodecFactory
// codecsByObject is used to override defaultCodecs for specific GroupVersionKind(object)
codecsByObject map[schema.GroupVersionKind]serializer.CodecFactory

// defaultCodecs is used to create a new REST client
defaultCodecs serializer.CodecFactory

// paramCodec is used by list and watch
paramCodec runtime.ParameterCodec
Expand Down Expand Up @@ -512,7 +535,12 @@ func (ip *Informers) makeListWatcher(gvk schema.GroupVersionKind, obj runtime.Ob
// Structured.
//
default:
client, err := apiutil.RESTClientForGVK(gvk, false, ip.config, ip.codecs, ip.httpClient)
codecFactory := ip.defaultCodecs
if override, ok := ip.codecsByObject[gvk]; ok {
codecFactory = override
}

client, err := apiutil.RESTClientForGVK(gvk, false, ip.config, codecFactory, ip.httpClient)
if err != nil {
return nil, err
}
Expand Down
40 changes: 34 additions & 6 deletions pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ type Options struct {
// Scheme, if provided, will be used to map go structs to GroupVersionKinds
Scheme *runtime.Scheme

// CodecFactoryOptionsByObject, if provided, will be used to indicate whether enable strict/pretty mode of CodecFactory for specific obj
CodecFactoryOptionsByObject map[Object]CodecFactoryOptions

// Mapper, if provided, will be used to map GroupVersionKinds to Resources
Mapper meta.RESTMapper

Expand All @@ -68,6 +71,15 @@ type CacheOptions struct {
Unstructured bool
}

// CodecFactoryOptions holds the options for configuring CodecFactory behavior which is same as serializer.CodecFactoryOptions
type CodecFactoryOptions struct {
// Strict configures all serializers in strict mode
Strict bool
// Pretty includes a pretty serializer along with the non-pretty one
Pretty bool
// drop serializers field in serializer.CodecFactoryOptions just for passing go-apidiff test
}

// NewClientFunc allows a user to define how to create a client.
type NewClientFunc func(config *rest.Config, options Options) (Client, error)

Expand Down Expand Up @@ -145,13 +157,29 @@ func newClient(config *rest.Config, options Options) (*client, error) {
}
}

resources := &clientRestResources{
httpClient: options.HTTPClient,
config: config,
scheme: options.Scheme,
mapper: options.Mapper,
codecs: serializer.NewCodecFactory(options.Scheme),
codecFactories := make(map[schema.GroupVersionKind]serializer.CodecFactory)
for obj, codecFactoryOptions := range options.CodecFactoryOptionsByObject {
gvk, err := apiutil.GVKForObject(obj, options.Scheme)
if err != nil {
continue
}
var mutators []serializer.CodecFactoryOptionsMutator
if codecFactoryOptions.Strict {
mutators = append(mutators, serializer.EnableStrict)
}
if codecFactoryOptions.Pretty {
mutators = append(mutators, serializer.EnablePretty)
}
codecFactories[gvk] = serializer.NewCodecFactory(options.Scheme, mutators...)
}

resources := &clientRestResources{
httpClient: options.HTTPClient,
config: config,
scheme: options.Scheme,
mapper: options.Mapper,
defaultCodecs: serializer.NewCodecFactory(options.Scheme),
codecsByObject: codecFactories,
structuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta),
unstructuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta),
}
Expand Down
13 changes: 10 additions & 3 deletions pkg/client/client_rest_resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,11 @@ type clientRestResources struct {
// mapper maps GroupVersionKinds to Resources
mapper meta.RESTMapper

// codecs are used to create a REST client for a gvk
codecs serializer.CodecFactory
// codecsByObject is used to override defaultCodecs for specific GroupVersionKind(object)
codecsByObject map[schema.GroupVersionKind]serializer.CodecFactory

// defaultCodecs are used to create a REST client for a gvk
defaultCodecs serializer.CodecFactory

// structuredResourceByType stores structured type metadata
structuredResourceByType map[schema.GroupVersionKind]*resourceMeta
Expand All @@ -62,7 +65,11 @@ func (c *clientRestResources) newResource(gvk schema.GroupVersionKind, isList, i
gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
}

client, err := apiutil.RESTClientForGVK(gvk, isUnstructured, c.config, c.codecs, c.httpClient)
codecFactory := c.defaultCodecs
if override, ok := c.codecsByObject[gvk]; ok {
codecFactory = override
}
client, err := apiutil.RESTClientForGVK(gvk, isUnstructured, c.config, codecFactory, c.httpClient)
if err != nil {
return nil, err
}
Expand Down
Loading