@@ -118,6 +118,7 @@ func (s *ResourceSyncer) processRelatedResource(ctx context.Context, log *zap.Su
118118 // remember which destination copies we (re)synced this pass, so a MatchOrigin prune can delete
119119 // the copies that no longer have a matching origin object.
120120 synced := sets .New [string ]()
121+ deletionPolicies := map [string ]metav1.DeletionPropagation {}
121122
122123 // We "forward" the deletion to the related objects only if the primary is already in deletion
123124 // and the related object either originated from the user (so on the service cluster we just
@@ -149,6 +150,9 @@ func (s *ResourceSyncer) processRelatedResource(ctx context.Context, log *zap.Su
149150 object : destObject ,
150151 }
151152
153+ deletionPolicy := relatedDeletionPropagationPolicy (relRes .Origin , resolved .original )
154+ deletionPolicies [relatedCopyKey (resolved .destination .Namespace , resolved .destination .Name )] = deletionPolicy
155+
152156 // When status sync is enabled, include "status" in subresources so it is stripped from
153157 // the spec patch (avoiding a no-op write on resources that have a status subresource).
154158 // The status is then separately written via the status subresource endpoint by syncStatusForward.
@@ -192,6 +196,8 @@ func (s *ResourceSyncer) processRelatedResource(ctx context.Context, log *zap.Su
192196 eventObjSide : eventObjSide ,
193197 // force deletion of related resources when the primary object is being deleted
194198 forceDelete : forceDelete ,
199+ // Kcp-origin objects can request how their service-cluster copies are deleted.
200+ deletionPropagationPolicy : deletionPolicy ,
195201 // propagate the SSA mode chosen for the primary syncer to keep
196202 // behavior consistent across the whole resource graph
197203 useServerSideApply : s .useServerSideApply ,
@@ -237,7 +243,7 @@ func (s *ResourceSyncer) processRelatedResource(ctx context.Context, log *zap.Su
237243 // had already disappeared mid-life (which the loop can no longer resolve).
238244 selector := relatedCopySelector (primary , remote .clusterName , s .pubRes .Name , relRes .Identifier , s .agentName )
239245
240- pruneRequeue , err := s .pruneRelatedCopies (ctx , log , dest , primary , projectedGVK , selector , nil , true )
246+ pruneRequeue , err := s .pruneRelatedCopies (ctx , log , dest , primary , projectedGVK , selector , nil , deletionPolicies , true )
241247 if err != nil {
242248 return false , fmt .Errorf ("failed to tear down related copies: %w" , err )
243249 }
@@ -283,7 +289,7 @@ func (s *ResourceSyncer) processRelatedResource(ctx context.Context, log *zap.Su
283289 }
284290 }
285291
286- pruneRequeue , err := s .pruneRelatedCopies (ctx , log , dest , primary , projectedGVK , selector , synced , false )
292+ pruneRequeue , err := s .pruneRelatedCopies (ctx , log , dest , primary , projectedGVK , selector , synced , deletionPolicies , false )
287293 if err != nil {
288294 return false , fmt .Errorf ("failed to prune related copies: %w" , err )
289295 }
@@ -387,7 +393,7 @@ func (s *ResourceSyncer) rememberRelatedObjects(ctx context.Context, log *zap.Su
387393// (mid-life prune). It only ever operates on the destination client, so origin objects are never
388394// touched, and it only ever sees objects that carry our provenance labels, so hand-created objects
389395// are never in scope.
390- func (s * ResourceSyncer ) pruneRelatedCopies (ctx context.Context , log * zap.SugaredLogger , dest syncSide , primary * unstructured.Unstructured , projectedGVK schema.GroupVersionKind , selector labels.Selector , keep sets.Set [string ], deleteAll bool ) (requeue bool , err error ) {
396+ func (s * ResourceSyncer ) pruneRelatedCopies (ctx context.Context , log * zap.SugaredLogger , dest syncSide , primary * unstructured.Unstructured , projectedGVK schema.GroupVersionKind , selector labels.Selector , keep sets.Set [string ], deletionPolicies map [ string ]metav1. DeletionPropagation , deleteAll bool ) (requeue bool , err error ) {
391397 list := & unstructured.UnstructuredList {}
392398 list .SetAPIVersion (projectedGVK .GroupVersion ().String ())
393399 list .SetKind (projectedGVK .Kind + "List" )
@@ -421,7 +427,9 @@ func (s *ResourceSyncer) pruneRelatedCopies(ctx context.Context, log *zap.Sugare
421427 }
422428
423429 log .Debugw ("Pruning related object copy…" , "namespace" , item .GetNamespace (), "name" , item .GetName ())
424- if err := dest .client .Delete (ctx , item ); err != nil {
430+ policy := deletionPolicies [relatedCopyKey (item .GetNamespace (), item .GetName ())]
431+ if err := dest .client .Delete (ctx , item ,
432+ ctrlruntimeclient .PropagationPolicy (normalizeDeletionPropagationPolicy (policy ))); err != nil {
425433 if apierrors .IsNotFound (err ) {
426434 continue
427435 }
0 commit comments