diff --git a/lib/cmdlib.py b/lib/cmdlib.py index 951621d2687ae941ca0fa6d4b06e0dfd863c99bf..cea239bd0c1821cf3f3a1d0d5a97666bb2681f66 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -6472,6 +6472,8 @@ class LUExportInstance(LogicalUnit): for disk in instance.disks: self.cfg.SetDiskID(disk, src_node) + # per-disk results + dresults = [] try: for idx, disk in enumerate(instance.disks): # new_dev_name will be a snapshot of an lvm leaf of the one we passed @@ -6505,15 +6507,22 @@ class LUExportInstance(LogicalUnit): if result.failed or not result.data: self.LogWarning("Could not export disk/%d from node %s to" " node %s", idx, src_node, dst_node.name) + dresults.append(False) + else: + dresults.append(True) msg = self.rpc.call_blockdev_remove(src_node, dev).RemoteFailMsg() if msg: self.LogWarning("Could not remove snapshot for disk/%d from node" " %s: %s", idx, src_node, msg) + else: + dresults.append(False) result = self.rpc.call_finalize_export(dst_node.name, instance, snap_disks) + fin_resu = True if result.failed or not result.data: self.LogWarning("Could not finalize export for instance %s on node %s", instance.name, dst_node.name) + fin_resu = False nodelist = self.cfg.GetNodeList() nodelist.remove(dst_node.name) @@ -6530,6 +6539,7 @@ class LUExportInstance(LogicalUnit): if not self.rpc.call_export_remove(node, instance.name): self.LogWarning("Could not remove older export for instance %s" " on node %s", instance.name, node) + return fin_resu, dresults class LURemoveExport(NoHooksLU): diff --git a/man/gnt-backup.sgml b/man/gnt-backup.sgml index d432b6ef6eda9190005f9752ce3df65579ea7c5c..ae3122ac661d4892b0c2064e38177e55b94c06e2 100644 --- a/man/gnt-backup.sgml +++ b/man/gnt-backup.sgml @@ -82,6 +82,16 @@ in the exported dump. </para> + <para> + The exit code of the command is 0 if all disks were backed up + successfully, 1 if no data was backed up or if the + configuration export failed, and 2 if just some of the disks + failed to backup. The exact details of the failures will be + shown during the command execution (and will be stored in the + job log). It is recommended that for any non-zero exit code, + the backup is considered invalid, and retried. + </para> + <para> Example: <screen> diff --git a/scripts/gnt-backup b/scripts/gnt-backup index 467b37d0a2a20d3e263fc83c24fa152aec2e355e..cbbde51f4bfff6fb58b031f05ac40c6830444327 100755 --- a/scripts/gnt-backup +++ b/scripts/gnt-backup @@ -74,8 +74,27 @@ def ExportInstance(opts, args): target_node=opts.node, shutdown=opts.shutdown) - SubmitOpCode(op) - + fin_resu, dlist = SubmitOpCode(op) + if not isinstance(dlist, list): + ToStderr("Cannot parse execution results") + return 1 + tot_dsk = len(dlist) + # TODO: handle diskless instances + if dlist.count(False) == 0: + # all OK + rcode = 0 + elif dlist.count(True) == 0: + ToStderr("Error: No disks were backed up successfully." + " The export doesn't have any valid data," + " it is recommended to retry the operation.") + rcode = 1 + else: + ToStderr("Partial export failure: %d disks backed up, %d disks failed.", + dlist.count(True), dlist.count(False)) + rcode = 2 + if not fin_resu: + rcode = 1 + return rcode def ImportInstance(opts, args): """Add an instance to the cluster.