Crossplane: Share data between resources within the same Composite

crossplane kubernetes composite status

6 min read | by Jordi Prats

Following up on the previous crossplane example on Composition: creating a SecurityGroup and a SecurityGroupRule using a Composition we are now going to push information from one of the objects into the Composition and then push it back to the other resource:

The composistion is going to create a SecurityGroup and push it's ID up to the Composite's status. Once the ID is on the Composition, this will push this ID into the SecurityGroupRule to set the SecurityGroup's ID to which we want to create the rule

To achieve this, first we will have to tell the CompositeResourceDefinition that we are going to have the status.sgId field that will hold a string:

apiVersion: apiextensions.crossplane.io/v1 kind: CompositeResourceDefinition metadata:  name: sgsallowoutgoing.pet2cattle.com spec:  group: pet2cattle.com  names:  kind: SGAllowOutgoing  plural: sgsallowoutgoing  versions:  - name: v1alpha1  served: true  referenceable: true  schema:  openAPIV3Schema:  type: object  properties:  spec:  type: object  properties:  parameters:  type: object  properties:  region:  type: string  required:  - region  required:  - parameters  status:  type: object  properties:  sgId:  description: SecurityGroup ID  type: string 

Once we have this sort of variable available, we are going to use the patches attribute to copy from the resource one of it's status fields into it. To do so we are going to use a ToCompositeFieldPath patch to copy it from status.atProvider.id (that's the SecurityGroup resource) to the status.sgId (that's the Composite resource we are building):

apiVersion: apiextensions.crossplane.io/v1 kind: Composition metadata:  name: sgsallowoutgoing  labels:  crossplane.io/xrd: sgsallowoutgoing.pet2cattle.com spec:  writeConnectionSecretsToNamespace: crossplane-system  compositeTypeRef:  apiVersion: pet2cattle.com/v1alpha1  kind: SGAllowOutgoing  resources:  - name: sg  base:  apiVersion: ec2.aws.jet.crossplane.io/v1alpha2  kind: SecurityGroup  spec:  forProvider:  description: 'xplane SG test'  vpcId: 'vpc-1234abcd'  providerConfigRef:  name: 'aws-jetprovider-config'  patches:  - type: FromCompositeFieldPath  fromFieldPath: metadata.name  toFieldPath: spec.forProvider.name  - type: FromCompositeFieldPath  fromFieldPath: metadata.name  toFieldPath: metadata.annotations.crossplane.io/external-name  - type: FromCompositeFieldPath  fromFieldPath: spec.parameters.region  toFieldPath: spec.forProvider.region  - type: ToCompositeFieldPath  fromFieldPath: status.atProvider.id  toFieldPath: status.sgId (...) 

With this we are going to be able to retrieve the SecurityGroup's ID from the SGAllowOutgoing resource (the Composition) but we want is to be able to define to set it into the SecurityGroupRule. To do so we can use the FromCompositeFieldPath patch to push it into it:

apiVersion: apiextensions.crossplane.io/v1 kind: Composition metadata:  name: sgsallowoutgoing  labels:  crossplane.io/xrd: sgsallowoutgoing.pet2cattle.com spec:  writeConnectionSecretsToNamespace: crossplane-system  compositeTypeRef:  apiVersion: pet2cattle.com/v1alpha1  kind: SGAllowOutgoing  resources: (...)  - name: sg-egress  base:  apiVersion: ec2.aws.jet.crossplane.io/v1alpha2  kind: SecurityGroupRule  spec:  forProvider:  fromPort: 0  toPort: 0  protocol: "-1"  type: 'egress'  cidrBlocks:  - '0.0.0.0/0'  providerConfigRef:  name: 'aws-jetprovider-config'  patches:  - type: FromCompositeFieldPath  fromFieldPath: spec.parameters.region  toFieldPath: spec.forProvider.region  - type: FromCompositeFieldPath  fromFieldPath: status.sgId  toFieldPath: spec.forProvider.securityGroupId 

To sum it up, the changes we made to the Composition are the following:

We have removed:

  • The need to adding labels to it's resources
  • The use of a selector to identify to which SG we need to set the rule

We have added:

  • A patch to copy the SecurityGroup ID up to the Composite
  • A patch to copy from the Composite to the SecurityGroupRule resource

An actual patch would look like this:

--- composition/composition.yaml 2022-03-14 23:48:19.246227739 +0100 +++ ../crossplane-composition-publish-status/composition.yaml 2022-03-15 18:19:47.375130779 +0100 @@ -28,11 +28,11 @@   fromFieldPath: metadata.name   toFieldPath: metadata.annotations.crossplane.io/external-name   - type: FromCompositeFieldPath - fromFieldPath: metadata.name - toFieldPath: metadata.labels.sgname - - type: FromCompositeFieldPath   fromFieldPath: spec.parameters.region   toFieldPath: spec.forProvider.region + - type: ToCompositeFieldPath + fromFieldPath: status.atProvider.id + toFieldPath: status.sgId   - name: sg-egress   base:   apiVersion: ec2.aws.jet.crossplane.io/v1alpha2 @@ -52,5 +52,5 @@   fromFieldPath: spec.parameters.region   toFieldPath: spec.forProvider.region   - type: FromCompositeFieldPath - fromFieldPath: metadata.name - toFieldPath: spec.forProvider.securityGroupIdSelector.matchLabels.sgname \ No newline at end of file + fromFieldPath: status.sgId + toFieldPath: spec.forProvider.securityGroupId \ No newline at end of file 

If we create one instance of this composition:

$ kubectl apply -f instances/sgone.yaml  sgallowoutgoing.pet2cattle.com/sgone created 

We can check how the SecurityGroup ID is now part of it's status:

$ kubectl describe sgallowoutgoing.pet2cattle.com/sgone Name: sgone Namespace:  Labels: crossplane.io/composite=sgone Annotations: <none> API Version: pet2cattle.com/v1alpha1 Kind: SGAllowOutgoing Metadata: (...) Spec:  Composition Ref:  Name: sgsallowoutgoing  Composition Update Policy: Automatic  Parameters:  Region: us-west-2  Resource Refs:  API Version: ec2.aws.jet.crossplane.io/v1alpha2  Kind: SecurityGroup  Name: sgone-5bvfc  API Version: ec2.aws.jet.crossplane.io/v1alpha2  Kind: SecurityGroupRule  Name: sgone-grd7m  Write Connection Secret To Ref:  Name: 203e831b-a64d-4d5a-9757-6f17a0c32940  Namespace: crossplane-system Status:  Conditions:  Last Transition Time: 2022-03-15T23:26:00Z  Reason: Creating  Status: False  Type: Ready  Connection Details:  Last Published Time: 2022-03-15T23:26:00Z  Sg Id: sg-3c426074e66289c02 Events:  Type Reason Age From Message  ---- ------ ---- ---- -------  Normal PublishConnectionSecret 40s defined/compositeresourcedefinition.apiextensions.crossplane.io Successfully published connection details  Normal SelectComposition 10s (x7 over 40s) defined/compositeresourcedefinition.apiextensions.crossplane.io Successfully selected composition  Normal ComposeResources 10s (x7 over 40s) defined/compositeresourcedefinition.apiextensions.crossplane.io Successfully composed resources 

If we check the SecurityGroupRule resource we will see how it was not possible to create the resource at first, since the SecurityGroup ID wasn't available yet. However, as soon as this ID propagated up to the Composite and then down to the SecurityGroupRule it could reconcile the resource by creating the rule on it:

$ kubectl describe SecurityGroupRule sgone-grd7m Name: sgone-grd7m Namespace:  Labels: crossplane.io/claim-name=  crossplane.io/claim-namespace=  crossplane.io/composite=sgone Annotations: crossplane.io/composition-resource-name: sg-egress  crossplane.io/external-create-pending: 2022-03-15T23:26:36Z  crossplane.io/external-create-succeeded: 2022-03-15T23:26:42Z  crossplane.io/external-name: sgrule-1606513619  terrajet.crossplane.io/provider-meta: {"schema_version":"2"} API Version: ec2.aws.jet.crossplane.io/v1alpha2 Kind: SecurityGroupRule Metadata: (...) Spec:  Deletion Policy: Delete  For Provider:  Cidr Blocks:  0.0.0.0/0  From Port: 0  Protocol: -1  Region: us-west-2  Security Group Id: sg-3c426074e66289c02  To Port: 0  Type: egress  Provider Config Ref:  Name: aws-jetprovider-config Status:  At Provider:  Id: sgrule-1606513619  Conditions:  Last Transition Time: 2022-03-15T23:26:42Z  Reason: ReconcileSuccess  Status: True  Type: Synced  Last Transition Time: 2022-03-15T23:26:46Z  Reason: Available  Status: True  Type: Ready  Last Transition Time: 2022-03-15T23:26:46Z  Reason: Finished  Status: True  Type: AsyncOperation Events:  Type Reason Age From Message  ---- ------ ---- ---- -------  Warning CannotObserveExternalResource 27s (x12 over 55s) managed/ec2.aws.jet.crossplane.io/v1alpha2, kind=securitygrouprule cannot run refresh: refresh failed: Missing required argument: The argument "security_group_id" is required, but no definition was found.: File name: main.tf.json  Normal CreatedExternalResource 17s managed/ec2.aws.jet.crossplane.io/v1alpha2, kind=securitygrouprule Successfully requested creation of external resource 

All the YAML definitions on this blog post have been uploaded the the repository pet2cattle/crossplane-composition-publish-status on GitHub


Posted on 22/03/2022