summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMohit Agrawal <moagrawal@redhat.com>2018-08-04 12:05:03 +0530
committerAtin Mukherjee <amukherj@redhat.com>2018-08-10 17:51:37 +0000
commitbd8fc26a278697c30537d879ea5402db7ebab577 (patch)
tree65772cd64d48429c9e8ee90a9e1ee934cdee04b0
parenta6900e829484435c5bd5d8efe38490cab54ac442 (diff)
glusterd: Compare volume_id before start/attach a brick
Problem: After reboot a node brick is not coming up because fsid comparison is failed before start a brick Solution: Instead of comparing fsid compare volume_id to resolve the same because fsid is changed after reboot a node but volume_id persist as a xattr on brick_root path at the time of creating a volume. Change-Id: Ic289aab1b4ebfd83bbcae8438fee26ae61a0fff4 fixes: bz#1612418 Signed-off-by: Mohit Agrawal <moagrawal@redhat.com>
-rw-r--r--tests/bugs/glusterd/bug-1595320.t (renamed from tests/basic/bug-1595320.t)9
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-utils.c47
2 files changed, 32 insertions, 24 deletions
diff --git a/tests/basic/bug-1595320.t b/tests/bugs/glusterd/bug-1595320.t
index 9d856eeadec..f41df9d0ffa 100644
--- a/tests/basic/bug-1595320.t
+++ b/tests/bugs/glusterd/bug-1595320.t
@@ -1,8 +1,8 @@
#!/bin/bash
-. $(dirname $0)/../include.rc
-. $(dirname $0)/../volume.rc
-. $(dirname $0)/../snapshot.rc
+. $(dirname $0)/../../include.rc
+. $(dirname $0)/../../volume.rc
+. $(dirname $0)/../../snapshot.rc
cleanup
@@ -52,7 +52,7 @@ EXPECT 0 count_brick_processes
# Unmount 3rd brick root from node
brick_root=$L3
-TEST umount -l $brick_root 2>/dev/null
+_umount_lv 3
# Start the volume only 2 brick should be start
TEST $CLI volume start $V0 force
@@ -70,6 +70,7 @@ n=`ls -lrth /proc/$brick_pid/fd | grep -iw $L3 | grep -v ".glusterfs" | wc -l`
TEST [ $n -eq 0 ]
# Mount the brick root
+TEST mkdir -p $brick_root
TEST mount -t xfs -o nouuid /dev/test_vg_3/brick_lvm $brick_root
# Replace brick_pid file to test brick_attach code
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c
index 0ac075bcc87..352e445e28b 100644
--- a/xlators/mgmt/glusterd/src/glusterd-utils.c
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.c
@@ -5522,6 +5522,12 @@ attach_brick_callback (struct rpc_req *req, struct iovec *iov, int count,
frame->local = NULL;
frame->cookie = NULL;
+ if (!iov) {
+ gf_log (frame->this->name, GF_LOG_ERROR, "iov is NULL");
+ ret = -1;
+ goto out;
+ }
+
ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_getspec_rsp);
if (ret < 0) {
gf_log (frame->this->name, GF_LOG_ERROR, "XDR decoding error");
@@ -6164,17 +6170,19 @@ glusterd_brick_start (glusterd_volinfo_t *volinfo,
gf_boolean_t wait,
gf_boolean_t only_connect)
{
- int ret = -1;
+ int ret = -1;
xlator_t *this = NULL;
glusterd_brickinfo_t *other_brick;
glusterd_conf_t *conf = NULL;
- int32_t pid = -1;
- char pidfile[PATH_MAX] = {0};
- char socketpath[PATH_MAX] = {0};
- char *brickpath = NULL;
+ int32_t pid = -1;
+ char pidfile[PATH_MAX] = {0};
+ char socketpath[PATH_MAX] = {0};
+ char *brickpath = NULL;
glusterd_volinfo_t *other_vol;
- struct statvfs brickstat = {0,};
gf_boolean_t is_service_running = _gf_false;
+ uuid_t volid = {0,};
+ ssize_t size = -1;
+
this = THIS;
GF_ASSERT (this);
@@ -6221,24 +6229,23 @@ glusterd_brick_start (glusterd_volinfo_t *volinfo,
GLUSTERD_GET_BRICK_PIDFILE (pidfile, volinfo, brickinfo, conf);
- ret = sys_statvfs (brickinfo->path, &brickstat);
- if (ret) {
- gf_msg (this->name, GF_LOG_ERROR,
- errno, GD_MSG_BRICKINFO_CREATE_FAIL,
- "failed to get statfs() call on brick %s",
- brickinfo->path);
+ /* Compare volume-id xattr is helpful to ensure the existence of a brick_root
+ path before the start/attach a brick
+ */
+ size = sys_lgetxattr (brickinfo->path, GF_XATTR_VOL_ID_KEY, volid, 16);
+ if (size != 16) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Missing %s extended attribute on brick root (%s),"
+ " brick is deemed not to be a part of the volume (%s) ",
+ GF_XATTR_VOL_ID_KEY, brickinfo->path, volinfo->volname);
goto out;
}
- /* Compare fsid is helpful to ensure the existence of a brick_root
- path before the start/attach a brick
- */
- if (brickinfo->statfs_fsid &&
- (brickinfo->statfs_fsid != brickstat.f_fsid)) {
+ if (strncmp (uuid_utoa (volinfo->volume_id), uuid_utoa(volid), GF_UUID_BUF_SIZE)) {
gf_log (this->name, GF_LOG_ERROR,
- "fsid comparison is failed it means Brick root path"
- " %s is not created by glusterd, start/attach will also fail",
- brickinfo->path);
+ "Mismatching %s extended attribute on brick root (%s),"
+ " brick is deemed not to be a part of the volume (%s)",
+ GF_XATTR_VOL_ID_KEY, brickinfo->path, volinfo->volname);
goto out;
}
is_service_running = gf_is_service_running (pidfile, &pid);
class='add'>+ not confdata.rx:
+ checkpoint_change = True
+ if not checkpoint_change:
+ return
gconf.__dict__.update(defaults.__dict__)
gcnf.update_to(gconf.__dict__)
@@ -331,6 +345,14 @@ def main_i():
raise GsyncdError('cannot recognize log level "%s"' % lvl0)
gconf.log_level = lvl2
+ if checkpoint_change:
+ GLogger._gsyncd_loginit(log_file=gconf.log_file, label='conf')
+ if confdata.op == 'set':
+ logging.info('checkpoint %s set' % confdata.val)
+ elif confdata.op == 'del':
+ logging.info('checkpoint info was reset')
+ return
+
go_daemon = rconf['go_daemon']
be_monitor = rconf.get('monitor')
diff --git a/xlators/features/marker/utils/syncdaemon/master.py b/xlators/features/marker/utils/syncdaemon/master.py
index 8e196f8c5f4..4826037f134 100644
--- a/xlators/features/marker/utils/syncdaemon/master.py
+++ b/xlators/features/marker/utils/syncdaemon/master.py
@@ -5,12 +5,20 @@ import stat
import random
import signal
import logging
+import socket
import errno
-from errno import ENOENT, ENODATA
+from errno import ENOENT, ENODATA, EPIPE
from threading import currentThread, Condition, Lock
+from datetime import datetime
+try:
+ from hashlib import md5 as md5
+except ImportError:
+ # py 2.4
+ from md5 import new as md5
from gconf import gconf
-from syncdutils import FreeObject, Thread, GsyncdError, boolify
+from syncdutils import FreeObject, Thread, GsyncdError, boolify, \
+ escape, unescape, select
URXTIME = (-1, 0)
@@ -113,6 +121,122 @@ class GMaster(object):
# the actual volinfo we make use of
self.volinfo = None
self.terminate = False
+ self.checkpoint_thread = None
+
+ @staticmethod
+ def _checkpt_param(chkpt, prm, timish=True):
+ """use config backend to lookup a parameter belonging to
+ checkpoint @chkpt"""
+ cprm = getattr(gconf, 'checkpoint_' + prm, None)
+ if not cprm:
+ return
+ chkpt_mapped, val = cprm.split(':', 1)
+ if unescape(chkpt_mapped) != chkpt:
+ return
+ if timish:
+ val = tuple(int(x) for x in val.split("."))
+ return val
+
+ @staticmethod
+ def _set_checkpt_param(chkpt, prm, val, timish=True):
+ """use config backend to store a parameter associated
+ with checkpoint @chkpt"""
+ if timish:
+ val = "%d.%d" % tuple(val)
+ gconf.configinterface.set('checkpoint_' + prm, "%s:%s" % (escape(chkpt), val))
+
+ @staticmethod
+ def humantime(*tpair):
+ """format xtime-like (sec, nsec) pair to human readable format"""
+ ts = datetime.fromtimestamp(float('.'.join(str(n) for n in tpair))).\
+ strftime("%Y-%m-%d %H:%M:%S")
+ if len(tpair) > 1:
+ ts += '.' + str(tpair[1])
+ return ts
+
+ def checkpt_service(self, chan, chkpt, tgt):
+ """checkpoint service loop
+
+ monitor and verify checkpoint status for @chkpt, and listen
+ for incoming requests for whom we serve a pretty-formatted
+ status report"""
+ if not chkpt:
+ # dummy loop for the case when there is no checkpt set
+ while True:
+ select([chan], [], [])
+ conn, _ = chan.accept()
+ conn.send('\0')
+ conn.close()
+ completed = self._checkpt_param(chkpt, 'completed')
+ while True:
+ s,_,_ = select([chan], [], [], (not completed) and 5 or None)
+ # either request made and we re-check to not
+ # give back stale data, or we still hunting for completion
+ if tgt < self.volmark:
+ # indexing has been reset since setting the checkpoint
+ status = "is invalid"
+ else:
+ xtr = self.xtime('.', self.slave)
+ if isinstance(xtr, int):
+ raise GsyncdError("slave root directory is unaccessible (%s)",
+ os.strerror(xtr))
+ ncompleted = (xtr >= tgt)
+ if completed and not ncompleted: # stale data
+ logging.warn("completion time %s for checkpoint %s became stale" % \
+ (self.humantime(*completed), chkpt))
+ completed = None
+ gconf.confdata.delete('checkpoint-completed')
+ if ncompleted and not completed: # just reaching completion
+ completed = [ int(x) for x in ("%.6f" % time.time()).split('.') ]
+ self._set_checkpt_param(chkpt, 'completed', completed)
+ logging.info("checkpoint %s completed" % chkpt)
+ status = completed and \
+ "completed at " + self.humantime(completed[0]) or \
+ "not reached yet"
+ if s:
+ conn = None
+ try:
+ conn, _ = chan.accept()
+ try:
+ conn.send(" | checkpoint %s %s\0" % (chkpt, status))
+ except:
+ exc = sys.exc_info()[1]
+ if (isinstance(exc, OSError) or isinstance(exc, IOError)) and \
+ exc.errno == EPIPE:
+ logging.debug('checkpoint client disconnected')
+ else:
+ raise
+ finally:
+ if conn:
+ conn.close()
+
+ def start_checkpoint_thread(self):
+ """prepare and start checkpoint service"""
+ if self.checkpoint_thread or not getattr(gconf, 'state_socket_unencoded', None):
+ return
+ chan = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ state_socket = "/tmp/%s.socket" % md5(gconf.state_socket_unencoded).hexdigest()
+ try:
+ os.unlink(state_socket)
+ except:
+ if sys.exc_info()[0] == OSError:
+ pass
+ chan.bind(state_socket)
+ chan.listen(1)
+ checkpt_tgt = None
+ if gconf.checkpoint:
+ checkpt_tgt = self._checkpt_param(gconf.checkpoint, 'target')
+ if not checkpt_tgt:
+ checkpt_tgt = self.xtime('.')
+ if isinstance(checkpt_tgt, int):
+ raise GsyncdError("master root directory is unaccessible (%s)",
+ os.strerror(checkpt_tgt))
+ self._set_checkpt_param(gconf.checkpoint, 'target', checkpt_tgt)
+ logging.debug("checkpoint target %d.%d has been determined for checkpoint %s" % \
+ (checkpt_tgt[0], checkpt_tgt[1], gconf.checkpoint))
+ t = Thread(target=self.checkpt_service, args=(chan, gconf.checkpoint, checkpt_tgt))
+ t.start()
+ self.checkpoint_thread = t
def crawl_loop(self):
"""start the keep-alive thread and iterate .crawl"""
@@ -291,6 +415,7 @@ class GMaster(object):
if self.volinfo:
if self.volinfo['retval']:
raise GsyncdError ("master is corrupt")
+ self.start_checkpoint_thread()
else:
if should_display_info or self.crawls == 0:
if self.inter_master:
diff --git a/xlators/features/marker/utils/syncdaemon/syncdutils.py b/xlators/features/marker/utils/syncdaemon/syncdutils.py
index f786bc34326..1d4eb20032c 100644
--- a/xlators/features/marker/utils/syncdaemon/syncdutils.py
+++ b/xlators/features/marker/utils/syncdaemon/syncdutils.py
@@ -138,6 +138,12 @@ def finalize(*a, **kw):
raise
if gconf.ssh_ctl_dir and not