Add the code to do the actual corosync.conf reload to cfg, along with
a corosync-cfgtool -R command to trigger it

Signed-off-by: Christine Caulfield <[email protected]>
---
 exec/cfg.c                 | 238 ++++++++++++++++++++++++++++++++++++++++++++-
 include/corosync/cfg.h     |   5 +-
 include/corosync/ipc_cfg.h |  14 ++-
 lib/cfg.c                  |  41 +++++++-
 man/corosync-cfgtool.8     |   3 +
 tools/corosync-cfgtool.c   |  31 +++++-
 6 files changed, 324 insertions(+), 8 deletions(-)

diff --git a/exec/cfg.c b/exec/cfg.c
index 503cde1..49c2507 100644
--- a/exec/cfg.c
+++ b/exec/cfg.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2005-2006 MontaVista Software, Inc.
- * Copyright (c) 2006-2012 Red Hat, Inc.
+ * Copyright (c) 2006-2013 Red Hat, Inc.
  *
  * All rights reserved.
  *
@@ -64,13 +64,15 @@
 #include <corosync/corodefs.h>
 
 #include "service.h"
+#include "main.h"
 
 LOGSYS_DECLARE_SUBSYS ("CFG");
 
 enum cfg_message_req_types {
         MESSAGE_REQ_EXEC_CFG_RINGREENABLE = 0,
        MESSAGE_REQ_EXEC_CFG_KILLNODE = 1,
-       MESSAGE_REQ_EXEC_CFG_SHUTDOWN = 2
+       MESSAGE_REQ_EXEC_CFG_SHUTDOWN = 2,
+       MESSAGE_REQ_EXEC_CFG_RELOAD_CONFIG = 3
 };
 
 #define DEFAULT_SHUTDOWN_TIMEOUT 5
@@ -122,6 +124,10 @@ static void message_handler_req_exec_cfg_shutdown (
         const void *message,
         unsigned int nodeid);
 
+static void message_handler_req_exec_cfg_reload_config (
+        const void *message,
+        unsigned int nodeid);
+
 static void exec_cfg_killnode_endian_convert (void *msg);
 
 static void message_handler_req_lib_cfg_ringstatusget (
@@ -152,6 +158,10 @@ static void message_handler_req_lib_cfg_local_get (
        void *conn,
        const void *msg);
 
+static void message_handler_req_lib_cfg_reload_config (
+       void *conn,
+       const void *msg);
+
 /*
  * Service Handler Definition
  */
@@ -184,6 +194,10 @@ static struct corosync_lib_handler cfg_lib_engine[] =
        { /* 6 */
                .lib_handler_fn         = message_handler_req_lib_cfg_local_get,
                .flow_control           = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
+       },
+       { /* 7 */
+               .lib_handler_fn         = 
message_handler_req_lib_cfg_reload_config,
+               .flow_control           = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
        }
 };
 
@@ -198,6 +212,9 @@ static struct corosync_exec_handler cfg_exec_engine[] =
        },
        { /* 2 */
                .exec_handler_fn = message_handler_req_exec_cfg_shutdown,
+       },
+       { /* 3 */
+               .exec_handler_fn = message_handler_req_exec_cfg_reload_config,
        }
 };
 
@@ -231,6 +248,11 @@ struct req_exec_cfg_ringreenable {
         mar_message_source_t source __attribute__((aligned(8)));
 };
 
+struct req_exec_cfg_reload_config {
+       struct qb_ipc_request_header header __attribute__((aligned(8)));
+       mar_message_source_t source __attribute__((aligned(8)));
+};
+
 struct req_exec_cfg_killnode {
        struct qb_ipc_request_header header __attribute__((aligned(8)));
         mar_uint32_t nodeid __attribute__((aligned(8)));
@@ -526,6 +548,196 @@ static void message_handler_req_exec_cfg_shutdown (
        LEAVE();
 }
 
+/* strcmp replacement that can handle NULLs */
+static int nullcheck_strcmp(const char* left, const char *right)
+{
+       if (!left && right)
+               return -1;
+       if (left && ! right)
+               return 1;
+
+       if (!left && !right)
+               return 0;
+
+       return strcmp(left, right);
+}
+
+/*
+ * If a key has changed value in the new file, then warn the user and remove 
it from the temp_map
+ */
+static void delete_and_notify_if_changed(icmap_map_t temp_map, const char 
*key_name)
+{
+       if (!(icmap_key_value_eq(temp_map, key_name, icmap_get_global_map(), 
key_name))) {
+               if (icmap_delete_r(temp_map, key_name) == CS_OK) {
+                       log_printf(LOGSYS_LEVEL_NOTICE, "Modified entry '%s' in 
corosync.conf cannot be changed at run-time", key_name);
+               }
+       }
+}
+/*
+ * Remove any keys from the new config file that in the new corosync.conf but 
that
+ * cannot be changed at run time. A log message will be issued for each
+ * entry that the user wants to change but they cannot.
+ *
+ * Add more here as needed.
+ */
+static void remove_ro_entries(icmap_map_t temp_map)
+{
+       delete_and_notify_if_changed(temp_map, "totem.secauth");
+       delete_and_notify_if_changed(temp_map, "totem.crypto_hash");
+       delete_and_notify_if_changed(temp_map, "totem.crypto_cipher");
+       delete_and_notify_if_changed(temp_map, "totem.version");
+       delete_and_notify_if_changed(temp_map, "totem.threads");
+       delete_and_notify_if_changed(temp_map, "totem.ip_version");
+       delete_and_notify_if_changed(temp_map, "totem.rrp_mode");
+       delete_and_notify_if_changed(temp_map, "totem.netmtu");
+       delete_and_notify_if_changed(temp_map, "totem.interface.ringnumber");
+       delete_and_notify_if_changed(temp_map, "totem.interface.bindnetaddr");
+       delete_and_notify_if_changed(temp_map, "totem.interface.mcastaddr");
+       delete_and_notify_if_changed(temp_map, "totem.interface.broadcast");
+       delete_and_notify_if_changed(temp_map, "totem.interface.mcastport");
+       delete_and_notify_if_changed(temp_map, "totem.interface.ttl");
+       delete_and_notify_if_changed(temp_map, "totem.vsftype");
+       delete_and_notify_if_changed(temp_map, "totem.transport");
+       delete_and_notify_if_changed(temp_map, "totem.cluster_name");
+       delete_and_notify_if_changed(temp_map, "quorum.provider");
+       delete_and_notify_if_changed(temp_map, "qb.ipc_type");
+}
+
+/*
+ * Remove entries that exist in the global map, but not in the temp_map, this 
will
+ * cause delete notifications to be sent to any listeners.
+ *
+ * NOTE: This routine depends entirely on the keys returned by the iterators
+ * being in alpha-sorted order.
+ */
+static void remove_deleted_entries(icmap_map_t temp_map, const char *prefix)
+{
+       icmap_iter_t old_iter;
+       icmap_iter_t new_iter;
+       const char *old_key, *new_key;
+       int ret;
+
+       old_iter = icmap_iter_init(prefix);
+       new_iter = icmap_iter_init_r(temp_map, prefix);
+
+       old_key = icmap_iter_next(old_iter, NULL, NULL);
+       new_key = icmap_iter_next(new_iter, NULL, NULL);
+
+       while (old_key || new_key) {
+               ret = nullcheck_strcmp(old_key, new_key);
+               if ((ret < 0 && old_key) || !new_key) {
+                       /*
+                        * new_key is greater, a line (or more) has been deleted
+                        * Continue until old is >= new
+                        */
+                       do {
+                               /* Remove it from icmap & send notifications */
+                               icmap_delete(old_key);
+
+                               old_key = icmap_iter_next(old_iter, NULL, NULL);
+                               ret = nullcheck_strcmp(old_key, new_key);
+                       } while (ret < 0 && old_key);
+               }
+               else if ((ret > 0 && new_key) || !old_key) {
+                       /*
+                        * old_key is greater, a line (or more) has been added
+                        * Continue until new is >= old
+                        *
+                        * we don't need to do anything special with this like 
tell
+                        * icmap. That will happen when we copy the values over
+                        */
+                       do {
+                               new_key = icmap_iter_next(new_iter, NULL, NULL);
+                               ret = nullcheck_strcmp(old_key, new_key);
+                       } while (ret > 0 && new_key);
+               }
+               if (ret == 0) {
+                       new_key = icmap_iter_next(new_iter, NULL, NULL);
+                       old_key = icmap_iter_next(old_iter, NULL, NULL);
+               }
+       }
+       icmap_iter_finalize(new_iter);
+       icmap_iter_finalize(old_iter);
+}
+
+/*
+ * Reload configuration file
+ */
+static void message_handler_req_exec_cfg_reload_config (
+        const void *message,
+        unsigned int nodeid)
+{
+       const struct req_exec_cfg_reload_config *req_exec_cfg_reload_config = 
message;
+       struct res_lib_cfg_reload_config res_lib_cfg_reload_config;
+       icmap_map_t temp_map;
+       const char *error_string;
+       int res = CS_OK;
+
+       ENTER();
+
+       log_printf(LOGSYS_LEVEL_NOTICE, "Config reload requested by node %d", 
nodeid);
+
+       /*
+        * Set up a new hashtable as a staging area.
+        */
+       if ((res = icmap_init_r(&temp_map)) != CS_OK) {
+               log_printf(LOGSYS_LEVEL_ERROR, "Unable to create temporary 
icmap. config file reload cancelled\n");
+               goto reload_fini;
+       }
+
+       /*
+        * Load new config into the temporary map
+        */
+       res = coroparse_configparse(temp_map, &error_string);
+       if (res == -1) {
+               log_printf (LOGSYS_LEVEL_ERROR, "Unable to reload config file: 
%s", error_string);
+               res = CS_ERR_LIBRARY;
+               goto reload_return;
+       }
+
+       /* Tell interested listeners that we have started a reload */
+       icmap_set_uint8("config.reload_in_progress", 1);
+
+       /* Detect deleted entries and remove them from the main icmap hashtable 
*/
+       remove_deleted_entries(temp_map, "logging.");
+       remove_deleted_entries(temp_map, "totem.");
+       remove_deleted_entries(temp_map, "nodelist.");
+       remove_deleted_entries(temp_map, "quorum.");
+
+       /* Remove entries that cannot be changed */
+       remove_ro_entries(temp_map);
+
+       /*
+        * Copy new keys into live config.
+        * If this fails we will have a partially loaded config because some 
keys (above) might
+        * have been reset to defaults - I'm not sure what to do here, we might 
have to quit.
+        */
+       if ( (res = icmap_copy_map(icmap_get_global_map(), temp_map)) != CS_OK) 
{
+               log_printf (LOGSYS_LEVEL_ERROR, "Error making new config live. 
cmap database may be inconsistent\n");
+       }
+
+       /* All done - let clients know */
+       icmap_set_uint8("config.reload_in_progress", 0);
+
+reload_fini:
+       /* Finished with the temporary storage */
+       icmap_fini_r(temp_map);
+
+reload_return:
+       /* All done, return result to the caller if it was on this system */
+       if (nodeid == api->totem_nodeid_get()) {
+               res_lib_cfg_reload_config.header.size = 
sizeof(res_lib_cfg_reload_config);
+               res_lib_cfg_reload_config.header.id = 
MESSAGE_RES_CFG_RELOAD_CONFIG;
+               res_lib_cfg_reload_config.header.error = res;
+               api->ipc_response_send(req_exec_cfg_reload_config->source.conn,
+                                      &res_lib_cfg_reload_config,
+                                      sizeof(res_lib_cfg_reload_config));
+               api->ipc_refcnt_dec(req_exec_cfg_reload_config->source.conn);;
+       }
+
+       LEAVE();
+}
+
 /*
  * Library Interface Implementation
  */
@@ -847,3 +1059,25 @@ static void message_handler_req_lib_cfg_local_get (void 
*conn, const void *msg)
        api->ipc_response_send(conn, &res_lib_cfg_local_get,
                sizeof(res_lib_cfg_local_get));
 }
+
+static void message_handler_req_lib_cfg_reload_config (void *conn, const void 
*msg)
+{
+       struct req_exec_cfg_reload_config req_exec_cfg_reload_config;
+       struct iovec iovec;
+
+       ENTER();
+
+       req_exec_cfg_reload_config.header.size =
+               sizeof (struct req_exec_cfg_reload_config);
+       req_exec_cfg_reload_config.header.id = SERVICE_ID_MAKE (CFG_SERVICE,
+               MESSAGE_REQ_EXEC_CFG_RELOAD_CONFIG);
+       api->ipc_source_set (&req_exec_cfg_reload_config.source, conn);
+       api->ipc_refcnt_inc(conn);
+
+       iovec.iov_base = (char *)&req_exec_cfg_reload_config;
+       iovec.iov_len = sizeof (struct req_exec_cfg_reload_config);
+
+       assert (api->totem_mcast (&iovec, 1, TOTEM_SAFE) == 0);
+
+       LEAVE();
+}
diff --git a/include/corosync/cfg.h b/include/corosync/cfg.h
index d26d5d1..cacbd6a 100644
--- a/include/corosync/cfg.h
+++ b/include/corosync/cfg.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2005 MontaVista Software, Inc.
- * Copyright (c) 2006-2012 Red Hat, Inc.
+ * Copyright (c) 2006-2013 Red Hat, Inc.
  *
  * All rights reserved.
  *
@@ -157,6 +157,9 @@ corosync_cfg_local_get (
        corosync_cfg_handle_t handle,
        unsigned int *local_nodeid);
 
+cs_error_t corosync_cfg_reload_config (
+       corosync_cfg_handle_t handle);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/corosync/ipc_cfg.h b/include/corosync/ipc_cfg.h
index f5f6748..a12a847 100644
--- a/include/corosync/ipc_cfg.h
+++ b/include/corosync/ipc_cfg.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2005 MontaVista Software, Inc.
- * Copyright (c) 2009-2012 Red Hat, Inc.
+ * Copyright (c) 2009-2013 Red Hat, Inc.
  *
  * All rights reserved.
  *
@@ -55,7 +55,8 @@ enum req_lib_cfg_types {
        MESSAGE_REQ_CFG_REPLYTOSHUTDOWN = 4,
        MESSAGE_REQ_CFG_GET_NODE_ADDRS = 5,
        MESSAGE_REQ_CFG_LOCAL_GET = 6,
-       MESSAGE_REQ_CFG_CRYPTO_SET = 7
+       MESSAGE_REQ_CFG_RELOAD_CONFIG = 7,
+       MESSAGE_REQ_CFG_CRYPTO_SET = 8
 };
 
 enum res_lib_cfg_types {
@@ -74,6 +75,7 @@ enum res_lib_cfg_types {
        MESSAGE_RES_CFG_LOCAL_GET = 12,
        MESSAGE_RES_CFG_REPLYTOSHUTDOWN = 13,
        MESSAGE_RES_CFG_CRYPTO_SET = 14,
+       MESSAGE_RES_CFG_RELOAD_CONFIG = 15
 };
 
 struct req_lib_cfg_ringstatusget {
@@ -150,6 +152,14 @@ struct res_lib_cfg_local_get {
        mar_uint32_t local_nodeid __attribute__((aligned(8)));
 };
 
+struct req_lib_cfg_reload_config {
+       struct qb_ipc_request_header header __attribute__((aligned(8)));
+};
+
+struct res_lib_cfg_reload_config {
+       struct qb_ipc_response_header header __attribute__((aligned(8)));
+};
+
 typedef enum {
        AIS_AMF_ADMINISTRATIVETARGET_SERVICEUNIT = 0,
        AIS_AMF_ADMINISTRATIVETARGET_SERVICEGROUP = 1,
diff --git a/lib/cfg.c b/lib/cfg.c
index d594324..7bb56de 100644
--- a/lib/cfg.c
+++ b/lib/cfg.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2002-2005 MontaVista Software, Inc.
- * Copyright (c) 2006-2011 Red Hat, Inc.
+ * Copyright (c) 2006-2013 Red Hat, Inc.
  *
  * All rights reserved.
  *
@@ -620,3 +620,42 @@ error_exit:
 
        return (error);
 }
+
+cs_error_t corosync_cfg_reload_config (
+       corosync_cfg_handle_t handle)
+{
+       cs_error_t error;
+       struct cfg_inst *cfg_inst;
+       struct iovec iov;
+       struct req_lib_cfg_reload_config req_lib_cfg_reload_config;
+       struct res_lib_cfg_reload_config res_lib_cfg_reload_config;
+
+       error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, handle, (void 
*)&cfg_inst));
+       if (error != CS_OK) {
+               return (error);
+       }
+
+       req_lib_cfg_reload_config.header.size = sizeof (struct 
qb_ipc_request_header);
+       req_lib_cfg_reload_config.header.id = MESSAGE_REQ_CFG_RELOAD_CONFIG;
+
+       iov.iov_base = (void *)&req_lib_cfg_reload_config;
+       iov.iov_len = sizeof (struct req_lib_cfg_reload_config);
+
+       error = qb_to_cs_error (qb_ipcc_sendv_recv (
+               cfg_inst->c,
+               &iov,
+               1,
+               &res_lib_cfg_reload_config,
+               sizeof (struct res_lib_cfg_reload_config), CS_IPC_TIMEOUT_MS));
+
+       if (error != CS_OK) {
+               goto error_exit;
+       }
+
+       error = res_lib_cfg_reload_config.header.error;
+
+error_exit:
+       (void)hdb_handle_put (&cfg_hdb, handle);
+
+       return (error);
+}
diff --git a/man/corosync-cfgtool.8 b/man/corosync-cfgtool.8
index f3c9784..6df8651 100644
--- a/man/corosync-cfgtool.8
+++ b/man/corosync-cfgtool.8
@@ -68,6 +68,9 @@ Display the IP address(es) of a node.
 .B -k
 Kill a node identified by node id.
 .TP 
+.B -R
+Tell all instances of corosync in this cluster to reload corosync.conf
+.TP 
 .B -H
 Shutdown corosync cleanly on this node.
 .SH "SEE ALSO"
diff --git a/tools/corosync-cfgtool.c b/tools/corosync-cfgtool.c
index 12a66a7..07d318a 100644
--- a/tools/corosync-cfgtool.c
+++ b/tools/corosync-cfgtool.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2012 Red Hat, Inc.
+ * Copyright (c) 2006-2013 Red Hat, Inc.
  *
  * All rights reserved.
  *
@@ -137,6 +137,29 @@ static void ringreenable_do (void)
        (void)corosync_cfg_finalize (handle);
 }
 
+static void reload_config_do (void)
+{
+       cs_error_t result;
+       corosync_cfg_handle_t handle;
+
+       printf ("Reloading corosync.conf...\n");
+       result = corosync_cfg_initialize (&handle, NULL);
+       if (result != CS_OK) {
+               printf ("Could not initialize corosync configuration API error 
%d\n", result);
+               exit (1);
+       }
+
+       result = corosync_cfg_reload_config (handle);
+       if (result != CS_OK) {
+               printf ("Could not reload configuration %d\n", result);
+       }
+       else {
+               printf ("Done\n");
+       }
+
+       (void)corosync_cfg_finalize (handle);
+}
+
 static void shutdown_do(void)
 {
        cs_error_t result;
@@ -232,11 +255,12 @@ static void usage_do (void)
        printf ("\t\tre-enable redundant ring operation.\n");
        printf ("\t-a\tDisplay the IP address(es) of a node\n");
        printf ("\t-k\tKill a node identified by node id.\n");
+       printf ("\t-R\tReload corosync.conf on all nodes.\n");
        printf ("\t-H\tShutdown corosync cleanly on this node.\n");
 }
 
 int main (int argc, char *argv[]) {
-       const char *options = "i:srk:a:hH";
+       const char *options = "i:srRk:a:hH";
        int opt;
        unsigned int nodeid;
        char interface_name[128] = "";
@@ -253,6 +277,9 @@ int main (int argc, char *argv[]) {
                case 's':
                        rc = ringstatusget_do (interface_name);
                        break;
+               case 'R':
+                       reload_config_do ();
+                       break;
                case 'r':
                        ringreenable_do ();
                        break;
-- 
1.8.1.4

_______________________________________________
discuss mailing list
[email protected]
http://lists.corosync.org/mailman/listinfo/discuss

Reply via email to