Skip to content

Commit dadf489

Browse files
authored
chore: merge role probe event handling (#10282)
1 parent 605d131 commit dadf489

13 files changed

Lines changed: 833 additions & 932 deletions

File tree

cmd/manager/main.go

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,22 @@ func main() {
433433
os.Exit(1)
434434
}
435435

436-
if viper.GetBool(appsFlagKey.viperName()) {
436+
appsEnabled := viper.GetBool(appsFlagKey.viperName())
437+
workloadsEnabled := viper.GetBool(workloadsFlagKey.viperName())
438+
if appsEnabled || workloadsEnabled {
439+
if err = (&k8scorecontrollers.EventReconciler{
440+
Client: mgr.GetClient(),
441+
Scheme: mgr.GetScheme(),
442+
Recorder: mgr.GetEventRecorderFor("event-controller"),
443+
AppsEnabled: appsEnabled,
444+
WorkloadsEnabled: workloadsEnabled,
445+
}).SetupWithManager(mgr); err != nil {
446+
setupLog.Error(err, "unable to create controller", "controller", "Event")
447+
os.Exit(1)
448+
}
449+
}
450+
451+
if appsEnabled {
437452
if err = (&appscontrollers.ClusterDefinitionReconciler{
438453
Client: mgr.GetClient(),
439454
Scheme: mgr.GetScheme(),
@@ -507,15 +522,6 @@ func main() {
507522
os.Exit(1)
508523
}
509524

510-
if err = (&k8scorecontrollers.EventReconciler{
511-
Client: mgr.GetClient(),
512-
Scheme: mgr.GetScheme(),
513-
Recorder: mgr.GetEventRecorderFor("event-controller"),
514-
}).SetupWithManager(mgr); err != nil {
515-
setupLog.Error(err, "unable to create controller", "controller", "Event")
516-
os.Exit(1)
517-
}
518-
519525
if err = (&rollout.RolloutReconciler{
520526
Client: mgr.GetClient(),
521527
Scheme: mgr.GetScheme(),
@@ -526,7 +532,7 @@ func main() {
526532
}
527533
}
528534

529-
if viper.GetBool(workloadsFlagKey.viperName()) {
535+
if workloadsEnabled {
530536
if err = (&workloadscontrollers.InstanceSetReconciler{
531537
Client: mgr.GetClient(),
532538
Scheme: mgr.GetScheme(),
@@ -554,14 +560,6 @@ func main() {
554560
os.Exit(1)
555561
}
556562

557-
if err = (&workloadscontrollers.InstanceEventReconciler{
558-
Client: mgr.GetClient(),
559-
Scheme: mgr.GetScheme(),
560-
Recorder: mgr.GetEventRecorderFor("instance-event-controller"),
561-
}).SetupWithManager(mgr); err != nil {
562-
setupLog.Error(err, "unable to create controller", "controller", "InstanceEvent")
563-
os.Exit(1)
564-
}
565563
}
566564

567565
if viper.GetBool(operationsFlagKey.viperName()) {

controllers/apps/component/suite_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,10 @@ var _ = BeforeSuite(func() {
183183
Expect(err).ToNot(HaveOccurred())
184184

185185
err = (&k8score.EventReconciler{
186-
Client: k8sManager.GetClient(),
187-
Scheme: k8sManager.GetScheme(),
188-
Recorder: k8sManager.GetEventRecorderFor("event-controller"),
186+
Client: k8sManager.GetClient(),
187+
Scheme: k8sManager.GetScheme(),
188+
Recorder: k8sManager.GetEventRecorderFor("event-controller"),
189+
AppsEnabled: true,
189190
}).SetupWithManager(k8sManager)
190191
Expect(err).ToNot(HaveOccurred())
191192

controllers/k8score/event_controller.go

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ import (
3232
"sigs.k8s.io/controller-runtime/pkg/controller"
3333
"sigs.k8s.io/controller-runtime/pkg/log"
3434

35+
"github.com/apecloud/kubeblocks/controllers/workloads"
3536
"github.com/apecloud/kubeblocks/pkg/constant"
3637
"github.com/apecloud/kubeblocks/pkg/controller/component"
37-
"github.com/apecloud/kubeblocks/pkg/controller/instanceset"
3838
intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil"
3939
viper "github.com/apecloud/kubeblocks/pkg/viperx"
4040
)
@@ -44,14 +44,16 @@ const (
4444
)
4545

4646
type eventHandler interface {
47-
Handle(cli client.Client, reqCtx intctrlutil.RequestCtx, recorder record.EventRecorder, event *corev1.Event) error
47+
Handle(cli client.Client, reqCtx intctrlutil.RequestCtx, recorder record.EventRecorder, event *corev1.Event) (bool, error)
4848
}
4949

5050
// EventReconciler reconciles an Event object
5151
type EventReconciler struct {
5252
client.Client
53-
Scheme *runtime.Scheme
54-
Recorder record.EventRecorder
53+
Scheme *runtime.Scheme
54+
Recorder record.EventRecorder
55+
AppsEnabled bool
56+
WorkloadsEnabled bool
5557
}
5658

5759
// events API only allows ready-only, create, patch
@@ -80,15 +82,17 @@ func (r *EventReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl
8082
return intctrlutil.Reconciled()
8183
}
8284

83-
handlers := []eventHandler{
84-
&instanceset.PodRoleEventHandler{},
85-
&component.AvailableEventHandler{},
86-
&component.KBAgentTaskEventHandler{},
87-
}
88-
for _, handler := range handlers {
89-
if err := handler.Handle(r.Client, reqCtx, r.Recorder, event); err != nil && !apierrors.IsNotFound(err) {
85+
handled := false
86+
for _, handler := range r.handlers() {
87+
ok, err := handler.Handle(r.Client, reqCtx, r.Recorder, event)
88+
if err != nil && !apierrors.IsNotFound(err) {
9089
return intctrlutil.RequeueWithError(err, reqCtx.Log, "handleEventError")
9190
}
91+
handled = handled || ok
92+
}
93+
94+
if !handled {
95+
return intctrlutil.Reconciled()
9296
}
9397

9498
if err := r.eventHandled(ctx, event); err != nil {
@@ -107,6 +111,20 @@ func (r *EventReconciler) SetupWithManager(mgr ctrl.Manager) error {
107111
Complete(r)
108112
}
109113

114+
func (r *EventReconciler) handlers() []eventHandler {
115+
handlers := make([]eventHandler, 0, 3)
116+
if r.AppsEnabled {
117+
handlers = append(handlers,
118+
&component.AvailableEventHandler{},
119+
&component.KBAgentTaskEventHandler{},
120+
)
121+
}
122+
if r.WorkloadsEnabled {
123+
handlers = append(handlers, &workloads.RoleEventHandler{})
124+
}
125+
return handlers
126+
}
127+
110128
func (r *EventReconciler) isEventHandled(event *corev1.Event) bool {
111129
count := fmt.Sprintf("%d", event.Count)
112130
annotations := event.GetAnnotations()

controllers/k8score/event_controller_test.go

Lines changed: 11 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ package k8score
2222
import (
2323
"encoding/json"
2424
"fmt"
25-
"strconv"
26-
"time"
2725

2826
. "github.com/onsi/ginkgo/v2"
2927
. "github.com/onsi/gomega"
@@ -33,45 +31,25 @@ import (
3331
"k8s.io/apimachinery/pkg/types"
3432
"sigs.k8s.io/controller-runtime/pkg/client"
3533

36-
appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
37-
workloads "github.com/apecloud/kubeblocks/apis/workloads/v1"
38-
"github.com/apecloud/kubeblocks/pkg/constant"
3934
"github.com/apecloud/kubeblocks/pkg/controller/builder"
40-
"github.com/apecloud/kubeblocks/pkg/controller/instanceset"
4135
"github.com/apecloud/kubeblocks/pkg/generics"
4236
"github.com/apecloud/kubeblocks/pkg/kbagent/proto"
4337
testapps "github.com/apecloud/kubeblocks/pkg/testutil/apps"
4438
)
4539

4640
var _ = Describe("Event Controller", func() {
4741
cleanEnv := func() {
48-
// must wait till resources deleted and no longer existed before the testcases start,
49-
// otherwise if later it needs to create some new resource objects with the same name,
50-
// in race conditions, it will find the existence of old objects, resulting failure to
51-
// create the new objects.
5242
By("clean resources")
5343

5444
testapps.ClearClusterResources(&testCtx)
5545

56-
// delete rest mocked objects
5746
inNS := client.InNamespace(testCtx.DefaultNamespace)
5847
ml := client.HasLabels{testCtx.TestObjLabelKey}
59-
// namespaced
6048
testapps.ClearResources(&testCtx, generics.EventSignature, inNS, ml)
6149
testapps.ClearResources(&testCtx, generics.PodSignature, inNS, ml)
6250
}
6351

64-
const (
65-
// roleChangedAnnotKey is used to mark the role change event has been handled.
66-
roleChangedAnnotKey = "role.kubeblocks.io/event-handled"
67-
)
68-
69-
var (
70-
beforeLastTS = time.Date(2021, time.January, 1, 12, 0, 0, 0, time.UTC)
71-
initLastTS = time.Date(2022, time.January, 1, 12, 0, 0, 0, time.UTC)
72-
afterLastTS = time.Date(2023, time.January, 1, 12, 0, 0, 0, time.UTC)
73-
eventSeq = 0
74-
)
52+
var eventSeq int
7553

7654
createRoleChangedEvent := func(podName, role string, podUid types.UID) *corev1.Event {
7755
eventSeq++
@@ -95,157 +73,30 @@ var _ = Describe("Event Controller", func() {
9573
SetMessage(string(message)).
9674
SetReason("roleProbe").
9775
SetType(corev1.EventTypeNormal).
98-
SetFirstTimestamp(metav1.NewTime(initLastTS)).
99-
SetLastTimestamp(metav1.NewTime(initLastTS)).
100-
SetEventTime(metav1.NewMicroTime(initLastTS)).
76+
SetEventTime(metav1.NewMicroTime(metav1.Now().Time)).
10177
SetReportingController(proto.ProbeEventReportingController).
10278
SetReportingInstance(podName).
10379
SetAction("mock-create-event-action").
10480
GetObject()
10581
}
10682

107-
createInvolvedPod := func(name, clusterName, componentName, itsName string) *corev1.Pod {
108-
return builder.NewPodBuilder(testCtx.DefaultNamespace, name).
109-
AddLabels(constant.AppInstanceLabelKey, clusterName).
110-
AddLabels(constant.KBAppComponentLabelKey, componentName).
111-
AddLabels(instanceset.WorkloadsInstanceLabelKey, itsName).
112-
SetContainers([]corev1.Container{
113-
{
114-
Image: "foo",
115-
Name: "bar",
116-
},
117-
}).
118-
GetObject()
119-
}
120-
12183
BeforeEach(cleanEnv)
12284

12385
AfterEach(cleanEnv)
12486

125-
Context("When receiving role changed event", func() {
126-
It("should handle it properly", func() {
127-
By("create cluster & compdef")
128-
compDefName := "test-compdef"
129-
clusterName := "test-cluster"
130-
defaultCompName := "mysql"
131-
compDefObj := testapps.NewComponentDefinitionFactory(compDefName).
132-
SetDefaultSpec().
133-
Create(&testCtx).
134-
GetObject()
135-
clusterObj := testapps.NewClusterFactory(testCtx.DefaultNamespace, clusterName, "").
136-
WithRandomName().
137-
AddComponent(defaultCompName, compDefObj.GetName()).
138-
Create(&testCtx).GetObject()
139-
Eventually(testapps.CheckObjExists(&testCtx, client.ObjectKeyFromObject(clusterObj), &appsv1.Cluster{}, true)).Should(Succeed())
140-
141-
itsName := fmt.Sprintf("%s-%s", clusterObj.Name, defaultCompName)
142-
its := testapps.NewInstanceSetFactory(clusterObj.Namespace, itsName, clusterObj.Name, defaultCompName).
143-
SetReplicas(int32(3)).
144-
AddContainer(corev1.Container{Name: testapps.DefaultMySQLContainerName, Image: testapps.ApeCloudMySQLImage}).
145-
Create(&testCtx).GetObject()
146-
Expect(testapps.GetAndChangeObj(&testCtx, client.ObjectKeyFromObject(its), func(tmpITS *workloads.InstanceSet) {
147-
tmpITS.Spec.Roles = []workloads.ReplicaRole{
148-
{
149-
Name: "leader",
150-
ParticipatesInQuorum: true,
151-
UpdatePriority: 5,
152-
},
153-
{
154-
Name: "follower",
155-
ParticipatesInQuorum: true,
156-
UpdatePriority: 4,
157-
},
158-
}
159-
})()).Should(Succeed())
160-
By("create involved pod")
161-
var uid types.UID
162-
podName := fmt.Sprintf("%s-%d", itsName, 0)
163-
pod := createInvolvedPod(podName, clusterObj.Name, defaultCompName, itsName)
164-
Expect(testCtx.CreateObj(ctx, pod)).Should(Succeed())
165-
Eventually(func() error {
166-
p := &corev1.Pod{}
167-
defer func() {
168-
uid = p.UID
169-
}()
170-
return k8sClient.Get(ctx, types.NamespacedName{
171-
Namespace: pod.Namespace,
172-
Name: pod.Name,
173-
}, p)
174-
}).Should(Succeed())
175-
Expect(uid).ShouldNot(BeNil())
176-
177-
By("send role changed event")
178-
role := "leader"
179-
sndEvent := createRoleChangedEvent(podName, role, uid)
87+
Context("When receiving role probe event", func() {
88+
It("should leave role probe events for the workloads role event reconciler", func() {
89+
sndEvent := createRoleChangedEvent("pod-0", "leader", types.UID("pod-uid"))
18090
Expect(testCtx.CreateObj(ctx, sndEvent)).Should(Succeed())
181-
Eventually(func() string {
91+
92+
Consistently(func(g Gomega) {
18293
event := &corev1.Event{}
183-
if err := k8sClient.Get(ctx, types.NamespacedName{
94+
g.Expect(k8sClient.Get(ctx, types.NamespacedName{
18495
Namespace: sndEvent.Namespace,
18596
Name: sndEvent.Name,
186-
}, event); err != nil {
187-
return err.Error()
188-
}
189-
return event.InvolvedObject.Name
190-
}).Should(Equal(sndEvent.InvolvedObject.Name))
191-
192-
Eventually(testapps.CheckObj(&testCtx, client.ObjectKeyFromObject(pod), func(g Gomega, p *corev1.Pod) {
193-
g.Expect(p).ShouldNot(BeNil())
194-
g.Expect(p.Labels).ShouldNot(BeNil())
195-
g.Expect(p.Labels[constant.RoleLabelKey]).Should(Equal(role))
196-
g.Expect(p.Annotations[constant.LastRoleEventVersionAnnotationKey]).Should(Equal(strconv.FormatInt(sndEvent.EventTime.UnixMicro(), 10)))
197-
})).Should(Succeed())
198-
199-
Eventually(testapps.CheckObj(&testCtx, client.ObjectKeyFromObject(sndEvent), func(g Gomega, e *corev1.Event) {
200-
g.Expect(e).ShouldNot(BeNil())
201-
g.Expect(e.Annotations).ShouldNot(BeNil())
202-
g.Expect(e.Annotations[roleChangedAnnotKey]).Should(Equal("count-0"))
203-
})).Should(Succeed())
204-
205-
By("send role changed event with beforeLastTS earlier than pod last role changes event timestamp annotation should not be update successfully")
206-
role = "follower"
207-
sndInvalidEvent := createRoleChangedEvent(podName, role, uid)
208-
sndInvalidEvent.EventTime = metav1.NewMicroTime(beforeLastTS)
209-
Expect(testCtx.CreateObj(ctx, sndInvalidEvent)).Should(Succeed())
210-
Eventually(func() string {
211-
event := &corev1.Event{}
212-
if err := k8sClient.Get(ctx, types.NamespacedName{
213-
Namespace: sndInvalidEvent.Namespace,
214-
Name: sndInvalidEvent.Name,
215-
}, event); err != nil {
216-
return err.Error()
217-
}
218-
return event.InvolvedObject.Name
219-
}).Should(Equal(sndInvalidEvent.InvolvedObject.Name))
220-
Eventually(testapps.CheckObj(&testCtx, client.ObjectKeyFromObject(pod), func(g Gomega, p *corev1.Pod) {
221-
g.Expect(p).ShouldNot(BeNil())
222-
g.Expect(p.Labels).ShouldNot(BeNil())
223-
g.Expect(p.Labels[constant.RoleLabelKey]).ShouldNot(Equal(role))
224-
g.Expect(p.Annotations[constant.LastRoleEventVersionAnnotationKey]).ShouldNot(Equal(strconv.FormatInt(sndInvalidEvent.EventTime.UnixMicro(), 10)))
225-
})).Should(Succeed())
226-
227-
By("send role changed event with afterLastTS later than pod last role changes event timestamp annotation should be update successfully")
228-
role = "follower"
229-
sndValidEvent := createRoleChangedEvent(podName, role, uid)
230-
sndValidEvent.LastTimestamp = metav1.NewTime(afterLastTS)
231-
sndValidEvent.EventTime = metav1.NewMicroTime(afterLastTS)
232-
Expect(testCtx.CreateObj(ctx, sndValidEvent)).Should(Succeed())
233-
Eventually(func() string {
234-
event := &corev1.Event{}
235-
if err := k8sClient.Get(ctx, types.NamespacedName{
236-
Namespace: sndValidEvent.Namespace,
237-
Name: sndValidEvent.Name,
238-
}, event); err != nil {
239-
return err.Error()
240-
}
241-
return event.InvolvedObject.Name
242-
}).Should(Equal(sndValidEvent.InvolvedObject.Name))
243-
Eventually(testapps.CheckObj(&testCtx, client.ObjectKeyFromObject(pod), func(g Gomega, p *corev1.Pod) {
244-
g.Expect(p).ShouldNot(BeNil())
245-
g.Expect(p.Labels).ShouldNot(BeNil())
246-
g.Expect(p.Labels[constant.RoleLabelKey]).Should(Equal(role))
247-
g.Expect(p.Annotations[constant.LastRoleEventVersionAnnotationKey]).Should(Equal(strconv.FormatInt(sndValidEvent.LastTimestamp.UnixMicro(), 10)))
248-
})).Should(Succeed())
97+
}, event)).Should(Succeed())
98+
g.Expect(event.Annotations).ShouldNot(HaveKey(eventHandledAnnotationKey))
99+
}).Should(Succeed())
249100
})
250101
})
251102
})

0 commit comments

Comments
 (0)