Skip to main content
Set up a Lager Box from Rust, as the lager CLI does. You can:
  • create and delete saved nets, and edit net and box metadata
  • install custom drivers, upload binaries and download files
  • assign USB-serial cables to device definitions, and run diagnostics
A CI job can then build its bench before its tests run, with no Python step. These calls are behind the admin feature, which adds no dependency:

Handle

AsyncLagerBox::admin() returns the same methods for the async client.
The box does not check the box lock on these routes. The lager CLI checks it before it sends a change. Hold lock_guard() around your changes, so that another user’s session cannot interleave with them.

Methods

Saved nets

save_net(record: &NetRecord) -> Result<()>

Create a net, or replace the saved record with the same name and role. NetRecord::new(name, role, instrument) builds a record. Its builder methods set the rest:
A record that nets() returns can be changed and saved back. The crate leaves out the box’s derived live_path, as the CLI does. The box keys a record by name and role. A record with the same name and another role stays beside the new one. To change a net’s role, delete the old record first.

rename_net(old_name: &str, record: &NetRecord) -> Result<()>

Save record in place of old_name. The box deletes every record named old_name, whatever its role, then saves record.

delete_net(name: &str, role: Option<&str>) -> Result<()> and delete_all_nets() -> Result<()>

delete_net with a role deletes only the record with that exact role. Without a role, it deletes every record with that name. An unknown net is Error::Box with HTTP 404.
delete_all_nets() deletes every saved net on the box, and it cannot be undone. If you need to restore them, read nets() first.

Metadata

net_metadata(name: &str) -> Result<NetMetadata>

Read a net’s metadata. This requires box software 0.46.0 or later.

set_net_metadata(name: &str, update: &NetMetadataUpdate) -> Result<NetMetadata>

Change a net’s metadata on every record with that name. A field that the update does not set keeps its value. clear() removes a field.
The box refuses an unknown field name, and a timestamp for a field that the update does not set, with Error::Box and HTTP 400.

box_metadata() and set_box_metadata(description, updated_at)

Read and replace the box description. A write replaces the whole record: None for the description clears it.

Instruments and the bench manifest

instruments() -> Result<Vec<Instrument>>

List the instruments the box sees. Each Instrument has a name for NetRecord::new, an address, the net_type roles it can serve and its channels. The rest of the scanner’s report is in extra. Each call scans the hardware again. To find a robot arm, the scan sends a short handshake to serial ports that no saved net uses.

bench_manifest() -> Result<BenchManifest>

Read the bench manifest, the whole box configuration as one document. This requires box software 0.50.0 or later. The schema belongs to the box, so document holds the JSON. box_id() and schema_version() read two common keys.

Custom drivers

These require box software 0.59.0 or later.

install_driver(driver_type: &str, bundle: &[u8]) -> Result<DriverInstall>

Upload a driver’s zip bundle, and replace an installed version. The box installs the Python packages that the manifest declares. That can take minutes, so the call waits up to 6 minutes.
A box older than 0.60.0 installs no Python packages. If the bundle declares packages, check status()?.capabilities.custom_driver_deps first. The box refuses an oversized bundle with HTTP 413, and a pip run past 300 seconds with HTTP 504.

drivers(), driver(type), reinstall_driver_deps(type) and remove_driver(type, force)

drivers() returns a DriverEntry per driver. Each entry has its status, version, deps and the nets that use it. A driver that does not load has status: "error" and an error message. remove_driver() without force fails with HTTP 409 while saved nets use the driver. The message names the nets. With force, the box removes the driver, and orphaned_nets lists the nets that lost it.

Binaries and files

add_binary(name: &str, data: &[u8]) -> Result<BinaryAdded>

Upload an executable into the box’s binaries directory, and replace a file with the same name. restart_required is true when the container needs a restart to see the file. lager update does that restart. binaries() lists the directory, and remove_binary(name) deletes a file.

download_file(path: &str) -> Result<Vec<u8>>

Download a file that a script left on the box, as bytes.
The box serves only files under /tmp/lager-output, /tmp/lager-results and /tmp/lager-job-output. Any other path is Error::Box with HTTP 403. download_file() has no client-side timeout. download_file_with_timeout(path, Some(duration)) sets one.

Custom devices

custom_devices() -> Result<CustomDevices>

List the device definitions the box knows (catalog), the current assignments, and the USB-serial cables that have no assignment. The box scans the cables, which takes seconds.

assign_custom_device(instrument: &str, cable: &CableId, baud: Option<u32>) -> Result<DeviceAssigned>

Assign a USB-serial cable to a device definition. CableId names the cable:
Use CableId::PortPath("1-1.4".into()) for a cable with no serial, or one that shares its serial with another cable.
An assignment deletes the saved nets that it makes stale, and the generic UART nets on the same cable. deleted_nets lists them.

remove_custom_device(cable: &CableId) -> Result<DeviceRemoval>

Remove a cable’s assignment and the saved nets that use it. A cable with no assignment returns removed: false, not an error.

Diagnostics

The checks behind lager diagnose. Each result gives typed fields for the common facts, and an extra map for the rest of the box’s report. The crate URL-encodes the address. A failed or skipped VISA probe is data, not an error: error, error_class and skipped say what happened.
Do not call diagnose_jlink() during a flash. It can connect to the target, and it can take over 30 seconds.

Older boxes

A route that the box does not serve fails with Error::UnsupportedByBox. Where a version is known, the message names it. A refusal that the route explains, such as an unknown net, is Error::Box with the box’s message.

Example: build the bench in CI, then test