Skip to content

Commit

Permalink
add CodecFactoryOptions for codecfactory
Browse files Browse the repository at this point in the history
  • Loading branch information
Chaunceyctx authored and Chaunceyctx committed Jan 8, 2025
1 parent a9b7c2d commit caa3e39
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 29 deletions.
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 @@ -419,11 +422,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
59 changes: 44 additions & 15 deletions pkg/cache/internal/informers.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,26 @@ 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
Test map[bool]map[bool]string
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 +64,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 +91,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 +160,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 +536,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

0 comments on commit caa3e39

Please sign in to comment.