mirror of https://github.com/crossplane/docs.git
1256 lines
40 KiB
Markdown
1256 lines
40 KiB
Markdown
---
|
|
title: Compositions
|
|
weight: 30
|
|
aliases:
|
|
- composition
|
|
description: "Compositions are a template for creating Crossplane resources"
|
|
---
|
|
|
|
Compositions are a template for creating multiple managed resources as a single
|
|
object.
|
|
|
|
A Composition _composes_ individual managed 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.
|
|
|
|
{{<expand "Confused about Compositions, XRDs, XRs and Claims?" >}}
|
|
Crossplane has four core components that users commonly mix up:
|
|
|
|
* Compositions - This page. A template to define how to create resources.
|
|
* [Composite Resource Definition]({{<ref "./composite-resource-definitions">}})
|
|
(`XRD`) - A custom API specification.
|
|
* [Composite Resource]({{<ref "./composite-resources">}}) (`XR`) - Created by
|
|
using the custom API defined in a Composite Resource Definition. XRs use the
|
|
Composition template to create new managed resources.
|
|
* [Claims]({{<ref "./claims" >}}) (`XRC`) - Like a Composite Resource, but
|
|
with namespace scoping.
|
|
{{</expand >}}
|
|
|
|
## Creating Compositions
|
|
|
|
Creating Compositions consists of:
|
|
* [Resource templates](#resource-templates) defining the resources to create.
|
|
* [Enabling Composite Resources](#enabling-composite-resources) to use this
|
|
Composition template.
|
|
|
|
<!-- vale Google.WordList = NO -->
|
|
Optionally, Compositions also support:
|
|
* [Modifying and patching](#changing-resource-fields) resource settings.
|
|
* [Storing connection details](#storing-connection-details) and secrets
|
|
generated by the managed resources.
|
|
* Using [Composition functions](#composition-functions) to allow custom
|
|
programs to run alongside the Composition.
|
|
* Creating a
|
|
[custom check of when a resource is ready](#resource-readiness-checks)
|
|
to use.
|
|
<!-- vale Google.WordList = YES -->
|
|
|
|
### Resource templates
|
|
The
|
|
{{<hover label="resources" line="4">}}resources{{</hover>}} field of a
|
|
Composition's
|
|
{{<hover label="resources" line="3">}}spec{{</hover>}}
|
|
defines the set of things that a Composite Resource creates.
|
|
|
|
{{<hint "note" >}}
|
|
Read more about Composite Resources in the
|
|
[Composite Resources page]({{<ref "./composite-resources" >}}).
|
|
{{< /hint >}}
|
|
|
|
|
|
For example, a Composition can define a template to create a virtual machine
|
|
and an associated storage bucket at the same time.
|
|
|
|
The {{<hover label="resources" line="4">}}resources{{</hover>}} field lists the
|
|
individual resources with a
|
|
{{<hover label="resources" line="5">}}name{{</hover>}}.
|
|
This name identifies the
|
|
resource inside the Composition and isn't related to the external name used with
|
|
the Provider.
|
|
|
|
#### Template a managed resource
|
|
The contents of the
|
|
{{<hover label="resources" line="6">}}base{{</hover>}} are identical to
|
|
creating a standalone [managed resource]({{<ref "./managed-resources">}}).
|
|
|
|
This example uses
|
|
[Upbound's Provider AWS](https://marketplace.upbound.io/providers/upbound/provider-aws/v0.35.0)
|
|
to define a
|
|
S3 storage {{<hover label="resources" line="8">}}Bucket{{</hover>}} and
|
|
EC2 compute {{<hover label="resources" line="15">}}Instance{{</hover>}}.
|
|
|
|
After defining the
|
|
{{<hover label="resources" line="7">}}apiVersion{{</hover>}} and
|
|
{{<hover label="resources" line="8">}}kind{{</hover>}}, define the
|
|
{{<hover label="resources" line="10">}}spec.forProvider{{</hover>}} fields
|
|
defining the settings of the resource.
|
|
|
|
```yaml {copy-lines="none",label="resources"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
spec:
|
|
resources:
|
|
- name: StorageBucket
|
|
base:
|
|
apiVersion: s3.aws.upbound.io/v1beta1
|
|
kind: Bucket
|
|
spec:
|
|
forProvider:
|
|
region: "us-east-2"
|
|
- name: VM
|
|
base:
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: Instance
|
|
spec:
|
|
forProvider:
|
|
ami: ami-0d9858aa3c6322f73
|
|
instanceType: t2.micro
|
|
region: "us-east-2"
|
|
```
|
|
|
|
When a [Composite Resource]({{<ref "./composite-resources" >}}) uses this
|
|
Composition template, the Composite Resource creates two new managed resources
|
|
with all the provided
|
|
{{<hover label="resources" line="17">}}spec.forProvider{{</hover>}} settings.
|
|
|
|
The {{<hover label="resources" line="16">}}spec{{</hover>}}
|
|
supports any settings used in a managed resource including
|
|
applying `annotations` and `labels` or using a specific
|
|
`providerConfigRef`.
|
|
|
|
{{<hint "note" >}}
|
|
Compositions allow applying a `metadata.name` to a resource's
|
|
{{<hover label="resources" line="16">}}spec{{</hover>}} but ignores it. The
|
|
`metadata.name` field doesn't influence the name
|
|
of the managed resource in Crossplane or the external resource inside the
|
|
Provider.
|
|
|
|
Use the `crossplane.io/external-name` annotation on the resource to influence
|
|
the external resource name.
|
|
{{< /hint >}}
|
|
|
|
#### Template a ProviderConfig
|
|
|
|
Compositions can define a ProviderConfig like it defines managed resources.
|
|
Generating a ProviderConfig may be useful in providing unique credentials to
|
|
each deployment.
|
|
|
|
|
|
```yaml {copy-lines="none"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
spec:
|
|
resources:
|
|
- name: my-aws-provider-config
|
|
base:
|
|
apiVersion: aws.upbound.io/v1beta1
|
|
kind: ProviderConfig
|
|
spec:
|
|
source: Secret
|
|
secretRef:
|
|
namespace: crossplane-system
|
|
name: aws-secret
|
|
key: creds
|
|
```
|
|
|
|
|
|
#### Template another Composite Resource
|
|
|
|
Compositions can use other Composite Resources to define more complicated
|
|
templates.
|
|
|
|
A common use case is a Composition that uses other
|
|
Compositions. For example, creating a Composition to create a standard set of
|
|
networking resources that other Compositions reference.
|
|
|
|
{{< hint "note" >}}
|
|
Both Compositions must have corresponding XRDs.
|
|
{{< /hint >}}
|
|
|
|
This example networking Composition defines the set of resources required to
|
|
create a new AWS virtual network. This includes a
|
|
{{<hover label="xnetwork" line="8">}}VPC{{</hover>}},
|
|
{{<hover label="xnetwork" line="13">}}InternetGateway{{</hover>}} and
|
|
{{<hover label="xnetwork" line="18">}}Subnet{{</hover>}}.
|
|
|
|
```yaml {copy-lines="none",label="xnetwork"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
spec:
|
|
resources:
|
|
- name: vpc-resource
|
|
base:
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: VPC
|
|
# Removed for Brevity
|
|
- name: gateway-resource
|
|
base:
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: InternetGateway
|
|
# Removed for Brevity
|
|
- name: subnet-resource
|
|
base:
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: Subnet
|
|
# Removed for Brevity
|
|
compositeTypeRef:
|
|
apiVersion: aws.platformref.upbound.io/v1alpha1
|
|
kind: XNetwork
|
|
```
|
|
|
|
The {{<hover label="xnetwork" line="20">}}compositeTypeRef{{</hover>}} gives
|
|
this Composition an
|
|
{{<hover label="xnetwork" line="21">}}apiVersion{{</hover>}} and
|
|
{{<hover label="xnetwork" line="22">}}kind{{</hover>}} to reference in another
|
|
Composition.
|
|
|
|
{{<hint "note" >}}
|
|
The [Enabling a Composite Resource](#enabling-composite-resources) section
|
|
describes the
|
|
{{<hover label="xnetwork" line="20">}}compositeTypeRef{{</hover>}} field.
|
|
{{< /hint >}}
|
|
|
|
A second Composition, defining other resources, in this example, an AWS Elastic
|
|
Kubernetes Cluster, can reference the previous
|
|
{{<hover label="xnetwork" line="22">}}XNetwork{{</hover>}}
|
|
|
|
```yaml {copy-lines="none",label="xcluster"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
spec:
|
|
resources:
|
|
- name: nested-network-composition
|
|
base:
|
|
apiVersion: aws.platformref.upbound.io/v1alpha1
|
|
kind: XNetwork
|
|
# Removed for brevity
|
|
- name: eks-cluster-resource
|
|
base:
|
|
apiVersion: eks.aws.upbound.io/v1beta1
|
|
kind: Cluster
|
|
# Removed for brevity
|
|
```
|
|
|
|
When a Composite Resource creates all the managed resources from this
|
|
Composition, the resources defined by the
|
|
{{<hover label="xcluster" line="8">}}XNetwork{{</hover>}} get created along with
|
|
the EKS {{<hover label="xcluster" line="13">}}cluster{{</hover >}}.
|
|
|
|
{{<hint "note" >}}
|
|
This abbreviated example is from the Upbound
|
|
[AWS Reference Platform](https://github.com/upbound/platform-ref-aws).
|
|
|
|
View the complete Compositions in the reference platform's
|
|
[package directory](https://github.com/upbound/platform-ref-aws/blob/main/package/cluster/composition.yaml).
|
|
{{</hint >}}
|
|
|
|
#### Cross-resource references
|
|
|
|
Inside a Composition some resources use identifiers or names of other resources.
|
|
For example, creating a new `network` and applying the network identifier to a
|
|
virtual machine.
|
|
|
|
Resources inside a Composition can cross-reference other resources by matching
|
|
a label or a _controller reference_.
|
|
|
|
{{<hint "note" >}}
|
|
Providers allow matching of labels and controller references on a
|
|
per-resource basis. Check the documentation for the specific Provider resource
|
|
to see what's supported.
|
|
|
|
Matching labels and controllers isn't supported across different Providers.
|
|
{{< /hint >}}
|
|
|
|
##### Match resource labels
|
|
|
|
To match a resource label, first apply a
|
|
{{<hover label="matchlabel" line="11">}}label{{</hover>}} to the resource to
|
|
match and use
|
|
{{<hover label="matchlabel" line="19">}}matchLabels{{</hover>}}
|
|
in the second resource.
|
|
|
|
This example creates a AWS
|
|
{{<hover label="matchlabel" line="7">}}Role{{</hover>}} and applies a
|
|
{{<hover label="matchlabel" line="11">}}label{{</hover>}}. The second resource
|
|
is a {{<hover label="matchlabel" line="14">}}RolePolicyAttachment{{</hover>}},
|
|
which requires attaching to an existing `Role`.
|
|
|
|
Using the resource's
|
|
{{<hover label="matchlabel" line="19">}}roleSelector.matchLabels{{</hover>}}
|
|
ensures this
|
|
{{<hover label="matchlabel" line="14">}}RolePolicyAttachment{{</hover>}}
|
|
references the matching
|
|
{{<hover label="matchlabel" line="7">}}Role{{</hover>}}, even if the unique role
|
|
identifier isn't known.
|
|
|
|
```yaml {label="matchlabel",copy-lines="none"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
spec:
|
|
resources:
|
|
- base:
|
|
apiVersion: iam.aws.upbound.io/v1beta1
|
|
kind: Role
|
|
name: iamRole
|
|
metadata:
|
|
labels:
|
|
role: controlplane
|
|
- base:
|
|
apiVersion: iam.aws.upbound.io/v1beta1
|
|
kind: RolePolicyAttachment
|
|
name: iamPolicy
|
|
spec:
|
|
forProvider:
|
|
roleSelector:
|
|
matchLabels:
|
|
role: controlplane
|
|
# Removed for brevity
|
|
```
|
|
|
|
##### Match a controller reference
|
|
|
|
Matching a controller reference ensures that the matching resource is
|
|
in the same composite resource.
|
|
|
|
Matching only a controller reference simplifies the matching process without
|
|
requiring labels or more information.
|
|
|
|
For example, creating an AWS
|
|
{{<hover label="controller1" line="14">}}InternetGateway{{</hover>}} requires a
|
|
{{<hover label="controller1" line="7">}}VPC{{</hover>}}.
|
|
|
|
The {{<hover label="controller1" line="14">}}InternetGateway{{</hover>}} could
|
|
match a label, but every VPC created by this Composition share the same label.
|
|
|
|
Using {{<hover label="controller1" line="19">}}matchControllerRef{{</hover>}}
|
|
matches only the VPC created in the same composite resource that created the
|
|
{{<hover label="controller1" line="14">}}InternetGateway{{</hover>}}.
|
|
|
|
```yaml {label="controller1",copy-lines="none"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
spec:
|
|
resources:
|
|
- base:
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: VPC
|
|
name: my-vpc
|
|
spec:
|
|
forProvider:
|
|
# Removed for brevity
|
|
- base:
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: InternetGateway
|
|
name: my-gateway
|
|
spec:
|
|
forProvider:
|
|
vpcIdSelector:
|
|
matchControllerRef: true
|
|
# Removed for brevity
|
|
```
|
|
|
|
|
|
Resources can match both labels and a controller reference to match a specific
|
|
resource in the larger composite resource.
|
|
|
|
For example, this Composition creates two
|
|
{{<hover label="controller2" line="17">}}VPC{{</hover>}}
|
|
resources, but the
|
|
{{<hover label="controller2" line="27">}}InternetGateway{{</hover>}}
|
|
must match only one.
|
|
|
|
Applying a {{<hover label="controller2" line="21">}}label{{</hover>}} to the
|
|
second {{<hover label="controller2" line="17">}}VPC{{</hover>}} allows the
|
|
{{<hover label="controller2" line="27">}}InternetGateway{{</hover>}} to match
|
|
the label
|
|
{{<hover label="controller2" line="34">}}type: internet{{</hover>}} and only
|
|
match objects in the same composite resource with
|
|
{{<hover label="controller2" line="32">}}matchControllerRef{{</hover>}}.
|
|
|
|
```yaml {label="controller2",copy-lines="none"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
spec:
|
|
resources:
|
|
- base:
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: VPC
|
|
name: my-first-vpc
|
|
metadata:
|
|
labels:
|
|
type: backend
|
|
spec:
|
|
forProvider:
|
|
# Removed for brevity
|
|
- base:
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: VPC
|
|
name: my-second-vpc
|
|
metadata:
|
|
labels:
|
|
type: internet
|
|
spec:
|
|
forProvider:
|
|
# Removed for brevity
|
|
- base:
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: InternetGateway
|
|
name: my-gateway
|
|
spec:
|
|
forProvider:
|
|
vpcIdSelector:
|
|
matchControllerRef: true
|
|
matchLabels:
|
|
type: internet
|
|
# Removed for brevity
|
|
```
|
|
### Enabling Composite Resources
|
|
|
|
A Composition is only a template defining how to create managed
|
|
resources. A Composition limits which Composite Resources can use this
|
|
template.
|
|
|
|
A Composition's {{<hover label="typeref" line="6">}}compositeTypeRef{{</hover>}}
|
|
defines which Composite Resource type can use this Composition.
|
|
|
|
{{<hint "note" >}}
|
|
Read more about Composite Resources in the
|
|
[Composite Resources page]({{<ref "./composite-resources" >}}).
|
|
{{< /hint >}}
|
|
|
|
Inside a Composition's
|
|
{{<hover label="typeref" line="5">}}spec{{</hover>}}
|
|
define the Composite Resource
|
|
{{<hover label="typeref" line="7">}}apiVersion{{</hover>}} and
|
|
{{<hover label="typeref" line="8">}}kind{{</hover>}}
|
|
that the Composition allows to use this template.
|
|
|
|
```yaml {label="typeref",copy-lines="none"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
metadata:
|
|
name: dynamodb-with-bucket
|
|
spec:
|
|
compositeTypeRef:
|
|
apiVersion: custom-api.example.org/v1alpha1
|
|
kind: database
|
|
# Removed for brevity
|
|
```
|
|
|
|
### Changing resource fields
|
|
|
|
Most Compositions require customizing the fields of the resources. This can
|
|
include applying unique passwords, modifying where to deploy resources,
|
|
or applying labels or annotations.
|
|
|
|
The primary method to change resources is using a resource
|
|
[patch and transform]({{<ref "./patch-and-transform" >}}). Patch and transforms
|
|
allow matching specific input fields, modifying them and applying them to the
|
|
managed resource.
|
|
|
|
{{<hint "important" >}}
|
|
The details of creating patch and transforms and their options are in the
|
|
[Patch and Transform page]({{<ref "./patch-and-transform" >}}).
|
|
|
|
This section describes applying patches and transforms to Compositions.
|
|
{{< /hint >}}
|
|
|
|
Apply patches to individual `resources` with the
|
|
{{<hover label="patch" line="13">}}patches{{</hover>}}
|
|
field.
|
|
|
|
For example, taking the
|
|
{{<hover label="patchClaim" line="6">}}location{{</hover>}} provided in a Claim
|
|
and applying it to the
|
|
{{<hover label="patch" line="12">}}region{{</hover>}} value in the managed
|
|
resource.
|
|
|
|
```yaml {copy-lines="none",label="patchClaim"}
|
|
apiVersion: example.org/v1alpha1
|
|
kind: ExampleClaim
|
|
metadata:
|
|
name: my-example-claim
|
|
spec:
|
|
location: "eu-north-1"
|
|
```
|
|
|
|
The Composition patch uses the
|
|
{{<hover label="patch" line="15">}}fromFieldPath{{</hover>}} to match the
|
|
{{<hover label="patchClaim" line="6">}}location{{</hover>}}
|
|
field in the Claim and the
|
|
{{<hover label="patch" line="16">}}toFieldPath{{</hover>}} to define which field
|
|
to change inside the Composition.
|
|
|
|
```yaml {copy-lines="none",label="patch"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
# Removed for Brevity
|
|
spec:
|
|
resources:
|
|
- name: s3Bucket
|
|
base:
|
|
apiVersion: s3.aws.upbound.io/v1beta1
|
|
kind: Bucket
|
|
spec:
|
|
forProvider:
|
|
region: "us-east-2"
|
|
patches:
|
|
- type: FromCompositeFieldPath
|
|
fromFieldPath: "spec.location"
|
|
toFieldPath: "spec.forProvider.region"
|
|
```
|
|
|
|
#### Patch sets
|
|
|
|
Some Compositions have resources which need identical patches applied. Instead
|
|
of repeating the same `patches` field, resources can reference a single
|
|
`patchSet`.
|
|
|
|
Define a {{<hover label="patchset" line="5">}}patchSet{{</hover>}} with a
|
|
{{<hover label="patchset" line="6">}}name{{</hover>}}
|
|
and
|
|
{{<hover label="patchset" line="7">}}patch{{</hover>}}
|
|
operations.
|
|
|
|
Then apply the
|
|
{{<hover label="patchset" line="5">}}patchSet{{</hover>}}
|
|
to each resource with
|
|
{{<hover label="patchset" line="16">}}type: patchSet{{< /hover >}}, referencing
|
|
the {{<hover label="patchset" line="6">}}name{{< /hover >}} in the
|
|
{{<hover label="patchset" line="17">}}patchSetName{{< /hover >}} field.
|
|
|
|
```yaml {copy-lines="none",label="patchset"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
# Removed for Brevity
|
|
spec:
|
|
patchSets:
|
|
- name: reusable-patch
|
|
patches:
|
|
- type: FromCompositeFieldPath
|
|
fromFieldPath: "location"
|
|
toFieldPath: "spec.forProvider.region"
|
|
resources:
|
|
- name: first-resource
|
|
base:
|
|
# Removed for Brevity
|
|
patches:
|
|
- type: PatchSet
|
|
patchSetName: reusable-patch
|
|
- name: second-resource
|
|
base:
|
|
# Removed for Brevity
|
|
patches:
|
|
- type: PatchSet
|
|
patchSetName: reusable-patch
|
|
```
|
|
|
|
#### Patch with EnvironmentConfigs
|
|
|
|
Crossplane uses EnvironmentConfigs as an in-memory data store. Compositions can
|
|
read and write from this data store as part of the patch process.
|
|
|
|
{{<hint "important" >}}
|
|
EnvironmentConfigs are an alpha feature. Alpha features aren't enabled by
|
|
default.
|
|
{{< /hint >}}
|
|
|
|
EnvironmentConfigs can predefine data that Compositions can use
|
|
or a Composite Resource can write data to the EnvironmentConfig for other
|
|
resources to read.
|
|
|
|
<!-- vale off -->
|
|
{{< hint "note" >}}
|
|
<!-- vale on -->
|
|
Read the [EnvironmentConfigs]({{<ref "./environment-configs" >}}) page for
|
|
more information on using EnvironmentConfigs.
|
|
{{< /hint >}}
|
|
|
|
To apply a patch using EnvironmentConfigs, first define which EnvironmentConfig
|
|
to use with
|
|
{{<hover label="envselect"
|
|
line="6">}}environment.environmentConfigs{{</hover>}}.
|
|
|
|
<!-- vale Google.Quotes = NO -->
|
|
<!-- vale gitlab.SentenceLength = NO -->
|
|
<!-- ignore false positive -->
|
|
Use either a
|
|
[reference]({{<ref "./managed-resources#matching-by-name-reference" >}})
|
|
or a [selector]({{<ref "./managed-resources#matching-by-selector" >}}) to
|
|
identify the EnvironmentConfig to use.
|
|
<!-- vale Google.Quotes = YES -->
|
|
|
|
```yaml {label="envselect",copy-lines="none"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
# Removed for Brevity
|
|
spec:
|
|
environment:
|
|
environmentConfigs:
|
|
- ref:
|
|
name: example-environment
|
|
resources:
|
|
# Removed for Brevity
|
|
```
|
|
|
|
Inside the {{<hover label="envpatch" line="16">}}patches{{</hover>}} of the
|
|
resource, use
|
|
{{<hover label="envpatch" line="17">}}ToEnvironmentFieldPath{{</hover>}} to copy
|
|
data from the resource to the EnvironmentConfig.
|
|
Use {{<hover label="envpatch" line="20">}}FromEnvironmentFieldPath{{</hover>}}
|
|
to copy data to the resource from the EnvironmentConfig.
|
|
|
|
```yaml {label="envpatch",copy-lines="none"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
# Removed for Brevity
|
|
spec:
|
|
environment:
|
|
# Removed for Brevity
|
|
resources:
|
|
# Removed for Brevity
|
|
- name: vpc
|
|
base:
|
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
|
kind: VPC
|
|
spec:
|
|
forProvider:
|
|
cidrBlock: 172.16.0.0/16
|
|
patches:
|
|
- type: ToEnvironmentFieldPath
|
|
fromFieldPath: status.atProvider.id
|
|
toFieldPath: vpcId
|
|
- type: FromEnvironmentFieldPath
|
|
fromFieldPath: tags
|
|
toFieldPath: spec.forProvider.tags
|
|
```
|
|
|
|
The [EnvironmentConfigs]({{<ref "./environment-configs" >}}) page has
|
|
more information on EnvironmentConfigs options and usage.
|
|
|
|
### Composition functions
|
|
|
|
Composition functions (`XFNs`) are containers executing any code you define.
|
|
Composition functions can read and write to any resource in the Composition
|
|
they're attached to. This allows composition functions to perform complex
|
|
operations to patch fields, determine if a resource is ready for use or notify
|
|
an external system about the details of resource.
|
|
|
|
{{<hint "important" >}}
|
|
Composition functions are an alpha feature. Alpha features aren't enabled by
|
|
default.
|
|
{{< /hint >}}
|
|
|
|
To attach a composition function to a Composition define a
|
|
{{<hover label="xfn" line="7">}}function{{</hover>}} inside the Composition
|
|
{{<hover label="xfn" line="4">}}spec{{</hover>}}.
|
|
|
|
Provide a {{<hover label="xfn" line="8">}}name{{</hover>}} for the function.
|
|
The {{<hover label="xfn" line="9">}}type{{</hover>}} is always `Container`.
|
|
The {{<hover label="xfn" line="11">}}container.image{{</hover>}} is the
|
|
location of the composition function container image.
|
|
|
|
```yaml {label="xfn",copy-lines="none"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
# Removed for Brevity
|
|
spec:
|
|
resources:
|
|
# Removed for Brevity
|
|
functions:
|
|
- name: rds-instance-password
|
|
type: Container
|
|
container:
|
|
image: xpkg.upbound.io/provider-aws-xfns/random-rds-password:v0.1.0
|
|
```
|
|
|
|
Read the [composition functions]({{<ref "./composition-functions">}}) page for
|
|
details on building and using composition functions.
|
|
|
|
### Storing connection details
|
|
|
|
Some managed resources generate unique details like usernames, passwords,
|
|
IP addresses, ports or other connection details.
|
|
|
|
When resources inside a Composition create connection details Crossplane creates
|
|
a Kubernetes secret object for each managed resource generating connection
|
|
details.
|
|
|
|
{{<hint "note">}}
|
|
This section discusses creating Kubernetes secrets.
|
|
Crossplane also supports using external secret stores like [HashiCorp Vault](https://www.vaultproject.io/).
|
|
|
|
Read the [external secrets store guide]({{<ref "/knowledge-base/integrations/vault-as-secret-store">}}) for more information on using Crossplane
|
|
with an external secret store.
|
|
{{</hint >}}
|
|
|
|
#### Composite resource combined secret
|
|
Crossplane can combine all the secrets generated by the resources inside a
|
|
Composition into a single Kubernetes secret and optionally copy the
|
|
secret object for [Claims]({{<ref "./claims#claim-connection-secrets">}}).
|
|
|
|
Set the value of
|
|
{{<hover label="writeConn" line="5">}}writeConnectionSecretsToNamespace{{</hover>}}
|
|
to the namespace where Crossplane should store the combined secret object.
|
|
|
|
```yaml {copy-lines="none",label="writeConn"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
# Removed for Brevity
|
|
spec:
|
|
writeConnectionSecretsToNamespace: my-namespace
|
|
resources:
|
|
# Removed for brevity
|
|
```
|
|
|
|
#### Composed resource secrets
|
|
Inside the
|
|
{{<hover label="writeConnRes" line="10">}}spec{{</hover>}} of
|
|
each resource producing connection details, define the
|
|
{{<hover label="writeConnRes" line="13">}}writeConnectionSecretToRef{{</hover>}}, with
|
|
a
|
|
{{<hover label="writeConnRes" line="14">}}namespace{{</hover>}} and
|
|
{{<hover label="writeConnRes" line="15">}}name{{</hover>}} of the secret object for
|
|
the resource.
|
|
|
|
If a
|
|
{{<hover label="writeConnRes" line="13">}}writeConnectionSecretToRef{{</hover>}}
|
|
isn't defined, Crossplane doesn't write any keys to the secret.
|
|
|
|
|
|
```yaml {label="writeConnRes"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
spec:
|
|
writeConnectionSecretsToNamespace: other-namespace
|
|
resources:
|
|
- name: key
|
|
base:
|
|
apiVersion: iam.aws.upbound.io/v1beta1
|
|
kind: AccessKey
|
|
spec:
|
|
forProvider:
|
|
# Removed for brevity
|
|
writeConnectionSecretToRef:
|
|
namespace: docs
|
|
name: key1
|
|
```
|
|
|
|
Crossplane saves a secret with the
|
|
{{<hover label="viewComposedSec" line="3">}}name{{</hover>}}
|
|
in the
|
|
{{<hover label="writeConnRes" line="14">}}namespace{{</hover>}} provided.
|
|
|
|
```shell {label="viewComposedSec"}
|
|
kubectl get secrets -n docs
|
|
NAME TYPE DATA AGE
|
|
key1 connection.crossplane.io/v1alpha1 4 4m30s
|
|
```
|
|
|
|
{{<hint "tip" >}}
|
|
|
|
Crossplane recommends using a [Patch]({{<ref "./patch-and-transform">}}) to
|
|
create a unique name for each secret.
|
|
|
|
For example, a
|
|
{{<hover label="tipPatch" line="15">}}patch{{</hover>}}
|
|
to add the unique identifier of the resource as the key
|
|
name.
|
|
|
|
```yaml {label="tipPatch",copy-lines="14-20"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
spec:
|
|
# Removed for brevity
|
|
resources:
|
|
- name: key
|
|
base:
|
|
apiVersion: iam.aws.upbound.io/v1beta1
|
|
kind: AccessKey
|
|
spec:
|
|
# Removed for brevity
|
|
writeConnectionSecretToRef:
|
|
namespace: docs
|
|
name: key1
|
|
patches:
|
|
- fromFieldPath: "metadata.uid"
|
|
toFieldPath: "spec.writeConnectionSecretToRef.name"
|
|
transforms:
|
|
- type: string
|
|
string:
|
|
fmt: "%s-secret"
|
|
```
|
|
{{< /hint >}}
|
|
|
|
#### Define secret keys
|
|
|
|
|
|
A Composition must define the specific secret keys a resource creates with
|
|
the
|
|
{{<hover label="conDeet" line="14">}}connectionDetails{{</hover>}} object.
|
|
|
|
{{<table "table table-sm" >}}
|
|
| Secret Type | Description |
|
|
| --- | --- |
|
|
| {{<hover label="conDeet" line="16">}}fromConnectionSecretKey{{</hover>}} | Create a secret key matching the key of a secret generated by the resource. |
|
|
| {{<hover label="conDeet" line="18">}}fromFieldPath{{</hover>}} | Create a secret key matching a field path of the resource. |
|
|
| {{<hover label="conDeet" line="20">}}value{{</hover>}} | Create a secret key with a predefined value. |
|
|
{{< /table >}}
|
|
|
|
{{<hint "note">}}
|
|
The {{<hover label="conDeet" line="20">}}value{{</hover>}} type must use a
|
|
string value.
|
|
|
|
The {{<hover label="conDeet" line="20">}}value{{</hover>}} isn't added to the
|
|
individual resource secret object. The
|
|
{{<hover label="conDeet" line="20">}}value{{</hover>}} only appears in the
|
|
combined composite resource secret.
|
|
{{< /hint >}}
|
|
|
|
```yaml {label="conDeet",copy-lines="none"}
|
|
kind: Composition
|
|
spec:
|
|
writeConnectionSecretsToNamespace: other-namespace
|
|
resources:
|
|
- name: key
|
|
base:
|
|
# Removed for brevity
|
|
spec:
|
|
forProvider:
|
|
# Removed for brevity
|
|
writeConnectionSecretToRef:
|
|
namespace: docs
|
|
name: key1
|
|
connectionDetails:
|
|
- name: myUsername
|
|
fromConnectionSecretKey: username
|
|
- name: myFieldSecret
|
|
fromFieldPath: spec.forProvider.user
|
|
- name: myStaticSecret
|
|
value: "docs.crossplane.io"
|
|
```
|
|
|
|
The
|
|
{{<hover label="conDeet" line="14">}}connectionDetails{{</hover>}}
|
|
in a resource can reference a secret from a resource with
|
|
{{<hover label="conDeet" line="16">}}fromConnectionSecretKey{{</hover>}},
|
|
from another field in the resource with
|
|
{{<hover label="conDeet" line="18">}}fromFieldPath{{</hover>}}
|
|
or a statically defined value with
|
|
{{<hover label="conDeet" line="20">}}value{{</hover>}}.
|
|
|
|
Crossplane sets the secret key to the
|
|
{{<hover label="conDeet" line="15">}}name{{</hover>}} value.
|
|
|
|
Describe the secret to view the secret keys inside the secret object.
|
|
|
|
{{<hint "tip" >}}
|
|
If more than one resource generates secrets with the same secret key name,
|
|
Crossplane only saves one value.
|
|
|
|
Use a custom {{<hover label="conDeet" line="15">}}name{{</hover>}} to create
|
|
unique secret keys.
|
|
{{< /hint >}}
|
|
|
|
{{<hint "important">}}
|
|
Crossplane only adds connection details listed in the
|
|
{{<hover label="conDeet" line="16">}}connectionDetails{{</hover>}}
|
|
to the combined secret object.
|
|
Any connection secrets in a managed resource, not defined in the
|
|
{{<hover label="conDeet" line="16">}}connectionDetails{{</hover>}}
|
|
aren't added to the combined secret object.
|
|
{{< /hint >}}
|
|
|
|
|
|
```shell {copy-lines="1"}
|
|
kubectl describe secret
|
|
Name: my-access-key-secret
|
|
Namespace: default
|
|
Labels: <none>
|
|
Annotations: <none>
|
|
|
|
Type: connection.crossplane.io/v1alpha1
|
|
|
|
Data
|
|
====
|
|
myUsername: 20 bytes
|
|
myFieldSecret: 24 bytes
|
|
myStaticSecret: 18 bytes
|
|
```
|
|
|
|
{{<hint "note" >}}
|
|
The CompositeResourceDefinition can also limit which keys Crossplane stores from
|
|
the composite resources.
|
|
By default an XRD writes all secret keys listed in the composed resources
|
|
`connectionDetails` to the combined secret object.
|
|
|
|
Read the
|
|
[CompositeResourceDefinition documentation]({{<ref "composite-resource-definitions#manage-connection-secrets">}})
|
|
for more information on restricting secret keys.
|
|
{{< /hint >}}
|
|
|
|
For more information on connection secrets read the
|
|
[Connection Secrets knowledge base article]({{<ref "/knowledge-base/guides/connection-details">}}).
|
|
|
|
{{<hint "warning">}}
|
|
You can't change the
|
|
{{<hover label="conDeet" line="16">}}connectionDetails{{</hover>}}
|
|
of a Composition.
|
|
You must delete and
|
|
recreate the Composition to change the
|
|
{{<hover label="conDeet" line="16">}}connectionDetails{{</hover>}} .
|
|
{{</hint >}}
|
|
|
|
|
|
#### Save connection details to an external secret store
|
|
|
|
Crossplane
|
|
[External Secret Stores]({{<ref "/knowledge-base/integrations/vault-as-secret-store" >}})
|
|
write secrets and connection details to external secret stores like HashiCorp
|
|
Vault.
|
|
|
|
{{<hint "important" >}}
|
|
External Secret Stores are an alpha feature.
|
|
|
|
They're not recommended for production use. Crossplane disables External Secret
|
|
Stores by default.
|
|
{{< /hint >}}
|
|
|
|
Use
|
|
{{<hover label="gcp-storeconfig"
|
|
line="11">}}publishConnectionDetailsWithStoreConfigRef{{</hover>}}
|
|
in place of
|
|
`writeConnectionSecretsToNamespace` to define the
|
|
{{<hover label="gcp-storeconfig" line="2">}}StoreConfig{{</hover>}}
|
|
to save connection details to.
|
|
|
|
For example, using a
|
|
{{<hover label="gcp-storeconfig" line="2">}}StoreConfig{{</hover>}} with the
|
|
{{<hover label="gcp-storeconfig" line="4">}}name{{</hover>}} "vault,"
|
|
use
|
|
{{<hover label="gcp-storeconfig" line="12">}}publishConnectionDetailsWithStoreConfigRef.name{{</hover>}}
|
|
matching the {{<hover label="gcp-storeconfig" line="4">}}StoreConfig.name{{</hover>}},
|
|
in this example, "vault."
|
|
|
|
|
|
```yaml {label="gcp-storeconfig",copy-lines="none"}
|
|
apiVersion: gcp.crossplane.io/v1alpha1
|
|
kind: StoreConfig
|
|
metadata:
|
|
name: vault
|
|
# Removed for brevity.
|
|
---
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
# Removed for Brevity
|
|
spec:
|
|
publishConnectionDetailsWithStoreConfigRef:
|
|
name: vault
|
|
resources:
|
|
# Removed for brevity
|
|
```
|
|
|
|
For more details read the [External Secret Stores]({{<ref "/knowledge-base/integrations/vault-as-secret-store" >}})
|
|
integration guide.
|
|
|
|
### Resource readiness checks
|
|
|
|
By default Crossplane considers a Composite Resource or Claim as `READY` when
|
|
the status of all created resource are `Type: Ready` and `Status: True`
|
|
|
|
Some resources, for example, a ProviderConfig, don't have a Kubernetes status
|
|
and are never considered `Ready`.
|
|
|
|
Custom readiness checks allow Compositions to define what custom conditions
|
|
to meet for a resource to be `Ready`.
|
|
|
|
{{< hint "tip" >}}
|
|
Use multiple readiness checks if a resource must meet multiple conditions for it
|
|
to be `Ready`.
|
|
{{< /hint >}}
|
|
|
|
<!-- vale Google.WordList = NO -->
|
|
Define a custom readiness check with the
|
|
{{<hover label="check" line="10" >}}readinessChecks{{</hover>}} field on a
|
|
resource.
|
|
<!-- vale Google.WordList = YES -->
|
|
|
|
Checks have a
|
|
{{<hover label="check" line="11" >}}type{{</hover>}} defining how to match the
|
|
resource and a {{<hover label="check" line="12" >}}fieldPath{{</hover>}} of
|
|
which field in the resource to compare.
|
|
|
|
```yaml {label="check",copy-lines="none"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
# Removed for Brevity
|
|
spec:
|
|
resources:
|
|
# Removed for Brevity
|
|
- name: my-resource
|
|
base:
|
|
# Removed for brevity
|
|
readinessChecks:
|
|
- type: <match type>
|
|
fieldPath: <resource field>
|
|
```
|
|
|
|
Compositions support matching resource fields by:
|
|
* [string match](#match-a-string)
|
|
* [integer match](#match-an-integer)
|
|
* [non-empty match](#match-that-a-field-exists)
|
|
* [always ready](#always-consider-a-resource-ready)
|
|
* [condition match](#match-a-condition)
|
|
|
|
#### Match a string
|
|
|
|
{{<hover label="matchstring" line="11">}}MatchString{{</hover>}} considers the composed resource to be ready when the value of a
|
|
field in that resource matches a specified string.
|
|
|
|
{{<hint "note" >}}
|
|
<!-- vale Google.WordList = NO -->
|
|
Crossplane only supports exact string matches. Substrings and regular
|
|
expressions aren't supported in a readiness check.
|
|
<!-- vale Google.WordList = YES -->
|
|
{{</hint >}}
|
|
|
|
|
|
For example, matching the string
|
|
{{<hover label="matchstring" line="13">}}Online{{</hover>}}
|
|
in the resource's
|
|
{{<hover label="matchstring" line="12">}}status.atProvider.state{{</hover>}}
|
|
field.
|
|
|
|
```yaml {label="matchstring",copy-lines="none"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
# Removed for Brevity
|
|
spec:
|
|
resources:
|
|
# Removed for Brevity
|
|
- name: my-resource
|
|
base:
|
|
# Removed for brevity
|
|
readinessChecks:
|
|
- type: MatchString
|
|
fieldPath: status.atProvider.state
|
|
matchString: "Online"
|
|
```
|
|
|
|
#### Match an integer
|
|
|
|
{{<hover label="matchint" line="11">}}MatchInteger{{</hover>}} considers the composed resource to be ready when the value of a
|
|
field in that resource matches a specified integer.
|
|
|
|
{{<hint "note" >}}
|
|
<!-- vale Google.WordList = NO -->
|
|
Crossplane doesn't support matching `0`.
|
|
<!-- vale Google.WordList = YES -->
|
|
{{</hint >}}
|
|
|
|
For example, matching the number
|
|
{{<hover label="matchint" line="13">}}4{{</hover>}}
|
|
in the resource's
|
|
{{<hover label="matchint" line="12">}}status.atProvider.state{{</hover>}}
|
|
field.
|
|
|
|
```yaml {label="matchint",copy-lines="none"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
# Removed for Brevity
|
|
spec:
|
|
resources:
|
|
# Removed for Brevity
|
|
- name: my-resource
|
|
base:
|
|
# Removed for brevity
|
|
readinessChecks:
|
|
- type: MatchInteger
|
|
fieldPath: status.atProvider.state
|
|
matchInteger: 4
|
|
```
|
|
|
|
#### Match that a field exists
|
|
{{<hover label="NonEmpty" line="11">}}NonEmpty{{</hover>}} considers the
|
|
composed resource to be ready when a field exists with a value.
|
|
|
|
{{<hint "note" >}}
|
|
<!-- vale Google.WordList = NO -->
|
|
Crossplane considers a value of `0` or an empty string as empty.
|
|
{{</hint >}}
|
|
|
|
For example, to check that a resource's
|
|
{{<hover label="NonEmpty" line="12">}}status.atProvider.state{{</hover>}}
|
|
field isn't empty.
|
|
<!-- vale Google.WordList = YES -->
|
|
|
|
```yaml {label="NonEmpty",copy-lines="none"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
# Removed for Brevity
|
|
spec:
|
|
resources:
|
|
# Removed for Brevity
|
|
- name: my-resource
|
|
base:
|
|
# Removed for brevity
|
|
readinessChecks:
|
|
- type: NonEmpty
|
|
fieldPath: status.atProvider.state
|
|
```
|
|
|
|
{{<hint "tip" >}}
|
|
Checking {{<hover label="NonEmpty" line="11">}}NonEmpty{{</hover>}} doesn't
|
|
require setting any other fields.
|
|
{{< /hint >}}
|
|
|
|
#### Always consider a resource ready
|
|
{{<hover label="none" line="11">}}None{{</hover>}} considers the
|
|
composed resource to be ready as soon as it's created. Crossplane doesn't wait
|
|
for any other conditions before declaring the resource ready.
|
|
|
|
For example, consider
|
|
{{<hover label="none" line="7">}}my-resource{{</hover>}}
|
|
ready as soon as it's created.
|
|
|
|
|
|
```yaml {label="none",copy-lines="none"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
# Removed for Brevity
|
|
spec:
|
|
resources:
|
|
# Removed for Brevity
|
|
- name: my-resource
|
|
base:
|
|
# Removed for brevity
|
|
readinessChecks:
|
|
- type: None
|
|
```
|
|
|
|
#### Match a condition
|
|
{{<hover label="condition" line="11">}}Condition{{</hover>}} considers the composed
|
|
resource to be ready when it finds the expected condition type, with the
|
|
expected status for it in its `status.conditions`.
|
|
|
|
For example, consider
|
|
{{<hover label="condition" line="7">}}my-resource{{</hover>}}, which is
|
|
ready if there is a condition of type
|
|
{{<hover label="condition" line="13">}}MyType{{</hover>}} with a status of
|
|
{{<hover label="condition" line="14">}}Success{{</hover>}}.
|
|
|
|
```yaml {label="condition",copy-lines="none"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
# Removed for Brevity
|
|
spec:
|
|
resources:
|
|
# Removed for Brevity
|
|
- name: my-resource
|
|
base:
|
|
# Removed for brevity
|
|
readinessChecks:
|
|
- type: MatchCondition
|
|
matchCondition:
|
|
type: MyType
|
|
status: Success
|
|
```
|
|
|
|
## Verify a Composition
|
|
|
|
View all available Compositions with `kubectl get composition`.
|
|
|
|
```shell {copy-lines="1"}
|
|
kubectl get composition
|
|
NAME XR-KIND XR-APIVERSION AGE
|
|
xapps.aws.platformref.upbound.io XApp aws.platformref.upbound.io/v1alpha1 123m
|
|
xclusters.aws.platformref.upbound.io XCluster aws.platformref.upbound.io/v1alpha1 123m
|
|
xeks.aws.platformref.upbound.io XEKS aws.platformref.upbound.io/v1alpha1 123m
|
|
xnetworks.aws.platformref.upbound.io XNetwork aws.platformref.upbound.io/v1alpha1 123m
|
|
xservices.aws.platformref.upbound.io XServices aws.platformref.upbound.io/v1alpha1 123m
|
|
xsqlinstances.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.
|
|
|
|
{{<hint "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.
|
|
{{< /hint >}}
|
|
|
|
## Composition validation
|
|
|
|
When creating a Composition Crossplane automatically validates specific
|
|
parameters in the Composition.
|
|
|
|
* All resources either use a `name` or don't. Compositions can't use both named
|
|
and unnamed resources.
|
|
* No duplicate resource names.
|
|
* Patch sets must have names.
|
|
* Patches that require a `fromFieldPath` value provide it.
|
|
* Patches that require a `toFieldPath` value provide it.
|
|
* Patches that require a `combine` field provide it.
|
|
* Readiness checks using `matchString` aren't empty.
|
|
* Readiness checks using `matchInteger` isn't `0`.
|
|
* Readiness checks requiring a `fieldPath` value provide it.
|
|
* If using composition functions, all resources must have names.
|
|
* Composition function container field isn't empty.
|
|
* Composition function `type` is `container`.
|
|
* Composition function names are unique.
|
|
|
|
### Resource schema validation
|
|
<!-- vale write-good.TooWordy = NO -->
|
|
Optionally, Crossplane can also validate the schema of the resources defined
|
|
inside a Composition. This verifies that the resource `apiVersion` and `kinds`
|
|
are valid.
|
|
<!-- vale write-good.TooWordy = YES -->
|
|
|
|
Enable "schema validation" with the
|
|
`--enable-composition-webhook-schema-validation` flag on the Crossplane pod.
|
|
The [Crossplane Pods]({{<ref "./pods#edit-the-deployment">}}) page has
|
|
more information on enabling Crossplane flags.
|
|
|
|
{{<hint "note" >}}
|
|
<!-- vale write-good.TooWordy = NO -->
|
|
Schema validation only checks the `apiVersion` and `kind` are valid. Schema
|
|
validation doesn't validate the fields of a specific resource.
|
|
<!-- vale write-good.TooWordy = YES -->
|
|
{{< /hint >}}
|
|
|
|
The default validations are still checked with schema validation enabled.
|
|
#### Validation modes
|
|
|
|
Schema validation supports two modes:
|
|
* `loose` (default) - Sends an warning for each schema error and installs the
|
|
Composition if the default validations pass.
|
|
* `strict` - Send an error for every schema validation error and rejects the
|
|
Composition.
|
|
|
|
Change the validation mode for a Composition with the
|
|
{{<hover label="mode" line="5">}}crossplane.io/composition-validation-mode{{</hover>}}
|
|
annotation.
|
|
|
|
For example, to enable `strict` mode checking:
|
|
|
|
```yaml {copy-lines="none",label="mode"}
|
|
apiVersion: apiextensions.crossplane.io/v1
|
|
kind: Composition
|
|
metadata:
|
|
annotations:
|
|
crossplane.io/composition-validation-mode: strict
|
|
# Removed for brevity
|
|
spec:
|
|
# Removed for brevity
|
|
```
|