Release 1.17

Signed-off-by: Sharp <rachel.sharp@upbound.io>
This commit is contained in:
Sharp 2024-08-28 21:24:43 -04:00
parent cc113034d4
commit 7c65422084
No known key found for this signature in database
GPG Key ID: 0C35FDAA4260054B
63 changed files with 39982 additions and 3 deletions

View File

@ -90,7 +90,7 @@ security:
# Global parameters accessible by any Page
params:
# The current "latest" version. Used in the version dropdown
latest: "1.16"
latest: "1.17"
docs: true
anchors:
# Generate heading anchors for any heading between min and max

51
content/v1.17/_index.md Normal file
View File

@ -0,0 +1,51 @@
---
title: "Overview"
weight: -1
cascade:
version: "v1.17"
---
{{< img src="/media/banner.png" alt="Crossplane Popsicle Truck" size="large" >}}
<br />
Crossplane is an open source Kubernetes extension that transforms your Kubernetes
cluster into a **universal control plane**.
Crossplane lets you manage anything, anywhere, all through standard Kubernetes
APIs. Crossplane can even let you
[order a pizza](https://blog.crossplane.io/providers-101-ordering-pizza-with-kubernetes-and-crossplane/)
directly from Kubernetes. If it has an API, Crossplane can connect to it.
With Crossplane, platform teams can create new abstractions and custom
APIs with the full power of Kubernetes policies, namespaces, role based access
controls and more. Crossplane brings all your non-Kubernetes resources under
one roof.
Custom APIs, created by platform teams, allow security and compliance
enforcement across resources or clouds, without exposing any complexity to the
developers. A single API call can create multiple resources, in multiple clouds
and use Kubernetes as the control plane for everything.
{{< hint "tip" >}}
**What's a control plane?**
<!-- vale Google.WordList = NO -->
Control planes create and manage the lifecycle of resources. Control planes
constantly _check_ that the intended resources exist, _report_ when the intended
state doesn't match reality and _act_ to make things right.
Crossplane extends the Kubernetes control plane to be a **universal control
plane** to check, report and act on any resource, anywhere.
<!-- vale Google.WordList = YES -->
{{< /hint >}}
# Get started
* [Install Crossplane]({{<ref "software/install">}}) in your Kubernetes cluster
* Learn more about how Crossplane works in the
[Crossplane introduction]({{<ref "getting-started/introduction" >}})
* Join the [Crossplane Slack](https://slack.crossplane.io/) and start a
conversation with a community of over 7,000 operators.
Crossplane is a [Cloud Native Compute Foundation](https://www.cncf.io/) project.

View File

@ -0,0 +1,13 @@
---
title: API Reference
weight: 400
description: "API details for Crossplane's core types"
cascade:
product: crds
---
The Crossplane API describes the types and parameters for the core Crossplane
components.
For details on the components read the [Concepts]({{<ref "../concepts/">}})
section.

View File

@ -0,0 +1,581 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
name: compositeresourcedefinitions.apiextensions.crossplane.io
spec:
group: apiextensions.crossplane.io
names:
categories:
- crossplane
kind: CompositeResourceDefinition
listKind: CompositeResourceDefinitionList
plural: compositeresourcedefinitions
shortNames:
- xrd
- xrds
singular: compositeresourcedefinition
scope: Cluster
versions:
- additionalPrinterColumns:
- jsonPath: .status.conditions[?(@.type=='Established')].status
name: ESTABLISHED
type: string
- jsonPath: .status.conditions[?(@.type=='Offered')].status
name: OFFERED
type: string
- jsonPath: .metadata.creationTimestamp
name: AGE
type: date
name: v1
schema:
openAPIV3Schema:
description: |-
A CompositeResourceDefinition defines the schema for a new custom Kubernetes
API.
Read the Crossplane documentation for
[more information about CustomResourceDefinitions](https://docs.crossplane.io/latest/concepts/composite-resource-definitions).
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: CompositeResourceDefinitionSpec specifies the desired state
of the definition.
properties:
claimNames:
description: |-
ClaimNames specifies the names of an optional composite resource claim.
When claim names are specified Crossplane will create a namespaced
'composite resource claim' CRD that corresponds to the defined composite
resource. This composite resource claim acts as a namespaced proxy for
the composite resource; creating, updating, or deleting the claim will
create, update, or delete a corresponding composite resource. You may add
claim names to an existing CompositeResourceDefinition, but they cannot
be changed or removed once they have been set.
properties:
categories:
description: |-
categories is a list of grouped resources this custom resource belongs to (e.g. 'all').
This is published in API discovery documents, and used by clients to support invocations like
`kubectl get all`.
items:
type: string
type: array
x-kubernetes-list-type: atomic
kind:
description: |-
kind is the serialized kind of the resource. It is normally CamelCase and singular.
Custom resource instances will use this value as the `kind` attribute in API calls.
type: string
listKind:
description: listKind is the serialized kind of the list for this
resource. Defaults to "`kind`List".
type: string
plural:
description: |-
plural is the plural name of the resource to serve.
The custom resources are served under `/apis/<group>/<version>/.../<plural>`.
Must match the name of the CustomResourceDefinition (in the form `<names.plural>.<group>`).
Must be all lowercase.
type: string
shortNames:
description: |-
shortNames are short names for the resource, exposed in API discovery documents,
and used by clients to support invocations like `kubectl get <shortname>`.
It must be all lowercase.
items:
type: string
type: array
x-kubernetes-list-type: atomic
singular:
description: singular is the singular name of the resource. It
must be all lowercase. Defaults to lowercased `kind`.
type: string
required:
- kind
- plural
type: object
x-kubernetes-validations:
- message: Value is immutable
rule: self == oldSelf
connectionSecretKeys:
description: |-
ConnectionSecretKeys is the list of keys that will be exposed to the end
user of the defined kind.
If the list is empty, all keys will be published.
items:
type: string
type: array
conversion:
description: Conversion defines all conversion settings for the defined
Composite resource.
properties:
strategy:
description: |-
strategy specifies how custom resources are converted between versions. Allowed values are:
- `"None"`: The converter only change the apiVersion and would not touch any other field in the custom resource.
- `"Webhook"`: API Server will call to an external webhook to do the conversion. Additional information
is needed for this option. This requires spec.preserveUnknownFields to be false, and spec.conversion.webhook to be set.
type: string
webhook:
description: webhook describes how to call the conversion webhook.
Required when `strategy` is set to `"Webhook"`.
properties:
clientConfig:
description: clientConfig is the instructions for how to call
the webhook if strategy is `Webhook`.
properties:
caBundle:
description: |-
caBundle is a PEM encoded CA bundle which will be used to validate the webhook's server certificate.
If unspecified, system trust roots on the apiserver are used.
format: byte
type: string
service:
description: |-
service is a reference to the service for this webhook. Either
service or url must be specified.
If the webhook is running within the cluster, then you should use `service`.
properties:
name:
description: |-
name is the name of the service.
Required
type: string
namespace:
description: |-
namespace is the namespace of the service.
Required
type: string
path:
description: path is an optional URL path at which
the webhook will be contacted.
type: string
port:
description: |-
port is an optional service port at which the webhook will be contacted.
`port` should be a valid port number (1-65535, inclusive).
Defaults to 443 for backward compatibility.
format: int32
type: integer
required:
- name
- namespace
type: object
url:
description: |-
url gives the location of the webhook, in standard URL form
(`scheme://host:port/path`). Exactly one of `url` or `service`
must be specified.
The `host` should not refer to a service running in the cluster; use
the `service` field instead. The host might be resolved via external
DNS in some apiservers (e.g., `kube-apiserver` cannot resolve
in-cluster DNS as that would be a layering violation). `host` may
also be an IP address.
Please note that using `localhost` or `127.0.0.1` as a `host` is
risky unless you take great care to run this webhook on all hosts
which run an apiserver which might need to make calls to this
webhook. Such installs are likely to be non-portable, i.e., not easy
to turn up in a new cluster.
The scheme must be "https"; the URL must begin with "https://".
A path is optional, and if present may be any string permissible in
a URL. You may use the path to pass an arbitrary string to the
webhook, for example, a cluster identifier.
Attempting to use a user or basic auth e.g. "user:password@" is not
allowed. Fragments ("#...") and query parameters ("?...") are not
allowed, either.
type: string
type: object
conversionReviewVersions:
description: |-
conversionReviewVersions is an ordered list of preferred `ConversionReview`
versions the Webhook expects. The API server will use the first version in
the list which it supports. If none of the versions specified in this list
are supported by API server, conversion will fail for the custom resource.
If a persisted Webhook configuration specifies allowed versions and does not
include any versions known to the API Server, calls to the webhook will fail.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- conversionReviewVersions
type: object
required:
- strategy
type: object
defaultCompositeDeletePolicy:
default: Background
description: |-
DefaultCompositeDeletePolicy is the policy used when deleting the Composite
that is associated with the Claim if no policy has been specified.
enum:
- Background
- Foreground
type: string
defaultCompositionRef:
description: |-
DefaultCompositionRef refers to the Composition resource that will be used
in case no composition selector is given.
properties:
name:
description: Name of the Composition.
type: string
required:
- name
type: object
defaultCompositionUpdatePolicy:
default: Automatic
description: |-
DefaultCompositionUpdatePolicy is the policy used when updating composites after a new
Composition Revision has been created if no policy has been specified on the composite.
enum:
- Automatic
- Manual
type: string
enforcedCompositionRef:
description: |-
EnforcedCompositionRef refers to the Composition resource that will be used
by all composite instances whose schema is defined by this definition.
properties:
name:
description: Name of the Composition.
type: string
required:
- name
type: object
x-kubernetes-validations:
- message: Value is immutable
rule: self == oldSelf
group:
description: |-
Group specifies the API group of the defined composite resource.
Composite resources are served under `/apis/<group>/...`. Must match the
name of the XRD (in the form `<names.plural>.<group>`).
type: string
x-kubernetes-validations:
- message: Value is immutable
rule: self == oldSelf
metadata:
description: Metadata specifies the desired metadata for the defined
composite resource and claim CRD's.
properties:
annotations:
additionalProperties:
type: string
description: |-
Annotations is an unstructured key value map stored with a resource that may be
set by external tools to store and retrieve arbitrary metadata. They are not
queryable and should be preserved when modifying objects.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations
type: object
labels:
additionalProperties:
type: string
description: |-
Map of string keys and values that can be used to organize and categorize
(scope and select) objects. May match selectors of replication controllers
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels
and services.
These labels are added to the composite resource and claim CRD's in addition
to any labels defined by `CompositionResourceDefinition` `metadata.labels`.
type: object
type: object
names:
description: |-
Names specifies the resource and kind names of the defined composite
resource.
properties:
categories:
description: |-
categories is a list of grouped resources this custom resource belongs to (e.g. 'all').
This is published in API discovery documents, and used by clients to support invocations like
`kubectl get all`.
items:
type: string
type: array
x-kubernetes-list-type: atomic
kind:
description: |-
kind is the serialized kind of the resource. It is normally CamelCase and singular.
Custom resource instances will use this value as the `kind` attribute in API calls.
type: string
listKind:
description: listKind is the serialized kind of the list for this
resource. Defaults to "`kind`List".
type: string
plural:
description: |-
plural is the plural name of the resource to serve.
The custom resources are served under `/apis/<group>/<version>/.../<plural>`.
Must match the name of the CustomResourceDefinition (in the form `<names.plural>.<group>`).
Must be all lowercase.
type: string
shortNames:
description: |-
shortNames are short names for the resource, exposed in API discovery documents,
and used by clients to support invocations like `kubectl get <shortname>`.
It must be all lowercase.
items:
type: string
type: array
x-kubernetes-list-type: atomic
singular:
description: singular is the singular name of the resource. It
must be all lowercase. Defaults to lowercased `kind`.
type: string
required:
- kind
- plural
type: object
x-kubernetes-validations:
- message: Value is immutable
rule: self == oldSelf
versions:
description: |-
Versions is the list of all API versions of the defined composite
resource. Version names are used to compute the order in which served
versions are listed in API discovery. If the version string is
"kube-like", it will sort above non "kube-like" version strings, which
are ordered lexicographically. "Kube-like" versions start with a "v",
then are followed by a number (the major version), then optionally the
string "alpha" or "beta" and another number (the minor version). These
are sorted first by GA > beta > alpha (where GA is a version with no
suffix such as beta or alpha), and then by comparing major version, then
minor version. An example sorted list of versions: v10, v2, v1, v11beta2,
v10beta3, v3beta1, v12alpha1, v11alpha2, foo1, foo10.
items:
description: CompositeResourceDefinitionVersion describes a version
of an XR.
properties:
additionalPrinterColumns:
description: |-
AdditionalPrinterColumns specifies additional columns returned in Table
output. If no columns are specified, a single column displaying the age
of the custom resource is used. See the following link for details:
https://kubernetes.io/docs/reference/using-api/api-concepts/#receiving-resources-as-tables
items:
description: CustomResourceColumnDefinition specifies a column
for server side printing.
properties:
description:
description: description is a human readable description
of this column.
type: string
format:
description: |-
format is an optional OpenAPI type definition for this column. The 'name' format is applied
to the primary identifier column to assist in clients identifying column is the resource name.
See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for details.
type: string
jsonPath:
description: |-
jsonPath is a simple JSON path (i.e. with array notation) which is evaluated against
each custom resource to produce the value for this column.
type: string
name:
description: name is a human readable name for the column.
type: string
priority:
description: |-
priority is an integer defining the relative importance of this column compared to others. Lower
numbers are considered higher priority. Columns that may be omitted in limited space scenarios
should be given a priority greater than 0.
format: int32
type: integer
type:
description: |-
type is an OpenAPI type definition for this column.
See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for details.
type: string
required:
- jsonPath
- name
- type
type: object
type: array
deprecated:
description: |-
The deprecated field specifies that this version is deprecated and should
not be used.
type: boolean
deprecationWarning:
description: |-
DeprecationWarning specifies the message that should be shown to the user
when using this version.
maxLength: 256
type: string
name:
description: |-
Name of this version, e.g. “v1”, “v2beta1”, etc. Composite resources are
served under this version at `/apis/<group>/<version>/...` if `served` is
true.
type: string
referenceable:
description: |-
Referenceable specifies that this version may be referenced by a
Composition in order to configure which resources an XR may be composed
of. Exactly one version must be marked as referenceable; all Compositions
must target only the referenceable version. The referenceable version
must be served. It's mapped to the CRD's `spec.versions[*].storage` field.
type: boolean
schema:
description: |-
Schema describes the schema used for validation, pruning, and defaulting
of this version of the defined composite resource. Fields required by all
composite resources will be injected into this schema automatically, and
will override equivalently named fields in this schema. Omitting this
schema results in a schema that contains only the fields required by all
composite resources.
properties:
openAPIV3Schema:
description: |-
OpenAPIV3Schema is the OpenAPI v3 schema to use for validation and
pruning.
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
served:
description: Served specifies that this version should be served
via REST APIs.
type: boolean
required:
- name
- referenceable
- served
type: object
type: array
required:
- group
- names
- versions
type: object
status:
description: CompositeResourceDefinitionStatus shows the observed state
of the definition.
properties:
conditions:
description: Conditions of the resource.
items:
description: A Condition that may apply to a resource.
properties:
lastTransitionTime:
description: |-
LastTransitionTime is the last time this condition transitioned from one
status to another.
format: date-time
type: string
message:
description: |-
A Message containing details about this condition's last transition from
one status to another, if any.
type: string
observedGeneration:
description: |-
ObservedGeneration represents the .metadata.generation that the condition was set based upon.
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
with respect to the current state of the instance.
format: int64
type: integer
reason:
description: A Reason for this condition's last transition from
one status to another.
type: string
status:
description: Status of this condition; is it currently True,
False, or Unknown?
type: string
type:
description: |-
Type of this condition. At most one of each condition type may apply to
a resource at any point in time.
type: string
required:
- lastTransitionTime
- reason
- status
- type
type: object
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
controllers:
description: |-
Controllers represents the status of the controllers that power this
composite resource definition.
properties:
compositeResourceClaimType:
description: |-
The CompositeResourceClaimTypeRef is the type of composite resource claim
that Crossplane is currently reconciling for this definition. Its version
will eventually become consistent with the definition's referenceable
version. Note that clients may interact with any served type; this is
simply the type that Crossplane interacts with.
properties:
apiVersion:
description: APIVersion of the type.
type: string
kind:
description: Kind of the type.
type: string
required:
- apiVersion
- kind
type: object
compositeResourceType:
description: |-
The CompositeResourceTypeRef is the type of composite resource that
Crossplane is currently reconciling for this definition. Its version will
eventually become consistent with the definition's referenceable version.
Note that clients may interact with any served type; this is simply the
type that Crossplane interacts with.
properties:
apiVersion:
description: APIVersion of the type.
type: string
kind:
description: Kind of the type.
type: string
required:
- apiVersion
- kind
type: object
type: object
type: object
type: object
served: true
storage: true
subresources:
status: {}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,63 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
name: environmentconfigs.apiextensions.crossplane.io
spec:
group: apiextensions.crossplane.io
names:
categories:
- crossplane
kind: EnvironmentConfig
listKind: EnvironmentConfigList
plural: environmentconfigs
shortNames:
- envcfg
singular: environmentconfig
scope: Cluster
versions:
- additionalPrinterColumns:
- jsonPath: .metadata.creationTimestamp
name: AGE
type: date
name: v1alpha1
schema:
openAPIV3Schema:
description: |-
An EnvironmentConfig contains user-defined unstructured values for
use in a Composition.
Read the Crossplane documentation for
[more information about EnvironmentConfigs](https://docs.crossplane.io/latest/concepts/environment-configs).
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
data:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: |-
The data of this EnvironmentConfig.
This may contain any kind of structure that can be serialized into JSON.
type: object
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
type: object
served: true
storage: true
subresources: {}

View File

@ -0,0 +1,217 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
name: usages.apiextensions.crossplane.io
spec:
group: apiextensions.crossplane.io
names:
categories:
- crossplane
kind: Usage
listKind: UsageList
plural: usages
singular: usage
scope: Cluster
versions:
- additionalPrinterColumns:
- jsonPath: .metadata.annotations.crossplane\.io/usage-details
name: DETAILS
type: string
- jsonPath: .status.conditions[?(@.type=='Ready')].status
name: READY
type: string
- jsonPath: .metadata.creationTimestamp
name: AGE
type: date
name: v1alpha1
schema:
openAPIV3Schema:
description: |-
A Usage defines a deletion blocking relationship between two resources.
Usages prevent accidental deletion of a single resource or deletion of
resources with dependent resources.
Read the Crossplane documentation for
[more information about Compositions](https://docs.crossplane.io/latest/concepts/usages).
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: UsageSpec defines the desired state of Usage.
properties:
by:
description: By is the resource that is "using the other resource".
properties:
apiVersion:
description: API version of the referent.
type: string
kind:
description: |-
Kind of the referent.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
resourceRef:
description: Reference to the resource.
properties:
name:
description: Name of the referent.
type: string
required:
- name
type: object
resourceSelector:
description: |-
Selector to the resource.
This field will be ignored if ResourceRef is set.
properties:
matchControllerRef:
description: |-
MatchControllerRef ensures an object with the same controller reference
as the selecting object is selected.
type: boolean
matchLabels:
additionalProperties:
type: string
description: MatchLabels ensures an object with matching labels
is selected.
type: object
type: object
type: object
x-kubernetes-validations:
- message: either a resource reference or a resource selector should
be set.
rule: has(self.resourceRef) || has(self.resourceSelector)
of:
description: Of is the resource that is "being used".
properties:
apiVersion:
description: API version of the referent.
type: string
kind:
description: |-
Kind of the referent.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
resourceRef:
description: Reference to the resource.
properties:
name:
description: Name of the referent.
type: string
required:
- name
type: object
resourceSelector:
description: |-
Selector to the resource.
This field will be ignored if ResourceRef is set.
properties:
matchControllerRef:
description: |-
MatchControllerRef ensures an object with the same controller reference
as the selecting object is selected.
type: boolean
matchLabels:
additionalProperties:
type: string
description: MatchLabels ensures an object with matching labels
is selected.
type: object
type: object
type: object
x-kubernetes-validations:
- message: either a resource reference or a resource selector should
be set.
rule: has(self.resourceRef) || has(self.resourceSelector)
reason:
description: Reason is the reason for blocking deletion of the resource.
type: string
replayDeletion:
description: ReplayDeletion will trigger a deletion on the used resource
during the deletion of the usage itself, if it was attempted to
be deleted at least once.
type: boolean
required:
- of
type: object
x-kubernetes-validations:
- message: either "spec.by" or "spec.reason" must be specified.
rule: has(self.by) || has(self.reason)
status:
description: UsageStatus defines the observed state of Usage.
properties:
conditions:
description: Conditions of the resource.
items:
description: A Condition that may apply to a resource.
properties:
lastTransitionTime:
description: |-
LastTransitionTime is the last time this condition transitioned from one
status to another.
format: date-time
type: string
message:
description: |-
A Message containing details about this condition's last transition from
one status to another, if any.
type: string
observedGeneration:
description: |-
ObservedGeneration represents the .metadata.generation that the condition was set based upon.
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
with respect to the current state of the instance.
format: int64
type: integer
reason:
description: A Reason for this condition's last transition from
one status to another.
type: string
status:
description: Status of this condition; is it currently True,
False, or Unknown?
type: string
type:
description: |-
Type of this condition. At most one of each condition type may apply to
a resource at any point in time.
type: string
required:
- lastTransitionTime
- reason
- status
- type
type: object
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
type: object
required:
- spec
type: object
served: true
storage: true
subresources:
status: {}

View File

@ -0,0 +1,287 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
name: configurationrevisions.pkg.crossplane.io
spec:
group: pkg.crossplane.io
names:
categories:
- crossplane
- pkgrev
kind: ConfigurationRevision
listKind: ConfigurationRevisionList
plural: configurationrevisions
singular: configurationrevision
scope: Cluster
versions:
- additionalPrinterColumns:
- jsonPath: .status.conditions[?(@.type=='Healthy')].status
name: HEALTHY
type: string
- jsonPath: .spec.revision
name: REVISION
type: string
- jsonPath: .spec.image
name: IMAGE
type: string
- jsonPath: .spec.desiredState
name: STATE
type: string
- jsonPath: .status.foundDependencies
name: DEP-FOUND
type: string
- jsonPath: .status.installedDependencies
name: DEP-INSTALLED
type: string
- jsonPath: .metadata.creationTimestamp
name: AGE
type: date
name: v1
schema:
openAPIV3Schema:
description: |-
A ConfigurationRevision represents a revision of a Configuration. Crossplane
creates new revisions when there are changes to a Configuration.
Crossplane creates and manages ConfigurationRevision. Don't directly edit
ConfigurationRevisions.
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: PackageRevisionSpec specifies the desired state of a PackageRevision.
properties:
commonLabels:
additionalProperties:
type: string
description: |-
Map of string keys and values that can be used to organize and categorize
(scope and select) objects. May match selectors of replication controllers
and services.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
type: object
desiredState:
description: DesiredState of the PackageRevision. Can be either Active
or Inactive.
type: string
ignoreCrossplaneConstraints:
default: false
description: |-
IgnoreCrossplaneConstraints indicates to the package manager whether to
honor Crossplane version constrains specified by the package.
Default is false.
type: boolean
image:
description: Package image used by install Pod to extract package
contents.
type: string
packagePullPolicy:
default: IfNotPresent
description: |-
PackagePullPolicy defines the pull policy for the package. It is also
applied to any images pulled for the package, such as a provider's
controller image.
Default is IfNotPresent.
type: string
packagePullSecrets:
description: |-
PackagePullSecrets are named secrets in the same namespace that can be
used to fetch packages from private registries. They are also applied to
any images pulled for the package, such as a provider's controller image.
items:
description: |-
LocalObjectReference contains enough information to let you locate the
referenced object inside the same namespace.
properties:
name:
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?
type: string
type: object
x-kubernetes-map-type: atomic
type: array
revision:
description: |-
Revision number. Indicates when the revision will be garbage collected
based on the parent's RevisionHistoryLimit.
format: int64
type: integer
skipDependencyResolution:
default: false
description: |-
SkipDependencyResolution indicates to the package manager whether to skip
resolving dependencies for a package. Setting this value to true may have
unintended consequences.
Default is false.
type: boolean
required:
- desiredState
- image
- revision
type: object
status:
description: PackageRevisionStatus represents the observed state of a
PackageRevision.
properties:
conditions:
description: Conditions of the resource.
items:
description: A Condition that may apply to a resource.
properties:
lastTransitionTime:
description: |-
LastTransitionTime is the last time this condition transitioned from one
status to another.
format: date-time
type: string
message:
description: |-
A Message containing details about this condition's last transition from
one status to another, if any.
type: string
observedGeneration:
description: |-
ObservedGeneration represents the .metadata.generation that the condition was set based upon.
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
with respect to the current state of the instance.
format: int64
type: integer
reason:
description: A Reason for this condition's last transition from
one status to another.
type: string
status:
description: Status of this condition; is it currently True,
False, or Unknown?
type: string
type:
description: |-
Type of this condition. At most one of each condition type may apply to
a resource at any point in time.
type: string
required:
- lastTransitionTime
- reason
- status
- type
type: object
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
foundDependencies:
description: Dependency information.
format: int64
type: integer
installedDependencies:
format: int64
type: integer
invalidDependencies:
format: int64
type: integer
objectRefs:
description: References to objects owned by PackageRevision.
items:
description: |-
A TypedReference refers to an object by Name, Kind, and APIVersion. It is
commonly used to reference cluster-scoped objects or objects where the
namespace is already known.
properties:
apiVersion:
description: APIVersion of the referenced object.
type: string
kind:
description: Kind of the referenced object.
type: string
name:
description: Name of the referenced object.
type: string
uid:
description: UID of the referenced object.
type: string
required:
- apiVersion
- kind
- name
type: object
type: array
permissionRequests:
description: |-
PermissionRequests made by this package. The package declares that its
controller needs these permissions to run. The RBAC manager is
responsible for granting them.
items:
description: |-
PolicyRule holds information that describes a policy rule, but does not contain information
about who the rule applies to or which namespace the rule applies to.
properties:
apiGroups:
description: |-
APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of
the enumerated resources in any API group will be allowed. "" represents the core API group and "*" represents all API groups.
items:
type: string
type: array
x-kubernetes-list-type: atomic
nonResourceURLs:
description: |-
NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path
Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding.
Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both.
items:
type: string
type: array
x-kubernetes-list-type: atomic
resourceNames:
description: ResourceNames is an optional white list of names
that the rule applies to. An empty set means that everything
is allowed.
items:
type: string
type: array
x-kubernetes-list-type: atomic
resources:
description: Resources is a list of resources this rule applies
to. '*' represents all resources.
items:
type: string
type: array
x-kubernetes-list-type: atomic
verbs:
description: Verbs is a list of Verbs that apply to ALL the
ResourceKinds contained in this rule. '*' represents all verbs.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- verbs
type: object
type: array
type: object
type: object
served: true
storage: true
subresources:
status: {}

View File

@ -0,0 +1,205 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
name: configurations.pkg.crossplane.io
spec:
group: pkg.crossplane.io
names:
categories:
- crossplane
- pkg
kind: Configuration
listKind: ConfigurationList
plural: configurations
singular: configuration
scope: Cluster
versions:
- additionalPrinterColumns:
- jsonPath: .status.conditions[?(@.type=='Installed')].status
name: INSTALLED
type: string
- jsonPath: .status.conditions[?(@.type=='Healthy')].status
name: HEALTHY
type: string
- jsonPath: .spec.package
name: PACKAGE
type: string
- jsonPath: .metadata.creationTimestamp
name: AGE
type: date
name: v1
schema:
openAPIV3Schema:
description: |-
A Configuration installs an OCI compatible Crossplane package, extending
Crossplane with support for new kinds of CompositeResourceDefinitions and
Compositions.
Read the Crossplane documentation for
[more information about Configuration packages](https://docs.crossplane.io/latest/concepts/packages).
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: |-
ConfigurationSpec specifies details about a request to install a
configuration to Crossplane.
properties:
commonLabels:
additionalProperties:
type: string
description: |-
Map of string keys and values that can be used to organize and categorize
(scope and select) objects. May match selectors of replication controllers
and services.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
type: object
ignoreCrossplaneConstraints:
default: false
description: |-
IgnoreCrossplaneConstraints indicates to the package manager whether to
honor Crossplane version constrains specified by the package.
Default is false.
type: boolean
package:
description: Package is the name of the package that is being requested.
type: string
packagePullPolicy:
default: IfNotPresent
description: |-
PackagePullPolicy defines the pull policy for the package.
Default is IfNotPresent.
type: string
packagePullSecrets:
description: |-
PackagePullSecrets are named secrets in the same namespace that can be used
to fetch packages from private registries.
items:
description: |-
LocalObjectReference contains enough information to let you locate the
referenced object inside the same namespace.
properties:
name:
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?
type: string
type: object
x-kubernetes-map-type: atomic
type: array
revisionActivationPolicy:
default: Automatic
description: |-
RevisionActivationPolicy specifies how the package controller should
update from one revision to the next. Options are Automatic or Manual.
Default is Automatic.
type: string
revisionHistoryLimit:
default: 1
description: |-
RevisionHistoryLimit dictates how the package controller cleans up old
inactive package revisions.
Defaults to 1. Can be disabled by explicitly setting to 0.
format: int64
type: integer
skipDependencyResolution:
default: false
description: |-
SkipDependencyResolution indicates to the package manager whether to skip
resolving dependencies for a package. Setting this value to true may have
unintended consequences.
Default is false.
type: boolean
required:
- package
type: object
status:
description: ConfigurationStatus represents the observed state of a Configuration.
properties:
conditions:
description: Conditions of the resource.
items:
description: A Condition that may apply to a resource.
properties:
lastTransitionTime:
description: |-
LastTransitionTime is the last time this condition transitioned from one
status to another.
format: date-time
type: string
message:
description: |-
A Message containing details about this condition's last transition from
one status to another, if any.
type: string
observedGeneration:
description: |-
ObservedGeneration represents the .metadata.generation that the condition was set based upon.
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
with respect to the current state of the instance.
format: int64
type: integer
reason:
description: A Reason for this condition's last transition from
one status to another.
type: string
status:
description: Status of this condition; is it currently True,
False, or Unknown?
type: string
type:
description: |-
Type of this condition. At most one of each condition type may apply to
a resource at any point in time.
type: string
required:
- lastTransitionTime
- reason
- status
- type
type: object
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
currentIdentifier:
description: |-
CurrentIdentifier is the most recent package source that was used to
produce a revision. The package manager uses this field to determine
whether to check for package updates for a given source when
packagePullPolicy is set to IfNotPresent. Manually removing this field
will cause the package manager to check that the current revision is
correct for the given package source.
type: string
currentRevision:
description: |-
CurrentRevision is the name of the current package revision. It will
reflect the most up to date revision, whether it has been activated or
not.
type: string
type: object
type: object
served: true
storage: true
subresources:
status: {}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,651 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
name: functionrevisions.pkg.crossplane.io
spec:
group: pkg.crossplane.io
names:
categories:
- crossplane
- pkgrev
kind: FunctionRevision
listKind: FunctionRevisionList
plural: functionrevisions
singular: functionrevision
scope: Cluster
versions:
- additionalPrinterColumns:
- jsonPath: .status.conditions[?(@.type=='Healthy')].status
name: HEALTHY
type: string
- jsonPath: .spec.revision
name: REVISION
type: string
- jsonPath: .spec.image
name: IMAGE
type: string
- jsonPath: .spec.desiredState
name: STATE
type: string
- jsonPath: .status.foundDependencies
name: DEP-FOUND
type: string
- jsonPath: .status.installedDependencies
name: DEP-INSTALLED
type: string
- jsonPath: .metadata.creationTimestamp
name: AGE
type: date
name: v1
schema:
openAPIV3Schema:
description: |-
A FunctionRevision represents a revision of a Function. Crossplane
creates new revisions when there are changes to the Function.
Crossplane creates and manages FunctionRevisions. Don't directly edit
FunctionRevisions.
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: FunctionRevisionSpec specifies configuration for a FunctionRevision.
properties:
commonLabels:
additionalProperties:
type: string
description: |-
Map of string keys and values that can be used to organize and categorize
(scope and select) objects. May match selectors of replication controllers
and services.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
type: object
controllerConfigRef:
description: |-
ControllerConfigRef references a ControllerConfig resource that will be
used to configure the packaged controller Deployment.
Deprecated: Use RuntimeConfigReference instead.
properties:
name:
description: Name of the ControllerConfig.
type: string
required:
- name
type: object
desiredState:
description: DesiredState of the PackageRevision. Can be either Active
or Inactive.
type: string
ignoreCrossplaneConstraints:
default: false
description: |-
IgnoreCrossplaneConstraints indicates to the package manager whether to
honor Crossplane version constrains specified by the package.
Default is false.
type: boolean
image:
description: Package image used by install Pod to extract package
contents.
type: string
packagePullPolicy:
default: IfNotPresent
description: |-
PackagePullPolicy defines the pull policy for the package. It is also
applied to any images pulled for the package, such as a provider's
controller image.
Default is IfNotPresent.
type: string
packagePullSecrets:
description: |-
PackagePullSecrets are named secrets in the same namespace that can be
used to fetch packages from private registries. They are also applied to
any images pulled for the package, such as a provider's controller image.
items:
description: |-
LocalObjectReference contains enough information to let you locate the
referenced object inside the same namespace.
properties:
name:
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?
type: string
type: object
x-kubernetes-map-type: atomic
type: array
revision:
description: |-
Revision number. Indicates when the revision will be garbage collected
based on the parent's RevisionHistoryLimit.
format: int64
type: integer
runtimeConfigRef:
default:
name: default
description: |-
RuntimeConfigRef references a RuntimeConfig resource that will be used
to configure the package runtime.
properties:
apiVersion:
default: pkg.crossplane.io/v1beta1
description: API version of the referent.
type: string
kind:
default: DeploymentRuntimeConfig
description: Kind of the referent.
type: string
name:
description: Name of the RuntimeConfig.
type: string
required:
- name
type: object
skipDependencyResolution:
default: false
description: |-
SkipDependencyResolution indicates to the package manager whether to skip
resolving dependencies for a package. Setting this value to true may have
unintended consequences.
Default is false.
type: boolean
tlsClientSecretName:
description: |-
TLSClientSecretName is the name of the TLS Secret that stores client
certificates of the Provider.
type: string
tlsServerSecretName:
description: |-
TLSServerSecretName is the name of the TLS Secret that stores server
certificates of the Provider.
type: string
required:
- desiredState
- image
- revision
type: object
status:
description: FunctionRevisionStatus represents the observed state of a
FunctionRevision.
properties:
conditions:
description: Conditions of the resource.
items:
description: A Condition that may apply to a resource.
properties:
lastTransitionTime:
description: |-
LastTransitionTime is the last time this condition transitioned from one
status to another.
format: date-time
type: string
message:
description: |-
A Message containing details about this condition's last transition from
one status to another, if any.
type: string
observedGeneration:
description: |-
ObservedGeneration represents the .metadata.generation that the condition was set based upon.
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
with respect to the current state of the instance.
format: int64
type: integer
reason:
description: A Reason for this condition's last transition from
one status to another.
type: string
status:
description: Status of this condition; is it currently True,
False, or Unknown?
type: string
type:
description: |-
Type of this condition. At most one of each condition type may apply to
a resource at any point in time.
type: string
required:
- lastTransitionTime
- reason
- status
- type
type: object
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
endpoint:
description: |-
Endpoint is the gRPC endpoint where Crossplane will send
RunFunctionRequests.
type: string
foundDependencies:
description: Dependency information.
format: int64
type: integer
installedDependencies:
format: int64
type: integer
invalidDependencies:
format: int64
type: integer
objectRefs:
description: References to objects owned by PackageRevision.
items:
description: |-
A TypedReference refers to an object by Name, Kind, and APIVersion. It is
commonly used to reference cluster-scoped objects or objects where the
namespace is already known.
properties:
apiVersion:
description: APIVersion of the referenced object.
type: string
kind:
description: Kind of the referenced object.
type: string
name:
description: Name of the referenced object.
type: string
uid:
description: UID of the referenced object.
type: string
required:
- apiVersion
- kind
- name
type: object
type: array
permissionRequests:
description: |-
PermissionRequests made by this package. The package declares that its
controller needs these permissions to run. The RBAC manager is
responsible for granting them.
items:
description: |-
PolicyRule holds information that describes a policy rule, but does not contain information
about who the rule applies to or which namespace the rule applies to.
properties:
apiGroups:
description: |-
APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of
the enumerated resources in any API group will be allowed. "" represents the core API group and "*" represents all API groups.
items:
type: string
type: array
x-kubernetes-list-type: atomic
nonResourceURLs:
description: |-
NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path
Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding.
Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both.
items:
type: string
type: array
x-kubernetes-list-type: atomic
resourceNames:
description: ResourceNames is an optional white list of names
that the rule applies to. An empty set means that everything
is allowed.
items:
type: string
type: array
x-kubernetes-list-type: atomic
resources:
description: Resources is a list of resources this rule applies
to. '*' represents all resources.
items:
type: string
type: array
x-kubernetes-list-type: atomic
verbs:
description: Verbs is a list of Verbs that apply to ALL the
ResourceKinds contained in this rule. '*' represents all verbs.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- verbs
type: object
type: array
type: object
type: object
served: true
storage: true
subresources:
status: {}
- additionalPrinterColumns:
- jsonPath: .status.conditions[?(@.type=='Healthy')].status
name: HEALTHY
type: string
- jsonPath: .spec.revision
name: REVISION
type: string
- jsonPath: .spec.image
name: IMAGE
type: string
- jsonPath: .spec.desiredState
name: STATE
type: string
- jsonPath: .status.foundDependencies
name: DEP-FOUND
type: string
- jsonPath: .status.installedDependencies
name: DEP-INSTALLED
type: string
- jsonPath: .metadata.creationTimestamp
name: AGE
type: date
name: v1beta1
schema:
openAPIV3Schema:
description: |-
A FunctionRevision represents a revision of a Function. Crossplane
creates new revisions when there are changes to the Function.
Crossplane creates and manages FunctionRevisions. Don't directly edit
FunctionRevisions.
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: FunctionRevisionSpec specifies configuration for a FunctionRevision.
properties:
commonLabels:
additionalProperties:
type: string
description: |-
Map of string keys and values that can be used to organize and categorize
(scope and select) objects. May match selectors of replication controllers
and services.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
type: object
controllerConfigRef:
description: |-
ControllerConfigRef references a ControllerConfig resource that will be
used to configure the packaged controller Deployment.
Deprecated: Use RuntimeConfigReference instead.
properties:
name:
description: Name of the ControllerConfig.
type: string
required:
- name
type: object
desiredState:
description: DesiredState of the PackageRevision. Can be either Active
or Inactive.
type: string
ignoreCrossplaneConstraints:
default: false
description: |-
IgnoreCrossplaneConstraints indicates to the package manager whether to
honor Crossplane version constrains specified by the package.
Default is false.
type: boolean
image:
description: Package image used by install Pod to extract package
contents.
type: string
packagePullPolicy:
default: IfNotPresent
description: |-
PackagePullPolicy defines the pull policy for the package. It is also
applied to any images pulled for the package, such as a provider's
controller image.
Default is IfNotPresent.
type: string
packagePullSecrets:
description: |-
PackagePullSecrets are named secrets in the same namespace that can be
used to fetch packages from private registries. They are also applied to
any images pulled for the package, such as a provider's controller image.
items:
description: |-
LocalObjectReference contains enough information to let you locate the
referenced object inside the same namespace.
properties:
name:
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?
type: string
type: object
x-kubernetes-map-type: atomic
type: array
revision:
description: |-
Revision number. Indicates when the revision will be garbage collected
based on the parent's RevisionHistoryLimit.
format: int64
type: integer
runtimeConfigRef:
default:
name: default
description: |-
RuntimeConfigRef references a RuntimeConfig resource that will be used
to configure the package runtime.
properties:
apiVersion:
default: pkg.crossplane.io/v1beta1
description: API version of the referent.
type: string
kind:
default: DeploymentRuntimeConfig
description: Kind of the referent.
type: string
name:
description: Name of the RuntimeConfig.
type: string
required:
- name
type: object
skipDependencyResolution:
default: false
description: |-
SkipDependencyResolution indicates to the package manager whether to skip
resolving dependencies for a package. Setting this value to true may have
unintended consequences.
Default is false.
type: boolean
tlsClientSecretName:
description: |-
TLSClientSecretName is the name of the TLS Secret that stores client
certificates of the Provider.
type: string
tlsServerSecretName:
description: |-
TLSServerSecretName is the name of the TLS Secret that stores server
certificates of the Provider.
type: string
required:
- desiredState
- image
- revision
type: object
status:
description: FunctionRevisionStatus represents the observed state of a
FunctionRevision.
properties:
conditions:
description: Conditions of the resource.
items:
description: A Condition that may apply to a resource.
properties:
lastTransitionTime:
description: |-
LastTransitionTime is the last time this condition transitioned from one
status to another.
format: date-time
type: string
message:
description: |-
A Message containing details about this condition's last transition from
one status to another, if any.
type: string
observedGeneration:
description: |-
ObservedGeneration represents the .metadata.generation that the condition was set based upon.
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
with respect to the current state of the instance.
format: int64
type: integer
reason:
description: A Reason for this condition's last transition from
one status to another.
type: string
status:
description: Status of this condition; is it currently True,
False, or Unknown?
type: string
type:
description: |-
Type of this condition. At most one of each condition type may apply to
a resource at any point in time.
type: string
required:
- lastTransitionTime
- reason
- status
- type
type: object
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
endpoint:
description: |-
Endpoint is the gRPC endpoint where Crossplane will send
RunFunctionRequests.
type: string
foundDependencies:
description: Dependency information.
format: int64
type: integer
installedDependencies:
format: int64
type: integer
invalidDependencies:
format: int64
type: integer
objectRefs:
description: References to objects owned by PackageRevision.
items:
description: |-
A TypedReference refers to an object by Name, Kind, and APIVersion. It is
commonly used to reference cluster-scoped objects or objects where the
namespace is already known.
properties:
apiVersion:
description: APIVersion of the referenced object.
type: string
kind:
description: Kind of the referenced object.
type: string
name:
description: Name of the referenced object.
type: string
uid:
description: UID of the referenced object.
type: string
required:
- apiVersion
- kind
- name
type: object
type: array
permissionRequests:
description: |-
PermissionRequests made by this package. The package declares that its
controller needs these permissions to run. The RBAC manager is
responsible for granting them.
items:
description: |-
PolicyRule holds information that describes a policy rule, but does not contain information
about who the rule applies to or which namespace the rule applies to.
properties:
apiGroups:
description: |-
APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of
the enumerated resources in any API group will be allowed. "" represents the core API group and "*" represents all API groups.
items:
type: string
type: array
x-kubernetes-list-type: atomic
nonResourceURLs:
description: |-
NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path
Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding.
Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both.
items:
type: string
type: array
x-kubernetes-list-type: atomic
resourceNames:
description: ResourceNames is an optional white list of names
that the rule applies to. An empty set means that everything
is allowed.
items:
type: string
type: array
x-kubernetes-list-type: atomic
resources:
description: Resources is a list of resources this rule applies
to. '*' represents all resources.
items:
type: string
type: array
x-kubernetes-list-type: atomic
verbs:
description: Verbs is a list of Verbs that apply to ALL the
ResourceKinds contained in this rule. '*' represents all verbs.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- verbs
type: object
type: array
type: object
type: object
served: true
storage: false
subresources:
status: {}

View File

@ -0,0 +1,451 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
name: functions.pkg.crossplane.io
spec:
group: pkg.crossplane.io
names:
categories:
- crossplane
- pkg
kind: Function
listKind: FunctionList
plural: functions
singular: function
scope: Cluster
versions:
- additionalPrinterColumns:
- jsonPath: .status.conditions[?(@.type=='Installed')].status
name: INSTALLED
type: string
- jsonPath: .status.conditions[?(@.type=='Healthy')].status
name: HEALTHY
type: string
- jsonPath: .spec.package
name: PACKAGE
type: string
- jsonPath: .metadata.creationTimestamp
name: AGE
type: date
name: v1
schema:
openAPIV3Schema:
description: |-
A Function installs an OCI compatible Crossplane package, extending
Crossplane with support for a new kind of composition function.
Read the Crossplane documentation for
[more information about Functions](https://docs.crossplane.io/latest/concepts/composition-functions).
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: FunctionSpec specifies the configuration of a Function.
properties:
commonLabels:
additionalProperties:
type: string
description: |-
Map of string keys and values that can be used to organize and categorize
(scope and select) objects. May match selectors of replication controllers
and services.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
type: object
controllerConfigRef:
description: |-
ControllerConfigRef references a ControllerConfig resource that will be
used to configure the packaged controller Deployment.
Deprecated: Use RuntimeConfigReference instead.
properties:
name:
description: Name of the ControllerConfig.
type: string
required:
- name
type: object
ignoreCrossplaneConstraints:
default: false
description: |-
IgnoreCrossplaneConstraints indicates to the package manager whether to
honor Crossplane version constrains specified by the package.
Default is false.
type: boolean
package:
description: Package is the name of the package that is being requested.
type: string
packagePullPolicy:
default: IfNotPresent
description: |-
PackagePullPolicy defines the pull policy for the package.
Default is IfNotPresent.
type: string
packagePullSecrets:
description: |-
PackagePullSecrets are named secrets in the same namespace that can be used
to fetch packages from private registries.
items:
description: |-
LocalObjectReference contains enough information to let you locate the
referenced object inside the same namespace.
properties:
name:
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?
type: string
type: object
x-kubernetes-map-type: atomic
type: array
revisionActivationPolicy:
default: Automatic
description: |-
RevisionActivationPolicy specifies how the package controller should
update from one revision to the next. Options are Automatic or Manual.
Default is Automatic.
type: string
revisionHistoryLimit:
default: 1
description: |-
RevisionHistoryLimit dictates how the package controller cleans up old
inactive package revisions.
Defaults to 1. Can be disabled by explicitly setting to 0.
format: int64
type: integer
runtimeConfigRef:
default:
name: default
description: |-
RuntimeConfigRef references a RuntimeConfig resource that will be used
to configure the package runtime.
properties:
apiVersion:
default: pkg.crossplane.io/v1beta1
description: API version of the referent.
type: string
kind:
default: DeploymentRuntimeConfig
description: Kind of the referent.
type: string
name:
description: Name of the RuntimeConfig.
type: string
required:
- name
type: object
skipDependencyResolution:
default: false
description: |-
SkipDependencyResolution indicates to the package manager whether to skip
resolving dependencies for a package. Setting this value to true may have
unintended consequences.
Default is false.
type: boolean
required:
- package
type: object
status:
description: FunctionStatus represents the observed state of a Function.
properties:
conditions:
description: Conditions of the resource.
items:
description: A Condition that may apply to a resource.
properties:
lastTransitionTime:
description: |-
LastTransitionTime is the last time this condition transitioned from one
status to another.
format: date-time
type: string
message:
description: |-
A Message containing details about this condition's last transition from
one status to another, if any.
type: string
observedGeneration:
description: |-
ObservedGeneration represents the .metadata.generation that the condition was set based upon.
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
with respect to the current state of the instance.
format: int64
type: integer
reason:
description: A Reason for this condition's last transition from
one status to another.
type: string
status:
description: Status of this condition; is it currently True,
False, or Unknown?
type: string
type:
description: |-
Type of this condition. At most one of each condition type may apply to
a resource at any point in time.
type: string
required:
- lastTransitionTime
- reason
- status
- type
type: object
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
currentIdentifier:
description: |-
CurrentIdentifier is the most recent package source that was used to
produce a revision. The package manager uses this field to determine
whether to check for package updates for a given source when
packagePullPolicy is set to IfNotPresent. Manually removing this field
will cause the package manager to check that the current revision is
correct for the given package source.
type: string
currentRevision:
description: |-
CurrentRevision is the name of the current package revision. It will
reflect the most up to date revision, whether it has been activated or
not.
type: string
type: object
type: object
served: true
storage: true
subresources:
status: {}
- additionalPrinterColumns:
- jsonPath: .status.conditions[?(@.type=='Installed')].status
name: INSTALLED
type: string
- jsonPath: .status.conditions[?(@.type=='Healthy')].status
name: HEALTHY
type: string
- jsonPath: .spec.package
name: PACKAGE
type: string
- jsonPath: .metadata.creationTimestamp
name: AGE
type: date
name: v1beta1
schema:
openAPIV3Schema:
description: |-
A Function installs an OCI compatible Crossplane package, extending
Crossplane with support for a new kind of composition function.
Read the Crossplane documentation for
[more information about Functions](https://docs.crossplane.io/latest/concepts/composition-functions).
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: FunctionSpec specifies the configuration of a Function.
properties:
commonLabels:
additionalProperties:
type: string
description: |-
Map of string keys and values that can be used to organize and categorize
(scope and select) objects. May match selectors of replication controllers
and services.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
type: object
controllerConfigRef:
description: |-
ControllerConfigRef references a ControllerConfig resource that will be
used to configure the packaged controller Deployment.
Deprecated: Use RuntimeConfigReference instead.
properties:
name:
description: Name of the ControllerConfig.
type: string
required:
- name
type: object
ignoreCrossplaneConstraints:
default: false
description: |-
IgnoreCrossplaneConstraints indicates to the package manager whether to
honor Crossplane version constrains specified by the package.
Default is false.
type: boolean
package:
description: Package is the name of the package that is being requested.
type: string
packagePullPolicy:
default: IfNotPresent
description: |-
PackagePullPolicy defines the pull policy for the package.
Default is IfNotPresent.
type: string
packagePullSecrets:
description: |-
PackagePullSecrets are named secrets in the same namespace that can be used
to fetch packages from private registries.
items:
description: |-
LocalObjectReference contains enough information to let you locate the
referenced object inside the same namespace.
properties:
name:
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?
type: string
type: object
x-kubernetes-map-type: atomic
type: array
revisionActivationPolicy:
default: Automatic
description: |-
RevisionActivationPolicy specifies how the package controller should
update from one revision to the next. Options are Automatic or Manual.
Default is Automatic.
type: string
revisionHistoryLimit:
default: 1
description: |-
RevisionHistoryLimit dictates how the package controller cleans up old
inactive package revisions.
Defaults to 1. Can be disabled by explicitly setting to 0.
format: int64
type: integer
runtimeConfigRef:
default:
name: default
description: |-
RuntimeConfigRef references a RuntimeConfig resource that will be used
to configure the package runtime.
properties:
apiVersion:
default: pkg.crossplane.io/v1beta1
description: API version of the referent.
type: string
kind:
default: DeploymentRuntimeConfig
description: Kind of the referent.
type: string
name:
description: Name of the RuntimeConfig.
type: string
required:
- name
type: object
skipDependencyResolution:
default: false
description: |-
SkipDependencyResolution indicates to the package manager whether to skip
resolving dependencies for a package. Setting this value to true may have
unintended consequences.
Default is false.
type: boolean
required:
- package
type: object
status:
description: FunctionStatus represents the observed state of a Function.
properties:
conditions:
description: Conditions of the resource.
items:
description: A Condition that may apply to a resource.
properties:
lastTransitionTime:
description: |-
LastTransitionTime is the last time this condition transitioned from one
status to another.
format: date-time
type: string
message:
description: |-
A Message containing details about this condition's last transition from
one status to another, if any.
type: string
observedGeneration:
description: |-
ObservedGeneration represents the .metadata.generation that the condition was set based upon.
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
with respect to the current state of the instance.
format: int64
type: integer
reason:
description: A Reason for this condition's last transition from
one status to another.
type: string
status:
description: Status of this condition; is it currently True,
False, or Unknown?
type: string
type:
description: |-
Type of this condition. At most one of each condition type may apply to
a resource at any point in time.
type: string
required:
- lastTransitionTime
- reason
- status
- type
type: object
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
currentIdentifier:
description: |-
CurrentIdentifier is the most recent package source that was used to
produce a revision. The package manager uses this field to determine
whether to check for package updates for a given source when
packagePullPolicy is set to IfNotPresent. Manually removing this field
will cause the package manager to check that the current revision is
correct for the given package source.
type: string
currentRevision:
description: |-
CurrentRevision is the name of the current package revision. It will
reflect the most up to date revision, whether it has been activated or
not.
type: string
type: object
type: object
served: true
storage: false
subresources:
status: {}

View File

@ -0,0 +1,100 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
name: locks.pkg.crossplane.io
spec:
group: pkg.crossplane.io
names:
kind: Lock
listKind: LockList
plural: locks
singular: lock
scope: Cluster
versions:
- additionalPrinterColumns:
- jsonPath: .metadata.creationTimestamp
name: AGE
type: date
name: v1beta1
schema:
openAPIV3Schema:
description: Lock is the CRD type that tracks package dependencies.
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
packages:
items:
description: LockPackage is a package that is in the lock.
properties:
dependencies:
description: |-
Dependencies are the list of dependencies of this package. The order of
the dependencies will dictate the order in which they are resolved.
items:
description: A Dependency is a dependency of a package in the
lock.
properties:
constraints:
description: |-
Constraints is a valid semver range, which will be used to select a valid
dependency version.
type: string
package:
description: Package is the OCI image name without a tag or
digest.
type: string
type:
description: Type is the type of package. Can be either Configuration
or Provider.
type: string
required:
- constraints
- package
- type
type: object
type: array
name:
description: Name corresponds to the name of the package revision
for this package.
type: string
source:
description: Source is the OCI image name without a tag or digest.
type: string
type:
description: Type is the type of package. Can be either Configuration
or Provider.
type: string
version:
description: Version is the tag or digest of the OCI image.
type: string
required:
- dependencies
- name
- source
- type
- version
type: object
type: array
type: object
served: true
storage: true
subresources:
status: {}

View File

@ -0,0 +1,330 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
name: providerrevisions.pkg.crossplane.io
spec:
group: pkg.crossplane.io
names:
categories:
- crossplane
- pkgrev
kind: ProviderRevision
listKind: ProviderRevisionList
plural: providerrevisions
singular: providerrevision
scope: Cluster
versions:
- additionalPrinterColumns:
- jsonPath: .status.conditions[?(@.type=='Healthy')].status
name: HEALTHY
type: string
- jsonPath: .spec.revision
name: REVISION
type: string
- jsonPath: .spec.image
name: IMAGE
type: string
- jsonPath: .spec.desiredState
name: STATE
type: string
- jsonPath: .status.foundDependencies
name: DEP-FOUND
type: string
- jsonPath: .status.installedDependencies
name: DEP-INSTALLED
type: string
- jsonPath: .metadata.creationTimestamp
name: AGE
type: date
name: v1
schema:
openAPIV3Schema:
description: |-
A ProviderRevision represents a revision of a Provider. Crossplane
creates new revisions when there are changes to a Provider.
Crossplane creates and manages ProviderRevisions. Don't directly edit
ProviderRevisions.
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: ProviderRevisionSpec specifies configuration for a ProviderRevision.
properties:
commonLabels:
additionalProperties:
type: string
description: |-
Map of string keys and values that can be used to organize and categorize
(scope and select) objects. May match selectors of replication controllers
and services.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
type: object
controllerConfigRef:
description: |-
ControllerConfigRef references a ControllerConfig resource that will be
used to configure the packaged controller Deployment.
Deprecated: Use RuntimeConfigReference instead.
properties:
name:
description: Name of the ControllerConfig.
type: string
required:
- name
type: object
desiredState:
description: DesiredState of the PackageRevision. Can be either Active
or Inactive.
type: string
ignoreCrossplaneConstraints:
default: false
description: |-
IgnoreCrossplaneConstraints indicates to the package manager whether to
honor Crossplane version constrains specified by the package.
Default is false.
type: boolean
image:
description: Package image used by install Pod to extract package
contents.
type: string
packagePullPolicy:
default: IfNotPresent
description: |-
PackagePullPolicy defines the pull policy for the package. It is also
applied to any images pulled for the package, such as a provider's
controller image.
Default is IfNotPresent.
type: string
packagePullSecrets:
description: |-
PackagePullSecrets are named secrets in the same namespace that can be
used to fetch packages from private registries. They are also applied to
any images pulled for the package, such as a provider's controller image.
items:
description: |-
LocalObjectReference contains enough information to let you locate the
referenced object inside the same namespace.
properties:
name:
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?
type: string
type: object
x-kubernetes-map-type: atomic
type: array
revision:
description: |-
Revision number. Indicates when the revision will be garbage collected
based on the parent's RevisionHistoryLimit.
format: int64
type: integer
runtimeConfigRef:
default:
name: default
description: |-
RuntimeConfigRef references a RuntimeConfig resource that will be used
to configure the package runtime.
properties:
apiVersion:
default: pkg.crossplane.io/v1beta1
description: API version of the referent.
type: string
kind:
default: DeploymentRuntimeConfig
description: Kind of the referent.
type: string
name:
description: Name of the RuntimeConfig.
type: string
required:
- name
type: object
skipDependencyResolution:
default: false
description: |-
SkipDependencyResolution indicates to the package manager whether to skip
resolving dependencies for a package. Setting this value to true may have
unintended consequences.
Default is false.
type: boolean
tlsClientSecretName:
description: |-
TLSClientSecretName is the name of the TLS Secret that stores client
certificates of the Provider.
type: string
tlsServerSecretName:
description: |-
TLSServerSecretName is the name of the TLS Secret that stores server
certificates of the Provider.
type: string
required:
- desiredState
- image
- revision
type: object
status:
description: PackageRevisionStatus represents the observed state of a
PackageRevision.
properties:
conditions:
description: Conditions of the resource.
items:
description: A Condition that may apply to a resource.
properties:
lastTransitionTime:
description: |-
LastTransitionTime is the last time this condition transitioned from one
status to another.
format: date-time
type: string
message:
description: |-
A Message containing details about this condition's last transition from
one status to another, if any.
type: string
observedGeneration:
description: |-
ObservedGeneration represents the .metadata.generation that the condition was set based upon.
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
with respect to the current state of the instance.
format: int64
type: integer
reason:
description: A Reason for this condition's last transition from
one status to another.
type: string
status:
description: Status of this condition; is it currently True,
False, or Unknown?
type: string
type:
description: |-
Type of this condition. At most one of each condition type may apply to
a resource at any point in time.
type: string
required:
- lastTransitionTime
- reason
- status
- type
type: object
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
foundDependencies:
description: Dependency information.
format: int64
type: integer
installedDependencies:
format: int64
type: integer
invalidDependencies:
format: int64
type: integer
objectRefs:
description: References to objects owned by PackageRevision.
items:
description: |-
A TypedReference refers to an object by Name, Kind, and APIVersion. It is
commonly used to reference cluster-scoped objects or objects where the
namespace is already known.
properties:
apiVersion:
description: APIVersion of the referenced object.
type: string
kind:
description: Kind of the referenced object.
type: string
name:
description: Name of the referenced object.
type: string
uid:
description: UID of the referenced object.
type: string
required:
- apiVersion
- kind
- name
type: object
type: array
permissionRequests:
description: |-
PermissionRequests made by this package. The package declares that its
controller needs these permissions to run. The RBAC manager is
responsible for granting them.
items:
description: |-
PolicyRule holds information that describes a policy rule, but does not contain information
about who the rule applies to or which namespace the rule applies to.
properties:
apiGroups:
description: |-
APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of
the enumerated resources in any API group will be allowed. "" represents the core API group and "*" represents all API groups.
items:
type: string
type: array
x-kubernetes-list-type: atomic
nonResourceURLs:
description: |-
NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path
Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding.
Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both.
items:
type: string
type: array
x-kubernetes-list-type: atomic
resourceNames:
description: ResourceNames is an optional white list of names
that the rule applies to. An empty set means that everything
is allowed.
items:
type: string
type: array
x-kubernetes-list-type: atomic
resources:
description: Resources is a list of resources this rule applies
to. '*' represents all resources.
items:
type: string
type: array
x-kubernetes-list-type: atomic
verbs:
description: Verbs is a list of Verbs that apply to ALL the
ResourceKinds contained in this rule. '*' represents all verbs.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- verbs
type: object
type: array
type: object
type: object
served: true
storage: true
subresources:
status: {}

View File

@ -0,0 +1,237 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
name: providers.pkg.crossplane.io
spec:
group: pkg.crossplane.io
names:
categories:
- crossplane
- pkg
kind: Provider
listKind: ProviderList
plural: providers
singular: provider
scope: Cluster
versions:
- additionalPrinterColumns:
- jsonPath: .status.conditions[?(@.type=='Installed')].status
name: INSTALLED
type: string
- jsonPath: .status.conditions[?(@.type=='Healthy')].status
name: HEALTHY
type: string
- jsonPath: .spec.package
name: PACKAGE
type: string
- jsonPath: .metadata.creationTimestamp
name: AGE
type: date
name: v1
schema:
openAPIV3Schema:
description: |-
A Provider installs an OCI compatible Crossplane package, extending
Crossplane with support for new kinds of managed resources.
Read the Crossplane documentation for
[more information about Providers](https://docs.crossplane.io/latest/concepts/providers).
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: |-
ProviderSpec specifies details about a request to install a provider to
Crossplane.
properties:
commonLabels:
additionalProperties:
type: string
description: |-
Map of string keys and values that can be used to organize and categorize
(scope and select) objects. May match selectors of replication controllers
and services.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
type: object
controllerConfigRef:
description: |-
ControllerConfigRef references a ControllerConfig resource that will be
used to configure the packaged controller Deployment.
Deprecated: Use RuntimeConfigReference instead.
properties:
name:
description: Name of the ControllerConfig.
type: string
required:
- name
type: object
ignoreCrossplaneConstraints:
default: false
description: |-
IgnoreCrossplaneConstraints indicates to the package manager whether to
honor Crossplane version constrains specified by the package.
Default is false.
type: boolean
package:
description: Package is the name of the package that is being requested.
type: string
packagePullPolicy:
default: IfNotPresent
description: |-
PackagePullPolicy defines the pull policy for the package.
Default is IfNotPresent.
type: string
packagePullSecrets:
description: |-
PackagePullSecrets are named secrets in the same namespace that can be used
to fetch packages from private registries.
items:
description: |-
LocalObjectReference contains enough information to let you locate the
referenced object inside the same namespace.
properties:
name:
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?
type: string
type: object
x-kubernetes-map-type: atomic
type: array
revisionActivationPolicy:
default: Automatic
description: |-
RevisionActivationPolicy specifies how the package controller should
update from one revision to the next. Options are Automatic or Manual.
Default is Automatic.
type: string
revisionHistoryLimit:
default: 1
description: |-
RevisionHistoryLimit dictates how the package controller cleans up old
inactive package revisions.
Defaults to 1. Can be disabled by explicitly setting to 0.
format: int64
type: integer
runtimeConfigRef:
default:
name: default
description: |-
RuntimeConfigRef references a RuntimeConfig resource that will be used
to configure the package runtime.
properties:
apiVersion:
default: pkg.crossplane.io/v1beta1
description: API version of the referent.
type: string
kind:
default: DeploymentRuntimeConfig
description: Kind of the referent.
type: string
name:
description: Name of the RuntimeConfig.
type: string
required:
- name
type: object
skipDependencyResolution:
default: false
description: |-
SkipDependencyResolution indicates to the package manager whether to skip
resolving dependencies for a package. Setting this value to true may have
unintended consequences.
Default is false.
type: boolean
required:
- package
type: object
status:
description: ProviderStatus represents the observed state of a Provider.
properties:
conditions:
description: Conditions of the resource.
items:
description: A Condition that may apply to a resource.
properties:
lastTransitionTime:
description: |-
LastTransitionTime is the last time this condition transitioned from one
status to another.
format: date-time
type: string
message:
description: |-
A Message containing details about this condition's last transition from
one status to another, if any.
type: string
observedGeneration:
description: |-
ObservedGeneration represents the .metadata.generation that the condition was set based upon.
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
with respect to the current state of the instance.
format: int64
type: integer
reason:
description: A Reason for this condition's last transition from
one status to another.
type: string
status:
description: Status of this condition; is it currently True,
False, or Unknown?
type: string
type:
description: |-
Type of this condition. At most one of each condition type may apply to
a resource at any point in time.
type: string
required:
- lastTransitionTime
- reason
- status
- type
type: object
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
currentIdentifier:
description: |-
CurrentIdentifier is the most recent package source that was used to
produce a revision. The package manager uses this field to determine
whether to check for package updates for a given source when
packagePullPolicy is set to IfNotPresent. Manually removing this field
will cause the package manager to check that the current revision is
correct for the given package source.
type: string
currentRevision:
description: |-
CurrentRevision is the name of the current package revision. It will
reflect the most up to date revision, whether it has been activated or
not.
type: string
type: object
type: object
served: true
storage: true
subresources:
status: {}

View File

@ -0,0 +1,172 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
name: storeconfigs.secrets.crossplane.io
spec:
group: secrets.crossplane.io
names:
categories:
- crossplane
- store
kind: StoreConfig
listKind: StoreConfigList
plural: storeconfigs
singular: storeconfig
scope: Cluster
versions:
- additionalPrinterColumns:
- jsonPath: .metadata.creationTimestamp
name: AGE
type: date
- jsonPath: .spec.type
name: TYPE
type: string
- jsonPath: .spec.defaultScope
name: DEFAULT-SCOPE
type: string
name: v1alpha1
schema:
openAPIV3Schema:
description: |-
A StoreConfig configures how Crossplane controllers should store connection
details in an external secret store.
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: A StoreConfigSpec defines the desired state of a StoreConfig.
properties:
defaultScope:
description: |-
DefaultScope used for scoping secrets for "cluster-scoped" resources.
If store type is "Kubernetes", this would mean the default namespace to
store connection secrets for cluster scoped resources.
In case of "Vault", this would be used as the default parent path.
Typically, should be set as Crossplane installation namespace.
type: string
kubernetes:
description: |-
Kubernetes configures a Kubernetes secret store.
If the "type" is "Kubernetes" but no config provided, in cluster config
will be used.
properties:
auth:
description: Credentials used to connect to the Kubernetes API.
properties:
env:
description: |-
Env is a reference to an environment variable that contains credentials
that must be used to connect to the provider.
properties:
name:
description: Name is the name of an environment variable.
type: string
required:
- name
type: object
fs:
description: |-
Fs is a reference to a filesystem location that contains credentials that
must be used to connect to the provider.
properties:
path:
description: Path is a filesystem path.
type: string
required:
- path
type: object
secretRef:
description: |-
A SecretRef is a reference to a secret key that contains the credentials
that must be used to connect to the provider.
properties:
key:
description: The key to select.
type: string
name:
description: Name of the secret.
type: string
namespace:
description: Namespace of the secret.
type: string
required:
- key
- name
- namespace
type: object
source:
description: Source of the credentials.
enum:
- None
- Secret
- Environment
- Filesystem
type: string
required:
- source
type: object
required:
- auth
type: object
plugin:
description: Plugin configures External secret store as a plugin.
properties:
configRef:
description: ConfigRef contains store config reference info.
properties:
apiVersion:
description: APIVersion of the referenced config.
type: string
kind:
description: Kind of the referenced config.
type: string
name:
description: Name of the referenced config.
type: string
required:
- apiVersion
- kind
- name
type: object
endpoint:
description: Endpoint is the endpoint of the gRPC server.
type: string
type: object
type:
default: Kubernetes
description: |-
Type configures which secret store to be used. Only the configuration
block for this store will be used and others will be ignored if provided.
Default is Kubernetes.
enum:
- Kubernetes
- Vault
- Plugin
type: string
required:
- defaultScope
type: object
required:
- spec
type: object
served: true
storage: true
subresources: {}

View File

@ -0,0 +1,64 @@
---
weight: 200
title: CLI Reference
description: "Documentation for the Crossplane command-line interface"
---
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
The Crossplane CLI is a single standalone binary with no external dependencies.
{{<hint "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.
{{< /hint >}}
To download the latest version for your CPU architecture with the Crossplane
install script.
```shell
curl -sL "https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh" | sh
```
[The script](https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh)
detects your CPU architecture and downloads the latest stable release.
{{<expand "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
{{<hint "important" >}}
<!-- vale write-good.Passive = NO -->
The CLI is named `crank` in the release repository. Download this file.
<!-- vale write-good.Passive = YES -->
The `crossplane` binary is the Kubernetes Crossplane pod image.
{{< /hint >}}
Move the binary to a location in your `$PATH`, for example `/usr/local/bin`.
{{< /expand >}}
### 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.14.0` add `XP_VERSION=v1.14.0` to the
download script curl command:
`curl -sL "https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh" | XP_VERSION=v1.14.0 sh`

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,70 @@
---
title: Concepts
weight: 50
description: Understand Crossplane's core components
---
Crossplane extends Kubernetes allowing it to create and manage
resources external to the Kubernetes cluster. Crossplane enables platform
engineers to create custom APIs and abstractions combining both native
Kubernetes resources and cloud resources under a single control plane.
With custom APIs, the platform users, like developers, don't need to know
any details about the underlying resources or requirements.
The platform users only need to know the details exposed by the platform, like
`big` or `small` or `US` or `EU`. Platform users don't need to know any details
about the underlying provider like instance type or region names.
Crossplane uses multiple core components to manage the various elements of
building and managing external resources through Kubernetes.
* [**The Crossplane pods**]({{<ref "./pods">}}) include the core Crossplane pod and
Crossplane RBAC manager pod. Together these pods manage all Crossplane
components and resources.
* [**Providers**]({{<ref "./providers">}}) connect Kubernetes to any external
provider, like AWS, Azure or GCP. Providers translate Kubernetes native
manifests and API calls into external API calls. Providers are responsible for
creating, deleting and managing the lifecycle of their resources.
* [**Managed resources**]({{<ref "./managed-resources">}}) are Kubernetes objects
representing things the Provider created outside of Kubernetes. Creating a
managed resource in Kubernetes requires a Provider to create a resource.
Deleting a managed resource requires a Provider to delete the associated
external resource.
* [**Compositions**]({{<ref "./compositions">}}) are a template of managed
resources. Compositions describe more complex deployments, combining multiple
managed resources and any resource customizations, like the size of a database
or the cloud provider region.
* [**Composite Resource Definitions**]({{<ref "./composite-resource-definitions">}})
represent a custom API, created by platform engineers and consumed by
developers or end users. Composite resource definitions use an OpenAPIv3
schema to further extend Kubernetes with custom API endpoints, revisions and
more.
* [**Composite Resources**]({{<ref "./composite-resources">}}) represent all the
objects created by a user calling the custom API. Every time a user access the
custom API Crossplane creates a single Composite Resource and links all
the related managed resources to it.
* [**Claims**]({{<ref "./claims">}}) are like Composite Resources, but exist
in a Kubernetes namespace. Every Claim links to a single cluster scoped
Composite Resource. Platform users create Claims in their unique namespace,
isolating their resources from other teams in other namespaces.
* [**EnvironmentConfigs**]({{<ref "./environment-configs">}}) are an in-memory
data store, like a Kubernetes ConfigMap. EnvironmentConfigs are useful for
custom resource mapping or storing and retrieving data across Claims and
Composite Resources.
* [**Usages**]({{<ref "./usages">}}) defining critical resources or custom
dependency mappings. Usages can prevent Crossplane from deleting or can
ensure that a parent resource waits for Crossplane to delete all child
resources first.
* [**Packages**]({{<ref "./packages">}}) are a convenient way to package up an
entire custom platform and define any other Crossplane related requirements.
Packages define how to install Providers, custom APIs or composition functions.

View File

@ -0,0 +1,207 @@
---
title: Claims
weight: 60
description: "Claims are a way to consume Crossplane resources with namespace scoping"
---
Claims represents a set of managed resources as a single
Kubernetes object, inside a namespace.
Users create claims when they access the
custom API, defined in the CompositeResourceDefinition.
{{< hint "tip" >}}
Claims are like [composite resources]({{<ref "./composite-resources">}}). The
difference between Claims and composite resources is Crossplane can create
Claims in a namespace, while composite resources are cluster scoped.
{{< /hint >}}
{{<expand "Confused about Compositions, XRDs, XRs and Claims?" >}}
Crossplane has four core components that users commonly mix up:
* [Compositions]({{<ref "./compositions">}}) - A template to define how to create resources.
* [Composite Resource Definition]({{<ref "./composite-resource-definitions">}})
(`XRD`) - A custom API specification.
* [Composite Resources]({{<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 (`XRC`) - This page. Like a Composite Resource, but
with namespace scoping.
{{</expand >}}
## Creating a Claim
Creating a Claim requires a
[Composition]({{<ref "./compositions">}}) and a
[CompositeResourceDefinition]({{<ref "./composite-resource-definitions">}})
(`XRD`) already installed.
{{<hint "note" >}}
The XRD must
[enable Claims]({{<ref "./composite-resource-definitions#enable-claims">}}).
{{< /hint >}}
The Composition defines the set of resources to create.
The XRD defines the custom API users call to request the set of resources.
![Diagram of the relationship of Crossplane components](/media/composition-how-it-works.svg)
For example,
this {{<hover label="xrd1" line="2">}}CompositeResourceDefinition{{</hover>}}
creates a composite resource API endpoint
{{<hover label="xrd1" line="4">}}xmydatabases.example.org{{</hover>}} and
enables a Claim API endpoint
{{<hover label="xrd1" line="11">}}database.example.org{{</hover>}}
```yaml {label="xrd1",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xmydatabases.example.org
spec:
group: example.org
names:
kind: XMyDatabase
plural: xmydatabases
claimNames:
kind: Database
plural: databases
# Removed for brevity
```
The Claim uses the XRD's
{{<hover label="xrd1" line="11">}}kind{{</hover>}} API endpoint to request
resources.
The Claim's {{<hover label="xrd1" line="1">}}apiVersion{{</hover>}} matches
the XRD {{<hover label="xrd1" line="6">}}group{{</hover>}} and the
{{<hover label="claim1" line="2">}}kind{{</hover>}} matches the XRD
{{<hover label="xrd1" line="11">}}claimNames.kind{{</hover>}}
```yaml {label="claim1",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: database
metadata:
name: my-claimed-database
spec:
# Removed for brevity
```
When a user creates a Claim in a namespace Crossplane also creates a composite
resource.
Use {{<hover label="claimcomp" line="1">}}kubectl describe{{</hover>}} on the
Claim to view the related composite resource.
The {{<hover label="claimcomp" line="6">}}Resource Ref{{</hover>}} is the
composite resource Crossplane created for this Claim.
```shell {label="claimcomp",copy-lines="1"}
kubectl describe database.example.org/my-claimed-database
Name: my-claimed-database
API Version: example.org/v1alpha1
Kind: database
Spec:
Resource Ref:
API Version: example.org/v1alpha1
Kind: XMyDatabase
Name: my-claimed-database-rr4ll
# Removed for brevity.
```
Use {{<hover label="getcomp" line="1">}}kubectl describe{{</hover>}} on the
composite resource to view the
{{<hover label="getcomp" line="6">}}Claim Ref{{</hover>}} linking the
composite resource to the original Claim.
```shell {label="getcomp",copy-lines="1"}
kubectl describe xmydatabase.example.org/my-claimed-database-rr4ll
Name: my-claimed-database-rr4ll
API Version: example.org/v1alpha1
Kind: XMyDatabase
Spec:
Claim Ref:
API Version: example.org/v1alpha1
Kind: database
Name: my-claimed-database
Namespace: default
```
{{<hint "note" >}}
Crossplane supports directly creating composite resources. Claims allow
namespace scoping and isolation for users consuming the custom APIs.
If you don't use namespaces in your Kubernetes deployment Claims aren't necessary.
{{< /hint >}}
### Claiming existing composite resources
By default, creating a Claim creates a new composite resource. Claims can also
link to existing composite resources.
A use case for claiming existing composite resources may be slow to provision
resources. Composite resources can be pre-provisioned and a Claim can
use those resources without waiting for their creation.
Set the Claim's {{<hover label="resourceref" line="6">}}resourceRef{{</hover>}}
and match the pre-existing composite resource
{{<hover label="resourceref" line="9">}}name{{</hover>}}.
```yaml {label="resourceref",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: database
metadata:
name: my-claimed-database
spec:
resourceRef:
apiVersion: example.org/v1alpha1
kind: XMyDatabase
name: my-pre-created-xr
```
If a Claim specifies a
{{<hover label="resourceref" line="6">}}resourceRef{{</hover>}} that doesn't
exist, Crossplane doesn't create a composite resource.
{{<hint "note" >}}
All Claims have a
{{<hover label="resourceref" line="6">}}resourceRef{{</hover>}}. Manually
defining the
{{<hover label="resourceref" line="6">}}resourceRef{{</hover>}}
isn't required. Crossplane fills in the
{{<hover label="resourceref" line="6">}}resourceRef{{</hover>}}
with the information from the composite resource created for the Claim.
{{< /hint >}}
## Claim connection secrets
If a Claim expects connection secrets the Claim must define a
{{<hover label="claimSec" line="6">}}writeConnectionSecretToRef{{</hover>}}
object.
The
{{<hover label="claimSec" line="6">}}writeConnectionSecretToRef{{</hover>}}
object defines the name of the Kubernetes secret object where Crossplane saves
the connection details.
{{<hint "note" >}}
The Crossplane creates the secret object in the same namespace as the Claim.
{{< /hint >}}
For example, to a new secret object named
{{<hover label="claimSec" line="7">}}my-claim-secret{{</hover>}} use
{{<hover label="claimSec" line="6">}}writeConnectionSecretToRef{{</hover>}} with
the
{{<hover label="claimSec" line="7">}}name: my-claim-secret{{</hover>}}.
```yaml {label="claimSec"}
apiVersion: example.org/v1alpha1
kind: database
metadata:
name: my-claimed-database
spec:
writeConnectionSecretToRef:
name: my-claim-secret
```
For more information on connection secrets read the [Connection Secrets knowledge base article]({{<ref "connection-details">}}).

View File

@ -0,0 +1,848 @@
---
title: Composite Resource Definitions
weight: 40
description: "Composite Resource Definitions or XRDs define custom API schemas"
---
Composite resource definitions (`XRDs`) define the schema for a custom API.
Users create composite resources (`XRs`) and Claims (`XCs`) using the API
schema defined by an `XRD`.
{{< hint "note" >}}
Read the [composite resources]({{<ref "./composite-resources">}}) page for more
information about composite resources.
Read the [Claims]({{<ref "./claims">}}) page for more
information about Claims.
{{</hint >}}
{{<expand "Confused about Compositions, XRDs, XRs and Claims?" >}}
Crossplane has four core components that users commonly mix up:
* [Compositions]({{<ref "./compositions" >}}) - A template to define how to create resources.
* Composite Resource Definition (`XRD`) - This page. 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 >}}
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 Claims and
connection secrets.
## Creating a CompositeResourceDefinition
Creating a CompositeResourceDefinition consists of:
* [Defining a custom API group](#xrd-groups).
* [Defining a custom API name](#xrd-names).
* [Defining a custom API schema and version](#xrd-versions).
Optionally, CompositeResourceDefinitions also support:
* [Offering a Claim](#enable-claims).
* [Defining connection secrets](#manage-connection-secrets).
* [Setting composite resource defaults](#set-composite-resource-defaults).
Composite resource definitions (`XRDs`) create new API endpoints inside a
Kubernetes cluster.
Creating a new API requires defining an API
{{<hover label="xrd1" line="6">}}group{{</hover>}},
{{<hover label="xrd1" line="7">}}name{{</hover>}} and
{{<hover label="xrd1" line="10">}}version{{</hover>}}.
```yaml {label="xrd1",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xmydatabases.example.org
spec:
group: example.org
names:
kind: XMyDatabase
plural: xmydatabases
versions:
- name: v1alpha1
# Removed for brevity
```
After applying an XRD, Crossplane creates a new Kubernetes custom resource
definition matching the defined API.
For example, the XRD
{{<hover label="xrd1" line="4">}}xmydatabases.example.org{{</hover >}}
creates a custom resource definition
{{<hover label="kubeapi" line="2">}}xmydatabases.example.org{{</hover >}}.
```shell {label="kubeapi",copy-lines="3"}
kubectl api-resources
NAME SHORTNAMES APIVERSION NAMESPACED KIND
xmydatabases.example.org v1alpha1 false xmydatabases
# Removed for brevity
```
{{<hint "warning">}}
You can't change the XRD
{{<hover label="xrd1" line="6">}}group{{</hover>}} or
{{<hover label="xrd1" line="7">}}names{{</hover>}}.
You must delete and
recreate the XRD to change the
{{<hover label="xrd1" line="6">}}group{{</hover>}} or
{{<hover label="xrd1" line="7">}}names{{</hover>}}.
{{</hint >}}
### 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.
<!-- vale write-good.Weasel = NO -->
Many XRDs may use the same `group` to create a logical collection of APIs.
<!-- vale write-good.Weasel = YES -->
For example a `database` group may have a `relational` and `nosql` kinds.
{{<hint "tip" >}}
Group names are cluster scoped. Choose group names that don't conflict with
Providers.
Avoid Provider names in the group.
{{< /hint >}}
### 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.
{{<hint "important" >}}
The XRD
{{<hover label="xrdName" line="4">}}metadata.name{{</hover>}} must be
{{<hover label="xrdName" line="9">}}plural{{</hover>}} name, `.` (dot character),
{{<hover label="xrdName" line="6">}}group{{</hover>}}.
For example, {{<hover label="xrdName"
line="4">}}xmydatabases.example.org{{</hover>}} matches the {{<hover
label="xrdName" line="9">}}plural{{</hover>}} name
{{<hover label="xrdName" line="9">}}xmydatabases{{</hover>}}, `.`
{{<hover label="xrdName" line="6">}}group{{</hover>}} name,
{{<hover label="xrdName" line="6">}}example.org{{</hover>}}.
```yaml {label="xrdName",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xmydatabases.example.org
spec:
group: example.org
names:
kind: XMyDatabase
plural: xmydatabases
# Removed for brevity
```
{{</hint >}}
### XRD versions
<!-- vale gitlab.SentenceLength = NO -->
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.
<!-- vale gitlab.SentenceLength = YES -->
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
<!-- vale write-good.Passive = NO -->
<!-- vale write-good.TooWordy = NO -->
The `schema` defines the names
of the parameters, the data types of the parameters and which parameters are
required or optional.
<!-- vale write-good.Passive = YES -->
<!-- vale write-good.TooWordy = YES -->
{{<hint "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).
{{< /hint >}}
Each
{{<hover label="schema" line="11">}}version{{</hover>}} of the API has a unique
{{<hover label="schema" line="12">}}schema{{</hover>}}.
All XRD {{<hover label="schema" line="12">}}schemas{{</hover>}} validate against
the {{<hover label="schema" line="13">}}openAPIV3Schema{{</hover>}}. The schema
is an OpenAPI
{{<hover label="schema" line="14">}}object{{</hover>}} with the
{{<hover label="schema" line="15">}}properties{{</hover>}} of a
{{<hover label="schema" line="16">}}spec{{</hover>}}
{{<hover label="schema" line="17">}}object{{</hover>}}.
Inside the {{<hover label="schema" line="18">}}spec.properties{{</hover>}} is the custom
API definition.
In this example, the key {{<hover label="schema" line="19">}}region{{</hover>}}
is a {{<hover label="schema" line="20">}}string{{</hover>}}.
```yaml {label="schema",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: xDatabase
plural: xdatabases
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
region:
type: string
# Removed for brevity
```
A composite resource using this API references the
{{<hover label="xr" line="1">}}group/version{{</hover>}} and
{{<hover label="xr" line="2">}}kind{{</hover>}}. The
{{<hover label="xr" line="5">}}spec{{</hover>}} has the
{{<hover label="xr" line="6">}}region{{</hover>}} key with a string value.
```yaml {label="xr"}
apiVersion: custom-api.example.org/v1alpha1
kind: xDatabase
metadata:
name: my-composite-resource
spec:
region: "US"
```
{{<hint "tip" >}}
The custom API defined inside the
{{<hover label="schema" line="18">}}spec.properties{{</hover>}} 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.
{{< /hint >}}
{{<hint "important" >}}
Changing or expanding the XRD schema requires restarting the [Crossplane pod]({{<ref "./pods#crossplane-pod">}}) to take effect.
{{< /hint >}}
##### Required fields
By default all fields in a schema are optional. Define a parameter as required
with the
{{< hover label="required" line="25">}}required{{</hover>}} attribute.
In this example the XRD requires
{{< hover label="required" line="19">}}region{{</hover>}} and
{{< hover label="required" line="21">}}size{{</hover>}} but
{{< hover label="required" line="23">}}name{{</hover>}} is optional.
```yaml {label="required",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: xDatabase
plural: xdatabases
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
region:
type: string
size:
type: string
name:
type: string
required:
- region
- size
# 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 {{<hover label="required2" line="7">}}spec{{</hover>}} object
2. a second {{<hover label="required2" line="14">}}location{{</hover>}} object
The {{<hover label="required2" line="7">}}spec{{</hover>}} object
{{<hover label="required2" line="23">}}requires{{</hover>}} the
{{<hover label="required2" line="10">}}size{{</hover>}} and
{{<hover label="required2" line="14">}}location{{</hover>}} but
{{<hover label="required2" line="12">}}name{{</hover>}} is optional.
Inside the required {{<hover label="required2" line="14">}}location{{</hover>}}
object,
{{<hover label="required2" line="17">}}country{{</hover>}} is
{{<hover label="required2" line="21">}}required{{</hover>}} and
{{<hover label="required2" line="19">}}zone{{</hover>}} is optional.
```yaml {copy-lines="none",label="required2"}
# Removed for brevity
- name: v1alpha1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
size:
type: string
name:
type: string
location:
type: object
properties:
country:
type: string
zone:
type: string
required:
- country
required:
- size
- location
```
The Swagger "[Describing Parameters](https://swagger.io/docs/specification/describing-parameters/)"
documentation has more examples.
##### Crossplane reserved fields
Crossplane doesn't allow the following fields in a schema:
* `spec.resourceRef`
* `spec.resourceRefs`
* `spec.claimRef`
* `spec.writeConnectionSecretToRef`
* `status.conditions`
* `status.connectionDetails`
Crossplane ignores any fields matching the reserved fields.
#### Serve and reference a schema
To use a schema it must be
{{<hover label="served" line="12" >}}served: true{{</hover >}}
and
{{<hover label="served" line="13" >}}referenceable: true{{</hover>}}.
```yaml {label="served"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: xDatabase
plural: xdatabases
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
region:
type: string
```
Composite resources can use any schema version set as
{{<hover label="served" line="12" >}}served: true{{</hover >}}.
Kubernetes rejects any composite resource using a schema version set as `served:
false`.
{{< hint "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.
{{< /hint >}}
The {{<hover label="served" line="13" >}}referenceable: true{{</hover>}}
field indicates which version of the schema Compositions use. Only one
version can be `referenceable`.
{{< hint "note" >}}
Changing which version is `referenceable:true` requires [updating the `compositeTypeRef.apiVersion`]({{<ref "./compositions#enable-composite-resources" >}})
of any Compositions referencing that XRD.
{{< /hint >}}
#### Multiple schema versions
{{<hint "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."
<!-- vale Crossplane.Spelling = NO -->
<!-- ignore to allow for CRDs -->
<!-- don't add to the spelling exceptions to catch when it's used instead of XRD -->
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.
<!-- vale Crossplane.Spelling = YES -->
Crossplane recommends implementing breaking schema changes as brand new XRDs.
{{< /hint >}}
For XRDs, to create a new version of an API add a new
{{<hover label="ver" line="21">}}name{{</hover>}} in the
{{<hover label="ver" line="10">}}versions{{</hover>}}
list.
For example, this XRD version
{{<hover label="ver" line="11">}}v1alpha1{{</hover>}} only has the field
{{<hover label="ver" line="19">}}region{{</hover>}}.
A second version,
{{<hover label="ver" line="21">}}v1{{</hover>}} expands the API to have both
{{<hover label="ver" line="29">}}region{{</hover>}} and
{{<hover label="ver" line="31">}}size{{</hover>}}.
```yaml {label="ver",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: xDatabase
plural: xdatabases
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
region:
type: string
- name: v1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
region:
type: string
size:
type: string
```
{{<hint "important" >}}
Changing or expanding the XRD schema requires restarting the [Crossplane pod]({{<ref "./pods#crossplane-pod">}}) to take effect.
{{< /hint >}}
### Enable Claims
Optionally, XRDs can allow Claims to use the XRD API.
{{<hint "note" >}}
Read the [Claims]({{<ref "./claims">}}) page for more
information about Claims.
{{</hint >}}
XRDs offer Claims with a
{{<hover label="claim" line="10">}}claimNames{{</hover >}} object.
The {{<hover label="claim" line="10">}}claimNames{{</hover >}} defines a
{{<hover label="claim" line="11">}}kind{{</hover >}} and
{{<hover label="claim" line="12">}}plural{{</hover >}} like the XRD
{{<hover label="claim" line="7">}}names{{</hover >}} object.
Also like XRD
{{<hover label="claim" line="7">}}names{{</hover >}}, use UpperCamelCase
for the
{{<hover label="claim" line="11">}}kind{{</hover >}} and lowercase for the
{{<hover label="claim" line="12">}}plural{{</hover >}}.
The Claim
{{<hover label="claim" line="11">}}kind{{</hover >}} and
{{<hover label="claim" line="12">}}plural{{</hover >}} must be unique. They
can't match any other Claim or other XRD
{{<hover label="claim" line="8">}}kind{{</hover >}}.
{{<hint "tip" >}}
Common Crossplane convention is to use
{{<hover label="claim" line="10">}}claimNames{{</hover >}} that match the XRD
{{<hover label="claim" line="7">}}names{{</hover >}}, but without the beginning
"x."
{{</hint >}}
```yaml {label="claim",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: xDatabase
plural: xdatabases
claimNames:
kind: Database
plural: databases
versions:
# Removed for brevity
```
{{<hint "important" >}}
You can't change the
{{<hover label="claim" line="10">}}claimNames{{</hover >}}
after they're defined. You must delete and
recreate the XRD to change the
{{<hover label="claim" line="10">}}claimNames{{</hover >}}.
{{</hint >}}
### Manage connection secrets
When a composite resource creates managed resources, Crossplane provides any
[connection secrets]({{<ref "./managed-resources#writeconnectionsecrettoref">}})
to the composite resource or Claim. This requires the creators of composite
resources and Claims to know the secrets provided by a managed resource.
In other cases, Crossplane administrators may not want to expose some or all the
generated connection secrets.
XRDs can define a list of
{{<hover label="key" line="10">}}connectionSecretKeys{{</hover>}}
to limit what's provided to a composite resource or Claim.
Crossplane only provides the keys listed in the
{{<hover label="key" line="10">}}connectionSecretKeys{{</hover>}}
to the composite resource or Claim using this XRD. Any other connection
secrets aren't passed to the composite resource or Claim.
{{<hint "important" >}}
The keys listed in the
{{<hover label="key" line="10">}}connectionSecretKeys{{</hover>}} must match the
key names listed in the Composition's `connectionDetails`.
An XRD ignores any keys listed that aren't created by a managed resource.
For more information read the
[Composition documentation]({{<ref "./compositions#store-connection-details">}}).
{{< /hint >}}
For example, an XRD passes the keys
{{<hover label="key" line="11">}}username{{</hover>}},
{{<hover label="key" line="12">}}password{{</hover>}} and
{{<hover label="key" line="13">}}address{{</hover>}}.
Composite resources or Claims save these in the secret defined by their
`writeConnectionSecretToRef` field.
```yaml {label="key",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: xDatabase
plural: xdatabases
connectionSecretKeys:
- username
- password
- address
versions:
# Removed for brevity
```
{{<hint "warning">}}
You can't change the `connectionSecretKeys` of an XRD. You must delete and
recreate the XRD to change the `connectionSecretKeys`.
{{</hint >}}
For more information on connection secrets read the
[Connection Secrets knowledge base article]({{<ref "connection-details">}}).
### Set composite resource defaults
XRDs can set default parameters for composite resources and Claims.
<!-- vale off -->
#### defaultCompositeDeletePolicy
<!-- vale on -->
The `defaultCompositeDeletePolicy` defines the default value for the claim's
`compositeDeletePolicy` property if the user doesn't specify a value when creating
the claim. The claim controller uses the `compositeDeletePolicy` property to specify
the propagation policy when deleting the associated composite.
The `compositeDeletePolicy` doesn't apply to standalone composites that don't have
associated claims.
Using a `defaultCompositeDeletePolicy: Background` policy causes the CRD for the claim to have
the default value `Background` for the `compositeDeletePolicy` property.
When a deleted claim has the `compositeDeletePolicy` property set to `Background`
the claim controller deletes the composite resource using the propagation policy `background`
and returns, relying on Kubernetes to delete the remaining child objects,
like managed resources, nested composites and secrets.
Using `defaultCompositeDeletePolicy: Foreground` causes the CRD for the claim to have
the `compositeDeletePolicy` default value `Foreground`. When a deleted claim has the
`compositeDeletePolicy` property set to `Foreground` the controller
deletes the associated composite using the propagation policy `foreground`. This causes Kubernetes
to use foreground cascading deletion which deletes all child resources before deleting the
parent resource. The claim controller waits for the composite deletion to finish before returning.
When creating a claim the user can override the `defaultCompositeDeletePolicy` by including
the `spec.compositeDeletePolicy` property with either the `Background` or `Foreground` value.
The default value is `defaultCompositeDeletePolicy: Background`.
Set
{{<hover label="delete" line="6">}}defaultCompositeDeletePolicy: Foreground{{</hover>}}
to change the XRD deletion policy.
```yaml {label="delete",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
defaultCompositeDeletePolicy: Foreground
group: custom-api.example.org
names:
# Removed for brevity
versions:
# Removed for brevity
```
<!-- vale off -->
#### defaultCompositionRef
<!-- vale on -->
It's possible for multiple [Compositions]({{<ref "./compositions">}}) to
reference the same XRD. If more than one Composition references the same XRD,
the composite resource or Claim must select which Composition to use.
An XRD can define the default Composition to use with the
`defaultCompositionRef` value.
Set a
{{<hover label="defaultComp" line="6">}}defaultCompositionRef{{</hover>}}
to set the default Composition.
```yaml {label="defaultComp",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
defaultCompositionRef:
name: myComposition
group: custom-api.example.org
names:
# Removed for brevity
versions:
# Removed for brevity
```
<!-- vale off -->
#### defaultCompositionUpdatePolicy
<!-- vale on -->
Changes to a Composition generate a new Composition revision. By default all
composite resources and Claims use the updated Composition revision.
Set the XRD `defaultCompositionUpdatePolicy` to `Manual` to prevent composite
resources and Claims from automatically using the new revision.
The default value is `defaultCompositionUpdatePolicy: Automatic`.
Set {{<hover label="compRev" line="6">}}defaultCompositionUpdatePolicy: Manual{{</hover>}}
to set the default Composition update policy for composite resources and Claims
using this XRD.
```yaml {label="compRev",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
defaultCompositionUpdatePolicy: Manual
group: custom-api.example.org
names:
# Removed for brevity
versions:
# Removed for brevity
```
<!-- vale off -->
#### enforcedCompositionRef
<!-- vale on -->
To require all composite resources or Claims to use a specific Composition use
the `enforcedCompositionRef` setting in the XRD.
For example, to require all composite resources and Claims using this XRD to use
the Composition
{{<hover label="enforceComp" line="6">}}myComposition{{</hover>}}
set
{{<hover label="enforceComp" line="6">}}enforcedCompositionRef.name: myComposition{{</hover>}}.
```yaml {label="defaultComp",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
enforcedCompositionRef:
name: myComposition
group: custom-api.example.org
names:
# Removed for brevity
versions:
# Removed for brevity
```
## Verify a CompositeResourceDefinition
Verify an XRD with `kubectl get compositeresourcedefinition` or the short form,
{{<hover label="getxrd" line="1">}}kubectl get xrd{{</hover>}}.
```yaml {label="getxrd",copy-lines="1"}
kubectl get xrd
NAME ESTABLISHED OFFERED AGE
xdatabases.custom-api.example.org True True 22m
```
The `ESTABLISHED` field indicates Crossplane installed the Kubernetes custom
resource definition for this XRD.
The `OFFERED` field indicates this XRD offers a Claim and Crossplane installed
the Kubernetes custom resource definitions for the Claim.
### XRD conditions
Crossplane uses a standard set of `Conditions` for XRDs.
View the conditions of a XRD under their `Status` with
`kubectl describe xrd`.
```yaml {copy-lines="none"}
kubectl describe xrd
Name: xpostgresqlinstances.database.starter.org
API Version: apiextensions.crossplane.io/v1
Kind: CompositeResourceDefinition
# Removed for brevity
Status:
Conditions:
Reason: WatchingCompositeResource
Status: True
Type: Established
Reason: WatchingCompositeResourceClaim
Status: True
Type: Offered
# Removed for brevity
```
<!-- vale off -->
#### WatchingCompositeResource
<!-- vale on -->
`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.
```yaml
Type: Established
Status: True
Reason: WatchingCompositeResource
```
<!-- vale off -->
#### TerminatingCompositeResource
<!-- vale on -->
`Reason: TerminatingCompositeResource` indicates Crossplane is deleting the
custom resource definitions related to the composite resource and is
terminating the composite resource controller.
```yaml
Type: Established
Status: False
Reason: TerminatingCompositeResource
```
<!-- vale off -->
#### WatchingCompositeResourceClaim
<!-- vale on -->
`Reason: WatchingCompositeResourceClaim` indicates Crossplane defined the new
Kubernetes custom resource definitions related to the offered Claims and is
watching for the creation of new Claims.
```yaml
Type: Offered
Status: True
Reason: WatchingCompositeResourceClaim
```
<!-- vale off -->
#### TerminatingCompositeResourceClaim
<!-- vale on -->
`Reason: TerminatingCompositeResourceClaim` indicates Crossplane is deleting the
custom resource definitions related to the offered Claims and is
terminating the Claims controller.
```yaml
Type: Offered
Status: False
Reason: TerminatingCompositeResourceClaim
```

View File

@ -0,0 +1,482 @@
---
title: Composite Resources
weight: 50
description: "Composite resources, an XR or XRs, represent a collection of related cloud resources."
---
A composite resource represents a set of managed resources as a single
Kubernetes object. Crossplane creates composite resources when users access a
custom API, defined in the CompositeResourceDefinition.
{{<hint "tip" >}}
Composite resources are a _composite_ of managed resources.
A _Composition_ defines how to _compose_ the managed resources together.
{{< /hint >}}
{{<expand "Confused about Compositions, XRDs, XRs and Claims?" >}}
Crossplane has four core components that users commonly mix up:
* [Compositions]({{<ref "./compositions">}}) - A template to define how to create resources.
* [Composite Resource Definition]({{<ref "./composite-resource-definitions">}})
(`XRD`) - A custom API specification.
* Composite Resource (`XR`) - This page. 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 composite resources
Creating composite resources requires a
[Composition]({{<ref "./compositions">}}) and a
[CompositeResourceDefinition]({{<ref "./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.
![Diagram of the relationship of Crossplane components](/media/composition-how-it-works.svg)
XRDs define the API used to create a composite resource.
For example,
this {{<hover label="xrd1" line="2">}}CompositeResourceDefinition{{</hover>}}
creates a custom API endpoint
{{<hover label="xrd1" line="4">}}xmydatabases.example.org{{</hover>}}.
```yaml {label="xrd1",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xmydatabases.example.org
spec:
group: example.org
names:
kind: xMyDatabase
plural: xmydatabases
# Removed for brevity
```
When a user calls the custom API,
{{<hover label="xrd1" line="4">}}xmydatabases.example.org{{</hover>}},
Crossplane chooses the Composition to use based on the Composition's
{{<hover label="typeref" line="6">}}compositeTypeRef{{</hover>}}
```yaml {label="typeref",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: my-composition
spec:
compositeTypeRef:
apiVersion: example.org/v1alpha1
kind: xMyDatabase
# Removed for brevity
```
The Composition
{{<hover label="typeref" line="6">}}compositeTypeRef{{</hover>}} matches the
XRD {{<hover label="xrd1" line="6">}}group{{</hover>}} and
{{<hover label="xrd1" line="9">}}kind{{</hover>}}.
Crossplane creates the resources defined in the matching Composition and
represents them as a single `composite` resource.
```shell{copy-lines="1"}
kubectl get composite
NAME SYNCED READY COMPOSITION AGE
my-composite-resource True True my-composition 4s
```
### Naming external resources
By default, managed resources created by a composite resource have the name of
the composite resource, followed by a random suffix.
<!-- vale Google.FirstPerson = NO -->
<!-- vale Crossplane.Spelling = NO -->
For example, a composite resource named "my-composite-resource" creates external
resources named "my-composite-resource-fqvkw."
<!-- vale Google.FirstPerson = YES -->
<!-- vale Crossplane.Spelling = YES -->
Resource names can be deterministic by applying an
{{<hover label="annotation" line="5">}}annotation{{</hover>}} to the composite
resource.
```yaml {label="annotation",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
annotations:
crossplane.io/external-name: my-custom-name
# Removed for brevity
```
Inside the Composition, use a
{{<hover label="comp" line="10">}}patch{{</hover>}}
to apply the external-name to the resources.
The {{<hover label="comp" line="11">}}fromFieldPath{{</hover>}} patch copies the
{{<hover label="comp" line="11">}}metadata.annotations{{</hover>}} field from
the composite resource to the
{{<hover label="comp" line="12">}}metadata.annotations{{</hover>}} inside the
managed resource.
{{<hint "note" >}}
If a managed resource has the `crossplane.io/external-name` annotation
Crossplane uses the annotation value to name the external resource.
{{</hint >}}
```yaml {label="comp",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: my-composition
spec:
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: database
base:
# Removed for brevity
patches:
- fromFieldPath: metadata.annotations
toFieldPath: metadata.annotations
```
For more information on using `function-patch-and-transform` to patch
resources refer to the
[Function Patch and Transform]({{<ref "../guides/function-patch-and-transform">}})
documentation.
### Composition selection
Select a specific Composition for a composite resource to use with
{{<hover label="compref" line="6">}}compositionRef{{</hover>}}
{{<hint "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]({{<ref "./compositions#enable-composite-resources">}})
section of the Composition documentation.
{{< /hint >}}
```yaml {label="compref",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
spec:
compositionRef:
name: my-other-composition
# Removed for brevity
```
A composite resource can also select a Composition based on labels instead of
the exact name with a
{{<hover label="complabel" line="6">}}compositionSelector{{</hover>}}.
Inside the {{<hover label="complabel" line="7">}}matchLabels{{</hover>}} section
provide one or more Composition labels to match.
```yaml {label="complabel",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
spec:
compositionSelector:
matchLabels:
environment: production
# Removed for brevity
```
### Composition revision policy
Crossplane tracks changes to Compositions as
[Composition revisions]({{<ref "composition-revisions">}}) .
A composite resource can use
a {{<hover label="comprev" line="6">}}compositionUpdatePolicy{{</hover>}} to
manually or automatically reference newer Composition revisions.
The default
{{<hover label="comprev" line="6">}}compositionUpdatePolicy{{</hover>}} is
"Automatic." Composite resources automatically use the latest Composition
revision.
Change the policy to
{{<hover label="comprev" line="6">}}Manual{{</hover>}} to prevent composite
resources from automatically upgrading.
```yaml {label="comprev",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
spec:
compositionUpdatePolicy: Manual
# Removed for brevity
```
### Composition revision selection
Crossplane records changes to Compositions as
[Composition revisions]({{<ref "composition-revisions">}}).
A composite resource can
select a specific Composition revision.
Use {{<hover label="comprevref" line="6">}}compositionRevisionRef{{</hover>}} to
select a specific Composition revision by name.
For example, to select a specific Composition revision use the name of the
desired Composition revision.
```yaml {label="comprevref",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
spec:
compositionUpdatePolicy: Manual
compositionRevisionRef:
name: my-composition-b5aa1eb
# Removed for brevity
```
{{<hint "note" >}}
Find the Composition revision name from
{{<hover label="getcomprev" line="1">}}kubectl get compositionrevision{{</hover>}}
```shell {label="getcomprev",copy-lines="1"}
kubectl get compositionrevision
NAME REVISION XR-KIND XR-APIVERSION AGE
my-composition-5c976ad 1 xmydatabases example.org/v1alpha1 65m
my-composition-b5aa1eb 2 xmydatabases example.org/v1alpha1 64m
```
{{< /hint >}}
A Composite resource can also select Composition revisions based on labels
instead of the exact name with a
{{<hover label="comprevsel" line="6">}}compositionRevisionSelector{{</hover>}}.
Inside the {{<hover label="comprevsel" line="7">}}matchLabels{{</hover>}}
section provide one or more Composition revision labels to match.
```yaml {label="comprevsel",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
spec:
compositionRevisionSelector:
matchLabels:
channel: dev
# Removed for brevity
```
### Manage connection secrets
When a composite resource creates resources, Crossplane provides any
[connection secrets]({{<ref "./managed-resources#writeconnectionsecrettoref">}})
to the composite resource.
{{<hint "important" >}}
A resource may only access connection secrets allowed by the XRD. By
default XRDs provide access to all connection secrets generated by managed
resources.
Read more about [managing connection secrets]({{<ref "./composite-resource-definitions#manage-connection-secrets">}})
in the XRD documentation.
{{< /hint >}}
Use
{{<hover label="writesecret" line="6">}}writeConnectionSecretToRef{{</hover>}}
to specify where the composite resource writes their connection secrets to.
For example, this composite resource saves the connection secrets in a
Kubernetes secret object named
{{<hover label="writesecret" line="7">}}my-secret{{</hover>}} in the namespace
{{<hover label="writesecret" line="8">}}crossplane-system{{</hover>}}.
```yaml {label="writesecret",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
spec:
writeConnectionSecretToRef:
name: my-secret
namespace: crossplane-system
# Removed for brevity
```
Composite resources can write connection secrets to an
[external secret store]({{<ref "../guides/vault-as-secret-store">}}),
like HashiCorp Vault.
{{<hint "important" >}}
External secret stores are an alpha feature. Alpha features aren't enabled by
default.
{{< /hint >}}
Use the {{<hover label="publishsecret"
line="6">}}publishConnectionDetailsTo{{</hover>}} field to save connection
secrets to an external secrets store.
```yaml {label="publishsecret",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
spec:
publishConnectionDetailsTo:
name: my-external-secret-store
# Removed for brevity
```
Read the [External Secrets Store]({{<ref "../guides/vault-as-secret-store">}}) documentation for more information on using
external secret stores.
For more information on connection secrets read the [Connection Secrets knowledge base article]({{<ref "connection-details">}}).
### Pausing composite resources
<!-- vale Google.WordList = NO -->
Crossplane supports pausing composite resources. A paused composite resource
doesn't check or make changes on its external resources.
<!-- vale Google.WordList = YES -->
To pause a composite resource apply the
{{<hover label="pause" line="4">}}crossplane.io/paused{{</hover>}} annotation.
```yaml {label="pause",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
annotations:
crossplane.io/paused: "true"
spec:
# Removed for brevity
```
## Verify composite resources
Use
{{<hover label="getcomposite" line="1">}}kubectl get composite{{</hover>}}
to view all the composite resources Crossplane created.
```shell{copy-lines="1",label="getcomposite"}
kubectl get composite
NAME SYNCED READY COMPOSITION AGE
my-composite-resource True True my-composition 4s
```
Use `kubectl get` for the specific custom API endpoint to view
only those resources.
```shell {copy-lines="1"}
kubectl get xMyDatabase.example.org
NAME SYNCED READY COMPOSITION AGE
my-composite-resource True True my-composition 12m
```
Use
{{<hover label="desccomposite" line="1">}}kubectl describe composite{{</hover>}}
to view the linked
{{<hover label="desccomposite" line="16">}}Composition Ref{{</hover>}},
and unique managed resources created in the
{{<hover label="desccomposite" line="22">}}Resource Refs{{</hover>}}.
```yaml {copy-lines="1",label="desccomposite"}
kubectl describe composite my-composite-resource
Name: my-composite-resource
API Version: example.org/v1alpha1
Kind: xMyDatabase
Spec:
Composition Ref:
Name: my-composition
Composition Revision Ref:
Name: my-composition-cf2d3a7
Composition Update Policy: Automatic
Resource Refs:
API Version: s3.aws.upbound.io/v1beta1
Kind: Bucket
Name: my-composite-resource-fmrks
API Version: dynamodb.aws.upbound.io/v1beta1
Kind: Table
Name: my-composite-resource-wnr9t
# Removed for brevity
```
### Composite resource conditions
The conditions of composite resources match the conditions of their managed
resources.
Read the
[conditions section]({{<ref "./managed-resources#conditions">}}) of the
managed resources documentation for details.
## Composite resource labels
Crossplane adds labels to composite resources to show their relationship to
other Crossplane components.
### Composite label
Crossplane adds the
{{<hover label="complabel" line="4">}} crossplane.io/composite{{</hover>}} label
to all composite resources. The label matches the name of the composite.
Crossplane applies the composite label to any managed resource created by a
composite, creating a reference between the managed resource and owning
composite resource.
```shell {label="claimname",copy-lines="1"}
kubectl describe xmydatabase.example.org/my-claimed-database-x9rx9
Name: my-claimed-database2-x9rx9
Namespace:
Labels: crossplane.io/composite=my-claimed-database-x9rx9
```
### Claim name label
Crossplane adds the
{{<hover label="claimname" line="4">}}crossplane.io/claim-name{{</hover>}}
label to composite resources created from a Claim. The label indicates the name
of the Claim linked to this composite resource.
```shell {label="claimname",copy-lines="1"}
kubectl describe xmydatabase.example.org/my-claimed-database-x9rx9
Name: my-claimed-database2-x9rx9
Namespace:
Labels: crossplane.io/claim-name=my-claimed-database
```
Composite resources created directly, without using a Claim, don't have a
{{<hover label="claimname" line="4">}}crossplane.io/claim-name{{</hover>}}
label.
### Claim namespace label
Crossplane adds the
{{<hover label="claimname" line="4">}}crossplane.io/claim-namespace{{</hover>}}
label to composite resources created from a Claim. The label indicates the
namespace of the Claim linked to this composite resource.
```shell {label="claimname",copy-lines="1"}
kubectl describe xmydatabase.example.org/my-claimed-database-x9rx9
Name: my-claimed-database2-x9rx9
Namespace:
Labels: crossplane.io/claim-namespace=default
```
Composite resources created directly, without using a Claim, don't have a
{{<hover label="claimname" line="4">}}crossplane.io/claim-namespace{{</hover>}}
label.

View File

@ -0,0 +1,461 @@
---
title: Composition Revisions
weight: 35
---
This guide discusses the use of "Composition Revisions" to safely make and roll
back changes to a Crossplane [`Composition`][composition-type]. It assumes
familiarity with Crossplane, and particularly with
[Compositions].
A `Composition` configures how Crossplane should reconcile a Composite Resource
(XR). Put otherwise, when you create an XR the selected `Composition` determines
what managed resources Crossplane will create in response. Let's say for example
that you define a `PlatformDB` XR, which represents your organisation's common
database configuration of an Azure MySQL Server and a few firewall rules. The
`Composition` contains the 'base' configuration for the MySQL server and the
firewall rules that are extended by the configuration for the `PlatformDB`.
There is a one-to-many relationship between a `Composition` and the XRs that use
it. You might define a `Composition` named `big-platform-db` that is used by ten
different `PlatformDB` XRs. Usually, in the interest of self-service, the
`Composition` is managed by a different team from the actual `PlatformDB` XRs.
For example the `Composition` may be written and maintained by a platform team
member, while individual application teams create `PlatformDB` XRs that use said
`Composition`.
Each `Composition` is mutable - you can update it as your organisation's needs
change. However, 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 will be instantly updated in accordance with
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 leverage the latest `Composition` settings at your own pace.
This enables you to [canary] changes to your infrastructure, or to roll back
some XRs to previous `Composition` settings without rolling back all XRs.
## Using Composition Revisions
When you enable Composition Revisions three things happen:
1. Crossplane creates a `CompositionRevision` for each `Composition` update.
1. Composite Resources gain a `spec.compositionRevisionRef` field that specifies
which `CompositionRevision` they use.
1. Composite Resources gain a `spec.compositionUpdatePolicy` field that
specifies how they should be updated to new Composition Revisions.
Each time you edit a `Composition` Crossplane will automatically create a
`CompositionRevision` that represents that 'revision' of the `Composition` -
that unique state. Each revision is allocated an increasing revision number.
This gives `CompositionRevision` consumers an idea about which revision is
'newest'.
Crossplane distinguishes between the 'newest' and the 'current' revision of a
`Composition`. That is, if you revert a `Composition` to a previous state that
corresponds to an existing `CompositionRevision` that revision will become
'current' even if it is not the 'newest' revision (i.e. the most latest _unique_
`Composition` configuration).
You can discover which revisions exist using `kubectl`:
```console
# Find all revisions of the Composition named 'example'
kubectl get compositionrevision -l crossplane.io/composition-name=example
```
This should produce output something like:
```console
NAME REVISION CURRENT AGE
example-18pdg 1 False 4m36s
example-2bgdr 2 True 73s
example-xjrdm 3 False 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 point in time.
Crossplane behaves the same way by default whether Composition Revisions are
enabled or not. This is because when you enable Composition Revisions all XRs
default to the `Automatic` `compositionUpdatePolicy`. XRs support two update
policies:
* `Automatic`: Automatically use the current `CompositionRevision`. (Default)
* `Manual`: Require manual intervention to change `CompositionRevision`.
The below XR uses the `Manual` policy. When this policy is used the XR will
select the current `CompositionRevision` when it is first created, but must
manually be updated when you wish it to use another `CompositionRevision`.
```yaml
apiVersion: example.org/v1alpha1
kind: PlatformDB
metadata:
name: example
spec:
parameters:
storageGB: 20
# The Manual policy specifies that you do not want this XR to update to the
# current CompositionRevision automatically.
compositionUpdatePolicy: Manual
compositionRef:
name: example
writeConnectionSecretToRef:
name: db-conn
```
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`.
```yaml
apiVersion: example.org/v1alpha1
kind: PlatformDB
metadata:
name: example
spec:
parameters:
storageGB: 20
compositionUpdatePolicy: Manual
compositionRef:
name: example
# Update the referenced CompositionRevision if and when you are ready.
compositionRevisionRef:
name: example-18pdg
writeConnectionSecretToRef:
name: db-conn
```
## 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 will
assign different CompositionRevisions to the created composite resources each time the composition is updated.
### Preparation
##### Install Crossplane
Install Crossplane v1.11.0 or later and wait until the Crossplane pods are running.
```shell
kubectl create namespace crossplane-system
helm repo add crossplane-master https://charts.crossplane.io/master/
helm repo update
helm install crossplane --namespace crossplane-system crossplane-master/crossplane --devel --version 1.11.0-rc.0.108.g0521c32e
kubectl get pods -n crossplane-system
```
Expected Output:
```shell
NAME READY STATUS RESTARTS AGE
crossplane-7f75ddcc46-f4d2z 1/1 Running 0 9s
crossplane-rbac-manager-78bd597746-sdv6w 1/1 Running 0 9s
```
#### Deploy Composition and XRD Examples
Apply the example Composition.
```yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
labels:
channel: dev
name: myvpcs.aws.example.upbound.io
spec:
writeConnectionSecretsToNamespace: crossplane-system
compositeTypeRef:
apiVersion: aws.example.upbound.io/v1alpha1
kind: MyVPC
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: my-vpc
base:
apiVersion: ec2.aws.upbound.io/v1beta1
kind: VPC
spec:
forProvider:
region: us-west-1
cidrBlock: 192.168.0.0/16
enableDnsSupport: true
enableDnsHostnames: true
```
Apply the example XRD.
```yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: myvpcs.aws.example.upbound.io
spec:
group: aws.example.upbound.io
names:
kind: MyVPC
plural: myvpcs
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
id:
type: string
description: ID of this VPC that other objects will use to refer to it.
required:
- id
```
Verify that Crossplane created the Composition revision
```shell
kubectl get compositionrevisions -o="custom-columns=NAME:.metadata.name,REVISION:.spec.revision,CHANNEL:.metadata.labels.channel"
```
Expected Output:
```shell
NAME REVISION CHANNEL
myvpcs.aws.example.upbound.io-ad265bc 1 dev
```
{{< hint "note" >}}
The label `dev` is automatically created from the Composition.
{{< /hint >}}
### 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. However, this can be changed by setting
`compositionUpdatePolicy: Manual` in the XR. It is also possible to select the latest revision with a specific label
with `compositionRevisionSelector.matchLabels` together with `compositionUpdatePolicy: Automatic`.
#### Default update policy
Create an XR without a `compositionUpdatePolicy` defined. The update policy is `Automatic` by default:
```yaml
apiVersion: aws.example.upbound.io/v1alpha1
kind: MyVPC
metadata:
name: vpc-auto
spec:
id: vpc-auto
```
Expected Output:
```shell
myvpc.aws.example.upbound.io/vpc-auto created
```
#### Manual update policy
Create a Composite Resource with `compositionUpdatePolicy: Manual` and `compositionRevisionRef`.
```yaml
apiVersion: aws.example.upbound.io/v1alpha1
kind: MyVPC
metadata:
name: vpc-man
spec:
id: vpc-man
compositionUpdatePolicy: Manual
compositionRevisionRef:
name: myvpcs.aws.example.upbound.io-ad265bc
```
Expected Output:
```shell
myvpc.aws.example.upbound.io/vpc-man created
```
#### Using a selector
Create an XR with a `compositionRevisionSelector` of `channel: dev`:
```yaml
apiVersion: aws.example.upbound.io/v1alpha1
kind: MyVPC
metadata:
name: vpc-dev
spec:
id: vpc-dev
compositionRevisionSelector:
matchLabels:
channel: dev
```
Expected Output:
```shell
myvpc.aws.example.upbound.io/vpc-dev created
```
Create an XR with a `compositionRevisionSelector` of `channel: staging`:
```yaml
apiVersion: aws.example.upbound.io/v1alpha1
kind: MyVPC
metadata:
name: vpc-staging
spec:
id: vpc-staging
compositionRevisionSelector:
matchLabels:
channel: staging
```
Expected Output:
```shell
myvpc.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.
```shell
kubectl get composite -o="custom-columns=NAME:.metadata.name,SYNCED:.status.conditions[0].status,REVISION:.spec.compositionRevisionRef.name,POLICY:.spec.compositionUpdatePolicy,MATCHLABEL:.spec.compositionRevisionSelector.matchLabels"
```
Expected Output:
```shell
NAME SYNCED REVISION POLICY MATCHLABEL
vpc-auto True myvpcs.aws.example.upbound.io-ad265bc Automatic <none>
vpc-dev True myvpcs.aws.example.upbound.io-ad265bc Automatic map[channel:dev]
vpc-man True myvpcs.aws.example.upbound.io-ad265bc Manual <none>
vpc-staging False <none> Automatic map[channel:staging]
```
{{< hint "note" >}}
The `vpc-staging` XR label doesn't match any existing Composition Revisions.
{{< /hint >}}
### Create new Composition revisions
Crossplane creates a new CompositionRevision when a Composition is created or updated. Label and annotation changes will
also trigger a new CompositionRevision.
#### Update the Composition label
Update the `Composition` label to `channel: staging`:
```shell
kubectl label composition myvpcs.aws.example.upbound.io channel=staging --overwrite
```
Expected Output:
```shell
composition.apiextensions.crossplane.io/myvpcs.aws.example.upbound.io labeled
```
Verify that Crossplane creates a new Composition revision:
```shell
kubectl get compositionrevisions -o="custom-columns=NAME:.metadata.name,REVISION:.spec.revision,CHANNEL:.metadata.labels.channel"
```
Expected Output:
```shell
NAME REVISION CHANNEL
myvpcs.aws.example.upbound.io-727b3c8 2 staging
myvpcs.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:
```shell
kubectl get composite -o="custom-columns=NAME:.metadata.name,SYNCED:.status.conditions[0].status,REVISION:.spec.compositionRevisionRef.name,POLICY:.spec.compositionUpdatePolicy,MATCHLABEL:.spec.compositionRevisionSelector.matchLabels"
```
Expected Output:
```shell
NAME SYNCED REVISION POLICY MATCHLABEL
vpc-auto True myvpcs.aws.example.upbound.io-727b3c8 Automatic <none>
vpc-dev True myvpcs.aws.example.upbound.io-ad265bc Automatic map[channel:dev]
vpc-man True myvpcs.aws.example.upbound.io-ad265bc Manual <none>
vpc-staging True myvpcs.aws.example.upbound.io-727b3c8 Automatic map[channel:staging]
```
{{< hint "note" >}}
`vpc-auto` always use the latest Revision.
`vpc-staging` now matches the label applied to Revision revision:2.
{{< /hint >}}
#### 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:
```yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
labels:
channel: dev
name: myvpcs.aws.example.upbound.io
spec:
writeConnectionSecretsToNamespace: crossplane-system
compositeTypeRef:
apiVersion: aws.example.upbound.io/v1alpha1
kind: MyVPC
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: my-vpc
base:
apiVersion: ec2.aws.upbound.io/v1beta1
kind: VPC
spec:
forProvider:
region: us-west-1
cidrBlock: 192.168.0.0/16
enableDnsSupport: false
enableDnsHostnames: true
```
Expected Output:
```shell
composition.apiextensions.crossplane.io/myvpcs.aws.example.upbound.io configured
```
Verify that Crossplane creates a new Composition revision:
```shell
kubectl get compositionrevisions -o="custom-columns=NAME:.metadata.name,REVISION:.spec.revision,CHANNEL:.metadata.labels.channel"
```
Expected Output:
```shell
NAME REVISION CHANNEL
myvpcs.aws.example.upbound.io-727b3c8 2 staging
myvpcs.aws.example.upbound.io-ad265bc 1 dev
myvpcs.aws.example.upbound.io-f81c553 3 dev
```
{{< hint "note" >}}
Changing the label and the spec values simultaneously is critical for deploying new changes to the `dev` channel.
{{< /hint >}}
Verify Crossplane assigns the Composite Resources `vpc-auto` and `vpc-dev` to Composite revision:3.
`vpc-staging` is assigned to revision:2, and `vpc-man` is still assigned to the original revision:1:
```shell
kubectl get composite -o="custom-columns=NAME:.metadata.name,SYNCED:.status.conditions[0].status,REVISION:.spec.compositionRevisionRef.name,POLICY:.spec.compositionUpdatePolicy,MATCHLABEL:.spec.compositionRevisionSelector.matchLabels"
```
Expected Output:
```shell
NAME SYNCED REVISION POLICY MATCHLABEL
vpc-auto True myvpcs.aws.example.upbound.io-f81c553 Automatic <none>
vpc-dev True myvpcs.aws.example.upbound.io-f81c553 Automatic map[channel:dev]
vpc-man True myvpcs.aws.example.upbound.io-ad265bc Manual <none>
vpc-staging True myvpcs.aws.example.upbound.io-727b3c8 Automatic map[channel:staging]
```
{{< hint "note" >}}
`vpc-dev` matches the updated label applied to Revision revision:3.
`vpc-staging` matches the label applied to Revision revision:2.
{{< /hint >}}
[composition-type]: {{<ref "../../master/concepts/compositions" >}}
[Compositions]: {{<ref "../../master/concepts/compositions" >}}
[canary]: https://martinfowler.com/bliki/CanaryRelease.html
[install-guide]: {{<ref "../../master/software/install" >}}

View File

@ -0,0 +1,989 @@
---
title: Compositions
weight: 30
aliases:
- composition
- composition-functions
- /knowledge-base/guides/composition-functions
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.
Here's an example Composition. When you create an
{{<hover label="intro" line="8">}}AcmeBucket{{</hover >}} composite resource
(XR) that uses this Composition, Crossplane uses the template to create the
Amazon S3 {{<hover label="intro" line="18">}}Bucket{{</hover >}} managed
resource.
```yaml {label="intro"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example
spec:
compositeTypeRef:
apiVersion: custom-api.example.org/v1alpha1
kind: AcmeBucket
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: storage-bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: "us-east-2"
```
{{<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 >}}
## Create a Composition
Creating a Composition consists of:
* [Using composition functions](#use-a-function-in-a-composition) to define the
resources to create.
* [Enabling composite resources](#enable-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).
{{<hint "tip" >}}
The Crossplane community has built lots of functions that let you template
Crossplane resources using
[CUE](https://github.com/crossplane-contrib/function-cue),
[KCL](https://github.com/crossplane-contrib/function-kcl),
Helm-like
[Go templates](https://github.com/crossplane-contrib/function-go-templating) or
legacy Crossplane
[Patch and Transforms]({{<ref "../guides/function-patch-and-transform">}}).
You can also [write your own function](#write-a-composition-function) using Go
or Python.
{{< /hint >}}
{{<hint "important" >}}
Crossplane has two modes of composition:
* `mode: Pipeline`
* `mode: Resources`
Use the `Pipeline` mode to use composition functions.
<!-- vale write-good.Passive = NO -->
The `Resources` mode is deprecated, and you shouldn't use it. Crossplane
supports Compositions that use the `Resources` mode for backward compatibility,
but the feature is no longer maintained. Crossplane doesn't accept new
`Resources` features, and only accepts security bug fixes.
<!-- vale write-good.Passive = YES -->
See the [CLI documentation]({{<ref "../cli/command-reference#beta-convert">}})
to learn how to use the `crossplane beta convert` command to convert a legacy
`Resources` Composition to the `Pipeline` mode.
{{< /hint >}}
### 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
{{<hover label="install" line="2">}}Function{{</hover >}} object setting the
{{<hover label="install" line="6">}}spec.package{{</hover >}} value to the
location of the function package.
For example, to install [Function Patch and Transform]({{<ref "../guides/function-patch-and-transform">}}),
```yaml {label="install"}
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
name: function-patch-and-transform
spec:
package: xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.1.4
```
{{< hint "tip" >}}
Functions are Crossplane Packages. Read more about Packages in the
[Packages documentation]({{<ref "packages" >}}).
{{< /hint >}}
By default, the Function pod installs in the same namespace as Crossplane
(`crossplane-system`).
### 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`.
```shell {copy-lines="1"}
kubectl get functions
NAME INSTALLED HEALTHY PACKAGE AGE
function-patch-and-transform True Unknown xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.1.4 10s
```
After the Function install completes and it's ready for use the `HEALTHY` status
reports `True`.
### 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 or delete a composite resource.
When Crossplane calls a Function it sends it the current state of the composite
resource. It also sends it the current state of any managed 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
{{<hover label="single" line="6">}}mode{{</hover>}} to
{{<hover label="single" line="6">}}Pipeline{{</hover>}}.
Define a {{<hover label="single" line="7">}}pipeline{{</hover>}} of
{{<hover label="single" line="8">}}steps{{</hover>}}. Each
{{<hover label="single" line="8">}}step{{</hover>}} calls a Function.
Each {{<hover label="single" line="8">}}step{{</hover>}} uses a
{{<hover label="single" line="9">}}functionRef{{</hover>}} to reference the
{{<hover label="single" line="10">}}name{{</hover>}} of the Function to call.
{{<hint "important" >}}
Compositions using {{<hover label="single" line="6">}}mode: Pipeline{{</hover>}}
can't specify resource templates with a `resources` field.
Use function "Patch and Transform" to create resource templates.
{{< /hint >}}
Some Functions also allow you to specify an
{{<hover label="single" line="11">}}input{{</hover>}}.
The function defines the
{{<hover label="single" line="13">}}kind{{</hover>}} of input.
This example uses
[Function Patch and Transform]({{<ref "../guides/function-patch-and-transform">}}).
Function Patch and Transform implements Crossplane resource
templates.
The input kind is {{<hover label="single" line="13">}}Resources{{</hover>}},
and it accepts {{<hover label="single" line="14">}}resources{{</hover>}} as input.
```yaml {label="single",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for Brevity
spec:
# Removed for Brevity
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: storage-bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: "us-east-2"
```
### 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 {{<hover label="double" line="10">}}function-cue{{</hover>}} to
create an S3 bucket. Crossplane then passes the bucket to
{{<hover label="double" line="23">}}function-auto-ready{{</hover>}}, which marks the
composite resource as ready when the bucket becomes ready.
```yaml {label="double",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for Brevity
spec:
# Removed for Brevity
mode: Pipeline
pipeline:
- step: cue-export-resources
functionRef:
name: function-cue
input:
apiVersion: cue.fn.crossplane.io/v1beta1
kind: CUEInput
name: storage-bucket
export:
target: Resources
value: |
apiVersion: "s3.aws.upbound.io/v1beta1"
kind: "Bucket"
spec: forProvider: region: "us-east-2"
- step: automatically-detect-readiness
functionRef:
name: function-auto-ready
```
### Enable 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
```
### Store 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 "../guides/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.
Set the value of `writeConnectionSecretsToNamespace` 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 `spec` of each resource producing connection details, define the
`writeConnectionSecretToRef`, with a `namespace` and `name` of the secret object
for the resource.
If a `writeConnectionSecretToRef` 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
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
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 `name` in the `namespace` provided.
```shell {label="viewComposedSec"}
kubectl get secrets -n docs
NAME TYPE DATA AGE
key1 connection.crossplane.io/v1alpha1 4 4m30s
```
{{<hint "tip" >}}
Remember to create a unique name for each secret.
{{< /hint >}}
#### External secret stores
Crossplane
[External Secret Stores]({{<ref "../guides/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 `publishConnectionDetailsWithStoreConfigRef` in place of
`writeConnectionSecretsToNamespace` to define the `StoreConfig` to save
connection details to.
For example, using a `StoreConfig` with the `name` "vault," use
`publishConnectionDetailsWithStoreConfigRef.name` matching the
`StoreConfig.name`, 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
# Removed for brevity
```
For more details read the
[External Secret Stores]({{<ref "../guides/vault-as-secret-store" >}})
integration guide.
## 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.
{{<hint "important">}}
The `crossplane render` command only supports composition functions. It doesn't
support `mode: Resources` Compositions.
{{< /hint >}}
{{<hint "tip">}}
See the [Crossplane CLI docs]({{<ref "../cli">}}) to
learn how to install and use the Crossplane CLI.
{{< /hint >}}
{{<hint "important">}}
Running `crossplane render` requires [Docker](https://www.docker.com).
{{< /hint >}}
Provide a composite resource, composition and composition functions to render
the output locally.
```shell
crossplane 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.
```yaml
---
apiVersion: example.crossplane.io/v1
kind: XBucket
metadata:
name: example-render
---
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
annotations:
crossplane.io/composition-resource-name: storage-bucket
generateName: example-render-
labels:
crossplane.io/composite: example-render
ownerReferences:
- apiVersion: example.crossplane.io/v1
blockOwnerDeletion: true
controller: true
kind: XBucket
name: example-render
uid: ""
spec:
forProvider:
region: us-east-2
```
{{<expand "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:
```yaml
apiVersion: example.crossplane.io/v1
kind: XBucket
metadata:
name: example-render
spec:
bucketRegion: us-east-2
```
The `composition.yaml` file contains the Composition to use to render the
composite resource:
```yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example-render
spec:
compositeTypeRef:
apiVersion: example.crossplane.io/v1
kind: XBucket
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: storage-bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.bucketRegion
toFieldPath: spec.forProvider.region
```
The `functions.yaml` file contains the Functions the Composition references in
its pipeline steps:
```yaml
---
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
name: function-patch-and-transform
spec:
package: xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.1.4
```
{{</expand>}}
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 {{<hover label="development" line="6">}}Development{{</hover>}}
runtime the Crossplane CLI ignores the Function's {{<hover label="development"
line="8">}}package{{</hover>}}. 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`.
```yaml {label="development"}
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
name: function-patch-and-transform
annotations:
render.crossplane.io/runtime: Development
spec:
package: xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.1.4
```
{{<hint "tip">}}
Use the `Development` runtime when you
[write a composition function](#write-a-composition-function) to test your
function end-to-end.
{{</hint>}}
`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
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 its integrity,
checking that the Composition is well formed, for example:
If using `mode: Resources`:
* The `resources` field isn't empty.
* 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 `mode: Pipeline` (Composition Functions):
* The `pipeline` field isn't empty.
* No duplicate step names.
### Composition schema aware validation
Crossplane also performs schema aware
validation of Compositions. Schema validation checks that `patches`,
`readinessChecks` and `connectionDetails` are valid according to the resource
schemas. For example, checking that the source and destination fields of a patch
are valid according to the source and destination resource schema.
{{<hint "note" >}}
Composition schema aware validation is a beta feature. Crossplane enables
beta features by default.
Disable schema aware validation by setting the
`--enable-composition-webhook-schema-validation=false` flag on the Crossplane
pod.
The [Crossplane Pods]({{<ref "./pods#edit-the-deployment">}}) page has
more information on enabling Crossplane flags.
{{< /hint >}}
#### Schema aware validation modes
Crossplane always rejects Compositions in case of integrity errors.
Set the schema aware validation mode to configure how Crossplane handles both
missing resource schemas and schema aware validation errors.
{{<hint "note" >}}
If a resource schema is missing, Crossplane skips schema aware validation
but still returns an error for integrity errors and a warning or an error
for the missing schemas.
{{< /hint >}}
The following modes are available:
{{< table "table table-sm table-striped" >}}
| Mode | Missing Schema | Schema Aware Error | Integrity Error |
| -------- | -------------- |--------------------|-----------------|
| `warn` | Warning | Warning | Error |
| `loose` | Warning | Error | Error |
| `strict` | Error | Error | Error |
{{< /table >}}
Change the validation mode for a Composition with the
{{<hover label="mode" line="5">}}crossplane.io/composition-schema-aware-validation-mode{{</hover>}}
annotation.
If not specified, the default mode is `warn`.
For example, to enable `loose` mode checking set the annotation value to
{{<hover label="mode" line="5">}}loose{{</hover>}}.
```yaml {copy-lines="none",label="mode"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
annotations:
crossplane.io/composition-schema-aware-validation-mode: loose
# Removed for brevity
spec:
# Removed for brevity
```
{{<hint "important" >}}
Validation modes also apply to Compositions defined by Configuration packages.
Depending on the mode configured in the Composition, schema aware validation
issues may result in warnings or the rejection of the Composition.
View the Crossplane logs for validation warnings.
Crossplane sets a Configuration as unhealthy if there are validation errors.
View the Configuration details with `kubectl describe configuration` to see the
specific errors.
{{< /hint >}}
## 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.
<!-- vale write-good.Passive = NO -->
Here's an example of a tiny, hello world function. This example is written in
[Go](https://go.dev).
<!-- vale write-good.Passive = YES -->
```go
func (f *Function) RunFunction(_ context.Context, req *fnv1.RunFunctionRequest) (*fnv1.RunFunctionResponse, error) {
rsp := response.To(req, response.DefaultTTL)
response.Normal(rsp, "Hello world!")
return rsp, nil
}
```
Crossplane has [language specific guides]({{<ref "../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](#how-composition-functions-work).
## 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](#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.
```mermaid
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, update, or delete 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.
{{<hint "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).
{{</hint>}}
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.
1. The __desired state__ of the composite resource, and any composed resources.
1. The function's __input__.
1. 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 __extra resources__ to determine the desired state it can
request any cluster-scoped resource Crossplane already has access to, either by
by name or labels through the returned RunFunctionResponse. Crossplane then
calls the function again including the requested __extra 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 __extra 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 __extra 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.
{{<hint "tip">}}
<!-- vale write-good.Weasel = NO -->
<!-- Disable Weasel to say "usually", which is correct in this context. -->
A _composed_ resource is a resource created by a composite resource. Composed
resources are usually Crossplane managed resources (MRs), but they can be any
kind of Crossplane resource. For example a composite resource could also create
a ProviderConfig, or another kind of composite resource.
<!-- vale write-good.Weasel = YES -->
{{</hint>}}
### 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.
```yaml
apiVersion: example.crossplane.io/v1
kind: XBucket
metadata:
name: example-render
spec:
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
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.
{{<hint "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.
{{</hint>}}
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.
{{<hint "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_.
{{</hint>}}
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.
```yaml
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
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.
{{<hint "tip">}}
Composition functions don't actually use YAML for desired and observed
resources. This example uses YAML for illustration purposes only.
{{</hint>}}
### Function input
If a Composition includes {{<hover label="input" line="14">}}input{{</hover>}}
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.
```yaml {label="input",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example-render
spec:
compositeTypeRef:
apiVersion: example.crossplane.io/v1
kind: XBucket
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: storage-bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.bucketRegion
toFieldPath: spec.forProvider.region
```
{{<hint "important">}}
Crossplane doesn't validate function input. It's a good idea for a function to
validate its own input.
{{</hint>}}
### 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.
Crossplane can write context too. If you enable the alpha
[composition environment]({{<ref "environment-configs">}}) feature Crossplane
writes the environment to the top-level context field
`apiextensions.crossplane.io/environment`.

View File

@ -0,0 +1,675 @@
---
title: Connection Details
weight: 110
description: "How to create and manage connection details across Crossplane managed resources, composite resources, Compositions and Claims"
---
Using connection details in Crossplane requires the following components:
* Defining the `writeConnectionSecretToRef.name` in a [Claim]({{<ref "/master/concepts/claims#claim-connection-secrets">}}).
* Defining the `writeConnectionSecretsToNamespace` value in the [Composition]({{<ref "/master/concepts/compositions#composite-resource-combined-secret">}}).
* Define the `writeConnectionSecretToRef` name and namespace for each resource in the
[Composition]({{<ref "/master/concepts/compositions#composed-resource-secrets">}}).
* Define the list of secret keys produced by each composed resource with in the
[Composition]({{<ref "/master/concepts/compositions">}}).
* Optionally, define the `connectionSecretKeys` in a
[CompositeResourceDefinition]({{<ref "/master/concepts/composite-resource-definitions#manage-connection-secrets">}}).
{{<hint "note">}}
This guide 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 "../guides/vault-as-secret-store">}}) for more information on using Crossplane
with an external secret store.
{{</hint >}}
## Background
When a [Provider]({{<ref "/master/concepts/providers">}}) creates a managed
resource, the resource may generate resource-specific details. These details can include
usernames, passwords or connection details like an IP address.
Crossplane refers to this information as the _connection details_ or
_connection secrets_.
The Provider
defines what information to present as a _connection
detail_ from a managed resource.
<!-- vale gitlab.SentenceLength = NO -->
<!-- wordy because of type names -->
When a managed resource is part of a
[Composition]({{<ref "/master/concepts/compositions">}}), the Composition,
[Composite Resource Definition]({{<ref "/master/concepts/composite-resource-definitions">}})
and optionally, the
[Claim]({{<ref "/master/concepts/claims">}}) define what details are visible
and where they're stored.
<!-- vale gitlab.SentenceLength = YES -->
{{<hint "note">}}
All the following examples use the same set of Compositions,
CompositeResourceDefinitions and Claims.
All examples rely on
[Upbound provider-aws-iam](https://marketplace.upbound.io/providers/upbound/provider-aws-iam/)
to create resources.
{{<expand "Reference Composition" >}}
```yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: xsecrettest.example.org
spec:
writeConnectionSecretsToNamespace: other-namespace
compositeTypeRef:
apiVersion: example.org/v1alpha1
kind: XSecretTest
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: key
base:
apiVersion: iam.aws.upbound.io/v1beta1
kind: AccessKey
spec:
forProvider:
userSelector:
matchControllerRef: true
writeConnectionSecretToRef:
namespace: docs
name: key1
connectionDetails:
- name: user
type: FromConnectionSecretKey
fromConnectionSecretKey: username
- name: password
type: FromConnectionSecretKey
fromConnectionSecretKey: password
- name: key
type: FromConnectionSecretKey
fromConnectionSecretKey: attribute.secret
- name: smtp
type: FromConnectionSecretKey
fromConnectionSecretKey: attribute.ses_smtp_password_v4
patches:
- fromFieldPath: "metadata.uid"
toFieldPath: "spec.writeConnectionSecretToRef.name"
transforms:
- type: string
string:
type: Format
fmt: "%s-secret1"
- name: user
base:
apiVersion: iam.aws.upbound.io/v1beta1
kind: User
spec:
forProvider: {}
- name: user2
base:
apiVersion: iam.aws.upbound.io/v1beta1
kind: User
metadata:
labels:
docs.crossplane.io: user
spec:
forProvider: {}
- name: key2
base:
apiVersion: iam.aws.upbound.io/v1beta1
kind: AccessKey
spec:
forProvider:
userSelector:
matchLabels:
docs.crossplane.io: user
writeConnectionSecretToRef:
namespace: docs
name: key2
connectionDetails:
- name: key2-user
type: FromConnectionSecretKey
fromConnectionSecretKey: username
- name: key2-password
type: FromConnectionSecretKey
fromConnectionSecretKey: password
- name: key2-secret
type: FromConnectionSecretKey
fromConnectionSecretKey: attribute.secret
- name: key2-smtp
type: FromConnectionSecretKey
fromConnectionSecretKey: attribute.ses_smtp_password_v4
patches:
- fromFieldPath: "metadata.uid"
toFieldPath: "spec.writeConnectionSecretToRef.name"
transforms:
- type: string
string:
type: Format
fmt: "%s-secret2"
`` `
{{</expand >}}
{{<expand "Reference CompositeResourceDefinition" >}}
```yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xsecrettests.example.org
spec:
group: example.org
connectionSecretKeys:
- username
- password
- attribute.secret
- attribute.ses_smtp_password_v4
- key2-user
- key2-pass
- key2-secret
- key2-smtp
names:
kind: XSecretTest
plural: xsecrettests
claimNames:
kind: SecretTest
plural: secrettests
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
```
{{</ expand >}}
{{<expand "Reference Claim" >}}
```yaml
apiVersion: example.org/v1alpha1
kind: SecretTest
metadata:
name: test-secrets
namespace: default
spec:
writeConnectionSecretToRef:
name: my-access-key-secret
```
{{</expand >}}
{{</hint >}}
## Connection secrets in a managed resource
<!-- vale gitlab.Substitutions = NO -->
<!-- vale gitlab.SentenceLength = NO -->
<!-- under 25 words -->
When a managed resource creates connection secrets, Crossplane can write the
secrets to a
[Kubernetes secret]({{<ref "/master/concepts/managed-resources#publish-secrets-to-kubernetes">}})
or an
[external secret store]({{<ref "/master/concepts/managed-resources#publish-secrets-to-an-external-secrets-store">}}).
<!-- vale gitlab.SentenceLength = YES -->
<!-- vale gitlab.Substitutions = YES -->
Creating an individual managed resource shows the connection secrets the
resource creates.
{{<hint "note" >}}
Read the [managed resources]({{<ref "/master/concepts/managed-resources">}})
documentation for more information on configuring resources and storing
connection secrets for individual resources.
{{< /hint >}}
For example, create an
{{<hover label="mr" line="2">}}AccessKey{{</hover>}} resource and save the
connection secrets in a Kubernetes secret named
{{<hover label="mr" line="12">}}my-accesskey-secret{{</hover>}}
in the
{{<hover label="mr" line="11">}}default{{</hover>}} namespace.
```yaml {label="mr"}
apiVersion: iam.aws.upbound.io/v1beta1
kind: AccessKey
metadata:
name: test-accesskey
spec:
forProvider:
userSelector:
matchLabels:
docs.crossplane.io: user
writeConnectionSecretToRef:
namespace: default
name: my-accesskey-secret
```
View the Kubernetes secret to see the connection details from the managed
resource.
This includes an
{{<hover label="mrSecret" line="11">}}attribute.secret{{</hover>}},
{{<hover label="mrSecret" line="12">}}attribute.ses_smtp_password_v4{{</hover>}},
{{<hover label="mrSecret" line="13">}}password{{</hover>}} and
{{<hover label="mrSecret" line="14">}}username{{</hover>}}
```yaml {label="mrSecret",copy-lines="1"}
kubectl describe secret my-accesskey-secret
Name: my-accesskey-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: connection.crossplane.io/v1alpha1
Data
====
attribute.secret: 40 bytes
attribute.ses_smtp_password_v4: 44 bytes
password: 40 bytes
username: 20 bytes
```
Compositions and CompositeResourceDefinitions require the exact names of the
secrets generated by a resource.
## Connection secrets in Compositions
Resources in a Composition that create connection details still create a
secret object containing their connection details.
Crossplane also generates
another secret object for each composite resource,
containing the secrets from all the defined resources.
For example, a Composition defines two
{{<hover label="comp1" line="9">}}AccessKey{{</hover>}}
objects.
Each {{<hover label="comp1" line="9">}}AccessKey{{</hover>}} writes a
connection secrets to the {{<hover label="comp1" line="15">}}name{{</hover>}}
inside the {{<hover label="comp1" line="14">}}namespace{{</hover>}} defined by
the resource
{{<hover label="comp1" line="13">}}writeConnectionSecretToRef{{</hover>}}.
Crossplane also creates a secret object for the entire Composition
saved in the namespace defined by
{{<hover label="comp1" line="4">}}writeConnectionSecretsToNamespace{{</hover>}}
with a Crossplane generated name.
```yaml {label="comp1",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
spec:
writeConnectionSecretsToNamespace: other-namespace
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: key1
base:
apiVersion: iam.aws.upbound.io/v1beta1
kind: AccessKey
spec:
forProvider:
# Removed for brevity
writeConnectionSecretToRef:
namespace: docs
name: key1-secret
- name: key2
base:
apiVersion: iam.aws.upbound.io/v1beta1
kind: AccessKey
spec:
forProvider:
# Removed for brevity
writeConnectionSecretToRef:
namespace: docs
name: key2-secret
# Removed for brevity
```
After applying a Claim, view the Kubernetes secrets to see three secret objects
created.
The secret
{{<hover label="compGetSec" line="3">}}key1-secret{{</hover>}} is from the resource
{{<hover label="comp1" line="6">}}key1{{</hover>}},
{{<hover label="compGetSec" line="4">}}key2-secret{{</hover>}} is from the resource
{{<hover label="comp1" line="16">}}key2{{</hover>}}.
Crossplane creates another secret in the namespace
{{<hover label="compGetSec" line="5">}}other-namespace{{</hover>}} with the
secrets from resource in the Composition.
```shell {label="compGetSec",copy-lines="1"}
kubectl get secrets -A
NAMESPACE NAME TYPE DATA AGE
docs key1-secret connection.crossplane.io/v1alpha1 4 4s
docs key2-secret connection.crossplane.io/v1alpha1 4 4s
other-namespace 70975471-c44f-4f6d-bde6-6bbdc9de1eb8 connection.crossplane.io/v1alpha1 0 6s
```
Although Crossplane creates a secret object, by default, Crossplane doesn't add
any data to the object.
```yaml {copy-lines="none"}
kubectl describe secret 70975471-c44f-4f6d-bde6-6bbdc9de1eb8 -n other-namespace
Name: 70975471-c44f-4f6d-bde6-6bbdc9de1eb8
Namespace: other-namespace
Type: connection.crossplane.io/v1alpha1
Data
====
```
The Composition must list the connection secrets to store for each resource.
Use the
{{<hover label="comp2" line="16">}}connectionDetails{{</hover>}} object under
each resource and define the secret keys the resource creates.
{{<hint "warning">}}
You can't change the
{{<hover label="comp2" line="16">}}connectionDetails{{</hover>}}
of a Composition.
You must delete and
recreate the Composition to change the
{{<hover label="comp2" line="16">}}connectionDetails{{</hover>}}.
{{</hint >}}
```yaml {label="comp2",copy-lines="16-20"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
spec:
writeConnectionSecretsToNamespace: other-namespace
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: key
base:
apiVersion: iam.aws.upbound.io/v1beta1
kind: AccessKey
spec:
forProvider:
# Removed for brevity
writeConnectionSecretToRef:
namespace: docs
name: key1
connectionDetails:
- name: user
type: FromConnectionSecretKey
fromConnectionSecretKey: username
- name: password
type: FromConnectionSecretKey
fromConnectionSecretKey: password
- name: key
type: FromConnectionSecretKey
fromConnectionSecretKey: attribute.secret
- name: smtp
type: FromConnectionSecretKey
fromConnectionSecretKey: attribute.ses_smtp_password_v4
# Removed for brevity
```
After applying a Claim the composite resource secret object contains the list of
keys listed in the
{{<hover label="comp2" line="16">}}connectionDetails{{</hover>}}.
```shell {copy-lines="1"}
kubectl describe secret -n other-namespace
Name: b0dc71f8-2688-4ebc-818a-bbad6a2c4f9a
Namespace: other-namespace
Type: connection.crossplane.io/v1alpha1
Data
====
username: 20 bytes
attribute.secret: 40 bytes
attribute.ses_smtp_password_v4: 44 bytes
password: 40 bytes
```
{{<hint "important">}}
If a key isn't listed in the
{{<hover label="comp2" line="16">}}connectionDetails{{</hover>}}
it isn't stored in the secret object.
{{< /hint >}}
### Managing conflicting secret keys
If resources produce conflicting keys, create a unique name with a connection
details
{{<hover label="comp3" line="25">}}name{{</hover>}}.
```yaml {label="comp3",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
spec:
writeConnectionSecretsToNamespace: other-namespace
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: key
base:
kind: AccessKey
spec:
# Removed for brevity
writeConnectionSecretToRef:
namespace: docs
name: key1
connectionDetails:
- name: user
type: FromConnectionSecretKey
fromConnectionSecretKey: username
- name: key2
base:
kind: AccessKey
spec:
# Removed for brevity
writeConnectionSecretToRef:
namespace: docs
name: key2
connectionDetails:
- name: key2-user
type: FromConnectionSecretKey
fromConnectionSecretKey: username
```
The secret object contains both keys,
{{<hover label="comp3Sec" line="9">}}username{{</hover>}}
and
{{<hover label="comp3Sec" line="10">}}key2-user{{</hover>}}
```shell {label="comp3Sec",copy-lines="1"}
kubectl describe secret -n other-namespace
Name: b0dc71f8-2688-4ebc-818a-bbad6a2c4f9a
Namespace: other-namespace
Type: connection.crossplane.io/v1alpha1
Data
====
username: 20 bytes
key2-user: 20 bytes
# Removed for brevity.
```
## Connection secrets in Composite Resource Definitions
The CompositeResourceDefinition (`XRD`), can restrict which secrets keys are
put in the combined secret and provided to a Claim.
By default an XRD writes all secret keys listed in the composed resource
`connectionDetails` to the combined secret object.
Limit the keys passed to the combined secret object and Claims with a
{{<hover label="xrd" line="4">}}connectionSecretKeys{{</hover>}} object.
Inside the {{<hover label="xrd" line="4">}}connectionSecretKeys{{</hover>}} list
the secret key names to create. Crossplane only adds the keys listed to the
combined secret.
{{<hint "warning">}}
You can't change the
{{<hover label="xrd" line="4">}}connectionSecretKeys{{</hover>}} of an XRD.
You must delete and
recreate the XRD to change the
{{<hover label="xrd" line="4">}}connectionSecretKeys{{</hover>}}.
{{</hint >}}
For example, an XRD may restrict the secrets to only the
{{<hover label="xrd" line="5">}}username{{</hover>}},
{{<hover label="xrd" line="6">}}password{{</hover>}} and custom named
{{<hover label="xrd" line="7">}}key2-user{{</hover>}} keys.
```yaml {label="xrd",copy-lines="4-12"}
kind: CompositeResourceDefinition
spec:
# Removed for brevity.
connectionSecretKeys:
- username
- password
- key2-user
```
The secret from an individual resource contains all the resources detailed in
the Composition's `connectionDetails`.
```shell {label="xrdSec",copy-lines="1"}
kubectl describe secret key1 -n docs
Name: key1
Namespace: docs
Data
====
password: 40 bytes
username: 20 bytes
attribute.secret: 40 bytes
attribute.ses_smtp_password_v4: 44 bytes
```
The Claim's secret only contains the
keys allowed by the XRD
{{<hover label="xrd" line="4">}}connectionSecretKeys{{</hover>}}
fields.
```shell {label="xrdSec2",copy-lines="2"}
kubectl describe secret my-access-key-secret
Name: my-access-key-secret
Data
====
key2-user: 20 bytes
password: 40 bytes
username: 20 bytes
```
## Secret objects
Compositions create a secret object for each resource and an extra secret
containing all the secrets from all resources.
Crossplane saves the resource secret objects in the location defined by the
resource's
{{<hover label="comp4" line="11">}}writeConnectionSecretToRef{{</hover>}}.
Crossplane saves the combined secret with a Crossplane generated name in the
namespace defined in the Composition's
{{<hover label="comp4" line="4">}}writeConnectionSecretsToNamespace{{</hover>}}.
```yaml {label="comp4",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
spec:
writeConnectionSecretsToNamespace: other-namespace
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: key
base:
kind: AccessKey
spec:
# Removed for brevity
writeConnectionSecretToRef:
namespace: docs
name: key1
connectionDetails:
- name: user
type: FromConnectionSecretKey
fromConnectionSecretKey: username
- name: key2
base:
kind: AccessKey
spec:
# Removed for brevity
writeConnectionSecretToRef:
namespace: docs
name: key2
connectionDetails:
- name: key2-user
type: FromConnectionSecretKey
fromConnectionSecretKey: username
```
If a Claim uses a secret, it's stored in the same namespace as the Claim with
the name defined in the Claim's
{{<hover label="claim3" line="7">}}writeConnectionSecretToRef{{</hover>}}.
```yaml {label="claim3",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: SecretTest
metadata:
name: test-secrets
namespace: default
spec:
writeConnectionSecretToRef:
name: my-access-key-secret
```
After applying the Claim Crossplane creates the following secrets:
* The Claim's secret, {{<hover label="allSec" line="3">}}my-access-key-secret{{</hover>}}
in the Claim's {{<hover label="claim3" line="5">}}namespace{{</hover>}}.
* The first resource's secret object, {{<hover label="allSec" line="4">}}key1{{</hover>}}.
* The second resource's secret object, {{<hover label="allSec" line="5">}}key2{{</hover>}}.
* The composite resource secret object in the
{{<hover label="allSec" line="6">}}other-namespace{{</hover>}} defined by the
Composition's `writeConnectionSecretsToNamespace`.
```shell {label="allSec",copy-lines="none"}
kubectl get secret -A
NAMESPACE NAME TYPE DATA AGE
default my-access-key-secret connection.crossplane.io/v1alpha1 8 29m
docs key1 connection.crossplane.io/v1alpha1 4 31m
docs key2 connection.crossplane.io/v1alpha1 4 31m
other-namespace b0dc71f8-2688-4ebc-818a-bbad6a2c4f9a connection.crossplane.io/v1alpha1 8 31m
```

View File

@ -0,0 +1,414 @@
---
title: Environment Configurations
weight: 75
state: alpha
alphaVersion: "1.11"
description: "Environment Configurations or EnvironmentConfigs are an in-memory datastore used in Compositions"
---
<!--
TODO: Add Policies
-->
A Crossplane EnvironmentConfig is a cluster scoped
[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.
{{<hint "important" >}}
The in-memory environment is unique to each composite resource.
A composite resource can't read data in another composite resource's
environment.
{{< /hint >}}
## Enable EnvironmentConfigs
EnvironmentConfigs are an alpha feature. Alpha features aren't enabled by
default.
Enable EnvironmentConfig support by
[changing the Crossplane pod setting]({{<ref "./pods#change-pod-settings">}})
and enabling
{{<hover label="deployment" line="12">}}--enable-environment-configs{{</hover>}}
argument.
```yaml {label="deployment",copy-lines="12"}
$ kubectl edit deployment crossplane --namespace crossplane-system
apiVersion: apps/v1
kind: Deployment
spec:
# Removed for brevity
template:
spec:
containers:
- args:
- core
- start
- --enable-environment-configs
```
{{<hint "tip" >}}
The [Crossplane install guide]({{<ref "../software/install#feature-flags">}})
describes enabling feature flags like
{{<hover label="deployment" line="12">}}--enable-environment-configs{{</hover>}}
with Helm.
{{< /hint >}}
<!-- vale Google.Headings = NO -->
## Create an EnvironmentConfig
<!-- vale Google.Headings = YES -->
An {{<hover label="env1" line="2">}}EnvironmentConfig{{</hover>}} has a single
object field,
{{<hover label="env1" line="5">}}data{{</hover>}}.
An EnvironmentConfig supports any data inside the
{{<hover label="env1" line="5">}}data{{</hover>}} field.
Here an example
{{<hover label="env1" line="2">}}EnvironmentConfig{{</hover>}}.
```yaml {label="env1"}
apiVersion: apiextensions.crossplane.io/v1alpha1
kind: EnvironmentConfig
metadata:
name: example-environment
data:
locations:
us: us-east-2
eu: eu-north-1
key1: value1
key2: value2
key3:
- item1
- item2
```
<!-- vale Google.Headings = NO -->
## Select an EnvironmentConfig
<!-- vale Google.Headings = YES -->
Select the EnvironmentConfigs to use
inside a Composition's
{{<hover label="comp" line="6">}}environment{{</hover>}} field.
The {{<hover label="comp" line="7">}}environmentConfigs{{</hover>}} field is a
list of environments this Composition can use.
Select an environment by
{{<hover label="comp" line="8">}}Reference{{</hover>}} or
by
{{<hover label="comp" line="11">}}Selector{{</hover>}}.
A
{{<hover label="comp" line="8">}}Reference{{</hover>}}
selects an environment by
{{<hover label="comp" line="10">}}name{{</hover>}}.
The
{{<hover label="comp" line="11">}}Selector{{</hover>}} selects an environment
based on the
{{<hover label="comp" line="13">}}Labels{{</hover>}} applied to the environment.
```yaml {label="comp",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example-composition
spec:
environment:
environmentConfigs:
- type: Reference
ref:
name: example-environment
- type: Selector
selector:
matchLabels:
# Removed for brevity
```
If a Composition uses multiple
{{<hover label="comp" line="7">}}environmentConfigs{{</hover>}}
Crossplane merges them together in the order they're listed.
{{<hint "note" >}}
If multiple
{{<hover label="comp" line="7">}}environmentConfigs{{</hover>}}
use the same key, the Composition uses the value of the last environment listed.
{{</hint >}}
### Select by name
Select an environment by name with
{{<hover label="byName" line="8">}}type: Reference{{</hover>}}.
Define the
{{<hover label="byName" line="9">}}ref{{</hover>}} object and the
{{<hover label="byName" line="10">}}name{{</hover>}} matching the exact name of
the environment.
For example, select the
{{<hover label="byName" line="7">}}environmentConfig{{</hover>}}
named
{{<hover label="byName" line="10">}}example-environment{{</hover>}}
```yaml {label="byName",copy-lines="all"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example-composition
spec:
environment:
environmentConfigs:
- type: Reference
ref:
name: example-environment
```
### Select by label
Select an environment by labels with a
{{<hover label="byLabel" line="8">}}type: Selector{{</hover>}}.
Define the {{<hover label="byLabel" line="9">}}selector{{</hover>}} object.
The
{{<hover label="byLabel" line="10">}}matchLabels{{</hover>}} object contains a
list of labels to match on.
Selecting a label requires matching both the label
{{<hover label="byLabel" line="11">}}key{{</hover>}}
and the value of key.
When matching the label's value, provide an exact value with a
{{<hover label="byLabel" line="12">}}type: Value{{</hover>}} and provide the value
to match in the
{{<hover label="byLabel" line="13">}}value{{</hover>}} field.
Crossplane can also match a label's value based on an input in the composite
resource. Use
{{<hover label="byLabel" line="15">}}type: FromCompositeFieldPath{{</hover>}}
and provide the field to match in the
{{<hover label="byLabel" line="16">}}valueFromFieldPath{{</hover>}} field.
```yaml {label="byLabel",copy-lines="all"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example-composition
spec:
environment:
environmentConfigs:
- type: Selector
selector:
matchLabels:
- key: my-label-key
type: Value
value: my-label-value
- key: my-label-key
type: FromCompositeFieldPath
valueFromFieldPath: spec.parameters.deploy
# Removed for brevity
```
#### Manage selector results
Selecting environments by labels may return more than one environment.
The Composition sorts all the results by the name of the environments and
only uses the first environment in the sorted list.
Set the {{<hover label="selectResults" line="10">}}mode{{</hover>}} as
{{<hover label="selectResults" line="10">}}mode: Multiple{{</hover>}} to return
all matched environments. Use
{{<hover label="selectResults" line="19">}}mode: Single{{</hover>}} to
return a single environment.
{{<hint "note" >}}
Sorting and the selection
{{<hover label="selectResults" line="10">}}mode{{</hover>}}
only applies to a single
{{<hover label="selectResults" line="8">}}type: Selector{{</hover>}}.
This doesn't change how Compositions merge multiple
{{<hover label="selectResults" line="7">}}environmentConfigs{{</hover>}}.
{{< /hint >}}
```yaml {label="selectResults"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example-composition
spec:
environment:
environmentConfigs:
- type: Selector
selector:
mode: Multiple
matchLabels:
- key: my-label-key
type: Value
value: my-label-value
- key: my-label-key
type: FromCompositeFieldPath
valueFromFieldPath: spec.parameters.deploy
- type: Selector
selector:
mode: Single
matchLabels:
- key: my-other-label-key
type: Value
value: my-other-label-value
- key: my-other-label-key
type: FromCompositeFieldPath
valueFromFieldPath: spec.parameters.deploy
```
When using
{{<hover label="maxMatch" line="10">}}mode: Multiple{{</hover>}} limit the
number of returned environments with
{{<hover label="maxMatch" line="11">}}maxMatch{{</hover>}} and define the
maximum number of environments returned.
Use `minMatch` and define the minimum
number of environments returned.
The Composition sorts the returned environments alphabetically by name. Sort the
environments on a different field with
{{<hover label="maxMatch" line="12">}}sortByFieldPath{{</hover>}} and define
the field to sort by.
```yaml {label="maxMatch"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example-composition
spec:
environment:
environmentConfigs:
- type: Selector
selector:
mode: Multiple
maxMatch: 4
sortByFieldPath: metadata.annotations[sort.by/weight]
matchLabels:
- key: my-label-key
type: Value
value: my-label-value
- key: my-label-key
type: FromCompositeFieldPath
valueFromFieldPath: spec.parameters.deploy
```
The environments selected by
{{<hover label="maxMatch" line="18">}}matchLabels{{</hover>}} are then merged
into any other environments listed in the
{{<hover label="maxMatch" line="7">}}environmentConfigs{{</hover>}}.
#### Optional selector labels
By default, Crossplane issues an error if a
{{<hover label="byLabelOptional" line="16">}}valueFromFieldPath{{</hover>}}
field doesn't exist in the composite resource.
Add
{{<hover label="byLabelOptional" line="17">}}fromFieldPathPolicy{{</hover>}}
as {{<hover label="byLabelOptional" line="17">}}Optional{{</hover>}}
to ignore a field if it doesn't exist.
```yaml {label="byLabelOptional",copy-lines="all"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example-composition
spec:
environment:
environmentConfigs:
- type: Selector
selector:
matchLabels:
- key: my-first-label-key
type: Value
value: my-first-label-value
- key: my-second-label-key
type: FromCompositeFieldPath
valueFromFieldPath: spec.parameters.deploy
fromFieldPathPolicy: Optional
# Removed for brevity
```
Set a default value for an optional label by setting the default
{{<hover label="byLabelOptionalDefault" line="15">}}value{{</hover>}} for the
{{<hover label="byLabelOptionalDefault" line="14">}}key{{</hover>}} first, then
define the
{{<hover label="byLabelOptionalDefault" line="20">}}Optional{{</hover>}} label.
For example, this Composition defines
{{<hover label="byLabelOptionalDefault" line="16">}}value: my-default-value{{</hover>}}
for the key {{<hover label="byLabelOptionalDefault" line="14">}}my-second-label-key{{</hover>}}.
If the label
{{<hover label="byLabelOptionalDefault" line="17">}}my-second-label-key{{</hover>}}
exists, Crossplane uses the value from the label instead.
```yaml {label="byLabelOptionalDefault",copy-lines="all"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example-composition
spec:
environment:
environmentConfigs:
- type: Selector
selector:
matchLabels:
- key: my-first-label-key
type: Value
value: my-label-value
- key: my-second-label-key
type: Value
value: my-default-value
- key: my-second-label-key
type: FromCompositeFieldPath
valueFromFieldPath: spec.parameters.deploy
fromFieldPathPolicy: Optional
# Removed for brevity
```
{{<hint "warning" >}}
Crossplane 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.
{{< /hint >}}
## Use EnvironmentConfigs in a Composition
When Crossplane creates or updates a composite resource, it merges all the
specified EnvironmentConfigs into an in-memory environment.
Crossplane sends the merged, in-memory environment to the composition function
pipeline using the
[pipeline context]({{<ref "./compositions#function-pipeline-context">}}).
It writes the environment to the `apiextensions.crossplane.io/environment`
context key.
Some composition functions can read the environment from the pipeline context
and use it to compose resources.
{{<hint "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]({{<ref "../guides/function-patch-and-transform">}}).
{{< /hint >}}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,470 @@
---
title: Configuration Packages
description: "Packages combine multiple Crossplane resources into a single, portable, OCI image."
altTitle: "Crossplane Packages"
weight: 200
---
A _Configuration_ package is an
[OCI container images](https://opencontainers.org/) containing a collection of
[Compositions]({{<ref "./compositions" >}}),
[Composite Resource Definitions]({{<ref "./composite-resource-definitions" >}})
and any required [Providers]({{<ref "./providers">}}) or
[Functions]({{<ref "./compositions" >}}).
Configuration packages make your Crossplane configuration fully portable.
{{<hint "important" >}}
Crossplane [Providers]({{<ref "./providers">}}) and
[Functions]({{<ref "./compositions">}}) are also Crossplane packages.
This document describes how to install and manage configuration packages.
Refer to the
[Provider]({{<ref "./providers">}}) and
[Composition Functions]({{<ref "./compositions">}}) chapters for
details on their usage of packages.
{{< /hint >}}
## Install a Configuration
Install a Configuration with a Crossplane
{{<hover line="2" label="install">}}Configuration{{</hover>}} object by setting
the {{<hover line="6" label="install">}}spec.package{{</hover>}} value to the
location of the configuration package.
{{< hint "important" >}}
Beginning with Crossplane version 1.15.0 Crossplane uses the Upbound Marketplace
Crossplane package registry at `xpkg.upbound.io` by default for downloading and
installing packages.
Specify the full domain name with the `package` or change the default Crossplane
registry with the `--registry` flag on the [Crossplane pod]({{<ref "./pods">}})
{{< /hint >}}
For example to install the
[Upbound AWS reference platform](https://marketplace.upbound.io/configurations/upbound/platform-ref-aws/v0.6.0),
```yaml {label="install"}
apiVersion: pkg.crossplane.io/v1
kind: Configuration
metadata:
name: platform-ref-aws
spec:
package: xpkg.upbound.io/upbound/platform-ref-aws:v0.6.0
```
Crossplane installs the Compositions, Composite Resource Definitions and
Providers listed in the Configuration.
### Install with Helm
Crossplane supports installing Configurations during an initial Crossplane
installation with the Crossplane Helm chart.
Use the
{{<hover label="helm" line="5" >}}--set configuration.packages{{</hover >}}
argument with `helm install`.
For example, to install the Upbound AWS reference platform,
```shell {label="helm"}
helm install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace \
--set configuration.packages='{xpkg.upbound.io/upbound/platform-ref-aws:v0.6.0}'
```
### Install offline
Installing Crossplane packages offline requires a local container registry like
[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
Configurations support multiple options to change configuration package related
settings.
#### Configuration revisions
When installing a newer version of an existing Configuration Crossplane creates
a new configuration revision.
View the configuration revisions with
{{<hover label="rev" line="1">}}kubectl get configurationrevisions{{</hover>}}.
```shell {label="rev",copy-lines="1"}
kubectl get configurationrevisions
NAME HEALTHY REVISION IMAGE STATE DEP-FOUND DEP-INSTALLED AGE
platform-ref-aws-1735d56cd88d True 2 xpkg.upbound.io/upbound/platform-ref-aws:v0.5.0 Active 2 2 46s
platform-ref-aws-3ac761211893 True 1 xpkg.upbound.io/upbound/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
{{<hover label="revHistory" line="6">}}revisionHistoryLimit{{</hover>}}.
The {{<hover label="revHistory" line="6">}}revisionHistoryLimit{{</hover>}}
field is an integer.
The default value is `1`.
Disable storing revisions by setting
{{<hover label="revHistory" line="6">}}revisionHistoryLimit{{</hover>}} to `0`.
For example, to change the default setting and store 10 revisions use
{{<hover label="revHistory" line="6">}}revisionHistoryLimit: 10{{</hover>}}.
```yaml {label="revHistory"}
apiVersion: pkg.crossplane.io/v1
kind: Configuration
metadata:
name: platform-ref-aws
spec:
revisionHistoryLimit: 10
# Removed for brevity
```
#### Configuration package pull policy
Use a {{<hover label="pullpolicy" line="6">}}packagePullPolicy{{</hover>}} 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.
{{<hint "tip" >}}
The Crossplane
{{<hover label="pullpolicy" line="6">}}packagePullPolicy{{</hover>}} 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.
{{< /hint >}}
For example, to `Always` download a given Configuration package use the
{{<hover label="pullpolicy" line="6">}}packagePullPolicy: Always{{</hover>}}
configuration.
```yaml {label="pullpolicy",copy-lines="6"}
apiVersion: pkg.crossplane.io/v1
kind: Configuration
metadata:
name: platform-ref-aws
spec:
packagePullPolicy: Always
# Removed for brevity
```
#### 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
{{<hover label="revision" line="6">}}revisionActivationPolicy{{</hover>}}.
The {{<hover label="revision" line="6">}}revisionActivationPolicy{{</hover>}}
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
{{<hover label="revision" line="6">}}revisionActivationPolicy: Manual{{</hover>}}.
```yaml {label="revision"}
apiVersion: pkg.crossplane.io/v1
kind: Configuration
metadata:
name: platform-ref-aws
spec:
revisionActivationPolicy: Manual
# Removed for brevity
```
#### 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 {{<hover label="pps" line="6">}}packagePullSecrets{{</hover>}} to provide a
Kubernetes secret to use for authentication when downloading a Configuration
package.
{{<hint "important" >}}
The Kubernetes secret must be in the same namespace as Crossplane.
{{</hint >}}
The {{<hover label="pps" line="6">}}packagePullSecrets{{</hover>}} is a list of
secrets.
For example, to use the secret named
{{<hover label="pps" line="6">}}example-secret{{</hover>}} configure a
{{<hover label="pps" line="6">}}packagePullSecrets{{</hover>}}.
```yaml {label="pps"}
apiVersion: pkg.crossplane.io/v1
kind: Configuration
metadata:
name: platform-ref-aws
spec:
packagePullSecrets:
- name: example-secret
# Removed for brevity
```
#### Ignore dependencies
By default Crossplane installs any [dependencies](#manage-dependencies) listed
in a Configuration package.
Crossplane can ignore a Configuration package's dependencies with
{{<hover label="pkgDep" line="6" >}}skipDependencyResolution{{</hover>}}.
{{< hint "warning" >}}
Most Configurations include dependencies for the required Providers.
If a Configuration ignores dependencies, the required Providers must be
manually installed.
{{< /hint >}}
For example, to disable dependency resolution configure
{{<hover label="pkgDep" line="6" >}}skipDependencyResolution: true{{</hover>}}.
```yaml {label="pkgDep"}
apiVersion: pkg.crossplane.io/v1
kind: Configuration
metadata:
name: platform-ref-aws
spec:
skipDependencyResolution: true
# Removed for brevity
```
#### 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
{{<hover label="xpVer" line="6">}}ignoreCrossplaneConstraints{{</hover>}}.
For example, to install a Configuration package into an unsupported Crossplane
version, configure
{{<hover label="xpVer" line="6">}}ignoreCrossplaneConstraints: true{{</hover>}}.
```yaml {label="xpVer"}
apiVersion: pkg.crossplane.io/v1
kind: Configuration
metadata:
name: platform-ref-aws
spec:
ignoreCrossplaneConstraints: true
# Removed for brevity
```
### Verify a Configuration
Verify a Configuration with
{{<hover label="verify" line="1">}}kubectl get configuration{{</hover >}}.
A working configuration reports `Installed` and `Healthy` as `True`.
```shell {label="verify",copy-lines="1"}
kubectl get configuration
NAME INSTALLED HEALTHY PACKAGE AGE
platform-ref-aws True True xpkg.upbound.io/upbound/platform-ref-aws:v0.6.0 54s
```
### 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 Upbound AWS reference platform is
`HEALTHY: False`.
```shell {copy-lines="1"}
kubectl get configuration
NAME INSTALLED HEALTHY PACKAGE AGE
platform-ref-aws True False xpkg.upbound.io/upbound/platform-ref-aws:v0.6.0 71s
```
To see more information on why the Configuration isn't `HEALTHY` use
{{<hover label="depend" line="1">}}kubectl describe configurationrevisions{{</hover>}}.
```yaml {copy-lines="1",label="depend"}
kubectl describe configurationrevision
Name: platform-ref-aws-a30ad655c769
API Version: pkg.crossplane.io/v1
Kind: ConfigurationRevision
# Removed for brevity
Spec:
Desired State: Active
Image: xpkg.upbound.io/upbound/platform-ref-aws:v0.6.0
Revision: 1
Status:
Conditions:
Last Transition Time: 2023-10-06T20:08:14Z
Reason: UnhealthyPackageRevision
Status: False
Type: Healthy
Controller Ref:
Name:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning LintPackage 29s (x2 over 29s) packages/configurationrevision.pkg.crossplane.io incompatible Crossplane version: package is not compatible with Crossplane version (v1.12.0)
```
The {{<hover label="depend" line="18">}}Events{{</hover>}} show a
{{<hover label="depend" line="21">}}Warning{{</hover>}} with a message that the
current version of Crossplane doesn't meet the Configuration package
requirements.
## Create a Configuration
Crossplane Configuration packages are
[OCI container images](https://opencontainers.org/) containing one or more YAML
files.
{{<hint "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/master/contributing/specifications/xpkg.md)
for package requirements when building packages with third-party tools.
{{</hint >}}
A Configuration package requires a `crossplane.yaml` file and may include
Composition and CompositeResourceDefinition files.
<!-- vale Google.Headings = NO -->
### The crossplane.yaml file
<!-- vale Google.Headings = YES -->
To build a Configuration package using the Crossplane CLI, create a file
named
{{<hover label="cfgMeta" line="1">}}crossplane.yaml{{</hover>}}.
The
{{<hover label="cfgMeta" line="1">}}crossplane.yaml{{</hover>}}
file defines the requirements and name of the
Configuration.
{{<hint "important" >}}
The Crossplane CLI only supports a file named `crossplane.yaml`.
{{< /hint >}}
Configuration package uses the
{{<hover label="cfgMeta" line="2">}}meta.pkg.crossplane.io{{</hover>}}
Crossplane API group.
Specify any other Configurations, Functions or Providers in the
{{<hover label="cfgMeta" line="7">}}dependsOn{{</hover>}} list.
Optionally, you can require a specific or minimum package version with the
{{<hover label="cfgMeta" line="9">}}version{{</hover>}} option.
You can also define a specific or minimum version of Crossplane for this
Configuration with the
{{<hover label="cfgMeta" line="11">}}crossplane.version{{</hover>}} option.
{{<hint "note" >}}
Defining the {{<hover label="cfgMeta" line="10">}}crossplane{{</hover>}} object
or required versions is optional.
{{< /hint >}}
```yaml {label="cfgMeta",copy-lines="all"}
$ cat crossplane.yaml
apiVersion: meta.pkg.crossplane.io/v1alpha1
kind: Configuration
metadata:
name: test-configuration
spec:
dependsOn:
- provider: xpkg.upbound.io/crossplane-contrib/provider-aws
version: ">=v0.36.0"
crossplane:
version: ">=v1.12.1-0"
```
### Build the package
Create the package using the
[Crossplane CLI]({{<ref "../cli">}}) command
`crossplane xpkg build --package-root=<directory>`.
Where the `<directory>` 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.
{{<hint "important" >}}
You must ignore any other YAML files with `--ignore=<file_list>`.
For
example, `crossplane xpkg build --package-root=test-directory --ignore=".tmp/*"`.
Including YAML files that aren't Compositions or CompositeResourceDefinitions,
including Claims isn't supported.
{{</hint >}}
By default, Crossplane creates an `.xpkg` file of the Configuration name and
a SHA-256 hash of the package contents.
For example, a {{<hover label="xpkgName" line="2">}}Configuration{{</hover>}}
named {{<hover label="xpkgName" line="4">}}test-configuration{{</hover>}}.
The
Crossplane CLI builds a package named `test-configuration-e8c244f6bf21.xpkg`.
```yaml {label="xpkgName"}
apiVersion: meta.pkg.crossplane.io/v1alpha1
kind: Configuration
metadata:
name: test-configuration
# Removed for brevity
```
Specify the output file with `--package-file=<filename>.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:
```shell
crossplane xpkg build --package-root=test-directory --package-file=test-package.xpkg
```
```shell
ls -1 ./
test-directory
test-package.xpkg
```

View File

@ -0,0 +1,407 @@
---
title: Crossplane Pods
weight: 1
description: Background on the components installed with Crossplane and their functions.
---
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
### 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.
{{<hint "tip" >}}
The Kubernetes documentation contains more information about
[init containers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/).
{{< /hint >}}
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
* StoreConfigs for connecting external secret stores like
[HashiCorp Vault](https://www.vaultproject.io/)
{{< hint "note" >}}
The [Install Crossplane]({{< ref "../software/install" >}}) section has more
information about customizing the Crossplane install.
{{< /hint >}}
The status `Init` on the Crossplane pod is the init container running.
```shell
kubectl get pods -n crossplane-system
NAME READY STATUS RESTARTS AGE
crossplane-9f6d5cd7b-r9j8w 0/1 Init:0/1 0 6s
```
The init container completes and starts the Crossplane core container
automatically.
```shell
kubectl get pods -n crossplane-system
NAME READY STATUS RESTARTS AGE
crossplane-9f6d5cd7b-r9j8w 1/1 Running 0 15s
```
### Core container
The main Crossplane container, called the _core_ container, enforces
the desired state of Crossplane resources, manages leader elections and process
webhooks.
{{<hint "note" >}}
The Crossplane pod only reconciles core Crossplane components, including Claims
and composite resources. Providers are responsible for reconciling their managed
resources.
{{< /hint >}}
#### 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.
<!-- vale write-good.TooWordy = NO -->
<!-- allow "maximum" -->
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.
<!-- vale write-good.TooWordy = YES -->
Managed resources use polling.
{{< hint "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.
{{< /hint >}}
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.
{{< hint "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.
{{< /hint >}}
##### 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`.
{{<hint "important" >}}
Real time compositions are an alpha feature. Alpha features aren't enabled by
default.
{{< /hint >}}
With real time compositions enabled, Crossplane doesn't use the `--poll-interval`
settings.
Enable real time compositions support by
[changing the Crossplane pod setting]({{<ref "./pods#change-pod-settings">}})
and enabling
{{<hover label="deployment" line="12">}}--enable-realtime-compositions{{</hover>}}
argument.
```yaml {label="deployment",copy-lines="12"}
$ kubectl edit deployment crossplane --namespace crossplane-system
apiVersion: apps/v1
kind: Deployment
spec:
# Removed for brevity
template:
spec:
containers:
- args:
- core
- start
- --enable-realtime-compositions
```
{{<hint "tip" >}}
The [Crossplane install guide]({{<ref "../software/install#feature-flags">}})
describes enabling feature flags like
{{<hover label="deployment" line="12">}}--enable-realtime-compositions{{</hover>}}
with Helm.
{{< /hint >}}
##### 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
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]({{<ref "#change-pod-settings">}}) section for
instructions on applying these settings.
<!-- vale Microsoft.HeadingAcronyms = NO -->
<!-- allow 'RBAC' since that's the name -->
## RBAC manager pod
<!-- vale Microsoft.HeadingAcronyms = YES -->
The Crossplane RBAC manager pod automates required Kubernetes RBAC permissions
for Crossplane and Crossplane Providers.
{{<hint "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/master/design/design-doc-rbac-manager.md)
provides more comprehensive details on the Crossplane RBAC requirements.
{{< /hint >}}
### 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`.
{{< hint "note" >}}
Instructions for changing Crossplane pod settings during installation are in the
[Crossplane Install]({{<ref "../software/install">}}) section.
{{< /hint >}}
<!-- vale Microsoft.HeadingAcronyms = NO -->
<!-- allow 'RBAC' since that's the name -->
### RBAC init container
<!-- vale Microsoft.HeadingAcronyms = YES -->
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
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]({{<ref "#crossplane-clusterroles">}}) to grant access to all Crossplane resources in the
cluster.
#### Crossplane ClusterRoles
The RBAC manager creates four Kubernetes ClusterRoles. These Roles grant
permissions over cluster wide Crossplane resources.
<!-- vale Google.Headings = NO -->
<!-- disable heading checking for the role names -->
<!-- vale Google.WordList = NO -->
<!-- allow "admin" -->
##### crossplane-admin
<!-- vale Google.WordList = YES -->
<!-- vale Crossplane.Spelling = NO -->
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.
<!-- vale Crossplane.Spelling = YES -->
View the full RBAC policy with
```shell
kubectl describe clusterrole crossplane-admin
```
##### 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
```shell
kubectl describe clusterrole crossplane-edit
```
##### 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
```shell
kubectl describe clusterrole crossplane-view
```
##### crossplane-browse
The `crossplane-browse` ClusterRole has the following permissions:
* read-only access to Crossplane compositions and XRDs. This allows resource claim
creators to discover and select an appropriate composition.
View the full RBAC policy with
```shell
kubectl describe clusterrole crossplane-browse
```
## 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.
{{< hint "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.
{{< /hint >}}
Both the Crossplane pod and the RBAC manager pods support leader elections.
Enable leader elections with the `--leader-election` pod argument.
{{< hint "warning" >}}
<!-- vale write-good.TooWordy = NO -->
<!-- "multiple" -->
<!-- vale write-good.Passive = NO -->
<!-- allow "is unsupported" -->
Running multiple Crossplane pods without leader election is unsupported.
<!-- vale write-good.Passive = YES -->
<!-- vale write-good.TooWordy = YES -->
{{< /hint >}}
## 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]({{<ref "../software/install#customize-the-crossplane-helm-chart">}})
and
[feature flags]({{<ref "../software/install#customize-the-crossplane-helm-chart">}})
are available in the
[Crossplane Install]({{<ref "../software/install">}})
section.
{{< hint "note" >}}
Instructions for changing Crossplane pod settings during installation are in the
[Crossplane Install]({{<ref "../software/install">}}) section.
{{< /hint >}}
### Edit the deployment
{{< hint "note" >}}
These settings apply to both the `crossplane` and `rbac-manager` pods and
`Deployments`.
{{< /hint >}}
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`
{{< hint "warning" >}}
Updating the Crossplane deployment restarts the Crossplane pod.
{{< /hint >}}
Add Crossplane pod arguments to the
{{<hover label="args" line="9" >}}spec.template.spec.containers[].args{{< /hover >}}
section of the deployment.
For example, to change the `sync-interval` add
{{<hover label="args" line="12" >}}--sync-interval=30m{{< /hover >}}.
```yaml {label="args", copy-lines="1"}
kubectl edit deployment crossplane --namespace crossplane-system
apiVersion: apps/v1
kind: Deployment
spec:
# Removed for brevity
template:
spec:
containers:
- args:
- core
- start
- --sync-interval=30m
```
### 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]({{<ref "../software/install">}}) section.

View File

@ -0,0 +1,884 @@
---
title: Providers
weight: 5
description: "Providers connect Crossplane to external APIs"
---
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/upbound/provider-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)
{{< hint "tip" >}}
Find more providers in the [Upbound Marketplace](https://marketplace.upbound.io).
{{< /hint >}}
<!-- vale write-good.Passive = NO -->
<!-- "are Managed" isn't passive in this context -->
Providers define every external resource they can create in Kubernetes as a
Kubernetes API endpoint.
These endpoints are
[_Managed Resources_]({{<ref "managed-resources" >}}).
<!-- vale write-good.Passive = YES -->
## 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
{{<hover label="install" line="2">}}Provider{{</hover >}} object setting the
{{<hover label="install" line="6">}}spec.package{{</hover >}} value to the
location of the provider package.
{{< hint "important" >}}
Beginning with Crossplane version 1.15.0 Crossplane uses the Upbound Marketplace
Crossplane package registry at `xpkg.upbound.io` by default for downloading and
installing packages.
Specify the full domain name with the `package` or change the default Crossplane
registry with the `--registry` flag on the [Crossplane pod]({{<ref "./pods">}})
{{< /hint >}}
For example, to install the
[AWS Community Provider](https://github.com/crossplane-contrib/provider-aws),
```yaml {label="install"}
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws
spec:
package: xpkg.upbound.io/crossplane-contrib/provider-aws:v0.39.0
```
By default, the Provider pod installs in the same namespace as Crossplane
(`crossplane-system`).
{{<hint "note" >}}
Providers are part of the
{{<hover label="install" line="1">}}pkg.crossplane.io{{</hover>}} group.
The {{<hover label="meta-pkg" line="1">}}meta.pkg.crossplane.io{{</hover>}}
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/master/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/master/contributing/specifications/xpkg.md#provider-package-requirements).
```yaml {label="meta-pkg"}
apiVersion: meta.pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws
spec:
# Removed for brevity
```
{{</hint >}}
### Install with Helm
Crossplane supports installing Providers during an initial Crossplane
installation with the Crossplane Helm chart.
Use the
{{<hover label="helm" line="5" >}}--set provider.packages{{</hover >}}
argument with `helm install`.
For example, to install the AWS Community Provider,
```shell {label="helm"}
helm install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace \
--set provider.packages='{xpkg.upbound.io/crossplane-contrib/provider-aws:v0.39.0}'
```
### 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
Providers support multiple configuration options to change installation related
settings.
#### Provider pull policy
Use a {{<hover label="pullpolicy" line="6">}}packagePullPolicy{{</hover>}} 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.
{{<hint "tip" >}}
The Crossplane
{{<hover label="pullpolicy" line="6">}}packagePullPolicy{{</hover>}} 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.
{{< /hint >}}
For example, to `Always` download a given Provider package use the
{{<hover label="pullpolicy" line="6">}}packagePullPolicy: Always{{</hover>}}
configuration.
```yaml {label="pullpolicy",copy-lines="6"}
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws
spec:
packagePullPolicy: Always
# Removed for brevity
```
#### 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
{{<hover label="revision" line="6">}}revisionActivationPolicy{{</hover>}}.
The {{<hover label="revision" line="6">}}revisionActivationPolicy{{</hover>}}
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
{{<hover label="revision" line="6">}}revisionActivationPolicy: Manual{{</hover>}}.
```yaml {label="revision"}
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws
spec:
revisionActivationPolicy: Manual
# Removed for brevity
```
#### 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.
{{<hint "note" >}}
Read the [Provider upgrade](#upgrade-a-provider) section for
more information on the use of package revisions.
{{< /hint >}}
Change the number of revisions Crossplane maintains with a Provider Package
{{<hover label="revHistoryLimit" line="6">}}revisionHistoryLimit{{</hover>}}.
The {{<hover label="revHistoryLimit" line="6">}}revisionHistoryLimit{{</hover>}}
field is an integer.
The default value is `1`.
Disable storing revisions by setting
{{<hover label="revHistoryLimit" line="6">}}revisionHistoryLimit{{</hover>}} to `0`.
For example, to change the default setting and store 10 revisions use
{{<hover label="revHistoryLimit" line="6">}}revisionHistoryLimit: 10{{</hover>}}.
```yaml {label="revHistoryLimit"}
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws
spec:
revisionHistoryLimit: 10
# Removed for brevity
```
#### 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 {{<hover label="pps" line="6">}}packagePullSecrets{{</hover>}} to provide a
Kubernetes secret to use for authentication when downloading a Provider package.
{{<hint "important" >}}
The Kubernetes secret must be in the same namespace as Crossplane.
{{</hint >}}
The {{<hover label="pps" line="6">}}packagePullSecrets{{</hover>}} is a list of
secrets.
For example, to use the secret named
{{<hover label="pps" line="6">}}example-secret{{</hover>}} configure a
{{<hover label="pps" line="6">}}packagePullSecrets{{</hover>}}.
```yaml {label="pps"}
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws
spec:
packagePullSecrets:
- name: example-secret
# Removed for brevity
```
{{<hint "note" >}}
Configured `packagePullSecrets` aren't passed to any Provider package
dependencies.
{{< /hint >}}
#### Ignore dependencies
By default Crossplane installs any [dependencies](#manage-dependencies) listed
in a Provider package.
Crossplane can ignore a Provider package's dependencies with
{{<hover label="pkgDep" line="6" >}}skipDependencyResolution{{</hover>}}.
For example, to disable dependency resolution configure
{{<hover label="pkgDep" line="6" >}}skipDependencyResolution: true{{</hover>}}.
```yaml {label="pkgDep"}
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws
spec:
skipDependencyResolution: true
# Removed for brevity
```
#### 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
{{<hover label="xpVer" line="6">}}ignoreCrossplaneConstraints{{</hover>}}.
For example, to install a Provider package into an unsupported Crossplane
version, configure
{{<hover label="xpVer" line="6">}}ignoreCrossplaneConstraints: true{{</hover>}}.
```yaml {label="xpVer"}
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws
spec:
ignoreCrossplaneConstraints: true
# Removed for brevity
```
### 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 Upbound AWS reference platform is
`HEALTHY: False`.
```shell {copy-lines="1"}
kubectl get providers
NAME INSTALLED HEALTHY PACKAGE AGE
provider-aws-s3 True False xpkg.upbound.io/upbound/provider-aws-s3:v0.41.0 12s
```
To see more information on why the Provider isn't `HEALTHY` use
{{<hover label="depend" line="1">}}kubectl describe providerrevisions{{</hover>}}.
```yaml {copy-lines="1",label="depend"}
kubectl describe providerrevisions
Name: provider-aws-s3-92206523fff4
API Version: pkg.crossplane.io/v1
Kind: ProviderRevision
Spec:
Desired State: Active
Image: xpkg.upbound.io/upbound/provider-aws-s3:v0.41.0
Revision: 1
Status:
Conditions:
Last Transition Time: 2023-10-10T21:06:39Z
Reason: UnhealthyPackageRevision
Status: False
Type: Healthy
Controller Ref:
Name:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning LintPackage 41s (x3 over 47s) packages/providerrevision.pkg.crossplane.io incompatible Crossplane version: package is not compatible with Crossplane version (v1.10.0)
```
The {{<hover label="depend" line="17">}}Events{{</hover>}} show a
{{<hover label="depend" line="20">}}Warning{{</hover>}} with a message that the
current version of Crossplane doesn't meet the Configuration package
requirements.
## 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
{{<hover label="getPR" line="1">}}kubectl get providerrevisions{{</hover>}}
```shell {label="getPR",copy-lines="1"}
kubectl get providerrevisions
NAME HEALTHY REVISION IMAGE STATE DEP-FOUND DEP-INSTALLED AGE
provider-aws-s3-dbc7f981d81f True 1 xpkg.upbound.io/upbound/provider-aws-s3:v0.37.0 Active 1 1 10d
provider-nop-552a394a8acc True 2 xpkg.upbound.io/crossplane-contrib/provider-nop:v0.3.0 Active 11d
provider-nop-7e62d2a1a709 True 1 xpkg.upbound.io/crossplane-contrib/provider-nop:v0.2.0 Inactive 13d
upbound-provider-family-aws-710d8cfe9f53 True 1 xpkg.upbound.io/upbound/provider-family-aws:v0.40.0 Active 10d
```
By default Crossplane keeps a single
{{<hover label="getPR" line="5">}}Inactive{{</hover>}} Provider.
Read the [revision history limit](#package-revision-history-limit) section to
change the default value.
Only a single revision of a Provider is
{{<hover label="getPR" line="4">}}Active{{</hover>}} at a time.
## Remove a Provider
Remove a Provider by deleting the Provider object with
`kubectl delete provider`.
{{< hint "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]({{<ref "../guides/troubleshoot-crossplane#deleting-when-a-resource-hangs" >}}).
{{< /hint >}}
## 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`.
```shell {copy-lines="1"}
kubectl get providers
NAME INSTALLED HEALTHY PACKAGE AGE
crossplane-contrib-provider-aws True Unknown xpkg.upbound.io/crossplane-contrib/provider-aws:v0.39.0 63s
```
After the Provider install completes and it's ready for use the `HEALTHY` status
reports `True`.
```shell {copy-lines="1"}
kubectl get providers
NAME INSTALLED HEALTHY PACKAGE AGE
crossplane-contrib-provider-aws True True xpkg.upbound.io/crossplane-contrib/provider-aws:v0.39.0 88s
```
{{<hint "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/master/design/one-pager-crd-scaling.md).
{{< /hint >}}
### Provider conditions
Crossplane uses a standard set of `Conditions` for Providers.
View the conditions of a provider under their `Status` with
`kubectl describe provider`.
```yaml
kubectl describe provider
Name: my-provider
API Version: pkg.crossplane.io/v1
Kind: Provider
# Removed for brevity
Status:
Conditions:
Reason: HealthyPackageRevision
Status: True
Type: Healthy
Reason: ActivePackageRevision
Status: True
Type: Installed
# Removed for brevity
```
#### 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
Each `Reason` relates to a specific `Type` and `Status`. Crossplane uses the
following `Reasons` for Provider `Conditions`.
<!-- vale Google.Headings = NO -->
##### InactivePackageRevision
`Reason: InactivePackageRevision` indicates the Provider Package is using an
inactive Provider Package Revision.
<!-- vale Google.Headings = YES -->
```yaml
Type: Installed
Status: False
Reason: InactivePackageRevision
```
<!-- vale Google.Headings = NO -->
##### ActivePackageRevision
<!-- vale Google.Headings = YES -->
The Provider Package is the current Package Revision, but Crossplane hasn't
finished installing the Package Revision yet.
{{< hint "tip" >}}
Providers stuck in this state are because of a problem with Package Revisions.
Use `kubectl describe providerrevisions` for more details.
{{< /hint >}}
```yaml
Type: Installed
Status: True
Reason: ActivePackageRevision
```
<!-- vale Google.Headings = NO -->
##### HealthyPackageRevision
The Provider is fully installed and ready to use.
{{<hint "tip" >}}
`Reason: HealthyPackageRevision` is the normal state of a working Provider.
{{< /hint >}}
<!-- vale Google.Headings = YES -->
```yaml
Type: Healthy
Status: True
Reason: HealthyPackageRevision
```
<!-- vale Google.Headings = NO -->
##### UnhealthyPackageRevision
<!-- vale Google.Headings = YES -->
There was an error installing the Provider Package Revision, preventing
Crossplane from installing the Provider Package.
{{<hint "tip" >}}
Use `kubectl describe providerrevisions` for more details on why the Package
Revision failed.
{{< /hint >}}
```yaml
Type: Healthy
Status: False
Reason: UnhealthyPackageRevision
```
<!-- vale Google.Headings = NO -->
##### UnknownPackageRevisionHealth
<!-- vale Google.Headings = YES -->
The status of the Provider Package Revision is `Unknown`. The Provider Package
Revision may be installing or has an issue.
{{<hint "tip" >}}
Use `kubectl describe providerrevisions` for more details on why the Package
Revision failed.
{{< /hint >}}
```yaml
Type: Healthy
Status: Unknown
Reason: UnknownPackageRevisionHealth
```
## Configure a Provider
Providers have two different types of configurations:
* _Controller 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.
{{<hint "important" >}}
Apply `ControllerConfig` objects to Providers.
Apply `ProviderConfig` objects to managed resources.
{{< /hint >}}
### Controller configuration
{{< hint "important" >}}
<!-- vale write-good.Passive = NO -->
<!-- vale gitlab.FutureTense = NO -->
The `ControllerConfig` type was deprecated in v1.11 and will be removed in
a future release.
<!-- vale write-good.Passive = YES -->
<!-- vale gitlab.FutureTense = YES -->
[`DeploymentRuntimeConfig`]({{<ref "#runtime-configuration" >}}) is the
replacement for Controller configuration and is available in v1.14+.
{{< /hint >}}
Applying a Crossplane `ControllerConfig` to a Provider changes the settings of
the Provider's pod. The
[Crossplane ControllerConfig schema]({{< ref "../api#ControllerConfig-spec" >}})
defines the supported set of ControllerConfig settings.
The most common use case for ControllerConfigs are providing `args` to a
Provider's pod enabling optional services. For example, enabling
[external secret stores]({{< ref "../guides/vault-as-secret-store#enable-external-secret-stores-in-the-provider" >}})
for a Provider.
Each Provider determines their supported set of `args`.
### Runtime configuration
{{<hint "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.
{{< /hint >}}
Runtime configuration is a generalized mechanism for configuring the runtime for
Crossplane packages with a runtime, namely `Providers` and `Functions`. It
replaces the deprecated `ControllerConfig` type and is available in v1.14+.
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.
{{<hint "note" >}}
Different from `ControllerConfig`, `DeploymentRuntimeConfig` embed the whole
Kubernetes Deployment spec, which allows for more flexibility in configuring
the runtime. Refer to the [design document](https://github.com/crossplane/crossplane/blob/2c5e7f07ba9e3d83d1c85169bbde685de8514ab8/design/one-pager-package-runtime-config.md)
for more details.
{{< /hint >}}
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:
```yaml
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-gcp-iam
spec:
package: xpkg.upbound.io/upbound/provider-gcp-iam:v0.37.0
runtimeConfigRef:
name: enable-ess
---
apiVersion: pkg.crossplane.io/v1beta1
kind: DeploymentRuntimeConfig
metadata:
name: enable-ess
spec:
deploymentTemplate:
spec:
selector: {}
template:
spec:
containers:
- name: package-runtime
args:
- --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.
<!-- vale write-good.Passive = NO -->
The package manager is opinionated about some fields to ensure
<!-- vale write-good.Passive = YES -->
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 as well as 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
<!-- vale gitlab.FutureTense = NO -->
configuration in the cluster, but won't change it if it already exists. This
<!-- vale gitlab.FutureTense = YES -->
allows users to customize the default runtime configuration to their needs.
{{<hint "tip" >}}
<!-- vale gitlab.SubstitutionWarning = NO -->
Since `DeploymentRuntimeConfig` uses the same schema as Kubernetes `Deployment`
<!-- vale gitlab.SubstitutionWarning = YES -->
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:
```yaml
apiVersion: pkg.crossplane.io/v1beta1
kind: DeploymentRuntimeConfig
metadata:
name: multi-replicas
spec:
deploymentTemplate:
spec:
replicas: 2
selector: {}
template: {}
```
{{< /hint >}}
#### 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:
```yaml
runAsNonRoot: true
runAsUser: 2000
runAsGroup: 2000
```
- Security Context for the runtime container as:
```yaml
allowPrivilegeEscalation: false
privileged: false
runAsGroup: 2000
runAsNonRoot: true
runAsUser: 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
`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:
```yaml
apiVersion: pkg.crossplane.io/v1beta1
kind: DeploymentRuntimeConfig
metadata:
name: my-runtime-config
spec:
deploymentTemplate:
metadata:
labels:
my-label: my-value
serviceAccountTemplate:
metadata:
name: my-service-account
```
### Provider configuration
The `ProviderConfig` determines settings the Provider uses communicating to the
external provider. Each Provider determines available settings of their
`ProviderConfig`.
<!-- vale write-good.Weasel = NO -->
<!-- allow "usually" -->
Provider authentication is usually configured with a `ProviderConfig`. For
example, to use basic key-pair authentication with Provider AWS a
{{<hover label="providerconfig" line="2" >}}ProviderConfig{{</hover >}}
{{<hover label="providerconfig" line="5" >}}spec{{</hover >}}
defines the
{{<hover label="providerconfig" line="6" >}}credentials{{</hover >}} and that
the Provider pod should look in the Kubernetes
{{<hover label="providerconfig" line="7" >}}Secrets{{</hover >}} objects and use
the key named
{{<hover label="providerconfig" line="10" >}}aws-creds{{</hover >}}.
<!-- vale write-good.Weasel = YES -->
```yaml {label="providerconfig"}
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: aws-provider
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-creds
key: creds
```
{{< hint "important" >}}
Authentication configuration may be different across Providers.
Read the documentation on a specific Provider for instructions on configuring
authentication for that Provider.
{{< /hint >}}
<!-- vale write-good.TooWordy = NO -->
<!-- allow multiple -->
ProviderConfig objects apply to individual Managed Resources. A single
Provider can authenticate with multiple users or accounts through
ProviderConfigs.
<!-- vale write-good.TooWordy = YES -->
Each account's credentials tie to a unique ProviderConfig. When creating a
managed resource, attach the desired ProviderConfig.
For example, two AWS ProviderConfigs, named
{{<hover label="user" line="4">}}user-keys{{</hover >}} and
{{<hover label="admin" line="4">}}admin-keys{{</hover >}}
use different Kubernetes secrets.
```yaml {label="user"}
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: user-keys
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: my-key
key: secret-key
```
```yaml {label="admin"}
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: admin-keys
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: admin-key
key: admin-secret-key
```
Apply the ProviderConfig when creating a managed resource.
This creates an AWS {{<hover label="user-bucket" line="2" >}}Bucket{{< /hover >}}
resource using the
{{<hover label="user-bucket" line="9" >}}user-keys{{< /hover >}} ProviderConfig.
```yaml {label="user-bucket"}
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: user-bucket
spec:
forProvider:
region: us-east-2
providerConfigRef:
name: user-keys
```
This creates a second {{<hover label="admin-bucket" line="2" >}}Bucket{{< /hover >}}
resource using the
{{<hover label="admin-bucket" line="9" >}}admin-keys{{< /hover >}} ProviderConfig.
```yaml {label="admin-bucket"}
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: user-bucket
spec:
forProvider:
region: us-east-2
providerConfigRef:
name: admin-keys
```

View File

@ -0,0 +1,105 @@
---
title: Server-Side Apply
state: alpha
alphaVersion: "1.15"
weight: 300
---
Crossplane can use server-side apply to sync claims with composite resources
(XRs), and to sync composite resources with composed resources.
When Crossplane uses server-side apply, the Kubernetes API server helps sync
resources. Using server-side apply makes syncing more predictable and less
buggy.
{{<hint "tip">}}
Server-side apply is a Kubernetes feature. Read more about server-side apply in
the [Kubernetes documentation](https://kubernetes.io/docs/reference/using-api/server-side-apply/).
{{</hint>}}
## Use server-side apply to sync claims with composite resources
When you create a claim, Crossplane creates a corresponding composite resource.
Crossplane keeps the claim in sync with the composite resource. When you change
the claim, Crossplane reflects those changes on the composite resource.
Read the [claims documentation]({{<ref "./claims">}}) to learn more about claims
and how they relate to composite resources.
Crossplane can use server-side apply to keep the claim in sync with the
composite resource.
Use the `--enable-ssa-claims` feature flag to enable using server-side apply.
Read the [Install Crossplane documentation]({{<ref "../software/install#feature-flags">}})
to learn about feature flags.
If you see fields reappearing after you delete them from a claim's `spec`,
enable server-side apply to fix the problem. Enabling server-side apply also
fixes the problem where Crossplane doesn't delete labels and annotations from
the composite resource when you delete them from the claim.
{{<hint "important">}}
When you enable server-side apply, Crossplane is stricter about how it syncs
a claim with its counterpart composite resource:
- The claim's `metadata` syncs to the composite resource's `metadata`.
- The claim's `spec` syncs to the composite resource's `spec`.
- The composite resource's `status` syncs to the claim's `status`.
When you enable server-side apply Crossplane doesn't sync the composite resource's `metadata`
and `spec` back to the claim's `metadata` and `spec`. It also doesn't sync the
claim's `status` to the composite resource's `status`.
{{</hint>}}
## Use server-side apply to sync claims end-to-end
To get the full benefit of server-side apply, use the `--enable-ssa-claims`
feature flag together with composition functions.
When you use composition functions, Crossplane uses server side apply to sync
composite resources with composed resources. Read more about this in the
[composition functions documentation]({{<ref "./compositions#how-composition-functions-work">}}).
```mermaid
graph LR
A(Claim) -- claim server-side apply --> B(Composite Resource)
B -- function server-side apply --> C(Composed Resource)
B -- function server-side apply --> D(Composed Resource)
B -- function server-side apply --> E(Composed Resource)
```
When you use server-side apply end-to-end there is a clear, predictable
propagation of fields from claim to composed resources, and back:
* `metadata` and `spec` flow forwards, from claim to XR to composed resources.
* `status` flows backwards, from composed resources to XR to claim.
{{<hint "important">}}
When you use composition functions, Crossplane is stricter about how it syncs
composite resources (XRs) with composed resources:
- The XR's `metadata` syncs to the composed resource's `metadata`.
- The XR's `spec` syncs to the composed resource's `spec`.
- The composed resource's `status` syncs to the XR's `status`.
When you use composition functions Crossplane doesn't sync the composed resource's `metadata`
and `spec` back to the XR's `metadata` and `spec`.
{{</hint>}}
When Crossplane uses server-side apply end-to-end to sync claims with composed
resources, it deletes fields from a composed resource's `spec` when you
delete fields from the claim's `spec`.
When Crossplane uses server-side apply end-to-end it's also able to merge claim
fields into complex composed resource fields. Objects and arrays of objects are
examples of complex composed resource fields.
{{<hint "tip">}}
Crossplane can only merge complex fields for resources that use server-side
apply merge strategy OpenAPI extensions. Read about these extensions in the
Kubernetes [server-side apply documentation](https://kubernetes.io/docs/reference/using-api/server-side-apply/#merge-strategy).
If you find that Crossplane isn't merging managed resource fields, raise an
issue against the relevant provider. Ask the provider maintainer to add
server-side apply merge strategy extensions to the managed resource.
{{</hint>}}

View File

@ -0,0 +1,292 @@
---
title: Usages
weight: 95
state: alpha
alphaVersion: "1.14"
description: "Usage defines a usage relationship for Managed Resources or Composites"
---
A `Usage` is a Crossplane resource that defines a usage relationship for a
Managed Resource or a Composite Resource. Two main use cases for the 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](#usage-for-deletion-protection) for the
first use case and the section [Usage for Deletion Ordering](#usage-for-deletion-ordering)
for the second one.
## Enable usages
Usages are an alpha feature. Alpha features aren't enabled by default.
Enable `Usage` support by
[changing the Crossplane pod setting]({{<ref "./pods#change-pod-settings">}})
and enabling
{{<hover label="deployment" line="12">}}--enable-usages{{</hover>}}
argument.
```yaml {label="deployment",copy-lines="12"}
$ kubectl edit deployment crossplane --namespace crossplane-system
apiVersion: apps/v1
kind: Deployment
spec:
# Removed for brevity
template:
spec:
containers:
- args:
- core
- start
- --enable-usages
```
{{<hint "tip" >}}
The [Crossplane install guide]({{<ref "../software/install#feature-flags">}})
describes enabling feature flags like
{{<hover label="deployment" line="12">}}\-\-enable-usages{{</hover>}}
with Helm.
{{< /hint >}}
<!-- vale Google.Headings = NO -->
## Create a usage
<!-- vale Google.Headings = YES -->
<!-- vale write-good.Passive = NO -->
A {{<hover label="protect" line="2">}}Usage{{</hover>}}
{{<hover label="protect" line="5">}}spec{{</hover>}} has a mandatory
{{<hover label="protect" line="6">}}of{{</hover>}} field for defining the resource
in use or protected. The
{{<hover label="protect" line="11">}}reason{{</hover>}} field defines the reason
for protection and the {{<hover label="order" line="11">}}by{{</hover>}} field
defines the using resource. Both fields are optional, but at least one of them
must be provided.
<!-- vale write-good.Passive = YES -->
{{<hint "important" >}}
<!-- vale write-good.Passive = NO -->
Usage relationships can be defined between `Managed Resources` and `Composites`.
<!-- vale write-good.TooWordy = NO -->
However, a `Composite` as the using resource (`spec.by`) would be ineffective
unless the `compositeDeletePolicy` `Foreground` is used because it wouldn't block
deletion of its child resources before its own deletion with the default deletion
policy `Background`.
<!-- vale write-good.TooWordy = YES -->
<!-- vale write-good.Passive = YES -->
{{< /hint >}}
### Usage for deletion protection
The following example prevents the deletion of the
{{<hover label="protect" line="10">}}my-database{{</hover>}} resource by rejecting
any deletion request with the
{{<hover label="protect" line="11">}}reason{{</hover>}} defined.
```yaml {label="protect"}
apiVersion: apiextensions.crossplane.io/v1alpha1
kind: Usage
metadata:
name: protect-production-database
spec:
of:
apiVersion: rds.aws.upbound.io/v1beta1
kind: Instance
resourceRef:
name: my-database
reason: "Production Database - should never be deleted!"
```
### Usage for deletion ordering
The following example prevents the deletion of
{{<hover label="order" line="10">}}my-cluster{{</hover>}} resource by rejecting
any deletion request before the deletion of
{{<hover label="order" line="15">}}my-prometheus-chart{{</hover>}} resource.
```yaml {label="order"}
apiVersion: apiextensions.crossplane.io/v1alpha1
kind: Usage
metadata:
name: release-uses-cluster
spec:
of:
apiVersion: eks.upbound.io/v1beta1
kind: Cluster
resourceRef:
name: my-cluster
by:
apiVersion: helm.crossplane.io/v1beta1
kind: Release
resourceRef:
name: my-prometheus-chart
```
### Using selectors with usages
Usages can use {{<hover label="selectors" line="9">}}selectors{{</hover>}}
to define the resource in use or the using one.
This enables using {{<hover label="selectors" line="12">}}labels{{</hover>}} or
{{<hover label="selectors" line="10">}}matching controller references{{</hover>}}
to define resource instead of providing the resource name.
```yaml {label="selectors"}
apiVersion: apiextensions.crossplane.io/v1alpha1
kind: Usage
metadata:
name: release-uses-cluster
spec:
of:
apiVersion: eks.upbound.io/v1beta1
kind: Cluster
resourceSelector:
matchControllerRef: false # default, and could be omitted
matchLabels:
foo: bar
by:
apiVersion: helm.crossplane.io/v1beta1
kind: Release
resourceSelector:
matchLabels:
baz: qux
```
After the `Usage` controller resolves the selectors, it persists the resource
name in the
{{<hover label="selectors-resolved" line="10">}}resourceRef.name{{</hover>}}
field. The following example shows the `Usage` resource after the resolution of
selectors.
{{<hint "important" >}}
<!-- vale write-good.Passive = NO -->
The selectors are resolved only once. If there are more than one matches, a
random resource is selected from the list of matched resources.
<!-- vale write-good.Passive = YES -->
{{< /hint >}}
```yaml {label="selectors-resolved"}
apiVersion: apiextensions.crossplane.io/v1alpha1
kind: Usage
metadata:
name: release-uses-cluster
spec:
of:
apiVersion: eks.upbound.io/v1beta1
kind: Cluster
resourceRef:
name: my-cluster
resourceSelector:
matchLabels:
foo: bar
by:
apiVersion: helm.crossplane.io/v1beta1
kind: Release
resourceRef:
name: my-cluster
resourceSelector:
matchLabels:
baz: qux
```
### 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
{{<hover label="replay" line="6">}}replayDeletion{{</hover>}} field to `true`.
```yaml {label="replay"}
apiVersion: apiextensions.crossplane.io/v1alpha1
kind: Usage
metadata:
name: release-uses-cluster
spec:
replayDeletion: true
of:
apiVersion: eks.upbound.io/v1beta1
kind: Cluster
resourceRef:
name: my-cluster
by:
apiVersion: helm.crossplane.io/v1beta1
kind: Release
resourceRef:
name: my-prometheus-chart
```
{{<hint "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.
{{< /hint >}}
## 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]({{<ref "./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]({{<ref "./managed-resources#referencing-other-resources" >}}).
The following example shows a Composition that defines a deletion ordering
between a `Cluster` and a `Release` resource. The `Usage` blocks deletion of
the `Cluster` resource until the `Release` resource is successfully deleted.
```yaml {label="composition"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
spec:
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: cluster
base:
apiVersion: container.gcp.upbound.io/v1beta1
kind: Cluster
# Removed for brevity
- name: release
base:
apiVersion: helm.crossplane.io/v1beta1
kind: Release
# Removed for brevity
- name: release-uses-cluster
base:
apiVersion: apiextensions.crossplane.io/v1alpha1
kind: Usage
spec:
replayDeletion: true
of:
apiVersion: container.gcp.upbound.io/v1beta1
kind: Cluster
resourceSelector:
matchControllerRef: true
by:
apiVersion: helm.crossplane.io/v1beta1
kind: Release
resourceSelector:
matchControllerRef: true
```
{{<hint "tip" >}}
<!-- vale write-good.Passive = NO -->
When there are multiple resources of same type in a Composition, the
{{<hover label="composition" line="18">}}Usage{{</hover>}} resource must
uniquely identify the resource in use or the using one. This could be
accomplished by using extra labels and combining
{{<hover label="composition" line="24">}}matchControllerRef{{</hover>}}
with a `matchLabels` selector. Another alternative is patching `resourceRef.name`
directly with the help of `ToCompositeFieldPath` and `FromCompositeFieldPath`
or `ToEnvironmentFieldPath` and `FromEnvironmentFieldPath` type patches.
<!-- vale write-good.Passive = YES -->
{{< /hint >}}

View File

@ -0,0 +1,16 @@
---
title: Getting Started
weight: 4
description: An introduction to Crossplane and Crossplane quickstart guides.
---
{{<img src="/media/banner.png" alt="Crossplane Popsicle Truck" size="large" >}}
## Hands-on
Want a hands-on example? Follow a Crossplane Quickstart for your cloud provider.
* [AWS quickstart]({{<ref "provider-aws" >}})
* [Azure quickstart]({{<ref "provider-azure" >}})
* [GCP quickstart]({{<ref "provider-gcp" >}})
## Install
Ready to get started? [Install Crossplane]({{<ref "../software/install" >}}) in a Kubernetes cluster.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,495 @@
---
title: Crossplane Introduction
weight: 2
---
Crossplane connects your Kubernetes cluster to external,
non-Kubernetes resources, and allows platform teams to build custom Kubernetes
APIs to consume those resources.
<!-- vale gitlab.SentenceLength = NO -->
Crossplane creates Kubernetes
[Custom Resource Definitions](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/)
(`CRDs`) to represent the external resources as native
[Kubernetes objects](https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/).
As native Kubernetes objects, you can use standard commands like `kubectl create`
and `kubectl describe`. The full
[Kubernetes API](https://kubernetes.io/docs/reference/using-api/) is available
for every Crossplane resource.
<!-- vale gitlab.SentenceLength = YES -->
Crossplane also acts as a
[Kubernetes Controller](https://kubernetes.io/docs/concepts/architecture/controller/)
to watch the state of the external resources and provide state enforcement. If
something modifies or deletes a resource outside of Kubernetes, Crossplane reverses
the change or recreates the deleted resource.
{{<img src="/media/crossplane-intro-diagram.png" alt="Diagram showing a user communicating to Kubernetes. Crossplane connected to Kubernetes and Crossplane communicating with AWS, Azure and GCP" align="center">}}
With Crossplane installed in a Kubernetes cluster, users only communicate with
Kubernetes. Crossplane manages the communication to external resources like AWS,
Azure or Google Cloud.
Crossplane also allows the creation of custom Kubernetes APIs. Platform teams can
combine external resources and simplify or customize the APIs presented to the
platform consumers.
## Crossplane components overview
This table provides a summary of Crossplane components and their roles.
{{< table "table table-hover table-sm">}}
| Component | Abbreviation | Scope | Summary |
| --- | --- | --- | ---- |
| [Provider]({{<ref "#providers">}}) | | cluster | Creates new Kubernetes Custom Resource Definitions for an external service. |
| [ProviderConfig]({{<ref "#provider-configurations">}}) | `PC` | cluster | Applies settings for a _Provider_. |
| [Managed Resource]({{<ref "#managed-resources">}}) | `MR` | cluster | A Provider resource created and managed by Crossplane inside the Kubernetes cluster. |
| [Composition]({{<ref "#compositions">}}) | | cluster | A template for creating multiple _managed resources_ at once. |
| [Composite Resources]({{<ref "#composite-resources" >}}) | `XR` | cluster | Uses a _Composition_ template to create multiple _managed resources_ as a single Kubernetes object. |
| [CompositeResourceDefinitions]({{<ref "#composite-resource-definitions" >}}) | `XRD` | cluster | Defines the API schema for _Composite Resources_ and _Claims_ |
| [Claims]({{<ref "#claims" >}}) | `XC` | namespace | Like a _Composite Resource_, but namespace scoped. |
{{< /table >}}
## The Crossplane Pod
When installed in a Kubernetes cluster Crossplane creates an initial set of
Custom Resource Definitions (`CRDs`) of the core Crossplane components.
{{< expand "View the initial Crossplane CRDs" >}}
After installing Crossplane use `kubectl get crds` to view the Crossplane
installed CRDs.
```shell
kubectl get crd
NAME
compositeresourcedefinitions.apiextensions.crossplane.io
compositionrevisions.apiextensions.crossplane.io
compositions.apiextensions.crossplane.io
configurationrevisions.pkg.crossplane.io
configurations.pkg.crossplane.io
controllerconfigs.pkg.crossplane.io
deploymentruntimeconfigs.pkg.crossplane.io
environmentconfigs.apiextensions.crossplane.io
functionrevisions.pkg.crossplane.io
functions.pkg.crossplane.io
locks.pkg.crossplane.io
providerrevisions.pkg.crossplane.io
providers.pkg.crossplane.io
storeconfigs.secrets.crossplane.io
usages.apiextensions.crossplane.io
```
{{< /expand >}}
The following sections describe the functions of some of these CRDs.
<!-- vale Google.Headings = NO -->
<!-- allow "Providers" -->
## Providers
<!-- vale Google.Headings = YES -->
A Crossplane _Provider_ creates a second set of CRDs that define how Crossplane
connects to a non-Kubernetes service. Each external service relies on its own
Provider. For example,
[AWS](https://marketplace.upbound.io/providers/upbound/provider-aws),
[Azure](https://marketplace.upbound.io/providers/upbound/provider-azure)
and [GCP](https://marketplace.upbound.io/providers/upbound/provider-gcp)
are different providers for each cloud service.
{{< hint "tip" >}}
Most Providers are for cloud services but Crossplane can use a Provider to
connect to any service with an API.
{{< /hint >}}
For example, an AWS Provider defines Kubernetes CRDs for AWS resources like EC2
compute instances or S3 storage buckets.
The Provider defines the Kubernetes API definition for the external resource.
For example, the
[Upbound Provider AWS](https://marketplace.upbound.io/providers/upbound/provider-aws/)
defines a
[`bucket`](https://marketplace.upbound.io/providers/upbound/provider-aws/v0.25.0/resources/s3.aws.upbound.io/Bucket/v1beta1)
resource for creating and managing AWS S3 storage buckets.
In the `bucket` CRD is a
[`spec.forProvider.region`](https://marketplace.upbound.io/providers/upbound/provider-aws/v0.25.0/resources/s3.aws.upbound.io/Bucket/v1beta1#doc:spec-forProvider-region)
value that defines which AWS region to deploy the bucket in.
The Upbound Marketplace contains a large
[collection of Crossplane Providers](https://marketplace.upbound.io/providers).
More providers are available in the [Crossplane Contrib repository](https://github.com/crossplane-contrib/).
Providers are cluster scoped and available to all cluster namespaces.
View all installed Providers with the command `kubectl get providers`.
## Provider configurations
Providers have _ProviderConfigs_. _ProviderConfigs_ configure settings
related to the Provider like authentication or global defaults for the
Provider.
The API endpoints for ProviderConfigs are unique to each Provider.
_ProviderConfigs_ are cluster scoped and available to all cluster namespaces.
View all installed ProviderConfigs with the command `kubectl get providerconfig`.
## Managed resources
A Provider's CRDs map to individual _resources_ inside the provider. When
Crossplane creates and monitors a resource it's a _Managed Resource_.
Using a Provider's CRD creates a unique _Managed Resource_. For example,
using the Provider AWS's `bucket` CRD, Crossplane creates a `bucket` _Managed Resource_
inside the Kubernetes cluster that's connected to an AWS S3 storage bucket.
The Crossplane controller provides state enforcement for _Managed Resources_.
Crossplane enforces the settings and existence of _Managed Resources_. This
"Controller Pattern" is like how the Kubernetes
[kube-controller-manager](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-controller-manager/)
enforces state for pods.
_Managed Resources_ are cluster scoped and available to all cluster namespaces.
Use `kubectl get managed` to view all _managed resources_.
{{<hint "warning" >}}
The `kubectl get managed` creates a lot of Kubernetes API queries.
Both the `kubectl` client and kube-apiserver throttle the API queries.
Depending on the size of the API server and number of managed resources, this
command may take minutes to return or may timeout.
For more information, read
[Kubernetes issue #111880](https://github.com/kubernetes/kubernetes/issues/111880)
and
[Crossplane issue #3459](https://github.com/crossplane/crossplane/issues/3459).
{{< /hint >}}
## Compositions
A _Composition_ is a template for a collection of _managed resource_. _Compositions_
allow platform teams to define a set of _managed resources_ as a
single object.
For example, a compute _managed resource_ may require the creation of a storage
resource and a virtual network as well. A single _Composition_ can define all three
resources in a single _Composition_ object.
Using _Compositions_ simplifies the deployment of infrastructure made up of
multiple _managed resources_. _Compositions_ also enforce standards and settings
across deployments.
Platform teams can define fixed or default settings for each _managed resource_ inside a
_Composition_ or define fields and settings that users may change.
Using the previous example, the platform team may set a compute resource size
and virtual network settings. But the platform team allows users to define the
storage resource size.
Creating a _Composition_ Crossplane doesn't create any managed
resources. The _Composition_ is only a template for a collection of _managed
resources_ and their settings. A _Composite Resource_ creates the specific resources.
{{< hint "note" >}}
The [_Composite Resources_]({{<ref "#composite-resources">}}) section discusses
_Composite Resources_.
{{< /hint >}}
_Compositions_ are cluster scoped and available to all cluster namespaces.
Use `kubectl get compositions` to view all _compositions_.
## Composite Resources
A _Composite Resource_ (`XR`) is a set of provisioned _managed resources_. A
_Composite Resource_ uses the template defined by a _Composition_ and applies
any user defined settings.
Multiple unique _Composite Resource_ objects can use the same _Composition_. For
example, a _Composition_ template can create a compute, storage and networking
set of _managed resources_. Crossplane uses the same _Composition_ template
every time a user requests this set of resources.
If a _Composition_ allows a user to define resource settings, users apply them
in a _Composite Resource_.
<!-- A _Composition_ defines which _Composite Resources_ can use the _Composition_
template with the _Composition_ `spec.compositeTypeRef` value. This defines the
{{<hover label="comp" line="7">}}apiVersion{{< /hover >}} and {{<hover
label="comp" line="8">}}kind{{< /hover >}} of _Composite Resources_ that can use the
_Composition_.
For example, in the _Composition_:
```yaml {label="comp"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: test.example.org
spec:
compositeTypeRef:
apiVersion: test.example.org/v1alpha1
kind: MyComputeResource
# Removed for brevity
```
A _Composite Resource_ that can use this template must match this
{{<hover label="comp" line="7">}}apiVersion{{< /hover >}} and {{<hover
label="comp" line="8">}}kind{{< /hover >}}.
```yaml {label="xr"}
apiVersion: test.example.org/v1alpha1
kind: MyComputeResource
metadata:
name: my-resource
spec:
storage: "large"
```
The _Composite Resource_ {{<hover label="xr" line="1">}}apiVersion{{< /hover >}}
matches the and _Composition_
{{<hover label="comp" line="7">}}apiVersion{{</hover >}} and the
_Composite Resource_ {{<hover label="xr" line="2">}}kind{{< /hover >}}
matches the _Composition_ {{<hover label="comp" line="8">}}kind{{< /hover >}}.
In this example, the _Composite Resource_ also sets the
{{<hover label="xr" line="7">}}storage{{< /hover >}} setting. The
_Composition_ uses this value when creating the associated _managed resources_
owned by this _Composite Resource_. -->
{{< hint "tip" >}}
_Compositions_ are templates for a set of _managed resources_.
_Composite Resources_ fill out the template and create _managed resources_.
Deleting a _Composite Resource_ deletes all the _managed resources_ it created.
{{< /hint >}}
_Composite Resources_ are cluster scoped and available to all cluster namespaces.
Use `kubectl get composite` to view all _Composite Resources_.
## Composite Resource Definitions
_Composite Resource Definitions_ (`XRDs`) create custom Kubernetes APIs used by
_Claims_ and _Composite Resources_.
{{< hint "note" >}}
The [_Claims_]({{<ref "#claims">}}) section discusses
_Claims_.
{{< /hint >}}
Platform teams define the custom APIs.
These APIs can define specific values
like storage space in gigabytes, generic settings like `small` or `large`,
deployment options like `cloud` or `onprem`. Crossplane doesn't limit the API definitions.
The _Composite Resource Definition's_ `kind` is from Crossplane.
```yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
```
The `spec` of a _Composite Resource Definition_ creates the `apiVersion`,
`kind` and `spec` of a _Composite Resource_.
{{< hint "tip" >}}
The _Composite Resource Definition_ defines the parameters for a _Composite
Resource_.
{{< /hint >}}
A _Composite Resource Definition_ has four main `spec` parameters:
* A {{<hover label="specGroup" line="3" >}}group{{< /hover >}}
to define the
{{< hover label="xr2" line="2" >}}apiVersion{{</hover >}}
in a _Composite Resource_ .
* The {{< hover label="specGroup" line="7" >}}versions.name{{</hover >}}
that defines the version used in a _Composite Resource_.
* A {{< hover label="specGroup" line="5" >}}names.kind{{</hover >}}
to define the _Composite Resource_
{{< hover label="xr2" line="3" >}}kind{{</hover>}}.
* A {{< hover label="specGroup" line="8" >}}versions.schema{{</hover>}} section
to define the _Composite Resource_ {{<hover label="xr2" line="6" >}}spec{{</hover >}}.
```yaml {label="specGroup"}
# Composite Resource Definition (XRD)
spec:
group: test.example.org
names:
kind: MyComputeResource
versions:
- name: v1alpha1
schema:
# Removed for brevity
```
A _Composite Resource_ based on this _Composite Resource Definition_ looks like this:
```yaml {label="xr2"}
# Composite Resource (XR)
apiVersion: test.example.org/v1alpha1
kind: MyComputeResource
metadata:
name: my-resource
spec:
storage: "large"
```
A _Composite Resource Definition_ {{< hover label="specGroup" line="8" >}}schema{{</hover >}} defines the _Composite Resource_
{{<hover label="xr2" line="6" >}}spec{{</hover >}} parameters.
These parameters are the new, custom APIs, that developers can use.
For example, creating a compute _managed resource_ requires knowledge of a
cloud provider's compute class names like AWS's `m6in.large` or GCP's
`e2-standard-2`.
A _Composite Resource Definition_ can limit the choices to `small` or `large`.
A _Composite Resource_ uses those options and the _Composition_ maps them
to specific cloud provider settings.
The following _Composite Resource Definition_ defines a {{<hover label="specVersions" line="17" >}}storage{{< /hover >}}
parameter. The storage is a
{{<hover label="specVersions" line="18">}}string{{< /hover >}}
and the OpenAPI
{{<hover label="specVersions" line="19" >}}oneOf{{< /hover >}} requires the
options to be either {{<hover label="specVersions" line="20" >}}small{{< /hover >}}
or {{<hover label="specVersions" line="21" >}}large{{< /hover >}}.
```yaml {label="specVersions"}
# Composite Resource Definition (XRD)
spec:
group: test.example.org
names:
kind: MyComputeResource
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
storage:
type: string
oneOf:
- pattern: '^small$'
- pattern: '^large$'
required:
- storage
```
A _Composite Resource Definition_ can define a wide variety of settings and options.
Creating a _Composite Resource Definition_ enables the creation of _Composite
Resources_ but can also create a _Claim_.
_Composite Resource Definitions_ with a `spec.claimNames` allow developers to
create _Claims_.
For example, the
{{< hover label="xrdClaim" line="6" >}}claimNames.kind{{</hover >}}
allows the creation of _Claims_ of `kind: computeClaim`.
```yaml {label="xrdClaim"}
# Composite Resource Definition (XRD)
spec:
group: test.example.org
names:
kind: MyComputeResource
claimNames:
kind: computeClaim
# Removed for brevity
```
## Claims
_Claims_ are the primary way developers interact with Crossplane.
_Claims_ access the custom APIs defined by the platform team in a _Composite
Resource Definition_.
_Claims_ look like _Composite Resources_, but they're namespace scoped,
while _Composite Resources_ are cluster scoped.
{{< hint "note" >}}
**Why does namespace scope matter?**
Having namespace scoped _Claims_ allows multiple teams, using unique namespaces,
to create the same types of resources, independent of each other. The compute
resources of team A are unique to the compute resources of team B.
Directly creating _Composite Resources_ requires cluster-wide permissions,
shared with all teams.
_Claims_ create the same set of resources, but on a namespace level.
{{< /hint >}}
The previous _Composite Resource Definition_ allows the creation of _Claims_
of the kind
{{<hover label="xrdClaim2" line="7" >}}computeClaim{{</hover>}}.
Claims use the same
{{< hover label="xrdClaim2" line="3" >}}apiVersion{{< /hover >}}
defined in _Composite Resource Definition_ and also used by
_Composite Resources_.
```yaml {label="xrdClaim2"}
# Composite Resource Definition (XRD)
spec:
group: test.example.org
names:
kind: MyComputeResource
claimNames:
kind: computeClaim
# Removed for brevity
```
In an example _Claim_ the
{{<hover label="claim" line="2">}}apiVersion{{< /hover >}}
matches the {{<hover label="xrdClaim2" line="3">}}group{{< /hover >}} in the
_Composite Resource Definition_.
The _Claim_ {{<hover label="claim" line="3">}}kind{{< /hover >}} matches the
_Composite Resource Definition_
{{<hover label="xrdClaim2" line="7">}}claimNames.kind{{< /hover >}}.
```yaml {label="claim"}
# Claim
apiVersion: test.example.org/v1alpha1
kind: computeClaim
metadata:
name: myClaim
namespace: devGroup
spec:
size: "large"
```
A _Claim_ can install in a {{<hover label="claim" line="6">}}namespace{{</hover >}}.
The _Composite Resource Definition_ defines the
{{<hover label="claim" line="7">}}spec{{< /hover >}} options the same way it
does for a _Composite Resource_
{{<hover label="xr-claim" line="6">}}spec{{< /hover >}}.
{{< hint "tip" >}}
_Composite Resources_ and _Claims_ are similar.
Only _Claims_ can be in
a {{<hover label="claim" line="6">}}namespace{{</hover >}}.
Also the _Composite Resource's_ {{<hover label="xr-claim"
line="3">}}kind{{</hover >}} may be different than the _Claim's_
{{<hover label="claim" line="3">}}kind{{< /hover >}}.
The _Composite Resource Definition_ defines the
{{<hover label="xrdClaim2" line="7">}}kind{{</hover >}} values.
{{< /hint >}}
```yaml {label="xr-claim"}
# Composite Resource (XR)
apiVersion: test.example.org/v1alpha1
kind: MyComputeResource
metadata:
name: my-resource
spec:
storage: "large"
```
_Claims_ are namespace scoped.
View all available Claims with the command `kubectl get claim`.
## Next steps
Build your own Crossplane platform using one of the quickstart guides.
* [Azure Quickstart]({{<ref "provider-azure" >}})
* [AWS Quickstart]({{<ref "provider-aws" >}})
* [GCP Quickstart]({{<ref "provider-gcp" >}})

View File

@ -0,0 +1,603 @@
---
title: AWS Quickstart Part 2
weight: 120
tocHidden: true
aliases:
- /master/getting-started/provider-aws-part-3
---
{{< hint "important" >}}
This guide is part 2 of a series.
[**Part 1**]({{<ref "provider-aws" >}}) covers
to installing Crossplane and connect your Kubernetes cluster to AWS.
{{< /hint >}}
This guide walks you through building and accessing a custom API with Crossplane.
## Prerequisites
* Complete [quickstart part 1]({{<ref "provider-aws" >}}) connecting Kubernetes
to AWS.
* an AWS account with permissions to create an AWS S3 storage bucket and a
DynamoDB instance
{{<expand "Skip part 1 and just get started" >}}
1. Add the Crossplane Helm repository and install Crossplane
```shell
helm repo add \
crossplane-stable https://charts.crossplane.io/stable
helm repo update
helm install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace
```
2. When the Crossplane pods finish installing and are ready, apply the AWS Provider
```yaml {label="provider",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-s3
spec:
package: xpkg.upbound.io/upbound/provider-aws-s3:v1.1.0
EOF
```
3. Create a file with your AWS keys
```ini
[default]
aws_access_key_id = <aws_access_key>
aws_secret_access_key = <aws_secret_key>
```
4. Create a Kubernetes secret from the AWS keys
```shell {label="kube-create-secret",copy-lines="all"}
kubectl create secret \
generic aws-secret \
-n crossplane-system \
--from-file=creds=./aws-credentials.txt
```
5. Create a _ProviderConfig_
```yaml {label="providerconfig",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-secret
key: creds
EOF
```
{{</expand >}}
## Install the DynamoDB Provider
Part 1 only installed the AWS S3 Provider. This section deploys an S3 bucket
along with a DynamoDB Table.
Deploying a DynamoDB Table requires the DynamoDB Provider as well.
Add the new Provider to the cluster.
```yaml
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-dynamodb
spec:
package: xpkg.upbound.io/upbound/provider-aws-dynamodb:v1.1.0
EOF
```
View the new DynamoDB provider with `kubectl get providers`.
```shell {copy-lines="1"}
kubectl get providers
NAME INSTALLED HEALTHY PACKAGE AGE
provider-aws-dynamodb True True xpkg.upbound.io/upbound/provider-aws-dynamodb:v1.1.0 3m55s
provider-aws-s3 True True xpkg.upbound.io/upbound/provider-aws-s3:v1.1.0 13m
upbound-provider-family-aws True True xpkg.upbound.io/upbound/provider-family-aws:v1.1.0 13m
```
## Create a custom API
<!-- vale alex.Condescending = NO -->
Crossplane allows you to build your own custom APIs for your users, abstracting
away details about the cloud provider and their resources. You can make your API
as complex or simple as you wish.
<!-- vale alex.Condescending = YES -->
The custom API is a Kubernetes object.
Here is an example custom API.
```yaml {label="exAPI"}
apiVersion: database.example.com/v1alpha1
kind: NoSQL
metadata:
name: my-nosql-database
spec:
location: "US"
```
Like any Kubernetes object the API has a
{{<hover label="exAPI" line="1">}}version{{</hover>}},
{{<hover label="exAPI" line="2">}}kind{{</hover>}} and
{{<hover label="exAPI" line="5">}}spec{{</hover>}}.
### Define a group and version
To create your own API start by defining an
[API group](https://kubernetes.io/docs/reference/using-api/#api-groups) and
[version](https://kubernetes.io/docs/reference/using-api/#api-versioning).
The _group_ can be any value, but common convention is to map to a fully
qualified domain name.
<!-- vale gitlab.SentenceLength = NO -->
The version shows how mature or stable the API is and increments when changing,
adding or removing fields in the API.
<!-- vale gitlab.SentenceLength = YES -->
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.
This guide uses the group
{{<hover label="version" line="1">}}database.example.com{{</hover>}}.
Because this is the first version of the API, this guide uses the version
{{<hover label="version" line="1">}}v1alpha1{{</hover>}}.
```yaml {label="version",copy-lines="none"}
apiVersion: database.example.com/v1alpha1
```
### Define a kind
The API group is a logical collection of related APIs. In a group are
individual kinds representing different resources.
For example a `database` group may have a `Relational` and `NoSQL` kinds.
The `kind` can be anything, but it must be
[UpperCamelCased](https://kubernetes.io/docs/contribute/style/style-guide/#use-upper-camel-case-for-api-objects).
This API's kind is
{{<hover label="kind" line="2">}}NoSQL{{</hover>}}
```yaml {label="kind",copy-lines="none"}
apiVersion: database.example.com/v1alpha1
kind: NoSQL
```
### Define a spec
The most important part of an API is the schema. The schema defines the inputs
accepted from users.
This API allows users to provide a
{{<hover label="spec" line="4">}}location{{</hover>}} of where to run their
cloud resources.
All other resource settings can't be configurable by the users. This allows
Crossplane to enforce any policies and standards without worrying about
user errors.
```yaml {label="spec",copy-lines="none"}
apiVersion: database.example.com/v1alpha1
kind: NoSQL
spec:
location: "US"
```
### Apply the API
Crossplane uses
{{<hover label="xrd" line="3">}}Composite Resource Definitions{{</hover>}}
(also called an `XRD`) to install your custom API in
Kubernetes.
The XRD {{<hover label="xrd" line="6">}}spec{{</hover>}} contains all the
information about the API including the
{{<hover label="xrd" line="7">}}group{{</hover>}},
{{<hover label="xrd" line="12">}}version{{</hover>}},
{{<hover label="xrd" line="9">}}kind{{</hover>}} and
{{<hover label="xrd" line="13">}}schema{{</hover>}}.
The XRD's {{<hover label="xrd" line="5">}}name{{</hover>}} must be the
combination of the {{<hover label="xrd" line="9">}}plural{{</hover>}} and
{{<hover label="xrd" line="7">}}group{{</hover>}}.
The {{<hover label="xrd" line="13">}}schema{{</hover>}} uses the
{{<hover label="xrd" line="14">}}OpenAPIv3{{</hover>}} specification to define
the API {{<hover label="xrd" line="17">}}spec{{</hover>}}.
The API defines a {{<hover label="xrd" line="20">}}location{{</hover>}} that
must be {{<hover label="xrd" line="22">}}oneOf{{</hover>}} either
{{<hover label="xrd" line="23">}}EU{{</hover>}} or
{{<hover label="xrd" line="24">}}US{{</hover>}}.
Apply this XRD to create the custom API in your Kubernetes cluster.
```yaml {label="xrd",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: nosqls.database.example.com
spec:
group: database.example.com
names:
kind: NoSQL
plural: nosqls
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
location:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
required:
- location
served: true
referenceable: true
claimNames:
kind: NoSQLClaim
plural: nosqlclaim
EOF
```
Adding the {{<hover label="xrd" line="29">}}claimNames{{</hover>}} allows users
to access this API either at the cluster level with the
{{<hover label="xrd" line="9">}}nosql{{</hover>}} endpoint or in a namespace
with the
{{<hover label="xrd" line="29">}}nosqlclaim{{</hover>}} endpoint.
The namespace scoped API is a Crossplane _Claim_.
{{<hint "tip" >}}
For more details on the fields and options of Composite Resource Definitions
read the
[XRD documentation]({{<ref "../concepts/composite-resource-definitions">}}).
{{< /hint >}}
View the installed XRD with `kubectl get xrd`.
```shell {copy-lines="1"}
kubectl get xrd
NAME ESTABLISHED OFFERED AGE
nosqls.database.example.com True True 2s
```
View the new custom API endpoints with `kubectl api-resources | grep nosql`
```shell {copy-lines="1",label="apiRes"}
kubectl api-resources | grep nosql
nosqlclaim database.example.com/v1alpha1 true NoSQLClaim
nosqls database.example.com/v1alpha1 false NoSQL
```
## Create a deployment template
When users access the custom API Crossplane takes their inputs and combines them
with a template describing what infrastructure to deploy. Crossplane calls this
template a _Composition_.
The {{<hover label="comp" line="3">}}Composition{{</hover>}} defines all the
cloud resources to deploy. Each entry in the template is a full resource
definition, defining all the resource settings and metadata like labels and
annotations.
This template creates an AWS
{{<hover label="comp" line="13">}}S3{{</hover>}}
{{<hover label="comp" line="14">}}Bucket{{</hover>}} and a
{{<hover label="comp" line="33">}}DynamoDB{{</hover>}}
{{<hover label="comp" line="34">}}Table{{</hover>}}.
This Composition takes the user's
{{<hover label="comp" line="21">}}location{{</hover>}} input and uses it as the
{{<hover label="comp" line="16">}}region{{</hover>}} used in the individual
resource.
{{<hint "important" >}}
This Composition uses an array of resource templates. You can patch each
template with data copied from the custom API. Crossplane calls this a _Patch
and Transform_ Composition.
You don't have to use Patch and Transform. Crossplane supports a variety of
alternatives, including Go Templating and CUE. You can also write a function in
Go or Python to template your resources.
Read the [Composition documentation]({{<ref "../concepts/compositions">}}) for
more information on configuring Compositions and all the available options.
{{< /hint >}}
Apply this Composition to your cluster.
```yaml {label="comp",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: dynamo-with-bucket
spec:
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: s3Bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: crossplane-quickstart-bucket
spec:
forProvider:
region: us-east-2
providerConfigRef:
name: default
patches:
- type: FromCompositeFieldPath
fromFieldPath: "spec.location"
toFieldPath: "spec.forProvider.region"
transforms:
- type: map
map:
EU: "eu-north-1"
US: "us-east-2"
- name: dynamoDB
base:
apiVersion: dynamodb.aws.upbound.io/v1beta1
kind: Table
metadata:
name: crossplane-quickstart-database
spec:
forProvider:
region: "us-east-2"
writeCapacity: 1
readCapacity: 1
attribute:
- name: S3ID
type: S
hashKey: S3ID
patches:
- type: FromCompositeFieldPath
fromFieldPath: "spec.location"
toFieldPath: "spec.forProvider.region"
transforms:
- type: map
map:
EU: "eu-north-1"
US: "us-east-2"
compositeTypeRef:
apiVersion: database.example.com/v1alpha1
kind: NoSQL
EOF
```
The {{<hover label="comp" line="52">}}compositeTypeRef{{</hover >}} defines
which custom APIs can use this template to create resources.
A Composition uses a pipeline of _composition functions_ to define the cloud
resources to deploy. This template uses
{{<hover label="comp" line="10">}}function-patch-and-transform{{</hover>}}.
You must install the function before you can use it in a Composition.
Apply this Function to install `function-patch-and-transform`:
```yaml {label="install"}
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
name: function-patch-and-transform
spec:
package: xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.1.4
EOF
```
{{<hint "tip" >}}
Read the [Composition documentation]({{<ref "../concepts/compositions">}}) for
more information on configuring Compositions and all the available options.
Read the
[Patch and Transform function documentation]({{<ref "../guides/function-patch-and-transform">}})
for more information on how it uses patches to map user inputs to Composition
resource templates.
{{< /hint >}}
View the Composition with `kubectl get composition`
```shell {copy-lines="1"}
kubectl get composition
NAME XR-KIND XR-APIVERSION AGE
dynamo-with-bucket NoSQL database.example.com/v1alpha1 3s
```
## Access the custom API
With the custom API (XRD) installed and associated to a resource template
(Composition) users can access the API to create resources.
Create a {{<hover label="xr" line="2">}}NoSQL{{</hover>}} object to create the
cloud resources.
```yaml {copy-lines="all",label="xr"}
cat <<EOF | kubectl apply -f -
apiVersion: database.example.com/v1alpha1
kind: NoSQL
metadata:
name: my-nosql-database
spec:
location: "US"
EOF
```
View the resource with `kubectl get nosql`.
```shell {copy-lines="1"}
kubectl get nosql
NAME SYNCED READY COMPOSITION AGE
my-nosql-database True True dynamo-with-bucket 14s
```
This object is a Crossplane _composite resource_ (also called an `XR`).
It's a
single object representing the collection of resources created from the
Composition template.
View the individual resources with `kubectl get managed`
```shell {copy-lines="1"}
kubectl get managed
NAME READY SYNCED EXTERNAL-NAME AGE
table.dynamodb.aws.upbound.io/my-nosql-database-t5wtx True True my-nosql-database-t5wtx 33s
NAME READY SYNCED EXTERNAL-NAME AGE
bucket.s3.aws.upbound.io/my-nosql-database-xtzph True True my-nosql-database-xtzph 33s
```
Delete the resources with `kubectl delete nosql`.
```shell {copy-lines="1"}
kubectl delete nosql my-nosql-database
nosql.database.example.com "my-nosql-database" deleted
```
Verify Crossplane deleted the resources with `kubectl get managed`
{{<hint "note" >}}
It may take up to 5 minutes to delete the resources.
{{< /hint >}}
```shell {copy-lines="1"}
kubectl get managed
No resources found
```
## Using the API with namespaces
Accessing the API `nosql` happens at the cluster scope.
Most organizations
isolate their users into namespaces.
A Crossplane _Claim_ is the custom API in a namespace.
Creating a _Claim_ is just like accessing the custom API endpoint, but with the
{{<hover label="claim" line="3">}}kind{{</hover>}}
from the custom API's `claimNames`.
Create a new namespace to test create a Claim in.
```shell
kubectl create namespace crossplane-test
```
Then create a Claim in the `crossplane-test` namespace.
```yaml {label="claim",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: database.example.com/v1alpha1
kind: NoSQLClaim
metadata:
name: my-nosql-database
namespace: crossplane-test
spec:
location: "US"
EOF
```
View the Claim with `kubectl get claim -n crossplane-test`.
```shell {copy-lines="1"}
kubectl get claim -n crossplane-test
NAME SYNCED READY CONNECTION-SECRET AGE
my-nosql-database True True 17s
```
The Claim automatically creates a composite resource, which creates the managed
resources.
View the Crossplane created composite resource with `kubectl get composite`.
```shell {copy-lines="1"}
kubectl get composite
NAME SYNCED READY COMPOSITION AGE
my-nosql-database-t9qrw True True dynamo-with-bucket 77s
```
Again, view the managed resources with `kubectl get managed`.
```shell {copy-lines="1"}
kubectl get managed
NAME READY SYNCED EXTERNAL-NAME AGE
table.dynamodb.aws.upbound.io/my-nosql-database-t9qrw-dcpwv True True my-nosql-database-t9qrw-dcpwv 116s
NAME READY SYNCED EXTERNAL-NAME AGE
bucket.s3.aws.upbound.io/my-nosql-database-t9qrw-g98lv True True my-nosql-database-t9qrw-g98lv 117s
```
Deleting the Claim deletes all the Crossplane generated resources.
`kubectl delete claim -n crossplane-test my-nosql-database`
```shell {copy-lines="1"}
kubectl delete claim -n crossplane-test my-nosql-database
nosqlclaim.database.example.com "my-nosql-database" deleted
```
{{<hint "note" >}}
It may take up to 5 minutes to delete the resources.
{{< /hint >}}
Verify Crossplane deleted the composite resource with `kubectl get composite`.
```shell {copy-lines="1"}
kubectl get composite
No resources found
```
Verify Crossplane deleted the managed resources with `kubectl get managed`.
```shell {copy-lines="1"}
kubectl get managed
No resources found
```
## Next steps
* Explore AWS resources that Crossplane can configure in the
[Provider CRD reference](https://marketplace.upbound.io/providers/upbound/provider-family-aws/).
* Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with
Crossplane users and contributors.
* Read more about the [Crossplane concepts]({{<ref "../concepts">}}) to find out what else you can do
with Crossplane.

View File

@ -0,0 +1,244 @@
---
title: AWS Quickstart
weight: 100
---
Connect Crossplane to AWS to create and manage cloud resources from Kubernetes
with the
[Upbound AWS Provider](https://marketplace.upbound.io/providers/upbound/provider-family-aws).
This guide is in two parts:
* Part 1 walks through installing Crossplane, configuring the provider to
authenticate to AWS and creating a _Managed Resource_ in AWS directly from your
Kubernetes cluster. This shows Crossplane can communicate with AWS.
* [Part 2]({{< ref "provider-aws-part-2" >}}) shows how to build and access a
custom API with Crossplane.
## Prerequisites
This quickstart requires:
* a Kubernetes cluster with at least 2 GB of RAM
* permissions to create pods and secrets in the Kubernetes cluster
* [Helm](https://helm.sh/) version v3.2.0 or later
* 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)
{{<include file="/master/getting-started/install-crossplane-include.md" type="page" >}}
## Install the AWS provider
Install the AWS S3 provider into the Kubernetes cluster with a Kubernetes
configuration file.
```yaml {label="provider",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-s3
spec:
package: xpkg.upbound.io/upbound/provider-aws-s3:v1.1.0
EOF
```
The Crossplane {{< hover label="provider" line="3" >}}Provider{{</hover>}}
installs the Kubernetes _Custom Resource Definitions_ (CRDs) representing AWS S3
services. These CRDs allow you to create AWS resources directly inside
Kubernetes.
Verify the provider installed with `kubectl get providers`.
```shell {copy-lines="1",label="getProvider"}
kubectl get providers
NAME INSTALLED HEALTHY PACKAGE AGE
provider-aws-s3 True True xpkg.upbound.io/upbound/provider-aws-s3:1.1.0 97s
upbound-provider-family-aws True True xpkg.upbound.io/upbound/provider-family-aws:1.1.0 88s
```
The S3 Provider installs a second Provider, the
{{<hover label="getProvider" line="4">}}upbound-provider-family-aws{{</hover >}}.
The family provider manages authentication to AWS across all AWS family
Providers.
You can view the new CRDs with `kubectl get crds`.
Every CRD maps to a unique AWS service Crossplane can provision and manage.
{{< hint type="tip" >}}
See details about all the supported CRDs in the
[Upbound Marketplace](https://marketplace.upbound.io/providers/upbound/provider-aws-s3/v1.1.0).
{{< /hint >}}
## Create a Kubernetes secret for AWS
The provider requires credentials to create and manage AWS resources.
Providers use a Kubernetes _Secret_ to connect the credentials to the provider.
Generate a Kubernetes _Secret_ from your AWS key-pair and
then configure the Provider to use it.
### Generate an AWS key-pair file
For basic user authentication, use an AWS Access keys key-pair file.
{{< hint type="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.
{{< /hint >}}
Create a text file containing the AWS account `aws_access_key_id` and `aws_secret_access_key`.
{{< editCode >}}
```ini {copy-lines="all"}
[default]
aws_access_key_id = $@<aws_access_key>$@
aws_secret_access_key = $@<aws_secret_key>$@
```
{{< /editCode >}}
Save this text file as `aws-credentials.txt`.
{{< hint type="note" >}}
The [Authentication](https://docs.upbound.io/providers/provider-aws/authentication/) section of the AWS Provider documentation describes other authentication methods.
{{< /hint >}}
### Create a Kubernetes secret with the AWS credentials
A Kubernetes generic secret has a name and contents.
Use
{{< hover label="kube-create-secret" line="1">}}kubectl create secret{{</hover >}}
to generate the secret object named
{{< hover label="kube-create-secret" line="2">}}aws-secret{{< /hover >}}
in the {{< hover label="kube-create-secret" line="3">}}crossplane-system{{</ hover >}} namespace.
Use the {{< hover label="kube-create-secret" line="4">}}--from-file={{</hover>}} argument to set the value to the contents of the {{< hover label="kube-create-secret" line="4">}}aws-credentials.txt{{< /hover >}} file.
```shell {label="kube-create-secret",copy-lines="all"}
kubectl create secret \
generic aws-secret \
-n crossplane-system \
--from-file=creds=./aws-credentials.txt
```
View the secret with `kubectl describe secret`
{{< hint type="note" >}}
The size may be larger if there are extra blank spaces in your text file.
{{< /hint >}}
```shell {copy-lines="1"}
kubectl describe secret aws-secret -n crossplane-system
Name: aws-secret
Namespace: crossplane-system
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
creds: 114 bytes
```
## Create a ProviderConfig
A {{< hover label="providerconfig" line="3">}}ProviderConfig{{</ hover >}}
customizes the settings of the AWS Provider.
Apply the
{{< hover label="providerconfig" line="3">}}ProviderConfig{{</ hover >}}
with the this Kubernetes configuration file:
```yaml {label="providerconfig",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-secret
key: creds
EOF
```
This attaches the AWS credentials, saved as a Kubernetes secret, as a
{{< hover label="providerconfig" line="9">}}secretRef{{</ hover>}}.
The
{{< hover label="providerconfig" line="11">}}spec.credentials.secretRef.name{{< /hover >}}
value is the name of the Kubernetes secret containing the AWS credentials in the
{{< hover label="providerconfig" line="10">}}spec.credentials.secretRef.namespace{{< /hover >}}.
## Create a managed resource
A _managed resource_ is anything Crossplane creates and manages outside of the
Kubernetes cluster.
This guide creates an AWS S3 bucket with Crossplane.
The S3 bucket is a _managed resource_.
{{< hint type="note" >}}
AWS S3 bucket names must be globally unique. To generate a unique name the example uses a random hash.
Any unique name is acceptable.
{{< /hint >}}
```yaml {label="xr"}
cat <<EOF | kubectl create -f -
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
generateName: crossplane-bucket-
spec:
forProvider:
region: us-east-2
providerConfigRef:
name: default
EOF
```
The {{< hover label="xr" line="3">}}apiVersion{{< /hover >}} and
{{< hover label="xr" line="4">}}kind{{</hover >}} are from the provider's CRDs.
The {{< hover label="xr" line="6">}}metadata.name{{< /hover >}} value is the
name of the created S3 bucket in AWS.
This example uses the generated name `crossplane-bucket-<hash>` in the
{{< hover label="xr" line="6">}}$bucket{{</hover >}} variable.
The {{< hover label="xr" line="9">}}spec.forProvider.region{{< /hover >}} tells
AWS which AWS region to use when deploying resources.
The region can be any
[AWS Regional endpoint](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints) code.
Use `kubectl get buckets` to verify Crossplane created the bucket.
{{< hint type="tip" >}}
Crossplane created the bucket when the values `READY` and `SYNCED` are `True`.
This may take up to 5 minutes.
{{< /hint >}}
```shell {copy-lines="1"}
kubectl get buckets
NAME READY SYNCED EXTERNAL-NAME AGE
crossplane-bucket-hhdzh True True crossplane-bucket-hhdzh 5s
```
## Delete the managed resource
Before shutting down your Kubernetes cluster, delete the S3 bucket just created.
Use `kubectl delete bucket <bucketname>` to remove the bucket.
```shell {copy-lines="1"}
kubectl delete bucket crossplane-bucket-hhdzh
bucket.s3.aws.upbound.io "crossplane-bucket-hhdzh" deleted
```
## Next steps
* [**Continue to part 2**]({{< ref "provider-aws-part-2">}}) to create and use a
custom API with Crossplane.
* Explore AWS resources that Crossplane can configure in the
[Provider CRD reference](https://marketplace.upbound.io/providers/upbound/provider-family-aws/).
* Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with
Crossplane users and contributors.

View File

@ -0,0 +1,710 @@
---
title: Azure Quickstart Part 2
weight: 120
tocHidden: true
aliases:
- /master/getting-started/provider-azure-part-3
---
{{< hint "important" >}}
This guide is part 2 of a series.
[**Part 1**]({{<ref "provider-azure" >}}) covers
to installing Crossplane and connect your Kubernetes cluster to Azure.
{{< /hint >}}
This guide walks you through building and accessing a custom API with Crossplane.
## Prerequisites
* Complete [quickstart part 1]({{<ref "provider-azure" >}}) connecting Kubernetes
to Azure.
* an Azure account with permissions to create an Azure Virtual Machine, Resource
Group and Virtual Networking.
{{<expand "Skip part 1 and just get started" >}}
1. Add the Crossplane Helm repository and install Crossplane
```shell
helm repo add \
crossplane-stable https://charts.crossplane.io/stable
helm repo update
&&
helm install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace
```
2. When the Crossplane pods finish installing and are ready, apply the Azure
Provider
```yaml {label="provider",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-azure-network
spec:
package: xpkg.upbound.io/upbound/provider-azure-network:v0.42.1
EOF
```
3. Use the Azure CLI to create a service principal and save the JSON output as
`azure-crednetials.json`
{{< editCode >}}
```console
az ad sp create-for-rbac \
--sdk-auth \
--role Owner \
--scopes /subscriptions/$@<subscription_id>$@
```
{{</ editCode >}}
4. Create a Kubernetes secret from the Azure JSON file.
```shell {label="kube-create-secret",copy-lines="all"}
kubectl create secret \
generic azure-secret \
-n crossplane-system \
--from-file=creds=./azure-credentials.json
```
5. Create a _ProviderConfig_
```yaml {label="providerconfig",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: azure.upbound.io/v1beta1
metadata:
name: default
kind: ProviderConfig
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: azure-secret
key: creds
EOF
```
{{</expand >}}
## Create a custom API
<!-- vale alex.Condescending = NO -->
Crossplane allows you to build your own custom APIs for your users, abstracting
away details about the cloud provider and their resources. You can make your API
as complex or simple as you wish.
<!-- vale alex.Condescending = YES -->
The custom API is a Kubernetes object.
Here is an example custom API.
```yaml {label="exAPI"}
apiVersion: compute.example.com/v1alpha1
kind: VirtualMachine
metadata:
name: my-vm
spec:
location: "US"
```
Like any Kubernetes object the API has a
{{<hover label="exAPI" line="1">}}version{{</hover>}},
{{<hover label="exAPI" line="2">}}kind{{</hover>}} and
{{<hover label="exAPI" line="5">}}spec{{</hover>}}.
### Define a group and version
To create your own API start by defining an
[API group](https://kubernetes.io/docs/reference/using-api/#api-groups) and
[version](https://kubernetes.io/docs/reference/using-api/#api-versioning).
The _group_ can be any value, but common convention is to map to a fully
qualified domain name.
<!-- vale gitlab.SentenceLength = NO -->
The version shows how mature or stable the API is and increments when changing,
adding or removing fields in the API.
<!-- vale gitlab.SentenceLength = YES -->
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.
This guide uses the group
{{<hover label="version" line="1">}}compute.example.com{{</hover>}}.
Because this is the first version of the API, this guide uses the version
{{<hover label="version" line="1">}}v1alpha1{{</hover>}}.
```yaml {label="version",copy-lines="none"}
apiVersion: compute.example.com/v1alpha1
```
### Define a kind
The API group is a logical collection of related APIs. In a group are
individual kinds representing different resources.
For example a `compute` group may have a `VirtualMachine` and `BareMetal` kinds.
The `kind` can be anything, but it must be
[UpperCamelCased](https://kubernetes.io/docs/contribute/style/style-guide/#use-upper-camel-case-for-api-objects).
This API's kind is
{{<hover label="kind" line="2">}}VirtualMachine{{</hover>}}
```yaml {label="kind",copy-lines="none"}
apiVersion: compute.example.com/v1alpha1
kind: VirtualMachine
```
### Define a spec
The most important part of an API is the schema. The schema defines the inputs
accepted from users.
This API allows users to provide a
{{<hover label="spec" line="4">}}location{{</hover>}} of where to run their
cloud resources.
All other resource settings can't be configurable by the users. This allows
Crossplane to enforce any policies and standards without worrying about
user errors.
```yaml {label="spec",copy-lines="none"}
apiVersion: compute.example.com/v1alpha1
kind: VirtualMachine
spec:
location: "US"
```
### Apply the API
Crossplane uses
{{<hover label="xrd" line="3">}}Composite Resource Definitions{{</hover>}}
(also called an `XRD`) to install your custom API in
Kubernetes.
The XRD {{<hover label="xrd" line="6">}}spec{{</hover>}} contains all the
information about the API including the
{{<hover label="xrd" line="7">}}group{{</hover>}},
{{<hover label="xrd" line="12">}}version{{</hover>}},
{{<hover label="xrd" line="9">}}kind{{</hover>}} and
{{<hover label="xrd" line="13">}}schema{{</hover>}}.
The XRD's {{<hover label="xrd" line="5">}}name{{</hover>}} must be the
combination of the {{<hover label="xrd" line="10">}}plural{{</hover>}} and
{{<hover label="xrd" line="7">}}group{{</hover>}}.
The {{<hover label="xrd" line="13">}}schema{{</hover>}} uses the
{{<hover label="xrd" line="14">}}OpenAPIv3{{</hover>}} specification to define
the API {{<hover label="xrd" line="17">}}spec{{</hover>}}.
The API defines a {{<hover label="xrd" line="20">}}location{{</hover>}} that
must be {{<hover label="xrd" line="22">}}oneOf{{</hover>}} either
{{<hover label="xrd" line="23">}}EU{{</hover>}} or
{{<hover label="xrd" line="24">}}US{{</hover>}}.
Apply this XRD to create the custom API in your Kubernetes cluster.
```yaml {label="xrd",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: virtualmachines.compute.example.com
spec:
group: compute.example.com
names:
kind: VirtualMachine
plural: virtualmachines
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
location:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
required:
- location
served: true
referenceable: true
claimNames:
kind: VirtualMachineClaim
plural: virtualmachineclaims
EOF
```
Adding the {{<hover label="xrd" line="29">}}claimNames{{</hover>}} allows users
to access this API either at the cluster level with the
{{<hover label="xrd" line="9">}}VirtualMachine{{</hover>}} endpoint or in a namespace
with the
{{<hover label="xrd" line="30">}}VirtualMachineClaim{{</hover>}} endpoint.
The namespace scoped API is a Crossplane _Claim_.
{{<hint "tip" >}}
For more details on the fields and options of Composite Resource Definitions
read the
[XRD documentation]({{<ref "../concepts/composite-resource-definitions">}}).
{{< /hint >}}
View the installed XRD with `kubectl get xrd`.
```shell {copy-lines="1"}
kubectl get xrd
NAME ESTABLISHED OFFERED AGE
virtualmachines.compute.example.com True True 43s
```
View the new custom API endpoints with `kubectl api-resources | grep VirtualMachine`
```shell {copy-lines="1",label="apiRes"}
kubectl api-resources | grep VirtualMachine
virtualmachineclaims compute.example.com/v1alpha1 true VirtualMachineClaim
virtualmachines compute.example.com/v1alpha1 false VirtualMachine
```
## Create a deployment template
When users access the custom API Crossplane takes their inputs and combines them
with a template describing what infrastructure to deploy. Crossplane calls this
template a _Composition_.
The {{<hover label="comp" line="3">}}Composition{{</hover>}} defines all the
cloud resources to deploy.
Each entry in the template
is a full resource definitions, defining all the resource settings and metadata
like labels and annotations.
This template creates an Azure
{{<hover label="comp" line="11">}}LinuxVirtualMachine{{</hover>}}
{{<hover label="comp" line="46">}}NetworkInterface{{</hover>}},
{{<hover label="comp" line="69">}}Subnet{{</hover>}}
{{<hover label="comp" line="90">}}VirtualNetwork{{</hover>}} and
{{<hover label="comp" line="110">}}ResourceGroup{{</hover>}}.
This Composition takes the user's
{{<hover label="comp" line="36">}}location{{</hover>}} input and uses it as the
{{<hover label="comp" line="37">}}location{{</hover>}} used in the individual
resource.
{{<hint "important" >}}
This Composition uses an array of resource templates. You can patch each
template with data copied from the custom API. Crossplane calls this a _Patch
and Transform_ Composition.
You don't have to use Patch and Transform. Crossplane supports a variety of
alternatives, including Go Templating and CUE. You can also write a function in
Go or Python to template your resources.
Read the [Composition documentation]({{<ref "../concepts/compositions">}}) for
more information on configuring Compositions and all the available options.
{{< /hint >}}
Apply this Composition to your cluster.
```yaml {label="comp",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: crossplane-quickstart-vm-with-network
spec:
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: quickstart-vm
base:
apiVersion: compute.azure.upbound.io/v1beta1
kind: LinuxVirtualMachine
spec:
forProvider:
adminUsername: adminuser
adminSshKey:
- publicKey: ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAABAQC+wWK73dCr+jgQOAxNsHAnNNNMEMWOHYEccp6wJm2gotpr9katuF/ZAdou5AaW1C61slRkHRkpRRX9FA9CYBiitZgvCCz+3nWNN7l/Up54Zps/pHWGZLHNJZRYyAB6j5yVLMVHIHriY49d/GZTZVNB8GoJv9Gakwc/fuEZYYl4YDFiGMBP///TzlI4jhiJzjKnEvqPFki5p2ZRJqcbCiF4pJrxUQR/RXqVFQdbRLZgYfJ8xGB878RENq3yQ39d8dVOkq4edbkzwcUmwwwkYVPIoDGsYLaRHnG+To7FvMeyO7xDVQkMKzopTQV8AuKpyvpqu0a9pWOMaiCyDytO7GGN
example@docs.crossplane.io
username: adminuser
location: "Central US"
osDisk:
- caching: ReadWrite
storageAccountType: Standard_LRS
resourceGroupNameSelector:
matchControllerRef: true
size: Standard_B1ms
sourceImageReference:
- offer: debian-11
publisher: Debian
sku: 11-backports-gen2
version: latest
networkInterfaceIdsSelector:
matchControllerRef: true
patches:
- type: FromCompositeFieldPath
fromFieldPath: "spec.location"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "Sweden Central"
US: "Central US"
- name: quickstart-nic
base:
apiVersion: network.azure.upbound.io/v1beta1
kind: NetworkInterface
spec:
forProvider:
ipConfiguration:
- name: crossplane-quickstart-configuration
privateIpAddressAllocation: Dynamic
subnetIdSelector:
matchControllerRef: true
location: "Central US"
resourceGroupNameSelector:
matchControllerRef: true
patches:
- type: FromCompositeFieldPath
fromFieldPath: "spec.location"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "Sweden Central"
US: "Central US"
- name: quickstart-subnet
base:
apiVersion: network.azure.upbound.io/v1beta1
kind: Subnet
spec:
forProvider:
addressPrefixes:
- 10.0.1.0/24
virtualNetworkNameSelector:
matchControllerRef: true
resourceGroupNameSelector:
matchControllerRef: true
patches:
- type: FromCompositeFieldPath
fromFieldPath: "spec.location"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "Sweden Central"
US: "Central US"
- name: quickstart-network
base:
apiVersion: network.azure.upbound.io/v1beta1
kind: VirtualNetwork
spec:
forProvider:
addressSpace:
- 10.0.0.0/16
location: "Central US"
resourceGroupNameSelector:
matchControllerRef: true
patches:
- type: FromCompositeFieldPath
fromFieldPath: "spec.location"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "Sweden Central"
US: "Central US"
- name: crossplane-resourcegroup
base:
apiVersion: azure.upbound.io/v1beta1
kind: ResourceGroup
spec:
forProvider:
location: Central US
patches:
- type: FromCompositeFieldPath
fromFieldPath: "spec.location"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "Sweden Central"
US: "Central US"
compositeTypeRef:
apiVersion: compute.example.com/v1alpha1
kind: VirtualMachine
EOF
```
The {{<hover label="comp" line="52">}}compositeTypeRef{{</hover >}} defines
which custom APIs can use this template to create resources.
A Composition uses a pipeline of _composition functions_ to define the cloud
resources to deploy. This template uses
{{<hover label="comp" line="10">}}function-patch-and-transform{{</hover>}}.
You must install the function before you can use it in a Composition.
Apply this Function to install `function-patch-and-transform`:
```yaml {label="install"}
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
name: function-patch-and-transform
spec:
package: xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.1.4
EOF
```
{{<hint "tip" >}}
Read the [Composition documentation]({{<ref "../concepts/compositions">}}) for
more information on configuring Compositions and all the available options.
Read the
[Patch and Transform function documentation]({{<ref "../guides/function-patch-and-transform">}})
for more information on how it uses patches to map user inputs to Composition
resource templates.
{{< /hint >}}
View the Composition with `kubectl get composition`
```shell {copy-lines="1"}
kubectl get composition
NAME XR-KIND XR-APIVERSION AGE
crossplane-quickstart-vm-with-network XVirtualMachine custom-api.example.org/v1alpha1 77s
```
## Install the Azure virtual machine provider
Part 1 only installed the Azure Virtual Network Provider. To deploying virtual
machines requires the Azure Compute provider as well.
Add the new Provider to the cluster.
```yaml
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-azure-compute
spec:
package: xpkg.upbound.io/upbound/provider-azure-compute:v0.42.1
EOF
```
View the new Compute provider with `kubectl get providers`.
```shell {copy-lines="1"}
kubectl get providers
NAME INSTALLED HEALTHY PACKAGE AGE
provider-azure-compute True True xpkg.upbound.io/upbound/provider-azure-compute:v0.42.1 25s
provider-azure-network True True xpkg.upbound.io/upbound/provider-azure-network:v0.42.1 3h
upbound-provider-family-azure True True xpkg.upbound.io/upbound/provider-family-azure:v0.42.1 3h
```
## Access the custom API
With the custom API (XRD) installed and associated to a resource template
(Composition) users can access the API to create resources.
Create a {{<hover label="xr" line="3">}}VirtualMachine{{</hover>}} object to
create the cloud resources.
```yaml {copy-lines="all",label="xr"}
cat <<EOF | kubectl apply -f -
apiVersion: compute.example.com/v1alpha1
kind: VirtualMachine
metadata:
name: my-vm
spec:
location: "EU"
EOF
```
View the resource with `kubectl get VirtualMachine`.
{{< hint "note" >}}
It may take up to five minutes for the resources to provision.
{{< /hint >}}
```shell {copy-lines="1"}
kubectl get VirtualMachine
NAME SYNCED READY COMPOSITION AGE
my-vm True True crossplane-quickstart-vm-with-network 3m3s
```
This object is a Crossplane _composite resource_ (also called an `XR`).
It's a
single object representing the collection of resources created from the
Composition template.
View the individual resources with `kubectl get managed`
```shell {copy-lines="1"}
kubectl get managed
NAME READY SYNCED EXTERNAL-NAME AGE
resourcegroup.azure.upbound.io/my-vm-7jb4n True True my-vm-7jb4n 3m43s
NAME READY SYNCED EXTERNAL-NAME AGE
linuxvirtualmachine.compute.azure.upbound.io/my-vm-5h7p4 True True my-vm-5h7p4 3m43s
NAME READY SYNCED EXTERNAL-NAME AGE
networkinterface.network.azure.upbound.io/my-vm-j7fpx True True my-vm-j7fpx 3m43s
NAME READY SYNCED EXTERNAL-NAME AGE
subnet.network.azure.upbound.io/my-vm-b2dqt True True my-vm-b2dqt 3m43s
NAME READY SYNCED EXTERNAL-NAME AGE
virtualnetwork.network.azure.upbound.io/my-vm-pd2sw True True my-vm-pd2sw 3m43s
```
Accessing the API created all five resources defined in the template and linked
them together.
Look at a specific resource to see it's created in the location used in the API.
```yaml {copy-lines="1"}
kubectl describe linuxvirtualmachine | grep Location
Location: Sweden Central
Location: swedencentral
```
Delete the resources with `kubectl delete VirtualMachine`.
```shell {copy-lines="1"}
kubectl delete VirtualMachine my-vm
virtualmachine.compute.example.com "my-vm" deleted
```
Verify Crossplane deleted the resources with `kubectl get managed`
{{<hint "note" >}}
It may take up to 5 minutes to delete the resources.
{{< /hint >}}
```shell {copy-lines="1"}
kubectl get managed
No resources found
```
## Using the API with namespaces
Accessing the API `VirtualMachine` happens at the cluster scope.
Most organizations
isolate their users into namespaces.
A Crossplane _Claim_ is the custom API in a namespace.
Creating a _Claim_ is just like accessing the custom API endpoint, but with the
{{<hover label="claim" line="3">}}kind{{</hover>}}
from the custom API's `claimNames`.
Create a new namespace to test create a Claim in.
```shell
kubectl create namespace crossplane-test
```
Then create a Claim in the `crossplane-test` namespace.
```yaml {label="claim",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: compute.example.com/v1alpha1
kind: VirtualMachineClaim
metadata:
name: my-namespaced-vm
namespace: crossplane-test
spec:
location: "EU"
EOF
```
View the Claim with `kubectl get claim -n crossplane-test`.
```shell {copy-lines="1"}
kubectl get claim -n crossplane-test
NAME SYNCED READY CONNECTION-SECRET AGE
my-namespaced-vm True True 5m11s
```
The Claim automatically creates a composite resource, which creates the managed
resources.
View the Crossplane created composite resource with `kubectl get composite`.
```shell {copy-lines="1"}
kubectl get composite
NAME SYNCED READY COMPOSITION AGE
my-namespaced-vm-r7gdr True True crossplane-quickstart-vm-with-network 5m33s
```
Again, view the managed resources with `kubectl get managed`.
```shell {copy-lines="1"}
NAME READY SYNCED EXTERNAL-NAME AGE
resourcegroup.azure.upbound.io/my-namespaced-vm-r7gdr-cvzw6 True True my-namespaced-vm-r7gdr-cvzw6 5m51s
NAME READY SYNCED EXTERNAL-NAME AGE
linuxvirtualmachine.compute.azure.upbound.io/my-namespaced-vm-r7gdr-vrbgb True True my-namespaced-vm-r7gdr-vrbgb 5m51s
NAME READY SYNCED EXTERNAL-NAME AGE
networkinterface.network.azure.upbound.io/my-namespaced-vm-r7gdr-hwrb8 True True my-namespaced-vm-r7gdr-hwrb8 5m51s
NAME READY SYNCED EXTERNAL-NAME AGE
subnet.network.azure.upbound.io/my-namespaced-vm-r7gdr-gh468 True True my-namespaced-vm-r7gdr-gh468 5m51s
NAME READY SYNCED EXTERNAL-NAME AGE
virtualnetwork.network.azure.upbound.io/my-namespaced-vm-r7gdr-5qhz7 True True my-namespaced-vm-r7gdr-5qhz7 5m51s
```
Deleting the Claim deletes all the Crossplane generated resources.
`kubectl delete claim -n crossplane-test my-VirtualMachine-database`
```shell {copy-lines="1"}
kubectl delete claim -n crossplane-test my-namespaced-vm
virtualmachineclaim.compute.example.com "my-namespaced-vm" deleted
```
{{<hint "note" >}}
It may take up to 5 minutes to delete the resources.
{{< /hint >}}
Verify Crossplane deleted the composite resource with `kubectl get composite`.
```shell {copy-lines="1"}
kubectl get composite
No resources found
```
Verify Crossplane deleted the managed resources with `kubectl get managed`.
```shell {copy-lines="1"}
kubectl get managed
No resources found
```
## Next steps
* Explore Azure resources that Crossplane can configure in the
[Provider CRD reference](https://marketplace.upbound.io/providers/upbound/provider-family-azure/).
* Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with
Crossplane users and contributors.
* Read more about the [Crossplane concepts]({{<ref "../concepts">}}) to find out
what else you can do with Crossplane.

View File

@ -0,0 +1,239 @@
---
title: Azure Quickstart
weight: 110
---
Connect Crossplane to Azure to create and manage cloud resources from Kubernetes
with the
[Upbound Azure Provider](https://marketplace.upbound.io/providers/upbound/provider-family-azure/).
This guide is in two parts:
* Part 1 walks through installing Crossplane, configuring the provider to
authenticate to Azure and creating a _Managed Resource_ in Azure directly from
your Kubernetes cluster. This shows Crossplane can communicate with Azure.
* [Part 2]({{< ref "provider-azure-part-2" >}}) shows how to build and access a
custom API with Crossplane.
## Prerequisites
This quickstart requires:
* a Kubernetes cluster with at least 2 GB of RAM
* permissions to create pods and secrets in the Kubernetes cluster
* [Helm](https://helm.sh/) version v3.2.0 or later
* an Azure account with permissions to create an
[Azure Virtual Machine](https://learn.microsoft.com/en-us/azure/virtual-machines/)
and
[Virtual Network](https://learn.microsoft.com/en-us/azure/virtual-network/)
* an Azure account with permissions to create an Azure [service principal](https://learn.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals#service-principal-object) and an [Azure resource group](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-portal)
{{<include file="/master/getting-started/install-crossplane-include.md" type="page" >}}
## Install the Azure provider
Install the Azure Network resource provider into the Kubernetes cluster with a Kubernetes configuration
file.
```yaml {label="provider",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-azure-network
spec:
package: xpkg.upbound.io/upbound/provider-azure-network:v0.42.1
EOF
```
The Crossplane {{< hover label="provider" line="3" >}}Provider{{</hover>}}
installs the Kubernetes _Custom Resource Definitions_ (CRDs) representing Azure Networking
services. These CRDs allow you to create Azure resources directly inside
Kubernetes.
Verify the provider installed with `kubectl get providers`.
```shell {copy-lines="1",label="getProvider"}
kubectl get providers
NAME INSTALLED HEALTHY PACKAGE AGE
provider-azure-network True True xpkg.upbound.io/upbound/provider-azure-network:v0.42.1 38s
upbound-provider-family-azure True True xpkg.upbound.io/upbound/provider-family-azure:v0.42.1 26s
```
The Network Provider installs a second Provider, the
{{<hover label="getProvider" line="4">}}upbound-provider-family-azure{{</hover>}}
provider.
The family provider manages authentication to Azure across all Azure family
Providers.
You can view the new CRDs with `kubectl get crds`.
Every CRD maps to a unique Azure service Crossplane can provision and manage.
{{< hint type="tip" >}}
See details about all the supported CRDs in the
[Upbound Marketplace](https://marketplace.upbound.io/providers/upbound/provider-family-azure/v0.42.1).
{{< /hint >}}
## Create a Kubernetes secret for Azure
The provider requires credentials to create and manage Azure resources.
Providers use a Kubernetes _Secret_ to connect the credentials to the provider.
This guide generates an Azure service principal JSON file and saves it as a
Kubernetes _Secret_.
### Install the Azure command-line
Generating an [authentication file](https://docs.microsoft.com/en-us/azure/developer/go/azure-sdk-authorization#use-file-based-authentication) requires the Azure command-line.
Follow the documentation from Microsoft to [Download and install the Azure command-line](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli).
Log in to the Azure command-line.
```command
az login
```
### Create an Azure service principal
Follow the Azure documentation to [find your Subscription ID](https://docs.microsoft.com/en-us/azure/azure-portal/get-subscription-tenant-id) from the Azure Portal.
Using the Azure command-line and provide your Subscription ID create a service principal and authentication file.
{{< editCode >}}
```console {copy-lines="all"}
az ad sp create-for-rbac \
--sdk-auth \
--role Owner \
--scopes /subscriptions/$@<subscription_id>$@
```
{{< /editCode >}}
Save your Azure JSON output as `azure-credentials.json`.
{{< hint type="note" >}}
The
[Authentication](https://docs.upbound.io/providers/provider-azure/authentication/)
section of the Azure Provider documentation describes other authentication methods.
{{< /hint >}}
### Create a Kubernetes secret with the Azure credentials
A Kubernetes generic secret has a name and contents. Use {{< hover label="kube-create-secret" line="1">}}kubectl create secret{{< /hover >}} to generate the secret object named {{< hover label="kube-create-secret" line="2">}}azure-secret{{< /hover >}} in the {{< hover label="kube-create-secret" line="3">}}crossplane-system{{</ hover >}} namespace.
<!-- vale gitlab.Substitutions = NO -->
<!-- ignore .json file name -->
Use the {{< hover label="kube-create-secret" line="4">}}--from-file={{</hover>}} argument to set the value to the contents of the {{< hover label="kube-create-secret" line="4">}}azure-credentials.json{{< /hover >}} file.
<!-- vale gitlab.Substitutions = YES -->
```shell {label="kube-create-secret",copy-lines="all"}
kubectl create secret \
generic azure-secret \
-n crossplane-system \
--from-file=creds=./azure-credentials.json
```
View the secret with `kubectl describe secret`
{{< hint type="note" >}}
The size may be larger if there are extra blank spaces in your text file.
{{< /hint >}}
```shell {copy-lines="1"}
kubectl describe secret azure-secret -n crossplane-system
Name: azure-secret
Namespace: crossplane-system
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
creds: 629 bytes
```
## Create a ProviderConfig
A `ProviderConfig` customizes the settings of the Azure Provider.
Apply the {{< hover label="providerconfig" line="5">}}ProviderConfig{{</ hover >}} with the command:
```yaml {label="providerconfig",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: azure.upbound.io/v1beta1
metadata:
name: default
kind: ProviderConfig
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: azure-secret
key: creds
EOF
```
This attaches the Azure credentials, saved as a Kubernetes secret, as a {{< hover label="providerconfig" line="9">}}secretRef{{</ hover>}}.
The {{< hover label="providerconfig" line="11">}}spec.credentials.secretRef.name{{< /hover >}} value is the name of the Kubernetes secret containing the Azure credentials in the {{< hover label="providerconfig" line="10">}}spec.credentials.secretRef.namespace{{< /hover >}}.
## Create a managed resource
A _managed resource_ is anything Crossplane creates and manages outside of the
Kubernetes cluster. This example creates an Azure Virtual Network with
Crossplane. The Virtual Network is a _managed resource_.
{{< hint type="note" >}}
Add your Azure Resource Group name. Follow the Azure documentation to
[create a resource group](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-portal)
if you don't have one.
{{< /hint >}}
{{< editCode >}}
```yaml {label="xr"}
cat <<EOF | kubectl create -f -
apiVersion: network.azure.upbound.io/v1beta1
kind: VirtualNetwork
metadata:
name: crossplane-quickstart-network
spec:
forProvider:
addressSpace:
- 10.0.0.0/16
location: "Sweden Central"
resourceGroupName: docs
EOF
```
{{< /editCode >}}
The {{< hover label="xr" line="2">}}apiVersion{{< /hover >}} and
{{< hover label="xr" line="3">}}kind{{</hover >}} are from the provider's CRDs.
The {{< hover label="xr" line="10">}}spec.forProvider.location{{< /hover >}}
tells Azure which location to use when deploying the resource.
Use `kubectl get virtualnetwork.network` to verify Crossplane created the
Azure Virtual Network.
{{< hint type="tip" >}}
Crossplane created the virtual network when the values `READY` and `SYNCED` are `True`.
This may take up to 5 minutes.
{{< /hint >}}
```shell {copy-lines="1"}
kubectl get virtualnetwork.network
NAME READY SYNCED EXTERNAL-NAME AGE
crossplane-quickstart-network True True crossplane-quickstart-network 10m
```
## Delete the managed resource
Before shutting down your Kubernetes cluster, delete the virtual network just
created.
Use `kubectl delete virtualnetwork.network` to delete the virtual network.
```shell {copy-lines="1"}
kubectl delete virtualnetwork.network crossplane-quickstart-network
virtualnetwork.network.azure.upbound.io "crossplane-quickstart-network" deleted
```
## Next steps
* [**Continue to part 2**]({{< ref "provider-azure-part-2">}}) to create and use
a custom API with Crossplane.
* Explore Azure resources that Crossplane can configure in the
[Provider CRD reference](https://marketplace.upbound.io/providers/upbound/provider-family-azure/).
* Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with
Crossplane users and contributors.

View File

@ -0,0 +1,608 @@
---
title: GCP Quickstart Part 2
weight: 120
tocHidden: true
aliases:
- /master/getting-started/provider-azure-part-3
---
{{< hint "important" >}}
This guide is part 2 of a series.
[**Part 1**]({{<ref "provider-gcp" >}}) covers
to installing Crossplane and connect your Kubernetes cluster to GCP.
{{< /hint >}}
This guide walks you through building and accessing a custom API with
Crossplane.
## Prerequisites
* Complete [quickstart part 1]({{<ref "provider-gcp" >}}) connecting Kubernetes
to GCP.
* a GCP account with permissions to create a GCP
[storage bucket](https://cloud.google.com/storage) and a
[Pub/Sub topic](https://cloud.google.com/pubsub).
{{<expand "Skip part 1 and just get started" >}}
1. Add the Crossplane Helm repository and install Crossplane.
```shell
helm repo add \
crossplane-stable https://charts.crossplane.io/stable
helm repo update
&&
helm install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace
```
2. When the Crossplane pods finish installing and are ready, apply the GCP
Provider.
```yaml {label="provider",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-gcp-storage
spec:
package: xpkg.upbound.io/upbound/provider-gcp-storage:v0.41.0
EOF
```
3. Create a file called `gcp-credentials.json` with your GCP service account
JSON file.
{{< hint "tip" >}}
The
[GCP documentation](https://cloud.google.com/iam/docs/creating-managing-service-account-keys)
provides information on how to generate a service account JSON file.
{{< /hint >}}
4. Create a Kubernetes secret from the GCP JSON file
```shell {label="kube-create-secret",copy-lines="all"}
kubectl create secret \
generic gcp-secret \
-n crossplane-system \
--from-file=creds=./gcp-credentials.json
```
5. Create a _ProviderConfig_
Include your
{{< hover label="providerconfig" line="7" >}}GCP project ID{{< /hover >}} in the
_ProviderConfig_ settings.
{{< hint type="tip" >}}
Find your GCP project ID from the `project_id` field of the
`gcp-credentials.json` file.
{{< /hint >}}
{{< editCode >}}
```yaml {label="providerconfig",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: gcp.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
projectID: $@<PROJECT_ID>$@
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: gcp-secret
key: creds
EOF
```
{{< /editCode >}}
{{</expand >}}
## Install the PubSub Provider
Part 1 only installed the GCP Storage Provider. This section deploys a
PubSub Topic along with a GCP storage bucket.
First install the GCP PubSub Provider.
Add the new Provider to the cluster.
```yaml
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-gcp-pubsub
spec:
package: xpkg.upbound.io/upbound/provider-gcp-pubsub:v0.41.0
EOF
```
View the new PubSub provider with `kubectl get providers`.
```shell {copy-lines="1"}
kubectl get providers
NAME INSTALLED HEALTHY PACKAGE AGE
provider-gcp-pubsub True True xpkg.upbound.io/upbound/provider-gcp-pubsub:v0.41.0 39s
provider-gcp-storage True True xpkg.upbound.io/upbound/provider-gcp-storage:v0.41.0 13m
upbound-provider-family-gcp True True xpkg.upbound.io/upbound/provider-family-gcp:v0.41.0 12m
```
## Create a custom API
<!-- vale alex.Condescending = NO -->
Crossplane allows you to build your own custom APIs for your users, abstracting
away details about the cloud provider and their resources. You can make your API
as complex or simple as you wish.
<!-- vale alex.Condescending = YES -->
The custom API is a Kubernetes object.
Here is an example custom API.
```yaml {label="exAPI"}
apiVersion: database.example.com/v1alpha1
kind: NoSQL
metadata:
name: my-nosql-database
spec:
location: "US"
```
Like any Kubernetes object the API has a
{{<hover label="exAPI" line="1">}}version{{</hover>}},
{{<hover label="exAPI" line="2">}}kind{{</hover>}} and
{{<hover label="exAPI" line="5">}}spec{{</hover>}}.
### Define a group and version
To create your own API start by defining an
[API group](https://kubernetes.io/docs/reference/using-api/#api-groups) and
[version](https://kubernetes.io/docs/reference/using-api/#api-versioning).
The _group_ can be any value, but common convention is to map to a fully
qualified domain name.
<!-- vale gitlab.SentenceLength = NO -->
The version shows how mature or stable the API is and increments when changing,
adding or removing fields in the API.
<!-- vale gitlab.SentenceLength = YES -->
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.
This guide uses the group
{{<hover label="version" line="1">}}database.example.com{{</hover>}}.
Because this is the first version of the API, this guide uses the version
{{<hover label="version" line="1">}}v1alpha1{{</hover>}}.
```yaml {label="version",copy-lines="none"}
apiVersion: database.example.com/v1alpha1
```
### Define a kind
The API group is a logical collection of related APIs. In a group are
individual kinds representing different resources.
For example a `queue` group may have a `PubSub` and `CloudTask` kinds.
The `kind` can be anything, but it must be
[UpperCamelCased](https://kubernetes.io/docs/contribute/style/style-guide/#use-upper-camel-case-for-api-objects).
This API's kind is
{{<hover label="kind" line="2">}}PubSub{{</hover>}}
```yaml {label="kind",copy-lines="none"}
apiVersion: queue.example.com/v1alpha1
kind: PubSub
```
### Define a spec
The most important part of an API is the schema. The schema defines the inputs
accepted from users.
This API allows users to provide a
{{<hover label="spec" line="4">}}location{{</hover>}} of where to run their
cloud resources.
All other resource settings can't be configurable by the users. This allows
Crossplane to enforce any policies and standards without worrying about
user errors.
```yaml {label="spec",copy-lines="none"}
apiVersion: queue.example.com/v1alpha1
kind: PubSub
spec:
location: "US"
```
### Apply the API
Crossplane uses
{{<hover label="xrd" line="3">}}Composite Resource Definitions{{</hover>}}
(also called an `XRD`) to install your custom API in
Kubernetes.
The XRD {{<hover label="xrd" line="6">}}spec{{</hover>}} contains all the
information about the API including the
{{<hover label="xrd" line="7">}}group{{</hover>}},
{{<hover label="xrd" line="12">}}version{{</hover>}},
{{<hover label="xrd" line="9">}}kind{{</hover>}} and
{{<hover label="xrd" line="13">}}schema{{</hover>}}.
The XRD's {{<hover label="xrd" line="5">}}name{{</hover>}} must be the
combination of the {{<hover label="xrd" line="9">}}plural{{</hover>}} and
{{<hover label="xrd" line="7">}}group{{</hover>}}.
The {{<hover label="xrd" line="13">}}schema{{</hover>}} uses the
{{<hover label="xrd" line="14">}}OpenAPIv3{{</hover>}} specification to define
the API {{<hover label="xrd" line="17">}}spec{{</hover>}}.
The API defines a {{<hover label="xrd" line="20">}}location{{</hover>}} that
must be {{<hover label="xrd" line="22">}}oneOf{{</hover>}} either
{{<hover label="xrd" line="23">}}EU{{</hover>}} or
{{<hover label="xrd" line="24">}}US{{</hover>}}.
Apply this XRD to create the custom API in your Kubernetes cluster.
```yaml {label="xrd",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: pubsubs.queue.example.com
spec:
group: queue.example.com
names:
kind: PubSub
plural: pubsubs
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
location:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
required:
- location
served: true
referenceable: true
claimNames:
kind: PubSubClaim
plural: pubsubclaims
EOF
```
Adding the {{<hover label="xrd" line="29">}}claimNames{{</hover>}} allows users
to access this API either at the cluster level with the
{{<hover label="xrd" line="9">}}pubsub{{</hover>}} endpoint or in a namespace
with the
{{<hover label="xrd" line="29">}}pubsubclaim{{</hover>}} endpoint.
The namespace scoped API is a Crossplane _Claim_.
{{<hint "tip" >}}
For more details on the fields and options of Composite Resource Definitions
read the
[XRD documentation]({{<ref "../concepts/composite-resource-definitions">}}).
{{< /hint >}}
View the installed XRD with `kubectl get xrd`.
```shell {copy-lines="1"}
kubectl get xrd
NAME ESTABLISHED OFFERED AGE
pubsubs.queue.example.com True True 7s
```
View the new custom API endpoints with `kubectl api-resources | grep pubsub`
```shell {copy-lines="1",label="apiRes"}
kubectl api-resources | grep queue.example
pubsubclaims queue.example.com/v1alpha1 true PubSubClaim
pubsubs queue.example.com/v1alpha1 false PubSub
```
## Create a deployment template
When users access the custom API Crossplane takes their inputs and combines them
with a template describing what infrastructure to deploy. Crossplane calls this
template a _Composition_.
The {{<hover label="comp" line="3">}}Composition{{</hover>}} defines all the
cloud resources to deploy.
Each entry in the template
is a full resource definitions, defining all the resource settings and metadata
like labels and annotations.
This template creates a GCP
{{<hover label="comp" line="10">}}Storage{{</hover>}}
{{<hover label="comp" line="11">}}Bucket{{</hover>}} and a
{{<hover label="comp" line="25">}}PubSub{{</hover>}}
{{<hover label="comp" line="26">}}Topic{{</hover>}}.
This Composition takes the user's
{{<hover label="comp" line="16">}}location{{</hover>}} input and uses it as the
{{<hover label="comp" line="14">}}location{{</hover>}} used in the individual
resource.
{{<hint "important" >}}
This Composition uses an array of resource templates. You can patch each
template with data copied from the custom API. Crossplane calls this a _Patch
and Transform_ Composition.
You don't have to use Patch and Transform. Crossplane supports a variety of
alternatives, including Go Templating and CUE. You can also write a function in
Go or Python to template your resources.
Read the [Composition documentation]({{<ref "../concepts/compositions">}}) for
more information on configuring Compositions and all the available options.
{{< /hint >}}
Apply this Composition to your cluster.
```yaml {label="comp",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: topic-with-bucket
spec:
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: crossplane-quickstart-bucket
base:
apiVersion: storage.gcp.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
location: "US"
patches:
- fromFieldPath: "spec.location"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "EU"
US: "US"
- name: crossplane-quickstart-topic
base:
apiVersion: pubsub.gcp.upbound.io/v1beta1
kind: Topic
spec:
forProvider:
messageStoragePolicy:
- allowedPersistenceRegions:
- "us-central1"
patches:
- fromFieldPath: "spec.location"
toFieldPath: "spec.forProvider.messageStoragePolicy[0].allowedPersistenceRegions[0]"
transforms:
- type: map
map:
EU: "europe-central2"
US: "us-central1"
compositeTypeRef:
apiVersion: queue.example.com/v1alpha1
kind: PubSub
EOF
```
The {{<hover label="comp" line="40">}}compositeTypeRef{{</hover >}} defines
which custom APIs can use this template to create resources.
A Composition uses a pipeline of _composition functions_ to define the cloud
resources to deploy. This template uses
{{<hover label="comp" line="10">}}function-patch-and-transform{{</hover>}}.
You must install the function before you can use it in a Composition.
Apply this Function to install `function-patch-and-transform`:
```yaml {label="install"}
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
name: function-patch-and-transform
spec:
package: xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.1.4
EOF
```
{{<hint "tip" >}}
Read the [Composition documentation]({{<ref "../concepts/compositions">}}) for
more information on configuring Compositions and all the available options.
Read the
[Patch and Transform function documentation]({{<ref "../guides/function-patch-and-transform">}})
for more information on how it uses patches to map user inputs to Composition
resource templates.
{{< /hint >}}
View the Composition with `kubectl get composition`
```shell {copy-lines="1"}
kubectl get composition
NAME XR-KIND XR-APIVERSION AGE
topic-with-bucket PubSub queue.example.com 3s
```
## Access the custom API
With the custom API (XRD) installed and associated to a resource template
(Composition) users can access the API to create resources.
Create a {{<hover label="xr" line="2">}}PubSub{{</hover>}} object to create the
cloud resources.
```yaml {copy-lines="all",label="xr"}
cat <<EOF | kubectl apply -f -
apiVersion: queue.example.com/v1alpha1
kind: PubSub
metadata:
name: my-pubsub-queue
spec:
location: "US"
EOF
```
View the resource with `kubectl get pubsub`.
```shell {copy-lines="1"}
kubectl get pubsub
NAME SYNCED READY COMPOSITION AGE
my-pubsub-queue True True topic-with-bucket 2m12s
```
This object is a Crossplane _composite resource_ (also called an `XR`).
It's a
single object representing the collection of resources created from the
Composition template.
View the individual resources with `kubectl get managed`
```shell {copy-lines="1"}
kubectl get managed
NAME READY SYNCED EXTERNAL-NAME AGE
topic.pubsub.gcp.upbound.io/my-pubsub-queue-cjswx True True my-pubsub-queue-cjswx 3m4s
NAME READY SYNCED EXTERNAL-NAME AGE
bucket.storage.gcp.upbound.io/my-pubsub-queue-vljg9 True True my-pubsub-queue-vljg9 3m4s
```
Delete the resources with `kubectl delete pubsub`.
```shell {copy-lines="1"}
kubectl delete pubsub my-pubsub-queue
pubsub.queue.example.com "my-pubsub-queue" deleted
```
Verify Crossplane deleted the resources with `kubectl get managed`
{{<hint "note" >}}
It may take up to 5 minutes to delete the resources.
{{< /hint >}}
```shell {copy-lines="1"}
kubectl get managed
No resources found
```
## Using the API with namespaces
Accessing the API `pubsub` happens at the cluster scope.
Most organizations
isolate their users into namespaces.
A Crossplane _Claim_ is the custom API in a namespace.
Creating a _Claim_ is just like accessing the custom API endpoint, but with the
{{<hover label="claim" line="3">}}kind{{</hover>}}
from the custom API's `claimNames`.
Create a new namespace to test create a Claim in.
```shell
kubectl create namespace crossplane-test
```
Then create a Claim in the `crossplane-test` namespace.
```yaml {label="claim",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: queue.example.com/v1alpha1
kind: PubSubClaim
metadata:
name: my-pubsub-queue
namespace: crossplane-test
spec:
location: "US"
EOF
```
View the Claim with `kubectl get claim -n crossplane-test`.
```shell {copy-lines="1"}
kubectl get claim -n crossplane-test
NAME SYNCED READY CONNECTION-SECRET AGE
my-pubsub-queue True True 2m10s
```
The Claim automatically creates a composite resource, which creates the managed
resources.
View the Crossplane created composite resource with `kubectl get composite`.
```shell {copy-lines="1"}
kubectl get composite
NAME SYNCED READY COMPOSITION AGE
my-pubsub-queue-7bm9n True True topic-with-bucket 3m10s
```
Again, view the managed resources with `kubectl get managed`.
```shell {copy-lines="1"}
kubectl get managed
NAME READY SYNCED EXTERNAL-NAME AGE
topic.pubsub.gcp.upbound.io/my-pubsub-queue-7bm9n-6kdq4 True True my-pubsub-queue-7bm9n-6kdq4 3m22s
NAME READY SYNCED EXTERNAL-NAME AGE
bucket.storage.gcp.upbound.io/my-pubsub-queue-7bm9n-hhwx8 True True my-pubsub-queue-7bm9n-hhwx8 3m22s
```
Deleting the Claim deletes all the Crossplane generated resources.
`kubectl delete claim -n crossplane-test my-pubsub-queue`
```shell {copy-lines="1"}
kubectl delete pubsubclaim my-pubsub-queue -n crossplane-test
pubsubclaim.queue.example.com "my-pubsub-queue" deleted
```
{{<hint "note" >}}
It may take up to 5 minutes to delete the resources.
{{< /hint >}}
Verify Crossplane deleted the composite resource with `kubectl get composite`.
```shell {copy-lines="1"}
kubectl get composite
No resources found
```
Verify Crossplane deleted the managed resources with `kubectl get managed`.
```shell {copy-lines="1"}
kubectl get managed
No resources found
```
## Next steps
* Explore AWS resources that Crossplane can configure in the
[Provider CRD reference](https://marketplace.upbound.io/providers/upbound/provider-family-aws/).
* Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with
Crossplane users and contributors.
* Read more about the [Crossplane concepts]({{<ref "../concepts">}}) to find out what else you can do
with Crossplane.

View File

@ -0,0 +1,251 @@
---
title: GCP Quickstart
weight: 140
---
Connect Crossplane to GCP to create and manage cloud resources from Kubernetes
with the
[Upbound GCP Provider](https://marketplace.upbound.io/providers/upbound/provider-family-gcp/).
This guide is in two parts:
* Part 1 walks through installing Crossplane, configuring the provider to
authenticate to GCP and creating a _Managed Resource_ in GCP directly from
your Kubernetes cluster. This shows Crossplane can communicate with GCP.
* [Part 2]({{< ref "provider-gcp-part-2" >}}) shows how to build and access a
custom API with Crossplane.
## Prerequisites
This quickstart requires:
* a Kubernetes cluster with at least 2 GB of RAM
* permissions to create pods and secrets in the Kubernetes cluster
* [Helm](https://helm.sh/) version v3.2.0 or later
* a GCP account with permissions to create a storage bucket
* GCP [account keys](https://cloud.google.com/iam/docs/creating-managing-service-account-keys)
* GCP [Project ID](https://support.google.com/googleapi/answer/7014113?hl=en)
{{<include file="/master/getting-started/install-crossplane-include.md" type="page" >}}
## Install the GCP provider
Install the provider into the Kubernetes cluster with a Kubernetes configuration
file.
```shell {label="provider",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-gcp-storage
spec:
package: xpkg.upbound.io/upbound/provider-gcp-storage:v0.41.0
EOF
```
The Crossplane {{< hover label="provider" line="3" >}}Provider{{</hover>}}
installs the Kubernetes _Custom Resource Definitions_ (CRDs) representing GCP storage
services. These CRDs allow you to create GCP resources directly inside
Kubernetes.
Verify the provider installed with `kubectl get providers`.
```shell {copy-lines="1",label="getProvider"}
kubectl get providers
NAME INSTALLED HEALTHY PACKAGE AGE
provider-gcp-storage True True xpkg.upbound.io/upbound/provider-gcp-storage:v0.41.0 36s
upbound-provider-family-gcp True True xpkg.upbound.io/upbound/provider-family-gcp:v0.41.0 29s
```
The Storage Provider installs a second Provider, the
{{<hover label="getProvider" line="4">}}upbound-provider-family-gcp{{</hover>}}
provider.
The family provider manages authentication to GCP across all GCP family
Providers.
You can view the new CRDs with `kubectl get crds`.
Every CRD maps to a unique GCP service Crossplane can provision and manage.
{{< hint "tip" >}}
See details about all the supported CRDs in the
[Upbound Marketplace](https://marketplace.upbound.io/providers/upbound/provider-family-gcp/).
{{< /hint >}}
## Create a Kubernetes secret for GCP
The provider requires credentials to create and manage GCP resources. Providers
use a Kubernetes _Secret_ to connect the credentials to the provider.
First generate a Kubernetes _Secret_ from a Google Cloud service account JSON
file and then configure the Provider to use it.
### Generate a GCP service account JSON file
For basic user authentication, use a Google Cloud service account JSON file.
{{< hint "tip" >}}
The
[GCP documentation](https://cloud.google.com/iam/docs/creating-managing-service-account-keys)
provides information on how to generate a service account JSON file.
{{< /hint >}}
Save this JSON file as `gcp-credentials.json`
### Create a Kubernetes secret with the GCP credentials
A Kubernetes generic secret has a name and contents. Use
{{< hover label="kube-create-secret" line="1">}}kubectl create secret{{< /hover >}}
to generate the secret object named
{{< hover label="kube-create-secret" line="2">}}gcp-secret{{< /hover >}} in the
{{< hover label="kube-create-secret" line="3">}}crossplane-system{{</ hover >}}
namespace.
Use the {{< hover label="kube-create-secret" line="4">}}--from-file={{</hover>}}
argument to set the value to the contents of the
{{< hover label="kube-create-secret" line="4">}}gcp-credentials.json{{< /hover >}}
file.
```shell {label="kube-create-secret",copy-lines="all"}
kubectl create secret \
generic gcp-secret \
-n crossplane-system \
--from-file=creds=./gcp-credentials.json
```
View the secret with `kubectl describe secret`
{{< hint "note" >}}
The file size may be a different depending on the contents.
{{< /hint >}}
```shell {copy-lines="1"}
kubectl describe secret gcp-secret -n crossplane-system
Name: gcp-secret
Namespace: crossplane-system
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
creds: 2330 bytes
```
{{< hint type="note" >}}
The
[Authentication](https://docs.upbound.io/providers/provider-gcp/authentication/)
section of the GCP Provider documentation describes other authentication methods.
{{< /hint >}}
## Create a ProviderConfig
A `ProviderConfig` customizes the settings of the GCP Provider.
Include your
{{< hover label="providerconfig" line="7" >}}GCP project ID{{< /hover >}} in the
_ProviderConfig_ settings.
{{< hint "tip" >}}
Find your GCP project ID from the `project_id` field of the
`gcp-credentials.json` file.
{{< /hint >}}
Apply the
{{< hover label="providerconfig" line="2">}}ProviderConfig{{</ hover >}} with
the command:
{{< editCode >}}
```yaml {label="providerconfig",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: gcp.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
projectID: $@<PROJECT_ID>$@
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: gcp-secret
key: creds
EOF
```
{{< /editCode >}}
This attaches the GCP credentials, saved as a Kubernetes secret, as a
{{< hover label="providerconfig" line="10">}}secretRef{{</ hover>}}.
The {{< hover label="providerconfig" line="12">}}spec.credentials.secretRef.name{{< /hover >}} value is the name of the Kubernetes secret containing the GCP credentials in the
{{< hover label="providerconfig" line="11">}}spec.credentials.secretRef.namespace{{< /hover >}}.
## Create a managed resource
A _managed resource_ is anything Crossplane creates and manages outside of the
Kubernetes cluster. This example creates a GCP storage bucket with Crossplane.
The storage bucket is a _managed resource_.
{{< hint "note" >}}
To generate a unique name use
{{<hover label="xr" line="5">}}generateName{{</hover >}} instead of `name`.
{{< /hint >}}
Create the Bucket with the following command:
```yaml {label="xr",copy-lines="all"}
cat <<EOF | kubectl create -f -
apiVersion: storage.gcp.upbound.io/v1beta1
kind: Bucket
metadata:
generateName: crossplane-bucket-
labels:
docs.crossplane.io/example: provider-gcp
spec:
forProvider:
location: US
providerConfigRef:
name: default
EOF
```
The {{< hover label="xr" line="2">}}apiVersion{{< /hover >}} and
{{< hover label="xr" line="3">}}kind{{</hover >}} are from the provider's CRDs.
The {{< hover label="xr" line="10">}}spec.forProvider.location{{< /hover >}}
tells GCP which GCP region to use when deploying resources.
For a
{{<hover label="xr" line="3">}}bucket{{</hover >}} the
region can be any
[GCP multi-region location](https://cloud.google.com/storage/docs/locations#location-mr)
Use `kubectl get bucket` to verify Crossplane created the bucket.
{{< hint type="tip" >}}
Crossplane created the bucket when the values `READY` and `SYNCED` are `True`.
This may take up to 5 minutes.
{{< /hint >}}
```shell {copy-lines="1"}
kubectl get bucket
NAME READY SYNCED EXTERNAL-NAME AGE
crossplane-bucket-8b7gw True True crossplane-bucket-8b7gw 2m2s
```
## Delete the managed resource
Before shutting down your Kubernetes cluster, delete the GCP bucket just
created.
Use `kubectl delete bucket` to remove the bucket.
{{<hint "tip" >}}
Use the `--selector` flag to delete by label instead of by name.
{{</hint>}}
```shell {copy-lines="1"}
kubectl delete bucket --selector docs.crossplane.io/example=provider-gcp
bucket.storage.gcp.upbound.io "crossplane-bucket-8b7gw" deleted
```
## Next steps
* [**Continue to part 2**]({{< ref "provider-gcp-part-2">}}) to create a
Crossplane _Composite Resource_ and _Claim_.
* Explore GCP resources that can Crossplane can configure in the
[Provider CRD reference](https://marketplace.upbound.io/providers/upbound/provider-family-gcp/).
* Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with
Crossplane users and contributors.

View File

@ -0,0 +1,5 @@
---
title: Guides
weight: 100
description: Crossplane integrations and detailed examples.
---

View File

@ -0,0 +1,216 @@
---
title: Configuring Crossplane with Argo CD
weight: 270
---
[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 of your resources. There are
configuration details 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). There are different ways to configure
how Argo CD 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
#### Set Resource Tracking Method
In order for Argo CD to correctly track Application resources that contain Crossplane related objects it needs
to be configured to use the annotation mechanism.
To configure it, edit the `argocd-cm` `ConfigMap` in the `argocd` `Namespace` as such:
```yaml
apiVersion: v1
kind: ConfigMap
data:
application.resourceTrackingMethod: annotation
```
#### Set Health Status
Argo CD has a built-in health assessment for Kubernetes resources. Some checks are supported by the community directly
in Argo's [repository](https://github.com/argoproj/argo-cd/tree/master/resource_customizations). For example the `Provider`
from `pkg.crossplane.io` has already been declared 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`.
{{<hint "note">}}
{{<hover label="argocfg" line="22">}} ProviderConfig{{</hover>}} may have no status or a `status.users` field.
{{</hint>}}
```yaml {label="argocfg"}
apiVersion: v1
kind: ConfigMap
data:
application.resourceTrackingMethod: annotation
resource.customizations: |
"*.upbound.io/*":
health.lua: |
health_status = {
status = "Progressing",
message = "Provisioning ..."
}
local function contains (table, val)
for i, v in ipairs(table) do
if v == val then
return true
end
end
return false
end
local has_no_status = {
"ProviderConfig",
"ProviderConfigUsage"
}
if obj.status == nil or next(obj.status) == nil and contains(has_no_status, obj.kind) then
health_status.status = "Healthy"
health_status.message = "Resource is up-to-date."
return health_status
end
if obj.status == nil or next(obj.status) == nil or obj.status.conditions == nil then
if obj.kind == "ProviderConfig" and obj.status.users ~= nil then
health_status.status = "Healthy"
health_status.message = "Resource is in use."
return health_status
end
return health_status
end
for i, condition in ipairs(obj.status.conditions) do
if condition.type == "LastAsyncOperation" then
if condition.status == "False" then
health_status.status = "Degraded"
health_status.message = condition.message
return health_status
end
end
if condition.type == "Synced" then
if condition.status == "False" then
health_status.status = "Degraded"
health_status.message = condition.message
return health_status
end
end
if condition.type == "Ready" then
if condition.status == "True" then
health_status.status = "Healthy"
health_status.message = "Resource is up-to-date."
return health_status
end
end
end
return health_status
"*.crossplane.io/*":
health.lua: |
health_status = {
status = "Progressing",
message = "Provisioning ..."
}
local function contains (table, val)
for i, v in ipairs(table) do
if v == val then
return true
end
end
return false
end
local has_no_status = {
"Composition",
"CompositionRevision",
"DeploymentRuntimeConfig",
"ControllerConfig",
"ProviderConfig",
"ProviderConfigUsage"
}
if obj.status == nil or next(obj.status) == nil and contains(has_no_status, obj.kind) then
health_status.status = "Healthy"
health_status.message = "Resource is up-to-date."
return health_status
end
if obj.status == nil or next(obj.status) == nil or obj.status.conditions == nil then
if obj.kind == "ProviderConfig" and obj.status.users ~= nil then
health_status.status = "Healthy"
health_status.message = "Resource is in use."
return health_status
end
return health_status
end
for i, condition in ipairs(obj.status.conditions) do
if condition.type == "LastAsyncOperation" then
if condition.status == "False" then
health_status.status = "Degraded"
health_status.message = condition.message
return health_status
end
end
if condition.type == "Synced" then
if condition.status == "False" then
health_status.status = "Degraded"
health_status.message = condition.message
return health_status
end
end
if contains({"Ready", "Healthy", "Offered", "Established"}, condition.type) then
if condition.status == "True" then
health_status.status = "Healthy"
health_status.message = "Resource is up-to-date."
return health_status
end
end
end
return health_status
```
#### Set Resource Exclusion
Crossplane providers generates a `ProviderConfigUsage` for each of the managed resource (MR) it handles. This resource
enable representing the relationship between MR and a ProviderConfig so that the controller can use it as finalizer when a
ProviderConfig is deleted. End-users of Crossplane are not expected to interact with this resource.
Argo CD UI reactivity can be impacted as the number of resource and types grow. To help keep this number low we
recommend hiding all `ProviderConfigUsage` resources from Argo CD UI.
To configure resource exclusion edit the `argocd-cm` `ConfigMap` in the `argocd` `Namespace` as such:
```yaml
apiVersion: v1
kind: ConfigMap
data:
resource.exclusions: |
- apiGroups:
- "*"
kinds:
- ProviderConfigUsage
```
The use of `"*"` as apiGroups will enable the mechanism for all Crossplane Providers.
#### Increase K8s Client QPS
As the number of CRDs grow on a control plane it will increase 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 a large number of CRDs.
The default value of `ARGOCD_K8S_CLIENT_QPS` is 50, modifying the value will also update `ARGOCD_K8S_CLIENT_BURST` as it
is default to `ARGOCD_K8S_CLIENT_QPS` x 2.

View File

@ -0,0 +1,10 @@
---
title: Disaster Recovery with Crossplane
weight: 10
---
AWS wrote a guide covering disaster recovery with Crossplane. The guide covers
using Crossplane to provision resources and Velero for Kubernetes backup and
recovery.
[Read the guide on AWS](https://aws.amazon.com/blogs/opensource/disaster-recovery-when-using-crossplane-for-infrastructure-provisioning-on-aws/).

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,285 @@
---
title: Import Existing Resources
weight: 200
---
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`]({{<ref "/v1.16/concepts/managed-resources#managementpolicies">}})
field enables importing external resources into Crossplane.
Crossplane can import resources either [manually]({{<ref "#import-resources-manually">}})
or [automatically]({{<ref "#import-resources-automatically">}}).
## Import resources manually
Crossplane can discover and import existing Provider resources by matching the
`crossplane.io/external-name` annotation in a managed resource.
To import an existing external resource in a Provider, create a new managed
resource with the `crossplane.io/external-name` annotation. Set the annotation
value to the name of the resource in the Provider.
For example, to import an existing GCP Network named
{{<hover label="annotation" line="5">}}my-existing-network{{</hover>}},
create a new managed resource and use the
{{<hover label="annotation" line="5">}}my-existing-network{{</hover>}} in the
annotation.
```yaml {label="annotation",copy-lines="none"}
apiVersion: compute.gcp.crossplane.io/v1beta1
kind: Network
metadata:
annotations:
crossplane.io/external-name: my-existing-network
```
The {{<hover label="name" line="5">}}metadata.name{{</hover>}}
field can be anything you want. For example,
{{<hover label="name" line="5">}}imported-network{{</hover>}}.
{{< hint "note" >}}
This name is the
name of the Kubernetes object. It's not related to the resource name inside the
Provider.
{{< /hint >}}
```yaml {label="name",copy-lines="none"}
apiVersion: compute.gcp.crossplane.io/v1beta1
kind: Network
metadata:
name: imported-network
annotations:
crossplane.io/external-name: my-existing-network
```
Leave the
{{<hover label="fp" line="8">}}spec.forProvider{{</hover>}} field empty.
Crossplane imports the settings and automatically applies them to the managed
resource.
{{< hint "important" >}}
If the managed resource has _required_ fields in the
{{<hover label="fp" line="8">}}spec.forProvider{{</hover>}} you must add it to
the `forProvider` field.
The values of those fields must match what's inside the Provider or Crossplane
overwrites the existing values.
{{< /hint >}}
```yaml {label="fp",copy-lines="all"}
apiVersion: compute.gcp.crossplane.io/v1beta1
kind: Network
metadata:
name: imported-network
annotations:
crossplane.io/external-name: my-existing-network
spec:
forProvider: {}
```
Crossplane now controls and manages this imported resource. Any changes to the
managed resource `spec` changes the external resource.
## Import resources automatically
Automatically import external resources with an `Observe` [management policy]({{<ref "/v1.16/concepts/managed-resources#managementpolicies">}}).
Crossplane imports observe only resources but never changes or deletes the
resources.
{{<hint "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.
{{< /hint >}}
<!-- vale off -->
### Apply the Observe management policy
<!-- vale on -->
Create a new managed resource matching the
{{<hover label="oo-policy" line="1">}}apiVersion{{</hover>}} and
{{<hover label="oo-policy" line="2">}}kind{{</hover>}} of the resource
to import and add
{{<hover label="oo-policy" line="4">}}managementPolicies: ["Observe"]{{</hover>}} to the
{{<hover label="oo-policy" line="3">}}spec{{</hover>}}
For example, to import a GCP SQL DatabaseInstance, create a new resource with
the {{<hover label="oo-policy" line="4">}}managementPolicies: ["Observe"]{{</hover>}}
set.
```yaml {label="oo-policy",copy-lines="none"}
apiVersion: sql.gcp.upbound.io/v1beta1
kind: DatabaseInstance
spec:
managementPolicies: ["Observe"]
```
### Add the external-name annotation
Add the {{<hover label="oo-ex-name" line="5">}}crossplane.io/external-name{{</hover>}}
annotation for the resource. This name must match the name inside the Provider.
For example, for a GCP database named
{{<hover label="oo-ex-name" line="5">}}my-external-database{{</hover>}}, apply
the
{{<hover label="oo-ex-name" line="5">}}crossplane.io/external-name{{</hover>}}
annotation with the value
{{<hover label="oo-ex-name" line="5">}}my-external-database{{</hover>}}.
```yaml {label="oo-ex-name",copy-lines="none"}
apiVersion: sql.gcp.upbound.io/v1beta1
kind: DatabaseInstance
metadata:
annotations:
crossplane.io/external-name: my-external-database
spec:
managementPolicies: ["Observe"]
```
### Create a Kubernetes object name
Create a {{<hover label="oo-name" line="4">}}name{{</hover>}} to use for the
Kubernetes object.
For example, name the Kubernetes object
{{<hover label="oo-name" line="4">}}my-imported-database{{</hover>}}.
```yaml {label="oo-name",copy-lines="none"}
apiVersion: sql.gcp.upbound.io/v1beta1
kind: DatabaseInstance
metadata:
name: my-imported-database
annotations:
crossplane.io/external-name: my-external-database
spec:
managementPolicies: ["Observe"]
```
### Identify a specific external resource
If more than one resource inside the Provider shares the same name, identify the
specific resource with a unique
{{<hover line="9" label="oo-region">}}spec.forProvider{{</hover>}} field.
For example, only import the GCP SQL database in the
{{<hover line="10" label="oo-region">}}us-central1{{</hover>}} region.
```yaml {label="oo-region"}
apiVersion: sql.gcp.upbound.io/v1beta1
kind: DatabaseInstance
metadata:
name: my-imported-database
annotations:
crossplane.io/external-name: my-external-database
spec:
managementPolicies: ["Observe"]
forProvider:
region: "us-central1"
```
### 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
Crossplane discovers the managed resource and populates the
{{<hover label="ooPopulated" line="12">}}status.atProvider{{</hover>}}
fields with the values from the external resource.
```yaml {label="ooPopulated",copy-lines="none"}
apiVersion: sql.gcp.upbound.io/v1beta1
kind: DatabaseInstance
metadata:
name: my-imported-database
annotations:
crossplane.io/external-name: my-external-database
spec:
managementPolicies: ["Observe"]
forProvider:
region: us-central1
status:
atProvider:
connectionName: crossplane-playground:us-central1:my-external-database
databaseVersion: POSTGRES_14
deletionProtection: true
firstIpAddress: 35.184.74.79
id: my-external-database
publicIpAddress: 35.184.74.79
region: us-central1
# Removed for brevity
settings:
- activationPolicy: ALWAYS
availabilityType: REGIONAL
diskSize: 100
# Removed for brevity
pricingPlan: PER_USE
tier: db-custom-4-26624
version: 4
conditions:
- lastTransitionTime: "2023-02-22T07:16:51Z"
reason: Available
status: "True"
type: Ready
- lastTransitionTime: "2023-02-22T07:16:51Z"
reason: ReconcileSuccess
status: "True"
type: Synced
```
<!-- vale off -->
## Control imported ObserveOnly resources
<!-- vale on -->
Crossplane can take active control of observe only imported resources by
changing the `managementPolicies` after import.
Change the {{<hover label="fc" line="8">}}managementPolicies{{</hover>}} field
of the managed resource to
{{<hover label="fc" line="8">}}["*"]{{</hover>}}.
Copy any required parameter values from
{{<hover label="fc" line="16">}}status.atProvider{{</hover>}} and provide them
in {{<hover label="fc" line="9">}}spec.forProvider{{</hover>}}.
{{< hint "tip" >}}
Manually copy the important `spec.atProvider` values to `spec.forProvider`.
{{< /hint >}}
```yaml {label="fc"}
apiVersion: sql.gcp.upbound.io/v1beta1
kind: DatabaseInstance
metadata:
name: my-imported-database
annotations:
crossplane.io/external-name: my-external-database
spec:
managementPolicies: ["*"]
forProvider:
databaseVersion: POSTGRES_14
region: us-central1
settings:
- diskSize: 100
tier: db-custom-4-26624
status:
atProvider:
databaseVersion: POSTGRES_14
region: us-central1
# Removed for brevity
settings:
- diskSize: 100
tier: db-custom-4-26624
# Removed for brevity
conditions:
- lastTransitionTime: "2023-02-22T07:16:51Z"
reason: Available
status: "True"
type: Ready
- lastTransitionTime: "2023-02-22T11:16:45Z"
reason: ReconcileSuccess
status: "True"
type: Synced
```
Crossplane now fully manages the imported resource. Crossplane applies any
changes to the managed resource in the Provider's external resource.

View File

@ -0,0 +1,323 @@
---
title: Multi-Tenant Crossplane
weight: 240
---
This guide describes how to use Crossplane effectively in multi-tenant
environments by utilizing Kubernetes primitives and compatible policy
enforcement projects in the cloud-native ecosystem.
## TL;DR
Infrastructure operators in multi-tenant Crossplane environments typically
utilize composition and Kubernetes RBAC to define lightweight, standardized
policies that dictate what level of self-service developers are given when
requesting infrastructure. This is primarily achieved through exposing abstract
resource types at the namespace scope, defining `Roles` for teams and
individuals within that namespace, and patching the `spec.providerConfigRef` of
the underlying managed resources so that they use a specific `ProviderConfig`
and credentials when provisioned from each namespace. Larger organizations, or
those with more complex environments, may choose to incorporate third-party
policy engines, or scale to multiple Crossplane clusters. The following sections
describe each of these scenarios in greater detail.
- [TL;DR](#tldr)
- [Background](#background)
- [Cluster-Scoped Managed Resources](#cluster-scoped-managed-resources)
- [Namespace Scoped Claims](#namespace-scoped-claims)
- [Single Cluster Multi-Tenancy](#single-cluster-multi-tenancy)
- [Composition as an Isolation Mechanism](#composition-as-an-isolation-mechanism)
- [Namespaces as an Isolation Mechanism](#namespaces-as-an-isolation-mechanism)
- [Policy Enforcement with Open Policy Agent](#policy-enforcement-with-open-policy-agent)
- [Multi-Cluster Multi-Tenancy](#multi-cluster-multi-tenancy)
- [Reproducible Platforms with Configuration Packages](#reproducible-platforms-with-configuration-packages)
- [Control Plane of Control Planes](#control-plane-of-control-planes)
## Background
Crossplane is designed to run in multi-tenant environments where many teams are
consuming the services and abstractions provided by infrastructure operators in
the cluster. This functionality is facilitated by two major design patterns in
the Crossplane ecosystem.
### Cluster-Scoped Managed Resources
Typically, Crossplane providers, which supply granular [managed resources] that
reflect an external API, authenticate by using a `ProviderConfig` object that
points to a credentials source (such as a Kubernetes `Secret`, the `Pod`
filesystem, or an environment variable). Then, every managed resource references
a `ProviderConfig` that points to credentials with sufficient permissions to
manage that resource type.
For example, the following `ProviderConfig` for `provider-aws` points to a
Kubernetes `Secret` with AWS credentials.
```yaml
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: cool-aws-creds
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-creds
key: creds
```
If a user desired for these credentials to be used to provision an
`RDSInstance`, they would reference the `ProviderConfig` in the object manifest:
```yaml
apiVersion: database.aws.crossplane.io/v1beta1
kind: RDSInstance
metadata:
name: rdsmysql
spec:
forProvider:
region: us-east-1
dbInstanceClass: db.t3.medium
masterUsername: masteruser
allocatedStorage: 20
engine: mysql
engineVersion: "5.6.35"
skipFinalSnapshotBeforeDeletion: true
providerConfigRef:
name: cool-aws-creds # name of ProviderConfig above
writeConnectionSecretToRef:
namespace: crossplane-system
name: aws-rdsmysql-conn
```
Since both the `ProviderConfig` and all managed resources are cluster-scoped,
the RDS controller in `provider-aws` will resolve this reference by fetching the
`ProviderConfig`, obtaining the credentials it points to, and using those
credentials to reconcile the `RDSInstance`. This means that anyone who has been
given [RBAC] to manage `RDSInstance` objects can use any credentials to do so.
In practice, Crossplane assumes that only folks acting as infrastructure
administrators or platform builders will interact directly with cluster-scoped
resources.
### Namespace Scoped Claims
While managed resources exist at the cluster scope, composite resources, which
are defined using a **CompositeResourceDefinition (XRD)** may exist at either
the cluster or namespace scope. Platform builders define XRDs and
**Compositions** that specify what granular managed resources should be created
in response to the creation of an instance of the XRD. More information about
this architecture can be found in the [Composition] documentation.
Every XRD is exposed at the cluster scope, but only those with `spec.claimNames`
defined will have a namespace-scoped variant.
```yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xmysqlinstances.example.org
spec:
group: example.org
names:
kind: XMySQLInstance
plural: xmysqlinstances
claimNames:
kind: MySQLInstance
plural: mysqlinstances
...
```
When the example above is created, Crossplane will produce two
[CustomResourceDefinitions]:
1. A cluster-scoped type with `kind: XMySQLInstance`. This is referred to as a
**Composite Resource (XR)**.
2. A namespace-scoped type with `kind: MySQLInstance`. This is referred to as a
**Claim (XRC)**.
Platform builders may choose to define an arbitrary number of Compositions that
map to these types, meaning that creating a `MySQLInstance` in a given namespace
can result in the creations of any set of managed resources at the cluster
scope. For instance, creating a `MySQLInstance` could result in the creation of
the `RDSInstance` defined above.
## Single Cluster Multi-Tenancy
Depending on the size and scope of an organization, platform teams may choose to
run one central Crossplane control plane, or many different ones for each team
or business unit. This section will focus on servicing multiple teams within a
single cluster, which may or may not be one of many other Crossplane clusters in
the organization.
### Composition as an Isolation Mechanism
While managed resources always reflect every field that the underlying provider
API exposes, XRDs can have any schema that a platform builder chooses. The
fields in the XRD schema can then be patched onto fields in the underlying
managed resource defined in a Composition, essentially exposing those fields as
configurable to the consumer of the XR or XRC.
This feature serves as a lightweight policy mechanism by only giving the
consumer the ability to customize the underlying resources to the extent the
platform builder desires. For instance, in the examples above, a platform
builder may choose to define a `spec.location` field in the schema of the
`XMySQLInstance` that is an enum with options `east` and `west`. In the
Composition, those fields could map to the `RDSInstance` `spec.region` field,
making the value either `us-east-1` or `us-west-1`. If no other patches were
defined for the `RDSInstance`, giving a user the ability (using RBAC) to create
a `XMySQLInstance` / `MySQLInstance` would be akin to giving the ability to
create a very specifically configured `RDSInstance`, where they can only decide
the region where it lives and they are restricted to two options.
This model is in contrast to many infrastructure as code tools where the end
user must have provider credentials to create the underlying resources that are
rendered from the abstraction. Crossplane takes a different approach, defining
various credentials in the cluster (using the `ProviderConfig`), then giving
only the provider controllers the ability to utilize those credentials and
provision infrastructure on the users behalf. This creates a consistent
permission model, even when using many providers with differing IAM models, by
standardizing on Kubernetes RBAC.
### Namespaces as an Isolation Mechanism
While the ability to define abstract schemas and patches to concrete resource
types using composition is powerful, the ability to define Claim types at the
namespace scope enhances the functionality further by enabling RBAC to be
applied with namespace restrictions. Most users in a cluster do not have access
to cluster-scoped resources as they are considered only relevant to
infrastructure admins by both Kubernetes and Crossplane.
Building on our simple `XMySQLInstance` / `MySQLInstance` example, a platform
builder may choose to define permissions on `MySQLInstance` at the namespace
scope using a `Role`. This allows for giving users the ability to create and
manage `MySQLInstances` in their given namespace, but not the ability to see
those defined in other namespaces.
Furthermore, because the `metadata.namespace` is a field on the XRC, patching can
be utilized to configure managed resources based on the namespace in which the
corresponding XRC was defined. This is especially useful if a platform builder
wants to designate specific credentials or a set of credentials that users in a
given namespace can utilize when provisioning infrastructure using an XRC. This
can be accomplished today by creating one or more `ProviderConfig` objects that
include the name of the namespace in the `ProviderConfig` name. For example, if
any `MySQLInstance` created in the `team-1` namespace should use specific AWS
credentials when the provider controller creates the underlying `RDSInstance`,
the platform builder could:
1. Define a `ProviderConfig` with name `team-1`.
```yaml
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: team-1
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: team-1-creds
key: creds
```
2. Define a `Composition` that patches the namespace of the Claim reference in the XR
to the `providerConfigRef` of the `RDSInstance`.
```yaml
...
resources:
- base:
apiVersion: database.aws.crossplane.io/v1beta1
kind: RDSInstance
spec:
forProvider:
...
patches:
- fromFieldPath: spec.claimRef.namespace
toFieldPath: spec.providerConfigRef.name
policy:
fromFieldPath: Required
```
This would result in the `RDSInstance` using the `ProviderConfig` of whatever
namespace the corresponding `MySQLInstance` was created in.
> Note that this model currently only allows for a single `ProviderConfig` per
> namespace. However, future Crossplane releases should allow for defining a set
> of `ProviderConfig` that can be selected from using [Multiple Source Field
> patching].
### Policy Enforcement with Open Policy Agent
In some Crossplane deployment models, only using composition and RBAC to define
policy will not be flexible enough. However, because Crossplane brings
management of external infrastructure to the Kubernetes API, it is well suited
to integrate with other projects in the cloud-native ecosystem. Organizations
and individuals that need a more robust policy engine, or just prefer a more
general language for defining policy, often turn to [Open Policy Agent] (OPA).
OPA allows platform builders to write custom logic in [Rego], a domain-specific
language. Writing policy in this manner allows for not only incorporating the
information available in the specific resource being evaluated, but also using
other state represented in the cluster. Crossplane users typically install OPA's
[Gatekeeper] to make policy management as streamlined as possible.
> A live demo of using OPA with Crossplane can be viewed [here].
## Multi-Cluster Multi-Tenancy
Organizations that deploy Crossplane across many clusters typically take
advantage of two major features that make managing multiple control planes much
simpler.
### Reproducible Platforms with Configuration Packages
[Configuration packages] allow platform builders to package their XRDs and
Compositions into [OCI images] that can be distributed via any OCI-compliant
image registry. These packages can also declare dependencies on providers,
meaning that a single package can declare all of the granular managed resources,
the controllers that must be deployed to reconcile them, and the abstract types
that expose the underlying resources using composition.
Organizations with many Crossplane deployments utilize Configuration packages to
reproduce their platform in each cluster. This can be as simple as installing
Crossplane with the flag to automatically install a Configuration package
alongside it.
```
helm install crossplane --namespace crossplane-system crossplane-stable/crossplane --set configuration.packages='{"registry.upbound.io/xp/getting-started-with-aws:latest"}'
```
### Control Plane of Control Planes
Taking the multi-cluster multi-tenancy model one step further, some
organizations opt to manage their many Crossplane clusters using a single
central Crossplane control plane. This requires setting up the central cluster,
then using a provider to spin up new clusters (such as an [EKS Cluster] using
[provider-aws]), then using [provider-helm] to install Crossplane into the new
remote cluster, potentially bundling a common Configuration package into each
install using the method described above.
This advanced pattern allows for full management of Crossplane clusters using
Crossplane itself, and when done properly, is a scalable solution to providing
dedicated control planes to many tenants within a single organization.
<!-- Named Links -->
[managed resources]: {{<ref "../../master/concepts/managed-resources" >}}
[RBAC]: https://kubernetes.io/docs/reference/access-authn-authz/rbac/
[Composition]: {{<ref "../../master/concepts/compositions" >}}
[CustomResourceDefinitions]: https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/
[Open Policy Agent]: https://www.openpolicyagent.org/
[Rego]: https://www.openpolicyagent.org/docs/latest/policy-language/
[Gatekeeper]: https://open-policy-agent.github.io/gatekeeper/website/docs/
[here]: https://youtu.be/TaF0_syejXc
[Multiple Source Field patching]: https://github.com/crossplane/crossplane/pull/2093
[Configuration packages]: {{<ref "../../master/concepts/packages" >}}
[OCI images]: https://github.com/opencontainers/image-spec
[EKS Cluster]: https://marketplace.upbound.io/providers/crossplane-contrib/provider-aws/latest/resources/eks.aws.crossplane.io/Cluster/v1beta1
[provider-aws]: https://marketplace.upbound.io/providers/crossplane-contrib/provider-aws
[provider-helm]: https://marketplace.upbound.io/providers/crossplane-contrib/provider-helm/
[Open Service Broker API]: https://github.com/openservicebrokerapi/servicebroker
[Crossplane Service Broker]: https://github.com/vshn/crossplane-service-broker
[Cloudfoundry]: https://www.cloudfoundry.org/
[Kubernetes Service Catalog]: https://github.com/kubernetes-sigs/service-catalog
[vshn/application-catalog-demo]: https://github.com/vshn/application-catalog-demo

View File

@ -0,0 +1,49 @@
---
title: Self-Signed CA Certs
weight: 270
---
> Using self-signed certificates is not advised in production, it is
recommended to only use self-signed certificates for testing.
When Crossplane loads Configuration and Provider Packages from private
registries, it must be configured to trust the CA and Intermediate certs.
Crossplane needs to be installed via the Helm chart with the
`registryCaBundleConfig.name` and `registryCaBundleConfig.key` parameters
defined. See [Install Crossplane]({{<ref "../../master/software/install" >}}).
## Configure
1. Create a CA Bundle (A file containing your Root and Intermediate
certificates in a specific order). This can be done with any text editor or
from the command line, so long as the resulting file contains all required crt
files in the proper order. In many cases, this will be either a single
self-signed Root CA crt file, or an Intermediate crt and Root crt file. The
order of the crt files should be from lowest to highest in signing order.
For example, if you have a chain of two certificates below your Root
certificate, you place the bottom level Intermediate cert at the beginning of
the file, then the Intermediate cert that singed that cert, then the Root cert
that signed that cert.
2. Save the files as `[yourdomain].ca-bundle`.
3. Create a Kubernetes ConfigMap in your Crossplane system namespace:
```
kubectl -n [Crossplane system namespace] create cm ca-bundle-config \
--from-file=ca-bundle=./[yourdomain].ca-bundle
```
4. Set the `registryCaBundleConfig.name` Helm chart parameter to
`ca-bundle-config` and the `registryCaBundleConfig.key` parameter to
`ca-bundle`.
> Providing Helm with parameter values is convered in the Helm docs,
[Helm install](https://helm.sh/docs/helm/helm_install/). An example block
in an `override.yaml` file would look like this:
```
registryCaBundleConfig:
name: ca-bundle-config
key: ca-bundle
```

View File

@ -0,0 +1,443 @@
---
title: Troubleshoot Crossplane
weight: 306
---
## Requested Resource Not Found
If you use the Crossplane CLI to install a `Provider` or
`Configuration` (e.g. `crossplane install provider
xpkg.upbound.io/crossplane-contrib/provider-aws:v0.33.0`) and get `the server
could not find the requested resource` error, more often than not, that is an
indicator that the Crossplane CLI you're using is outdated. In other words
some Crossplane API has been graduated from alpha to beta or stable and the old
plugin is not aware of this change.
## 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 will frequently give insightful information about its
condition. For example, to determine the status of a GCP `CloudSQLInstance`
managed resource use `kubectl describe` for the resource.
```shell {copy-lines="1"}
kubectl describe cloudsqlinstance my-db
Status:
Conditions:
Last Transition Time: 2019-09-16T13:46:42Z
Reason: Creating
Status: False
Type: Ready
```
Most Crossplane resources set the `Ready` condition. `Ready` represents the
availability of the resource - whether it is creating, deleting, available,
unavailable, binding, etc.
## Resource Events
Most Crossplane resources emit _events_ when something interesting happens. You
can see the events associated with a resource by running `kubectl describe` -
e.g. `kubectl describe cloudsqlinstance my-db`. You can also see all events in a
particular namespace by running `kubectl get events`.
```console
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
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 events are namespaced, while many Crossplane resources (XRs, etc)
> are cluster scoped. Crossplane emits events for cluster scoped resources to
> the 'default' namespace.
## 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:
```shell
kubectl -n crossplane-system logs -lapp=crossplane
```
> Note that Crossplane emits few 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
Remember that much of Crossplane's functionality is provided by providers. You
can use `kubectl logs` to view provider logs too. By convention, they also emit
few logs by default.
```shell
kubectl -n crossplane-system logs <name-of-provider-pod>
```
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
`ControllerConfig` and reference it from the `Provider`:
```yaml
apiVersion: pkg.crossplane.io/v1alpha1
kind: ControllerConfig
metadata:
name: debug-config
spec:
args:
- --debug
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws
spec:
package: xpkg.upbound.io/crossplane-contrib/provider-aws:v0.33.0
controllerConfigRef:
name: debug-config
```
> Note that a reference to a `ControllerConfig` can be added to an already
> installed `Provider` and it will update its `Deployment` accordingly.
## Compositions and composite resource definition
### General troubleshooting steps
Crossplane and its providers log most error messages to resources' event fields. Whenever your Composite Resources aren't getting provisioned, follow the following steps:
1. Get the events for the root resource using `kubectl describe` or `kubectl get event`
2. If there are errors in the events, address them.
3. If there are no errors, follow its sub-resources.
`kubectl get <KIND> <NAME> -o=jsonpath='{.spec.resourceRef}{" "}{.spec.resourceRefs}' | jq`
4. Repeat this process for each resource returned.
{{< hint "note" >}}
The rest of this section show you how to debug issues related to compositions without using external tooling.
If you are using ArgoCD or FluxCD with UI, you can visualize object relationships in the UI.
You can also use the kube-lineage plugin to visualize object relationships in your terminal.
{{< /hint >}}
### Examples
#### Composition
<!-- vale Google.WordList = NO -->
You deployed an example application using a claim. Kind = `ExampleApp`. Name = `example-application`.
The example application never reaches available state as shown below.
1. View the claim.
```bash
kubectl describe exampleapp example-application
Status:
Conditions:
Last Transition Time: 2022-03-01T22:57:38Z
Reason: Composite resource claim is waiting for composite resource to become Ready
Status: False
Type: Ready
Events: <none>
```
2. If the claim doesn't have errors, inspect the `.spec.resourceRef` field of the claim.
```bash
kubectl get exampleapp example-application -o=jsonpath='{.spec.resourceRef}{" "}{.spec.resourceRefs}' | jq
{
"apiVersion": "awsblueprints.io/v1alpha1",
"kind": "XExampleApp",
"name": "example-application-xqlsz"
}
```
3. In the preceding output, you see the cluster scoped resource for this claim. Kind = `XExampleApp` name = `example-application-xqlsz`
4. View the cluster scoped resource's events.
```bash
kubectl describe xexampleapp example-application-xqlsz
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal PublishConnectionSecret 9s (x2 over 10s) defined/compositeresourcedefinition.apiextensions.crossplane.io Successfully published connection details
Normal SelectComposition 6s (x6 over 11s) defined/compositeresourcedefinition.apiextensions.crossplane.io Successfully selected composition
Warning ComposeResources 6s (x6 over 10s) defined/compositeresourcedefinition.apiextensions.crossplane.io can't render composed resource from resource template at index 3: can't use dry-run create to name composed resource: an empty namespace may not be set during creation
Normal ComposeResources 6s (x6 over 10s) defined/compositeresourcedefinition.apiextensions.crossplane.io Successfully composed resources
```
5. You see errors in the events. it's complaining about not specifying namespace in its compositions. For this particular kind of error, you can get its sub-resources and check which one isn't created.
```bash
kubectl get xexampleapp example-application-xqlsz -o=jsonpath='{.spec.resourceRef}{" "}{.spec.resourceRefs}' | jq
[
{
"apiVersion": "awsblueprints.io/v1alpha1",
"kind": "XDynamoDBTable",
"name": "example-application-xqlsz-6j9nm"
},
{
"apiVersion": "awsblueprints.io/v1alpha1",
"kind": "XIAMPolicy",
"name": "example-application-xqlsz-lp9wt"
},
{
"apiVersion": "awsblueprints.io/v1alpha1",
"kind": "XIAMPolicy",
"name": "example-application-xqlsz-btwkn"
},
{
"apiVersion": "awsblueprints.io/v1alpha1",
"kind": "IRSA"
}
]
```
6. Notice the last element in the array doesn't have a name. When a resource in composition fails validation, the resource object isn't created and doesn't have a name. For this particular issue, you must specify the namespace for the IRSA resource.
#### Composite resource definition
Debugging Composite Resource Definition (XRD) is like debugging Compositions.
1. Get the XRD
```bash
kubectl get xrd testing.awsblueprints.io
NAME ESTABLISHED OFFERED AGE
testing.awsblueprints.io 66s
```
2. Notice its status it not established. You describe this XRD to get its events.
```bash
kubectl describe xrd testing.awsblueprints.io
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ApplyClusterRoles 3m19s (x3 over 3m19s) rbac/compositeresourcedefinition.apiextensions.crossplane.io Applied RBAC ClusterRoles
Normal RenderCRD 18s (x9 over 3m19s) defined/compositeresourcedefinition.apiextensions.crossplane.io Rendered composite resource CustomResourceDefinition
Warning EstablishComposite 18s (x9 over 3m19s) defined/compositeresourcedefinition.apiextensions.crossplane.io can't apply rendered composite resource CustomResourceDefinition: can't create object: CustomResourceDefinition.apiextensions.k8s.io "testing.awsblueprints.io" is invalid: metadata.name: Invalid value: "testing.awsblueprints.io": must be spec.names.plural+"."+spec.group
```
3. You see in the events that Crossplane can't generate corresponding CRDs for this XRD. In this case, ensure the name is `spec.names.plural+"."+spec.group`
#### Providers
You can use install providers in two ways: `configuration.pkg.crossplane.io` and `provider.pkg.crossplane.io`. You can use either one to install providers with no functional differences to providers themselves.
If you define a `configuration.pkg.crossplane.io` object, Crossplane creates a
`provider.pkg.crossplane.io` object and manages it. Refer to [the Packages
documentation]({{<ref "/master/concepts/packages">}})
for more information about Crossplane Packages.
If you are experiencing provider issues, steps below are a good starting point.
1. Check the status of provider object.
```bash
kubectl describe provider.pkg.crossplane.io provider-aws
Status:
Conditions:
Last Transition Time: 2022-08-04T16:19:44Z
Reason: HealthyPackageRevision
Status: True
Type: Healthy
Last Transition Time: 2022-08-04T16:14:29Z
Reason: ActivePackageRevision
Status: True
Type: Installed
Current Identifier: crossplane/provider-aws:v0.29.0
Current Revision: provider-aws-a2e16ca2fc1a
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal InstallPackageRevision 9m49s (x237 over 4d17h) packages/provider.pkg.crossplane.io Successfully installed package revision
```
In the output above you see that this provider is healthy. To get more information about this provider, you can dig deeper. The `Current Revision` field let you know of your next object to look at.
2. When you create a provider object, Crossplane creates a `ProviderRevision` object based on the contents of the OCI image. In this example, you're specifying the OCI image to be `crossplane/provider-aws:v0.29.0`. This image contains a YAML file which defines Kubernetes objects such as Deployment, ServiceAccount, and CRDs.
The `ProviderRevision` object creates resources necessary for a provider to function based on the contents of the YAML file. To inspect what's deployed as part of the provider package, you inspect the ProviderRevision object. The `Current Revision` field above indicates which ProviderRevision object this provider uses.
```bash
kubectl get providerrevision provider-aws-a2e16ca2fc1a
NAME HEALTHY REVISION IMAGE STATE DEP-FOUND DEP-INSTALLED AGE
provider-aws-a2e16ca2fc1a True 1 crossplane/provider-aws:v0.29.0 Active 19d
```
When you describe the object, you find all CRDs managed by this object.
```bash
kubectl describe providerrevision provider-aws-a2e16ca2fc1a
Status:
Controller Ref:
Name: provider-aws-a2e16ca2fc1a
Object Refs:
API Version: apiextensions.k8s.io/v1
Kind: CustomResourceDefinition
Name: natgateways.ec2.aws.crossplane.io
UID: 5c36d1bc-61b8-44f8-bca0-47e368af87a9
....
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SyncPackage 22m (x369 over 4d18h) packages/providerrevision.pkg.crossplane.io Successfully configured package revision
Normal BindClusterRole 15m (x348 over 4d18h) rbac/providerrevision.pkg.crossplane.io Bound system ClusterRole to provider ServiceAccount
Normal ApplyClusterRoles 15m (x364 over 4d18h) rbac/providerrevision.pkg.crossplane.io Applied RBAC ClusterRoles
```
The event field also indicates any issues that may have occurred during this process.
<!-- vale Google.WordList = YES -->
3. If you don't see any errors in the event field above, you should check if Crossplane provisioned deployments and their status.
```bash
kubectl get deployment -n crossplane-system
NAME READY UP-TO-DATE AVAILABLE AGE
crossplane 1/1 1 1 105d
crossplane-rbac-manager 1/1 1 1 105d
provider-aws-a2e16ca2fc1a 1/1 1 1 19d
kubectl get pods -n crossplane-system
NAME READY STATUS RESTARTS AGE
crossplane-54db688c8d-qng6b 2/2 Running 0 4d19h
crossplane-rbac-manager-5776c9fbf4-wn5rj 1/1 Running 0 4d19h
provider-aws-a2e16ca2fc1a-776769ccbd-4dqml 1/1 Running 0 4d23h
```
If there are any pods failing, check its logs and remedy the problem.
## 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 of its resources, run the
following command to simply scale down its deployment:
```bash
kubectl -n crossplane-system scale --replicas=0 deployment/crossplane
```
Once you have been able to rectify the problem or smooth things out, you can
unpause Crossplane simply by scaling its deployment back up:
```bash
kubectl -n crossplane-system scale --replicas=1 deployment/crossplane
```
## Pausing Providers
Providers can also be paused when troubleshooting an issue or orchestrating a
complex migration of resources. Creating and referencing a `ControllerConfig` is
the easiest way to scale down a provider, and the `ControllerConfig` can be
modified or the reference can be removed to scale it back up:
```yaml
apiVersion: pkg.crossplane.io/v1alpha1
kind: ControllerConfig
metadata:
name: scale-config
spec:
replicas: 0
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws
spec:
package: xpkg.upbound.io/crossplane-contrib/provider-aws:v0.33.0
controllerConfigRef:
name: scale-config
```
> Note that a reference to a `ControllerConfig` can be added to an already
> installed `Provider` and it will update its `Deployment` accordingly.
## Deleting When a Resource Hangs
The resources that Crossplane manages will automatically be cleaned up so as not
to leave anything running behind. This is accomplished by using finalizers, but
in certain scenarios the finalizer can prevent the Kubernetes object from
getting deleted.
To deal with this, we essentially want to patch the object to remove its
finalizer, which will then allow it to be deleted completely. Note that this
won't necessarily delete the external resource that Crossplane was managing, so
you will want to go to your cloud provider's console and look there for any
lingering resources to clean up.
In general, a finalizer can be removed from an object with this command:
```shell
kubectl patch <resource-type> <resource-name> -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:
```shell
kubectl patch cloudsqlinstance my-db -p '{"metadata":{"finalizers": []}}' --type=merge
```
## Tips, Tricks, and Troubleshooting
In this section we'll cover 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.
### Troubleshooting Claims and XRs
Crossplane relies heavily on status conditions and events for troubleshooting.
You can see both using `kubectl describe` - for example:
```console
# Describe the PostgreSQLInstance claim named my-db
kubectl describe postgresqlinstance.database.example.org my-db
```
Per Kubernetes convention, Crossplane keeps errors close to the place they
happen. This means that if your claim is not becoming ready due to an issue with
your `Composition` or with a composed resource you'll need to "follow the
references" to find out why. Your claim will only tell you that the XR is not
yet ready.
To follow the references:
1. Find your XR by running `kubectl describe` on your claim and looking for its
"Resource Ref" (aka `spec.resourceRef`).
1. Run `kubectl describe` on your XR. This is where you'll find out about issues
with the `Composition` you're using, if any.
1. If there are no issues but your XR doesn't seem to be becoming ready, take a
look for the "Resource Refs" (or `spec.resourceRefs`) to find your composed
resources.
1. Run `kubectl describe` on each referenced composed resource to determine
whether it is ready and what issues, if any, it is encountering.
<!-- Named Links -->
[Requested Resource Not Found]: #requested-resource-not-found
[install Crossplane CLI]: "../getting-started/install-configure"
[Resource Status and Conditions]: #resource-status-and-conditions
[Resource Events]: #resource-events
[Crossplane Logs]: #crossplane-logs
[Provider Logs]: #provider-logs
[Pausing Crossplane]: #pausing-crossplane
[Pausing Providers]: #pausing-providers
[Deleting When a Resource Hangs]: #deleting-when-a-resource-hangs
[Installing Crossplane Package]: #installing-crossplane-package
[Crossplane package]: /master/concepts/packages/
[Handling Crossplane Package Dependency]: #handling-crossplane-package-dependency
[semver spec]: https://github.com/Masterminds/semver#basic-comparisons

View File

@ -0,0 +1,639 @@
---
title: Vault as an External Secret Store
weight: 230
---
This guide walks through the steps required to configure Crossplane and
its Providers to use [Vault] as an [External Secret Store] (`ESS`) with [ESS Plugin Vault].
{{<hint "warning" >}}
External Secret Stores are an alpha feature.
They're not recommended for production use. Crossplane disables External Secret
Stores by default.
{{< /hint >}}
Crossplane uses sensitive information including Provider credentials, inputs to
managed resources and connection details.
The [Vault credential injection guide]({{<ref "vault-injection" >}}) details
using Vault and Crossplane for Provider credentials.
Crossplane doesn't support for using Vault for managed resources input.
[Crossplane issue #2985](https://github.com/crossplane/crossplane/issues/2985)
tracks support for this feature.
Supporting connection details with Vault requires a Crossplane external secret
store.
## Prerequisites
This guide requires [Helm](https://helm.sh) version 3.11 or later.
## Install Vault
{{<hint "note" >}}
Detailed instructions on [installing
Vault](https://developer.hashicorp.com/vault/docs/platform/k8s/helm)
are available from the Vault documentation.
{{< /hint >}}
### Add the Vault Helm chart
Add the Helm repository for `hashicorp`.
```shell
helm repo add hashicorp https://helm.releases.hashicorp.com --force-update
```
Install Vault using Helm.
```shell
helm -n vault-system upgrade --install vault hashicorp/vault --create-namespace
```
### Unseal Vault
If Vault is [sealed](https://developer.hashicorp.com/vault/docs/concepts/seal)
unseal Vault using the unseal keys.
Get the Vault keys.
```shell
kubectl -n vault-system exec vault-0 -- vault operator init -key-shares=1 -key-threshold=1 -format=json > cluster-keys.json
VAULT_UNSEAL_KEY=$(cat cluster-keys.json | jq -r ".unseal_keys_b64[]")
```
Unseal the vault using the keys.
```shell {copy-lines="1"}
kubectl -n vault-system exec vault-0 -- vault operator unseal $VAULT_UNSEAL_KEY
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed false
Total Shares 1
Threshold 1
Version 1.13.1
Build Date 2023-03-23T12:51:35Z
Storage Type file
Cluster Name vault-cluster-df884357
Cluster ID b3145d26-2c1a-a7f2-a364-81753033c0d9
HA Enabled false
```
## Configure Vault Kubernetes authentication
Enable the [Kubernetes auth method] for Vault to authenticate requests based on
Kubernetes service accounts.
### Get the Vault root token
The Vault root token is inside the JSON file created when
[unsealing Vault](#unseal-vault).
```shell
cat cluster-keys.json | jq -r ".root_token"
```
### Enable Kubernetes authentication
Connect to a shell in the Vault pod.
```shell {copy-lines="1"}
kubectl -n vault-system exec -it vault-0 -- /bin/sh
/ $
```
From the Vault shell, login to Vault using the _root token_.
```shell {copy-lines="1"}
vault login # use the root token from above
Token (will be hidden):
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.
Key Value
--- -----
token hvs.TSN4SssfMBM0HAtwGrxgARgn
token_accessor qodxHrINVlRXKyrGeeDkxnih
token_duration ∞
token_renewable false
token_policies ["root"]
identity_policies []
policies ["root"]
```
Enable the Kubernetes authentication method in Vault.
```shell {copy-lines="1"}
vault auth enable kubernetes
Success! Enabled kubernetes auth method at: kubernetes/
```
Configure Vault to communicate with Kubernetes and exit the Vault shell
```shell {copy-lines="1-4"}
vault write auth/kubernetes/config \
token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
Success! Data written to: auth/kubernetes/config
/ $ exit
```
## Configure Vault for Crossplane integration
Crossplane relies on the Vault key-value secrets engine to store information and
Vault requires a permissions policy for the Crossplane service account.
<!-- vale Crossplane.Spelling = NO -->
<!-- allow "kv" -->
### Enable the Vault kv secrets engine
<!-- vale Crossplane.Spelling = YES -->
Enable the [Vault KV Secrets Engine].
{{< hint "important" >}}
Vault has two versions of the
[KV Secrets Engine](https://developer.hashicorp.com/vault/docs/secrets/kv).
This example uses version 2.
{{</hint >}}
```shell {copy-lines="1"}
kubectl -n vault-system exec -it vault-0 -- vault secrets enable -path=secret kv-v2
Success! Enabled the kv-v2 secrets engine at: secret/
```
### Create a Vault policy for Crossplane
Create the Vault policy to allow Crossplane to read and write data from Vault.
```shell {copy-lines="1-8"}
kubectl -n vault-system exec -i vault-0 -- vault policy write crossplane - <<EOF
path "secret/data/*" {
capabilities = ["create", "read", "update", "delete"]
}
path "secret/metadata/*" {
capabilities = ["create", "read", "update", "delete"]
}
EOF
Success! Uploaded policy: crossplane
```
Apply the policy to Vault.
```shell {copy-lines="1-5"}
kubectl -n vault-system exec -it vault-0 -- vault write auth/kubernetes/role/crossplane \
bound_service_account_names="*" \
bound_service_account_namespaces=crossplane-system \
policies=crossplane \
ttl=24h
Success! Data written to: auth/kubernetes/role/crossplane
```
## Install Crossplane
{{<hint "important" >}}
Crossplane v1.12 introduced the plugin support. Make sure your version of Crossplane supports plugins.
{{< /hint >}}
Install the Crossplane with the External Secrets Stores feature enabled.
```shell
helm upgrade --install crossplane crossplane-stable/crossplane --namespace crossplane-system --create-namespace --set args='{--enable-external-secret-stores}'
```
## Install the Crossplane Vault plugin
The Crossplane Vault plugin isn't part of the default Crossplane install.
The plugin installs as a unique Pod that uses the [Vault Agent Sidecar
Injection] to connect the Vault secret store to Crossplane.
First, configure annotations for the Vault plugin pod.
```yaml
cat > values.yaml <<EOF
podAnnotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-inject-token: "true"
vault.hashicorp.com/role: crossplane
vault.hashicorp.com/agent-run-as-user: "65532"
EOF
```
Next, install the Crossplane ESS Plugin pod to the `crossplane-system` namespace
and apply the Vault annotations.
```shell
helm upgrade --install ess-plugin-vault oci://xpkg.upbound.io/crossplane-contrib/ess-plugin-vault --namespace crossplane-system -f values.yaml
```
## Configure Crossplane
Using the Vault plugin requires configuration to connect to the Vault
service. The plugin also requires Providers to enable external secret stores.
With the plugin and providers configured, Crossplane requires two `StoreConfig`
objects to describe how Crossplane and the Providers communicate with vault.
### Enable external secret stores in the Provider
{{<hint "note">}}
This example uses Provider GCP, but the
{{<hover label="ControllerConfig" line="2">}}ControllerConfig{{</hover>}} is the
same for all Providers.
{{</hint >}}
Create a `ControllerConfig` object to enable external secret stores.
```yaml {label="ControllerConfig"}
echo "apiVersion: pkg.crossplane.io/v1alpha1
kind: ControllerConfig
metadata:
name: vault-config
spec:
args:
- --enable-external-secret-stores" | kubectl apply -f -
```
Install the Provider and apply the ControllerConfig.
```yaml
echo "apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-gcp
spec:
package: xpkg.upbound.io/crossplane-contrib/provider-gcp:v0.23.0-rc.0.19.ge9b75ee5
controllerConfigRef:
name: vault-config" | kubectl apply -f -
```
### Connect the Crossplane plugin to Vault
Create a {{<hover label="VaultConfig" line="2">}}VaultConfig{{</hover>}}
resource for the plugin to connect to the Vault service:
```yaml {label="VaultConfig"}
echo "apiVersion: secrets.crossplane.io/v1alpha1
kind: VaultConfig
metadata:
name: vault-internal
spec:
server: http://vault.vault-system:8200
mountPath: secret/
version: v2
auth:
method: Token
token:
source: Filesystem
fs:
path: /vault/secrets/token" | kubectl apply -f -
```
### Create a Crossplane StoreConfig
Create a {{<hover label="xp-storeconfig" line="2">}}StoreConfig{{</hover >}}
object from the
{{<hover label="xp-storeconfig" line="1">}}secrets.crossplane.io{{</hover >}}
group. Crossplane uses the StoreConfig to connect to the Vault plugin service.
The {{<hover label="xp-storeconfig" line="10">}}configRef{{</hover >}} connects
the StoreConfig to the specific Vault plugin configuration.
```yaml {label="xp-storeconfig"}
echo "apiVersion: secrets.crossplane.io/v1alpha1
kind: StoreConfig
metadata:
name: vault
spec:
type: Plugin
defaultScope: crossplane-system
plugin:
endpoint: ess-plugin-vault.crossplane-system:4040
configRef:
apiVersion: secrets.crossplane.io/v1alpha1
kind: VaultConfig
name: vault-internal" | kubectl apply -f -
```
### Create a Provider StoreConfig
Create a {{<hover label="gcp-storeconfig" line="2">}}StoreConfig{{</hover >}}
object from the Provider's API group,
{{<hover label="gcp-storeconfig" line="1">}}gcp.crossplane.io{{</hover >}}.
The Provider uses this StoreConfig to communicate with Vault for
Managed Resources.
The {{<hover label="gcp-storeconfig" line="10">}}configRef{{</hover >}} connects
the StoreConfig to the specific Vault plugin configuration.
```yaml {label="gcp-storeconfig"}
echo "apiVersion: gcp.crossplane.io/v1alpha1
kind: StoreConfig
metadata:
name: vault
spec:
type: Plugin
defaultScope: crossplane-system
plugin:
endpoint: ess-plugin-vault.crossplane-system:4040
configRef:
apiVersion: secrets.crossplane.io/v1alpha1
kind: VaultConfig
name: vault-internal" | kubectl apply -f -
```
## Create Provider resources
Check that Crossplane installed the Provider and the Provider is healthy.
```shell {copy-lines="1"}
kubectl get providers
NAME INSTALLED HEALTHY PACKAGE AGE
provider-gcp True True xpkg.upbound.io/crossplane-contrib/provider-gcp:v0.23.0-rc.0.19.ge9b75ee5 10m
```
### Create a CompositeResourceDefinition
Create a `CompositeResourceDefinition` to define a custom API endpoint.
```yaml
echo "apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: compositeessinstances.ess.example.org
annotations:
feature: ess
spec:
group: ess.example.org
names:
kind: CompositeESSInstance
plural: compositeessinstances
claimNames:
kind: ESSInstance
plural: essinstances
connectionSecretKeys:
- publicKey
- publicKeyType
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
parameters:
type: object
properties:
serviceAccount:
type: string
required:
- serviceAccount
required:
- parameters" | kubectl apply -f -
```
### Create a Composition
Create a `Composition` to create a Service Account and Service Account Key
inside GCP.
Creating a Service Account Key generates
{{<hover label="comp" line="39" >}}connectionDetails{{</hover>}} that the
Provider stores in Vault using the
{{<hover label="comp" line="31">}}publishConnectionDetailsTo{{</hover>}} details.
```yaml {label="comp"}
echo "apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: essinstances.ess.example.org
labels:
feature: ess
spec:
publishConnectionDetailsWithStoreConfigRef:
name: vault
compositeTypeRef:
apiVersion: ess.example.org/v1alpha1
kind: CompositeESSInstance
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: serviceaccount
base:
apiVersion: iam.gcp.crossplane.io/v1alpha1
kind: ServiceAccount
metadata:
name: ess-test-sa
spec:
forProvider:
displayName: a service account to test ess
- name: serviceaccountkey
base:
apiVersion: iam.gcp.crossplane.io/v1alpha1
kind: ServiceAccountKey
spec:
forProvider:
serviceAccountSelector:
matchControllerRef: true
publishConnectionDetailsTo:
name: ess-mr-conn
metadata:
labels:
environment: development
team: backend
configRef:
name: vault
connectionDetails:
- name: publicKey
type: FromConnectionSecretKey
fromConnectionSecretKey: publicKey
- name: publicKey
type: FromConnectionSecretKey
fromConnectionSecretKey: publicKeyType" | kubectl apply -f -
```
### Create a Claim
Now create a `Claim` to have Crossplane create the GCP resources and associated
secrets.
Like the Composition, the Claim uses
{{<hover label="claim" line="12">}}publishConnectionDetailsTo{{</hover>}} to
connect to Vault and store the secrets.
```yaml {label="claim"}
echo "apiVersion: ess.example.org/v1alpha1
kind: ESSInstance
metadata:
name: my-ess
namespace: default
spec:
parameters:
serviceAccount: ess-test-sa
compositionSelector:
matchLabels:
feature: ess
publishConnectionDetailsTo:
name: ess-claim-conn
metadata:
labels:
environment: development
team: backend
configRef:
name: vault" | kubectl apply -f -
```
## Verify the resources
Verify all resources are `READY` and `SYNCED`:
```shell {copy-lines="1"}
kubectl get managed
NAME READY SYNCED DISPLAYNAME EMAIL DISABLED
serviceaccount.iam.gcp.crossplane.io/my-ess-zvmkz-vhklg True True a service account to test ess my-ess-zvmkz-vhklg@testingforbugbounty.iam.gserviceaccount.com
NAME READY SYNCED KEY_ID CREATED_AT EXPIRES_AT
serviceaccountkey.iam.gcp.crossplane.io/my-ess-zvmkz-bq8pz True True 5cda49b7c32393254b5abb121b4adc07e140502c 2022-03-23T10:54:50Z
```
View the claims
```shell {copy-lines="1"}
kubectl -n default get claim
NAME READY CONNECTION-SECRET AGE
my-ess True 19s
```
View the composite resources.
```shell {copy-lines="1"}
kubectl get composite
NAME READY COMPOSITION AGE
my-ess-zvmkz True essinstances.ess.example.org 32s
```
## Verify Vault secrets
Look inside Vault to view the secrets from the managed resources.
```shell {copy-lines="1",label="vault-key"}
kubectl -n vault-system exec -i vault-0 -- vault kv list /secret/default
Keys
----
ess-claim-conn
```
The key {{<hover label="vault-key" line="4">}}ess-claim-conn{{</hover>}}
is the name of the Claim's
{{<hover label="claim" line="12">}}publishConnectionDetailsTo{{</hover>}}
configuration.
Check connection secrets in the "crossplane-system" Vault scope.
```shell {copy-lines="1",label="scope-key"}
kubectl -n vault-system exec -i vault-0 -- vault kv list /secret/crossplane-system
Keys
----
d2408335-eb88-4146-927b-8025f405da86
ess-mr-conn
```
The key
{{<hover label="scope-key"line="4">}}d2408335-eb88-4146-927b-8025f405da86{{</hover>}}
comes from
<!-- ## WHERE DOES IT COME FROM? -->
and the key
{{<hover label="scope-key"line="5">}}ess-mr-conn{{</hover>}}
comes from the Composition's
{{<hover label="comp" line="31">}}publishConnectionDetailsTo{{</hover>}}
configuration.
Check contents of Claim's connection secret `ess-claim-conn` to see the key
created by the managed resource.
```shell {copy-lines="1"}
kubectl -n vault-system exec -i vault-0 -- vault kv get /secret/default/ess-claim-conn
======= Metadata =======
Key Value
--- -----
created_time 2022-03-18T21:24:07.2085726Z
custom_metadata map[environment:development secret.crossplane.io/ner-uid:881cd9a0-6cc6-418f-8e1d-b36062c1e108 team:backend]
deletion_time n/a
destroyed false
version 1
======== Data ========
Key Value
--- -----
publicKey -----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzsEYCokmYEsZJCc9QN/8
Fm1M/kTPp7Gat/MXLTP3zFyCTBFVNLN79MbAKdinWi6ePXEb75vzB79IdZcWj8lo
8trnS64QjNB9Vs4Xk5UvDALwleFN/bZeperxivDPwVPvT9Aqy/U9kohoS/LHyE8w
uWQb5AuMeVQ1gtCTnCqQZ4d2MSVhQXYVvAWax1spJ9LT7mHub5j95xDdYIcOV3VJ
l9CIo4VrWIT8THFN2NnjTrGq9+0TzXY0bV674bjJkfBC6v6yXs5HTetG+Uekq/xf
FCjrrDi1+2UR9Mu2WTuvl8qn50be+mbwdJO5wE32jewxdYrVVmj19+PkaEeAwGTc
vwIDAQAB
-----END PUBLIC KEY-----
publicKeyType TYPE_RAW_PUBLIC_KEY
```
Check contents of managed resource connection secret `ess-mr-conn`. The public
key is identical to the public key in the Claim since the Claim is using this
managed resource.
```shell {copy-lines="1"}
kubectl -n vault-system exec -i vault-0 -- vault kv get /secret/crossplane-system/ess-mr-conn
======= Metadata =======
Key Value
--- -----
created_time 2022-03-18T21:21:07.9298076Z
custom_metadata map[environment:development secret.crossplane.io/ner-uid:4cd973f8-76fc-45d6-ad45-0b27b5e9252a team:backend]
deletion_time n/a
destroyed false
version 2
========= Data =========
Key Value
--- -----
privateKey {
"type": "service_account",
"project_id": "REDACTED",
"private_key_id": "REDACTED",
"private_key": "-----BEGIN PRIVATE KEY-----\nREDACTED\n-----END PRIVATE KEY-----\n",
"client_email": "ess-test-sa@REDACTED.iam.gserviceaccount.com",
"client_id": "REDACTED",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/ess-test-sa%40REDACTED.iam.gserviceaccount.com"
}
privateKeyType TYPE_GOOGLE_CREDENTIALS_FILE
publicKey -----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzsEYCokmYEsZJCc9QN/8
Fm1M/kTPp7Gat/MXLTP3zFyCTBFVNLN79MbAKdinWi6ePXEb75vzB79IdZcWj8lo
8trnS64QjNB9Vs4Xk5UvDALwleFN/bZeperxivDPwVPvT9Aqy/U9kohoS/LHyE8w
uWQb5AuMeVQ1gtCTnCqQZ4d2MSVhQXYVvAWax1spJ9LT7mHub5j95xDdYIcOV3VJ
l9CIo4VrWIT8THFN2NnjTrGq9+0TzXY0bV674bjJkfBC6v6yXs5HTetG+Uekq/xf
FCjrrDi1+2UR9Mu2WTuvl8qn50be+mbwdJO5wE32jewxdYrVVmj19+PkaEeAwGTc
vwIDAQAB
-----END PUBLIC KEY-----
publicKeyType TYPE_RAW_PUBLIC_KEY
```
### Remove the resources
Deleting the Claim removes the managed resources and associated keys from Vault.
```shell
kubectl delete claim my-ess
```
<!-- named links -->
[Vault]: https://www.vaultproject.io/
[External Secret Store]: https://github.com/crossplane/crossplane/blob/master/design/design-doc-external-secret-stores.md
[this issue]: https://github.com/crossplane/crossplane/issues/2985
[Kubernetes Auth Method]: https://www.vaultproject.io/docs/auth/kubernetes
[Unseal]: https://www.vaultproject.io/docs/concepts/seal
[Vault KV Secrets Engine]: https://developer.hashicorp.com/vault/docs/secrets/kv
[Vault Agent Sidecar Injection]: https://www.vaultproject.io/docs/platform/k8s/injector
[ESS Plugin Vault]: https://github.com/crossplane-contrib/ess-plugin-vault

View File

@ -0,0 +1,506 @@
---
title: Vault Credential Injection
weight: 230
---
> This guide is adapted from the [Vault on Minikube] and [Vault Kubernetes
> Sidecar] guides.
Most Crossplane providers support supplying credentials from at least the
following sources:
- Kubernetes Secret
- Environment Variable
- Filesystem
A provider may optionally support additional credentials sources, but the common
sources cover a wide variety of use cases. One specific use case that is popular
among organizations that use [Vault] for secrets management is using a sidecar
to inject credentials into the filesystem. This guide will demonstrate how to
use the [Vault Kubernetes Sidecar] to provide credentials for [provider-gcp]
and [provider-aws].
> Note: in this guide we will copy GCP credentials and AWS access keys
> into Vault's KV secrets engine. This is a simple generic approach to
> managing secrets with Vault, but is not as robust as using Vault's
> dedicated cloud provider secrets engines for [AWS], [Azure], and [GCP].
## Setup
> Note: this guide walks through setting up Vault running in the same cluster as
> Crossplane. You may also choose to use an existing Vault instance that runs
> outside the cluster but has Kubernetes authentication enabled.
Before getting started, you must ensure that you have installed Crossplane and
Vault and that they are running in your cluster.
1. Install Crossplane
```console
kubectl create namespace crossplane-system
helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update
helm install crossplane --namespace crossplane-system crossplane-stable/crossplane
```
2. Install Vault Helm Chart
```console
helm repo add hashicorp https://helm.releases.hashicorp.com
helm install vault hashicorp/vault
```
3. Unseal Vault Instance
In order for Vault to access encrypted data from physical storage, it must be
[unsealed].
```console
kubectl exec vault-0 -- vault operator init -key-shares=1 -key-threshold=1 -format=json > cluster-keys.json
VAULT_UNSEAL_KEY=$(cat cluster-keys.json | jq -r ".unseal_keys_b64[]")
kubectl exec vault-0 -- vault operator unseal $VAULT_UNSEAL_KEY
```
4. Enable Kubernetes Authentication Method
In order for Vault to be able to authenticate requests based on Kubernetes
service accounts, the [Kubernetes authentication backend] must be enabled. This
requires logging in to Vault and configuring it with a service account token,
API server address, and certificate. Because we are running Vault in Kubernetes,
these values are already available via the container filesystem and environment
variables.
```console
cat cluster-keys.json | jq -r ".root_token" # get root token
kubectl exec -it vault-0 -- /bin/sh
vault login # use root token from above
vault auth enable kubernetes
vault write auth/kubernetes/config \
token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
```
5. Exit Vault Container
The next steps will be executed in your local environment.
```console
exit
```
{{< tabs >}}
{{< tab "GCP" >}}
## Create GCP Service Account
In order to provision infrastructure on GCP, you will need to create a service
account with appropriate permissions. In this guide we will only provision a
CloudSQL instance, so the service account will be bound to the `cloudsql.admin`
role. The following steps will setup a GCP service account, give it the
necessary permissions for Crossplane to be able to manage CloudSQL instances,
and emit the service account credentials in a JSON file.
```console
# replace this with your own gcp project id and the name of the service account
# that will be created.
PROJECT_ID=my-project
NEW_SA_NAME=test-service-account-name
# create service account
SA="${NEW_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
gcloud iam service-accounts create $NEW_SA_NAME --project $PROJECT_ID
# enable cloud API
SERVICE="sqladmin.googleapis.com"
gcloud services enable $SERVICE --project $PROJECT_ID
# grant access to cloud API
ROLE="roles/cloudsql.admin"
gcloud projects add-iam-policy-binding --role="$ROLE" $PROJECT_ID --member "serviceAccount:$SA"
# create service account keyfile
gcloud iam service-accounts keys create creds.json --project $PROJECT_ID --iam-account $SA
```
You should now have valid service account credentials in `creds.json`.
## Store Credentials in Vault
After setting up Vault, you will need to store your credentials in the [kv
secrets engine].
> Note: the steps below involve copying credentials into the container
> filesystem before storing them in Vault. You may also choose to use Vault's
> HTTP API or UI by port-forwarding the container to your local environment
> (`kubectl port-forward vault-0 8200:8200`).
1. Copy Credentials File into Vault Container
Copy your credentials into the container filesystem so that your can store them
in Vault.
```console
kubectl cp creds.json vault-0:/tmp/creds.json
```
2. Enable KV Secrets Engine
Secrets engines must be enabled before they can be used. Enable the `kv-v2`
secrets engine at the `secret` path.
```console
kubectl exec -it vault-0 -- /bin/sh
vault secrets enable -path=secret kv-v2
```
3. Store GCP Credentials in KV Engine
The path of your GCP credentials is how the secret will be referenced when
injecting it into the `provider-gcp` controller `Pod`.
```console
vault kv put secret/provider-creds/gcp-default @tmp/creds.json
```
4. Clean Up Credentials File
You no longer need our GCP credentials file in the container filesystem, so go
ahead and clean it up.
```console
rm tmp/creds.json
```
{{< /tab >}}
{{< tab "AWS" >}}
## Create AWS IAM User
In order to provision infrastructure on AWS, you will need to use an existing or create a new IAM
user with appropriate permissions. The following steps will create an AWS IAM user and give it the necessary
permissions.
> Note: if you have an existing IAM user with appropriate permissions, you can skip this step but you will
> still need to provide the values for the `ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables.
```console
# create a new IAM user
IAM_USER=test-user
aws iam create-user --user-name $IAM_USER
# grant the IAM user the necessary permissions
aws iam attach-user-policy --user-name $IAM_USER --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
# create a new IAM access key for the user
aws iam create-access-key --user-name $IAM_USER > creds.json
# assign the access key values to environment variables
ACCESS_KEY_ID=$(jq -r .AccessKey.AccessKeyId creds.json)
AWS_SECRET_ACCESS_KEY=$(jq -r .AccessKey.SecretAccessKey creds.json)
```
## Store Credentials in Vault
After setting up Vault, you will need to store your credentials in the [kv
secrets engine].
1. Enable KV Secrets Engine
Secrets engines must be enabled before they can be used. Enable the `kv-v2`
secrets engine at the `secret` path.
```console
kubectl exec -it vault-0 -- env \
ACCESS_KEY_ID=${ACCESS_KEY_ID} \
AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} \
/bin/sh
vault secrets enable -path=secret kv-v2
```
2. Store AWS Credentials in KV Engine
The path of your AWS credentials is how the secret will be referenced when
injecting it into the `provider-aws` controller `Pod`.
```
vault kv put secret/provider-creds/aws-default access_key="$ACCESS_KEY_ID" secret_key="$AWS_SECRET_ACCESS_KEY"
```
{{< /tab >}}
{{< /tabs >}}
## Create a Vault Policy for Reading Provider Credentials
In order for our controllers to have the Vault sidecar inject the credentials
into their filesystem, you must associate the `Pod` with a [policy]. This policy
will allow for reading and listing all secrets on the `provider-creds` path in
the `kv-v2` secrets engine.
```console
vault policy write provider-creds - <<EOF
path "secret/data/provider-creds/*" {
capabilities = ["read", "list"]
}
EOF
```
## Create a Role for Crossplane Provider Pods
1. Create Role
The last step is to create a role that is bound to the policy you created and
associate it with a group of Kubernetes service accounts. This role can be
assumed by any (`*`) service account in the `crossplane-system` namespace.
```console
vault write auth/kubernetes/role/crossplane-providers \
bound_service_account_names="*" \
bound_service_account_namespaces=crossplane-system \
policies=provider-creds \
ttl=24h
```
2. Exit Vault Container
The next steps will be executed in your local environment.
```console
exit
```
{{< tabs >}}
{{< tab "GCP" >}}
## Install provider-gcp
You are now ready to install `provider-gcp`. Crossplane provides a
`ControllerConfig` type that allows you to customize the deployment of a
provider's controller `Pod`. A `ControllerConfig` can be created and referenced
by any number of `Provider` objects that wish to use its configuration. In the
example below, the `Pod` annotations indicate to the Vault mutating webhook that
we want for the secret stored at `secret/provider-creds/gcp-default` to be
injected into the container filesystem by assuming role `crossplane-providers`.
There is also so template formatting added to make sure the secret data is
presented in a form that `provider-gcp` is expecting.
{% raw %}
```console
echo "apiVersion: pkg.crossplane.io/v1alpha1
kind: ControllerConfig
metadata:
name: vault-config
spec:
metadata:
annotations:
vault.hashicorp.com/agent-inject: \"true\"
vault.hashicorp.com/role: "crossplane-providers"
vault.hashicorp.com/agent-inject-secret-creds.txt: "secret/provider-creds/gcp-default"
vault.hashicorp.com/agent-inject-template-creds.txt: |
{{- with secret \"secret/provider-creds/gcp-default\" -}}
{{ .Data.data | toJSON }}
{{- end -}}
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-gcp
spec:
package: xpkg.upbound.io/crossplane-contrib/provider-gcp:v0.22.0
controllerConfigRef:
name: vault-config" | kubectl apply -f -
```
{% endraw %}
## Configure provider-gcp
One `provider-gcp` is installed and running, you will want to create a
`ProviderConfig` that specifies the credentials in the filesystem that should be
used to provision managed resources that reference this `ProviderConfig`.
Because the name of this `ProviderConfig` is `default` it will be used by any
managed resources that do not explicitly reference a `ProviderConfig`.
> Note: make sure that the `PROJECT_ID` environment variable that was defined
> earlier is still set correctly.
```console
echo "apiVersion: gcp.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
projectID: ${PROJECT_ID}
credentials:
source: Filesystem
fs:
path: /vault/secrets/creds.txt" | kubectl apply -f -
```
To verify that the GCP credentials are being injected into the container run the
following command:
```console
PROVIDER_CONTROLLER_POD=$(kubectl -n crossplane-system get pod -l pkg.crossplane.io/provider=provider-gcp -o name --no-headers=true)
kubectl -n crossplane-system exec -it $PROVIDER_CONTROLLER_POD -c provider-gcp -- cat /vault/secrets/creds.txt
```
## Provision Infrastructure
The final step is to actually provision a `CloudSQLInstance`. Creating the
object below will result in the creation of a Cloud SQL Postgres database on
GCP.
```console
echo "apiVersion: database.gcp.crossplane.io/v1beta1
kind: CloudSQLInstance
metadata:
name: postgres-vault-demo
spec:
forProvider:
databaseVersion: POSTGRES_12
region: us-central1
settings:
tier: db-custom-1-3840
dataDiskType: PD_SSD
dataDiskSizeGb: 10
writeConnectionSecretToRef:
namespace: crossplane-system
name: cloudsqlpostgresql-conn" | kubectl apply -f -
```
You can monitor the progress of the database provisioning with the following
command:
```console
kubectl get cloudsqlinstance -w
```
{{< /tab >}}
{{< tab "AWS" >}}
## Install provider-aws
You are now ready to install `provider-aws`. Crossplane provides a
`ControllerConfig` type that allows you to customize the deployment of a
provider's controller `Pod`. A `ControllerConfig` can be created and referenced
by any number of `Provider` objects that wish to use its configuration. In the
example below, the `Pod` annotations indicate to the Vault mutating webhook that
we want for the secret stored at `secret/provider-creds/aws-default` to be
injected into the container filesystem by assuming role `crossplane-providers`.
There is also some template formatting added to make sure the secret data is
presented in a form that `provider-aws` is expecting.
{% raw %}
```console
echo "apiVersion: pkg.crossplane.io/v1alpha1
kind: ControllerConfig
metadata:
name: aws-vault-config
spec:
args:
- --debug
metadata:
annotations:
vault.hashicorp.com/agent-inject: \"true\"
vault.hashicorp.com/role: \"crossplane-providers\"
vault.hashicorp.com/agent-inject-secret-creds.txt: \"secret/provider-creds/aws-default\"
vault.hashicorp.com/agent-inject-template-creds.txt: |
{{- with secret \"secret/provider-creds/aws-default\" -}}
[default]
aws_access_key_id="{{ .Data.data.access_key }}"
aws_secret_access_key="{{ .Data.data.secret_key }}"
{{- end -}}
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws
spec:
package: xpkg.upbound.io/crossplane-contrib/provider-aws:v0.33.0
controllerConfigRef:
name: aws-vault-config" | kubectl apply -f -
```
{% endraw %}
## Configure provider-aws
Once `provider-aws` is installed and running, you will want to create a
`ProviderConfig` that specifies the credentials in the filesystem that should be
used to provision managed resources that reference this `ProviderConfig`.
Because the name of this `ProviderConfig` is `default` it will be used by any
managed resources that do not explicitly reference a `ProviderConfig`.
```console
echo "apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: Filesystem
fs:
path: /vault/secrets/creds.txt" | kubectl apply -f -
```
To verify that the AWS credentials are being injected into the container run the
following command:
```console
PROVIDER_CONTROLLER_POD=$(kubectl -n crossplane-system get pod -l pkg.crossplane.io/provider=provider-aws -o name --no-headers=true)
kubectl -n crossplane-system exec -it $PROVIDER_CONTROLLER_POD -c provider-aws -- cat /vault/secrets/creds.txt
```
## Provision Infrastructure
The final step is to actually provision a `Bucket`. Creating the
object below will result in the creation of a S3 bucket on AWS.
```console
echo "apiVersion: s3.aws.crossplane.io/v1beta1
kind: Bucket
metadata:
name: s3-vault-demo
spec:
forProvider:
acl: private
locationConstraint: us-east-1
publicAccessBlockConfiguration:
blockPublicPolicy: true
tagging:
tagSet:
- key: Name
value: s3-vault-demo
providerConfigRef:
name: default" | kubectl apply -f -
```
You can monitor the progress of the bucket provisioning with the following
command:
```console
kubectl get bucket -w
```
{{< /tab >}}
{{< /tabs >}}
<!-- named links -->
[Vault on Minikube]: https://learn.hashicorp.com/tutorials/vault/kubernetes-minikube
[Vault Kubernetes Sidecar]: https://learn.hashicorp.com/tutorials/vault/kubernetes-sidecar
[Vault]: https://www.vaultproject.io/
[Vault Kubernetes Sidecar]: https://www.vaultproject.io/docs/platform/k8s/injector
[provider-gcp]: https://marketplace.upbound.io/providers/crossplane-contrib/provider-gcp
[provider-aws]: https://marketplace.upbound.io/providers/crossplane-contrib/provider-aws
[AWS]: https://www.vaultproject.io/docs/secrets/aws
[Azure]: https://www.vaultproject.io/docs/secrets/azure
[GCP]: https://www.vaultproject.io/docs/secrets/gcp
[unsealed]: https://www.vaultproject.io/docs/concepts/seal
[Kubernetes authentication backend]: https://www.vaultproject.io/docs/auth/kubernetes
[kv secrets engine]: https://www.vaultproject.io/docs/secrets/kv/kv-v2
[policy]: https://www.vaultproject.io/docs/concepts/policies

View File

@ -0,0 +1,835 @@
---
title: Write a Composition Function in Go
weight: 80
description: "Composition functions allow you to template resources using Go"
---
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]({{<ref "../concepts/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).
{{< hint "important" >}}
It helps to be familiar with
[how composition functions work]({{<ref "../concepts/compositions#how-composition-functions-work" >}})
before following this guide.
{{< /hint >}}
## Understand the steps
This guide covers writing a composition function for an
{{<hover label="xr" line="2">}}XBuckets{{</hover>}} composite resource (XR).
```yaml {label="xr"}
apiVersion: example.crossplane.io/v1
kind: XBuckets
metadata:
name: example-buckets
spec:
region: us-east-2
names:
- crossplane-functions-example-a
- crossplane-functions-example-b
- crossplane-functions-example-c
```
<!-- vale gitlab.FutureTense = NO -->
<!--
This section is setting the stage for future sections. It doesn't make sense to
refer to the function in the present tense, because it doesn't exist yet.
-->
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.
<!-- vale gitlab.FutureTense = YES -->
To write a function in Go:
1. [Install the tools you need to write the function](#install-the-tools-you-need-to-write-the-function)
1. [Initialize the function from a template](#initialize-the-function-from-a-template)
1. [Edit the template to add the function's logic](#edit-the-template-to-add-the-functions-logic)
1. [Test the function end-to-end](#test-the-function-end-to-end)
1. [Build and push the function to a package repository](#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
To write a function in Go you need:
* [Go](https://go.dev/dl/) v1.21 or newer. The guide uses Go v1.21.
* [Docker Engine](https://docs.docker.com/engine/). This guide uses Engine v24.
* The [Crossplane CLI]({{<ref "../cli" >}}) v1.14 or newer. This guide uses Crossplane
CLI v1.14.
{{<hint "note">}}
You don't need access to a Kubernetes cluster or a Crossplane control plane to
build or test a composition function.
{{</hint>}}
## 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.
```shell {copy-lines=1}
crossplane xpkg init function-xbuckets function-template-go -d function-xbuckets
Initialized package "function-xbuckets" in directory "/home/negz/control/negz/function-xbuckets" from https://github.com/crossplane/function-template-go/tree/91a1a5eed21964ff98966d72cc6db6f089ad63f4 (main)
```
The `crossplane xpkg init` command creates a directory named
`function-xbuckets`. When you run the command the new directory should look like
this:
```shell {copy-lines=1}
ls function-xbuckets
Dockerfile fn.go fn_test.go go.mod go.sum input/ LICENSE main.go package/ README.md 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.
{{<hint "tip">}}
<!-- vale gitlab.FutureTense = NO -->
<!--
This tip talks about future plans for Crossplane.
-->
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.
<!-- vale gitlab.FutureTense = YES -->
{{</hint>}}
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]({{<ref "../concepts/compositions" >}})
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.
{{<hint "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.
```shell
go generate ./...
```
{{</hint>}}
## Edit the template to add the function's logic
You add your function's logic to the
{{<hover label="hello-world" line="1">}}RunFunction{{</hover>}}
method in `fn.go`. When you first open the file it contains a "hello world"
function.
```go {label="hello-world"}
func (f *Function) RunFunction(_ context.Context, req *fnv1.RunFunctionRequest) (*fnv1.RunFunctionResponse, error) {
f.log.Info("Running Function", "tag", req.GetMeta().GetTag())
rsp := response.To(req, response.DefaultTTL)
in := &v1beta1.Input{}
if err := request.GetInput(req, in); err != nil {
response.Fatal(rsp, errors.Wrapf(err, "cannot get Function input from %T", req))
return rsp, nil
}
response.Normalf(rsp, "I was run with input %q", in.Example)
return rsp, nil
}
```
All Go composition functions have a `RunFunction` method. Crossplane passes
everything the function needs to run in a
{{<hover label="hello-world" line="1">}}RunFunctionRequest{{</hover>}} struct.
The function tells Crossplane what resources it should compose by returning a
{{<hover label="hello-world" line="13">}}RunFunctionResponse{{</hover>}} struct.
{{<hint "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).
{{</hint>}}
Edit the `RunFunction` method to replace it with this code.
```go {hl_lines="4-56"}
func (f *Function) RunFunction(_ context.Context, req *fnv1.RunFunctionRequest) (*fnv1.RunFunctionResponse, error) {
rsp := response.To(req, response.DefaultTTL)
xr, err := request.GetObservedCompositeResource(req)
if err != nil {
response.Fatal(rsp, errors.Wrapf(err, "cannot get observed composite resource from %T", req))
return rsp, nil
}
region, err := xr.Resource.GetString("spec.region")
if err != nil {
response.Fatal(rsp, errors.Wrapf(err, "cannot read spec.region field of %s", xr.Resource.GetKind()))
return rsp, nil
}
names, err := xr.Resource.GetStringArray("spec.names")
if err != nil {
response.Fatal(rsp, errors.Wrapf(err, "cannot read spec.names field of %s", xr.Resource.GetKind()))
return rsp, nil
}
desired, err := request.GetDesiredComposedResources(req)
if err != nil {
response.Fatal(rsp, errors.Wrapf(err, "cannot get desired resources from %T", req))
return rsp, nil
}
_ = v1beta1.AddToScheme(composed.Scheme)
for _, name := range names {
b := &v1beta1.Bucket{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
"crossplane.io/external-name": name,
},
},
Spec: v1beta1.BucketSpec{
ForProvider: v1beta1.BucketParameters{
Region: ptr.To[string](region),
},
},
}
cd, err := composed.From(b)
if err != nil {
response.Fatal(rsp, errors.Wrapf(err, "cannot convert %T to %T", b, &composed.Unstructured{}))
return rsp, nil
}
desired[resource.Name("xbuckets-"+name)] = &resource.DesiredComposed{Resource: cd}
}
if err := response.SetDesiredComposedResources(rsp, desired); err != nil {
response.Fatal(rsp, errors.Wrapf(err, "cannot set desired composed resources in %T", rsp))
return rsp, nil
}
return rsp, nil
}
```
Expand the below block to view the full `fn.go`, including imports and
commentary explaining the function's logic.
{{<expand "The full fn.go file" >}}
```go
package main
import (
"context"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
"github.com/upbound/provider-aws/apis/s3/v1beta1"
"github.com/crossplane/function-sdk-go/errors"
"github.com/crossplane/function-sdk-go/logging"
fnv1 "github.com/crossplane/function-sdk-go/proto/v1"
"github.com/crossplane/function-sdk-go/request"
"github.com/crossplane/function-sdk-go/resource"
"github.com/crossplane/function-sdk-go/resource/composed"
"github.com/crossplane/function-sdk-go/response"
)
// Function returns whatever response you ask it to.
type Function struct {
fnv1.UnimplementedFunctionRunnerServiceServer
log logging.Logger
}
// RunFunction observes an XBuckets composite resource (XR). It adds an S3
// bucket to the desired state for every entry in the XR's spec.names array.
func (f *Function) RunFunction(_ context.Context, req *fnv1.RunFunctionRequest) (*fnv1.RunFunctionResponse, error) {
f.log.Info("Running Function", "tag", req.GetMeta().GetTag())
// Create a response to the request. This copies the desired state and
// pipeline context from the request to the response.
rsp := response.To(req, response.DefaultTTL)
// Read the observed XR from the request. Most functions use the observed XR
// to add desired managed resources.
xr, err := request.GetObservedCompositeResource(req)
if err != nil {
// If the function can't read the XR, the request is malformed. This
// should never happen. The function returns a fatal result. This tells
// Crossplane to stop running functions and return an error.
response.Fatal(rsp, errors.Wrapf(err, "cannot get observed composite resource from %T", req))
return rsp, nil
}
// Create an updated logger with useful information about the XR.
log := f.log.WithValues(
"xr-version", xr.Resource.GetAPIVersion(),
"xr-kind", xr.Resource.GetKind(),
"xr-name", xr.Resource.GetName(),
)
// Get the region from the XR. The XR has getter methods like GetString,
// GetBool, etc. You can use them to get values by their field path.
region, err := xr.Resource.GetString("spec.region")
if err != nil {
response.Fatal(rsp, errors.Wrapf(err, "cannot read spec.region field of %s", xr.Resource.GetKind()))
return rsp, nil
}
// Get the array of bucket names from the XR.
names, err := xr.Resource.GetStringArray("spec.names")
if err != nil {
response.Fatal(rsp, errors.Wrapf(err, "cannot read spec.names field of %s", xr.Resource.GetKind()))
return rsp, nil
}
// Get all desired composed resources from the request. The function will
// update this map of resources, then save it. This get, update, set pattern
// ensures the function keeps any resources added by other functions.
desired, err := request.GetDesiredComposedResources(req)
if err != nil {
response.Fatal(rsp, errors.Wrapf(err, "cannot get desired resources from %T", req))
return rsp, nil
}
// Add v1beta1 types (including Bucket) to the composed resource scheme.
// composed.From uses this to automatically set apiVersion and kind.
_ = v1beta1.AddToScheme(composed.Scheme)
// Add a desired S3 bucket for each name.
for _, name := range names {
// One advantage of writing a function in Go is strong typing. The
// function can import and use managed resource types from the provider.
b := &v1beta1.Bucket{
ObjectMeta: metav1.ObjectMeta{
// Set the external name annotation to the desired bucket name.
// This controls what the bucket will be named in AWS.
Annotations: map[string]string{
"crossplane.io/external-name": name,
},
},
Spec: v1beta1.BucketSpec{
ForProvider: v1beta1.BucketParameters{
// Set the bucket's region to the value read from the XR.
Region: ptr.To[string](region),
},
},
}
// Convert the bucket to the unstructured resource data format the SDK
// uses to store desired composed resources.
cd, err := composed.From(b)
if err != nil {
response.Fatal(rsp, errors.Wrapf(err, "cannot convert %T to %T", b, &composed.Unstructured{}))
return rsp, nil
}
// Add the bucket to the map of desired composed resources. It's
// important that the function adds the same bucket every time it's
// called. It's also important that the bucket is added with the same
// resource.Name every time it's called. The function prefixes the name
// with "xbuckets-" to avoid collisions with any other composed
// resources that might be in the desired resources map.
desired[resource.Name("xbuckets-"+name)] = &resource.DesiredComposed{Resource: cd}
}
// Finally, save the updated desired composed resources to the response.
if err := response.SetDesiredComposedResources(rsp, desired); err != nil {
response.Fatal(rsp, errors.Wrapf(err, "cannot set desired composed resources in %T", rsp))
return rsp, nil
}
// Log what the function did. This will only appear in the function's pod
// logs. A function can use response.Normal and response.Warning to emit
// Kubernetes events associated with the XR it's operating on.
log.Info("Added desired buckets", "region", region, "count", len(names))
return rsp, nil
}
```
{{</expand>}}
This code:
1. Gets the observed composite resource from the `RunFunctionRequest`.
1. Gets the region and bucket names from the observed composite resource.
1. Adds one desired S3 bucket for each bucket name.
1. Returns the desired S3 buckets in a `RunFunctionResponse`.
The code uses the `v1beta1.Bucket` type from
[Upbound's AWS S3 provider](https://github.com/upbound/provider-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:
```shell
go get github.com/upbound/provider-aws@v0.43.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.
{{<hint "tip">}}
Read the
[Go package documentation](https://pkg.go.dev/github.com/crossplane/function-sdk-go)
for the SDK.
{{</hint>}}
## 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://github.com/golang/go/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.
{{<expand "The full fn_test.go file" >}}
```go
package main
import (
"context"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"google.golang.org/protobuf/testing/protocmp"
"google.golang.org/protobuf/types/known/durationpb"
"github.com/crossplane/crossplane-runtime/pkg/logging"
fnv1 "github.com/crossplane/function-sdk-go/proto/v1"
"github.com/crossplane/function-sdk-go/resource"
)
func TestRunFunction(t *testing.T) {
type args struct {
ctx context.Context
req *fnv1.RunFunctionRequest
}
type want struct {
rsp *fnv1.RunFunctionResponse
err error
}
cases := map[string]struct {
reason string
args args
want want
}{
"AddTwoBuckets": {
reason: "The Function should add two buckets to the desired composed resources",
args: args{
req: &fnv1.RunFunctionRequest{
Observed: &fnv1.State{
Composite: &fnv1.Resource{
// MustStructJSON is a handy way to provide mock
// resources.
Resource: resource.MustStructJSON(`{
"apiVersion": "example.crossplane.io/v1alpha1",
"kind": "XBuckets",
"metadata": {
"name": "test"
},
"spec": {
"region": "us-east-2",
"names": [
"test-bucket-a",
"test-bucket-b"
]
}
}`),
},
},
},
},
want: want{
rsp: &fnv1.RunFunctionResponse{
Meta: &fnv1.ResponseMeta{Ttl: durationpb.New(60 * time.Second)},
Desired: &fnv1.State{
Resources: map[string]*fnv1.Resource{
"xbuckets-test-bucket-a": {Resource: resource.MustStructJSON(`{
"apiVersion": "s3.aws.upbound.io/v1beta1",
"kind": "Bucket",
"metadata": {
"annotations": {
"crossplane.io/external-name": "test-bucket-a"
}
},
"spec": {
"forProvider": {
"region": "us-east-2"
}
}
}`)},
"xbuckets-test-bucket-b": {Resource: resource.MustStructJSON(`{
"apiVersion": "s3.aws.upbound.io/v1beta1",
"kind": "Bucket",
"metadata": {
"annotations": {
"crossplane.io/external-name": "test-bucket-b"
}
},
"spec": {
"forProvider": {
"region": "us-east-2"
}
}
}`)},
},
},
},
},
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
f := &Function{log: logging.NewNopLogger()}
rsp, err := f.RunFunction(tc.args.ctx, tc.args.req)
if diff := cmp.Diff(tc.want.rsp, rsp, protocmp.Transform()); diff != "" {
t.Errorf("%s\nf.RunFunction(...): -want rsp, +got rsp:\n%s", tc.reason, diff)
}
if diff := cmp.Diff(tc.want.err, err, cmpopts.EquateErrors()); diff != "" {
t.Errorf("%s\nf.RunFunction(...): -want err, +got err:\n%s", tc.reason, diff)
}
})
}
}
```
{{</expand>}}
Run the unit tests using the `go test` command:
```shell
go test -v -cover .
=== RUN TestRunFunction
=== RUN TestRunFunction/AddTwoBuckets
--- PASS: TestRunFunction (0.00s)
--- PASS: TestRunFunction/AddTwoBuckets (0.00s)
PASS
coverage: 52.6% of statements
ok 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.
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.
{{<expand "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:
```yaml
apiVersion: example.crossplane.io/v1
kind: XBuckets
metadata:
name: example-buckets
spec:
region: us-east-2
names:
- crossplane-functions-example-a
- crossplane-functions-example-b
- crossplane-functions-example-c
```
<br />
The `composition.yaml` file contains the Composition to use to render the
composite resource:
```yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: create-buckets
spec:
compositeTypeRef:
apiVersion: example.crossplane.io/v1
kind: XBuckets
mode: Pipeline
pipeline:
- step: create-buckets
functionRef:
name: function-xbuckets
```
<br />
The `functions.yaml` file contains the Functions the Composition references in
its pipeline steps:
```yaml
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
name: function-xbuckets
annotations:
render.crossplane.io/runtime: Development
spec:
# The CLI ignores this package when using the Development runtime.
# You can set it to any value.
package: xpkg.upbound.io/negz/function-xbuckets:v0.1.0
```
{{</expand>}}
The Function in `functions.yaml` uses the
{{<hover label="development" line="6">}}Development{{</hover>}}
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.
```yaml {label="development"}
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
name: function-xbuckets
annotations:
render.crossplane.io/runtime: Development
```
Use `go run` to run your function locally.
```shell {label="run"}
go run . --insecure --debug
```
{{<hint "warning">}}
The {{<hover label="run" line="1">}}insecure{{</hover>}} flag tells the function
to run without encryption or authentication. Only use it during testing and
development.
{{</hint>}}
In a separate terminal, run `crossplane render`.
```shell
crossplane 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:
```shell
go run . --insecure --debug
2023-10-31T16:17:32.158-0700 INFO function-xbuckets/fn.go:29 Running Function {"tag": ""}
2023-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.
```yaml
---
apiVersion: example.crossplane.io/v1
kind: XBuckets
metadata:
name: example-buckets
---
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
annotations:
crossplane.io/composition-resource-name: xbuckets-crossplane-functions-example-b
crossplane.io/external-name: crossplane-functions-example-b
generateName: example-buckets-
labels:
crossplane.io/composite: example-buckets
ownerReferences:
# Omitted for brevity
spec:
forProvider:
region: us-east-2
---
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
annotations:
crossplane.io/composition-resource-name: xbuckets-crossplane-functions-example-c
crossplane.io/external-name: crossplane-functions-example-c
generateName: example-buckets-
labels:
crossplane.io/composite: example-buckets
ownerReferences:
# Omitted for brevity
spec:
forProvider:
region: us-east-2
---
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
annotations:
crossplane.io/composition-resource-name: xbuckets-crossplane-functions-example-a
crossplane.io/external-name: crossplane-functions-example-a
generateName: example-buckets-
labels:
crossplane.io/composite: example-buckets
ownerReferences:
# Omitted for brevity
spec:
forProvider:
region: us-east-2
```
{{<hint "tip">}}
Read the composition functions documentation to learn more about
[testing composition functions]({{< ref "../concepts/compositions#test-a-composition" >}}).
{{</hint>}}
## 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.upbound.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]({{<ref "../concepts/compositions" >}}).
to learn how to use a function in a control plane.
Use Docker to build a runtime for each platform.
```shell {copy-lines="1"}
docker build . --quiet --platform=linux/amd64 --tag runtime-amd64
sha256:fdf40374cc6f0b46191499fbc1dbbb05ddb76aca854f69f2912e580cfe624b4b
```
```shell {copy-lines="1"}
docker build . --quiet --platform=linux/arm64 --tag runtime-arm64
sha256:cb015ceabf46d2a55ccaeebb11db5659a2fb5e93de36713364efcf6d699069af
```
{{<hint "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.
{{</hint>}}
Use the Crossplane CLI to build a package for each platform. Each package embeds
a runtime image.
The {{<hover label="build" line="2">}}--package-root{{</hover>}} flag specifies
the `package` directory, which contains `crossplane.yaml`. This includes
metadata about the package.
The {{<hover label="build" line="3">}}--embed-runtime-image{{</hover>}} flag
specifies the runtime image tag built using Docker.
The {{<hover label="build" line="4">}}--package-file{{</hover>}} flag specifies
specifies where to write the package file to disk. Crossplane package files use
the extension `.xpkg`.
```shell {label="build"}
crossplane xpkg build \
--package-root=package \
--embed-runtime-image=runtime-amd64 \
--package-file=function-amd64.xpkg
```
```shell
crossplane xpkg build \
--package-root=package \
--embed-runtime-image=runtime-arm64 \
--package-file=function-arm64.xpkg
```
{{<hint "tip">}}
Crossplane packages are special OCI images. Read more about packages in the
[packages documentation]({{< ref "../concepts/packages" >}}).
{{</hint>}}
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.
```shell
crossplane xpkg push \
--package-files=function-amd64.xpkg,function-arm64.xpkg \
negz/function-xbuckets:v0.1.0
```
{{<hint "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`.
The CI workflow can automatically push packages to `xpkg.upbound.io`. For this
to work you must create a repository at https://marketplace.upbound.io. Give the
CI workflow access to push to the Marketplace by creating an API token and
[adding it to your repository](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-a-repository).
Save your API token access ID as a secret named `XPKG_ACCESS_ID` and your API
token as a secret named `XPKG_TOKEN`.
{{</hint>}}

View File

@ -0,0 +1,742 @@
---
title: Write a Composition Function in Python
weight: 81
description: "Composition functions allow you to template resources using Python"
---
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]({{<ref "../concepts/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).
{{< hint "important" >}}
It helps to be familiar with
[how composition functions work]({{<ref "../concepts/compositions#how-composition-functions-work" >}})
before following this guide.
{{< /hint >}}
## Understand the steps
This guide covers writing a composition function for an
{{<hover label="xr" line="2">}}XBuckets{{</hover>}} composite resource (XR).
```yaml {label="xr"}
apiVersion: example.crossplane.io/v1
kind: XBuckets
metadata:
name: example-buckets
spec:
region: us-east-2
names:
- crossplane-functions-example-a
- crossplane-functions-example-b
- crossplane-functions-example-c
```
<!-- vale gitlab.FutureTense = NO -->
<!--
This section is setting the stage for future sections. It doesn't make sense to
refer to the function in the present tense, because it doesn't exist yet.
-->
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.
<!-- vale gitlab.FutureTense = YES -->
To write a function in Python:
1. [Install the tools you need to write the function](#install-the-tools-you-need-to-write-the-function)
1. [Initialize the function from a template](#initialize-the-function-from-a-template)
1. [Edit the template to add the function's logic](#edit-the-template-to-add-the-functions-logic)
1. [Test the function end-to-end](#test-the-function-end-to-end)
1. [Build and push the function to a package repository](#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
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]({{<ref "../cli" >}}) v1.14 or newer. This guide uses Crossplane
CLI v1.14.
{{<hint "note">}}
You don't need access to a Kubernetes cluster or a Crossplane control plane to
build or test a composition function.
{{</hint>}}
## 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.
```shell {copy-lines=1}
crossplane xpkg init function-xbuckets https://github.com/crossplane/function-template-python -d function-xbuckets
Initialized 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:
```shell {copy-lines=1}
ls function-xbuckets
Dockerfile example/ function/ LICENSE package/ pyproject.toml README.md renovate.json tests/
```
Your function's code lives in the `function` directory:
```shell {copy-lines=1}
ls function/
__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.
{{<hint "tip">}}
<!-- vale gitlab.FutureTense = NO -->
<!--
This tip talks about future plans for Crossplane.
-->
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.
<!-- vale gitlab.FutureTense = YES -->
{{</hint>}}
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]({{<ref "../concepts/compositions" >}})
documentation explains composition function inputs.
{{<hint "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.
{{</hint>}}
## Edit the template to add the function's logic
You add your function's logic to the
{{<hover label="hello-world" line="1">}}RunFunction{{</hover>}}
method in `function/fn.py`. When you first open the file it contains a "hello
world" function.
```python {label="hello-world"}
async def RunFunction(self, req: fnv1.RunFunctionRequest, _: grpc.aio.ServicerContext) -> fnv1.RunFunctionResponse:
log = self.log.bind(tag=req.meta.tag)
log.info("Running function")
rsp = response.to(req)
example = ""
if "example" in req.input:
example = req.input["example"]
# TODO: Add your function logic here!
response.normal(rsp, f"I was run with input {example}!")
log.info("I was run!", input=example)
return rsp
```
All Python composition functions have a `RunFunction` method. Crossplane passes
everything the function needs to run in a
{{<hover label="hello-world" line="1">}}RunFunctionRequest{{</hover>}} object.
The function tells Crossplane what resources it should compose by returning a
{{<hover label="hello-world" line="15">}}RunFunctionResponse{{</hover>}} object.
Edit the `RunFunction` method to replace it with this code.
```python {hl_lines="7-28"}
async def RunFunction(self, req: fnv1.RunFunctionRequest, _: grpc.aio.ServicerContext) -> fnv1.RunFunctionResponse:
log = self.log.bind(tag=req.meta.tag)
log.info("Running function")
rsp = response.to(req)
region = req.observed.composite.resource["spec"]["region"]
names = req.observed.composite.resource["spec"]["names"]
for name in names:
rsp.desired.resources[f"xbuckets-{name}"].resource.update(
{
"apiVersion": "s3.aws.upbound.io/v1beta1",
"kind": "Bucket",
"metadata": {
"annotations": {
"crossplane.io/external-name": name,
},
},
"spec": {
"forProvider": {
"region": region,
},
},
}
)
log.info("Added desired buckets", region=region, count=len(names))
return rsp
```
Expand the below block to view the full `fn.py`, including imports and
commentary explaining the function's logic.
{{<expand "The full fn.py file" >}}
```python
"""A Crossplane composition function."""
import grpc
from crossplane.function import logging, response
from crossplane.function.proto.v1 import run_function_pb2 as fnv1
from crossplane.function.proto.v1 import run_function_pb2_grpc as grpcv1
class FunctionRunner(grpcv1.FunctionRunnerService):
"""A FunctionRunner handles gRPC RunFunctionRequests."""
def __init__(self):
"""Create a new FunctionRunner."""
self.log = logging.get_logger()
async def RunFunction(
self, req: fnv1.RunFunctionRequest, _: grpc.aio.ServicerContext
) -> fnv1.RunFunctionResponse:
"""Run the function."""
# Create a logger for this request.
log = self.log.bind(tag=req.meta.tag)
log.info("Running function")
# Create a response to the request. This copies the desired state and
# pipeline context from the request to the response.
rsp = response.to(req)
# Get the region and a list of bucket names from the observed composite
# resource (XR). Crossplane represents resources using the Struct
# well-known protobuf type. The Struct Python object can be accessed
# like a dictionary.
region = req.observed.composite.resource["spec"]["region"]
names = req.observed.composite.resource["spec"]["names"]
# Add a desired S3 bucket for each name.
for name in names:
# Crossplane represents desired composed resources using a protobuf
# map of messages. This works a little like a Python defaultdict.
# Instead of assigning to a new key in the dict-like map, you access
# the key and mutate its value as if it did exist.
#
# The below code works because accessing the xbuckets-{name} key
# automatically creates a new, empty fnv1.Resource message. The
# Resource message has a resource field containing an empty Struct
# object that can be populated from a dictionary by calling update.
#
# https://protobuf.dev/reference/python/python-generated/#map-fields
rsp.desired.resources[f"xbuckets-{name}"].resource.update(
{
"apiVersion": "s3.aws.upbound.io/v1beta1",
"kind": "Bucket",
"metadata": {
"annotations": {
"crossplane.io/external-name": name,
},
},
"spec": {
"forProvider": {
"region": region,
},
},
}
)
# Log what the function did. This will only appear in the function's pod
# logs. A function can use response.normal() and response.warning() to
# emit Kubernetes events associated with the XR it's operating on.
log.info("Added desired buckets", region=region, count=len(names))
return rsp
```
{{</expand>}}
This code:
1. Gets the observed composite resource from the `RunFunctionRequest`.
1. Gets the region and bucket names from the observed composite resource.
1. Adds one desired S3 bucket for each bucket name.
1. 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.
{{<hint "tip">}}
Read [the Python Function SDK documentation](https://crossplane.github.io/function-sdk-python).
{{</hint>}}
{{<hint "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:
```python
resource = {"apiVersion": "example.org/v1", "kind": "Composed", ...}
rsp.desired.resources["new-resource"] = fnv1.Resource(resource=resource)
```
Pretend it already exists and mutate it, like this:
```python
resource = {"apiVersion": "example.org/v1", "kind": "Composed", ...}
rsp.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.
{{</hint>}}
## 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.
{{<expand "The full test_fn.py file" >}}
```python
import dataclasses
import unittest
from crossplane.function import logging, resource
from crossplane.function.proto.v1 import run_function_pb2 as fnv1
from google.protobuf import duration_pb2 as durationpb
from google.protobuf import json_format
from google.protobuf import struct_pb2 as structpb
from function import fn
class TestFunctionRunner(unittest.IsolatedAsyncioTestCase):
def setUp(self) -> None:
logging.configure(level=logging.Level.DISABLED)
self.maxDiff = 2000
async def test_run_function(self) -> None:
@dataclasses.dataclass
class TestCase:
reason: str
req: fnv1.RunFunctionRequest
want: fnv1.RunFunctionResponse
cases = [
TestCase(
reason="The function should compose two S3 buckets.",
req=fnv1.RunFunctionRequest(
observed=fnv1.State(
composite=fnv1.Resource(
resource=resource.dict_to_struct(
{
"apiVersion": "example.crossplane.io/v1alpha1",
"kind": "XBuckets",
"metadata": {"name": "test"},
"spec": {
"region": "us-east-2",
"names": ["test-bucket-a", "test-bucket-b"],
},
}
)
)
)
),
want=fnv1.RunFunctionResponse(
meta=fnv1.ResponseMeta(ttl=durationpb.Duration(seconds=60)),
desired=fnv1.State(
resources={
"xbuckets-test-bucket-a": fnv1.Resource(
resource=resource.dict_to_struct(
{
"apiVersion": "s3.aws.upbound.io/v1beta1",
"kind": "Bucket",
"metadata": {
"annotations": {
"crossplane.io/external-name": "test-bucket-a"
},
},
"spec": {
"forProvider": {"region": "us-east-2"}
},
}
)
),
"xbuckets-test-bucket-b": fnv1.Resource(
resource=resource.dict_to_struct(
{
"apiVersion": "s3.aws.upbound.io/v1beta1",
"kind": "Bucket",
"metadata": {
"annotations": {
"crossplane.io/external-name": "test-bucket-b"
},
},
"spec": {
"forProvider": {"region": "us-east-2"}
},
}
)
),
},
),
context=structpb.Struct(),
),
),
]
runner = fn.FunctionRunner()
for case in cases:
got = await runner.RunFunction(case.req, None)
self.assertEqual(
json_format.MessageToDict(got),
json_format.MessageToDict(case.want),
"-want, +got",
)
if __name__ == "__main__":
unittest.main()
```
{{</expand>}}
Run the unit tests using `hatch run`:
```shell {copy-lines="1"}
hatch run test:unit
.
----------------------------------------------------------------------
Ran 1 test in 0.003s
OK
```
{{<hint "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.
{{</hint>}}
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.
{{<expand "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:
```yaml
apiVersion: example.crossplane.io/v1
kind: XBuckets
metadata:
name: example-buckets
spec:
region: us-east-2
names:
- crossplane-functions-example-a
- crossplane-functions-example-b
- crossplane-functions-example-c
```
<br />
The `composition.yaml` file contains the Composition to use to render the
composite resource:
```yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: create-buckets
spec:
compositeTypeRef:
apiVersion: example.crossplane.io/v1
kind: XBuckets
mode: Pipeline
pipeline:
- step: create-buckets
functionRef:
name: function-xbuckets
```
<br />
The `functions.yaml` file contains the Functions the Composition references in
its pipeline steps:
```yaml
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
name: function-xbuckets
annotations:
render.crossplane.io/runtime: Development
spec:
# The CLI ignores this package when using the Development runtime.
# You can set it to any value.
package: xpkg.upbound.io/negz/function-xbuckets:v0.1.0
```
{{</expand>}}
The Function in `functions.yaml` uses the
{{<hover label="development" line="6">}}Development{{</hover>}}
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.
```yaml {label="development"}
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
name: function-xbuckets
annotations:
render.crossplane.io/runtime: Development
```
Use `hatch run development` to run your function locally.
```shell {label="run"}
hatch run development
```
{{<hint "warning">}}
`hatch run development` runs the function without encryption or authentication.
Only use it during testing and development.
{{</hint>}}
In a separate terminal, run `crossplane render`.
```shell
crossplane 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:
```shell
hatch run development
2024-01-11T22:12:58.153572Z [info ] Running function filename=fn.py lineno=22 tag=
2024-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.
```yaml
---
apiVersion: example.crossplane.io/v1
kind: XBuckets
metadata:
name: example-buckets
---
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
annotations:
crossplane.io/composition-resource-name: xbuckets-crossplane-functions-example-b
crossplane.io/external-name: crossplane-functions-example-b
generateName: example-buckets-
labels:
crossplane.io/composite: example-buckets
ownerReferences:
# Omitted for brevity
spec:
forProvider:
region: us-east-2
---
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
annotations:
crossplane.io/composition-resource-name: xbuckets-crossplane-functions-example-c
crossplane.io/external-name: crossplane-functions-example-c
generateName: example-buckets-
labels:
crossplane.io/composite: example-buckets
ownerReferences:
# Omitted for brevity
spec:
forProvider:
region: us-east-2
---
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
annotations:
crossplane.io/composition-resource-name: xbuckets-crossplane-functions-example-a
crossplane.io/external-name: crossplane-functions-example-a
generateName: example-buckets-
labels:
crossplane.io/composite: example-buckets
ownerReferences:
# Omitted for brevity
spec:
forProvider:
region: us-east-2
```
{{<hint "tip">}}
Read the composition functions documentation to learn more about
[testing composition functions]({{< ref "../concepts/compositions#test-a-composition" >}}).
{{</hint>}}
## 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.upbound.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]({{<ref "../concepts/compositions" >}}).
to learn how to use a function in a control plane.
Use Docker to build a runtime for each platform.
```shell {copy-lines="1"}
docker build . --quiet --platform=linux/amd64 --tag runtime-amd64
sha256:fdf40374cc6f0b46191499fbc1dbbb05ddb76aca854f69f2912e580cfe624b4b
```
```shell {copy-lines="1"}
docker build . --quiet --platform=linux/arm64 --tag runtime-arm64
sha256:cb015ceabf46d2a55ccaeebb11db5659a2fb5e93de36713364efcf6d699069af
```
{{<hint "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.
{{</hint>}}
{{<hint "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.
{{</hint>}}
Use the Crossplane CLI to build a package for each platform. Each package embeds
a runtime image.
The {{<hover label="build" line="2">}}--package-root{{</hover>}} flag specifies
the `package` directory, which contains `crossplane.yaml`. This includes
metadata about the package.
The {{<hover label="build" line="3">}}--embed-runtime-image{{</hover>}} flag
specifies the runtime image tag built using Docker.
The {{<hover label="build" line="4">}}--package-file{{</hover>}} flag specifies
specifies where to write the package file to disk. Crossplane package files use
the extension `.xpkg`.
```shell {label="build"}
crossplane xpkg build \
--package-root=package \
--embed-runtime-image=runtime-amd64 \
--package-file=function-amd64.xpkg
```
```shell
crossplane xpkg build \
--package-root=package \
--embed-runtime-image=runtime-arm64 \
--package-file=function-arm64.xpkg
```
{{<hint "tip">}}
Crossplane packages are special OCI images. Read more about packages in the
[packages documentation]({{< ref "../concepts/packages" >}}).
{{</hint>}}
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.
```shell
crossplane xpkg push \
--package-files=function-amd64.xpkg,function-arm64.xpkg \
negz/function-xbuckets:v0.1.0
```
{{<hint "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`.
The CI workflow can automatically push packages to `xpkg.upbound.io`. For this
to work you must create a repository at https://marketplace.upbound.io. Give the
CI workflow access to push to the Marketplace by creating an API token and
[adding it to your repository](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-a-repository).
Save your API token access ID as a secret named `XPKG_ACCESS_ID` and your API
token as a secret named `XPKG_TOKEN`.
{{</hint>}}

View File

@ -0,0 +1,35 @@
---
title: Learn More
description: Learn more about Crossplane.
weight: 500
---
If you have any questions, please drop us a note on [Crossplane Slack][join-crossplane-slack] or [contact us][contact-us]!
***Learn more about using Crossplane***
- [Latest Design Docs](https://github.com/crossplane/crossplane/tree/master/design)
- [Roadmap](https://github.com/crossplane/crossplane/blob/master/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/master/CONTRIBUTING.md)
***Join the growing Crossplane community and get involved!***
- Join our [Community Slack](https://slack.crossplane.io/)!
- Submit an issue on [GitHub](https://github.com/crossplane/crossplane)
- Attend our bi-weekly [Community Meeting](https://github.com/crossplane/crossplane#get-involved)
- Join our bi-weekly live stream: [The Binding Status](https://github.com/crossplane/tbs)
- Subscribe to our [YouTube Channel](https://www.youtube.com/channel/UC19FgzMBMqBro361HbE46Fw)
- Drop us a note on Twitter: [@crossplane_io](https://twitter.com/crossplane_io)
- Email us: [info@crossplane.io](mailto:info@crossplane.io)
<!-- Named links -->
[join-crossplane-slack]: https://slack.crossplane.io
[contact-us]: https://github.com/crossplane/crossplane#contact

View File

@ -0,0 +1,56 @@
---
title: Feature Lifecycle
toc: true
weight: 309
indent: true
---
# Feature Lifecycle
Crossplane follows a similar feature lifecycle to [upstream
Kubernetes][kube-features]. All major new features must be added in alpha. Alpha
features are expected to eventually graduate to beta, and then to general
availability (GA). Features that languish at alpha or beta may be subject to
deprecation.
## Alpha Features
Alpha are off by default, and must be enabled by a feature flag, for example
`--enable-composition-revisions`. API types pertaining to alpha features use a
`vNalphaN` style API version, like `v1alpha`. **Alpha features are subject to
removal or breaking changes without notice**, and generally not considered ready
for use in production.
In some cases alpha features require fields be added to existing beta or GA
API types. In these cases fields must clearly be marked (i.e 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
Beta features are on by default, but may be disabled by a feature flag. API
types pertaining to beta features use a `vNbetaN` style API version, like
`v1beta1`. Beta features are considered to be well tested, and will not be
removed completely without being marked deprecated for at least two releases.
The schema and/or semantics of objects may change in incompatible ways in a
subsequent beta or stable release. When this happens, we will provide
instructions for migrating to the next version. This may require deleting,
editing, and re-creating API objects. The editing process may require some
thought. This may require downtime for applications that rely on the feature.
In some cases beta features require fields be added to existing GA API types. In
these cases fields must clearly be marked (i.e 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
GA features are always enabled - they cannot be disabled. API types pertaining
to GA features use `vN` style API versions, like `v1`. GA features are widely
used and thoroughly tested. They guarantee API stability - only backward
compatible changes are allowed.
[kube-features]: https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/#feature-stages

View File

@ -0,0 +1,100 @@
---
title: Release Cycle
weight: 308
---
Starting with the v1.10.0 release, Crossplane is released on a quarterly (13
week) cadence. A cycle is comprised of three general stages:
- Weeks 1—11: [Active Development]
- Week 12: [Feature Freeze]
- Week 13: [Code Freeze]
This results in four releases per year, with the most recent three releases
being maintained at any given time. When a new release is cut, the fourth most
recent release reaches end of life (EOL). Users can expect any given release to
be maintained for nine months.
### Definition of maintenance
The Crossplane community defines maintenance in that relevant bug fixes that are
merged to the main development branch will be eligible to be back-ported to the
release branch of any currently maintained version, and patch releases will be
cut appropriately. It's also possible that a fix may be merged directly to the
release branch if no longer applicable on the main development branch.
Maintenance doesn't indicate any SLA on response time for user support in the
form of Slack messages or issues, but problems will be addressed on a best
effort basis by maintainers and contributors for currently maintained releases.
### Patch releases
_This policy is subject to change in the future._
Patch releases are cut for currently maintained minor versions on an as-needed
basis. Any critical back-ported fixes will be included in a patch release as
soon as possible after merge.
### Pre-releases
_This policy is subject to change in the future._
Alpha, Beta, and RC releases are cut for an upcoming release on an as-needed
basis. As a policy, at least one pre-release will be cut prior to any minor
release. Pre-releases won't be made on release branches.
### Provider releases
The Crossplane release cycle isn't required to be adhered to by any other
Crossplane projects, but a similar cadence is encouraged. Maintainers listed in
each repository's `OWNERS.md` file are responsible for determining and
publishing the release cycle for their project.
## Release stages
The following stages are the main milestones in a Crossplane release.
### Active development
During active development, any code that meets the requisite criteria (i.e.
passing appropriate tests, approved by a maintainer, etc.) will be merged into
the main development branch. At present, there is no requirement to formally
submit an enhancement proposal prior to the start of the release cycle, but
contributors are encouraged to open an issue and gather feedback before starting
work on a major implementation (see [CONTRIBUTING.md] for more information).
### Feature freeze
During feature freeze, no new functionality should be merged into the main
development branch. Bug fixes, documentation changes, and non-critical changes
may be made. In the case that a new feature is deemed absolutely necessary for a
release, the Crossplane maintainers will weigh the impact of the change and make
a decision on whether it should be included.
### 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
functionality.
- Documentation only changes. It's possible that a documentation freeze will be
implemented in the future, but it's not currently enforced.
- Fixes to a critical bug that wasn't previously identified. Merging a bug fix
during code freeze requires application for and approval of an exception by
Crossplane maintainers. This process is currently informal, but may be
formalized in the future.
## 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][community calendar]. 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.
<!-- Named links -->
[Active Development]: #active-development
[Feature Freeze]: #feature-freeze
[Code Freeze]: #code-freeze
[CONTRIBUTING.md]: https://github.com/crossplane/crossplane/blob/master/CONTRIBUTING.md
[community calendar]: https://calendar.google.com/calendar/embed?src=c_2cdn0hs9e2m05rrv1233cjoj1k%40group.calendar.google.com

View File

@ -0,0 +1,14 @@
---
title: Install, Upgrade and Uninstall
weight: 10
description: Manage Crossplane installations
---
## [Install Crossplane](install/)
How to install and customize Crossplane in an existing Kubernetes cluster.
## [Upgrade Crossplane](upgrade/)
How to upgrade Crossplane to newer versions of the software.
## [Uninstall Crossplane](uninstall/)
How to remove Crossplane from a Kubernetes cluster.

View File

@ -0,0 +1,341 @@
---
title: Install Crossplane
weight: 100
---
Crossplane installs into an existing Kubernetes cluster, creating the
`Crossplane` pod, enabling the installation of Crossplane _Provider_ resources.
{{< hint type="tip" >}}
If you don't have a Kubernetes cluster create one locally with [Kind](https://kind.sigs.k8s.io/).
{{< /hint >}}
## 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
Install Crossplane using the Crossplane published _Helm chart_.
### Add the Crossplane Helm repository
Add the Crossplane repository with the `helm repo add` command.
```shell
helm repo add crossplane-stable https://charts.crossplane.io/stable
```
Update the
local Helm chart cache with `helm repo update`.
```shell
helm repo update
```
### Install the Crossplane Helm chart
Install the Crossplane Helm chart with `helm install`.
{{< hint "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.
{{< /hint >}}
Crossplane creates and installs into the `crossplane-system` namespace.
```shell
helm install crossplane \
--namespace crossplane-system \
--create-namespace crossplane-stable/crossplane
```
View the installed Crossplane pods with `kubectl get pods -n crossplane-system`.
```shell {copy-lines="1"}
kubectl get pods -n crossplane-system
NAME READY STATUS RESTARTS AGE
crossplane-6d67f8cd9d-g2gjw 1/1 Running 0 26m
crossplane-rbac-manager-86d9b5cf9f-2vc4s 1/1 Running 0 26m
```
{{< hint "tip" >}}
Install a specific version of Crossplane with the `--version <version>` option. For example, to install version `1.10.0`:
```shell
helm install crossplane \
--namespace crossplane-system \
--create-namespace crossplane-stable/crossplane \
--version 1.10.0
```
{{< /hint >}}
## Installed deployments
Crossplane creates two Kubernetes _deployments_ in the `crossplane-system`
namespace to deploy the Crossplane pods.
```shell {copy-lines="1"}
kubectl get deployments -n crossplane-system
NAME READY UP-TO-DATE AVAILABLE AGE
crossplane 1/1 1 1 8m13s
crossplane-rbac-manager 1/1 1 1 8m13s
```
### Crossplane deployment
The Crossplane deployment starts with the `crossplane-init container`. The
`init` container installs the Crossplane _Custom Resource Definitions_ into the
Kubernetes cluster.
After the `init` container finishes, the `crossplane` pod manages two Kubernetes
controllers.
* The _Package Manager controller_ installs the
provider, function and configuration packages.
* The _Composition controller_ installs and manages the
Crossplane _Composite Resource Definitions_, _Compositions_ and _Claims_.
### Crossplane RBAC manager deployment
The `crossplane-rbac-manager` creates and manages Kubernetes _ClusterRoles_ for
installed Crossplane _Provider_ and their _Custom Resource Definitions_.
The
[Crossplane RBAC Manager design document](https://github.com/crossplane/crossplane/blob/master/design/design-doc-rbac-manager.md)
has more information on the installed _ClusterRoles_.
## Installation options
### Customize the Crossplane Helm chart
Crossplane supports customizations at install time by configuring the Helm
chart.
Apply customizations with the command line or with a Helm _values_ file.
<!-- Generated from Helm README at https://github.com/crossplane/crossplane/blob/master/cluster/charts/crossplane/README.md -->
<!-- vale gitlab.Substitutions = NO -->
<!-- allow lowercase yaml -->
{{<expand "All Crossplane customization options" >}}
{{< table "table table-hover table-striped table-sm">}}
| Parameter | Description | Default |
| --- | --- | --- |
| `affinity` | Add `affinities` to the Crossplane pod deployment. | `{}` |
| `args` | Add custom arguments to the Crossplane pod. | `[]` |
| `configuration.packages` | A list of Configuration packages to install. | `[]` |
| `customAnnotations` | Add custom `annotations` to the Crossplane pod deployment. | `{}` |
| `customLabels` | Add custom `labels` to the Crossplane pod deployment. | `{}` |
| `deploymentStrategy` | The deployment strategy for the Crossplane and RBAC Manager pods. | `"RollingUpdate"` |
| `extraEnvVarsCrossplane` | Add custom environmental variables to the Crossplane pod deployment. Replaces any `.` in a variable name with `_`. For example, `SAMPLE.KEY=value1` becomes `SAMPLE_KEY=value1`. | `{}` |
| `extraEnvVarsRBACManager` | Add custom environmental variables to the RBAC Manager pod deployment. Replaces any `.` in a variable name with `_`. For example, `SAMPLE.KEY=value1` becomes `SAMPLE_KEY=value1`. | `{}` |
| `extraObjects` | To add arbitrary Kubernetes Objects during a Helm Install | `[]` |
| `extraVolumeMountsCrossplane` | Add custom `volumeMounts` to the Crossplane pod. | `{}` |
| `extraVolumesCrossplane` | Add custom `volumes` to the Crossplane pod. | `{}` |
| `function.packages` | A list of Function packages to install. | `[]` |
| `hostNetwork` | Enable `hostNetwork` for the Crossplane deployment. Caution: enabling `hostNetwork` grants the Crossplane Pod access to the host network namespace. | `false` |
| `image.pullPolicy` | The image pull policy used for Crossplane and RBAC Manager pods. | `"IfNotPresent"` |
| `image.repository` | Repository for the Crossplane pod image. | `"xpkg.upbound.io/crossplane/crossplane"` |
| `image.tag` | The Crossplane image tag. Defaults to the value of `appVersion` in `Chart.yaml`. | `""` |
| `imagePullSecrets` | The imagePullSecret names to add to the Crossplane ServiceAccount. | `{}` |
| `leaderElection` | Enable [leader election](https://docs.crossplane.io/latest/concepts/pods/#leader-election) for the Crossplane pod. | `true` |
| `metrics.enabled` | Enable Prometheus path, port and scrape annotations and expose port 8080 for both the Crossplane and RBAC Manager pods. | `false` |
| `nodeSelector` | Add `nodeSelectors` to the Crossplane pod deployment. | `{}` |
| `packageCache.configMap` | The name of a ConfigMap to use as the package cache. Disables the default package cache `emptyDir` Volume. | `""` |
| `packageCache.medium` | Set to `Memory` to hold the package cache in a RAM backed file system. Useful for Crossplane development. | `""` |
| `packageCache.pvc` | The name of a PersistentVolumeClaim to use as the package cache. Disables the default package cache `emptyDir` Volume. | `""` |
| `packageCache.sizeLimit` | The size limit for the package cache. If medium is `Memory` the `sizeLimit` can't exceed Node memory. | `"20Mi"` |
| `podSecurityContextCrossplane` | Add a custom `securityContext` to the Crossplane pod. | `{}` |
| `podSecurityContextRBACManager` | Add a custom `securityContext` to the RBAC Manager pod. | `{}` |
| `priorityClassName` | The PriorityClass name to apply to the Crossplane and RBAC Manager pods. | `""` |
| `provider.packages` | A list of Provider packages to install. | `[]` |
| `rbacManager.affinity` | Add `affinities` to the RBAC Manager pod deployment. | `{}` |
| `rbacManager.args` | Add custom arguments to the RBAC Manager pod. | `[]` |
| `rbacManager.deploy` | Deploy the RBAC Manager pod and its required roles. | `true` |
| `rbacManager.leaderElection` | Enable [leader election](https://docs.crossplane.io/latest/concepts/pods/#leader-election) for the RBAC Manager pod. | `true` |
| `rbacManager.nodeSelector` | Add `nodeSelectors` to the RBAC Manager pod deployment. | `{}` |
| `rbacManager.replicas` | The number of RBAC Manager pod `replicas` to deploy. | `1` |
| `rbacManager.skipAggregatedClusterRoles` | Don't install aggregated Crossplane ClusterRoles. | `false` |
| `rbacManager.tolerations` | Add `tolerations` to the RBAC Manager pod deployment. | `[]` |
| `rbacManager.topologySpreadConstraints` | Add `topologySpreadConstraints` to the RBAC Manager pod deployment. | `[]` |
| `registryCaBundleConfig.key` | The ConfigMap key containing a custom CA bundle to enable fetching packages from registries with unknown or untrusted certificates. | `""` |
| `registryCaBundleConfig.name` | The ConfigMap name containing a custom CA bundle to enable fetching packages from registries with unknown or untrusted certificates. | `""` |
| `replicas` | The number of Crossplane pod `replicas` to deploy. | `1` |
| `resourcesCrossplane.limits.cpu` | CPU resource limits for the Crossplane pod. | `"100m"` |
| `resourcesCrossplane.limits.memory` | Memory resource limits for the Crossplane pod. | `"512Mi"` |
| `resourcesCrossplane.requests.cpu` | CPU resource requests for the Crossplane pod. | `"100m"` |
| `resourcesCrossplane.requests.memory` | Memory resource requests for the Crossplane pod. | `"256Mi"` |
| `resourcesRBACManager.limits.cpu` | CPU resource limits for the RBAC Manager pod. | `"100m"` |
| `resourcesRBACManager.limits.memory` | Memory resource limits for the RBAC Manager pod. | `"512Mi"` |
| `resourcesRBACManager.requests.cpu` | CPU resource requests for the RBAC Manager pod. | `"100m"` |
| `resourcesRBACManager.requests.memory` | Memory resource requests for the RBAC Manager pod. | `"256Mi"` |
| `securityContextCrossplane.allowPrivilegeEscalation` | Enable `allowPrivilegeEscalation` for the Crossplane pod. | `false` |
| `securityContextCrossplane.readOnlyRootFilesystem` | Set the Crossplane pod root file system as read-only. | `true` |
| `securityContextCrossplane.runAsGroup` | The group ID used by the Crossplane pod. | `65532` |
| `securityContextCrossplane.runAsUser` | The user ID used by the Crossplane pod. | `65532` |
| `securityContextRBACManager.allowPrivilegeEscalation` | Enable `allowPrivilegeEscalation` for the RBAC Manager pod. | `false` |
| `securityContextRBACManager.readOnlyRootFilesystem` | Set the RBAC Manager pod root file system as read-only. | `true` |
| `securityContextRBACManager.runAsGroup` | The group ID used by the RBAC Manager pod. | `65532` |
| `securityContextRBACManager.runAsUser` | The user ID used by the RBAC Manager pod. | `65532` |
| `serviceAccount.customAnnotations` | Add custom `annotations` to the Crossplane ServiceAccount. | `{}` |
| `tolerations` | Add `tolerations` to the Crossplane pod deployment. | `[]` |
| `topologySpreadConstraints` | Add `topologySpreadConstraints` to the Crossplane pod deployment. | `[]` |
| `webhooks.enabled` | Enable webhooks for Crossplane and installed Provider packages. | `true` |
{{< /table >}}
{{< /expand >}}
<!-- vale gitlab.Substitutions = YES -->
#### Command line customization
Apply custom settings at the command line with
`helm install crossplane --set <setting>=<value>`.
For example, to change the image pull policy:
```shell
helm install crossplane \
--namespace crossplane-system \
--create-namespace \
crossplane-stable/crossplane \
--set image.pullPolicy=Always
```
Helm supports comma-separated arguments.
For example, to change the image pull policy and number of replicas:
```shell
helm install crossplane \
--namespace crossplane-system \
--create-namespace \
crossplane-stable/crossplane \
--set image.pullPolicy=Always,replicas=2
```
#### Helm values file
Apply custom settings in a Helm _values_ file with
`helm install crossplane -f <filename>`.
A YAML file defines the customized settings.
For example, to change the image pull policy and number of replicas:
Create a YAML with the customized settings.
```yaml
replicas: 2
image:
pullPolicy: Always
```
Apply the file with `helm install`:
```shell
helm install crossplane \
--namespace crossplane-system \
--create-namespace \
crossplane-stable/crossplane \
-f settings.yaml
```
#### 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.
{{< expand "Feature flags" >}}
{{< table caption="Feature flags" >}}
| Status | Flag | Description |
| --- | --- | --- |
| Beta | `--enable-composition-functions` | Enable support for Composition Functions. |
| Beta | `--enable-composition-functions-extra-resources` | Enable support for Composition Functions Extra Resources. Only respected with `--enable-composition-functions` enabled. |
| Beta | `--enable-composition-webhook-schema-validation` | Enable Composition validation using schemas. |
| Beta | `--enable-deployment-runtime-configs` | Enable support for DeploymentRuntimeConfigs. |
| Alpha | `--enable-environment-configs` | Enable support for EnvironmentConfigs. |
| Alpha | `--enable-external-secret-stores` | Enable support for External Secret Stores. |
| Alpha | `--enable-realtime-compositions` | Enable support for real time compositions. |
| Alpha | `--enable-ssa-claims` | Enable support for using server-side apply to sync claims with XRs. |
| Alpha | `--enable-usages` | Enable support for Usages. |
{{< /table >}}
{{< /expand >}}
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"}'`.
#### Change the default package registry
Beginning with Crossplane version 1.15.0 Crossplane downloads packages from the
[Upbound Marketplace](https://marketplace.upbound.io) at `xpkg.upbound.io`
instead of DockerHub.
Change the default registry location during the Crossplane install with
`--set args='{"--registry=index.docker.io"}'`.
### Install pre-release Crossplane versions
Install a pre-release versions of Crossplane from the `master` Crossplane Helm channel.
Versions in the `master` channel are under active development and may be unstable.
{{< hint "warning" >}}
Don't use Crossplane `master` releases in production. Only use `stable` channel.
Only use `master` for testing and development.
{{< /hint >}}
#### Add the Crossplane master Helm repository
Add the Crossplane repository with the `helm repo add` command.
```shell
helm repo add crossplane-master https://charts.crossplane.io/master/
```
Update the
local Helm chart cache with `helm repo update`.
```shell
helm repo update
```
#### Install the Crossplane master Helm chart
Install the Crossplane `master` Helm chart with `helm install`.
{{< hint "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.
{{< /hint >}}
Crossplane creates and installs into the `crossplane-system` namespace.
```shell
helm install crossplane \
--namespace crossplane-system \
--create-namespace crossplane-master/crossplane \
--devel
```
## Crossplane distributions
Third-party vendors may maintain their own Crossplane distributions. Vendor
supported distribution may have features or tooling that isn't in the
Community Crossplane distribution.
The CNCF certified third-party distributions as
"[conformant](https://github.com/cncf/crossplane-conformance)" with the
Community Crossplane distribution.
### Vendors
Below are vendors providing conformant Crossplane distributions.
#### Upbound
Upbound, the founders of Crossplane, maintains a free and open source
distribution of Crossplane called
[Universal Crossplane](https://www.upbound.io/product/universal-crossplane)
(`UXP`).
Find information on UXP in the
[Upbound UXP documentation](https://docs.upbound.io/uxp/install/).

View File

@ -0,0 +1,183 @@
---
title: Uninstall Crossplane
weight: 300
---
{{<hint "warning" >}}
Resources created by Crossplane aren't deleted if Crossplane isn't uninstalled
in order.
This can leave cloud resources running, requiring manual deletion.
{{< /hint >}}
## 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 like _claims_.
{{<hint "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.
{{<expand "An example kubectl get managed" >}}
```shell {copy-lines="1"}
kubectl get managed
NAME READY SYNCED EXTERNAL-NAME AGE
securitygroup.ec2.aws.upbound.io/my-db-7mc7h-j84h8 True True sg-0da6e9c29113596b6 3m1s
securitygroup.ec2.aws.upbound.io/my-db-8bhr2-9wsx9 True True sg-02695166f010ec05b 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
route.ec2.aws.upbound.io/my-db-7mc7h-vw985 True True r-rtb-05822b8df433e4e2b1080289494 3m1s
route.ec2.aws.upbound.io/my-db-8bhr2-7m2wq False True 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
securitygrouprule.ec2.aws.upbound.io/my-db-7mc7h-mkd9s True True sgrule-778063708 3m1s
securitygrouprule.ec2.aws.upbound.io/my-db-8bhr2-lzr89 False True 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
routetable.ec2.aws.upbound.io/my-db-7mc7h-mnqvm True True rtb-05822b8df433e4e2b 3m1s
routetable.ec2.aws.upbound.io/my-db-8bhr2-dfhj6 True True rtb-02e875abd25658254 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
subnet.ec2.aws.upbound.io/my-db-7mc7h-7m49d True True subnet-0c1ab32c5ec129dd1 3m2s
subnet.ec2.aws.upbound.io/my-db-7mc7h-9t64t True True subnet-07075c17c7a72f79e 3m2s
subnet.ec2.aws.upbound.io/my-db-7mc7h-rs8t8 True True subnet-08e88e826a42e55b4 3m2s
subnet.ec2.aws.upbound.io/my-db-8bhr2-9sjpx True True subnet-05d21c7b52f7ac8ca 2m26s
subnet.ec2.aws.upbound.io/my-db-8bhr2-dvrxf True True subnet-0432310376b5d09de 2m26s
subnet.ec2.aws.upbound.io/my-db-8bhr2-t7dpr True True subnet-0080fdcb6e9b70632 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
vpc.ec2.aws.upbound.io/my-db-7mc7h-ktbbh True True vpc-08d7dd84e0c12f33e 3m3s
vpc.ec2.aws.upbound.io/my-db-8bhr2-mrh2x True True vpc-06994bf323fc1daea 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
internetgateway.ec2.aws.upbound.io/my-db-7mc7h-s2x4v True True igw-0189c4da07a3142dc 3m1s
internetgateway.ec2.aws.upbound.io/my-db-8bhr2-q7dzl True True igw-01bf2a1dbbebf6a27 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
routetableassociation.ec2.aws.upbound.io/my-db-7mc7h-28qb4 True True rtbassoc-0718d680b5a0e68fe 3m1s
routetableassociation.ec2.aws.upbound.io/my-db-7mc7h-9hdlr True True rtbassoc-0faaedb88c6e1518c 3m1s
routetableassociation.ec2.aws.upbound.io/my-db-7mc7h-txhmz True True rtbassoc-0e5010724ca027864 3m1s
routetableassociation.ec2.aws.upbound.io/my-db-8bhr2-bvgkt False True 2m26s
routetableassociation.ec2.aws.upbound.io/my-db-8bhr2-d9gbg False True 2m26s
routetableassociation.ec2.aws.upbound.io/my-db-8bhr2-k6k8m False True 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
instance.rds.aws.upbound.io/my-db-7mc7h-5d6w4 False True my-db-7mc7h-5d6w4 3m1s
instance.rds.aws.upbound.io/my-db-8bhr2-tx9kf False True my-db-8bhr2-tx9kf 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
subnetgroup.rds.aws.upbound.io/my-db-7mc7h-8c8n9 True True my-db-7mc7h-8c8n9 3m2s
subnetgroup.rds.aws.upbound.io/my-db-8bhr2-mc5ps True True my-db-8bhr2-mc5ps 2m27s
NAME READY SYNCED EXTERNAL-NAME AGE
bucket.s3.aws.upbound.io/crossplane-bucket-867737b10 True True
crossplane-bucket-867737b10 5m26s
```
{{</expand >}}
{{< /hint >}}
### 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`.
```shell {copy-lines="1"}
kubectl get xrd
NAME ESTABLISHED OFFERED AGE
compositepostgresqlinstances.database.example.org True True 40s
```
Delete the _composite resource definitions_ with `kubectl delete xrd`.
```shell
kubectl delete xrd compositepostgresqlinstances.database.example.org
```
### Remove managed resources
Manually delete any _managed resources_ manually created.
Use `kubectl get managed` to view remaining _managed resources_.
```shell {copy-lines="1"}
kubectl get managed
NAME READY SYNCED EXTERNAL-NAME AGE
bucket.s3.aws.upbound.io/crossplane-bucket-867737b10 True True crossplane-bucket-867737b10 8h
```
Use `kubectl delete` to remove the resources.
```shell
kubectl delete bucket.s3.aws.upbound.io/crossplane-bucket-867737b10
```
### Remove Crossplane providers
List the installed _providers_ with `kubectl get providers`.
```shell {copy-lines="1"}
kubectl get providers
NAME INSTALLED HEALTHY PACKAGE AGE
upbound-provider-aws True True xpkg.upbound.io/upbound/provider-aws:v0.27.0 8h
```
Remove the installed _providers_ with `kubectl delete provider`.
```shell
kubectl delete provider upbound-provider-aws
```
## Uninstall the Crossplane deployment
Uninstall Crossplane using Helm with `helm uninstall`
```shell
helm uninstall crossplane --namespace crossplane-system
```
Verify Helm removed the Crossplane pods with `kubectl get pods`
```shell
kubectl get pods -n crossplane-system
No resources found in crossplane-system namespace.
```
## 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`.
```shell
kubectl delete namespace crossplane-system
```
Verify Kubernetes removed the namespace with `kubectl get namespaces`
```shell
kubectl get namespace
NAME STATUS AGE
default Active 2m45s
kube-flannel Active 2m42s
kube-node-lease Active 2m47s
kube-public Active 2m47s
kube-system Active 2m47s
```

View File

@ -0,0 +1,60 @@
---
title: Upgrade Crossplane
weight: 200
---
The recommended upgrade method for an existing Crossplane install is to use
[Helm](http://helm.io).
## Prerequisites
* [Helm](https://helm.sh/docs/intro/install/) version `v3.2.0` or later
## Add the Crossplane Helm repository
Verify Helm has the Crossplane repository.
```shell
helm repo add crossplane-stable https://charts.crossplane.io/stable
```
## Update the Helm repository
Update the local Crossplane Helm chart with `helm repo update`.
```shell
helm repo update
```
{{<hint "important" >}}
Upgrading Crossplane without updating the Helm chart installs the last version
available in the locally cached Helm chart.
{{< /hint >}}
## Upgrade Crossplane
Upgrade Crossplane with `helm upgrade`, providing the Crossplane namespace.
By default, Crossplane installs into the `crossplane-system`
namespace.
```shell
helm 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.
For example, in v1.15.0 Crossplane changed the default image registry from
`index.docker.io` to `xpkg.upbound.io`. Upgrading Crossplane from a version
before v1.15.0 updates the default package registry.
Override new defaults by
[customizing the Helm chart]({{<ref "install#customize-the-crossplane-helm-chart" >}})
with the upgrade command.
For example, to maintain the original image registry use
```shell
helm upgrade crossplane --namespace crossplane-system crossplane-stable/crossplane `--set 'args={"--registry=index.docker.io"}'
```

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
# Which which version is the "Latest"?
LATEST_VER="1.16"
LATEST_VER="1.17"
# Make a copy of /content/$LATEST_VER to the directory /latest
# Search indexing only points to /latest, this prevents broken or out of date
@ -31,4 +31,4 @@ hugo --minify --baseURL $DEPLOY_PRIME_URL
else
echo "Building other deploy $CONTEXT with URL https://deploy-preview-$REVIEW_ID--crossplane.netlify.app/"
hugo --minify --baseURL https://deploy-preview-$REVIEW_ID--crossplane.netlify.app/
fi
fi