DUT Configuration

Device under Test (DUT)

This configuration dut.yaml describes every aspect of a DUT. Below are the key components:

Branch scope: Each DUT belongs to a single branch of the project (see the Branches reference), alongside that branch’s workflows and storage. One physical device therefore appears once per branch that uses it, and FirmwareCI knows those entries are the same hardware — see Disabling a Device.

Required Fields

AttributeTypeDescription
namestringUnique name of the DUT. Letters, digits, -, and _, starting and ending with a letter or digit.
labelstringLabel that identifies a group of DUTs. Workflows pick DUTs by this label with runs-on. Same characters as name.
reservation-systemstringHow FirmwareCI reserves the DUT for a job. One of dutctl, virtual, or mock (see Reservation).

Optional Fields

AttributeTypeDescription
attributesobjectAttributes of the DUT.

DUT Attributes

The attributes field accepts any key-value combination to describe properties of your DUT. Common attributes include host addresses, port numbers, hardware capabilities, or any device-specific configuration.

These attributes can be referenced in test files using the attributes templating syntax: [[attributes.KeyName]]. This allows tests to access DUT-specific configuration without hardcoding values.

Values must be strings, so quote numbers and booleans (Port: "22"). Attribute names are case-sensitive and must not contain - or !. Some reservation systems require certain attributes (see Reservation).

For complete details on templating syntax, see Templating and Variables.

Note: Attributes are stored and shown in plain text. Do not put passwords or tokens into attributes. Use secrets in the test instead.

Example

name: Board-1
label: board
reservation-system: dutctl
attributes:
  Agent: "lab-pi.local:2024"
  Device: "board-1"
  Host: "board-1.lab"

Reservation

Before a job starts, FirmwareCI reserves a DUT so that nothing else can use the hardware during the job. After the post-stage, FirmwareCI releases the reservation, whether the job passed or failed. reservation-system selects how the DUT is reserved:

reservation-systemRequired attributesUse for
dutctlAgent, DeviceReal hardware connected to a dutagent. FirmwareCI locks the device on the agent. See dutctl.
virtual—Virtual DUTs such as QEMU machines. No hardware is locked. See virtual.
mock—Trying out a configuration without hardware. See mock.

The reservation-system value and the attribute names are case-sensitive.

How a Job Gets a DUT

  1. The workflow’s runs-on names a label. FirmwareCI looks for DUTs with this label on the job’s branch. Several DUTs with the same label form a pool, and the job takes the first one that is free.
  2. FirmwareCI reserves the DUT through its reservation system.
  3. The job runs: pre-stage, test stages, post-stage.
  4. FirmwareCI releases the reservation.

If every DUT in the pool is busy, unavailable, or disabled, the job stays Queued, and FirmwareCI tries again every few seconds. There is no time limit: the job waits until a DUT becomes free. The job does not show why it is waiting; the device status does.

If no DUT on the branch has the label, the job fails right away with no DUT exists for label <label> on branch .... Check that runs-on matches the label and that the DUT is defined on this branch.

dutctl

Use dutctl for hardware that is connected to a dutagent. Two attributes are required:

AttributeDescription
AgentAddress of the dutagent as host:port, for example lab-pi.local:2024. http:// is added if no scheme is given.
DeviceName of the device on the agent, as the agent lists it.

The dutctl step uses the same values. FirmwareCI does not fill them in, so template them into each step:

parameters:
  agent: "[[attributes.Agent]]"
  device: "[[attributes.Device]]"

During a Job

  • Before the job starts, FirmwareCI locks the device on the agent and holds the lock as <job-id>@firmwareci.
  • The lock does not block the job’s own dutctl steps. Manual dutctl commands against the device are refused until the job is done.
  • After the post-stage, FirmwareCI unlocks the device. If unlocking fails, the lock expires after about eight hours.

Manual Locks

If someone locked the device manually with the dutctl CLI, FirmwareCI treats the device as busy, and jobs wait. The device page still shows Idle, because it only knows about FirmwareCI jobs. Release a manual lock when you are done. To keep jobs away from a device, disable it instead.

Reachability

The FirmwareCI server locks and unlocks the device, and the job’s dutctl steps run the commands. Both must reach the agent at the address in Agent.

Health Checks

FirmwareCI checks every agent about once a minute. If an agent does not answer three times in a row, or no longer lists the device, the device becomes Unavailable with the reason reservation backend unreachable, and a job that is running on it is aborted. The status clears on its own when the agent answers again.

If locking fails when a job tries to reserve the device, the device page shows the error, for example dutctl lock board-1 at http://lab-pi.local:2024: agent unreachable, and the job tries the next DUT in the pool.

virtual

Use virtual for DUTs that do not need exclusive hardware, such as QEMU machines that the job starts itself. Nothing is locked, and one virtual DUT can run several jobs at the same time. The FirmwareCI server limits how many virtual jobs run at once; further jobs wait in the queue. No attributes are required.

mock

Use mock to try out a configuration without real hardware. Nothing is reserved. Only one mock job runs at a time on the FirmwareCI server; further jobs wait in the queue. No attributes are required.

Device Status

A device that exists is not necessarily one a job can run on. The device list and device page show which of these applies:

StatusWhat it means
IdleFree, and the next matching job may take it.
BusyA job is running on it right now. It frees itself when that job finishes. A manual dutctl lock does not appear here; the device stays Idle (see Manual Locks).
UnavailableFirmwareCI cannot reach the device — usually the agent is stopped or the address is wrong. It checks periodically, so a stopped agent shows up within about a minute, and the status clears itself once the device answers again. The reason is shown on the device page. See Health Checks.
DisabledSomebody deliberately took it out of the pool. See below.

Disabling a Device

Disable a device when you do not want CI to schedule onto it — the hardware is broken and you are tired of watching jobs fail on it, or you want to use the board manually for an afternoon.

Open the device and choose Disable. You are asked for two things:

  • A reason. It is shown to whoever finds the device out of the pool, so write what the next person needs to know (“PSU replaced, waiting for parts”).
  • How long. Pick one of the presets, type your own (90m, 2h, 1d12h), or — as an admin — leave it disabled indefinitely.

To put it back, open the device and choose Enable.

It applies to the hardware, not to one branch

The same physical device is declared once per branch that uses it. Disabling acts on the device, so every one of those entries is covered at once and you do not have to go hunting through branches. The confirmation dialog tells you how many entries are affected before you commit.

For the same reason, disabling is not part of your repository configuration: pushing a change to dut.yaml will not quietly re-enable a device somebody took out of the pool.

A job already running on the device is left alone — disabling is about the next job. If you need the board immediately, abort the running job as well.

Who may disable what

The duration is the permission: a device that comes back on its own is safe for anyone to take, one that does not is an admin’s call.

RoleWith a durationIndefinitely
Organization adminyes, any durationyes
Organization useryes, up to 4 hoursno
Viewernono

A device you disabled can be enabled again by you or by an admin — a colleague cannot pull a board out from under you mid-debug, and only an admin can return broken hardware to the pool.

Devices come back by themselves when the time is up; nothing is left holding hardware because somebody forgot. The record of who disabled it, why, and when it came back is kept.

Optional Files

Pre-Stage

This configuration pre.yaml describes the setup process of a DUT. Below are the key components:

Pre-Stage Required Fields

AttributeTypeDescription
pre-stagearrayList of test step commands (see Commands)

Pre-Stage Example

pre-stage:
  - cmd: dutctl
    name: Flash the provided binary.
    parameters:
      agent: "[[attributes.Agent]]"
      device: "[[attributes.Device]]"
      command: flash
      args: [write, "[[input.Binary]]"]
    options:
      timeout: 10m

  - cmd: ping
    name: Wait for the device to become online.
    options:
      timeout: 4m
    parameters:
      host: "[[attributes.Host]]"

The command names come from the agent’s configuration (see Commands). For a complete pre-stage and post-stage, see Connecting Hardware with dutctl.

Post-Stage

This configuration post.yaml describes the teardown process of a DUT. Below are the key components:

Post-Stage Required Fields

AttributeTypeDescription
post-stagearrayList of test step commands (see Commands)

Post-Stage Example

post-stage:
  - cmd: dutctl
    name: Clean up. Shutdown the DUT.
    parameters:
      agent: "[[attributes.Agent]]"
      device: "[[attributes.Device]]"
      command: power
      args: ["off"]

Common Issues

ProblemSolution
fwci validate reports reservation-system is requiredAdd reservation-system to dut.yaml.
fwci validate reports that Agent or Device is requiredAdd both attributes to dut.yaml, with exactly this capitalization.
Job stays QueuedCheck the device list for the DUTs with the label: they are busy, unavailable, or disabled. Release manual dutctl locks (see Manual Locks).
Job fails with no DUT exists for labelSet runs-on to the label of a DUT on this branch.
Device is Unavailable with agent unreachableStart the agent, fix the host or port in Agent, and make sure the FirmwareCI server can reach it.
Device is Unavailable, but the agent is runningSet Device to the device name the agent lists.
Your own dutctl command is refused while a job runsWait for the job, abort it, or disable the device to keep the next jobs away.