Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 125 additions & 0 deletions content/docs/examples/hello-world.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
---
title: Hello World
description: Hello World WASM example
---

This is a simple hello world example. The WASM module prints "Hello World!" to stdout. For this example we can use the standard proplet deployment without any additional configuration.

## Source Code

The source code is available in the [examples/hello-world](https://github.com/absmach/propeller/blob/main/examples/hello-world/hello-world.go) directory.

<CodeFromSource
src="https://raw.githubusercontent.com/absmach/propeller/refs/heads/main/examples/hello-world/hello-world.go"
lang="go"
/>

## Create Task

To create a task for this example, we need to build the example to wasm and then create a task with the wasm file.

```bash
cd propeller
make hello-world
```

Your output should look like this:

```bash
GOOS=js GOARCH=wasm tinygo build -buildmode=c-shared -o build/hello-world.wasm -target wasi examples/hello-world/hello-world.go
```

Now we can create a task with the wasm file:

```bash
curl -X POST "http://localhost:7070/tasks" \
-H "Content-Type: application/json" \
-d '{"name": "main", "inputs": []}'
```

Your output should look like this:

```json
{
"id": "53db63cb-885c-4364-849c-f69640aaa601",
"name": "main",
"kind": "standard",
"state": 0,
"cli_args": null,
"inputs": [],
"daemon": false,
"encrypted": false,
"start_time": "0001-01-01T00:00:00Z",
"finish_time": "0001-01-01T00:00:00Z",
"created_at": "2026-02-13T10:53:49.157542442Z",
"updated_at": "0001-01-01T00:00:00Z",
"next_run": "0001-01-01T00:00:00Z",
"priority": 50
}
```

## Upload Wasm

Now we need to upload the wasm file:

```bash
curl -X PUT "http://localhost:7070/tasks/53db63cb-885c-4364-849c-f69640aaa601/upload" \
-F "file=@$(pwd)/build/hello-world.wasm"
```

## Start Task

Now we can start the task:

```bash
curl -X POST "http://localhost:7070/tasks/53db63cb-885c-4364-849c-f69640aaa601/start"
```

Your output should look like this:

```json
{ "started": true }
```

The results of the task will be something like this.

```bash
curl -X GET "http://localhost:7070/tasks/53db63cb-885c-4364-849c-f69640aaa601"
```

Your output should look like this:

```json
{
"id": "53db63cb-885c-4364-849c-f69640aaa601",
"name": "main",
"kind": "standard",
"state": 3,
"file": "...<redacted>...",
"cli_args": null,
"inputs": [],
"daemon": false,
"encrypted": false,
"proplet_id": "a95517f9-5655-4cf5-a7c8-aa00290b3895",
"results": "Hello World!\n",
"start_time": "2026-02-13T11:00:43.010348944Z",
"finish_time": "2026-02-13T11:00:43.202889598Z",
"created_at": "2026-02-13T10:53:49.157542442Z",
"updated_at": "2026-02-13T11:00:43.202889537Z",
"next_run": "0001-01-01T00:00:00Z",
"priority": 50
}
```

## Invoking Using WasmTime

```bash
wasmtime --invoke main ./build/hello-world.wasm
```

The results of the task will be something like this.

```bash
warning: using `--invoke` with a function that takes arguments is experimental and may break in the future
Hello World!
```
86 changes: 86 additions & 0 deletions content/docs/examples/ml-wasm.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
title: ML Inference (TinyGo)
description: Run ML inference in WASM using a linear regression model
---

This example demonstrates a simple ML inference workload compiled to WASM. A linear regression model is trained in Python using scikit-learn, and the coefficients are extracted into a pure Go implementation that runs entirely inside the WASM module — no Python runtime needed at inference time.

The model approximates: `y = 2*x0 + 3*x1`

Before building, a Python training script generates the model and the Go model code is extracted:

```bash
cd examples/ml-wasm
python3 train_model.py
go run model_gen.go > /dev/null # validates coefficients
cd ../..
```

This creates `mymodel.pkl` and embeds the coefficients in `model_gen.go`. The weights are:

- `intercept = 0.0`
- `weight[0] = 2.0` (for input x0)
- `weight[1] = 3.0` (for input x1)

## Source Code

The source code is available in the [examples/ml-wasm](https://github.com/absmach/propeller/blob/main/examples/ml-wasm) directory.

<CodeFromSource
src="https://raw.githubusercontent.com/absmach/propeller/refs/heads/main/examples/ml-wasm/main.go"
lang="go"
/>

### Training Script

<CodeFromSource
src="https://raw.githubusercontent.com/absmach/propeller/refs/heads/main/examples/ml-wasm/train_model.py"
lang="python"
/>

### Generated Model

<CodeFromSource
src="https://raw.githubusercontent.com/absmach/propeller/refs/heads/main/examples/ml-wasm/model_gen.go"
lang="go"
/>

## Create Task

Build the WASM binary:

```bash
cd propeller
GOOS=wasip2 GOARCH=wasm go build -o build/ml-wasm.wasm examples/ml-wasm/main.go examples/ml-wasm/model_gen.go
```

Now we can create a task:

```bash
curl -X POST "http://localhost:7070/tasks" \
-H "Content-Type: application/json" \
-d '{"name": "predict", "inputs": ["200", "300"]}'
```

Inputs are scaled by 100 (e.g. `200` = `2.0`) — the module divides by 100, runs inference, and multiplies the result by 100.

## Upload Wasm

```bash
curl -X PUT "http://localhost:7070/tasks/<task-id>/upload" \
-F "file=@$(pwd)/build/ml-wasm.wasm"
```

## Start Task

```bash
curl -X POST "http://localhost:7070/tasks/<task-id>/start"
```

The result for inputs `[2.0, 3.0]` should be approximately `1300` (i.e. `(2*2.0 + 3*3.0) * 100 = 1300`).

## Invoking Using WasmTime

```bash
wasmtime --invoke predict ./build/ml-wasm.wasm 200 300
```
59 changes: 59 additions & 0 deletions content/docs/examples/plugin-auth.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
title: Plugin — Auth
description: Authorization plugin for the Propeller manager
---

The Auth plugin demonstrates how to extend the Propeller manager with custom authorization logic. It runs as a WASM plugin loaded by the manager and hooks into two lifecycle points:

- **`authorize`** — validates whether a request is allowed based on the task name and user context
- **`enrich`** — injects additional environment variables into the task before dispatch

This plugin is compiled to `wasm32-wasip1` and loaded by the Propeller manager at startup via the `PROPELLER_PLUGIN_PATH` environment variable.

## Source Code

The source code is available in the [examples/plugin-auth](https://github.com/absmach/propeller/blob/main/examples/plugin-auth) directory.

<CodeFromSource
src="https://raw.githubusercontent.com/absmach/propeller/refs/heads/main/examples/plugin-auth/src/lib.rs"
lang="rust"
/>

## Plugin Behaviour

| Action | Rule |
| --------- | -------------------------------------------------------------------- |
| `create` | Denied if `user_id` is empty |
| `start` | Denied if `user_id` is empty, or if the task was created by a different user |
| other | Always allowed |

The enrich handler injects `PROPELLER_PLUGIN_AUTHZ=plugin-auth` and `PROPELLER_CREATED_BY=<user_id>` into the task environment.

## Build

```bash
cd propeller
make plugin-auth
```

Your output should look like this:

```bash
mkdir -p build/plugins
cd examples/plugin-auth && cargo build --target wasm32-wasip1 --release
cp examples/plugin-auth/target/wasm32-wasip1/release/plugin_auth.wasm build/plugins/plugin-auth.wasm
```

## Use

Place the compiled `.wasm` file in a directory the manager can access and set the environment variable:

```bash
export PROPELLER_PLUGIN_PATH="/path/to/plugins/plugin-auth.wasm"
```

On startup, the manager logs:

```bash
INFO Plugin loaded: plugin-auth (wasm32-wasip1)
```
48 changes: 48 additions & 0 deletions content/docs/examples/plugin-proxy.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: Plugin — Registry Proxy
description: Registry mirror rewriting plugin for the Propeller manager
---

The Registry Proxy plugin rewrites OCI image references at request time so the proplet fetches WASM modules from a private registry mirror instead of the upstream registry. This is useful in air-gapped environments or when you want to cache and audit all WASM images used across your deployment.

It only implements the `enrich` hook — it rewrites `image_url` on the task before the manager dispatches it.

## Source Code

The source code is available in the [examples/plugin-proxy](https://github.com/absmach/propeller/blob/main/examples/plugin-proxy) directory.

<CodeFromSource
src="https://raw.githubusercontent.com/absmach/propeller/refs/heads/main/examples/plugin-proxy/src/lib.rs"
lang="rust"
/>

## Rewrite Rules

| Original `imageUrl` | Mirror configured | Result |
| ---------------------------------------- | ------------------------------ | ----------------------------------------- |
| `ghcr.io/org/task:latest` | `mirror.corp.com` | `mirror.corp.com/org/task:latest` |
| `myimage:latest` | `mirror.corp.com` | `mirror.corp.com/myimage:latest` |
| `mirror.corp.com/org/task:latest` | `mirror.corp.com` | `mirror.corp.com/org/task:latest` (no-op) |
| `localhost:5000/org/task:latest` | `mirror.corp.com` | `mirror.corp.com/org/task:latest` |

If `PROPELLER_REGISTRY_MIRROR` is not set or empty, the plugin returns the image URL unchanged.

## Build

```bash
cd propeller
make plugin-proxy
```

## Use

```bash
export PROPELLER_PLUGIN_PATH="/path/to/plugins/plugin-proxy.wasm"
export PROPELLER_REGISTRY_MIRROR="mirror.corp.com"
```

On startup, the manager logs:

```bash
INFO Plugin loaded: plugin-proxy (wasm32-wasip1)
```
52 changes: 52 additions & 0 deletions content/docs/examples/proplet-plugin-example.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
title: Proplet Plugin Example
description: Example of a proplet-side lifecycle plugin
---

This example demonstrates a proplet-side plugin using the `propeller-proplet-plugin-sdk`. Unlike manager plugins (which run in the manager process), proplet plugins run inside the proplet and hook into the task lifecycle at the point of execution.

The plugin exports four lifecycle hooks:

- **`authorize`** — deny tasks with an empty name
- **`enrich`** — forward environment variables to the task
- **`on_task_start`** — log when a task begins
- **`on_task_complete`** — log when a task finishes

## Source Code

The source code is available in the [examples/proplet-plugin-example](https://github.com/absmach/propeller/blob/main/examples/proplet-plugin-example) directory.

<CodeFromSource
src="https://raw.githubusercontent.com/absmach/propeller/refs/heads/main/examples/proplet-plugin-example/src/lib.rs"
lang="rust"
/>

## Build

```bash
cd propeller
make proplet-plugin-example
```

Your output should look like this:

```bash
mkdir -p build/proplet-plugins
cd examples/proplet-plugin-example && cargo build --target wasm32-wasip2 --release
cp examples/proplet-plugin-example/target/wasm32-wasip2/release/proplet_plugin_example.wasm build/proplet-plugins/proplet-plugin-example.wasm
```

## Use

Place the compiled `.wasm` file in a directory the proplet can access and set:

```bash
export PROPLET_PLUGIN_DIR="/path/to/proplet-plugins"
```

On task execution, the proplet logs:

```bash
[example-plugin] task starting: <task-id>
[example-plugin] task <task-id> finished (success=true)
```
Loading