Skip to content
Open
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
115 changes: 115 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# This workflow builds and pushes a multi-arch image to Quay.io
# Adapted from actions-arm64-native-example by @gartnera
# ref: https://github.com/gartnera/actions-arm64-native-example/blob/main/.github/workflows/build.yml

name: build

on:
push:
pull_request:

env:
QUAY_REPO: quay.io/${{ github.repository_owner }}/${{ github.event.repository.name }}

jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-22.04
- platform: linux/arm64
runner: ubuntu-22.04-arm
runs-on: ${{ matrix.runner || 'ubuntu-22.04' }}
steps:
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV

- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.QUAY_REPO }}

- name: Login to Quay.io
uses: docker/login-action@v3
with:
registry: quay.io
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_ROBOT_TOKEN }}

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build and push by digest
id: build
uses: docker/build-push-action@v6
with:
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.QUAY_REPO }},push-by-digest=true,name-canonical=true,push=true

- name: Export digest
run: |
mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"

- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1

merge:
runs-on: ubuntu-latest
needs:
- build
steps:
- name: Download digests
uses: actions/download-artifact@v4
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true

- name: Login to Quay.io
uses: docker/login-action@v3
with:
registry: quay.io
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_ROBOT_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.QUAY_REPO }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}

- name: Create manifest list and push
working-directory: ${{ runner.temp }}/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.QUAY_REPO }}@sha256:%s ' *)

- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.QUAY_REPO }}:${{ steps.meta.outputs.version }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ go.work.sum
.env

build/
*.DS_Store
*funnel.db
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Use the official Golang image as the base image
FROM golang:1.23-alpine
FROM golang:1.24.2-alpine

# Set the Current Working Directory inside the container
WORKDIR /app
Expand All @@ -20,4 +20,4 @@ RUN mkdir -p ./build/plugins
RUN go build -o ./build/cli .

# Build the plugin
RUN go build -o ./build/plugins/authorizer ./plugin
RUN go build -o ./build/plugins/authorizer ./plugin-go
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ clean:
rm -rf $(DIR)/*

build:
# Build CLI
# Build CLI
go build -o $(DIR)/cli

# Build Plugin
go build -o $(DIR)/plugins/authorizer ./plugin-go


tests:
# Build test server
go build -o $(DIR)/test-server ./tests/test-server.go
Expand Down
60 changes: 54 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ First build and run the test User Database server:
> | `test-server` | the Test Server used for storing user and credentials (called by the plugin) |
> | `plugins/authorizer` | the plugin binary |

## 2. Start the Test Server
## 2. Start the Test Server

```sh
➜ ./test-server
Expand Down Expand Up @@ -106,15 +106,16 @@ sequenceDiagram
## Overview πŸŒ€

The following includes examples and resources for writing Plugins (in Go, Python, or any other [supported language](https://grpc.io/docs/languages/)!)
 

- [gRPC Example](https://github.com/hashicorp/go-plugin/tree/main/examples/grpc) (this is largely what Funnel Plugins is based off of, along with this [manager](https://github.com/eliben/code-for-blog/blob/main/2023/go-plugin-htmlize-rpc/plugin/manager.go#L28-L83) snippet by [Eli Bendersky](https://eli.thegreenplace.net/2023/rpc-based-plugins-in-go/) for loading the plugin binaries)
 

- [Intro](https://github.com/hashicorp/go-plugin/blob/main/docs/extensive-go-plugin-tutorial.md) (super helpful reference from beginning to end)

## Communicating with Funnel

> [!WARNING]
> TODO: Add the following to the docs 🚧
>
> - API "contract" between the Plugin and Funnel Server":
> - What exactly will the Plugin require for inputs and outputs (`Config`)?
> - What functions will plugin authors need to implement (e.g. `Get`)?
Expand Down Expand Up @@ -146,17 +147,64 @@ For authoring custom plugins in Python, see the [example Python plugin](./plugin
> [!TIP]
> Understanding gRPC and protobufs isn't necessary to writing plugins, but it can be helpful when errors or bugs arise πŸ›

Under the hood, all communication between the Plugin and the Funnel Server happens over gRPC using Protocal Buffers (*protobufs*).
Under the hood, all communication between the Plugin and the Funnel Server happens over gRPC using Protocal Buffers (_protobufs_).

- [Protobuf Overview](https://protobuf.dev/)
  

- Tutorials for [Go](https://protobuf.dev/getting-started/gotutorial/) and [Python](https://protobuf.dev/getting-started/pythontutorial/)
 

- [Awesome gRPC](https://github.com/grpc-ecosystem/awesome-grpc#protocol-buffers) β€” pretty up-to-date resource for all things Protobuf and gRPC! 😎

# Additional Resources πŸ“š

- https://github.com/hashicorp/go-plugin
- https://pkg.go.dev/github.com/hashicorp/go-plugin
- https://eli.thegreenplace.net/2023/rpc-based-plugins-in-go
- https://github.com/eliben/code-for-blog/tree/main/2023/go-plugin-htmlize-rpc

## Local testing

Assuming funnel is running `funnel server run -c config.yaml`
with a plugin enabled in the config like

```
Plugins:
Path: build/plugins/authorizer
Params:
Host: http://localhost:8080/token?user=
```

Create a task that will pass through the plugin with

```
curl -X POST \
http://localhost:8000/v1/tasks \
-H "Content-Type: application/json" \
-H "Authorization: testauthz" \
-d @tests/plugin-test.json
```

where tests/plugin-test.json is a basic json test like:

```
{
"name": "Hello world",
"description": "Demonstrates the most basic echo task.",
"executors": [
{
"image": "alpine",
"command": ["echo", "hello world"]
}
],
"tags": {
"user": "foo"
}
}
```

This should hit the plugin, contact whatever endpoint is specified,
and return the response packet from the specified server.

Any special headers that are passed when creating the task should be accessible in the example test server run with

`go run tests/test-server.go --users-csv tests/example-users.csv`
23 changes: 0 additions & 23 deletions buf.gen.yaml

This file was deleted.

57 changes: 32 additions & 25 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,42 +1,49 @@
module example.com
module github.com/ohsu-comp-bio/funnel-plugins

go 1.22
go 1.24.0

toolchain go1.22.5
toolchain go1.24.2

require (
github.com/hashicorp/go-plugin v1.4.9
github.com/ohsu-comp-bio/funnel v0.0.0-20250226001524-3169fd6d9435
github.com/hashicorp/go-plugin v1.6.3
github.com/ohsu-comp-bio/funnel v0.0.0-20250514233149-7f362add7305
google.golang.org/protobuf v1.36.6
)

require (
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/getlantern/deepcopy v0.0.0-20160317154340-7f45deb8130a // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.26.0 // indirect
github.com/goccy/go-yaml v1.17.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/term v0.27.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/term v0.31.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e // indirect
)

require (
github.com/fatih/color v1.7.0 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/hashicorp/go-hclog v0.14.1
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect
github.com/mattn/go-colorable v0.1.7 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/oklog/run v1.0.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.22.0 // indirect
google.golang.org/grpc v1.70.0
google.golang.org/protobuf v1.36.5
golang.org/x/net v0.39.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/text v0.24.0 // indirect
google.golang.org/grpc v1.72.0 // indirect
)
Loading