summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAravinda VK <avishwan@redhat.com>2015-01-06 18:20:45 +0530
committerVijay Bellur <vbellur@redhat.com>2015-03-17 04:56:24 -0700
commit79009691c01f2b32b523d91a159aadd0e414f31b (patch)
tree412ea20c19a3b606f0f98c546965e26b01d78961
parentfb6858b47585244fd3cef2f0e8155a13752e0365 (diff)
geo-rep: mountbroker user management
Non root geo-replication setup is now simplified. This patch provides cli for mountbroker user and options management To set Options, gluster system:: execute mountbroker opt <KEY> <VALUE> # for example, gluster system:: execute mountbroker opt mountbroker-root /var/mountbroker-root gluster system:: execute mountbroker opt geo-replication-log-group geogroup gluster system:: execute mountbroker opt rpc-auth-allow-insecure on To remove option, gluster system:: execute mountbroker optdel <KEY> # for example, gluster system:: execute mountbroker optdel geo-replication-log-group To add/edit user, gluster system:: execute mountbroker user <USERNAME> <VOLUMES> # for example gluster system:: execute mountbroker user geoaccount slavevol1,slavevol2 To remove user, gluster system:: execute mountbroker userdel <USERNAME> # for example gluster system:: execute mountbroker userdel geoaccount For info, gluster system:: execute mountbroker info gluster system:: execute mountbroker -j info For JSON output add -j after mountbroker, for example, gluster system:: execute mountbroker -j user geoaccount slavevol1,slavevol2 PS: Each peer prints its own JSON output, aggregator required from consumer side BUG: 1136312 Change-Id: Ie52210c0bcc91ac2ffd3ba58988222ffca62b47f Signed-off-by: Aravinda VK <avishwan@redhat.com> Reviewed-on: http://review.gluster.org/9398 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: darshan n <dnarayan@redhat.com> Reviewed-by: Kotresh HR <khiremat@redhat.com> Reviewed-by: Vijay Bellur <vbellur@redhat.com>
-rw-r--r--.gitignore1
-rw-r--r--configure.ac10
-rw-r--r--geo-replication/src/Makefile.am3
-rw-r--r--geo-replication/src/peer_mountbroker177
-rw-r--r--geo-replication/src/peer_mountbroker.in177
-rw-r--r--glusterfs.spec.in4
6 files changed, 371 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index 977f99a..acead36 100644
--- a/.gitignore
+++ b/.gitignore
@@ -59,6 +59,7 @@ geo-replication/src/gsyncd
geo-replication/src/gsyncd
geo-replication/src/peer_add_secret_pub
geo-replication/src/peer_gsec_create
+geo-replication/src/peer_mountbroker
geo-replication/src/set_geo_rep_pem_keys.sh
geo-replication/syncdaemon.egg-info
geo-replication/syncdaemon/configinterface.py
diff --git a/configure.ac b/configure.ac
index fbb6e4a..f4de446 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,6 +40,7 @@ AC_CONFIG_FILES([Makefile
libglusterfs/src/Makefile
geo-replication/src/peer_gsec_create
geo-replication/src/peer_add_secret_pub
+ geo-replication/src/peer_mountbroker
geo-replication/syncdaemon/configinterface.py
glusterfsd/Makefile
glusterfsd/src/Makefile
@@ -887,6 +888,14 @@ else
LOCALSTATEDIR=$(eval echo ${localstatedir})
fi
+old_prefix=$prefix
+if test "x$prefix" = xNONE; then
+ prefix=$ac_default_prefix
+fi
+GLUSTERD_VOLFILE="$(eval echo ${sysconfdir})/glusterfs/glusterd.vol"
+prefix=$old_prefix
+
+
case $host_os in
linux*)
GF_HOST_OS="GF_LINUX_HOST_OS"
@@ -1175,6 +1184,7 @@ AM_CONDITIONAL([GF_BSD_HOST_OS], test "${GF_HOST_OS}" = "GF_BSD_HOST_OS")
AC_SUBST(GLUSTERD_WORKDIR)
AM_CONDITIONAL([GF_INSTALL_GLUSTERD_WORKDIR], test ! -d ${GLUSTERD_WORKDIR} && test -d ${sysconfdir}/glusterd )
+AC_SUBST(GLUSTERD_VOLFILE)
dnl pkg-config versioning
dnl
diff --git a/geo-replication/src/Makefile.am b/geo-replication/src/Makefile.am
index 68b18c6..512128d 100644
--- a/geo-replication/src/Makefile.am
+++ b/geo-replication/src/Makefile.am
@@ -1,6 +1,7 @@
gsyncddir = $(libexecdir)/glusterfs
-gsyncd_SCRIPTS = gverify.sh peer_add_secret_pub peer_gsec_create set_geo_rep_pem_keys.sh
+gsyncd_SCRIPTS = gverify.sh peer_add_secret_pub peer_gsec_create \
+ set_geo_rep_pem_keys.sh peer_mountbroker
# peer_gsec_create and peer_add_secret_pub are not added to
# EXTRA_DIST as it's derived from a .in file
diff --git a/geo-replication/src/peer_mountbroker b/geo-replication/src/peer_mountbroker
new file mode 100644
index 0000000..4d34e7c
--- /dev/null
+++ b/geo-replication/src/peer_mountbroker
@@ -0,0 +1,177 @@
+#!/usr/bin/env python
+import os
+from argparse import ArgumentParser, RawDescriptionHelpFormatter
+import json
+import sys
+
+
+PROG_DESCRIPTION = """
+GlusterFS Mountbroker user management
+"""
+
+args = None
+
+
+def ok(message=""):
+ if (not args and "-j" in sys.argv) or (args and args.json):
+ print json.dumps({"ok": True, "message": message})
+ else:
+ if message:
+ print message
+
+ sys.exit(0)
+
+
+def notok(message=""):
+ if (not args and "-j" in sys.argv) or (args and args.json):
+ print json.dumps({"ok": False, "message": message})
+ else:
+ print "error: %s" % message
+
+ # Always return zero due to limitation while executing
+ # as `gluster system:: execute`
+ sys.exit(0)
+
+
+class NoStdErrParser(ArgumentParser):
+ """
+ with gluster system:: execute, stderr gives
+ "Unable to end. Error : Bad file descriptor" error,
+ so deriving new class, prints error message and
+ exits with zero.
+ """
+ def error(self, message):
+ notok(message)
+
+
+class MountbrokerUserMgmt(object):
+ def __init__(self, volfile):
+ self.volfile = volfile
+ self._options = {}
+ self.commented_lines = []
+ self._parse()
+
+ def _parse(self):
+ with open(self.volfile, "r") as f:
+ for line in f:
+ line = line.strip()
+ if line.startswith("option "):
+ key, value = line.split(" ")[1:]
+ self._options[key] = value
+ if line.startswith("#"):
+ self.commented_lines.append(line)
+
+ def _get_write_data(self):
+ op = "volume management\n"
+ op += " type mgmt/glusterd\n"
+ for k, v in self._options.iteritems():
+ op += " option %s %s\n" % (k, v)
+ for line in self.commented_lines:
+ op += " %s\n" % line
+ op += "end-volume"
+ return op
+
+ def save(self):
+ with open(self.volfile + "_tmp", "w") as f:
+ f.write(self._get_write_data())
+ f.flush()
+ os.fsync(f.fileno())
+ os.rename(self.volfile + "_tmp", self.volfile)
+
+ def set_opt(self, key, value):
+ self._options[key] = value.strip()
+
+ def remove_opt(self, key):
+ if key in self._options:
+ del(self._options[key])
+
+ def add_user(self, user, volumes):
+ self.set_opt("mountbroker-geo-replication.%s" % user,
+ ",".join(volumes))
+
+ def remove_user(self, user):
+ self.remove_opt("mountbroker-geo-replication.%s" % user)
+
+ def info(self):
+ data = {"users": []}
+
+ for k, v in self._options.iteritems():
+ if k.startswith("mountbroker-geo-replication."):
+ data["users"].append(
+ {"name": k.split(".")[-1], "volumes": v.split(",")}
+ )
+ else:
+ data[k] = v
+
+ return data
+
+
+def format_info(data):
+ op = "%s %s\n" % ("Option".ljust(50), "Value".ljust(50))
+ op += ("-" * 101) + "\n"
+ for key, value in data.iteritems():
+ if key != "users":
+ op += "%s %s\n" % (key.ljust(50), value)
+
+ op += "\nUsers: %s\n" % ("None" if not data["users"] else "")
+ for user in data["users"]:
+ op += "%s: %s\n" % (user["name"], ", ".join(user["volumes"]))
+ op += "\n\n"
+ return op
+
+
+def _get_args():
+ parser = NoStdErrParser(formatter_class=RawDescriptionHelpFormatter,
+ description=PROG_DESCRIPTION)
+
+ parser.add_argument('-j', dest="json", help="JSON output",
+ action="store_true")
+ subparsers = parser.add_subparsers(title='subcommands', dest='cmd')
+ parser_useradd = subparsers.add_parser('user')
+ parser_userdel = subparsers.add_parser('userdel')
+ subparsers.add_parser('info')
+ parser_opt = subparsers.add_parser('opt')
+ parser_optdel = subparsers.add_parser('optdel')
+
+ parser_useradd.add_argument('username', help="Username", type=str)
+ parser_useradd.add_argument('volumes', type=str, default='',
+ help="Volumes list. ',' seperated")
+
+ parser_userdel.add_argument('username', help="Username", type=str)
+
+ parser_opt.add_argument('opt_name', help="Name", type=str)
+ parser_opt.add_argument('opt_value', help="Value", type=str)
+
+ parser_optdel.add_argument('opt_name', help="Name", type=str)
+
+ return parser.parse_args()
+
+
+def main():
+ global args
+ args = _get_args()
+
+ m = MountbrokerUserMgmt("/etc/glusterfs/glusterd.vol")
+
+ if args.cmd == "opt":
+ m.set_opt(args.opt_name, args.opt_value)
+ elif args.cmd == "optdel":
+ m.remove_opt(args.opt_name)
+ elif args.cmd == "userdel":
+ m.remove_user(args.username)
+ elif args.cmd == "user":
+ volumes = [v.strip() for v in args.volumes.split(",")
+ if v.strip() != ""]
+ m.add_user(args.username, volumes)
+ elif args.cmd == "info":
+ info = m.info()
+ if not args.json:
+ info = format_info(info)
+ ok(info)
+
+ if args.cmd != "info":
+ m.save()
+ ok()
+
+if __name__ == "__main__":
+ main()
diff --git a/geo-replication/src/peer_mountbroker.in b/geo-replication/src/peer_mountbroker.in
new file mode 100644
index 0000000..4c97c69
--- /dev/null
+++ b/geo-replication/src/peer_mountbroker.in
@@ -0,0 +1,177 @@
+#!/usr/bin/env python
+import os
+from argparse import ArgumentParser, RawDescriptionHelpFormatter
+import json
+import sys
+
+
+PROG_DESCRIPTION = """
+GlusterFS Mountbroker user management
+"""
+
+args = None
+
+
+def ok(message=""):
+ if (not args and "-j" in sys.argv) or (args and args.json):
+ print json.dumps({"ok": True, "message": message})
+ else:
+ if message:
+ print message
+
+ sys.exit(0)
+
+
+def notok(message=""):
+ if (not args and "-j" in sys.argv) or (args and args.json):
+ print json.dumps({"ok": False, "message": message})
+ else:
+ print "error: %s" % message
+
+ # Always return zero due to limitation while executing
+ # as `gluster system:: execute`
+ sys.exit(0)
+
+
+class NoStdErrParser(ArgumentParser):
+ """
+ with gluster system:: execute, stderr gives
+ "Unable to end. Error : Bad file descriptor" error,
+ so deriving new class, prints error message and
+ exits with zero.
+ """
+ def error(self, message):
+ notok(message)
+
+
+class MountbrokerUserMgmt(object):
+ def __init__(self, volfile):
+ self.volfile = volfile
+ self._options = {}
+ self.commented_lines = []
+ self._parse()
+
+ def _parse(self):
+ with open(self.volfile, "r") as f:
+ for line in f:
+ line = line.strip()
+ if line.startswith("option "):
+ key, value = line.split(" ")[1:]
+ self._options[key] = value
+ if line.startswith("#"):
+ self.commented_lines.append(line)
+
+ def _get_write_data(self):
+ op = "volume management\n"
+ op += " type mgmt/glusterd\n"
+ for k, v in self._options.iteritems():
+ op += " option %s %s\n" % (k, v)
+ for line in self.commented_lines:
+ op += " %s\n" % line
+ op += "end-volume"
+ return op
+
+ def save(self):
+ with open(self.volfile + "_tmp", "w") as f:
+ f.write(self._get_write_data())
+ f.flush()
+ os.fsync(f.fileno())
+ os.rename(self.volfile + "_tmp", self.volfile)
+
+ def set_opt(self, key, value):
+ self._options[key] = value.strip()
+
+ def remove_opt(self, key):
+ if key in self._options:
+ del(self._options[key])
+
+ def add_user(self, user, volumes):
+ self.set_opt("mountbroker-geo-replication.%s" % user,
+ ",".join(volumes))
+
+ def remove_user(self, user):
+ self.remove_opt("mountbroker-geo-replication.%s" % user)
+
+ def info(self):
+ data = {"users": []}
+
+ for k, v in self._options.iteritems():
+ if k.startswith("mountbroker-geo-replication."):
+ data["users"].append(
+ {"name": k.split(".")[-1], "volumes": v.split(",")}
+ )
+ else:
+ data[k] = v
+
+ return data
+
+
+def format_info(data):
+ op = "%s %s\n" % ("Option".ljust(50), "Value".ljust(50))
+ op += ("-" * 101) + "\n"
+ for key, value in data.iteritems():
+ if key != "users":
+ op += "%s %s\n" % (key.ljust(50), value)
+
+ op += "\nUsers: %s\n" % ("None" if not data["users"] else "")
+ for user in data["users"]:
+ op += "%s: %s\n" % (user["name"], ", ".join(user["volumes"]))
+ op += "\n\n"
+ return op
+
+
+def _get_args():
+ parser = NoStdErrParser(formatter_class=RawDescriptionHelpFormatter,
+ description=PROG_DESCRIPTION)
+
+ parser.add_argument('-j', dest="json", help="JSON output",
+ action="store_true")
+ subparsers = parser.add_subparsers(title='subcommands', dest='cmd')
+ parser_useradd = subparsers.add_parser('user')
+ parser_userdel = subparsers.add_parser('userdel')
+ subparsers.add_parser('info')
+ parser_opt = subparsers.add_parser('opt')
+ parser_optdel = subparsers.add_parser('optdel')
+
+ parser_useradd.add_argument('username', help="Username", type=str)
+ parser_useradd.add_argument('volumes', type=str, default='',
+ help="Volumes list. ',' seperated")
+
+ parser_userdel.add_argument('username', help="Username", type=str)
+
+ parser_opt.add_argument('opt_name', help="Name", type=str)
+ parser_opt.add_argument('opt_value', help="Value", type=str)
+
+ parser_optdel.add_argument('opt_name', help="Name", type=str)
+
+ return parser.parse_args()
+
+
+def main():
+ global args
+ args = _get_args()
+
+ m = MountbrokerUserMgmt("@GLUSTERD_VOLFILE@")
+
+ if args.cmd == "opt":
+ m.set_opt(args.opt_name, args.opt_value)
+ elif args.cmd == "optdel":
+ m.remove_opt(args.opt_name)
+ elif args.cmd == "userdel":
+ m.remove_user(args.username)
+ elif args.cmd == "user":
+ volumes = [v.strip() for v in args.volumes.split(",")
+ if v.strip() != ""]
+ m.add_user(args.username, volumes)
+ elif args.cmd == "info":
+ info = m.info()
+ if not args.json:
+ info = format_info(info)
+ ok(info)
+
+ if args.cmd != "info":
+ m.save()
+ ok()
+
+if __name__ == "__main__":
+ main()
diff --git a/glusterfs.spec.in b/glusterfs.spec.in
index affb753..ef8326f 100644
--- a/glusterfs.spec.in
+++ b/glusterfs.spec.in
@@ -943,6 +943,7 @@ fi
%{_libexecdir}/glusterfs/set_geo_rep_pem_keys.sh
%{_libexecdir}/glusterfs/peer_add_secret_pub
%{_libexecdir}/glusterfs/peer_gsec_create
+%{_libexecdir}/glusterfs/peer_mountbroker
%ghost %dir %attr(0755,-,-) %{_sharedstatedir}/glusterd/geo-replication
%dir %{_sharedstatedir}/glusterd/hooks
%dir %{_sharedstatedir}/glusterd/hooks/1
@@ -1078,6 +1079,9 @@ fi
* Fri Jan 16 2015 Niels de Vos <ndevos@redhat.com>
- add support for /run/gluster through a tmpfiles.d config file (#1182934)
+* Tue Jan 6 2015 Aravinda VK<avishwan@redhat.com>
+- Added new libexec script for mountbroker user management (peer_mountbroker)
+
* Fri Dec 12 2014 Niels de Vos <ndevos@redhat.com>
- do not package all /usr/share/glusterfs/* files in regression-tests (#1169005)