Functions require inputs and outputs to process requests and return values to your control plane.
Inputs
Compositions execute in a pipeline of one or more sequential functions. A function updates desired resource state and returns it to Crossplane. Function requests and values rely on four pieces of information:
- The observed state of the composite resource, and any composed resources.
- The desired state of the composite resource, and any composed resources.
- The function’s input.
- The function pipeline’s context.
Each composition pipeline provides this information as inputs into the function.
In Python, these four pieces of information are passed to the function as part
of the req: RunFunctionRequest
argument:
from crossplane.function.proto.v1 import run_function_pb2 as fnv1
def compose(req: fnv1.RunFunctionRequest, rsp: fnv1.RunFunctionResponse):
observed = req.observed # Observed state
desired = req.desired # Desired state
input = req.input # Function input
context = req.context # Function pipeline context
Most functions reference the observed composite resource (XR) to produce
composed resources, typically managed resources (MRs). In Python, you can find the
observed XR in req.observed.composite.resource
.
When you generate an embedded function with up function generate
, the command
creates a Python library that includes type definitions based on your XRDs. You can
convert the observed XR to its Python type as follows:
from crossplane.function.proto.v1 import run_function_pb2 as fnv1
from .model.com.example.platform.xmytype import v1alpha1
def compose(req: fnv1.RunFunctionRequest, rsp: fnv1.RunFunctionResponse):
observed_xr = v1alpha1.XMyType(**req.observed.composite.resource)
After this, VSCode adds tab-completion and type checking when working with the XR.
Outputs
Composition functions influence the state of the control plane via three kinds of outputs:
- The desired state of the composite resource, and composed resources.
- Status conditions to apply to the composite resource and, optionally, its claim.
- Context to pass to subsequent functions in the pipeline.
Most functions produce a set of composed resources as part of the desired state.
In Python, outputs are part of the res: RunFunctionResponse
argument, which is
pre-populated with the request’s desired state and context. A Python function
only needs to update any fields in these objects that it wishes to change.
You can add or update composed resources using the resource.updater
helper
function in the Crossplane Python SDK:
from crossplane.function import resource
from crossplane.function.proto.v1 import run_function_pb2 as fnv1
def compose(req: fnv1.RunFunctionRequest, rsp: fnv1.RunFunctionResponse):
composed = ... # Construct a composed resource
resource.update(rsp.desired.resources[composed.metadata.name], composed)
Similarly, you can update the status of the composite resource by updating it in the response:
from crossplane.function.proto.v1 import run_function_pb2 as fnv1
from .model.com.example.platform.xmytype import v1alpha1
def compose(req: fnv1.RunFunctionRequest, rsp: fnv1.RunFunctionResponse):
observed_xr = v1alpha1.XMyType(**req.observed.composite.resource)
observed_xr.status.someInformation = "cool-status"
resource.update(rsp.desired.composite.resource, observed_xr)