Crossplane sends requests to your functions to ask them what resources to compose for a given composite resource (XR). Your function answers with a response.
Inputs
Compositions execute a pipeline of one or more sequential functions. A function updates desired resource state and returns it to Crossplane. Function requests contain 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.
Crossplane passes these pieces of information 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
extra = req.extra_resources # Any extra resources the function pipeline requested
You can select the RunFunctionRequest
object in Visual Studio Code to see what
fields it has.
The Python function SDK generates the RunFunctionRequest
object from a
protobuf definition. Read the
Python Generated Code Guide
to learn about protobuf generated code.
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, Visual Studio Code 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 rsp: 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 select the RunFunctionResponse
object in Visual Studio Code to see
what fields it has.
The Python function SDK generates the RunFunctionResponse
object from a
protobuf definition. Read the
Python Generated Code Guide
to learn about protobuf generated code.
You can add or update composed resources using the resource.update
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["my-resource"], composed)
Similarly, you can update the status of the composite resource by updating it in the response:
from crossplane.function import resource
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)
If you don’t want to use a model, you can also pass resource.update
a Python
dictionary.
from crossplane.function import resource
from crossplane.function.proto.v1 import run_function_pb2 as fnv1
def compose(req: fnv1.RunFunctionRequest, rsp: fnv1.RunFunctionResponse):
resource.update(rsp.desired.composite.resource, {
"status: {
"replicas": 3,
},
})