System, health and settings
GET /healthz
Liveness plus the running version. Also served on the plaintext listener. The update flow polls this until the target version answers.
curl -sk https://appliance:8443/healthz
{"ok": true, "ts": "2026-09-01T07:12:04.118Z", "version": "v1.0.0"}
GET /api/status
The whole live picture in one document: every library with its drives, slots, and cartridges; every pool’s statistics; FC target state; and an aggregate fabric summary. The UI polls this and applies the event stream on top. It is the first thing to read when a caption in the UI is vague.
curl -sk https://appliance:8443/api/status -H "Authorization: Bearer $OVTL_KEY"
{
"updated_at": "2026-09-01T07:12:03Z",
"libraries": [
{
"library": {"id": 10, "product": "3573-TL", "serial": "OVTL280164", "home_dir": "/var/lib/openvtl/pools/prod", "num_slots": 100, "num_ie": 4, "num_drives": 2, "changer_sg": "/dev/sg3", "live": true, "name": "PROD-VTL"},
"drives": [
{"index": 0, "library": 10, "queue_id": 11, "serial": "OVTD280164A", "product": "ULT3580-TD5", "sg": "/dev/sg4", "st": "/dev/st0", "loaded": "OVB003L5", "source_slot": 3, "activity": "writing", "blocks_written": 1845210, "blocks_read": 0, "last_active": "2026-09-01T07:12:02Z"}
],
"slots": [
{"kind": "storage", "num": 1, "label": "OVB001L5"},
{"kind": "storage", "num": 2, "label": "OVB002L5"},
{"kind": "storage", "num": 3, "label": ""},
{"kind": "ie", "num": 1, "label": ""}
],
"cartridges": [
{"label": "OVB001L5", "library": 10, "size_bytes": 267421859840, "phys_bytes": 171798691840, "modified": "2026-08-31T00:14:20Z", "location": "slot:1"}
]
}
],
"pools": [
{"name": "prod", "mountpoint": "/var/lib/openvtl/pools/prod", "fs_total_bytes": 3408486400000, "fs_used_bytes": 622770257920, "logical_bytes": 7696581394432, "dedup_ratio": 9.31, "compress_ratio": 1.46, "record_bytes": 16384, "phys_est_bytes": 66892600000, "zpool_size_bytes": 3408486400000, "zpool_alloc_bytes": 622770257920, "collected_at": "2026-09-01T07:12:00Z"}
],
"fc": {"target_wwn": "", "verified": true, "no_hba": false, "detail": "fc: 2 port(s), 3 LUNs identity-verified, ACLs reconciled", "verified_at": "2026-08-31T00:05:41Z"},
"cartridges": [
{"label": "OVB001L5", "library": 10, "size_bytes": 267421859840, "phys_bytes": 171798691840, "modified": "2026-08-31T00:14:20Z", "location": "slot:1", "local_state": "resident", "last_export_gen": "20260831T001507Z"}
],
"fabrics": {"fc": {"present": true, "verified": true, "detail": "fc: 2 port(s), 3 LUNs identity-verified, ACLs reconciled", "sessions": 2}}
}
| Field | Meaning |
|---|---|
libraries[].library.live |
The changer device is present and being polled. A library declared but not yet activated shows live: false with empty drives and slots. |
libraries[].library.product |
The emulated model’s wire identifier: 3573-TL is TS3100/TS3200 (3573); 03584L32 is TS3500 (3584). |
drives[].activity |
idle, reading, writing, or mounting. Counters are since boot. |
cartridges[].location |
slot:N, ie:N, drive:N, or missing. |
cartridges[].local_state |
resident or evicted (a labelled stub with no data on disk). |
pools[] |
Per-pool ZFS figures. logical_bytes is what the host wrote; phys_est_bytes is the pool’s estimated share of real disk after global dedup; zpool_* figures are the shared system pool and repeat on every entry. Older vdo_* fields remain for shape stability. |
fc.target_wwn |
Always empty: every serving port presents the same LUN table. Per-port WWNs are in GET /api/targets. |
fabrics.fc.sessions |
Live initiator logins across all ports. |
GET /api/library
An older, smaller shape: {"libraries": [...]} with the same per-library
objects as /api/status but without display names or the
cartridge state join. Prefer /api/status.
GET /api/system
{
"version": "v1.0.0",
"started_at": "2026-08-31T00:05:12Z",
"uptime_sec": 112012,
"active_jobs": 1,
"plain_listener": ":8080",
"draining": false,
"apikeys_enabled": true,
"system_name": "demo01",
"system_uuid": "5f2c1c8e-0d0a-4d1e-9b7a-2f9f5f0c1a11"
}
plain_listener is empty when the plaintext port is disabled.
system_name is the first segment of this appliance’s keys in an S3
bucket; system_uuid is its stable backstop.
POST /api/system/restart
Restarts the control plane only. The tape emulator, the FC target, and host I/O do not notice.
| Body field | Values |
|---|---|
confirm |
"restart", required. |
mode |
graceful (default) waits for active jobs to finish, up to 30 minutes, and refuses new job-creating calls with 409 meanwhile. immediate restarts now; interrupted jobs become retryable and exports resume from their chunk ledger. |
curl -sk -X POST https://appliance:8443/api/system/restart \
-H "Authorization: Bearer $OVTL_KEY" -H 'Content-Type: application/json' \
-d '{"confirm":"restart","mode":"graceful"}'
With no jobs active, either mode restarts within a second and returns
200 {"ok": true, "detail": "restarting now"}. With jobs active,
graceful returns 202 {"ok": true, "draining": true, "active_jobs": 1, "detail": "…"} and the restart fires once the queue is empty. A second
graceful request while one is draining is a 400.
POST /api/system/dataplane-restart
The wedged-daemon recovery sequence: restarts the tape emulator and
rebuilds the FC target fabrics. Every host session drops. Vary the
host’s tape devices off and on afterwards. Refused with 400 while any
job is active or queued, and with 409 while a graceful restart is
draining. The steps stream on the event bus as maint_step events, and
any library that comes up live is marked active.
curl -sk -X POST https://appliance:8443/api/system/dataplane-restart \
-H "Authorization: Bearer $OVTL_KEY" -H 'Content-Type: application/json' \
-d '{"confirm":"restart"}'
{
"steps": ["stopped mhvtl.target", "flushed IPC queues", "started mhvtl.target", "discovery settled: 3 sg devices", "fc: 2 port(s), 3 LUNs identity-verified, ACLs reconciled"],
"fc": {"OK": true, "Detail": "fc: 2 port(s), 3 LUNs identity-verified, ACLs reconciled"}
}
The steps strings are human-readable and change between releases; do
not parse them. A failed sequence is a 500 carrying the steps that
completed.
POST /api/system/reboot
Reboots the appliance. Host sessions drop; boot orchestration restores pools, daemons, and targets; active jobs are interrupted and become retryable. The response is sent before the reboot fires.
curl -sk -X POST https://appliance:8443/api/system/reboot \
-H "Authorization: Bearer $OVTL_KEY" -H 'Content-Type: application/json' \
-d '{"confirm":"reboot"}'
{"ok": true, "detail": "rebooting — boot orchestration restores pools, daemons and targets; interrupted jobs become retryable"}
GET /api/system/support-bundle
Streams a redacted diagnostics archive (application/gzip,
Content-Disposition: attachment) for support: logs, status, storage
state, FC state, non-secret settings, recent events and audit entries.
It never contains the database file, S3 credentials, password or key
hashes, or session tokens. Admin-only even though it is a GET;
downloading it is audited as support.bundle.
curl -sk -OJ https://appliance:8443/api/system/support-bundle -H "Authorization: Bearer $OVTL_KEY"
GET /api/license
The support key: a fingerprint derived from the machine’s durable identity, shown in Settings and given to support to link the appliance to an account. Nothing is uploaded.
{"fingerprint": "OVTL-XXXXX-XXXXX-XXXXX-XXXXX", "changed": false, "previous": ""}
changed becomes true when the key differs from the last acknowledged
one (an OS reinstall or a hardware transfer re-keys the box).
POST /api/license/ack
Records the current key as acknowledged, clearing the change notice.
Returns {"ok": true, "fingerprint": "…"}.
GET /api/settings
The closed set of operator-editable settings. Values are strings.
{
"apikeys.enabled": "1",
"evict.threshold_pct": "",
"export.default_remote": "1",
"export.ie_watcher": "on",
"fc.disabled_ports": "",
"minting.enabled": "",
"nag.no_offsite_dismissed": "",
"system.name": "demo01"
}
| Key | Meaning |
|---|---|
apikeys.enabled |
"1" honours API keys; anything else ignores them. |
export.ie_watcher |
"on" auto-exports a cartridge the host ejects to the import/export slot and returns it to its slot once the upload verifies. Default off. |
export.default_remote |
Remote id the watcher and eviction policy use. |
evict.threshold_pct |
Pool fill percentage above which exported cartridges are evicted automatically. Empty disables. |
fc.disabled_ports |
Comma-separated port WWNs excluded from serving. Normally managed by PUT /api/targets/ports. |
system.name |
This appliance’s name in S3 keys: 1 to 32 characters, lowercase letters, digits, -, _, starting with a letter or digit. |
minting.enabled |
Reserved; no effect in v1.0.0. |
nag.no_offsite_dismissed |
"1" hides the dashboard’s no-remote warning. Cleared when the last remote is deleted. |
PUT /api/settings
Sets one or more keys. Unknown keys are refused with 400 and nothing
is written. Returns the full settings map.
curl -sk -X PUT https://appliance:8443/api/settings \
-H "Authorization: Bearer $OVTL_KEY" -H 'Content-Type: application/json' \
-d '{"export.ie_watcher":"on","export.default_remote":"1"}'
GET /api/models
The emulation catalog behind the create-library form: library models
with their variants, and drive models with the barcode suffix and
native capacity a minted cartridge takes. Only entries with
creatable: true can be created; ibmi_compatible marks what has been
validated against IBM i. The catalog also lists frames the emulator
recognises but cannot create.
{
"libraries": [
{"vendor": "IBM", "display": "TS3100/TS3200 (3573)", "variants": [{"product": "3573-TL", "family": "LTO", "display": "3573-TL", "creatable": true}], "ibmi_compatible": true, "creatable": true, "max_drives": 4},
{"vendor": "IBM", "display": "TS3500 (3584)", "variants": [{"product": "03584L32", "family": "LTO", "display": "3584-L32 (LTO base frame)", "creatable": true}, {"product": "03584L52", "family": "LTO", "display": "3584-L52 (LTO base frame)", "creatable": false}], "ibmi_compatible": true, "creatable": true, "max_drives": 12}
],
"drives": [
{"product": "ULT3580-TD5", "vendor": "IBM", "display": "IBM LTO-5 (ULT3580-TD5)", "family": "LTO", "density": "LTO5", "suffix": "L5", "capacity_mb": 1500000, "ibmi_compatible": true},
{"product": "ULT3580-TD9", "vendor": "IBM", "display": "IBM LTO-9 (ULT3580-TD9)", "family": "LTO", "density": "LTO8", "suffix": "L8", "capacity_mb": 18000000, "ibmi_compatible": true}
]
}
Abridged: the real response lists LTO-3 through LTO-9 and the other frames the emulator knows.