Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 64 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# function-sequencer

Function Sequencer is a Crossplane function that enables Composition authors to define sequencing rules delaying the
creation of resources until other resources are ready.
creation of resources until other resources are ready. The same sequencing rules can be used, in reverse, to define the order that resources are deleted, when foreground cascading deletion is used.

For example, the pipeline step below, will ensure that `second-resource` and `third-resource` not to be created until
For example, the pipeline step below will ensure that `second-resource` and `third-resource` not to be created until
the `first-resource` is ready.

```yaml
Expand Down Expand Up @@ -71,6 +71,68 @@ state prematurely when there are pending resources that the composite reconciler
- first-subresource-.*
- second-resource
```
## Deletion Sequencing
The same rule sequences can be used to determine the order in which the resources should be deleted.
Deletion Sequencing is enabled by setting the `enableDeletionSequencing` input to `true` and causes the function to create
`Usage` and `ClusterUsage` resources to enforce the proper order of resource deletion.

Deletion Sequencing requires that
[foreground cascading deletion](https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion)
is used when the composite resource is deleted.

The `usageVersion` input attribute controls
whether the function creates Crossplane v1 `Usage.apiextensions.crossplane.io` resources or Crossplane v2
`Usage.protection.crossplane.io` and `ClusterUsage.protection.crossplane.io` resources.

The `replayDeletion` input is mapped to the `Usage`/`ClusterUsage` `replayDeletion` attribute which determines whether
deletion of a resource is retried after the initial attempt. This can significantly reduce the amount of time
required to delete all the resources in a composite and defaults to `true` for the deletion
sequencing use case. This can be disabled by setting `replayDeletion` to `false`.

```yaml
- step: sequence-creation-and-deletion
functionRef:
name: function-sequencer
input:
apiVersion: sequencer.fn.crossplane.io/v1beta1
kind: Input
enableDeletionSequencing: true
replayDeletion: true
rules:
- sequence:
- first
- second
- third
usageVersion: v1
```
creates two `Usage` resources, one for the `third`->`second` dependency and one for the `second`->`first` dependency.
When the composite is deleted with the option `--cascade=foreground` the `third` resource will be deleted, followed by
the `second` and finally the `first`.

### Regular Expressions

Deletion sequencing creates `Usage`/`ClusterUsage` resources for all dependencies identified by the input sequences, including
those defined by pattern matching. For example:

```yaml
- step: sequence-creation-and-deletion
functionRef:
name: function-sequencer
input:
apiVersion: sequencer.fn.crossplane.io/v1beta1
kind: Input
enableDeletionSequencing: true
replayDeletion: true
rules:
- sequence:
- first-subresource-.*
- second-resource
usageVersion: v1
```

creates a `Usage` resource for every resource that matches `first-subresource-*`, with `by` set to the `second-resource`.
This ensures that `second-resource` is deleted before any of the `first-resource-*` resources are deleted.

## Installation

It can be installed as follows from the Upbound marketplace: https://marketplace.upbound.io/functions/crossplane-contrib/function-sequencer
Expand Down
267 changes: 264 additions & 3 deletions example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
You can run your function locally and test it using `crossplane beta render`
with these example manifests.

### Run the function locally

```shell
# Run the function locally
$ go run . --insecure --debug
```

### Then, in another terminal, call it with these example manifests

```shell
# Then, in another terminal, call it with these example manifests
$ crossplane beta render xr.yaml composition.yaml functions.yaml -r
$ crossplane render xr.yaml composition.yaml functions.yaml -r
---
apiVersion: example.crossplane.io/v1
kind: XR
Expand All @@ -23,3 +25,262 @@ message: I was run with input "Hello world"!
severity: SEVERITY_NORMAL
step: run-the-template
```

### Regex Pattern Example
```shell
$ crossplane render xr.yaml composition-regex.yaml functions.yaml -r -o observed-regex.yaml
---
apiVersion: example.crossplane.io/v1
kind: XR
metadata:
name: example-xr
status:
conditions:
- lastTransitionTime: "2024-01-01T00:00:00Z"
message: 'Unready resources: second-object'
reason: Creating
status: "False"
type: Ready
---
apiVersion: nop.crossplane.io/v1alpha1
kind: NopResource
metadata:
annotations:
crossplane.io/composition-resource-name: first-subresource-1
labels:
crossplane.io/composite: example-xr
name: first-subresource-1
ownerReferences:
- apiVersion: example.crossplane.io/v1
blockOwnerDeletion: true
controller: true
kind: XR
name: example-xr
uid: ""
spec:
forProvider:
conditionAfter:
- conditionStatus: "False"
conditionType: Ready
time: 5s
- conditionStatus: "True"
conditionType: Ready
time: 10s
- conditionStatus: "False"
conditionType: Ready
time: 30s
- conditionStatus: "True"
conditionType: Ready
time: 90s
---
apiVersion: nop.crossplane.io/v1alpha1
kind: NopResource
metadata:
annotations:
crossplane.io/composition-resource-name: first-subresource-2
labels:
crossplane.io/composite: example-xr
name: first-subresource-2
ownerReferences:
- apiVersion: example.crossplane.io/v1
blockOwnerDeletion: true
controller: true
kind: XR
name: example-xr
uid: ""
spec:
forProvider:
conditionAfter:
- conditionStatus: "False"
conditionType: Ready
time: 5s
- conditionStatus: "True"
conditionType: Ready
time: 10s
---
apiVersion: nop.crossplane.io/v1alpha1
kind: NopResource
metadata:
annotations:
crossplane.io/composition-resource-name: second-object
labels:
crossplane.io/composite: example-xr
name: second-object
ownerReferences:
- apiVersion: example.crossplane.io/v1
blockOwnerDeletion: true
controller: true
kind: XR
name: example-xr
uid: ""
spec:
forProvider:
conditionAfter:
- conditionStatus: "False"
conditionType: Ready
time: 5s
- conditionStatus: "True"
conditionType: Ready
time: 10s
---
apiVersion: render.crossplane.io/v1beta1
kind: Result
message: Delaying creation of resource(s) matching "third-resource" because "object$"
is not fully ready (0 of 1)
severity: SEVERITY_NORMAL
step: sequence-creation
```
### Deletion Sequencing Example
```shell
$ crossplane render xr.yaml composition-with-deletion-sequencing.yaml functions.yaml -r -o observed-deletion-sequencing.yaml
---
apiVersion: example.crossplane.io/v1
kind: XR
metadata:
name: example-xr
status:
conditions:
- lastTransitionTime: "2024-01-01T00:00:00Z"
reason: Available
status: "True"
type: Ready
---
apiVersion: nop.crossplane.io/v1alpha1
kind: NopResource
metadata:
annotations:
crossplane.io/composition-resource-name: first-resource
labels:
crossplane.io/composite: example-xr
name: first
ownerReferences:
- apiVersion: example.crossplane.io/v1
blockOwnerDeletion: true
controller: true
kind: XR
name: example-xr
uid: ""
spec:
forProvider:
conditionAfter:
- conditionStatus: "False"
conditionType: Ready
time: 5s
- conditionStatus: "True"
conditionType: Ready
time: 10s
- conditionStatus: "False"
conditionType: Ready
time: 30s
- conditionStatus: "True"
conditionType: Ready
time: 90s
---
apiVersion: nop.crossplane.io/v1alpha1
kind: NopResource
metadata:
annotations:
crossplane.io/composition-resource-name: second-resource
labels:
crossplane.io/composite: example-xr
name: second
ownerReferences:
- apiVersion: example.crossplane.io/v1
blockOwnerDeletion: true
controller: true
kind: XR
name: example-xr
uid: ""
spec:
forProvider:
conditionAfter:
- conditionStatus: "False"
conditionType: Ready
time: 5s
- conditionStatus: "True"
conditionType: Ready
time: 10s
---
apiVersion: apiextensions.crossplane.io/v1beta1
kind: Usage
metadata:
annotations:
crossplane.io/composition-resource-name: second-resource-first-resource-usage
labels:
crossplane.io/composite: example-xr
name: nopresource-second-nopresource-first-4f1a57-dependency
ownerReferences:
- apiVersion: example.crossplane.io/v1
blockOwnerDeletion: true
controller: true
kind: XR
name: example-xr
uid: ""
spec:
by:
apiVersion: nop.crossplane.io/v1alpha1
kind: NopResource
resourceRef:
name: second
of:
apiVersion: nop.crossplane.io/v1alpha1
kind: NopResource
resourceRef:
name: first
reason: dependency
replayDeletion: true
---
apiVersion: nop.crossplane.io/v1alpha1
kind: NopResource
metadata:
annotations:
crossplane.io/composition-resource-name: third-resource
labels:
crossplane.io/composite: example-xr
name: third
ownerReferences:
- apiVersion: example.crossplane.io/v1
blockOwnerDeletion: true
controller: true
kind: XR
name: example-xr
uid: ""
spec:
forProvider:
conditionAfter:
- conditionStatus: "False"
conditionType: Ready
time: 5s
- conditionStatus: "True"
conditionType: Ready
time: 10s
---
apiVersion: apiextensions.crossplane.io/v1beta1
kind: Usage
metadata:
annotations:
crossplane.io/composition-resource-name: third-resource-first-resource-usage
labels:
crossplane.io/composite: example-xr
name: nopresource-third-nopresource-first-1b4fc5-dependency
ownerReferences:
- apiVersion: example.crossplane.io/v1
blockOwnerDeletion: true
controller: true
kind: XR
name: example-xr
uid: ""
spec:
by:
apiVersion: nop.crossplane.io/v1alpha1
kind: NopResource
resourceRef:
name: third
of:
apiVersion: nop.crossplane.io/v1alpha1
kind: NopResource
resourceRef:
name: first
reason: dependency
replayDeletion: true
```
Loading
Loading