Skip to content

Repository files navigation

function-pythonic

Introduction

A Crossplane composition function that lets you compose Composites using a set of python classes enabling an elegant and terse syntax. Here is what the following example is doing:

  • Create an MR named 'vpc' with apiVersion 'ec2.aws.crossplane.io/v1beta1' and kind 'VPC'
  • Set the vpc region and cidr from the XR spec values
  • Set the XR status.vpcId to the created vpc id
apiVersion: apiextensions.crossplane.io/v1kind: Compositionmetadata:
name: create-vpcspec:
compositeTypeRef:
apiVersion: example.crossplane.io/v1kind: XRmode: Pipelinepipeline:
- step:
functionRef:
name: function-pythonicinput:
apiVersion: pythonic.fn.crossplane.io/v1alpha1kind: Compositecomposite: | class VpcComposite(BaseComposite): def compose(self): vpc = self.resources.vpc('VPC', 'ec2.aws.crossplane.io/v1beta1') vpc.spec.forProvider.region = self.spec.region vpc.spec.forProvider.cidrBlock = self.spec.cidr self.status.vpcId = vpc.status.atProvider.vpcId

In addtion to an inline script, the python implementation can be specified as the complete path to a python class. Python packages can be deployed using ConfigMaps, enabling using your IDE of choice for writting the code. See ConfigMap Packages and Filing System Packages.

Examples

In the examples directory are many exemples, including all of the function-go-templating examples implemented using function-pythonic. The eks-cluster example is a good complex example creating the entire vpc structure needed for an EKS cluster.

Installing function-pythonic

apiVersion: pkg.crossplane.io/v1kind: Functionmetadata:
name: function-pythonicspec:
package: xpkg.crossplane.io/crossplane-contrib/function-pythonic:v0.6.0

Crossplane V1

When running function-pythonic in Crossplane V1, the --crossplane-v1 command line option should be specified. This requires using a Crossplane DeploymentRuntimeConfig.

apiVersion: pkg.crossplane.io/v1kind: Functionmetadata:
name: function-pythonicspec:
package: xpkg.crossplane.io/crossplane-contrib/function-pythonic:v0.6.0runtimeConfigRef:
name: function-pythonic--apiVersion: pkg.crossplane.io/v1beta1kind: DeploymentRuntimeConfigmetadata:
name: function-pythonicspec:
deploymentTemplate:
spec:
selector: {}template:
spec:
containers:
- name: package-runtimeargs:
- --debug
- --crossplane-v1

Composed Resource Dependencies

function-pythonic automatically handles dependencies between composed resources.

Just compose everything as if it is immediately created and the framework will delay the creation of any resources which depend on other resources which do not exist yet. In other words, it accomplishes what function-sequencer provides, but it automatically detects the dependencies.

If a resource has been created and a dependency no longer exists due to some unexpected condition, the composition will be terminated or the observed value for that field will be used, depending on the unknownsFatal settings.

Take the following example:

vpc=self.resources.VPC('VPC', 'ec2.aws.crossplane.io/v1beta1')
vpc.spec.forProvider.region= 'us-east-1vpc.spec.forProvider.cidrBlock='10.0.0.0/16'subnet=self.resources.SubnetA('Subnet', 'ec2.aws.crossplane.io/v1beta1')
subnet.spec.forProvider.region='us-east-1'subnet.spec.forProvider.vpcId=vpc.status.atProvider.vpcIdsubnet.spec.forProvider.availabilityZone='us-east-1a'subnet.spec.forProvider.cidrBlock='10.0.0.0/20'

If the Subnet does not yet exist, the framework will detect if the vpcId set in the Subnet is unknown, and will delay the creation of the subnet.

Once the Subnet has been created, if for some unexpected reason the vpcId passed to the Subnet is unknown, the framework will detect it and either terminate the Composite composition or use the vpcId in the observed Subnet. The default action taken is to fast fail by terminating the composition. This can be overridden for all composed resource by setting the Composite self.unknownsFatal field to False, or at the individual composed resource level by setting the Resource.unknownsFatal field to False.

Explicit Dependencies

At times, the above implicit dependency handling does not account for all cases. Explicit dependencies can be configured using the resource addDependency method. The dependency's "ready" is used to determine when that dependency is available for use. The dependency's ready state can either be explictly set, or will be defaulted to it's auto-ready calculation.

Here is an example of specifying an explicit dependency:

crd = self.resources.KarpenterCrdRelease('Release', 'helm.crossplane.io/v1beta1')crd.spec.deletionPolicy = 'Orphan'crd.spec.forProvider.chart.repository = 'oci://public.ecr.aws/karpenter'crd.spec.forProvider.chart.name = 'karpenter-crd'crd.spec.forProvider.chart.version = '1.8.6'crd.spec.forProvider.namespace = 'karpenter'crd.externalName = 'karpenter-crd'karpenter = self.resources.KarpenterRelease('Release', 'helm.crossplane.io/v1beta1')karpenter.addDependency(crd)karpenter.spec.deletionPolicy = 'Orphan'karpenter.spec.forProvider.chart.repository = 'oci://public.ecr.aws/karpenter'karpenter.spec.forProvider.chart.name = 'karpenter'karpenter.spec.forProvider.chart.version = '1.8.6'karpenter.spec.forProvider.namespace = 'karpenter'karpenter.externalName = 'karpenter'

Usage Dependencies

function-pythonic can be configured to automatically create Crossplane Usages dependencies between resources. Modifying the above VPC example with:

self.usages=Truevpc=self.resources.VPC('VPC', 'ec2.aws.crossplane.io/v1beta1')
vpc.spec.forProvider.region= 'us-east-1vpc.spec.forProvider.cidrBlock='10.0.0.0/16'subnet=self.resources.SubnetA('Subnet', 'ec2.aws.crossplane.io/v1beta1')
subnet.spec.forProvider.region='us-east-1'subnet.spec.forProvider.vpcId=vpc.status.atProvider.vpcIdsubnet.spec.forProvider.availabilityZone='us-east-1a'subnet.spec.forProvider.cidrBlock='10.0.0.0/20'

Will generate the appropriate Crossplane Usage resource.

API Documentation

Pythonic access of Protobuf Messages

All Protobuf messages are wrapped by a set of python classes which enable using both object attribute names and dictionary key names to traverse the Protobuf message contents. For example, the following examples obtain the same value from the RunFunctionRequest message:

region=request.observed.composite.resource.spec.regionregion=request['observed']['composite']['resource']['spec']['region']

Getting values from free form map and list values will not throw errors for keys that do not exist, but will return an unknown placeholder which evaluates as False. For example, the following will evaluate as False with a just created RunFunctionResponse message:

vpcId=response.desired.resources.vpc.resource.status.atProvider.vpcIdifvpcId:
# The vpcId is available

Note that maps or lists that do exist but do not have any members will evaluate as True, contrary to Python dicts and lists. Use the len function to test if the map or list exists and has members.

When setting fields, all intermediary unknown placeholders will automatically be created. For example, this will create all items needed to set the region on the desired resource:

response.desired.resources.vpc.resource.spec.forProvider.region='us-east-1'

Calling a message or map will clear it and will set any provided key word arguments. For example, this will either create or clear the resource and then set its apiVersion and kind:

response.desired.resources.vpc.resource(kind='VPC', apiVersion='ec2.aws.crossplane.io/v1beta1')

The following functions are provided to create Protobuf structures:

FunctionDescription
MapCreate a new Protobuf map
ListCreate a new Protobuf list
UnknownCreate a new Protobuf unknown placeholder
YamlCreate a new Protobuf structure from a yaml string
YamlAllCreate a new Protobuf list from a yaml string
JsonCreate a new Protobuf structure from a json string
B64EncodeEncode a string into base 64
B64DecodeDecode a string from base 64

The following items are supported in all the Protobuf Message wrapper classes: bool, len, contains, iter, hash, ==, str, format

To convert a Protobuf message to a string value, use either str or format.

yaml=str(request) # get the request as yamlyaml=format(request) # also get the request as yamlyaml=format(request, 'yaml') # yet another get the request as yamljson=format(request, 'json') # get the request as jsonjson=format(request, 'jsonc') # get the request as json compactproto=format(request, 'protobuf') # get the request as a protobuf string

Composite Composition

Composite composition is performed from a Composite orientation. A BaseComposite class is subclassed and the compose method is implemented.

classMyComposite(BaseComposite):
defcompose(self):
# Compose the Composite

The compose method can also declare itself as performing async io:

classMyAsyncComposite(BaseComposite):
asyncdefcompose(self):
# Compose the Composite using async io when needed

BaseComposite

The BaseComposite class provides the following fields for manipulating the Composite itself:

FieldTypeDescription
self.observedMapLow level direct access to the observed composite
self.desiredMapLow level direct access to the desired composite
self.apiVersionStringThe composite observed apiVersion
self.kindStringThe composite observed kind
self.metadataMapThe composite observed metadata
self.specMapThe composite observed spec
self.statusMapThe composite desired and observed status, read from observed if not in desired
self.outputMapThe step output, only used during Operations
self.conditionsConditionsThe composite desired and observed conditions, read from observed if not in desired
self.resultsResultsReturned results applied to the Composite and optionally on the Claim
self.connectionSecretMapThe name, namespace, and resourceName to use when generating the connection secret in Crossplane v2
self.connectionMapThe composite desired connection details
self.connection.observedMapThe composite observed connection details
self.readyBooleanThe composite desired ready state

The BaseComposite also provides access to the following Crossplane Function level features:

FieldTypeDescription
self.requestMessageLow level direct access to the RunFunctionRequest message
self.responseMessageLow level direct access to the RunFunctionResponse message
self.loggerLoggerPython logger to log messages to the running function stdout
self.capabilitiesCapabilitiesThis Crossplane version's Capabilities
self.parametersMapThe configured step parameters
self.ttlIntegerGet or set the response TTL, in seconds
self.credentialsCredentialsThe request credentials
self.contextMapThe response context, initialized from the request context
self.environmentMapThe response environment, initialized from the request context environment
self.requiredsRequiredsRequest and read additional local Kubernetes resources
self.watchedRequiredResourceTHe WatchOperation's changed resource
self.schemasSchemasRequest and read CustomResourceDefinition schemas
self.resourcesResourcesDefine and process composed resources
self.usagesBooleanGenerate Crossplane Usages for resource dependencies, default False
self.autoReadyBooleanPerform auto ready processing on all composed resources, default True
self.unknownsFatalBooleanTerminate the composition if already created resources are assigned unknown values, default False

Capabiities

The Capabilities of the Crossplane version calling function-pythonic.

FieldTypeDescription
bool(Capabilities)BooleanWhether or not the Crossplane version supports Capabilities
Capabiities.requiredsBooleanFunctions can return required resources and Crossplane will fetch the required resources
Capabiities.credentialsBooleanFunctions can receive credentials from secrets specified in the Composition
Capabiities.conditionsBooleanFunctions can return status conditions to be applied to the XR and optionally its claim
Capabiities.schemasBooleanFunctions can request OpenAPI schemas and Crossplane will return them

Composed Resources

Creating and accessing composed resources is performed using the BaseComposite.resources field. BaseComposite.resources is a dictionary of the composed resources whose key is the composition resource name. The value returned when getting a resource from BaseComposite is the following Resource class:

FieldTypeDescription
Resource(apiVersion,kind,namespace,name)ResourceReset the resource and set the optional parameters
Resource.nameStringThe composition composed resource name
Resource.observedMapLow level direct access to the observed composed resource
Resource.desiredMapLow level direct access to the desired composed resource
Resource.apiVersionStringThe composed resource apiVersion
Resource.kindStringThe composed resource kind
Resource.externalNameStringThe composed resource external name
Resource.metadataMapThe composed resource desired metadata
Resource.specMapThe resource spec
Resource.dataMapThe resource data
Resource.statusMapThe resource status
Resource.conditionsConditionsThe resource conditions
Resource.connectionMapThe resource observed connection details
Resource.readyBooleanThe resource ready state
Resource.addDependencyMethodAdd another composed resource as a dependency
Resource.setReadyConditionMethodSet Resource.ready to the Ready Condition status
Resource.usagesBooleanGenerate Crossplane Usages for this resource, default is Composite.autoReady
Resource.autoReadyBooleanPerform auto ready processing on this resource, default is Composite.autoReady
Resource.unknownsFatalBooleanTerminate the composition if this resource has been created and is assigned unknown values, default is Composite.unknownsFatal

Required Resources

Creating and accessing required resources is performed using the BaseComposite.requireds field. BaseComposite.requireds is a dictionary of the required resources whose key is the required schema name. The value returned when getting a required resource from BaseComposite is the following RequiredResources class:

FieldTypeDescription
RequiredResource(apiVersion,kind,namespace,name,labels)RequiredResourceReset the required resource and set the optional parameters
RequiredResources.nameStringThe required resources name
RequiredResources.apiVersionStringThe required resources apiVersion
RequiredResources.kindStringThe required resources kind
RequiredResources.namespaceStringThe namespace to match when returning the required resources, see note below
RequiredResources.matchNameStringThe names to match when returning the required resources
RequiredResources.matchLabelsMapThe labels to match when returning the required resources

RequiredResources acts like a Python list to provide access to the found required resources. Each resource in the list is the following RequiredResource class:

FieldTypeDescription
RequiredResource.nameStringThe required resource name
RequiredResource.observedMapLow level direct access to the observed required resource
RequiredResource.apiVersionStringThe required resource apiVersion
RequiredResource.kindStringThe required resource kind
RequiredResource.metadataMapThe required resource metadata
RequiredResource.specMapThe required resource spec
RequiredResource.dataMapThe required resource data
RequiredResource.statusMapThe required resource status
RequiredResource.conditionsMapThe required resource conditions
RequiredResource.connectionMapThe required resource connection details

Required Schemas

Creating and accessing required schemas is performed using the BaseComposite.schemas field. BaseComposite.schemas is a dictionary of the required schema whose key is the required resource name. The value returned when getting a required resource from BaseComposite is the following Schema class:

FieldTypeDescription
Schema(apiVersion,kind)SchemaReset the required schema and set the optional parameters
Schema.nameStringThe required schema name
Schema.apiVersionStringThe required schema selector apiVersion
Schema.kindStringThe required schema selector kind
Schema.__getitem__MapThe required schema openAPIV3Schema
Schema.__getattr__MapThe required schema openAPIV3Schema

Conditions

The BaseComposite.conditions, Resource.conditions, and RequiredResource.conditions fields are maps of that entity's status conditions array, with the map key being the condition type. The fields are read only for Resource.conditions and RequiredResource.conditions.

FieldTypeDescription
Condition.typeStringThe condtion type, or name
Condition.statusBooleanThe condition status
Condition.reasonStringPascalCase, machine-readable reason for this condition
Condition.messageStringHuman-readable details about the condition
Condition.lastTransitionTimeTimestampLast transition time, read only
Condition.claimBooleanAlso apply the condition the claim

Results

The BaseComposite.results field is a list of results to apply to the Composite and optionally to the Claim.

FieldTypeDescription
Result.infoBooleanNormal informational result
Result.warningBooleanWarning level result
Result.fatalBooleanFatal results also terminate composing the Composite
Result.reasonStringPascalCase, machine-readable reason for this result
Result.messageStringHuman-readable details about the result
Result.claimBooleanAlso apply the result to the claim

Inlined Composites

Tired of creating a CompositeResourceDefinition, a Composition, and a Composite just to run that Composition once in a setup or initialize task?

function-pythonic supports "inlined" Compositions, where the python module is obtained from a field in the Composite's spec.

apiVersion: inlined.example.org/v1alpha1kind: Stepmetadata:
name: inlined-examplespec:
composite: | class HelloComposite(BaseComposite): def compose(self): self.status.step = 'Hello, World!'

The CompositeResourceDefinition and Composition to support the above example:

apiVersion: apiextensions.crossplane.io/v1kind: CompositeResourceDefinitionmetadata:
name: inlined.example.org/v1alpha1spec:
group: inlined.example.orgnames:
kind: Stepplural: stepsdefaultCompositionRef:
name: steps.inlined.example.orgversions:
- name: v1alpha1served: truereferenceable: trueschema:
openAPIV3Schema:
type: objectproperties:
spec:
type: objectproperties:
composite:
type: stringdescription: 'A Python module that defines a class with the signature: class Composite(BaseComposite)'required:
- compositestatus:
type: objectproperties:
composite:
x-kubernetes-preserve-unknown-fields: true
apiVersion: apiextensions.crossplane.io/v1kind: Compositionmetadata:
name: steps.inlined.example.orgspec:
compositeTypeRef:
apiVersion: inlined.example.org/v1alpha1kind: Stepmode: Pipelinepipeline:
- step: inlinedfunctionRef:
name: function-pythonicinput:
apiVersion: pythonic.fn.crossplane.io/v1alpha1kind: Compositeinlined: composite

Quick Start Development

function-pythonic includes a pure python implementation of the crossplane render ... command, which can be used to render Compositions that only use function-pythonic. This makes it very easy to test and debug using your IDE of choice. It is also blindingly fast compared to crossplane render. To use, install the crossplane-function-pythonic python package into the python environment.

$ pip install crossplane-function-pythonic

Then to render function-pythonic Compositions, use the function-pythonic render ... command.

$ function-pythonic render --help
usage: Crossplane Function Pythonic render [-h] [--debug] [--log-name-width WIDTH] [--logger-level LOGGER=LEVEL] [--python-path DIRECTORY]
[--render-unknowns] [--allow-oversize-protos] [--crossplane-v1] [--kube-context CONTEXT]
[--context-files KEY=PATH] [--context-values KEY=VALUE] [--observed-resources PATH]
[--required-resources PATH] [--required-schemas PATH] [--include-full-xr] [--include-connection-xr]
[--include-function-results] [--include-context]
COMPOSITE [COMPOSITION]
positional arguments:
COMPOSITE A YAML file containing the Composite resource to render, or kind:apiVersion:namespace:name of cluster Composite.
COMPOSITION A YAML file containing the Composition resource, or the complete path of a function-pythonic BaseComposite subclass.
options:
-h, --help show this help message and exit
--debug, -d Emit debug logs.
--log-name-width WIDTH
Width of the logger name in the log output, default 40.
--logger-level LOGGER=LEVEL
Logger level, for example: botocore.hooks=INFO
--python-path DIRECTORY
Filing system directories to add to the python path.
--render-unknowns, -u
Render resources with unknowns, useful during local development.
--allow-oversize-protos
Allow oversized protobuf messages
--crossplane-v1 Enable Crossplane V1 compatibility mode
--kube-context, -k CONTEXT
The kubectl context to use to obtain external resources from, such as required resources, connections, etc.
--context-files KEY=PATH
Context key-value pairs to pass to the Function pipeline. Values must be files containing YAML/JSON.
--context-values KEY=VALUE
Context key-value pairs to pass to the Function pipeline. Values must be YAML/JSON. Keys take precedence over --context-files.
--observed-resources, -o PATH
A YAML file or directory of YAML files specifying the observed state of composed resources.
--required-resources, -e PATH
A YAML file or directory of YAML files specifying required resources to pass to the Function pipeline.
--required-schemas, -s PATH
A JSON file or directory of JSON files specifying required schemas to pass to the Function pipeline.
--include-full-xr, -x
Include a direct copy of the input XR's spedc and metadata fields in the rendered output. --include-connection-xr Include the Composite connection values in the rendered output as a resource of kind: Connection. --include-function-results, -r Include informational and warning messages from Functions in the rendered output as resources of kind: Result. --include-context, -c Include the context in the rendered output as a resource of kind: Context.

The following example demonstrates how to locally render function-python compositions. First, create the following files:

xr.yaml

apiVersion: pythonic.fn.crossplane.io/v1alpha1kind: Hellometadata:
name: worldspec:
who: World

composition.yaml

apiVersion: apiextensions.crossplane.io/v1kind: Compositionmetadata:
name: hellos.pythonic.crossplane.iospec:
compositeTypeRef:
apiVersion: pythonic.crossplane.io/v1alpha1kind: Hellomode: Pipelinepipeline:
- step: pythonicfunctionRef:
name: function-pythonicinput:
apiVersion: pythonic.fn.crossplane.io/v1alpha1kind: Compositecomposite: | class GreetingComposite(BaseComposite): def compose(self): self.status.greeting = f"Hello, {self.spec.who}!"

Then, to render the above composite and composition, run:

$ function-pythonic render --debug --render-unknowns xr.yaml composition.yaml
[2025-12-29 09:44:57.949] io.crossplane.fn.pythonic.Hello.world [DEBUG ] Starting compose, 1st step, 1st pass
[2025-12-29 09:44:57.949] io.crossplane.fn.pythonic.Hello.world [INFO ] Completed compose
---
apiVersion: pythonic.fn.crossplane.io/v1alpha1
kind: Hello
metadata:
name: world
status:
conditions:
- lastTransitionTime: '2026-01-01T00:00:00Z'
reason: Available
status: 'True'
type: Ready
- lastTransitionTime: '2026-01-01T00:00:00Z'
message: All resources are composed
reason: AllComposed
status: 'True'
type: ResourcesComposed
greeting: Hello, World!

Most of the examples contain a render.sh command which uses function-pythonic render to render the example.

Shared Python Packages

Python packages and modules can be added to the function-pythonic runtime by including the python code in any of the following resources: ConfigMap, Secret, EnvironmentConfig, or Composition

ConfigMap Packages

ConfigMap based python packages are enable using the --packages-configmaps and --packages-namespace command line options. ConfigMaps with the label function-pythonic.package will be incorporated in the python path at the location configured in the label value. For example, the following ConfigMap will enable python to use import example.pythonic.features

apiVersion: v1kind: ConfigMapmetadata:
namespace: crossplane-systemname: example-pythoniclabels:
function-pythonic.package: example.pythonicdata:
features.py: | def anything(): return 'something'

Then, in your Composition:

...
- step: pythonicfunctionRef:
name: function-pythonicinput:
apiVersion: pythonic.fn.crossplane.io/v1alpha1kind: Compositecomposite: | from example.pythonic import features class FetureComposite(BaseComposite): def compose(self): anything = features.anything()...

The entire function-pythonic Composite class can be coded in the ConfigMap and only the complete Composite class path is needed in the step configuration.

apiVersion: v1kind: ConfigMapmetadata:
namespace: crossplane-systemname: example-pythoniclabels:
function-pythonic.package: example.pythonicdata:
features.py: | from crossplane.pythonic import BaseComposite class FeatureOneComposite(BaseComposite): def compose(self): # go at it!
...
- step: pythonicfunctionRef:
name: function-pythonicinput:
apiVersion: pythonic.fn.crossplane.io/v1alpha1kind: Compositecomposite: example.pythonic.features.FeatureOneComposite...

This requires enabling the the packages support using the --packages-configmaps command line option in the DeploymentRuntimeConfig and configuring the required Kubernetes RBAC permissions. For example:

apiVersion: pkg.crossplane.io/v1kind: Functionmetadata:
name: function-pythonicspec:
package: xpkg.crossplane.io/crossplane-contrib/function-pythonic:v0.6.0runtimeConfigRef:
name: function-pythonic
---
apiVersion: pkg.crossplane.io/v1beta1kind: DeploymentRuntimeConfigmetadata:
name: function-pythonicspec:
deploymentTemplate:
spec:
selector: {}template:
spec:
containers:
- name: package-runtimeargs:
- --debug
- --packagesserviceAccountName: function-pythonicserviceAccountTemplate:
metadata:
name: function-pythonic
---
apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata:
name: function-pythonicrules:
- apiGroups:
- ''resources:
- configmapsverbs:
- list
- watch
- patch
- apiGroups:
- ''resources:
- eventsverbs:
- create
---
apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata:
name: function-pythonicroleRef:
apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: function-pythonicsubjects:
- kind: ServiceAccountnamespace: crossplane-systemname: function-pythonic

When enabled, labeled ConfigMaps are obtained cluster wide, requiring the above ClusterRole permissions. The --packages-namespace command line option will restrict to only using the supplied namespace. This option can be invoked multiple times. The above RBAC permission can then be per namespace RBAC Role permissions.

Secret Packages

Secrets can also be used in an identical manner as ConfigMaps by enabling the --packages-secrets command line option. Secrets permissions need to be added to the above RBAC configuration. Secret based python packages also enable provisioning files with binary data.

EnvironmentConfig Packages

EnvironmentConfig based provisioning enable an entire package and module directory structure. Use the --packages-environmentconfigs command line option and configure the ClusterRole RBAC access.

apiVersion: apiextensions.crossplane.io/v1beta1kind: EnvironmentConfigmetadata:
name: testlabels:
function-pythonic.package: 'true'data:
arootpackage:
asubpackage:
bmodule.py: | def hello(where): return f"Hello, {where}!"amodule.py: | def goodby(where): return f"Goodby, {where}!"

Composition Packages

Composition based provisioning works just like EnvironmentConfig where a directory structure is created. Use the --packages-compositions command line option and configure the ClusterRole RBAC access. The main reason to use Composition based provision is because Compositions can be included in a Crossplane Configuration Package.

apiVersion: apiextensions.crossplane.io/v1kind: Compositionmetadata:
labels:
function-pythonic.package: 'true'name: testspec:
compositeTypeRef:
apiVersion: code.pythoni.com/v1alpha1kind: Codemode: Pipelinepipeline:
- step: renderfunctionRef:
name: function-pythonicinput:
apiVersion: pythonic.fn.crossplane.io/v1alpha1kind: Compositepackages:
arootpackage:
asubpackage:
bmodule.py: | def hello(where): return f"Hello, {where}!"amodule.py: | def goodby(where): return f"Goodby, {where}!"

Step Parameters

Step specific parameters can be configured to be used by the composite implementation. This is useful when setting the composite to the python class. For example:

apiVersion: v1kind: ConfigMapmetadata:
namespace: crossplane-systemname: example-pythoniclabels:
function-pythonic.package: example.pythonicdata:
features.py: | from crossplane.pythonic import BaseComposite class GreetingComposite(BaseComposite): def compose(self): cm = self.resources.ConfigMap('ConfigMap', 'v1') cm.data.greeting = f"Hello, {self.parameters.who}!"
...
- step: pythonicfunctionRef:
name: function-pythonicinput:
apiVersion: pythonic.fn.crossplane.io/v1alpha1kind: Compositeparameters:
who: Worldcomposite: example.pythonic.features.GreetingComposite...

Filing System Packages

Composition Composite implementations can be coded in a stand alone python files by configuring the function-pythonic deployment with the code mounted into the package-runtime container, and then adding the mount point to the python path using the --python-path command line option.

apiVersion: pkg.crossplane.io/v1beta1kind: DeploymentRuntimeConfigmetadata:
name: function-pythonicspec:
deploymentTemplate:
spec:
template:
spec:
containers:
- name: package-runtimeargs:
- --debug
- --python-path
- /mnt/compositesvolumeMounts:
- name: compositesmountPath: /mnt/compositesvolumes:
- name: compositesconfigMap:
name: pythonic-composites

See the filing-system example.

Install Additional Python Packages

function-pythonic supports a --pip-install command line option which will run pip install with the configured pip install command. For example:

apiVersion: pkg.crossplane.io/v1beta1kind: DeploymentRuntimeConfigmetadata:
name: function-pythonicspec:
deploymentTemplate:
spec:
template:
spec:
containers:
- name: package-runtimeargs:
- --debug
- --pip-install
- --quiet aiobotocore==2.23.2

Enable Oversize Protos

The Protobuf python package used by function-pythonic limits the depth of yaml elements and the total size of yaml parsed. This results in a limit of approximately 30 levels of nested yaml fields. This check can be disabled using the --allow-oversize-protos command line option. For example:

apiVersion: pkg.crossplane.io/v1beta1kind: DeploymentRuntimeConfigmetadata:
name: function-pythonicspec:
deploymentTemplate:
spec:
template:
spec:
containers:
- name: package-runtimeargs:
- --debug
- --allow-oversize-protos

About

Python based Crossplane Function providing a clean and elegant syntax for writing Crossplane Compositions.

Resources

Stars

16 stars

Watchers

3 watching

Forks

Releases

Packages

Contributors

Languages