]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: try to connect to nbdkit early to detect errors
authorJonathon Jongsma <jjongsma@redhat.com>
Fri, 16 Dec 2022 23:10:49 +0000 (17:10 -0600)
committerJonathon Jongsma <jjongsma@redhat.com>
Tue, 19 Sep 2023 19:28:50 +0000 (14:28 -0500)
When using nbdkit to serve a network disk source, the nbdkit process
will start and wait for an nbd connection before actually attempting to
connect to the (remote) disk location. Because of this, nbdkit will not
report an error until after qemu is launched and tries to read from the
disk. This results in a fairly user-unfriendly error saying that qemu
was unable to start because "Requested export not available".

Ideally we'd like to be able to tell the user *why* the export is not
available, but this sort of information is only available to nbdkit, not
qemu. It could be because the url was incorrect, or because of an
authentication failure, or one of many other possibilities.

To make this friendlier for users and easier to detect
misconfigurations, try to connect to nbdkit immediately after starting
nbdkit and before we try to start qemu. This requires adding a
dependency on libnbd. If an error occurs when connecting to nbdkit, read
back from the nbdkit error log and provide that information in the error
report from qemuNbdkitProcessStart().

User-visible change demonstrated below:
Previous error:

    $ virsh start nbdkit-test
    2023-01-18 19:47:45.778+0000: 30895: error : virNetClientProgramDispatchError:172 : internal
    error: process exited while connecting to monitor: 2023-01-18T19:47:45.704658Z
    qemu-system-x86_64: -blockdev {"driver":"nbd","server":{"type":"unix",
    "path":"/var/lib/libvirt/qemu/domain-1-nbdkit-test/nbdkit-libvirt-1-storage.socket"},
    "node-name":"libvirt-1-storage","auto-read-only":true,"discard":"unmap"}: Requested export not
    available
    error: Failed to start domain 'nbdkit-test'
    error: internal error: process exited while connecting to monitor: 2023-01-18T19:47:45.704658Z
    qemu-system-x86_64: -blockdev {"driver":"nbd","server":{"type":"unix",
    "path":"/var/lib/libvirt/qemu/domain-1-nbdkit-test/nbdkit-libvirt-1-storage.socket"},
    "node-name":"libvirt-1-storage","auto-read-only":true,"discard":"unmap"}: Requested export not
    available

After this change:

    $ virsh start nbdkit-test
    2023-01-18 19:44:36.242+0000: 30895: error : virNetClientProgramDispatchError:172 : internal
    error: Failed to connect to nbdkit for 'http://localhost:8888/nonexistent.iso': nbdkit: curl[1]:
    error: problem doing HEAD request to fetch size of URL [http://localhost:8888/nonexistent.iso]:
    HTTP response code said error: The requested URL returned error: 404
    error: Failed to start domain 'nbdkit-test'
    error: internal error: Failed to connect to nbdkit for 'http://localhost:8888/nonexistent.iso]:
    error: problem doing HEAD request to fetch size of URL [http://localhost:8888/nonexistent.iso]:
    HTTP response code said error: The requested URL returned error: 404

Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
meson.build
meson_options.txt
src/qemu/meson.build
src/qemu/qemu_nbdkit.c

index 2d9966bab0baebe2a9c9675bbd94a6ce596914df..ca5633cd980035546730769c2f948b14130f48e9 100644 (file)
@@ -1011,6 +1011,12 @@ endif
 libiscsi_version = '1.18.0'
 libiscsi_dep = dependency('libiscsi', version: '>=' + libiscsi_version, required: get_option('libiscsi'))
 
+libnbd_version = '1.0'
+libnbd_dep = dependency('libnbd', version: '>=' + libnbd_version, required: get_option('libnbd'))
+if libnbd_dep.found()
+  conf.set('WITH_LIBNBD', 1)
+endif
+
 libnl_version = '3.0'
 if not get_option('libnl').disabled() and host_machine.system() == 'linux'
   libnl_dep = dependency('libnl-3.0', version: '>=' + libnl_version, required: get_option('libnl'))
@@ -2228,6 +2234,7 @@ libs_summary = {
   'glusterfs': glusterfs_dep.found(),
   'libiscsi': libiscsi_dep.found(),
   'libkvm': libkvm_dep.found(),
+  'libnbd': libnbd_dep.found(),
   'libnl': libnl_dep.found(),
   'libparted': libparted_dep.found(),
   'libpcap': libpcap_dep.found(),
index 9174c4021c4f667e6b3e44ea11851a537c002d30..ba6e49afc519e0a7b5335a3b9a310e39508a2768 100644 (file)
@@ -25,6 +25,7 @@ option('curl', type: 'feature', value: 'auto', description: 'curl support')
 option('fuse', type: 'feature', value: 'auto', description: 'fuse support')
 option('glusterfs', type: 'feature', value: 'auto', description: 'glusterfs support')
 option('libiscsi', type: 'feature', value: 'auto', description: 'libiscsi support')
+option('libnbd', type: 'feature', value: 'auto', description: 'libnbd support')
 option('libnl', type: 'feature', value: 'auto', description: 'libnl support')
 option('libpcap', type: 'feature', value: 'auto', description: 'libpcap support')
 option('libssh', type: 'feature', value: 'auto', description: 'libssh support')
index 6d7a1bfbb0c36d93a6986046d8ea3989f426e8e9..607b597c8cccd606e6d1ce90235aa88ff0780c33 100644 (file)
@@ -99,6 +99,7 @@ if conf.has('WITH_QEMU')
       access_dep,
       capng_dep,
       gnutls_dep,
+      libnbd_dep,
       libnl_dep,
       log_dep,
       selinux_dep,
index 2ad34d6484e5a1cf8fe40e58ade0f7bfb237961c..db86a1832107cfc0e1338f444963f41fcf647532 100644 (file)
@@ -19,6 +19,9 @@
 
 #include <config.h>
 #include <glib.h>
+#if WITH_LIBNBD
+# include <libnbd.h>
+#endif
 #include <sys/syscall.h>
 
 #include "vircommand.h"
@@ -1136,6 +1139,9 @@ qemuNbdkitProcessStart(qemuNbdkitProcess *proc,
     g_autofree char *basename = g_strdup_printf("%s-nbdkit-%i", vm->def->name, proc->source->id);
     int logfd = -1;
     g_autoptr(qemuLogContext) logContext = NULL;
+#if WITH_LIBNBD
+    struct nbd_handle *nbd = NULL;
+#endif
 
     if (!(cmd = qemuNbdkitProcessBuildCommand(proc)))
         return -1;
@@ -1176,6 +1182,23 @@ qemuNbdkitProcessStart(qemuNbdkitProcess *proc,
 
     while (virTimeBackOffWait(&timebackoff)) {
         if (virFileExists(proc->socketfile)) {
+#if WITH_LIBNBD
+            /* if the disk source was misconfigured, nbdkit will not produce an error
+             * until somebody connects to the socket and tries to access the nbd
+             * export. This results in poor user experience because the only error we
+             * would get from qemu is something like "Requested export not available".
+             * So let's try to access it ourselves so that we can error out early and
+             * provide a useful message to the user.
+             */
+            nbd = nbd_create();
+            if (nbd_connect_unix(nbd, proc->socketfile) < 0) {
+                VIR_WARN("nbd_connect_unix failed: %s", nbd_get_error());
+                nbd_close(nbd);
+                goto errorlog;
+            }
+            nbd_close(nbd);
+
+#endif
             if (qemuNbdkitProcessStartMonitor(proc, vm) < 0)
                 goto error;
             return 0;