Skip to content

Commit fc41bf6

Browse files
committed
Add watch-filter label
1 parent 6db673f commit fc41bf6

15 files changed

+243
-33
lines changed

api/v1alpha4/common_types.go

+6
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ const (
5353
// on the reconciled object.
5454
PausedAnnotation = "cluster.x-k8s.io/paused"
5555

56+
// WatchLabel is a label othat can be applied to any Cluster API object.
57+
//
58+
// Controllers which allow for selective reconciliation may check this label and proceed
59+
// with reconciliation of the object only if this label and a configured value is present.
60+
WatchLabel = "cluster.x-k8s.io/watch-filter"
61+
5662
// DeleteMachineAnnotation marks control plane and worker nodes that will be given priority for deletion
5763
// when KCP or a machineset scales down. This annotation is given top priority on all delete policies.
5864
DeleteMachineAnnotation = "cluster.x-k8s.io/delete-machine"

controllers/cluster_controller.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ const (
6363

6464
// ClusterReconciler reconciles a Cluster object
6565
type ClusterReconciler struct {
66-
Client client.Client
66+
Client client.Client
67+
WatchFilterValue string
6768

6869
restConfig *rest.Config
6970
recorder record.EventRecorder
@@ -78,7 +79,7 @@ func (r *ClusterReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manag
7879
handler.EnqueueRequestsFromMapFunc(r.controlPlaneMachineToCluster),
7980
).
8081
WithOptions(options).
81-
WithEventFilter(predicates.ResourceNotPaused(ctrl.LoggerFrom(ctx))).
82+
WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)).
8283
Build(r)
8384

8485
if err != nil {

controllers/machine_controller.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,9 @@ var (
7373

7474
// MachineReconciler reconciles a Machine object
7575
type MachineReconciler struct {
76-
Client client.Client
77-
Tracker *remote.ClusterCacheTracker
76+
Client client.Client
77+
Tracker *remote.ClusterCacheTracker
78+
WatchFilterValue string
7879

7980
controller controller.Controller
8081
restConfig *rest.Config
@@ -91,7 +92,7 @@ func (r *MachineReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manag
9192
controller, err := ctrl.NewControllerManagedBy(mgr).
9293
For(&clusterv1.Machine{}).
9394
WithOptions(options).
94-
WithEventFilter(predicates.ResourceNotPaused(ctrl.LoggerFrom(ctx))).
95+
WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)).
9596
Build(r)
9697
if err != nil {
9798
return errors.Wrap(err, "failed setting up with a controller manager")

controllers/machinedeployment_controller.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ var (
5353

5454
// MachineDeploymentReconciler reconciles a MachineDeployment object
5555
type MachineDeploymentReconciler struct {
56-
Client client.Client
56+
Client client.Client
57+
WatchFilterValue string
5758

5859
recorder record.EventRecorder
5960
restConfig *rest.Config
@@ -73,7 +74,7 @@ func (r *MachineDeploymentReconciler) SetupWithManager(ctx context.Context, mgr
7374
handler.EnqueueRequestsFromMapFunc(r.MachineSetToDeployments),
7475
).
7576
WithOptions(options).
76-
WithEventFilter(predicates.ResourceNotPaused(ctrl.LoggerFrom(ctx))).
77+
WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)).
7778
Build(r)
7879
if err != nil {
7980
return errors.Wrap(err, "failed setting up with a controller manager")

controllers/machinehealthcheck_controller.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,9 @@ const (
6565

6666
// MachineHealthCheckReconciler reconciles a MachineHealthCheck object
6767
type MachineHealthCheckReconciler struct {
68-
Client client.Client
69-
Tracker *remote.ClusterCacheTracker
68+
Client client.Client
69+
Tracker *remote.ClusterCacheTracker
70+
WatchFilterValue string
7071

7172
controller controller.Controller
7273
recorder record.EventRecorder
@@ -80,7 +81,7 @@ func (r *MachineHealthCheckReconciler) SetupWithManager(ctx context.Context, mgr
8081
handler.EnqueueRequestsFromMapFunc(r.machineToMachineHealthCheck),
8182
).
8283
WithOptions(options).
83-
WithEventFilter(predicates.ResourceNotPaused(ctrl.LoggerFrom(ctx))).
84+
WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)).
8485
Build(r)
8586
if err != nil {
8687
return errors.Wrap(err, "failed setting up with a controller manager")

controllers/machineset_controller.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,9 @@ var (
6767

6868
// MachineSetReconciler reconciles a MachineSet object
6969
type MachineSetReconciler struct {
70-
Client client.Client
71-
Tracker *remote.ClusterCacheTracker
70+
Client client.Client
71+
Tracker *remote.ClusterCacheTracker
72+
WatchFilterValue string
7273

7374
recorder record.EventRecorder
7475
restConfig *rest.Config
@@ -88,7 +89,7 @@ func (r *MachineSetReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Ma
8889
handler.EnqueueRequestsFromMapFunc(r.MachineToMachineSets),
8990
).
9091
WithOptions(options).
91-
WithEventFilter(predicates.ResourceNotPaused(ctrl.LoggerFrom(ctx))).
92+
WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)).
9293
Build(r)
9394
if err != nil {
9495
return errors.Wrap(err, "failed setting up with a controller manager")

docs/book/src/developer/architecture/controllers/support-multiple-instances.md

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ in case the above limitations/extra complexity are acceptable for them.
2424
In order to make it possible for users to deploy multiple instances of the same provider:
2525

2626
- Providers MUST support the `--namespace` flag in their controllers.
27+
- Providers MUST support the `--watch-filter` flag in their controllers.
2728

2829
⚠️ Users selecting this deployment model, please be aware:
2930

docs/book/src/developer/providers/v1alpha3-to-v1alpha4.md

+25-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ Provider's `/config` folder has the same structure of `/config` folder in CAPI
8080
- ../manager
8181
```
8282
- Remove the `patchesStrategicMerge` list
83-
- Copy the `vars` list into a temporary file to be used later in the process
83+
- Copy the `vars` list into a temporary file to be used later in the process
8484
- Remove the `vars` list
8585
1. Edit the `config/webhook/kustomizeconfig.yaml` file:
8686
- In the `varReference:` list, remove the item with `kind: Deployment`
@@ -181,3 +181,27 @@ with `cert-manager.io/v1`
181181
group: cert-manager.io
182182
version: v1
183183
```
184+
## Support the cluster.x-k8s.io/watch-filter label and watch-filter flag.
185+
186+
- A new label `cluster.x-k8s.io/watch-filter` provides the ability to filter the controllers to only reconcile objects with a specific label.
187+
- A new flag `watch-filter` enables users to specify the label value for the `cluster.x-k8s.io/watch-filter` label on controller boot.
188+
- The flag which enables users to set the flag value can be structured like this:
189+
```go
190+
fs.StringVar(&watchFilterValue, "watch-filter", "", fmt.Sprintf("Label value that the controller watches to reconcile cluster-api objects. Label key is always %s. If unspecified, the controller watches for all cluster-api objects.", clusterv1.WatchLabel))
191+
```
192+
- The `ResourceNotPausedAndHasFilterLabel` predicate is a useful helper to check for the pause annotation and the filter label easily:
193+
```go
194+
c, err := ctrl.NewControllerManagedBy(mgr).
195+
For(&clusterv1.MachineSet{}).
196+
Owns(&clusterv1.Machine{}).
197+
Watches(
198+
&source.Kind{Type: &clusterv1.Machine{}},
199+
handler.EnqueueRequestsFromMapFunc(r.MachineToMachineSets),
200+
).
201+
WithOptions(options).
202+
WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)).
203+
Build(r)
204+
if err != nil {
205+
return errors.Wrap(err, "failed setting up with a controller manager")
206+
}
207+
```

exp/addons/controllers/clusterresourceset_controller.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,9 @@ var (
6060

6161
// ClusterResourceSetReconciler reconciles a ClusterResourceSet object
6262
type ClusterResourceSetReconciler struct {
63-
Client client.Client
64-
Tracker *remote.ClusterCacheTracker
63+
Client client.Client
64+
Tracker *remote.ClusterCacheTracker
65+
WatchFilterValue string
6566
}
6667

6768
func (r *ClusterResourceSetReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error {
@@ -88,7 +89,7 @@ func (r *ClusterResourceSetReconciler) SetupWithManager(ctx context.Context, mgr
8889
),
8990
).
9091
WithOptions(options).
91-
WithEventFilter(predicates.ResourceNotPaused(ctrl.LoggerFrom(ctx))).
92+
WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)).
9293
Complete(r)
9394

9495
if err != nil {

exp/addons/controllers/clusterresourcesetbinding_controller.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ import (
3737

3838
// ClusterResourceSetBindingReconciler reconciles a ClusterResourceSetBinding object
3939
type ClusterResourceSetBindingReconciler struct {
40-
Client client.Client
40+
Client client.Client
41+
WatchFilterValue string
4142
}
4243

4344
func (r *ClusterResourceSetBindingReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error {
@@ -48,7 +49,7 @@ func (r *ClusterResourceSetBindingReconciler) SetupWithManager(ctx context.Conte
4849
handler.EnqueueRequestsFromMapFunc(r.clusterToClusterResourceSetBinding),
4950
).
5051
WithOptions(options).
51-
WithEventFilter(predicates.ResourceNotPaused(ctrl.LoggerFrom(ctx))).
52+
WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)).
5253
Build(r)
5354
if err != nil {
5455
return errors.Wrap(err, "failed setting up with a controller manager")

exp/controllers/machinepool_controller.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ const (
5858

5959
// MachinePoolReconciler reconciles a MachinePool object
6060
type MachinePoolReconciler struct {
61-
Client client.Client
61+
Client client.Client
62+
WatchFilterValue string
6263

6364
config *rest.Config
6465
controller controller.Controller
@@ -75,7 +76,7 @@ func (r *MachinePoolReconciler) SetupWithManager(ctx context.Context, mgr ctrl.M
7576
c, err := ctrl.NewControllerManagedBy(mgr).
7677
For(&expv1.MachinePool{}).
7778
WithOptions(options).
78-
WithEventFilter(predicates.ResourceNotPaused(ctrl.LoggerFrom(ctx))).
79+
WithEventFilter(predicates.ResourceNotPausedAndHasFilterLabel(ctrl.LoggerFrom(ctx), r.WatchFilterValue)).
7980
Build(r)
8081
if err != nil {
8182
return errors.Wrap(err, "failed setting up with a controller manager")

main.go

+25-12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package main
1818
import (
1919
"context"
2020
"flag"
21+
"fmt"
2122
"math/rand"
2223
"net/http"
2324
_ "net/http/pprof"
@@ -58,6 +59,7 @@ var (
5859
leaderElectionRenewDeadline time.Duration
5960
leaderElectionRetryPeriod time.Duration
6061
watchNamespace string
62+
watchFilterValue string
6163
profilerAddress string
6264
clusterConcurrency int
6365
machineConcurrency int
@@ -102,6 +104,9 @@ func InitFlags(fs *pflag.FlagSet) {
102104
fs.StringVar(&watchNamespace, "namespace", "",
103105
"Namespace that the controller watches to reconcile cluster-api objects. If unspecified, the controller watches for cluster-api objects across all namespaces.")
104106

107+
fs.StringVar(&watchFilterValue, "watch-filter", "",
108+
fmt.Sprintf("Label value that the controller watches to reconcile cluster-api objects. Label key is always %s. If unspecified, the controller watches for all cluster-api objects.", clusterv1.WatchLabel))
109+
105110
fs.StringVar(&profilerAddress, "profiler-address", "",
106111
"Bind address to expose the pprof profiler (e.g. localhost:6060)")
107112

@@ -224,35 +229,40 @@ func setupReconcilers(ctx context.Context, mgr ctrl.Manager) {
224229
}
225230

226231
if err := (&controllers.ClusterReconciler{
227-
Client: mgr.GetClient(),
232+
Client: mgr.GetClient(),
233+
WatchFilterValue: watchFilterValue,
228234
}).SetupWithManager(ctx, mgr, concurrency(clusterConcurrency)); err != nil {
229235
setupLog.Error(err, "unable to create controller", "controller", "Cluster")
230236
os.Exit(1)
231237
}
232238
if err := (&controllers.MachineReconciler{
233-
Client: mgr.GetClient(),
234-
Tracker: tracker,
239+
Client: mgr.GetClient(),
240+
Tracker: tracker,
241+
WatchFilterValue: watchFilterValue,
235242
}).SetupWithManager(ctx, mgr, concurrency(machineConcurrency)); err != nil {
236243
setupLog.Error(err, "unable to create controller", "controller", "Machine")
237244
os.Exit(1)
238245
}
239246
if err := (&controllers.MachineSetReconciler{
240-
Client: mgr.GetClient(),
241-
Tracker: tracker,
247+
Client: mgr.GetClient(),
248+
Tracker: tracker,
249+
WatchFilterValue: watchFilterValue,
242250
}).SetupWithManager(ctx, mgr, concurrency(machineSetConcurrency)); err != nil {
243251
setupLog.Error(err, "unable to create controller", "controller", "MachineSet")
244252
os.Exit(1)
245253
}
246254
if err := (&controllers.MachineDeploymentReconciler{
247-
Client: mgr.GetClient(),
255+
Client: mgr.GetClient(),
256+
WatchFilterValue: watchFilterValue,
248257
}).SetupWithManager(ctx, mgr, concurrency(machineDeploymentConcurrency)); err != nil {
249258
setupLog.Error(err, "unable to create controller", "controller", "MachineDeployment")
250259
os.Exit(1)
251260
}
252261

253262
if feature.Gates.Enabled(feature.MachinePool) {
254263
if err := (&expcontrollers.MachinePoolReconciler{
255-
Client: mgr.GetClient(),
264+
Client: mgr.GetClient(),
265+
WatchFilterValue: watchFilterValue,
256266
}).SetupWithManager(ctx, mgr, concurrency(machinePoolConcurrency)); err != nil {
257267
setupLog.Error(err, "unable to create controller", "controller", "MachinePool")
258268
os.Exit(1)
@@ -261,23 +271,26 @@ func setupReconcilers(ctx context.Context, mgr ctrl.Manager) {
261271

262272
if feature.Gates.Enabled(feature.ClusterResourceSet) {
263273
if err := (&addonscontrollers.ClusterResourceSetReconciler{
264-
Client: mgr.GetClient(),
265-
Tracker: tracker,
274+
Client: mgr.GetClient(),
275+
Tracker: tracker,
276+
WatchFilterValue: watchFilterValue,
266277
}).SetupWithManager(ctx, mgr, concurrency(clusterResourceSetConcurrency)); err != nil {
267278
setupLog.Error(err, "unable to create controller", "controller", "ClusterResourceSet")
268279
os.Exit(1)
269280
}
270281
if err := (&addonscontrollers.ClusterResourceSetBindingReconciler{
271-
Client: mgr.GetClient(),
282+
Client: mgr.GetClient(),
283+
WatchFilterValue: watchFilterValue,
272284
}).SetupWithManager(ctx, mgr, concurrency(clusterResourceSetConcurrency)); err != nil {
273285
setupLog.Error(err, "unable to create controller", "controller", "ClusterResourceSetBinding")
274286
os.Exit(1)
275287
}
276288
}
277289

278290
if err := (&controllers.MachineHealthCheckReconciler{
279-
Client: mgr.GetClient(),
280-
Tracker: tracker,
291+
Client: mgr.GetClient(),
292+
Tracker: tracker,
293+
WatchFilterValue: watchFilterValue,
281294
}).SetupWithManager(ctx, mgr, concurrency(machineHealthCheckConcurrency)); err != nil {
282295
setupLog.Error(err, "unable to create controller", "controller", "MachineHealthCheck")
283296
os.Exit(1)

util/labels/helpers.go

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
Copyright 2021 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package labels
18+
19+
import (
20+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4"
22+
)
23+
24+
// HasWatchLabel returns true if the object has a label with the WatchLabel key matching the given value.
25+
func HasWatchLabel(o metav1.Object, labelValue string) bool {
26+
val, ok := o.GetLabels()[clusterv1.WatchLabel]
27+
if !ok {
28+
return false
29+
}
30+
return val == labelValue
31+
}

0 commit comments

Comments
 (0)