ampbase

OPAMP CONTROL PLANE

Documentation

Configurations

A configuration is the YAML or TOML your agent normally reads from disk — Ampbase just becomes the canonical place to author, version, and roll it out. Every channel holds a list of configurations, each tied to an agent type.

Versioning is automatic

Every save creates a new immutable version with a ULID. Versions are append-only — nothing is ever overwritten. That means:

  • You can compare any two versions side-by-side from the UI.
  • Rollback is a deploy of an earlier version.
  • The full edit history (who, when, why) is in the audit log.

A configuration has two version pointers:

  • Current version — the latest edit. May or may not be running anywhere.
  • Deployed version — the version agents are actually pulling.

Editing changes the current version. Deploying changes the deployed version. They diverge intentionally while you stage a change.

Deploy is the verb

The deploy action sets the deployed version. After deploy:

  1. Each connected agent receives the new payload on its next OpAMP message (sub-second on WebSocket).
  2. The supervisor writes it to the agent's config path and sends SIGHUP (or restarts, depending on the agent adapter).
  3. The supervisor runs a post-apply health check, then reports the new config hash back to Ampbase.

If health-check fails, the supervisor keeps the previous config running and reports back as degraded. You see this in the agent's UI row.

Rollouts via feature flags

A plain deploy updates the configuration's deployed-version pointer in one step — fast, but all agents flip at once. For graduated rollouts (canary, weighted, region-by-region), route the configuration through a feature flag instead. The flag evaluates against each agent's attributes and decides which version that agent receives.

You don't need to re-author the configuration to switch between modes — the same versions stay in place; only the routing changes.

Bundles: compose multiple configs

A bundle groups multiple configurations into one deployable unit. Like configurations, bundles version on every save and have a deployed-version pointer; deploying a bundle ships every member atomically, each pinned to whichever version was current when the bundle version was snapshotted. Bundles are scoped to one agent type — the composition is across files, not across agents.

Reach for a bundle when:

  • Your agent reads multiple files. Refinery has both a config file and a rules file; a bundle deploys them together with no window where one side has updated and the other hasn't.
  • You want a base config plus additions. Author one base Config that lives in every bundle, then add a per-deployment Config on top. Edit the base once and every bundle that includes it benefits on its next snapshot.
  • You want Ampbase to manage some files but not others. Leave a file out of the bundle and Ampbase won't touch it on the host — useful when ops keeps one file under direct control (e.g. Refinery's config) while Ampbase manages the other (e.g. rules).

Like Configs, bundles plug into feature flags. A flag variant can target a bundle version, so the same canary / weighted / regional rollout patterns apply — see Feature flags.

Validation

The supervisor pre-validates configurations before applying them on the agent host:

  • otelcol — runs otelcol validate --config <file> and refuses to apply if it errors.
  • vector — runs vector validate with a kill timeout.
  • telegraf — runs telegraf --test --quiet.
  • fluent-bit — YAML pass-through; Fluent Bit catches schema errors on reload.
  • refinery — YAML syntax validation only.

A configuration that fails pre-validation is rejected and the previous config stays in place. The agent row reflects the failure with the validator's stderr so you can see exactly why.

Collector configs are also checked structurally when you save them, so the obvious breakage surfaces in the editor instead of on your hosts. Saving a collector config whose service section wires a component no section defines is refused outright — the collector would not start on it. Deploying one is refused for the same reason, which is what catches a config saved before this check existed: if the version page shows a structural error, setting that version as the channel default is refused too, with the same explanation. A component you define but no pipeline uses is saved and noted on the version page: the collector runs fine that way, but the component still has to exist in the agent's build for the config to load, so an unused definition is worth removing rather than leaving. These checks read one document at a time, so they apply to configs you save and deploy on their own; entries in a bundle are merged before the collector reads them and are checked by the supervisor on the host.

Build requirements and fleet coverage

Validation asks "is this config well-formed?". There's a second question it can't answer: "can the builds in this channel actually run it?" — a config that wires the Kafka exporter is perfectly valid and still won't start on a collector build that doesn't have one.

So every save records what the version requires of a build: every component the config names, in the agent's own vocabulary. For a collector that means everything a section defines as well as everything the service section wires — the collector checks every defined component against the build when it starts, so a component you define but never wire into a pipeline still has to exist in the build for the config to load, and it is counted here. (It also shows up as an unused-definition note when you save; removing it is what shrinks the requirement.) For Fluent Bit, Vector and Telegraf, declaring a plugin is using it, so every declared plugin is required.

The version page shows the set at the top, under Build requirements, together with how much of the channel can run it:

Build requirements                     500 agents in this channel

  exporter/kafka   processor/transform

  480/500 supported   12 missing a component   8 unknown

  exporter/kafka — missing on 12 builds

Unknown is its own number and stays that way. An agent that has never reported its build, or whose enumeration couldn't be read, is neither supported nor missing — it's an agent Ampbase can't describe. It is never folded into either of the other two counts, because failing to prove a component absent isn't evidence that it is. A fleet mid-supervisor-upgrade reads as mostly unknown, and that's the honest answer, not a problem with the version.

Two more states the panel can show instead of a set, both meaning the requirement itself is unknown — never "requires nothing":

  • Requirements could not be derived — the version's content couldn't be read for components (unparseable, or a construct Ampbase can't see through). The stated cause travels with it.
  • Requirements not derived — the version was saved before Ampbase recorded build requirements. Saving a new version records them.

Under either, a gated rollout treats the version as needing confirmation and withholds it rather than assuming it's safe.

One more note you may see on a derived set: that it was recorded under older rules — before Ampbase counted components a config defines but never wires. The set is real, but it can show less than the version requires. Ampbase re-derives those records automatically; the note disappears once it has.

Two known limits, so you're not surprised by them: a Vector configuration written in TOML has no derivable requirements — requirement extraction reads Vector configs as YAML, so a TOML one lands in Requirements could not be derived. And Telegraf's data_format parsers and serializers aren't part of the requirement, because the format name in a plugin table isn't reliably the plugin name in the build; a config using a parser the build lacks fails the way it always has, without a warning here.

Bundles work the same way, with the union of every entry's requirements — and each component is labelled with the entry that requires it, so you know which file to change.

If the channel has telemetry intelligence export enabled, coverage also counts the exporter Ampbase adds to the config at delivery time. That component doesn't appear in your config, but the agent has to have it, so it's part of the requirement.

Coverage is a readout, except in one place

Saving a version is never gated on coverage, at any number. Authoring a config ahead of the fleet is a normal workflow, and a saved version reaches nobody. Pointing a flag variant at it isn't gated either: the component gate makes an all-ineligible variant inert, so there's nothing to acknowledge.

The exception is setting a version as the channel default, and it's the exception for a specific reason: the default is deliberately not gated. Every agent receives it whatever its build can run — that's what makes it a safe fallback — which also makes it the one path nothing protects. So the deploy dialog attaches friction to that action:

  • Partial coverage warns. It states the numbers and proceeds. Agents whose builds can't run it keep their last-applied config.
  • A fleet where nothing has reported warns and never blocks. It states the unknown counts. Unknowns alone never escalate.
  • Zero coverage among agents that have reported requires you to type a phrase — something like deploy without exporter/kafka — and the dialog quotes the measurement it's asking you to acknowledge: "of 500 agents seen: 480 report manifests, none can run this version; 20 unknown". That's a specific claim about your fleet, not a generic are-you-sure. Proceeding means delivering a config the reported builds can't be shown to run. A renamed component doesn't normally trip this — a build reporting a required component under a newer name counts as having it (see Feature flags, under Renamed components are recognized) — so if zero coverage appears right after an agent upgrade anyway, the build may report a rename Ampbase can't match by module; check the agent's release notes before you decide.

The same confirmation applies to setting a bundle as the channel default.

What a build for this channel has to contain

A version page answers "what does this version need". If you build your own agent image — a trimmed collector, say — you need the other question: what does a build for this whole channel have to contain? One version's requirements are not that answer. A channel serves its default to every agent, and each enabled flag variant serves something else to the agents it routes to, so the build has to satisfy all of them at once. Build an image from the default's list alone and every flagged variant that needs anything extra is correctly withheld from those agents the moment you deploy it.

The configurations index answers the whole question, under Build requirements for this channel. It is the union of every active rollout target — the channel default plus every variant of every enabled flag — grouped by agent type, because one image serves one agent type:

Build requirements for this channel     union of every active rollout target

  otelcol   OpenTelemetry Collector — 4 components from 3 targets

  exporter/kafka · base, canary      exporter/loki · loki-trial
  exporter/otlphttp · base, canary, loki-trial, intelligence export
  processor/transform · base

  Plain list
  ┌───────────────────────────────┐
  │ exporter/kafka                │
  │ exporter/loki                 │
  │ exporter/otlphttp             │
  │ processor/transform           │
  └───────────────────────────────┘

Each component names the targets that require it, so you can see what a component is there for before deciding to keep shipping it — and the plain list is the same set with nothing else in it, ready to paste into a build manifest.

Three things worth knowing about what is and isn't in there:

  • Disabled flags are not counted. A disabled flag routes nothing, so building for its variant only makes the image bigger. Re-enable it and the union grows again.
  • The export tap is counted. If the channel has telemetry intelligence export enabled, Ampbase adds an exporter to every config at delivery. It appears in the union attributed to intelligence export, because no config of yours names it and the build still needs it.
  • Agent types whose builds can't be missing a component get no section. There is no build content to derive for them.

A union that couldn't be completed says so. If any active rollout target can't be counted — its requirements couldn't be derived, the version was saved before Ampbase recorded them, or a read failed — the affected build is marked This union is incomplete above the list, and every uncounted target is named under Targets that could not be counted with the reason. An incomplete union can name fewer components than the channel actually demands, so treat the list as a floor rather than the answer until the gap is closed. The one case that isn't a gap: a target whose requirements were derived and are empty — that version genuinely needs nothing of the build.

If a target's requirements were recorded under older derivation rules, the union says that too, in the same words the version page uses — the list is real but can show less than the channel requires until the record is re-derived.

Audit

Every create, save, and deploy emits an event recorded in the channel's audit log — dual-written to both the channel log and the org log so org admins see everything that touched their fleet without crossing channel boundaries.


Spotted a problem with these docs? Email support@ampbase.io.