From mboxrd@z Thu Jan 1 00:00:00 1970 From: Lon Hohberger Date: Wed, 2 Feb 2011 19:37:12 -0500 Subject: [Cluster-devel] [PATCH] rgmanager: dbus notifications (Merged) Message-ID: <1296693432-29361-1-git-send-email-lhh@redhat.com> List-Id: To: cluster-devel.redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Includes aforementioned makefile fix Everything in one patch for easy reading. Resolves: rhbz#657756 Signed-off-by: Lon Hohberger --- rgmanager/include/rg_dbus.h | 20 +++ rgmanager/man/rgmanager.8 | 2 + rgmanager/src/daemons/Makefile | 7 +- rgmanager/src/daemons/main.c | 19 ++- rgmanager/src/daemons/update-dbus.c | 266 +++++++++++++++++++++++++++++++++++ 5 files changed, 309 insertions(+), 5 deletions(-) create mode 100644 rgmanager/include/rg_dbus.h create mode 100644 rgmanager/src/daemons/update-dbus.c diff --git a/rgmanager/include/rg_dbus.h b/rgmanager/include/rg_dbus.h new file mode 100644 index 0000000..3ef5ae1 --- /dev/null +++ b/rgmanager/include/rg_dbus.h @@ -0,0 +1,20 @@ +#ifndef _RGM_DBUS_H +#define _RGM_DBUS_H + +int rgm_dbus_init(void); +int rgm_dbus_release(void); +extern int rgm_dbus_notify; + +#ifdef DBUS + +#define RGM_DBUS_DEFAULT 1 +#define RGM_DBUS_UPDATE (rgm_dbus_notify?rgm_dbus_update:0) +int32_t rgm_dbus_update(char *key, uint64_t view, void *data, uint32_t size); + +#else + +#define RGM_DBUS_DEFAULT 0 +#define RGM_DBUS_UPDATE NULL + +#endif /* DBUS */ +#endif diff --git a/rgmanager/man/rgmanager.8 b/rgmanager/man/rgmanager.8 index 39b2195..2b018d2 100644 --- a/rgmanager/man/rgmanager.8 +++ b/rgmanager/man/rgmanager.8 @@ -371,6 +371,8 @@ will leave the virtual machine running. Run in the foreground (do not fork). .IP \-d Enable debug-level logging. +.IP \-q +Disable DBus signals which are normally sent when services change state. .IP \-w Disable internal process monitoring (for debugging). .IP \-N diff --git a/rgmanager/src/daemons/Makefile b/rgmanager/src/daemons/Makefile index 94e0dbb..4dbbe5a 100644 --- a/rgmanager/src/daemons/Makefile +++ b/rgmanager/src/daemons/Makefile @@ -29,6 +29,7 @@ OBJS1= fo_domain.o \ service_op.o \ slang_event.o \ event_config.o \ + update-dbus.o \ watchdog.o OBJS2= test-noccs.o \ @@ -40,12 +41,13 @@ OBJS2= test-noccs.o \ rg_locks-noccs.o \ event_config-noccs.o -CFLAGS += -DSHAREDIR=\"${sharedir}\" -D_GNU_SOURCE +CFLAGS += -DDBUS -DSHAREDIR=\"${sharedir}\" -D_GNU_SOURCE CFLAGS += -fPIC CFLAGS += -I${ccsincdir} -I${cmanincdir} -I${dlmincdir} -I${logtincdir} CFLAGS += `xml2-config --cflags` -I${slangincdir} CFLAGS += -I$(S)/../../include CFLAGS += -I${incdir} +CFLAGS += `pkg-config --cflags dbus-1` NOCCS_CFLAGS += -DNO_CCS @@ -59,6 +61,7 @@ DLM_LDFLAGS += -L${dlmlibdir} -ldlm XML2_LDFLAGS += `xml2-config --libs` SLANG_LDFLAGS += -L${slanglibdir} -lslang EXTRA_LDFLAGS += -lpthread +DBUS_LDFLAGS += `pkg-config --libs dbus-1` LDDEPS += ../clulib/libclulib.a @@ -66,7 +69,7 @@ ${TARGET1}: ${OBJS1} ${LDDEPS} $(CC) -o $@ $^ $(CCS_LDFLAGS) $(CMAN_LDFLAGS) \ $(DLM_LDFLAGS) $(XML2_LDFLAGS) \ $(SLANG_LDFLAGS) $(EXTRA_LDFLAGS) \ - $(LOGSYS_LDFLAGS) $(LD_FLAGS) + $(LOGSYS_LDFLAGS) $(LD_FLAGS) $(DBUS_LDFLAGS) # # Our test program links against the local allocator so that diff --git a/rgmanager/src/daemons/main.c b/rgmanager/src/daemons/main.c index 4e34246..02cd2dc 100644 --- a/rgmanager/src/daemons/main.c +++ b/rgmanager/src/daemons/main.c @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef WRAP_THREADS void dump_thread_states(FILE *); @@ -43,7 +44,6 @@ static uint8_t ALIGNED port = RG_PORT; static char *rgmanager_lsname = (char *)"rgmanager"; /* XXX default */ static int status_poll_interval = DEFAULT_CHECK_INTERVAL; - static void segfault(int __attribute__ ((unused)) sig) { @@ -684,6 +684,8 @@ event_loop(msgctx_t *localctx, msgctx_t *clusterctx) dump_internal_state("/var/lib/cluster/rgmanager-dump"); } + rgm_dbus_init(); + while (running && (tv.tv_sec || tv.tv_usec)) { FD_ZERO(&rfds); max = -1; @@ -949,7 +951,7 @@ main(int argc, char **argv) pthread_t th; cman_handle_t clu = NULL; - while ((rv = getopt(argc, argv, "wfdN")) != EOF) { + while ((rv = getopt(argc, argv, "wfdNq")) != EOF) { switch (rv) { case 'w': wd = 0; @@ -963,6 +965,9 @@ main(int argc, char **argv) case 'f': foreground = 1; break; + case 'q': + rgm_dbus_notify = 0; + break; default: return 1; break; @@ -1032,6 +1037,12 @@ main(int argc, char **argv) configure_rgmanager(-1, debug, &cluster_timeout); logt_print(LOG_NOTICE, "Resource Group Manager Starting\n"); + if (rgm_dbus_notify && rgm_dbus_init() != 0) { + rgm_dbus_notify = 0; + logt_print(LOG_NOTICE, "Failed to initialize DBus; " + "notifications disabled\n"); + } + if (init_resource_groups(0, do_init) != 0) { logt_print(LOG_CRIT, "#8: Couldn't initialize services\n"); goto out_ls; @@ -1074,7 +1085,8 @@ main(int argc, char **argv) ds_key_init("rg_lockdown", 32, 10); #else - if (vf_init(me.cn_nodeid, port, NULL, NULL, cluster_timeout) != 0) { + if (vf_init(me.cn_nodeid, port, NULL, RGM_DBUS_UPDATE, + cluster_timeout) != 0) { logt_print(LOG_CRIT, "#11: Couldn't set up VF listen socket\n"); goto out_ls; } @@ -1106,6 +1118,7 @@ out_ls: clu_lock_finished(rgmanager_lsname); out: + rgm_dbus_release(); logt_print(LOG_NOTICE, "Shutdown complete, exiting\n"); cman_finish(clu); diff --git a/rgmanager/src/daemons/update-dbus.c b/rgmanager/src/daemons/update-dbus.c new file mode 100644 index 0000000..f465d1d --- /dev/null +++ b/rgmanager/src/daemons/update-dbus.c @@ -0,0 +1,266 @@ +/* DBus notifications */ +#include +#include +#include + +#ifdef DBUS + +#include +#include +#include +#include +#include +#include +#include + + +#define DBUS_RGM_NAME "com.redhat.cluster.rgmanager" +#define DBUS_RGM_IFACE "com.redhat.cluster.rgmanager" +#define DBUS_RGM_PATH "/com/redhat/cluster/rgmanager" + +static DBusConnection *db = NULL; +static pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER; +static pthread_t th = 0; +#endif + +/* Set this to the desired value prior to calling rgm_dbus_init() */ +int rgm_dbus_notify = RGM_DBUS_DEFAULT; + + +int +rgm_dbus_init(void) +#ifdef DBUS +{ + DBusConnection *dbc = NULL; + DBusError err; + + if (!rgm_dbus_notify) + return 0; + + pthread_mutex_lock(&mu); + if (db) { + pthread_mutex_unlock(&mu); + return 0; + } + + dbus_error_init(&err); + + dbc = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err); + if (!dbc) { + logt_print(LOG_DEBUG, + "DBus Failed to initialize: dbus_bus_get: %s\n", + err.message); + dbus_error_free(&err); + pthread_mutex_unlock(&mu); + return -1; + } + + dbus_connection_set_exit_on_disconnect(dbc, FALSE); + + db = dbc; + pthread_mutex_unlock(&mu); + logt_print(LOG_DEBUG, "DBus Notifications Initialized\n"); + return 0; +} +#else +{ + errno = ENOSYS; + return -1; +} +#endif + + +#ifdef DBUS +static int +_rgm_dbus_release(void) +{ + pthread_t t; + + if (!db) + return 0; + + /* tell thread to exit - not sure how to tell dbus + * to wake up, so just have it poll XXX */ + + /* if the thread left because the dbus connection died, + this block is avoided */ + if (th) { + t = th; + th = 0; + pthread_join(t, NULL); + } + + dbus_connection_close(db); + dbus_connection_unref(db); + db = NULL; + + logt_print(LOG_DEBUG, "DBus Released\n"); + return 0; +} +#endif + + +/* Clean shutdown (e.g. when exiting */ +int +rgm_dbus_release(void) +#ifdef DBUS +{ + int ret; + + pthread_mutex_lock(&mu); + ret = _rgm_dbus_release(); + pthread_mutex_unlock(&mu); + return ret; +} +#else +{ + return 0; +} +#endif + + +#ifdef DBUS +/* Auto-flush thread. Since sending only guarantees queueing, + * we need this thread to push things out over dbus in the + * background */ +static void * +_dbus_auto_flush(void *arg) +{ + /* DBus connection functions are thread safe */ + dbus_connection_ref(db); + while (dbus_connection_read_write(db, 500)) { + if (!th) + break; + } + + dbus_connection_unref(db); + th = 0; + return NULL; +} + + +static int +_rgm_dbus_notify(const char *svcname, + const char *svcstatus, + const char *svcflags, + const char *svcowner, + const char *svclast) +{ + DBusMessage *msg = NULL; + int ret = -1; + + if (!db) { + goto out_free; + } + + pthread_mutex_lock(&mu); + + /* Check to ensure the connection is still valid. If it + * isn't, clean up and shut down the dbus connection. + * + * The main rgmanager thread will periodically try to + * reinitialize the dbus notification subsystem unless + * the administrator ran rgmanager with the -D command + * line option. + */ + if (dbus_connection_get_is_connected(db) != TRUE) { + goto out_unlock; + } + + if (!th) { + /* start auto-flush thread if needed */ + pthread_create(&th, NULL, _dbus_auto_flush, NULL); + } + + if (!(msg = dbus_message_new_signal(DBUS_RGM_PATH, + DBUS_RGM_IFACE, + "ServiceStateChange"))) { + goto out_unlock; + } + + if (!dbus_message_append_args(msg, + DBUS_TYPE_STRING, &svcname, + DBUS_TYPE_STRING, &svcstatus, + DBUS_TYPE_STRING, &svcflags, + DBUS_TYPE_STRING, &svcowner, + DBUS_TYPE_STRING, &svclast, + DBUS_TYPE_INVALID)) { + goto out_unlock; + } + + dbus_connection_send(db, msg, NULL); + ret = 0; + +out_unlock: + pthread_mutex_unlock(&mu); + if (msg) + dbus_message_unref(msg); +out_free: + return ret; +} + + +/* + * view-formation callback function + */ +int32_t +rgm_dbus_update(char *key, uint64_t view, void *data, uint32_t size) +{ + char flags[64]; + rg_state_t *st; + cluster_member_list_t *m = NULL; + const char *owner; + const char *last; + int ret = 0; + + if (!rgm_dbus_notify) + goto out_free; + if (!db) + goto out_free; + if (view == 1) + goto out_free; + if (size != (sizeof(*st))) + goto out_free; + + st = (rg_state_t *)data; + swab_rg_state_t(st); + + /* Don't send transitional states */ + if (st->rs_state == RG_STATE_STARTING || + st->rs_state == RG_STATE_STOPPING) + goto out_free; + + m = member_list(); + if (!m) + goto out_free; + + owner = memb_id_to_name(m, st->rs_owner); + last = memb_id_to_name(m, st->rs_last_owner); + + if (!owner) + owner = "(none)"; + if (!last) + last = "(none)"; + + flags[0] = 0; + rg_flags_str(flags, sizeof(flags), st->rs_flags, (char *)" "); + if (flags[0] == 0) + snprintf(flags, sizeof(flags), "(none)"); + + ret = _rgm_dbus_notify(st->rs_name, + rg_state_str(st->rs_state), + (char *)flags, owner, last); + + if (ret < 0) { + logt_print(LOG_ERR, "Error sending update for %s; " + "DBus notifications disabled\n", key); + rgm_dbus_release(); + } + +out_free: + if (m) + free_member_list(m); + free(data); + return 0; +} +#endif -- 1.7.2.3