@@ -577,7 +577,7 @@ func (r *Reconciler) Apply(ctx context.Context, inventory *[]*InventoryItem, obj
577577
578578 switch item .Phase {
579579 case PhaseScheduledForCompletion :
580- if err := r .deleteObject (ctx , item , existingObject ); err != nil {
580+ if err := r .deleteObject (ctx , item , existingObject , hashedOwnerId ); err != nil {
581581 return false , errors .Wrapf (err , "error deleting object %s" , item )
582582 }
583583 item .Phase = PhaseCompleting
@@ -662,7 +662,7 @@ func (r *Reconciler) Apply(ctx context.Context, inventory *[]*InventoryItem, obj
662662 switch updatePolicy {
663663 case UpdatePolicyRecreate :
664664 // TODO: perform an additional owner id check
665- if err := r .deleteObject (ctx , object , existingObject ); err != nil {
665+ if err := r .deleteObject (ctx , object , existingObject , hashedOwnerId ); err != nil {
666666 return false , errors .Wrapf (err , "error deleting (while recreating) object %s" , item )
667667 }
668668 default :
@@ -772,7 +772,7 @@ func (r *Reconciler) Apply(ctx context.Context, inventory *[]*InventoryItem, obj
772772 // note: here is a theoretical risk that we delete an existing foreign object, because informers are not yet synced
773773 // however not sending the delete request is also not an option, because this might lead to orphaned own dependents
774774 // TODO: perform an additional owner id check
775- if err := r .deleteObject (ctx , item , existingObject ); err != nil {
775+ if err := r .deleteObject (ctx , item , existingObject , hashedOwnerId ); err != nil {
776776 return false , errors .Wrapf (err , "error deleting object %s" , item )
777777 }
778778 item .Phase = PhaseDeleting
@@ -824,9 +824,11 @@ func (r *Reconciler) Apply(ctx context.Context, inventory *[]*InventoryItem, obj
824824// This method will change the passed inventory (remove elements, change elements). If Delete() returns true, then all objects are gone; otherwise,
825825// if it returns false, the caller should recall it timely, until it returns true. In any case, the passed inventory should match the state of the
826826// inventory after the previous invocation of Delete(); usually, the caller saves the inventory after calling Delete(), and loads it before calling Delete().
827- func (r * Reconciler ) Delete (ctx context.Context , inventory * []* InventoryItem ) (bool , error ) {
827+ func (r * Reconciler ) Delete (ctx context.Context , inventory * []* InventoryItem , ownerId string ) (bool , error ) {
828828 log := log .FromContext (ctx )
829829
830+ hashedOwnerId := sha256base32 ([]byte (ownerId ))
831+
830832 // delete objects and maintain inventory;
831833 // objects are deleted in waves according to their delete order;
832834 // that means, only if all objects of a wave are gone, the next wave will be processed;
@@ -877,7 +879,7 @@ func (r *Reconciler) Delete(ctx context.Context, inventory *[]*InventoryItem) (b
877879 // note: here is a theoretical risk that we delete an existing (foreign) object, because informers are not yet synced
878880 // however not sending the delete request is also not an option, because this might lead to orphaned own dependents
879881 // TODO: perform an additional owner id check
880- if err := r .deleteObject (ctx , item , existingObject ); err != nil {
882+ if err := r .deleteObject (ctx , item , existingObject , hashedOwnerId ); err != nil {
881883 return false , errors .Wrapf (err , "error deleting object %s" , item )
882884 }
883885 item .Phase = PhaseDeleting
@@ -1111,7 +1113,7 @@ func (r *Reconciler) updateObject(ctx context.Context, object client.Object, exi
11111113// then an error will be returned after issuing the delete call; otherwise, if the crd or api service is not in use, then our
11121114// finalizer (i.e. the finalizer equal to the reconciler name) will be cleared, such that the object can be physically
11131115// removed (unless other finalizers prevent this)
1114- func (r * Reconciler ) deleteObject (ctx context.Context , key types.ObjectKey , existingObject * unstructured.Unstructured ) (err error ) {
1116+ func (r * Reconciler ) deleteObject (ctx context.Context , key types.ObjectKey , existingObject * unstructured.Unstructured , ownerId string ) (err error ) {
11151117 if counter := r .metrics .DeleteCounter ; counter != nil {
11161118 counter .Inc ()
11171119 }
@@ -1131,6 +1133,10 @@ func (r *Reconciler) deleteObject(ctx context.Context, key types.ObjectKey, exis
11311133
11321134 // TODO: validate (by panic) that existingObject (if present) fits to key
11331135
1136+ if existingObject != nil && existingObject .GetLabels ()[r .labelKeyOwnerId ] != ownerId {
1137+ return fmt .Errorf ("owner conflict; object %s has no or different owner" , types .ObjectKeyToString (key ))
1138+ }
1139+
11341140 object := & unstructured.Unstructured {}
11351141 object .SetGroupVersionKind (key .GetObjectKind ().GroupVersionKind ())
11361142 object .SetNamespace (key .GetNamespace ())
0 commit comments