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