A JavaScript function for Crossplane that enables executing inline JavaScript/TypeScript code in compositions.
Crossplane Function JS is a specialized Crossplane function that allows you to write JavaScript/TypeScript code directly in your compositions. It consists of a Go gRPC server that receives requests from Crossplane and manages Node.js servers that execute the JavaScript/TypeScript code.
The architecture is designed for robustness and isolation:
- The Go server acts as a proxy between Crossplane and the Node.js servers
- Each unique piece of inline code gets its own isolated Node.js server instance
- Node.js servers are lazy instantiated based on the hash of the inline code
- Unused Node.js servers are garbage collected to conserve resources
graph TD
A[Crossplane] -->|gRPC Requests| B[Go gRPC Server]
B -->|Manages| C[Process Manager]
C -->|Creates/Manages| D[Node.js Server 1]
C -->|Creates/Manages| E[Node.js Server 2]
C -->|Creates/Manages| F[Node.js Server N]
D -->|Executes| G[Inline Code 1]
E -->|Executes| H[Inline Code 2]
F -->|Executes| I[Inline Code N]
G -->|Returns Result| D
H -->|Returns Result| E
I -->|Returns Result| F
D -->|Returns Composition| B
E -->|Returns Composition| B
F -->|Returns Composition| B
B -->|Returns Composition| A
- Go gRPC Server: Receives requests from Crossplane, manages Node.js processes, and forwards requests.
- Process Manager: Manages the lifecycle of Node.js processes, including creation, health checking, and garbage collection.
- Node.js Servers: Execute JavaScript/TypeScript code from compositions.
- Inline Code Execution: Write JavaScript/TypeScript code directly in your compositions
- Code Isolation: Each piece of inline code runs in its own Node.js server for robustness
- Optional Dependencies: Specify npm dependencies for your inline code (recommended for development only)
- Optional Inline yarn.lock: Include a yarn.lock file in your composition for dependency version locking
- CLI Tool: Generate composition manifests with inline code from source files
- Kubernetes cluster with Crossplane v2.0.0 or later installed
- Helm 3+
# Install the chart
helm install crossplane-function-js oci://ghcr.io/socialgouv/helm/crossplane-function-js --version 0.0.2
For more details on chart configuration options, see the chart documentation.
-
Clone the repository:
git clone https://github.com/socialgouv/crossplane-function-js.git cd crossplane-function-js
-
Allow direnv to load the Devbox environment:
direnv allow
This will automatically activate the Devbox development environment with all required tools:
- Node.js (latest)
- Go (latest)
- Yarn (latest)
- Kubernetes tools (kubectl, helm, kind, k9s)
- Development utilities (jq, go-task)
-
Install dependencies:
yarn
The development environment provides the following tools via Devbox:
- Node.js: Latest version for JavaScript/TypeScript development
- Go: Latest version for the gRPC server
- Yarn: Package manager for Node.js dependencies
- kubectl: Kubernetes command-line tool
- Helm: Kubernetes package manager
- Kind: Kubernetes in Docker for local testing
- K9s: Terminal-based Kubernetes cluster management
- jq: JSON processor for data manipulation
- go-task: Task runner for development workflows
The environment is automatically configured with:
KUBECONFIG
set to$PWD/.kubeconfig
for local cluster management- All tools available in the shell PATH
Here's an example of a composition that uses inline JavaScript code:
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example-composition
spec:
compositeTypeRef:
apiVersion: example.org/v1alpha1
kind: XExample
pipeline:
- step: transform-with-js
functionRef:
name: function-xfuncjs
input:
spec:
source:
inline: |
export default async function(input) {
// Your JavaScript/TypeScript code here
const composite = input.observed.composite.resource;
// Transform the input
const transformed = {
// Your transformed resources
};
return {
resources: transformed
};
}
The CLI tool can be used to generate composition manifests from source files:
-
Create a directory structure for your functions:
functions/ ├── example1/ │ ├── composition.fn.ts │ ├── xrd.yaml │ ├── package.json (optional) │ └── composition.yaml (optional) └── example2/ ├── composition.fn.ts ├── xrd.yaml └── package.json
-
Run the CLI tool:
npx @crossplane-js/cli gen-manifests
-
This will generate composition manifests in the
manifests/
directory.
By default, the CLI uses a template for generating compositions. However, you can provide your own template by creating a composition.yaml
file in the same directory as your composition.fn.ts
file.
If you create a custom template, you should maintain the following placeholders if you want to preserve the substitution functionality:
__FUNCTION_NAME__
: Will be replaced with the name of the function directory__FUNCTION_CODE__
: Will be replaced with the content of thecomposition.fn.ts
file__DEPENDENCIES__
: Will be replaced with dependencies from package.json__YARN_LOCK__
: Will be replaced with the content of yarn.lock
The CLI handles dependencies and yarn.lock files as follows:
-
Dependencies: By default, the
__DEPENDENCIES__
placeholder will be replaced with dependencies from thepackage.json
file in the same directory as thecomposition.fn.ts
file. If nopackage.json
exists in that directory, it will use dependencies from thepackage.json
in the parent directory (the one containing thefunctions
directory). -
yarn.lock: Similarly, the
__YARN_LOCK__
placeholder will be replaced with the content of theyarn.lock
file in the same directory as thecomposition.fn.ts
file. If noyarn.lock
exists in that directory, it will use theyarn.lock
from the parent directory.
This approach allows you to have function-specific dependencies or share dependencies across all functions.
To help in writing compositions, the CLI tool can generate type-safe models for the following:
- Base Kubernetes resources
- CRDs derived from the XRDs of your custom resources
- External extra CRDs defined in a configuration file (optional)
Run the CLI tool:
npx @crossplane-js/cli gen-models
To generate a models/
directory containing models that can be imported in
your composition functions.
To generate models for extra CRDs, create a config.yaml
in the base
directory, next to the functions/
directory with a extraCrds
field
containing an array of extra CRDs urls to use in model generation, e.g.:
extraCrds:
- https://github.com/fluxcd/source-controller/releases/download/v1.7.0/source-controller.crds.yaml
The project includes end-to-end tests that use a Kind cluster to verify functionality:
# Set up the test environment
task setup-test-env
# Run the end-to-end tests
task e2e-test
# Clean up the test environment
task clean-test-env
The tests:
- Set up a Kind cluster with a local registry
- Install Crossplane v2.x
- Deploy the XFuncJS server
- Apply test compositions and resources
- Verify that the resources are created correctly
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request