FAQ
What is an RRID?
An RRID is the project:kind:maintenance_id:review_id identifier that names a
maintenance request across the SUSE ecosystem — for example
SUSE:Maintenance:12345:678901. It is parsed by splitting on : (empty tokens
dropped, so leading/trailing/doubled colons are ignored) into exactly four
positional components; more than four is rejected, and a missing component is a
parse error. This grammar and its errors are a stable contract with the rest of
the maintenance ecosystem.
Can I set the template directory without passing it every time?
Yes. Set template_dir under [mtui] in your config file, or export
$TEMPLATE_DIR (the built-in default reads it). See
Configuration.
Can I work on several updates at once?
Yes. Load more than one testreport and each is a template in the session:
list_templates shows the loaded set and switch changes the active one. A
command that acts on a template runs against the active one by default
(session-level commands such as list_templates, updates or config take no
template flag); scope it with -T <RRID>/--template <RRID>, or fan out with
--all-templates where the command allows it. Under fan-out each template gets
its own === <RRID> === banner.
Can I run mtui without loading a testreport?
Yes, for the commands that do not need one — notably list_refhosts, which
searches the reference-host inventory offline (no SSH, no lock, no loaded
template). Host-action commands need a loaded template with connected hosts.
Does mtui support SSH password authentication?
No — and it never will. mtui is pubkey-only by design: it authenticates from
your SSH agent or ~/.ssh/id_*. This is preserved from MTUI.
Can several testers use the same reference hosts at once?
Yes, but the locks are advisory and fail-fast, not a queue. Every mtui on the
fleet writes the same timestamp:user:pid[:comment] layout, so sessions see one
another’s claims — a host held by someone else is skipped, and an
install/update aborts with “Hosts locked” rather than waiting. Raise
[lock] wait (default 0) to poll for a busy host during pool arbitration.
There are two locks with that layout: the operation lock
(/var/lock/mtui.lock, PID-based, guards serialized zypper transactions) and the
pool-claim lock (/var/lock/mtui-pool.lock, RRID-based). Stale-lock reaping is
configurable under [lock] — see Configuration.
Where does mtui find the reference-host inventory?
From refhosts.yml, resolved by the ordered [refhosts] resolvers list
(default https,path): the HTTPS database ([refhosts] https_uri, cached with a
https_expiration TTL) and/or a local file ([refhosts] path). The file is
grouped by location on disk, but location is a legacy grouping — rows are merged,
flattened, and de-duplicated at load.
How do I change the editor used by the edit command?
edit spawns your $EDITOR (or $VISUAL) on the controlling terminal, as usual.
Set it in your shell environment. When the loaded report is a JSON document, a bare
edit opens the document editor instead (see the next question); edit FILE always
uses $EDITOR.
How do I fill in a report document by hand?
With a document loaded, edit opens a full-screen form over it, one tab per
section: summary (verdict and comment), people, issues, testing and
review, then update and install, which are read-only. Tab/Shift-Tab
switch sections, Up/Down move, Enter edits a field or opens a group,
Left/Right step an enum or yes/no field, n sets a field to null, Ctrl-S
saves and q/Ctrl-C quits (asking first when there are unsaved changes); ?
lists the keys.
Only the tester’s answers are editable: verdicts, comments, issue
reproducer/status/comment, the reviewer name and the review questions. Fields the
pipeline or export fills in are shown greyed. Every field is checked against the
report schema as you edit it, and Ctrl-S re-checks the whole document; a refusal
leaves the editor open on the offending field.
A save marks the document as edited but not uploaded — commit uploads it, and
unload/regenerate refuse to drop it without --discard-authored. regenerate also
looks at the server’s copy: in the REPL it asks before discarding tester content found
there or in the loaded document, and over MCP it refuses. export keeps the verdicts
and comments you entered under testing.install and testing.regression; it rewrites
only the install checks and the kernel results block inside the regression comment. The
editor needs a terminal on both stdin and stdout.
How do I export results into the testreport?
export authors the collected update data (and, for the openQA-sourced
workflows, openQA data) onto the loaded report document’s testing.* sections and
writes the install logs to the report directory. The document stays local until
commit uploads it. Re-exporting updates the same sections in place.
A Manual export must run from the session that ran update: the before/after
package versions exist only in that process, so from any other session export
refuses rather than write a report with no verdict. --allow-unverified writes
the unverified scaffold anyway.
Where do OBS/Gitea credentials come from?
- OBS/IBS: from your
oscrc, located likeoscitself —$OSC_CONFIG, then$XDG_CONFIG_HOME/osc/oscrc, then~/.oscrc. There is no mtui-side path option; point$OSC_CONFIGat a non-default file. The API to act against is[obs] api_url. - Gitea: the
[gitea] tokenconfig option. It is treated as a secret — masked as<set>inconfigoutput and sent only in anAuthorizationheader, never logged.
Do I still need osc installed?
No. The QAM review workflow (assign/unassign/approve/reject/comment)
talks to the OBS/IBS API natively — no osc subprocess.
Why does assign/approve go to Gitea when I expected OBS (or vice versa)?
mtui decides per update, from the loaded report document, not from the
RRID: an update whose document’s workflow is gitea is Gitea-served, otherwise
it is OBS-served. This matters because the RRID’s shape
cannot answer the question during the SL-Micro 6.0/6.1 cutover — both workflows
share the SLFO:1.1 id space, and an update can briefly be served both
ways at once. When that happens mtui always drives the Gitea workflow and
leaves that update’s OBS review request alone — assign/unassign/
reject/comment/approve never touch it. If an update’s OBS request looks
stuck open, check whether its report document’s workflow is gitea; if so,
that is expected, not a bug.
How do I install packages the update newly introduces?
Feature updates often add packages that only exist in the test-update repository,
so prepare can’t install them yet. Run update --newpackage to install the new
packages right after the update applies.
Why does prepare (or update) refuse to run?
When the loaded report’s metadata names no package versions, prepare and
update refuse with an error rather than reporting prepare completed on <hosts> over a no-op that installs nothing (#396). Check
list_packages -w and the report metadata; a host the fan-out cannot build a
command for (unresolvable release, no matching template) likewise fails the
run by name.
How do I control what prepare installs?
prepare has three switches:
prepare -f/--force— force installation even on package conflicts.prepare -i/--installed— narrow the package list to what each host already carries (skip pulling in additional patchinfo packages). Each host still installs its own list in a single transaction.prepare -u/--update— enable the test-update repositories and install from there.
Independently of those switches, on a report whose metadata carries a
binaries block the list is narrowed per host to what that host’s products
actually compose (base product plus addons). A host whose products compose
none of the list is failed by name rather than sent a list zypper will refuse
with “capability not found” (104); a host no product of which the metadata
names keeps the full list and logs a warning. An architecture a product
declares but the binaries block never mentions at all composes nothing
rather than falling back to the full list — it is treated as known-and-empty,
not unknown, so it gets the same named refusal as any other host whose
products compose none of the requested packages.
update’s own prepare narrows the same way, and a host it refuses is left out
of the patch — no prepare ran on it, so there is no package baseline to patch
— and named in the update’s error instead of being patched anyway. update’s
own operation lock, repository add/remove and pre/post package version check
are scoped to the hosts that actually compose it, so a refused host draws none
of them either: it cannot contend the group’s lock, have its repository
configuration changed, or block a composing peer’s patch behind its own
unresolvable updater.
Can I run a command on only some of the connected hosts?
Yes — temporarily disable the rest with set_host_state, then re-enable:
set_host_state -t hostA -t hostC disabled
run zypper lr # runs only on the still-enabled hosts
set_host_state enabled # re-enable all
disabled hosts run nothing (and print nothing).
Can I export the update log from a specific refhost?
Yes: export -t <host>. By default export writes the collected data for every
host in the list — including disabled ones — so to keep a temporarily-added host
out of the report, remove_host -t <host> before exporting.
Why doesn’t put *.rpm upload anything?
Inside the REPL nothing expands the *, so put looks for a file literally
named *.rpm and errors with File *.rpm not found. That is deliberate, not
a gap (#399): put pushes to
every enabled refhost in the group, which is exactly where an over-broad
pattern does damage, so mtui refuses to guess how wide a pattern was meant to
be. To upload several files, put the directory containing them (it is
walked recursively), or expand the glob in your own shell before invoking
mtui.
Where are the per-host install logs stored?
Under the loaded report’s directory, in
template_dir/<RRID>/install_logs/<host>.log (one file per refhost). The
install_logs sub-directory name is configurable under [mtui]; see
Configuration.
What does Ctrl-C do?
It depends on whether a command is running.
At the prompt, Ctrl-C clears the line you were typing and reprompts. It never
exits mtui — use quit, exit, or Ctrl-D for that, so the session’s hosts are
unlocked and closed on the way out.
While a command is running, the first Ctrl-C asks it to stop at its next checkpoint. Every path releases the hosts’ operation locks on the way out, so nothing is left behind — but how soon the command stops depends on where its checkpoints are:
updatechecks between its steps, and for the last time just before the point of no return: once the patch command has been dispatched the update runs to its end (rolling back on failure) rather than leaving a half-applied update behind.prepare --installedchecks before and after its installed-package probe, and stops without installing anything;downgradeon non-transactional hosts checks between packages. A transactional (SL-Micro)downgradeapplies in one transaction, so it finishes first like the commands below.- A command applying to several loaded templates stops at the next template boundary, and reports how many it got through.
install,uninstall,run, andrebootfinish the host operation already under way first, then stop.
A command that did stop at a checkpoint reports error: cancelled, naming what
it completed first where it can. A command with no checkpoint left to reach
simply finishes and reports normally — the cancel arrived too late to change
anything, and saying “cancelled” would be a lie about work that was in fact done.
Two long waits are their own case: request_review --watch and regenerate
stop watching and tell you so (the review request stays posted, the
regeneration keeps running on the server), and both count as success. Either
way the session stays usable — the next command starts with a clean slate.
A second Ctrl-C force-quits (exit status 130). This is the escape hatch for a host that has stopped responding, and it comes at a cost: the running command is abandoned where it stands, so the operation locks it holds are left behind. Your command history is still saved. mtui warns when this happens; see the next entry for the cleanup.
Ctrl-C during the teardown behaves the same way but cancels nothing: the
teardown is what releases the pool claims and closes the hosts, so it always runs
to completion. A press there warns that it is in progress, and a second one
force-quits — leaving both the operation locks and the pool claims
(unlock --force and unlock --pool). This holds however you asked to leave:
Ctrl-D and a typed quit/exit dispatch the same teardown and get the same
protection.
Two carve-outs. Ctrl-C during the initial load at startup (-a/-k/--sut,
before the first prompt appears) still exits immediately, without teardown. Any
locks or pool claims that partial load had already taken need
unlock --force/unlock --pool, as after any crash.
And in a non-interactive (piped) session — mtui reading commands from a pipe
rather than a terminal — there is no line editor holding the keyboard, so a
Ctrl-C arriving between commands is queued and then discarded when the next
command starts: it interrupts nothing. Interrupt such a session with a signal to
the process (kill -INT) while a command is running, or kill it outright.
How do I remove a dangling lock left by a crashed session?
Reconnect to the same hosts and run unlock -f (force) to remove locks left by
another user or session. mtui also reaps locks older than [lock] stale_age
automatically on connect (see Configuration); unlock -p
removes a pool-claim lock instead of the operation lock.
Which update should I pick up next?
updates lists the queue live from the TeReGen API, sorted by priority. By
default it shows the actionable pickup queue — unassigned updates that are in
testing. Widen or filter it:
updates --review-group qam-sle --limit 5
updates -G qam-sle -G qam-teradata # groups OR together
updates --mine # updates assigned to you
updates --status all # every status and assignee
updates -F Rating -F 'Assigned Roles' -F 'Unassigned Roles' # osc-qam field names
updates --json # the raw TeReGen rows, for scripting
-F accepts the field names osc qam list -F uses — case-insensitively, with
spaces, hyphens and underscores treated as equivalent: ReviewRequestID,
Incident Priority, Rating, Category, Status, Kind, Deadline,
Assignee, Assigned Roles, Unassigned Roles, Title, URL, Products,
SRCRPMs, Bugs, Creator. Fields the
TeReGen queue listing does not carry (Package-Streams, Issues, Comments) are named in the error
rather than silently absent. Unassigned Roles renders n/a when it cannot
be answered honestly: on SLFO rows (TeReGen does not expose review groups on
them) and on any row served without assignment data, where “every group open”
would be indistinguishable from the truth. --json and -F are mutually
exclusive, and Assignee/Assigned Roles are refused under --status all,
where TeReGen omits the assignment data they would render.