[Libguestfs] [PATCH libnbd] interop: Add test of qemu-storage-daemon.

Richard W.M. Jones rjones at redhat.com
Thu Oct 1 09:50:02 UTC 2020


---
 .gitignore          |  1 +
 configure.ac        |  6 ++-
 interop/Makefile.am | 24 ++++++++++++
 interop/interop.c   | 89 ++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 118 insertions(+), 2 deletions(-)

diff --git a/.gitignore b/.gitignore
index aa9e0bb..199e445 100644
--- a/.gitignore
+++ b/.gitignore
@@ -94,6 +94,7 @@ Makefile.in
 /interop/interop-qemu-nbd
 /interop/interop-qemu-nbd-tls-certs
 /interop/interop-qemu-nbd-tls-psk
+/interop/interop-qemu-storage-daemon
 /interop/list-exports-nbd-server
 /interop/list-exports-qemu-nbd
 /interop/socket-activation-nbdkit
diff --git a/configure.ac b/configure.ac
index 328c6cb..6bb057f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -182,11 +182,15 @@ AS_IF([test "x$NBDKIT" != "x"], [
 AM_CONDITIONAL([HAVE_NBDKIT],
     [test "x$NBDKIT" != "x" && test "x$have_nbdkit_features" = "xyes"])
 
-dnl nbd-server and qemu-nbd for interop testing.
+dnl nbd-server, qemu-nbd and qemu-storage-daemon for interop testing.
 AC_CHECK_PROG([NBD_SERVER], [nbd-server], [nbd-server])
 AM_CONDITIONAL([HAVE_NBD_SERVER], [test "x$NBD_SERVER" != "x"])
 AC_CHECK_PROG([QEMU_NBD], [qemu-nbd], [qemu-nbd])
 AM_CONDITIONAL([HAVE_QEMU_NBD], [test "x$QEMU_NBD" != "x"])
+AC_CHECK_PROG([QEMU_STORAGE_DAEMON],
+               [qemu-storage-daemon], [qemu-storage-daemon])
+AM_CONDITIONAL([HAVE_QEMU_STORAGE_DAEMON],
+               [test "x$QEMU_STORAGE_DAEMON" != "x"])
 
 dnl glib2 main loop for examples that interoperate with the glib main loop.
 PKG_CHECK_MODULES([GLIB], [glib-2.0], [
diff --git a/interop/Makefile.am b/interop/Makefile.am
index 9787c26..7712777 100644
--- a/interop/Makefile.am
+++ b/interop/Makefile.am
@@ -174,6 +174,30 @@ structured_read_LDADD = $(top_builddir)/lib/libnbd.la
 
 endif HAVE_QEMU_NBD
 
+# We treat qemu-storage-daemon as effectively the same as qemu-nbd
+# since they use the same code, but there is a single test to make
+# sure we can use it.
+if HAVE_QEMU_STORAGE_DAEMON
+
+check_PROGRAMS += interop-qemu-storage-daemon
+TESTS += interop-qemu-storage-daemon
+
+# NB for upstream we must change --export parameters:
+#  device= -> node.name=
+#  name=   -> id=
+interop_qemu_storage_daemon_SOURCES = interop.c
+interop_qemu_storage_daemon_CPPFLAGS = \
+	-I$(top_srcdir)/include \
+	-DUNIXSOCKET=\"`mktemp -u /tmp/libnbd-interop-qsd.XXXXXX`\" \
+	-DSERVER=\"$(QEMU_STORAGE_DAEMON)\" \
+	-DSERVER_PARAMS='"--blockdev", SPRINTF ("raw,file.driver=file,file.filename=%s,node-name=disk0", tmpfile), "--nbd-server", SPRINTF ("addr.type=unix,addr.path=%s", UNIXSOCKET), "--export", "nbd,device=disk0,name=/"' \
+	-DEXPORT_NAME='"/"' \
+	$(NULL)
+interop_qemu_storage_daemon_CFLAGS = $(WARNINGS_CFLAGS)
+interop_qemu_storage_daemon_LDADD = $(top_builddir)/lib/libnbd.la
+
+endif HAVE_QEMU_STORAGE_DAEMON
+
 if HAVE_NBDKIT
 
 check_PROGRAMS += \
diff --git a/interop/interop.c b/interop/interop.c
index ec3e735..64608fc 100644
--- a/interop/interop.c
+++ b/interop/interop.c
@@ -35,6 +35,27 @@
 
 #define SIZE (1024*1024)
 
+struct free_on_exit {
+  struct free_on_exit *next;
+  void *v;
+};
+
+/* Macro which can be used in SERVER_PARAMS to deal with the case
+ * where a parameter must be embedded inside a parameter.  The return
+ * value is automatically freed.
+ */
+#define SPRINTF(fs,...)                                                 \
+  ({                                                                    \
+    char *ret;                                                          \
+    if (asprintf (&ret, (fs), ##__VA_ARGS__) == -1) abort ();           \
+    struct free_on_exit *f = malloc (sizeof *f);                        \
+    if (!f) abort ();                                                   \
+    f->next = free_on_exit_list;                                        \
+    f->v = ret;                                                         \
+    free_on_exit_list = f;                                              \
+    ret;                                                                \
+  })
+
 #if CERTS || PSK
 #define TLS 1
 #ifndef TLS_MODE
@@ -45,13 +66,17 @@
 int
 main (int argc, char *argv[])
 {
+  struct free_on_exit *free_on_exit_list = NULL;
   struct nbd_handle *nbd;
   char tmpfile[] = "/tmp/nbdXXXXXX";
-  char *args[] = { SERVER, SERVER_PARAMS, NULL };
+  size_t i;
   int fd;
   int64_t actual_size;
   char buf[512];
   int r = -1;
+#ifdef UNIXSOCKET
+  pid_t pid = 0;
+#endif
 
   /* Create a large sparse temporary file. */
   fd = mkstemp (tmpfile);
@@ -62,6 +87,16 @@ main (int argc, char *argv[])
     goto out;
   }
 
+  /* Server name and parameters.  These come from -D options defined
+   * in Makefile.am.
+   */
+  char *args[] = { SERVER, SERVER_PARAMS, NULL };
+  printf ("server:");
+  for (i = 0; args[i] != NULL; ++i)
+    printf (" %s", args[i]);
+  printf ("\n");
+  fflush (stdout);
+
   nbd = nbd_create ();
   if (nbd == NULL) {
     fprintf (stderr, "%s\n", nbd_get_error ());
@@ -103,6 +138,7 @@ main (int argc, char *argv[])
 #endif
 
   /* Start the server. */
+#ifndef UNIXSOCKET
 #if SOCKET_ACTIVATION
 #define NBD_CONNECT nbd_connect_systemd_socket_activation
 #else
@@ -112,6 +148,40 @@ main (int argc, char *argv[])
     fprintf (stderr, "%s\n", nbd_get_error ());
     goto out;
   }
+#else /* UNIXSOCKET */
+  /* This is for servers which don't support either stdin/stdout or
+   * systemd socket activation.  We have to run the command in the
+   * background and connect to the Unix domain socket.
+   */
+  pid = fork ();
+  if (pid == -1) {
+    perror ("fork");
+    goto out;
+  }
+  if (pid == 0) {
+    execvp (args[0], args);
+    perror (args[0]);
+    _exit (EXIT_FAILURE);
+  }
+  /* Unfortunately qemu-storage-daemon doesn't support pidfiles, so we
+   * have to wait for the socket to be created then sleep "a bit".
+   */
+  for (i = 0; i < 60; ++i) {
+    if (access (UNIXSOCKET, R_OK) == 0)
+      break;
+    sleep (1);
+  }
+  sleep (1);
+  /* Connect to the socket. */
+  if (nbd_connect_unix (nbd, UNIXSOCKET) == -1) {
+    fprintf (stderr, "%s\n", nbd_get_error ());
+    goto out;
+  }
+  /* We don't need the socket to exist in the filesystem any more, so
+   * we can remove it early.
+   */
+  unlink (UNIXSOCKET);
+#endif /* UNIXSOCKET */
 
 #if TLS
   if (TLS_MODE == LIBNBD_TLS_REQUIRE) {
@@ -179,5 +249,22 @@ main (int argc, char *argv[])
  out:
   unlink (tmpfile);
 
+#ifdef UNIXSOCKET
+  /* Kill the background server. */
+  if (pid > 0) {
+    printf ("killing %s PID %d ...\n", args[0], (int) pid);
+    fflush (stdout);
+    kill (pid, SIGTERM);
+  }
+#endif
+
+  /* Free strings allocated by SPRINTF macro. */
+  while (free_on_exit_list != NULL) {
+    struct free_on_exit *next = free_on_exit_list->next;
+    free (free_on_exit_list->v);
+    free (free_on_exit_list);
+    free_on_exit_list = next;
+  }
+
   exit (r == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
 }
-- 
2.27.0




More information about the Libguestfs mailing list