Update crossplane-runtime and support foreground deletion
Signed-off-by: Bob Haddleton <bob.haddleton@nokia.com>
This commit is contained in:
parent
ff08fb4a41
commit
ba4c8a43ab
|
@ -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
|
|
@ -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
2
go.mod
|
@ -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
4
go.sum
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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
|
||||
}),
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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"},
|
||||
|
|
Loading…
Reference in New Issue