From 79009691c01f2b32b523d91a159aadd0e414f31b Mon Sep 17 00:00:00 2001 From: Aravinda VK Date: Tue, 6 Jan 2015 18:20:45 +0530 Subject: 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 # 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 # for example, gluster system:: execute mountbroker optdel geo-replication-log-group To add/edit user, gluster system:: execute mountbroker user # for example gluster system:: execute mountbroker user geoaccount slavevol1,slavevol2 To remove user, gluster system:: execute mountbroker userdel # 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 Reviewed-on: http://review.gluster.org/9398 Tested-by: Gluster Build System Reviewed-by: darshan n Reviewed-by: Kotresh HR Reviewed-by: Vijay Bellur --- geo-replication/src/Makefile.am | 3 +- geo-replication/src/peer_mountbroker | 177 ++++++++++++++++++++++++++++++++ geo-replication/src/peer_mountbroker.in | 177 ++++++++++++++++++++++++++++++++ 3 files changed, 356 insertions(+), 1 deletion(-) create mode 100644 geo-replication/src/peer_mountbroker create mode 100644 geo-replication/src/peer_mountbroker.in (limited to 'geo-replication') diff --git a/geo-replication/src/Makefile.am b/geo-replication/src/Makefile.am index 68b18c66e88..512128dfd2d 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 00000000000..4d34e7c8e2a --- /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 00000000000..4c97c6923c4 --- /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() -- cgit