From 4a2441e76f4240568093080769ede07bb7fb2016 Mon Sep 17 00:00:00 2001 From: Kotresh HR Date: Sun, 20 Oct 2019 01:01:39 +0530 Subject: [PATCH 311/313] geo-rep: Fix Permission denied traceback on non root setup Problem: While syncing rename of directory in hybrid crawl, geo-rep crashes as below. Traceback (most recent call last): File "/usr/local/libexec/glusterfs/python/syncdaemon/repce.py", line 118, in worker res = getattr(self.obj, rmeth)(*in_data[2:]) File "/usr/local/libexec/glusterfs/python/syncdaemon/resource.py", line 588, in entry_ops src_entry = get_slv_dir_path(slv_host, slv_volume, gfid) File "/usr/local/libexec/glusterfs/python/syncdaemon/syncdutils.py", line 687, in get_slv_dir_path [ENOENT], [ESTALE]) File "/usr/local/libexec/glusterfs/python/syncdaemon/syncdutils.py", line 546, in errno_wrap return call(*arg) PermissionError: [Errno 13] Permission denied: '/bricks/brick1/b1/.glusterfs/8e/c0/8ec0fcd4-d50f-4a6e-b473-a7943ab66640' Cause: Conversion of gfid to path for a directory uses readlink on backend .glusterfs gfid path. But this fails for non root user with permission denied. Fix: Use gfid2path interface to get the path from gfid Backport of: > Patch: https://review.gluster.org/23570 > Change-Id: I9d40c713a1b32cea95144cbc0f384ada82972222 > fixes: bz#1763439 > Signed-off-by: Kotresh HR Change-Id: I9d40c713a1b32cea95144cbc0f384ada82972222 BUG: 1763412 Signed-off-by: Kotresh HR Reviewed-on: https://code.engineering.redhat.com/gerrit/183665 Tested-by: RHGS Build Bot Reviewed-by: Sunil Kumar Heggodu Gopala Acharya --- geo-replication/syncdaemon/gsyncd.py | 3 +- geo-replication/syncdaemon/syncdutils.py | 35 ++++++++++++++++------ tests/00-geo-rep/00-georep-verify-non-root-setup.t | 30 +++++++++++++++---- 3 files changed, 52 insertions(+), 16 deletions(-) diff --git a/geo-replication/syncdaemon/gsyncd.py b/geo-replication/syncdaemon/gsyncd.py index 7b48d82..8940384 100644 --- a/geo-replication/syncdaemon/gsyncd.py +++ b/geo-replication/syncdaemon/gsyncd.py @@ -231,7 +231,8 @@ def main(): # Set default path for config file in that case # If an subcmd accepts config file then it also accepts # master and Slave arguments. - if config_file is None and hasattr(args, "config_file"): + if config_file is None and hasattr(args, "config_file") \ + and args.subcmd != "slave": config_file = "%s/geo-replication/%s_%s_%s/gsyncd.conf" % ( GLUSTERD_WORKDIR, args.master, diff --git a/geo-replication/syncdaemon/syncdutils.py b/geo-replication/syncdaemon/syncdutils.py index aadaebd..b08098e 100644 --- a/geo-replication/syncdaemon/syncdutils.py +++ b/geo-replication/syncdaemon/syncdutils.py @@ -57,6 +57,7 @@ from hashlib import sha256 as sha256 # auxiliary gfid based access prefix _CL_AUX_GFID_PFX = ".gfid/" +ROOT_GFID = "00000000-0000-0000-0000-000000000001" GF_OP_RETRIES = 10 GX_GFID_CANONICAL_LEN = 37 # canonical gfid len + '\0' @@ -670,6 +671,7 @@ def get_slv_dir_path(slv_host, slv_volume, gfid): global slv_bricks dir_path = ENOENT + pfx = gauxpfx() if not slv_bricks: slv_info = Volinfo(slv_volume, slv_host, master=False) @@ -683,15 +685,30 @@ def get_slv_dir_path(slv_host, slv_volume, gfid): gfid[2:4], gfid], [ENOENT], [ESTALE]) if dir_path != ENOENT: - realpath = errno_wrap(os.readlink, [dir_path], - [ENOENT], [ESTALE]) - if not isinstance(realpath, int): - realpath_parts = realpath.split('/') - pargfid = realpath_parts[-2] - basename = realpath_parts[-1] - pfx = gauxpfx() - dir_entry = os.path.join(pfx, pargfid, basename) - return dir_entry + try: + realpath = errno_wrap(os.readlink, [dir_path], + [ENOENT], [ESTALE]) + if not isinstance(realpath, int): + realpath_parts = realpath.split('/') + pargfid = realpath_parts[-2] + basename = realpath_parts[-1] + dir_entry = os.path.join(pfx, pargfid, basename) + return dir_entry + except OSError: + # .gfid/GFID + gfidpath = unescape_space_newline(os.path.join(pfx, gfid)) + realpath = errno_wrap(Xattr.lgetxattr_buf, + [gfidpath, 'glusterfs.gfid2path'], [ENOENT], [ESTALE]) + if not isinstance(realpath, int): + basename = os.path.basename(realpath).rstrip('\x00') + dirpath = os.path.dirname(realpath) + if dirpath is "/": + pargfid = ROOT_GFID + else: + dirpath = dirpath.strip("/") + pargfid = get_gfid_from_mnt(dirpath) + dir_entry = os.path.join(pfx, pargfid, basename) + return dir_entry return None diff --git a/tests/00-geo-rep/00-georep-verify-non-root-setup.t b/tests/00-geo-rep/00-georep-verify-non-root-setup.t index e753c1f..c9fd8b2 100644 --- a/tests/00-geo-rep/00-georep-verify-non-root-setup.t +++ b/tests/00-geo-rep/00-georep-verify-non-root-setup.t @@ -118,8 +118,8 @@ clean_lock_files TEST /usr/sbin/groupadd $grp clean_lock_files -##Create non-root user and assign it to newly created group - +##Del if exists and create non-root user and assign it to newly created group +userdel -r -f $usr TEST /usr/sbin/useradd -G $grp $usr ##Modify password for non-root user to have control over distributing ssh-key @@ -140,8 +140,6 @@ TEST killall_gluster; TEST glusterd; TEST pidof glusterd; - - ##Create, start and mount meta_volume TEST $CLI volume create $META_VOL replica 3 $H0:$B0/${META_VOL}{1,2,3}; TEST $CLI volume start $META_VOL @@ -225,6 +223,26 @@ TEST $GEOREP_CLI $master $slave_url resume #Validate failure of volume stop when geo-rep is running TEST ! $CLI volume stop $GMV0 +#Hybrid directory rename test BZ#1763439 +TEST $GEOREP_CLI $master $slave_url config change_detector xsync +mkdir ${master_mnt}/dir1 +mkdir ${master_mnt}/dir1/dir2 +mkdir ${master_mnt}/dir1/dir3 +mkdir ${master_mnt}/hybrid_d1 + +EXPECT_WITHIN $GEO_REP_TIMEOUT 0 directory_ok ${slave_mnt}/hybrid_d1 +EXPECT_WITHIN $GEO_REP_TIMEOUT 0 directory_ok ${slave_mnt}/dir1 +EXPECT_WITHIN $GEO_REP_TIMEOUT 0 directory_ok ${slave_mnt}/dir1/dir2 +EXPECT_WITHIN $GEO_REP_TIMEOUT 0 directory_ok ${slave_mnt}/dir1/dir3 + +mv ${master_mnt}/hybrid_d1 ${master_mnt}/hybrid_rn_d1 +mv ${master_mnt}/dir1/dir2 ${master_mnt}/rn_dir2 +mv ${master_mnt}/dir1/dir3 ${master_mnt}/dir1/rn_dir3 + +EXPECT_WITHIN $GEO_REP_TIMEOUT 0 directory_ok ${slave_mnt}/hybrid_rn_d1 +EXPECT_WITHIN $GEO_REP_TIMEOUT 0 directory_ok ${slave_mnt}/rn_dir2 +EXPECT_WITHIN $GEO_REP_TIMEOUT 0 directory_ok ${slave_mnt}/dir1/rn_dir3 + #Stop Geo-rep TEST $GEOREP_CLI $master $slave_url stop @@ -232,8 +250,8 @@ TEST $GEOREP_CLI $master $slave_url stop TEST $GEOREP_CLI $master $slave_url delete #Cleanup authorized_keys -sed -i '/^command=.*SSH_ORIGINAL_COMMAND#.*/d' ~/.ssh/authorized_keys -sed -i '/^command=.*gsyncd.*/d' ~/.ssh/authorized_keys +sed -i '/^command=.*SSH_ORIGINAL_COMMAND#.*/d' /home/$usr/.ssh/authorized_keys +sed -i '/^command=.*gsyncd.*/d' /home/$usr/.ssh/authorized_keys #clear mountbroker gluster-mountbroker remove --user $usr -- 1.8.3.1