From nobody Wed May 15 18:48:05 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1532009388905808.6950446042091; Thu, 19 Jul 2018 07:09:48 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.24]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C5BEB307CF25; Thu, 19 Jul 2018 14:09:46 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 7B1F2308BDAC; Thu, 19 Jul 2018 14:09:46 +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 07BAE1800B69; Thu, 19 Jul 2018 14:09:46 +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 w6JE9Kfw012186 for ; Thu, 19 Jul 2018 10:09:20 -0400 Received: by smtp.corp.redhat.com (Postfix) id 60AD7177B5; Thu, 19 Jul 2018 14:09:20 +0000 (UTC) Received: from mx1.redhat.com (ext-mx13.extmail.prod.ext.phx2.redhat.com [10.5.110.42]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 574E2194A9 for ; Thu, 19 Jul 2018 14:09:20 +0000 (UTC) Received: from se07-out.mail.pcextreme.nl (se07-out.mail.pcextreme.nl [185.107.227.76]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E2245307C708 for ; Thu, 19 Jul 2018 14:09:17 +0000 (UTC) From: Wido den Hollander To: libvir-list@redhat.com Date: Thu, 19 Jul 2018 16:09:08 +0200 Message-Id: <20180719140908.43554-2-wido@widodh.nl> In-Reply-To: <20180719140908.43554-1-wido@widodh.nl> References: <20180719140908.43554-1-wido@widodh.nl> X-Originating-IP: 2a00:f10:400:2:446:66ff:fe00:2ce X-SpamExperts-Domain: out.pcextreme.nl X-SpamExperts-Username: 2a00:f10:400:2:446:66ff:fe00:2ce Authentication-Results: mail.pcextreme.nl; auth=pass smtp.auth=2a00:f10:400:2:446:66ff:fe00:2ce@out.pcextreme.nl X-SpamExperts-Outgoing-Class: ham X-SpamExperts-Outgoing-Evidence: SB/global_tokens (0.00159663912098) X-Recommended-Action: accept X-Filter-ID: EX5BVjFpneJeBchSMxfU5j5EgCfxdea7wfeIPZZ4+8p602E9L7XzfQH6nu9C/Fh9KJzpNe6xgvOx q3u0UDjvO0JAAYg/9Ix7k4FatThqAOyBT2ES8TdH8rq7CUN4bAtii/77mVkkLnpxqOrZwNHqf/La iWux2Z8CqFvZSu/nPUxQyacT2UA9FxLvxR5esQOYMcK2/dazfTEeqb/vVOToC8JfMLoARmxy4o14 wWNkVlZcL+MdujCjU5iV47di8pZylAtM3hMeyj3Qw/Sp3zuMaL3KvIJNaHrI6eGWO0FZh0hsmQyB sRL77VLkCKc6a6vT0TyXe6jsMXnTy/o9BuCfMeOTuuhDW/weKosDzmxjCavuvBac+xzHGc4GitBU L0OLCglklExTUK/9Pt1q598+JmQB2ErbcicDbPONrkjWuIOp21GAvb2Z3+HyJnBhVq8hTWruJBH6 Y3IFBQ2qUGxoD3W7otIk95OJaZ8nwvOYLhgYR/UCTQ9NAEq/yPvrIQ88AKMmXLf+gZxR4kKQYJrn 9AohMoZLI6WJJPX7d2dTJdoamUdylUIKhf3z2GAHxH7INQUKzIXKvn8MWwLfdAWo7j8zraHKMgjY mr4qjQTLieq0BDrm8MfqyYFG7m5QdMpUk1RhTAuJvJCaKzlqOUJRrAeYUOp7A73HI6oJg7w/Vofc 4kMfZkbXVTnIZuNGqsNkAXWHBJTqik9Ve/7HUkPBE+wHxWGYuL+SS7SZOk7hscZFx1XrXjBZrekb JVj3E7ZHVkVw1LkD8GcG9d6fCoCMjiNmqcuIkbCx6zQOhixhzgKH/yjb654pWGM7w4Xz+TijZVgW 04dc1jUtZZ367XmlknEZQ62LE5yicy3etIXf0ady2DNwOgV373pfDhBQ21Oddh7YHOQ2r53w2IP4 ZoGjlWmR3Zm2ki6aHzt8l2dvVW6gmozQHhsjMv4ltzvhy0XdlkRlSVbqNdUsBp5H0N/fZF/3z3LM gPLi0vZXJYA5/g2QgYFpibx/ChfDARs9qLl/I9ZSHMPgDGHc4gq7Kr6slNtXAeSCOAbk3L0b00fs mZuNrzg5ELEf3slz7mRHSb+ekD96tNc4Eft2cj0ILR1v30Zt37H3WQYPbQZHDuENtjg= X-Report-Abuse-To: spam@semaster01.mail.pcextreme.nl X-Greylist: Sender passed SPF test, Sender IP whitelisted by DNSRBL, ACL 207 matched, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.42]); Thu, 19 Jul 2018 14:09:18 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.42]); Thu, 19 Jul 2018 14:09:18 +0000 (UTC) for IP:'185.107.227.76' DOMAIN:'se07-out.mail.pcextreme.nl' HELO:'se07-out.mail.pcextreme.nl' FROM:'wido@widodh.nl' RCPT:'' X-RedHat-Spam-Score: -0.7 (RCVD_IN_DNSWL_LOW) 185.107.227.76 se07-out.mail.pcextreme.nl 185.107.227.76 se07-out.mail.pcextreme.nl X-Scanned-By: MIMEDefang 2.84 on 10.5.110.42 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-loop: libvir-list@redhat.com Cc: Wido den Hollander Subject: [libvirt] [java PATCH 1/1] Add support for Qemu Guest Agent commands 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: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.24 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.44]); Thu, 19 Jul 2018 14:09:47 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Through Qemu we can send commands to a Qemu Guest Agent running inside a domain. This way we can communicate with a running Domain by asking for it's network information, requesting a filesystem trim or even execute a command inside a Domain. Commands need to be send as JSON Strings, but these have been wrapped into the QemuCommand class which has a list of pre-defined and the most commonly used commands. RAW commands can also be send for more flexibility. Signed-off-by: Wido den Hollander --- src/main/java/org/libvirt/Domain.java | 34 ++++++ src/main/java/org/libvirt/Library.java | 3 + .../java/org/libvirt/jna/LibvirtQemu.java | 16 +++ .../java/org/libvirt/qemu/QemuCommand.java | 106 ++++++++++++++++++ .../org/libvirt/qemu/TestQemuCommand.java | 24 ++++ 5 files changed, 183 insertions(+) create mode 100644 src/main/java/org/libvirt/jna/LibvirtQemu.java create mode 100644 src/main/java/org/libvirt/qemu/QemuCommand.java create mode 100644 src/test/java/org/libvirt/qemu/TestQemuCommand.java diff --git a/src/main/java/org/libvirt/Domain.java b/src/main/java/org/libv= irt/Domain.java index 83a500c..9138238 100644 --- a/src/main/java/org/libvirt/Domain.java +++ b/src/main/java/org/libvirt/Domain.java @@ -8,6 +8,7 @@ import org.libvirt.jna.CString; import org.libvirt.jna.DomainPointer; import org.libvirt.jna.DomainSnapshotPointer; import org.libvirt.jna.Libvirt; +import org.libvirt.jna.LibvirtQemu; import org.libvirt.jna.SizeT; import org.libvirt.jna.virDomainBlockInfo; import org.libvirt.jna.virDomainBlockStats; @@ -21,7 +22,9 @@ import org.libvirt.event.RebootListener; import org.libvirt.event.LifecycleListener; import org.libvirt.event.PMWakeupListener; import org.libvirt.event.PMSuspendListener; +import org.libvirt.qemu.QemuCommand; import static org.libvirt.Library.libvirt; +import static org.libvirt.Library.libvirtqemu; import static org.libvirt.ErrorHandler.processError; import static org.libvirt.ErrorHandler.processErrorIfZero; =20 @@ -1556,4 +1559,35 @@ public class Domain { return processError(libvirt.virDomainUpdateDeviceFlags(VDP, xml, f= lags)); } =20 + /** + * Send a Qemu Guest Agent command to a domain + * + * @param cmd + * The command which has to be send + * @param timeout + * The timeout for waiting on an answer. See QemuAgentFlags= for more information. + * @param flags + * Flags to be send + * @return String + * @throws LibvirtException + */ + public String qemuAgentCommand(QemuCommand command) throws LibvirtExce= ption { + return this.qemuAgentCommand(command, 0); + } + + /** + * Send a Qemu Guest Agent command to a domain + * @see Qemu= Documentation + * @param command + * The command which has to be send + * @param timeout + * The timeout for waiting on an answer. See QemuAgentFlags= for more information + * @return String + * @throws LibvirtException + */ + public String qemuAgentCommand(QemuCommand command, int timeout) throw= s LibvirtException { + CString result =3D libvirtqemu.virDomainQemuAgentCommand(this.VDP,= command.toString(), timeout, 0); + processError(result); + return result.toString(); + } } diff --git a/src/main/java/org/libvirt/Library.java b/src/main/java/org/lib= virt/Library.java index 8e054c6..30f15be 100644 --- a/src/main/java/org/libvirt/Library.java +++ b/src/main/java/org/libvirt/Library.java @@ -2,6 +2,7 @@ package org.libvirt; =20 import org.libvirt.jna.Libvirt; import org.libvirt.jna.Libvirt.VirEventTimeoutCallback; +import org.libvirt.jna.LibvirtQemu; import org.libvirt.jna.CString; import static org.libvirt.ErrorHandler.processError; =20 @@ -34,6 +35,7 @@ public final class Library { }; =20 final static Libvirt libvirt; + final static LibvirtQemu libvirtqemu; =20 // an empty string array constant // prefer this over creating empty arrays dynamically. @@ -47,6 +49,7 @@ public final class Library { } catch (Exception e) { e.printStackTrace(); } + libvirtqemu =3D LibvirtQemu.INSTANCE; } =20 private Library() {} diff --git a/src/main/java/org/libvirt/jna/LibvirtQemu.java b/src/main/java= /org/libvirt/jna/LibvirtQemu.java new file mode 100644 index 0000000..82213e9 --- /dev/null +++ b/src/main/java/org/libvirt/jna/LibvirtQemu.java @@ -0,0 +1,16 @@ +package org.libvirt.jna; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.Platform; + +/** + * The libvirt Qemu interface which is exposed via JNA + */ + +public interface LibvirtQemu extends Library { + + LibvirtQemu INSTANCE =3D (LibvirtQemu) Native.loadLibrary(Platform.isW= indows() ? "virt-qemu-0" : "virt-qemu", LibvirtQemu.class); + + CString virDomainQemuAgentCommand(DomainPointer virDomainPtr, String c= md, int timeout, int flags); +} diff --git a/src/main/java/org/libvirt/qemu/QemuCommand.java b/src/main/jav= a/org/libvirt/qemu/QemuCommand.java new file mode 100644 index 0000000..5b28c81 --- /dev/null +++ b/src/main/java/org/libvirt/qemu/QemuCommand.java @@ -0,0 +1,106 @@ +package org.libvirt.qemu; + +import java.lang.IllegalArgumentException; + +public class QemuCommand { + + public enum Command { + + GUEST_INFO("guest-info", false), + GUEST_SYNC_DELIMITED("guest-sync-delimited", true), + GUEST_SYNC("guest-sync", true), + GUEST_PING("guest-ping", false), + GUEST_GET_TIME("guest-get-time", false), + GUEST_SET_TIME("guest-set-time", true), + GUEST_SHUTDOWN("guest-shutdown", false), + GUEST_FILE_OPEN("guest-file-open", true), + GUEST_FILE_CLOSE("guest-file-close", true), + GUEST_FILE_READ("guest-file-read", true), + GUEST_FILE_WRITE("guest-file-write", true), + GUEST_FILE_SEEK("guest-file-seek", true), + GUEST_FILE_FLUSH("guest-file-flush", true), + GUEST_FSFREEZE_STATUS("guest-fsfreeze-status", false), + GUEST_FSFREEZE_FREEZE("guest-fsfreeze-freeze", false), + GUEST_FSFREEZE_LIST("guest-fsfreeze-freeze-list", true), + GUEST_FSFREEZE_THAW("guest-fsfreeze-thaw", false), + GUEST_FSTRIM("guest-fstrim", true), + GUEST_SUSPEND_DISK("guest-suspend-disk", false), + GUEST_SUSPEND_RAM("guest-suspend-ram", false), + GUEST_SUSPEND_HYBRID("guest-suspend-hybrid", false), + GUEST_GET_NETWORK_INTERFACES("guest-network-get-interfaces", false= ), + GUEST_GET_VCPUS("guest-get-vcpus", false), + GUEST_SET_VCPUS("guest-set-vcpus", true), + GUEST_GET_FSINFO("guest-get-fsinfo", false), + GUEST_SET_USER_PASSWORD("guest-set-user-password", true), + GUEST_GET_MEMORY_BLOCKS("guest-get-memory-blocks", false), + GUEST_SET_MEMORY_BLOCKS("guest-set-memory-blocks", true), + GUEST_GET_MEMORY_BLOCK_INFO("guest-get-memory-block-info", false), + GUEST_EXEC_STATUS("guest-exec-status", false), + GUEST_EXEC("guest-exec", true); + + private final String command; + private final Boolean requiresArguments; + + Command(String command, Boolean requiresArguments) { + this.command =3D command; + this.requiresArguments =3D requiresArguments; + } + + private String getCommand() { + return command; + } + + private Boolean requiresArguments() { + return requiresArguments; + } + } + + Command command; + String arguments; + String raw; + + public static QemuCommand create(Command cmd) { + return new QemuCommand(cmd, null); + } + + public static QemuCommand create(Command cmd, String args) { + return new QemuCommand(cmd, args); + } + + public static QemuCommand raw(String jsonObject) { + return new QemuCommand(jsonObject); + } + + private QemuCommand(Command command, String arguments) { + if (command.requiresArguments() && arguments =3D=3D null) { + throw new IllegalArgumentException(command.getCommand() + " re= quires a argument"); + } else if(!command.requiresArguments() && arguments !=3D null) { + throw new IllegalArgumentException(command.getCommand() + " do= es not take a argument"); + } + + this.command =3D command; + this.arguments =3D arguments; + } + + private QemuCommand(String raw) { + this.raw =3D raw; + } + + public String toString() { + if (this.raw !=3D null) { + return this.raw; + } + + String json =3D ""; + + json +=3D "{"; + json +=3D "\"execute\": \"" + command.getCommand() + "\""; + + if (arguments !=3D null && arguments.length() > 0) { + json +=3D "\"arguments\": " + arguments + "\""; + } + + json +=3D "}"; + return json; + } +} diff --git a/src/test/java/org/libvirt/qemu/TestQemuCommand.java b/src/test= /java/org/libvirt/qemu/TestQemuCommand.java new file mode 100644 index 0000000..f372310 --- /dev/null +++ b/src/test/java/org/libvirt/qemu/TestQemuCommand.java @@ -0,0 +1,24 @@ +package org.libvirt.qemu; + +import junit.framework.TestCase; + +public final class TestQemuCommand extends TestCase { + + public void testCommandWithoutArguments() { + QemuCommand command =3D QemuCommand.create(QemuCommand.Command.GUE= ST_INFO); + assertEquals("{\"execute\": \"guest-info\"}", command.toString()); + } + + public void testCommandWithoutNonRequiredArguments() { + try { + QemuCommand command =3D QemuCommand.create(QemuCommand.Command= .GUEST_INFO, "I am Not Required"); + fail("Expected a IllegalArgumentException which was not thrown= "); + } catch(IllegalArgumentException e) {} + } + + public void testRawCommand() { + String rawcommand =3D "this is a raw string"; + QemuCommand command =3D QemuCommand.raw(rawcommand); + assertEquals(rawcommand, command.toString()); + } +} --=20 2.17.1 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list