Skip to content

Commit ebfd4be

Browse files
committed
Enable schedule reconciles from clusters in different shards
A cluster being updated would not make much of a difference, because mapping schedules to and from clusters works based on the schedules and clusters' respective namespaces. However, creating a new cluster in the same namespace still needs to be taken into account across shards, as a cluster living in a different shard may be relevant to a schedule, living in its same namespace and matching its targets.
1 parent 9aaa8ad commit ebfd4be

2 files changed

Lines changed: 71 additions & 7 deletions

File tree

integrationtests/controller/schedule/schedule_test.go

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ var _ = Describe("Bundle Status Fields", func() {
2828
})
2929
})
3030

31-
DescribeTable("A Cluster change triggers a schedule status fields update",
32-
func(updatedClusterLabels map[string]string) {
31+
When("a Cluster living in the same namespace as a schedule is updated to match the schedule's targets", func() {
32+
It("schedules the cluster", func() {
3333
By("creating the cluster and schedule")
3434
cluster, err := utils.CreateCluster(ctx, k8sClient, "cluster", namespace, nil, namespace)
3535
Expect(err).NotTo(HaveOccurred())
@@ -80,7 +80,7 @@ var _ = Describe("Bundle Status Fields", func() {
8080
Eventually(func() error {
8181
err = k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "cluster"}, cluster)
8282
Expect(err).NotTo(HaveOccurred())
83-
cluster.Labels = updatedClusterLabels
83+
cluster.Labels = map[string]string{"can-be-scheduled": "yes"}
8484
return k8sClient.Update(ctx, cluster)
8585
}).ShouldNot(HaveOccurred())
8686

@@ -90,7 +90,69 @@ var _ = Describe("Bundle Status Fields", func() {
9090
g.Expect(err).NotTo(HaveOccurred())
9191
g.Expect(cluster.Status.Scheduled).To(BeTrue())
9292
}).Should(Succeed())
93-
},
94-
Entry("cluster with default (empty) shard ID", map[string]string{"can-be-scheduled": "yes"}),
95-
)
93+
})
94+
})
95+
96+
When("another Cluster with a different shard ID and matching the schedule's targets is added into the same namespace", func() {
97+
It("schedules the cluster", func() {
98+
By("creating the cluster and schedule")
99+
cluster, err := utils.CreateCluster(ctx, k8sClient, "cluster", namespace, nil, namespace)
100+
Expect(err).NotTo(HaveOccurred())
101+
Expect(cluster).To(Not(BeNil()))
102+
103+
schedule := v1alpha1.Schedule{
104+
ObjectMeta: metav1.ObjectMeta{
105+
Name: "my-schedule",
106+
Namespace: namespace,
107+
},
108+
Spec: v1alpha1.ScheduleSpec{
109+
Schedule: "0 */1 * * * *", // Every minute
110+
Duration: metav1.Duration{Duration: 30 * time.Second},
111+
Targets: v1alpha1.ScheduleTargets{
112+
Clusters: []v1alpha1.ScheduleTarget{
113+
{
114+
ClusterSelector: &metav1.LabelSelector{},
115+
},
116+
},
117+
},
118+
},
119+
}
120+
err = k8sClient.Create(ctx, &schedule)
121+
Expect(err).NotTo(HaveOccurred())
122+
123+
Eventually(func(g Gomega) {
124+
err = k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "my-schedule"}, &schedule)
125+
g.Expect(err).NotTo(HaveOccurred())
126+
}).Should(Succeed())
127+
128+
defer func() {
129+
Expect(k8sClient.Delete(ctx, &v1alpha1.Schedule{ObjectMeta: metav1.ObjectMeta{
130+
Name: "my-schedule",
131+
Namespace: namespace,
132+
}})).NotTo(HaveOccurred())
133+
134+
}()
135+
136+
By("validating that the cluster is scheduled")
137+
Eventually(func(g Gomega) {
138+
err = k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "cluster"}, cluster)
139+
g.Expect(err).NotTo(HaveOccurred())
140+
g.Expect(cluster.Status.Scheduled).To(BeTrue())
141+
}).Should(Succeed())
142+
143+
By("adding another cluster with a different shard ID to the same namespace")
144+
labels := map[string]string{"fleet.cattle.io/shard-ref": "different-shard"}
145+
shardedCluster, err := utils.CreateCluster(ctx, k8sClient, "cluster2", namespace, labels, namespace)
146+
Expect(err).NotTo(HaveOccurred())
147+
Expect(shardedCluster).To(Not(BeNil()))
148+
149+
By("validating that the cluster is scheduled")
150+
Eventually(func(g Gomega) {
151+
var shardedCluster v1alpha1.Cluster
152+
err = k8sClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: "cluster2"}, &shardedCluster)
153+
g.Expect(err).NotTo(HaveOccurred())
154+
g.Expect(shardedCluster.Status.Scheduled).To(BeTrue())
155+
}).Should(Succeed())
156+
})
157+
})
96158
})

internal/cmd/controller/reconciler/schedule_controller.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,16 @@ func (r *ScheduleReconciler) SetupWithManager(mgr ctrl.Manager) error {
5454
For(&fleet.Schedule{},
5555
builder.WithPredicates(
5656
predicate.GenerationChangedPredicate{},
57+
sharding.FilterByShardID(r.ShardID),
5758
),
5859
).
5960
Watches(
6061
&fleet.Cluster{},
6162
handler.EnqueueRequestsFromMapFunc(r.mapClustersToSchedules),
6263
builder.WithPredicates(clusterChangedPredicate()),
64+
// Deliberately skipping the sharding filter here: a schedule may live in the namespace of a cluster with both
65+
// bearing distinct shard IDs.
6366
).
64-
WithEventFilter(sharding.FilterByShardID(r.ShardID)).
6567
WithOptions(controller.Options{MaxConcurrentReconciles: r.Workers}).
6668
Complete(r)
6769
}

0 commit comments

Comments
 (0)