diff options
-rwxr-xr-x | xlators/features/marker/utils/gsyncd.in | 2 | ||||
-rw-r--r-- | xlators/features/marker/utils/syncdaemon/gsyncd.py | 5 | ||||
-rw-r--r-- | xlators/features/marker/utils/syncdaemon/resource.py | 146 | ||||
-rw-r--r-- | xlators/features/marker/utils/syncdaemon/syncdutils.py | 6 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd.c | 84 |
5 files changed, 197 insertions, 46 deletions
diff --git a/xlators/features/marker/utils/gsyncd.in b/xlators/features/marker/utils/gsyncd.in index a7af8c0b0b4..b517b341f96 100755 --- a/xlators/features/marker/utils/gsyncd.in +++ b/xlators/features/marker/utils/gsyncd.in @@ -42,7 +42,7 @@ else fi if [ $config_wanted = 1 ]; then - wd="`${gluster} system:: getwd`" + wd="`${gluster} --log-file=/dev/stderr system:: getwd`" if [ $? -eq 0 ]; then config_file="$wd/geo-replication/gsyncd.conf" fi diff --git a/xlators/features/marker/utils/syncdaemon/gsyncd.py b/xlators/features/marker/utils/syncdaemon/gsyncd.py index c0d39ffd62d..797000970a5 100644 --- a/xlators/features/marker/utils/syncdaemon/gsyncd.py +++ b/xlators/features/marker/utils/syncdaemon/gsyncd.py @@ -139,9 +139,12 @@ def main_i(): return lambda o, oo, vx, p: store_local(o, oo, FreeObject(op=op, **dmake(vx)), p) op = OptionParser(usage="%prog [options...] <master> <slave>", version="%prog 0.0.1") - op.add_option('--gluster-command', metavar='CMD', default='glusterfs') + op.add_option('--gluster-command-dir', metavar='DIR', default='') op.add_option('--gluster-log-file', metavar='LOGF', default=os.devnull, type=str, action='callback', callback=store_abs) op.add_option('--gluster-log-level', metavar='LVL') + op.add_option('--gluster-params', metavar='PRMS', default='') + op.add_option('--gluster-cli-options', metavar='OPTS', default='--log-file=/dev/stderr') + op.add_option('--mountbroker', metavar='LABEL') op.add_option('-p', '--pid-file', metavar='PIDF', type=str, action='callback', callback=store_abs) op.add_option('-l', '--log-file', metavar='LOGF', type=str, action='callback', callback=store_abs) op.add_option('--state-file', metavar='STATF', type=str, action='callback', callback=store_abs) diff --git a/xlators/features/marker/utils/syncdaemon/resource.py b/xlators/features/marker/utils/syncdaemon/resource.py index f92e8573409..b851d661a9e 100644 --- a/xlators/features/marker/utils/syncdaemon/resource.py +++ b/xlators/features/marker/utils/syncdaemon/resource.py @@ -1,7 +1,6 @@ import re import os import sys -import pwd import stat import time import errno @@ -579,41 +578,126 @@ class GLUSTER(AbstractUrl, SlaveLocal, SlaveRemote): """determine our position in the connectibility matrix""" return True - def connect(self): - """inhibit the resource beyond + class Mounter(object): + """Abstract base class for mounter backends""" - - create temprorary mount point - - call glusterfs to mount the volume over there - - change to mounted fs root - - lazy umount + delete temp. mount point - """ - def umount_l(d): - po = Popen(['umount', '-l', d], stderr=subprocess.PIPE) + def __init__(self, params): + self.params = params + + @classmethod + def get_glusterprog(cls): + return os.path.join(gconf.gluster_command_dir, cls.glusterprog) + + def umount_l(self, d): + """perform lazy umount""" + po = Popen(self.make_umount_argv(d), stderr=subprocess.PIPE) po.wait() return po - d = tempfile.mkdtemp(prefix='gsyncd-aux-mount-') - mounted = False - try: - po = Popen(gconf.gluster_command.split() + \ - (gconf.gluster_log_level and ['-L', gconf.gluster_log_level] or []) + \ - ['-l', gconf.gluster_log_file, '-s', self.host, - '--volfile-id', self.volume, '--client-pid=-1', d], - stderr=subprocess.PIPE) + + @classmethod + def make_umount_argv(cls, d): + raise NotImplementedError + + def make_mount_argv(self, *a): + raise NotImplementedError + + def cleanup_mntpt(self): + pass + + def handle_mounter(self, po): po.wait() - po.terminate_geterr() - mounted = True - logging.debug('auxiliary glusterfs mount in place') - os.chdir(d) - umount_l(d).terminate_geterr() + + def inhibit(self, *a): + """inhibit a gluster filesystem + + Mount glusterfs over a temporary mountpoint, + change into the mount, and lazy unmount the + filesystem. + """ mounted = False - finally: try: - if mounted: - umount_l(d).terminate_geterr(fail_on_err = False) - os.rmdir(d) - except: - logging.warn('stale mount possibly left behind on ' + d) - logging.debug('auxiliary glusterfs mount prepared') + po = Popen(self.make_mount_argv(*a), **self.mountkw) + self.handle_mounter(po) + po.terminate_geterr() + d = self.mntpt + mounted = True + logging.debug('auxiliary glusterfs mount in place') + os.chdir(d) + self.umount_l(d).terminate_geterr() + mounted = False + finally: + try: + if mounted: + self.umount_l(d).terminate_geterr(fail_on_err = False) + self.cleanup_mntpt() + except: + logging.warn('stale mount possibly left behind on ' + d) + logging.debug('auxiliary glusterfs mount prepared') + + class DirectMounter(Mounter): + """mounter backend which calls mount(8), umount(8) directly""" + + mountkw = {'stderr': subprocess.PIPE} + glusterprog = 'glusterfs' + + @staticmethod + def make_umount_argv(d): + return ['umount', '-l', d] + + def make_mount_argv(self): + self.mntpt = tempfile.mkdtemp(prefix = 'gsyncd-aux-mount-') + return [self.get_glusterprog()] + ['--' + p for p in self.params] + [self.mntpt] + + def cleanup_mntpt(self): + os.rmdir(self.mntpt) + + class MountbrokerMounter(Mounter): + """mounter backend using the mountbroker gluster service""" + + mountkw = {'stderr': subprocess.PIPE, 'stdout': subprocess.PIPE} + glusterprog = 'gluster' + + @classmethod + def make_cli_argv(cls): + return [cls.get_glusterprog()] + gconf.gluster_cli_options.split() + ['system::'] + + @classmethod + def make_umount_argv(cls, d): + return cls.make_cli_argv() + ['umount', d, 'lazy'] + + def make_mount_argv(self, label): + return self.make_cli_argv() + \ + ['mount', label, 'user-map-root=' + syncdutils.getusername()] + self.params + + def handle_mounter(self, po): + self.mntpt = po.stdout.readline()[:-1] + po.stdout.close() + sup(self, po) + if po.returncode != 0: + # if cli terminated with error due to being + # refused by glusterd, what it put + # out on stdout is a diagnostic message + logging.error('glusterd answered: %s' % self.mntpt) + + def connect(self): + """inhibit the resource beyond + + Choose mounting backend (direct or mountbroker), + set up glusterfs parameters and perform the mount + with given backend + """ + + label = getattr(gconf, 'mountbroker', None) + if not label: + uid = os.geteuid() + if uid != 0: + label = syncdutils.getusername(uid) + mounter = label and self.MountbrokerMounter or self.DirectMounter + params = gconf.gluster_params.split() + \ + (gconf.gluster_log_level and ['log-level=' + gconf.gluster_log_level] or []) + \ + ['log-file=' + gconf.gluster_log_file, 'volfile-server=' + self.host, + 'volfile-id=' + self.volume, 'client-pid=-1'] + mounter(params).inhibit(*[l for l in [label] if l]) def connect_remote(self, *a, **kw): sup(self, *a, **kw) @@ -653,7 +737,7 @@ class SSH(AbstractUrl, SlaveRemote): if m: u, h = m.groups() else: - u, h = pwd.getpwuid(os.geteuid()).pw_name, self.remote_addr + u, h = syncdutils.getusername(), self.remote_addr remote_addr = '@'.join([u, gethostbyname(h)]) return ':'.join([remote_addr, self.inner_rsc.get_url(canonical=True)]) diff --git a/xlators/features/marker/utils/syncdaemon/syncdutils.py b/xlators/features/marker/utils/syncdaemon/syncdutils.py index 6a08fbdaf9a..f82f412a014 100644 --- a/xlators/features/marker/utils/syncdaemon/syncdutils.py +++ b/xlators/features/marker/utils/syncdaemon/syncdutils.py @@ -1,5 +1,6 @@ import os import sys +import pwd import time import fcntl import shutil @@ -216,3 +217,8 @@ class Thread(baseThread): class GsyncdError(Exception): pass + +def getusername(uid = None): + if uid == None: + uid = os.geteuid() + return pwd.getpwuid(uid).pw_name diff --git a/xlators/mgmt/glusterd/src/glusterd.c b/xlators/mgmt/glusterd/src/glusterd.c index 6daf84a06c2..cb7f9769dbe 100644 --- a/xlators/mgmt/glusterd/src/glusterd.c +++ b/xlators/mgmt/glusterd/src/glusterd.c @@ -23,6 +23,7 @@ #include "config.h" #endif #include <time.h> +#include <grp.h> #include <sys/uio.h> #include <sys/resource.h> @@ -299,10 +300,37 @@ glusterd_check_gsync_present () } -int +static int +group_write_allow (char *path, gid_t gid) +{ + struct stat st = {0,}; + int ret = 0; + + ret = stat (path, &st); + if (ret == -1) + goto out; + GF_ASSERT (S_ISDIR (st.st_mode)); + + ret = chown (path, -1, gid); + if (ret == -1) + goto out; + + ret = chmod (path, (st.st_mode & ~S_IFMT) | S_IWGRP|S_IXGRP|S_ISVTX); + + out: + if (ret == -1) + gf_log ("", GF_LOG_CRITICAL, + "failed to set up write access to %s for group %d (%s)", + path, gid, strerror (errno)); + return ret; +} + +static int glusterd_crt_georep_folders (char *georepdir, glusterd_conf_t *conf) { - int ret = 0; + char *greplg_s = NULL; + struct group *gr = NULL; + int ret = 0; GF_ASSERT (georepdir); GF_ASSERT (conf); @@ -351,11 +379,29 @@ glusterd_crt_georep_folders (char *georepdir, glusterd_conf_t *conf) "Unable to create "GEOREP" slave log directory"); goto out; } - ret = 0; + + ret = dict_get_str (THIS->options, GEOREP"-log-group", &greplg_s); + if (ret) + ret = 0; + else { + gr = getgrnam (greplg_s); + if (!gr) { + gf_log ("glusterd", GF_LOG_CRITICAL, + "group "GEOREP"-log-group %s does not exist", greplg_s); + ret = -1; + goto out; + } + + ret = group_write_allow (DEFAULT_LOG_FILE_DIRECTORY"/"GEOREP, + gr->gr_gid); + if (ret == 0) + ret = group_write_allow (DEFAULT_LOG_FILE_DIRECTORY"/" + GEOREP"-slaves", gr->gr_gid); + } + out: gf_log("", GF_LOG_DEBUG, "Returning %d", ret); return ret; - } #endif @@ -417,12 +463,17 @@ configure_syncdaemon (glusterd_conf_t *conf) "/usr/local/libexec/glusterfs/gsyncd", ".", "^ssh:", NULL); RUN_GSYNCD_CMD; - /* gluster-command */ + /* gluster-command-dir */ /* XXX $sbindir should be used (throughout the codebase) */ runinit_gsyncd_setrx (&runner, conf); - runner_add_args (&runner, "gluster-command", - GFS_PREFIX"/sbin/glusterfs " - "--xlator-option *-dht.assert-no-child-down=true", + runner_add_args (&runner, "gluster-command-dir", GFS_PREFIX"/sbin/", + ".", ".", NULL); + RUN_GSYNCD_CMD; + + /* gluster-params */ + runinit_gsyncd_setrx (&runner, conf); + runner_add_args (&runner, "gluster-params", + "xlator-option=*-dht.assert-no-child-down=true", ".", ".", NULL); RUN_GSYNCD_CMD; @@ -470,11 +521,16 @@ configure_syncdaemon (glusterd_conf_t *conf) * slave pre-configuration ************/ - /* gluster-command */ + /* gluster-command-dir */ + runinit_gsyncd_setrx (&runner, conf); + runner_add_args (&runner, "gluster-command-dir", GFS_PREFIX"/sbin/", + ".", NULL); + RUN_GSYNCD_CMD; + + /* gluster-params */ runinit_gsyncd_setrx (&runner, conf); - runner_add_args (&runner, "gluster-command", - GFS_PREFIX"/sbin/glusterfs " - "--xlator-option *-dht.assert-no-child-down=true", + runner_add_args (&runner, "gluster-params", + "xlator-option=*-dht.assert-no-child-down=true", ".", NULL); RUN_GSYNCD_CMD; @@ -1001,6 +1057,8 @@ struct volume_options options[] = { { .key = {"mountbroker-"GEOREP".*"}, .type = GF_OPTION_TYPE_ANY, }, - + { .key = {GEOREP"-log-group"}, + .type = GF_OPTION_TYPE_ANY, + }, { .key = {NULL} }, }; |