From 70192bfe5f7f956843d094ec9cb484b23ce45556 Mon Sep 17 00:00:00 2001 From: Saravanakumar Arumugam Date: Tue, 29 Dec 2015 19:22:36 +0530 Subject: glusterd/geo-rep: slave volume uuid to identify a geo-rep session Problem: Currently, it is possible to create multiple geo-rep session from the Master host to Slave host(s), where Slave host(s) belonging to the same volume. For example: Consider Master Host M1 having volume tv1 and Slave volume tv2, which spans across two Slave hosts S1 and S2. Currently, it is possible to create geo-rep session from M1(tv1) to S1(tv2) as well as from M1(tv1) to S2(tv2). When the Slave Host is alone modified, it is identified as a new geo-rep session (as slave host and slave volume together are identifying Slave side). Also, it is possible to create both root and non-root geo-rep session between same Master volume and Slave volume. This should also be avoided. Solution: This multiple geo-rep session creation must be avoided and in order to avoid, use Slave volume uuid to identify a Slave. This way, we can identify whether a session is already created for the same Slave volume and avoid creating again (using different host). When the session creation is forced in the above scenario, rename the existing geo-rep session directory with new Slave Host mentioned. Change-Id: I9239759cbc0d15dad63c48b8cf62950bb687c7c8 BUG: 1335728 Signed-off-by: Saravanakumar Arumugam Signed-off-by: Aravinda VK Reviewed-on: http://review.gluster.org/13111 Reviewed-by: Kotresh HR Tested-by: Kotresh HR Reviewed-by: Atin Mukherjee (cherry picked from commit a9128cda34b1f696b717ba09fa0ac5a929be8969) Reviewed-on: http://review.gluster.org/14322 Smoke: Gluster Build System NetBSD-regression: NetBSD Build System CentOS-regression: Gluster Build System --- geo-replication/syncdaemon/configinterface.py.in | 12 +++++++ geo-replication/syncdaemon/gsyncd.py | 45 ++++++++++++++++++++++++ 2 files changed, 57 insertions(+) (limited to 'geo-replication') diff --git a/geo-replication/syncdaemon/configinterface.py.in b/geo-replication/syncdaemon/configinterface.py.in index f8df49935f1..0570061955f 100644 --- a/geo-replication/syncdaemon/configinterface.py.in +++ b/geo-replication/syncdaemon/configinterface.py.in @@ -64,6 +64,18 @@ CONFIGS = ( "ignore_deletes", "true", "false"), + ("peersrx . .", + "pid-file", + "@GLUSTERD_WORKDIR@/geo-replication/${mastervol}_${remotehost}_" + "${slavevol}/${eSlave}.pid", + "@GLUSTERD_WORKDIR@/geo-replication/${mastervol}_${remotehost}_" + "${slavevol}/monitor.pid"), + ("peersrx . .", + "state-file", + "@GLUSTERD_WORKDIR@/geo-replication/${mastervol}_${remotehost}_" + "${slavevol}/${eSlave}.status", + "@GLUSTERD_WORKDIR@/geo-replication/${mastervol}_${remotehost}_" + "${slavevol}/monitor.status"), ) diff --git a/geo-replication/syncdaemon/gsyncd.py b/geo-replication/syncdaemon/gsyncd.py index fdb5348d363..1667e97b245 100644 --- a/geo-replication/syncdaemon/gsyncd.py +++ b/geo-replication/syncdaemon/gsyncd.py @@ -32,9 +32,14 @@ from syncdutils import GsyncdError, select, set_term_handler from configinterface import GConffile, upgrade_config_file import resource from monitor import monitor +import xml.etree.ElementTree as XET +from subprocess import PIPE +import subprocess from changelogagent import agent, Changelog from gsyncdstatus import set_monitor_status, GeorepStatus +ParseError = XET.ParseError if hasattr(XET, 'ParseError') else SyntaxError + class GLogger(Logger): @@ -112,6 +117,36 @@ class GLogger(Logger): gconf.log_exit = True +# Given slave host and its volume name, get corresponding volume uuid +def slave_vol_uuid_get(host, vol): + po = subprocess.Popen(['gluster', '--xml', '--remote-host=' + host, + 'volume', 'info', vol], bufsize=0, + stdin=None, stdout=PIPE, stderr=PIPE) + vix, err = po.communicate() + if po.returncode != 0: + logging.info("Volume info failed, unable to get " + "volume uuid of %s present in %s," + "returning empty string: %s" % + (vol, host, po.returncode)) + return "" + vi = XET.fromstring(vix) + if vi.find('opRet').text != '0': + logging.info("Unable to get volume uuid of %s, " + "present in %s returning empty string: %s" % + (vol, host, vi.find('opErrstr').text)) + return "" + + try: + voluuid = vi.find("volInfo/volumes/volume/id").text + except (ParseError, AttributeError, ValueError) as e: + logging.info("Parsing failed to volume uuid of %s, " + "present in %s returning empty string: %s" % + (vol, host, e)) + voluuid = "" + + return voluuid + + def startup(**kw): """set up logging, pidfile grabbing, daemonization""" if getattr(gconf, 'pid_file', None) and kw.get('go_daemon') != 'postconn': @@ -314,6 +349,8 @@ def main_i(): action='callback', callback=store_local_curry('dont')) op.add_option('--verify', type=str, dest="verify", action='callback', callback=store_local) + op.add_option('--slavevoluuid-get', type=str, dest="slavevoluuid_get", + action='callback', callback=store_local) op.add_option('--create', type=str, dest="create", action='callback', callback=store_local) op.add_option('--delete', dest='delete', action='callback', @@ -375,6 +412,14 @@ def main_i(): defaults = op.get_default_values() opts, args = op.parse_args(values=optparse.Values()) args_orig = args[:] + + voluuid_get = rconf.get('slavevoluuid_get') + if voluuid_get: + slave_host, slave_vol = voluuid_get.split("::") + svol_uuid = slave_vol_uuid_get(slave_host, slave_vol) + print svol_uuid + return + r = rconf.get('resource_local') if r: if len(args) == 0: -- cgit