From nobody Sat May 4 12:30:36 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 216.205.24.124 as permitted sender) client-ip=216.205.24.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 216.205.24.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1631885911; cv=none; d=zohomail.com; s=zohoarc; b=HmxRB2S1Wb4b3GPbSHeIkNxijzzJ6gAEuOf7IvK7nrasx1tkcBiMReNd9elel/VjDuJ5KQRsePEmULFf442DLbmwiFwc6YGTB86bUJLPH57MQajjEJIPx6VNYm/c6UjimCyEh3Ssa581grYcXzYkcbtWp7djkrhxeoYbTPNO7jA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1631885911; h=Content-Type:Content-Transfer-Encoding:Date:From:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Sender:Subject:To; bh=5Ro1oEJgAv91bligcmV/4UBEtxFvrtKIzt4+Qz4D7vw=; b=NYdsA+vdu3czlnhx6fSR+515fhz/TxRsDAuo2LLIYwd1YS8Vd9ckOHogYSGxuMZLHMR7whzBJT/f0J/8dVBWh0rGKhtmcg6iFRBmoVTSsZ/9Y03TUmxTXaoNd1IUlmy7LJ/P3rbY2S9ePXbSvAo27vW5NkrNqBn01olQFs7fYBk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 216.205.24.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by mx.zohomail.com with SMTPS id 1631885911137776.8780070797523; Fri, 17 Sep 2021 06:38:31 -0700 (PDT) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-497-Mr0Smo0kPCKB4GRnGiZ7mQ-1; Fri, 17 Sep 2021 09:38:28 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 176B2100CCC2; Fri, 17 Sep 2021 13:38:23 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E8C7D61140; Fri, 17 Sep 2021 13:38:22 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 8426B4EA37; Fri, 17 Sep 2021 13:38:22 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 18HDZ1sA014018 for ; Fri, 17 Sep 2021 09:35:01 -0400 Received: by smtp.corp.redhat.com (Postfix) id BA17D196F4; Fri, 17 Sep 2021 13:35:01 +0000 (UTC) Received: from speedmetal.redhat.com (unknown [10.40.208.16]) by smtp.corp.redhat.com (Postfix) with ESMTP id 08154196F2 for ; Fri, 17 Sep 2021 13:34:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1631885910; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=5Ro1oEJgAv91bligcmV/4UBEtxFvrtKIzt4+Qz4D7vw=; b=ERBrFp8NVaUZqscG9VHXTXaRabZ9MiQPOuLOWPqXZ4QFh8xEdlYZpozVBWExCOdClQ/rZx v5gHl9YLH8eiO0XQB/zMTjYi0EyoNc58MqZbw+X1ZVbRt4XyhCTTdGLeNyCaCa5MsjyTW4 utIMLYQ+Ey/W3aOaNJpYdxikQTb6MAg= X-MC-Unique: Mr0Smo0kPCKB4GRnGiZ7mQ-1 From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH v2] virsh: Add QMP command wrapping for 'qemu-monitor-command' Date: Fri, 17 Sep 2021 15:34:56 +0200 Message-Id: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-loop: libvir-list@redhat.com X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1631885913012100001 Content-Type: text/plain; charset="utf-8" Issuing simple QMP commands is pain as they need to be wrapped by the JSON wrapper: { "execute": "COMMAND" } and optionally also: { "execute": "COMMAND", "arguments":...} For simple commands without arguments we can add syntax sugar to virsh which allows simple usage of QMP and additionally prepares also for passing through of the 'arguments' section: virsh qemu-monitor-command $VM query-status is equivalent to virsh qemu-monitor-command $VM '{"execute":"query-status"}' and virsh qemu-monitor-command $VM query-named-block-nodes '{"flat":true}' or virsh qemu-monitor-command $VM query-named-block-nodes '"flat":true' is equivalent to virsh qemu-monitor-command $VM '{"execute":"query-named-block-nodes", "arg= uments":{"flat":true}}' Signed-off-by: Peter Krempa Reviewed-by: Michal Privoznik --- v2: - dropped the '--qmpwrap' option and do wrapping if we don't get a JSON object instead. Similarly for arguments. docs/manpages/virsh.rst | 16 ++++++- tools/virsh-domain.c | 98 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 103 insertions(+), 11 deletions(-) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index 350ded2026..b4d31bf884 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -7772,7 +7772,21 @@ If more than one argument is provided for *command*,= they are concatenated with a space in between before passing the single command to the monitor. Note that libvirt uses the QMP to talk to qemu so *command* must be valid = JSON -in QMP format to work properly. +in QMP format to work properly. If *command* is not a JSON object libvirt = tries +to wrap it as a JSON object to provide convenient interface such as the gr= oups +of commands with identical handling: + +:: + + # simple command + $ virsh qemu-monitor-command VM commandname + $ virsh qemu-monitor-command VM '{"execute":"commandname"}' + + # with arguments + $ virsh qemu-monitor-command VM commandname '"arg1":123' '"arg2":"test"' + $ virsh qemu-monitor-command VM commandname '{"arg1":123,"arg2":"test"}' + $ virsh qemu-monitor-command VM '{"execute":"commandname", "arguments":= {"arg1":123,"arg2":"test"}}' + If *--pretty* is given the QMP reply is pretty-printed. diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 70aa4167c2..659aa1a242 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -9445,6 +9445,84 @@ static const vshCmdOptDef opts_qemu_monitor_command[= ] =3D { {.name =3D NULL} }; + +static char * +cmdQemuMonitorCommandConcatCmd(vshControl *ctl, + const vshCmd *cmd, + const vshCmdOpt *opt) +{ + g_auto(virBuffer) buf =3D VIR_BUFFER_INITIALIZER; + + while ((opt =3D vshCommandOptArgv(ctl, cmd, opt))) + virBufferAsprintf(&buf, "%s ", opt->data); + + virBufferTrim(&buf, " "); + + return virBufferContentAndReset(&buf); +} + + +static char * +cmdQemuMonitorCommandQMPWrap(vshControl *ctl, + const vshCmd *cmd) +{ + g_autofree char *fullcmd =3D cmdQemuMonitorCommandConcatCmd(ctl, cmd, = NULL); + g_autoptr(virJSONValue) fullcmdjson =3D virJSONValueFromString(fullcmd= ); + g_autofree char *fullargs =3D NULL; + g_autoptr(virJSONValue) fullargsjson =3D NULL; + const vshCmdOpt *opt =3D NULL; + const char *commandname =3D NULL; + g_autoptr(virJSONValue) command =3D NULL; + g_autoptr(virJSONValue) arguments =3D NULL; + + /* if we've got a JSON object, pass it through */ + if (virJSONValueIsObject(fullcmdjson)) + return g_steal_pointer(&fullcmd); + + /* we try to wrap the command and possible arguments into a JSON objec= t, if + * we as fall back we pass through what we've got from the user */ + + if ((opt =3D vshCommandOptArgv(ctl, cmd, opt))) + commandname =3D opt->data; + + /* now we process arguments similarly to how we've dealt with the full= command */ + if ((fullargs =3D cmdQemuMonitorCommandConcatCmd(ctl, cmd, opt))) + fullargsjson =3D virJSONValueFromString(fullargs); + + /* for empty args or a valid JSON object we just use that */ + if (!fullargs || virJSONValueIsObject(fullargsjson)) { + arguments =3D g_steal_pointer(&fullargsjson); + } else { + /* for a non-object we try to concatenate individual _ARGV bits in= to a + * JSON object wrapper and try using that */ + g_auto(virBuffer) buf =3D VIR_BUFFER_INITIALIZER; + + virBufferAddLit(&buf, "{"); + /* opt points to the _ARGV option bit containing the command so we= 'll + * iterate through the arguments now */ + while ((opt =3D vshCommandOptArgv(ctl, cmd, opt))) + virBufferAsprintf(&buf, "%s,", opt->data); + + virBufferTrim(&buf, ","); + virBufferAddLit(&buf, "}"); + + if (!(arguments =3D virJSONValueFromString(virBufferCurrentContent= (&buf)))) { + vshError(ctl, _("failed to wrap arguments '%s' into a QMP comm= and wrapper"), + fullargs); + return NULL; + } + } + + if (virJSONValueObjectCreate(&command, + "s:execute", commandname, + "A:arguments", &arguments, + NULL) < 0) + return NULL; + + return virJSONValueToString(command, false); +} + + static bool cmdQemuMonitorCommand(vshControl *ctl, const vshCmd *cmd) { @@ -9453,8 +9531,6 @@ cmdQemuMonitorCommand(vshControl *ctl, const vshCmd *= cmd) g_autofree char *result =3D NULL; g_autoptr(virJSONValue) resultjson =3D NULL; unsigned int flags =3D 0; - const vshCmdOpt *opt =3D NULL; - g_auto(virBuffer) buf =3D VIR_BUFFER_INITIALIZER; bool pretty =3D vshCommandOptBool(cmd, "pretty"); bool returnval =3D vshCommandOptBool(cmd, "return-value"); virJSONValue *formatjson; @@ -9466,15 +9542,17 @@ cmdQemuMonitorCommand(vshControl *ctl, const vshCmd= *cmd) if (!(dom =3D virshCommandOptDomain(ctl, cmd, NULL))) return false; - while ((opt =3D vshCommandOptArgv(ctl, cmd, opt))) - virBufferAsprintf(&buf, "%s ", opt->data); - - virBufferTrim(&buf, " "); - - monitor_cmd =3D virBufferContentAndReset(&buf); - - if (vshCommandOptBool(cmd, "hmp")) + if (vshCommandOptBool(cmd, "hmp")) { flags |=3D VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP; + monitor_cmd =3D cmdQemuMonitorCommandConcatCmd(ctl, cmd, NULL); + } else { + monitor_cmd =3D cmdQemuMonitorCommandQMPWrap(ctl, cmd); + } + + if (!monitor_cmd) { + vshSaveLibvirtError(); + return NULL; + } if (virDomainQemuMonitorCommand(dom, monitor_cmd, &result, flags) < 0) return false; --=20 2.31.1