Ceph RADOS cluster mutex helper for Samba CTDB
PATCH 1/1 Ceph RADOS cluster mutex helper for Samba CTDB
Hi,
The attached patch-set implements a cluster mutex helper for Samba CTDB using Ceph librados.
ctdb_mutex_ceph_rados_helper_lock can be used as a recovery lock provider for CTDB. When configured, split brain avoidance during CTDB recovery will be handled using locks against an object located in a Ceph RADOS pool.
I've also attached a standalone test script - @Martin: does this belong in the ctdb test suite, or can I just commit it as a standalone test? It has a few non-standard dependencies: a running Ceph cluster, the rados and jq binaries.
Feedback appreciated.
Cheers, David
--
ctdb/doc/Makefile | 3 +- ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml | 90 ++++++ ctdb/tools/ctdb_mutex_ceph_rados_helper.c | 334 ++++++++++++++++++++ ctdb/wscript | 19 ++ 4 files changed, 445 insertions(+), 1 deletion(-)
From 47e653373073f1564844465eb416cdebb1dc4aa6 Mon Sep 17 00:00:00 2001
From: David Disseldorp <[email protected]>
Date: Thu, 1 Dec 2016 13:33:22 +0100
Subject: [PATCH 1/2] ctdb: cluster mutex helper using Ceph RADOS
ctdb_mutex_ceph_rados_helper implements the cluster mutex helper API atop Ceph using the librados rados_lock_exclusive()/rados_unlock() functionality.
Once configured, split brain avoidance during CTDB recovery will be handled using locks against an object located in a Ceph RADOS pool.
--- ctdb/tools/ctdb_mutex_ceph_rados_helper.c | 334 ++++++++++++++++++++++++++++++ ctdb/wscript | 19 ++ 2 files changed, 353 insertions(+) create mode 100644 ctdb/tools/ctdb_mutex_ceph_rados_helper.c
ctdb/tools/ctdb_mutex_ceph_rados_helper.c new file +334 -0
@@ -0,0 +1,334 @@ +/* +CTDB mutex helper using Ceph librados locks + +Copyright (C) David Disseldorp 2016 + +Based on ctdb_mutex_fcntl_helper.c, which is: +Copyright (C) Martin Schwenke 2015 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" +#include "system/filesys.h" +#include "system/network.h" + +/* protocol.h is just needed for ctdb_sock_addr, which is used in system.h */ +#include "protocol/protocol.h" +#include "common/system.h" +#include "lib/util/time.h" +#include "tevent.h" +#include "talloc.h" +#include "rados/librados.h" + +#define CTDB_MUTEX_CEPH_LOCK_NAME "ctdb_reclock_mutex" +#define CTDB_MUTEX_CEPH_LOCK_COOKIE CTDB_MUTEX_CEPH_LOCK_NAME +#define CTDB_MUTEX_CEPH_LOCK_DESC "CTDB recovery lock" + +#define CTDB_MUTEX_STATUS_HOLDING "0" +#define CTDB_MUTEX_STATUS_CONTENDED "1" +#define CTDB_MUTEX_STATUS_TIMEOUT "2" +#define CTDB_MUTEX_STATUS_ERROR "3" + +static char *progname =NULL ; + +static int ctdb_mutex_rados_ctx_create (const char *ceph_cluster_name, +const char *ceph_auth_name, +const char *pool_name, +rados_t *_ceph_cluster, +rados_ioctx_t *_ioctx) +{ +rados_t ceph_cluster =NULL ; +rados_ioctx_t ioctx =NULL ; +int ret; + + ret =rados_create2 (&ceph_cluster, ceph_cluster_name, ceph_auth_name,0 ); +if (ret <0 ) { +fprintf (stderr,"%s: failed to initialise Ceph cluster %s as %s" +" - (%s)\n" , progname, ceph_cluster_name, ceph_auth_name, +strerror (-ret)); +return ret; + } + +/* path=NULL tells librados to use default locations */ + ret =rados_conf_read_file (ceph_cluster,NULL ); +if (ret <0 ) { +fprintf (stderr,"%s: failed to parse Ceph cluster config" +" - (%s)\n" , progname,strerror (-ret)); +rados_shutdown (ceph_cluster); +return ret; + } + + ret =rados_connect (ceph_cluster); +if (ret <0 ) { +fprintf (stderr,"%s: failed to connect to Ceph cluster %s as %s" +" - (%s)\n" , progname, ceph_cluster_name, ceph_auth_name, +strerror (-ret)); +rados_shutdown (ceph_cluster); +return ret; + } + + + ret =rados_ioctx_create (ceph_cluster, pool_name, &ioctx); +if (ret <0 ) { +fprintf (stderr,"%s: failed to create Ceph ioctx for pool %s" +" - (%s)\n" , progname, pool_name,strerror (-ret)); +rados_shutdown (ceph_cluster); +return ret; + } + + *_ceph_cluster = ceph_cluster; + *_ioctx = ioctx; + +return 0 ; +} + +static void ctdb_mutex_rados_ctx_destroy (rados_t ceph_cluster, +rados_ioctx_t ioctx) +{ +rados_ioctx_destroy (ioctx); +rados_shutdown (ceph_cluster); +} + +static int ctdb_mutex_rados_lock (rados_ioctx_t *ioctx, +const char *oid) +{ +int ret; + + ret =rados_lock_exclusive (ioctx, oid, +CTDB_MUTEX_CEPH_LOCK_NAME , +CTDB_MUTEX_CEPH_LOCK_COOKIE , +CTDB_MUTEX_CEPH_LOCK_DESC , +NULL ,/* infinite duration */ +0 ); +if ((ret == -EEXIST ) || (ret == -EBUSY )) { +/* lock contention */ +return ret; + }else if (ret <0 ) { +/* unexpected failure */ +fprintf (stderr, +"%s: Failed to get lock on RADOS object '%s' - (%s)\n" , + progname, oid,strerror (-ret)); +return ret; + } + +/* lock obtained */ +return 0 ; +} + +static int ctdb_mutex_rados_unlock (rados_ioctx_t *ioctx, +const char *oid) +{ +int ret; + + ret =rados_unlock (ioctx, oid, +CTDB_MUTEX_CEPH_LOCK_NAME , +CTDB_MUTEX_CEPH_LOCK_COOKIE ); +if (ret <0 ) { +fprintf (stderr, +"%s: Failed to drop lock on RADOS object '%s' - (%s)\n" , + progname, oid,strerror (-ret)); +return ret; + } + +return 0 ; +} + +struct ctdb_mutex_rados_state { +bool holding_mutex; +const char *ceph_cluster_name; +const char *ceph_auth_name; +const char *pool_name; +const char *object; +int ppid; +struct tevent_context *ev; +struct tevent_signal *sig_ev; +struct tevent_timer *timer_ev; +rados_t ceph_cluster; +rados_ioctx_t ioctx; +}; + +static void ctdb_mutex_rados_sigterm_cb (struct tevent_context *ev, +struct tevent_signal *se, +int signum, +int count, +void *siginfo, +void *private_data) +{ +struct ctdb_mutex_rados_state *cmr_state = private_data; +int ret; + +if (!cmr_state->holding_mutex) { +fprintf (stderr,"Sigterm callback invoked without mutex!\n" ); + ret = -EINVAL ; + goto err_ctx_cleanup; + } + + ret =ctdb_mutex_rados_unlock (cmr_state->ioctx, cmr_state->object); +err_ctx_cleanup: +ctdb_mutex_rados_ctx_destroy (cmr_state->ceph_cluster, + cmr_state->ioctx); +talloc_free (cmr_state); +exit (ret ?1 :0 ); +} + +static void ctdb_mutex_rados_timer_cb (struct tevent_context *ev, +struct tevent_timer *te, +struct timeval current_time, +void *private_data) +{ +struct ctdb_mutex_rados_state *cmr_state = private_data; +int ret; + +if (!cmr_state->holding_mutex) { +fprintf (stderr,"Timer callback invoked without mutex!\n" ); + ret = -EINVAL ; + goto err_ctx_cleanup; + } + +if ((kill (cmr_state->ppid,0 ) ==0 ) || (errno !=ESRCH )) { +/* parent still around, keep waiting */ + cmr_state->timer_ev =tevent_add_timer (cmr_state->ev, cmr_state, +timeval_current_ofs (5 ,0 ), + ctdb_mutex_rados_timer_cb, + cmr_state); +if (cmr_state->timer_ev ==NULL ) { +fprintf (stderr,"Failed to create timer event\n" ); +/* rely on signal cb */ + } +return ; + } + +/* parent ended, drop lock and exit */ + ret =ctdb_mutex_rados_unlock (cmr_state->ioctx, cmr_state->object); +err_ctx_cleanup: +ctdb_mutex_rados_ctx_destroy (cmr_state->ceph_cluster, + cmr_state->ioctx); +talloc_free (cmr_state); +exit (ret ?1 :0 ); +} + +int main (int argc,char *argv[]) +{ +int ret; +struct ctdb_mutex_rados_state *cmr_state; + + progname = argv[0 ]; + +if (argc !=5 ) { +fprintf (stderr,"Usage: %s <Ceph Cluster> <Ceph user> " +"<RADOS pool> <RADOS object>\n" , + progname); + ret = -EINVAL ; + goto err_out; + } + + ret =setvbuf (stdout,NULL , _IONBF,0 ); +if (ret !=0 ) { +fprintf (stderr,"Failed to configure unbuffered stdout I/O\n" ); + } + + cmr_state = talloc_zero(NULL, struct ctdb_mutex_rados_state); +if (cmr_state ==NULL ) { +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + ret = -ENOMEM ; + goto err_out; + } + + cmr_state->ceph_cluster_name = argv[1 ]; + cmr_state->ceph_auth_name = argv[2 ]; + cmr_state->pool_name = argv[3 ]; + cmr_state->object = argv[4 ]; + + cmr_state->ppid =getppid (); +if (cmr_state->ppid ==1 ) { +/* +* The original parent is gone and the process has +* been reparented to init. This can happen if the +* helper is started just as the parent is killed +* during shutdown. The error message doesn't need to +* be stellar, since there won't be anything around to +* capture and log it... +*/ +fprintf (stderr,"%s: PPID == 1\n" , progname); + ret = -EPIPE ; + goto err_state_free; + } + + cmr_state->ev =tevent_context_init (cmr_state); +if (cmr_state->ev ==NULL ) { +fprintf (stderr,"tevent_context_init failed\n" ); +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + ret = -ENOMEM ; + goto err_state_free; + } + +/* wait for sigterm */ + cmr_state->sig_ev =tevent_add_signal (cmr_state->ev, cmr_state,SIGTERM ,0 , + ctdb_mutex_rados_sigterm_cb, + cmr_state); +if (cmr_state->sig_ev ==NULL ) { +fprintf (stderr,"Failed to create signal event\n" ); +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + ret = -ENOMEM ; + goto err_state_free; + } + +/* periodically check parent */ + cmr_state->timer_ev =tevent_add_timer (cmr_state->ev, cmr_state, +timeval_current_ofs (5 ,0 ), + ctdb_mutex_rados_timer_cb, + cmr_state); +if (cmr_state->timer_ev ==NULL ) { +fprintf (stderr,"Failed to create timer event\n" ); +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + ret = -ENOMEM ; + goto err_state_free; + } + + ret =ctdb_mutex_rados_ctx_create (cmr_state->ceph_cluster_name, + cmr_state->ceph_auth_name, + cmr_state->pool_name, + &cmr_state->ceph_cluster, + &cmr_state->ioctx); +if (ret <0 ) { +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + goto err_state_free; + } + + ret =ctdb_mutex_rados_lock (cmr_state->ioctx, cmr_state->object); +if ((ret == -EEXIST ) || (ret == -EBUSY )) { +fprintf (stdout,CTDB_MUTEX_STATUS_CONTENDED ); + goto err_ctx_cleanup; + }else if (ret <0 ) { +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + goto err_ctx_cleanup; + } + + cmr_state->holding_mutex = true; +fprintf (stdout,CTDB_MUTEX_STATUS_HOLDING ); + +/* wait for the signal / timer events to do their work */ + ret =tevent_loop_wait (cmr_state->ev); +if (ret <0 ) { + goto err_ctx_cleanup; + } +err_ctx_cleanup: +ctdb_mutex_rados_ctx_destroy (cmr_state->ceph_cluster, + cmr_state->ioctx); +err_state_free: +talloc_free (cmr_state); +err_out: +return ret ?1 :0 ; +}
ctdb/wscript +19 -0
@@ -69,6 +69,9 @@ def set_options(opt): opt.add_option('--enable-pmda', help=("Turn on PCP pmda support (default=no)"), action="store_true", dest='ctdb_pmda', default=False) + opt.add_option('--enable-ceph-reclock', + help=("Enable Ceph CTDB recovery lock helper (default=no)"), + action="store_true", dest='ctdb_ceph_reclock', default=False) opt.add_option('--with-logdir', help=("Path to log directory"),
@@ -159,6 +162,15 @@ def configure(conf): conf.env.CTDB_PMDADIR = os.path.join(conf.env.LOCALSTATEDIR, 'lib/pcp/pmdas/ctdb') + if Options.options.ctdb_ceph_reclock: + if (conf.CHECK_HEADERS('rados/librados.h', False, False, 'rados') and + conf.CHECK_LIB('rados', shlib=True)): + Logs.info('Building with Ceph librados recovery lock support') + conf.define('HAVE_LIBRADOS', 1) + else: + Logs.error("Missing librados for Ceph recovery lock support") + sys.exit(1) + have_infiniband = False if Options.options.ctdb_infiniband: ib_support = True
@@ -517,6 +529,13 @@ def build(bld): bld.INSTALL_FILES('${CTDB_PMDADIR}', 'utils/pmda/README', destname='README') + if bld.env.HAVE_LIBRADOS: + bld.SAMBA_BINARY('ctdb_mutex_ceph_rados_helper', + source='tools/ctdb_mutex_ceph_rados_helper.c', + deps='ctdb-system rados', + includes='include', + install_path='${CTDB_HELPER_BINDIR}') + sed_expr1 = 's|/usr/local/var/lib/ctdb|%s|g' % (bld.env.CTDB_VARDIR) sed_expr2 = 's|/usr/local/etc/ctdb|%s|g' % (bld.env.CTDB_ETCDIR) sed_expr3 = 's|/usr/local/var/log|%s|g' % (bld.env.CTDB_LOGDIR)
Signature · 14 lines
2.10.2 From fb53f42d1e02e0f33d1a1304c7d708203d75a14d Mon Sep 17 00:00:00 2001 From: David Disseldorp <[email protected]> Date: Thu, 1 Dec 2016 14:22:45 +0100 Subject: [PATCH 2/2] ctdb/doc: man page for Ceph RADOS cluster mutex helper Signed-off-by: David Disseldorp <[email protected]> --- ctdb/doc/Makefile | 3 +- ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml | 90 +++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml
ctdb/doc/Makefile +2 -1
@@ -8,7 +8,8 @@ DOCS = ctdb.1 ctdb.1.html \ ctdbd.conf.5 ctdbd.conf.5.html \ ctdb.7 ctdb.7.html \ ctdb-statistics.7 ctdb-statistics.7.html \ - ctdb-tunables.7 ctdb-tunables.7.html + ctdb-tunables.7 ctdb-tunables.7.html \ + ctdb_mutex_ceph_rados_helper.7 ctdb_mutex_ceph_rados_helper.7.html all: $(DOCS)
ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml new file +90 -0
90 lines not on this page · raw message
Signature · 1 line
2.10.2
A message that is not in the archive (sent off-list or not yet received): CAJ+X7mTkBLQDYb+r9LELQe-sqfG_4YkQ9HbkDFAp70cPp7V8zA@mail.gmail.com
Quoted 20 lines · Amitay Isaacs
Quoted 10 lines · David Disseldorp
Hi,
The attached patch-set implements a cluster mutex helper for Samba CTDB using Ceph librados.
ctdb_mutex_ceph_rados_helper_lockcan be used as a recovery lock provider for CTDB. When configured, split brain avoidance during CTDB recovery will be handled using locks against an object located in a Ceph RADOS pool.Quoted 8 lines
I've also attached a standalone test script - @Martin: does this belong in the ctdb test suite, or can I just commit it as a standalone test? It has a few non-standard dependencies: a running Ceph cluster, the rados and jq binaries.
Feedback appreciated.
Quoted 7 lines
This code does not belong in ctdb/tools. You can move it to an appropriate directory in ctdb/utils.
Please include the test code also as part of the commit. Someone with ceph-rados setup should be able to run this test.
I would appreciate if you can add few comments in the test script describing the requirements and how to run the test.
Thanks for the feedback, Amitay. Please find a v2 patchset attached, with the following changes:
- move ctdb_mutex_ceph_rados_helper under ctdb/utils/ceph
- add test_ceph_rados_reclock.sh and document usage
Cheers, David
--
ctdb/doc/Makefile | 3 +- ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml | 90 +++++ .../utils/ceph/ctdb_mutex_ceph_rados_helper.c | 334 ++++++++++++++++++ ctdb/utils/ceph/test_ceph_rados_reclock.sh | 151 ++++++++ ctdb/wscript | 19 + 5 files changed, 596 insertions(+), 1 deletion(-)
This time with the patch-set attached...
Quoted 6 lines
ctdb/doc/Makefile | 3 +- ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml | 90 +++++ .../utils/ceph/ctdb_mutex_ceph_rados_helper.c | 334 ++++++++++++++++++ ctdb/utils/ceph/test_ceph_rados_reclock.sh | 151 ++++++++ ctdb/wscript | 19 + 5 files changed, 596 insertions(+), 1 deletion(-)
From f723522c259f6b46cec088cc951ce801e491a063 Mon Sep 17 00:00:00 2001
From: David Disseldorp <[email protected]>
Date: Thu, 1 Dec 2016 13:33:22 +0100
Subject: [PATCH 1/3] ctdb: cluster mutex helper using Ceph RADOS
ctdb_mutex_ceph_rados_helper implements the cluster mutex helper API atop Ceph using the librados rados_lock_exclusive()/rados_unlock() functionality.
Once configured, split brain avoidance during CTDB recovery will be handled using locks against an object located in a Ceph RADOS pool.
--- ctdb/utils/ceph/ctdb_mutex_ceph_rados_helper.c | 334 +++++++++++++++++++++++++ ctdb/wscript | 19 ++ 2 files changed, 353 insertions(+) create mode 100644 ctdb/utils/ceph/ctdb_mutex_ceph_rados_helper.c
ctdb/utils/ceph/ctdb_mutex_ceph_rados_helper.c new file +334 -0
@@ -0,0 +1,334 @@ +/* +CTDB mutex helper using Ceph librados locks + +Copyright (C) David Disseldorp 2016 + +Based on ctdb_mutex_fcntl_helper.c, which is: +Copyright (C) Martin Schwenke 2015 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" +#include "system/filesys.h" +#include "system/network.h" + +/* protocol.h is just needed for ctdb_sock_addr, which is used in system.h */ +#include "protocol/protocol.h" +#include "common/system.h" +#include "lib/util/time.h" +#include "tevent.h" +#include "talloc.h" +#include "rados/librados.h" + +#define CTDB_MUTEX_CEPH_LOCK_NAME "ctdb_reclock_mutex" +#define CTDB_MUTEX_CEPH_LOCK_COOKIE CTDB_MUTEX_CEPH_LOCK_NAME +#define CTDB_MUTEX_CEPH_LOCK_DESC "CTDB recovery lock" + +#define CTDB_MUTEX_STATUS_HOLDING "0" +#define CTDB_MUTEX_STATUS_CONTENDED "1" +#define CTDB_MUTEX_STATUS_TIMEOUT "2" +#define CTDB_MUTEX_STATUS_ERROR "3" + +static char *progname =NULL ; + +static int ctdb_mutex_rados_ctx_create (const char *ceph_cluster_name, +const char *ceph_auth_name, +const char *pool_name, +rados_t *_ceph_cluster, +rados_ioctx_t *_ioctx) +{ +rados_t ceph_cluster =NULL ; +rados_ioctx_t ioctx =NULL ; +int ret; + + ret =rados_create2 (&ceph_cluster, ceph_cluster_name, ceph_auth_name,0 ); +if (ret <0 ) { +fprintf (stderr,"%s: failed to initialise Ceph cluster %s as %s" +" - (%s)\n" , progname, ceph_cluster_name, ceph_auth_name, +strerror (-ret)); +return ret; + } + +/* path=NULL tells librados to use default locations */ + ret =rados_conf_read_file (ceph_cluster,NULL ); +if (ret <0 ) { +fprintf (stderr,"%s: failed to parse Ceph cluster config" +" - (%s)\n" , progname,strerror (-ret)); +rados_shutdown (ceph_cluster); +return ret; + } + + ret =rados_connect (ceph_cluster); +if (ret <0 ) { +fprintf (stderr,"%s: failed to connect to Ceph cluster %s as %s" +" - (%s)\n" , progname, ceph_cluster_name, ceph_auth_name, +strerror (-ret)); +rados_shutdown (ceph_cluster); +return ret; + } + + + ret =rados_ioctx_create (ceph_cluster, pool_name, &ioctx); +if (ret <0 ) { +fprintf (stderr,"%s: failed to create Ceph ioctx for pool %s" +" - (%s)\n" , progname, pool_name,strerror (-ret)); +rados_shutdown (ceph_cluster); +return ret; + } + + *_ceph_cluster = ceph_cluster; + *_ioctx = ioctx; + +return 0 ; +} + +static void ctdb_mutex_rados_ctx_destroy (rados_t ceph_cluster, +rados_ioctx_t ioctx) +{ +rados_ioctx_destroy (ioctx); +rados_shutdown (ceph_cluster); +} + +static int ctdb_mutex_rados_lock (rados_ioctx_t *ioctx, +const char *oid) +{ +int ret; + + ret =rados_lock_exclusive (ioctx, oid, +CTDB_MUTEX_CEPH_LOCK_NAME , +CTDB_MUTEX_CEPH_LOCK_COOKIE , +CTDB_MUTEX_CEPH_LOCK_DESC , +NULL ,/* infinite duration */ +0 ); +if ((ret == -EEXIST ) || (ret == -EBUSY )) { +/* lock contention */ +return ret; + }else if (ret <0 ) { +/* unexpected failure */ +fprintf (stderr, +"%s: Failed to get lock on RADOS object '%s' - (%s)\n" , + progname, oid,strerror (-ret)); +return ret; + } + +/* lock obtained */ +return 0 ; +} + +static int ctdb_mutex_rados_unlock (rados_ioctx_t *ioctx, +const char *oid) +{ +int ret; + + ret =rados_unlock (ioctx, oid, +CTDB_MUTEX_CEPH_LOCK_NAME , +CTDB_MUTEX_CEPH_LOCK_COOKIE ); +if (ret <0 ) { +fprintf (stderr, +"%s: Failed to drop lock on RADOS object '%s' - (%s)\n" , + progname, oid,strerror (-ret)); +return ret; + } + +return 0 ; +} + +struct ctdb_mutex_rados_state { +bool holding_mutex; +const char *ceph_cluster_name; +const char *ceph_auth_name; +const char *pool_name; +const char *object; +int ppid; +struct tevent_context *ev; +struct tevent_signal *sig_ev; +struct tevent_timer *timer_ev; +rados_t ceph_cluster; +rados_ioctx_t ioctx; +}; + +static void ctdb_mutex_rados_sigterm_cb (struct tevent_context *ev, +struct tevent_signal *se, +int signum, +int count, +void *siginfo, +void *private_data) +{ +struct ctdb_mutex_rados_state *cmr_state = private_data; +int ret; + +if (!cmr_state->holding_mutex) { +fprintf (stderr,"Sigterm callback invoked without mutex!\n" ); + ret = -EINVAL ; + goto err_ctx_cleanup; + } + + ret =ctdb_mutex_rados_unlock (cmr_state->ioctx, cmr_state->object); +err_ctx_cleanup: +ctdb_mutex_rados_ctx_destroy (cmr_state->ceph_cluster, + cmr_state->ioctx); +talloc_free (cmr_state); +exit (ret ?1 :0 ); +} + +static void ctdb_mutex_rados_timer_cb (struct tevent_context *ev, +struct tevent_timer *te, +struct timeval current_time, +void *private_data) +{ +struct ctdb_mutex_rados_state *cmr_state = private_data; +int ret; + +if (!cmr_state->holding_mutex) { +fprintf (stderr,"Timer callback invoked without mutex!\n" ); + ret = -EINVAL ; + goto err_ctx_cleanup; + } + +if ((kill (cmr_state->ppid,0 ) ==0 ) || (errno !=ESRCH )) { +/* parent still around, keep waiting */ + cmr_state->timer_ev =tevent_add_timer (cmr_state->ev, cmr_state, +timeval_current_ofs (5 ,0 ), + ctdb_mutex_rados_timer_cb, + cmr_state); +if (cmr_state->timer_ev ==NULL ) { +fprintf (stderr,"Failed to create timer event\n" ); +/* rely on signal cb */ + } +return ; + } + +/* parent ended, drop lock and exit */ + ret =ctdb_mutex_rados_unlock (cmr_state->ioctx, cmr_state->object); +err_ctx_cleanup: +ctdb_mutex_rados_ctx_destroy (cmr_state->ceph_cluster, + cmr_state->ioctx); +talloc_free (cmr_state); +exit (ret ?1 :0 ); +} + +int main (int argc,char *argv[]) +{ +int ret; +struct ctdb_mutex_rados_state *cmr_state; + + progname = argv[0 ]; + +if (argc !=5 ) { +fprintf (stderr,"Usage: %s <Ceph Cluster> <Ceph user> " +"<RADOS pool> <RADOS object>\n" , + progname); + ret = -EINVAL ; + goto err_out; + } + + ret =setvbuf (stdout,NULL , _IONBF,0 ); +if (ret !=0 ) { +fprintf (stderr,"Failed to configure unbuffered stdout I/O\n" ); + } + + cmr_state = talloc_zero(NULL, struct ctdb_mutex_rados_state); +if (cmr_state ==NULL ) { +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + ret = -ENOMEM ; + goto err_out; + } + + cmr_state->ceph_cluster_name = argv[1 ]; + cmr_state->ceph_auth_name = argv[2 ]; + cmr_state->pool_name = argv[3 ]; + cmr_state->object = argv[4 ]; + + cmr_state->ppid =getppid (); +if (cmr_state->ppid ==1 ) { +/* +* The original parent is gone and the process has +* been reparented to init. This can happen if the +* helper is started just as the parent is killed +* during shutdown. The error message doesn't need to +* be stellar, since there won't be anything around to +* capture and log it... +*/ +fprintf (stderr,"%s: PPID == 1\n" , progname); + ret = -EPIPE ; + goto err_state_free; + } + + cmr_state->ev =tevent_context_init (cmr_state); +if (cmr_state->ev ==NULL ) { +fprintf (stderr,"tevent_context_init failed\n" ); +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + ret = -ENOMEM ; + goto err_state_free; + } + +/* wait for sigterm */ + cmr_state->sig_ev =tevent_add_signal (cmr_state->ev, cmr_state,SIGTERM ,0 , + ctdb_mutex_rados_sigterm_cb, + cmr_state); +if (cmr_state->sig_ev ==NULL ) { +fprintf (stderr,"Failed to create signal event\n" ); +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + ret = -ENOMEM ; + goto err_state_free; + } + +/* periodically check parent */ + cmr_state->timer_ev =tevent_add_timer (cmr_state->ev, cmr_state, +timeval_current_ofs (5 ,0 ), + ctdb_mutex_rados_timer_cb, + cmr_state); +if (cmr_state->timer_ev ==NULL ) { +fprintf (stderr,"Failed to create timer event\n" ); +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + ret = -ENOMEM ; + goto err_state_free; + } + + ret =ctdb_mutex_rados_ctx_create (cmr_state->ceph_cluster_name, + cmr_state->ceph_auth_name, + cmr_state->pool_name, + &cmr_state->ceph_cluster, + &cmr_state->ioctx); +if (ret <0 ) { +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + goto err_state_free; + } + + ret =ctdb_mutex_rados_lock (cmr_state->ioctx, cmr_state->object); +if ((ret == -EEXIST ) || (ret == -EBUSY )) { +fprintf (stdout,CTDB_MUTEX_STATUS_CONTENDED ); + goto err_ctx_cleanup; + }else if (ret <0 ) { +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + goto err_ctx_cleanup; + } + + cmr_state->holding_mutex = true; +fprintf (stdout,CTDB_MUTEX_STATUS_HOLDING ); + +/* wait for the signal / timer events to do their work */ + ret =tevent_loop_wait (cmr_state->ev); +if (ret <0 ) { + goto err_ctx_cleanup; + } +err_ctx_cleanup: +ctdb_mutex_rados_ctx_destroy (cmr_state->ceph_cluster, + cmr_state->ioctx); +err_state_free: +talloc_free (cmr_state); +err_out: +return ret ?1 :0 ; +}
ctdb/wscript +19 -0
@@ -70,6 +70,9 @@ def set_options(opt): opt.add_option('--enable-pmda', help=("Turn on PCP pmda support (default=no)"), action="store_true", dest='ctdb_pmda', default=False) + opt.add_option('--enable-ceph-reclock', + help=("Enable Ceph CTDB recovery lock helper (default=no)"), + action="store_true", dest='ctdb_ceph_reclock', default=False) opt.add_option('--with-logdir', help=("Path to log directory"),
@@ -160,6 +163,15 @@ def configure(conf): conf.env.CTDB_PMDADIR = os.path.join(conf.env.LOCALSTATEDIR, 'lib/pcp/pmdas/ctdb') + if Options.options.ctdb_ceph_reclock: + if (conf.CHECK_HEADERS('rados/librados.h', False, False, 'rados') and + conf.CHECK_LIB('rados', shlib=True)): + Logs.info('Building with Ceph librados recovery lock support') + conf.define('HAVE_LIBRADOS', 1) + else: + Logs.error("Missing librados for Ceph recovery lock support") + sys.exit(1) + have_infiniband = False if Options.options.ctdb_infiniband: ib_support = True
@@ -516,6 +528,13 @@ def build(bld): bld.INSTALL_FILES('${CTDB_PMDADIR}', 'utils/pmda/README', destname='README') + if bld.env.HAVE_LIBRADOS: + bld.SAMBA_BINARY('ctdb_mutex_ceph_rados_helper', + source='utils/ceph/ctdb_mutex_ceph_rados_helper.c', + deps='ctdb-system rados', + includes='include', + install_path='${CTDB_HELPER_BINDIR}') + sed_expr1 = 's|/usr/local/var/lib/ctdb|%s|g' % (bld.env.CTDB_VARDIR) sed_expr2 = 's|/usr/local/etc/ctdb|%s|g' % (bld.env.CTDB_ETCDIR) sed_expr3 = 's|/usr/local/var/log|%s|g' % (bld.env.CTDB_LOGDIR)
Signature · 14 lines
2.10.2 From 2e4e170dba4fdbd5bdf0c62c4c71e361d97bf6ee Mon Sep 17 00:00:00 2001 From: David Disseldorp <[email protected]> Date: Thu, 1 Dec 2016 14:22:45 +0100 Subject: [PATCH 2/3] ctdb/doc: man page for Ceph RADOS cluster mutex helper Signed-off-by: David Disseldorp <[email protected]> --- ctdb/doc/Makefile | 3 +- ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml | 90 +++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml
ctdb/doc/Makefile +2 -1
@@ -9,7 +9,8 @@ DOCS = ctdb.1 ctdb.1.html \ ctdb.7 ctdb.7.html \ ctdb-statistics.7 ctdb-statistics.7.html \ ctdb-etcd.7 ctdb-etcd.7.html \ - ctdb-tunables.7 ctdb-tunables.7.html + ctdb-tunables.7 ctdb-tunables.7.html \ + ctdb_mutex_ceph_rados_helper.7 ctdb_mutex_ceph_rados_helper.7.html all: $(DOCS)
ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml new file +90 -0
90 lines not on this page · raw message
Signature · 25 lines
2.10.2 From ba0581fbfcd2d5718e2223aba3121f9a9c0f8a4a Mon Sep 17 00:00:00 2001 From: David Disseldorp <[email protected]> Date: Tue, 6 Dec 2016 13:03:27 +0100 Subject: [PATCH 3/3] ctdb: add test script for ctdb_mutex_ceph_rados_helper This standalone test script performs the following: - using ctdb_mutex_ceph_rados_helper, take a lock on the Ceph RADOS object a CLUSTER/$POOL/$OBJECT using the Ceph keyring for $USER + confirm that lock is obtained, via ctdb_mutex_ceph_rados_helper "0" output - check RADOS object lock state, using the "rados lock info" command - attempt to obtain the lock again, using ctdb_mutex_ceph_rados_helper + confirm that the lock is not successfully taken - tell the first locker to drop the lock and exit, via SIGTERM - once the first locker has exited, attempt to get the lock again + confirm that this attempt succeeds Signed-off-by: David Disseldorp <[email protected]> --- ctdb/utils/ceph/test_ceph_rados_reclock.sh | 151 +++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100755 ctdb/utils/ceph/test_ceph_rados_reclock.sh
ctdb/utils/ceph/test_ceph_rados_reclock.sh new file +151 -0
151 lines not on this page · raw message
Signature · 1 line
2.10.2
A message that is not in the archive (sent off-list or not yet received): CAJ+X7mRh04D+Yvtf0xx3dT6rTa=9KvJagyK=1PJQC=1R+u++7w@mail.gmail.com
Hi Amitay,
Quoted 14 lines · Amitay Isaacs
Hi David,
Quoted 9 lines · David Disseldorp
This time with the patch-set attached...
Quoted 6 lines
ctdb/doc/Makefile | 3 +- ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml | 90 +++++ .../utils/ceph/ctdb_mutex_ceph_rados_helper.c | 334 ++++++++++++++++++ ctdb/utils/ceph/test_ceph_rados_reclock.sh | 151 ++++++++ ctdb/wscript | 19 + 5 files changed, 596 insertions(+), 1 deletion(-)
Quoted 7 lines
In patch 1, why do you need to include any of the CTDB files (
protocol/protocol.handcommon/system.h) and have dependency on ctdb-system? I don't see you are using any of the functions defined incommon/system.h.Please include the manpage in
SAMBA_BINARY()definition. Also include it in manpages[] list. It might be better to merge patch 1 and patch 2.
Thanks for the feedback. Please find a new version attached (atop the etcd changes), attempting to address your points above:
- drop unnecessary includes and ctdb-system dependency
+ add separate talloc and tevent deps
+ use tevent_timeval_current_ofs() instead of timeval_current_ofs()
- conditionally generate the man page
Cheers, David
From 54c16ac1dfafb06111aeafb2377b06bd5db36994 Mon Sep 17 00:00:00 2001
From: David Disseldorp <[email protected]>
Date: Thu, 1 Dec 2016 13:33:22 +0100
Subject: [PATCH 1/3] ctdb: cluster mutex helper using Ceph RADOS
ctdb_mutex_ceph_rados_helper implements the cluster mutex helper API atop Ceph using the librados rados_lock_exclusive()/rados_unlock() functionality.
Once configured, split brain avoidance during CTDB recovery will be handled using locks against an object located in a Ceph RADOS pool.
--- ctdb/utils/ceph/ctdb_mutex_ceph_rados_helper.c | 328 +++++++++++++++++++++++++ ctdb/wscript | 19 ++ 2 files changed, 347 insertions(+) create mode 100644 ctdb/utils/ceph/ctdb_mutex_ceph_rados_helper.c
ctdb/utils/ceph/ctdb_mutex_ceph_rados_helper.c new file +328 -0
@@ -0,0 +1,328 @@ +/* +CTDB mutex helper using Ceph librados locks + +Copyright (C) David Disseldorp 2016 + +Based on ctdb_mutex_fcntl_helper.c, which is: +Copyright (C) Martin Schwenke 2015 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" + +#include "tevent.h" +#include "talloc.h" +#include "rados/librados.h" + +#define CTDB_MUTEX_CEPH_LOCK_NAME "ctdb_reclock_mutex" +#define CTDB_MUTEX_CEPH_LOCK_COOKIE CTDB_MUTEX_CEPH_LOCK_NAME +#define CTDB_MUTEX_CEPH_LOCK_DESC "CTDB recovery lock" + +#define CTDB_MUTEX_STATUS_HOLDING "0" +#define CTDB_MUTEX_STATUS_CONTENDED "1" +#define CTDB_MUTEX_STATUS_TIMEOUT "2" +#define CTDB_MUTEX_STATUS_ERROR "3" + +static char *progname =NULL ; + +static int ctdb_mutex_rados_ctx_create (const char *ceph_cluster_name, +const char *ceph_auth_name, +const char *pool_name, +rados_t *_ceph_cluster, +rados_ioctx_t *_ioctx) +{ +rados_t ceph_cluster =NULL ; +rados_ioctx_t ioctx =NULL ; +int ret; + + ret =rados_create2 (&ceph_cluster, ceph_cluster_name, ceph_auth_name,0 ); +if (ret <0 ) { +fprintf (stderr,"%s: failed to initialise Ceph cluster %s as %s" +" - (%s)\n" , progname, ceph_cluster_name, ceph_auth_name, +strerror (-ret)); +return ret; + } + +/* path=NULL tells librados to use default locations */ + ret =rados_conf_read_file (ceph_cluster,NULL ); +if (ret <0 ) { +fprintf (stderr,"%s: failed to parse Ceph cluster config" +" - (%s)\n" , progname,strerror (-ret)); +rados_shutdown (ceph_cluster); +return ret; + } + + ret =rados_connect (ceph_cluster); +if (ret <0 ) { +fprintf (stderr,"%s: failed to connect to Ceph cluster %s as %s" +" - (%s)\n" , progname, ceph_cluster_name, ceph_auth_name, +strerror (-ret)); +rados_shutdown (ceph_cluster); +return ret; + } + + + ret =rados_ioctx_create (ceph_cluster, pool_name, &ioctx); +if (ret <0 ) { +fprintf (stderr,"%s: failed to create Ceph ioctx for pool %s" +" - (%s)\n" , progname, pool_name,strerror (-ret)); +rados_shutdown (ceph_cluster); +return ret; + } + + *_ceph_cluster = ceph_cluster; + *_ioctx = ioctx; + +return 0 ; +} + +static void ctdb_mutex_rados_ctx_destroy (rados_t ceph_cluster, +rados_ioctx_t ioctx) +{ +rados_ioctx_destroy (ioctx); +rados_shutdown (ceph_cluster); +} + +static int ctdb_mutex_rados_lock (rados_ioctx_t *ioctx, +const char *oid) +{ +int ret; + + ret =rados_lock_exclusive (ioctx, oid, +CTDB_MUTEX_CEPH_LOCK_NAME , +CTDB_MUTEX_CEPH_LOCK_COOKIE , +CTDB_MUTEX_CEPH_LOCK_DESC , +NULL ,/* infinite duration */ +0 ); +if ((ret == -EEXIST ) || (ret == -EBUSY )) { +/* lock contention */ +return ret; + }else if (ret <0 ) { +/* unexpected failure */ +fprintf (stderr, +"%s: Failed to get lock on RADOS object '%s' - (%s)\n" , + progname, oid,strerror (-ret)); +return ret; + } + +/* lock obtained */ +return 0 ; +} + +static int ctdb_mutex_rados_unlock (rados_ioctx_t *ioctx, +const char *oid) +{ +int ret; + + ret =rados_unlock (ioctx, oid, +CTDB_MUTEX_CEPH_LOCK_NAME , +CTDB_MUTEX_CEPH_LOCK_COOKIE ); +if (ret <0 ) { +fprintf (stderr, +"%s: Failed to drop lock on RADOS object '%s' - (%s)\n" , + progname, oid,strerror (-ret)); +return ret; + } + +return 0 ; +} + +struct ctdb_mutex_rados_state { +bool holding_mutex; +const char *ceph_cluster_name; +const char *ceph_auth_name; +const char *pool_name; +const char *object; +int ppid; +struct tevent_context *ev; +struct tevent_signal *sig_ev; +struct tevent_timer *timer_ev; +rados_t ceph_cluster; +rados_ioctx_t ioctx; +}; + +static void ctdb_mutex_rados_sigterm_cb (struct tevent_context *ev, +struct tevent_signal *se, +int signum, +int count, +void *siginfo, +void *private_data) +{ +struct ctdb_mutex_rados_state *cmr_state = private_data; +int ret; + +if (!cmr_state->holding_mutex) { +fprintf (stderr,"Sigterm callback invoked without mutex!\n" ); + ret = -EINVAL ; + goto err_ctx_cleanup; + } + + ret =ctdb_mutex_rados_unlock (cmr_state->ioctx, cmr_state->object); +err_ctx_cleanup: +ctdb_mutex_rados_ctx_destroy (cmr_state->ceph_cluster, + cmr_state->ioctx); +talloc_free (cmr_state); +exit (ret ?1 :0 ); +} + +static void ctdb_mutex_rados_timer_cb (struct tevent_context *ev, +struct tevent_timer *te, +struct timeval current_time, +void *private_data) +{ +struct ctdb_mutex_rados_state *cmr_state = private_data; +int ret; + +if (!cmr_state->holding_mutex) { +fprintf (stderr,"Timer callback invoked without mutex!\n" ); + ret = -EINVAL ; + goto err_ctx_cleanup; + } + +if ((kill (cmr_state->ppid,0 ) ==0 ) || (errno !=ESRCH )) { +/* parent still around, keep waiting */ + cmr_state->timer_ev =tevent_add_timer (cmr_state->ev, cmr_state, +tevent_timeval_current_ofs (5 ,0 ), + ctdb_mutex_rados_timer_cb, + cmr_state); +if (cmr_state->timer_ev ==NULL ) { +fprintf (stderr,"Failed to create timer event\n" ); +/* rely on signal cb */ + } +return ; + } + +/* parent ended, drop lock and exit */ + ret =ctdb_mutex_rados_unlock (cmr_state->ioctx, cmr_state->object); +err_ctx_cleanup: +ctdb_mutex_rados_ctx_destroy (cmr_state->ceph_cluster, + cmr_state->ioctx); +talloc_free (cmr_state); +exit (ret ?1 :0 ); +} + +int main (int argc,char *argv[]) +{ +int ret; +struct ctdb_mutex_rados_state *cmr_state; + + progname = argv[0 ]; + +if (argc !=5 ) { +fprintf (stderr,"Usage: %s <Ceph Cluster> <Ceph user> " +"<RADOS pool> <RADOS object>\n" , + progname); + ret = -EINVAL ; + goto err_out; + } + + ret =setvbuf (stdout,NULL , _IONBF,0 ); +if (ret !=0 ) { +fprintf (stderr,"Failed to configure unbuffered stdout I/O\n" ); + } + + cmr_state = talloc_zero(NULL, struct ctdb_mutex_rados_state); +if (cmr_state ==NULL ) { +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + ret = -ENOMEM ; + goto err_out; + } + + cmr_state->ceph_cluster_name = argv[1 ]; + cmr_state->ceph_auth_name = argv[2 ]; + cmr_state->pool_name = argv[3 ]; + cmr_state->object = argv[4 ]; + + cmr_state->ppid =getppid (); +if (cmr_state->ppid ==1 ) { +/* +* The original parent is gone and the process has +* been reparented to init. This can happen if the +* helper is started just as the parent is killed +* during shutdown. The error message doesn't need to +* be stellar, since there won't be anything around to +* capture and log it... +*/ +fprintf (stderr,"%s: PPID == 1\n" , progname); + ret = -EPIPE ; + goto err_state_free; + } + + cmr_state->ev =tevent_context_init (cmr_state); +if (cmr_state->ev ==NULL ) { +fprintf (stderr,"tevent_context_init failed\n" ); +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + ret = -ENOMEM ; + goto err_state_free; + } + +/* wait for sigterm */ + cmr_state->sig_ev =tevent_add_signal (cmr_state->ev, cmr_state,SIGTERM ,0 , + ctdb_mutex_rados_sigterm_cb, + cmr_state); +if (cmr_state->sig_ev ==NULL ) { +fprintf (stderr,"Failed to create signal event\n" ); +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + ret = -ENOMEM ; + goto err_state_free; + } + +/* periodically check parent */ + cmr_state->timer_ev =tevent_add_timer (cmr_state->ev, cmr_state, +tevent_timeval_current_ofs (5 ,0 ), + ctdb_mutex_rados_timer_cb, + cmr_state); +if (cmr_state->timer_ev ==NULL ) { +fprintf (stderr,"Failed to create timer event\n" ); +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + ret = -ENOMEM ; + goto err_state_free; + } + + ret =ctdb_mutex_rados_ctx_create (cmr_state->ceph_cluster_name, + cmr_state->ceph_auth_name, + cmr_state->pool_name, + &cmr_state->ceph_cluster, + &cmr_state->ioctx); +if (ret <0 ) { +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + goto err_state_free; + } + + ret =ctdb_mutex_rados_lock (cmr_state->ioctx, cmr_state->object); +if ((ret == -EEXIST ) || (ret == -EBUSY )) { +fprintf (stdout,CTDB_MUTEX_STATUS_CONTENDED ); + goto err_ctx_cleanup; + }else if (ret <0 ) { +fprintf (stdout,CTDB_MUTEX_STATUS_ERROR ); + goto err_ctx_cleanup; + } + + cmr_state->holding_mutex = true; +fprintf (stdout,CTDB_MUTEX_STATUS_HOLDING ); + +/* wait for the signal / timer events to do their work */ + ret =tevent_loop_wait (cmr_state->ev); +if (ret <0 ) { + goto err_ctx_cleanup; + } +err_ctx_cleanup: +ctdb_mutex_rados_ctx_destroy (cmr_state->ceph_cluster, + cmr_state->ioctx); +err_state_free: +talloc_free (cmr_state); +err_out: +return ret ?1 :0 ; +}
ctdb/wscript +19 -0
@@ -79,6 +79,9 @@ def set_options(opt): opt.add_option('--enable-etcd-reclock', help=("Enable etcd recovery lock helper (default=no)"), action="store_true", dest='ctdb_etcd_reclock', default=False) + opt.add_option('--enable-ceph-reclock', + help=("Enable Ceph CTDB recovery lock helper (default=no)"), + action="store_true", dest='ctdb_ceph_reclock', default=False) opt.add_option('--with-logdir', help=("Path to log directory"),
@@ -201,6 +204,15 @@ def configure(conf): Logs.info('Building with etcd support') conf.env.etcd_reclock = have_etcd_reclock + if Options.options.ctdb_ceph_reclock: + if (conf.CHECK_HEADERS('rados/librados.h', False, False, 'rados') and + conf.CHECK_LIB('rados', shlib=True)): + Logs.info('Building with Ceph librados recovery lock support') + conf.define('HAVE_LIBRADOS', 1) + else: + Logs.error("Missing librados for Ceph recovery lock support") + sys.exit(1) + conf.env.CTDB_BINDIR = os.path.join(conf.env.EXEC_PREFIX, 'bin') conf.env.CTDB_ETCDIR = os.path.join(conf.env.SYSCONFDIR, 'ctdb') conf.env.CTDB_VARDIR = os.path.join(conf.env.LOCALSTATEDIR, 'lib/ctdb')
@@ -540,6 +552,13 @@ def build(bld): bld.INSTALL_FILES('${CTDB_PMDADIR}', 'utils/pmda/README', destname='README') + if bld.env.HAVE_LIBRADOS: + bld.SAMBA_BINARY('ctdb_mutex_ceph_rados_helper', + source='utils/ceph/ctdb_mutex_ceph_rados_helper.c', + deps='talloc tevent rados', + includes='include', + install_path='${CTDB_HELPER_BINDIR}') + sed_expr1 = 's|/usr/local/var/lib/ctdb|%s|g' % (bld.env.CTDB_VARDIR) sed_expr2 = 's|/usr/local/etc/ctdb|%s|g' % (bld.env.CTDB_ETCDIR) sed_expr3 = 's|/usr/local/var/log|%s|g' % (bld.env.CTDB_LOGDIR)
Signature · 14 lines
2.10.2 From 35912b7dca417639615ad5662b5a76ee3e25a6ec Mon Sep 17 00:00:00 2001 From: David Disseldorp <[email protected]> Date: Thu, 1 Dec 2016 14:22:45 +0100 Subject: [PATCH 2/3] ctdb/doc: man page for Ceph RADOS cluster mutex helper Signed-off-by: David Disseldorp <[email protected]> --- ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml | 90 +++++++++++++++++++++++++++++ ctdb/wscript | 12 +++- 2 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml
ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml new file +90 -0
90 lines not on this page · raw message
ctdb/wscript +10 -2
@@ -58,6 +58,10 @@ manpages_etcd = [ 'ctdb-etcd.7', ] +manpages_ceph = [ + 'ctdb_mutex_ceph_rados_helper.7', +] + def set_options(opt): opt.PRIVATE_EXTENSION_DEFAULT('ctdb')
@@ -273,7 +277,9 @@ def configure(conf): conf.env.ctdb_prebuilt_manpages = [] manpages = manpages_binary + manpages_misc if conf.env.etcd_reclock: - manpages = manpages + manpages_etcd + manpages += manpages_etcd + if conf.env.HAVE_LIBRADOS: + manpages += manpages_ceph for m in manpages: if os.path.exists(os.path.join("doc", m)): Logs.info(" %s: yes" % (m))
@@ -572,7 +578,9 @@ def build(bld): manpages_extra = manpages_misc if bld.env.etcd_reclock: - manpages_extra = manpages_extra + manpages_etcd + manpages_extra += manpages_etcd + if bld.env.HAVE_LIBRADOS: + manpages_extra += manpages_ceph for f in manpages_binary + manpages_extra: x = '%s.xml' % (f) bld.SAMBA_GENERATOR(x,
Signature · 25 lines
2.10.2 From dbc411675b338ba755c4521a0d859e2c9d67bf87 Mon Sep 17 00:00:00 2001 From: David Disseldorp <[email protected]> Date: Tue, 6 Dec 2016 13:03:27 +0100 Subject: [PATCH 3/3] ctdb: add test script for ctdb_mutex_ceph_rados_helper This standalone test script performs the following: - using ctdb_mutex_ceph_rados_helper, take a lock on the Ceph RADOS object a CLUSTER/$POOL/$OBJECT using the Ceph keyring for $USER + confirm that lock is obtained, via ctdb_mutex_ceph_rados_helper "0" output - check RADOS object lock state, using the "rados lock info" command - attempt to obtain the lock again, using ctdb_mutex_ceph_rados_helper + confirm that the lock is not successfully taken - tell the first locker to drop the lock and exit, via SIGTERM - once the first locker has exited, attempt to get the lock again + confirm that this attempt succeeds Signed-off-by: David Disseldorp <[email protected]> --- ctdb/utils/ceph/test_ceph_rados_reclock.sh | 151 +++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100755 ctdb/utils/ceph/test_ceph_rados_reclock.sh
ctdb/utils/ceph/test_ceph_rados_reclock.sh new file +151 -0
151 lines not on this page · raw message
Signature · 1 line
2.10.2
Quoted 28 lines · David Disseldorp
Hi Amitay,
Quoted 9 lines · Amitay Isaacs
Hi David,
Quoted 5 lines · David Disseldorp
This time with the patch-set attached...
Quoted 3 lines
ctdb/doc/Makefile | 3 +- ctdb/doc/ctdb_mutex_ceph_rados_helper.7.xml | 90 +++++ .../utils/ceph/ctdb_mutex_ceph_rados_helper.c | 334++++++++++++++++++
Quoted 11 lines
Quoted 4 lines
Quoted 3 lines
ctdb/utils/ceph/test_ceph_rados_reclock.sh | 151 ++++++++ ctdb/wscript | 19 + 5 files changed, 596 insertions(+), 1 deletion(-)In patch 1, why do you need to include any of the CTDB files (
protocol/protocol.handcommon/system.h) and have dependency on ctdb-system? I don't see you are using any of the functions defined incommon/system.h.Please include the manpage in
SAMBA_BINARY()definition. Also include itin
Quoted 1 line
manpages[] list. It might be better to merge patch 1 and patch 2.
Quoted 8 lines
Thanks for the feedback. Please find a new version attached (atop the etcd changes), attempting to address your points above:
- drop unnecessary includes and ctdb-system dependency
+ add separate talloc and tevent deps
+ usetevent_timeval_current_ofs()instead oftimeval_current_ofs()
- conditionally generate the man pageCheers, David
Looks good. Pushed to autobuild with following minor fixups.
- In manpage, replace ctdb_mutex_ceph_rados_helper_lock with ctdb_mutex_ceph_rados_helper
- In wscript, add missing manpages_ceph in the dist target
Amitay.