Categorygithub.com/crossplane-contrib/function-patch-and-transform

# README

function-patch-and-transform

CI GitHub release (latest SemVer)

This composition function does everything Crossplane's built-in patch & transform (P&T) composition does. Instead of specifying spec.resources in your Composition, you can use this function.

Using this function, P&T looks like this:

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: example
spec:
  # Omitted 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: bucket
        base:
          apiVersion: s3.aws.upbound.io/v1beta1
          kind: Bucket
          spec:
            forProvider:
              region: us-east-2
        patches:
        - type: FromCompositeFieldPath
          fromFieldPath: "spec.location"
          toFieldPath: "spec.forProvider.region"
          transforms:
          - type: map
            map: 
              EU: "eu-north-1"
              US: "us-east-2"

Notice that it looks very similar to native P&T. The difference is that everything is under spec.pipeline[0].input.resources, not spec.resources. This is the Function's input.

Okay, but why?

There are a lot of good reasons to use a function to use a function to do P&T composition. In fact, it's so compelling that the Crossplane maintainers are considering deprecating native P&T. See Crossplane issue #4746 for details.

Mix and match P&T with other functions

With this function you can use P&T with other functions. For example you can create a desired resource using the Go Templating function, then patch the result using this function.

To include results from previous functions, simply provide a resources entry for each and specify a name field that matches the name of the resource from the previous function. Also, do not specify any value for the base field of each resource.

It's not just patches either. You can use P&T to derive composite resource connection details from a resource produced by another function, or use it to determine whether a resource produced by another function is ready.

A straightforward example for multistep mix and match pipeline with function-patch-and-transform and function-go-templating can be found here

Decouple P&T development from Crossplane core

When P&T development happens in a function, it's not coupled to the Crossplane release cycle. The maintainers of this function can cut releases more frequently to add new features to P&T.

It also becomes easier to fork. You could fork this function, add a new kind of transform and try it out for a few weeks before sending a PR upstream. Or, if your new feature is controversial, it's now a lot less work to maintain your own fork long term.

Test P&T locally using the Crossplane CLI

You can use the Crossplane CLI to run any function locally and see what composed resources it would create. This only works with functions - not native P&T.

For example, using the files in the example directory:

$ crossplane beta render xr.yaml composition.yaml functions.yaml

Produces the following output, showing what resources Crossplane would compose:

---
apiVersion: example.crossplane.io/v1
kind: XR
metadata:
  name: example-xr
---
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
  annotations:
    crossplane.io/composition-resource-name: bucket
  generateName: example-xr-
  labels:
    crossplane.io/composite: example-xr
  ownerReferences:
    # Omitted for brevity
spec:
  forProvider:
    region: us-east-2

See the composition functions documentation to learn how to use crossplane beta render.

Differences from the native implementation

This function has a few small, intentional breaking changes compared to the native implementation.

New Required fields

These fields are now required. This makes P&T configuration less ambiguous:

  • resources[i].name
  • resources[i].connectionDetails[i].name
  • resources[i].connectionDetails[i].type
  • resources[i].patches[i].transforms[i].string.type
  • resources[i].patches[i].transforms[i].math.type

mergeOptions replaced by toFieldPath

Also, the resources[i].patches[i].policy.mergeOptions field is no longer supported. This functionality has been replaced by the resources[i].patches[i].policy.toFieldPath field. The table below outlines previous behavior that was possible with mergeOptions and how to achieve it with the new toFieldPath field:

#mergeOptionsappendSlicekeepMapValuestoFieldPath
1nilN/AN/Anil which defaults to Replace
2non-nilnil or falsetrueMergeObjects
3non-niltruenil or falseForceMergeObjectsAppendArrays
4non-nilnil or falsenil or falseForceMergeObjects
5non-niltruetrueMergeObjectsAppendArrays

As an example, a previous configuration using the no longer supported mergeOptions:

policy:
  mergeOptions:
    appendSlice: true
    keepMapValues: true

Should be replaced with:

policy:
  toFieldPath: MergeObjectsAppendArrays

Starting with Crossplane v1.16.0, the convert command in the Crossplane CLI will automatically convert mergeOptions to toFieldPath for you.

Developing this function

This function uses Go, Docker, and the Crossplane CLI to build functions.

# Run code generation - see input/generate.go
$ go generate ./...

# Run tests - see fn_test.go
$ go test ./...

# Build the function's runtime image - see Dockerfile
$ docker build . --tag=runtime

# Build a function package - see package/crossplane.yaml
$ crossplane xpkg build -f package --embed-runtime-image=runtime

# Packages

No description provided by the author

# Functions

ApplyCombineFromVariablesPatch patches the "to" resource, taking a list of input variables and combining them into a single output value.
ApplyComposedPatch applies a patch to or from a composed resource.
ApplyEnvironmentPatch applies a patch to or from the environment.
ApplyFromFieldPathPatch patches the "to" resource, using a source field on the "from" resource.
Combine calls the appropriate combiner.
CombineString returns a single output by running a string format with all of its input variables.
ComposedTemplates returns the supplied composed resource templates with any supplied patchsets dereferenced.
ExtractConnectionDetails extracts XR connection details from the supplied composed resource.
GetConversionFunc returns the conversion function for the given input and output types, or an error if no conversion is supported.
IsReady returns whether the composed resource is ready.
Matches returns true if the pattern matches the supplied input.
Resolve the supplied Transform.
ResolveConvert resolves a Convert transform by looking up the appropriate conversion function for the given input type and invoking it.
ResolveMap resolves a Map transform.
ResolveMatch resolves a Match transform.
ResolveMath resolves a Math transform.
ResolveString resolves a String transform.
ResolveTransforms applies a list of transforms to a patch value.
RunReadinessCheck runs the readiness check against the supplied object.
ToComposedResource returns true if the supplied patch is to a composed resource, not from it.
ValidateCombine validates a Combine.
ValidateComposedTemplate validates a ComposedTemplate.
ValidateConnectionDetail checks if the connection detail is logically valid.
ValidateConvertTransform validates a ConvertTransform.
ValidateEnvironment validates (patches to and from) the Environment.
ValidateMapTransform validates MapTransform.
ValidateMatchConditionReadinessCheck checks if the match condition is logically valid.
ValidateMatchTransform validates a MatchTransform.
ValidateMatchTransformPattern validates a MatchTransformPattern.
ValidateMathTransform validates a MathTransform.
ValidatePatch validates a ComposedPatch.
ValidatePatchSet validates a PatchSet.
ValidateReadinessCheck checks if the readiness check is logically valid.
ValidateResources validates the Resources object.
ValidateStringTransform validates a StringTransform.
ValidateTransform validates a Transform.
WrapFieldError wraps the given field.Error adding the given field.Path as root of the Field.
WrapFieldErrorList wraps the given field.ErrorList adding the given field.Path as root of the Field.

# Structs

CLI of this Function.
Function performs patch-and-transform style Composition.

# Interfaces

A ConditionedObject is a runtime object with conditions.
ConnectionDetailsExtractor extracts the connection details of a resource.
A PatchInterface is a patch that can be applied between resources.
PatchWithPatchSetName is a PatchInterface that has a PatchSetName field.
A ReadinessChecker checks whether a composed resource is ready or not.

# Type aliases

A ConnectionDetailsExtractorFn is a function that satisfies ConnectionDetailsExtractor.
A ReadinessCheckerFn checks whether a composed resource is ready or not.