The Go SDK for composition functions
Go to file
Steven Borrelli 66fe852bf9
Sync with upstream crossplane-runtime changes
* Bump crossplane-runtime
* Update GetInteger to handle floats locally
* Use new claim.Reference type

Signed-off-by: Steven Borrelli <steve@borrelli.org>
2023-10-24 14:16:20 -07:00
.github Merge pull request #57 from crossplane/renovate/fkirc-skip-duplicate-actions-5.x 2023-10-23 10:42:04 +02:00
build@a6e25afa0d Add generated gRPC APIs 2023-08-31 15:05:08 -07:00
context Support injecting Function environment via context 2023-10-12 18:29:31 -07:00
errors chore: make root NewLogger proxy logging.NewLogger 2023-09-28 08:49:26 +02:00
logging chore: make root NewLogger proxy logging.NewLogger 2023-09-28 08:49:26 +02:00
proto Support injecting Function environment via context 2023-10-12 18:29:31 -07:00
request Merge pull request #39 from negz/contextual 2023-10-13 18:11:28 +02:00
resource Sync with upstream crossplane-runtime changes 2023-10-24 14:16:20 -07:00
response Handle nil context fields, not just a nil context 2023-10-16 16:28:38 -07:00
.gitignore Initial commit 2023-09-02 13:28:20 -07:00
.gitmodules Add generated gRPC APIs 2023-08-31 15:05:08 -07:00
.golangci.yml Add the beginnings of a Function SDK 2023-09-12 05:45:19 -07:00
LICENSE Initial commit 2023-09-02 13:28:20 -07:00
Makefile Run golangci-lint with --fix by default 2023-10-23 11:58:38 +02:00
README.md fix(docs): Remove duplicate call to GetObservedCompositeResource in docs 2023-10-11 14:08:32 -04:00
go.mod Sync with upstream crossplane-runtime changes 2023-10-24 14:16:20 -07:00
go.sum Sync with upstream crossplane-runtime changes 2023-10-24 14:16:20 -07:00
sdk.go chore: make root NewLogger proxy logging.NewLogger 2023-09-28 08:49:26 +02:00
sdk_test.go Sync with upstream crossplane-runtime changes 2023-10-24 14:16:20 -07:00

README.md

function-sdk-go

The Go SDK for Composition Functions.

This SDK is currently a beta and does not yet have a stable API. It follows the same contributing guidelines as Crossplane.

func (f *Function) RunFunction(_ context.Context, req *fnv1beta1.RunFunctionRequest) (*fnv1beta1.RunFunctionResponse, error) {
	// This creates a new response to the supplied request. Note that Functions
	// are run in a pipeline! Other Functions may have run before this one. If
	// they did, response.To will copy their desired state from req to rsp. Be
	// sure to pass through any desired state your Function is not concerned
	// with unmodified.
	rsp := response.To(req, response.DefaultTTL)

	// Input is supplied by the author of a Composition when they choose to run
	// your Function. Input is arbitrary, except that it must be a KRM-like
	// object. Supporting input is also optional - if you don't need to you can
	// delete this, and delete the input directory.
	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
	}

	// Get the observed composite resource (XR) from the request. There should
	// always be an observed XR in the request - this represents the current
	// state of the XR.
	oxr, err := request.GetObservedCompositeResource(req)
	if err != nil {
		response.Fatal(rsp, errors.Wrapf(err, "cannot get observed XR from %T", req))
		return rsp, nil
	}

	// Read the desired number of widgets from our observed XR. We don't have
	// a struct for the XR, so we use an unstructured, fieldpath based getter.
	widgets, err := oxr.Resource.GetInteger("spec.widgets")
	if err != nil {
		response.Fatal(rsp, errors.Wrap(err, "cannot get desired spec.widgets from observed XR"))
		return rsp, nil
	}

	// Get any existing desired composed resources from the request.
	// Desired composed resources would exist if a previous Function in the
	// pipeline added them.
	desired, err := request.GetDesiredComposedResources(req)
	if err != nil {
		response.Fatal(rsp, errors.Wrapf(err, "cannot get desired composed resources from %T", req))
		return rsp, nil
	}

	// Create a desired composed resource using unstructured data.
	desired["new"] = &resource.DesiredComposed{Resource: composed.New()}
	desired["new"].Resource.SetAPIVersion("example.org/v1")
	desired["new"].Resource.SetKind("CoolResource")

	// Set the desired composed resource's widgets to the value extracted from
	// the observed XR.
	desired["new"].Resource.SetInteger("spec.widgets", widgets)

	// You could create a desired composed resource using structured data, too.
	// db, _ := composed.From(&v1beta1.Instance{})
	// desired["database"] = &resource.DesiredComposed{Resource: db}

	// Set the labels of all desired resources, including our new one.
	for _, r := range desired {
		r.Resource.SetLabels(map[string]string{"coolness": "high"})
	}

	// Set our updated desired composed resource in the response we'll return.
	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
}