|
|
3604df |
From 62ad86bf93d94212eddbb50b010f5bd2908e9600 Mon Sep 17 00:00:00 2001
|
|
|
3604df |
From: Milind Changire <mchangir@redhat.com>
|
|
|
3604df |
Date: Wed, 26 Oct 2016 15:28:14 +0530
|
|
|
3604df |
Subject: [PATCH 145/157] tools/glusterfind: kill remote processes and separate run-time directories
|
|
|
3604df |
|
|
|
3604df |
Problem #1:
|
|
|
3604df |
Hitting CTRL+C leaves stale processes on remote nodes if glusterfind pre
|
|
|
3604df |
has been initiated.
|
|
|
3604df |
|
|
|
3604df |
Solution #1:
|
|
|
3604df |
Adding "-t -t" to ssh command-line forces pseudo-terminal to be assigned
|
|
|
3604df |
to remote process. When local process receives Keyboard Interrupt,
|
|
|
3604df |
SIGHUP is immediately conveyed to the remote terminal causing remote
|
|
|
3604df |
changelog.py process to terminate immediately.
|
|
|
3604df |
|
|
|
3604df |
Problem #2:
|
|
|
3604df |
Concurrent glusterfind pre runs are not possible on the same glusterfind
|
|
|
3604df |
session in case of a runaway process.
|
|
|
3604df |
|
|
|
3604df |
Solution #2:
|
|
|
3604df |
glusterfind pre runs now add random directory name to the working
|
|
|
3604df |
directory to store and manage temporary database and changelog
|
|
|
3604df |
processing.
|
|
|
3604df |
If KeyboardInterrupt is received, the function call
|
|
|
3604df |
run_cmd_nodes("cleanup", args, tmpfilename=gtmpfilename)
|
|
|
3604df |
cleans up the remote run specific directory.
|
|
|
3604df |
|
|
|
3604df |
Patch:
|
|
|
3604df |
7571380 cli/xml: Fix wrong XML format in volume get command
|
|
|
3604df |
broke "gluster volume get <vol> changelog.rollover-time --xml"
|
|
|
3604df |
Now fixed function utils.py::get_changelog_rollover_time()
|
|
|
3604df |
|
|
|
3604df |
Fixed spurious trailing space getting written if second path is empty in
|
|
|
3604df |
main.py::write_output()
|
|
|
3604df |
Fixed repetitive changelog processing in changelog.py::get_changes()
|
|
|
3604df |
|
|
|
3604df |
mainline:
|
|
|
3604df |
> > Reviewed-on: http://review.gluster.org/15609
|
|
|
3604df |
> > Smoke: Gluster Build System <jenkins@build.gluster.org>
|
|
|
3604df |
> > CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
|
|
|
3604df |
> > NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
|
|
|
3604df |
> > Reviewed-by: Aravinda VK <avishwan@redhat.com>
|
|
|
3604df |
(cherry picked from commit feea851fad4f89b48bfe89fe3b75250cc7bd6501)
|
|
|
3604df |
|
|
|
3604df |
release-3.9:
|
|
|
3604df |
> Reviewed-on: http://review.gluster.org/15729
|
|
|
3604df |
> Smoke: Gluster Build System <jenkins@build.gluster.org>
|
|
|
3604df |
> NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
|
|
|
3604df |
> CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
|
|
|
3604df |
> Reviewed-by: Aravinda VK <avishwan@redhat.com>
|
|
|
3604df |
(cherry picked from commit 915ae56a65d5a96bfddf977193dca60535ac7c11)
|
|
|
3604df |
|
|
|
3604df |
Change-Id: Ia8d96e2cd47bf2a64416bece312e67631a1dbf29
|
|
|
3604df |
BUG: 1379790
|
|
|
3604df |
Signed-off-by: Milind Changire <mchangir@redhat.com>
|
|
|
3604df |
Reviewed-on: https://code.engineering.redhat.com/gerrit/88272
|
|
|
3604df |
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
|
|
|
3604df |
---
|
|
|
3604df |
tools/glusterfind/src/changelog.py | 2 +-
|
|
|
3604df |
tools/glusterfind/src/main.py | 68 +++++++++++++++++++++++++++++-------
|
|
|
3604df |
tools/glusterfind/src/nodeagent.py | 4 ++-
|
|
|
3604df |
tools/glusterfind/src/utils.py | 2 +-
|
|
|
3604df |
4 files changed, 60 insertions(+), 16 deletions(-)
|
|
|
3604df |
|
|
|
3604df |
diff --git a/tools/glusterfind/src/changelog.py b/tools/glusterfind/src/changelog.py
|
|
|
3604df |
index 283a035..721b8d0 100644
|
|
|
3604df |
--- a/tools/glusterfind/src/changelog.py
|
|
|
3604df |
+++ b/tools/glusterfind/src/changelog.py
|
|
|
3604df |
@@ -284,7 +284,7 @@ def get_changes(brick, hash_dir, log_file, start, end, args):
|
|
|
3604df |
# history_getchanges()
|
|
|
3604df |
changes = []
|
|
|
3604df |
while libgfchangelog.cl_history_scan() > 0:
|
|
|
3604df |
- changes += libgfchangelog.cl_history_getchanges()
|
|
|
3604df |
+ changes = libgfchangelog.cl_history_getchanges()
|
|
|
3604df |
|
|
|
3604df |
for change in changes:
|
|
|
3604df |
# Ignore if last processed changelog comes
|
|
|
3604df |
diff --git a/tools/glusterfind/src/main.py b/tools/glusterfind/src/main.py
|
|
|
3604df |
index 37d6c38..0c993f5 100644
|
|
|
3604df |
--- a/tools/glusterfind/src/main.py
|
|
|
3604df |
+++ b/tools/glusterfind/src/main.py
|
|
|
3604df |
@@ -18,6 +18,9 @@ import xml.etree.cElementTree as etree
|
|
|
3604df |
from argparse import ArgumentParser, RawDescriptionHelpFormatter, Action
|
|
|
3604df |
import logging
|
|
|
3604df |
import shutil
|
|
|
3604df |
+import tempfile
|
|
|
3604df |
+import signal
|
|
|
3604df |
+from datetime import datetime
|
|
|
3604df |
|
|
|
3604df |
from utils import execute, is_host_local, mkdirp, fail
|
|
|
3604df |
from utils import setup_logger, human_time, handle_rm_error
|
|
|
3604df |
@@ -34,6 +37,7 @@ ParseError = etree.ParseError if hasattr(etree, 'ParseError') else SyntaxError
|
|
|
3604df |
logger = logging.getLogger()
|
|
|
3604df |
node_outfiles = []
|
|
|
3604df |
vol_statusStr = ""
|
|
|
3604df |
+gtmpfilename = None
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
class StoreAbsPath(Action):
|
|
|
3604df |
@@ -71,6 +75,8 @@ def node_cmd(host, host_uuid, task, cmd, args, opts):
|
|
|
3604df |
cmd = ["ssh",
|
|
|
3604df |
"-oNumberOfPasswordPrompts=0",
|
|
|
3604df |
"-oStrictHostKeyChecking=no",
|
|
|
3604df |
+ "-t",
|
|
|
3604df |
+ "-t",
|
|
|
3604df |
"-i", pem_key_path,
|
|
|
3604df |
"root@%s" % host] + cmd
|
|
|
3604df |
|
|
|
3604df |
@@ -98,8 +104,13 @@ def run_cmd_nodes(task, args, **kwargs):
|
|
|
3604df |
host_uuid = node[0]
|
|
|
3604df |
cmd = []
|
|
|
3604df |
opts = {}
|
|
|
3604df |
+
|
|
|
3604df |
+ # tmpfilename is valid only for tasks: pre, query and cleanup
|
|
|
3604df |
+ tmpfilename = kwargs.get("tmpfilename", "BADNAME")
|
|
|
3604df |
+
|
|
|
3604df |
node_outfile = os.path.join(conf.get_opt("working_dir"),
|
|
|
3604df |
args.session, args.volume,
|
|
|
3604df |
+ tmpfilename,
|
|
|
3604df |
"tmp_output_%s" % num)
|
|
|
3604df |
|
|
|
3604df |
if task == "pre":
|
|
|
3604df |
@@ -117,6 +128,9 @@ def run_cmd_nodes(task, args, **kwargs):
|
|
|
3604df |
tag = '""' if not is_host_local(host_uuid) else ""
|
|
|
3604df |
|
|
|
3604df |
node_outfiles.append(node_outfile)
|
|
|
3604df |
+ # remote file will be copied into this directory
|
|
|
3604df |
+ mkdirp(os.path.dirname(node_outfile),
|
|
|
3604df |
+ exit_on_err=True, logger=logger)
|
|
|
3604df |
|
|
|
3604df |
cmd = [change_detector,
|
|
|
3604df |
args.session,
|
|
|
3604df |
@@ -144,6 +158,9 @@ def run_cmd_nodes(task, args, **kwargs):
|
|
|
3604df |
tag = '""' if not is_host_local(host_uuid) else ""
|
|
|
3604df |
|
|
|
3604df |
node_outfiles.append(node_outfile)
|
|
|
3604df |
+ # remote file will be copied into this directory
|
|
|
3604df |
+ mkdirp(os.path.dirname(node_outfile),
|
|
|
3604df |
+ exit_on_err=True, logger=logger)
|
|
|
3604df |
|
|
|
3604df |
cmd = [change_detector,
|
|
|
3604df |
args.session,
|
|
|
3604df |
@@ -162,8 +179,9 @@ def run_cmd_nodes(task, args, **kwargs):
|
|
|
3604df |
opts["node_outfile"] = node_outfile
|
|
|
3604df |
opts["copy_outfile"] = True
|
|
|
3604df |
elif task == "cleanup":
|
|
|
3604df |
- # After pre run, cleanup the working directory and other temp files
|
|
|
3604df |
- # Remove the copied node_outfile in main node
|
|
|
3604df |
+ # After pre/query run, cleanup the working directory and other
|
|
|
3604df |
+ # temp files. Remove the directory to which node_outfile has
|
|
|
3604df |
+ # been copied in main node
|
|
|
3604df |
try:
|
|
|
3604df |
os.remove(node_outfile)
|
|
|
3604df |
except (OSError, IOError):
|
|
|
3604df |
@@ -174,7 +192,9 @@ def run_cmd_nodes(task, args, **kwargs):
|
|
|
3604df |
cmd = [conf.get_opt("nodeagent"),
|
|
|
3604df |
"cleanup",
|
|
|
3604df |
args.session,
|
|
|
3604df |
- args.volume] + (["--debug"] if args.debug else [])
|
|
|
3604df |
+ args.volume,
|
|
|
3604df |
+ os.path.dirname(node_outfile)] + \
|
|
|
3604df |
+ (["--debug"] if args.debug else [])
|
|
|
3604df |
elif task == "create":
|
|
|
3604df |
if vol_statusStr != "Started":
|
|
|
3604df |
fail("Volume %s is not online" % args.volume,
|
|
|
3604df |
@@ -422,8 +442,8 @@ def enable_volume_options(args):
|
|
|
3604df |
% args.volume)
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
-def write_output(args, outfilemerger):
|
|
|
3604df |
- with codecs.open(args.outfile, "a", encoding="utf-8") as f:
|
|
|
3604df |
+def write_output(outfile, outfilemerger):
|
|
|
3604df |
+ with codecs.open(outfile, "a", encoding="utf-8") as f:
|
|
|
3604df |
for row in outfilemerger.get():
|
|
|
3604df |
# Multiple paths in case of Hardlinks
|
|
|
3604df |
paths = row[1].split(",")
|
|
|
3604df |
@@ -438,9 +458,10 @@ def write_output(args, outfilemerger):
|
|
|
3604df |
if p_rep == row_2_rep:
|
|
|
3604df |
continue
|
|
|
3604df |
|
|
|
3604df |
- f.write(u"{0} {1} {2}\n".format(row[0],
|
|
|
3604df |
- p_rep,
|
|
|
3604df |
- row_2_rep))
|
|
|
3604df |
+ if row_2_rep and row_2_rep != "":
|
|
|
3604df |
+ f.write(u"{0} {1} {2}\n".format(row[0], p_rep, row_2_rep))
|
|
|
3604df |
+ else:
|
|
|
3604df |
+ f.write(u"{0} {1}\n".format(row[0], p_rep))
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
def mode_create(session_dir, args):
|
|
|
3604df |
@@ -490,6 +511,8 @@ def mode_create(session_dir, args):
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
def mode_query(session_dir, args):
|
|
|
3604df |
+ global gtmpfilename
|
|
|
3604df |
+
|
|
|
3604df |
# Verify volume status
|
|
|
3604df |
cmd = ["gluster", 'volume', 'info', args.volume, "--xml"]
|
|
|
3604df |
_, data, _ = execute(cmd,
|
|
|
3604df |
@@ -533,7 +556,10 @@ def mode_query(session_dir, args):
|
|
|
3604df |
"Start time: %s"
|
|
|
3604df |
% ("default", args.volume, start))
|
|
|
3604df |
|
|
|
3604df |
- run_cmd_nodes("query", args, start=start)
|
|
|
3604df |
+ prefix = datetime.now().strftime("%Y%m%d-%H%M%S-%f-")
|
|
|
3604df |
+ gtmpfilename = prefix + next(tempfile._get_candidate_names())
|
|
|
3604df |
+
|
|
|
3604df |
+ run_cmd_nodes("query", args, start=start, tmpfilename=gtmpfilename)
|
|
|
3604df |
|
|
|
3604df |
# Merger
|
|
|
3604df |
if args.full:
|
|
|
3604df |
@@ -545,7 +571,7 @@ def mode_query(session_dir, args):
|
|
|
3604df |
# Read each Changelogs db and generate finaldb
|
|
|
3604df |
create_file(args.outfile, exit_on_err=True, logger=logger)
|
|
|
3604df |
outfilemerger = OutputMerger(args.outfile + ".db", node_outfiles)
|
|
|
3604df |
- write_output(args, outfilemerger)
|
|
|
3604df |
+ write_output(args.outfile, outfilemerger)
|
|
|
3604df |
|
|
|
3604df |
try:
|
|
|
3604df |
os.remove(args.outfile + ".db")
|
|
|
3604df |
@@ -558,6 +584,8 @@ def mode_query(session_dir, args):
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
def mode_pre(session_dir, args):
|
|
|
3604df |
+ global gtmpfilename
|
|
|
3604df |
+
|
|
|
3604df |
"""
|
|
|
3604df |
Read from Session file and write to session.pre file
|
|
|
3604df |
"""
|
|
|
3604df |
@@ -587,7 +615,10 @@ def mode_pre(session_dir, args):
|
|
|
3604df |
"Start time: %s, End time: %s"
|
|
|
3604df |
% (args.session, args.volume, start, endtime_to_update))
|
|
|
3604df |
|
|
|
3604df |
- run_cmd_nodes("pre", args, start=start)
|
|
|
3604df |
+ prefix = datetime.now().strftime("%Y%m%d-%H%M%S-%f-")
|
|
|
3604df |
+ gtmpfilename = prefix + next(tempfile._get_candidate_names())
|
|
|
3604df |
+
|
|
|
3604df |
+ run_cmd_nodes("pre", args, start=start, tmpfilename=gtmpfilename)
|
|
|
3604df |
|
|
|
3604df |
# Merger
|
|
|
3604df |
if args.full:
|
|
|
3604df |
@@ -599,8 +630,7 @@ def mode_pre(session_dir, args):
|
|
|
3604df |
# Read each Changelogs db and generate finaldb
|
|
|
3604df |
create_file(args.outfile, exit_on_err=True, logger=logger)
|
|
|
3604df |
outfilemerger = OutputMerger(args.outfile + ".db", node_outfiles)
|
|
|
3604df |
-
|
|
|
3604df |
- write_output(args, outfilemerger)
|
|
|
3604df |
+ write_output(args.outfile, outfilemerger)
|
|
|
3604df |
|
|
|
3604df |
try:
|
|
|
3604df |
os.remove(args.outfile + ".db")
|
|
|
3604df |
@@ -713,6 +743,10 @@ def mode_list(session_dir, args):
|
|
|
3604df |
|
|
|
3604df |
|
|
|
3604df |
def main():
|
|
|
3604df |
+ global gtmpfilename
|
|
|
3604df |
+
|
|
|
3604df |
+ args = None
|
|
|
3604df |
+
|
|
|
3604df |
try:
|
|
|
3604df |
args = _get_args()
|
|
|
3604df |
mkdirp(conf.get_opt("session_dir"), exit_on_err=True)
|
|
|
3604df |
@@ -756,5 +790,13 @@ def main():
|
|
|
3604df |
# mode_<args.mode> will be the function name to be called
|
|
|
3604df |
globals()["mode_" + args.mode](session_dir, args)
|
|
|
3604df |
except KeyboardInterrupt:
|
|
|
3604df |
+ if args is not None:
|
|
|
3604df |
+ if args.mode == "pre" or args.mode == "query":
|
|
|
3604df |
+ # cleanup session
|
|
|
3604df |
+ if gtmpfilename is not None:
|
|
|
3604df |
+ # no more interrupts until we clean up
|
|
|
3604df |
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
|
|
|
3604df |
+ run_cmd_nodes("cleanup", args, tmpfilename=gtmpfilename)
|
|
|
3604df |
+
|
|
|
3604df |
# Interrupted, exit with non zero error code
|
|
|
3604df |
sys.exit(2)
|
|
|
3604df |
diff --git a/tools/glusterfind/src/nodeagent.py b/tools/glusterfind/src/nodeagent.py
|
|
|
3604df |
index f707449..07d8282 100644
|
|
|
3604df |
--- a/tools/glusterfind/src/nodeagent.py
|
|
|
3604df |
+++ b/tools/glusterfind/src/nodeagent.py
|
|
|
3604df |
@@ -26,7 +26,8 @@ logger = logging.getLogger()
|
|
|
3604df |
def mode_cleanup(args):
|
|
|
3604df |
working_dir = os.path.join(conf.get_opt("working_dir"),
|
|
|
3604df |
args.session,
|
|
|
3604df |
- args.volume)
|
|
|
3604df |
+ args.volume,
|
|
|
3604df |
+ args.tmpfilename)
|
|
|
3604df |
|
|
|
3604df |
mkdirp(os.path.join(conf.get_opt("log_dir"), args.session, args.volume),
|
|
|
3604df |
exit_on_err=True)
|
|
|
3604df |
@@ -98,6 +99,7 @@ def _get_args():
|
|
|
3604df |
parser_cleanup = subparsers.add_parser('cleanup')
|
|
|
3604df |
parser_cleanup.add_argument("session", help="Session Name")
|
|
|
3604df |
parser_cleanup.add_argument("volume", help="Volume Name")
|
|
|
3604df |
+ parser_cleanup.add_argument("tmpfilename", help="Temporary File Name")
|
|
|
3604df |
parser_cleanup.add_argument("--debug", help="Debug", action="store_true")
|
|
|
3604df |
|
|
|
3604df |
parser_session_create = subparsers.add_parser('create')
|
|
|
3604df |
diff --git a/tools/glusterfind/src/utils.py b/tools/glusterfind/src/utils.py
|
|
|
3604df |
index 598cc9e..70737be 100644
|
|
|
3604df |
--- a/tools/glusterfind/src/utils.py
|
|
|
3604df |
+++ b/tools/glusterfind/src/utils.py
|
|
|
3604df |
@@ -227,7 +227,7 @@ def get_changelog_rollover_time(volumename):
|
|
|
3604df |
|
|
|
3604df |
try:
|
|
|
3604df |
tree = etree.fromstring(out)
|
|
|
3604df |
- return int(tree.find('volGetopts/Value').text)
|
|
|
3604df |
+ return int(tree.find('volGetopts/Opt/Value').text)
|
|
|
3604df |
except ParseError:
|
|
|
3604df |
return DEFAULT_CHANGELOG_INTERVAL
|
|
|
3604df |
|
|
|
3604df |
--
|
|
|
3604df |
1.7.1
|
|
|
3604df |
|