Skip to content

Commit dc13dbf

Browse files
committed
Added a selectively-caching delegating client
Avoid caching Secrets or ConfigMaps Based on changes to the upstream controller-runtime: kubernetes-sigs/controller-runtime#1249
1 parent 84f4eb9 commit dc13dbf

File tree

4 files changed

+135
-20
lines changed

4 files changed

+135
-20
lines changed

bootstrap/kubeadm/main.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"time"
2626

2727
"github.com/spf13/pflag"
28+
corev1 "k8s.io/api/core/v1"
2829
"k8s.io/apimachinery/pkg/runtime"
2930
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
3031
"k8s.io/client-go/rest"
@@ -137,8 +138,23 @@ func main() {
137138
RetryPeriod: &leaderElectionRetryPeriod,
138139
Namespace: watchNamespace,
139140
SyncPeriod: &syncPeriod,
140-
NewClient: util.ManagerCachelessClientFunc,
141-
Port: webhookPort,
141+
NewClient: func(cache cache.Cache, config *rest.Config, options client.Options) (client.Client, error) {
142+
c, err := client.New(config, options)
143+
if err != nil {
144+
return nil, err
145+
}
146+
147+
return util.NewSelectiveDelegatingClient(util.NewSelectiveDelegatingClientInput{
148+
CacheReader: cache,
149+
Client: c,
150+
Scheme: options.Scheme,
151+
UncachedObjects: []runtime.Object{
152+
&corev1.Secret{},
153+
&corev1.ConfigMap{},
154+
},
155+
})
156+
},
157+
Port: webhookPort,
142158
})
143159
if err != nil {
144160
setupLog.Error(err, "unable to start manager")

controlplane/kubeadm/main.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"time"
2626

2727
"github.com/spf13/pflag"
28+
corev1 "k8s.io/api/core/v1"
2829
"k8s.io/apimachinery/pkg/runtime"
2930
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
3031
"k8s.io/client-go/rest"
@@ -129,8 +130,23 @@ func main() {
129130
RetryPeriod: &leaderElectionRetryPeriod,
130131
Namespace: watchNamespace,
131132
SyncPeriod: &syncPeriod,
132-
NewClient: util.ManagerCachelessClientFunc,
133-
Port: webhookPort,
133+
NewClient: func(cache cache.Cache, config *rest.Config, options client.Options) (client.Client, error) {
134+
c, err := client.New(config, options)
135+
if err != nil {
136+
return nil, err
137+
}
138+
139+
return util.NewSelectiveDelegatingClient(util.NewSelectiveDelegatingClientInput{
140+
CacheReader: cache,
141+
Client: c,
142+
Scheme: options.Scheme,
143+
UncachedObjects: []runtime.Object{
144+
&corev1.Secret{},
145+
&corev1.ConfigMap{},
146+
},
147+
})
148+
},
149+
Port: webhookPort,
134150
})
135151
if err != nil {
136152
setupLog.Error(err, "unable to start manager")

main.go

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ import (
2424
"time"
2525

2626
"github.com/spf13/pflag"
27+
corev1 "k8s.io/api/core/v1"
2728
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
2829
"k8s.io/apimachinery/pkg/runtime"
2930
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
31+
"k8s.io/client-go/rest"
3032
"k8s.io/klog"
3133
"k8s.io/klog/klogr"
3234
clusterv1alpha2 "sigs.k8s.io/cluster-api/api/v1alpha2"
@@ -41,6 +43,8 @@ import (
4143
"sigs.k8s.io/cluster-api/feature"
4244
"sigs.k8s.io/cluster-api/util"
4345
ctrl "sigs.k8s.io/controller-runtime"
46+
"sigs.k8s.io/controller-runtime/pkg/cache"
47+
"sigs.k8s.io/controller-runtime/pkg/client"
4448
"sigs.k8s.io/controller-runtime/pkg/controller"
4549
"sigs.k8s.io/controller-runtime/pkg/healthz"
4650
// +kubebuilder:scaffold:imports
@@ -155,16 +159,31 @@ func main() {
155159
}
156160

157161
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
158-
Scheme: scheme,
159-
MetricsBindAddress: metricsAddr,
160-
LeaderElection: enableLeaderElection,
161-
LeaderElectionID: "controller-leader-election-capi",
162-
LeaseDuration: &leaderElectionLeaseDuration,
163-
RenewDeadline: &leaderElectionRenewDeadline,
164-
RetryPeriod: &leaderElectionRetryPeriod,
165-
Namespace: watchNamespace,
166-
SyncPeriod: &syncPeriod,
167-
NewClient: util.ManagerCachelessClientFunc,
162+
Scheme: scheme,
163+
MetricsBindAddress: metricsAddr,
164+
LeaderElection: enableLeaderElection,
165+
LeaderElectionID: "controller-leader-election-capi",
166+
LeaseDuration: &leaderElectionLeaseDuration,
167+
RenewDeadline: &leaderElectionRenewDeadline,
168+
RetryPeriod: &leaderElectionRetryPeriod,
169+
Namespace: watchNamespace,
170+
SyncPeriod: &syncPeriod,
171+
NewClient: func(cache cache.Cache, config *rest.Config, options client.Options) (client.Client, error) {
172+
c, err := client.New(config, options)
173+
if err != nil {
174+
return nil, err
175+
}
176+
177+
return util.NewSelectiveDelegatingClient(util.NewSelectiveDelegatingClientInput{
178+
CacheReader: cache,
179+
Client: c,
180+
Scheme: options.Scheme,
181+
UncachedObjects: []runtime.Object{
182+
&corev1.Secret{},
183+
&corev1.ConfigMap{},
184+
},
185+
})
186+
},
168187
Port: webhookPort,
169188
HealthProbeBindAddress: healthAddr,
170189
})

util/util.go

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -703,12 +703,6 @@ func ManagerDelegatingClientFunc(cache cache.Cache, config *rest.Config, options
703703
}, nil
704704
}
705705

706-
// ManagerCachelessClientFunc returns a manager.NewClientFunc to be used when creating
707-
// a new controller runtime manager.
708-
func ManagerCachelessClientFunc(cache cache.Cache, config *rest.Config, options client.Options) (client.Client, error) {
709-
return client.New(config, options)
710-
}
711-
712706
// LowestNonZeroResult compares two reconciliation results
713707
// and returns the one with lowest requeue time.
714708
func LowestNonZeroResult(i, j ctrl.Result) ctrl.Result {
@@ -727,3 +721,73 @@ func LowestNonZeroResult(i, j ctrl.Result) ctrl.Result {
727721
return j
728722
}
729723
}
724+
725+
// NewSelectiveDelegatingClientInput encapsulates the input parameters to create
726+
// a new selective delegating client
727+
type NewSelectiveDelegatingClientInput struct {
728+
CacheReader client.Reader
729+
Client client.Client
730+
UncachedObjects []runtime.Object
731+
Scheme *runtime.Scheme
732+
}
733+
734+
type selectiveDelegatingReader struct {
735+
CacheReader client.Reader
736+
ClientReader client.Reader
737+
738+
uncachedGVKs map[schema.GroupVersionKind]struct{}
739+
scheme *runtime.Scheme
740+
}
741+
742+
func (d *selectiveDelegatingReader) isUncached(obj runtime.Object) (bool, error) {
743+
gvk, err := apiutil.GVKForObject(obj, d.scheme)
744+
if err != nil {
745+
return false, err
746+
}
747+
_, isUncached := d.uncachedGVKs[gvk]
748+
_, isUnstructured := obj.(*unstructured.Unstructured)
749+
_, isUnstructuredList := obj.(*unstructured.UnstructuredList)
750+
return isUncached || isUnstructured || isUnstructuredList, nil
751+
}
752+
753+
// Get retrieves an obj for a given object key from the Kubernetes Cluster.
754+
func (d *selectiveDelegatingReader) Get(ctx context.Context, key client.ObjectKey, obj runtime.Object) error {
755+
if isUncached, err := d.isUncached(obj); err != nil {
756+
return err
757+
} else if isUncached {
758+
return d.ClientReader.Get(ctx, key, obj)
759+
}
760+
return d.CacheReader.Get(ctx, key, obj)
761+
}
762+
763+
// List retrieves list of objects for a given namespace and list options.
764+
func (d *selectiveDelegatingReader) List(ctx context.Context, list runtime.Object, opts ...client.ListOption) error {
765+
if isUncached, err := d.isUncached(list); err != nil {
766+
return err
767+
} else if isUncached {
768+
return d.ClientReader.List(ctx, list, opts...)
769+
}
770+
return d.CacheReader.List(ctx, list, opts...)
771+
}
772+
773+
func NewSelectiveDelegatingClient(in NewSelectiveDelegatingClientInput) (client.Client, error) {
774+
uncachedGVKs := map[schema.GroupVersionKind]struct{}{}
775+
for _, obj := range in.UncachedObjects {
776+
gvk, err := apiutil.GVKForObject(obj, in.Scheme)
777+
if err != nil {
778+
return nil, err
779+
}
780+
uncachedGVKs[gvk] = struct{}{}
781+
}
782+
783+
return &client.DelegatingClient{
784+
Reader: &selectiveDelegatingReader{
785+
CacheReader: in.CacheReader,
786+
ClientReader: in.Client,
787+
scheme: in.Scheme,
788+
uncachedGVKs: uncachedGVKs,
789+
},
790+
Writer: in.Client,
791+
StatusClient: in.Client,
792+
}, nil
793+
}

0 commit comments

Comments
 (0)