@@ -31,6 +31,7 @@ import (
3131 corev1 "k8s.io/api/core/v1"
3232 apierrors "k8s.io/apimachinery/pkg/api/errors"
3333 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
34+ "k8s.io/apimachinery/pkg/runtime"
3435 "k8s.io/apimachinery/pkg/types"
3536 ctrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client"
3637)
@@ -57,15 +58,39 @@ type objectSyncer struct {
5758 mutator mutation.Mutator
5859 // stateStore is capable of remembering the state of a Kubernetes object
5960 stateStore ObjectStateStore
61+ // eventObjSide is configuring whether the source or destination object will
62+ // receive events. Since these objects might be created during the sync,
63+ // they cannot be specified here directly.
64+ eventObjSide syncSideType
6065}
6166
67+ type syncSideType int
68+
69+ const (
70+ syncSideSource syncSideType = iota
71+ syncSideDestination
72+ )
73+
6274type syncSide struct {
6375 clusterName logicalcluster.Name
6476 workspacePath logicalcluster.Path
6577 client ctrlruntimeclient.Client
6678 object * unstructured.Unstructured
6779}
6880
81+ func (s * objectSyncer ) recordEvent (ctx context.Context , source , dest syncSide , eventtype , reason , msg string , args ... any ) {
82+ recorder := recorderFromContext (ctx )
83+
84+ var obj runtime.Object
85+ if s .eventObjSide == syncSideDestination {
86+ obj = dest .object
87+ } else {
88+ obj = source .object
89+ }
90+
91+ recorder .Eventf (obj , eventtype , reason , msg , args ... )
92+ }
93+
6994func (s * objectSyncer ) Sync (ctx context.Context , log * zap.SugaredLogger , source , dest syncSide ) (requeue bool , err error ) {
7095 // handle deletion: if source object is in deletion, delete the destination object (the clone)
7196 if source .object .GetDeletionTimestamp () != nil {
@@ -81,6 +106,7 @@ func (s *objectSyncer) Sync(ctx context.Context, log *zap.SugaredLogger, source,
81106
82107 // the patch above would trigger a new reconciliation anyway
83108 if updated {
109+ s .recordEvent (ctx , source , dest , corev1 .EventTypeNormal , "ObjectAccepted" , "Object has been seen by the service provider." )
84110 return true , nil
85111 }
86112 }
@@ -103,6 +129,7 @@ func (s *objectSyncer) Sync(ctx context.Context, log *zap.SugaredLogger, source,
103129
104130 // The function above either created a new destination object or patched-in the missing labels,
105131 // in both cases do we want to requeue.
132+ s .recordEvent (ctx , source , dest , corev1 .EventTypeNormal , "ObjectPlaced" , "Object has been placed." )
106133 return true , nil
107134 }
108135
@@ -254,6 +281,8 @@ func (s *objectSyncer) syncObjectSpec(ctx context.Context, log *zap.SugaredLogge
254281 }
255282
256283 if requeue {
284+ s .recordEvent (ctx , source , dest , corev1 .EventTypeNormal , "ObjectSynced" , "The current desired state of the object has been synchronized." )
285+
257286 // remember this object state for the next reconciliation (this will strip any syncer-related
258287 // metadata the 3-way diff may have added above)
259288 if err := s .stateStore .Put (ctx , sourceObjCopy , source .clusterName , s .subresources ); err != nil {
@@ -282,6 +311,8 @@ func (s *objectSyncer) syncObjectStatus(ctx context.Context, log *zap.SugaredLog
282311 if err := source .client .Status ().Update (ctx , source .object ); err != nil {
283312 return false , fmt .Errorf ("failed to update source object status: %w" , err )
284313 }
314+
315+ s .recordEvent (ctx , source , dest , corev1 .EventTypeNormal , "ObjectStatusSynced" , "The current object status has been updated." )
285316 }
286317
287318 // always return false; there is no need to requeue the source object when we changed its status
@@ -406,6 +437,7 @@ func (s *objectSyncer) handleDeletion(ctx context.Context, log *zap.SugaredLogge
406437 if dest .object != nil {
407438 if dest .object .GetDeletionTimestamp () == nil {
408439 log .Debugw ("Deleting destination object…" , "dest-object" , newObjectKey (dest .object , dest .clusterName , logicalcluster .None ))
440+ s .recordEvent (ctx , source , dest , corev1 .EventTypeNormal , "ObjectCleanup" , "Object deletion has been started and will progress in the background." )
409441 if err := dest .client .Delete (ctx , dest .object ); err != nil {
410442 return false , fmt .Errorf ("failed to delete destination object: %w" , err )
411443 }
@@ -422,6 +454,7 @@ func (s *objectSyncer) handleDeletion(ctx context.Context, log *zap.SugaredLogge
422454
423455 // if we just removed the finalizer, we can requeue the source object
424456 if updated {
457+ s .recordEvent (ctx , source , dest , corev1 .EventTypeNormal , "ObjectDeleted" , "Object deletion has been completed, finalizer has been removed." )
425458 return true , nil
426459 }
427460
0 commit comments