Skip to content
Open
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
68 changes: 68 additions & 0 deletions docs/rfcs/ocb-plugins-hooks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# OCB Hooks

Author: @braydonk

AI USAGE DISCLOSURE: Some parts of the POC development leveraged Google Antigravity. The RFC contents are written entirely by me.

## Abstract

This RFC proposes a new feature in OCB that I am calling "hooks". It introduces a plugin interface for OCB plugins managed via [Hashicorp's Go Plugin framework][Hashicorp Go Plugin] which can be configured as hooks during OCB's process for generating and compiling a distribution. As of now, there are 4 hooks available: Pre/Post Generate, and Pre/Post Compile. Each hook can be individually skipped, or both skipped when Generation/Compilation respectively are disabled.

@jade-guiton-dd jade-guiton-dd Jul 24, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You had mentioned that using the Go Plugin framework makes it easier on hook authors, but after looking at the POC code I'm not entirely convinced the extra dependency has much value here, since we're typically making a single call, passing in one of four "actions" + the raw YAML config section, and getting back a potential error. An alternative could be to have hooks be simple binaries that communicate through stdin/stderr/files, with the ocbplugin module containing utilities to abstract over the communication method. I may try to fork your POC to try this out if I have the time.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll be interested to see what you have in mind. The feeling I got was that writing our own standard for how to communicate between OCB and a valid OCB plugin binary was going to essentially be writing our own communication framework from scratch. Maybe there would be a nice way to write a library such that most of the details are abstracted away from plugin authors, but currently the only thing plugin authors explicitly have to know related to the "plugin" framework is that they need a main() that calls our ocbplugin.Serve function. Otherwise they're just implementing an interface with normal Go code.

I'm open to the idea if you want to put something together.

@jade-guiton-dd jade-guiton-dd Jul 24, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed a quick-and-dirty fork of your prototype on my branch (comparison with your branch, comparison with main), to demonstrate both of my suggestions:

  • It runs each plugin binary directly with cmd/exec, passing as a command line argument the path to a temporary YAML file containing the action (pre-generate, etc.) and the hook's YAML config
  • The plugin source config is spliced into the hook config itself, and mod / version is replaced by a single gomod config. The path config was renamed gopath to avoid interfering with the scriptplugin's own config, whether this is the right way to avoid this conflict can be bikeshed later I think.

Part of the +150 -537 diff was me just deleting tests that no longer compile, but despite that I think it overall simplifies things. I've tested the prototype with this basic config:

dist:
  name: otelcol-custom
  description: Custom Collector Distribution
  output_path: ./build
receivers:
  - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.156.0
exporters:
  - gomod: go.opentelemetry.io/collector/exporter/nopexporter v0.156.0
hooks:
  post_generate:
    - gopath: ./scriptplugin
      path: ./scriptplugin/example/post_generate.sh

(I tried testing the downloading of remote plugins, but I couldn't get pseudoversions to work like I wanted for this unfortunately. I'm not sure if you necessarily need a main directory to define a new binary?)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to start with a smaller number of hook types for now? It would be interesting to see what use cases cover each and see if e.g. we can start only with the one(s) needed for the OBI use case

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


## Proof of Concept

A proof of concept is [available on my Collector fork][POC].

## Example Configuration

The following is an example configuration that sets up a plugin that can run bash shell scripts, with pregenerate and prebuild setups:

Check warning on line 17 in docs/rfcs/ocb-plugins-hooks.md

View workflow job for this annotation

GitHub Actions / spell-check

Unknown word (prebuild)

```yaml
dist:
name: otelcol-custom
description: Custom Collector Distribution
output_path: ./build
receivers:
- gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.156.0
exporters:
- gomod: go.opentelemetry.io/collector/exporter/nopexporter v0.156.0
hooks:
plugins:
- name: scriptplugin

Check warning on line 30 in docs/rfcs/ocb-plugins-hooks.md

View workflow job for this annotation

GitHub Actions / spell-check

Unknown word (scriptplugin)
module: go.opentelemetry.io/cmd/builder/scriptplugin

Check warning on line 31 in docs/rfcs/ocb-plugins-hooks.md

View workflow job for this annotation

GitHub Actions / spell-check

Unknown word (scriptplugin)
version: v0.157.0
pre_generate:
- plugin: scriptplugin

Check warning on line 34 in docs/rfcs/ocb-plugins-hooks.md

View workflow job for this annotation

GitHub Actions / spell-check

Unknown word (scriptplugin)
path: ./scripts/pre_generate.sh
args:
- "--verbose"
Comment on lines +28 to +37

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the goal of hooks is to make running OCB as streamlined as possible (without a wrapper shell script), I wonder if we could simplify the config a tad:

hooks:
  pre_generate:
    - gomod: go.opentelemetry.io/cmd/builder/scriptplugin v0.157.0
      path: ./scripts/pre_generate.sh
      args: ["--verbose"]

(This proposal and the above are assuming the "actions" are fairly independent and there isn't a strong use case for keeping data in memory between separate actions for the same hook.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The goals for the setup I chose was:

  1. Install and run plugin subprocesses only once per OCB run
  2. Be able to detect already installed plugins in case of multiple runs on the same machine
  3. Support purely local plugins

2 would not be much of a downside if we fully rely on Go's module cache in a scenario where we only leverage go install. But for the other two points, I'm not sure how to support it in a scenario where we only rely on gomod inline to each hook execution.

@jade-guiton-dd jade-guiton-dd Jul 24, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I see how 2 and 3 would be an issue here. ocb would run go install . in the local path like you're currently doing, then run the produced binary once for each hook.

Regarding 1 however, if "running plugin subprocesses only once per OCB run" is an absolute requirement, then indeed neither of my suggestions are applicable. But my assumption is that using the same plugin in multiple steps is fairly rare, and even in those cases, the overhead of running the same binary a handful of times is nothing compared to the actual work being done in the hook (let alone the Go compilation).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be great to add these goals to the text of the RFC

Comment on lines +29 to +37

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the previous comment: could we pick one of these for the initial plugin support? There's a lot of overlap between the two

pre_build:
- plugin: scriptplugin

Check warning on line 39 in docs/rfcs/ocb-plugins-hooks.md

View workflow job for this annotation

GitHub Actions / spell-check

Unknown word (scriptplugin)
path: ./scripts/pre_build.sh
env:
BUILD_ENV: "staging"
```

A set of plugin sources are configured, which can be installed remotely via `module`/`version`, or locally via `path`. Those plugins can then be referenced by name in the different hook configurations, along with a generic configuration that will be passed to the hook.

## Defining a Plugin

An `ocbplugin` package will be provided for plugin authors. It will feature an interface for OCB plugins to implement, as well as helpers to facilitate their plugin host setup, which automatically configures the required handshake that OCB will expect.

Check warning on line 49 in docs/rfcs/ocb-plugins-hooks.md

View workflow job for this annotation

GitHub Actions / spell-check

Unknown word (ocbplugin)

See the [Hashicorp Go Plugin][Hashicorp Go Plugin] library for more information on what these plugins generally look like, and [the example implementation of a bash script execution plugin in the POC](https://github.com/braydonk/opentelemetry-collector/tree/ocb_plugin_experiment/cmd/builder/scriptplugin).

OPEN QUESTION: Should this package live under `cmd/builder`? It is a bit odd for a library module to live under a `cmd` directory, but there is no `pkg` directory in `opentelemetry-collector`.

## Plugin Management

The procedure in OCB is as follows:

1. If any hooks are configured, go through the list of plugins and install them. By default the plugins will be installed into `$HOME/.ocb` (or `$(pwd)/.ocb` if user's home directory can't be resolved). Users can configure a plugin directory via the `OCB_PLUGIN_DIR` environment variable. Unless the `--reinstall-hooks` flag is provided, if any plugins are already detected as being installed it can reuse them.
1. Hooks are run in their respective places. The first time a hook is requested, OCB will start it as a subprocess and manage an RPC client to it for the rest of the generation/compilation process. If any plugin is incapable of being started for any reason, such as requesting an unsupported hook action, failing the handshake, or just not serving RPCs properly at all, it will fail the full OCB process.
1. Hooks will reuse the same plugin subprocess for each time the plugin is configured. After OCB is finished, all subprocesses are cleaned up.

## OBI Plugin Example

Within the POC I also [implemented an example OBI plugin](https://github.com/braydonk/opentelemetry-collector/tree/ocb_plugin_experiment/cmd/builder/obiplugin) and an [example config using it](https://github.com/braydonk/opentelemetry-collector/blob/ocb_plugin_experiment/cmd/builder/obiplugin/example/ocb-obi-config.yaml) that mirrors the functionality of [the `prepare-obi.sh` script in the releases repo](https://github.com/open-telemetry/opentelemetry-collector-releases/blob/145e73e8663aff5ce978ea38cf0cbd4a97017141/scripts/prepare-obi.sh) instead working as an OCB pre_generate hook. Since this feature was inspired by the need to include the OBI receiver in a unique way within OCB, I decided to implement it as part of this POC. In reality, this hook can be created and managed by the OBI SIG to work whatever way makes sense for them, and they can instruct users to use the plugin remotely via the `module` and `version`, rather than the `path` source like I have in the example config.

[Hashicorp Go Plugin]: https://github.com/hashicorp/go-plugin
[POC]: https://github.com/open-telemetry/opentelemetry-collector/compare/main...braydonk:opentelemetry-collector:ocb_plugin_experiment
Loading