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