This composition function automatically detects composed resources that are ready. It considers a composed resource ready if:
- Another function added the composed resource to the desired state.
- The composed resource appears in the observed state (i.e. it exists).
- For standard Kubernetes resources with health check implementations (see list below), the resource passes resource-specific health checks.
- For all other resources (Crossplane managed resources, custom resources, etc.), the composed resource has the status condition
type: Ready,status: True.
Crossplane considers a composite resource (XR) to be ready when all of its desired composed resources are ready.
This function implements resource-specific health checks for standard Kubernetes resources. The following table shows the current implementation status:
- Pod - Succeeded, or Running with Ready condition (RestartPolicy: Always)
- Service - ClusterIP/NodePort: immediately ready; LoadBalancer: requires ingress assignment
- Namespace - Always ready if it exists
- Node
- ConfigMap - Always ready if it exists
- Secret - Always ready if it exists
- ServiceAccount - Always ready if it exists
- Endpoints
- PersistentVolume
- PersistentVolumeClaim - Phase is Bound
- ReplicationController
- ResourceQuota
- LimitRange
- Event
- Deployment -
spec.replicas == status.availableReplicas, all replicas updated,Availablecondition isTrue - StatefulSet -
spec.replicas == status.readyReplicas, all replicas at current revision - DaemonSet - All desired pods are scheduled, ready, updated, and available
- ReplicaSet - Observed generation matches, available replicas match desired, no replica failures
- Job - Complete condition is True (not Failed or Suspended)
- CronJob - Suspended, has active jobs, or last execution succeeded
- HorizontalPodAutoscaler - ScalingActive or ScalingLimited, no failed conditions
- Ingress - Load balancer ingress is assigned
- IngressClass
- NetworkPolicy
- Role
- ClusterRole
- RoleBinding
- ClusterRoleBinding
- StorageClass
- VolumeAttachment
- CSIDriver
- CSINode
- PodDisruptionBudget
For all other resource types (Crossplane managed resources, custom resources, etc.), the function falls back to checking the standard Ready status condition.
Some resource types — notably Crossplane Configuration and Provider
packages, Cluster API Cluster and many more — do not surface a Ready status condition, so the default
fallback never considers them ready. To handle these cases the function
supports user-defined readiness expressions written in
CEL, gated behind the CELHealthcheckCustomizations alpha feature
gate.
Enable the feature gate when running the function:
function-auto-ready --feature-gates=CELHealthcheckCustomizations=trueCustomizations are supplied as a map keyed by <group>_<version>_<kind>
(the group's dots replaced with underscores; the core group is the empty
string). Each value is a CEL expression evaluated against the observed
composed resource, bound to the variable object. The expression must
return a boolean — any other result, or an evaluation error, is treated
as not ready and surfaces a Warning on the response. When a customization
exists for a given GVK it takes precedence over the built-in health check.
There are two ways to supply customizations, and they can be combined:
Define rules directly in the function input. This is the simplest option when the rules are static and do not need to vary across environments:
- step: automatically-detect-ready-composed-resources
functionRef:
name: function-auto-ready
input:
apiVersion: autoready.fn.crossplane.io/v1alpha1
kind: Input
celHealthCheckCustomization:
pkg.crossplane.io_v1_Configuration: >-
object.status.conditions.exists(c, c.type == 'Installed' && c.status == 'True') &&
object.status.conditions.exists(c, c.type == 'Healthy' && c.status == 'True')
cluster.cluster.x-k8s.io_v1beta1_Cluster: >-
object.status.conditions.exists(c, c.type == 'Ready' && c.status == 'True')Read the map from the function's request context by providing a field path. This is useful when rules need to vary per environment or be shared across multiple compositions:
- step: automatically-detect-ready-composed-resources
functionRef:
name: function-auto-ready
input:
apiVersion: autoready.fn.crossplane.io/v1alpha1
kind: Input
celHealthCheckCustomizationFrom: "[apiextensions.crossplane.io/environment].celHealthCheckCustomizations"Any source that populates the function context can supply the map —
typically function-environment-configs reading an EnvironmentConfig,
but an earlier pipeline step works just as well.
Both fields can be set at the same time. Context-provided rules are loaded first; inline rules are then merged on top of them. Inline entries take precedence, so they can selectively override context-provided rules for specific GVKs without replacing the entire map.
See example/cel-healthcheck for a runnable
example that checks the Installed and Healthy conditions on a
Crossplane Configuration.
In this example, the Go Templating function is used to add a desired composed resource - an Amazon Web Services S3 Bucket. Once Crossplane has created the Bucket, the Auto Ready function will let Crossplane know when it is ready. Because this XR only has one composed resource, the XR will become ready when the Bucket becomes ready.
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example
spec:
compositeTypeRef:
apiVersion: example.crossplane.io/v1beta1
kind: XR
mode: Pipeline
pipeline:
- step: create-a-bucket
functionRef:
name: function-go-templating
input:
apiVersion: gotemplating.fn.crossplane.io/v1beta1
kind: GoTemplate
source: Inline
inline:
template: |
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
annotations:
gotemplating.fn.crossplane.io/composition-resource-name: bucket
spec:
forProvider:
region: {{ .observed.composite.resource.spec.region }}
- step: automatically-detect-ready-composed-resources
functionRef:
name: function-auto-readySee the example directory for an example you can run locally using the Crossplane CLI:
$ crossplane render xr.yaml composition.yaml functions.yamlTo test with observed resources (simulating resources that already exist):
$ crossplane render xr.yaml composition-k8s.yaml functions.yaml -o observed-k8s.yamlSee the composition functions documentation to learn more
about crossplane render.
You can set the ttl input to control the Function response cache time-to-live.
This is useful for tuning reconciliation behavior in large compositions.
- step: auto-detect-ready-resources
functionRef:
name: function-auto-ready
input:
apiVersion: autoready.fn.crossplane.io/v1beta1
kind: Input
ttl: 5mThere is also a --ttl input parameter to the function that can be used to set the default TTL used when it is not set
in the composition function input. Use a DeploymentRuntimeConfig to set this parameter.
apiVersion: pkg.crossplane.io/v1beta1
kind: DeploymentRuntimeConfig
metadata:
name: function-auto-ready
spec:
deploymentTemplate:
spec:
selector: {}
template:
spec:
containers:
- name: package-runtime
args:
- --debug
- --ttl="5m"This function uses Go, Docker, and the Crossplane CLI to build functions.
# Run code generation - see input/generate.go
$ go generate ./...
# Run tests - see fn_test.go
$ go test ./...
# Build the function's runtime image - see Dockerfile
$ docker build . --tag=runtime
# Build a function package - see package/crossplane.yaml
$ crossplane xpkg build -f package --embed-runtime-image=runtime