Update crossplane-runtime and support foreground deletion

Signed-off-by: Bob Haddleton <bob.haddleton@nokia.com>
This commit is contained in:
Bob Haddleton 2022-08-12 20:00:29 -05:00
parent ff08fb4a41
commit ba4c8a43ab
15 changed files with 448 additions and 40 deletions

View File

@ -0,0 +1,262 @@
# Foreground Cascading Deletion Support
* Owner: Bob Haddleton (@bobh66)
* Reviewers: Crossplane Maintainers
* Status: Draft
## Background
When a Claim is deleted, Crossplane deletes the associated Composite resource
using the default "Background" kubernetes propagation policy. Crossplane
delegates the deletion of all the Composed resources from that Composite to
kubernetes via the ownerReference on each resource. When the "root" Composite
resource is deleted by the claim reconciler, kubernetes garbage collection
deletes all the Composed resources for the entire graph, which sets the
deletionTimestamp attribute on each resource. That triggers essentially
simultaneous deletion of all Composite and Managed Resources that are related to
the root Composite.
Crossplane places finalizers on the objects that it creates to ensure that the
objects are processed by the Crossplane resource controllers before they are
deleted. Crossplane directly manages the deletion of the Composite and Managed
resources that it creates, calling the appropriate Delete() function for the
resources when the deletionTimestamp attribute shows up on an object.
While all the Composed objects (Composite and Managed) have Controller
ownerReferences that point to the composite that created them, there is no
ownerReference on the "root" Composite that references the Claim. This is due
to the fact that the Composite object is cluster-scoped and the Claim is
namespace-scoped. Kubernetes does not allow a cluster-scoped
object to be "owned" by a namespaced object. This renders the
_--cascade=foreground_ option non-functional for Claim objects. Kubernetes does
not find any objects that refer to the Claim in an ownerReference, so it doesn't
set the _foregroundDeletion_ finalizer, and it marks the Claim as deleted. The
Claim reconciler sees the deletionTimestamp indicator and calls Delete() on the
associated Composite, using the default Propagation Policy of "background".
If a standalone Composite object is deleted with --cascade=foreground, all the
"leaf" node Managed Resources are immediately deleted as described above, and
the ConnectionDetails are removed from all the Composite resources, and then the
Composite resources are deleted from etcd from the "bottom up" by garbage
collection using the _foregroundDeletion_ finalizer.
As a result of the above:
- The _--cascade=foreground_ option to kubectl is effectively non-functional on
all Crossplane resources.
- Deletion of the claim or composite returns immediately, while actual managed
resource deletion may take a considerable amount of time.
- Failed deletion of managed resources is not visible to the user. [1612]
### Goals
We would like to come up with a design that:
- Will not break any existing functionality.
- Will support the use of Foreground Cascading Deletion on Composite objects.
- Will support a simulated Foreground Cascading Deletion on Claim objects.
## Out of Scope
This design does not consider any changes to the Claim/Composite reference
design that would allow _kubectl delete --cascade=foreground_ to work from the
command line on a Claim resource.
This design is not intended to block resource deletion requests to the
Kubernetes API.
This design does not address use of the Orphan propagation policy when deleting
Claims or standalone Composite objects.
## Design
The intent of this design is to allow Foreground Cascading Deletion to work on
Crossplane resources.
Foreground Cascading Deletion requires the _blockOwnerDeletion_ attribute to be
set to _true_ on the Controller ownerReference that Crossplane adds to all
Composed resources.
Given the restrictions on Claim/Composite references, in order to simulate
Foreground Cascading Deletion on claims, a new attribute is added to the Claim
which enables the claim controller to call _Delete()_ on the composite resource
with propagation policy _Foreground_.
### API
#### Claim: compositeDeletePolicy
A _compositeDeletePolicy_ attribute is added to the Claim spec to indicate to
the claim reconciler that it should use a specific Propagation Policy when
deleting the associated Composite, This attribute has possible values of
Background (default) and Foreground. The value "Orphan" is intentionally not
supported as there is no requirement to leave the Composite resource in place
(and under reconciliation) while deleting the Claim.
The Claim reconciler uses the value of compositeDeletePolicy in the Delete API
call for the associated Composite. If Background is used the Composite deletion
will occur as it does today and all associated resources will be marked for
deletion immediately and then reconciled.
If the value Foreground is used then the Composite and all of it's composed
resources will be deleted using Foreground Cascading Deletion and the delete
process with start at the leaf nodes and proceed back to the composite.
**Examples:**
Delete the Composite resource using Background propagation policy (existing
scenario):
```yaml
spec:
compositeDeletePolicy: Background
```
Delete the Composite resource using Foreground propagation policy:
```yaml
spec:
compositeDeletePolicy: Foreground
```
### User Experience - Before
#### Claim Delete - Background
- User executes _kubectl delete -n namespace <claim name>_.
- Kubernetes adds the deletionTimestamp attribute to the claim's metadata.
- Crossplane claim reconciler detects the deletion and executes a Kubernetes API
Delete on the associated Composite with the default Background propagation
policy.
- Kubernetes generates a graph of resources using ownerReferences and marks all
resources as deleted with deletionTimestamp.
- Crossplane composite and managed reconcilers detect the deletion:
- The Composite reconcilers delete the associated ConnectionDetails and
remove the Crossplane finalizer.
- The Managed reconcilers delete the remote external resources and remove the
Crossplane finalizer.
- Kubernetes garbage collection removes the Composite/Managed objects after the
Crossplane finalizers are removed.
#### Claim Delete - Foreground
- User executes _kubectl delete -n namespace --cascade=foreground <claim name>_.
- Kubernetes adds the deletionTimestamp attribute to the claim's metadata.
- There are no resources with ownerReferences that point at the claim so no
finalizers are added.
- Crossplane claim reconciler detects the deletion and executes a Kubernetes API
Delete on the associated Composite with the default Background propagation
policy.
- Kubernetes generates a graph of resources using ownerReferences and marks all
resources as deleted with deletionTimestamp.
- Crossplane composite and managed reconcilers detect the deletion.
- The Composite reconcilers delete the associated ConnectionDetails and
remove the Crossplane finalizer.
- The Managed reconcilers delete the remote external resources and remove the
Crossplane finalizer.
- Kubernetes garbage collection removes the Composite/Managed objects after the
Crossplane finalizers are removed
#### Standalone Composite Delete - Background
- User executes _kubectl delete <composite name>_.
- Kubernetes adds the deletionTimestamp attribute to the composite's metadata.
- Kubernetes generates a graph of resources using ownerReferences and marks all
resources as deleted with deletionTimestamp.
- Crossplane composite and managed reconcilers detect the deletion.
- The Composite reconcilers delete the associated ConnectionDetails and
remove the Crossplane finalizer.
- The Managed reconcilers delete the remote external resources and remove the
Crossplane finalizer.
- Kubernetes garbage collection removes the Composite/Managed objects after the
Crossplane finalizers are removed.
#### Composite Delete - Foreground
- User executes _kubectl delete --cascade=foreground <composite name>_.
- Kubernetes adds the deletionTimestamp attribute to the composite's metadata.
- Kubernetes generates a graph of resources using ownerReferences and marks all
resources as deleted with deletionTimestamp.
- Crossplane composite and managed reconcilers detect the deletion.
- The Composite reconcilers delete the ConnectionDetails and remove the
Crossplane finalizer.
- The Managed reconcilers delete the remote external resources and remove the
Crossplane finalizer.
- Kubernetes garbage collection removes the Composite/Managed objects after the
Crossplane finalizers are removed.
### User Experience - After
#### Claim Delete - Background (no change)
#### Claim Delete - Foreground
- A Claim exists with compositeDeletePolicy: Foreground.
- User executes _kubectl delete -n namespace <claim name>_.
- Kubernetes adds the deletionTimestamp attribute to the claim's metadata.
- There are no resources with ownerReferences that point at the claim so no
finalizers are added at this stage.
- Crossplane claim reconciler detects the deletion and executes a Kubernetes API
Delete on the associated Composite with the Foreground propagation policy
- Kubernetes generates a graph of resources using ownerReferences, adds
_foregroundDeletion_ finalizers to all "controller" objects, and marks all
resources as deleted with deletionTimestamp.
- Crossplane composite and managed reconcilers detect the deletion:
- The Composite reconcilers delete the associated ConnectionDetails and
remove the Crossplane finalizer. The _foregroundDeletion_ finalizer on the
Composites block garbage collection from deleting the resource.
- The Managed reconcilers delete the remote external resources and remove the
Crossplane finalizer, and garbage collection removes the resources.
- When all the Composed Resources for a Composite have been removed, Kubernetes
removes the _foregroundDeletion_ finalizer from the Composite, and it is
removed by garbage collection.
- This process repeats itself until all the Composites have been deleted,
including the root Composite.
- The Claim reconciler detects that the Composite has been deleted and removes
the Crossplane finalizer.
- Kubernetes garbage collection removes the Claim object after the Crossplane
finalizer has been removed.
#### Standalone Composite Delete - Background (no change)
#### Composite Delete - Foreground
- User executes _kubectl delete --cascade=foreground <composite name>_.
- Kubernetes adds the deletionTimestamp attribute to the composite's metadata.
- Kubernetes generates a graph of resources using ownerReferences, adds
_foregroundDeletion_ finalizers to all "controller" objects, and marks all
resources as deleted with deletionTimestamp.
- Crossplane composite and managed reconcilers detect the deletion:
- The Composite reconcilers delete the associated ConnectionDetails and
remove the Crossplane finalizer. The _foregroundDeletion_ finalizer on the
Composites block garbage collection from deleting the resource.
- The Managed reconcilers delete the remote external resources and remove the
Crossplane finalizer, and garbage collection removes the resources.
- When all the Composed Resources for a Composite have been removed, Kubernetes
removes the _foregroundDeletion_ finalizer from the Composite, and it is
removed by garbage collection.
- This process repeats itself until all the Composites have been deleted,
including the root Composite.
### Implementation
Support for Foreground Cascading Deletion requires:
- setting the _blockOwnerDeletion_ flag to true on all Controller
ownerReferences created by Crossplane
- adding a compositeDeletePolicy attribute to the Claim API
- update the claim reconciler to use the compositeDeletePolicy when calling
Delete() on the composite
- update the claim reconciler to requeue and wait for the composite to finish
deletion in the Foreground case
Setting the _blockOwnerDeletion_ flag in the Controller ownerReference is
required to indicate that Kubernetes should set the _foregroundDeletion_
finalizer on the owner resource when foreground cascading deletion is specified.
This is the also expected configuration for controller owner references as
described in the Kubernetes server.
We can simulate foreground cascading deletion on Claim objects by adding a
compositeDeletePolicy attribute to the Claim specification. This attribute will
determine the propagation policy that should be used by the Claim reconciler
when it calls the Delete() function on the associated Composite object. If the
compositeDeletePolicy value is "Foreground", then the Composite will be deleted
with the Foreground propagation policy and the Claim reconciler will requeue as
long as the Composite resource is not deleted.
[foreground]: https://kubernetes.io/docs/tasks/administer-cluster/use-cascading-deletion/
[block]: https://github.com/kubernetes/kubernetes/blob/master/pkg/controller/controller_utils.go#L510
[1612]: https://github.com/crossplane/crossplane/issues/1612

View File

@ -37,6 +37,17 @@ spec:
apiVersion: database.example.org/v1alpha1
kind: PostgreSQLInstance
name: my-db
# The compositeDeletePolicy specifies the propagation policy that will be used by Crossplane
# when deleting the Composite Resource that is associated with the Claim. The default
# value is Background, which causes the Composite resource to be deleted using
# the kubernetes default propagation policy of Background, and all associated
# resources will be deleted simultaneously. The other value for this field is Foreground,
# which will cause the Composite resource to be deleted using Foreground Cascading Deletion.
# Kubernetes will add a foregroundDeletion finalizer to all of the resources in the
# dependency graph, and they will be deleted starting with the edge or leaf nodes and
# working back towards the root Composite. See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#cascading-deletion
# for more information on cascading deletion.
compositeDeletePolicy: Background
# The compositionRef specifies which Composition this XR will use to compose
# resources when it is created, updated, or deleted. This can be omitted and
# will be set automatically if the XRD has a default or enforced composition

2
go.mod
View File

@ -5,7 +5,7 @@ go 1.19
require (
github.com/Masterminds/semver v1.5.0
github.com/alecthomas/kong v0.2.17
github.com/crossplane/crossplane-runtime v0.19.0-rc.0.0.20220930073209-84e629b95898
github.com/crossplane/crossplane-runtime v0.19.0-rc.0.0.20221012013934-bce61005a175
github.com/google/go-cmp v0.5.8
github.com/google/go-containerregistry v0.9.0
github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20220517194345-84eb52633e96

4
go.sum
View File

@ -248,8 +248,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/crossplane/crossplane-runtime v0.19.0-rc.0.0.20220930073209-84e629b95898 h1:vzNAK/BejxhHTURzVUjeAusBPuv5K5Nf0ae0JdK69tQ=
github.com/crossplane/crossplane-runtime v0.19.0-rc.0.0.20220930073209-84e629b95898/go.mod h1:o9ExoilV6k2M3qzSFoRVX4phuww0mLmjs1WrDTvsR4s=
github.com/crossplane/crossplane-runtime v0.19.0-rc.0.0.20221012013934-bce61005a175 h1:qGLew6IazCwfgvY4/xh5lQiumip/WrULpQfW4duol6g=
github.com/crossplane/crossplane-runtime v0.19.0-rc.0.0.20221012013934-bce61005a175/go.mod h1:o9ExoilV6k2M3qzSFoRVX4phuww0mLmjs1WrDTvsR4s=
github.com/daixiang0/gci v0.2.9/go.mod h1:+4dZ7TISfSmqfAGv59ePaHfNzgGtIkHAhhdKggP1JAc=
github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg=
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

View File

@ -374,6 +374,12 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
cm.SetConditions(xpv1.Deleting())
if meta.WasCreated(cp) {
if meta.WasDeleted(cp) {
if *cm.GetCompositeDeletePolicy() == xpv1.CompositeDeleteForeground {
log.Debug("Waiting for the Composite to finish deleting (foreground deletion)")
return reconcile.Result{Requeue: true}, nil
}
}
ref := cp.GetClaimReference()
want := meta.ReferenceTo(cm, cm.GetObjectKind().GroupVersionKind())
if !cmp.Equal(want, ref, cmpopts.IgnoreFields(corev1.ObjectReference{}, "UID")) {
@ -390,13 +396,21 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
return reconcile.Result{Requeue: false}, errors.Wrap(r.client.Status().Update(ctx, cm), errUpdateClaimStatus)
}
if err := r.client.Delete(ctx, cp); resource.IgnoreNotFound(err) != nil {
do := &client.DeleteOptions{}
if *cm.GetCompositeDeletePolicy() == xpv1.CompositeDeleteForeground {
client.PropagationPolicy(metav1.DeletePropagationForeground).ApplyToDelete(do)
}
if err := r.client.Delete(ctx, cp, do); resource.IgnoreNotFound(err) != nil {
log.Debug(errDeleteComposite, "error", err)
err = errors.Wrap(err, errDeleteComposite)
record.Event(cm, event.Warning(reasonDelete, err))
cm.SetConditions(xpv1.ReconcileError(err))
return reconcile.Result{Requeue: true}, errors.Wrap(r.client.Status().Update(ctx, cm), errUpdateClaimStatus)
}
if *cm.GetCompositeDeletePolicy() == xpv1.CompositeDeleteForeground {
log.Debug("Requeue to wait for the Composite to finish deleting (foreground deletion)")
return reconcile.Result{Requeue: true}, nil
}
}
// Claims do not publish connection details but may propagate XR

View File

@ -203,6 +203,8 @@ func TestReconcile(t *testing.T) {
o.SetName(name)
o.SetDeletionTimestamp(&now)
o.SetResourceReference(&corev1.ObjectReference{})
bg := xpv1.CompositeDeleteBackground
o.SetCompositeDeletePolicy(&bg)
}),
},
want: want{
@ -212,6 +214,8 @@ func TestReconcile(t *testing.T) {
o.SetDeletionTimestamp(&now)
o.SetResourceReference(&corev1.ObjectReference{})
o.SetConditions(xpv1.Deleting(), xpv1.ReconcileError(errors.Wrap(errBoom, errDeleteComposite)))
bg := xpv1.CompositeDeleteBackground
o.SetCompositeDeletePolicy(&bg)
}),
r: reconcile.Result{Requeue: true},
},
@ -252,6 +256,13 @@ func TestReconcile(t *testing.T) {
WithClientApplicator(resource.ClientApplicator{
Client: &test.MockClient{
MockDelete: test.NewMockDeleteFn(nil),
MockGet: test.NewMockGetFn(nil, func(obj client.Object) error {
if o, ok := obj.(*composite.Unstructured); ok {
o.SetCreationTimestamp(metav1.Now())
o.SetClaimReference(&corev1.ObjectReference{Name: name})
}
return nil
}),
},
}),
WithClaimFinalizer(resource.FinalizerFns{
@ -259,19 +270,106 @@ func TestReconcile(t *testing.T) {
}),
},
claim: withClaim(func(o *claim.Unstructured) {
o.SetName(name)
o.SetDeletionTimestamp(&now)
bg := xpv1.CompositeDeleteBackground
o.SetCompositeDeletePolicy(&bg)
o.SetResourceReference(&corev1.ObjectReference{})
}),
},
want: want{
claim: withClaim(func(o *claim.Unstructured) {
o.SetName(name)
o.SetDeletionTimestamp(&now)
o.SetResourceReference(&corev1.ObjectReference{})
bg := xpv1.CompositeDeleteBackground
o.SetCompositeDeletePolicy(&bg)
o.SetConditions(xpv1.Deleting(), xpv1.ReconcileSuccess())
}),
r: reconcile.Result{Requeue: false},
},
},
"SuccessfulForegroundDelete": {
reason: "We should requeue if we successfully delete the bound composite resource using Foreground deletion",
args: args{
mgr: &fake.Manager{},
opts: []ReconcilerOption{
WithClientApplicator(resource.ClientApplicator{
Client: &test.MockClient{
MockDelete: test.NewMockDeleteFn(nil),
MockGet: test.NewMockGetFn(nil, func(obj client.Object) error {
if o, ok := obj.(*composite.Unstructured); ok {
o.SetCreationTimestamp(metav1.Now())
o.SetClaimReference(&corev1.ObjectReference{Name: name})
}
return nil
}),
},
}),
WithClaimFinalizer(resource.FinalizerFns{
RemoveFinalizerFn: func(ctx context.Context, obj resource.Object) error { return nil },
}),
},
claim: withClaim(func(o *claim.Unstructured) {
o.SetName(name)
o.SetDeletionTimestamp(&now)
fg := xpv1.CompositeDeleteForeground
o.SetCompositeDeletePolicy(&fg)
o.SetResourceReference(&corev1.ObjectReference{})
}),
},
want: want{
claim: withClaim(func(o *claim.Unstructured) {
o.SetName(name)
o.SetDeletionTimestamp(&now)
o.SetResourceReference(&corev1.ObjectReference{})
fg := xpv1.CompositeDeleteForeground
o.SetCompositeDeletePolicy(&fg)
}),
r: reconcile.Result{Requeue: true},
},
},
"ForegroundDeleteWaitForCompositeDeletion": {
reason: "We should requeue if we successfully deleted the bound composite resource using Foreground deletion and it has not yet been deleted",
args: args{
mgr: &fake.Manager{},
opts: []ReconcilerOption{
WithClientApplicator(resource.ClientApplicator{
Client: &test.MockClient{
MockDelete: test.NewMockDeleteFn(nil),
MockGet: test.NewMockGetFn(nil, func(obj client.Object) error {
if o, ok := obj.(*composite.Unstructured); ok {
o.SetCreationTimestamp(now)
o.SetDeletionTimestamp(&now)
o.SetClaimReference(&corev1.ObjectReference{Name: name})
}
return nil
}),
},
}),
WithClaimFinalizer(resource.FinalizerFns{
RemoveFinalizerFn: func(ctx context.Context, obj resource.Object) error { return nil },
}),
},
claim: withClaim(func(o *claim.Unstructured) {
o.SetName(name)
o.SetDeletionTimestamp(&now)
fg := xpv1.CompositeDeleteForeground
o.SetCompositeDeletePolicy(&fg)
o.SetResourceReference(&corev1.ObjectReference{})
}),
},
want: want{
claim: withClaim(func(o *claim.Unstructured) {
o.SetName(name)
o.SetDeletionTimestamp(&now)
o.SetResourceReference(&corev1.ObjectReference{})
fg := xpv1.CompositeDeleteForeground
o.SetCompositeDeletePolicy(&fg)
}),
r: reconcile.Result{Requeue: true},
},
},
"AddFinalizerError": {
reason: "We should return any error we encounter while adding the claim's finalizer",
args: args{

View File

@ -242,8 +242,9 @@ func TestFetchRevision(t *testing.T) {
v1alpha1.LabelCompositionSpecHash: comp.Spec.Hash(),
},
OwnerReferences: []metav1.OwnerReference{{
UID: comp.GetUID(),
Controller: &ctrl,
UID: comp.GetUID(),
Controller: &ctrl,
BlockOwnerDeletion: &ctrl,
}},
},
Spec: v1alpha1.CompositionRevisionSpec{Revision: 2},
@ -257,8 +258,9 @@ func TestFetchRevision(t *testing.T) {
v1alpha1.LabelCompositionSpecHash: "I'm different!",
},
OwnerReferences: []metav1.OwnerReference{{
UID: comp.GetUID(),
Controller: &ctrl,
UID: comp.GetUID(),
Controller: &ctrl,
BlockOwnerDeletion: &ctrl,
}},
},
Spec: v1alpha1.CompositionRevisionSpec{Revision: 1},

View File

@ -230,7 +230,7 @@ func TestRender(t *testing.T) {
xcrd.LabelKeyClaimName: "rola",
xcrd.LabelKeyClaimNamespace: "rolans",
},
OwnerReferences: []metav1.OwnerReference{{Controller: &ctrl}},
OwnerReferences: []metav1.OwnerReference{{Controller: &ctrl, BlockOwnerDeletion: &ctrl}},
}},
err: errors.Wrap(errBoom, errName),
},
@ -245,7 +245,7 @@ func TestRender(t *testing.T) {
xcrd.LabelKeyClaimNamespace: "rolans",
}}},
cd: &fake.Composed{ObjectMeta: metav1.ObjectMeta{Name: "cd",
OwnerReferences: []metav1.OwnerReference{{Controller: &ctrl,
OwnerReferences: []metav1.OwnerReference{{Controller: &ctrl, BlockOwnerDeletion: &ctrl,
UID: "random_uid"}}}},
t: v1.ComposedTemplate{Base: runtime.RawExtension{Raw: tmpl}},
},
@ -258,7 +258,7 @@ func TestRender(t *testing.T) {
xcrd.LabelKeyClaimName: "rola",
xcrd.LabelKeyClaimNamespace: "rolans",
},
OwnerReferences: []metav1.OwnerReference{{Controller: &ctrl,
OwnerReferences: []metav1.OwnerReference{{Controller: &ctrl, BlockOwnerDeletion: &ctrl,
UID: "random_uid"}},
}},
err: errors.Wrap(errors.Errorf("cd is already controlled by (UID random_uid)"), errSetControllerRef),
@ -285,7 +285,7 @@ func TestRender(t *testing.T) {
xcrd.LabelKeyClaimName: "rola",
xcrd.LabelKeyClaimNamespace: "rolans",
},
OwnerReferences: []metav1.OwnerReference{{Controller: &ctrl}},
OwnerReferences: []metav1.OwnerReference{{Controller: &ctrl, BlockOwnerDeletion: &ctrl}},
}},
},
},
@ -468,8 +468,9 @@ func TestGarbageCollectingAssociator(t *testing.T) {
// This resource is not controlled by us.
ctrl := true
obj.SetOwnerReferences([]metav1.OwnerReference{{
Controller: &ctrl,
UID: types.UID("who-dat"),
Controller: &ctrl,
BlockOwnerDeletion: &ctrl,
UID: types.UID("who-dat"),
}})
return nil
}),

View File

@ -36,6 +36,7 @@ import (
"github.com/crossplane/crossplane-runtime/pkg/logging"
"github.com/crossplane/crossplane-runtime/pkg/resource/fake"
"github.com/crossplane/crossplane-runtime/pkg/test"
v1 "github.com/crossplane/crossplane/apis/apiextensions/v1"
"github.com/crossplane/crossplane/apis/apiextensions/v1alpha1"
)
@ -66,8 +67,9 @@ func TestReconcile(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{
Name: comp.GetName() + "-2",
OwnerReferences: []metav1.OwnerReference{{
UID: comp.GetUID(),
Controller: &ctrl,
UID: comp.GetUID(),
Controller: &ctrl,
BlockOwnerDeletion: &ctrl,
}},
Labels: map[string]string{
v1alpha1.LabelCompositionSpecHash: "some-older-hash",
@ -87,8 +89,9 @@ func TestReconcile(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{
Name: comp.GetName() + "-3",
OwnerReferences: []metav1.OwnerReference{{
UID: comp.GetUID(),
Controller: &ctrl,
UID: comp.GetUID(),
Controller: &ctrl,
BlockOwnerDeletion: &ctrl,
}},
Labels: map[string]string{
v1alpha1.LabelCompositionSpecHash: comp.Spec.Hash(),
@ -108,8 +111,9 @@ func TestReconcile(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{
Name: comp.GetName() + "-4",
OwnerReferences: []metav1.OwnerReference{{
UID: comp.GetUID(),
Controller: &ctrl,
UID: comp.GetUID(),
Controller: &ctrl,
BlockOwnerDeletion: &ctrl,
}},
Labels: map[string]string{
v1alpha1.LabelCompositionSpecHash: comp.Spec.Hash(),

View File

@ -205,10 +205,11 @@ func TestNewCompositionRevision(t *testing.T) {
v1alpha1.LabelCompositionSpecHash: hash,
},
OwnerReferences: []metav1.OwnerReference{{
APIVersion: v1.SchemeGroupVersion.String(),
Kind: v1.CompositionKind,
Name: comp.GetName(),
Controller: &ctrl,
APIVersion: v1.SchemeGroupVersion.String(),
Kind: v1.CompositionKind,
Name: comp.GetName(),
Controller: &ctrl,
BlockOwnerDeletion: &ctrl,
}},
},
Spec: v1alpha1.CompositionRevisionSpec{

View File

@ -37,11 +37,12 @@ func TestRenderClusterRoles(t *testing.T) {
ctrl := true
owner := metav1.OwnerReference{
APIVersion: v1.CompositeResourceDefinitionGroupVersionKind.GroupVersion().String(),
Kind: v1.CompositeResourceDefinitionKind,
Name: name,
UID: uid,
Controller: &ctrl,
APIVersion: v1.CompositeResourceDefinitionGroupVersionKind.GroupVersion().String(),
Kind: v1.CompositeResourceDefinitionKind,
Name: name,
UID: uid,
Controller: &ctrl,
BlockOwnerDeletion: &ctrl,
}
cases := map[string]struct {

View File

@ -124,11 +124,12 @@ func TestRenderClusterRoles(t *testing.T) {
ctrl := true
owner := metav1.OwnerReference{
APIVersion: "v1",
Kind: "Namespace",
Name: name,
UID: uid,
Controller: &ctrl,
APIVersion: "v1",
Kind: "Namespace",
Name: name,
UID: uid,
Controller: &ctrl,
BlockOwnerDeletion: &ctrl,
}
crNameA := "A"

View File

@ -34,11 +34,12 @@ func TestRenderClusterRoles(t *testing.T) {
ctrl := true
crCtrlr := metav1.OwnerReference{
APIVersion: v1.ProviderRevisionGroupVersionKind.GroupVersion().String(),
Kind: v1.ProviderRevisionKind,
Name: prName,
UID: prUID,
Controller: &ctrl,
APIVersion: v1.ProviderRevisionGroupVersionKind.GroupVersion().String(),
Kind: v1.ProviderRevisionKind,
Name: prName,
UID: prUID,
Controller: &ctrl,
BlockOwnerDeletion: &ctrl,
}
nameEdit := namePrefix + prName + nameSuffixEdit

View File

@ -637,7 +637,12 @@ func TestForCompositeResourceClaim(t *testing.T) {
{Raw: []byte(`"5.7"`)},
},
},
"compositeDeletePolicy": {
Type: "string",
Default: &extv1.JSON{Raw: []byte(`"Background"`)},
Enum: []extv1.JSON{{Raw: []byte(`"Background"`)},
{Raw: []byte(`"Foreground"`)}},
},
// From CompositeResourceClaimSpecProps()
"compositionRef": {
Type: "object",

View File

@ -216,6 +216,13 @@ func CompositeResourceClaimSpecProps() map[string]extv1.JSONSchemaProps {
},
Default: &extv1.JSON{Raw: []byte(`"Automatic"`)},
},
"compositeDeletePolicy": {
Type: "string",
Enum: []extv1.JSON{
{Raw: []byte(`"Background"`)},
{Raw: []byte(`"Foreground"`)},
},
Default: &extv1.JSON{Raw: []byte(`"Background"`)}},
"resourceRef": {
Type: "object",
Required: []string{"apiVersion", "kind", "name"},