NAME
qemu-monitor-command - send QEMU guest-agent commands to a zone-hosted VM
SYNOPSIS
/opt/omnicube/sbin/qemu-monitor-command -z zone [options]
qemu-monitor-command -z|--zone zone [-c|--command command] [-j|--json json] [--arguments.key value ...] [-f|--format] [-d|--debug] [-e|--expect|--no-expect]
DESCRIPTION
qemu-monitor-command talks to the QEMU guest agent (org.qemu.guest_agent) running inside a guest hosted by an OmniCube zone, and prints the agent's raw JSON reply on standard output. It is the low-level building block used by manage_zone.sh(8) and by the zone monitors to query or control a guest without going through the guest's network stack.
The command name given with -c is normalised by stripping a leading guest- prefix, then wrapped in a QMP-style request object:
{"execute":"guest-<command>"}
{"execute":"guest-<command>","arguments":<json>}
With no -c the request defaults to guest-info.
Socket discovery
The agent socket is not configured directly; it is derived from the zone configuration read with zonecfg(8). The zone path comes from zonecfg -z zone info zonepath, and every candidate socket path is built as zonepath/root followed by the trailing component of the attribute value (the text after the last , or = in it). Candidates are produced in priority order:
A zone should expose exactly one guest-agent socket. When both candidates exist the query still succeeds, but the ambiguity is reported on standard error, naming the socket that was used and the ones that were ignored, so that standard output stays parseable JSON.
Socket selection
Before anything is sent, the zone must be running: this is checked with zoneadm -z zone list -v filtered through the GNU grep at /usr/bin/ggrep. For an ordinary command the candidates are then tried in order and the first non-empty reply wins, which is how a dead socket is skipped.
That heuristic cannot work for the silent commands listed in SILENT_COMMANDS: shutdown, suspend-disk, suspend-ram and suspend-hybrid. These return nothing even on success, so "no output" would cause the request to be delivered to every candidate in turn. For them the live socket is selected with a bare {execute:guest-ping} probe instead - sent without the caller's own arguments, since guest-ping accepts none - and a candidate is accepted only when the whitespace-stripped reply is exactly {return:{}}. The real command is then sent to that socket, once. If it produces output (the agent objected to it) that output is printed; otherwise the ping reply is printed, which is the normal silent success.
Transports
Two transports can carry the request, both reaching the socket through pfexec:
The transport is autodetected: expect is used when both /opt/ooce/bin/expect and /usr/bin/socat exist as regular files, plain socat otherwise. -e and --no-expect pin the choice, and are resolved after option parsing so the option always wins over what happens to be installed. A pinned transport whose binaries are missing is a fatal error rather than an empty reply that would look like an absent guest agent.
OPTIONS
EXAMPLES
Example 1: query the agent and the guest OS
qemu-monitor-command -z win2022 -f qemu-monitor-command -z win2022 -c get-osinfo -f
Example 2: freeze filesystems before a snapshot
qemu-monitor-command -z sql01 -c fsfreeze-freeze qemu-monitor-command -z sql01 -c fsfreeze-thaw
Example 3: a silent command with dot-notation arguments
The socket is selected by a guest-ping probe first, then the shutdown request is delivered to it exactly once:
qemu-monitor-command -z win2022 -c shutdown \\
--arguments.mode powerdown
Example 4: equivalent literal-JSON form, with tracing
qemu-monitor-command -z win2022 -c shutdown \\
-j '{"mode":"powerdown"}' -d
DIAGNOSTICS
Errors that concern the zone or the agent are reported on standard output as a JSON object so that a calling script can parse success and failure the same way:
{"error":{"class":"QA_CMD","desc":"<zone>: <message>"}}
Usage errors, invalid names, missing transport binaries, the --json override warning and all -d tracing are plain text.
EXIT STATUS
FILES
ENVIRONMENT
SECURITY
The socket lives under a root-owned zone path, so both transports are invoked with pfexec; the required uid=0 entries for /usr/bin/socat and /opt/ooce/bin/expect are part of the OmniCube Administration profile. Because that interpreter runs privileged, the zone name and command name are constrained to their real character sets before use, and the socket path and payload are passed to expect through the environment rather than being interpolated into the Tcl script: brace quoting in Tcl ends at the first unbalanced }, so an interpolated payload containing that character would be evaluated as code by a process running as root. Note that granting the OmniCube Administration profile is root-equivalent, precisely because it includes socat and expect.
SEE ALSO
omnicube_utils(3), omnicube(7), manage_zone.sh(8), restart_windows_server(8), shutdown_windows_server(8), zone_monitor.sh(8).
NOTES
The value given to -j is inserted into the request without being parsed, so malformed JSON reaches the agent and is rejected by it, not by this command.
Ordinary commands are tried against each candidate socket in turn, which means a command that legitimately returns nothing and is not in SILENT_COMMANDS would be delivered more than once; add such a command to that list rather than relying on the reply heuristic.
The expect transport gives up on a socket after two seconds, so a guest whose agent is alive but slow to answer (a freeze under load, for example) can look like a dead socket.