# Table of Contents - [Welcome · Crossplane v2.0](#welcome-crossplane-v2-0) - [Welcome · Crossplane v2.0](#welcome-crossplane-v2-0) - [What’s Crossplane? · Crossplane v2.0](#what-s-crossplane-crossplane-v2-0) - [Install Crossplane · Crossplane v2.0](#install-crossplane-crossplane-v2-0) - [Get Started · Crossplane v2.0](#get-started-crossplane-v2-0) - [Composition · Crossplane v2.0](#composition-crossplane-v2-0) - [Get Started With Operations · Crossplane v2.0](#get-started-with-operations-crossplane-v2-0) - [Get Started With Composition · Crossplane v2.0](#get-started-with-composition-crossplane-v2-0) - [What’s New in v2? · Crossplane v2.0](#what-s-new-in-v2-crossplane-v2-0) - [Get Started With Managed Resources · Crossplane v2.0](#get-started-with-managed-resources-crossplane-v2-0) - [Composition Revisions · Crossplane v2.0](#composition-revisions-crossplane-v2-0) - [Managed Resource Activation Policies · Crossplane v2.0](#managed-resource-activation-policies-crossplane-v2-0) - [Composite Resource Definitions · Crossplane v2.0](#composite-resource-definitions-crossplane-v2-0) - [Operations · Crossplane v2.0](#operations-crossplane-v2-0) - [Environment Configs · Crossplane v2.0](#environment-configs-crossplane-v2-0) - [Managed Resources · Crossplane v2.0](#managed-resources-crossplane-v2-0) - [Usages · Crossplane v2.0](#usages-crossplane-v2-0) - [Managed Resources · Crossplane v2.0](#managed-resources-crossplane-v2-0) - [Managed Resource Definitions · Crossplane v2.0](#managed-resource-definitions-crossplane-v2-0) - [Contributing Guide · Crossplane ](#contributing-guide-crossplane-) - [Operations · Crossplane v2.0](#operations-crossplane-v2-0) - [Packages · Crossplane v2.0](#packages-crossplane-v2-0) - [Watch Operations · Crossplane v2.0](#watch-operations-crossplane-v2-0) - [Cron Operations · Crossplane v2.0](#cron-operations-crossplane-v2-0) - [Composite Resources · Crossplane v2.0](#composite-resources-crossplane-v2-0) - [Functions · Crossplane v2.0](#functions-crossplane-v2-0) - [Compositions · Crossplane v2.0](#compositions-crossplane-v2-0) - [Crossplane Pods · Crossplane v2.0](#crossplane-pods-crossplane-v2-0) - [Configurations · Crossplane v2.0](#configurations-crossplane-v2-0) - [Disabling Unused Managed Resources · Crossplane v2.0](#disabling-unused-managed-resources-crossplane-v2-0) - [Implementing safe-start in Providers · Crossplane v2.0](#implementing-safe-start-in-providers-crossplane-v2-0) - [Upgrade Crossplane · Crossplane v2.0](#upgrade-crossplane-crossplane-v2-0) - [Install Crossplane from source code · Crossplane v2.0](#install-crossplane-from-source-code-crossplane-v2-0) - [Uninstall Crossplane · Crossplane v2.0](#uninstall-crossplane-crossplane-v2-0) - [Community Extension Projects · Crossplane v2.0](#community-extension-projects-crossplane-v2-0) - [Upgrade to Crossplane v2 · Crossplane v2.0](#upgrade-to-crossplane-v2-crossplane-v2-0) - [Providers · Crossplane v2.0](#providers-crossplane-v2-0) - [Guides · Crossplane v2.0](#guides-crossplane-v2-0) - [Metrics · Crossplane v2.0](#metrics-crossplane-v2-0) - [Change Logs · Crossplane v2.0](#change-logs-crossplane-v2-0) - [Image Configs · Crossplane v2.0](#image-configs-crossplane-v2-0) - [Releasing Crossplane Extensions · Crossplane v2.0](#releasing-crossplane-extensions-crossplane-v2-0) - [Write a Composition Function in Go · Crossplane v2.0](#write-a-composition-function-in-go-crossplane-v2-0) - [Configuring Crossplane with Argo CD · Crossplane v2.0](#configuring-crossplane-with-argo-cd-crossplane-v2-0) - [Troubleshoot Crossplane · Crossplane v2.0](#troubleshoot-crossplane-crossplane-v2-0) - [Write a Composition Function in Python · Crossplane v2.0](#write-a-composition-function-in-python-crossplane-v2-0) - [Feature Lifecycle · Crossplane v2.0](#feature-lifecycle-crossplane-v2-0) - [Learn More · Crossplane v2.0](#learn-more-crossplane-v2-0) - [CLI Reference · Crossplane v2.0](#cli-reference-crossplane-v2-0) - [Import Existing Resources · Crossplane v2.0](#import-existing-resources-crossplane-v2-0) - [Release Cycle · Crossplane v2.0](#release-cycle-crossplane-v2-0) - [Command Reference · Crossplane v2.0](#command-reference-crossplane-v2-0) - [Function Patch and Transform · Crossplane v2.0](#function-patch-and-transform-crossplane-v2-0) - [Welcome · Crossplane master](#welcome-crossplane-master) - [Overview · Crossplane v1.20](#overview-crossplane-v1-20) - [Overview · Crossplane v1.19](#overview-crossplane-v1-19) - [API Reference · Crossplane v2.0](#api-reference-crossplane-v2-0) - [What’s Crossplane? · Crossplane master](#what-s-crossplane-crossplane-master) - [Install Crossplane · Crossplane v1.19](#install-crossplane-crossplane-v1-19) - [Install Crossplane · Crossplane v1.20](#install-crossplane-crossplane-v1-20) - [Install Crossplane · Crossplane master](#install-crossplane-crossplane-master) - [Get Started · Crossplane master](#get-started-crossplane-master) - [Composition · Crossplane master](#composition-crossplane-master) - [Get Started With Operations · Crossplane master](#get-started-with-operations-crossplane-master) - [What’s New in v2? · Crossplane master](#what-s-new-in-v2-crossplane-master) - [Get Started With Composition · Crossplane master](#get-started-with-composition-crossplane-master) - [Get Started With Managed Resources · Crossplane master](#get-started-with-managed-resources-crossplane-master) - [Composition Revisions · Crossplane v1.20](#composition-revisions-crossplane-v1-20) - [Composition Revisions · Crossplane master](#composition-revisions-crossplane-master) - [Composition Revisions · Crossplane v1.19](#composition-revisions-crossplane-v1-19) - [Managed Resource Activation Policies · Crossplane master](#managed-resource-activation-policies-crossplane-master) - [Composite Resource Definitions · Crossplane master](#composite-resource-definitions-crossplane-master) --- # Welcome · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/#) [master](https://docs.crossplane.io/master/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Welcome ======= On this page **On this page** * * * Welcome to the Crossplane documentation. Crossplane is a control plane framework for platform engineering. Using the documentation ======================= Crossplane organizes its documentation into the following sections: * [What’s Crossplane?](https://docs.crossplane.io/v2.0/whats-crossplane/) introduces Crossplane and explains why you should use it. * [What’s New in v2?](https://docs.crossplane.io/v2.0/whats-new/) highlights what’s changed in Crossplane v2. * [Get Started](https://docs.crossplane.io/v2.0/get-started/) explains how to install Crossplane and create a control plane. * [Composition](https://docs.crossplane.io/v2.0/composition/) covers the key concepts of composition. * [Operations](https://docs.crossplane.io/v2.0/operations/) covers the key concepts of operations. * [Managed Resources](https://docs.crossplane.io/v2.0/managed-resources/) covers the key concepts of managed resources. * [Packages](https://docs.crossplane.io/v2.0/packages/) covers the key concepts of the Crossplane package manager. * [Guides](https://docs.crossplane.io/v2.0/guides/) guide you through common use cases, like monitoring Crossplane or extending it by writing a composition function. * [CLI Reference](https://docs.crossplane.io/v2.0/cli/) documents the `crossplane` command-line interface that you can use to configure a Crossplane control plane. * [API Reference](https://docs.crossplane.io/v2.0/api/) documents the APIs that you can use to configure a Crossplane control plane. --- # Welcome · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/#) [master](https://docs.crossplane.io/master/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Welcome ======= On this page **On this page** * * * Welcome to the Crossplane documentation. Crossplane is a control plane framework for platform engineering. Using the documentation ======================= Crossplane organizes its documentation into the following sections: * [What’s Crossplane?](https://docs.crossplane.io/v2.0/whats-crossplane/) introduces Crossplane and explains why you should use it. * [What’s New in v2?](https://docs.crossplane.io/v2.0/whats-new/) highlights what’s changed in Crossplane v2. * [Get Started](https://docs.crossplane.io/v2.0/get-started/) explains how to install Crossplane and create a control plane. * [Composition](https://docs.crossplane.io/v2.0/composition/) covers the key concepts of composition. * [Operations](https://docs.crossplane.io/v2.0/operations/) covers the key concepts of operations. * [Managed Resources](https://docs.crossplane.io/v2.0/managed-resources/) covers the key concepts of managed resources. * [Packages](https://docs.crossplane.io/v2.0/packages/) covers the key concepts of the Crossplane package manager. * [Guides](https://docs.crossplane.io/v2.0/guides/) guide you through common use cases, like monitoring Crossplane or extending it by writing a composition function. * [CLI Reference](https://docs.crossplane.io/v2.0/cli/) documents the `crossplane` command-line interface that you can use to configure a Crossplane control plane. * [API Reference](https://docs.crossplane.io/v2.0/api/) documents the APIs that you can use to configure a Crossplane control plane. --- # What’s Crossplane? · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/whats-crossplane/#) [master](https://docs.crossplane.io/master/whats-crossplane/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/whats-crossplane/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) What’s Crossplane? ================== On this page **On this page** * * * Crossplane is a control plane framework for platform engineering. **Crossplane lets you build control planes to manage your cloud native software.** It lets you design the APIs and abstractions that your users use to interact with your control planes. Tip **A control plane is software that controls other software.** Control planes are a core cloud native pattern. The major cloud providers are all built using control planes. Control planes expose an API. You use the API to tell the control plane what software it should configure and how - this is your _desired state_. A control plane can configure any cloud native software. It could deploy an app, create a load balancer, or create a GitHub repository. The control plane configures your software, then monitors it throughout its lifecycle. If your software ever _drifts_ from your desired state, the control plane automatically corrects the drift. Crossplane has a rich ecosystem of extensions that make building a control plane faster and easier. It’s built on Kubernetes, so it works with all the Kubernetes tools you already use. **Crossplane’s key value is that it unlocks the benefits of building your own Kubernetes custom resources without having to write controllers for them.** Not familiar with Kubernetes custom resources and controllers? [This DevOps Toolkit video](https://www.youtube.com/watch?v=aM2Y9m2Kazk) has a great explanation. Note Kubebuilder is a popular project for building Kubernetes controllers. Look at the [Kubebuilder documentation](https://book.kubebuilder.io/) to see what’s involved in writing a controller. Crossplane components[](https://docs.crossplane.io/v2.0/whats-crossplane/#crossplane-components) ------------------------------------------------------------------------------------------------- Crossplane has four major components: * [Composition](https://docs.crossplane.io/v2.0/whats-crossplane/#composition) * [Managed resources](https://docs.crossplane.io/v2.0/whats-crossplane/#managed-resources) * [Operations](https://docs.crossplane.io/v2.0/whats-crossplane/#operations) * [Package manager](https://docs.crossplane.io/v2.0/whats-crossplane/#package-manager) You can use all four components to build your control plane, or pick only the ones you need. ### Composition[](https://docs.crossplane.io/v2.0/whats-crossplane/#composition) Composition lets you build custom APIs to control your cloud native software. Crossplane extends Kubernetes. You build your custom APIs by using Crossplane to extend Kubernetes with new custom resources. **To extend Kubernetes without using Crossplane you need a Kubernetes controller.** The controller is the software that reacts when a user calls the custom resource API. Say you want your control plane to serve an `App` custom resource API. When someone creates an `App`, the control plane should create a Kubernetes `Deployment` and a `Service`. **If there’s not already a controller that does what you want - and exposes the API you want - you have to write the controller yourself.** **With Crossplane you don’t have to write a controller**. Instead you configure a pipeline of functions. The functions return declarative configuration that Crossplane should apply. flowchart TD user(User) subgraph control \[Control Plane\] api(App API) subgraph crossplane \[Composition Engine\] fn(Python Function) end deployment(Deployment API) service(Service API) end user -- create --> api crossplane watch@<-- watch --> api crossplane -- create --> deployment crossplane -- create --> service watch@{animate: true} With Composition you avoid writing and maintaining complex controller code that’s hard to get right. Instead you focus on expressing your business logic, and work in your preferred language. Important Composition functions are like configuration language plugins. Functions allow you to write your configuration in multiple languages, including [YAML](https://yaml.org/) , [KCL](https://www.kcl-lang.io/) , [Python](https://python.org/) , and [Go](https://go.dev/) . You can use composition together with [managed resources](https://docs.crossplane.io/v2.0/whats-crossplane/#managed-resources) to build new custom resource APIs powered by managed resources. Follow [Get Started with Composition](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/) to see how composition works. ### Managed resources[](https://docs.crossplane.io/v2.0/whats-crossplane/#managed-resources) Managed resources (MRs) are ready-made Kubernetes custom resources. Each MR extends Kubernetes with the ability to manage a new system. For example there’s an RDS instance MR that extends Kubernetes with the ability to manage [AWS RDS](https://aws.amazon.com/rds/) instances. Crossplane has an extensive library of managed resources you can use to manage almost any cloud provider, or cloud native software. **With Crossplane you don’t have to write a controller if you want to manage something outside of your Kubernetes cluster using a custom resource.** There’s already a Crossplane managed resource for that. flowchart TD user(User) subgraph control \[Control Plane\] instance(RDS Instance API) controller(Managed Resource Controller) end subgraph aws \[Amazon Web Services\] rds(RDS Instance) end user -- create --> instance controller watch-rds@<-- watch --> instance controller -- create --> rds watch-rds@{animate: true} You can use managed resources together with [composition](https://docs.crossplane.io/v2.0/whats-crossplane/#composition) to build new custom resource APIs powered by MRs. flowchart TD user(User) subgraph control \[Control Plane\] api(App API) subgraph crossplane \[Composition Engine\] fn(Python Function) end deployment(Deployment API) service(Service API) instance(RDS Instance API) controller(Managed Resource Controller) end subgraph aws \[Amazon Web Services\] rds(RDS Instance) end user -- create --> api crossplane watch-apps@<-- watch --> api crossplane -- create --> deployment crossplane -- create --> service crossplane -- create --> instance controller watch-rds@<-- watch --> instance controller -- create --> rds watch-apps@{animate: true} watch-rds@{animate: true} Follow [Get Started with Managed Resources](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/) to see how managed resources work. ### Operations[](https://docs.crossplane.io/v2.0/whats-crossplane/#operations) Operations let you run operational tasks using function pipelines. While composition and managed resources focus on creating and managing infrastructure, operations handle tasks that don’t fit the typical resource creation pattern - like certificate monitoring, rolling upgrades, or scheduled maintenance. **Operations run function pipelines to completion like a Kubernetes Job.** Instead of continuously managing resources, they perform specific tasks and report the results. Say you want your control plane to watch SSL certificates on Kubernetes `Ingress` resources. When someone creates an Operation, the control plane should check the certificate and annotate the `Ingress` with expiry information. flowchart TD user(User) subgraph control \[Control Plane\] operation(SSL Monitor Operation) subgraph crossplane \[Operation Engine\] fn(Python Function) end ingress(Ingress API) end subgraph ext \[External System\] cert(SSL Certificate) end user -- create --> operation crossplane watch@<-- watch --> operation crossplane -- read --> ingress crossplane -- check --> cert crossplane -- annotate --> ingress watch@{animate: true} Operations support three modes: * **Operation** - Run once to completion * **CronOperation** - Run on a scheduled basis * **WatchOperation** - Run when resources change You can use operations alongside composition and managed resources to build complete operational workflows for your control plane. Follow [Get Started with Operations](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/) to see how operations work. Note Operations are an alpha feature available in Crossplane v2. ### Package manager[](https://docs.crossplane.io/v2.0/whats-crossplane/#package-manager) The Crossplane package manager lets you install new managed resources and composition functions. You can also package any part of a control plane’s configuration and install it using the package manager. This allows you to deploy multiple control planes with identical capabilities - for example one control plane per region or per service. Read about Crossplane [packages](https://docs.crossplane.io/v2.0/packages/) to learn about the package manager. --- # Install Crossplane · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/get-started/install/#) [master](https://docs.crossplane.io/master/get-started/install/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/get-started/install/) [v1.20](https://docs.crossplane.io/v1.20/software/install/) [v1.19](https://docs.crossplane.io/v1.19/software/install/) Install Crossplane ================== On this page **On this page** * * * Crossplane installs into an existing Kubernetes cluster, creating the Crossplane pod. Installing Crossplane enables the installation of Crossplane _Provider_, _Function_, and _Configuration_ resources. Tip If you don’t have a Kubernetes cluster create one locally with [Kind](https://kind.sigs.k8s.io/) . Prerequisites[](https://docs.crossplane.io/v2.0/get-started/install/#prerequisites) ------------------------------------------------------------------------------------ * An actively [supported Kubernetes version](https://kubernetes.io/releases/patch-releases/#support-period) * [Helm](https://helm.sh/docs/intro/install/) version `v3.2.0` or later Install Crossplane[](https://docs.crossplane.io/v2.0/get-started/install/#install-crossplane) ---------------------------------------------------------------------------------------------- Install Crossplane using the _Helm chart_. ### Add the Crossplane Helm repository[](https://docs.crossplane.io/v2.0/get-started/install/#add-the-crossplane-helm-repository) Add the Crossplane stable repository with the `helm repo add` command. 1helm repo add crossplane-stable https://charts.crossplane.io/stable Update the local Helm chart cache with `helm repo update`. 1helm repo update ### Install the Crossplane Helm chart[](https://docs.crossplane.io/v2.0/get-started/install/#install-the-crossplane-helm-chart) Install the Crossplane Helm chart with `helm install`. Tip View the changes Crossplane makes to your cluster with the `helm install --dry-run --debug` options. Helm shows what configurations it applies without making changes to the Kubernetes cluster. Crossplane creates and installs into the `crossplane-system` namespace. 1helm install crossplane \ 2--namespace crossplane-system \ 3--create-namespace crossplane-stable/crossplane View the installed Crossplane pods with `kubectl get pods -n crossplane-system`. 1kubectl get pods -n crossplane-system 2NAME READY STATUS RESTARTS AGE 3crossplane-6d67f8cd9d-g2gjw 1/1 Running 0 26m 4crossplane-rbac-manager-86d9b5cf9f-2vc4s 1/1 Running 0 26m Installation options[](https://docs.crossplane.io/v2.0/get-started/install/#installation-options) -------------------------------------------------------------------------------------------------- ### Customize the Crossplane Helm chart[](https://docs.crossplane.io/v2.0/get-started/install/#customize-the-crossplane-helm-chart) Crossplane supports customizations at install time by configuring the Helm chart. Read [the Helm chart README](https://github.com/crossplane/crossplane/blob/main/cluster/charts/crossplane/README.md#configuration) to learn what customizations are available. Read [the Helm documentation](https://helm.sh/docs/) to learn how to run Helm with custom options using `--set` or `values.yaml`. #### Feature flags[](https://docs.crossplane.io/v2.0/get-started/install/#feature-flags) Crossplane introduces new features behind feature flags. By default alpha features are off. Crossplane enables beta features by default. To enable a feature flag, set the `args` value in the Helm chart. Available feature flags can be directly found by running `crossplane core start --help`, or by looking at the table below. Feature flags ------------- | Status | Flag | Description | | --- | --- | --- | | Beta | `--enable-deployment-runtime-configs` | Enable support for DeploymentRuntimeConfigs. | | Beta | `--enable-usages` | Enable support for Usages. | | Beta | `--enable-realtime-compositions` | Enable support for real time compositions. | | Alpha | `--enable-dependency-version-upgrades` | Enable automatic version upgrades of dependencies when updating packages. | | Alpha | `--enable-function-response-cache` | Enable caching of composition function responses to improve performance. | | Alpha | `--enable-signature-verification` | Enable support for package signature verification via ImageConfig API. | Set these flags either in the `values.yaml` file or at install time using the `--set` flag, for example: `--set args='{"--enable-composition-functions","--enable-composition-webhook-schema-validation"}'`. Install pre-release Crossplane versions[](https://docs.crossplane.io/v2.0/get-started/install/#install-pre-release-crossplane-versions) ---------------------------------------------------------------------------------------------------------------------------------------- Install pre-release versions of Crossplane from the `master` Crossplane Helm channel. Versions in the `master` channel are under active development and may be unstable. Warning Don’t use Crossplane `master` releases in production. Only use `stable` channel. Only use `master` for testing and development. ### Add the Crossplane master Helm repository[](https://docs.crossplane.io/v2.0/get-started/install/#add-the-crossplane-master-helm-repository) Add the Crossplane repository with the `helm repo add` command. 1helm repo add crossplane-master https://charts.crossplane.io/master/ Update the local Helm chart cache with `helm repo update`. 1helm repo update ### Install the Crossplane master Helm chart[](https://docs.crossplane.io/v2.0/get-started/install/#install-the-crossplane-master-helm-chart) Install the Crossplane Helm chart from the `master` channel with `helm install`. Use the `--devel` flag to install the latest pre-release version. 1helm install crossplane \ 2--namespace crossplane-system \ 3--create-namespace crossplane-master/crossplane \ 4--devel Build and install from source[](https://docs.crossplane.io/v2.0/get-started/install/#build-and-install-from-source) -------------------------------------------------------------------------------------------------------------------- Building Crossplane from the source code gives you complete control over the build and installation process. Full instructions for this advanced installation path is in the [install from source code guide](https://docs.crossplane.io/v2.0/guides/install-from-source/) . --- # Get Started · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/get-started/#) [master](https://docs.crossplane.io/master/get-started/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/get-started/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Get Started =========== Get started with Crossplane. Topics in this section: * [Install Crossplane](https://docs.crossplane.io/v2.0/get-started/install/) - Install Crossplane in a Kubernetes cluster * [Get Started With Composition](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/) - Build custom APIs with Crossplane composition * [Get Started With Managed Resources](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/) - Manage cloud resources in Kubernetes with Crossplane providers * [Get Started With Operations](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/) - Run operational tasks with Crossplane operations --- # Composition · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/composition/#) [master](https://docs.crossplane.io/master/composition/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/composition/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Composition =========== Build custom APIs by composing Kubernetes resources Topics in this section: * [Composite Resources](https://docs.crossplane.io/v2.0/composition/composite-resources/) - Custom APIs created by composing Kubernetes resources * [Composite Resource Definitions](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/) - Define schemas for composite resources * [Compositions](https://docs.crossplane.io/v2.0/composition/compositions/) - Define which resources to create and how * [Composition Revisions](https://docs.crossplane.io/v2.0/composition/composition-revisions/) - Manage changes to Compositions with revisions * [Environment Configs](https://docs.crossplane.io/v2.0/composition/environment-configs/) - In-memory data stores for Compositions --- # Get Started With Operations · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/#) [master](https://docs.crossplane.io/master/get-started/get-started-with-operations/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Get Started With Operations =========================== This is an alpha feature. Crossplane may change or drop this feature at any time. This feature was introduced in v2. For more information read the [Crossplane feature lifecycle](https://docs.crossplane.io/v2.0/learn/feature-lifecycle/) . On this page **On this page** * * * This guide shows how to use Crossplane Operations to automate day-two operational tasks. You create an `Operation` that checks SSL certificate expiry for a website. **Crossplane calls this _Operations_.** Operations run function pipelines to perform tasks that don’t fit the typical resource creation pattern - like certificate monitoring, rolling upgrades, or scheduled maintenance. An `Operation` looks like this: 1apiVersion: ops.crossplane.io/v1alpha1 2kind: Operation 3metadata: 4 name: check-cert-expiry 5spec: 6 mode: Pipeline 7 pipeline: 8 - step: check-certificate 9 functionRef: 10 name: crossplane-contrib-function-python 11 input: 12 apiVersion: python.fn.crossplane.io/v1beta1 13 kind: Script 14 script: | 15 import ssl 16 import socket 17 from datetime import datetime 18 19 from crossplane.function import request, response 20 21 def operate(req, rsp): 22 hostname = "google.com" 23 port = 443 24 25 # Get SSL certificate info 26 context = ssl.create_default_context() 27 with socket.create_connection((hostname, port)) as sock: 28 with context.wrap_socket(sock, server_hostname=hostname) as ssock: 29 cert = ssock.getpeercert() 30 31 # Parse expiration date 32 expiry_date = datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y %Z') 33 days_until_expiry = (expiry_date - datetime.now()).days 34 35 # Return results in operation output 36 response.set_output(rsp, { 37 "hostname": hostname, 38 "certificateExpires": cert['notAfter'], 39 "daysUntilExpiry": days_until_expiry, 40 "status": "warning" if days_until_expiry < 30 else "ok" 41 }) **The `Operation` runs once to completion, like a Kubernetes `Job`.** When you create the `Operation`, Crossplane runs the function pipeline. The function checks SSL certificate expiry for google.com and returns the results in the operation’s output. This basic example shows the concept. In the walkthrough below, you create a more realistic `Operation` that reads Kubernetes `Ingress` resources and annotates them with certificate expiry information for monitoring tools. Prerequisites[](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/#prerequisites) -------------------------------------------------------------------------------------------------------- This guide requires: * A Kubernetes cluster with at least 2 GB of RAM * The Crossplane v2 preview [installed on the Kubernetes cluster](https://docs.crossplane.io/v2.0/get-started/install/) with Operations enabled Tip Enable Operations by adding `--enable-operations` to Crossplane’s startup arguments. If using Helm: 1helm upgrade --install crossplane crossplane-stable/crossplane \ 2 --namespace crossplane-system \ 3 --set args='{"--enable-operations"}' Create an operation[](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/#create-an-operation) -------------------------------------------------------------------------------------------------------------------- Follow these steps to create your first `Operation`: 1. [Create a sample Ingress](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/#create-a-sample-ingress) for certificate checking 2. [Install the function](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/#install-the-function) you want to use for the operation 3. [Create the Operation](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/#create-the-operation) that checks the `Ingress` 4. [Check the Operation](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/#check-the-operation) as it runs ### Create a sample Ingress[](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/#create-a-sample-ingress) Create an `Ingress` that references a real hostname but doesn’t route actual traffic: 1apiVersion: networking.k8s.io/v1 2kind: Ingress 3metadata: 4 name: example-app 5 namespace: default 6spec: 7 rules: 8 - host: google.com 9 http: 10 paths: 11 - path: / 12 pathType: Prefix 13 backend: 14 service: 15 name: nonexistent-service 16 port: 17 number: 80 Save as `ingress.yaml` and apply it: 1kubectl apply -f ingress.yaml ### Grant Ingress permissions[](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/#grant-ingress-permissions) `Operations` need permission to access and change `Ingresses`. Create a `ClusterRole` that grants Crossplane access to `Ingresses`: 1apiVersion: rbac.authorization.k8s.io/v1 2kind: ClusterRole 3metadata: 4 name: operations-ingress-access 5 labels: 6 rbac.crossplane.io/aggregate-to-crossplane: "true" 7rules: 8- apiGroups: ["networking.k8s.io"] 9 resources: ["ingresses"] 10 verbs: ["get", "list", "watch", "patch", "update"] Save as `ingress-rbac.yaml` and apply it: 1kubectl apply -f ingress-rbac.yaml ### Install the function[](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/#install-the-function) Operations use operation functions to implement their logic. Use the Python function, which supports both composition and operations. Create this function to install Python support: 1apiVersion: pkg.crossplane.io/v1 2kind: Function 3metadata: 4 name: crossplane-contrib-function-python 5spec: 6 package: xpkg.crossplane.io/crossplane-contrib/function-python:v0.2.0 Save the function as `function.yaml` and apply it: 1kubectl apply -f function.yaml Check that Crossplane installed the function: 1kubectl get -f function.yaml 2NAME INSTALLED HEALTHY PACKAGE AGE 3crossplane-contrib-function-python True True xpkg.crossplane.io/crossplane-contrib/function-python:v0.2.0 12s ### Create the operation[](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/#create-the-operation) Create this `Operation` that monitors the `Ingress` certificate: 1apiVersion: ops.crossplane.io/v1alpha1 2kind: Operation 3metadata: 4 name: ingress-cert-monitor 5spec: 6 mode: Pipeline 7 pipeline: 8 - step: check-ingress-certificate 9 functionRef: 10 name: crossplane-contrib-function-python 11 requirements: 12 requiredResources: 13 - requirementName: ingress 14 apiVersion: networking.k8s.io/v1 15 kind: Ingress 16 name: example-app 17 namespace: default 18 input: 19 apiVersion: python.fn.crossplane.io/v1beta1 20 kind: Script 21 script: | 22 import ssl 23 import socket 24 from datetime import datetime 25 26 from crossplane.function import request, response 27 28 def operate(req, rsp): 29 # Get the Ingress resource 30 ingress = request.get_required_resource(req, "ingress") 31 if not ingress: 32 response.set_output(rsp, {"error": "No ingress resource found"}) 33 return 34 35 # Extract hostname from Ingress rules 36 hostname = ingress["spec"]["rules"][0]["host"] 37 port = 443 38 39 # Get SSL certificate info 40 context = ssl.create_default_context() 41 with socket.create_connection((hostname, port)) as sock: 42 with context.wrap_socket(sock, server_hostname=hostname) as ssock: 43 cert = ssock.getpeercert() 44 45 # Parse expiration date 46 expiry_date = datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y %Z') 47 days_until_expiry = (expiry_date - datetime.now()).days 48 49 # Add warning if certificate expires soon 50 if days_until_expiry < 30: 51 response.warning(rsp, f"Certificate for {hostname} expires in {days_until_expiry} days") 52 53 # Annotate the Ingress with certificate expiry info 54 rsp.desired.resources["ingress"].resource.update({ 55 "apiVersion": "networking.k8s.io/v1", 56 "kind": "Ingress", 57 "metadata": { 58 "name": ingress["metadata"]["name"], 59 "namespace": ingress["metadata"]["namespace"], 60 "annotations": { 61 "cert-monitor.crossplane.io/expires": cert['notAfter'], 62 "cert-monitor.crossplane.io/days-until-expiry": str(days_until_expiry), 63 "cert-monitor.crossplane.io/status": "warning" if days_until_expiry < 30 else "ok" 64 } 65 } 66 }) 67 68 # Return results in operation output for monitoring 69 response.set_output(rsp, { 70 "ingressName": ingress["metadata"]["name"], 71 "hostname": hostname, 72 "certificateExpires": cert['notAfter'], 73 "daysUntilExpiry": days_until_expiry, 74 "status": "warning" if days_until_expiry < 30 else "ok" 75 }) Save the operation as `operation.yaml` and apply it: 1kubectl apply -f operation.yaml ### Check the operation[](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/#check-the-operation) Check that the `Operation` runs successfully: 1kubectl get -f operation.yaml 2NAME SYNCED SUCCEEDED AGE 3ingress-cert-monitor True True 15s Tip `Operations` show `SUCCEEDED=True` when they complete successfully. Check the `Operation`’s detailed status: 1kubectl describe operation ingress-cert-monitor 2# ... metadata ... 3Status: 4 Conditions: 5 Last Transition Time: 2024-01-15T10:30:15Z 6 Reason: PipelineSuccess 7 Status: True 8 Type: Succeeded 9 Last Transition Time: 2024-01-15T10:30:15Z 10 Reason: ValidPipeline 11 Status: True 12 Type: ValidPipeline 13 Pipeline: 14 Output: 15 Certificate Expires: Sep 29 08:34:02 2025 GMT 16 Days Until Expiry: 54 17 Hostname: google.com 18 Ingress Name: example-app 19 Status: ok 20 Step: check-ingress-certificate Tip The `status.pipeline` field shows the output returned by each function step. Use this field for tracking what the operation accomplished. Check that the `Operation` annotated the `Ingress` with certificate information: 1kubectl get ingress example-app -o yaml 2apiVersion: networking.k8s.io/v1 3kind: Ingress 4metadata: 5 annotations: 6 cert-monitor.crossplane.io/days-until-expiry: "54" 7 cert-monitor.crossplane.io/expires: Sep 29 08:34:02 2025 GMT 8 cert-monitor.crossplane.io/status: ok 9 name: example-app 10 namespace: default 11spec: 12 # ... ingress spec ... Tip This pattern shows how `Operations` can both read and change existing Kubernetes resources. The `Operation` annotated the `Ingress` with certificate expiry information that other tools can use for monitoring and alerting. Clean up[](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/#clean-up) ---------------------------------------------------------------------------------------------- Delete the resources you created: 1kubectl delete -f operation.yaml 2kubectl delete -f ingress.yaml 3kubectl delete -f ingress-rbac.yaml 4kubectl delete -f function.yaml Next steps[](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/#next-steps) -------------------------------------------------------------------------------------------------- `Operations` are powerful building blocks for operational workflows. Learn more about: * [**`Operation` concepts**](https://docs.crossplane.io/v2.0/operations/operation/) - Core `Operation` features and best practices * [**`CronOperation`**](https://docs.crossplane.io/v2.0/operations/cronoperation/) - Schedule operations to run automatically * [**`WatchOperation`**](https://docs.crossplane.io/v2.0/operations/watchoperation/) - Trigger operations when resources change Explore the complete [Operations documentation](https://docs.crossplane.io/v2.0/operations/) for advanced features and examples. --- # Get Started With Composition · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/#) [master](https://docs.crossplane.io/master/get-started/get-started-with-composition/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Get Started With Composition ============================ On this page **On this page** * * * This guide shows how to create a new kind of custom resource named `App`. When a user calls the custom resource API to create an `App`, Crossplane creates a `Deployment` and a `Service`. **Crossplane calls this _composition_.** The `App` is _composed of_ the `Deployment` and the `Service`. Tip The guide shows how to configure composition using YAML, templated YAML, Python, and KCL. You can pick your preferred language. An `App` custom resource looks like this: 1apiVersion: example.crossplane.io/v1 2kind: App 3metadata: 4 namespace: default 5 name: my-app 6spec: 7 image: nginx 8status: 9 replicas: 2 # Copied from the Deployment's status 10 address: 10.0.0.1 # Copied from the Service's status **The `App` is the custom API Crossplane users use to configure an app.** When users create an `App` Crossplane creates this `Deployment` and `Service`: 1--- 2apiVersion: apps/v1 3kind: Deployment 4metadata: 5 namespace: default 6 name: my-app-dhj3a 7 labels: 8 example.crossplane.io/app: my-app # Copied from the App's name 9spec: 10 replicas: 2 11 selector: 12 matchLabels: 13 example.crossplane.io/app: my-app # Copied from the App's name 14 template: 15 metadata: 16 labels: 17 example.crossplane.io/app: my-app # Copied from the App's name 18 spec: 19 containers: 20 - name: app 21 image: nginx # Copied from the App's spec 22 ports: 23 - containerPort: 80 24--- 25apiVersion: v1 26kind: Service 27metadata: 28 namespace: default 29 name: my-app-03mda 30 labels: 31 example.crossplane.io/app: my-app # Copied from the App's name 32spec: 33 selector: 34 example.crossplane.io/app: my-app # Copied from the App's name 35 ports: 36 - protocol: TCP 37 port: 8080 38 targetPort: 80 Crossplane builds on Kubernetes, so users can use `kubectl` or any other tool from the Kubernetes ecosystem to work with apps. Tip Kubernetes custom resources are just JSON REST APIs, so users can use any tool that supports REST APIs to work with apps. Prerequisites[](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/#prerequisites) --------------------------------------------------------------------------------------------------------- This guide requires: * A Kubernetes cluster with at least 2 GB of RAM * Crossplane v2 [installed on the Kubernetes cluster](https://docs.crossplane.io/v2.0/get-started/install/) Create the custom resource[](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/#create-the-custom-resource) ----------------------------------------------------------------------------------------------------------------------------------- Follow these steps to create a new kind of custom resource using Crossplane: 1. [Define](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/#define-the-schema) the schema of the `App` custom resource 2. [Install](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/#install-the-function) the function you want to use to configure how Crossplane composes apps 3. [Configure](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/#configure-the-composition) how Crossplane composes apps After you complete these steps you can [use the new `App` custom resource](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/#use-the-custom-resource) . ### Define the schema[](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/#define-the-schema) Crossplane calls a custom resource that’s powered by composition a _composite resource_, or XR. Note Kubernetes calls user-defined API resources _custom resources_. Crossplane calls user-defined API resources that use composition _composite resources_. A composite resource is a kind of custom resource. Create this _composite resource definition_ (XRD) to define the schema of the new `App` composite resource (XR). 1apiVersion: apiextensions.crossplane.io/v2 2kind: CompositeResourceDefinition 3metadata: 4 name: apps.example.crossplane.io 5spec: 6 scope: Namespaced 7 group: example.crossplane.io 8 names: 9 kind: App 10 plural: apps 11 versions: 12 - name: v1 13 served: true 14 referenceable: true 15 schema: 16 openAPIV3Schema: 17 type: object 18 properties: 19 spec: 20 type: object 21 properties: 22 image: 23 description: The app's OCI container image. 24 type: string 25 required: 26 - image 27 status: 28 type: object 29 properties: 30 replicas: 31 description: The number of available app replicas. 32 type: integer 33 address: 34 description: The app's IP address. 35 type: string Save the XRD as `xrd.yaml` and apply it: 1kubectl apply -f xrd.yaml Check that Crossplane has established the XRD: 1kubectl get -f xrd.yaml 2NAME ESTABLISHED OFFERED AGE 3apps.example.crossplane.io True 21s Now that Crossplane has established the XRD, Kubernetes is serving API requests for the new `App` XR. Crossplane now knows it’s responsible for the new `App` XR, but it doesn’t know what to do when you create or update one. You tell Crossplane what to do by [installing a function](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/#install-the-function) and [configuring a composition](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/#configure-the-composition) . ### Install the function[](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/#install-the-function) You can use different _composition functions_ to configure what Crossplane does when someone creates or updates a composite resource (XR). Composition functions are like configuration language plugins. Pick what language to use to configure how Crossplane turns an `App` XR into a `Deployment` and a `Service`. * YAML * Templated YAML * Python * KCL YAML is a good choice for small, static compositions. It doesn’t support loops or conditionals. Create this composition function to install YAML support: 1apiVersion: pkg.crossplane.io/v1 2kind: Function 3metadata: 4 name: crossplane-contrib-function-patch-and-transform 5spec: 6 package: xpkg.crossplane.io/crossplane-contrib/function-patch-and-transform:v0.8.2 Save the function as `fn.yaml` and apply it: 1kubectl apply -f fn.yaml Check that Crossplane installed the function: 1kubectl get -f fn.yaml 2NAME INSTALLED HEALTHY PACKAGE AGE 3crossplane-contrib-function-patch-and-transform True True xpkg.crossplane.io/crossplane-contrib/function-patch-and-transform:v0.8.2 10s Templated YAML is a good choice if you’re used to writing [Helm charts](https://helm.sh/) . Create this composition function to install templated YAML support: 1apiVersion: pkg.crossplane.io/v1 2kind: Function 3metadata: 4 name: crossplane-contrib-function-go-templating 5spec: 6 package: xpkg.crossplane.io/crossplane-contrib/function-go-templating:v0.9.2 Save the function as `fn.yaml` and apply it: 1kubectl apply -f fn.yaml Check that Crossplane installed the function: 1kubectl get -f fn.yaml 2NAME INSTALLED HEALTHY PACKAGE AGE 3crossplane-contrib-function-go-templating True True xpkg.crossplane.io/crossplane-contrib/function-go-templating:v0.9.2 9s Python is a good choice for compositions with dynamic logic. You can use the full [Python standard library](https://docs.python.org/3/library/index.html) . Create this composition function to install Python support: 1apiVersion: pkg.crossplane.io/v1 2kind: Function 3metadata: 4 name: crossplane-contrib-function-python 5spec: 6 package: xpkg.crossplane.io/crossplane-contrib/function-python:v0.1.0 Save the function as `fn.yaml` and apply it: 1kubectl apply -f fn.yaml Check that Crossplane installed the function: 1kubectl get -f fn.yaml 2NAME INSTALLED HEALTHY PACKAGE AGE 3crossplane-contrib-function-python True True xpkg.crossplane.io/crossplane-contrib/function-python:v0.1.0 12s [KCL](https://kcl-lang.io/) is a good choice for compositions with dynamic logic. It’s fast and sandboxed. Create this composition function to install KCL support: 1apiVersion: pkg.crossplane.io/v1 2kind: Function 3metadata: 4 name: crossplane-contrib-function-kcl 5spec: 6 package: xpkg.crossplane.io/crossplane-contrib/function-kcl:v0.11.2 Save the function as `fn.yaml` and apply it: 1kubectl apply -f fn.yaml Check that Crossplane installed the function: 1kubectl get -f fn.yaml 2NAME INSTALLED HEALTHY PACKAGE AGE 3crossplane-contrib-function-kcl True True xpkg.crossplane.io/crossplane-contrib/function-kcl:v0.11.2 6s ### Configure the composition[](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/#configure-the-composition) A composition tells Crossplane what functions to call when you create or update a composite resource (XR). Create a composition to tell Crossplane what to do when you create or update an `App` XR. * YAML * Templated YAML * Python * KCL Create this composition to use YAML to configure Crossplane: 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: app-yaml 5spec: 6 compositeTypeRef: 7 apiVersion: example.crossplane.io/v1 8 kind: App 9 mode: Pipeline 10 pipeline: 11 - step: create-deployment-and-service 12 functionRef: 13 name: crossplane-contrib-function-patch-and-transform 14 input: 15 apiVersion: pt.fn.crossplane.io/v1beta1 16 kind: Resources 17 resources: 18 - name: deployment 19 base: 20 apiVersion: apps/v1 21 kind: Deployment 22 spec: 23 replicas: 2 24 template: 25 spec: 26 containers: 27 - name: app 28 ports: 29 - containerPort: 80 30 patches: 31 - type: FromCompositeFieldPath 32 fromFieldPath: metadata.name 33 toFieldPath: metadata.labels[example.crossplane.io/app] 34 - type: FromCompositeFieldPath 35 fromFieldPath: metadata.name 36 toFieldPath: spec.selector.matchLabels[example.crossplane.io/app] 37 - type: FromCompositeFieldPath 38 fromFieldPath: metadata.name 39 toFieldPath: spec.template.metadata.labels[example.crossplane.io/app] 40 - type: FromCompositeFieldPath 41 fromFieldPath: spec.image 42 toFieldPath: spec.template.spec.containers[0].image 43 - type: ToCompositeFieldPath 44 fromFieldPath: status.availableReplicas 45 toFieldPath: status.replicas 46 readinessChecks: 47 - type: MatchCondition 48 matchCondition: 49 type: Available 50 status: "True" 51 - name: service 52 base: 53 apiVersion: v1 54 kind: Service 55 spec: 56 ports: 57 - protocol: TCP 58 port: 8080 59 targetPort: 80 60 patches: 61 - type: FromCompositeFieldPath 62 fromFieldPath: metadata.name 63 toFieldPath: metadata.labels[example.crossplane.io/app] 64 - type: FromCompositeFieldPath 65 fromFieldPath: metadata.name 66 toFieldPath: spec.selector[example.crossplane.io/app] 67 - type: ToCompositeFieldPath 68 fromFieldPath: spec.clusterIP 69 toFieldPath: status.address 70 readinessChecks: 71 - type: NonEmpty 72 fieldPath: spec.clusterIP Create this composition to use templated YAML to configure Crossplane: 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: app-templated-yaml 5spec: 6 compositeTypeRef: 7 apiVersion: example.crossplane.io/v1 8 kind: App 9 mode: Pipeline 10 pipeline: 11 - step: create-deployment-and-service 12 functionRef: 13 name: crossplane-contrib-function-go-templating 14 input: 15 apiVersion: gotemplating.fn.crossplane.io/v1beta1 16 kind: GoTemplate 17 source: Inline 18 inline: 19 template: | 20 --- 21 apiVersion: apps/v1 22 kind: Deployment 23 metadata: 24 annotations: 25 gotemplating.fn.crossplane.io/composition-resource-name: deployment 26 {{ if eq (.observed.resources.deployment | getResourceCondition "Available").Status "True" }} 27 gotemplating.fn.crossplane.io/ready: "True" 28 {{ end }} 29 labels: 30 example.crossplane.io/app: {{ .observed.composite.resource.metadata.name }} 31 spec: 32 replicas: 2 33 selector: 34 matchLabels: 35 example.crossplane.io/app: {{ .observed.composite.resource.metadata.name }} 36 template: 37 metadata: 38 labels: 39 example.crossplane.io/app: {{ .observed.composite.resource.metadata.name }} 40 spec: 41 containers: 42 - name: app 43 image: {{ .observed.composite.resource.spec.image }} 44 ports: 45 - containerPort: 80 46 --- 47 apiVersion: v1 48 kind: Service 49 metadata: 50 annotations: 51 gotemplating.fn.crossplane.io/composition-resource-name: service 52 {{ if (get (getComposedResource . "service").spec "clusterIP") }} 53 gotemplating.fn.crossplane.io/ready: "True" 54 {{ end }} 55 labels: 56 example.crossplane.io/app: {{ .observed.composite.resource.metadata.name }} 57 spec: 58 selector: 59 example.crossplane.io/app: {{ .observed.composite.resource.metadata.name }} 60 ports: 61 - protocol: TCP 62 port: 8080 63 targetPort: 80 64 --- 65 apiVersion: example.crossplane.io/v1 66 kind: App 67 status: 68 replicas: {{ get (getComposedResource . "deployment").status "availableReplicas" | default 0 }} 69 address: {{ get (getComposedResource . "service").spec "clusterIP" | default "" | quote }} Create this composition to use Python to configure Crossplane: 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: app-python 5spec: 6 compositeTypeRef: 7 apiVersion: example.crossplane.io/v1 8 kind: App 9 mode: Pipeline 10 pipeline: 11 - step: create-deployment-and-service 12 functionRef: 13 name: crossplane-contrib-function-python 14 input: 15 apiVersion: python.fn.crossplane.io/v1beta1 16 kind: Script 17 script: | 18 def compose(req, rsp): 19 observed_xr = req.observed.composite.resource 20 21 rsp.desired.resources["deployment"].resource.update({ 22 "apiVersion": "apps/v1", 23 "kind": "Deployment", 24 "metadata": { 25 "labels": {"example.crossplane.io/app": observed_xr["metadata"]["name"]}, 26 }, 27 "spec": { 28 "replicas": 2, 29 "selector": {"matchLabels": {"example.crossplane.io/app": observed_xr["metadata"]["name"]}}, 30 "template": { 31 "metadata": { 32 "labels": {"example.crossplane.io/app": observed_xr["metadata"]["name"]}, 33 }, 34 "spec": { 35 "containers": [{\ 36 "name": "app",\ 37 "image": observed_xr["spec"]["image"],\ 38 "ports": [{"containerPort": 80}]\ 39 }], 40 }, 41 }, 42 }, 43 }) 44 45 observed_deployment = req.observed.resources["deployment"].resource 46 if "status" in observed_deployment: 47 if "availableReplicas" in observed_deployment["status"]: 48 rsp.desired.composite.resource.get_or_create_struct("status")["replicas"] = observed_deployment["status"]["availableReplicas"] 49 if "conditions" in observed_deployment["status"]: 50 for condition in observed_deployment["status"]["conditions"]: 51 if condition["type"] == "Available" and condition["status"] == "True": 52 rsp.desired.resources["deployment"].ready = True 53 54 rsp.desired.resources["service"].resource.update({ 55 "apiVersion": "v1", 56 "kind": "Service", 57 "metadata": { 58 "labels": {"example.crossplane.io/app": observed_xr["metadata"]["name"]}, 59 }, 60 "spec": { 61 "selector": {"example.crossplane.io/app": observed_xr["metadata"]["name"]}, 62 "ports": [{"protocol": "TCP", "port": 8080, "targetPort": 80}], 63 }, 64 }) 65 66 observed_service = req.observed.resources["service"].resource 67 if "spec" in observed_service and "clusterIP" in observed_service["spec"]: 68 rsp.desired.composite.resource.get_or_create_struct("status")["address"] = observed_service["spec"]["clusterIP"] 69 rsp.desired.resources["service"].ready = True Tip You can write your own function in Python. It’s a good idea to write your own function for larger configurations. When you write your own function you can write multiple files of Python. You don’t embed the Python in YAML, so it’s easier to use a Python IDE. Read the [guide to writing a composition function in Python](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-python/) . Create this composition to use KCL to configure Crossplane: 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: app-kcl 5spec: 6 compositeTypeRef: 7 apiVersion: example.crossplane.io/v1 8 kind: App 9 mode: Pipeline 10 pipeline: 11 - step: create-deployment-and-service 12 functionRef: 13 name: crossplane-contrib-function-kcl 14 input: 15 apiVersion: krm.kcl.dev/v1alpha1 16 kind: KCLInput 17 spec: 18 source: | 19 observed_xr = option("params").oxr 20 21 _desired_deployment = { 22 apiVersion = "apps/v1" 23 kind = "Deployment" 24 metadata = { 25 annotations = { 26 "krm.kcl.dev/composition-resource-name" = "deployment" 27 } 28 labels = {"example.crossplane.io/app" = observed_xr.metadata.name} 29 } 30 spec = { 31 replicas = 2 32 selector.matchLabels = {"example.crossplane.io/app" = observed_xr.metadata.name} 33 template = { 34 metadata.labels = {"example.crossplane.io/app" = observed_xr.metadata.name} 35 spec.containers = [{\ 36 name = "app"\ 37 image = observed_xr.spec.image\ 38 ports = [{containerPort = 80}]\ 39 }] 40 } 41 } 42 } 43 44 observed_deployment = option("params").ocds["deployment"]?.Resource 45 if any_true([c.type == "Available" and c.status == "True" for c in observed_deployment?.status?.conditions or []]): 46 _desired_deployment.metadata.annotations["krm.kcl.dev/ready"] = "True" 47 48 _desired_service = { 49 apiVersion = "v1" 50 kind = "Service" 51 metadata = { 52 annotations = { 53 "krm.kcl.dev/composition-resource-name" = "service" 54 } 55 labels = {"example.crossplane.io/app" = observed_xr.metadata.name} 56 } 57 spec = { 58 selector = {"example.crossplane.io/app" = observed_xr.metadata.name} 59 ports = [{protocol = "TCP", port = 8080, targetPort = 80}] 60 } 61 } 62 63 observed_service = option("params").ocds["service"]?.Resource 64 if observed_service?.spec?.clusterIP: 65 _desired_service.metadata.annotations["krm.kcl.dev/ready"] = "True" 66 67 _desired_xr = { 68 **option("params").dxr 69 70 status.address = observed_service?.spec?.clusterIP or "" 71 status.replicas = observed_deployment?.status?.availableReplicas or 0 72 } 73 74 items = [_desired_deployment, _desired_service, _desired_xr] Save the composition as `composition.yaml` and apply it: 1kubectl apply -f composition.yaml Note A composition can include multiple functions. Functions can change the results of earlier functions in the pipeline. Crossplane uses the result returned by the last function. Tip If you edit this composition to include a different kind of resource you might need to grant Crossplane access to compose it. Read [the composition documentation](https://docs.crossplane.io/v2.0/composition/compositions/#grant-access-to-composed-resources) to learn how to grant Crossplane access. Use the custom resource[](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/#use-the-custom-resource) ----------------------------------------------------------------------------------------------------------------------------- Crossplane now understands `App` custom resources. Create an `App`: 1apiVersion: example.crossplane.io/v1 2kind: App 3metadata: 4 namespace: default 5 name: my-app 6spec: 7 image: nginx Save the `App` as `app.yaml` and apply it: 1kubectl apply -f app.yaml Check that the `App` is ready: 1kubectl get -f app.yaml 2NAME SYNCED READY COMPOSITION AGE 3my-app True True app-yaml 56s Note The `COMPOSITION` column shows what composition the `App` is using. You can create multiple compositions for each kind of XR. [Read the XR page](https://docs.crossplane.io/v2.0/composition/composite-resources/) to learn how to select which composition Crossplane uses. Check that Crossplane created a `Deployment` and a `Service`: 1kubectl get deploy,service -l example.crossplane.io/app=my-app 2NAME READY UP-TO-DATE AVAILABLE AGE 3deployment.apps/my-app-2r2rk 2/2 2 2 11m 4 5NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 6service/my-app-xfkzg ClusterIP 10.96.148.56 8080/TCP 11m Tip Use `kubectl edit -f app.yaml` to edit the `App`’s image. Crossplane updates the `Deployment`’s image to match. Delete the `App`. 1kubectl delete -f app.yaml When you delete the `App`, Crossplane deletes the `Deployment` and `Service`. Next steps[](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/#next-steps) --------------------------------------------------------------------------------------------------- Managed resources (MRs) are ready-made Kubernetes custom resources. Crossplane has an extensive library of managed resources you can use to manage almost any cloud provider, or cloud native software. [Get started with managed resources](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/) to learn more about them. You can use MRs with composition. Try updating your `App` composition to include an MR. --- # What’s New in v2? · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/whats-new/#) [master](https://docs.crossplane.io/master/whats-new/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/whats-new/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) What’s New in v2? ================= On this page **On this page** * * * **Crossplane v2 makes Crossplane more useful, more intuitive, and less opinionated.** Crossplane v2 makes four major changes: * **Composite resources are now namespaced** * **Managed resources are now namespaced** * **Composition supports any Kubernetes resource** * **Operations enable operational workflows** **Crossplane v2 is better suited to building control planes for applications, not just infrastructure.** It removes the need for awkward abstractions like claims and provider-kubernetes Objects. Tip Most users can upgrade to Crossplane v2 without breaking changes. Read about Crossplane v2’s [backward compatibility](https://docs.crossplane.io/v2.0/whats-new/#backward-compatibility) . Note This page assumes you’re familiar with Crossplane. New to Crossplane? Read [What’s Crossplane](https://docs.crossplane.io/v2.0/whats-crossplane/) instead. Namespaced composite resources[](https://docs.crossplane.io/v2.0/whats-new/#namespaced-composite-resources) ------------------------------------------------------------------------------------------------------------ Crossplane v2 makes composite resources (XRs) namespaced by default. A namespaced XR can compose any resource ([not just Crossplane resources](https://docs.crossplane.io/v2.0/whats-new/#compose-any-resource) ) in its namespace. A namespaced XR looks like this: 1apiVersion: example.crossplane.io/v1 2kind: App 3metadata: 4 namespace: default 5 name: my-app 6spec: 7 image: nginx 8 crossplane: 9 compositionRef: 10 name: app-kcl 11 compositionRevisionRef: 12 name: app-kcl-41b6efe 13 resourceRefs: 14 - apiVersion: apps/v1 15 kind: Deployment 16 name: my-app-9bj8j 17 - apiVersion: v1 18 kind: Service 19 name: my-app-bflc4 Note Crossplane v2 moves all an XR’s “Crossplane machinery” under `spec.crossplane`. This makes it easier for users to tell which fields are important to them, and which are just “Crossplane stuff” they can ignore. Composite resource definitions (XRDs) now have a `scope` field. The `scope` field defaults to `Namespaced` in the new v2 version of the XRD API. 1apiVersion: apiextensions.crossplane.io/v2 2kind: CompositeResourceDefinition 3metadata: 4 name: apps.example.crossplane.io 5spec: 6 scope: Namespaced 7 group: example.crossplane.io 8 names: 9 kind: App 10 plural: apps 11 versions: 12 - name: v1 13 # Removed for brevity You can also set the `scope` field to `Cluster` to create a cluster scoped XR. A cluster scoped XR can compose any cluster scoped resource. A cluster scoped XR can also compose any namespaced resource in any namespace. With namespaced XRs there’s no longer a need for claims. **The new namespaced and cluster scoped XRs in Crossplane v2 don’t support claims.** Tip Crossplane v2 is backward compatible with v1-style XRs. When you use v1 of the XRD API `scope` defaults to a special `LegacyCluster` mode. `LegacyCluster` XRs support claims and don’t use `spec.crossplane`. Read more about Crossplane v2’s [backward compatibility](https://docs.crossplane.io/v2.0/whats-new/#backward-compatibility) . Namespaced managed resources[](https://docs.crossplane.io/v2.0/whats-new/#namespaced-managed-resources) -------------------------------------------------------------------------------------------------------- Crossplane v2 makes all managed resources (MRs) namespaced. This enables a namespaced XR to consist of entirely namespaced resources - whether they’re a Crossplane MR like an `RDSInstance`, a Kubernetes resource like a `Deployment`, or a third party custom resource like a [Cluster API](https://cluster-api.sigs.k8s.io/) `Cluster`. A namespaced MR looks like this: 1apiVersion: s3.aws.m.upbound.io/v1beta1 2kind: Bucket 3metadata: 4 namespace: default 5 generateName: my-bucket 6spec: 7 forProvider: 8 region: us-east-2 Namespaced MRs work great with or without composition. Crossplane v2 isn’t opinionated about using composition and MRs together. Namespaces enable fine grained access control over who can create what MRs. Note Namespaced AWS managed resources are fully available in Crossplane v2. Maintainers are actively working to update managed resources for other systems including Azure, GCP, Terraform, Helm, GitHub, etc to support namespaced MRs. Tip Crossplane v2 is backward compatible with v1-style cluster scoped MRs. New provider releases will support both namespaced and cluster scoped MRs. Crossplane v2 considers cluster scoped MRs a legacy feature. Crossplane will deprecate and remove cluster scoped MRs at a future date. Read more about Crossplane v2’s [backward compatibility](https://docs.crossplane.io/v2.0/whats-new/#backward-compatibility) . Crossplane v2 also introduces [managed resource definitions](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/) for selective activation of provider resources, reducing cluster overhead by installing only the managed resources you actually need. Compose any resource[](https://docs.crossplane.io/v2.0/whats-new/#compose-any-resource) ---------------------------------------------------------------------------------------- Crossplane v2 isn’t opinionated about using composition together with managed resources. You can create a composite resource (XR) that composes any resource, whether it’s a Crossplane MR like an `RDSInstance`, a Kubernetes resource like a `Deployment`, or a third party custom resource like a [CloudNativePG](https://cloudnative-pg.io/) PostgreSQL `Cluster`. flowchart LR user(User) subgraph ns \[my-namespace\] direction LR xr("App (XR)") dply("Deployment") svc("Service") pg("CloudNativePG Cluster") end user --create-->xr xr compose-dply@--compose--> dply xr compose-svc@--compose--> svc xr compose-pg@--compose--> pg compose-dply@{animate: true} compose-dply@{animate: true} compose-svc@{animate: true} compose-pg@{animate: true} This opens composition to exciting new use cases - for example building custom app models with Crossplane. Tip You must grant Crossplane access to compose resources that aren’t Crossplane resources like MRs or XRs. Read [the composition documentation](https://docs.crossplane.io/v2.0/composition/compositions/#grant-access-to-composed-resources) to learn how to grant Crossplane access. Operations enable operational workflows[](https://docs.crossplane.io/v2.0/whats-new/#operations-enable-operational-workflows) ------------------------------------------------------------------------------------------------------------------------------ Crossplane v2 introduces Operations - a new way to run operational tasks using function pipelines. Operations handle tasks that don’t fit the typical resource creation pattern. Things like certificate monitoring, rolling upgrades, scheduled maintenance, or responding to resource changes. **Operations run function pipelines to completion, like a Kubernetes Job.** Instead of continuously managing resources, they perform specific tasks and report the results. 1apiVersion: ops.crossplane.io/v1alpha1 2kind: CronOperation 3metadata: 4 name: cert-monitor 5spec: 6 schedule: "0 6 * * *" # Daily at 6 AM 7 mode: Pipeline 8 pipeline: 9 - step: check-certificates 10 functionRef: 11 name: crossplane-contrib-function-python 12 # function checks SSL certificates and reports status Operations support three modes: * **Operation** - Run once to completion * **CronOperation** - Run on a scheduled basis * **WatchOperation** - Run when resources change Operations can read existing resources and optionally change them. This enables workflows like annotating resources with operational data, triggering maintenance tasks, or implementing custom operational policies. Note Operations are an alpha feature in Crossplane v2. Backward compatibility[](https://docs.crossplane.io/v2.0/whats-new/#backward-compatibility) -------------------------------------------------------------------------------------------- Crossplane v2 makes the following breaking changes: * It removes native patch and transform composition. * It removes the `ControllerConfig` type. * It removes support for external secret stores. * It removes the default registry for Crossplane Packages. Crossplane deprecated native patch and transform composition in Crossplane v1.17. It’s replaced by composition functions. Crossplane deprecated the `ControllerConfig` type in v1.11. It’s replaced by the `DeploymentRuntimeConfig` type. Crossplane added external secret stores in v1.7. External secret stores have remained in alpha for over two years and are now unmaintained. Crossplane v2 drops the `--registry` flag that allowed users to specify a default registry value and now requires users to always specify a fully qualified URL when installing packages, both directly via `spec.package` and indirectly as dependencies. Using fully qualified images was already a best practice, but it’s now enforced to avoid confusion and unexpected behavior, to ensure users are aware of the registry used by their packages. Important As long as you’re not using these deprecated or alpha features, Crossplane v2 is backward compatible with Crossplane v1.x. Important Before upgrading to Crossplane v2, please ensure all your Packages are using fully qualified images that explicitly specify a registry (`registry.example.com/repo/package:tag`). Run `kubectl get pkg` to look for any packages that aren’t fully qualified, then update or rebuild any Packages to use fully qualified images as needed. Crossplane v2 supports legacy v1-style XRs and MRs. Most users can upgrade from v1.x to Crossplane v2 without breaking changes. Existing Compositions require minor updates to work with Crossplane v2 style XRs and MRs. Follow the [Crossplane v2 upgrade guide](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/) for step-by-step migration instructions. --- # Get Started With Managed Resources · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/#) [master](https://docs.crossplane.io/master/get-started/get-started-with-managed-resources/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Get Started With Managed Resources ================================== On this page **On this page** * * * This guide shows how to install and use a new kind of custom resource called `Bucket`. When a user calls the custom resource API to create a `Bucket`, Crossplane creates a bucket in AWS S3. **Crossplane calls this a _managed resource_**. A managed resource is a ready-made custom resource that manages something outside of the control plane. A `Bucket` managed resource looks like this: 1apiVersion: s3.aws.m.upbound.io/v1beta1 2kind: Bucket 3metadata: 4 namespace: default 5 name: crossplane-bucket-example 6spec: 7 forProvider: 8 region: us-east-2 Note Kubernetes calls third party API resources _custom resources_. Prerequisites[](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/#prerequisites) --------------------------------------------------------------------------------------------------------------- This guide requires: * A Kubernetes cluster with at least 2 GB of RAM * Crossplane v2 [installed on the Kubernetes cluster](https://docs.crossplane.io/v2.0/get-started/install/) * An AWS account with permissions to create an S3 storage bucket * AWS [access keys](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-creds) Install support for the managed resource[](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/#install-support-for-the-managed-resource) --------------------------------------------------------------------------------------------------------------------------------------------------------------------- Follow these steps to install support for the `Bucket` managed resource: 1. [Install](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/#install-the-provider) the provider 2. [Save](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/#save-the-providers-credentials) the provider’s credentials as a secret 3. [Configure](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/#configure-the-provider) the provider to use the secret After you complete these steps you can [use the `Bucket` managed resource](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/#use-the-managed-resource) . ### Install the provider[](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/#install-the-provider) A Crossplane _provider_ installs support for a set of related managed resources. The AWS S3 provider installs support for all the AWS S3 managed resources. Create this provider to install the AWS S3 provider: 1apiVersion: pkg.crossplane.io/v1 2kind: Provider 3metadata: 4 name: crossplane-contrib-provider-aws-s3 5spec: 6 package: xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v2.0.0 Save this as `provider.yaml` and apply it: 1kubectl apply -f provider.yaml Check that Crossplane installed the provider: 1kubectl get providers 2NAME INSTALLED HEALTHY PACKAGE AGE 3crossplane-contrib-provider-family-aws True True xpkg.crossplane.io/crossplane-contrib/provider-family-aws:v2.0.0 27s 4crossplane-contrib-provider-aws-s3 True True xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v2.0.0 31s Note The S3 provider installs a second provider, the `crossplane-contrib-provider-family-aws`. The family provider manages authentication to AWS across all AWS family providers. Crossplane installed the AWS S3 provider. The provider needs credentials to connect to AWS. Before you can use managed resources, you have to [save the provider’s credentials](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/#save-the-providers-credentials) and [configure the provider to use them](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/#configure-the-provider) . ### Save the provider’s credentials[](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/#save-the-providers-credentials) The provider needs credentials to create and manage AWS resources. Providers use a Kubernetes _secret_ to connect the credentials to the provider. Generate a secret from your AWS key-pair. Tip The [AWS documentation](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-creds) provides information on how to generate AWS Access keys. Create a file containing the AWS account `aws_access_key_id` and `aws_secret_access_key`: 1[default] 2aws_access_key_id = 3aws_secret_access_key = Save the text file as `aws-credentials.ini`. Note The [Authentication](https://docs.upbound.io/providers/provider-aws/authentication/) section of the AWS Provider documentation describes other authentication methods. Create a secret from the text file: 1kubectl create secret generic aws-secret \ 2 --namespace=crossplane-system \ 3 --from-file=creds=./aws-credentials.ini Important Crossplane providers don’t have to store their credentials in a secret. They can load their credentials from multiple sources. Next, [configure the provider](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/#configure-the-provider) to use the credentials. ### Configure the provider[](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/#configure-the-provider) A `provider configuration` customizes the settings of the AWS Provider. All providers need a configuration to tell them where to load credentials. Create this cluster-wide provider configuration: 1apiVersion: aws.m.upbound.io/v1beta1 2kind: ClusterProviderConfig 3metadata: 4 name: default 5spec: 6 credentials: 7 source: Secret 8 secretRef: 9 namespace: crossplane-system 10 name: aws-secret 11 key: creds Save the provider configuration as `providerconfig.yaml` and apply it: 1kubectl apply -f providerconfig.yaml This tells the provider to load credentials from [the secret](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/#save-the-providers-credentials) . Note This example uses a `ClusterProviderConfig` that applies to managed resources across all namespaces. You can also use a namespaced `ProviderConfig` that only applies to managed resources in a specific namespace. See the [`providerConfigRef`](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#providerconfigref) section in the managed resources docs for more details. Use the managed resource[](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/#use-the-managed-resource) ------------------------------------------------------------------------------------------------------------------------------------- Note AWS S3 bucket names must be globally unique. This example uses `generateName` to generate a random name. Any unique name is acceptable. 1apiVersion: s3.aws.m.upbound.io/v1beta1 2kind: Bucket 3metadata: 4 namespace: default 5 generateName: crossplane-bucket- 6spec: 7 forProvider: 8 region: us-east-2 Save the bucket to `bucket.yaml` and apply it: 1kubectl create -f bucket.yaml Check that Crossplane created the bucket: 1kubectl get buckets.s3.aws.m.upbound.io 2NAME SYNCED READY EXTERNAL-NAME AGE 3crossplane-bucket-7tfcj True True crossplane-bucket-7tfcj 3m4s Tip Crossplane created the bucket when the values `READY` and `SYNCED` are `True`. Delete the bucket: 1kubectl delete buckets.s3.aws.m.upbound.io crossplane-bucket-7tfcj 2bucket.s3.aws.m.upbound.io "crossplane-bucket-7tfcj" deleted When you delete the bucket managed resource, Crossplane deletes the S3 bucket from AWS. Important Make sure to delete the S3 bucket before uninstalling the provider or shutting down your control plane. If those are no longer running, they can’t clean up any managed resources and you would need to do so manually. Next steps[](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/#next-steps) --------------------------------------------------------------------------------------------------------- Crossplane allows you to compose **any kind of resource** into custom APIs for your users, which includes managed resources. Enjoy the freedom that Crossplane gives you to compose the diverse set of resources your applications need for their unique environments, scenarios, and requirements. Follow [Get Started with Composition](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/) to learn more about how composition works. --- # Composition Revisions · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/composition/composition-revisions/#) [master](https://docs.crossplane.io/master/composition/composition-revisions/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/composition/composition-revisions/) [v1.20](https://docs.crossplane.io/v1.20/concepts/composition-revisions/) [v1.19](https://docs.crossplane.io/v1.19/concepts/composition-revisions/) Composition Revisions ===================== On this page **On this page** * * * This guide discusses the use of “Composition Revisions” to make and roll back changes to a Crossplane [`Composition`](https://docs.crossplane.io/v2.0/composition/compositions/) . It assumes familiarity with Crossplane and [Compositions](https://docs.crossplane.io/v2.0/composition/compositions/) . A `Composition` configures how Crossplane should reconcile a Composite Resource (XR). Put otherwise, when you create an XR the selected `Composition` determines what resources Crossplane creates in response. For example, you define a `PlatformDB` XR, which represents your organisation’s common database configuration of an Azure MySQL Server and some firewall rules. The `Composition` contains the ‘base’ configuration for the MySQL server and the firewall rules that the `PlatformDB` configuration extends. A `Composition` associates with multiple XRs that use it. You might define a `Composition` named `big-platform-db` that’s used by ten different `PlatformDB` XRs. Often, in the interest of self-service, a different team manages the `Composition` than the actual `PlatformDB` XRs. For example a platform team member may write and maintain the `Composition`, while individual app teams create `PlatformDB` XRs that use said `Composition`. Each `Composition` is mutable - you can update it as your organisation’s needs change. Updating a `Composition` without Composition Revisions can be a risky process. Crossplane constantly uses the `Composition` to ensure that your actual infrastructure - your MySQL Servers and firewall rules - match your desired state. If you have 10 `PlatformDB` XRs all using the `big-platform-db` `Composition`, all 10 of those XRs are instantly updated following any updates you make to the `big-platform-db` `Composition`. Composition Revisions allow XRs to opt out of automatic updates. Instead you can update your XRs to use the latest `Composition` settings at your own pace. This enables you to [canary](https://martinfowler.com/bliki/CanaryRelease.html) changes to your infrastructure, or to roll back some XRs to previous `Composition` settings without rolling back all XRs. Using composition revisions[](https://docs.crossplane.io/v2.0/composition/composition-revisions/#using-composition-revisions) ------------------------------------------------------------------------------------------------------------------------------ When you enable Composition Revisions three things happen: 1. Crossplane creates a `CompositionRevision` for each `Composition` update. 2. Composite Resources gain a `spec.crossplane.compositionRevisionRef` field that specifies which `CompositionRevision` they use. 3. Composite Resources gain a `spec.crossplane.compositionUpdatePolicy` field that specifies how Crossplane should update them to new Composition Revisions. Each time you edit a `Composition` Crossplane automatically creates a `CompositionRevision` that represents that ‘revision’ of the `Composition` - that unique state. Crossplane allocates each revision an increasing revision number. This gives `CompositionRevision` consumers an idea about which revision is ’newest’. You can discover which revisions exist using `kubectl`: 1# Find all revisions of the Composition named 'example' 2kubectl get compositionrevision -l crossplane.io/composition-name=example This should produce output something like: 1NAME REVISION AGE 2example-18pdgs2 1 4m36s 3example-2bgdr31 2 73s 4example-xjrdmzz 3 61s > A `Composition` is a mutable resource that you can update as your needs change over time. Each `CompositionRevision` is an immutable snapshot of those needs at a particular time. Crossplane behaves the same way by default whether you enable Composition Revisions or not. When you enable Composition Revisions all XRs default to the `Automatic` `compositionUpdatePolicy`. XRs support two update policies: * `Automatic`: Automatically use the latest `CompositionRevision`. (Default) * `Manual`: Require manual intervention to change `CompositionRevision`. The below XR uses the `Manual` policy. When you use this policy the XR selects the latest `CompositionRevision` when it’s first created, but must manually update it when you wish it to use another `CompositionRevision`. 1apiVersion: example.org/v1alpha1 2kind: PlatformDB 3metadata: 4 namespace: default 5 name: example 6spec: 7 storageGB: 20 8 crossplane: 9 # The Manual policy specifies that you don't want this XR to update to the 10 # latest CompositionRevision automatically. 11 compositionUpdatePolicy: Manual 12 compositionRef: 13 name: example Crossplane sets an XR’s `compositionRevisionRef` automatically at creation time regardless of your chosen `compositionUpdatePolicy`. If you choose the `Manual` policy you must edit the `compositionRevisionRef` field when you want your XR to use a different `CompositionRevision`. 1apiVersion: example.org/v1alpha1 2kind: PlatformDB 3metadata: 4 namespace: default 5 name: example 6spec: 7 storageGB: 20 8 crossplane: 9 compositionUpdatePolicy: Manual 10 compositionRef: 11 name: example 12 # Update the referenced CompositionRevision if and when you are ready. 13 compositionRevisionRef: 14 name: example-18pdg Complete example[](https://docs.crossplane.io/v2.0/composition/composition-revisions/#complete-example) -------------------------------------------------------------------------------------------------------- This tutorial discusses how CompositionRevisions work and how they manage Composite Resource (XR) updates. This starts with a `Composition` and `CompositeResourceDefinition` (XRD) that defines a `MyVPC` resource and continues with creating multiple XRs to observe different upgrade paths. Crossplane assigns different CompositionRevisions to composite resources each time you update the composition. ### Preparation[](https://docs.crossplane.io/v2.0/composition/composition-revisions/#preparation) #### Deploy composition and XRD examples[](https://docs.crossplane.io/v2.0/composition/composition-revisions/#deploy-composition-and-xrd-examples) Apply the example Composition. 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 labels: 5 channel: dev 6 name: myvpcs.aws.example.upbound.io 7spec: 8 compositeTypeRef: 9 apiVersion: aws.example.upbound.io/v1alpha1 10 kind: MyVPC 11 mode: Pipeline 12 pipeline: 13 - step: patch-and-transform 14 functionRef: 15 name: function-patch-and-transform 16 input: 17 apiVersion: pt.fn.crossplane.io/v1beta1 18 kind: Resources 19 resources: 20 - name: my-vpc 21 base: 22 apiVersion: ec2.aws.m.upbound.io/v1beta1 23 kind: VPC 24 spec: 25 forProvider: 26 region: us-west-1 27 cidrBlock: 192.168.0.0/16 28 enableDnsSupport: true 29 enableDnsHostnames: true Apply the example XRD. 1apiVersion: apiextensions.crossplane.io/v1 2kind: CompositeResourceDefinition 3metadata: 4 name: myvpcs.aws.example.upbound.io 5spec: 6 group: aws.example.upbound.io 7 names: 8 kind: MyVPC 9 plural: myvpcs 10 versions: 11 - name: v1alpha1 12 served: true 13 referenceable: true 14 schema: 15 openAPIV3Schema: 16 type: object 17 properties: 18 spec: 19 type: object 20 properties: 21 id: 22 type: string 23 description: ID of this VPC that other objects will use to refer to it. 24 required: 25 - id Verify that Crossplane created the Composition revision 1kubectl get compositionrevisions -o="custom-columns=NAME:.metadata.name,REVISION:.spec.revision,CHANNEL:.metadata.labels.channel" Expected Output: 1NAME REVISION CHANNEL 2myvpcs.aws.example.upbound.io-ad265bc 1 dev Note The label `dev` is automatically created from the Composition. ### Create composite resources[](https://docs.crossplane.io/v2.0/composition/composition-revisions/#create-composite-resources) This tutorial has four composite resources to cover different update policies and composition selection options. The default behavior is updating XRs to the latest revision of the Composition. You can change this by setting `compositionUpdatePolicy: Manual` in the XR. It’s also possible to select the latest revision with a specific label with `compositionRevisionSelector.matchLabels` together with `compositionUpdatePolicy: Automatic`. #### Default update policy[](https://docs.crossplane.io/v2.0/composition/composition-revisions/#default-update-policy) Create an XR without a `compositionUpdatePolicy` defined. The update policy is `Automatic` by default: 1apiVersion: aws.example.upbound.io/v1alpha1 2kind: MyVPC 3metadata: 4 namespace: default 5 name: vpc-auto 6spec: 7 id: vpc-auto Expected Output: 1myvpc.aws.example.upbound.io/vpc-auto created #### Manual update policy[](https://docs.crossplane.io/v2.0/composition/composition-revisions/#manual-update-policy) Create a Composite Resource with `compositionUpdatePolicy: Manual` and `compositionRevisionRef`. 1apiVersion: aws.example.upbound.io/v1alpha1 2kind: MyVPC 3metadata: 4 namespace: default 5 name: vpc-man 6spec: 7 id: vpc-man 8 crossplane: 9 compositionUpdatePolicy: Manual 10 compositionRevisionRef: 11 name: myvpcs.aws.example.upbound.io-ad265bc Expected Output: 1myvpc.aws.example.upbound.io/vpc-man created #### Using a selector[](https://docs.crossplane.io/v2.0/composition/composition-revisions/#using-a-selector) Create an XR with a `compositionRevisionSelector` of `channel: dev`: 1apiVersion: aws.example.upbound.io/v1alpha1 2kind: MyVPC 3metadata: 4 namespace: default 5 name: vpc-dev 6spec: 7 id: vpc-dev 8 crossplane: 9 compositionRevisionSelector: 10 matchLabels: 11 channel: dev Expected Output: 1myvpc.aws.example.upbound.io/vpc-dev created Create an XR with a `compositionRevisionSelector` of `channel: staging`: 1apiVersion: aws.example.upbound.io/v1alpha1 2kind: MyVPC 3metadata: 4 namespace: default 5 name: vpc-staging 6spec: 7 id: vpc-staging 8 crossplane: 9 compositionRevisionSelector: 10 matchLabels: 11 channel: staging Expected Output: 1myvpc.aws.example.upbound.io/vpc-staging created Verify the Composite Resource with the label `channel: staging` doesn’t have a `REVISION`. All other XRs have a `REVISION` matching the created Composition Revision. 1kubectl get composite -o="custom-columns=NAME:.metadata.name,SYNCED:.status.conditions[0].status,REVISION:.spec.crossplane.compositionRevisionRef.name,POLICY:.spec.crossplane.compositionUpdatePolicy,MATCHLABEL:.spec.crossplane.compositionRevisionSelector.matchLabels" Expected Output: 1NAME SYNCED REVISION POLICY MATCHLABEL 2vpc-auto True myvpcs.aws.example.upbound.io-ad265bc Automatic 3vpc-dev True myvpcs.aws.example.upbound.io-ad265bc Automatic map[channel:dev] 4vpc-man True myvpcs.aws.example.upbound.io-ad265bc Manual 5vpc-staging False Automatic map[channel:staging] Note The `vpc-staging` XR label doesn’t match any existing Composition Revisions. ### Create new composition revisions[](https://docs.crossplane.io/v2.0/composition/composition-revisions/#create-new-composition-revisions) Crossplane creates a new CompositionRevision when you create or update a Composition. Label and annotation changes also trigger a new CompositionRevision. #### Update the composition label[](https://docs.crossplane.io/v2.0/composition/composition-revisions/#update-the-composition-label) Update the `Composition` label to `channel: staging`: 1kubectl label composition myvpcs.aws.example.upbound.io channel=staging --overwrite Expected Output: 1composition.apiextensions.crossplane.io/myvpcs.aws.example.upbound.io labeled Verify that Crossplane creates a new Composition revision: 1kubectl get compositionrevisions -o="custom-columns=NAME:.metadata.name,REVISION:.spec.revision,CHANNEL:.metadata.labels.channel" Expected Output: 1NAME REVISION CHANNEL 2myvpcs.aws.example.upbound.io-727b3c8 2 staging 3myvpcs.aws.example.upbound.io-ad265bc 1 dev Verify that Crossplane assigns the Composite Resources `vpc-auto` and `vpc-staging` to Composite `revision:2`. XRs `vpc-man` and `vpc-dev` are still assigned to the original `revision:1`: 1kubectl get composite -o="custom-columns=NAME:.metadata.name,SYNCED:.status.conditions[0].status,REVISION:.spec.crossplane.compositionRevisionRef.name,POLICY:.spec.crossplane.compositionUpdatePolicy,MATCHLABEL:.spec.crossplane.compositionRevisionSelector.matchLabels" Expected Output: 1NAME SYNCED REVISION POLICY MATCHLABEL 2vpc-auto True myvpcs.aws.example.upbound.io-727b3c8 Automatic 3vpc-dev True myvpcs.aws.example.upbound.io-ad265bc Automatic map[channel:dev] 4vpc-man True myvpcs.aws.example.upbound.io-ad265bc Manual 5vpc-staging True myvpcs.aws.example.upbound.io-727b3c8 Automatic map[channel:staging] Note `vpc-auto` always use the latest Revision. `vpc-staging` now matches the label applied to Revision `revision:2`. #### Update composition spec and label[](https://docs.crossplane.io/v2.0/composition/composition-revisions/#update-composition-spec-and-label) Update the Composition to disable DNS support in the VPC and change the label from `staging` back to `dev`. Apply the following changes to update the `Composition` spec and label: 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 labels: 5 channel: dev 6 name: myvpcs.aws.example.upbound.io 7spec: 8 compositeTypeRef: 9 apiVersion: aws.example.upbound.io/v1alpha1 10 kind: MyVPC 11 mode: Pipeline 12 pipeline: 13 - step: patch-and-transform 14 functionRef: 15 name: function-patch-and-transform 16 input: 17 apiVersion: pt.fn.crossplane.io/v1beta1 18 kind: Resources 19 resources: 20 - name: my-vpc 21 base: 22 apiVersion: ec2.aws.m.upbound.io/v1beta1 23 kind: VPC 24 spec: 25 forProvider: 26 region: us-west-1 27 cidrBlock: 192.168.0.0/16 28 enableDnsSupport: false 29 enableDnsHostnames: true Expected Output: 1composition.apiextensions.crossplane.io/myvpcs.aws.example.upbound.io configured Verify that Crossplane creates a new Composition revision: 1kubectl get compositionrevisions -o="custom-columns=NAME:.metadata.name,REVISION:.spec.revision,CHANNEL:.metadata.labels.channel" Expected Output: 1NAME REVISION CHANNEL 2myvpcs.aws.example.upbound.io-727b3c8 2 staging 3myvpcs.aws.example.upbound.io-ad265bc 1 dev 4myvpcs.aws.example.upbound.io-f81c553 3 dev Note Changing the label and the spec values simultaneously is critical for deploying new changes to the `dev` channel. Verify Crossplane assigns the Composite Resources `vpc-auto` and `vpc-dev` to Composite `revision:3`. Crossplane assigns `vpc-staging` to `revision:2`, and still assigns `vpc-man` to the original `revision:1`: 1kubectl get composite -o="custom-columns=NAME:.metadata.name,SYNCED:.status.conditions[0].status,REVISION:.spec.crossplane.compositionRevisionRef.name,POLICY:.spec.crossplane.compositionUpdatePolicy,MATCHLABEL:.spec.crossplane.compositionRevisionSelector.matchLabels" Expected Output: 1NAME SYNCED REVISION POLICY MATCHLABEL 2vpc-auto True myvpcs.aws.example.upbound.io-f81c553 Automatic 3vpc-dev True myvpcs.aws.example.upbound.io-f81c553 Automatic map[channel:dev] 4vpc-man True myvpcs.aws.example.upbound.io-ad265bc Manual 5vpc-staging True myvpcs.aws.example.upbound.io-727b3c8 Automatic map[channel:staging] Note `vpc-dev` matches the updated label applied to Revision `revision:3`. `vpc-staging` matches the label applied to Revision `revision:2`. --- # Managed Resource Activation Policies · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#) [master](https://docs.crossplane.io/master/managed-resources/managed-resource-activation-policies/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Managed Resource Activation Policies ==================================== This is an alpha feature. Crossplane may change or drop this feature at any time. This feature was introduced in v2. For more information read the [Crossplane feature lifecycle](https://docs.crossplane.io/v2.0/learn/feature-lifecycle/) . On this page **On this page** * * * Important Managed resource activation policies work with [managed resource definitions](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/) , which Crossplane v2.0+ enables by default. To disable this behavior, set `--enable-custom-to-managed-resource-conversion=false` when installing Crossplane. A `ManagedResourceActivationPolicy` (MRAP) controls which [ManagedResourceDefinitions](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/) become active in your cluster. MRAPs enable selective installation of provider resources, allowing you to activate only the 10 managed resources you need instead of the 100+ that a provider ships. The selective activation problem[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#the-selective-activation-problem) ------------------------------------------------------------------------------------------------------------------------------------------------------------- Modern Crossplane providers can ship dozens or hundreds of managed resources, but most users only need a small subset. Before MRAPs, you got “all or nothing” - installing a provider meant getting every managed resource it supported, consuming unnecessary cluster resources. MRAPs solve this by providing pattern-based activation of ManagedResourceDefinitions, letting you choose which provider resources to enable. How MRAPs work[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#how-mraps-work) ------------------------------------------------------------------------------------------------------------------------- MRAPs contain activation patterns that match ManagedResourceDefinition names. When you create or update an MRAP, Crossplane: 1. **Lists all MRDs** in the cluster 2. **Matches MRD names** against the activation patterns 3. **Activates matching MRDs** by setting their `state` to `Active` 4. **Updates the MRAP status** with the list of activated resources 1apiVersion: apiextensions.crossplane.io/v1alpha1 2kind: ManagedResourceActivationPolicy 3metadata: 4 name: aws-core-resources 5spec: 6 activate: 7 - buckets.s3.aws.m.crossplane.io # Modern v2 style S3 buckets 8 - instances.rds.aws.m.crossplane.io # Modern v2 style RDS instances 9 - "*.ec2.aws.m.crossplane.io" # All modern v2 style EC2 resources When you apply this MRAP, Crossplane activates the specified S3 Bucket, RDS Instance, and all EC2 resources, leaving other AWS resources inactive. Key features[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#key-features) --------------------------------------------------------------------------------------------------------------------- * **Pattern-based matching**: Use wildcards to activate groups of resources * **Multiple policy support**: Different MRAPs can activate different resource sets * **Status tracking**: See which resources each policy activated * **Automatic activation**: New MRDs matching existing patterns activate automatically Pattern matching[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#pattern-matching) ----------------------------------------------------------------------------------------------------------------------------- ### Exact matching[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#exact-matching) Specify complete MRD names for precise control: 1spec: 2 activate: 3 - buckets.s3.aws.m.crossplane.io 4 - databases.rds.aws.m.crossplane.io 5 - clusters.eks.aws.m.crossplane.io Important Use the **plural** name when using a complete MRD name, aligning with how Kubernetes expresses the complete names of CRDs. For example, use `buckets`, as opposed to `bucket`, in `buckets.s3.aws.m.crossplane.io`. ### Wildcard patterns[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#wildcard-patterns) Use `*` wildcards to match multiple resources: 1spec: 2 activate: 3 - "*.s3.aws.m.crossplane.io" # All S3 resources 4 - "*.ec2.aws.m.crossplane.io" # All EC2 resources 5 - "*.rds.aws.m.crossplane.io" # All RDS databases Important MRAPs use prefix-only wildcards, not full regular expressions. Only `*` at the beginning of a pattern works (for example, `*.s3.aws.m.crossplane.io`). Patterns like `s3.*.aws.m.crossplane.io` or `*.s3.*` aren’t valid. Tip You can mix exact names and wildcards for flexible activation: 1spec: 2 activate: 3 - buckets.s3.aws.m.crossplane.io # Exact S3 buckets 4 - "*.ec2.aws.m.crossplane.io" # All EC2 resources 5 - clusters.eks.aws.m.crossplane.io # Exact EKS clusters Legacy and modern resource versions[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#legacy-and-modern-resource-versions) ------------------------------------------------------------------------------------------------------------------------------------------------------------------- Crossplane v2 supports two styles of managed resources: * **Modern v2 style** (recommended): Use `*.m.crossplane.io` domains for namespaced managed resources with better isolation and security * **Legacy v1 style**: Use `*.crossplane.io` domains for cluster-scoped managed resources (maintained for backward compatibility) ### Activating modern resources[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#activating-modern-resources) Most examples in this guide use modern v2 style resources: 1spec: 2 activate: 3 - buckets.s3.aws.m.crossplane.io # Modern v2 S3 bucket 4 - "*.ec2.aws.m.crossplane.io" # All modern v2 EC2 resources ### Activating legacy resources[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#activating-legacy-resources) To activate legacy v1 style resources, use patterns without `.m`: 1spec: 2 activate: 3 - buckets.s3.aws.crossplane.io # Legacy v1 S3 bucket 4 - "*.ec2.aws.crossplane.io" # All legacy v1 EC2 resources ### Mixed activation[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#mixed-activation) You can activate both modern and legacy resources in the same MRAP: 1spec: 2 activate: 3 - "*.aws.m.crossplane.io" # All modern AWS resources 4 - "*.aws.crossplane.io" # All legacy AWS resources Common activation strategies[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#common-activation-strategies) ----------------------------------------------------------------------------------------------------------------------------------------------------- ### Activate everything (default behavior)[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#activate-everything-default-behavior) The Crossplane Helm chart creates a default MRAP that activates all resources: 1apiVersion: apiextensions.crossplane.io/v1alpha1 2kind: ManagedResourceActivationPolicy 3metadata: 4 name: default 5spec: 6 activate: 7 - "*" # Activate all MRDs You can customize this during installation: 1# Disable default activations entirely 2helm install crossplane crossplane-stable/crossplane \ 3 --set provider.defaultActivations={} 4 5# Or provide custom default activations 6helm install crossplane crossplane-stable/crossplane \ 7 --set provider.defaultActivations={\ 8 "*.s3.aws.m.crossplane.io","*.ec2.aws.m.crossplane.io"} ### Provider-specific activation[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#provider-specific-activation) Activate all resources from specific providers: 1apiVersion: apiextensions.crossplane.io/v1alpha1 2kind: ManagedResourceActivationPolicy 3metadata: 4 name: aws-provider-resources 5spec: 6 activate: 7 - "*.aws.crossplane.io" # All AWS resources 8 - "*.aws.m.crossplane.io" # All AWS managed resources (v2 style) ### Service-specific activation[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#service-specific-activation) Activate resources for specific cloud services: 1apiVersion: apiextensions.crossplane.io/v1alpha1 2kind: ManagedResourceActivationPolicy 3metadata: 4 name: storage-and-compute 5spec: 6 activate: 7 - "*.s3.aws.m.crossplane.io" # AWS S3 resources 8 - "*.ec2.aws.m.crossplane.io" # AWS EC2 resources 9 - "*.storage.gcp.m.crossplane.io" # GCP Storage resources 10 - "*.compute.gcp.m.crossplane.io" # GCP Compute resources ### Minimal activation[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#minimal-activation) Activate only the resources you know you need: 1apiVersion: apiextensions.crossplane.io/v1alpha1 2kind: ManagedResourceActivationPolicy 3metadata: 4 name: minimal-footprint 5spec: 6 activate: 7 - buckets.s3.aws.m.crossplane.io # Just S3 buckets 8 - instances.ec2.aws.m.crossplane.io # Just EC2 instances 9 - databases.rds.aws.m.crossplane.io # Just RDS databases Multiple MRAPs[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#multiple-mraps) ------------------------------------------------------------------------------------------------------------------------- You can have multiple MRAPs in your cluster. Crossplane processes all MRAPs together and activates any MRD that matches at least one pattern. ### Team-based activation[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#team-based-activation) Different teams can manage their own activation policies: 1# Storage team MRAP 2apiVersion: apiextensions.crossplane.io/v1alpha1 3kind: ManagedResourceActivationPolicy 4metadata: 5 name: storage-team 6spec: 7 activate: 8 - "*.s3.aws.m.crossplane.io" 9 - "*.storage.gcp.m.crossplane.io" 10--- 11# Database team MRAP 12apiVersion: apiextensions.crossplane.io/v1alpha1 13kind: ManagedResourceActivationPolicy 14metadata: 15 name: database-team 16spec: 17 activate: 18 - "*.rds.aws.m.crossplane.io" 19 - "*.sql.gcp.m.crossplane.io" ### Configuration package activation[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#configuration-package-activation) Configuration packages can include MRAPs to declare their resource dependencies: 1# In your Configuration package 2apiVersion: apiextensions.crossplane.io/v1alpha1 3kind: ManagedResourceActivationPolicy 4metadata: 5 name: web-platform-dependencies 6spec: 7 activate: 8 - buckets.s3.aws.m.crossplane.io # For static assets 9 - instances.ec2.aws.m.crossplane.io # For web servers 10 - databases.rds.aws.m.crossplane.io # For application data 11 - certificates.acm.aws.m.crossplane.io # For HTTPS Working with MRAPs[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#working-with-mraps) --------------------------------------------------------------------------------------------------------------------------------- ### Creating MRAPs[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#creating-mraps) Apply an MRAP like any Kubernetes resource: 1kubectl apply -f my-activation-policy.yaml ### Viewing MRAPs[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#viewing-mraps) List all MRAPs: 1kubectl get managedresourceactivationpolicies View MRAP details and status: 1kubectl describe mrap aws-core-resources ### Checking activation status[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#checking-activation-status) MRAPs track which resources they’ve activated: 1status: 2 conditions: 3 - type: Healthy 4 status: "True" 5 reason: Running 6 activated: 7 - buckets.s3.aws.m.crossplane.io 8 - instances.ec2.aws.m.crossplane.io 9 - instances.rds.aws.m.crossplane.io 10 - securitygroups.ec2.aws.m.crossplane.io 11 - subnets.ec2.aws.m.crossplane.io 12 - vpcs.ec2.aws.m.crossplane.io MRAP status conditions[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#mrap-status-conditions) ----------------------------------------------------------------------------------------------------------------------------------------- ### Healthy condition[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#healthy-condition) * **`Healthy: True, Reason: Running`**: MRAP works * **`Healthy: Unknown, Reason: EncounteredErrors`**: Some MRDs failed to activate Troubleshooting MRAPs[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#troubleshooting-mraps) --------------------------------------------------------------------------------------------------------------------------------------- ### MRAP exists but resources aren’t activated[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#mrap-exists-but-resources-arent-activated) **Symptoms**: MRAP shows `activated: []` or missing expected resources **Causes and solutions:** 1. **Pattern doesn’t match MRD names** 1# List available MRDs 2kubectl get mrds 3 4# Check your pattern matches 5kubectl get mrds -o name | grep "your-pattern" 2. **MRDs don’t exist yet** * Install the required provider first * Providers create MRDs when they start 3. **Provider doesn’t support activation** 1# Check provider capabilities 2kubectl get providerrevision \ 3 -o jsonpath='{.status.capabilities}' 4# Look for "safe-start" ### MRAP shows activation errors[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#mrap-shows-activation-errors) **Symptoms**: MRAP has `Healthy: Unknown` status with errors **Status condition example:** 1conditions: 2- type: Healthy 3 status: "Unknown" 4 reason: EncounteredErrors 5 message: "failed to activate 2 of 5 ManagedResourceDefinitions" **Solution**: select MRAP events for specific failure details: 1kubectl describe mrap 2# Look at the Events section for activation errors ### Resources activate when you don’t expect them to[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#resources-activate-when-you-dont-expect-them-to) **Symptoms**: more resources are active than expected **Cause**: multiple MRAPs with overlapping patterns (this is normal behavior) **Solution**: review all MRAP patterns to understand which policies are activating which resources 1# List all MRAP activation patterns 2kubectl get mrap \ 3 -o jsonpath='{range .items[*]}{.metadata.name}: {.spec.activate}{"\n"}{end}' 4 5# Check which MRAPs activated each resource 6kubectl get mrap \ 7 -o jsonpath='{range .items[*]}{.metadata.name}: {.status.activated}{"\n"}{end}' Best practices[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#best-practices) ------------------------------------------------------------------------------------------------------------------------- MRAPs are additive - multiple MRAPs can activate the same resource without conflicts. This enables team-based activation strategies and Configuration package dependencies. 1. **Start specific, broaden as needed** - Begin with exact resource names (using the plural name for each resource), add wildcards only when beneficial for maintainability 2. **Plan for provider evolution** - Design wildcard patterns that accommodate new resources as providers add them (for example, `*.s3.aws.m.crossplane.io` works for future S3 resources) 3. **Group related resources logically** - Create MRAPs that activate resources teams actually use together 4. **Include activation dependencies in Configuration packages** - Configuration packages should declare what MRDs they need rather than assuming resources are available 5. **Use conservative patterns in shared environments** - Avoid overly broad wildcards that activate unnecessary resources when multiple teams share providers Next steps[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/#next-steps) ----------------------------------------------------------------------------------------------------------------- * Learn about [ManagedResourceDefinitions](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/) to understand what MRAPs activate * See the [disabling unused managed resources guide](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/) for step-by-step implementation * Check the [API reference](https://docs.crossplane.io/v2.0/api/) for complete MRAP schema documentation --- # Composite Resource Definitions · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#) [master](https://docs.crossplane.io/master/composition/composite-resource-definitions/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/) [v1.20](https://docs.crossplane.io/v1.20/concepts/composite-resource-definitions/) [v1.19](https://docs.crossplane.io/v1.19/concepts/composite-resource-definitions/) Composite Resource Definitions ============================== On this page **On this page** * * * Composite resource definitions (`XRDs`) define the schema for a custom API. Users create composite resources (`XRs`) using the API schema defined by an XRD. Note Read the [composite resources](https://docs.crossplane.io/v2.0/composition/composite-resources/) page for more information about composite resources. What are XRs, XRDs and Compositions? ------------------------------------ A [composite resource](https://docs.crossplane.io/v2.0/composition/composite-resources/) or XR is a custom API. You use two Crossplane types to create a new custom API: * A Composite Resource Definition (XRD) - This page. Defines the XR’s schema. * A [Composition](https://docs.crossplane.io/v2.0/composition/compositions/) - Configures how the XR creates other resources. Crossplane XRDs are like [Kubernetes custom resource definitions](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/) . XRDs require fewer fields and add options related to Crossplane, like connection secrets. Creating a CompositeResourceDefinition[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#creating-a-compositeresourcedefinition) ------------------------------------------------------------------------------------------------------------------------------------------------------------- Creating a CompositeResourceDefinition consists of: * [Defining a custom API group](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#xrd-groups) . * [Defining a custom API name](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#xrd-names) . * [Defining a custom API schema and version](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#xrd-versions) . * [Setting the scope](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#xrd-scope) (namespaced or cluster-scoped). Optionally, CompositeResourceDefinitions also support: * [Setting composite resource defaults](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#set-composite-resource-defaults) . Composite resource definitions (`XRDs`) create new API endpoints inside a Kubernetes cluster. Creating a new API requires defining an API `group`, `name` and `version`. 1apiVersion: apiextensions.crossplane.io/v2 2kind: CompositeResourceDefinition 3metadata: 4 name: mydatabases.example.org 5spec: 6 scope: Namespaced 7 group: example.org 8 names: 9 kind: XMyDatabase 10 plural: mydatabases 11 versions: 12 - name: v1alpha1 13 # Removed for brevity After applying an XRD, Crossplane creates a new Kubernetes custom resource definition matching the defined API. For example, the XRD `mydatabases.example.org` creates a custom resource definition `mydatabases.example.org`. 1kubectl api-resources 2NAME SHORTNAMES APIVERSION NAMESPACED KIND 3mydatabases.example.org v1alpha1 true mydatabases 4# Removed for brevity Warning You can’t change the XRD `group` or `names`. You must delete and recreate the XRD to change the `group` or `names`. ### XRD groups[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#xrd-groups) Groups define a collection of related API endpoints. The `group` can be any value, but common convention is to map to a fully qualified domain name. Many XRDs may use the same `group` to create a logical collection of APIs. For example a `database` group may have a `relational` and `nosql` kinds. ### XRD names[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#xrd-names) The `names` field defines how to refer to this specific XRD. The required name fields are: * `kind` - the `kind` value to use when calling this API. The kind is [UpperCamelCased](https://kubernetes.io/docs/contribute/style/style-guide/#use-upper-camel-case-for-api-objects) . Crossplane recommends starting XRD `kinds` with an `X` to show it’s a custom Crossplane API definition. * `plural` - the plural name used for the API URL. The plural name must be lowercase. Important The XRD `metadata.name` must be `plural` name, `.` (dot character), `group`. For example, `mydatabases.example.org` matches the `plural` name `mydatabases`, `.` `group` name, `example.org`. 1apiVersion: apiextensions.crossplane.io/v1 2kind: CompositeResourceDefinition 3metadata: 4 name: mydatabases.example.org 5spec: 6 group: example.org 7 names: 8 kind: XMyDatabase 9 plural: mydatabases 10 # Removed for brevity ### XRD versions[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#xrd-versions) The XRD `version` is like the [API versioning used by Kubernetes](https://kubernetes.io/docs/reference/using-api/#api-versioning) . The version shows how mature or stable the API is and increments when changing, adding or removing fields in the API. Crossplane doesn’t require specific versions or a specific version naming convention, but following [Kubernetes API versioning guidelines](https://kubernetes.io/docs/reference/using-api/#api-versioning) is strongly recommended. * `v1alpha1` - A new API that may change at any time. * `v1beta1` - An existing API that’s considered stable. Breaking changes are strongly discouraged. * `v1` - A stable API that doesn’t have breaking changes. #### Define a schema[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#define-a-schema) The `schema` defines the names of the parameters, the data types of the parameters and which parameters are required or optional. Note All `schemas` follow the Kubernetes custom resource definition [OpenAPIv3 structural schema](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#specifying-a-structural-schema) . Each `version` of the API has a unique `schema`. All XRD `schemas` validate against the `openAPIV3Schema`. The schema is an OpenAPI `object` with the `properties` of a `spec` `object`. Inside the `spec.properties` is the custom API definition. In this example, the key `region` is a `string`. 1apiVersion: apiextensions.crossplane.io/v1 2kind: CompositeResourceDefinition 3metadata: 4 name: xdatabases.custom-api.example.org 5spec: 6 group: custom-api.example.org 7 names: 8 kind: xDatabase 9 plural: xdatabases 10 versions: 11 - name: v1alpha1 12 schema: 13 openAPIV3Schema: 14 type: object 15 properties: 16 spec: 17 type: object 18 properties: 19 region: 20 type: string 21 # Removed for brevity A composite resource using this API references the `group/version` and `kind`. The `spec` has the `region` key with a string value. 1apiVersion: custom-api.example.org/v1alpha1 2kind: xDatabase 3metadata: 4 name: my-composite-resource 5spec: 6 region: "US" Tip The custom API defined inside the `spec.properties` is an OpenAPIv3 specification. The [data models page](https://swagger.io/docs/specification/data-models/) of the Swagger documentation provides a list of examples using data types and input restrictions. The Kubernetes documentation lists [the set of special restrictions](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#validation) on what your OpenAPIv3 custom API can use. Important Changing or expanding the XRD schema requires restarting the [Crossplane pod](https://docs.crossplane.io/v2.0/guides/pods/#crossplane-pod) to take effect. ##### Required fields[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#required-fields) By default all fields in a schema are optional. Define a parameter as required with the `required` attribute. In this example the XRD requires `region` and `size` but `name` is optional. 1apiVersion: apiextensions.crossplane.io/v1 2kind: CompositeResourceDefinition 3metadata: 4 name: xdatabases.custom-api.example.org 5spec: 6 group: custom-api.example.org 7 names: 8 kind: xDatabase 9 plural: xdatabases 10 versions: 11 - name: v1alpha1 12 schema: 13 openAPIV3Schema: 14 type: object 15 properties: 16 spec: 17 type: object 18 properties: 19 region: 20 type: string 21 size: 22 type: string 23 name: 24 type: string 25 required: 26 - region 27 - size 28 # Removed for brevity According to the OpenAPIv3 specification, the `required` field is per-object. If a schema contains multiple objects the schema may need multiple `required` fields. This XRD defines two objects: 1. the top-level `spec` object 2. a second `location` object The `spec` object `requires` the `size` and `location` but `name` is optional. Inside the required `location` object, `country` is `required` and `zone` is optional. 1# Removed for brevity 2- name: v1alpha1 3 schema: 4 openAPIV3Schema: 5 type: object 6 properties: 7 spec: 8 type: object 9 properties: 10 size: 11 type: string 12 name: 13 type: string 14 location: 15 type: object 16 properties: 17 country: 18 type: string 19 zone: 20 type: string 21 required: 22 - country 23 required: 24 - size 25 - location The Swagger “[Describing Parameters](https://swagger.io/docs/specification/describing-parameters/) ” documentation has more examples. ##### Crossplane reserved fields[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#crossplane-reserved-fields) Crossplane doesn’t allow the following fields in a schema: * Any field under the object `spec.crossplane` * Any field under the object `status.crossplane` * `status.conditions` Crossplane ignores any fields matching the reserved fields. #### Serve and reference a schema[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#serve-and-reference-a-schema) To use a schema it must be `served: true` and `referenceable: true`. 1apiVersion: apiextensions.crossplane.io/v1 2kind: CompositeResourceDefinition 3metadata: 4 name: xdatabases.custom-api.example.org 5spec: 6 group: custom-api.example.org 7 names: 8 kind: xDatabase 9 plural: xdatabases 10 versions: 11 - name: v1alpha1 12 served: true 13 referenceable: true 14 schema: 15 openAPIV3Schema: 16 type: object 17 properties: 18 spec: 19 type: object 20 properties: 21 region: 22 type: string Composite resources can use any schema version set as `served: true`. Kubernetes rejects any composite resource using a schema version set as `served: false`. Tip Setting a schema version as `served:false` causes errors for users using an older schema. This can be an effective way to identify and upgrade users before deleting the older schema version. The `referenceable: true` field indicates which version of the schema Compositions use. Only one version can be `referenceable`. Note Changing which version is `referenceable:true` requires [updating the `compositeTypeRef.apiVersion`](https://docs.crossplane.io/v2.0/composition/compositions/#match-composite-resources) of any Compositions referencing that XRD. #### Multiple schema versions[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#multiple-schema-versions) Warning Crossplane supports defining multiple `versions`, but the schema of each version can’t change any existing fields, also called “making a breaking change.” Breaking schema changes between versions requires the use of [conversion webhooks](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/#webhook-conversion) . New versions may define new optional parameters, but new required fields are a “breaking change.” Crossplane XRDs use Kubernetes custom resource definitions for versioning. Read the Kubernetes documentation on [versions in CustomResourceDefinitions](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/) for more background on versions and breaking changes. Crossplane recommends implementing breaking schema changes as brand new XRDs. For XRDs, to create a new version of an API add a new `name` in the `versions` list. For example, this XRD version `v1alpha1` only has the field `region`. A second version, `v1` expands the API to have both `region` and `size`. 1apiVersion: apiextensions.crossplane.io/v1 2kind: CompositeResourceDefinition 3metadata: 4 name: xdatabases.custom-api.example.org 5spec: 6 group: custom-api.example.org 7 names: 8 kind: xDatabase 9 plural: xdatabases 10 versions: 11 - name: v1alpha1 12 schema: 13 openAPIV3Schema: 14 type: object 15 properties: 16 spec: 17 type: object 18 properties: 19 region: 20 type: string 21 - name: v1 22 schema: 23 openAPIV3Schema: 24 type: object 25 properties: 26 spec: 27 type: object 28 properties: 29 region: 30 type: string 31 size: 32 type: string Important Changing or expanding the XRD schema requires restarting the [Crossplane pod](https://docs.crossplane.io/v2.0/guides/pods/#crossplane-pod) to take effect. ### XRD scope[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#xrd-scope) The `scope` field determines whether composite resources created from this XRD exist in a namespace or at cluster scope. 1apiVersion: apiextensions.crossplane.io/v2 2kind: CompositeResourceDefinition 3metadata: 4 name: mydatabases.example.org 5spec: 6 scope: Namespaced 7 # Removed for brevity The scope field supports three values: * `Namespaced` - **(Default in v2)** - Composite resources exist in a namespace and can only compose resources in the same namespace. * `Cluster` - Composite resources are cluster-scoped and can compose resources in any namespace or at cluster scope. * `LegacyCluster` - Cluster-scoped with support for claims (v1 compatibility mode). Note Most XRDs should use `Namespaced` scope. This provides better security isolation and follows standard Kubernetes patterns. Use `Cluster` scope only for platform level resources like RBAC or cluster configuration. ### Set composite resource defaults[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#set-composite-resource-defaults) XRDs can set default parameters for composite resources. #### defaultCompositionRef[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#defaultcompositionref) It’s possible for multiple [Compositions](https://docs.crossplane.io/v2.0/composition/compositions/) to reference the same XRD. If more than one Composition references the same XRD, the composite resource must select which Composition to use. An XRD can define the default Composition to use with the `defaultCompositionRef` value. Set a `defaultCompositionRef` to set the default Composition. 1apiVersion: apiextensions.crossplane.io/v1 2kind: CompositeResourceDefinition 3metadata: 4 name: xdatabases.custom-api.example.org 5spec: 6 defaultCompositionRef: 7 name: myComposition 8 group: custom-api.example.org 9 names: 10 # Removed for brevity 11 versions: 12 # Removed for brevity #### defaultCompositionUpdatePolicy[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#defaultcompositionupdatepolicy) Changes to a Composition generate a new Composition revision. By default all composite resources use the updated Composition revision. Set the XRD `defaultCompositionUpdatePolicy` to `Manual` to prevent composite resources from automatically using the new revision. The default value is `defaultCompositionUpdatePolicy: Automatic`. Set `defaultCompositionUpdatePolicy: Manual` to set the default Composition update policy for composite resources and using this XRD. 1apiVersion: apiextensions.crossplane.io/v1 2kind: CompositeResourceDefinition 3metadata: 4 name: xdatabases.custom-api.example.org 5spec: 6 defaultCompositionUpdatePolicy: Manual 7 group: custom-api.example.org 8 names: 9 # Removed for brevity 10 versions: 11 # Removed for brevity #### enforcedCompositionRef[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#enforcedcompositionref) To require all composite resources to use a specific Composition use the `enforcedCompositionRef` setting in the XRD. For example, to require all composite resources using this XRD to use the Composition `myComposition` set `enforcedCompositionRef.name: myComposition`. 1apiVersion: apiextensions.crossplane.io/v1 2kind: CompositeResourceDefinition 3metadata: 4 name: xdatabases.custom-api.example.org 5spec: 6 enforcedCompositionRef: 7 name: myComposition 8 group: custom-api.example.org 9 names: 10 # Removed for brevity 11 versions: 12 # Removed for brevity Verify a CompositeResourceDefinition[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#verify-a-compositeresourcedefinition) --------------------------------------------------------------------------------------------------------------------------------------------------------- Verify an XRD with `kubectl get compositeresourcedefinition` or the short form, `kubectl get xrd`. 1kubectl get xrd 2NAME ESTABLISHED OFFERED AGE 3xdatabases.custom-api.example.org True True 22m The `ESTABLISHED` field indicates Crossplane installed the Kubernetes custom resource definition for this XRD. ### XRD conditions[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#xrd-conditions) Crossplane uses a standard set of `Conditions` for XRDs. View the conditions of a XRD under their `Status` with `kubectl describe xrd`. 1kubectl describe xrd 2Name: xpostgresqlinstances.database.starter.org 3API Version: apiextensions.crossplane.io/v1 4Kind: CompositeResourceDefinition 5# Removed for brevity 6Status: 7 Conditions: 8 Reason: WatchingCompositeResource 9 Status: True 10 Type: Established 11# Removed for brevity #### WatchingCompositeResource[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#watchingcompositeresource) `Reason: WatchingCompositeResource` indicates Crossplane defined the new Kubernetes custom resource definitions related to the composite resource and is watching for the creation of new composite resources. 1Type: Established 2Status: True 3Reason: WatchingCompositeResource #### TerminatingCompositeResource[](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/#terminatingcompositeresource) `Reason: TerminatingCompositeResource` indicates Crossplane is deleting the custom resource definitions related to the composite resource and is terminating the composite resource controller. 1Type: Established 2Status: False 3Reason: TerminatingCompositeResource --- # Operations · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/operations/#) [master](https://docs.crossplane.io/master/operations/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/operations/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Operations ========== This is an alpha feature. Crossplane may change or drop this feature at any time. This feature was introduced in v2. For more information read the [Crossplane feature lifecycle](https://docs.crossplane.io/v2.0/learn/feature-lifecycle/) . Run operational tasks with Crossplane Topics in this section: * [Operations](https://docs.crossplane.io/v2.0/operations/operation/) - Run function pipelines once to completion * [Cron Operations](https://docs.crossplane.io/v2.0/operations/cronoperation/) - Run function pipelines on a schedule * [Watch Operations](https://docs.crossplane.io/v2.0/operations/watchoperation/) - Run function pipelines on resource changes --- # Environment Configs · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/composition/environment-configs/#) [master](https://docs.crossplane.io/master/composition/environment-configs/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/composition/environment-configs/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Environment Configs =================== This is a beta feature. This feature was introduced in v1.11. This feature graduated to beta status in v1.18. For more information read the [Crossplane feature lifecycle](https://docs.crossplane.io/v2.0/learn/feature-lifecycle/) . On this page **On this page** * * * A Crossplane EnvironmentConfig is a cluster-scoped, strongly typed, [ConfigMap](https://kubernetes.io/docs/concepts/configuration/configmap/) \-like resource used by Compositions. Compositions can use the environment to store information from individual resources or to apply patches. Crossplane supports multiple `EnvironmentConfigs`, each acting as a unique data store. When Crossplane creates a composite resource, Crossplane merges all the EnvironmentConfigs referenced in the associated Composition and creates a unique in-memory environment for that composite resource. The composite resource can read and write data to their unique in-memory environment. Important The in-memory environment is unique to each composite resource. A composite resource can’t read data in another composite resource’s environment. Create an EnvironmentConfig[](https://docs.crossplane.io/v2.0/composition/environment-configs/#create-an-environmentconfig) ---------------------------------------------------------------------------------------------------------------------------- An `EnvironmentConfig` has a single object field, `data`. An EnvironmentConfig supports any data inside the `data` field. Here an example `EnvironmentConfig`. 1apiVersion: apiextensions.crossplane.io/v1beta1 2kind: EnvironmentConfig 3metadata: 4 name: example-environment 5data: 6 locations: 7 us: us-east-2 8 eu: eu-north-1 9 key1: value1 10 key2: value2 11 key3: 12 - item1 13 - item2 Access EnvironmentConfigs[](https://docs.crossplane.io/v2.0/composition/environment-configs/#access-environmentconfigs) ------------------------------------------------------------------------------------------------------------------------ [Composition Functions](https://docs.crossplane.io/v2.0/composition/compositions/) supporting [extra-resources](https://docs.crossplane.io/v2.0/composition/compositions/) , for example [function-environment-configs](https://github.com/crossplane-contrib/function-environment-configs) or [function-go-templating](https://github.com/crossplane-contrib/function-go-templating) . Migration from alpha composition environment[](https://docs.crossplane.io/v2.0/composition/environment-configs/#migration-from-alpha-composition-environment) -------------------------------------------------------------------------------------------------------------------------------------------------------------- Crossplane (`<=v1.17`) natively supported selecting `EnvironmentConfigs`, merging them into an `in-memory environment` and patching between that, composed and composite resources. From `v1.18`, Crossplane removed this native capability, in favor of [Composition Functions](https://docs.crossplane.io/v2.0/composition/compositions/) . Users that enabled Alpha Composition Environments (`--enable-environment-configs`) and leveraged the native features (`spec.environment.patches`, `spec.environment.environmentConfigs` and `*Environment` patches), have to migrate to Composition Functions to continue doing so. Automated migration to `Pipeline` mode is available through `crossplane beta convert pipeline-composition`, which moves a composition using `Resource` mode, to [function-patch-and-transform](https://docs.crossplane.io/v2.0/guides/function-patch-and-transform/) and, if needed, [function-environment-configs](https://github.com/crossplane-contrib/function-environment-configs) . See the documentation of [function-environment-configs](https://github.com/crossplane-contrib/function-environment-configs) for more details about manual migration. Select an EnvironmentConfig using function-environment-configs[](https://docs.crossplane.io/v2.0/composition/environment-configs/#select-an-environmentconfig-using-function-environment-configs) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Select the EnvironmentConfigs to use through [function-environment-configs](https://github.com/crossplane-contrib/function-environment-configs) ’s `Input`. The `environmentConfigs` field is a list of `EnvironmentConfigs` to retrieve, merge and pass to the next step in the pipeline through the [Context](https://docs.crossplane.io/v2.0/composition/compositions/#function-pipeline-context) at a well known key, `apiextensions.crossplane.io/environment`. Select an environment by `Reference` or by `Selector`: * A `Reference` selects an `EnvironmentConfig` by name. * The `Selector` selects an `EnvironmentConfig` by labels. 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: example-composition 5spec: 6 mode: Pipeline 7 pipeline: 8 - step: environmentConfigs 9 functionRef: 10 name: function-environment-configs 11 input: 12 apiVersion: environmentconfigs.fn.crossplane.io/v1beta1 13 kind: Input 14 spec: 15 environmentConfigs: 16 - type: Reference 17 ref: 18 name: example-environment 19 - type: Selector 20 selector: 21 matchLabels: 22 # Removed for brevity 23 # the environment will be passed to the next function in the pipeline 24 # as part of the context 25 26# Next step consuming the merged environment removed for brevity... If a Composition uses multiple `EnvironmentConfigs`, [function-environment-configs](https://github.com/crossplane-contrib/function-environment-configs) merges them together in the order they’re listed. ### Select by name[](https://docs.crossplane.io/v2.0/composition/environment-configs/#select-by-name) Select an `EnvironmentConfig` by name with `type: Reference`. Define `ref.name` to match the exact name of the environment. For example, select the `EnvironmentConfig` named `example-environment`: 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: example-composition 5spec: 6 mode: Pipeline 7 pipeline: 8 - step: environmentConfigs 9 functionRef: 10 name: function-environment-configs 11 input: 12 apiVersion: environmentconfigs.fn.crossplane.io/v1beta1 13 kind: Input 14 spec: 15 environmentConfigs: 16 - type: Reference 17 ref: 18 name: example-environment ### Select by label[](https://docs.crossplane.io/v2.0/composition/environment-configs/#select-by-label) Select an `EnvironmentConfig` by labels with a `type: Selector`. Define `selector.matchLabels` to a list of selectors either of type `Value`, or `FromCompositeFieldPath`. When matching the label’s value, provide an exact value with a `type: Value` and provide the value to match in the `value` field. [function-environment-configs](https://github.com/crossplane-contrib/function-environment-configs) can also match a label’s value based on an input in the composite resource. Use `type: FromCompositeFieldPath` and provide the field to match in the `valueFromFieldPath` field. 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: example-composition 5spec: 6 mode: Pipeline 7 pipeline: 8 - step: environmentConfigs 9 functionRef: 10 name: function-environment-configs 11 input: 12 apiVersion: environmentconfigs.fn.crossplane.io/v1beta1 13 kind: Input 14 spec: 15 environmentConfigs: 16 - type: Selector 17 selector: 18 matchLabels: 19 - key: my-label-key 20 type: Value 21 value: my-label-value 22 - key: my-label-key 23 type: FromCompositeFieldPath 24 valueFromFieldPath: spec.parameters.deploy 25 # Removed for brevity #### Manage selector results[](https://docs.crossplane.io/v2.0/composition/environment-configs/#manage-selector-results) Selecting environments by labels may return more than one environment. [function-environment-configs](https://github.com/crossplane-contrib/function-environment-configs) , by default, sorts all the results by name and only uses the first environment in the sorted list. Set the `selector.mode` to `Multiple` to return all matched EnvironmentConfigs. Use `mode: Single` to return a single environment, and error out if more than Crossplane finds one match. Sorting and the selection mode only applies to a single `Selector`. 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: example-composition 5spec: 6 mode: Pipeline 7 pipeline: 8 - step: environmentConfigs 9 functionRef: 10 name: function-environment-configs 11 input: 12 apiVersion: environmentconfigs.fn.crossplane.io/v1beta1 13 kind: Input 14 spec: 15 environmentConfigs: 16 - type: Selector 17 selector: 18 mode: Multiple 19 matchLabels: 20 - key: my-label-key 21 type: Value 22 value: my-label-value 23 - key: my-label-key 24 type: FromCompositeFieldPath 25 valueFromFieldPath: spec.parameters.deploy 26 - type: Selector 27 selector: 28 mode: Single 29 matchLabels: 30 - key: my-other-label-key 31 type: Value 32 value: my-other-label-value 33 - key: my-other-label-key 34 type: FromCompositeFieldPath 35 valueFromFieldPath: spec.parameters.deploy When using `mode: Multiple` limit the number of returned `EnvironmentConfigs` with `maxMatch` and define the maximum number to select. Use `minMatch` and define the minimum number of environments returned. The Function sorts the returned environments alphabetically by name by default. Sort the environments on a different field with `sortByFieldPath` and define the field to sort by. 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: example-composition 5spec: 6 mode: Pipeline 7 pipeline: 8 - step: environmentConfigs 9 functionRef: 10 name: function-environment-configs 11 input: 12 apiVersion: environmentconfigs.fn.crossplane.io/v1beta1 13 kind: Input 14 spec: 15 environmentConfigs: 16 - type: Selector 17 selector: 18 mode: Multiple 19 maxMatch: 4 20 sortByFieldPath: metadata.annotations[sort.by/weight] 21 matchLabels: 22 - key: my-label-key 23 type: Value 24 value: my-label-value 25 - key: my-label-key 26 type: FromCompositeFieldPath 27 valueFromFieldPath: spec.parameters.deploy The EnvironmentConfigs selected by `matchLabels` are then merged with all the other ones specified. #### Optional selector labels[](https://docs.crossplane.io/v2.0/composition/environment-configs/#optional-selector-labels) By default, Crossplane issues an error if the specified `valueFromFieldPath` field doesn’t exist in the composite resource. Set `fromFieldPathPolicy` to `Optional` to ignore a field if it doesn’t exist. 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: example-composition 5spec: 6 mode: Pipeline 7 pipeline: 8 - step: environmentConfigs 9 functionRef: 10 name: function-environment-configs 11 input: 12 apiVersion: environmentconfigs.fn.crossplane.io/v1beta1 13 kind: Input 14 spec: 15 environmentConfigs: 16 - type: Selector 17 selector: 18 mode: Multiple 19 maxMatch: 4 20 sortByFieldPath: metadata.annotations[sort.by/weight] 21 matchLabels: 22 - key: my-label-key 23 type: Value 24 value: my-label-value 25 - key: my-label-key 26 type: FromCompositeFieldPath 27 valueFromFieldPath: spec.parameters.deploy 28 fromFieldPathPolicy: Optional 29 # Removed for brevity Set a default value for an optional label by setting the default `value` for the `key` first using a `Value` selector, then define the `Optional` `FromCompositeFieldPath` one. For example, the Composition below defines `value: my-default-value` for the key `my-second-label-key`. If the Composite resource defines `spec.parameters.deploy`, [function-environment-configs](https://github.com/crossplane-contrib/function-environment-configs) uses that instead. 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: example-composition 5spec: 6 mode: Pipeline 7 pipeline: 8 - step: environmentConfigs 9 functionRef: 10 name: function-environment-configs 11 input: 12 apiVersion: environmentconfigs.fn.crossplane.io/v1beta1 13 kind: Input 14 spec: 15 environmentConfigs: 16 - type: Selector 17 selector: 18 matchLabels: 19 - key: my-first-label-key 20 type: Value 21 value: my-label-value 22 - key: my-second-label-key 23 type: Value 24 value: my-default-value 25 - key: my-second-label-key 26 type: FromCompositeFieldPath 27 valueFromFieldPath: spec.parameters.deploy 28 fromFieldPathPolicy: Optional 29 # Removed for brevity Warning [function-environment-configs](https://github.com/crossplane-contrib/function-environment-configs) applies values in order. The value of the last key defined always takes precedence. Defining the default value _after_ the label always overwrites the label value. Patching with EnvironmentConfigs using function-patch-and-transform[](https://docs.crossplane.io/v2.0/composition/environment-configs/#patching-with-environmentconfigs-using-function-patch-and-transform) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ `EnvironmentConfigs` selected as explained earlier, are then merged in an `in-memory environment` by [function-environment-configs](https://github.com/crossplane-contrib/function-environment-configs) and passed to the next function in the pipeline at a well known key, `apiextensions.crossplane.io/environment`. You can use [function-patch-and-transform](https://docs.crossplane.io/v2.0/guides/function-patch-and-transform/) to read or write data between the in-memory environment and composite resource or individual composed resources. Tip The Patch and Transform function can use the environment to patch composed resources. Read about EnvironmentConfig patch types in the [Patch and Transform function documentation](https://docs.crossplane.io/v2.0/guides/function-patch-and-transform/) . ### Patch between Composite resource and environment[](https://docs.crossplane.io/v2.0/composition/environment-configs/#patch-between-composite-resource-and-environment) To patch between Composite resource and environment define patches at `spec.environment.patches` in the `Resources` input of [function-patch-and-transform](https://docs.crossplane.io/v2.0/guides/function-patch-and-transform/) . Use the `ToCompositeFieldPath` patch type to copy data from the in-memory environment to the Composite resource. Use the `FromCompositeFieldPath` to copy data from the Composite resource to the in-memory environment. 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: example-composition 5spec: 6 mode: Pipeline 7 pipeline: 8 # Removed for Brevity 9 - step: patch-and-transform 10 functionRef: 11 name: function-patch-and-transform 12 input: 13 apiVersion: pt.fn.crossplane.io/v1beta1 14 kind: Resources 15 environment: 16 patches: 17 - type: ToCompositeFieldPath 18 fromFieldPath: tags 19 toFieldPath: metadata.labels[envTag] 20 - type: FromCompositeFieldPath 21 fromFieldPath: metadata.name 22 toFieldPath: newEnvironmentKey 23# Removed for Brevity Individual resources can use any data written to the in-memory environment. You can use `CombineFromComposite` and `CombineToComposite` to combine multiple values and write the result either to the in-memory environment or the Composite resource, respectively. ### Patch an individual resource[](https://docs.crossplane.io/v2.0/composition/environment-configs/#patch-an-individual-resource) To patch between individual resources and the in-memory environment, inside the patches of the resource, use `ToEnvironmentFieldPath` to copy data from the resource to the in-memory environment. Use `FromEnvironmentFieldPath` to copy data to the resource from the in-memory environment. 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: example-composition 5spec: 6 mode: Pipeline 7 pipeline: 8 # Removed for Brevity 9 - step: patch-and-transform 10 functionRef: 11 name: function-patch-and-transform 12 input: 13 apiVersion: pt.fn.crossplane.io/v1beta1 14 kind: Resources 15 # Removed for Brevity 16 resources: 17 - name: vpc 18 base: 19 apiVersion: ec2.aws.m.upbound.io/v1beta1 20 kind: VPC 21 spec: 22 forProvider: 23 cidrBlock: 172.16.0.0/16 24 patches: 25 - type: ToEnvironmentFieldPath 26 fromFieldPath: status.atProvider.id 27 toFieldPath: vpcId 28 - type: FromEnvironmentFieldPath 29 fromFieldPath: tags 30 toFieldPath: spec.forProvider.tags Tip The [Patch and Transform](https://docs.crossplane.io/v2.0/guides/function-patch-and-transform/) documentation has more information on patching individual resources. --- # Managed Resources · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/managed-resources/#) [master](https://docs.crossplane.io/master/managed-resources/managed-resources/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/) [v1.20](https://docs.crossplane.io/v1.20/concepts/managed-resources/) [v1.19](https://docs.crossplane.io/v1.19/concepts/managed-resources/) Managed Resources ================= Manage cloud resources in Kubernetes Topics in this section: * [Managed Resources](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/) - Kubernetes representations of cloud resources * [Managed Resource Definitions](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/) - Enable selective activation of provider resources * [Managed Resource Activation Policies](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/) - Choose which provider resources Crossplane activates * [Usages](https://docs.crossplane.io/v2.0/managed-resources/usages/) - Block deletion of in-use resources --- # Usages · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/managed-resources/usages/#) [master](https://docs.crossplane.io/master/managed-resources/usages/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/managed-resources/usages/) [v1.20](https://docs.crossplane.io/v1.20/concepts/usages/) [v1.19](https://docs.crossplane.io/v1.19/concepts/usages/) Usages ====== This is a beta feature. This feature was introduced in v1.14. This feature graduated to beta status in v1.19. For more information read the [Crossplane feature lifecycle](https://docs.crossplane.io/v2.0/learn/feature-lifecycle/) . On this page **On this page** * * * A `Usage` indicates a resource is in use. Two main use cases for Usages are as follows: 1. Protecting a resource from accidental deletion. 2. Deletion ordering by ensuring that a resource isn’t deleted before the deletion of its dependent resources. See the section [Usage for Deletion Protection](https://docs.crossplane.io/v2.0/managed-resources/usages/#usage-for-deletion-protection) for the first use case and the section [Usage for Deletion Ordering](https://docs.crossplane.io/v2.0/managed-resources/usages/#usage-for-deletion-ordering) for the second one. Enable usages[](https://docs.crossplane.io/v2.0/managed-resources/usages/#enable-usages) ----------------------------------------------------------------------------------------- Usages are a beta feature. Crossplane enables beta features by default. Disable `Usage` support by [changing the Crossplane pod setting](https://docs.crossplane.io/v2.0/guides/pods/#change-pod-settings) and setting `--enable-usages=false` argument. 1$ kubectl edit deployment crossplane --namespace crossplane-system 2apiVersion: apps/v1 3kind: Deployment 4spec: 5# Removed for brevity 6 template: 7 spec: 8 containers: 9 - args: 10 - core 11 - start 12 - --enable-usages=false Tip The [Crossplane install guide](https://docs.crossplane.io/v2.0/get-started/install/#feature-flags) describes enabling feature flags like `--enable-usages` with Helm. Create a usage[](https://docs.crossplane.io/v2.0/managed-resources/usages/#create-a-usage) ------------------------------------------------------------------------------------------- A `Usage` `spec` has a mandatory `of` field for defining the resource in use or protected. The `reason` field defines the reason for protection and the `by` field defines the using resource. Both fields are optional, but at least one of them must be provided. ### Usage for deletion protection[](https://docs.crossplane.io/v2.0/managed-resources/usages/#usage-for-deletion-protection) The following example prevents the deletion of the `my-database` resource by rejecting any deletion request with the `reason` defined. 1apiVersion: protection.crossplane.io/v1beta1 2kind: Usage 3metadata: 4 namespace: default 5 name: protect-production-database 6spec: 7 of: 8 apiVersion: rds.aws.m.upbound.io/v1beta1 9 kind: Instance 10 resourceRef: 11 name: my-database 12 reason: "Production Database - should never be deleted!" ### Usage for deletion ordering[](https://docs.crossplane.io/v2.0/managed-resources/usages/#usage-for-deletion-ordering) The following example prevents the deletion of `my-cluster` resource by rejecting any deletion request before the deletion of `my-prometheus-chart` resource. 1apiVersion: protection.crossplane.io/v1beta1 2kind: Usage 3metadata: 4 namespace: default 5 name: release-uses-cluster 6spec: 7 of: 8 apiVersion: eks.m.upbound.io/v1beta1 9 kind: Cluster 10 resourceRef: 11 name: my-cluster 12 by: 13 apiVersion: helm.m.crossplane.io/v1beta1 14 kind: Release 15 resourceRef: 16 name: my-prometheus-chart ### Using selectors with usages[](https://docs.crossplane.io/v2.0/managed-resources/usages/#using-selectors-with-usages) Usages can use `selectors` to define the resource in use or the using one. This enables using `labels` or `matching controller references` to define resource instead of providing the resource name. 1apiVersion: protection.crossplane.io/v1beta1 2kind: Usage 3metadata: 4 namespace: default 5 name: release-uses-cluster 6spec: 7 of: 8 apiVersion: eks.m.upbound.io/v1beta1 9 kind: Cluster 10 resourceSelector: 11 matchControllerRef: false # default, and could be omitted 12 matchLabels: 13 foo: bar 14 by: 15 apiVersion: helm.m.crossplane.io/v1beta1 16 kind: Release 17 resourceSelector: 18 matchLabels: 19 baz: qux After the `Usage` controller resolves the selectors, it persists the resource name in the `resourceRef.name` field. The following example shows the `Usage` resource after the resolution of selectors. Important The selectors are resolved only once. If there are more than one matches, a random resource is selected from the list of matched resources. 1apiVersion: protection.crossplane.io/v1beta1 2kind: Usage 3metadata: 4 namespace: default 5 name: release-uses-cluster 6spec: 7 of: 8 apiVersion: eks.m.upbound.io/v1beta1 9 kind: Cluster 10 resourceRef: 11 name: my-cluster 12 resourceSelector: 13 matchLabels: 14 foo: bar 15 by: 16 apiVersion: helm.m.crossplane.io/v1beta1 17 kind: Release 18 resourceRef: 19 name: my-cluster 20 resourceSelector: 21 matchLabels: 22 baz: qux ### Replay blocked deletion attempt[](https://docs.crossplane.io/v2.0/managed-resources/usages/#replay-blocked-deletion-attempt) By default, the deletion of a `Usage` resource doesn’t trigger the deletion of the resource in use even if there were deletion attempts blocked by the `Usage`. Replaying the blocked deletion is possible by setting the `replayDeletion` field to `true`. 1apiVersion: protection.crossplane.io/v1beta1 2kind: Usage 3metadata: 4 namespace: default 5 name: release-uses-cluster 6spec: 7 replayDeletion: true 8 of: 9 apiVersion: eks.m.upbound.io/v1beta1 10 kind: Cluster 11 resourceRef: 12 name: my-cluster 13 by: 14 apiVersion: helm.m.crossplane.io/v1beta1 15 kind: Release 16 resourceRef: 17 name: my-prometheus-chart Tip Replay deletion is useful when the used resource is part of a composition. This configuration radically decreases time for the deletion of the used resource, hence the composite owning it, by replaying the deletion of the used resource right after the using resource disappears instead of waiting for the long exponential backoff durations of the Kubernetes garbage collector. Usage in a Composition[](https://docs.crossplane.io/v2.0/managed-resources/usages/#usage-in-a-composition) ----------------------------------------------------------------------------------------------------------- A typical use case for Usages is to define a deletion ordering between the resources in a Composition. The Usages support [matching controller reference](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#matching-by-controller-reference) in selectors to ensures that the matching resource is in the same composite resource in the same way as [cross-resource referencing](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#referencing-other-resources) . Tip When there are multiple resources of same type in a Composition, the `Usage` resource must uniquely identify the resource in use or the using one. This could be accomplished by using extra labels and combining `matchControllerRef` with a `matchLabels` selector. Usage across namespaces[](https://docs.crossplane.io/v2.0/managed-resources/usages/#usage-across-namespaces) ------------------------------------------------------------------------------------------------------------- A `Usage` with `of` and `by` represents a usage relationship between two resources in the same namespace as the `Usage` by default. A `Usage` can represent a usage relationship between a `by` resource in the same namespace as the `Usage` and an `of` resource in a different namespace. To use a resource in a different namespace, specify the `namespace` in the `of` `resourceRef` or `resourceSelector`. 1apiVersion: protection.crossplane.io/v1beta1 2kind: Usage 3metadata: 4 namespace: default 5 name: release-uses-cluster 6spec: 7 of: 8 apiVersion: eks.m.upbound.io/v1beta1 9 kind: Cluster 10 resourceRef: 11 namespace: cluster-infra 12 name: my-cluster 13 by: 14 apiVersion: helm.m.crossplane.io/v1beta1 15 kind: Release 16 resourceRef: 17 name: my-prometheus-chart ClusterUsages[](https://docs.crossplane.io/v2.0/managed-resources/usages/#clusterusages) ----------------------------------------------------------------------------------------- Use a `ClusterUsage` to protect cluster scoped resources. 1apiVersion: protection.crossplane.io/v1beta1 2kind: ClusterUsage 3metadata: 4 name: protect-important-crd 5spec: 6 of: 7 apiVersion: apiextensions.k8s.io/v1 8 kind: CustomResourceDefinition 9 resourceRef: 10 name: importantresources.example.crossplane.io 11 reason: "Very important CRD - should never be deleted!" --- # Managed Resources · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#) [master](https://docs.crossplane.io/master/managed-resources/managed-resources/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/) [v1.20](https://docs.crossplane.io/v1.20/concepts/managed-resources/) [v1.19](https://docs.crossplane.io/v1.19/concepts/managed-resources/) Managed Resources ================= On this page **On this page** * * * A _managed resource_ (`MR`) represents an external service in a Provider. When users create a new managed resource, the Provider reacts by creating an external resource inside the Provider’s environment. Every external service managed by Crossplane maps to a managed resource. Note Crossplane calls the object inside Kubernetes a _managed resource_ and the external object inside the Provider an _external resource_. Examples of managed resources include: * Amazon AWS EC2 `Instance` defined in [provider-upjet-aws](https://github.com/crossplane-contrib/provider-upjet-aws) . * Google Cloud GKE `Cluster` defined in [provider-upjet-gcp](https://github.com/crossplane-contrib/provider-upjet-gcp) . * Microsoft Azure PostgreSQL `Database` defined in [provider-upjet-azure](https://github.com/crossplane-contrib/provider-upjet-azure) . Managed resource fields[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#managed-resource-fields) ------------------------------------------------------------------------------------------------------------------------ The Provider defines the group, kind and version of a managed resource. The Provider also define the available settings of a managed resource. ### Group, kind and version[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#group-kind-and-version) Each managed resource is a unique API endpoint with their own group, kind and version. For example the [AWS Provider](https://github.com/crossplane-contrib/provider-upjet-aws) defines the `Instance` kind from the group `ec2.aws.m.upbound.io` 1apiVersion: ec2.aws.m.upbound.io/v1beta1 2kind: Instance ### forProvider[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#forprovider) The `spec.forProvider` of a managed resource maps to the parameters of the external resource. For example, when creating an AWS EC2 instance, the Provider supports defining the AWS `region` and the VM size, called the `instanceType`. Note The Provider defines the settings and their valid values. Providers also define required and optional values in the `forProvider` definition. Refer to the documentation of your specific Provider for details. 1apiVersion: ec2.aws.m.upbound.io/v1beta1 2kind: Instance 3# Removed for brevity 4spec: 5 forProvider: 6 region: us-west-1 7 instanceType: t2.micro Important Crossplane considers the `forProvider` field of a managed resource the “source of truth” for external resources. Crossplane overrides any changes made to an external resource outside of Crossplane. If a user makes a change inside a Provider’s web console, Crossplane reverts that change back to what’s configured in the `forProvider` setting. #### Referencing other resources[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#referencing-other-resources) Some fields in a managed resource may depend on values from other managed resources. For example a VM may need the name of a virtual network to use. Managed resources can reference other managed resources by external name, name reference or selector. ##### Matching by external name[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#matching-by-external-name) When matching a resource by name Crossplane looks for the name of the external resource in the Provider. For example, a AWS VPC object named `my-test-vpc` has the external name `vpc-01353cfe93950a8ff`. 1kubectl get vpc 2NAME READY SYNCED EXTERNAL-NAME AGE 3my-test-vpc True True vpc-01353cfe93950a8ff 49m To match the VPC by name, use the external name. For example, creating a Subnet managed resource attached to this VPC. 1apiVersion: ec2.aws.m.upbound.io/v1beta1 2kind: Subnet 3spec: 4 forProvider: 5 # Removed for brevity 6 vpcId: vpc-01353cfe93950a8ff ##### Matching by name reference[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#matching-by-name-reference) To match a resource based on the name of the managed resource and not the external resource name inside the Provider, use a `nameRef`. For example, a AWS VPC object named `my-test-vpc` has the external name `vpc-01353cfe93950a8ff`. 1kubectl get vpc 2NAME READY SYNCED EXTERNAL-NAME AGE 3my-test-vpc True True vpc-01353cfe93950a8ff 49m To match the VPC by name reference, use the managed resource name. For example, creating a Subnet managed resource attached to this VPC. 1apiVersion: ec2.aws.m.upbound.io/v1beta1 2kind: Subnet 3spec: 4 forProvider: 5 # Removed for brevity 6 vpcIdRef: 7 name: my-test-vpc ##### Matching by selector[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#matching-by-selector) Matching by selector is the most flexible matching method. Use `matchLabels` to match the labels applied to a resource. For example, this Subnet resource only matches VPC resources with the label `my-label: label-value`. 1apiVersion: ec2.aws.m.upbound.io/v1beta1 2kind: Subnet 3spec: 4 forProvider: 5 # Removed for brevity 6 vpcIdSelector: 7 matchLabels: 8 my-label: label-value ##### Matching by controller reference[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#matching-by-controller-reference) Matching a controller reference ensures that the matching resource has the same Kubernetes controller reference. Matching a controller reference is useful for matching a resource that’s composed by the same composite resource (XR). Note Learn more about composite resources in the [Composite Resources](https://docs.crossplane.io/v2.0/composition/composite-resources/) section. Matching only a controller reference simplifies the matching process without requiring labels or more information. For example, creating an AWS `InternetGateway` requires a `VPC`. The `InternetGateway` could match a label, but every VPC created by this Composition shares the same label. Using `matchControllerRef` matches only the VPC created in the same composite resource that created the `InternetGateway`. #### Immutable fields[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#immutable-fields) Some providers don’t support changing the fields of some managed resources after creation. For example, you can’t change the `region` of an Amazon AWS RDS `Instance`. These fields are _immutable fields_. Amazon requires you delete and recreate the resource. Crossplane allows you to edit the immutable field of a managed resource, but doesn’t apply the change. Crossplane never deletes a resource based on a `forProvider` change. Note Crossplane behaves differently than other tools like Terraform. Terraform deletes and recreates a resource to change an immutable field. Crossplane only deletes an external resource if their corresponding managed you delete the resource object from Kubernetes. #### Late initialization[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#late-initialization) Crossplane treats the managed resource as the source of truth by default; it expects to have all values under `spec.forProvider` including the optional ones. If not provided, Crossplane populates the empty fields with the values assigned by the provider. For example, consider fields such as `region` and `availabilityZone`. You might specify only the region and let the cloud provider choose the availability zone. In this case, if the provider assigns an availability zone, Crossplane uses that value to populate the `spec.forProvider.availabilityZone` field. Note With [managementPolicies](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#managementpolicies) , this behavior can be turned off by not including the `LateInitialize` policy in the `managementPolicies` list. ### initProvider[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#initprovider) Important The managed resource `initProvider` option is a beta feature related to [managementPolicies](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#managementpolicies) . The `initProvider` defines settings Crossplane applies only when creating a new managed resource. Crossplane ignores settings defined in the `initProvider` field that change after creation. Note Settings in `forProvider` are always enforced by Crossplane. Crossplane reverts any changes to a `forProvider` field in the external resource. Settings in `initProvider` aren’t enforced by Crossplane. Crossplane ignores any changes to a `initProvider` field in the external resource. Using `initProvider` is useful for setting initial values that a Provider may automatically change, like an auto scaling group. For example, creating a `NodeGroup` with an initial `desiredSize`. Crossplane doesn’t change the `desiredSize` setting back when an autoscaler scales the Node Group external resource. Tip Crossplane recommends configuring `managementPolicies` without `LateInitialize` to avoid conflicts with `initProvider` settings. 1apiVersion: eks.aws.m.upbound.io/v1beta1 2kind: NodeGroup 3metadata: 4 namespace: default 5 name: sample-eks-ng 6spec: 7 managementPolicies: ["Observe", "Create", "Update", "Delete"] 8 initProvider: 9 scalingConfig: 10 desiredSize: 1 11 forProvider: 12 region: us-west-1 13 clusterName: my-cluster 14 scalingConfig: 15 maxSize: 4 16 minSize: 1 ### managementPolicies[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#managementpolicies) Note The managed resource `managementPolicies` option is a beta feature. Crossplane enables beta features by default. The Provider determines support for management policies. Refer to the Provider’s documentation to see if the Provider supports management policies. Crossplane `managementPolicies` determine which actions Crossplane can take on a managed resource and its corresponding external resource. Apply one or more `managementPolicies` to a managed resource to determine what permissions Crossplane has over the resource. For example, give Crossplane permission to create and delete an external resource, but not make any changes, set the policies to `["Create", "Delete", "Observe"]`. 1apiVersion: ec2.aws.m.upbound.io/v1beta1 2kind: Subnet 3spec: 4 managementPolicies: ["Create", "Delete", "Observe"] 5 forProvider: 6 # Removed for brevity The default policy grants Crossplane full control over the resources. Defining the `managementPolicies` field with an empty array [pauses](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#paused) the resource. Important The Provider determines support for management policies. Refer to the Provider’s documentation to see if the Provider supports management policies. Crossplane supports the following policies: | Policy | Description | | --- | --- | | `*` | _Default policy_. Crossplane has full control over a resource. | | `Create` | If the external resource doesn’t exist, Crossplane creates it based on the managed resource settings. | | `Delete` | Crossplane can delete the external resource when deleting the managed resource. | | `LateInitialize` | Crossplane initializes some external resource settings not defined in the `spec.forProvider` of the managed resource. See [the late initialization](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#late-initialization)
section for more details. | | `Observe` | Crossplane only observes the resource and doesn’t make any changes. Used for observe only resources. | | `Update` | Crossplane changes the external resource when changing the managed resource. | The following is a list of common policy combinations: | Create | Delete | LateInitialize | Observe | Update | Description | | --- | --- | --- | --- | --- | --- | | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | _Default policy_. Crossplane has full control over the resource. | | ✔️ | ✔️ | ✔️ | ✔️ | | After creation any changes made to the managed resource aren’t passed to the external resource. Useful for immutable external resources. | | ✔️ | ✔️ | | ✔️ | ✔️ | Prevent Crossplane from managing any settings not defined in the managed resource. Useful for immutable fields in an external resource. | | ✔️ | ✔️ | | ✔️ | | Crossplane doesn’t import any settings from the external resource and doesn’t push changes to the managed resource. Crossplane recreates the external resource if it’s deleted. | | ✔️ | | ✔️ | ✔️ | ✔️ | Crossplane doesn’t delete the external resource when deleting the managed resource. | | ✔️ | | ✔️ | ✔️ | | Crossplane doesn’t delete the external resource when deleting the managed resource. Crossplane doesn’t apply changes to the external resource after creation. | | ✔️ | | | ✔️ | ✔️ | Crossplane doesn’t delete the external resource when deleting the managed resource. Crossplane doesn’t import any settings from the external resource. | | ✔️ | | | ✔️ | | Crossplane creates the external resource but doesn’t apply any changes to the external resource or managed resource. Crossplane can’t delete the resource. | | | | | ✔️ | | Crossplane only observes a resource. | | | | | | | No policy set. An alternative method for [pausing](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#paused)
a resource. | ### providerConfigRef[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#providerconfigref) The `providerConfigRef` on a managed resource tells the Provider which [ProviderConfig](https://docs.crossplane.io/v2.0/packages/providers/#provider-configuration) to use when creating the managed resource. Use a ProviderConfig to define the authentication method to use when communicating to the Provider. Important If `providerConfigRef` isn’t applied, Providers use the ProviderConfig named `default`. For example, a managed resource references a ProviderConfig named `user-keys`. This matches the `name` of a ProviderConfig. 1apiVersion: ec2.aws.m.upbound.io/v1beta1 2kind: Instance 3metadata: 4 namespace: default 5 name: my-instance 6spec: 7 forProvider: 8 # Removed for brevity 9 providerConfigRef: 10 name: user-keys 11 kind: ProviderConfig 1apiVersion: aws.m.upbound.io/v1beta1 2kind: ProviderConfig 3metadata: 4 namespace: default 5 name: user-keys 6# Removed for brevity Tip Each managed resource can reference different ProviderConfigs. This allows different managed resources to authenticate with different credentials to the same Provider. #### ProviderConfig types[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#providerconfig-types) The AWS provider supports two types of ProviderConfig resources: **ProviderConfig** (namespace-scoped): 1# ProviderConfig - only applies to MRs in same namespace 2apiVersion: aws.m.upbound.io/v1beta1 3kind: ProviderConfig 4metadata: 5 namespace: default 6 name: my-config **ClusterProviderConfig** (cluster-wide): 1# ClusterProviderConfig - applies to MRs across all namespaces 2apiVersion: aws.m.upbound.io/v1beta1 3kind: ClusterProviderConfig 4metadata: 5 name: my-cluster-config When referencing any ProviderConfig, managed resources must specify both `name` and `kind`: 1spec: 2 providerConfigRef: 3 name: my-cluster-config 4 kind: ClusterProviderConfig 1spec: 2 providerConfigRef: 3 name: my-config 4 kind: ProviderConfig # References namespaced ProviderConfig If you omit `providerConfigRef` entirely, it defaults to: 1spec: 2 providerConfigRef: 3 name: default 4 kind: ClusterProviderConfig ### writeConnectionSecretToRef[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#writeconnectionsecrettoref) When a Provider creates a managed resource it may generate resource-specific details, like usernames, passwords or connection details like an IP address. Crossplane stores these details in a Kubernetes Secret object specified by the `writeConnectionSecretToRef` values. For example, when creating an AWS RDS database instance with the Crossplane [AWS provider](https://github.com/crossplane-contrib/provider-upjet-aws) generates an endpoint, password, port and username data. The Provider saves these variables in the Kubernetes secret `rds-secret`, referenced by the `writeConnectionSecretToRef` field. 1apiVersion: rds.aws.m.upbound.io/v1beta1 2kind: Instance 3metadata: 4 namespace: default 5 name: my-rds-instance 6spec: 7 forProvider: 8 # Removed for brevity 9 writeConnectionSecretToRef: 10 name: rds-secret Viewing the Secret object shows the saved fields. 1kubectl describe secret rds-secret 2Name: rds-secret 3# Removed for brevity 4Data 5==== 6port: 4 bytes 7username: 10 bytes 8endpoint: 54 bytes 9password: 27 bytes Important The Provider determines the data written to the Secret object. Refer to the specific Provider documentation for the generated Secret data. [ManagedResourceDefinitions](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/) can document what connection details a managed resource provides, though most providers don’t yet populate this information. Annotations[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#annotations) ------------------------------------------------------------------------------------------------ Crossplane applies a standard set of Kubernetes `annotations` to managed resources. | Annotation | Definition | | --- | --- | | `crossplane.io/external-name` | The name of the managed resource inside the Provider. | | `crossplane.io/external-create-pending` | The timestamp of when Crossplane began creating the managed resource. | | `crossplane.io/external-create-succeeded` | The timestamp of when the Provider successfully created the managed resource. | | `crossplane.io/external-create-failed` | The timestamp of when the Provider failed to create the managed resource. | | `crossplane.io/paused` | Indicates Crossplane isn’t reconciling this resource. Read the [Pause Annotation](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#paused)
for more details. | ### Naming external resources[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#naming-external-resources) By default Providers give external resources the same name as the Kubernetes object. For example, a managed resource named `my-rds-instance` has the name `my-rds-instance` as an external resource inside the Provider’s environment. 1apiVersion: rds.aws.m.upbound.io/v1beta1 2kind: Instance 3metadata: 4 namespace: default 5 name: my-rds-instance 1kubectl get instance 2NAME READY SYNCED EXTERNAL-NAME AGE 3my-rds-instance True True my-rds-instance 11m Managed resource created with a `crossplane.io/external-name` annotation already provided use the annotation value as the external resource name. For example, the Provider creates managed resource named `my-rds-instance` but uses the name `my-custom-name` for the external resource inside AWS. 1apiVersion: rds.aws.m.upbound.io/v1beta1 2kind: Instance 3metadata: 4 namespace: default 5 name: my-rds-instance 6 annotations: 7 crossplane.io/external-name: my-custom-name 1kubectl get instance 2NAME READY SYNCED EXTERNAL-NAME AGE 3my-rds-instance True True my-custom-name 11m ### Creation annotations[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#creation-annotations) When an external system like AWS generates nondeterministic resource names it’s possible for a provider to create a resource but not record that it did. When this happens the provider can’t manage the resource. Tip Crossplane calls resources that a provider creates but doesn’t manage _leaked resources_. Providers set three creation annotations to avoid and detect leaked resources: * `crossplane.io/external-create-pending` - The last time the provider was about to create the resource. * `crossplane.io/external-create-succeeded` - The last time the provider successfully created the resource. * `crossplane.io/external-create-failed` - The last time the provider failed to create the resource. Use `kubectl get` to view the annotations on a managed resource. For example, an AWS VPC resource: 1$ kubectl get -o yaml vpc my-vpc 2apiVersion: ec2.aws.m.upbound.io/v1beta1 3kind: VPC 4metadata: 5 namespace: default 6 name: my-vpc 7 annotations: 8 crossplane.io/external-name: vpc-1234567890abcdef0 9 crossplane.io/external-create-pending: "2023-12-18T21:48:06Z" 10 crossplane.io/external-create-succeeded: "2023-12-18T21:48:40Z" A provider uses the `crossplane.io/external-name` annotation to lookup a managed resource in an external system. The provider looks up the resource in the external system to determine if it exists, and if it matches the managed resource’s desired state. If the provider can’t find the resource, it creates it. Some external systems don’t let a provider specify a resource’s name when the provider creates it. Instead the external system generates an nondeterministic name and returns it to the provider. When the external system generates the resource’s name, the provider attempts to save it to the managed resource’s `crossplane.io/external-name` annotation. If it doesn’t, it _leaks_ the resource. A provider can’t guarantee that it can save the annotation. The provider could restart or lose network connectivity between creating the resource and saving the annotation. A provider can detect that it might have leaked a resource. If the provider thinks it might have leaked a resource, it stops reconciling it until you tell the provider it’s safe to proceed. Important Anytime an external system generates a resource’s name there is a risk the provider could leak the resource. The safest thing for a provider to do when it detects that it might have leaked a resource is to stop and wait for human intervention. This ensures the provider doesn’t create duplicates of the leaked resource. Duplicate resources can be costly and dangerous. When a provider thinks it might have leaked a resource it creates a `cannot determine creation result` event associated with the managed resource. Use `kubectl describe` to see the event. 1kubectl describe queue my-sqs-queue 2 3# Removed for brevity 4 5Events: 6 Type Reason Age From Message 7 ---- ------ ---- ---- ------- 8 Warning CannotInitializeManagedResource 29m (x19 over 19h) managed/queue.sqs.aws.m.crossplane.io cannot determine creation result - remove the crossplane.io/external-create-pending annotation if it is safe to proceed Providers use the creation annotations to detect that they might have leaked a resource. Each time a provider reconciles a managed resource it checks the resource’s creation annotations. If the provider sees a create pending time that’s more recent than the most recent create succeeded or create failed time, it knows that it might have leaked a resource. Note Providers don’t remove the creation annotations. They use the timestamps to determine which is most recent. It’s normal for a managed resource to have multiple creation annotations. The provider knows it might have leaked a resource because it updates all the resource’s annotations at the same time. If the provider couldn’t update the creation annotations after it created the resource, it also couldn’t update the `crossplane.io/external-name` annotation. Tip If a resource has a `cannot determine creation result` error, inspect the external system. Use the timestamp from the `crossplane.io/external-create-pending` annotation to determine when the provider might have leaked a resource. Look for resources created around this time. If you find a leaked resource, and it’s safe to do so, delete it from the external system. Remove the `crossplane.io/external-create-pending` annotation from the managed resource after you’re sure no leaked resource exists. This tells the provider to resume reconciliation of and recreate the managed resource. Providers also use the creation annotations to avoid leaking resources. When a provider writes the `crossplane.io/external-create-pending` annotation it knows it’s reconciling the latest version of the managed resource. The write would fail if the provider was reconciling an old version of the managed resource. If the provider reconciled an old version with an outdated `crossplane.io/external-name` annotation it could mistakenly determine that the resource didn’t exist. The provider would create a new resource, and leak the existing one. Some external systems have a delay between when a provider creates a resource and when the system reports that it exists. The provider uses the most recent create succeeded time to account for this delay. If the provider didn’t account for the delay, it could mistakenly determine that the resource didn’t exist. The provider would create a new resource, and leak the existing one. ### Paused[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#paused) Manually applying the `crossplane.io/paused` annotation causes the Provider to stop reconciling the managed resource. Pausing a resource is useful when modifying Providers or preventing race-conditions when editing Kubernetes objects. Apply a `crossplane.io/paused: "true"` annotation to a managed resource to pause reconciliation. Note Only the value `"true"` pauses reconciliation. 1apiVersion: ec2.aws.m.upbound.io/v1beta1 2kind: Instance 3metadata: 4 namespace: default 5 name: my-rds-instance 6 annotations: 7 crossplane.io/paused: "true" 8spec: 9 forProvider: 10 region: us-west-1 11 instanceType: t2.micro Remove the annotation to resume reconciliation. Important Kubernetes and Crossplane can’t delete resources with a `paused` annotation, even with `kubectl delete`. Read [Crossplane discussion #4839](https://github.com/crossplane/crossplane/issues/4839) for more details. Finalizers[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#finalizers) ---------------------------------------------------------------------------------------------- Crossplane applies a [Finalizer](https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers/) on managed resources to control their deletion. Note Kubernetes can’t delete objects with Finalizers. When Crossplane deletes a managed resource the Provider begins deleting the external resource, but the managed resource remains until the external resource is fully deleted. When the external resource is fully deleted Crossplane removes the Finalizer and deletes the managed resource object. Conditions[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#conditions) ---------------------------------------------------------------------------------------------- Crossplane has a standard set of `Conditions` for a managed resource. View the `Conditions` of a managed resource with `kubectl describe ` Note Providers may define their own custom `Conditions`. ### Available[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#available) `Reason: Available` indicates the Provider created the managed resource and it’s ready for use. 1Conditions: 2 Type: Ready 3 Status: True 4 Reason: Available ### Creating[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#creating) `Reason: Creating` indicates the Provider is attempting to create the managed resource. 1Conditions: 2 Type: Ready 3 Status: False 4 Reason: Creating ### Deleting[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#deleting) `Reason: Deleting` indicates the Provider is attempting to delete the managed resource. 1Conditions: 2 Type: Ready 3 Status: False 4 Reason: Deleting ### ReconcilePaused[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#reconcilepaused) `Reason: ReconcilePaused` indicates the managed resource has a [Pause](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#paused) annotation 1Conditions: 2 Type: Synced 3 Status: False 4 Reason: ReconcilePaused ### ReconcileError[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#reconcileerror) `Reason: ReconcileError` indicates Crossplane encountered an error while reconciling the managed resource. The `Message:` value of the `Condition` helps identify the Crossplane error. 1Conditions: 2 Type: Synced 3 Status: False 4 Reason: ReconcileError ### ReconcileSuccess[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#reconcilesuccess) `Reason: ReconcileSuccess` indicates the Provider created and is monitoring the managed resource. 1Conditions: 2 Type: Synced 3 Status: True 4 Reason: ReconcileSuccess ### Unavailable[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#unavailable) `Reason: Unavailable` indicates Crossplane expects the managed resource to be available, but the Provider reports the resource is unhealthy. 1Conditions: 2 Type: Ready 3 Status: False 4 Reason: Unavailable ### Unknown[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#unknown) `Reason: Unknown` indicates the Provider has an unexpected error with the managed resource. The `conditions.message` provides more information on what went wrong. 1Conditions: 2 Type: Unknown 3 Status: False 4 Reason: Unknown ### Upjet Provider conditions[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#upjet-provider-conditions) [Upjet](https://github.com/upbound/upjet) , the open source tool to generate Crossplane Providers, also has a set of standard `Conditions`. #### AsyncOperation[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#asyncoperation) Some resources may take more than a minute to create. Upjet based providers can complete their Kubernetes command before creating the managed resource by using an asynchronous operation. ##### Finished[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#finished) The `Reason: Finished` indicates the asynchronous operation completed successfully. 1Conditions: 2 Type: AsyncOperation 3 Status: True 4 Reason: Finished ##### Ongoing[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#ongoing) `Reason: Ongoing` indicates the managed resource operation is still in progress. 1Conditions: 2 Type: AsyncOperation 3 Status: True 4 Reason: Ongoing #### LastAsyncOperation[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#lastasyncoperation) The Upjet `Type: LastAsyncOperation` captures the previous asynchronous operation status as either `Success` or a failure `Reason`. ##### ApplyFailure[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#applyfailure) `Reason: ApplyFailure` indicates the Provider failed to apply a setting to the managed resource. The `conditions.message` provides more information on what went wrong. 1Conditions: 2 Type: LastAsyncOperation 3 Status: False 4 Reason: ApplyFailure ##### DestroyFailure[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#destroyfailure) `Reason: DestroyFailure` indicates the Provider failed to delete the managed resource. The `conditions.message` provides more information on what went wrong. 1Conditions: 2 Type: LastAsyncOperation 3 Status: False 4 Reason: DestroyFailure ##### Success[](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#success) `Reason: Success` indicates the Provider successfully created the managed resource asynchronously. 1Conditions: 2 Type: LastAsyncOperation 3 Status: True 4 Reason: Success --- # Managed Resource Definitions · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#) [master](https://docs.crossplane.io/master/managed-resources/managed-resource-definitions/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Managed Resource Definitions ============================ This is an alpha feature. Crossplane may change or drop this feature at any time. This feature was introduced in v2. For more information read the [Crossplane feature lifecycle](https://docs.crossplane.io/v2.0/learn/feature-lifecycle/) . On this page **On this page** * * * Important Crossplane v2.0+ enables managed resource definitions by default. This automatically converts provider CRDs to MRDs during installation. To disable this behavior, set `--enable-custom-to-managed-resource-conversion=false` when installing Crossplane. A `ManagedResourceDefinition` (MRD) is a lightweight abstraction over Kubernetes CustomResourceDefinitions (CRDs) that enables selective activation of managed resources. MRDs solve the problem of providers installing hundreds of CRDs when you only need one or two, reducing API server overhead and improving cluster performance. The CRD scaling problem[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#the-crd-scaling-problem) ----------------------------------------------------------------------------------------------------------------------------------- Large Crossplane providers can install 100+ managed resource CRDs. Each CRD consumes about 3 MiB of API server memory and creates API endpoints that affect cluster performance: * **Memory pressure**: Large providers can consume 300+ MiB of API server memory * **Slower kubectl operations**: Commands like `kubectl get managed` must query all custom resource endpoints * **Increased API server load**: More CRDs mean more API endpoints to serve * **Unnecessary resource overhead**: Most users only need a subset of provider resources MRDs address this by allowing providers to ship resource definitions that only become active CRDs when explicitly needed. How MRDs work[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#how-mrds-work) --------------------------------------------------------------------------------------------------------------- An MRD contains the same schema as a CRD but adds two key fields: * **`connectionDetails`**: Documents what connection secrets the resource provides * **`state`**: Controls whether the underlying CRD exists (`Active` or `Inactive`) When an MRD’s state is `Inactive`, no CRD exists in the cluster. When activated, Crossplane creates the corresponding CRD and the provider can start managing instances of that resource. 1apiVersion: apiextensions.crossplane.io/v1alpha1 2kind: ManagedResourceDefinition 3metadata: 4 name: buckets.s3.aws.m.crossplane.io 5spec: 6 group: s3.aws.m.crossplane.io 7 names: 8 kind: Bucket 9 plural: buckets 10 scope: Cluster 11 versions: 12 - name: v1alpha1 13 served: true 14 storage: true 15 schema: 16 openAPIV3Schema: 17 type: object 18 properties: 19 spec: 20 type: object 21 properties: 22 forProvider: 23 type: object 24 properties: 25 region: 26 type: string 27 versioning: 28 type: boolean 29 connectionDetails: 30 - name: bucket-name 31 description: The name of the created S3 bucket 32 - name: region 33 description: The AWS region where the bucket was created 34 state: Inactive # Default state - no CRD created yet Key characteristics[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#key-characteristics) --------------------------------------------------------------------------------------------------------------------------- * **Selective activation**: Only create CRDs for resources you actually need * **Performance benefits**: Inactive MRDs consume minimal cluster resources * **Connection details documentation**: Schema for documenting available connection secrets * **One-way state transition**: MRDs can go from `Inactive` to `Active` but not back MRD states[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#mrd-states) --------------------------------------------------------------------------------------------------------- ### Inactive state[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#inactive-state) When `state: Inactive` (the default): * No CRD exists in the cluster * No API endpoints exist * The provider doesn’t start a controller for this resource * Minimal memory and CPU overhead 1spec: 2 state: Inactive # Default for all MRDs ### Active state[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#active-state) When `state: Active`: * Crossplane creates the corresponding CRD * API endpoints become available for the resource * The provider starts a controller to manage instances * Full capability like traditional managed resources 1spec: 2 state: Active # CRD will be created Important MRD state transitions are one-way only. Once an MRD becomes `Active`, it can’t return to `Inactive`. This prevents accidental deletion of CRDs that may have existing resources. Connection details documentation[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#connection-details-documentation) ----------------------------------------------------------------------------------------------------------------------------------------------------- MRDs can document what connection details a managed resource provides. This helps users understand what data is available in connection secrets without having to create test resources. 1spec: 2 connectionDetails: 3 - name: endpoint 4 description: The RDS instance endpoint for database connections 5 - name: port 6 description: The port number for database connections 7 - name: username 8 description: The master username for database access 9 - name: password 10 description: The auto-generated master password Note Connection details are currently a schema-only feature. Most providers don’t yet populate the `connectionDetails` field in their MRDs, but the structure is available for future implementation. Working with MRDs[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#working-with-mrds) ----------------------------------------------------------------------------------------------------------------------- ### Viewing MRDs[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#viewing-mrds) List all MRDs in your cluster: 1kubectl get managedresourcedefinitions View MRD details: 1kubectl describe mrd buckets.s3.aws.m.crossplane.io ### Checking MRD status[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#checking-mrd-status) MRDs provide status information about their lifecycle: 1status: 2 conditions: 3 - type: Established 4 status: "False" 5 reason: InactiveManagedResource 6 message: "ManagedResourceDefinition is inactive" **Status conditions:** * **`Established: False, Reason: InactiveManagedResource`**: MRD is inactive, no CRD created * **`Established: Unknown, Reason: PendingManagedResource`**: Crossplane is creating the CRD * **`Established: True, Reason: EstablishedManagedResource`**: CRD exists and is ready * **`Healthy: True, Reason: Running`**: MRD controller operating * **`Healthy: Unknown, Reason: EncounteredErrors`**: MRD controller experiencing issues ### Manually activating MRDs[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#manually-activating-mrds) You can manually activate an MRD by changing its state: 1kubectl patch mrd buckets.s3.aws.m.crossplane.io --type='merge' \ 2 -p='{"spec":{"state":"Active"}}' The recommended approach is to use [ManagedResourceActivationPolicies](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/) for systematic activation. How providers work with MRDs[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#how-providers-work-with-mrds) --------------------------------------------------------------------------------------------------------------------------------------------- Crossplane v2.0+ automatically converts all provider CRDs to MRDs during package installation, regardless of the provider’s age or original format. The provider’s `safe-start` capability determines the default MRD state: ### Providers with `safe-start` capability[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#providers-with-safe-start-capability) * MRDs start with `state: Inactive` by default * Support selective activation via [ManagedResourceActivationPolicies](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/) * Reduced resource overhead for unused resources * Provider can start without all CRDs being active 1# Provider package metadata 2apiVersion: meta.pkg.crossplane.io/v1 3kind: Provider 4spec: 5 capabilities: 6 - safe-start Tip Crossplane uses fuzzy matching for capabilities, so `safe-start`, `safe_start`, `safestart`, and `SafeStart` all match the `safe-start` capability. ### Providers without `safe-start` capability[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#providers-without-safe-start-capability) * MRDs start with `state: Active` by default (legacy behavior) * All CRDs become available for backward compatibility * Full resource overhead like traditional providers Troubleshooting MRDs[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#troubleshooting-mrds) ----------------------------------------------------------------------------------------------------------------------------- ### MRD exists but no CRD appears[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#mrd-exists-but-no-crd-appears) **Symptoms**: MRD is present but `kubectl get ` shows “no resources found” **Cause**: MRD is in `Inactive` state **Solution**: Activate the MRD using an [ManagedResourceActivationPolicy](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/) or manually patch the state 1# Check MRD state 2kubectl get mrd -o jsonpath='{.spec.state}' 3 4# Activate if needed 5kubectl patch mrd --type='merge' -p='{"spec":{"state":"Active"}}' ### MRD activation fails[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#mrd-activation-fails) **Symptoms**: MRD state is `Active` but `Established` condition remains `False` **Cause**: CRD creation failed due to schema issues or conflicts **Solution**: Check MRD events and status for error details 1kubectl describe mrd **Other status conditions for troubleshooting:** * **`Established: False, Reason: BlockedManagedResourceActivationPolicy`**: Blocked by activation policy issues * **`Established: False, Reason: TerminatingManagedResource`**: Crossplane is deleting the MRD **Common events you might see:** * `Normal CreateCustomResourceDefinition` - CRD successfully created * `Normal UpdateCustomResourceDefinition` - CRD successfully updated * `Warning CreateCustomResourceDefinition` - CRD creation failed * `Warning UpdateCustomResourceDefinition` - CRD update failed * `Warning Reconcile` - General reconciliation errors Common issues: * Malformed OpenAPI schema in the MRD * CRD name conflicts with existing resources * Insufficient RBAC permissions for Crossplane ### Provider doesn’t support activation[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#provider-doesnt-support-activation) **Symptoms**: Provider starts all controllers regardless of MRD states **Cause**: Provider doesn’t implement late activation support **Solution**: Check provider capabilities and use a compatible provider version 1# Check if provider supports late activation 2kubectl get providerrevision \ 3 -o jsonpath='{.status.capabilities}' Look for the `safe-start` capability. Next steps[](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/#next-steps) --------------------------------------------------------------------------------------------------------- * Learn about [ManagedResourceActivationPolicies](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/) for systematic resource activation * See the [disabling unused managed resources guide](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/) for practical implementation * Check the [API reference](https://docs.crossplane.io/v2.0/api/) for complete MRD schema documentation --- # Contributing Guide · Crossplane Contributing Guide ================== On this page **On this page** * * * The Crossplane Contributing Guide is for anyone interested in contributing to the Crossplane documentation. Information on contributing to the Crossplane software project is in the Crossplane [`CONTRIBUTING.md`](https://github.com/crossplane/crossplane/blob/main/CONTRIBUTING.md) file. Code of conduct[](https://docs.crossplane.io/contribute/#code-of-conduct) -------------------------------------------------------------------------- Crossplane follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md) . Taken directly from the code: > As contributors and maintainers in the CNCF community, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. > > We are committed to making participation in the CNCF community a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. Reporting violations[](https://docs.crossplane.io/contribute/#reporting-violations) ------------------------------------------------------------------------------------ To report violations contact the Crossplane maintainers at `crossplane-info@lists.cncf.io` or the CNCF at `conduct@cncf.io`. All the information needed to contribute to the Crossplane documentation is here. * Read [contributing to the docs](https://docs.crossplane.io/contribute/contribute/) for information about the docs repository, cloning and local development. * The [writing style guide](https://docs.crossplane.io/contribute/writing-style-guide/) describes the guidelines for language, spelling and language style. * The [code styling guide](https://docs.crossplane.io/contribute/code-style-guide/) covers the Crossplane guidelines specific to including code blocks in docs to provide the best reader experience. * [Styling features](https://docs.crossplane.io/contribute/features/) describes the features Crossplane documentation uses to improve on traditional Markdown. This includes how to optimize images, use tabs and hiding long outputs. * The [infrastructure](https://docs.crossplane.io/contribute/infrastructure/) section provides technical information about the documentation infrastructure. This includes how Crossplane documentation uses the [Hugo](https://gohugo.io/) static site generator, CSS layouts and JavaScript. Licensing[](https://docs.crossplane.io/contribute/#licensing) -------------------------------------------------------------- The Crossplane documentation is under the [Creative Commons Attribution](https://creativecommons.org/licenses/by/4.0/) license. CC-BY allows reuse, remixing and republishing of Crossplane documentation with attribution to the Crossplane organization. Issues and feature requests[](https://docs.crossplane.io/contribute/#issues-and-feature-requests) -------------------------------------------------------------------------------------------------- Open an [issue](https://github.com/crossplane/crossplane/issues) to report a problem or request documentation content. --- # Operations · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/operations/operation/#) [master](https://docs.crossplane.io/master/operations/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/operations/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Operations ========== This is an alpha feature. Crossplane may change or drop this feature at any time. This feature was introduced in v2. For more information read the [Crossplane feature lifecycle](https://docs.crossplane.io/v2.0/learn/feature-lifecycle/) . On this page **On this page** * * * An `Operation` runs a function pipeline once to completion to perform operational tasks that don’t fit the typical resource creation pattern. Unlike compositions that continuously reconcile desired state, Operations focus on tasks like backups, rolling upgrades, configuration validation, and scheduled maintenance. How operations work[](https://docs.crossplane.io/v2.0/operations/operation/#how-operations-work) ------------------------------------------------------------------------------------------------- Operations are like Kubernetes Jobs - they run once to completion rather than continuously reconciling. Like compositions, Operations use function pipelines to implement their logic, but they’re designed for operational workflows instead of resource composition. 1apiVersion: ops.crossplane.io/v1alpha1 2kind: Operation 3metadata: 4 name: backup-database 5spec: 6 mode: Pipeline 7 pipeline: 8 - step: create-backup 9 functionRef: 10 name: function-database-backup 11 input: 12 apiVersion: fn.crossplane.io/v1beta1 13 kind: DatabaseBackupInput 14 database: production-db 15 retentionDays: 30 When you create this Operation, Crossplane: 1. **Validates** the operation and its function dependencies 2. **Executes** the function pipeline step by step 3. **Applies** any resources the functions create or change 4. **Updates** the Operation status with results and completion state Important Operations are an alpha feature. You must enable them by adding `--enable-operations` to Crossplane’s arguments. Key characteristics[](https://docs.crossplane.io/v2.0/operations/operation/#key-characteristics) ------------------------------------------------------------------------------------------------- * **Runs once to completion** (like Kubernetes Jobs) * **Uses function pipelines** (like Compositions) * **Can create or change any Kubernetes resources** * **Provides detailed status and output from each step** * **Supports retry on failure with configurable limits** Operation functions vs composition functions[](https://docs.crossplane.io/v2.0/operations/operation/#operation-functions-vs-composition-functions) --------------------------------------------------------------------------------------------------------------------------------------------------- Operations and compositions both use function pipelines, but with important differences: **Composition Functions:** * **Purpose**: Create and maintain resources * **Lifecycle**: Continuous reconciliation * **Input**: Observed composite resources * **Output**: Desired composed resources * **Ownership**: Creates owner references **Operation Functions:** * **Purpose**: Perform operational tasks * **Lifecycle**: Run once to completion * **Input**: Required resources only * **Output**: Any Kubernetes resources * **Ownership**: Force applies without owners Functions can support both modes by declaring the appropriate capabilities in their package metadata. Function authors declare this in the `crossplane.yaml` file when building the function package: 1apiVersion: meta.pkg.crossplane.io/v1 2kind: Function 3metadata: 4 name: my-function 5spec: 6 capabilities: 7 - composition 8 - operation This allows Crossplane to know which modes the function supports and avoid trying to use a composition-only function for operations. Common use cases[](https://docs.crossplane.io/v2.0/operations/operation/#common-use-cases) ------------------------------------------------------------------------------------------- Note The following examples use hypothetical functions for illustration. At launch, only function-python supports operations. ### Rolling upgrades[](https://docs.crossplane.io/v2.0/operations/operation/#rolling-upgrades) Use Operations for controlled rolling upgrades: 1apiVersion: ops.crossplane.io/v1alpha1 2kind: Operation 3metadata: 4 name: cluster-upgrade 5spec: 6 mode: Pipeline 7 pipeline: 8 - step: rolling-upgrade 9 functionRef: 10 name: function-cluster-upgrade 11 input: 12 apiVersion: fn.crossplane.io/v1beta1 13 kind: ClusterUpgradeInput 14 targetVersion: "1.28" 15 batches: [0.25, 0.5, 1.0] # 25%, 50%, then 100% 16 healthChecks: [Synced, Ready] ### One-time maintenance[](https://docs.crossplane.io/v2.0/operations/operation/#one-time-maintenance) Use Operations for specific maintenance tasks: 1apiVersion: ops.crossplane.io/v1alpha1 2kind: Operation 3metadata: 4 name: certificate-rotation 5spec: 6 mode: Pipeline 7 pipeline: 8 - step: rotate-certificates 9 functionRef: 10 name: function-cert-rotation 11 input: 12 apiVersion: fn.crossplane.io/v1beta1 13 kind: CertRotationInput 14 targetCertificates: 15 matchLabels: 16 rotate: "true" Advanced configuration[](https://docs.crossplane.io/v2.0/operations/operation/#advanced-configuration) ------------------------------------------------------------------------------------------------------- ### Retry behavior[](https://docs.crossplane.io/v2.0/operations/operation/#retry-behavior) Operations automatically retry when they fail. Configure the retry limit to control how often attempts occur: 1apiVersion: ops.crossplane.io/v1alpha1 2kind: Operation 3metadata: 4 name: resilient-operation 5spec: 6 retryLimit: 10 # Try up to 10 times before giving up (default: 5) 7 mode: Pipeline 8 pipeline: 9 - step: flaky-task 10 functionRef: 11 name: function-flaky-task 12 input: 13 apiVersion: fn.crossplane.io/v1beta1 14 kind: FlakyTaskInput 15 # Task that might fail due to temporary issues 16 timeout: "30s" **Retry behavior:** * Each retry resets the entire pipeline - if step 2 of 3 fails, the retry starts from step 1 * Operations use exponential backoff: 1 s, 2 s, 4 s, 8 s, 16 s, 32 s, then 60 s max * Operations track the number of failures in `status.failures` * After reaching `retryLimit`, the Operation becomes `Succeeded=False` ### Credentials[](https://docs.crossplane.io/v2.0/operations/operation/#credentials) Operations can provide credentials to functions through Secrets: 1apiVersion: ops.crossplane.io/v1alpha1 2kind: Operation 3metadata: 4 name: secure-backup 5spec: 6 mode: Pipeline 7 pipeline: 8 - step: backup-with-credentials 9 functionRef: 10 name: function-backup 11 credentials: 12 - name: backup-creds 13 source: Secret 14 secretRef: 15 namespace: crossplane-system 16 name: backup-credentials 17 key: api-key 18 - name: database-creds 19 source: Secret 20 secretRef: 21 namespace: crossplane-system 22 name: database-credentials 23 key: connection-string 24 input: 25 apiVersion: fn.crossplane.io/v1beta1 26 kind: BackupInput 27 destination: s3://my-backup-bucket ### Multiple pipeline steps[](https://docs.crossplane.io/v2.0/operations/operation/#multiple-pipeline-steps) Complex operations can use multiple pipeline steps: 1apiVersion: ops.crossplane.io/v1alpha1 2kind: Operation 3metadata: 4 name: multi-step-deployment 5spec: 6 mode: Pipeline 7 pipeline: 8 - step: validate-config 9 functionRef: 10 name: function-validator 11 input: 12 apiVersion: fn.crossplane.io/v1beta1 13 kind: ValidatorInput 14 configName: app-config 15 - step: backup-current 16 functionRef: 17 name: function-backup 18 input: 19 apiVersion: fn.crossplane.io/v1beta1 20 kind: BackupInput 21 target: current-deployment 22 - step: deploy-new-version 23 functionRef: 24 name: function-deploy 25 input: 26 apiVersion: fn.crossplane.io/v1beta1 27 kind: DeployInput 28 image: myapp:v2.0.0 29 strategy: rollingUpdate 30 - step: verify-health 31 functionRef: 32 name: function-health-check 33 input: 34 apiVersion: fn.crossplane.io/v1beta1 35 kind: HealthCheckInput 36 timeout: 300s 37 healthEndpoint: /health ### RBAC permissions[](https://docs.crossplane.io/v2.0/operations/operation/#rbac-permissions) If your Operation needs to access resources that Crossplane doesn’t have permissions for by default, create a ClusterRole that aggregates to Crossplane: 1apiVersion: rbac.authorization.k8s.io/v1 2kind: ClusterRole 3metadata: 4 name: operation-additional-permissions 5 labels: 6 rbac.crossplane.io/aggregate-to-crossplane: "true" 7rules: 8# Additional permissions for Operations 9- apiGroups: ["networking.k8s.io"] 10 resources: ["ingresses"] 11 verbs: ["get", "list", "patch", "update"] 12- apiGroups: [""] 13 resources: ["persistentvolumes"] 14 verbs: ["get", "list"] 15# Add other resources your Operations need to access This ClusterRole is automatically aggregated to Crossplane’s main ClusterRole, giving the Crossplane service account the permissions needed for your Operations. Note The [RBAC manager](https://docs.crossplane.io/v2.0/guides/pods/#rbac-manager-pod) automatically grants Crossplane access to Crossplane resources (MRs, XRs, etc.). You only need to create more ClusterRoles for other Kubernetes resources that your Operations need to access. For more details on RBAC configuration, see the [Compositions RBAC documentation](https://docs.crossplane.io/v2.0/composition/compositions/#grant-access-to-composed-resources) . ### Function response cache[](https://docs.crossplane.io/v2.0/operations/operation/#function-response-cache) Note Function response caching is an alpha feature. Enable it by setting the `--enable-function-response-cache` feature flag. Operations can use function response caching to improve performance for operations that: * Call the same functions often with identical inputs * Use functions that perform expensive computations or external API calls * Run frequently through CronOperation or WatchOperation The cache works the same way as for Compositions - function responses with time to live values cache and reuse identical requests until they expire. Function response caching helps Operations that: * Validate configurations using expensive checks * Query external systems for status information * Perform complex calculations that don’t change frequently For cache configuration details, see the [Function response cache documentation](https://docs.crossplane.io/v2.0/composition/compositions/#function-response-cache) . ### Required resources[](https://docs.crossplane.io/v2.0/operations/operation/#required-resources) Operations can preload resources for functions to access: 1apiVersion: ops.crossplane.io/v1alpha1 2kind: Operation 3metadata: 4 name: resource-aware-operation 5spec: 6 mode: Pipeline 7 pipeline: 8 - step: process-deployment 9 functionRef: 10 name: function-processor 11 requirements: 12 requiredResources: 13 - requirementName: app-deployment 14 apiVersion: apps/v1 15 kind: Deployment 16 name: my-app 17 namespace: production 18 - requirementName: app-service 19 apiVersion: v1 20 kind: Service 21 name: my-app-service 22 namespace: production 23 input: 24 apiVersion: fn.crossplane.io/v1beta1 25 kind: ProcessorInput 26 action: upgrade Functions access these resources through the standard request structure: 1from crossplane.function import request, response 2 3def operate(req, rsp): 4 # Access required resources 5 deployment = request.get_required_resource(req, "app-deployment") 6 service = request.get_required_resource(req, "app-service") 7 8 if not deployment or not service: 9 response.set_output(rsp, {"error": "Required resources not found"}) 10 return 11 12 # Process the resources 13 new_replicas = deployment["spec"]["replicas"] * 2 14 15 # Return updated resources with full GVK and metadata for server-side apply 16 rsp.desired.resources["app-deployment"].resource.update({ 17 "apiVersion": "apps/v1", 18 "kind": "Deployment", 19 "metadata": { 20 "name": deployment["metadata"]["name"], 21 "namespace": deployment["metadata"]["namespace"] 22 }, 23 "spec": {"replicas": new_replicas} 24 }) Status and monitoring[](https://docs.crossplane.io/v2.0/operations/operation/#status-and-monitoring) ----------------------------------------------------------------------------------------------------- Operations provide rich status information: 1status: 2 conditions: 3 - type: Synced 4 status: "True" 5 reason: ReconcileSuccess 6 - type: Succeeded 7 status: "True" 8 reason: PipelineSuccess 9 - type: ValidPipeline 10 status: "True" 11 reason: ValidPipeline 12 failures: 1 # Number of retry attempts 13 pipeline: 14 - step: create-backup 15 output: 16 backupId: "backup-20240115-103000" 17 size: "2.3GB" 18 appliedResourceRefs: 19 - apiVersion: "v1" 20 kind: "Secret" 21 namespace: "production" 22 name: "backup-secret" 23 - apiVersion: "apps/v1" 24 kind: "Deployment" 25 name: "updated-deployment" **Key status fields:** * **`conditions`**: Standard Crossplane conditions (Synced) and Operation-specific conditions: * **`Succeeded`**: `True` when the operation completed successfully, `False` when it failed * **`ValidPipeline`**: `True` when all functions have the required `operation` capability * **`failures`**: Number of times the operation has failed and retried * **`pipeline`**: Output from each function step for tracking progress * **`appliedResourceRefs`**: References to all resources the Operation created or modified ### Events[](https://docs.crossplane.io/v2.0/operations/operation/#events) Operations emit Kubernetes events for important activities: * Function run results and warnings * Resource apply failures * Operation lifecycle events (creation, completion, failure) ### Troubleshooting operations[](https://docs.crossplane.io/v2.0/operations/operation/#troubleshooting-operations) **Check operation status:** 1kubectl get operation my-operation -o wide **View detailed information:** 1kubectl describe operation my-operation **Common failure scenarios:** 1. **Operations do nothing** - Operations feature not enabled: 1# Operation exists but has no status conditions and never progresses 2status: {} _Solution_: enable Operations by adding `--enable-operations` to Crossplane’s startup arguments. 2. **ValidPipeline condition is False** - Function doesn’t support operations: 1conditions: 2- type: ValidPipeline 3 status: "False" 4 reason: InvalidFunctionCapability 5 message: "Function function-name doesn't support operations" _Solution_: use a function that declares `operation` capability. 3. **Succeeded condition is False** - Function run failed: 1conditions: 2- type: Succeeded 3 status: "False" 4 reason: PipelineFailure 5 message: "Function returned error: connection timeout" _Solution_: view function logs and fix the underlying issue. 4. **Resource apply failures** - View events for details: 1kubectl get events --field-selector involvedObject.name=my-operation **Debug function runs:** 1# View function logs 2kubectl logs -n crossplane-system deployment/function-python 3 4# Check operation events 5kubectl get events --field-selector involvedObject.kind=Operation 6 7# Inspect operation status in detail 8kubectl get operation my-operation -o jsonpath='{.status.pipeline}' | jq '.' Resource management[](https://docs.crossplane.io/v2.0/operations/operation/#resource-management) ------------------------------------------------------------------------------------------------- Operations can create or change any Kubernetes resources using server-side apply with force ownership. This means: **What Operations can do:** * Create new resources of any kind * Change existing resources by taking ownership of specific fields * Apply changes that may conflict with other controllers **What Operations can’t do:** * Delete resources (current limitation of alpha implementation) * Establish owner references (resources aren’t garbage collected) * Continuously maintain desired state (they run once) Important Use caution with Operations that change resources managed by other controllers. Operations force ownership when applying changes, which can cause conflicts. Test an operation[](https://docs.crossplane.io/v2.0/operations/operation/#test-an-operation) --------------------------------------------------------------------------------------------- You can preview the output of any Operation using the Crossplane CLI. You don’t need a Crossplane control plane to do this. The Crossplane CLI uses Docker Engine to run functions. Tip See the [Crossplane CLI docs](https://docs.crossplane.io/v2.0/cli/) to learn how to install and use the Crossplane CLI. Important Running `crossplane alpha render op` requires [Docker](https://www.docker.com/) . Provide an operation, composition functions, and any required resources to render the output locally. 1crossplane alpha render op operation.yaml functions.yaml --required-resources=ingress.yaml `crossplane alpha render op` prints the Operation status and any resources the operation functions created or modified. It shows what would happen if you applied the Operation to a cluster. 1--- 2# Operation status showing function results 3apiVersion: ops.crossplane.io/v1alpha1 4kind: Operation 5metadata: 6 name: ingress-cert-monitor 7status: 8 conditions: 9 - type: Succeeded 10 status: "True" 11 reason: PipelineSuccess 12 pipeline: 13 - step: check-ingress-certificate 14 output: 15 certificateExpires: "Sep 29 08:34:02 2025 GMT" 16 daysUntilExpiry: 53 17 hostname: google.com 18 ingressName: example-app 19 status: ok 20--- 21# Modified Ingress resource with certificate annotations 22apiVersion: networking.k8s.io/v1 23kind: Ingress 24metadata: 25 annotations: 26 cert-monitor.crossplane.io/expires: Sep 29 08:34:02 2025 GMT 27 cert-monitor.crossplane.io/days-until-expiry: "53" 28 cert-monitor.crossplane.io/status: ok 29 name: example-app 30 namespace: default 31spec: 32 # ... ingress spec unchanged Use `--required-resources` to provide resources that your operation functions need access to. You can specify multiple files or use glob patterns: 1# Multiple specific files 2crossplane alpha render op operation.yaml functions.yaml \ 3 --required-resources=deployment.yaml,service.yaml,configmap.yaml 4 5# Glob pattern for all YAML files in a directory 6crossplane alpha render op operation.yaml functions.yaml \ 7 --required-resources="resources/*.yaml" Tip Use the `crossplane alpha render op` command to test your Operations locally before deploying them to a cluster. The command helps validate function logic and required resource access patterns. Best practices[](https://docs.crossplane.io/v2.0/operations/operation/#best-practices) --------------------------------------------------------------------------------------- ### Operation-specific practices[](https://docs.crossplane.io/v2.0/operations/operation/#operation-specific-practices) 1. **Plan for rollback** - Design operations to be reversible when possible, because Operations don’t auto rollback like Compositions 2. **Make operations idempotent** - Operations should be safe to retry if they fail partway through 3. **Use required resources** - Prepopulate functions with needed resources for efficiency rather than requesting them during running ### Function development[](https://docs.crossplane.io/v2.0/operations/operation/#function-development) 1. **Declare capabilities** - Explicitly declare `operation` capability in function metadata to enable Operations support 2. **Return meaningful output** - Use the output field to track what the operation accomplished for monitoring and debugging Next steps[](https://docs.crossplane.io/v2.0/operations/operation/#next-steps) ------------------------------------------------------------------------------- * [Get started with Operations](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/) to create your first Operation * Learn about [CronOperation](https://docs.crossplane.io/v2.0/operations/cronoperation/) for scheduled operations * Learn about [WatchOperation](https://docs.crossplane.io/v2.0/operations/watchoperation/) for reactive operations --- # Packages · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/packages/#) [master](https://docs.crossplane.io/master/packages/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/packages/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Packages ======== Extend Crossplane with packages Topics in this section: * [Providers](https://docs.crossplane.io/v2.0/packages/providers/) - Providers connect Crossplane to external APIs * [Functions](https://docs.crossplane.io/v2.0/packages/functions/) - Functions extend Crossplane with new ways to configure composition * [Configurations](https://docs.crossplane.io/v2.0/packages/configurations/) - Portable packages of Crossplane resources * [Image Configs](https://docs.crossplane.io/v2.0/packages/image-configs/) - Centralized control of package image configuration --- # Watch Operations · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/operations/watchoperation/#) [master](https://docs.crossplane.io/master/operations/watchoperation/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/operations/watchoperation/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Watch Operations ================ This is an alpha feature. Crossplane may change or drop this feature at any time. This feature was introduced in v2. For more information read the [Crossplane feature lifecycle](https://docs.crossplane.io/v2.0/learn/feature-lifecycle/) . On this page **On this page** * * * A `WatchOperation` creates [Operations](https://docs.crossplane.io/v2.0/operations/operation/) when watched Kubernetes resources change. Use WatchOperations for reactive operational workflows such as backing up databases before deletion, validating configurations after updates, or triggering alerts when resources fail. How WatchOperations work[](https://docs.crossplane.io/v2.0/operations/watchoperation/#how-watchoperations-work) ---------------------------------------------------------------------------------------------------------------- WatchOperations watch specific Kubernetes resources and create new Operations whenever those resources change. The changed resource is automatically injected into the Operation for the function to process. 1apiVersion: ops.crossplane.io/v1alpha1 2kind: WatchOperation 3metadata: 4 name: config-validator 5spec: 6 watch: 7 apiVersion: v1 8 kind: ConfigMap 9 matchLabels: 10 validate: "true" 11 concurrencyPolicy: Allow 12 operationTemplate: 13 spec: 14 mode: Pipeline 15 pipeline: 16 - step: validate 17 functionRef: 18 name: function-config-validator 19 input: 20 apiVersion: fn.crossplane.io/v1beta1 21 kind: ConfigValidatorInput 22 rules: 23 - required: ["database.url", "database.port"] 24 - format: "email" 25 field: "notification.email" 26 - step: notify 27 functionRef: 28 name: function-slack-notifier 29 input: 30 apiVersion: fn.crossplane.io/v1beta1 31 kind: SlackNotifierInput 32 channel: "#alerts" 33 severity: "warning" Important WatchOperations are an alpha feature. You must enable Operations by adding `--enable-operations` to Crossplane’s arguments. Key features[](https://docs.crossplane.io/v2.0/operations/watchoperation/#key-features) ---------------------------------------------------------------------------------------- * **Watches any Kubernetes resource type** - Not limited to Crossplane resources * **Supports namespace and label filtering** - Target specific resources * **Automatically injects changed resources** - Functions receive the triggering resource * **Configurable concurrency policies** - Control operation creation Resource watching[](https://docs.crossplane.io/v2.0/operations/watchoperation/#resource-watching) -------------------------------------------------------------------------------------------------- WatchOperations can watch any Kubernetes resource with flexible filtering: ### Watch all resources of a type[](https://docs.crossplane.io/v2.0/operations/watchoperation/#watch-all-resources-of-a-type) 1spec: 2 watch: 3 apiVersion: apps/v1 4 kind: Deployment ### Watch resources in a specific namespace[](https://docs.crossplane.io/v2.0/operations/watchoperation/#watch-resources-in-a-specific-namespace) 1spec: 2 watch: 3 apiVersion: v1 4 kind: ConfigMap 5 namespace: production ### Watch resources with specific labels[](https://docs.crossplane.io/v2.0/operations/watchoperation/#watch-resources-with-specific-labels) 1spec: 2 watch: 3 apiVersion: example.org/v1 4 kind: Database 5 matchLabels: 6 backup: "enabled" 7 environment: "production" ### Watch cluster-scoped resources[](https://docs.crossplane.io/v2.0/operations/watchoperation/#watch-cluster-scoped-resources) 1spec: 2 watch: 3 apiVersion: v1 4 kind: Node 5 matchLabels: 6 node-role.kubernetes.io/worker: "" Resource injection[](https://docs.crossplane.io/v2.0/operations/watchoperation/#resource-injection) ---------------------------------------------------------------------------------------------------- When a WatchOperation creates an Operation, it automatically injects the changed resource using the special requirement name `ops.crossplane.io/watched-resource`. Functions can access this resource without explicitly requesting it. For example, when a ConfigMap with label `validate: "true"` changes, the WatchOperation creates an Operation like this: 1apiVersion: ops.crossplane.io/v1alpha1 2kind: Operation 3metadata: 4 name: config-validator-abc123 5spec: 6 mode: Pipeline 7 pipeline: 8 - step: validate 9 functionRef: 10 name: function-config-validator 11 requirements: 12 requiredResources: 13 - requirementName: ops.crossplane.io/watched-resource 14 apiVersion: v1 15 kind: ConfigMap 16 name: my-config 17 namespace: default 18 # ... other pipeline steps from operationTemplate The watched resource is automatically available to functions in `req.required_resources` under the special name `ops.crossplane.io/watched-resource`. Concurrency policies[](https://docs.crossplane.io/v2.0/operations/watchoperation/#concurrency-policies) -------------------------------------------------------------------------------------------------------- WatchOperations support the same concurrency policies as CronOperations: * **Allow (default)**: Multiple Operations can run simultaneously. Use this when operations don’t interfere with each other. * **Forbid**: New Operations don’t start if previous ones are still running. Use this for operations that can’t run concurrently. * **Replace**: New Operations stop running ones before starting. Use this when you always want the latest operation to run. Common use cases[](https://docs.crossplane.io/v2.0/operations/watchoperation/#common-use-cases) ------------------------------------------------------------------------------------------------ Note The following examples use hypothetical functions for illustration. At launch, only function-python supports operations. ### Configuration validation[](https://docs.crossplane.io/v2.0/operations/watchoperation/#configuration-validation) Validate ConfigMaps when they change: 1apiVersion: ops.crossplane.io/v1alpha1 2kind: WatchOperation 3metadata: 4 name: config-validator 5spec: 6 watch: 7 apiVersion: v1 8 kind: ConfigMap 9 matchLabels: 10 validate: "true" 11 operationTemplate: 12 spec: 13 mode: Pipeline 14 pipeline: 15 - step: validate-config 16 functionRef: 17 name: function-config-validator 18 input: 19 apiVersion: fn.crossplane.io/v1beta1 20 kind: ConfigValidatorInput 21 rules: 22 - required: ["database.host", "database.port"] 23 - format: "email" 24 field: "notification.email" ### Database backup on deletion[](https://docs.crossplane.io/v2.0/operations/watchoperation/#database-backup-on-deletion) Backup databases before they’re deleted: 1apiVersion: ops.crossplane.io/v1alpha1 2kind: WatchOperation 3metadata: 4 name: backup-on-deletion 5spec: 6 watch: 7 apiVersion: rds.aws.m.upbound.io/v1beta1 8 kind: Instance 9 # Note: Watching for deletion requires function logic 10 # to check deletion timestamp 11 operationTemplate: 12 spec: 13 mode: Pipeline 14 pipeline: 15 - step: create-backup 16 functionRef: 17 name: function-rds-backup 18 input: 19 apiVersion: fn.crossplane.io/v1beta1 20 kind: RDSBackupInput 21 retentionDays: 30 ### Resource failure alerting[](https://docs.crossplane.io/v2.0/operations/watchoperation/#resource-failure-alerting) Alert when resources enter a failed state: 1apiVersion: ops.crossplane.io/v1alpha1 2kind: WatchOperation 3metadata: 4 name: failure-alerts 5spec: 6 watch: 7 apiVersion: example.org/v1 8 kind: App 9 matchLabels: 10 alert: "enabled" 11 operationTemplate: 12 spec: 13 mode: Pipeline 14 pipeline: 15 - step: check-status 16 functionRef: 17 name: function-status-checker 18 input: 19 apiVersion: fn.crossplane.io/v1beta1 20 kind: StatusCheckerInput 21 alertConditions: 22 - type: "Ready" 23 status: "False" 24 - step: send-alert 25 functionRef: 26 name: function-alertmanager 27 input: 28 apiVersion: fn.crossplane.io/v1beta1 29 kind: AlertInput 30 severity: "critical" Advanced configuration[](https://docs.crossplane.io/v2.0/operations/watchoperation/#advanced-configuration) ------------------------------------------------------------------------------------------------------------ ### Advanced watch patterns[](https://docs.crossplane.io/v2.0/operations/watchoperation/#advanced-watch-patterns) Complex resource watching with multiple conditions: 1# Watch Deployments in specific namespaces with multiple label conditions 2apiVersion: ops.crossplane.io/v1alpha1 3kind: WatchOperation 4metadata: 5 name: multi-condition-watcher 6spec: 7 watch: 8 apiVersion: apps/v1 9 kind: Deployment 10 namespace: production # Only production namespace 11 matchLabels: 12 app.kubernetes.io/managed-by: "crossplane" 13 environment: "prod" 14 backup-required: "true" 15 operationTemplate: 16 spec: 17 mode: Pipeline 18 pipeline: 19 - step: backup-deployment 20 functionRef: 21 name: function-deployment-backup 1# Watch custom resources across all namespaces 2apiVersion: ops.crossplane.io/v1alpha1 3kind: WatchOperation 4metadata: 5 name: database-lifecycle-manager 6spec: 7 watch: 8 apiVersion: database.example.io/v1 9 kind: PostgreSQLInstance 10 # No namespace specified = watch all namespaces 11 matchLabels: 12 lifecycle-management: "enabled" 13 operationTemplate: 14 spec: 15 mode: Pipeline 16 pipeline: 17 - step: lifecycle-check 18 functionRef: 19 name: function-database-lifecycle 20 input: 21 apiVersion: fn.crossplane.io/v1beta1 22 kind: DatabaseLifecycleInput 23 checkDeletionTimestamp: true 24 autoBackup: true ### Cross-resource workflows[](https://docs.crossplane.io/v2.0/operations/watchoperation/#cross-resource-workflows) WatchOperations can watch one resource type and dynamically fetch related resources. Here’s a WatchOperation that watches Ingresses and manages certificates: 1apiVersion: ops.crossplane.io/v1alpha1 2kind: WatchOperation 3metadata: 4 name: ingress-certificate-manager 5spec: 6 watch: 7 apiVersion: networking.k8s.io/v1 8 kind: Ingress 9 matchLabels: 10 auto-cert: "enabled" 11 operationTemplate: 12 spec: 13 mode: Pipeline 14 pipeline: 15 - step: manage-certificates 16 functionRef: 17 name: function-cert-manager 18 input: 19 apiVersion: fn.crossplane.io/v1beta1 20 kind: CertManagerInput 21 issuer: "letsencrypt-prod" 22 renewBefore: "720h" # 30 days The function examines the watched Ingress and dynamically requests related resources: 1from crossplane.function import request, response 2 3def operate(req, rsp): 4 # Access the watched Ingress resource 5 ingress = request.get_required_resource(req, "ops.crossplane.io/watched-resource") 6 if not ingress: 7 response.fatal(rsp, "No watched resource found") 8 return 9 10 # Extract the service name from the Ingress backend 11 rules = ingress.get("spec", {}).get("rules", []) 12 if not rules: 13 response.fatal(rsp, "Could not extract service name from ingress") 14 return 15 16 backend = rules[0].get("http", {}).get("paths", [{}])[0].get("backend", {}) 17 service_name = backend.get("service", {}).get("name") 18 if not service_name: 19 response.fatal(rsp, "Could not extract service name from ingress") 20 return 21 22 ingress_namespace = ingress.get("metadata", {}).get("namespace", "default") 23 24 # CRITICAL: Always request the same resources to ensure requirement 25 # stabilization. Crossplane calls the function repeatedly until 26 # requirements don't change. 27 response.require_resources( 28 rsp, 29 name="related-service", 30 api_version="v1", 31 kind="Service", 32 match_name=service_name, 33 namespace=ingress_namespace 34 ) 35 36 # Check if the service is available and process accordingly 37 service = request.get_required_resource(req, "related-service") 38 if service: 39 # Success: Both resources available 40 response.set_output(rsp, { 41 "status": "success", 42 "message": "Certificate management completed", 43 "ingress_host": ingress.get("spec", {}).get("rules", [{}])[0].get("host"), 44 "service_name": service.get("metadata", {}).get("name") 45 }) 46 return 47 48 # Waiting: Service not available yet 49 response.set_output(rsp, { 50 "status": "waiting", 51 "message": f"Waiting for service '{service_name}' to be available" 52 }) Important **Critical resource stabilization pattern**: functions must return the **same requirements** in each iteration to signal completion. The function in the preceding example always calls `response.require_resources()` regardless of whether the service exists. This ensures Crossplane knows when to stop calling the function. Common mistake: only requesting resources when missing breaks the stabilization contract and causes timeout errors. This pattern allows functions to: 1. Examine the watched resource (injected automatically) 2. Dynamically determine what other resources the function needs 3. Request those resources consistently using `response.require_resources()` 4. Process all resources when available, or provide status when waiting Status and monitoring[](https://docs.crossplane.io/v2.0/operations/watchoperation/#status-and-monitoring) ---------------------------------------------------------------------------------------------------------- WatchOperations provide status information about watching: 1status: 2 conditions: 3 - type: Synced 4 status: "True" 5 reason: ReconcileSuccess 6 - type: Watching 7 status: "True" 8 reason: WatchActive 9 watchingResources: 12 10 runningOperationRefs: 11 - name: config-validator-anjda 12 - name: config-validator-f0d92 **Key status fields:** * **Conditions**: Standard Crossplane conditions (Synced) and WatchOperation-specific conditions: * **Watching**: `True` when the WatchOperation is actively watching resources, `False` when paused or failed * **`watchingResources`**: Number of resources under watch * **`runningOperationRefs`**: Running Operations created by this WatchOperation ### Events[](https://docs.crossplane.io/v2.0/operations/watchoperation/#events) WatchOperations emit events for important activities: * `EstablishWatched` (Warning) - Watch establishment failures * `TerminateWatched` (Warning) - Watch termination failures * `GarbageCollectOperations` (Warning) - Operation cleanup failures * `CreateOperation` (Warning) - Operation creation failures * `ReplaceRunningOperation` (Warning) - Operation replacement failures ### Monitoring[](https://docs.crossplane.io/v2.0/operations/watchoperation/#monitoring) Monitor WatchOperations using: 1# Check WatchOperation status 2kubectl get watchoperation my-watchop 3 4# View recent Operations created by the WatchOperation 5kubectl get operations -l crossplane.io/watchoperation=my-watchop 6 7# Check watched resource count 8kubectl describe watchoperation my-watchop 9 10# Check events 11kubectl get events --field-selector involvedObject.name=my-watchop Best practices[](https://docs.crossplane.io/v2.0/operations/watchoperation/#best-practices) -------------------------------------------------------------------------------------------- ### Resource selection[](https://docs.crossplane.io/v2.0/operations/watchoperation/#resource-selection) 1. **Use specific label selectors** - Prevent unnecessary Operations with precise filtering 2. **Avoid high-churn resources** - Be careful watching frequently changing resources 3. **Start small** - Begin with narrow selectors and expand as needed ### Event handling[](https://docs.crossplane.io/v2.0/operations/watchoperation/#event-handling) 1. **Implement event filtering** - Check generation, deletion timestamp, and status conditions to avoid processing irrelevant changes 2. **Monitor operation volume** - Popular resources can create numerous Operations ### Concurrency policies[](https://docs.crossplane.io/v2.0/operations/watchoperation/#concurrency-policies-1) 1. **Choose appropriate concurrency policies**: * **Allow** for independent processing that can run in parallel * **Forbid** for operations that must complete before processing new changes * **Replace** for status-checking or monitoring where only latest state matters ### History management[](https://docs.crossplane.io/v2.0/operations/watchoperation/#history-management) Like CronOperations, WatchOperations automatically clean up completed Operations: 1apiVersion: ops.crossplane.io/v1alpha1 2kind: WatchOperation 3metadata: 4 name: config-validator 5spec: 6 watch: 7 apiVersion: v1 8 kind: ConfigMap 9 successfulHistoryLimit: 10 # Keep 10 successful Operations (default: 3) 10 failedHistoryLimit: 5 # Keep 5 failed Operations (default: 1) 11 operationTemplate: 12 # Operation template here ### Watched resource injection[](https://docs.crossplane.io/v2.0/operations/watchoperation/#watched-resource-injection) WatchOperations automatically inject the changed resource into the created Operation using a special requirement name `ops.crossplane.io/watched-resource`: 1from crossplane.function import request, response 2 3def operate(req, rsp): 4 # Access the resource that triggered this Operation 5 watched_resource = request.get_required_resource(req, "ops.crossplane.io/watched-resource") 6 if not watched_resource: 7 response.set_output(rsp, {"error": "No watched resource found"}) 8 return 9 10 # Process based on the watched resource 11 if watched_resource["kind"] == "ConfigMap": 12 config_data = watched_resource["data"] 13 # Validate configuration... The watched resource is available in the function’s `required_resources` map without needing to declare it in the Operation template. For general Operations best practices including function development and operational considerations, see [Operation best practices](https://docs.crossplane.io/v2.0/operations/operation/#best-practices) . Troubleshooting[](https://docs.crossplane.io/v2.0/operations/watchoperation/#troubleshooting) ---------------------------------------------------------------------------------------------- ### WatchOperation not creating Operations[](https://docs.crossplane.io/v2.0/operations/watchoperation/#watchoperation-not-creating-operations) 1. Verify the WatchOperation has `Watching=True` condition 2. Check that watched resources exist and match the selector 3. Ensure resources are actually changing 4. Look for events indicating watch establishment failures ### Too many Operations created[](https://docs.crossplane.io/v2.0/operations/watchoperation/#too-many-operations-created) 1. Refine label selectors to match fewer resources 2. Consider using `Forbid` or `Replace` concurrency policy 3. Check if resources are changing more frequently than expected 4. Review function logic to ensure it’s not causing resource updates ### Operations failing to process watched resources[](https://docs.crossplane.io/v2.0/operations/watchoperation/#operations-failing-to-process-watched-resources) 1. Verify function capabilities include `operation` 2. Check that functions handle the `ops.crossplane.io/watched-resource` 3. Review function logs for processing errors 4. Ensure functions can handle the specific resource types under watch Next steps[](https://docs.crossplane.io/v2.0/operations/watchoperation/#next-steps) ------------------------------------------------------------------------------------ * Learn about [Operation](https://docs.crossplane.io/v2.0/operations/operation/) for one-time operational tasks * Learn about [CronOperation](https://docs.crossplane.io/v2.0/operations/cronoperation/) for scheduled operations * [Get started with Operations](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/) to create your first reactive operation --- # Cron Operations · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/operations/cronoperation/#) [master](https://docs.crossplane.io/master/operations/cronoperation/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/operations/cronoperation/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Cron Operations =============== This is an alpha feature. Crossplane may change or drop this feature at any time. This feature was introduced in v2. For more information read the [Crossplane feature lifecycle](https://docs.crossplane.io/v2.0/learn/feature-lifecycle/) . On this page **On this page** * * * A `CronOperation` creates [Operations](https://docs.crossplane.io/v2.0/operations/operation/) on a schedule, like Kubernetes CronJobs. Use CronOperations for recurring operational tasks such as database backups, certificate rotation, or periodic maintenance. How CronOperations work[](https://docs.crossplane.io/v2.0/operations/cronoperation/#how-cronoperations-work) ------------------------------------------------------------------------------------------------------------- CronOperations contain a template for an Operation and create new Operations based on a cron schedule. Each scheduled run creates a new Operation that executes once to completion. 1apiVersion: ops.crossplane.io/v1alpha1 2kind: CronOperation 3metadata: 4 name: daily-backup 5spec: 6 schedule: "0 2 * * *" # Daily at 2 AM 7 concurrencyPolicy: Forbid 8 successfulHistoryLimit: 5 9 failedHistoryLimit: 3 10 operationTemplate: 11 spec: 12 mode: Pipeline 13 pipeline: 14 - step: backup 15 functionRef: 16 name: function-database-backup 17 input: 18 apiVersion: fn.crossplane.io/v1beta1 19 kind: DatabaseBackupInput 20 retentionDays: 7 Important CronOperations are an alpha feature. You must enable Operations by adding `--enable-operations` to Crossplane’s arguments. Key features[](https://docs.crossplane.io/v2.0/operations/cronoperation/#key-features) --------------------------------------------------------------------------------------- * **Standard cron scheduling syntax** - Uses the same format as Kubernetes CronJobs * **Configurable concurrency policies** (Allow, Forbid, Replace) * **Automatic cleanup of old Operations** - Maintains history limits * **Tracks run history and running operations** - Provides visibility into scheduled runs Scheduling[](https://docs.crossplane.io/v2.0/operations/cronoperation/#scheduling) ----------------------------------------------------------------------------------- CronOperations use standard cron syntax: ┌───────────── minute (0 - 59) │ ┌───────────── hour (0 - 23) │ │ ┌───────────── day of the month (1 - 31) │ │ │ ┌───────────── month (1 - 12) │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday) │ │ │ │ │ │ │ │ │ │ * * * * * **Common schedule examples:** * `"0 2 * * *"` - Every day at 2:00 AM * `"0 0 * * 0"` - Every Sunday at midnight * `"0 0 1 * *"` - Every month on the first at midnight * `"*/15 * * * *"` - Every 15 minutes Concurrency policies[](https://docs.crossplane.io/v2.0/operations/cronoperation/#concurrency-policies) ------------------------------------------------------------------------------------------------------- CronOperations support three concurrency policies: * **Allow (default)**: Multiple Operations can run simultaneously. Use this when operations don’t interfere with each other. * **Forbid**: New Operations don’t start if previous ones are still running. Use this for operations that can’t run concurrently. * **Replace**: New Operations stop running ones before starting. Use this when you always want the latest operation to run. History management[](https://docs.crossplane.io/v2.0/operations/cronoperation/#history-management) --------------------------------------------------------------------------------------------------- Control the number of completed Operations to keep: 1spec: 2 successfulHistoryLimit: 5 # Keep 5 successful operations 3 failedHistoryLimit: 3 # Keep 3 failed operations for debugging This helps balance debugging capabilities with resource usage. Common use cases[](https://docs.crossplane.io/v2.0/operations/cronoperation/#common-use-cases) ----------------------------------------------------------------------------------------------- Note The following examples use hypothetical functions for illustration. At launch, only function-python supports operations. ### Scheduled database backups[](https://docs.crossplane.io/v2.0/operations/cronoperation/#scheduled-database-backups) 1apiVersion: ops.crossplane.io/v1alpha1 2kind: CronOperation 3metadata: 4 name: postgres-backup 5spec: 6 schedule: "0 3 * * *" # Daily at 3 AM 7 concurrencyPolicy: Forbid # Don't allow overlapping backups 8 operationTemplate: 9 spec: 10 mode: Pipeline 11 pipeline: 12 - step: backup 13 functionRef: 14 name: function-postgres-backup 15 input: 16 apiVersion: fn.crossplane.io/v1beta1 17 kind: PostgresBackupInput 18 instance: production-db 19 s3Bucket: db-backups ### Scheduled maintenance[](https://docs.crossplane.io/v2.0/operations/cronoperation/#scheduled-maintenance) 1apiVersion: ops.crossplane.io/v1alpha1 2kind: CronOperation 3metadata: 4 name: weekly-maintenance 5spec: 6 schedule: "0 3 * * 0" # Weekly on Sunday at 3 AM 7 operationTemplate: 8 spec: 9 mode: Pipeline 10 pipeline: 11 - step: cleanup-logs 12 functionRef: 13 name: function-log-cleanup 14 input: 15 apiVersion: fn.crossplane.io/v1beta1 16 kind: LogCleanupInput 17 retentionDays: 30 18 - step: update-certificates 19 functionRef: 20 name: function-cert-renewal ### Periodic health checks[](https://docs.crossplane.io/v2.0/operations/cronoperation/#periodic-health-checks) 1apiVersion: ops.crossplane.io/v1alpha1 2kind: CronOperation 3metadata: 4 name: health-check 5spec: 6 schedule: "*/30 * * * *" # Every 30 minutes 7 operationTemplate: 8 spec: 9 mode: Pipeline 10 pipeline: 11 - step: check-cluster-health 12 functionRef: 13 name: function-health-check 14 input: 15 apiVersion: fn.crossplane.io/v1beta1 16 kind: HealthCheckInput 17 alertThreshold: 80 Advanced configuration[](https://docs.crossplane.io/v2.0/operations/cronoperation/#advanced-configuration) ----------------------------------------------------------------------------------------------------------- ### Complex scheduling patterns[](https://docs.crossplane.io/v2.0/operations/cronoperation/#complex-scheduling-patterns) Advanced cron schedule examples for specific use cases: 1# Weekdays only at 9 AM (Monday-Friday) 2schedule: "0 9 * * 1-5" 3 4# Every 4 hours during business days 5schedule: "0 8,12,16 * * 1-5" 6 7# First and last day of each month 8schedule: "0 2 1,L * *" 9 10# Every quarter (1st of Jan, Apr, Jul, Oct) 11schedule: "0 2 1 1,4,7,10 *" 12 13# Business hours only, every 2 hours 14schedule: "0 9-17/2 * * 1-5" ### Starting deadline[](https://docs.crossplane.io/v2.0/operations/cronoperation/#starting-deadline) CronOperations support a `startingDeadlineSeconds` field that controls how long to wait after the scheduled time before considering it too late to create the Operation: 1apiVersion: ops.crossplane.io/v1alpha1 2kind: CronOperation 3metadata: 4 name: deadline-example 5spec: 6 schedule: "0 9 * * 1-5" # Weekdays at 9 AM 7 startingDeadlineSeconds: 900 # 15 minutes 8 operationTemplate: 9 spec: 10 mode: Pipeline 11 pipeline: 12 - step: morning-tasks 13 functionRef: 14 name: function-morning-tasks If the Operation can’t start in 15 minutes of 9 AM (due to controller downtime, resource constraints, etc.), the scheduled run is skipped. Skip operations for: * **Time-sensitive operations** - Skip operations that become meaningless if delayed * **Resource protection** - Prevent backup Operations piling up during outages * **SLA compliance** - Ensure operations run in acceptable time windows ### Time zone considerations[](https://docs.crossplane.io/v2.0/operations/cronoperation/#time-zone-considerations) Important CronOperations use the cluster’s local time zone, same as Kubernetes CronJobs. To ensure consistent scheduling across different environments, consider: 1. **Standardize cluster time zones** - Use UTC in production clusters 2. **Document time zone assumptions** - Note expected time zone in comments 3. **Account for DST changes** - Be aware that some schedules may skip or repeat during transitions Status and monitoring[](https://docs.crossplane.io/v2.0/operations/cronoperation/#status-and-monitoring) --------------------------------------------------------------------------------------------------------- CronOperations provide status information about scheduling: 1status: 2 conditions: 3 - type: Synced 4 status: "True" 5 reason: ReconcileSuccess 6 - type: Scheduling 7 status: "True" 8 reason: ScheduleActive 9 lastScheduleTime: "2024-01-15T10:00:00Z" 10 lastSuccessfulTime: "2024-01-15T10:02:30Z" 11 runningOperationRefs: 12 - name: daily-backup-1705305600 **Key status fields:** * **Conditions**: Standard Crossplane conditions (Synced) and CronOperation-specific conditions: * **Scheduling**: `True` when the CronOperation is actively scheduling operations, `False` when paused or has incorrect schedule syntax * **`lastScheduleTime`**: When the CronOperation last created an Operation * **`lastSuccessfulTime`**: When an Operation last completed successfully * **`runningOperationRefs`**: Running Operations ### Events[](https://docs.crossplane.io/v2.0/operations/cronoperation/#events) CronOperations emit events for important activities: * `CreateOperation` (Warning) - Scheduled operation creation failures * `GarbageCollectOperations` (Warning) - Garbage collection failures * `ReplaceRunningOperation` (Warning) - Running operation deletion failures * `InvalidSchedule` (Warning) - Cron schedule parsing errors ### Monitoring[](https://docs.crossplane.io/v2.0/operations/cronoperation/#monitoring) Monitor CronOperations using: 1# Check CronOperation status 2kubectl get cronoperation my-cronop 3 4# View recent Operations created by the CronOperation 5kubectl get operations -l crossplane.io/cronoperation=my-cronop 6 7# Check events 8kubectl get events --field-selector involvedObject.name=my-cronop Best practices[](https://docs.crossplane.io/v2.0/operations/cronoperation/#best-practices) ------------------------------------------------------------------------------------------- ### Scheduling considerations[](https://docs.crossplane.io/v2.0/operations/cronoperation/#scheduling-considerations) 1. **Consider time zones** - CronOperations use the host’s local time (same as Kubernetes CronJobs) 2. **Plan for long-running operations** - Ensure operations complete before next scheduled run 3. **Set reasonable history limits** - Balance debugging needs with cluster resource usage ### Concurrency policies[](https://docs.crossplane.io/v2.0/operations/cronoperation/#concurrency-policies-1) 1. **Choose appropriate concurrency policies**: * **Forbid** for backups, maintenance, or operations that must complete alone * **Replace** for health checks or monitoring where latest data is most important * **Allow** for independent tasks that can run simultaneously For general Operations best practices including function development and operational considerations, see [Operation best practices](https://docs.crossplane.io/v2.0/operations/operation/#best-practices) . Troubleshooting[](https://docs.crossplane.io/v2.0/operations/cronoperation/#troubleshooting) --------------------------------------------------------------------------------------------- ### CronOperation not creating Operations[](https://docs.crossplane.io/v2.0/operations/cronoperation/#cronoperation-not-creating-operations) 1. Check the cron schedule syntax 2. Verify the CronOperation has `Synced=True` condition 3. Look for events indicating schedule parsing errors ### Operations failing often[](https://docs.crossplane.io/v2.0/operations/cronoperation/#operations-failing-often) 1. Check Operation events and logs 2. Verify function capabilities include `operation` 3. Review retry limits and adjust as needed ### Resource cleanup issues[](https://docs.crossplane.io/v2.0/operations/cronoperation/#resource-cleanup-issues) 1. Verify you set history limits appropriately 2. Check for events about garbage collection failures Next steps[](https://docs.crossplane.io/v2.0/operations/cronoperation/#next-steps) ----------------------------------------------------------------------------------- * Learn about [Operation](https://docs.crossplane.io/v2.0/operations/operation/) for one-time operational tasks * Learn about [WatchOperation](https://docs.crossplane.io/v2.0/operations/watchoperation/) for reactive operations * [Get started with Operations](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/) to try scheduling your first operation --- # Composite Resources · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/composition/composite-resources/#) [master](https://docs.crossplane.io/master/composition/composite-resources/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/composition/composite-resources/) [v1.20](https://docs.crossplane.io/v1.20/concepts/composite-resources/) [v1.19](https://docs.crossplane.io/v1.19/concepts/composite-resources/) Composite Resources =================== On this page **On this page** * * * A composite resource, or XR, represents a set of Kubernetes resources as a single Kubernetes object. Crossplane creates composite resources when users access a custom API, defined in the CompositeResourceDefinition. Tip Composite resources are a _composite_ of Kubernetes resources. A _Composition_ defines how to _compose_ the resources together. What are XRs, XRDs and Compositions? ------------------------------------ A composite resource or XR (this page) is a custom API. You use two Crossplane types to create a new custom API: * A [Composite Resource Definition](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/) (XRD) - Defines the XR’s schema. * A [Composition](https://docs.crossplane.io/v2.0/composition/compositions/) - Configures how the XR creates other resources. Create composite resources[](https://docs.crossplane.io/v2.0/composition/composite-resources/#create-composite-resources) -------------------------------------------------------------------------------------------------------------------------- Creating composite resources requires a [Composition](https://docs.crossplane.io/v2.0/composition/compositions/) and a [CompositeResourceDefinition](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/) (XRD). The Composition defines the set of resources to create. The XRD defines the custom API users call to request the set of resources. flowchart TD user(\["User"\]) xr("Composite Resource (XR)") xrd("Composite Resource Definition (XRD)") comp("Composition") cda("Composed Resource A") cdb("Composed Resource B") cdc("Composed Resource C") xrd -.defines.-> xr comp configure-xr@-.configures.-> xr user --creates--> xr xr compose-a@--composes-->cda xr compose-b@--composes-->cdb xr compose-c@--composes-->cdc configure-xr@{animate: true} compose-a@{animate: true} compose-b@{animate: true} compose-c@{animate: true} XRDs define the API used to create a composite resource. For example, this `CompositeResourceDefinition` creates a custom API endpoint `mydatabases.example.org`. 1apiVersion: apiextensions.crossplane.io/v1 2kind: CompositeResourceDefinition 3metadata: 4 name: mydatabases.example.org 5spec: 6 group: example.org 7 names: 8 kind: MyDatabase 9 plural: mydatabases 10 # Removed for brevity When a user calls the custom API, `mydatabases.example.org`, Crossplane chooses the Composition to use based on the Composition’s `compositeTypeRef` 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: my-composition 5spec: 6 compositeTypeRef: 7 apiVersion: example.org/v1alpha1 8 kind: MyDatabase 9 # Removed for brevity The Composition `compositeTypeRef` matches the XRD `group` and `kind`. Crossplane creates the resources defined in the matching Composition and represents them as a single `composite` resource. 1kubectl get composite 2NAME SYNCED READY COMPOSITION AGE 3my-composite-resource True True my-composition 4s ### Composition selection[](https://docs.crossplane.io/v2.0/composition/composite-resources/#composition-selection) Select a specific Composition for a composite resource to use with `compositionRef` Important The selected Composition must allow the composite resource to use it with a `compositeTypeRef`. Read more about the `compositeTypeRef` field in the [Enable Composite Resources](https://docs.crossplane.io/v2.0/composition/compositions/#match-composite-resources) section of the Composition documentation. 1apiVersion: example.org/v1alpha1 2kind: MyDatabase 3metadata: 4 namespace: default 5 name: my-composite-resource 6spec: 7 crossplane: 8 compositionRef: 9 name: my-other-composition 10 # Removed for brevity A composite resource can also select a Composition based on labels instead of the exact name with a `compositionSelector`. Inside the `matchLabels` section provide one or more Composition labels to match. 1apiVersion: example.org/v1alpha1 2kind: MyDatabase 3metadata: 4 namespace: default 5 name: my-composite-resource 6spec: 7 crossplane: 8 compositionSelector: 9 matchLabels: 10 environment: production 11 # Removed for brevity ### Composition revision policy[](https://docs.crossplane.io/v2.0/composition/composite-resources/#composition-revision-policy) Crossplane tracks changes to Compositions as [Composition revisions](https://docs.crossplane.io/v2.0/composition/composition-revisions/) . A composite resource can use a `compositionUpdatePolicy` to manually or automatically reference newer Composition revisions. The default `compositionUpdatePolicy` is “Automatic.” Composite resources automatically use the latest Composition revision. Change the policy to `Manual` to prevent composite resources from automatically upgrading. 1apiVersion: example.org/v1alpha1 2kind: MyDatabase 3metadata: 4 namespace: default 5 name: my-composite-resource 6spec: 7 crossplane: 8 compositionUpdatePolicy: Manual 9 # Removed for brevity ### Composition revision selection[](https://docs.crossplane.io/v2.0/composition/composite-resources/#composition-revision-selection) Crossplane records changes to Compositions as [Composition revisions](https://docs.crossplane.io/v2.0/composition/composition-revisions/) . A composite resource can select a specific Composition revision. Use `compositionRevisionRef` to select a specific Composition revision by name. For example, to select a specific Composition revision use the name of the desired Composition revision. 1apiVersion: example.org/v1alpha1 2kind: MyDatabase 3metadata: 4 namespace: default 5 name: my-composite-resource 6spec: 7 crossplane: 8 compositionUpdatePolicy: Manual 9 compositionRevisionRef: 10 name: my-composition-b5aa1eb 11 # Removed for brevity Note Find the Composition revision name from `kubectl get compositionrevision` 1kubectl get compositionrevision 2NAME REVISION XR-KIND XR-APIVERSION AGE 3my-composition-5c976ad 1 mydatabases example.org/v1alpha1 65m 4my-composition-b5aa1eb 2 mydatabases example.org/v1alpha1 64m A Composite resource can also select Composition revisions based on labels instead of the exact name with a `compositionRevisionSelector`. Inside the `matchLabels` section provide one or more Composition revision labels to match. 1apiVersion: example.org/v1alpha1 2kind: MyDatabase 3metadata: 4 namespace: default 5 name: my-composite-resource 6spec: 7 crossplane: 8 compositionRevisionSelector: 9 matchLabels: 10 channel: dev 11 # Removed for brevity ### Pausing composite resources[](https://docs.crossplane.io/v2.0/composition/composite-resources/#pausing-composite-resources) Crossplane supports pausing composite resources. A paused composite resource doesn’t check or make changes on its external resources. To pause a composite resource apply the `crossplane.io/paused` annotation. 1apiVersion: example.org/v1alpha1 2kind: MyDatabase 3metadata: 4 namespace: default 5 name: my-composite-resource 6 annotations: 7 crossplane.io/paused: "true" 8spec: 9 # Removed for brevity Verify composite resources[](https://docs.crossplane.io/v2.0/composition/composite-resources/#verify-composite-resources) -------------------------------------------------------------------------------------------------------------------------- Use `kubectl get composite` to view all the composite resources Crossplane created. 1kubectl get composite 2NAME SYNCED READY COMPOSITION AGE 3my-composite-resource True True my-composition 4s Use `kubectl get` for the specific custom API endpoint to view only those resources. 1kubectl get mydatabases 2NAME SYNCED READY COMPOSITION AGE 3my-composite-resource True True my-composition 12m Use `kubectl describe composite` to view the linked `Composition Ref`, and unique resources created in the `Resource Refs`. 1kubectl describe composite my-composite-resource 2Name: my-composite-resource 3Namespace: default 4API Version: example.org/v1alpha1 5Kind: MyDatabase 6Spec: 7 Composition Ref: 8 Name: my-composition 9 Composition Revision Ref: 10 Name: my-composition-cf2d3a7 11 Composition Update Policy: Automatic 12 Resource Refs: 13 API Version: s3.aws.m.upbound.io/v1beta1 14 Kind: Bucket 15 Name: my-composite-resource-fmrks 16 API Version: dynamodb.aws.m.upbound.io/v1beta1 17 Kind: Table 18 Name: my-composite-resource-wnr9t 19# Removed for brevity ### Composite resource conditions[](https://docs.crossplane.io/v2.0/composition/composite-resources/#composite-resource-conditions) A composite resource has two status conditions: Synced and Ready. Crossplane sets the Synced status condition to True when it’s able to successfully reconcile the composite resource. If Crossplane can’t reconcile the composite resource it reports an error in the Synced condition. Crossplane sets the Ready status condition to True when the composite resource’s composition function pipeline reports that all its composed resources are ready. If a composed resource isn’t ready Crossplane reports it in the Ready condition. Composite resource labels[](https://docs.crossplane.io/v2.0/composition/composite-resources/#composite-resource-labels) ------------------------------------------------------------------------------------------------------------------------ Crossplane adds labels to composed resources to show their relationship to other Crossplane components. Crossplane adds the `crossplane.io/composite` label to all composed resources. The label matches the name of the composite. Crossplane applies the composite label to any resource created by a composite, creating a reference between the resource and owning composite resource. 1kubectl describe mydatabase.example.org/my-database-x9rx9 2Name: my-database2-x9rx9 3Namespace: default 4Labels: crossplane.io/composite=my-database-x9rx9 --- # Functions · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/packages/functions/#) [master](https://docs.crossplane.io/master/packages/functions/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/packages/functions/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Functions ========= On this page **On this page** * * * Functions extend Crossplane with new ways to configure [composition](https://docs.crossplane.io/v2.0/composition/) . You can use different _composition functions_ to configure what Crossplane does when someone creates or updates a [composite resource (XR)](https://docs.crossplane.io/v2.0/composition/composite-resources/) . Important This page is a work in progress. Functions are packages, like [Providers](https://docs.crossplane.io/v2.0/packages/providers/) and [Configurations](https://docs.crossplane.io/v2.0/packages/configurations/) . Their APIs are similar. You install and configure them the same way as a provider. Read the [composition](https://docs.crossplane.io/v2.0/composition/compositions/) documentation to learn how to use functions in a composition. Install a function[](https://docs.crossplane.io/v2.0/packages/functions/#install-a-function) --------------------------------------------------------------------------------------------- Install a Function with a Crossplane `Function` object setting the `spec.package` value to the location of the function package. For example, to install the [patch and transform function](https://github.com/crossplane-contrib/function-patch-and-transform) , 1apiVersion: pkg.crossplane.io/v1 2kind: Function 3metadata: 4 name: crossplane-contrib-function-patch-and-transform 5spec: 6 package: xpkg.crossplane.io/crossplane-contrib/function-patch-and-transform:v0.8.2 By default, the Function pod installs in the same namespace as Crossplane (`crossplane-system`). Note Functions are part of the `pkg.crossplane.io` group. The `meta.pkg.crossplane.io` group is for creating Function packages. Instructions on building Functions are outside of the scope of this document. Read the Crossplane contributing [Function Development Guide](https://github.com/crossplane/crossplane/blob/main/contributing/guide-provider-development.md) for more information. For information on the specification of Function packages read the [Crossplane Function Package specification](https://github.com/crossplane/crossplane/blob/main/contributing/specifications/xpkg.md#provider-package-requirements) . 1apiVersion: meta.pkg.crossplane.io/v1 2kind: Function 3metadata: 4 name: provider-aws 5spec: 6# Removed for brevity --- # Compositions · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/composition/compositions/#) [master](https://docs.crossplane.io/master/composition/compositions/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/composition/compositions/) [v1.20](https://docs.crossplane.io/v1.20/concepts/compositions/) [v1.19](https://docs.crossplane.io/v1.19/concepts/compositions/) Compositions ============ On this page **On this page** * * * Compositions are a template for creating multiple Kubernetes resources as a single _composite_ resource. A Composition _composes_ individual resources together into a larger, reusable, solution. An example Composition may combine a virtual machine, storage resources and networking policies. A Composition template links all these individual resources together. Here’s an example Composition. When you create an `AcmeBucket` composite resource (XR) that uses this Composition, Crossplane uses the template to create the Amazon S3 `Bucket` managed resource. 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: example 5spec: 6 compositeTypeRef: 7 apiVersion: custom-api.example.org/v1alpha1 8 kind: AcmeBucket 9 mode: Pipeline 10 pipeline: 11 - step: patch-and-transform 12 functionRef: 13 name: function-patch-and-transform 14 input: 15 apiVersion: pt.fn.crossplane.io/v1beta1 16 kind: Resources 17 resources: 18 - name: storage-bucket 19 base: 20 apiVersion: s3.aws.m.upbound.io/v1beta1 21 kind: Bucket 22 spec: 23 forProvider: 24 region: "us-east-2" What are XRs, XRDs and Compositions? ------------------------------------ A [composite resource](https://docs.crossplane.io/v2.0/composition/composite-resources/) or XR is a custom API. You use two Crossplane types to create a new custom API: * A [Composite Resource Definition](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/) (XRD) - Defines the XR’s schema. * A Composition - This page. Configures how the XR creates other resources. Create a composition[](https://docs.crossplane.io/v2.0/composition/compositions/#create-a-composition) ------------------------------------------------------------------------------------------------------- Creating a Composition consists of: * [Using composition functions](https://docs.crossplane.io/v2.0/composition/compositions/#use-a-function-in-a-composition) to define the resources to create. * [Enabling composite resources](https://docs.crossplane.io/v2.0/composition/compositions/#match-composite-resources) to use the Composition template. A Composition is a pipeline of composition functions. Composition functions (or just functions, for short) are Crossplane extensions that template Crossplane resources. Crossplane calls the composition functions to determine what resources it should create when you create a composite resource (XR). Tip Crossplane has functions that let you template composed resources using YAML [patch and transforms](https://docs.crossplane.io/v2.0/guides/function-patch-and-transform/) . Helm-like [YAML templates](https://github.com/crossplane-contrib/function-go-templating) , [CUE](https://github.com/crossplane-contrib/function-cue) , [KCL](https://github.com/crossplane-contrib/function-kcl) , or [Python](https://github.com/crossplane-contrib/function-python) . You can also [write your own function](https://docs.crossplane.io/v2.0/composition/compositions/#write-a-composition-function) using Go or Python. ### Install a composition function[](https://docs.crossplane.io/v2.0/composition/compositions/#install-a-composition-function) Installing a Function creates a function pod. Crossplane sends requests to this pod to ask it what resources to create when you create a composite resource. Install a Function with a Crossplane `Function` object setting the `spec.package` value to the location of the function package. For example, to install [Function Patch and Transform](https://docs.crossplane.io/v2.0/guides/function-patch-and-transform/) , 1apiVersion: pkg.crossplane.io/v1 2kind: Function 3metadata: 4 name: function-patch-and-transform 5spec: 6 package: xpkg.crossplane.io/crossplane-contrib/function-patch-and-transform:v0.8.2 Tip Functions are Crossplane Packages. Read more about Packages in the [Packages documentation](https://docs.crossplane.io/v2.0/packages/functions/) . By default, the Function pod installs in the same namespace as Crossplane (`crossplane-system`). ### Verify a composition function[](https://docs.crossplane.io/v2.0/composition/compositions/#verify-a-composition-function) View the status of a Function with `kubectl get functions` During the install a Function reports `INSTALLED` as `True` and `HEALTHY` as `Unknown`. 1kubectl get functions 2NAME INSTALLED HEALTHY PACKAGE AGE 3function-patch-and-transform True Unknown xpkg.crossplane.io/crossplane-contrib/function-patch-and-transform:v0.8.2 10s After the Function install completes and it’s ready for use the `HEALTHY` status reports `True`. ### Use a function in a composition[](https://docs.crossplane.io/v2.0/composition/compositions/#use-a-function-in-a-composition) Crossplane calls a Function to determine what resources it should create when you create a composite resource. The Function also tells Crossplane what to do with these resources when you update a composite resource. Note Composition functions don’t run when you delete a composite resource. Crossplane handles deletion of composed resources automatically. When Crossplane calls a Function it sends it the current state of the composite resource. It also sends it the current state of any resources the composite resource owns. Crossplane knows what Function to call when a composite resource changes by looking at the Composition the composite resource uses. To use composition functions set the Composition `mode` to `Pipeline`. Define a `pipeline` of `steps`. Each `step` calls a Function. Each `step` uses a `functionRef` to reference the `name` of the Function to call. Some Functions also allow you to specify an `input`. The function defines the `kind` of input. This example uses [Function Patch and Transform](https://docs.crossplane.io/v2.0/guides/function-patch-and-transform/) . Function Patch and Transform implements Crossplane resource templates. The input kind is `Resources`, and it accepts `resources` as input. 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3# Removed for Brevity 4spec: 5 # Removed for Brevity 6 mode: Pipeline 7 pipeline: 8 - step: patch-and-transform 9 functionRef: 10 name: function-patch-and-transform 11 input: 12 apiVersion: pt.fn.crossplane.io/v1beta1 13 kind: Resources 14 resources: 15 - name: storage-bucket 16 base: 17 apiVersion: s3.aws.m.upbound.io/v1beta1 18 kind: Bucket 19 spec: 20 forProvider: 21 region: "us-east-2" ### Use a pipeline of functions in a composition[](https://docs.crossplane.io/v2.0/composition/compositions/#use-a-pipeline-of-functions-in-a-composition) Crossplane can ask more than one Function what to do when a composite resource changes. When a Composition has a pipeline of two or more steps, Crossplane calls them all. It calls them in the order they appear in the pipeline. Crossplane passes each Function in the pipeline the result of the previous Function. This enables powerful combinations of Functions. In this example, Crossplane calls `function-cue` to create an S3 bucket. Crossplane then passes the bucket to `function-auto-ready`, which marks the composite resource as ready when the bucket becomes ready. 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3# Removed for Brevity 4spec: 5 # Removed for Brevity 6 mode: Pipeline 7 pipeline: 8 - step: cue-export-resources 9 functionRef: 10 name: function-cue 11 input: 12 apiVersion: cue.fn.crossplane.io/v1beta1 13 kind: CUEInput 14 name: storage-bucket 15 export: 16 target: Resources 17 value: | 18 apiVersion: "s3.aws.m.upbound.io/v1beta1" 19 kind: "Bucket" 20 spec: forProvider: region: "us-east-2" 21 - step: automatically-detect-readiness 22 functionRef: 23 name: function-auto-ready ### Match composite resources[](https://docs.crossplane.io/v2.0/composition/compositions/#match-composite-resources) A Composition is only a template defining how to create composed resources. A Composition limits which kind of composite resource (XR) can use this template. A Composition’s `compositeTypeRef` defines which Composite Resource type can use this Composition. Note Read more about Composite Resources in the [Composite Resources page](https://docs.crossplane.io/v2.0/composition/composite-resources/) . Inside a Composition’s `spec` define the Composite Resource `apiVersion` and `kind` that the Composition allows to use this template. 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: dynamodb-with-bucket 5spec: 6 compositeTypeRef: 7 apiVersion: custom-api.example.org/v1alpha1 8 kind: database 9 # Removed for brevity ### Grant access to composed resources[](https://docs.crossplane.io/v2.0/composition/compositions/#grant-access-to-composed-resources) Crossplane uses its [service account](https://kubernetes.io/docs/concepts/security/service-accounts/) to create the composed resources that a function pipeline returns. Crossplane’s service account has access to create, update, and delete any resource installed by a [provider](https://docs.crossplane.io/v2.0/packages/providers/) , or defined by an XRD. This includes all [MRs](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/) and [XRs](https://docs.crossplane.io/v2.0/composition/composite-resources/) . It also has access to some types of Kubernetes resources that it needs to function - for example it can create deployments. You must grant Crossplane access to compose any other kind of resource. You do this by creating an [RBAC ClusterRole](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) . The ClusterRole must aggregate to Crossplane’s primary ClusterRole using [ClusterRole aggregation](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#aggregated-clusterroles) . Here’s a ClusterRole that grants Crossplane access to manage [CloudNativePG](https://cloudnative-pg.io/) PostgreSQL clusters. 1apiVersion: rbac.authorization.k8s.io/v1 2kind: ClusterRole 3metadata: 4 name: cnpg:aggregate-to-crossplane 5 labels: 6 rbac.crossplane.io/aggregate-to-crossplane: "true" 7rules: 8- apiGroups: 9 - postgresql.cnpg.io 10 resources: 11 - clusters 12 verbs: 13 - "*" The `rbac.crossplane.io/aggregate-to-crossplane: "true"` label is critical. It configures the role to aggregate to Crossplane’s primary cluster role. Note The [RBAC manager](https://docs.crossplane.io/v2.0/guides/pods/#rbac-manager-pod) automatically grants Crossplane access to MRs and XRs. The RBAC manager uses [escalate access](https://kubernetes.io/docs/concepts/security/rbac-good-practices/#escalate-verb) to grant Crossplane access that the RBAC manager doesn’t have. The RBAC manager is an optional Crossplane component that’s enabled by default. **If you disable the RBAC manager, you must manually grant Crossplane access to _any_ kind of resource you wish to compose - including XRs and MRs.** Test a composition[](https://docs.crossplane.io/v2.0/composition/compositions/#test-a-composition) --------------------------------------------------------------------------------------------------- You can preview the output of any composition using the Crossplane CLI. You don’t need a Crossplane control plane to do this. The Crossplane CLI uses Docker Engine to run functions. Tip See the [Crossplane CLI docs](https://docs.crossplane.io/v2.0/cli/) to learn how to install and use the Crossplane CLI. Important Running `crossplane render` requires [Docker](https://www.docker.com/) . Provide a composite resource, composition and composition functions to render the output locally. 1crossplane render xr.yaml composition.yaml functions.yaml `crossplane render` prints resources as YAML to stdout. It prints the composite resource first, followed by the resources the composition functions created. 1--- 2apiVersion: example.crossplane.io/v1 3kind: Bucket 4metadata: 5 name: example-render 6--- 7apiVersion: s3.aws.m.upbound.io/v1beta1 8kind: Bucket 9metadata: 10 annotations: 11 crossplane.io/composition-resource-name: storage-bucket 12 generateName: example-render- 13 labels: 14 crossplane.io/composite: example-render 15 ownerReferences: 16 - apiVersion: example.crossplane.io/v1 17 blockOwnerDeletion: true 18 controller: true 19 kind: Bucket 20 name: example-render 21 uid: "" 22spec: 23 forProvider: 24 region: us-east-2 The xr.yaml, composition.yaml and function.yaml files used in the example ------------------------------------------------------------------------- You can recreate the output below by running `crossplane render` with these files. The `xr.yaml` file contains the composite resource to render: 1apiVersion: example.crossplane.io/v1 2kind: Bucket 3metadata: 4 name: example-render 5spec: 6 bucketRegion: us-east-2 The `composition.yaml` file contains the Composition to use to render the composite resource: 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: example-render 5spec: 6 compositeTypeRef: 7 apiVersion: example.crossplane.io/v1 8 kind: Bucket 9 mode: Pipeline 10 pipeline: 11 - step: patch-and-transform 12 functionRef: 13 name: function-patch-and-transform 14 input: 15 apiVersion: pt.fn.crossplane.io/v1beta1 16 kind: Resources 17 resources: 18 - name: storage-bucket 19 base: 20 apiVersion: s3.aws.m.upbound.io/v1beta1 21 kind: Bucket 22 patches: 23 - type: FromCompositeFieldPath 24 fromFieldPath: spec.bucketRegion 25 toFieldPath: spec.forProvider.region The `functions.yaml` file contains the Functions the Composition references in its pipeline steps: 1--- 2apiVersion: pkg.crossplane.io/v1 3kind: Function 4metadata: 5 name: function-patch-and-transform 6spec: 7 package: xpkg.crossplane.io/crossplane-contrib/function-patch-and-transform:v0.8.2 The Crossplane CLI uses Docker Engine to run functions. You can change how the Crossplane CLI runs a function by adding an annotation in `functions.yaml`. Add the `render.crossplane.io/runtime` annotation to a Function to change how it’s run. `crossplane render` supports two `render.crossplane.io/runtime` values: * `Docker` (the default) connects to Docker Engine. It uses Docker to pull and run a function runtime. * `Development` connects to a function runtime you have run manually. When you use the `Development` runtime the Crossplane CLI ignores the Function’s `package`. Instead it expects you to make sure the function is listening on localhost port 9443. The function must be listening without gRPC transport security. Most function SDKs let you run a function with the `--insecure` flag to disable transport security. For example you can run a Go function locally using `go run . --insecure`. 1apiVersion: pkg.crossplane.io/v1 2kind: Function 3metadata: 4 name: function-patch-and-transform 5 annotations: 6 render.crossplane.io/runtime: Development 7spec: 8 package: xpkg.crossplane.io/crossplane-contrib/function-patch-and-transform:v0.8.2 Tip Use the `Development` runtime when you [write a composition function](https://docs.crossplane.io/v2.0/composition/compositions/#write-a-composition-function) to test your function end-to-end. `crossplane render` also supports the following Function annotations. These annotations affect how it runs Functions: * `render.crossplane.io/runtime-docker-cleanup` - When using the `Docker` runtime this annotation specifies whether the CLI should stop the function container after it calls the function. It supports the values `Stop`, to stop the container, and `Orphan`, to leave it running. * `render.crossplane.io/runtime-docker-pull-policy` - When using the `Docker` runtime this annotation specifies when the CLI should pull the Function’s package. It supports the values `Always`, `Never`, and `IfNotPresent`. * `render.crossplane.io/runtime-development-target` - When using the `Development` runtime this annotation tells the CLI to connect to a Function running at the specified target. It uses [gRPC target syntax](https://github.com/grpc/grpc/blob/v1.59.1/doc/naming.md) . Verify a composition[](https://docs.crossplane.io/v2.0/composition/compositions/#verify-a-composition) ------------------------------------------------------------------------------------------------------- View all available Compositions with `kubectl get composition`. 1kubectl get composition 2NAME XR-KIND XR-APIVERSION AGE 3xapps.aws.platformref.upbound.io XApp aws.platformref.upbound.io/v1alpha1 123m 4xclusters.aws.platformref.upbound.io XCluster aws.platformref.upbound.io/v1alpha1 123m 5xeks.aws.platformref.upbound.io XEKS aws.platformref.upbound.io/v1alpha1 123m 6xnetworks.aws.platformref.upbound.io XNetwork aws.platformref.upbound.io/v1alpha1 123m 7xservices.aws.platformref.upbound.io XServices aws.platformref.upbound.io/v1alpha1 123m 8xsqlinstances.aws.platformref.upbound.io XSQLInstance aws.platformref.upbound.io/v1alpha1 123m The `XR-KIND` lists the Composite Resource `kind` that’s allowed to use the Composition template. The `XR-APIVERSION` lists the Composite Resource API versions allowed to use the Composition template. Note The output of `kubectl get composition` is different than `kubectl get composite`. `kubectl get composition` lists all available Compositions. `kubectl get composite` lists all created Composite Resources and their related Composition. Write a composition function[](https://docs.crossplane.io/v2.0/composition/compositions/#write-a-composition-function) ----------------------------------------------------------------------------------------------------------------------- Composition functions let you replace complicated Compositions with code written in your programming language of choice. Crossplane has tools, software development kits (SDKs) and templates to help you write a function. Here’s an example of a tiny, hello world function. This example is written in [Go](https://go.dev/) . 1func (f *Function) RunFunction(_ context.Context, req *fnv1.RunFunctionRequest) (*fnv1.RunFunctionResponse, error) { 2 rsp := response.To(req, response.DefaultTTL) 3 response.Normal(rsp, "Hello world!") 4 return rsp, nil 5} Crossplane has [language specific guides](https://docs.crossplane.io/v2.0/guides/) to writing a composition function. Refer to the guide for your preferred language to learn how to write a composition function. When you’re writing a composition function it’s useful to know how composition functions work. Read the next section to learn [how composition functions work](https://docs.crossplane.io/v2.0/composition/compositions/#how-composition-functions-work) . How composition functions work[](https://docs.crossplane.io/v2.0/composition/compositions/#how-composition-functions-work) --------------------------------------------------------------------------------------------------------------------------- Each composition function is actually a [gRPC](https://grpc.io/) server. gRPC is a high performance, open source remote procedure call (RPC) framework. When you [install a function](https://docs.crossplane.io/v2.0/composition/compositions/#install-a-composition-function) Crossplane deploys the function as a gRPC server. Crossplane encrypts and authenticates all gRPC communication. You don’t have to be a gRPC expert to write a function. Crossplane’s function SDKs setup gRPC for you. It’s useful to understand how Crossplane calls your function though, and how your function should respond. sequenceDiagram User->>+API Server: Create composite resource Crossplane Pod->>+API Server: Observe composite resource Crossplane Pod->>+Function Pod: gRPC RunFunctionRequest Function Pod->>+Crossplane Pod: gRPC RunFunctionResponse loop Extra resources needed? Crossplane Pod->>+API Server: Get Extra resources Crossplane Pod->>+Function Pod: gRPC RunFunctionRequest Function Pod->>+Crossplane Pod: gRPC RunFunctionResponse end Crossplane Pod->>+API Server: Apply desired composed resources When you create or update a composite resource that uses composition functions Crossplane calls each function in the order they appear in the Composition’s pipeline. Crossplane calls each function by sending it a gRPC RunFunctionRequest. The function must respond with a gRPC RunFunctionResponse. Tip You can find detailed schemas for the RunFunctionRequest and RunFunctionResponse RPCs in the [Buf Schema Registry](https://buf.build/crossplane/crossplane/docs/main:apiextensions.fn.proto.v1beta1) . When Crossplane calls a function the first time it includes four important things in the RunFunctionRequest. 1. The **observed state** of the composite resource, and any composed resources. 2. The **desired state** of the composite resource, and any composed resources. 3. The function’s **input**. 4. The function pipeline’s **context**. A function’s main job is to update the **desired state** and return it to Crossplane. It does this by returning a RunFunctionResponse. Most composition functions read the observed state of the composite resource, and use it to add composed resources to the desired state. This tells Crossplane which composed resources it should create or update. If the function needs **required resources** to determine the desired state it can request any cluster-scoped or namespaced resource Crossplane already has access to, either by name or labels through the returned RunFunctionResponse. Crossplane then calls the function again including the requested **required resources** and the **context** returned by the Function itself alongside the same **input**, **observed** and **desired state** of the previous RunFunctionRequest. Functions can iteratively request **required resources** if needed, but to avoid endlessly looping Crossplane limits the number of iterations to 5. Crossplane considers the function satisfied as soon as the **required resources** requests become stable, so the Function returns the same exact request two times in a row. Crossplane errors if stability isn’t reached after 5 iterations. Tip A _composed_ resource is a resource created by a composite resource. Composed resources can be any kind of Kubernetes resource. ### Observed state[](https://docs.crossplane.io/v2.0/composition/compositions/#observed-state) When you create a composite resource like this one, Crossplane _observes_ it and sends it to the composition function as part of the observed state. 1apiVersion: example.crossplane.io/v1 2kind: Bucket 3metadata: 4 name: example-render 5spec: 6 bucketRegion: us-east-2 If any composed resources already exist, Crossplane observes them and sends them to your function as part of the observed state. Crossplane also observes the connection details of your composite resource and any composed resources. It sends them to your function as part of the observed state. Crossplane observes the composite resource and any composed resources once, right before it starts calling the functions in the pipeline. This means that Crossplane sends every function in the pipeline the same observed state. ### Desired state[](https://docs.crossplane.io/v2.0/composition/compositions/#desired-state) Desired state is the set of the changes the function pipeline wants to make to the composite resource and any composed resources. When a function adds composed resources to the desired state Crossplane creates them. A function can change: * The `status` of the composite resource. * The `metadata` and `spec` of any composed resource. A function can also change the connection details and readiness of the composite resource. A function indicates that the composite resource is ready by telling Crossplane whether its composed resources are ready. When the function pipeline tells Crossplane that all composed resources are ready, Crossplane marks the composite resource as ready. A function can’t change: * The `metadata` or `spec` of the composite resource. * The `status` of any composed resource. * The connection details of any composed resource. A pipeline of functions _accumulates_ desired state. This means that each function builds upon the desired state of previous functions in the pipeline. Crossplane sends a function the desired state accumulated by all previous functions in the pipeline. The function adds to or updates the desired state and then passes it on. When the last function in the pipeline has run, Crossplane applies the desired state it returns. Important A function **must** copy all desired state from its RunFunctionRequest to its RunFunctionResponse. If a function adds a resource to its desired state the next function must copy it to its desired state. If it doesn’t, Crossplane doesn’t apply the resource. If the resource exists, Crossplane deletes it. A function can _intentionally_ choose not to copy parts of the desired state. For example a function may choose not to copy a desired resource to prevent that resource from existing. Most function SDKs handle copying desired state automatically. A function should only add the fields it cares about to the desired state. It should add these fields every time Crossplane calls it. If a function adds a field to the desired state once, but doesn’t add it the next time it’s called, Crossplane deletes the field. The same is true for composed resources. If a function adds a composed resource to the desired state, but doesn’t add it the next time it’s called, Crossplane deletes the composed resource. Tip Crossplane uses [server side apply](https://kubernetes.io/docs/reference/using-api/server-side-apply/) to apply the desired state returned by a function pipeline. In server side apply terminology, the desired state is a _fully specified intent_. For example, if all a function wants is to make sure an S3 bucket in region `us-east-2` exists, it should add this resource to its desired composed resources. 1apiVersion: s3.aws.m.upbound.io/v1beta1 2kind: Bucket 3spec: 4 forProvider: 5 region: us-east-2 Even if the Bucket already exists and has other `spec` fields, or a `status`, `name`, `labels`, etc the function should omit them. The function should only include the fields it has an opinion about. Crossplane takes care of applying the fields the function cares about, merging them with the existing Bucket. Tip Composition functions don’t actually use YAML for desired and observed resources. This example uses YAML for illustration purposes only. ### Function input[](https://docs.crossplane.io/v2.0/composition/compositions/#function-input) If a Composition includes `input` Crossplane sends it to the function. Input is a useful way to provide extra configuration to a function. Supporting input is optional. Not all functions support input. 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: example-render 5spec: 6 compositeTypeRef: 7 apiVersion: example.crossplane.io/v1 8 kind: Bucket 9 mode: Pipeline 10 pipeline: 11 - step: patch-and-transform 12 functionRef: 13 name: function-patch-and-transform 14 input: 15 apiVersion: pt.fn.crossplane.io/v1beta1 16 kind: Resources 17 resources: 18 - name: storage-bucket 19 base: 20 apiVersion: s3.aws.m.upbound.io/v1beta1 21 kind: Bucket 22 patches: 23 - type: FromCompositeFieldPath 24 fromFieldPath: spec.bucketRegion 25 toFieldPath: spec.forProvider.region Important Crossplane doesn’t validate function input. It’s a good idea for a function to validate its own input. ### Required resources[](https://docs.crossplane.io/v2.0/composition/compositions/#required-resources) Note Crossplane v1 called this feature “extra resources.” The v2 API uses the name “required resources” and adds support for bootstrap requirements. Functions can request access to existing Kubernetes resources to help determine the desired state. Functions use this capability to read configuration from ConfigMaps, select the status of other resources, or make decisions based on existing cluster state. Functions can receive required resources in two ways: #### Bootstrap requirements[](https://docs.crossplane.io/v2.0/composition/compositions/#bootstrap-requirements) You can provide required resources in the Composition pipeline step. This approach performs better than requesting resources during function runtime: 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: app-with-config 5spec: 6 compositeTypeRef: 7 apiVersion: example.crossplane.io/v1 8 kind: App 9 mode: Pipeline 10 pipeline: 11 - step: create-deployment-from-config 12 functionRef: 13 name: crossplane-contrib-function-python 14 requirements: 15 requiredResources: 16 - requirementName: app-config 17 apiVersion: v1 18 kind: ConfigMap 19 name: app-configuration 20 namespace: default 21 input: 22 apiVersion: python.fn.crossplane.io/v1beta1 23 kind: Script 24 script: | 25 from crossplane.function import request 26 27 def compose(req, rsp): 28 observed_xr = req.observed.composite.resource 29 30 # Access the required ConfigMap using the helper function 31 config_map = request.get_required_resource(req, "app-config") 32 33 if not config_map: 34 # Fallback image if ConfigMap not found 35 image = "nginx:latest" 36 else: 37 # Read image from ConfigMap data 38 image = config_map.get("data", {}).get("image", "nginx:latest") 39 40 # Create deployment with the configured image 41 rsp.desired.resources["deployment"].resource.update({ 42 "apiVersion": "apps/v1", 43 "kind": "Deployment", 44 "metadata": { 45 "labels": {"example.crossplane.io/app": observed_xr["metadata"]["name"]}, 46 }, 47 "spec": { 48 "replicas": 2, 49 "selector": {"matchLabels": {"example.crossplane.io/app": observed_xr["metadata"]["name"]}}, 50 "template": { 51 "metadata": { 52 "labels": {"example.crossplane.io/app": observed_xr["metadata"]["name"]}, 53 }, 54 "spec": { 55 "containers": [{\ 56 "name": "app",\ 57 "image": image,\ 58 "ports": [{"containerPort": 80}]\ 59 }], 60 }, 61 }, 62 }, 63 }) #### Dynamic resource requests[](https://docs.crossplane.io/v2.0/composition/compositions/#dynamic-resource-requests) Functions can also request resources during runtime through the RunFunctionResponse. Crossplane calls the function again with the requested resources: 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: app-dynamic-config 5spec: 6 compositeTypeRef: 7 apiVersion: example.crossplane.io/v1 8 kind: App 9 mode: Pipeline 10 pipeline: 11 - step: create-deployment-from-dynamic-config 12 functionRef: 13 name: crossplane-contrib-function-python 14 input: 15 apiVersion: python.fn.crossplane.io/v1beta1 16 kind: Script 17 script: | 18 from crossplane.function import request, response 19 20 def compose(req, rsp): 21 observed_xr = req.observed.composite.resource 22 23 # Always request the ConfigMap to ensure stable requirements 24 config_name = observed_xr["spec"].get("configName", "default-config") 25 namespace = observed_xr["metadata"].get("namespace", "default") 26 27 response.require_resources( 28 rsp, 29 name="dynamic-config", 30 api_version="v1", 31 kind="ConfigMap", 32 match_name=config_name, 33 namespace=namespace 34 ) 35 36 # Check if we have the required ConfigMap 37 config_map = request.get_required_resource(req, "dynamic-config") 38 39 if not config_map: 40 # ConfigMap not found yet - Crossplane will call us again 41 return 42 43 # ConfigMap found - use the image data to create deployment 44 image = config_map.get("data", {}).get("image", "nginx:latest") 45 46 rsp.desired.resources["deployment"].resource.update({ 47 "apiVersion": "apps/v1", 48 "kind": "Deployment", 49 "metadata": { 50 "labels": {"example.crossplane.io/app": observed_xr["metadata"]["name"]}, 51 }, 52 "spec": { 53 "replicas": 2, 54 "selector": {"matchLabels": {"example.crossplane.io/app": observed_xr["metadata"]["name"]}}, 55 "template": { 56 "metadata": { 57 "labels": {"example.crossplane.io/app": observed_xr["metadata"]["name"]}, 58 }, 59 "spec": { 60 "containers": [{\ 61 "name": "app",\ 62 "image": image,\ 63 "ports": [{"containerPort": 80}]\ 64 }], 65 }, 66 }, 67 }, 68 }) Tip Use bootstrap requirements when possible for better performance. Dynamic requests require more function calls and work best when the required resources depend on the observed state or earlier function results. Functions can request resources by: * **Name**: `name: "my-configmap"` for a specific resource * **Labels**: `matchLabels: {"env": "prod"}` for multiple resources * **Namespace**: Include `namespace: "production"` for namespaced resources Crossplane limits dynamic resource requests to 5 iterations to prevent infinite loops. The function signals completion by returning the same resource requirements two iterations in a row. ### Function pipeline context[](https://docs.crossplane.io/v2.0/composition/compositions/#function-pipeline-context) Sometimes two functions in a pipeline want to share information with each other that isn’t desired state. Functions can use context for this. Any function can write to the pipeline context. Crossplane passes the context to all following functions. When Crossplane has called all functions it discards the pipeline context. ### Function response cache[](https://docs.crossplane.io/v2.0/composition/compositions/#function-response-cache) Note Function response caching is an alpha feature. Enable it by setting the `--enable-function-response-cache` feature flag. Crossplane can cache function responses to improve performance by reducing repeated function calls. When enabled, Crossplane caches responses from composition functions that include a time to live (TTL) value. The cache works by: * Storing function responses on disk based on a hash of the request * Only caching responses with a nonzero TTL * Automatically removing expired cache entries * Reusing cached responses for identical requests until they expire This feature helps functions that: * Perform expensive computations or external API calls * Return stable results for the same inputs * Include appropriate TTL values in their responses #### Cache configuration[](https://docs.crossplane.io/v2.0/composition/compositions/#cache-configuration) Control the cache behavior with these Crossplane pod arguments: * `--xfn-cache-max-ttl` - Maximum cache duration (default: 24 hours) The cache stores files in the `/cache/xfn/` directory in the Crossplane pod. For better performance, consider using an in-memory cache by mounting an emptyDir volume with `medium: Memory`. --- # Crossplane Pods · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/pods/#) [master](https://docs.crossplane.io/master/guides/pods/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/pods/) [v1.20](https://docs.crossplane.io/v1.20/concepts/pods/) [v1.19](https://docs.crossplane.io/v1.19/concepts/pods/) Crossplane Pods =============== On this page **On this page** * * * The base Crossplane installation consists of two pods, the `crossplane` pod and the `crossplane-rbac-manager` pod. Both pods install in the `crossplane-system` namespace by default. Crossplane pod[](https://docs.crossplane.io/v2.0/guides/pods/#crossplane-pod) ------------------------------------------------------------------------------ ### Init container[](https://docs.crossplane.io/v2.0/guides/pods/#init-container) Before starting the core Crossplane container an _init_ container runs. The init container installs the core Crossplane [Custom Resource Definitions](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#customresourcedefinitions) (`CRDs`), configures Crossplane webhooks and installs any supplied Providers or Configurations. Tip The Kubernetes documentation contains more information about [init containers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) . The settings the init container sets include installing Provider or Configuration packages with Crossplane, customizing the namespace Crossplane installs in and defining webhook configurations. The core CRDs installed by the init container include: * CompositeResourceDefinitions, Compositions, Configurations and Providers * Locks to manage package dependencies * DeploymentRuntimeConfigs to apply settings to installed Providers and Functions Note The [Install Crossplane](https://docs.crossplane.io/v2.0/get-started/install/) section has more information about customizing the Crossplane install. The status `Init` on the Crossplane pod is the init container running. 1kubectl get pods -n crossplane-system 2NAME READY STATUS RESTARTS AGE 3crossplane-9f6d5cd7b-r9j8w 0/1 Init:0/1 0 6s The init container completes and starts the Crossplane core container automatically. 1kubectl get pods -n crossplane-system 2NAME READY STATUS RESTARTS AGE 3crossplane-9f6d5cd7b-r9j8w 1/1 Running 0 15s ### Core container[](https://docs.crossplane.io/v2.0/guides/pods/#core-container) The main Crossplane container, called the _core_ container, enforces the desired state of Crossplane resources, manages leader elections and process webhooks. Note The Crossplane pod only reconciles core Crossplane components, including composite resources. Providers are responsible for reconciling their managed resources. #### Reconcile loop[](https://docs.crossplane.io/v2.0/guides/pods/#reconcile-loop) The core container operates on a _reconcile loop_, constantly checking the status of deployed resources and correcting any “drift.” After checking a resource Crossplane waits some time and checks again. Crossplane monitors resources through a Kubernetes [_watch_](https://kubernetes.io/docs/reference/using-api/api-concepts/#efficient-detection-of-changes) or through periodic polling. Some resources may be both watched and polled. Crossplane requests that the API server notifies Crossplane of any changes on objects. This notification tool is a _watch_. Watched objects include Providers, managed resources and CompositeResourceDefinitions. For objects that Kubernetes can’t provide a watch for, Crossplane periodically poll the resource to find it’s state. The default polling rate is one minute. Change the polling rate with the `--poll-interval` pod argument. Reducing the poll-interval value causes Crossplane to poll resources more frequently. This increases the load of the Crossplane pod and results in more frequent provider API calls. Increasing the poll-interval causes Crossplane to poll resources less frequently. This increases the maximum time until Crossplane discovers changes in the cloud provider that require updating. Managed resources use polling. Note Managed resources watch for Kubernetes events like deletion or changes to their `spec`. Managed resources rely on polling to detect changes in the external system. Crossplane double-checks all resources to confirm they’re in the desired state. Crossplane does this every one hour by default. Use the `--sync-interval` Crossplane pod argument to change this interval. The `--max-reconcile-rate` rate defines the rate, in times per second, Crossplane reconciles resources. Reducing the `--max-reconcile-rate`, or making it smaller, reduces CPU resources Crossplane uses, but increases the amount of time until changed resources are fully synced. Increasing the `--max-reconcile-rate`, or making it larger, increases the CPU resources Crossplane uses but allows Crossplane to reconcile all resources faster. Important Most Providers use their own `--max-reconcile-rate`. This determines the same settings for Providers and their managed resources. Applying the `--max-reconcile-rate` to Crossplane only controls the rate for core Crossplane resources. ##### Enable real time Compositions[](https://docs.crossplane.io/v2.0/guides/pods/#enable-real-time-compositions) With real time compositions enabled Crossplane watches every composed resource with a Kubernetes watch. Crossplane receives events from the Kubernetes API server when a composed resource changes. For example, when a provider sets the `Ready` condition to `true`. Important Real time compositions are a beta feature. Crossplane enables beta features by default. With real time compositions enabled, Crossplane doesn’t use the `--poll-interval` settings. Enable real time compositions support by [changing the Crossplane pod setting](https://docs.crossplane.io/v2.0/guides/pods/#change-pod-settings) and enabling `--enable-realtime-compositions` argument. 1$ kubectl edit deployment crossplane --namespace crossplane-system 2apiVersion: apps/v1 3kind: Deployment 4spec: 5# Removed for brevity 6 template: 7 spec: 8 containers: 9 - args: 10 - core 11 - start 12 - --enable-realtime-compositions Tip The [Crossplane install guide](https://docs.crossplane.io/v2.0/get-started/install/#feature-flags) describes enabling feature flags like `–enable-realtime-compositions` with Helm. ##### Reconcile retry rate[](https://docs.crossplane.io/v2.0/guides/pods/#reconcile-retry-rate) The `--max-reconcile-rate` setting configures the number of times per second Crossplane or a provider attempts to correct a resource. The default value is 10 times per second. All core Crossplane components share the reconcile rate. Each Provider implements their own max reconcile rate setting. ##### Number of reconcilers[](https://docs.crossplane.io/v2.0/guides/pods/#number-of-reconcilers) The second value `--max-reconcile-rate` defines is the number of resources that Crossplane can reconcile at once. If there are more resources than the configured `--max-reconcile-rate` the remaining resources must wait until Crossplane reconciles a an existing resource. Read the [Change Pod Settings](https://docs.crossplane.io/v2.0/guides/pods/#change-pod-settings) section for instructions on applying these settings. RBAC manager pod[](https://docs.crossplane.io/v2.0/guides/pods/#rbac-manager-pod) ---------------------------------------------------------------------------------- The Crossplane RBAC manager pod automates required Kubernetes RBAC permissions for Crossplane and Crossplane Providers. Note Crossplane installs and enables the RBAC manager by default. Disabling the RBAC manager requires manual Kubernetes permissions definitions for proper Crossplane operations. The [RBAC manager design document](https://github.com/crossplane/crossplane/blob/main/design/design-doc-rbac-manager.md) provides more comprehensive details on the Crossplane RBAC requirements. ### Disable the RBAC manager[](https://docs.crossplane.io/v2.0/guides/pods/#disable-the-rbac-manager) Disable the RBAC manager after installation by deleting the `crossplane-rbac-manager` deployment from the `crossplane-system` namespace. Disable the RBAC manager before installation by editing the Helm `values.yaml` file, setting `rbacManager.deploy` to `false`. Note Instructions for changing Crossplane pod settings during installation are in the [Crossplane Install](https://docs.crossplane.io/v2.0/get-started/install/) section. ### RBAC init container[](https://docs.crossplane.io/v2.0/guides/pods/#rbac-init-container) The RBAC manager requires the `CompositeResourceDefinition` and `ProviderRevision` resources to be available before starting. The RBAC manager init container waits for these resources before starting the main RBAC manager container. ### RBAC manager container[](https://docs.crossplane.io/v2.0/guides/pods/#rbac-manager-container) The RBAC manager container preforms the following tasks: * creating and binding RBAC roles to Provider ServiceAccounts, allowing them to control their managed resources * allowing the `crossplane` ServiceAccount to create managed resources * creating ClusterRoles to access Crossplane resources in all namespaces Use the [ClusterRoles](https://docs.crossplane.io/v2.0/guides/pods/#crossplane-clusterroles) to grant access to all Crossplane resources in the cluster. #### Crossplane ClusterRoles[](https://docs.crossplane.io/v2.0/guides/pods/#crossplane-clusterroles) The RBAC manager creates four Kubernetes ClusterRoles. These Roles grant permissions over cluster wide Crossplane resources. ##### crossplane-admin[](https://docs.crossplane.io/v2.0/guides/pods/#crossplane-admin) The `crossplane-admin` ClusterRole has the following permissions: * full access to all Crossplane types * full access to all secrets and namespaces (even those unrelated to Crossplane) * read-only access to all cluster RBAC roles, CustomResourceDefinitions and events * ability to bind RBAC roles to other entities. View the full RBAC policy with 1kubectl describe clusterrole crossplane-admin ##### crossplane-edit[](https://docs.crossplane.io/v2.0/guides/pods/#crossplane-edit) The `crossplane-edit` ClusterRole has the following permissions: * full access to all Crossplane types * full access to all secrets (even those unrelated to Crossplane) * read-only access to all namespaces and events (even those unrelated to Crossplane). View the full RBAC policy with 1kubectl describe clusterrole crossplane-edit ##### crossplane-view[](https://docs.crossplane.io/v2.0/guides/pods/#crossplane-view) The `crossplane-view` ClusterRole has the following permissions: * read-only access to all Crossplane types * read-only access to all namespaces and events (even those unrelated to Crossplane). View the full RBAC policy with 1kubectl describe clusterrole crossplane-view Leader election[](https://docs.crossplane.io/v2.0/guides/pods/#leader-election) -------------------------------------------------------------------------------- By default only a single Crossplane pod runs in a cluster. If more than one Crossplane pod runs both pods try to manage Crossplane resources. To prevent conflicts Crossplane uses a _leader election_ to have a single pod in control at a time. Other Crossplane pods standby until the leader fails. Note It’s possible to run more than one Crossplane or RBAC manager pods for redundancy. Kubernetes restarts any failed Crossplane or RBAC manager pods. Redundant pods aren’t required in most deployments. Both the Crossplane pod and the RBAC manager pods support leader elections. Enable leader elections with the `--leader-election` pod argument. Warning Running multiple Crossplane pods without leader election is unsupported. Change pod settings[](https://docs.crossplane.io/v2.0/guides/pods/#change-pod-settings) ---------------------------------------------------------------------------------------- Change Crossplane pod settings either before installing Crossplane by editing the Helm `values.yml` file or after installation by editing the `Deployment`. The full list of [configuration options](https://docs.crossplane.io/v2.0/get-started/install/#customize-the-crossplane-helm-chart) and [feature flags](https://docs.crossplane.io/v2.0/get-started/install/#feature-flags) are available in the [Crossplane Install](https://docs.crossplane.io/v2.0/get-started/install/) section. Note Instructions for changing Crossplane pod settings during installation are in the [Crossplane Install](https://docs.crossplane.io/v2.0/get-started/install/) section. ### Edit the deployment[](https://docs.crossplane.io/v2.0/guides/pods/#edit-the-deployment) Note These settings apply to both the `crossplane` and `rbac-manager` pods and `Deployments`. To change the settings of an installed Crossplane pod, edit the `crossplane` deployment in the `crossplane-system` namespace with the command `kubectl edit deployment crossplane --namespace crossplane-system` Warning Updating the Crossplane deployment restarts the Crossplane pod. Add Crossplane pod arguments to the `spec.template.spec.containers[].args` section of the deployment. For example, to change the `sync-interval` add `--sync-interval=30m`. 1kubectl edit deployment crossplane --namespace crossplane-system 2apiVersion: apps/v1 3kind: Deployment 4spec: 5# Removed for brevity 6 template: 7 spec: 8 containers: 9 - args: 10 - core 11 - start 12 - --sync-interval=30m ### Use environmental variables[](https://docs.crossplane.io/v2.0/guides/pods/#use-environmental-variables) The core Crossplane pod checks for configured environmental variables at startup to change default settings. The full list of configurable environmental variables are available in the [Crossplane Install](https://docs.crossplane.io/v2.0/get-started/install/) section. --- # Configurations · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/packages/configurations/#) [master](https://docs.crossplane.io/master/packages/configurations/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/packages/configurations/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Configurations ============== On this page **On this page** * * * A _Configuration_ package is an [OCI container image](https://opencontainers.org/) containing a collection of [Compositions](https://docs.crossplane.io/v2.0/composition/compositions/) , [Composite Resource Definitions](https://docs.crossplane.io/v2.0/composition/composite-resource-definitions/) and any required [Providers](https://docs.crossplane.io/v2.0/packages/providers/) or [Functions](https://docs.crossplane.io/v2.0/packages/functions/) . Configuration packages make your Crossplane configuration fully portable. Important Crossplane Providers and Functions are also Crossplane packages. This document describes how to install and manage configuration packages. Refer to the [Provider](https://docs.crossplane.io/v2.0/packages/providers/) and [Functions](https://docs.crossplane.io/v2.0/packages/functions/) chapters for details on their usage of packages. Install a configuration[](https://docs.crossplane.io/v2.0/packages/configurations/#install-a-configuration) ------------------------------------------------------------------------------------------------------------ Install a Configuration with a Crossplane `Configuration` object by setting the `spec.package` value to the location of the configuration package. For example to install the [Getting Started Configuration](https://github.com/crossplane-contrib/configuration-quickstart) , 1apiVersion: pkg.crossplane.io/v1 2kind: Configuration 3metadata: 4 name: configuration-quickstart 5spec: 6 package: xpkg.crossplane.io/crossplane-contrib/configuration-quickstart:v0.1.0 Tip Crossplane supports installations with image digests instead of tags to get deterministic and repeatable installations. 1apiVersion: pkg.crossplane.io/v1 2kind: Configuration 3metadata: 4 name: configuration-quickstart 5spec: 6 package: xpkg.crossplane.io/crossplane-contrib/configuration-quickstart@sha256:ef9795d146190637351a5c5848e0bab5e0c190fec7780f6c426fbffa0cb68358 Crossplane installs the Compositions, Composite Resource Definitions and Providers listed in the Configuration. ### Install with Helm[](https://docs.crossplane.io/v2.0/packages/configurations/#install-with-helm) Crossplane supports installing Configurations during an initial Crossplane installation with the Crossplane Helm chart. Use the `--set configuration.packages` argument with `helm install`. For example, to install the Getting Started configuration, 1helm install crossplane \ 2crossplane-stable/crossplane \ 3--namespace crossplane-system \ 4--create-namespace \ 5--set configuration.packages='{xpkg.crossplane.io/crossplane-contrib/configuration-quickstart:v0.1.0}' ### Install offline[](https://docs.crossplane.io/v2.0/packages/configurations/#install-offline) Installing Crossplane packages offline requires a local container registry, such as [Harbor](https://goharbor.io/) to host the packages. Crossplane only supports installing packages from a container registry. Crossplane doesn’t support installing packages directly from Kubernetes volumes. ### Installation options[](https://docs.crossplane.io/v2.0/packages/configurations/#installation-options) Configurations support multiple options to change configuration package related settings. #### Configuration revisions[](https://docs.crossplane.io/v2.0/packages/configurations/#configuration-revisions) When installing a newer version of an existing Configuration Crossplane creates a new configuration revision. View the configuration revisions with `kubectl get configurationrevisions`. 1kubectl get configurationrevisions 2NAME HEALTHY REVISION IMAGE STATE DEP-FOUND DEP-INSTALLED AGE 3platform-ref-aws-1735d56cd88d True 2 xpkg.crossplane.io/crossplane-contrib/platform-ref-aws:v0.5.0 Active 2 2 46s 4platform-ref-aws-3ac761211893 True 1 xpkg.crossplane.io/crossplane-contrib/platform-ref-aws:v0.4.1 Inactive 5m13s Only a single revision is active at a time. The active revision determines the available resources, including Compositions and Composite Resource Definitions. By default Crossplane keeps only a single _Inactive_ revision. Change the number of revisions Crossplane maintains with a Configuration package `revisionHistoryLimit`. The `revisionHistoryLimit` field is an integer. The default value is `1`. Disable storing revisions by setting `revisionHistoryLimit` to `0`. For example, to change the default setting and store 10 revisions use `revisionHistoryLimit: 10`. 1apiVersion: pkg.crossplane.io/v1 2kind: Configuration 3metadata: 4 name: platform-ref-aws 5spec: 6 revisionHistoryLimit: 10 7# Removed for brevity #### Configuration package pull policy[](https://docs.crossplane.io/v2.0/packages/configurations/#configuration-package-pull-policy) Use a `packagePullPolicy` to define when Crossplane should download the Configuration package to the local Crossplane package cache. The `packagePullPolicy` options are: * `IfNotPresent` - (**default**) Only download the package if it isn’t in the cache. * `Always` - Check for new packages every minute and download any matching package that isn’t in the cache. * `Never` - Never download the package. Packages are only installed from the local package cache. Tip The Crossplane `packagePullPolicy` works like the Kubernetes container image [image pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) . Crossplane supports the use of tags and package digest hashes like Kubernetes images. For example, to `Always` download a given Configuration package use the `packagePullPolicy: Always` configuration. 1apiVersion: pkg.crossplane.io/v1 2kind: Configuration 3metadata: 4 name: platform-ref-aws 5spec: 6 packagePullPolicy: Always 7# Removed for brevity #### Revision activation policy[](https://docs.crossplane.io/v2.0/packages/configurations/#revision-activation-policy) The `Active` package revision is the package controller actively reconciling resources. By default Crossplane sets the most recently installed package revision as `Active`. Control the Configuration upgrade behavior with a `revisionActivationPolicy`. The `revisionActivationPolicy` options are: * `Automatic` - (**default**) Automatically activate the last installed configuration. * `Manual` - Don’t automatically activate a configuration. For example, to change the upgrade behavior to require manual upgrades, set `revisionActivationPolicy: Manual`. 1apiVersion: pkg.crossplane.io/v1 2kind: Configuration 3metadata: 4 name: platform-ref-aws 5spec: 6 revisionActivationPolicy: Manual 7# Removed for brevity #### Install a Configuration from a private registry[](https://docs.crossplane.io/v2.0/packages/configurations/#install-a-configuration-from-a-private-registry) Like Kubernetes uses `imagePullSecrets` to [install images from private registries](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/) , Crossplane uses `packagePullSecrets` to install Configuration packages from a private registry. Use `packagePullSecrets` to provide a Kubernetes secret to use for authentication when downloading a Configuration package. Important The Kubernetes secret must be in the same namespace as Crossplane. The `packagePullSecrets` is a list of secrets. For example, to use the secret named `example-secret` configure a `packagePullSecrets`. 1apiVersion: pkg.crossplane.io/v1 2kind: Configuration 3metadata: 4 name: platform-ref-aws 5spec: 6 packagePullSecrets: 7 - name: example-secret 8# Removed for brevity #### Ignore dependencies[](https://docs.crossplane.io/v2.0/packages/configurations/#ignore-dependencies) By default Crossplane installs any [dependencies](https://docs.crossplane.io/v2.0/packages/configurations/#manage-dependencies) listed in a Configuration package. Crossplane can ignore a Configuration package’s dependencies with `skipDependencyResolution`. Warning Most Configurations include dependencies for the required Providers. If a Configuration ignores dependencies, the required Providers must be manually installed. For example, to disable dependency resolution configure `skipDependencyResolution: true`. 1apiVersion: pkg.crossplane.io/v1 2kind: Configuration 3metadata: 4 name: platform-ref-aws 5spec: 6 skipDependencyResolution: true 7# Removed for brevity #### Automatically update dependency versions[](https://docs.crossplane.io/v2.0/packages/configurations/#automatically-update-dependency-versions) Crossplane can automatically upgrade a package’s dependency version to the minimum valid version that satisfies all the constraints. It’s an alpha feature that requires enabling with the `--enable-dependency-version-upgrades` flag. Sometimes, Crossplane requires dependency version downgrade for proceeding with installations. Suppose configuration A, which depends on package X with the constraint`>=v0.0.0`, installs on the control plane. In this case, the package manager installs the latest version of package X, such as `v3.0.0`. Later, you decide to install configuration B, which depends on package X with the constraint `<=v2.0.0`. Since version `v2.0.0`satisfies both conditions, Crossplane must downgrade package X to allow the installation of configuration B, which Crossplane disables by default. For enabling automatic dependency version downgrades, there is a configuration option as a helm value `packageManager.enableAutomaticDependencyDowngrade=true`. Downgrading a package can cause unexpected behavior, so this Crossplane disables this option by default. After enabling this option, the package manager automatically downgrades a package’s dependency version to the maximum valid version that satisfies the constraints. Note This configuration requires the `--enable-dependency-version-upgrades` flag. Please see the [configuration options](https://docs.crossplane.io/v2.0/get-started/install/#customize-the-crossplane-helm-chart) and [feature flags](https://docs.crossplane.io/v2.0/get-started/install/#feature-flags) are available in the [Crossplane Install](https://docs.crossplane.io/v2.0/get-started/install/) section for more details. Important Enabling automatic dependency downgrades may have unintended consequences, such as: 1. CRDs missing in the downgraded version, possibly leaving orphaned MRs without controllers to reconcile them. 2. Loss of data if downgraded CRD versions omit fields that you set before. 3. Changes in the CRD storage version, which may prevent package version update. #### Ignore Crossplane version requirements[](https://docs.crossplane.io/v2.0/packages/configurations/#ignore-crossplane-version-requirements) A Configuration package may require a specific or minimum Crossplane version before installing. By default, Crossplane doesn’t install a Configuration if the Crossplane version doesn’t meet the required version. Crossplane can ignore the required version with `ignoreCrossplaneConstraints`. For example, to install a Configuration package into an unsupported Crossplane version, configure `ignoreCrossplaneConstraints: true`. 1apiVersion: pkg.crossplane.io/v1 2kind: Configuration 3metadata: 4 name: platform-ref-aws 5spec: 6 ignoreCrossplaneConstraints: true 7# Removed for brevity ### Verify a configuration[](https://docs.crossplane.io/v2.0/packages/configurations/#verify-a-configuration) Verify a Configuration with `kubectl get configuration`. A working configuration reports `Installed` and `Healthy` as `True`. 1kubectl get configuration 2NAME INSTALLED HEALTHY PACKAGE AGE 3platform-ref-aws True True xpkg.crossplane.io/crossplane-contrib/configuration-quickstart:v0.1.0 54s ### Manage dependencies[](https://docs.crossplane.io/v2.0/packages/configurations/#manage-dependencies) Configuration packages may include dependencies on other packages including Functions, Providers or other Configurations. If Crossplane can’t meet the dependencies of a Configuration the Configuration reports `HEALTHY` as `False`. For example, this installation of the Getting Started Configuration is `HEALTHY: False`. 1kubectl get configuration 2NAME INSTALLED HEALTHY PACKAGE AGE 3platform-ref-aws True False xpkg.crossplane.io/crossplane-contrib/configuration-quickstart:v0.1.0 71s To see more information on why the Configuration isn’t `HEALTHY` use `kubectl describe configurationrevisions`. 1kubectl describe configurationrevision 2Name: platform-ref-aws-a30ad655c769 3API Version: pkg.crossplane.io/v1 4Kind: ConfigurationRevision 5# Removed for brevity 6Spec: 7 Desired State: Active 8 Image: xpkg.crossplane.io/crossplane-contrib/configuration-quickstart:v0.1.0 9 Revision: 1 10Status: 11 Conditions: 12 Last Transition Time: 2023-10-06T20:08:14Z 13 Reason: UnhealthyPackageRevision 14 Status: False 15 Type: Healthy 16 Controller Ref: 17 Name: 18Events: 19 Type Reason Age From Message 20 ---- ------ ---- ---- ------- 21 Warning LintPackage 29s (x2 over 29s) packages/configurationrevision.pkg.crossplane.io incompatible Crossplane version: package isn't compatible with Crossplane version (v1.12.0) The `Events` show a `Warning` with a message that the current version of Crossplane doesn’t meet the Configuration package requirements. Create a configuration[](https://docs.crossplane.io/v2.0/packages/configurations/#create-a-configuration) ---------------------------------------------------------------------------------------------------------- Crossplane Configuration packages are [OCI container images](https://opencontainers.org/) containing one or more YAML files. Important Configuration packages are fully OCI compliant. Any tool that builds OCI images can build Configuration packages. It’s strongly recommended to use the Crossplane command-line tool to provide error checking and formatting to Crossplane package builds. Read the [Crossplane package specification](https://github.com/crossplane/crossplane/blob/main/contributing/specifications/xpkg.md) for package requirements when building packages with third-party tools. A Configuration package requires a `crossplane.yaml` file and may include Composition and CompositeResourceDefinition files. ### The crossplane.yaml file[](https://docs.crossplane.io/v2.0/packages/configurations/#the-crossplaneyaml-file) To build a Configuration package using the Crossplane CLI, create a file named `crossplane.yaml`. The `crossplane.yaml` file defines the requirements and name of the Configuration. Important The Crossplane CLI only supports a file named `crossplane.yaml`. Configuration package uses the `meta.pkg.crossplane.io` Crossplane API group. Specify any other Configurations, Functions or Providers in the `dependsOn` list. Optionally, you can require a specific or minimum package version with the `version` option. You can also define a specific or minimum version of Crossplane for this Configuration with the `crossplane.version` option. Note Defining the `crossplane` object or required versions is optional. 1$ cat crossplane.yaml 2apiVersion: meta.pkg.crossplane.io/v1alpha1 3kind: Configuration 4metadata: 5 name: test-configuration 6spec: 7 dependsOn: 8 - apiVersion: pkg.crossplane.io/v1 9 kind: Provider 10 package: xpkg.crossplane.io/crossplane-contrib/provider-aws 11 version: ">=v0.36.0" 12 crossplane: 13 version: ">=v1.12.1-0" ### Build the package[](https://docs.crossplane.io/v2.0/packages/configurations/#build-the-package) Create the package using the [Crossplane CLI](https://docs.crossplane.io/v2.0/cli/) command `crossplane xpkg build --package-root=`. Where the `` is the directory containing the `crossplane.yaml` file and any Composition or CompositeResourceDefinition YAML files. The CLI recursively searches for `.yml` or `.yaml` files in the directory to include in the package. Important You must ignore any other YAML files with `--ignore=`. For example, `crossplane xpkg build --package-root=test-directory --ignore=".tmp/*"`. Including YAML files that aren’t Compositions or CompositeResourceDefinitions isn’t supported. By default, Crossplane creates a `.xpkg` file of the Configuration name and a SHA-256 hash of the package contents. For example, a `Configuration` named `test-configuration`. The Crossplane CLI builds a package named `test-configuration-e8c244f6bf21.xpkg`. 1apiVersion: meta.pkg.crossplane.io/v1alpha1 2kind: Configuration 3metadata: 4 name: test-configuration 5# Removed for brevity Specify the output file with `--package-file=.xpkg` option. For example, to build a package from a directory named `test-directory` and generate a package named `test-package.xpkg` in the current working directory, use the command: 1crossplane xpkg build --package-root=test-directory --package-file=test-package.xpkg 1ls -1 ./ 2test-directory 3test-package.xpkg --- # Disabling Unused Managed Resources · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/#) [master](https://docs.crossplane.io/master/guides/disabling-unused-managed-resources/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Disabling Unused Managed Resources ================================== This is an alpha feature. Crossplane may change or drop this feature at any time. This feature was introduced in v2. For more information read the [Crossplane feature lifecycle](https://docs.crossplane.io/v2.0/learn/feature-lifecycle/) . On this page **On this page** * * * Important This guide uses [managed resource definitions](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/) and [managed resource activation policies](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/) , which Crossplane v2.0+ enables by default. To disable this behavior, set `--enable-custom-to-managed-resource-conversion=false` when installing Crossplane. Large Crossplane providers can install 100+ managed resource CRDs, consuming significant cluster resources even when you only need one or two resource types. This guide shows how to use [ManagedResourceDefinitions](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/) and [ManagedResourceActivationPolicies](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/) to install only the provider resources you actually need. Before you begin[](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/#before-you-begin) ---------------------------------------------------------------------------------------------------------------- This guide requires: * Crossplane v2.0+ installed in your cluster * A provider with `safe-start` capability (this guide uses `provider-aws-ec2:v2.0.0`) * Basic familiarity with Kubernetes and Crossplane concepts Important ManagedResourceDefinitions and ManagedResourceActivationPolicies are alpha features in Crossplane v2.0+. The problem: Resource overhead[](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/#the-problem-resource-overhead) ------------------------------------------------------------------------------------------------------------------------------------------- Installing a large cloud provider in Crossplane creates hundreds of CRDs: 1# Before selective activation - provider-aws-ec2 installs ~200 CRDs 2kubectl get crds | grep aws.crossplane.io | wc -l 3# Output: 200 4 5# Each CRD consumes ~3 MiB of API server memory 6# 200 CRDs × 3 MiB = 600 MiB of memory usage Most users only need a small subset of these resources. Selective activation lets you install just what you need. Step 1: Disable automatic activation[](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/#step-1-disable-automatic-activation) ------------------------------------------------------------------------------------------------------------------------------------------------------- By default, the Crossplane Helm chart creates an activation policy that enables all provider resources. To use selective activation, disable this default behavior. ### Option A: Helm installation[](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/#option-a-helm-installation) 1helm install crossplane crossplane-stable/crossplane \ 2 --namespace crossplane-system \ 3 --create-namespace \ 4 --set provider.defaultActivations={} ### Option B: Existing installation[](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/#option-b-existing-installation) Delete the default activation policy: 1kubectl delete managedresourceactivationpolicy default Step 2: Install your provider[](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/#step-2-install-your-provider) ----------------------------------------------------------------------------------------------------------------------------------------- Install your provider as normal. Crossplane automatically converts the provider’s CRDs to ManagedResourceDefinitions: 1apiVersion: pkg.crossplane.io/v1 2kind: Provider 3metadata: 4 name: provider-aws-ec2 5spec: 6 package: xpkg.crossplane.io/provider-aws-ec2:v2.0.0 Save this as `provider.yaml` and apply it: 1kubectl apply -f provider.yaml 2 3# Wait for provider to be ready 4kubectl wait --for=condition=Healthy provider/provider-aws-ec2 --timeout=5m Step 3: Verify Crossplane created MRDs[](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/#step-3-verify-crossplane-created-mrds) ----------------------------------------------------------------------------------------------------------------------------------------------------------- After the provider installs, check ManagedResourceDefinitions that Crossplane created in inactive state: 1# List ManagedResourceDefinitions 2kubectl get managedresourcedefinitions 3 4# Check their states (should be "Inactive") 5kubectl get mrds -o jsonpath='{.items[*].spec.state}' \ 6 | tr ' ' '\n' | sort | uniq -c 7# 200 Inactive Notice that Crossplane didn’t create any CRDs yet: 1kubectl get crds | grep ec2.aws.m.crossplane.io 2# No output - CRDs don't exist until MRDs are activated Step 4: Create an activation policy[](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/#step-4-create-an-activation-policy) ----------------------------------------------------------------------------------------------------------------------------------------------------- Create a ManagedResourceActivationPolicy to selectively activate only the resources you need: 1apiVersion: apiextensions.crossplane.io/v1alpha1 2kind: ManagedResourceActivationPolicy 3metadata: 4 name: my-app-resources 5spec: 6 activate: 7 - instances.ec2.aws.m.crossplane.io # EC2 instances for compute 8 - securitygroups.ec2.aws.m.crossplane.io # Security groups for networking 9 - vpcs.ec2.aws.m.crossplane.io # VPCs for isolation Save this as `activation-policy.yaml` and apply it: 1kubectl apply -f activation-policy.yaml Step 5: Verify selective activation[](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/#step-5-verify-selective-activation) ----------------------------------------------------------------------------------------------------------------------------------------------------- Check that Crossplane activated only the specified resources: 1# Check MRD states - only some should be Active now 2kubectl get mrds \ 3 -o jsonpath='{range .items[*]}{.metadata.name}: {.spec.state}{"\n"}{end}' \ 4 | grep Active 5# instances.ec2.aws.m.crossplane.io: Active 6# securitygroups.ec2.aws.m.crossplane.io: Active 7# vpcs.ec2.aws.m.crossplane.io: Active 8 9# Verify Crossplane created corresponding CRDs 10kubectl get crds | grep ec2.aws.m.crossplane.io 11# instances.ec2.aws.m.crossplane.io 12# securitygroups.ec2.aws.m.crossplane.io 13# vpcs.ec2.aws.m.crossplane.io 14 15# Count CRDs from EC2 provider - should match activated MRDs 16kubectl get crds | grep ec2.aws.m.crossplane.io | wc -l 17# 3 (only the activated resources) Step 6: Measure the impact[](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/#step-6-measure-the-impact) ----------------------------------------------------------------------------------------------------------------------------------- Check the significant reduction in resource overhead: 1# Count CRDs from EC2 provider - should be much lower than 200 2kubectl get crds | grep aws.crossplane.io | wc -l 3# 3 CRDs (99% reduction from 200) 4 5# Calculate memory savings 6echo "197 CRDs saved × 3 MiB = 591 MiB saved (99% reduction)" 7 8# Verify inactive MRDs still exist but consume minimal resources 9kubectl get mrds \ 10 -o jsonpath='{.items[?(@.spec.state=="Inactive")]..metadata.name}' | wc -w 11# 197 inactive MRDs (~20 MiB total overhead vs 600 MiB for active CRDs) 12 13# Check total MRDs (active + inactive) 14kubectl get mrds | wc -l 15# 200 total MRDs (3 active, 197 inactive) The selective activation provides massive resource savings while maintaining full capability for the resources you actually use. Next steps[](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/#next-steps) ---------------------------------------------------------------------------------------------------- * Learn more about [ManagedResourceDefinitions](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/) for detailed concepts and troubleshooting * Explore [ManagedResourceActivationPolicies](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/) for advanced activation strategies and best practices * Check the [API reference](https://docs.crossplane.io/v2.0/api/) for complete schema documentation --- # Implementing safe-start in Providers · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/implementing-safe-start/#) [master](https://docs.crossplane.io/master/guides/implementing-safe-start/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/implementing-safe-start/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Implementing safe-start in Providers ==================================== This is an alpha feature. Crossplane may change or drop this feature at any time. This feature was introduced in v2. For more information read the [Crossplane feature lifecycle](https://docs.crossplane.io/v2.0/learn/feature-lifecycle/) . On this page **On this page** * * * This guide shows provider developers how to implement safe-start capability in their Crossplane providers. safe-start enables [disabling unused managed resources](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/) through ManagedResourceDefinitions, improving performance and reducing resource overhead. Important safe-start requires Crossplane v2.0+ and crossplane-runtime v2.0+. Implementing safe-start involves code changes that affect provider startup behavior. What safe-start provides[](https://docs.crossplane.io/v2.0/guides/implementing-safe-start/#what-safe-start-provides) --------------------------------------------------------------------------------------------------------------------- safe-start changes how your provider handles CRD installation: **Without safe-start:** * Providers create all managed resource CRDs when installed * Users get all resources even if they only need one or two * Higher memory usage and API server load **With safe-start:** * Providers create ManagedResourceDefinitions but CRDs only when activated * Users activate only needed resources through ManagedResourceActivationPolicies * Significant reduction in cluster resource overhead Prerequisites[](https://docs.crossplane.io/v2.0/guides/implementing-safe-start/#prerequisites) ----------------------------------------------------------------------------------------------- Before implementing safe-start: * Provider built with crossplane-runtime v2.0+ * Understanding of [ManagedResourceDefinitions](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-definitions/) * Test environment with Crossplane v2.0+ Implementation steps[](https://docs.crossplane.io/v2.0/guides/implementing-safe-start/#implementation-steps) ------------------------------------------------------------------------------------------------------------- ### Step 1: Declare safe-start capability[](https://docs.crossplane.io/v2.0/guides/implementing-safe-start/#step-1-declare-safe-start-capability) Add safe-start to your provider package metadata: 1# package/crossplane.yaml 2apiVersion: meta.pkg.crossplane.io/v1 3kind: Provider 4metadata: 5 name: provider-example 6spec: 7 capabilities: 8 - safe-start ### Step 2: Add required imports[](https://docs.crossplane.io/v2.0/guides/implementing-safe-start/#step-2-add-required-imports) Update your main.go imports (see [crossplane-runtime godoc](https://pkg.go.dev/github.com/crossplane/crossplane-runtime/v2) for full API reference): 1import ( 2 // existing imports... 3 4 "k8s.io/apimachinery/pkg/runtime/schema" 5 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 6 7 "github.com/crossplane/crossplane-runtime/v2/pkg/controller" 8 "github.com/crossplane/crossplane-runtime/v2/pkg/gate" 9 "github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/customresourcesgate" 10) ### Step 3: Initialize the gate[](https://docs.crossplane.io/v2.0/guides/implementing-safe-start/#step-3-initialize-the-gate) Add gate initialization in your main function: 1func main() { 2 // existing setup code... 3 4 o := controller.Options{ 5 // existing options... 6 Gate: new(gate.Gate[schema.GroupVersionKind]), 7 } 8 9 // Add CustomResourceDefinition to scheme for gate controller 10 if err := apiextensionsv1.AddToScheme(mgr.GetScheme()); err != nil { 11 panic(err) 12 } 13 14 // Setup controllers 15 if err := yourprovider.Setup(mgr, o); err != nil { 16 panic(err) 17 } 18 19 // Setup the CRD gate controller 20 if err := customresourcesgate.Setup(mgr, o); err != nil { 21 panic(err) 22 } 23 24 // start manager... 25} ### Step 4: Use gated controller setup[](https://docs.crossplane.io/v2.0/guides/implementing-safe-start/#step-4-use-gated-controller-setup) Create a gated setup function for each managed resource controller: 1// SetupGated registers controller setup with the gate, waiting for the 2// required CRD 3func SetupGated(mgr ctrl.Manager, o controller.Options) error { 4 o.Gate.Register(func() { 5 if err := Setup(mgr, o); err != nil { 6 panic(err) 7 } 8 }, v1alpha1.MyResourceGroupVersionKind) 9 return nil 10} 11 12// Setup is your existing controller setup function (unchanged) 13func Setup(mgr ctrl.Manager, o controller.Options) error { 14 // existing controller setup code... 15} ### Step 5: Update controller registration[](https://docs.crossplane.io/v2.0/guides/implementing-safe-start/#step-5-update-controller-registration) Change your controller setup to use the gated versions: 1// internal/controller/controller.go 2func Setup(mgr ctrl.Manager, o controller.Options) error { 3 for _, setup := range []func(ctrl.Manager, controller.Options) error{ 4 myresource.SetupGated, // Changed from myresource.Setup 5 // other gated setups... 6 } { 7 if err := setup(mgr, o); err != nil { 8 return err 9 } 10 } 11 return nil 12} Implementation details[](https://docs.crossplane.io/v2.0/guides/implementing-safe-start/#implementation-details) ----------------------------------------------------------------------------------------------------------------- The safe-start implementation uses a “gate” pattern: 1. **Gate initialization**: Creates a gate that tracks CRD readiness 2. **Controller registration**: Controllers register with the gate, specifying which CRDs they need 3. **CRD monitoring**: The `customresourcesgate` controller watches for CRD creation/deletion 4. **Delayed startup**: Controllers only start when their required CRDs become active Testing your implementation[](https://docs.crossplane.io/v2.0/guides/implementing-safe-start/#testing-your-implementation) --------------------------------------------------------------------------------------------------------------------------- Test safe-start behavior with this basic workflow: 1# Install Crossplane v2.0+ 2helm install crossplane crossplane-stable/crossplane \ 3 --namespace crossplane-system \ 4 --set provider.defaultActivations={} 5 6# Install your provider 7kubectl apply -f provider.yaml 8 9# Check that MRDs are created but inactive 10kubectl get mrds 11# All should show STATE: Inactive 12 13# No CRDs should exist yet 14kubectl get crds | grep yourprovider.m.crossplane.io 15# Should return no results 16 17# Create activation policy 18kubectl apply -f - < ### CRDs don’t appear[](https://docs.crossplane.io/v2.0/guides/implementing-safe-start/#crds-dont-appear) **Cause**: MRDs might not activate or activation policy doesn’t match. **Solution**: verify activation policy patterns match MRD names: 1kubectl get mrds 2kubectl get mrap -o yaml Migration considerations[](https://docs.crossplane.io/v2.0/guides/implementing-safe-start/#migration-considerations) --------------------------------------------------------------------------------------------------------------------- When adding safe-start to existing providers: * **Existing installations**: Continue working as expected (no CRD changes) * **New installations**: Start with inactive MRDs, require activation policies Next steps[](https://docs.crossplane.io/v2.0/guides/implementing-safe-start/#next-steps) ----------------------------------------------------------------------------------------- * Test your safe-start implementation with different activation patterns * Update provider documentation to explain activation requirements * Consider the user experience for providers that now require activation policies Learn more about the user experience in [disabling unused managed resources](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/) . --- # Upgrade Crossplane · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/upgrade-crossplane/#) [master](https://docs.crossplane.io/master/guides/upgrade-crossplane/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/upgrade-crossplane/) [v1.20](https://docs.crossplane.io/v1.20/software/upgrade/) [v1.19](https://docs.crossplane.io/v1.19/software/upgrade/) Upgrade Crossplane ================== On this page **On this page** * * * The recommended upgrade method for an existing Crossplane install is to use [Helm](http://helm.io/) . Important Always upgrade Crossplane **one minor version at a time**, using the most recent patch version available for each. For example, if you are on `v1.18` and want to upgrade to `v2.0`, you should first upgrade to `v1.19`, then `v1.20`, before finally upgrading to `v2.0`. The upgrade path in this example looks like `v1.18` → `v1.19` → `v1.20` → `v2.0`. Prerequisites[](https://docs.crossplane.io/v2.0/guides/upgrade-crossplane/#prerequisites) ------------------------------------------------------------------------------------------ * [Helm](https://helm.sh/docs/intro/install/) version `v3.2.0` or later Add the Crossplane Helm repository[](https://docs.crossplane.io/v2.0/guides/upgrade-crossplane/#add-the-crossplane-helm-repository) ------------------------------------------------------------------------------------------------------------------------------------ Verify Helm has the Crossplane repository. 1helm repo add crossplane-stable https://charts.crossplane.io/stable Update the Helm repository[](https://docs.crossplane.io/v2.0/guides/upgrade-crossplane/#update-the-helm-repository) -------------------------------------------------------------------------------------------------------------------- Update the local Crossplane Helm chart with `helm repo update`. 1helm repo update Important Upgrading Crossplane without updating the Helm chart installs the last version available in the locally cached Helm chart. Upgrade Crossplane[](https://docs.crossplane.io/v2.0/guides/upgrade-crossplane/#upgrade-crossplane) ---------------------------------------------------------------------------------------------------- Upgrade Crossplane with `helm upgrade`, providing the Crossplane namespace. By default, Crossplane installs into the `crossplane-system` namespace. 1helm upgrade crossplane --namespace crossplane-system crossplane-stable/crossplane Helm preserves any arguments or flags originally used when installing Crossplane. Crossplane uses any new default behaviors unless they’re changed in the `helm upgrade` command. Override new defaults by [customizing the Helm chart](https://docs.crossplane.io/v2.0/get-started/install/#customize-the-crossplane-helm-chart) with the upgrade command. --- # Install Crossplane from source code · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/install-from-source/#) [master](https://docs.crossplane.io/master/guides/install-from-source/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/install-from-source/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Install Crossplane from source code =================================== On this page **On this page** * * * Building Crossplane from the source code gives you complete control over the build and installation process. You build the Crossplane container image and Helm chart directly from the source code, push the image to your own registry, and install to your Kubernetes cluster. Important Installing Crossplane from source is an advanced installation path for users who require complete control over the build and deployment process. Most users should follow the [standard installation instructions](https://docs.crossplane.io/v2.0/get-started/install/) This approach is useful when you want to: * Control the entire build and deployment pipeline * Use your own container registry and cluster * Deploy to offline or restricted environments * Build from a specific commit or branch ### Prerequisites[](https://docs.crossplane.io/v2.0/guides/install-from-source/#prerequisites) Building Crossplane from source requires: * [Docker](https://docs.docker.com/get-docker/) * [Earthly](https://earthly.dev/get-earthly) version `v0.8.16` or later * [kubectl](https://kubernetes.io/docs/tasks/tools/) configured for your target cluster * An actively [supported Kubernetes version](https://kubernetes.io/releases/patch-releases/#support-period) * [Helm](https://helm.sh/docs/intro/install/) version `v3.2.0` or later * Access to a container registry (Docker Hub, GHCR, Harbor, or any OCI compliant registry) ### Clone the Crossplane repository[](https://docs.crossplane.io/v2.0/guides/install-from-source/#clone-the-crossplane-repository) Clone the Crossplane repository and optionally checkout a specific release. 1git clone https://github.com/crossplane/crossplane.git 2cd crossplane Tip To build a specific release, checkout the release tag before building. 1git checkout v2.0.2 ### Determine artifacts destination[](https://docs.crossplane.io/v2.0/guides/install-from-source/#determine-artifacts-destination) Identify the registry and version tag where you will push your built software artifacts and save them in environment variables: 1export REGISTRY="your-registry.com/your-org"; \ 2 export VERSION="v2.0.0-yourtag" ### Build the artifacts[](https://docs.crossplane.io/v2.0/guides/install-from-source/#build-the-artifacts) Build Crossplane binaries, container image, and Helm chart for multi-platform architectures: 1earthly +multiplatform-build \ 2 --CROSSPLANE_REPO=${REGISTRY}/crossplane \ 3 --CROSSPLANE_VERSION=${VERSION} Earthly creates the container image locally and saves the binaries and Helm chart under `_output/bin` and `_output/charts/` respectively. ### Push the image to your registry[](https://docs.crossplane.io/v2.0/guides/install-from-source/#push-the-image-to-your-registry) Log in to your registry of choice and push the Crossplane image that was built in the previous steps. Tip Ensure you log into your registry before attempting to `push`. 1docker push ${REGISTRY}/crossplane:${VERSION} ### Install Crossplane with the custom image[](https://docs.crossplane.io/v2.0/guides/install-from-source/#install-crossplane-with-the-custom-image) Locate the built Helm chart in the `_output/charts/` directory. 1CHART_PATH="_output/charts/crossplane-${VERSION#v}.tgz" Install Crossplane to your cluster using the custom image. 1helm install crossplane ${CHART_PATH} \ 2 --namespace crossplane-system \ 3 --create-namespace \ 4 --set image.repository=${REGISTRY}/crossplane \ 5 --set image.tag=${VERSION} \ 6 --set image.pullPolicy=IfNotPresent Important If your registry requires authentication, create an `imagePullSecret` before installing. 1kubectl create secret docker-registry regcred \ 2 --docker-server=${REGISTRY} \ 3 --docker-username= \ 4 --docker-password= \ 5 --namespace crossplane-system Add the secret reference to the `helm install` command. 1--set imagePullSecrets[0].name=regcred ### Verify the installation[](https://docs.crossplane.io/v2.0/guides/install-from-source/#verify-the-installation) View the installed Crossplane pods with `kubectl get pods`. 1kubectl get pods -n crossplane-system 2NAME READY STATUS RESTARTS AGE 3crossplane-5644774bd4-zvcwc 1/1 Running 0 72s 4crossplane-rbac-manager-84dc89c564-b9x6q 1/1 Running 0 72s Verify the Crossplane deployment is using your custom image. 1kubectl get deployment crossplane -n crossplane-system -o jsonpath='{.spec.template.spec.containers[0].image}' 2your-registry.com/your-org/crossplane:v2.0.0-yourtag ### Optional: Build the Crossplane CLI[](https://docs.crossplane.io/v2.0/guides/install-from-source/#optional-build-the-crossplane-cli) The `crossplane` CLI provides commands for managing Crossplane resources. You can optionally build this binary from source code for your local machine and use it to manage your control plane. Build the CLI for your local machine. 1earthly +build --CROSSPLANE_VERSION=${VERSION} Earthly creates the CLI binary in `_output/bin/_/`. Copy it to your system path. For macOS ARM64: 1sudo cp _output/bin/darwin_arm64/crank /usr/local/bin/crossplane 2chmod +x /usr/local/bin/crossplane For Linux AMD64: 1sudo cp _output/bin/linux_amd64/crank /usr/local/bin/crossplane 2chmod +x /usr/local/bin/crossplane Verify the installation. 1crossplane version 2v2.0.0-yourtag --- # Uninstall Crossplane · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/uninstall-crossplane/#) [master](https://docs.crossplane.io/master/guides/uninstall-crossplane/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/uninstall-crossplane/) [v1.20](https://docs.crossplane.io/v1.20/software/uninstall/) [v1.19](https://docs.crossplane.io/v1.19/software/uninstall/) Uninstall Crossplane ==================== On this page **On this page** * * * Warning Resources created by Crossplane aren’t deleted if Crossplane isn’t uninstalled in order. This can leave cloud resources running, requiring manual deletion. Ordered Crossplane uninstall[](https://docs.crossplane.io/v2.0/guides/uninstall-crossplane/#ordered-crossplane-uninstall) -------------------------------------------------------------------------------------------------------------------------- Most Crossplane resources have dependencies on other Crossplane resources. For example, a _managed resource_ is dependent on the _provider_. Failure to delete Crossplane resources in order may prevent Crossplane from deleting provisioned external resources. Removing Crossplane resources should happen in the following order: 1. Remove all _composite resource definitions_ 2. Remove all remaining _managed resources_ 3. Remove all _providers_ Deleting the Crossplane pod removes remaining Crossplane components. Tip Collect an inventory of all external resources with `kubectl get managed`. Depending on the size of the Kubernetes API server and number of resources, this command may take minutes to return. An example kubectl get managed ------------------------------ 1kubectl get managed 2NAME READY SYNCED EXTERNAL-NAME AGE 3securitygroup.ec2.aws.m.upbound.io/my-db-7mc7h-j84h8 True True sg-0da6e9c29113596b6 3m1s 4securitygroup.ec2.aws.m.upbound.io/my-db-8bhr2-9wsx9 True True sg-02695166f010ec05b 2m26s 5 6NAME READY SYNCED EXTERNAL-NAME AGE 7route.ec2.aws.m.upbound.io/my-db-7mc7h-vw985 True True r-rtb-05822b8df433e4e2b1080289494 3m1s 8route.ec2.aws.m.upbound.io/my-db-8bhr2-7m2wq False True 2m26s 9 10NAME READY SYNCED EXTERNAL-NAME AGE 11securitygrouprule.ec2.aws.m.upbound.io/my-db-7mc7h-mkd9s True True sgrule-778063708 3m1s 12securitygrouprule.ec2.aws.m.upbound.io/my-db-8bhr2-lzr89 False True 2m26s 13 14NAME READY SYNCED EXTERNAL-NAME AGE 15routetable.ec2.aws.m.upbound.io/my-db-7mc7h-mnqvm True True rtb-05822b8df433e4e2b 3m1s 16routetable.ec2.aws.m.upbound.io/my-db-8bhr2-dfhj6 True True rtb-02e875abd25658254 2m26s 17 18NAME READY SYNCED EXTERNAL-NAME AGE 19subnet.ec2.aws.m.upbound.io/my-db-7mc7h-7m49d True True subnet-0c1ab32c5ec129dd1 3m2s 20subnet.ec2.aws.m.upbound.io/my-db-7mc7h-9t64t True True subnet-07075c17c7a72f79e 3m2s 21subnet.ec2.aws.m.upbound.io/my-db-7mc7h-rs8t8 True True subnet-08e88e826a42e55b4 3m2s 22subnet.ec2.aws.m.upbound.io/my-db-8bhr2-9sjpx True True subnet-05d21c7b52f7ac8ca 2m26s 23subnet.ec2.aws.m.upbound.io/my-db-8bhr2-dvrxf True True subnet-0432310376b5d09de 2m26s 24subnet.ec2.aws.m.upbound.io/my-db-8bhr2-t7dpr True True subnet-0080fdcb6e9b70632 2m26s 25 26NAME READY SYNCED EXTERNAL-NAME AGE 27vpc.ec2.aws.m.upbound.io/my-db-7mc7h-ktbbh True True vpc-08d7dd84e0c12f33e 3m3s 28vpc.ec2.aws.m.upbound.io/my-db-8bhr2-mrh2x True True vpc-06994bf323fc1daea 2m26s 29 30NAME READY SYNCED EXTERNAL-NAME AGE 31internetgateway.ec2.aws.m.upbound.io/my-db-7mc7h-s2x4v True True igw-0189c4da07a3142dc 3m1s 32internetgateway.ec2.aws.m.upbound.io/my-db-8bhr2-q7dzl True True igw-01bf2a1dbbebf6a27 2m26s 33 34NAME READY SYNCED EXTERNAL-NAME AGE 35routetableassociation.ec2.aws.m.upbound.io/my-db-7mc7h-28qb4 True True rtbassoc-0718d680b5a0e68fe 3m1s 36routetableassociation.ec2.aws.m.upbound.io/my-db-7mc7h-9hdlr True True rtbassoc-0faaedb88c6e1518c 3m1s 37routetableassociation.ec2.aws.m.upbound.io/my-db-7mc7h-txhmz True True rtbassoc-0e5010724ca027864 3m1s 38routetableassociation.ec2.aws.m.upbound.io/my-db-8bhr2-bvgkt False True 2m26s 39routetableassociation.ec2.aws.m.upbound.io/my-db-8bhr2-d9gbg False True 2m26s 40routetableassociation.ec2.aws.m.upbound.io/my-db-8bhr2-k6k8m False True 2m26s 41 42NAME READY SYNCED EXTERNAL-NAME AGE 43instance.rds.aws.m.upbound.io/my-db-7mc7h-5d6w4 False True my-db-7mc7h-5d6w4 3m1s 44instance.rds.aws.m.upbound.io/my-db-8bhr2-tx9kf False True my-db-8bhr2-tx9kf 2m26s 45 46NAME READY SYNCED EXTERNAL-NAME AGE 47subnetgroup.rds.aws.m.upbound.io/my-db-7mc7h-8c8n9 True True my-db-7mc7h-8c8n9 3m2s 48subnetgroup.rds.aws.m.upbound.io/my-db-8bhr2-mc5ps True True my-db-8bhr2-mc5ps 2m27s 49 50NAME READY SYNCED EXTERNAL-NAME AGE 51bucket.s3.aws.m.upbound.io/crossplane-bucket-867737b10 True True 52crossplane-bucket-867737b10 5m26s ### Remove composite resource definitions[](https://docs.crossplane.io/v2.0/guides/uninstall-crossplane/#remove-composite-resource-definitions) Removing installed _composite resource definitions_ removes any _composite resources_ defined by the _composite resource definition_ and the _managed resourced_ they created. View the installed _composite resource definitions_ with `kubectl get xrd`. 1kubectl get xrd 2NAME ESTABLISHED OFFERED AGE 3compositepostgresqlinstances.database.example.org True True 40s Delete the _composite resource definitions_ with `kubectl delete xrd`. 1kubectl delete xrd compositepostgresqlinstances.database.example.org ### Remove managed resources[](https://docs.crossplane.io/v2.0/guides/uninstall-crossplane/#remove-managed-resources) Manually delete any _managed resources_ manually created. Use `kubectl get managed` to view remaining _managed resources_. 1kubectl get managed 2NAME READY SYNCED EXTERNAL-NAME AGE 3bucket.s3.aws.m.upbound.io/crossplane-bucket-867737b10 True True crossplane-bucket-867737b10 8h Use `kubectl delete` to remove the resources. 1kubectl delete bucket.s3.aws.m.upbound.io/crossplane-bucket-867737b10 ### Remove Crossplane providers[](https://docs.crossplane.io/v2.0/guides/uninstall-crossplane/#remove-crossplane-providers) List the installed _providers_ with `kubectl get providers`. 1kubectl get providers 2NAME INSTALLED HEALTHY PACKAGE AGE 3crossplane-contrib-provider-aws-s3 True True xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v2.0.0 8h Remove the installed _providers_ with `kubectl delete provider`. 1kubectl delete provider crossplane-contrib-provider-aws Uninstall the Crossplane deployment[](https://docs.crossplane.io/v2.0/guides/uninstall-crossplane/#uninstall-the-crossplane-deployment) ---------------------------------------------------------------------------------------------------------------------------------------- Uninstall Crossplane using Helm with `helm uninstall` 1helm uninstall crossplane --namespace crossplane-system Verify Helm removed the Crossplane pods with `kubectl get pods` 1kubectl get pods -n crossplane-system 2No resources found in crossplane-system namespace. Delete the Crossplane namespace[](https://docs.crossplane.io/v2.0/guides/uninstall-crossplane/#delete-the-crossplane-namespace) -------------------------------------------------------------------------------------------------------------------------------- When Helm installs Crossplane it creates the `crossplane-system` namespace. Helm doesn’t uninstall this namespace with `helm uninstall`. Manually delete the Crossplane namespace with `kubectl delete namespace`. 1kubectl delete namespace crossplane-system Verify Kubernetes removed the namespace with `kubectl get namespaces` 1kubectl get namespace 2NAME STATUS AGE 3default Active 2m45s 4kube-flannel Active 2m42s 5kube-node-lease Active 2m47s 6kube-public Active 2m47s 7kube-system Active 2m47s Warning Custom Resource Definitions (CRDs) aren’t automatically removed by `helm uninstall`. CRDs with names ending in `*.crossplane.io` remain in your cluster after uninstalling Crossplane. If desired, manually delete these CRDs: 1# View remaining Crossplane CRDs 2kubectl get crd | grep crossplane.io 3 4# Example: Delete a specific CRD 5kubectl delete crd providers.pkg.crossplane.io Important Deleting CRDs removes all custom resources of that type. Ensure no important data exists before deletion. --- # Community Extension Projects · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/learn/community-extension-projects/#) [master](https://docs.crossplane.io/master/learn/community-extension-projects/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/learn/community-extension-projects/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Community Extension Projects ============================ On this page **On this page** * * * The Crossplane community has built a rich set of [Community Extension Projects](https://github.com/crossplane/crossplane/blob/main/GOVERNANCE.md#community-extension-projects) for use by Crossplane adopters to extend the usefulness of their Crossplane powered control planes. They’re all hosted under the [crossplane-contrib](https://github.com/crossplane-contrib) organization. Note All Community Extension Projects should maintain good project health and adhere to the policies stated in the [project governance](https://github.com/crossplane/crossplane/blob/main/GOVERNANCE.md#policies-for-community-extension-projects) . If a project falls out of compliance then the repository is archived and the project is removed from this list. All projects on this page should be ready to use by Crossplane adopters. Providers[](https://docs.crossplane.io/v2.0/learn/community-extension-projects/#providers) ------------------------------------------------------------------------------------------- * [provider-upjet-alibabacloud](https://github.com/crossplane-contrib/provider-upjet-alibabacloud) * [provider-ansible](https://github.com/crossplane-contrib/provider-ansible) * [provider-argocd](https://github.com/crossplane-contrib/provider-argocd) * [provider-aws](https://github.com/crossplane-contrib/provider-aws) * [provider-upjet-aws](https://github.com/crossplane-contrib/provider-upjet-aws) * [provider-upjet-azure](https://github.com/crossplane-contrib/provider-upjet-azure) * [provider-upjet-azuread](https://github.com/crossplane-contrib/provider-upjet-azuread) * [provider-capi](https://github.com/crossplane-contrib/provider-capi) * [crossplane-provider-castai](https://github.com/crossplane-contrib/crossplane-provider-castai) * [provider-civo](https://github.com/crossplane-contrib/provider-civo) * [provider-cloudflare](https://github.com/crossplane-contrib/provider-cloudflare) * [provider-cloudinit](https://github.com/crossplane-contrib/provider-cloudinit) * [provider-confluent](https://github.com/crossplane-contrib/provider-confluent) * [provider-upjet-digitalocean](https://github.com/crossplane-contrib/provider-upjet-digitalocean) * [provider-jet-ec](https://github.com/crossplane-contrib/provider-jet-ec) * [provider-upjet-ec](https://github.com/crossplane-contrib/provider-upjet-ec) * [provider-upjet-edgeadc](https://github.com/crossplane-contrib/provider-upjet-edgeadc) * [provider-jet-equinix](https://github.com/crossplane-contrib/provider-jet-equinix) * [provider-gcp-beta](https://github.com/crossplane-contrib/provider-gcp-beta) * [provider-upjet-gcp](https://github.com/crossplane-contrib/provider-upjet-gcp) * [provider-gitlab](https://github.com/crossplane-contrib/provider-gitlab) * [provider-upjet-github](https://github.com/crossplane-contrib/provider-upjet-github) * [provider-helm](https://github.com/crossplane-contrib/provider-helm) * [provider-http](https://github.com/crossplane-contrib/provider-http) * [provider-ibm-cloud](https://github.com/crossplane-contrib/provider-ibm-cloud) * [provider-infoblox-nios](https://github.com/crossplane-contrib/provider-infoblox-nios) * [provider-influxdb](https://github.com/crossplane-contrib/provider-influxdb) * [provider-kafka](https://github.com/crossplane-contrib/provider-kafka) * [provider-upjet-kafka](https://github.com/crossplane-contrib/provider-upjet-kafka) * [provider-keycloak](https://github.com/crossplane-contrib/provider-keycloak) * [provider-kops](https://github.com/crossplane-contrib/provider-kops) * [provider-kubernetes](https://github.com/crossplane-contrib/provider-kubernetes) * [provider-mongodbatlas](https://github.com/crossplane-contrib/provider-mongodbatlas) * [provider-upjet-mysql](https://github.com/crossplane-contrib/provider-upjet-mysql) * [provider-newrelic](https://github.com/crossplane-contrib/provider-newrelic) * [crossplane-provider-newrelic](https://github.com/crossplane-contrib/crossplane-provider-newrelic) * [provider-nop](https://github.com/crossplane-contrib/provider-nop) * [provider-okta](https://github.com/crossplane-contrib/provider-okta) * [provider-openstack](https://github.com/crossplane-contrib/provider-openstack) * [provider-pagerduty](https://github.com/crossplane-contrib/provider-pagerduty) * [provider-palette](https://github.com/crossplane-contrib/provider-palette) * [provider-jet-rancher](https://github.com/crossplane-contrib/provider-jet-rancher) * [provider-redpanda](https://github.com/crossplane-contrib/provider-redpanda) * [provider-secret](https://github.com/crossplane-contrib/provider-secret) * [provider-spotify](https://github.com/crossplane-contrib/provider-spotify) * [provider-sql](https://github.com/crossplane-contrib/provider-sql) * [provider-styra](https://github.com/crossplane-contrib/provider-styra) * [provider-talos](https://github.com/crossplane-contrib/provider-talos) * [provider-tencentcloud](https://github.com/crossplane-contrib/provider-tencentcloud) * [provider-terraform](https://github.com/crossplane-contrib/provider-terraform) * [provider-jet-vault](https://github.com/crossplane-contrib/provider-jet-vault) * [provider-workflows](https://github.com/crossplane-contrib/provider-workflows) * [provider-zpa](https://github.com/crossplane-contrib/provider-zpa) Functions[](https://docs.crossplane.io/v2.0/learn/community-extension-projects/#functions) ------------------------------------------------------------------------------------------- * [function-auto-ready](https://github.com/crossplane-contrib/function-auto-ready) * [function-cel-filter](https://github.com/crossplane-contrib/function-cel-filter) * [function-cue](https://github.com/crossplane-contrib/function-cue) * [function-dummy](https://github.com/crossplane-contrib/function-dummy) * [function-environment-configs](https://github.com/crossplane-contrib/function-environment-configs) * [function-extra-resources](https://github.com/crossplane-contrib/function-extra-resources) * [function-go-templating](https://github.com/crossplane-contrib/function-go-templating) * [function-hcl](https://github.com/crossplane-contrib/function-hcl) * [function-kcl](https://github.com/crossplane-contrib/function-kcl) * [function-patch-and-transform](https://github.com/crossplane-contrib/function-patch-and-transform) * [function-python](https://github.com/crossplane-contrib/function-python) * [function-sequencer](https://github.com/crossplane-contrib/function-sequencer) * [function-shell](https://github.com/crossplane-contrib/function-shell) * [function-status-transformer](https://github.com/crossplane-contrib/function-status-transformer) * [function-tag-manager](https://github.com/crossplane-contrib/function-tag-manager) * [function-unit-test](https://github.com/crossplane-contrib/function-unit-test) Configurations[](https://docs.crossplane.io/v2.0/learn/community-extension-projects/#configurations) ----------------------------------------------------------------------------------------------------- * [configuration-quickstart](https://github.com/crossplane-contrib/configuration-quickstart) Tools and utilities[](https://docs.crossplane.io/v2.0/learn/community-extension-projects/#tools-and-utilities) --------------------------------------------------------------------------------------------------------------- * [crossplane-cdk8s](https://github.com/crossplane-contrib/crossplane-cdk8s) * [crossplane-diff](https://github.com/crossplane-contrib/crossplane-diff) * [crossplane-lint](https://github.com/crossplane-contrib/crossplane-lint) * [ess-plugin-vault](https://github.com/crossplane-contrib/ess-plugin-vault) * [setup-crossplane-action](https://github.com/crossplane-contrib/setup-crossplane-action) * [x-generation](https://github.com/crossplane-contrib/x-generation) * [xp-testing](https://github.com/crossplane-contrib/xp-testing) * [xpkg-action](https://github.com/crossplane-contrib/xpkg-action) --- # Upgrade to Crossplane v2 · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#) [master](https://docs.crossplane.io/master/guides/upgrade-to-crossplane-v2/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/) [v1.20](https://docs.crossplane.io/v1.20/) [v1.19](https://docs.crossplane.io/v1.19/) Upgrade to Crossplane v2 ======================== On this page **On this page** * * * Crossplane v2 introduces significant improvements while maintaining backward compatibility with most v1 configurations. This guide helps you upgrade from Crossplane v1.x to v2. Learn about [new features in Crossplane v2](https://docs.crossplane.io/v2.0/whats-new/) including namespaced resources, the ability to compose any Kubernetes resource, and new operational workflows. Important Only upgrade to Crossplane v2 from Crossplane v1.20, the final v1.x release. If you’re running an earlier version, upgrade to v1.20 first. Note There’s no automated tooling yet to migrate existing v1 cluster-scoped XRs and MRs to v2 namespaced style. You can upgrade to Crossplane v2 and start using the new namespaced features right away - your existing v1 resources continue working unchanged. See [crossplane/crossplane#6726](https://github.com/crossplane/crossplane/issues/6726) for migration tooling progress. Prerequisites[](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#prerequisites) ------------------------------------------------------------------------------------------------ Before upgrading, ensure: * You’re running Crossplane v1.20 * You’re not using deprecated features (see [removed features](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#removed-features) ) * All packages use fully qualified image names * [Helm](https://helm.sh/docs/intro/install/) version v3.2.0 or later Removed features[](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#removed-features) ------------------------------------------------------------------------------------------------------ Crossplane v2 removes these deprecated features: * [Native patch and transform composition](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#native-patch-and-transform-composition) * [ControllerConfig type](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#controllerconfig-type) * [External secret stores](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#external-secret-stores) * [Default registry flag](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#default-registry-flag) ### Native patch and transform composition[](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#native-patch-and-transform-composition) **Deprecated in**: v1.17 **Replaced by**: [Composition functions](https://docs.crossplane.io/v2.0/composition/compositions/) If you’re using `spec.mode: Resources` in your Compositions, migrate to composition functions before upgrading. **Migration help**: use the Crossplane v1.20 CLI to automatically convert your Compositions: 1# Convert patch and transform to function pipelines 2crossplane beta convert pipeline-composition old-composition.yaml -o new-composition.yaml ### ControllerConfig type[](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#controllerconfig-type) **Deprecated in**: v1.11 **Replaced by**: [DeploymentRuntimeConfig](https://docs.crossplane.io/v2.0/packages/providers/#runtime-configuration) Update any ControllerConfig resources to use DeploymentRuntimeConfig instead. **Migration help**: use the Crossplane v1.20 CLI to automatically convert your ControllerConfigs: 1# Convert ControllerConfig to DeploymentRuntimeConfig 2crossplane beta convert deployment-runtime controller-config.yaml -o deployment-runtime-config.yaml ### External secret stores[](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#external-secret-stores) **Status**: alpha feature, unmaintained If you’re using external secret stores, migrate to native Kubernetes secrets or [External Secrets Operator](https://external-secrets.io/latest/) before upgrading. ### Default registry flag[](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#default-registry-flag) **Removed**: `--registry` flag for default package registry All packages must now use fully qualified names including the registry host name. Check your packages with: 1kubectl get pkg -o wide Update any packages without registry host names before upgrading. For example: * ❌ `crossplane-contrib/provider-aws-s3:v1.23.0` * ✅ `xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v1.23.0` Who can upgrade[](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#who-can-upgrade) ---------------------------------------------------------------------------------------------------- You can upgrade to Crossplane v2 if you meet these criteria: * ✅ Running Crossplane v1.20 * ✅ Not using native patch and transform composition * ✅ Not using ControllerConfig resources * ✅ Not using external secret stores * ✅ All packages use fully qualified image names If you’re using any removed features, migrate away from them first. Upgrade approach[](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#upgrade-approach) ------------------------------------------------------------------------------------------------------ The recommended upgrade approach: 1. [Prepare for upgrade](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#1-prepare-for-upgrade) 2. [Upgrade Crossplane core](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#2-upgrade-crossplane-core) 3. [Configure managed resource activation policies](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#3-configure-managed-resource-activation-policies) 4. [Upgrade providers](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#4-upgrade-providers) 5. [Start using v2 features](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#5-start-using-v2-features) ### 1\. Prepare for upgrade[](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#1-prepare-for-upgrade) Review your cluster for [removed features](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#removed-features) and address any that you’re using. Each removed feature section includes commands to inspect your cluster and migration tools to help convert resources. ### 2\. Upgrade Crossplane core[](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#2-upgrade-crossplane-core) Add the Crossplane Helm repository: 1helm repo add crossplane-stable https://charts.crossplane.io/stable 2helm repo update Upgrade to Crossplane v2: 1helm upgrade crossplane \ 2 --namespace crossplane-system \ 3 crossplane-stable/crossplane Verify the upgrade: 1kubectl get pods -n crossplane-system ### 3\. Configure managed resource activation policies[](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#3-configure-managed-resource-activation-policies) Crossplane v2 automatically creates a default [MRAP](https://docs.crossplane.io/v2.0/managed-resources/managed-resource-activation-policies/) that activates all managed resources (`*`). Before installing v2 providers, you can optionally customize this for better cluster resource efficiency. Check what managed resources you use: 1# See your managed resource types 2kubectl get managed Optionally, replace the default MRAP with a targeted one that activates only the resources you need: 1# Delete the default catch-all MRAP 2kubectl delete mrap default Create a targeted MRAP: 1apiVersion: apiextensions.crossplane.io/v1alpha1 2kind: ManagedResourceActivationPolicy 3metadata: 4 name: my-resources 5spec: 6 activate: 7 # Legacy cluster-scoped resources (existing v1 resources) 8 - buckets.s3.aws.upbound.io 9 - instances.ec2.aws.upbound.io 10 11 # Modern namespaced resources (new v2 resources) 12 - buckets.s3.aws.m.upbound.io 13 - instances.ec2.aws.m.upbound.io Tip Notice the distinction: `s3.aws.upbound.io` (legacy cluster-scoped) vs `s3.aws.m.upbound.io` (v2 namespaced). The `.m.` indicates modern namespaced managed resources. ### 4\. Upgrade providers[](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#4-upgrade-providers) Upgrade your providers to versions that support both namespaced and cluster-scoped managed resources: 1# Check current provider versions 2kubectl get providers Update your provider manifests to use v2 versions: 1apiVersion: pkg.crossplane.io/v1 2kind: Provider 3metadata: 4 name: crossplane-contrib-provider-aws-s3 5spec: 6 package: xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v2.0.0 Note Provider v2 releases support both legacy cluster-scoped and new namespaced managed resources. Your existing cluster-scoped MRs continue working unchanged. ### 5\. Start using v2 features[](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#5-start-using-v2-features) After upgrading, you can begin using Crossplane v2 features: * **Namespaced managed resources**: Try the [managed resources getting started guide](https://docs.crossplane.io/v2.0/get-started/get-started-with-managed-resources/) * **Composition functions**: Follow the [composition getting started guide](https://docs.crossplane.io/v2.0/get-started/get-started-with-composition/) * **Operations**: Explore the [operations getting started guide](https://docs.crossplane.io/v2.0/get-started/get-started-with-operations/) * **Managed resource definitions**: See the [MRDs guide](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/) Updating compositions for v2[](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#updating-compositions-for-v2) ------------------------------------------------------------------------------------------------------------------------------ Existing Compositions work with Crossplane v2 with minimal changes. v2 managed resources are schematically identical to v1 managed resources - they’re just namespaced. Important **Don’t update existing compositions that are actively used by composite resources in your control plane.** Updating a live composition that’s in use by existing XRs could disrupt or replace your resources. Use the below migration approach only when creating new compositions for new resources. To use v2 namespaced managed resources in compositions: 1. **Update the API group** from `.crossplane.io` to `.m.crossplane.io` 2. **Check the API version** - v2 namespaced providers often reset the API version to `v1beta1` For example `provider-aws-s3:v2.0.0` has two `Bucket` MRs: * `apiVersion: s3.aws.upbound.io/v1beta2` - Legacy, cluster scoped * `apiVersion: s3.aws.m.upbound.io/v1beta1` - Namespaced The `spec.forProvider` and `status.atProvider` fields are schematically identical. Tip Use `kubectl get mrds` to see available MR API versions. Note Not all providers use `.crossplane.io` domains. For example, `provider-aws-s3` uses `.upbound.io` domains for historical reasons. The general pattern for namespaced resources is adding `.m` to the existing domain: `` becomes `m.` (like `upbound.io` → `m.upbound.io` or `crossplane.io` → `m.crossplane.io`). **Before (v1 cluster-scoped)**: 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: my-app 5spec: 6 compositeTypeRef: 7 apiVersion: example.crossplane.io/v1 8 kind: XBucket 9 mode: Pipeline 10 pipeline: 11 - step: create-bucket 12 functionRef: 13 name: crossplane-contrib-function-go-templating 14 input: 15 apiVersion: gotemplating.fn.crossplane.io/v1beta1 16 kind: GoTemplate 17 source: Inline 18 inline: 19 template: | 20 apiVersion: s3.aws.upbound.io/v1beta2 21 kind: Bucket 22 metadata: 23 name: {{ .observed.composite.resource.metadata.name }} 24 spec: 25 forProvider: 26 region: us-east-2 **After (v2 namespaced)**: 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: my-app 5spec: 6 compositeTypeRef: 7 apiVersion: example.crossplane.io/v1 8 kind: Bucket 9 mode: Pipeline 10 pipeline: 11 - step: create-bucket 12 functionRef: 13 name: crossplane-contrib-function-go-templating 14 input: 15 apiVersion: gotemplating.fn.crossplane.io/v1beta1 16 kind: GoTemplate 17 source: Inline 18 inline: 19 template: | 20 apiVersion: s3.aws.m.upbound.io/v1beta1 # Added .m, reset to v1beta1 21 kind: Bucket 22 metadata: 23 name: {{ .observed.composite.resource.metadata.name }} 24 spec: 25 forProvider: 26 region: us-east-2 Tip **Namespace handling in compositions**: * **Namespaced XRs**: Don’t specify `metadata.namespace` in templates. Crossplane ignores template namespaces and uses the XR’s namespace. * **Modern cluster-scoped XRs** (`scope: Cluster`): Can compose resources in any namespace. Include `metadata.namespace` in templates to specify the target namespace. * **Legacy cluster-scoped XRs** (`scope: LegacyCluster`): Can’t compose namespaced resources. Legacy resource behavior[](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#legacy-resource-behavior) ---------------------------------------------------------------------------------------------------------------------- Your existing v1 resources continue working in Crossplane v2: * **Legacy cluster-scoped XRs**: Continue working with claims support * **Legacy cluster-scoped MRs**: Continue working unchanged * **Existing Compositions**: Continue working with legacy XRs These resources use `LegacyCluster` scope internally and maintain full backward compatibility. For example, existing v1-style XRDs continue working with claims: 1apiVersion: apiextensions.crossplane.io/v1 2kind: CompositeResourceDefinition 3metadata: 4 name: xdatabases.example.crossplane.io 5spec: 6 # v1 XRDs default to LegacyCluster scope (shown explicitly) 7 scope: LegacyCluster 8 group: example.crossplane.io 9 names: 10 kind: XDatabase 11 plural: xdatabases 12 claimNames: 13 kind: Database 14 plural: databases 15 # schema definition... Users can create claims that work as before: 1apiVersion: example.crossplane.io/v1 2kind: Database 3metadata: 4 name: my-database 5 namespace: production 6spec: 7 engine: postgres 8 size: large Next steps[](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/#next-steps) ------------------------------------------------------------------------------------------ After upgrading: 1. **Explore namespaced resources**: Try creating XRs and MRs in namespaces 2. **Build app compositions**: Use v2’s ability to compose any Kubernetes resource 3. **Try Operations**: Experiment with operational workflows 4. **Plan migration**: Consider which existing resources to migrate to v2 patterns Read more about [what’s new in v2](https://docs.crossplane.io/v2.0/whats-new/) and explore the updated [composition documentation](https://docs.crossplane.io/v2.0/composition/compositions/) . --- # Providers · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/packages/providers/#) [master](https://docs.crossplane.io/master/packages/providers/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/packages/providers/) [v1.20](https://docs.crossplane.io/v1.20/concepts/providers/) [v1.19](https://docs.crossplane.io/v1.19/concepts/providers/) Providers ========= On this page **On this page** * * * Providers enable Crossplane to provision infrastructure on an external service. Providers create new Kubernetes APIs and map them to external APIs. Providers are responsible for all aspects of connecting to non-Kubernetes resources. This includes authentication, making external API calls and providing [Kubernetes Controller](https://kubernetes.io/docs/concepts/architecture/controller/) logic for any external resources. Examples of providers include: * [Provider AWS](https://github.com/crossplane-contrib/provider-upjet-aws) * [Provider Azure](https://github.com/upbound/provider-azure) * [Provider GCP](https://github.com/upbound/provider-gcp) * [Provider Kubernetes](https://github.com/crossplane-contrib/provider-kubernetes) Providers define every external resource they can create in Kubernetes as a Kubernetes API endpoint. These endpoints are [_Managed Resources_](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/) . Install a provider[](https://docs.crossplane.io/v2.0/packages/providers/#install-a-provider) --------------------------------------------------------------------------------------------- Installing a provider creates new Kubernetes resources representing the Provider’s APIs. Installing a provider also creates a Provider pod that’s responsible for reconciling the Provider’s APIs into the Kubernetes cluster. Providers constantly watch the state of the desired managed resources and create any external resources that are missing. Install a Provider with a Crossplane `Provider` object setting the `spec.package` value to the location of the provider package. For example, to install the [AWS Provider](https://github.com/crossplane-contrib/provider-upjet-aws) , 1apiVersion: pkg.crossplane.io/v1 2kind: Provider 3metadata: 4 name: crossplane-contrib-provider-aws-s3-s3 5spec: 6 package: xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v2.0.0 By default, the Provider pod installs in the same namespace as Crossplane (`crossplane-system`). Note Providers are part of the `pkg.crossplane.io` group. The `meta.pkg.crossplane.io` group is for creating Provider packages. Instructions on building Providers are outside of the scope of this document. Read the Crossplane contributing [Provider Development Guide](https://github.com/crossplane/crossplane/blob/main/contributing/guide-provider-development.md) for more information. For information on the specification of Provider packages read the [Crossplane Provider Package specification](https://github.com/crossplane/crossplane/blob/main/contributing/specifications/xpkg.md#provider-package-requirements) . 1apiVersion: meta.pkg.crossplane.io/v1 2kind: Provider 3metadata: 4 name: crossplane-contrib-provider-aws-s3 5spec: 6# Removed for brevity ### Install with Helm[](https://docs.crossplane.io/v2.0/packages/providers/#install-with-helm) Crossplane supports installing Providers during an initial Crossplane installation with the Crossplane Helm chart. Use the `--set provider.packages` argument with `helm install`. For example, to install the AWS S3 Provider, 1helm install crossplane \ 2crossplane-stable/crossplane \ 3--namespace crossplane-system \ 4--create-namespace \ 5--set provider.packages='{xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v2.0.0}' ### Install offline[](https://docs.crossplane.io/v2.0/packages/providers/#install-offline) Installing Crossplane Providers offline requires a local container registry like [Harbor](https://goharbor.io/) to host Provider packages. Crossplane only supports installing Provider packages from a container registry. Crossplane doesn’t support installing Provider packages directly from Kubernetes volumes. ### Installation options[](https://docs.crossplane.io/v2.0/packages/providers/#installation-options) Providers support multiple configuration options to change installation related settings. Tip Crossplane supports installations with image digests instead of tags to get deterministic and repeatable installations. 1apiVersion: pkg.crossplane.io/v1 2kind: Provider 3metadata: 4 name: crossplane-contrib-provider-aws-s3 5spec: 6 package: xpkg.crossplane.io/crossplane-contrib/provider-aws-s3@sha256:ee6bece46dbb54cc3f0233961f5baac317fa4e4a81b41198bdc72fc472d113d0 #### Provider pull policy[](https://docs.crossplane.io/v2.0/packages/providers/#provider-pull-policy) Use a `packagePullPolicy` to define when Crossplane should download the Provider package to the local Crossplane package cache. The `packagePullPolicy` options are: * `IfNotPresent` - (**default**) Only download the package if it isn’t in the cache. * `Always` - Check for new packages every minute and download any matching package that isn’t in the cache. * `Never` - Never download the package. Packages are only installed from the local package cache. Tip The Crossplane `packagePullPolicy` works like the Kubernetes container image [image pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) . Crossplane supports the use of tags and package digest hashes like Kubernetes images. For example, to `Always` download a given Provider package use the `packagePullPolicy: Always` configuration. 1apiVersion: pkg.crossplane.io/v1 2kind: Provider 3metadata: 4 name: crossplane-contrib-provider-aws-s3 5spec: 6 packagePullPolicy: Always 7# Removed for brevity #### Revision activation policy[](https://docs.crossplane.io/v2.0/packages/providers/#revision-activation-policy) The `Active` package revision is the package controller actively reconciling resources. By default Crossplane sets the most recently installed package revision as `Active`. Control the Provider upgrade behavior with a `revisionActivationPolicy`. The `revisionActivationPolicy` options are: * `Automatic` - (**default**) Automatically activate the last installed Provider. * `Manual` - Don’t automatically activate a Provider. For example, to change the upgrade behavior to require manual upgrades, set `revisionActivationPolicy: Manual`. 1apiVersion: pkg.crossplane.io/v1 2kind: Provider 3metadata: 4 name: crossplane-contrib-provider-aws-s3 5spec: 6 revisionActivationPolicy: Manual 7# Removed for brevity #### Package revision history limit[](https://docs.crossplane.io/v2.0/packages/providers/#package-revision-history-limit) When Crossplane installs a different version of the same Provider package Crossplane creates a new _revision_. By default Crossplane maintains one _Inactive_ revision. Note Read the [Provider upgrade](https://docs.crossplane.io/v2.0/packages/providers/#upgrade-a-provider) section for more information on the use of package revisions. Change the number of revisions Crossplane maintains with a Provider Package `revisionHistoryLimit`. The `revisionHistoryLimit` field is an integer. The default value is `1`. Disable storing revisions by setting `revisionHistoryLimit` to `0`. For example, to change the default setting and store 10 revisions use `revisionHistoryLimit: 10`. 1apiVersion: pkg.crossplane.io/v1 2kind: Provider 3metadata: 4 name: crossplane-contrib-provider-aws-s3 5spec: 6 revisionHistoryLimit: 10 7# Removed for brevity #### Install a provider from a private registry[](https://docs.crossplane.io/v2.0/packages/providers/#install-a-provider-from-a-private-registry) Like Kubernetes uses `imagePullSecrets` to [install images from private registries](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/) , Crossplane uses `packagePullSecrets` to install Provider packages from a private registry. Use `packagePullSecrets` to provide a Kubernetes secret to use for authentication when downloading a Provider package. Important The Kubernetes secret must be in the same namespace as Crossplane. The `packagePullSecrets` is a list of secrets. For example, to use the secret named `example-secret` configure a `packagePullSecrets`. 1apiVersion: pkg.crossplane.io/v1 2kind: Provider 3metadata: 4 name: crossplane-contrib-provider-aws-s3 5spec: 6 packagePullSecrets: 7 - name: example-secret 8# Removed for brevity Note Configured `packagePullSecrets` aren’t passed to any Provider package dependencies. #### Ignore dependencies[](https://docs.crossplane.io/v2.0/packages/providers/#ignore-dependencies) By default Crossplane installs any [dependencies](https://docs.crossplane.io/v2.0/packages/providers/#manage-dependencies) listed in a Provider package. Crossplane can ignore a Provider package’s dependencies with `skipDependencyResolution`. For example, to disable dependency resolution configure `skipDependencyResolution: true`. 1apiVersion: pkg.crossplane.io/v1 2kind: Provider 3metadata: 4 name: crossplane-contrib-provider-aws-s3 5spec: 6 skipDependencyResolution: true 7# Removed for brevity #### Automatically update dependency versions[](https://docs.crossplane.io/v2.0/packages/providers/#automatically-update-dependency-versions) Crossplane can automatically upgrade a package’s dependency version to the minimum valid version that satisfies all the constraints. It’s an alpha feature that requires enabling with the `--enable-dependency-version-upgrades` flag. Sometimes, Crossplane requires dependency version downgrade for proceeding with installations. Suppose configuration A, which depends on package X with the constraint`>=v0.0.0`, installs on the control plane. In this case, the package manager installs the latest version of package X, such as `v3.0.0`. Later, you decide to install configuration B, which depends on package X with the constraint `<=v2.0.0`. Since version `v2.0.0`satisfies both conditions, Crossplane must downgrade package X to allow the installation of configuration B, which Crossplane disables by default. For enabling automatic dependency version downgrades, there is a configuration option as a helm value `packageManager.enableAutomaticDependencyDowngrade=true`. Downgrading a package can cause unexpected behavior, so this Crossplane disables this option by default. After enabling this option, the package manager automatically downgrades a package’s dependency version to the maximum valid version that satisfies the constraints. Note This configuration requires the `--enable-dependency-version-upgrades` flag. Please see the [configuration options](https://docs.crossplane.io/v2.0/get-started/install/#customize-the-crossplane-helm-chart) and [feature flags](https://docs.crossplane.io/v2.0/get-started/install/#feature-flags) are available in the [Crossplane Install](https://docs.crossplane.io/v2.0/get-started/install/) section for more details. Important Enabling automatic dependency downgrades may have unintended consequences, such as: 1. CRDs missing in the downgraded version, possibly leaving orphaned MRs without controllers to reconcile them. 2. Loss of data if downgraded CRD versions omit fields that you set before. 3. Changes in the CRD storage version, which may prevent package version update. #### Ignore Crossplane version requirements[](https://docs.crossplane.io/v2.0/packages/providers/#ignore-crossplane-version-requirements) A Provider package may require a specific or minimum Crossplane version before installing. By default, Crossplane doesn’t install a Provider if the Crossplane version doesn’t meet the required version. Crossplane can ignore the required version with `ignoreCrossplaneConstraints`. For example, to install a Provider package into an unsupported Crossplane version, configure `ignoreCrossplaneConstraints: true`. 1apiVersion: pkg.crossplane.io/v1 2kind: Provider 3metadata: 4 name: crossplane-contrib-provider-aws-s3 5spec: 6 ignoreCrossplaneConstraints: true 7# Removed for brevity ### Manage dependencies[](https://docs.crossplane.io/v2.0/packages/providers/#manage-dependencies) Providers packages may include dependencies on other packages including Configurations or other Providers. If Crossplane can’t meet the dependencies of a Provider package the Provider reports `HEALTHY` as `False`. For example, this installation of the Getting Started Configuration is `HEALTHY: False`. 1kubectl get providers 2NAME INSTALLED HEALTHY PACKAGE AGE 3crossplane-contrib-provider-aws-s3 True False xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v2.0.0 12s To see more information on why the Provider isn’t `HEALTHY` use `kubectl describe providerrevisions`. 1kubectl describe providerrevisions 2Name: provider-aws-s3-92206523fff4 3API Version: pkg.crossplane.io/v1 4Kind: ProviderRevision 5Spec: 6 Desired State: Active 7 Image: xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v2.0.0 8 Revision: 1 9Status: 10 Conditions: 11 Last Transition Time: 2023-10-10T21:06:39Z 12 Reason: UnhealthyPackageRevision 13 Status: False 14 Type: Healthy 15 Controller Ref: 16 Name: 17Events: 18 Type Reason Age From Message 19 ---- ------ ---- ---- ------- 20 Warning LintPackage 41s (x3 over 47s) packages/providerrevision.pkg.crossplane.io incompatible Crossplane version: package isn't compatible with Crossplane version (v1.10.0) The `Events` show a `Warning` with a message that the current version of Crossplane doesn’t meet the Configuration package requirements. Upgrade a provider[](https://docs.crossplane.io/v2.0/packages/providers/#upgrade-a-provider) --------------------------------------------------------------------------------------------- To upgrade an existing Provider edit the installed Provider Package by either applying a new Provider manifest or with `kubectl edit providers`. Update the version number in the Provider’s `spec.package` and apply the change. Crossplane installs the new image and creates a new `ProviderRevision`. The `ProviderRevision` allows Crossplane to store deprecated Provider CRDs without removing them until you decide. View the `ProviderRevisions` with `kubectl get providerrevisions` 1kubectl get providerrevisions 2NAME HEALTHY REVISION IMAGE STATE DEP-FOUND DEP-INSTALLED AGE 3provider-aws-s3-dbc7f981d81f True 1 xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v2.0.0 Active 1 1 10d 4provider-nop-552a394a8acc True 2 xpkg.crossplane.io/crossplane-contrib/provider-nop:v0.3.0 Active 11d 5provider-nop-7e62d2a1a709 True 1 xpkg.crossplane.io/crossplane-contrib/provider-nop:v0.2.0 Inactive 13d 6crossplane-contrib-provider-family-aws-710d8cfe9f53 True 1 xpkg.crossplane.io/crossplane-contrib/provider-family-aws:v2.0.0 Active 10d By default Crossplane keeps a single `Inactive` Provider. Read the [revision history limit](https://docs.crossplane.io/v2.0/packages/providers/#package-revision-history-limit) section to change the default value. Only a single revision of a Provider is `Active` at a time. Remove a provider[](https://docs.crossplane.io/v2.0/packages/providers/#remove-a-provider) ------------------------------------------------------------------------------------------- Remove a Provider by deleting the Provider object with `kubectl delete provider`. Warning Removing a Provider without first removing the Provider’s managed resources may abandon the resources. The external resources aren’t deleted. If you remove the Provider first, you must manually delete external resources through your cloud provider. Managed resources must be manually deleted by removing their finalizers. For more information on deleting abandoned resources read the [Crossplane troubleshooting guide](https://docs.crossplane.io/v2.0/guides/troubleshoot-crossplane/#deleting-when-a-resource-hangs) . Verify a Provider[](https://docs.crossplane.io/v2.0/packages/providers/#verify-a-provider) ------------------------------------------------------------------------------------------- Providers install their own APIs representing the managed resources they support. Providers may also create Deployments, Service Accounts or RBAC configuration. View the status of a Provider with `kubectl get providers` During the install a Provider report `INSTALLED` as `True` and `HEALTHY` as `Unknown`. 1kubectl get providers 2NAME INSTALLED HEALTHY PACKAGE AGE 3crossplane-contrib-provider-aws-s3 True Unknown xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v2.0.0 63s After the Provider install completes and it’s ready for use the `HEALTHY` status reports `True`. 1kubectl get providers 2NAME INSTALLED HEALTHY PACKAGE AGE 3crossplane-contrib-provider-aws-s3 True True xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v2.0.0 88s Important Some Providers install hundreds of Kubernetes Custom Resource Definitions (`CRDs`). This can create significant strain on undersized API Servers, impacting Provider install times. The Crossplane community has more [details on scaling CRDs](https://github.com/crossplane/crossplane/blob/main/design/one-pager-crd-scaling.md) . ### Provider conditions[](https://docs.crossplane.io/v2.0/packages/providers/#provider-conditions) Crossplane uses a standard set of `Conditions` for Providers. View the conditions of a provider under their `Status` with `kubectl describe provider`. 1kubectl describe provider 2Name: my-provider 3API Version: pkg.crossplane.io/v1 4Kind: Provider 5# Removed for brevity 6Status: 7 Conditions: 8 Reason: HealthyPackageRevision 9 Status: True 10 Type: Healthy 11 Reason: ActivePackageRevision 12 Status: True 13 Type: Installed 14# Removed for brevity #### Types[](https://docs.crossplane.io/v2.0/packages/providers/#types) Provider `Conditions` support two `Types`: * `Type: Installed` - the Provider package installed but isn’t ready for use. * `Type: Healthy` - The Provider package is ready to use. #### Reasons[](https://docs.crossplane.io/v2.0/packages/providers/#reasons) Each `Reason` relates to a specific `Type` and `Status`. Crossplane uses the following `Reasons` for Provider `Conditions`. ##### InactivePackageRevision[](https://docs.crossplane.io/v2.0/packages/providers/#inactivepackagerevision) `Reason: InactivePackageRevision` indicates the Provider Package is using an inactive Provider Package Revision. 1Type: Installed 2Status: False 3Reason: InactivePackageRevision ##### ActivePackageRevision[](https://docs.crossplane.io/v2.0/packages/providers/#activepackagerevision) The Provider Package is the current Package Revision, but Crossplane hasn’t finished installing the Package Revision yet. Tip Providers stuck in this state are because of a problem with Package Revisions. Use `kubectl describe providerrevisions` for more details. 1Type: Installed 2Status: True 3Reason: ActivePackageRevision ##### HealthyPackageRevision[](https://docs.crossplane.io/v2.0/packages/providers/#healthypackagerevision) The Provider is fully installed and ready to use. Tip `Reason: HealthyPackageRevision` is the normal state of a working Provider. 1Type: Healthy 2Status: True 3Reason: HealthyPackageRevision ##### UnhealthyPackageRevision[](https://docs.crossplane.io/v2.0/packages/providers/#unhealthypackagerevision) There was an error installing the Provider Package Revision, preventing Crossplane from installing the Provider Package. Tip Use `kubectl describe providerrevisions` for more details on why the Package Revision failed. 1Type: Healthy 2Status: False 3Reason: UnhealthyPackageRevision ##### UnknownPackageRevisionHealth[](https://docs.crossplane.io/v2.0/packages/providers/#unknownpackagerevisionhealth) The status of the Provider Package Revision is `Unknown`. The Provider Package Revision may be installing or has an issue. Tip Use `kubectl describe providerrevisions` for more details on why the Package Revision failed. 1Type: Healthy 2Status: Unknown 3Reason: UnknownPackageRevisionHealth Configure a Provider[](https://docs.crossplane.io/v2.0/packages/providers/#configure-a-provider) ------------------------------------------------------------------------------------------------- Providers have two different types of configurations: * _Runtime configurations_ that change the settings of the Provider pod running inside the Kubernetes cluster. For example, setting a `toleration` on the Provider pod. * _Provider configurations_ that change settings used when communicating with an external provider. For example, cloud provider authentication. ### Runtime configuration[](https://docs.crossplane.io/v2.0/packages/providers/#runtime-configuration) Important `DeploymentRuntimeConfigs` is a beta feature. It’s on by default, and you can disable it by passing `--enable-deployment-runtime-configs=false` to the Crossplane deployment. Runtime configuration is a generalized mechanism for configuring the runtime for Crossplane packages with a runtime, namely `Providers` and `Functions`. With its default configuration, Crossplane uses Kubernetes Deployments to deploy runtime for packages, more specifically, a controller for a `Provider` or a gRPC server for a `Function`. It’s possible to configure the runtime manifest by applying a `DeploymentRuntimeConfig` and referencing it in the `Provider` or `Function` object. As an example, to enable the external secret stores alpha feature for a `Provider` by adding the `--enable-external-secret-stores` argument to the controller, one can apply the following: 1apiVersion: pkg.crossplane.io/v1 2kind: Provider 3metadata: 4 name: provider-gcp-iam 5spec: 6 package: xpkg.crossplane.io/crossplane-contrib/provider-gcp-iam:v2.0.0 7 runtimeConfigRef: 8 name: enable-ess 9--- 10apiVersion: pkg.crossplane.io/v1beta1 11kind: DeploymentRuntimeConfig 12metadata: 13 name: enable-ess 14spec: 15 deploymentTemplate: 16 spec: 17 selector: {} 18 template: 19 spec: 20 containers: 21 - name: package-runtime 22 args: 23 - --enable-external-secret-stores Please note that the packages manager uses `package-runtime` as the name of the runtime container. When you use a different container name, the package manager introduces it as a sidecar container instead of modifying the package runtime container. The package manager is opinionated about some fields to ensure the runtime is working and overlay them on top of the values in the runtime configuration. For example, it defaults the replica count to 1 if not set and overrides the label selectors to make sure the Deployment and Service match. It also injects any necessary environment variables, ports and volumes and volume mounts. The `Provider` or `Functions`’s `spec.runtimeConfigRef.name` field defaults to value `default`, which means Crossplane uses the default runtime configuration if not specified. Crossplane ensures there is always a default runtime configuration in the cluster, but won’t change it if it already exists. This allows users to customize the default runtime configuration to their needs. Tip Since `DeploymentRuntimeConfig` uses the same schema as Kubernetes `Deployment` spec, you may need to pass empty values to bypass the schema validation. For example, if you just want to change the `replicas` field, you would need to pass the following: 1apiVersion: pkg.crossplane.io/v1beta1 2kind: DeploymentRuntimeConfig 3metadata: 4 name: multi-replicas 5spec: 6 deploymentTemplate: 7 spec: 8 replicas: 2 9 selector: {} 10 template: {} #### Configuring runtime deployment spec[](https://docs.crossplane.io/v2.0/packages/providers/#configuring-runtime-deployment-spec) Using the Deployment spec provided in the `DeploymentRuntimeConfig` as a base, the package manager builds the Deployment spec for the package runtime with the following rules: * Injects the package runtime container as the first container in the `containers` array, with name `package-runtime`. * If not provided, defaults with the following: * `spec.replicas` as 1. * Image pull policy as `IfNotPresent`. * Pod Security Context as: 1runAsNonRoot: true 2runAsUser: 2000 3runAsGroup: 2000 * Security Context for the runtime container as: 1allowPrivilegeEscalation: false 2privileged: false 3runAsGroup: 2000 4runAsNonRoot: true 5runAsUser: 2000 * Applies the following: * **Sets** `metadata.namespace` as Crossplane namespace. * **Sets** `metadata.ownerReferences` such that the deployment owned by the package revision. * **Sets** `spec.selectors` using generated labels. * **Sets** `spec.serviceAccount` with the created **Service Account**. * **Adds** pull secrets provided in the Package spec as image pull secrets, `spec.packagePullSecrets`. * **Sets** the **Image Pull Policy** with the value provided in the Package spec, `spec.packagePullPolicy`. * **Adds** necessary **Ports** to the runtime container. * **Adds** necessary **Environments** to the runtime container. * Mounts TLS secrets by **adding** necessary **Volumes**, **Volume Mounts** and **Environments** to the runtime container. #### Configuring metadata of runtime resources[](https://docs.crossplane.io/v2.0/packages/providers/#configuring-metadata-of-runtime-resources) `DeploymentRuntimeConfig` also enables configuring the following metadata of Runtime resources, namely `Deployment`, `ServiceAccount` and `Service`: * name * labels * annotations The following example shows how to configure the name of the ServiceAccount and the labels of the Deployment: 1apiVersion: pkg.crossplane.io/v1beta1 2kind: DeploymentRuntimeConfig 3metadata: 4 name: my-runtime-config 5spec: 6 deploymentTemplate: 7 metadata: 8 labels: 9 my-label: my-value 10 serviceAccountTemplate: 11 metadata: 12 name: my-service-account Important Setting the `serviceAccountTemplate.metadata.name` field will override the name of service account created by the package manager and used in the provider deployment. The package manager will own that service account and may conflict with other owners attempting to take ownership. A common mistake is configuring the same service account for multiple packages in this way which ends up causing frequent reconciliation loops and loads on the API server. If you just want to use an existing service account, you should instead only set the `deploymentTemplate.spec.template.spec.serviceAccountName` field. Crossplane will then use the existing service account without taking the ownership and still take care of binding the necessary permissions. ### Provider configuration[](https://docs.crossplane.io/v2.0/packages/providers/#provider-configuration) The `ProviderConfig` determines settings the Provider uses communicating to the external provider. Each Provider determines available settings of their `ProviderConfig`. Provider authentication is usually configured with a `ProviderConfig`. For example, to use basic key-pair authentication with Provider AWS a `ProviderConfig` `spec` defines the `credentials` and that the Provider pod should look in the Kubernetes `Secrets` objects and use the key named `aws-creds`. 1apiVersion: aws.m.upbound.io/v1beta1 2kind: ProviderConfig 3metadata: 4 namespace: default 5 name: aws-provider 6spec: 7 credentials: 8 source: Secret 9 secretRef: 10 namespace: crossplane-system 11 name: aws-creds 12 key: creds Important Authentication configuration may be different across Providers. Read the documentation on a specific Provider for instructions on configuring authentication for that Provider. #### ProviderConfig types[](https://docs.crossplane.io/v2.0/packages/providers/#providerconfig-types) The AWS provider supports two types of ProviderConfig resources: **ProviderConfig** (namespace-scoped): 1apiVersion: aws.m.upbound.io/v1beta1 2kind: ProviderConfig 3metadata: 4 namespace: default 5 name: my-config 6# Applies only to MRs in the same namespace **ClusterProviderConfig** (cluster-wide): 1apiVersion: aws.m.upbound.io/v1beta1 2kind: ClusterProviderConfig 3metadata: 4 name: my-cluster-config 5# Applies to MRs across all namespaces When referencing any ProviderConfig, managed resources must specify both `name` and `kind`: 1spec: 2 providerConfigRef: 3 name: my-cluster-config 4 kind: ClusterProviderConfig 1spec: 2 providerConfigRef: 3 name: my-config 4 kind: ProviderConfig # References namespaced ProviderConfig If you omit `providerConfigRef` entirely, it defaults to: 1spec: 2 providerConfigRef: 3 name: default 4 kind: ClusterProviderConfig ProviderConfig objects apply to individual Managed Resources. A single Provider can authenticate with multiple users or accounts through ProviderConfigs. Each account’s credentials tie to a unique ProviderConfig. When creating a managed resource, attach the desired ProviderConfig. For example, two AWS ProviderConfigs, named `user-keys` and `admin-keys` use different Kubernetes secrets. 1apiVersion: aws.m.upbound.io/v1beta1 2kind: ProviderConfig 3metadata: 4 namespace: default 5 name: user-keys 6spec: 7 credentials: 8 source: Secret 9 secretRef: 10 namespace: crossplane-system 11 name: my-key 12 key: secret-key 1apiVersion: aws.m.upbound.io/v1beta1 2kind: ProviderConfig 3metadata: 4 namespace: default 5 name: admin-keys 6spec: 7 credentials: 8 source: Secret 9 secretRef: 10 namespace: crossplane-system 11 name: admin-key 12 key: admin-secret-key Apply the ProviderConfig when creating a managed resource. This creates an AWS `Bucket` resource using the `user-keys` ProviderConfig. 1apiVersion: s3.aws.m.upbound.io/v1beta1 2kind: Bucket 3metadata: 4 namespace: default 5 name: user-bucket 6spec: 7 forProvider: 8 region: us-east-2 9 providerConfigRef: 10 name: user-keys 11 kind: ProviderConfig This creates a second `Bucket` resource using the `admin-keys` ProviderConfig. 1apiVersion: s3.aws.m.upbound.io/v1beta1 2kind: Bucket 3metadata: 4 namespace: default 5 name: admin-bucket 6spec: 7 forProvider: 8 region: us-east-2 9 providerConfigRef: 10 name: admin-keys 11 kind: ProviderConfig --- # Guides · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/#) [master](https://docs.crossplane.io/master/guides/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/) [v1.20](https://docs.crossplane.io/v1.20/guides/) [v1.19](https://docs.crossplane.io/v1.19/guides/) Guides ====== Crossplane integrations and detailed examples. Topics in this section: * [Crossplane Pods](https://docs.crossplane.io/v2.0/guides/pods/) - Components installed with Crossplane * [Metrics](https://docs.crossplane.io/v2.0/guides/metrics/) - Monitor Crossplane operations with metrics * [Function Patch and Transform](https://docs.crossplane.io/v2.0/guides/function-patch-and-transform/) - Write legacy Compositions * [Releasing Crossplane Extensions](https://docs.crossplane.io/v2.0/guides/extensions-release-process/) - Build pipelines for Crossplane extensions * [Write a Composition Function in Go](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-go/) - Build composition functions in Go * [Write a Composition Function in Python](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-python/) - Build composition functions in Python * [Disabling Unused Managed Resources](https://docs.crossplane.io/v2.0/guides/disabling-unused-managed-resources/) - Reduce CRD overhead by disabling unused managed resources * [Implementing safe-start in Providers](https://docs.crossplane.io/v2.0/guides/implementing-safe-start/) - Add selective resource activation to providers * [Import Existing Resources](https://docs.crossplane.io/v2.0/guides/import-existing-resources/) - Import existing resources into your control plane for Crossplane to manage * [Change Logs](https://docs.crossplane.io/v2.0/guides/change-logs/) - Change logs help you audit all changes made to your resources * [Configuring Crossplane with Argo CD](https://docs.crossplane.io/v2.0/guides/crossplane-with-argo-cd/) - Deploy Crossplane resources with GitOps * [Troubleshoot Crossplane](https://docs.crossplane.io/v2.0/guides/troubleshoot-crossplane/) - Debug common Crossplane issues * [Upgrade Crossplane](https://docs.crossplane.io/v2.0/guides/upgrade-crossplane/) - Upgrade Crossplane to newer versions * [Upgrade to Crossplane v2](https://docs.crossplane.io/v2.0/guides/upgrade-to-crossplane-v2/) - Upgrade from Crossplane v1 to v2 * [Uninstall Crossplane](https://docs.crossplane.io/v2.0/guides/uninstall-crossplane/) - Remove Crossplane from your cluster * [Install Crossplane from source code](https://docs.crossplane.io/v2.0/guides/install-from-source/) - Build and install Crossplane from source code into a control plane --- # Metrics · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/metrics/#) [master](https://docs.crossplane.io/master/guides/metrics/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/metrics/) [v1.20](https://docs.crossplane.io/v1.20/guides/metrics/) [v1.19](https://docs.crossplane.io/v1.19/guides/metrics/) Metrics ======= Crossplane produces [Prometheus style metrics](https://prometheus.io/docs/introduction/overview/#what-are-metrics) for effective monitoring and alerting in your environment. These metrics are essential for helping to identify and resolve potential issues. This page offers explanations of all these metrics gathered from Crossplane. Understanding these metrics helps you maintain the health and performance of your resources. Please note that this document focuses on Crossplane specific metrics and doesn’t cover standard Go metrics. To enable the export of metrics it’s necessary to configure the `--set metrics.enabled=true` option in the [helm chart](https://github.com/crossplane/crossplane/blob/main/cluster/charts/crossplane/README.md#configuration) . 1metrics: 2 enabled: true These Prometheus annotations expose the metrics: 1prometheus.io/path: /metrics 2prometheus.io/port: "8080" 3prometheus.io/scrape: "true" | Metric Name | Description | Further Explanation | | --- | --- | --- | | `certwatcher_read_certificate_errors_total` | Total number of certificate read errors | | | `certwatcher_read_certificate_total` | Total number of certificate reads | | | `composition_run_function_seconds_bucket` | Histogram of RunFunctionResponse latency (seconds) | | | `controller_runtime_active_workers` | Number of used workers per controller | The number of threads processing jobs from the work queue. | | `controller_runtime_max_concurrent_reconciles` | Maximum number of concurrent reconciles per controller | Describes how reconciles can happen in parallel. | | `controller_runtime_reconcile_errors_total` | Total number of reconciliation errors per controller | A counter that counts reconcile errors. Sharp or non stop rising of this metric might be a problem. | | `controller_runtime_reconcile_time_seconds_bucket` | Length of time per reconciliation per controller | | | `controller_runtime_reconcile_total` | Total number of reconciliations per controller | | | `controller_runtime_webhook_latency_seconds_bucket` | Histogram of the latency of processing admission requests | | | `controller_runtime_webhook_requests_in_flight` | Current number of admission requests served | | | `controller_runtime_webhook_requests_total` | Total number of admission requests by HTTP status code | | | `rest_client_requests_total` | Number of HTTP requests, partitioned by status code, method, and host | | | `workqueue_adds_total` | Total number of adds handled by `workqueue` | | | `workqueue_depth` | Current depth of `workqueue` | | | `workqueue_longest_running_processor_seconds` | The number of seconds has the longest running processor for `workqueue` been running | | | `workqueue_queue_duration_seconds_bucket` | How long in seconds an item stays in `workqueue` before requested | The time it takes from the moment a job enter the `workqueue` until the processing of this job starts. | | `workqueue_retries_total` | Total number of retries handled by `workqueue` | | | `workqueue_unfinished_work_seconds` | The number of seconds of work done that’s in progress and hasn’t observed by `work_duration`. Large values means stuck threads. | | | `workqueue_work_duration_seconds_bucket` | How long in seconds processing an item from `workqueue` takes | The time it takes from the moment the job start until it finish (either successfully or with an error). | | `crossplane_managed_resource_exists` | The number of managed resources that exist | | | `crossplane_managed_resource_ready` | The number of managed resources in `Ready=True` state | | | `crossplane_managed_resource_synced` | The number of managed resources in `Synced=True` state | | | `upjet_resource_ext_api_duration_bucket` | Measures in seconds how long it takes a Cloud SDK call to complete | | | `upjet_resource_external_api_calls_total` | The number of external API calls | The number of calls to cloud providers, with labels describing the endpoints resources. | | `upjet_resource_reconcile_delay_seconds_bucket` | Measures in seconds how long the reconciles for a resource delay from the configured poll periods | | | `crossplane_managed_resource_deletion_seconds_bucket` | The time it took to delete a managed resource | | | `crossplane_managed_resource_first_time_to_readiness_seconds_bucket` | The time it took for a managed resource to become ready first time after creation | | | `crossplane_managed_resource_first_time_to_reconcile_seconds_bucket` | The time it took to detect a managed resource by the controller | | | `upjet_resource_ttr_bucket` | Measures in seconds the `time-to-readiness` `(TTR)` for managed resources | | --- # Change Logs · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/change-logs/#) [master](https://docs.crossplane.io/master/guides/change-logs/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/change-logs/) [v1.20](https://docs.crossplane.io/v1.20/guides/change-logs/) [v1.19](https://docs.crossplane.io/v1.19/) Change Logs =========== This is an alpha feature. Crossplane may change or drop this feature at any time. This feature was introduced in v1.17. For more information read the [Crossplane feature lifecycle](https://docs.crossplane.io/v2.0/learn/feature-lifecycle/) . On this page **On this page** * * * The change logs feature helps users of Crossplane Providers understand what changes a provider makes to the resources it manages. Whenever a provider creates, updates, or deletes a managed resource, the provider records an entry explaining the details of the change in its change log. Change logs are important for awareness of the changes that a provider is making to its managed resources. Due to the nature of Crossplane’s active reconciliation, it’s possible for a provider to make changes to managed resources without any user interaction. Consider the scenario when someone updates a resource outside of Crossplane, for example via the AWS console or `gcloud` CLI. When Crossplane detects this configuration drift, it enforces the declared state and corrects the unexpected change without any user interaction. With Crossplane acting continuously and autonomously to update critical infrastructure, it’s vital for users to have insight into the operations the provider performs, so they can build and maintain a strong sense of confidence and trust in their control planes. Change logs provide details about all changes the provider makes, so users can remain aware of any changes, even when they aren’t explicitly expecting any. Tip Change logs help you understand all the changes a provider is making to your resources, even when changes weren’t explicitly requested, for example because of Crossplane’s automatic correction of configuration drift. Enabling change logs[](https://docs.crossplane.io/v2.0/guides/change-logs/#enabling-change-logs) ------------------------------------------------------------------------------------------------- Important Change logs are an alpha feature and must be explicitly enabled for each provider through the use of a `DeploymentRuntimeConfig`. To enable change logs for a provider, use a `DeploymentRuntimeConfig` to configure each provider pod that should start producing change logs. The `DeploymentRuntimeConfig` has several important configuration details: 1. A command line argument to the provider container that enables the change logs feature, for example `--enable-changelogs`. 2. A [side car container](https://github.com/crossplane/changelogs-sidecar) that collects change events and produces change log entries to the provider’s pod logs. 3. A shared volume mounted to both the provider and sidecar containers that enables communication of change events between the two containers. ### Prerequisites[](https://docs.crossplane.io/v2.0/guides/change-logs/#prerequisites) This guide assumes you have a control plane with [Crossplane installed](https://docs.crossplane.io/v2.0/get-started/install/) . It also assumes you have the [`jq` tool installed](https://jqlang.org/download/) , to perform lightweight querying and filtering of the content in the change logs. The only other prerequisite for enabling change logs is provider support for the change logs feature. Support for change logs is optional, and not all providers in the Crossplane ecosystem have added it yet. Tip Not all providers support the change logs feature. Check with your provider of choice to confirm it has added support for change logs. This guide walks through a full example of generating change logs with [`provider-kubernetes`](https://github.com/crossplane-contrib/provider-kubernetes) . ### Create a `DeploymentRuntimeConfig`[](https://docs.crossplane.io/v2.0/guides/change-logs/#create-a-deploymentruntimeconfig) Create a `DeploymentRuntimeConfig` that enables change logs for the provider when it’s installed by performing the following configuration steps: 1. Set the `--enable-changelogs` flag on the provider. 2. Add the `sidecar container` to the provider pod. 3. Declare a `shared volume` and mount it in the `provider container` and the `sidecar container`. 1cat < --docker-password= Configuring signature verification[](https://docs.crossplane.io/v2.0/packages/image-configs/#configuring-signature-verification) --------------------------------------------------------------------------------------------------------------------------------- Important Signature verification is an alpha feature and needs to be enabled with the `--enable-signature-verification` feature flag. You can use `ImageConfig` to configure signature verification for images. When you enable signature verification, the package manager verifies the signature of each image before pulling it. If the signature isn’t valid, the package manager rejects the package deployment. In the following example, the `ImageConfig` resource named `verify-acme-packages` configures verification of the signature of images with the prefixes `registry1.com/acme-co/configuration-foo` and `registry1.com/acme-co/configuration-bar`. In the example below, the `ImageConfig` resource named `verify-acme-packages` is set up to verify the signatures of images with the prefixes `registry1.com/acme-co/configuration-foo` and `registry1.com/acme-co/configuration-bar`. 1apiVersion: pkg.crossplane.io/v1beta1 2kind: ImageConfig 3metadata: 4 name: verify-acme-packages 5spec: 6 matchImages: 7 - type: Prefix 8 prefix: registry1.com/acme-co/configuration-foo 9 - type: Prefix 10 prefix: registry1.com/acme-co/configuration-bar 11 verification: 12 provider: Cosign 13 cosign: 14 authorities: 15 - name: verify acme packages 16 keyless: 17 identities: 18 - issuer: https://token.actions.githubusercontent.com 19 subject: https://github.com/acme-co/crossplane-packages/.github/workflows/supplychain.yml@refs/heads/main 20 attestations: 21 - name: verify attestations 22 predicateType: spdxjson `spec.verification.provider` specifies the signature verification provider. The only supported provider is `Cosign`. `spec.verification.cosign` contains the configuration for the Cosign provider. The `authorities` field contains the configuration for the authorities that sign the images. The `attestations` field contains the configuration for verifying the attestations of the images. The `ImageConfig` API follows the same API shape as [Policy Controller](https://docs.sigstore.dev/policy-controller/overview/) from [Sigstore](https://docs.sigstore.dev/) . Crossplane initially supports a subset of the Policy Controller configuration options which can be found in the [API reference](https://docs.crossplane.io/v2.0/api/#ImageConfig-spec-verification-cosign) for the `ImageConfig` resource together with their descriptions. When multiple authorities are provided, the package manager verifies the signature against each authority until it finds a valid one. If any of the authorities’ signatures are valid, the package manager accepts the image. Similarly, when multiple identities or attestations are provided, the package manager verifies until it finds a valid match and fails if none of them matches. Matching the image reference to the `ImageConfig` works similarly to the pull secret configuration, as described in the previous section. ### Checking the signature verification status[](https://docs.crossplane.io/v2.0/packages/image-configs/#checking-the-signature-verification-status) When you enable signature verification, the respective controller reports the verification status as a condition of type `Verified` on the package revision resources. This condition indicates whether the signature verification was successful, failed, skipped, or incomplete due to an error. #### Example conditions[](https://docs.crossplane.io/v2.0/packages/image-configs/#example-conditions) **Verification skipped:** The package manager skipped signature verification for the package revision because there were no matching `ImageConfig` with signature verification configuration. 1 - lastTransitionTime: "2024-10-23T16:38:51Z" 2 reason: SignatureVerificationSkipped 3 status: "True" 4 type: Verified **Verification successful:** The package manager successfully verified the signature of the image in the package revision. 1 - lastTransitionTime: "2024-10-23T16:43:05Z" 2 message: Signature verification succeeded with ImageConfig named "verify-acme-packages" 3 reason: VerificationSucceeded 4 status: "True" 5 type: Verified **Verification failed:** The package manager failed to verify the signature of the image in the package revision. 1 - lastTransitionTime: "2024-10-23T16:42:44Z" 2 message: 'Signature verification failed with ImageConfig named "verify-acme-packages": 3 [signature keyless validation failed for authority verify acme packages\ 4 for registry1.com/acme-co/configuration-foo:v0.2.0: no signatures found: ]' 5 reason: SignatureVerificationFailed 6 status: "False" 7 type: Verified **Verification incomplete:** The package manager encountered an error while verifying the signature of the image in the package revision. 1 - lastTransitionTime: "2024-10-23T16:44:22Z" 2 message: 'Error occurred during signature verification cannot get image verification 3 config: cannot get cosign verification config: no data found for key "cosign.pub" 4 in secret "cosign-public-key"' 5 reason: SignatureVerificationIncomplete 6 status: "False" 7 type: Verified If you can’t see this condition on the package revision resource, namely `ProviderRevision`, `ConfigurationRevision`, or `FunctionRevision`, ensure that you enable the feature. Rewriting image paths[](https://docs.crossplane.io/v2.0/packages/image-configs/#rewriting-image-paths) ------------------------------------------------------------------------------------------------------- You can use an `ImageConfig` to pull package images from an alternative location such as a private registry. `spec.rewriteImages` specifies how to rewrite the paths of matched images. Only prefix replacement is supported. The prefix specified in `spec.rewriteImage.prefix` replaces the matched prefix from `matchImages`. For example, the following `ImageConfig` replaces `xpkg.crossplane.io` with `registry1.com` for any image with the prefix `xpkg.crossplane.io`. 1apiVersion: pkg.crossplane.io/v1beta1 2kind: ImageConfig 3metadata: 4 name: private-registry-rewrite 5spec: 6 matchImages: 7 - prefix: xpkg.crossplane.io 8 rewriteImage: 9 prefix: registry1.com In this example, installing the provider package `xpkg.crossplane.io/crossplane-contrib/provider-nop:v0.4.0` will result in the package manager pulling the provider from `registry1.com/crossplane-contrib/provider-nop:v0.4.0`. Rewriting image paths via `ImageConfig` is useful when mirroring packages to a private registry, because it allows a package and all its dependencies to be pulled from the same registry. For example, the provider `xpkg.crossplane.io/crossplane-contrib/provider-aws-s3` has a dependency on `xpkg.crossplane.io/crossplane-contrib/provider-family-aws`. If you mirror the packages to your own registry at `registry1.com` and install them without an `ImageConfig`, the package manager still attempts to pull the dependency from `xpkg.crossplane.io`. With the preceding `ImageConfig`, the dependency is pulled from `registry1.com`. Rewriting an image path with `ImageConfig` doesn’t change the `spec.package` field of the package resource. The rewritten path is recorded in the `status.resolvedPackage` field. The preceding example results in the following: 1kubectl describe provider crossplane-contrib-provider-family-aws 2... 3Spec: 4 ... 5 Package: xpkg.crossplane.io/crossplane-contrib/provider-family-aws:v1.22.0 6Status: 7 ... 8 Resolved Package: registry1.com/crossplane-contrib/provider-family-aws:v1.22.0 ### Interaction with other operations[](https://docs.crossplane.io/v2.0/packages/image-configs/#interaction-with-other-operations) Tip Image rewriting is always done before other `ImageConfig` operations. If you wish to also configure pull secrets or signature verification as well as rewriting, those `ImageConfig` resources must match the rewritten image path. For example, if you are mirroring packages from `xpkg.crossplane.io` to `registry1.com` and need to configure pull secrets for `registry1.com`, two `ImageConfig` resources are necessary: 1# Rewrite xpkg.crossplane.io -> registry1.com 2--- 3apiVersion: pkg.crossplane.io/v1beta1 4kind: ImageConfig 5metadata: 6 name: private-registry-rewrite 7spec: 8 matchImages: 9 - prefix: xpkg.crossplane.io 10 rewriteImage: 11 prefix: registry1.com 12 13# Configure pull secrets for registry1.com 14--- 15apiVersion: pkg.crossplane.io/v1beta1 16kind: ImageConfig 17metadata: 18 name: private-registry-auth 19spec: 20 matchImages: 21 - type: Prefix 22 prefix: registry1.com 23 registry: 24 authentication: 25 pullSecretRef: 26 name: private-registry-credentials Debugging[](https://docs.crossplane.io/v2.0/packages/image-configs/#debugging) ------------------------------------------------------------------------------- When the package manager selects an `ImageConfig` for a package, it throws an event with the reason `ImageConfigSelection` and the name of the selected `ImageConfig` and injected pull secret. You can find these events both on the package and package revision resources. The package manager also updates the `appliedImageConfigRefs` field in the package status to show the purpose for which each `ImageConfig` was selected. For example, the following event and status show that the `ImageConfig` named `acme-packages` was used to provide a pull secret for the configuration named `acme-configuration-foo`: 1kubectl describe configuration acme-configuration-foo 2... 3Status: 4 Applied Image Config Refs: 5 Name: acme-packages 6 Reason: SetImagePullSecret 7... 8Events: 9 Type Reason Age From Message 10 ---- ------ ---- ---- ------- 11 Normal ImageConfigSelection 45s packages/configuration.pkg.crossplane.io Selected pullSecret "acme-registry-credentials" from ImageConfig "acme-packages" for registry authentication If you can’t find the expected event and `appliedImageConfigRefs` entry, ensure the prefix of the image reference matches the `matchImages` list of any `ImageConfig` resources in the cluster. --- # Releasing Crossplane Extensions · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/extensions-release-process/#) [master](https://docs.crossplane.io/master/guides/extensions-release-process/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/extensions-release-process/) [v1.20](https://docs.crossplane.io/v1.20/guides/extensions-release-process/) [v1.19](https://docs.crossplane.io/v1.19/guides/extensions-release-process/) Releasing Crossplane Extensions =============================== On this page **On this page** * * * Distributing Crossplane extensions[](https://docs.crossplane.io/v2.0/guides/extensions-release-process/#distributing-crossplane-extensions) -------------------------------------------------------------------------------------------------------------------------------------------- Crossplane provides a packaging specification for extending a Crossplane instance with APIs and business logic for composing resources. Building a Crossplane extension involves creating OCI images in the [xpkg](https://github.com/crossplane/crossplane/blob/main/contributing/specifications/xpkg.md) format. Authors and maintainers of Crossplane extensions must push their packages to an OCI registry before users can reference and use them. The release process for Crossplane extensions grew organically in the community and developed its own conventions and common configurations. Authors of these extensions should follow this guide to enable automation for building and pushing their packages as part of their git workflow. This guide provides step-by-step instructions for configuring automated CI pipelines in GitHub Actions for pushing your Crossplane extensions to `xpkg.crossplane.io`, the main registry that the Crossplane community uses today. Tip For more information about Crossplane packages, review the [xpkg concepts](https://docs.crossplane.io/v2.0/packages/) . Note This guide focuses on building and releasing Crossplane extensions. The release process for the core Crossplane software is available in the [`crossplane/release`](https://github.com/crossplane/release) repository. Typical workflow[](https://docs.crossplane.io/v2.0/guides/extensions-release-process/#typical-workflow) -------------------------------------------------------------------------------------------------------- A typical GitHub workflow definition to build and release an extension contains the following steps: 1. Fetching the source repository 2. Authenticating to a remote registry 3. Building and packaging artifacts 4. Pushing (publishing) the artifact Warning The supplied credentials for the remote registry require read and write access as upload requests to the registry specify `push` authorization scope. Quickstart: Releasing a Provider to `xpkg.crossplane.io`[](https://docs.crossplane.io/v2.0/guides/extensions-release-process/#quickstart-releasing-a-provider-to-xpkgcrossplaneio) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### Prerequisites[](https://docs.crossplane.io/v2.0/guides/extensions-release-process/#prerequisites) * A GitHub repository, for example created from the [Upjet template](https://github.com/crossplane/upjet-provider-template) ### Steps[](https://docs.crossplane.io/v2.0/guides/extensions-release-process/#steps) 1. Create a new YAML file under `.github/workflows`. By convention, name this file `publish-provider-package.yaml`. 2. Copy the following workflow definition into the file, replacing `` with the desired name of the repository in the registry. 1name: Publish Provider Package 2 3on: 4 workflow_dispatch: 5 inputs: 6 version: 7 description: "Version string to use while publishing the package (e.g. v1.0.0-alpha.1)" 8 default: '' 9 required: false 10 go-version: 11 description: 'Go version to use if building needs to be done' 12 default: '1.23' 13 required: false 14 15jobs: 16 publish-provider-package: 17 uses: crossplane-contrib/provider-workflows/.github/workflows/publish-provider-non-family.yml@main 18 with: 19 repository: 20 version: ${{ github.event.inputs.version }} 21 go-version: ${{ github.event.inputs.go-version }} 22 cleanup-disk: true 23 secrets: 24 GHCR_PAT: ${{ secrets.GITHUB_TOKEN }} 3. Commit the workflow file to the default branch of the GitHub repository. 4. The workflow should now be available to trigger via the GitHub UI in the `Actions` tab. 5. Create a release branch with the `release-` prefix in the name in the GitHub UI. For example, `release-0.1`. 6. Tag the desired commit on release branch with a valid semver release tag. For example, `v0.1.0`. By default, this is the inferred reference pushed to the registry. 7. Manually run the workflow in the GitHub UI, targeting the release branch from step 5. See [branching conventions](https://docs.crossplane.io/v2.0/guides/extensions-release-process/#branching-conventions) for more details on tagging practices and optionally overriding the inferred git tag version. Quickstart: Releasing a Function to `xpkg.crossplane.io`[](https://docs.crossplane.io/v2.0/guides/extensions-release-process/#quickstart-releasing-a-function-to-xpkgcrossplaneio) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- The template repository for [functions](https://github.com/crossplane/function-template-go/blob/main/.github/workflows/ci.yml) provides a functional GitHub Action YAML file that pushes to `xpkg.crossplane.io` without extra configuration. To build and push a new release to the registry: 1. Cut a release branch with the `release-` prefix in the name in the GitHub UI. For example, `release-0.1`. 2. Tag the desired commit on release branch with a valid semver release tag for a corresponding GitHub Release. For example, `v0.1.0`. 3. Manually run the workflow in the GitHub UI, targeting the release branch from step 1. The workflow generates a default version string if user input isn’t provided. See [branching conventions](https://docs.crossplane.io/v2.0/guides/extensions-release-process/#branching-conventions) for more details on tagging practices and optionally overriding the inferred git tag version. Common configuration[](https://docs.crossplane.io/v2.0/guides/extensions-release-process/#common-configuration) ---------------------------------------------------------------------------------------------------------------- While the reusable workflows referenced in the quickstart guides are for convenience, users may choose to write their own custom GitHub Actions. This and following sections provide more detailed information about common configuration options and conventions to implement the release process. All workflows require references to credentials for a remote registry. Typically, users configure them as [GitHub Actions Secrets](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions) , and the workflow performs authentication via the`docker/login-action` [action](http://github.com/docker/login-action) . For example, adding the following step to a pipeline authenticates the job to `ghcr.io` using the workflow’s ephemeral GitHub OIDC token. 1 - name: Login to GHCR 2 uses: docker/login-action@v3 3 with: 4 registry: ghcr.io 5 username: ${{ github.repository_owner }} 6 password: ${{ secrets.GITHUB_TOKEN }} Important By default, the job’s OIDC token doesn’t have permission to write packages to `ghcr.io`. Permissions are configurable in the GitHub repository’s settings or declared [explicitly](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token) in the workflow definition YAML file. Writing packages requires a `permissions` block with `packages: write` if it isn’t configured elsewhere for the repository. For other registries, it’s still best practice to reference credentials as custom Secret variables. For example: 1 - name: Login to Another Registry 2 uses: docker/login-action@v3 3 with: 4 registry: my-registry.io 5 username: ${{ env.REGISTRY_USER }} 6 password: ${{ secrets.REGISTRY_PASSWORD }} Branching conventions[](https://docs.crossplane.io/v2.0/guides/extensions-release-process/#branching-conventions) ------------------------------------------------------------------------------------------------------------------ Repositories for Crossplane extensions follow similar branching conventions to upstream Crossplane, where the release process assumes the workflow executing in branches with the `release-*` prefix. `main` is often included, though a conventional release process would not build and push off of tags on `main`. 1on: 2 push: 3 branches: 4 - main 5 - release-* For example, when releasing `v0.1.0` of an extension, the conventional process is to cut a release branch `release-0.1` at the git commit where it builds from, and tag it as `v0.1.0`. Note Some custom workflows may accept an explicit input for the remote reference instead of inferring it from a git ref. The [`ci.yml`](https://github.com/crossplane-contrib/function-python/blob/main/.github/workflows/ci.yml) file for `crossplane-contrib/function-python` is a good example. Configuring workflows for function packages[](https://docs.crossplane.io/v2.0/guides/extensions-release-process/#configuring-workflows-for-function-packages) -------------------------------------------------------------------------------------------------------------------------------------------------------------- Function workflow definitions differ based on the base language the function implementation uses. For example, a Python function requires a Python environment in the GitHub Action runner: 1 - name: Setup Python 2 uses: actions/setup-python@v5 3 with: 4 python-version: ${{ env.PYTHON_VERSION }} 5 6 - name: Setup Hatch 7 run: pipx install hatch==1.7.0 8 9 - name: Lint 10 run: hatch run lint:check While the template repository provides a working pipeline definition, users may choose to customize their environment with different tooling. Functions also require a runtime image of the core business logic to build and embed into the Function package. The default workflow definition builds for two platforms: `linux/amd64` and `linux/arm64`. 1 - name: Build Runtime 2 id: image 3 uses: docker/build-push-action@v6 4 with: 5 context: . 6 platforms: linux/${{ matrix.arch }} 7 cache-from: type=gha 8 cache-to: type=gha,mode=max 9 target: image 10 build-args: 11 PYTHON_VERSION=${{ env.PYTHON_VERSION }} 12 outputs: type=docker,dest=runtime-${{ matrix.arch }}.tar Configuring workflows for provider packages[](https://docs.crossplane.io/v2.0/guides/extensions-release-process/#configuring-workflows-for-provider-packages) -------------------------------------------------------------------------------------------------------------------------------------------------------------- Providers, unlike Functions, use custom `make` targets in the [build submodule](https://github.com/crossplane/build) for building and pushing Crossplane Provider packages. Configuring the workflow for a specific registry involves two steps: 1. Updating the registry variables in the top-level `Makefile`. 2. Referencing GitHub Actions Secrets for authorized credentials to the registry. ### Configure target registry[](https://docs.crossplane.io/v2.0/guides/extensions-release-process/#configure-target-registry) The provider template repository includes a top-level [`Makefile`](https://github.com/crossplane/upjet-provider-template/blob/main/Makefile) . Edit the following variables to define the target registry: 1. `XPKG_REG_ORGS` - a space-delimited list of target repositories. 2. `XPKG_REG_ORGS_NO_PROMOTE` - for registries that don’t use or infer channel tags. For example, the following dual-pushes to `xpkg.crossplane.io` and `index.docker.io`: 1XPKG_REG_ORGS ?= xpkg.crossplane.io/crossplane-contrib index.docker.io/crossplanecontrib 2 3XPKG_REG_ORGS_NO_PROMOTE ?= xpkg.crossplane.io/crossplane-contrib Reusable workflows[](https://docs.crossplane.io/v2.0/guides/extensions-release-process/#reusable-workflows) ------------------------------------------------------------------------------------------------------------ The [crossplane-contrib/provider-workflows](https://github.com/crossplane-contrib/provider-workflows/blob/main/.github/workflows) repository provide reusable workflow definitions that are callable from a custom CI pipeline. For example, the following snippet references the callable workflow to build and push the `provider-kubernetes` package to `xpkg.crossplane.io`: 1jobs: 2 publish-provider-package: 3 uses: crossplane-contrib/provider-workflows/.github/workflows/publish-provider-non-family.yml@main 4 with: 5 repository: provider-kubernetes 6 version: ${{ github.event.inputs.version }} 7 go-version: ${{ github.event.inputs.go-version }} 8 cleanup-disk: true 9 secrets: 10 GHCR_PAT: ${{ secrets.GITHUB_TOKEN }} Tip The reusable workflows referenced here publish to `ghcr.io` by default. Ensure that the default GitHub Actions OIDC token inherits the `packages: write` permission. Troubleshooting[](https://docs.crossplane.io/v2.0/guides/extensions-release-process/#troubleshooting) ------------------------------------------------------------------------------------------------------ Why is my workflow is failing with a 404 error code? ---------------------------------------------------- Ensure the target repository exists in the registry. You need to create it if it doesn’t already exist. Why is my workflow failing with a 401 error code? ------------------------------------------------- Ensure the credentials used during the registry login step has authorization to pull and push, and that the `{{ secrets.* }}` variable substitutions match what’s configured in GitHub. --- # Write a Composition Function in Go · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-go/#) [master](https://docs.crossplane.io/master/guides/write-a-composition-function-in-go/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-go/) [v1.20](https://docs.crossplane.io/v1.20/guides/write-a-composition-function-in-go/) [v1.19](https://docs.crossplane.io/v1.19/guides/write-a-composition-function-in-go/) Write a Composition Function in Go ================================== On this page **On this page** * * * Composition functions (or just functions, for short) are custom programs that template Crossplane resources. Crossplane calls composition functions to determine what resources it should create when you create a composite resource (XR). Read the [concepts](https://docs.crossplane.io/v2.0/composition/compositions/) page to learn more about composition functions. You can write a function to template resources using a general purpose programming language. Using a general purpose programming language allows a function to use advanced logic to template resources, like loops and conditionals. This guide explains how to write a composition function in [Go](https://go.dev/) . Important It helps to be familiar with [how composition functions work](https://docs.crossplane.io/v2.0/composition/compositions/#how-composition-functions-work) before following this guide. Understand the steps[](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-go/#understand-the-steps) ------------------------------------------------------------------------------------------------------------------------ This guide covers writing a composition function for an `XBuckets` composite resource (XR). 1apiVersion: example.crossplane.io/v1 2kind: XBuckets 3metadata: 4 name: example-buckets 5spec: 6 region: us-east-2 7 names: 8 - crossplane-functions-example-a 9 - crossplane-functions-example-b 10 - crossplane-functions-example-c An `XBuckets` XR has a region and an array of bucket names. The function will create an Amazon Web Services (AWS) S3 bucket for each entry in the names array. To write a function in Go: 1. [Install the tools you need to write the function](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-go/#install-the-tools-you-need-to-write-the-function) 2. [Initialize the function from a template](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-go/#initialize-the-function-from-a-template) 3. [Edit the template to add the function’s logic](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-go/#edit-the-template-to-add-the-functions-logic) 4. [Test the function end-to-end](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-go/#test-the-function-end-to-end) 5. [Build and push the function to a package repository](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-go/#build-and-push-the-function-to-a-package-registry) This guide covers each of these steps in detail. Install the tools you need to write the function[](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-go/#install-the-tools-you-need-to-write-the-function) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- To write a function in Go you need: * [Go](https://go.dev/dl/) v1.23 or newer. The guide uses Go v1.23. * [Docker Engine](https://docs.docker.com/engine/) . This guide uses Engine v24. * The [Crossplane CLI](https://docs.crossplane.io/v2.0/cli/) v1.17 or newer. This guide uses Crossplane CLI v1.17. Note You don’t need access to a Kubernetes cluster or a Crossplane control plane to build or test a composition function. Initialize the function from a template[](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-go/#initialize-the-function-from-a-template) -------------------------------------------------------------------------------------------------------------------------------------------------------------- Use the `crossplane xpkg init` command to initialize a new function. When you run this command it initializes your function using [a GitHub repository](https://github.com/crossplane/function-template-go) as a template. 1crossplane xpkg init function-xbuckets function-template-go -d function-xbuckets 2Initialized package "function-xbuckets" in directory "/home/negz/control/negz/function-xbuckets" from https://github.com/crossplane/function-template-go/tree/91a1a5eed21964ff98966d72cc6db6f089ad63f4 (main) 3 4To get started: 5 61. Replace `function-template-go` with your function in `go.mod`, 7 `package/crossplane.yaml`, and any Go imports. (You can also do this 8 automatically by running the `./init.sh ` script.) 92. Update `input/v1beta1/` to reflect your desired input (and run `go generate`) 103. Add your logic to `RunFunction` in `fn.go` 114. Add tests for your logic in `fn_test.go` 125. Update `README.md`, to be about your function! 13 14Found init.sh script! 15Do you want to run it? [y]es/[n]o/[v]iew: y 16Function function-xbuckets has been initialised successfully The `crossplane xpkg init` command creates a directory named `function-xbuckets`. When you run the command the new directory should look like this: 1ls function-xbuckets 2Dockerfile LICENSE NOTES.txt README.md example fn.go fn_test.go go.mod go.sum init.sh input main.go package renovate.json The `fn.go` file is where you add the function’s code. It’s useful to know about some other files in the template: * `main.go` runs the function. You don’t need to edit `main.go`. * `Dockerfile` builds the function runtime. You don’t need to edit `Dockerfile`. * The `input` directory defines the function’s input type. * The `package` directory contains metadata used to build the function package. Tip Starting with v1.15 of the Crossplane CLI, `crossplane xpkg init` gives you the option of running an initialization script to automate tasks like replacing the template name with the new function’s name. You must make some changes before you start adding code: * Edit `package/crossplane.yaml` to change the package’s name. * Edit `go.mod` to change the Go module’s name. Name your package `function-xbuckets`. The name of your module depends on where you want to keep your function code. If you push Go code to GitHub, you can use your GitHub username. For example `module github.com/negz/function-xbuckets`. The function in this guide doesn’t use an input type. For this function you should delete the `input` and `package/input` directories. The `input` directory defines a Go struct that a function can use to take input, using the `input` field from a Composition. The [composition functions](https://docs.crossplane.io/v2.0/composition/compositions/#function-input) documentation explains how to pass an input to a composition function. The `package/input` directory contains an OpenAPI schema generated from the structs in the `input` directory. Tip If you’re writing a function that uses an input, edit the input to meet your function’s requirements. Change the input’s kind and API group. Don’t use `Input` and `template.fn.crossplane.io`. Instead use something meaningful to your function. When you edit files under the `input` directory you must update some generated files by running `go generate`. See `input/generate.go` for details. 1go generate ./... Edit the template to add the function’s logic[](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-go/#edit-the-template-to-add-the-functions-logic) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- You add your function’s logic to the `RunFunction` method in `fn.go`. When you first open the file it contains a “hello world” function. 1func (f *Function) RunFunction(_ context.Context, req *fnv1.RunFunctionRequest) (*fnv1.RunFunctionResponse, error) { 2 f.log.Info("Running Function", "tag", req.GetMeta().GetTag()) 3 4 rsp := response.To(req, response.DefaultTTL) 5 6 in := &v1beta1.Input{} 7 if err := request.GetInput(req, in); err != nil { 8 response.Fatal(rsp, errors.Wrapf(err, "cannot get Function input from %T", req)) 9 return rsp, nil 10 } 11 12 response.Normalf(rsp, "I was run with input %q", in.Example) 13 return rsp, nil 14} All Go composition functions have a `RunFunction` method. Crossplane passes everything the function needs to run in a `RunFunctionRequest` struct. The function tells Crossplane what resources it should compose by returning a `RunFunctionResponse` struct. Tip Crossplane generates the `RunFunctionRequest` and `RunFunctionResponse` structs using [Protocol Buffers](http://protobuf.dev/) . You can find detailed schemas for `RunFunctionRequest` and `RunFunctionResponse` in the [Buf Schema Registry](https://buf.build/crossplane/crossplane/docs/main:apiextensions.fn.proto.v1) . Edit the `RunFunction` method to replace it with this code. 1func (f *Function) RunFunction(_ context.Context, req *fnv1.RunFunctionRequest) (*fnv1.RunFunctionResponse, error) { 2 rsp := response.To(req, response.DefaultTTL) 3 4 xr, err := request.GetObservedCompositeResource(req) 5 if err != nil { 6 response.Fatal(rsp, errors.Wrapf(err, "cannot get observed composite resource from %T", req)) 7 return rsp, nil 8 } 9 10 region, err := xr.Resource.GetString("spec.region") 11 if err != nil { 12 response.Fatal(rsp, errors.Wrapf(err, "cannot read spec.region field of %s", xr.Resource.GetKind())) 13 return rsp, nil 14 } 15 16 names, err := xr.Resource.GetStringArray("spec.names") 17 if err != nil { 18 response.Fatal(rsp, errors.Wrapf(err, "cannot read spec.names field of %s", xr.Resource.GetKind())) 19 return rsp, nil 20 } 21 22 desired, err := request.GetDesiredComposedResources(req) 23 if err != nil { 24 response.Fatal(rsp, errors.Wrapf(err, "cannot get desired resources from %T", req)) 25 return rsp, nil 26 } 27 28 _ = v1beta1.AddToScheme(composed.Scheme) 29 30 for _, name := range names { 31 b := &v1beta1.Bucket{ 32 ObjectMeta: metav1.ObjectMeta{ 33 Annotations: map[string]string{ 34 "crossplane.io/external-name": name, 35 }, 36 }, 37 Spec: v1beta1.BucketSpec{ 38 ForProvider: v1beta1.BucketParameters{ 39 Region: ptr.To[string](region), 40 }, 41 }, 42 } 43 44 cd, err := composed.From(b) 45 if err != nil { 46 response.Fatal(rsp, errors.Wrapf(err, "cannot convert %T to %T", b, &composed.Unstructured{})) 47 return rsp, nil 48 } 49 50 desired[resource.Name("xbuckets-"+name)] = &resource.DesiredComposed{Resource: cd} 51 } 52 53 if err := response.SetDesiredComposedResources(rsp, desired); err != nil { 54 response.Fatal(rsp, errors.Wrapf(err, "cannot set desired composed resources in %T", rsp)) 55 return rsp, nil 56 } 57 58 return rsp, nil 59} Expand the below block to view the full `fn.go`, including imports and commentary explaining the function’s logic. The full fn.go file ------------------- 1package main 2 3import ( 4 "context" 5 6 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 7 "k8s.io/utils/ptr" 8 9 "github.com/crossplane-contrib/provider-upjet-aws/apis/s3/v1beta1" 10 11 "github.com/crossplane/function-sdk-go/errors" 12 "github.com/crossplane/function-sdk-go/logging" 13 fnv1 "github.com/crossplane/function-sdk-go/proto/v1" 14 "github.com/crossplane/function-sdk-go/request" 15 "github.com/crossplane/function-sdk-go/resource" 16 "github.com/crossplane/function-sdk-go/resource/composed" 17 "github.com/crossplane/function-sdk-go/response" 18) 19 20// Function returns whatever response you ask it to. 21type Function struct { 22 fnv1.UnimplementedFunctionRunnerServiceServer 23 24 log logging.Logger 25} 26 27// RunFunction observes an XBuckets composite resource (XR). It adds an S3 28// bucket to the desired state for every entry in the XR's spec.names array. 29func (f *Function) RunFunction(_ context.Context, req *fnv1.RunFunctionRequest) (*fnv1.RunFunctionResponse, error) { 30 f.log.Info("Running Function", "tag", req.GetMeta().GetTag()) 31 32 // Create a response to the request. This copies the desired state and 33 // pipeline context from the request to the response. 34 rsp := response.To(req, response.DefaultTTL) 35 36 // Read the observed XR from the request. Most functions use the observed XR 37 // to add desired managed resources. 38 xr, err := request.GetObservedCompositeResource(req) 39 if err != nil { 40 // You can set a custom status condition on the XR. This 41 // allows you to communicate with the user. 42 response.ConditionFalse(rsp, "FunctionSuccess", "InternalError"). 43 WithMessage("Something went wrong."). 44 TargetComposite() 45 46 // You can emit an event regarding the XR. This allows you to 47 // communicate with the user. Note that events should be used 48 // sparingly and are subject to throttling 49 response.Warning(rsp, errors.New("something went wrong")). 50 TargetComposite() 51 52 // If the function can't read the XR, the request is malformed. This 53 // should never happen. The function returns a fatal result. This tells 54 // Crossplane to stop running functions and return an error. 55 response.Fatal(rsp, errors.Wrapf(err, "cannot get observed composite resource from %T", req)) 56 return rsp, nil 57 } 58 59 // Create an updated logger with useful information about the XR. 60 log := f.log.WithValues( 61 "xr-version", xr.Resource.GetAPIVersion(), 62 "xr-kind", xr.Resource.GetKind(), 63 "xr-name", xr.Resource.GetName(), 64 ) 65 66 // Get the region from the XR. The XR has getter methods like GetString, 67 // GetBool, etc. You can use them to get values by their field path. 68 region, err := xr.Resource.GetString("spec.region") 69 if err != nil { 70 response.Fatal(rsp, errors.Wrapf(err, "cannot read spec.region field of %s", xr.Resource.GetKind())) 71 return rsp, nil 72 } 73 74 // Get the array of bucket names from the XR. 75 names, err := xr.Resource.GetStringArray("spec.names") 76 if err != nil { 77 response.Fatal(rsp, errors.Wrapf(err, "cannot read spec.names field of %s", xr.Resource.GetKind())) 78 return rsp, nil 79 } 80 81 // Get all desired composed resources from the request. The function will 82 // update this map of resources, then save it. This get, update, set pattern 83 // ensures the function keeps any resources added by other functions. 84 desired, err := request.GetDesiredComposedResources(req) 85 if err != nil { 86 response.Fatal(rsp, errors.Wrapf(err, "cannot get desired resources from %T", req)) 87 return rsp, nil 88 } 89 90 // Add v1beta1 types (including Bucket) to the composed resource scheme. 91 // composed.From uses this to automatically set apiVersion and kind. 92 _ = v1beta1.AddToScheme(composed.Scheme) 93 94 // Add a desired S3 bucket for each name. 95 for _, name := range names { 96 // One advantage of writing a function in Go is strong typing. The 97 // function can import and use managed resource types from the provider. 98 b := &v1beta1.Bucket{ 99 ObjectMeta: metav1.ObjectMeta{ 100 // Set the external name annotation to the desired bucket name. 101 // This controls what the bucket will be named in AWS. 102 Annotations: map[string]string{ 103 "crossplane.io/external-name": name, 104 }, 105 }, 106 Spec: v1beta1.BucketSpec{ 107 ForProvider: v1beta1.BucketParameters{ 108 // Set the bucket's region to the value read from the XR. 109 Region: ptr.To[string](region), 110 }, 111 }, 112 } 113 114 // Convert the bucket to the unstructured resource data format the SDK 115 // uses to store desired composed resources. 116 cd, err := composed.From(b) 117 if err != nil { 118 response.Fatal(rsp, errors.Wrapf(err, "cannot convert %T to %T", b, &composed.Unstructured{})) 119 return rsp, nil 120 } 121 122 // Add the bucket to the map of desired composed resources. It's 123 // important that the function adds the same bucket every time it's 124 // called. It's also important that the bucket is added with the same 125 // resource.Name every time it's called. The function prefixes the name 126 // with "xbuckets-" to avoid collisions with any other composed 127 // resources that might be in the desired resources map. 128 desired[resource.Name("xbuckets-"+name)] = &resource.DesiredComposed{Resource: cd} 129 } 130 131 // Finally, save the updated desired composed resources to the response. 132 if err := response.SetDesiredComposedResources(rsp, desired); err != nil { 133 response.Fatal(rsp, errors.Wrapf(err, "cannot set desired composed resources in %T", rsp)) 134 return rsp, nil 135 } 136 137 // Log what the function did. This will only appear in the function's pod 138 // logs. A function can use response.Normal and response.Warning to emit 139 // Kubernetes events associated with the XR it's operating on. 140 log.Info("Added desired buckets", "region", region, "count", len(names)) 141 142 // You can set a custom status condition on the XR. This allows you 143 // to communicate with the user. 144 response.ConditionTrue(rsp, "FunctionSuccess", "Success"). 145 TargetComposite() 146 147 return rsp, nil 148} This code: 1. Gets the observed composite resource from the `RunFunctionRequest`. 2. Gets the region and bucket names from the observed composite resource. 3. Adds one desired S3 bucket for each bucket name. 4. Returns the desired S3 buckets in a `RunFunctionResponse`. The code uses the `v1beta1.Bucket` type from the [AWS S3 provider](https://github.com/crossplane-contrib/provider-upjet-aws) . One advantage of writing a function in Go is that you can compose resources using the same strongly typed structs Crossplane uses in its providers. You must get the AWS Provider Go module to use this type: 1go get github.com/crossplane-contrib/provider-upjet-aws@v2.0.0 Crossplane provides a [software development kit](https://github.com/crossplane/function-sdk-go) (SDK) for writing composition functions in [Go](https://go.dev/) . This function uses utilities from the SDK. In particular the `request` and `response` packages make working with the `RunFunctionRequest` and `RunFunctionResponse` types easier. Tip Read the [Go package documentation](https://pkg.go.dev/github.com/crossplane/function-sdk-go) for the SDK. Test the function end-to-end[](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-go/#test-the-function-end-to-end) ---------------------------------------------------------------------------------------------------------------------------------------- Test your function by adding unit tests, and by using the `crossplane render` command. Go has rich support for unit testing. When you initialize a function from the template it adds some unit tests to `fn_test.go`. These tests follow Go’s [recommendations](https://go.dev/wiki/TestComments) . They use only [`pkg/testing`](https://pkg.go.dev/testing) from the Go standard library and [`google/go-cmp`](https://pkg.go.dev/github.com/google/go-cmp/cmp) . To add test cases, update the `cases` map in `TestRunFunction`. Expand the below block to view the full `fn_test.go` file for the function. The full fn\_test.go file ------------------------- 1package main 2 3import ( 4 "context" 5 "testing" 6 "time" 7 8 "github.com/google/go-cmp/cmp" 9 "github.com/google/go-cmp/cmp/cmpopts" 10 "google.golang.org/protobuf/testing/protocmp" 11 "google.golang.org/protobuf/types/known/durationpb" 12 13 "github.com/crossplane/crossplane-runtime/pkg/logging" 14 15 fnv1 "github.com/crossplane/function-sdk-go/proto/v1" 16 "github.com/crossplane/function-sdk-go/resource" 17) 18 19func TestRunFunction(t *testing.T) { 20 type args struct { 21 ctx context.Context 22 req *fnv1.RunFunctionRequest 23 } 24 type want struct { 25 rsp *fnv1.RunFunctionResponse 26 err error 27 } 28 29 cases := map[string]struct { 30 reason string 31 args args 32 want want 33 }{ 34 "AddTwoBuckets": { 35 reason: "The Function should add two buckets to the desired composed resources", 36 args: args{ 37 req: &fnv1.RunFunctionRequest{ 38 Observed: &fnv1.State{ 39 Composite: &fnv1.Resource{ 40 // MustStructJSON is a handy way to provide mock 41 // resources. 42 Resource: resource.MustStructJSON(`{ 43 "apiVersion": "example.crossplane.io/v1alpha1", 44 "kind": "XBuckets", 45 "metadata": { 46 "name": "test" 47 }, 48 "spec": { 49 "region": "us-east-2", 50 "names": [\ 51 "test-bucket-a",\ 52 "test-bucket-b"\ 53 ] 54 } 55 }`), 56 }, 57 }, 58 }, 59 }, 60 want: want{ 61 rsp: &fnv1.RunFunctionResponse{ 62 Meta: &fnv1.ResponseMeta{Ttl: durationpb.New(60 * time.Second)}, 63 Desired: &fnv1.State{ 64 Resources: map[string]*fnv1.Resource{ 65 "xbuckets-test-bucket-a": {Resource: resource.MustStructJSON(`{ 66 "apiVersion": "s3.aws.m.upbound.io/v1beta1", 67 "kind": "Bucket", 68 "metadata": { 69 "annotations": { 70 "crossplane.io/external-name": "test-bucket-a" 71 } 72 }, 73 "spec": { 74 "forProvider": { 75 "region": "us-east-2" 76 } 77 }, 78 "status": { 79 "observedGeneration": 0 80 } 81 }`)}, 82 "xbuckets-test-bucket-b": {Resource: resource.MustStructJSON(`{ 83 "apiVersion": "s3.aws.m.upbound.io/v1beta1", 84 "kind": "Bucket", 85 "metadata": { 86 "annotations": { 87 "crossplane.io/external-name": "test-bucket-b" 88 } 89 }, 90 "spec": { 91 "forProvider": { 92 "region": "us-east-2" 93 } 94 }, 95 "status": { 96 "observedGeneration": 0 97 } 98 }`)}, 99 }, 100 }, 101 Conditions: []*fnv1.Condition{ 102 { 103 Type: "FunctionSuccess", 104 Status: fnv1.Status_STATUS_CONDITION_TRUE, 105 Reason: "Success", 106 Target: fnv1.Target_TARGET_COMPOSITE.Enum(), 107 }, 108 }, 109 }, 110 }, 111 }, 112 } 113 114 for name, tc := range cases { 115 t.Run(name, func(t *testing.T) { 116 f := &Function{log: logging.NewNopLogger()} 117 rsp, err := f.RunFunction(tc.args.ctx, tc.args.req) 118 119 if diff := cmp.Diff(tc.want.rsp, rsp, protocmp.Transform()); diff != "" { 120 t.Errorf("%s\nf.RunFunction(...): -want rsp, +got rsp:\n%s", tc.reason, diff) 121 } 122 123 if diff := cmp.Diff(tc.want.err, err, cmpopts.EquateErrors()); diff != "" { 124 t.Errorf("%s\nf.RunFunction(...): -want err, +got err:\n%s", tc.reason, diff) 125 } 126 }) 127 } 128} Run the unit tests using the `go test` command: 1go test -v -cover . 2=== RUN TestRunFunction 3=== RUN TestRunFunction/AddTwoBuckets 4--- PASS: TestRunFunction (0.00s) 5 --- PASS: TestRunFunction/AddTwoBuckets (0.00s) 6PASS 7coverage: 52.6% of statements 8ok github.com/negz/function-xbuckets 0.016s coverage: 52.6% of statements You can preview the output of a Composition that uses this function using the Crossplane CLI. You don’t need a Crossplane control plane to do this. Under `function-xbuckets`, there is a directory named `example` with Composite Resource, Composition and Function YAML files. Expand the following block to see example files. The xr.yaml, composition.yaml and function.yaml files ----------------------------------------------------- You can recreate the output below using by running `crossplane render` with these files. The `xr.yaml` file contains the composite resource to render: 1apiVersion: example.crossplane.io/v1 2kind: XBuckets 3metadata: 4 name: example-buckets 5spec: 6 region: us-east-2 7 names: 8 - crossplane-functions-example-a 9 - crossplane-functions-example-b 10 - crossplane-functions-example-c The `composition.yaml` file contains the Composition to use to render the composite resource: 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: create-buckets 5spec: 6 compositeTypeRef: 7 apiVersion: example.crossplane.io/v1 8 kind: XBuckets 9 mode: Pipeline 10 pipeline: 11 - step: create-buckets 12 functionRef: 13 name: function-xbuckets The `functions.yaml` file contains the Functions the Composition references in its pipeline steps: 1apiVersion: pkg.crossplane.io/v1 2kind: Function 3metadata: 4 name: function-xbuckets 5 annotations: 6 render.crossplane.io/runtime: Development 7spec: 8 # The CLI ignores this package when using the Development runtime. 9 # You can set it to any value. 10 package: xpkg.crossplane.io/negz/function-xbuckets:v0.1.0 The Function in `functions.yaml` uses the `Development` runtime. This tells `crossplane render` that your function is running locally. It connects to your locally running function instead of using Docker to pull and run the function. 1apiVersion: pkg.crossplane.io/v1 2kind: Function 3metadata: 4 name: function-xbuckets 5 annotations: 6 render.crossplane.io/runtime: Development Use `go run` to run your function locally. 1go run . --insecure --debug Warning The `insecure` flag tells the function to run without encryption or authentication. Only use it during testing and development. In a separate terminal, run `crossplane render`. 1crossplane render xr.yaml composition.yaml functions.yaml This command calls your function. In the terminal where your function is running you should now see log output: 1go run . --insecure --debug 22023-10-31T16:17:32.158-0700 INFO function-xbuckets/fn.go:29 Running Function {"tag": ""} 32023-10-31T16:17:32.159-0700 INFO function-xbuckets/fn.go:125 Added desired buckets {"xr-version": "example.crossplane.io/v1", "xr-kind": "XBuckets", "xr-name": "example-buckets", "region": "us-east-2", "count": 3} The `crossplane render` command prints the desired resources the function returns. 1--- 2apiVersion: example.crossplane.io/v1 3kind: XBuckets 4metadata: 5 name: example-buckets 6--- 7apiVersion: s3.aws.m.upbound.io/v1beta1 8kind: Bucket 9metadata: 10 annotations: 11 crossplane.io/composition-resource-name: xbuckets-crossplane-functions-example-b 12 crossplane.io/external-name: crossplane-functions-example-b 13 generateName: example-buckets- 14 labels: 15 crossplane.io/composite: example-buckets 16 ownerReferences: 17 # Omitted for brevity 18spec: 19 forProvider: 20 region: us-east-2 21--- 22apiVersion: s3.aws.m.upbound.io/v1beta1 23kind: Bucket 24metadata: 25 annotations: 26 crossplane.io/composition-resource-name: xbuckets-crossplane-functions-example-c 27 crossplane.io/external-name: crossplane-functions-example-c 28 generateName: example-buckets- 29 labels: 30 crossplane.io/composite: example-buckets 31 ownerReferences: 32 # Omitted for brevity 33spec: 34 forProvider: 35 region: us-east-2 36--- 37apiVersion: s3.aws.m.upbound.io/v1beta1 38kind: Bucket 39metadata: 40 annotations: 41 crossplane.io/composition-resource-name: xbuckets-crossplane-functions-example-a 42 crossplane.io/external-name: crossplane-functions-example-a 43 generateName: example-buckets- 44 labels: 45 crossplane.io/composite: example-buckets 46 ownerReferences: 47 # Omitted for brevity 48spec: 49 forProvider: 50 region: us-east-2 Tip Read the composition functions documentation to learn more about [testing composition functions](https://docs.crossplane.io/v2.0/composition/compositions/#test-a-composition) . Build and push the function to a package registry[](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-go/#build-and-push-the-function-to-a-package-registry) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- You build a function in two stages. First you build the function’s runtime. This is the Open Container Initiative (OCI) image Crossplane uses to run your function. You then embed that runtime in a package, and push it to a package registry. The Crossplane CLI uses `xpkg.crossplane.io` as its default package registry. A function supports a single platform, like `linux/amd64`, by default. You can support multiple platforms by building a runtime and package for each platform, then pushing all the packages to a single tag in the registry. Pushing your function to a registry allows you to use your function in a Crossplane control plane. See the [composition functions documentation](https://docs.crossplane.io/v2.0/composition/compositions/) to learn how to use a function in a control plane. Use Docker to build a runtime for each platform. 1docker build . --quiet --platform=linux/amd64 --tag runtime-amd64 2sha256:fdf40374cc6f0b46191499fbc1dbbb05ddb76aca854f69f2912e580cfe624b4b 1docker build . --quiet --platform=linux/arm64 --tag runtime-arm64 2sha256:cb015ceabf46d2a55ccaeebb11db5659a2fb5e93de36713364efcf6d699069af Tip You can use whatever tag you want. There’s no need to push the runtime images to a registry. The tag is only used to tell `crossplane xpkg build` what runtime to embed. Use the Crossplane CLI to build a package for each platform. Each package embeds a runtime image. The `--package-root` flag specifies the `package` directory, which contains `crossplane.yaml`. This includes metadata about the package. The `--embed-runtime-image` flag specifies the runtime image tag built using Docker. The `--package-file` flag specifies where to write the package file to disk. Crossplane package files use the extension `.xpkg`. 1crossplane xpkg build \ 2 --package-root=package \ 3 --embed-runtime-image=runtime-amd64 \ 4 --package-file=function-amd64.xpkg 1crossplane xpkg build \ 2 --package-root=package \ 3 --embed-runtime-image=runtime-arm64 \ 4 --package-file=function-arm64.xpkg Tip Crossplane packages are special OCI images. Read more about packages in the [packages documentation](https://docs.crossplane.io/v2.0/packages/configurations/) . Push both package files to a registry. Pushing both files to one tag in the registry creates a [multi-platform](https://docs.docker.com/build/building/multi-platform/) package that runs on both `linux/arm64` and `linux/amd64` hosts. 1crossplane xpkg push \ 2 --package-files=function-amd64.xpkg,function-arm64.xpkg \ 3 negz/function-xbuckets:v0.1.0 Tip If you push the function to a GitHub repository the template automatically sets up continuous integration (CI) using [GitHub Actions](https://github.com/features/actions) . The CI workflow will lint, test, and build your function. You can see how the template configures CI by reading `.github/workflows/ci.yaml`. --- # Configuring Crossplane with Argo CD · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/crossplane-with-argo-cd/#) [master](https://docs.crossplane.io/master/guides/crossplane-with-argo-cd/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/crossplane-with-argo-cd/) [v1.20](https://docs.crossplane.io/v1.20/guides/crossplane-with-argo-cd/) [v1.19](https://docs.crossplane.io/v1.19/guides/crossplane-with-argo-cd/) Configuring Crossplane with Argo CD =================================== On this page **On this page** * * * [Argo CD](https://argoproj.github.io/cd/) and [Crossplane](https://crossplane.io/) are a great combination. Argo CD provides GitOps while Crossplane turns any Kubernetes cluster into a Universal Control Plane for all your resources. Configuration details are required in order for the two to work together properly. This doc will help you understand these requirements. It is recommended to use Argo CD version 2.4.8 or later with Crossplane. Argo CD synchronizes Kubernetes resource manifests stored in a Git repository with those running in a Kubernetes cluster (GitOps). Argo CD has different ways to configure how it tracks resources. With Crossplane, you need to configure Argo CD to use Annotation based resource tracking. See the [Argo CD docs](https://argo-cd.readthedocs.io/en/latest/user-guide/resource_tracking/) for additional detail. ### Configuring Argo CD with Crossplane[](https://docs.crossplane.io/v2.0/guides/crossplane-with-argo-cd/#configuring-argo-cd-with-crossplane) #### Set resource tracking method[](https://docs.crossplane.io/v2.0/guides/crossplane-with-argo-cd/#set-resource-tracking-method) In order for Argo CD to track Application resources that contain Crossplane related objects, configure it to use the annotation mechanism. To configure it, edit the `argocd-cm` `ConfigMap` in the `argocd` `Namespace` as such: 1apiVersion: v1 2kind: ConfigMap 3data: 4 application.resourceTrackingMethod: annotation #### Set health status[](https://docs.crossplane.io/v2.0/guides/crossplane-with-argo-cd/#set-health-status) Argo CD has a built-in health assessment for Kubernetes resources. The community directly supports some checks in Argo’s [repository](https://github.com/argoproj/argo-cd/tree/master/resource_customizations) . For example the `Provider` from `pkg.crossplane.io` already exists which means there no further configuration needed. Argo CD also enable customising these checks per instance, and that’s the mechanism used to provide support of Provider’s CRDs. To configure it, edit the `argocd-cm` `ConfigMap` in the `argocd` `Namespace`. Note `ProviderConfig` may have no status or a `status.users` field. 1apiVersion: v1 2kind: ConfigMap 3data: 4 application.resourceTrackingMethod: annotation 5 resource.customizations: | 6 "*.upbound.io/*": 7 health.lua: | 8 health_status = { 9 status = "Progressing", 10 message = "Provisioning ..." 11 } 12 13 local function contains (table, val) 14 for i, v in ipairs(table) do 15 if v == val then 16 return true 17 end 18 end 19 return false 20 end 21 22 local has_no_status = { 23 "ClusterProviderConfig", 24 "ProviderConfig", 25 "ProviderConfigUsage" 26 } 27 28 if obj.status == nil or next(obj.status) == nil and contains(has_no_status, obj.kind) then 29 health_status.status = "Healthy" 30 health_status.message = "Resource is up-to-date." 31 return health_status 32 end 33 34 if obj.status == nil or next(obj.status) == nil or obj.status.conditions == nil then 35 if (obj.kind == "ProviderConfig" or obj.kind == "ClusterProviderConfig") and obj.status.users ~= nil then 36 health_status.status = "Healthy" 37 health_status.message = "Resource is in use." 38 return health_status 39 end 40 return health_status 41 end 42 43 for i, condition in ipairs(obj.status.conditions) do 44 if condition.type == "LastAsyncOperation" then 45 if condition.status == "False" then 46 health_status.status = "Degraded" 47 health_status.message = condition.message 48 return health_status 49 end 50 end 51 52 if condition.type == "Synced" then 53 if condition.status == "False" then 54 health_status.status = "Degraded" 55 health_status.message = condition.message 56 return health_status 57 end 58 end 59 60 if condition.type == "Ready" then 61 if condition.status == "True" then 62 health_status.status = "Healthy" 63 health_status.message = "Resource is up-to-date." 64 return health_status 65 end 66 end 67 end 68 69 return health_status 70 71 "*.crossplane.io/*": 72 health.lua: | 73 health_status = { 74 status = "Progressing", 75 message = "Provisioning ..." 76 } 77 78 local function contains (table, val) 79 for i, v in ipairs(table) do 80 if v == val then 81 return true 82 end 83 end 84 return false 85 end 86 87 local has_no_status = { 88 "Composition", 89 "CompositionRevision", 90 "DeploymentRuntimeConfig", 91 "ClusterProviderConfig", 92 "ProviderConfig", 93 "ProviderConfigUsage" 94 } 95 if obj.status == nil or next(obj.status) == nil and contains(has_no_status, obj.kind) then 96 health_status.status = "Healthy" 97 health_status.message = "Resource is up-to-date." 98 return health_status 99 end 100 101 if obj.status == nil or next(obj.status) == nil or obj.status.conditions == nil then 102 if (obj.kind == "ProviderConfig" or obj.kind == "ClusterProviderConfig") and obj.status.users ~= nil then 103 health_status.status = "Healthy" 104 health_status.message = "Resource is in use." 105 return health_status 106 end 107 return health_status 108 end 109 110 for i, condition in ipairs(obj.status.conditions) do 111 if condition.type == "LastAsyncOperation" then 112 if condition.status == "False" then 113 health_status.status = "Degraded" 114 health_status.message = condition.message 115 return health_status 116 end 117 end 118 119 if condition.type == "Synced" then 120 if condition.status == "False" then 121 health_status.status = "Degraded" 122 health_status.message = condition.message 123 return health_status 124 end 125 end 126 127 if contains({"Ready", "Healthy", "Offered", "Established", "ValidPipeline", "RevisionHealthy"}, condition.type) then 128 if condition.status == "True" then 129 health_status.status = "Healthy" 130 health_status.message = "Resource is up-to-date." 131 return health_status 132 end 133 end 134 end 135 136 return health_status #### Set resource exclusion[](https://docs.crossplane.io/v2.0/guides/crossplane-with-argo-cd/#set-resource-exclusion) Crossplane providers generate a `ProviderConfigUsage` for each managed resource (MR) they handle. This resource enables representing the relationship between MR and a ProviderConfig so that the controller can use it as a finalizer when you delete a ProviderConfig. End users of Crossplane don’t need to interact with this resource. A growing number of resources and types can impact Argo CD UI reactivity. To help keep this number low, Crossplane recommend hiding all `ProviderConfigUsage` resources from Argo CD UI. To configure resource exclusion edit the `argocd-cm` `ConfigMap` in the `argocd` `Namespace` as such: 1apiVersion: v1 2kind: ConfigMap 3data: 4 resource.exclusions: | 5 - apiGroups: 6 - "*" 7 kinds: 8 - ProviderConfigUsage The use of `"*"` as apiGroups enables the mechanism for all Crossplane Providers. #### Increase Kubernetes client QPS[](https://docs.crossplane.io/v2.0/guides/crossplane-with-argo-cd/#increase-kubernetes-client-qps) As the number of CRDs grow on a control plane it increases the amount of queries Argo CD Application Controller needs to send to the Kubernetes API. If this is the case you can increase the rate limits of the Argo CD Kubernetes client. Set the environment variable `ARGOCD_K8S_CLIENT_QPS` to `300` for improved compatibility with multiple CRDs. The default value of `ARGOCD_K8S_CLIENT_QPS` is 50, modifying the value also updates `ARGOCD_K8S_CLIENT_BURST` as it is default to `ARGOCD_K8S_CLIENT_QPS` x 2. --- # Troubleshoot Crossplane · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/troubleshoot-crossplane/#) [master](https://docs.crossplane.io/master/guides/troubleshoot-crossplane/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/troubleshoot-crossplane/) [v1.20](https://docs.crossplane.io/v1.20/guides/troubleshoot-crossplane/) [v1.19](https://docs.crossplane.io/v1.19/guides/troubleshoot-crossplane/) Troubleshoot Crossplane ======================= On this page **On this page** * * * Requested resource not found[](https://docs.crossplane.io/v2.0/guides/troubleshoot-crossplane/#requested-resource-not-found) ----------------------------------------------------------------------------------------------------------------------------- If you use the Crossplane CLI to install a `Provider` or `Configuration` (for example, `crossplane xpkg install provider xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v2.0.0`) and get `the server could not find the requested resource` error, more often than not, that’s an indicator that your Crossplane CLI needs updating. In other words Crossplane graduated some API from alpha to beta or stable and the old plugin isn’t aware of this change. Resource status and conditions[](https://docs.crossplane.io/v2.0/guides/troubleshoot-crossplane/#resource-status-and-conditions) --------------------------------------------------------------------------------------------------------------------------------- Most Crossplane resources have a `status` section that can represent the current state of that particular resource. Running `kubectl describe` against a Crossplane resource frequently gives insightful information about its condition. For example, to determine the status of a GCP `CloudSQLInstance` managed resource use `kubectl describe` for the resource. 1kubectl describe cloudsqlinstance my-db 2Status: 3 Conditions: 4 Last Transition Time: 2019-09-16T13:46:42Z 5 Reason: Creating 6 Status: False 7 Type: Ready Most Crossplane resources set the `Ready` condition. `Ready` represents the availability of the resource - whether it’s creating, deleting, available, unavailable, binding, etc. Resource events[](https://docs.crossplane.io/v2.0/guides/troubleshoot-crossplane/#resource-events) --------------------------------------------------------------------------------------------------- Most Crossplane resources emit _events_ when something interesting happens. You can see the events associated with a resource by running `kubectl describe` - for example, `kubectl describe cloudsqlinstance my-db`. You can also see all events in a particular namespace by running `kubectl get events`. 1Events: 2 Type Reason Age From Message 3 ---- ------ ---- ---- ------- 4 Warning CannotConnectToProvider 16s (x4 over 46s) managed/postgresqlserver.database.azure.crossplane.io cannot get referenced ProviderConfig: ProviderConfig.azure.crossplane.io "default" not found > Note that Kubernetes namespaces events, while most Crossplane resources (XRs, etc) are cluster scoped. Crossplane emits events for cluster scoped resources to the ‘default’ namespace. Crossplane Logs[](https://docs.crossplane.io/v2.0/guides/troubleshoot-crossplane/#crossplane-logs) --------------------------------------------------------------------------------------------------- The next place to look to get more information or investigate a failure would be in the Crossplane pod logs, which should be running in the `crossplane-system` namespace. To get the current Crossplane logs, run the following: 1kubectl -n crossplane-system logs -lapp=crossplane > Note that Crossplane emits minimal logs by default - events are typically the best place to look for information about what Crossplane is doing. You may need to restart Crossplane with the `--debug` flag if you can’t find what you’re looking for. Provider logs[](https://docs.crossplane.io/v2.0/guides/troubleshoot-crossplane/#provider-logs) ----------------------------------------------------------------------------------------------- Remember that providers provide much of Crossplane’s features. You can use `kubectl logs` to view provider logs too. By convention, they also emit minimal logs by default. 1kubectl -n crossplane-system logs All providers maintained by the Crossplane community mirror Crossplane’s support of the `--debug` flag. The easiest way to set flags on a provider is to create a `DeploymentRuntimeConfig` and reference it from the `Provider`: 1apiVersion: pkg.crossplane.io/v1beta1 2kind: DeploymentRuntimeConfig 3metadata: 4 name: debug-config 5spec: 6 deploymentTemplate: 7 spec: 8 selector: {} 9 template: 10 spec: 11 containers: 12 - name: package-runtime 13 args: 14 - --debug 15--- 16apiVersion: pkg.crossplane.io/v1 17kind: Provider 18metadata: 19 name: crossplane-contrib-provider-aws-s3 20spec: 21 package: xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v2.0.0 22 runtimeConfigRef: 23 apiVersion: pkg.crossplane.io/v1beta1 24 kind: DeploymentRuntimeConfig 25 name: debug-config > Note that you can add a reference to a `DeploymentRuntimeConfig` to an already installed `Provider` and it updates its `Deployment` accordingly. Pausing Crossplane[](https://docs.crossplane.io/v2.0/guides/troubleshoot-crossplane/#pausing-crossplane) --------------------------------------------------------------------------------------------------------- Sometimes, for example when you encounter a bug, it can be useful to pause Crossplane if you want to stop it from actively attempting to manage your resources. To pause Crossplane without deleting all its resources, run the following command to scale down its deployment: 1kubectl -n crossplane-system scale --replicas=0 deployment/crossplane After you have been able to rectify the problem or smooth things out, you can unpause Crossplane by scaling its deployment back up: 1kubectl -n crossplane-system scale --replicas=1 deployment/crossplane Pausing Providers[](https://docs.crossplane.io/v2.0/guides/troubleshoot-crossplane/#pausing-providers) ------------------------------------------------------------------------------------------------------- You can also pause Providers when troubleshooting an issue or orchestrating a complex migration of resources. Creating and referencing a `DeploymentRuntimeConfig` is the easiest way to scale down a provider, and you can change the `DeploymentRuntimeConfig` or remove the reference to scale it back up: 1apiVersion: pkg.crossplane.io/v1beta1 2kind: DeploymentRuntimeConfig 3metadata: 4 name: scale-config 5spec: 6 deploymentTemplate: 7 spec: 8 selector: {} 9 replicas: 0 10 template: {} 11--- 12apiVersion: pkg.crossplane.io/v1 13kind: Provider 14metadata: 15 name: crossplane-contrib-provider-aws-s3 16spec: 17 package: xpkg.crossplane.io/crossplane-contrib/provider-aws-s3:v2.0.0 18 runtimeConfigRef: 19 apiVersion: pkg.crossplane.io/v1beta1 20 kind: DeploymentRuntimeConfig 21 name: scale-config > Note that you can add a reference to a `DeploymentRuntimeConfig` to an already installed `Provider` and it updates its `Deployment` accordingly. Deleting when a resource hangs[](https://docs.crossplane.io/v2.0/guides/troubleshoot-crossplane/#deleting-when-a-resource-hangs) --------------------------------------------------------------------------------------------------------------------------------- The resources that Crossplane manages are automatically cleaned up so as not to leave anything running behind. Crossplane accomplishes this by using finalizers, but in certain scenarios the finalizer can prevent the Kubernetes object from getting deleted. To deal with this, patch the object to remove its finalizer, which then allows Kubernetes to delete it. Note that this doesn’t necessarily delete the external resource that Crossplane was managing, so you want to go to your cloud provider’s console and look there for any lingering resources to clean up. In general, you can remove a finalizer from an object with this command: 1kubectl patch -p '{"metadata":{"finalizers": []}}' --type=merge For example, for a `CloudSQLInstance` managed resource (`database.gcp.crossplane.io`) named `my-db`, you can remove its finalizer with: 1kubectl patch cloudsqlinstance my-db -p '{"metadata":{"finalizers": []}}' --type=merge Tips, tricks, and troubleshooting[](https://docs.crossplane.io/v2.0/guides/troubleshoot-crossplane/#tips-tricks-and-troubleshooting) ------------------------------------------------------------------------------------------------------------------------------------- This section covers some common tips, tricks, and troubleshooting steps for working with Composite Resources. If you’re trying to track down why your Composite Resources aren’t working the \[Troubleshooting\]\[trouble-ref\] page also has some useful information. --- # Write a Composition Function in Python · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-python/#) [master](https://docs.crossplane.io/master/guides/write-a-composition-function-in-python/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-python/) [v1.20](https://docs.crossplane.io/v1.20/guides/write-a-composition-function-in-python/) [v1.19](https://docs.crossplane.io/v1.19/guides/write-a-composition-function-in-python/) Write a Composition Function in Python ====================================== On this page **On this page** * * * Composition functions (or just functions, for short) are custom programs that template Crossplane resources. Crossplane calls composition functions to determine what resources it should create when you create a composite resource (XR). Read the [concepts](https://docs.crossplane.io/v2.0/composition/compositions/) page to learn more about composition functions. You can write a function to template resources using a general purpose programming language. Using a general purpose programming language allows a function to use advanced logic to template resources, like loops and conditionals. This guide explains how to write a composition function in [Python](https://python.org/) . Important It helps to be familiar with [how composition functions work](https://docs.crossplane.io/v2.0/composition/compositions/#how-composition-functions-work) before following this guide. Understand the steps[](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-python/#understand-the-steps) ---------------------------------------------------------------------------------------------------------------------------- This guide covers writing a composition function for an `XBuckets` composite resource (XR). 1apiVersion: example.crossplane.io/v1 2kind: XBuckets 3metadata: 4 name: example-buckets 5spec: 6 region: us-east-2 7 names: 8 - crossplane-functions-example-a 9 - crossplane-functions-example-b 10 - crossplane-functions-example-c An `XBuckets` XR has a region and an array of bucket names. The function will create an Amazon Web Services (AWS) S3 bucket for each entry in the names array. To write a function in Python: 1. [Install the tools you need to write the function](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-python/#install-the-tools-you-need-to-write-the-function) 2. [Initialize the function from a template](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-python/#initialize-the-function-from-a-template) 3. [Edit the template to add the function’s logic](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-python/#edit-the-template-to-add-the-functions-logic) 4. [Test the function end-to-end](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-python/#test-the-function-end-to-end) 5. [Build and push the function to a package repository](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-python/#build-and-push-the-function-to-a-package-registry) This guide covers each of these steps in detail. Install the tools you need to write the function[](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-python/#install-the-tools-you-need-to-write-the-function) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ To write a function in Python you need: * [Python](https://www.python.org/downloads/) v3.11. * [Hatch](https://hatch.pypa.io/) , a Python build tool. This guide uses v1.7. * [Docker Engine](https://docs.docker.com/engine/) . This guide uses Engine v24. * The [Crossplane CLI](https://docs.crossplane.io/v2.0/cli/) v1.14 or newer. This guide uses Crossplane CLI v1.14. Note You don’t need access to a Kubernetes cluster or a Crossplane control plane to build or test a composition function. Initialize the function from a template[](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-python/#initialize-the-function-from-a-template) ------------------------------------------------------------------------------------------------------------------------------------------------------------------ Use the `crossplane xpkg init` command to initialize a new function. When you run this command it initializes your function using [a GitHub repository](https://github.com/crossplane/function-template-python) as a template. 1crossplane xpkg init function-xbuckets https://github.com/crossplane/function-template-python -d function-xbuckets 2Initialized package "function-xbuckets" in directory "/home/negz/control/negz/function-xbuckets" from https://github.com/crossplane/function-template-python/tree/bfed6923ab4c8e7adeed70f41138645fc7d38111 (main) The `crossplane xpkg init` command creates a directory named `function-xbuckets`. When you run the command the new directory should look like this: 1ls function-xbuckets 2Dockerfile example/ function/ LICENSE package/ pyproject.toml README.md renovate.json tests/ Your function’s code lives in the `function` directory: 1ls function/ 2__version__.py fn.py main.py The `function/fn.py` file is where you add the function’s code. It’s useful to know about some other files in the template: * `function/main.py` runs the function. You don’t need to edit `main.py`. * `Dockerfile` builds the function runtime. You don’t need to edit `Dockerfile`. * The `package` directory contains metadata used to build the function package. Tip In v1.14 of the Crossplane CLI `crossplane xpkg init` just clones a template GitHub repository. A future CLI release will automate tasks like replacing the template name with the new function’s name. See Crossplane issue [#4941](https://github.com/crossplane/crossplane/issues/4941) for details. Edit `package/crossplane.yaml` to change the package’s name before you start adding code. Name your package `function-xbuckets`. The `package/input` directory defines the OpenAPI schema for the a function’s input. The function in this guide doesn’t accept an input. Delete the `package/input` directory. The [composition functions](https://docs.crossplane.io/v2.0/composition/compositions/) documentation explains composition function inputs. Tip If you’re writing a function that uses an input, edit the input YAML file to meet your function’s requirements. Change the input’s kind and API group. Don’t use `Input` and `template.fn.crossplane.io`. Instead use something meaningful to your function. Edit the template to add the function’s logic[](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-python/#edit-the-template-to-add-the-functions-logic) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- You add your function’s logic to the `RunFunction` method in `function/fn.py`. When you first open the file it contains a “hello world” function. 1async def RunFunction(self, req: fnv1.RunFunctionRequest, _: grpc.aio.ServicerContext) -> fnv1.RunFunctionResponse: 2 log = self.log.bind(tag=req.meta.tag) 3 log.info("Running function") 4 5 rsp = response.to(req) 6 7 example = "" 8 if "example" in req.input: 9 example = req.input["example"] 10 11 # TODO: Add your function logic here! 12 response.normal(rsp, f"I was run with input {example}!") 13 log.info("I was run!", input=example) 14 15 return rsp All Python composition functions have a `RunFunction` method. Crossplane passes everything the function needs to run in a `RunFunctionRequest` object. The function tells Crossplane what resources it should compose by returning a `RunFunctionResponse` object. Edit the `RunFunction` method to replace it with this code. 1async def RunFunction(self, req: fnv1.RunFunctionRequest, _: grpc.aio.ServicerContext) -> fnv1.RunFunctionResponse: 2 log = self.log.bind(tag=req.meta.tag) 3 log.info("Running function") 4 5 rsp = response.to(req) 6 7 region = req.observed.composite.resource["spec"]["region"] 8 names = req.observed.composite.resource["spec"]["names"] 9 10 for name in names: 11 rsp.desired.resources[f"xbuckets-{name}"].resource.update( 12 { 13 "apiVersion": "s3.aws.m.upbound.io/v1beta1", 14 "kind": "Bucket", 15 "metadata": { 16 "annotations": { 17 "crossplane.io/external-name": name, 18 }, 19 }, 20 "spec": { 21 "forProvider": { 22 "region": region, 23 }, 24 }, 25 } 26 ) 27 28 log.info("Added desired buckets", region=region, count=len(names)) 29 30 return rsp Expand the below block to view the full `fn.py`, including imports and commentary explaining the function’s logic. The full fn.py file ------------------- 1"""A Crossplane composition function.""" 2 3import grpc 4from crossplane.function import logging, response 5from crossplane.function.proto.v1 import run_function_pb2 as fnv1 6from crossplane.function.proto.v1 import run_function_pb2_grpc as grpcv1 7 8 9class FunctionRunner(grpcv1.FunctionRunnerService): 10 """A FunctionRunner handles gRPC RunFunctionRequests.""" 11 12 def __init__(self): 13 """Create a new FunctionRunner.""" 14 self.log = logging.get_logger() 15 16 async def RunFunction( 17 self, req: fnv1.RunFunctionRequest, _: grpc.aio.ServicerContext 18 ) -> fnv1.RunFunctionResponse: 19 """Run the function.""" 20 # Create a logger for this request. 21 log = self.log.bind(tag=req.meta.tag) 22 log.info("Running function") 23 24 # Create a response to the request. This copies the desired state and 25 # pipeline context from the request to the response. 26 rsp = response.to(req) 27 28 # Get the region and a list of bucket names from the observed composite 29 # resource (XR). Crossplane represents resources using the Struct 30 # well-known protobuf type. The Struct Python object can be accessed 31 # like a dictionary. 32 region = req.observed.composite.resource["spec"]["region"] 33 names = req.observed.composite.resource["spec"]["names"] 34 35 # Add a desired S3 bucket for each name. 36 for name in names: 37 # Crossplane represents desired composed resources using a protobuf 38 # map of messages. This works a little like a Python defaultdict. 39 # Instead of assigning to a new key in the dict-like map, you access 40 # the key and mutate its value as if it did exist. 41 # 42 # The below code works because accessing the xbuckets-{name} key 43 # automatically creates a new, empty fnv1.Resource message. The 44 # Resource message has a resource field containing an empty Struct 45 # object that can be populated from a dictionary by calling update. 46 # 47 # https://protobuf.dev/reference/python/python-generated/#map-fields 48 rsp.desired.resources[f"xbuckets-{name}"].resource.update( 49 { 50 "apiVersion": "s3.aws.m.upbound.io/v1beta1", 51 "kind": "Bucket", 52 "metadata": { 53 "annotations": { 54 "crossplane.io/external-name": name, 55 }, 56 }, 57 "spec": { 58 "forProvider": { 59 "region": region, 60 }, 61 }, 62 } 63 ) 64 65 # Log what the function did. This will only appear in the function's pod 66 # logs. A function can use response.normal() and response.warning() to 67 # emit Kubernetes events associated with the XR it's operating on. 68 log.info("Added desired buckets", region=region, count=len(names)) 69 70 return rsp This code: 1. Gets the observed composite resource from the `RunFunctionRequest`. 2. Gets the region and bucket names from the observed composite resource. 3. Adds one desired S3 bucket for each bucket name. 4. Returns the desired S3 buckets in a `RunFunctionResponse`. Crossplane provides a [software development kit](https://github.com/crossplane/function-sdk-python) (SDK) for writing composition functions in Python. This function uses utilities from the SDK. Tip Read [the Python Function SDK documentation](https://crossplane.github.io/function-sdk-python) . Important The Python SDK automatically generates the `RunFunctionRequest` and `RunFunctionResponse` Python objects from a [Protocol Buffers](https://protobuf.dev/) schema. You can see the schema in the [Buf Schema Registry](https://buf.build/crossplane/crossplane/docs/main:apiextensions.fn.proto.v1) . The fields of the generated Python objects behave similarly to builtin Python types like dictionaries and lists. Be aware that there are some differences. Notably, you access the map of observed and desired resources like a dictionary but you can’t add a new desired resource by assigning to a map key. Instead, access and mutate the map key as if it already exists. Instead of adding a new resource like this: 1resource = {"apiVersion": "example.org/v1", "kind": "Composed", ...} 2rsp.desired.resources["new-resource"] = fnv1.Resource(resource=resource) Pretend it already exists and mutate it, like this: 1resource = {"apiVersion": "example.org/v1", "kind": "Composed", ...} 2rsp.desired.resources["new-resource"].resource.update(resource) Refer to the Protocol Buffers [Python Generated Code Guide](https://protobuf.dev/reference/python/python-generated/#fields) for further details. Test the function end-to-end[](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-python/#test-the-function-end-to-end) -------------------------------------------------------------------------------------------------------------------------------------------- Test your function by adding unit tests, and by using the `crossplane render` command. When you initialize a function from the template it adds some unit tests to `tests/test_fn.py`. These tests use the [`unittest`](https://docs.python.org/3/library/unittest.html) module from the Python standard library. To add test cases, update the `cases` list in `test_run_function`. Expand the below block to view the full `tests/test_fn.py` file for the function. The full test\_fn.py file ------------------------- 1import dataclasses 2import unittest 3 4from crossplane.function import logging, resource 5from crossplane.function.proto.v1 import run_function_pb2 as fnv1 6from google.protobuf import duration_pb2 as durationpb 7from google.protobuf import json_format 8from google.protobuf import struct_pb2 as structpb 9 10from function import fn 11 12 13class TestFunctionRunner(unittest.IsolatedAsyncioTestCase): 14 def setUp(self) -> None: 15 logging.configure(level=logging.Level.DISABLED) 16 self.maxDiff = 2000 17 18 async def test_run_function(self) -> None: 19 @dataclasses.dataclass 20 class TestCase: 21 reason: str 22 req: fnv1.RunFunctionRequest 23 want: fnv1.RunFunctionResponse 24 25 cases = [\ 26 TestCase(\ 27 reason="The function should compose two S3 buckets.",\ 28 req=fnv1.RunFunctionRequest(\ 29 observed=fnv1.State(\ 30 composite=fnv1.Resource(\ 31 resource=resource.dict_to_struct(\ 32 {\ 33 "apiVersion": "example.crossplane.io/v1alpha1",\ 34 "kind": "XBuckets",\ 35 "metadata": {"name": "test"},\ 36 "spec": {\ 37 "region": "us-east-2",\ 38 "names": ["test-bucket-a", "test-bucket-b"],\ 39 },\ 40 }\ 41 )\ 42 )\ 43 )\ 44 ),\ 45 want=fnv1.RunFunctionResponse(\ 46 meta=fnv1.ResponseMeta(ttl=durationpb.Duration(seconds=60)),\ 47 desired=fnv1.State(\ 48 resources={\ 49 "xbuckets-test-bucket-a": fnv1.Resource(\ 50 resource=resource.dict_to_struct(\ 51 {\ 52 "apiVersion": "s3.aws.m.upbound.io/v1beta1",\ 53 "kind": "Bucket",\ 54 "metadata": {\ 55 "annotations": {\ 56 "crossplane.io/external-name": "test-bucket-a"\ 57 },\ 58 },\ 59 "spec": {\ 60 "forProvider": {"region": "us-east-2"}\ 61 },\ 62 }\ 63 )\ 64 ),\ 65 "xbuckets-test-bucket-b": fnv1.Resource(\ 66 resource=resource.dict_to_struct(\ 67 {\ 68 "apiVersion": "s3.aws.m.upbound.io/v1beta1",\ 69 "kind": "Bucket",\ 70 "metadata": {\ 71 "annotations": {\ 72 "crossplane.io/external-name": "test-bucket-b"\ 73 },\ 74 },\ 75 "spec": {\ 76 "forProvider": {"region": "us-east-2"}\ 77 },\ 78 }\ 79 )\ 80 ),\ 81 },\ 82 ),\ 83 context=structpb.Struct(),\ 84 ),\ 85 ),\ 86 ] 87 88 runner = fn.FunctionRunner() 89 90 for case in cases: 91 got = await runner.RunFunction(case.req, None) 92 self.assertEqual( 93 json_format.MessageToDict(got), 94 json_format.MessageToDict(case.want), 95 "-want, +got", 96 ) 97 98 99if __name__ == "__main__": 100 unittest.main() Run the unit tests using `hatch run`: 1hatch run test:unit 2. 3---------------------------------------------------------------------- 4Ran 1 test in 0.003s 5 6OK Tip [Hatch](https://hatch.pypa.io/) is a Python build tool. It builds Python artifacts like wheels. It also manages virtual environments, similar to `virtualenv` or `venv`. The `hatch run` command creates a virtual environment and runs a command in that environment. You can preview the output of a Composition that uses this function using the Crossplane CLI. You don’t need a Crossplane control plane to do this. Create a directory under `function-xbuckets` named `example` and create Composite Resource, Composition and Function YAML files. Expand the following block to see example files. The xr.yaml, composition.yaml and function.yaml files ----------------------------------------------------- You can recreate the output below using by running `crossplane render` with these files. The `xr.yaml` file contains the composite resource to render: 1apiVersion: example.crossplane.io/v1 2kind: XBuckets 3metadata: 4 name: example-buckets 5spec: 6 region: us-east-2 7 names: 8 - crossplane-functions-example-a 9 - crossplane-functions-example-b 10 - crossplane-functions-example-c The `composition.yaml` file contains the Composition to use to render the composite resource: 1apiVersion: apiextensions.crossplane.io/v1 2kind: Composition 3metadata: 4 name: create-buckets 5spec: 6 compositeTypeRef: 7 apiVersion: example.crossplane.io/v1 8 kind: XBuckets 9 mode: Pipeline 10 pipeline: 11 - step: create-buckets 12 functionRef: 13 name: function-xbuckets The `functions.yaml` file contains the Functions the Composition references in its pipeline steps: 1apiVersion: pkg.crossplane.io/v1 2kind: Function 3metadata: 4 name: function-xbuckets 5 annotations: 6 render.crossplane.io/runtime: Development 7spec: 8 # The CLI ignores this package when using the Development runtime. 9 # You can set it to any value. 10 package: xpkg.crossplane.io/negz/function-xbuckets:v0.1.0 The Function in `functions.yaml` uses the `Development` runtime. This tells `crossplane render` that your function is running locally. It connects to your locally running function instead of using Docker to pull and run the function. 1apiVersion: pkg.crossplane.io/v1 2kind: Function 3metadata: 4 name: function-xbuckets 5 annotations: 6 render.crossplane.io/runtime: Development Use `hatch run development` to run your function locally. 1hatch run development Warning `hatch run development` runs the function without encryption or authentication. Only use it during testing and development. In a separate terminal, run `crossplane render`. 1crossplane render xr.yaml composition.yaml functions.yaml This command calls your function. In the terminal where your function is running you should now see log output: 1hatch run development 22024-01-11T22:12:58.153572Z [info ] Running function filename=fn.py lineno=22 tag= 32024-01-11T22:12:58.153792Z [info ] Added desired buckets count=3 filename=fn.py lineno=68 region=us-east-2 tag= The `crossplane render` command prints the desired resources the function returns. 1--- 2apiVersion: example.crossplane.io/v1 3kind: XBuckets 4metadata: 5 name: example-buckets 6--- 7apiVersion: s3.aws.m.upbound.io/v1beta1 8kind: Bucket 9metadata: 10 annotations: 11 crossplane.io/composition-resource-name: xbuckets-crossplane-functions-example-b 12 crossplane.io/external-name: crossplane-functions-example-b 13 generateName: example-buckets- 14 labels: 15 crossplane.io/composite: example-buckets 16 ownerReferences: 17 # Omitted for brevity 18spec: 19 forProvider: 20 region: us-east-2 21--- 22apiVersion: s3.aws.m.upbound.io/v1beta1 23kind: Bucket 24metadata: 25 annotations: 26 crossplane.io/composition-resource-name: xbuckets-crossplane-functions-example-c 27 crossplane.io/external-name: crossplane-functions-example-c 28 generateName: example-buckets- 29 labels: 30 crossplane.io/composite: example-buckets 31 ownerReferences: 32 # Omitted for brevity 33spec: 34 forProvider: 35 region: us-east-2 36--- 37apiVersion: s3.aws.m.upbound.io/v1beta1 38kind: Bucket 39metadata: 40 annotations: 41 crossplane.io/composition-resource-name: xbuckets-crossplane-functions-example-a 42 crossplane.io/external-name: crossplane-functions-example-a 43 generateName: example-buckets- 44 labels: 45 crossplane.io/composite: example-buckets 46 ownerReferences: 47 # Omitted for brevity 48spec: 49 forProvider: 50 region: us-east-2 Tip Read the composition functions documentation to learn more about [testing composition functions](https://docs.crossplane.io/v2.0/composition/compositions/#test-a-composition) . Build and push the function to a package registry[](https://docs.crossplane.io/v2.0/guides/write-a-composition-function-in-python/#build-and-push-the-function-to-a-package-registry) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- You build a function in two stages. First you build the function’s runtime. This is the Open Container Initiative (OCI) image Crossplane uses to run your function. You then embed that runtime in a package, and push it to a package registry. The Crossplane CLI uses `xpkg.crossplane.io` as its default package registry. A function supports a single platform, like `linux/amd64`, by default. You can support multiple platforms by building a runtime and package for each platform, then pushing all the packages to a single tag in the registry. Pushing your function to a registry allows you to use your function in a Crossplane control plane. See the [composition functions documentation](https://docs.crossplane.io/v2.0/composition/compositions/) . to learn how to use a function in a control plane. Use Docker to build a runtime for each platform. 1docker build . --quiet --platform=linux/amd64 --tag runtime-amd64 2sha256:fdf40374cc6f0b46191499fbc1dbbb05ddb76aca854f69f2912e580cfe624b4b 1docker build . --quiet --platform=linux/arm64 --tag runtime-arm64 2sha256:cb015ceabf46d2a55ccaeebb11db5659a2fb5e93de36713364efcf6d699069af Tip You can use whatever tag you want. There’s no need to push the runtime images to a registry. The tag is only used to tell `crossplane xpkg build` what runtime to embed. Important Docker uses emulation to create images for different platforms. If building an image for a different platform fails, make sure you have installed `binfmt`. See the [Docker documentation](https://docs.docker.com/build/building/multi-platform/#qemu) for instructions. Use the Crossplane CLI to build a package for each platform. Each package embeds a runtime image. The `--package-root` flag specifies the `package` directory, which contains `crossplane.yaml`. This includes metadata about the package. The `--embed-runtime-image` flag specifies the runtime image tag built using Docker. The `--package-file` flag specifies where to write the package file to disk. Crossplane package files use the extension `.xpkg`. 1crossplane xpkg build \ 2 --package-root=package \ 3 --embed-runtime-image=runtime-amd64 \ 4 --package-file=function-amd64.xpkg 1crossplane xpkg build \ 2 --package-root=package \ 3 --embed-runtime-image=runtime-arm64 \ 4 --package-file=function-arm64.xpkg Tip Crossplane packages are special OCI images. Read more about packages in the [packages documentation](https://docs.crossplane.io/v2.0/packages/configurations/) . Push both package files to a registry. Pushing both files to one tag in the registry creates a [multi-platform](https://docs.docker.com/build/building/multi-platform/) package that runs on both `linux/arm64` and `linux/amd64` hosts. 1crossplane xpkg push \ 2 --package-files=function-amd64.xpkg,function-arm64.xpkg \ 3 negz/function-xbuckets:v0.1.0 Tip If you push the function to a GitHub repository the template automatically sets up continuous integration (CI) using [GitHub Actions](https://github.com/features/actions) . The CI workflow will lint, test, and build your function. You can see how the template configures CI by reading `.github/workflows/ci.yaml`. --- # Feature Lifecycle · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/learn/feature-lifecycle/#) [master](https://docs.crossplane.io/master/learn/feature-lifecycle/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/learn/feature-lifecycle/) [v1.20](https://docs.crossplane.io/v1.20/learn/feature-lifecycle/) [v1.19](https://docs.crossplane.io/v1.19/learn/feature-lifecycle/) Feature Lifecycle ================= On this page **On this page** * * * Feature lifecycle ================= Crossplane follows a similar feature lifecycle to [upstream Kubernetes](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/#feature-stages) . Crossplane adds all major new features in alpha. Alpha features graduate to beta, and then to general availability (GA). Features that languish at alpha or beta may be subject to deprecation. Alpha features[](https://docs.crossplane.io/v2.0/learn/feature-lifecycle/#alpha-features) ------------------------------------------------------------------------------------------ Alpha features are off by default, and you must enable them by a feature flag, for example `--enable-composition-revisions`. API types for alpha features use a `vNalphaN` style API version, like `v1alpha`. **Alpha features are subject to removal or breaking changes without notice**, and aren’t considered ready for use in production. Sometimes alpha features require Crossplane to add fields to existing beta or GA API types. In these cases you must mark fields (for instance in their OpenAPI schema) as alpha and subject to alpha API constraints (or lack thereof). All alpha features should have an issue tracking their graduation to beta. Beta features[](https://docs.crossplane.io/v2.0/learn/feature-lifecycle/#beta-features) ---------------------------------------------------------------------------------------- Beta features are on by default, but you may disable them by a feature flag. API types for beta features use a `vNbetaN` style API version, like `v1beta1`. Crossplane considers beta features to be well tested, and doesn’t removed without Crossplane marking them deprecated for at least two releases. The schema and/or semantics of objects may change in incompatible ways in a later beta or stable release. When this happens, the team provides instructions for migrating to the next version. This may require deleting, editing, and recreating API objects. The editing process may require some thought. This may require downtime for applications that rely on the feature. Sometimes beta features require Crossplane to add fields to existing GA API types. In these cases you must mark fields (for instance in their OpenAPI schema) as beta and subject to beta API constraints (or lack thereof). All beta features should have an issue tracking their graduation to GA. GA features[](https://docs.crossplane.io/v2.0/learn/feature-lifecycle/#ga-features) ------------------------------------------------------------------------------------ GA features are always enabled - you can’t disable them. API types pertaining to GA features use `vN` style API versions, like `v1`. GA features are widely used and well tested. They guarantee API stability - Crossplane only allows backward compatible changes. --- # Learn More · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/learn/#) [master](https://docs.crossplane.io/master/learn/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/learn/) [v1.20](https://docs.crossplane.io/v1.20/learn/) [v1.19](https://docs.crossplane.io/v1.19/learn/) Learn More ========== If you have any questions, please post in [Crossplane Slack](https://slack.crossplane.io/) or [contact the team](https://github.com/crossplane/crossplane#contact) . _**Learn more about using Crossplane**_ * [Latest Design Docs](https://github.com/crossplane/crossplane/tree/main/design) * [Roadmap](https://github.com/crossplane/crossplane/blob/main/ROADMAP.md) * [Crossplane Architecture](https://docs.google.com/document/d/1whncqdUeU2cATGEJhHvzXWC9xdK29Er45NJeoemxebo/edit?usp=sharing) * [GitLab deploys into multiple clouds from kubectl using Crossplane](https://about.gitlab.com/2019/05/20/gitlab-first-deployed-kubernetes-api-to-multiple-clouds/) * [CNCF Talks & Community Presentations](https://www.youtube.com/playlist?list=PL510POnNVaaZJj9OG6PbgsZvgYbhwJRyE) * [Software Engineering Daily - Intro Podcast](https://softwareengineeringdaily.com/2019/01/02/crossplane-multicloud-control-plane-with-bassam-tabbara/) _**Writing Kubernetes controllers to extend Crossplane**_ * [Keep the Space Shuttle Flying: Writing Robust Operators](https://www.youtube.com/watch?v=uf97lOApOv8) * [Best practices for building Kubernetes Operators](https://cloud.google.com/blog/products/containers-kubernetes/best-practices-for-building-kubernetes-operators-and-stateful-apps) * [Programming Kubernetes Book](https://www.oreilly.com/library/view/programming-kubernetes/9781492047094/) * [Contributor Guide](https://github.com/crossplane/crossplane/blob/main/CONTRIBUTING.md) _**Join the growing Crossplane community and get involved**_ * Join the [Community Slack](https://slack.crossplane.io/) ! * Submit an issue on [GitHub](https://github.com/crossplane/crossplane) * Attend the biweekly [Community Meeting](https://github.com/crossplane/crossplane#get-involved) * Join the biweekly live stream: [The Binding Status](https://github.com/crossplane/tbs) * Subscribe to the [YouTube Channel](https://www.youtube.com/channel/UC19FgzMBMqBro361HbE46Fw) * Follow on Twitter: [@crossplane\_io](https://twitter.com/crossplane_io) * email: [crossplane-info@lists.cncf.io](mailto:crossplane-info@lists.cncf.io) --- # CLI Reference · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/cli/#) [master](https://docs.crossplane.io/master/cli/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/cli/) [v1.20](https://docs.crossplane.io/v1.20/cli/) [v1.19](https://docs.crossplane.io/v1.19/cli/) CLI Reference ============= On this page **On this page** * * * The Crossplane CLI helps simplify some development and administration aspects of Crossplane. The Crossplane CLI includes: * tools to build, install, update and push Crossplane Packages * standalone Composition Function testing and rendering without the need to access a Kubernetes cluster running Crossplane * troubleshoot Crossplane Compositions, Composite Resources and Managed Resources Installing the CLI[](https://docs.crossplane.io/v2.0/cli/#installing-the-cli) ------------------------------------------------------------------------------ The Crossplane CLI is a single standalone binary with no external dependencies. Note Install the Crossplane CLI on a user’s computer. Most Crossplane CLI commands are independent of Kubernetes and don’t require access to a Crossplane pod. To download the latest version for your CPU architecture with the Crossplane install script. 1curl -sL "https://raw.githubusercontent.com/crossplane/crossplane/main/install.sh" | sh [The script](https://raw.githubusercontent.com/crossplane/crossplane/main/install.sh) detects your CPU architecture and downloads the latest stable release. Manually install the Crossplane CLI ----------------------------------- If you don’t want to run shell script you can manually download a binary from the Crossplane releases repository at [https://releases.crossplane.io/stable/current/bin](https://releases.crossplane.io/stable/current/bin) Important The release repository names the CLI `crank`. Download this file. The `crossplane` binary is the Kubernetes Crossplane pod image. Move the binary to a location in your `$PATH`, for example `/usr/local/bin`. ### Download other CLI versions[](https://docs.crossplane.io/v2.0/cli/#download-other-cli-versions) Download different Crossplane CLI versions or different release branches with the `XP_CHANNEL` and `XP_VERSION` environmental variables. By default the CLI installs from the `XP_CHANNEL` named `stable` and the `XP_VERSION` of `current`, matching the most recent stable release. For example, to install CLI version `v1.20.0` add `XP_VERSION=v1.20.0` to the download script curl command: 1curl -sL "https://raw.githubusercontent.com/crossplane/crossplane/main/install.sh" | XP_VERSION=v1.20.0 sh To install the CLI from the `master` channel add `XP_CHANNEL=master`: 1curl -sL "https://raw.githubusercontent.com/crossplane/crossplane/main/install.sh" | XP_CHANNEL=master sh --- # Import Existing Resources · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/import-existing-resources/#) [master](https://docs.crossplane.io/master/guides/import-existing-resources/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/guides/import-existing-resources/) [v1.20](https://docs.crossplane.io/v1.20/guides/import-existing-resources/) [v1.19](https://docs.crossplane.io/v1.19/guides/import-existing-resources/) Import Existing Resources ========================= On this page **On this page** * * * If you have resources that are already provisioned in a Provider, you can import them as managed resources and let Crossplane manage them. A managed resource’s [`managementPolicies`](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#managementpolicies) field enables importing external resources into Crossplane. Import resources in observe only mode[](https://docs.crossplane.io/v2.0/guides/import-existing-resources/#import-resources-in-observe-only-mode) ------------------------------------------------------------------------------------------------------------------------------------------------- Start by importing external resources with an `Observe` [management policy](https://docs.crossplane.io/v2.0/managed-resources/managed-resources/#managementpolicies) . Crossplane imports observe only resources but never changes or deletes the resources. Important The managed resource `managementPolicies` option is a beta feature. The Provider determines support for management policies. Refer to the Provider’s documentation to see if the Provider supports management policies. ### Apply the Observe management policy[](https://docs.crossplane.io/v2.0/guides/import-existing-resources/#apply-the-observe-management-policy) Create a new managed resource matching the `apiVersion` and `kind` of the resource to import and add `managementPolicies: ["Observe"]` to the `spec` For example, to import a GCP SQL DatabaseInstance, create a new resource with the `managementPolicies: ["Observe"]` set. 1apiVersion: sql.gcp.upbound.io/v1beta1 2kind: DatabaseInstance 3spec: 4 managementPolicies: ["Observe"] ### Add the external-name annotation[](https://docs.crossplane.io/v2.0/guides/import-existing-resources/#add-the-external-name-annotation) Add the `crossplane.io/external-name` annotation for the resource. This name must match the name inside the Provider. For example, for a GCP database named `my-external-database`, apply the `crossplane.io/external-name` annotation with the value `my-external-database`. 1apiVersion: sql.gcp.upbound.io/v1beta1 2kind: DatabaseInstance 3metadata: 4 annotations: 5 crossplane.io/external-name: my-external-database 6spec: 7 managementPolicies: ["Observe"] ### Create a Kubernetes object name[](https://docs.crossplane.io/v2.0/guides/import-existing-resources/#create-a-kubernetes-object-name) Create a `name` to use for the Kubernetes object. For example, name the Kubernetes object `my-imported-database`. 1apiVersion: sql.gcp.upbound.io/v1beta1 2kind: DatabaseInstance 3metadata: 4 name: my-imported-database 5 annotations: 6 crossplane.io/external-name: my-external-database 7spec: 8 managementPolicies: ["Observe"] ### Identify a specific external resource[](https://docs.crossplane.io/v2.0/guides/import-existing-resources/#identify-a-specific-external-resource) If more than one resource inside the Provider shares the same name, identify the specific resource with a unique `spec.forProvider` field. For example, only import the GCP SQL database in the `us-central1` region. 1apiVersion: sql.gcp.upbound.io/v1beta1 2kind: DatabaseInstance 3metadata: 4 name: my-imported-database 5 annotations: 6 crossplane.io/external-name: my-external-database 7spec: 8 managementPolicies: ["Observe"] 9 forProvider: 10 region: "us-central1" ### Apply the managed resource[](https://docs.crossplane.io/v2.0/guides/import-existing-resources/#apply-the-managed-resource) Apply the new managed resource. Crossplane syncs the status of the external resource in the cloud with the newly created managed resource. ### View the discovered resource[](https://docs.crossplane.io/v2.0/guides/import-existing-resources/#view-the-discovered-resource) Crossplane discovers the managed resource and populates the `status.atProvider` fields with the values from the external resource. 1apiVersion: sql.gcp.upbound.io/v1beta1 2kind: DatabaseInstance 3metadata: 4 name: my-imported-database 5 annotations: 6 crossplane.io/external-name: my-external-database 7spec: 8 managementPolicies: ["Observe"] 9 forProvider: 10 region: us-central1 11status: 12 atProvider: 13 connectionName: crossplane-playground:us-central1:my-external-database 14 databaseVersion: POSTGRES_14 15 deletionProtection: true 16 firstIpAddress: 35.184.74.79 17 id: my-external-database 18 publicIpAddress: 35.184.74.79 19 region: us-central1 20 # Removed for brevity 21 settings: 22 - activationPolicy: ALWAYS 23 availabilityType: REGIONAL 24 diskSize: 100 25 # Removed for brevity 26 pricingPlan: PER_USE 27 tier: db-custom-4-26624 28 version: 4 29 conditions: 30 - lastTransitionTime: "2023-02-22T07:16:51Z" 31 reason: Available 32 status: "True" 33 type: Ready 34 - lastTransitionTime: "2023-02-22T07:16:51Z" 35 reason: ReconcileSuccess 36 status: "True" 37 type: Synced Control imported observe only resources[](https://docs.crossplane.io/v2.0/guides/import-existing-resources/#control-imported-observe-only-resources) ----------------------------------------------------------------------------------------------------------------------------------------------------- Crossplane can take active control of observe only imported resources by changing the `managementPolicies` after import. Change the `managementPolicies` field of the managed resource to `["*"]`. Copy any required parameter values from `status.atProvider` and provide them in `spec.forProvider`. Tip Manually copy the important `spec.atProvider` values to `spec.forProvider`. 1apiVersion: sql.gcp.upbound.io/v1beta1 2kind: DatabaseInstance 3metadata: 4 name: my-imported-database 5 annotations: 6 crossplane.io/external-name: my-external-database 7spec: 8 managementPolicies: ["*"] 9 forProvider: 10 databaseVersion: POSTGRES_14 11 region: us-central1 12 settings: 13 - diskSize: 100 14 tier: db-custom-4-26624 15status: 16 atProvider: 17 databaseVersion: POSTGRES_14 18 region: us-central1 19 # Removed for brevity 20 settings: 21 - diskSize: 100 22 tier: db-custom-4-26624 23 # Removed for brevity 24 conditions: 25 - lastTransitionTime: "2023-02-22T07:16:51Z" 26 reason: Available 27 status: "True" 28 type: Ready 29 - lastTransitionTime: "2023-02-22T11:16:45Z" 30 reason: ReconcileSuccess 31 status: "True" 32 type: Synced Crossplane now fully manages the imported resource. Crossplane applies any changes to the managed resource in the Provider’s external resource. --- # Release Cycle · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/learn/release-cycle/#) [master](https://docs.crossplane.io/master/learn/release-cycle/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/learn/release-cycle/) [v1.20](https://docs.crossplane.io/v1.20/learn/release-cycle/) [v1.19](https://docs.crossplane.io/v1.19/learn/release-cycle/) Release Cycle ============= On this page **On this page** * * * Starting with the v1.10.0 release, Crossplane releases on a quarterly (13 week) cadence. A cycle comprises three general stages: * Weeks 1—11: [Active Development](https://docs.crossplane.io/v2.0/learn/release-cycle/#active-development) * Week 12: [Feature Freeze](https://docs.crossplane.io/v2.0/learn/release-cycle/#feature-freeze) * Week 13: [Code Freeze](https://docs.crossplane.io/v2.0/learn/release-cycle/#code-freeze) This results in four releases per year, with the most recent three releases under maintenance at any given time. When Crossplane cuts a new release, the fourth most recent release reaches end of life (EOL). Users can expect Crossplane to maintain any given release for nine months. ### Definition of maintenance[](https://docs.crossplane.io/v2.0/learn/release-cycle/#definition-of-maintenance) The Crossplane community defines maintenance in that relevant bug fixes that merge to the main development branch are eligible for backporting to the release branch of any maintained version, and Crossplane cuts patch releases appropriately. It’s also possible that maintainers merge a fix directly to the release branch if no longer applicable on the main development branch. Maintenance doesn’t include any SLA on response time for user support in the form of Slack messages or issues, but maintainers and contributors address problems on a best effort basis for maintained releases. ### Patch releases[](https://docs.crossplane.io/v2.0/learn/release-cycle/#patch-releases) _This policy is subject to change in the future._ Crossplane cuts patch releases for maintained minor versions on an as needed basis. Crossplane includes any critical backported fixes in a patch release as soon as possible after merge. ### Pre-releases[](https://docs.crossplane.io/v2.0/learn/release-cycle/#pre-releases) _This policy is subject to change in the future._ Crossplane cuts Alpha, Beta, and RC releases for an upcoming release on an as needed basis. As a policy, Crossplane cuts at least one pre-release before any minor release. Crossplane doesn’t make pre-releases on release branches. ### Provider releases[](https://docs.crossplane.io/v2.0/learn/release-cycle/#provider-releases) Other Crossplane projects don’t need to adhere to the Crossplane release cycle, but Crossplane encourages a similar cadence. Maintainers listed in each repository’s `OWNERS.md` file are responsible for determining and publishing the release cycle for their project. Release stages[](https://docs.crossplane.io/v2.0/learn/release-cycle/#release-stages) -------------------------------------------------------------------------------------- The following stages are the main milestones in a Crossplane release. ### Active development[](https://docs.crossplane.io/v2.0/learn/release-cycle/#active-development) During active development, maintainers merge any code that meets the requisite criteria (such as passing appropriate tests, approved by a maintainer, etc.) into the main development branch. At present, there is no need to formally submit an enhancement proposal before the start of the release cycle, but Crossplane encourages contributors to open an issue and gather feedback before starting work on a major implementation (see [CONTRIBUTING.md](https://github.com/crossplane/crossplane/blob/main/CONTRIBUTING.md) for more information). ### Feature freeze[](https://docs.crossplane.io/v2.0/learn/release-cycle/#feature-freeze) During feature freeze, maintainers shouldn’t merge new features into the main development branch. Maintainers may make bug fixes, documentation changes, and non critical changes. In the case that maintainers deem a new feature essential for a release, the Crossplane maintainers weigh the impact of the change and make a decision on whether to include it. ### Code freeze[](https://docs.crossplane.io/v2.0/learn/release-cycle/#code-freeze) During code freeze, there should be no changes merged to the main development branch with the following exceptions: * Fixes to a failing test that’s deemed to be incorrectly testing features. * Documentation only changes. It’s possible that a documentation freeze is implemented in the future, but it’s not enforced. * Fixes to a critical bug that wasn’t identified before. Merging a bug fix during code freeze requires requesting and approval of an exception by Crossplane maintainers. This process is informal, but may be formalized in the future. Release dates[](https://docs.crossplane.io/v2.0/learn/release-cycle/#release-dates) ------------------------------------------------------------------------------------ Crossplane releases once a quarter (every 13 weeks). Typically, the release happens on the Tuesday of the last week of the quarter, as shown on the [community calendar](https://zoom-lfx.platform.linuxfoundation.org/meetings/crossplane) . Keep in mind that the specific date is **approximate**. A lot of factors can alter the date slightly, such as code reviews, testing, and bug fixing to ensure a quality release. Release process[](https://docs.crossplane.io/v2.0/learn/release-cycle/#release-process) ---------------------------------------------------------------------------------------- The release process for the Crossplane project is fully documented in the [`crossplane/release`](https://github.com/crossplane/release) repository. --- # Command Reference · Crossplane v2.0 [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/cli/command-reference/#) [master](https://docs.crossplane.io/master/cli/command-reference/) [v2.0\ \ Latest](https://docs.crossplane.io/v2.0/cli/command-reference/) [v1.20](https://docs.crossplane.io/v1.20/cli/command-reference/) [v1.19](https://docs.crossplane.io/v1.19/cli/command-reference/) Command Reference ================= On this page **On this page** * * * The `crossplane` CLI provides utilities to make using Crossplane easier. Read the [Crossplane CLI overview](https://docs.crossplane.io/v2.0/cli/) page for information on installing `crossplane`. Global flags[](https://docs.crossplane.io/v2.0/cli/command-reference/#global-flags) ------------------------------------------------------------------------------------ The following flags are available for all commands. | Short flag | Long flag | Description | | --- | --- | --- | | `-h` | `--help` | Show context sensitive help. | | | `--verbose` | Print verbose output. | version[](https://docs.crossplane.io/v2.0/cli/command-reference/#version) -------------------------------------------------------------------------- The `crossplane version` command returns the version of Crossplane CLI and the control plane. 1crossplane version 2Client Version: v1.17.0 3Server Version: v1.17.0 render[](https://docs.crossplane.io/v2.0/cli/command-reference/#render) ------------------------------------------------------------------------ The `crossplane render` command previews the output of a [composite resource](https://docs.crossplane.io/v2.0/composition/composite-resources/) after applying any [composition functions](https://docs.crossplane.io/v2.0/composition/compositions/) . Important The `crossplane render` command requires you to use composition functions. The `crossplane render` command connects to the locally running Docker Engine to pull and run composition functions. Important Running `crossplane render` requires [Docker](https://www.docker.com/) . Provide a composite resource, composition and composition function YAML definition with the command to render the output locally. For example, `crossplane render xr.yaml composition.yaml function.yaml` The output includes the original composite resource followed by the generated managed resources. An example render output ------------------------ 1--- 2apiVersion: nopexample.org/v1 3kind: XBucket 4metadata: 5 name: test-xrender 6status: 7 bucketRegion: us-east-2 8--- 9apiVersion: s3.aws.m.upbound.io/v1beta1 10kind: Bucket 11metadata: 12 annotations: 13 crossplane.io/composition-resource-name: my-bucket 14 generateName: test-xrender- 15 labels: 16 crossplane.io/composite: test-xrender 17 namespace: default 18 ownerReferences: 19 - apiVersion: nopexample.org/v1 20 blockOwnerDeletion: true 21 controller: true 22 kind: XBucket 23 name: test-xrender 24 uid: "" 25spec: 26 forProvider: 27 region: us-east-2 ### Flags[](https://docs.crossplane.io/v2.0/cli/command-reference/#flags) | Short flag | Long flag | Description | | --- | --- | --- | | | `--context-files==,=` | A comma separated list of files to load for function “contexts.” | | | `--context-values==,=` | A comma separated list of key-value pairs to load for function “contexts.” | | `-r` | `--include-function-results` | Include the “results” or events from the function. | | `-o` | `--observed-resources=` | Provide artificial managed resource data to the function. | | `-e` | `--extra-resources=PATH` | A YAML file or directory of YAML files specifying extra resources to pass to the Function pipeline. | | `-c` | `--include-context` | Include the context in the rendered output as a resource of kind: Context. | | `-x` | `--include-full-xr` | Include a copy of the input Composite Resource spec and metadata fields in the rendered output. | | | `--timeout=` | Amount of time to wait for a function to finish. (Default 1 minute) | The `crossplane render` command relies on standard [Docker environmental variables](https://docs.docker.com/engine/reference/commandline/cli/#environment-variables) to connect to the local Docker Engine and run composition functions. ### Provide function context[](https://docs.crossplane.io/v2.0/cli/command-reference/#provide-function-context) The `--context-files` and `--context-values` flags can provide data to a function’s `context`. The context is JSON formatted data. ### Include function results[](https://docs.crossplane.io/v2.0/cli/command-reference/#include-function-results) If a function produces Kubernetes events with statuses use the `--include-function-results` to print them along with the managed resource outputs. ### Include the composite resource[](https://docs.crossplane.io/v2.0/cli/command-reference/#include-the-composite-resource) Composition functions can only change the `status` field of a composite resource. By default, the `crossplane render` command only prints the `status` field with `metadata.name`. Use `--include-full-xr` to print the full composite resource, including the `spec` and `metadata` fields. ### Mock managed resources[](https://docs.crossplane.io/v2.0/cli/command-reference/#mock-managed-resources) Provide mocked, or artificial data representing a managed resource with `--observed-resources`. The `crossplane render` command treats the provided inputs as if they were resources in a Crossplane cluster. A function can reference and manipulate the included resource as part of running the function. The `observed-resources` may be a single YAML file with multiple resources or a directory of YAML files representing multiple resources. Inside the YAML file include an `apiVersion`, `kind`, `metadata` and `spec`. 1apiVersion: example.org/v1alpha1 2kind: ComposedResource 3metadata: 4 name: test-render-b 5 annotations: 6 crossplane.io/composition-resource-name: resource-b 7spec: 8 coolerField: "I'm cooler!" The schema of the resource isn’t validated and may contain any data. ### Mock extra resources[](https://docs.crossplane.io/v2.0/cli/command-reference/#mock-extra-resources) Extra Resources allow a Composition to request Crossplane Objects on the cluster that aren’t part of the Composition. The `--extra-resources` option points at a directory containing YAML manifests of resources to mock. Use Extra Resources in combination with a function like [function-extra-resources](https://github.com/crossplane-contrib/function-extra-resources) or the built-in support in [function-go-templating](https://github.com/crossplane-contrib/function-go-templating?tab=readme-ov-file#extraresources) . xpkg[](https://docs.crossplane.io/v2.0/cli/command-reference/#xpkg) -------------------------------------------------------------------- The `crossplane xpkg` commands create, install and update Crossplane [packages](https://docs.crossplane.io/v2.0/packages/configurations/) and enable authentication and publishing of Crossplane packages to a Crossplane package registry. ### xpkg build[](https://docs.crossplane.io/v2.0/cli/command-reference/#xpkg-build) Using `crossplane xpkg build` provides automation and simplification to build Crossplane packages. The Crossplane CLI combines a directory of YAML files and packages them as an [OCI container image](https://opencontainers.org/) . The CLI applies the required annotations and values to meet the [Crossplane XPKG specification](https://github.com/crossplane/crossplane/blob/main/contributing/specifications/xpkg.md) . The `crossplane` CLI supports building [configuration](https://docs.crossplane.io/v2.0/packages/configurations/) , [function](https://docs.crossplane.io/v2.0/composition/compositions/) and [provider](https://docs.crossplane.io/v2.0/packages/providers/) package types. #### Flags[](https://docs.crossplane.io/v2.0/cli/command-reference/#flags-1) | Short flag | Long flag | Description | | --- | --- | --- | | | `--embed-runtime-image-name=NAME` | The image name and tag of an image to include in the package. Only for provider and function packages. | | | `--embed-runtime-image-tarball=PATH` | The filename of an image to include in the package. Only for provider and function packages. | | `-e` | `--examples-root="./examples"` | The path to a directory of examples related to the package. | | | `--ignore=PATH,...` | List of files and directories to ignore. | | `-o` | `--package-file=PATH` | Directory and filename of the created package. | | `-f` | `--package-root="."` | Directory to search for YAML files. | The `crossplane xpkg build` command recursively looks in the directory set by `--package-root` and attempts to combine any files ending in `.yml` or `.yaml` into a package. All YAML files must be valid Kubernetes manifests with `apiVersion`, `kind`, `metadata` and `spec` fields. #### Ignore files[](https://docs.crossplane.io/v2.0/cli/command-reference/#ignore-files) Use `--ignore` to provide a list of files and directories to ignore. For example, `crossplane xpkg build --ignore="./test/*,kind-config.yaml"` #### Set the package name[](https://docs.crossplane.io/v2.0/cli/command-reference/#set-the-package-name) `crossplane` automatically names the new package a combination of the `metadata.name` and a hash of the package contents and saves the contents in the same location as `--package-root`. Define a specific location and filename with `--package-file` or `-o`. For example, `crossplane xpkg build -o /home/crossplane/example.xpkg`. #### Include examples[](https://docs.crossplane.io/v2.0/cli/command-reference/#include-examples) Include YAML files demonstrating how to use the package with `--examples-root`. #### Include a runtime image[](https://docs.crossplane.io/v2.0/cli/command-reference/#include-a-runtime-image) Functions and Providers require YAML files describing their dependencies and settings and a container image for their runtime. Using `--embed-runtime-image-name` runs a specified image and includes the image inside the function or provider package. Note Images referenced with `--embed-runtime-image-name` must be in the local Docker cache. Use `docker pull` to download a missing image. The `--embed-runtime-image-tarball` flag includes a local OCI image tarball inside the function or provider package. ### xpkg init[](https://docs.crossplane.io/v2.0/cli/command-reference/#xpkg-init) The `crossplane xpkg init` command populates the current directory with files to build a package. Provide a name to use for the package and the package template to start from with the command `crossplane xpkg init