Creating a Composition
A CompositeResourceDefinition
(XRD) defines the type and schema of your Composite Resource (XR). It informs Crossplane about the desired XR and its fields. An XRD is similar to a CustomResourceDefinition (CRD) but with a more opinionated structure. Creating an XRD primarily involves specifying an OpenAPI "structural schema".
Let's start by providing a definition that allows application team members to create a DynamoDB table in their respective namespaces. In this example, users only need to specify the name, key attributes, and index name fields.
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdynamodbtables.awsblueprints.io
spec:
group: awsblueprints.io
names:
kind: XDynamoDBTable
plural: xdynamodbtables
claimNames:
kind: DynamoDBTable
plural: dynamodbtables
connectionSecretKeys:
- tableName
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
description: Table is the Schema for the tables API
properties:
spec:
type: object
properties:
resourceConfig:
properties:
deletionPolicy:
description: Defaults to Delete
enum:
- Delete
- Orphan
type: string
name:
type: string
providerConfigName:
type: string
default: aws-provider-config
region:
type: string
default: ""
tags:
additionalProperties:
type: string
description: Key-value map of resource tags.
type: object
required:
- region
type: object
dynamoConfig:
properties:
attribute: #required for hashKey and/or rangeKey
items:
properties:
name: #name of the hashKey and/or rangeKey
type: string
type:
enum:
- B #binary
- N #number
- S #string
type: string
required:
- name
- type
type: object
type: array
hashKey:
type: string
rangeKey:
type: string
billingMode:
type: string
default: PAY_PER_REQUEST
readCapacity:
type: number
writeCapacity:
type: number
globalSecondaryIndex:
items:
properties:
hashKey:
type: string
name:
type: string
rangeKey:
type: string
readCapacity:
type: number
writeCapacity:
type: number
projectionType:
type: string
default: ALL
nonKeyAttributes: #required for gsi
items:
type: string
type: array
type: object
required:
- name
type: array
localSecondaryIndex:
items:
properties:
name:
type: string
rangeKey:
type: string
projectionType:
type: string
nonKeyAttributes: #required for lsi
items:
type: string
type: array
type: object
required:
- name
- rangeKey
- projectionType
- nonKeyAttributes
type: array
required:
- attribute
type: object
required:
- dynamoConfig
status:
type: object
description: TableStatus defines the observed state of Table
properties:
tableArn:
description: Indicates this table's ARN
type: string
tableName:
description: Indicates this table's Name
type: string
required:
- spec
A Composition informs Crossplane about the actions to take when a Composite Resource is created. Each Composition establishes a link between an XR and a set of one or more Managed Resources. When the XR is created, updated, or deleted, the associated Managed Resources are correspondingly created, updated, or deleted.
The following Composition provisions the managed resource Table
:
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: table.dynamodb.awsblueprints.io
labels:
awsblueprints.io/provider: aws
awsblueprints.io/environment: dev
spec:
writeConnectionSecretsToNamespace: crossplane-system
compositeTypeRef:
apiVersion: awsblueprints.io/v1alpha1
kind: XDynamoDBTable
patchSets:
- name: common-fields
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.resourceConfig.providerConfigName
toFieldPath: spec.providerConfigRef.name
- type: FromCompositeFieldPath
fromFieldPath: spec.name
toFieldPath: metadata.annotations[crossplane.io/external-name]
- type: FromCompositeFieldPath
fromFieldPath: metadata.name
toFieldPath: metadata.annotations[crossplane.io/external-name]
transforms:
- type: string
string:
type: Regexp
regexp:
match: ^(.*?)-crossplane
resources:
- name: table
connectionDetails:
- type: FromFieldPath
name: tableName
fromFieldPath: status.atProvider.id
base:
apiVersion: dynamodb.aws.upbound.io/v1beta1
kind: Table
spec:
forProvider:
writeConnectionSecretToRef:
name: cartsdynamo
namespace: crossplane-system
region: ""
providerConfigRef:
name: aws-provider-config
patches:
- type: PatchSet
patchSetName: common-fields
- type: FromCompositeFieldPath
fromFieldPath: spec.dynamoConfig.attribute
toFieldPath: spec.forProvider.attribute
policy:
mergeOptions:
appendSlice: true
keepMapValues: true
- type: FromCompositeFieldPath
fromFieldPath: spec.resourceConfig.tags
toFieldPath: spec.forProvider.tags
policy:
mergeOptions:
keepMapValues: true
- type: FromCompositeFieldPath
fromFieldPath: spec.dynamoConfig.attribute[0].name
toFieldPath: spec.forProvider.hashKey
- type: FromCompositeFieldPath
fromFieldPath: spec.dynamoConfig.billingMode
toFieldPath: spec.forProvider.billingMode
- type: FromCompositeFieldPath
fromFieldPath: spec.dynamoConfig.rangeKey
toFieldPath: spec.forProvider.rangeKey
- type: FromCompositeFieldPath
fromFieldPath: spec.dynamoConfig.readCapacity
toFieldPath: spec.forProvider.readCapacity
- type: FromCompositeFieldPath
fromFieldPath: spec.dynamoConfig.writeCapacity
toFieldPath: spec.forProvider.writeCapacity
- type: FromCompositeFieldPath
fromFieldPath: spec.dynamoConfig.globalSecondaryIndex[0].name
toFieldPath: spec.forProvider.globalSecondaryIndex[0].name
- type: FromCompositeFieldPath
fromFieldPath: spec.dynamoConfig.attribute[1].name
toFieldPath: spec.forProvider.globalSecondaryIndex[0].hashKey
- type: FromCompositeFieldPath
fromFieldPath: spec.dynamoConfig.globalSecondaryIndex[0].projectionType
toFieldPath: spec.forProvider.globalSecondaryIndex[0].projectionType
policy:
mergeOptions:
keepMapValues: true
- type: FromCompositeFieldPath
fromFieldPath: spec.dynamoConfig.localSecondaryIndex
toFieldPath: spec.forProvider.localSecondaryIndex
policy:
mergeOptions:
keepMapValues: true
- type: ToCompositeFieldPath
fromFieldPath: status.atProvider.id
toFieldPath: status.tableName
- type: ToCompositeFieldPath
fromFieldPath: status.atProvider.arn
toFieldPath: status.tableArn
Let's apply this configuration to our EKS cluster:
compositeresourcedefinition.apiextensions.crossplane.io/xdynamodbtables.awsblueprints.io created
composition.apiextensions.crossplane.io/table.dynamodb.awsblueprints.io created
With these resources in place, we've successfully set up a Crossplane Composition for creating DynamoDB tables. This abstraction allows application developers to provision standardized DynamoDB tables without needing to understand the underlying AWS-specific details.