e3c68b
From 87e6ea2cd63898c5d243b0f0c719f4f6347fb829 Mon Sep 17 00:00:00 2001
e3c68b
From: Milind Changire <mchangir@redhat.com>
e3c68b
Date: Thu, 5 Jan 2017 19:53:19 +0530
e3c68b
Subject: [PATCH 347/349] tools/glusterfind: handle offline bricks
e3c68b
e3c68b
Problem:
e3c68b
glusterfind is unable to copy remote output file to local node when a
e3c68b
remove-brick is in progress on the remote node. After copying remote
e3c68b
files, in the --full output listing path, a "sort -u" command is run on
e3c68b
the collected files. However, "sort" exits with an error code if it
e3c68b
finds any file missing.
e3c68b
e3c68b
Solution:
e3c68b
Maintain a map of (pid, output file) when the node commands are started
e3c68b
and remove the mapping for the pid for which the command returns an
e3c68b
error. Use the list of files present in the map for the "sort" command.
e3c68b
e3c68b
Backport of:
e3c68b
> Patch: https://review.gluster.org/16332
e3c68b
> Change-Id: Ie6e019037379f4cb163f24b1c65eb382efc2fb3b
e3c68b
> fixes: bz#1410439
e3c68b
> Signed-off-by: Milind Changire <mchangir@redhat.com>
e3c68b
> Signed-off-by: Shwetha K Acharya <sacharya@redhat.com>
e3c68b
e3c68b
BUG: 1789447
e3c68b
Change-Id: Ie6e019037379f4cb163f24b1c65eb382efc2fb3b
e3c68b
Signed-off-by: Kotresh HR <khiremat@redhat.com>
e3c68b
Reviewed-on: https://code.engineering.redhat.com/gerrit/189214
e3c68b
Tested-by: RHGS Build Bot <nigelb@redhat.com>
e3c68b
Reviewed-by: Sunny Kumar <sunkumar@redhat.com>
e3c68b
---
e3c68b
 tools/glusterfind/src/gfind_py2py3.py | 25 ++++++++++++++
e3c68b
 tools/glusterfind/src/main.py         | 61 +++++++++++++++++++++--------------
e3c68b
 2 files changed, 61 insertions(+), 25 deletions(-)
e3c68b
e3c68b
diff --git a/tools/glusterfind/src/gfind_py2py3.py b/tools/glusterfind/src/gfind_py2py3.py
e3c68b
index 1d41ec5..87324fb 100644
e3c68b
--- a/tools/glusterfind/src/gfind_py2py3.py
e3c68b
+++ b/tools/glusterfind/src/gfind_py2py3.py
e3c68b
@@ -40,6 +40,19 @@ if sys.version_info >= (3,):
e3c68b
     def gfind_history_changelog_done(libgfc, clfile):
e3c68b
         return libgfc.gf_history_changelog_done(clfile.encode())
e3c68b
 
e3c68b
+    def gfind_write_row(f, row, field_separator, p_rep, row_2_rep):
e3c68b
+        f.write(u"{0}{1}{2}{3}{4}\n".format(row,
e3c68b
+                                            field_separator,
e3c68b
+                                            p_rep,
e3c68b
+                                            field_separator,
e3c68b
+                                            row_2_rep))
e3c68b
+
e3c68b
+    def gfind_write(f, row, field_separator, p_rep):
e3c68b
+        f.write(u"{0}{1}{2}\n".format(row,
e3c68b
+                                      field_separator,
e3c68b
+                                      p_rep))
e3c68b
+
e3c68b
+
e3c68b
 else:
e3c68b
 
e3c68b
     # Raw conversion of bytearray to string
e3c68b
@@ -61,3 +74,15 @@ else:
e3c68b
 
e3c68b
     def gfind_history_changelog_done(libgfc, clfile):
e3c68b
         return libgfc.gf_history_changelog_done(clfile)
e3c68b
+
e3c68b
+    def gfind_write_row(f, row, field_separator, p_rep, row_2_rep):
e3c68b
+        f.write(u"{0}{1}{2}{3}{4}\n".format(row,
e3c68b
+                                            field_separator,
e3c68b
+                                            p_rep,
e3c68b
+                                            field_separator,
e3c68b
+                                            row_2_rep).encode())
e3c68b
+
e3c68b
+    def gfind_write(f, row, field_separator, p_rep):
e3c68b
+        f.write(u"{0}{1}{2}\n".format(row,
e3c68b
+                                      field_separator,
e3c68b
+                                      p_rep).encode())
e3c68b
diff --git a/tools/glusterfind/src/main.py b/tools/glusterfind/src/main.py
e3c68b
index cc5a86f..fefe4a3 100644
e3c68b
--- a/tools/glusterfind/src/main.py
e3c68b
+++ b/tools/glusterfind/src/main.py
e3c68b
@@ -16,6 +16,7 @@ from multiprocessing import Process
e3c68b
 import os
e3c68b
 import xml.etree.cElementTree as etree
e3c68b
 from argparse import ArgumentParser, RawDescriptionHelpFormatter, Action
e3c68b
+from gfind_py2py3 import gfind_write_row, gfind_write
e3c68b
 import logging
e3c68b
 import shutil
e3c68b
 import tempfile
e3c68b
@@ -35,9 +36,9 @@ GlusterFS Incremental API
e3c68b
 ParseError = etree.ParseError if hasattr(etree, 'ParseError') else SyntaxError
e3c68b
 
e3c68b
 logger = logging.getLogger()
e3c68b
-node_outfiles = []
e3c68b
 vol_statusStr = ""
e3c68b
 gtmpfilename = None
e3c68b
+g_pid_nodefile_map = {}
e3c68b
 
e3c68b
 
e3c68b
 class StoreAbsPath(Action):
e3c68b
@@ -111,7 +112,7 @@ def node_cmd(host, host_uuid, task, cmd, args, opts):
e3c68b
 
e3c68b
 
e3c68b
 def run_cmd_nodes(task, args, **kwargs):
e3c68b
-    global node_outfiles
e3c68b
+    global g_pid_nodefile_map
e3c68b
     nodes = get_nodes(args.volume)
e3c68b
     pool = []
e3c68b
     for num, node in enumerate(nodes):
e3c68b
@@ -142,7 +143,6 @@ def run_cmd_nodes(task, args, **kwargs):
e3c68b
                 if tag == "":
e3c68b
                     tag = '""' if not is_host_local(host_uuid) else ""
e3c68b
 
e3c68b
-            node_outfiles.append(node_outfile)
e3c68b
             # remote file will be copied into this directory
e3c68b
             mkdirp(os.path.dirname(node_outfile),
e3c68b
                    exit_on_err=True, logger=logger)
e3c68b
@@ -180,7 +180,6 @@ def run_cmd_nodes(task, args, **kwargs):
e3c68b
                 if tag == "":
e3c68b
                     tag = '""' if not is_host_local(host_uuid) else ""
e3c68b
 
e3c68b
-            node_outfiles.append(node_outfile)
e3c68b
             # remote file will be copied into this directory
e3c68b
             mkdirp(os.path.dirname(node_outfile),
e3c68b
                    exit_on_err=True, logger=logger)
e3c68b
@@ -264,6 +263,7 @@ def run_cmd_nodes(task, args, **kwargs):
e3c68b
                         args=(host, host_uuid, task, cmd, args, opts))
e3c68b
             p.start()
e3c68b
             pool.append(p)
e3c68b
+            g_pid_nodefile_map[p.pid] = node_outfile
e3c68b
 
e3c68b
     for num, p in enumerate(pool):
e3c68b
         p.join()
e3c68b
@@ -271,8 +271,11 @@ def run_cmd_nodes(task, args, **kwargs):
e3c68b
             logger.warn("Command %s failed in %s" % (task, nodes[num][1]))
e3c68b
             if task in ["create", "delete"]:
e3c68b
                 fail("Command %s failed in %s" % (task, nodes[num][1]))
e3c68b
-            elif task == "pre" and args.disable_partial:
e3c68b
-                sys.exit(1)
e3c68b
+            elif task == "pre" or task == "query":
e3c68b
+                if args.disable_partial:
e3c68b
+                    sys.exit(1)
e3c68b
+                else:
e3c68b
+                    del g_pid_nodefile_map[p.pid]
e3c68b
 
e3c68b
 
e3c68b
 @cache_output
e3c68b
@@ -512,16 +515,10 @@ def write_output(outfile, outfilemerger, field_separator):
e3c68b
                     continue
e3c68b
 
e3c68b
                 if row_2_rep and row_2_rep != "":
e3c68b
-                    f.write(u"{0}{1}{2}{3}{4}\n".format(row[0],
e3c68b
-                                                        field_separator,
e3c68b
-                                                        p_rep,
e3c68b
-                                                        field_separator,
e3c68b
-                                                        row_2_rep).encode())
e3c68b
-                else:
e3c68b
-                    f.write(u"{0}{1}{2}\n".format(row[0],
e3c68b
-                                                  field_separator,
e3c68b
-                                                  p_rep).encode())
e3c68b
+                    gfind_write_row(f, row[0], field_separator, p_rep, field_separator, row_2_rep)
e3c68b
 
e3c68b
+                else:
e3c68b
+                    gfind_write(f, row[0], field_separator, p_rep)
e3c68b
 
e3c68b
 def mode_create(session_dir, args):
e3c68b
     logger.debug("Init is called - Session: %s, Volume: %s"
e3c68b
@@ -571,6 +568,7 @@ def mode_create(session_dir, args):
e3c68b
 
e3c68b
 def mode_query(session_dir, args):
e3c68b
     global gtmpfilename
e3c68b
+    global g_pid_nodefile_map
e3c68b
 
e3c68b
     # Verify volume status
e3c68b
     cmd = ["gluster", 'volume', 'info', args.volume, "--xml"]
e3c68b
@@ -634,14 +632,20 @@ def mode_query(session_dir, args):
e3c68b
 
e3c68b
     # Merger
e3c68b
     if args.full:
e3c68b
-        cmd = ["sort", "-u"] + node_outfiles + ["-o", args.outfile]
e3c68b
-        execute(cmd,
e3c68b
-                exit_msg="Failed to merge output files "
e3c68b
-                "collected from nodes", logger=logger)
e3c68b
+        if len(g_pid_nodefile_map) > 0:
e3c68b
+            cmd = ["sort", "-u"] + g_pid_nodefile_map.values() + \
e3c68b
+                  ["-o", args.outfile]
e3c68b
+            execute(cmd,
e3c68b
+                    exit_msg="Failed to merge output files "
e3c68b
+                    "collected from nodes", logger=logger)
e3c68b
+        else:
e3c68b
+            fail("Failed to collect any output files from peers. "
e3c68b
+                 "Looks like all bricks are offline.", logger=logger)
e3c68b
     else:
e3c68b
         # Read each Changelogs db and generate finaldb
e3c68b
         create_file(args.outfile, exit_on_err=True, logger=logger)
e3c68b
-        outfilemerger = OutputMerger(args.outfile + ".db", node_outfiles)
e3c68b
+        outfilemerger = OutputMerger(args.outfile + ".db",
e3c68b
+                                     g_pid_nodefile_map.values())
e3c68b
         write_output(args.outfile, outfilemerger, args.field_separator)
e3c68b
 
e3c68b
     try:
e3c68b
@@ -656,6 +660,7 @@ def mode_query(session_dir, args):
e3c68b
 
e3c68b
 def mode_pre(session_dir, args):
e3c68b
     global gtmpfilename
e3c68b
+    global g_pid_nodefile_map
e3c68b
 
e3c68b
     """
e3c68b
     Read from Session file and write to session.pre file
e3c68b
@@ -696,14 +701,20 @@ def mode_pre(session_dir, args):
e3c68b
 
e3c68b
     # Merger
e3c68b
     if args.full:
e3c68b
-        cmd = ["sort", "-u"] + node_outfiles + ["-o", args.outfile]
e3c68b
-        execute(cmd,
e3c68b
-                exit_msg="Failed to merge output files "
e3c68b
-                "collected from nodes", logger=logger)
e3c68b
+        if len(g_pid_nodefile_map) > 0:
e3c68b
+            cmd = ["sort", "-u"] + g_pid_nodefile_map.values() + \
e3c68b
+                  ["-o", args.outfile]
e3c68b
+            execute(cmd,
e3c68b
+                    exit_msg="Failed to merge output files "
e3c68b
+                    "collected from nodes", logger=logger)
e3c68b
+        else:
e3c68b
+            fail("Failed to collect any output files from peers. "
e3c68b
+                 "Looks like all bricks are offline.", logger=logger)
e3c68b
     else:
e3c68b
         # Read each Changelogs db and generate finaldb
e3c68b
         create_file(args.outfile, exit_on_err=True, logger=logger)
e3c68b
-        outfilemerger = OutputMerger(args.outfile + ".db", node_outfiles)
e3c68b
+        outfilemerger = OutputMerger(args.outfile + ".db",
e3c68b
+                                     g_pid_nodefile_map.values())
e3c68b
         write_output(args.outfile, outfilemerger, args.field_separator)
e3c68b
 
e3c68b
     try:
e3c68b
-- 
e3c68b
1.8.3.1
e3c68b