A central library of runtime StreamDevice support patterns. Each pattern is a
self-contained set of StreamDevice files (protocol, EPICS DB/template and the ibek
support definition that wires them up) that an IOC instance can vendor at a pinned
version using ibek pattern.
Vendoring copies a pattern's files into an IOC instance's config/ directory and
records exactly which version was taken, with per-file integrity hashes. The IOC then
loads that device support at runtime, with no image rebuild — the generic
ioc-streamdevice image already ships StreamDevice; this repo only supplies the
per-device protocol/DB/support files.
This repo is consumed by the ibek pattern subsystem in
epics-containers/ibek. It is one of two
central pattern libraries; its sibling
ibek-runtime-support
holds non-StreamDevice runtime patterns (extra entities/DB for otherwise-generic IOCs).
A pattern is a top-level folder named after the pattern. The folder name is the pattern name used on the command line.
A pattern holds an arbitrary file-set, not a fixed triplet. The only required
member is the ibek support definition; everything else is whatever that definition
references:
| File | Role | Required |
|---|---|---|
*.ibek.support.yaml |
ibek support module: declares the entity_models, their parameters, and which DB/template files to instantiate |
yes |
*.proto |
StreamDevice protocol file(s) | typical |
*.template / *.db |
EPICS database/template instantiated by the entity | typical |
*.req |
autosave request file(s) | optional |
*.pvi.device.yaml |
PVI device descriptor (UI/PV generation) | optional |
| anything else the support yaml references | … | optional |
There is no hard-coded proto/template/support shape. The vendoring lock simply hashes a file list, so it already generalises to any combination of the above (or files not yet invented). Add the files your support yaml needs and they are vendored together as a unit.
This repo provides StreamDevice patterns for many devices, each a top-level folder
auto-generated from the device's DLS XMLbuilder support module (etc/builder.py +
its StreamDevice protocol and EPICS template). The lakeshore340 pattern is the
worked example of the file-set:
lakeshore340/
lakeshore340.ibek.support.yaml # entity_model "lakeshore340", parameters, databases:
lakeshore340.proto # StreamDevice protocol
lakeshore340.template # EPICS records
The extracted device files are stored PRISTINE. The .proto/.protocol and
.template/.db files are copied byte-for-byte from their DLS production support
module and must stay identical to it (that is what lets us diff them against future DLS
releases). They carry no provenance header.
The repo-authored *.ibek.support.yaml is the one exception: because we generate it
here (it is not extracted), it may begin with a short DLS-source provenance comment —
the originating module, version and /dls_sw/prod/... path — recording where the
pattern came from. That comment is static and deterministic, so it does not affect
consumer-side hashing.
Either way, the consumer-side vendor header below must never be committed here.
When ibek pattern vendors a file into an IOC instance, it injects a deterministic
provenance header as the first line before hashing:
# Vendored from github.com/epics-containers/ibek-runtime-streamdevice@v0.1.0 — DO NOT EDIT
(note: em dash —). Because the header is added at vendor time and is part of the
content that is hashed into the instance's lock file, integrity checking on the
consumer side is a trivial sha256(file_as_written) == lock. The header is
deterministic (no timestamps or absolute paths) so it is reproducible.
Do not commit this vendor header here. It is a consumer-side artifact: it is added
at vendor time and the header you see in a vendored copy belongs to the IOC instance,
not to this library (distinct from the static DLS-source comment described above, which
the support.yaml may carry).
Releases are cut as repo-wide semantic-version git tags (v0.1.0, v0.2.0, …). A
tag is an immutable point covering every pattern in the repo at that revision, so
name@<tag> always resolves to the same bytes.
There is intentionally no per-pattern version: a single tag versions the whole library. Bump the tag when any pattern changes; consumers opt in to the new content by moving their pin.
On the consumer side, Renovate tracks the pin using
the github-releases datasource and raises a PR to bump the pinned version when a
new tag is published, keeping IOC instances current without manual edits.
All consumer commands run against an IOC instance directory (services/<instance>/
in a services repo). ibek pattern writes the vendored files into the instance's
config/, and writes runtime-lock.yaml + ioc.schema.json at the instance root
(not in config/, which is the ≤ 1 MiB K8s ConfigMap and holds runtime inputs only).
Qualified name <library>:<pattern>@<tag> selects the library, pattern and version:
ibek pattern add ibek-runtime-streamdevice:lakeshore340@v0.1.0 services/bl01t-ea-lake-01This:
- fetches the pattern's file-set at tag
v0.1.0, - writes each file into
services/bl01t-ea-lake-01/config/with the vendored header, - records
version,sourceand a per-filesha256inservices/bl01t-ea-lake-01/runtime-lock.yaml, - merges the pattern's entity models into the instance's
services/bl01t-ea-lake-01/ioc.schema.jsonand pointsconfig/ioc.yaml's first line at it (# yaml-language-server: $schema=../ioc.schema.json).
You then reference the entity in config/ioc.yaml (the entity type is
<module>.<entity_model>, here both are lakeshore340):
entities:
- type: lakeshore340.lakeshore340
P: BL01T-EA-TEST-01
PORT: p1
ADDR: 12
LOOP: 2
SCAN: 5
TEMPSCAN: 2
name: lakeshoreThe resulting runtime-lock.yaml looks like:
version: v0.1.0
source: github.com/epics-containers/ibek-runtime-streamdevice
files:
config/lakeshore340.ibek.support.yaml: "sha256:…"
config/lakeshore340.proto: "sha256:…"
config/lakeshore340.template: "sha256:…"(a hash value may be "DIRTY # <reason>" for a deliberately locally-modified file).
ibek pattern update lakeshore340 services/bl01t-ea-lake-01 -v v0.2.0
# or update every pinned pattern to its latest resolvable version:
ibek pattern update services/bl01t-ea-lake-01ibek pattern check services/bl01t-ea-lake-01Re-hashes each vendored file and fails if it drifts from runtime-lock.yaml. Allow
intentional local edits with --allow-dirty (or IBEK_ALLOW_DIRTY=1); such files must
be marked DIRTY in the lock.
ibek pattern restore lakeshore340 services/bl01t-ea-lake-01 # one pattern
ibek pattern restore services/bl01t-ea-lake-01 # all patternsRewrites the vendored files from the locked version, discarding local edits.
ibek pattern schema services/bl01t-ea-lake-01The vendored files are generated into their runtime locations (proto/DB placement) by
ibek runtime generate2 <config-dir>when the IOC starts, so the pattern's StreamDevice protocol and DB end up where the IOC loads them from.
lakeshore340 also exists in
epics-containers/ibek-support. The
two are different delivery paths for the same device, and must not silently
diverge:
- This repo (runtime path) is canonical for runtime vendoring. Patterns are
vendored into an instance at a pinned version and loaded by a generic
ioc-streamdeviceimage with no image rebuild. There is noinstall.ymland no compilation step — just protocol/DB/support files. ibek-support'slakeshore340is the build-time / compiled path. It carries aninstall.ymland is baked into a purpose-built container image at build time.
When you change lakeshore340 device support (protocol, records, or parameters), apply
the equivalent change to both repos, or explicitly document why they differ.
Treat them as two views of one device and keep them in step.
Not every DLS StreamDevice module can take the runtime path: some need a module-specific
compiled library, .dbd, or SNL sequencer program that the generic
ioc-streamdevice image does not ship, so they are build-time-only. Those modules — and
the test used to tell them apart — are listed in BUILD-TIME-ONLY.md.
- Create a top-level folder named after the pattern, e.g.
mydevice/. - Drop in the file-set:
mydevice.ibek.support.yaml— theibeksupport module (module name, one or moreentity_modelswith their parameters, and adatabases:list referencing the template/DB files),- the
*.proto,*.template/*.db, and any other files that support yaml references.
- Keep every file pristine — no vendored header (that is added by
ibek patternat vendor time). - Validate locally by vendoring into a scratch IOC instance:
ibek pattern add ibek-runtime-streamdevice:mydevice@HEAD <instance>(or test against a branch) and runibek pattern check. - Open a PR. Once merged, cut a new semver tag (
vX.Y.Z) so consumers can pin the new pattern; Renovate will then offer the bump downstream.