]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: Check QEMU error on failed migration
authorJiri Denemark <jdenemar@redhat.com>
Thu, 12 Oct 2017 13:19:19 +0000 (15:19 +0200)
committerJiri Denemark <jdenemar@redhat.com>
Tue, 17 Oct 2017 08:41:45 +0000 (10:41 +0200)
When migration fails, QEMU may provide a description of the error in
the reply to query-migrate QMP command. We can fetch this error and use
it instead of the generic "unexpectedly failed" message.

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
src/qemu/qemu_driver.c
src/qemu/qemu_migration.c
src/qemu/qemu_migration.h
src/qemu/qemu_monitor.c
src/qemu/qemu_monitor.h
src/qemu/qemu_monitor_json.c
src/qemu/qemu_monitor_json.h
tests/qemumonitorjsontest.c

index f889003ba6249d75c4b3893a9ff565284a1ca176..7c8ad326751c9c32bf16d3cca1b892d4af069dfd 100644 (file)
@@ -13117,7 +13117,8 @@ qemuDomainGetJobStatsInternal(virQEMUDriverPtr driver,
         jobInfo->status == QEMU_DOMAIN_JOB_STATUS_POSTCOPY) {
         if (events &&
             jobInfo->status != QEMU_DOMAIN_JOB_STATUS_ACTIVE &&
-            qemuMigrationFetchStats(driver, vm, QEMU_ASYNC_JOB_NONE, jobInfo) < 0)
+            qemuMigrationFetchStats(driver, vm, QEMU_ASYNC_JOB_NONE,
+                                    jobInfo, NULL) < 0)
             goto cleanup;
 
         if (jobInfo->status == QEMU_DOMAIN_JOB_STATUS_ACTIVE &&
index dd60071bfdbbf6872fee37c726694a0960939a49..b286d68061eb7d20fd1d170f5b25f799483afb4b 100644 (file)
@@ -1382,7 +1382,8 @@ int
 qemuMigrationFetchStats(virQEMUDriverPtr driver,
                         virDomainObjPtr vm,
                         qemuDomainAsyncJob asyncJob,
-                        qemuDomainJobInfoPtr jobInfo)
+                        qemuDomainJobInfoPtr jobInfo,
+                        char **error)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
     qemuMonitorMigrationStats stats;
@@ -1391,7 +1392,7 @@ qemuMigrationFetchStats(virQEMUDriverPtr driver,
     if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
         return -1;
 
-    rv = qemuMonitorGetMigrationStats(priv->mon, &stats);
+    rv = qemuMonitorGetMigrationStats(priv->mon, &stats, error);
 
     if (qemuDomainObjExitMonitor(driver, vm) < 0 || rv < 0)
         return -1;
@@ -1427,12 +1428,15 @@ qemuMigrationCheckJobStatus(virQEMUDriverPtr driver,
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
     qemuDomainJobInfoPtr jobInfo = priv->job.current;
-
+    char *error = NULL;
     bool events = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATION_EVENT);
+    int ret = -1;
 
-    if (!events &&
-        qemuMigrationFetchStats(driver, vm, asyncJob, jobInfo) < 0)
-        return -1;
+    if (!events ||
+        jobInfo->stats.status == QEMU_MONITOR_MIGRATION_STATUS_ERROR) {
+        if (qemuMigrationFetchStats(driver, vm, asyncJob, jobInfo, &error) < 0)
+            return -1;
+    }
 
     qemuMigrationUpdateJobType(jobInfo);
 
@@ -1440,17 +1444,18 @@ qemuMigrationCheckJobStatus(virQEMUDriverPtr driver,
     case QEMU_DOMAIN_JOB_STATUS_NONE:
         virReportError(VIR_ERR_OPERATION_FAILED, _("%s: %s"),
                        qemuMigrationJobName(vm), _("is not active"));
-        return -1;
+        goto cleanup;
 
     case QEMU_DOMAIN_JOB_STATUS_FAILED:
         virReportError(VIR_ERR_OPERATION_FAILED, _("%s: %s"),
-                       qemuMigrationJobName(vm), _("unexpectedly failed"));
-        return -1;
+                       qemuMigrationJobName(vm),
+                       error ? error : _("unexpectedly failed"));
+        goto cleanup;
 
     case QEMU_DOMAIN_JOB_STATUS_CANCELED:
         virReportError(VIR_ERR_OPERATION_ABORTED, _("%s: %s"),
                        qemuMigrationJobName(vm), _("canceled by client"));
-        return -1;
+        goto cleanup;
 
     case QEMU_DOMAIN_JOB_STATUS_COMPLETED:
     case QEMU_DOMAIN_JOB_STATUS_ACTIVE:
@@ -1459,7 +1464,12 @@ qemuMigrationCheckJobStatus(virQEMUDriverPtr driver,
     case QEMU_DOMAIN_JOB_STATUS_POSTCOPY:
         break;
     }
-    return 0;
+
+    ret = 0;
+
+ cleanup:
+    VIR_FREE(error);
+    return ret;
 }
 
 
@@ -1577,7 +1587,7 @@ qemuMigrationWaitForCompletion(virQEMUDriverPtr driver,
     }
 
     if (events)
-        ignore_value(qemuMigrationFetchStats(driver, vm, asyncJob, jobInfo));
+        ignore_value(qemuMigrationFetchStats(driver, vm, asyncJob, jobInfo, NULL));
 
     qemuDomainJobInfoUpdateTime(jobInfo);
     qemuDomainJobInfoUpdateDowntime(jobInfo);
@@ -3177,7 +3187,7 @@ qemuMigrationConfirmPhase(virQEMUDriverPtr driver,
         if (virDomainObjGetState(vm, &reason) == VIR_DOMAIN_PAUSED &&
             reason == VIR_DOMAIN_PAUSED_POSTCOPY &&
             qemuMigrationFetchStats(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT,
-                                    jobInfo) < 0)
+                                    jobInfo, NULL) < 0)
             VIR_WARN("Could not refresh migration statistics");
 
         qemuDomainJobInfoUpdateTime(jobInfo);
index 57c747934df1e6a73db12ab3b17b8f6a0b6d2f25..63a43256242cf40248e8e1e5804bfa8de272e799 100644 (file)
@@ -282,7 +282,8 @@ int
 qemuMigrationFetchStats(virQEMUDriverPtr driver,
                         virDomainObjPtr vm,
                         qemuDomainAsyncJob asyncJob,
-                        qemuDomainJobInfoPtr jobInfo);
+                        qemuDomainJobInfoPtr jobInfo,
+                        char **error);
 
 int
 qemuMigrationErrorInit(virQEMUDriverPtr driver);
index aac318f787e0b047eeb4890cd69f89af29bba898..8ffce5a35d5e479da43272473285e4ae76709543 100644 (file)
@@ -2632,12 +2632,16 @@ qemuMonitorSetMigrationParams(qemuMonitorPtr mon,
 
 int
 qemuMonitorGetMigrationStats(qemuMonitorPtr mon,
-                             qemuMonitorMigrationStatsPtr stats)
+                             qemuMonitorMigrationStatsPtr stats,
+                             char **error)
 {
     QEMU_CHECK_MONITOR(mon);
 
+    if (error)
+        *error = NULL;
+
     if (mon->json)
-        return qemuMonitorJSONGetMigrationStats(mon, stats);
+        return qemuMonitorJSONGetMigrationStats(mon, stats, error);
     else
         return qemuMonitorTextGetMigrationStats(mon, stats);
 }
index 40d90d0da68af2feaa53d1b8b33ad331906cf555..57893c61c61d45fc3f9ae8bc6fccf53ecda74110 100644 (file)
@@ -696,7 +696,8 @@ struct _qemuMonitorMigrationStats {
 };
 
 int qemuMonitorGetMigrationStats(qemuMonitorPtr mon,
-                                 qemuMonitorMigrationStatsPtr stats);
+                                 qemuMonitorMigrationStatsPtr stats,
+                                 char **error);
 
 typedef enum {
     QEMU_MONITOR_MIGRATION_CAPS_XBZRLE,
index 5546d1aa1f6e576eabf57b19a3b58a85d4d592d4..171cdf1b7c2b1e72298ab2adcd82f3ddc840d110 100644 (file)
@@ -2792,7 +2792,8 @@ qemuMonitorJSONSetMigrationParams(qemuMonitorPtr mon,
 
 static int
 qemuMonitorJSONGetMigrationStatsReply(virJSONValuePtr reply,
-                                      qemuMonitorMigrationStatsPtr stats)
+                                      qemuMonitorMigrationStatsPtr stats,
+                                      char **error)
 {
     virJSONValuePtr ret;
     virJSONValuePtr ram;
@@ -2801,6 +2802,7 @@ qemuMonitorJSONGetMigrationStatsReply(virJSONValuePtr reply,
     const char *statusstr;
     int rc;
     double mbps;
+    const char *tmp;
 
     ret = virJSONValueObjectGetObject(reply, "return");
 
@@ -2839,11 +2841,18 @@ qemuMonitorJSONGetMigrationStatsReply(virJSONValuePtr reply,
     switch ((qemuMonitorMigrationStatus) stats->status) {
     case QEMU_MONITOR_MIGRATION_STATUS_INACTIVE:
     case QEMU_MONITOR_MIGRATION_STATUS_SETUP:
-    case QEMU_MONITOR_MIGRATION_STATUS_ERROR:
     case QEMU_MONITOR_MIGRATION_STATUS_CANCELLED:
     case QEMU_MONITOR_MIGRATION_STATUS_LAST:
         break;
 
+    case QEMU_MONITOR_MIGRATION_STATUS_ERROR:
+        if (error) {
+            tmp = virJSONValueObjectGetString(ret, "error-desc");
+            if (tmp && VIR_STRDUP(*error, tmp) < 0)
+                return -1;
+        }
+        break;
+
     case QEMU_MONITOR_MIGRATION_STATUS_ACTIVE:
     case QEMU_MONITOR_MIGRATION_STATUS_POSTCOPY:
     case QEMU_MONITOR_MIGRATION_STATUS_COMPLETED:
@@ -2989,7 +2998,8 @@ qemuMonitorJSONGetMigrationStatsReply(virJSONValuePtr reply,
 
 
 int qemuMonitorJSONGetMigrationStats(qemuMonitorPtr mon,
-                                     qemuMonitorMigrationStatsPtr stats)
+                                     qemuMonitorMigrationStatsPtr stats,
+                                     char **error)
 {
     int ret = -1;
     virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-migrate",
@@ -3007,7 +3017,7 @@ int qemuMonitorJSONGetMigrationStats(qemuMonitorPtr mon,
     if (qemuMonitorJSONCheckError(cmd, reply) < 0)
         goto cleanup;
 
-    if (qemuMonitorJSONGetMigrationStatsReply(reply, stats) < 0)
+    if (qemuMonitorJSONGetMigrationStatsReply(reply, stats, error) < 0)
         goto cleanup;
 
     ret = 0;
index f418c74264269a2305ed7f9f373be88e223b0537..7c45be672565f5248bd9f177c6e23915c33cce01 100644 (file)
@@ -141,7 +141,8 @@ int qemuMonitorJSONSetMigrationParams(qemuMonitorPtr mon,
                                       qemuMonitorMigrationParamsPtr params);
 
 int qemuMonitorJSONGetMigrationStats(qemuMonitorPtr mon,
-                                     qemuMonitorMigrationStatsPtr stats);
+                                     qemuMonitorMigrationStatsPtr stats,
+                                     char **error);
 
 int qemuMonitorJSONGetMigrationCapabilities(qemuMonitorPtr mon,
                                             char ***capabilities);
index df3ef0a932edb4881adc0d64ea2d2fc005fd2052..475fd270e12c80ce2afb560f2faf226071852278 100644 (file)
@@ -1907,6 +1907,7 @@ testQemuMonitorJSONqemuMonitorJSONGetMigrationStats(const void *data)
     qemuMonitorTestPtr test = qemuMonitorTestNewSimple(true, xmlopt);
     int ret = -1;
     qemuMonitorMigrationStats stats, expectedStats;
+    char *error = NULL;
 
     if (!test)
         return -1;
@@ -1931,21 +1932,43 @@ testQemuMonitorJSONqemuMonitorJSONGetMigrationStats(const void *data)
                                "        }"
                                "    },"
                                "    \"id\": \"libvirt-13\""
+                               "}") < 0 ||
+        qemuMonitorTestAddItem(test, "query-migrate",
+                               "{"
+                               "    \"return\": {"
+                               "        \"status\": \"failed\","
+                               "        \"error-desc\": \"It's broken\""
+                               "    },"
+                               "    \"id\": \"libvirt-14\""
                                "}") < 0)
         goto cleanup;
 
-    if (qemuMonitorJSONGetMigrationStats(qemuMonitorTestGetMonitor(test), &stats) < 0)
+    if (qemuMonitorJSONGetMigrationStats(qemuMonitorTestGetMonitor(test),
+                                         &stats, &error) < 0)
+        goto cleanup;
+
+    if (memcmp(&stats, &expectedStats, sizeof(stats)) != 0 || error) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       "Invalid migration statistics");
+        goto cleanup;
+    }
+
+    memset(&stats, 0, sizeof(stats));
+    if (qemuMonitorJSONGetMigrationStats(qemuMonitorTestGetMonitor(test),
+                                         &stats, &error) < 0)
         goto cleanup;
 
-    if (memcmp(&stats, &expectedStats, sizeof(stats)) != 0) {
+    if (stats.status != QEMU_MONITOR_MIGRATION_STATUS_ERROR ||
+        STRNEQ_NULLABLE(error, "It's broken")) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       "Invalid migration status");
+                       "Invalid failed migration status");
         goto cleanup;
     }
 
     ret = 0;
  cleanup:
     qemuMonitorTestFree(test);
+    VIR_FREE(error);
     return ret;
 }