From 084f05a5176cb3ea47e5f5b7f711ace5b8bdef07 Mon Sep 17 00:00:00 2001 From: Iustin Pop <iustin@google.com> Date: Wed, 5 Aug 2009 13:02:48 +0200 Subject: [PATCH] export: add meaningful exit code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently βgnt-backup exportβ always returns exit code zero, even in the face of complete failure during backup (only failure to stop/start the instance will cause job failure and thus non-zero exit code). This is bad, since one cannot script the backup. This patch adds some simple results from the LU so that the command line script can return good exit code. It will: - return zero for full success (snapshot removal errors are ignored though) - return one for full failure (finalize export failure or all disks failure) - return two for partial failure (some disks backed up, some not) Signed-off-by: Iustin Pop <iustin@google.com> Reviewed-by: Michael Hanselmann <hansmi@google.com> --- lib/cmdlib.py | 10 ++++++++++ man/gnt-backup.sgml | 10 ++++++++++ scripts/gnt-backup | 23 +++++++++++++++++++++-- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/lib/cmdlib.py b/lib/cmdlib.py index 951621d26..cea239bd0 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 d432b6ef6..ae3122ac6 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 467b37d0a..cbbde51f4 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. -- GitLab