This patch adds significant functionality to 'cman_tool version'. If -r0 is specified, then the configuration file is validated (using ccs_config_validate), distributed around the cluster (if necessary, using ccs_sync) and activated. This provides a single command to update a configuration ... something people have been asking for for ages.

I'm not 100% happy about bundling it into cman_tool version, but neither am I convinced that this warrants another cman_tool sub-command ... so if anyone has any better ideas please speak up.

Chrissie
diff --git a/cman/cman_tool/Makefile b/cman/cman_tool/Makefile
index 0dee578..149b758 100644
--- a/cman/cman_tool/Makefile
+++ b/cman/cman_tool/Makefile
@@ -13,12 +13,14 @@ include $(OBJDIR)/make/uninstall.mk
 OBJS=  main.o \
        join.o
 
-CFLAGS += -DCOROSYNCBIN=\"${corosyncbin}\"
+CFLAGS += -DCOROSYNCBIN=\"${corosyncbin}\" -DSBINDIR=\"${sbindir}\"
 CFLAGS += -I${cmanincdir}
 CFLAGS += -I${incdir}
+CFLAGS += -I${ccsincdir}
 
 LDFLAGS += -L${cmanlibdir} -lcman
 LDFLAGS += -L${libdir}
+LDFLAGS += -L${ccslibdir} -lconfdb -lccs
 
 ${TARGET}: ${OBJS}
        $(CC) -o $@ $^ $(LDFLAGS)
diff --git a/cman/cman_tool/cman_tool.h b/cman/cman_tool/cman_tool.h
index d6374d5..a766a12 100644
--- a/cman/cman_tool/cman_tool.h
+++ b/cman/cman_tool/cman_tool.h
@@ -82,6 +82,7 @@ struct commandline
        unsigned int config_version;
 
        int config_version_opt;
+       int config_novalidate_opt;
        int votes_opt;
        int expected_votes_opt;
        int port_opt;
diff --git a/cman/cman_tool/join.c b/cman/cman_tool/join.c
index 02ef73a..697e944 100644
--- a/cman/cman_tool/join.c
+++ b/cman/cman_tool/join.c
@@ -2,6 +2,7 @@
 #include <stdint.h>
 #include <signal.h>
 #include <netinet/in.h>
+#include <corosync/confdb.h>
 #include "libcman.h"
 #include "cman_tool.h"
 
@@ -111,10 +112,19 @@ int join(commandline_t *comline, char *main_envp[])
        int envptr = 0;
        int argvptr = 0;
        char scratch[1024];
+       char config_modules[1024];
        cman_handle_t h = NULL;
        int status;
+       hdb_handle_t object_handle;
+       confdb_handle_t confdb_handle;
+       int res;
        pid_t corosync_pid;
        int p[2];
+       confdb_callbacks_t callbacks = {
+               .confdb_key_change_notify_fn = NULL,
+               .confdb_object_create_change_notify_fn = NULL,
+               .confdb_object_delete_change_notify_fn = NULL
+       };
 
         /*
         * If we can talk to cman then we're already joined (or joining);
@@ -166,15 +176,15 @@ int join(commandline_t *comline, char *main_envp[])
        }
        if (comline->noconfig_opt) {
                envp[envptr++] = strdup("CMAN_NOCONFIG=true");
-               snprintf(scratch, sizeof(scratch), 
"COROSYNC_DEFAULT_CONFIG_IFACE=cmanpreconfig%s",
+               snprintf(config_modules, sizeof(config_modules), 
"cmanpreconfig%s",
                         
comline->noopenais_opt?"":":openaisserviceenablestable");
-               envp[envptr++] = strdup(scratch);
        }
        else {
-               snprintf(scratch, sizeof(scratch), 
"COROSYNC_DEFAULT_CONFIG_IFACE=%s:cmanpreconfig%s", comline->config_lcrso,
+               snprintf(config_modules, sizeof(config_modules), 
"%s:cmanpreconfig%s", comline->config_lcrso,
                         
comline->noopenais_opt?"":":openaisserviceenablestable");
-               envp[envptr++] = strdup(scratch);
        }
+       snprintf(scratch, sizeof(scratch), "COROSYNC_DEFAULT_CONFIG_IFACE=%s", 
config_modules);
+       envp[envptr++] = strdup(scratch);
 
        /* Copy any COROSYNC_* env variables to the new daemon */
        i=0;
@@ -324,5 +334,19 @@ int join(commandline_t *comline, char *main_envp[])
                fprintf(stderr, "corosync started, but not joined the cluster 
yet.\n");
 
        cman_finish(h);
+
+       /* Save the configuration information in corosync's objdb so we know 
where we came from */
+       res = confdb_initialize (&confdb_handle, &callbacks);
+       if (res != CS_OK)
+               goto join_exit;
+
+       res = confdb_object_create(confdb_handle, OBJECT_PARENT_HANDLE, 
"cman_private", strlen("cman_private"), &object_handle);
+       if (res == CS_OK) {
+               res = confdb_key_create(confdb_handle, object_handle, 
"config_modules", strlen("config_modules"), config_modules, 
strlen(config_modules));
+
+       }
+       confdb_finalize (confdb_handle);
+
+join_exit:
        return 0;
 }
diff --git a/cman/cman_tool/main.c b/cman/cman_tool/main.c
index 2d28bc2..d60a1c3 100644
--- a/cman/cman_tool/main.c
+++ b/cman/cman_tool/main.c
@@ -2,6 +2,7 @@
 #include <unistd.h>
 #include <signal.h>
 #include <time.h>
+#include <ccs.h>
 #include <netinet/in.h>
 #include "copyright.cf"
 #include "libcman.h"
@@ -9,7 +10,7 @@
 
 #define DEFAULT_CONFIG_MODULE "xmlconfig"
 
-#define OPTION_STRING          ("m:n:v:e:2p:c:r:i:N:t:o:k:F:C:VAPwfqah?Xd::")
+#define OPTION_STRING          ("m:n:v:e:2p:c:r:i:N:t:o:k:F:C:VAPwfqah?XDd::")
 #define OP_JOIN                        1
 #define OP_LEAVE               2
 #define OP_EXPECTED            3
@@ -116,6 +117,7 @@ static void print_usage(int subcmd)
        if (!subcmd || subcmd == OP_VERSION) {
                printf("version\n");
                printf("  -r <config>      A new config version to set on all 
members\n");
+               printf("  -D               Don't check configuration for 
validity before loading\n");
                printf("\n");
        }
 }
@@ -642,11 +644,73 @@ static void set_votes(commandline_t *comline)
        cman_finish(h);
 }
 
+static int validate_config(commandline_t *comline, int *setversion)
+{
+       struct stat st;
+       int ccs_handle;
+       int ccs_res;
+       int cmd_res;
+       char *config_value;
+       char validator[PATH_MAX];
+       char command[PATH_MAX];
+
+       *setversion = 0;
+
+       /* Look for ccs_config_validate */
+       snprintf(validator, sizeof(validator), "%s/ccs_config_validate", 
SBINDIR);
+       if (stat(validator, &st) != 0 || !(st.st_mode & S_IXUSR)) {
+               fprintf(stderr, "Cannot find ccs_config_validate, configuration 
was not checked but assumed to be OK.\n");
+               return 0;
+       }
+
+       /* Get the config modules that corosync was loaded with */
+       ccs_handle = ccs_connect();
+       if (!ccs_handle) {
+               fprintf(stderr, "Cannot contact ccs to get configuration 
information\n");
+               return 1;
+       }
+
+       ccs_res = ccs_get(ccs_handle, "/cman_private/@config_modules", 
&config_value);
+       ccs_disconnect(ccs_handle);
+       if (ccs_res) {
+               fprintf(stderr, "Cannot work out where corosync got it's 
configuration information from so I\n");
+               fprintf(stderr, "can't validate it. Use the -D switch to bypass 
this and load the\n");
+               fprintf(stderr, "configuration unchecked.\n");
+               return 1;
+       }
+
+       snprintf(command, sizeof(command), "%s -C %s", validator, config_value);
+
+       if (comline->verbose > 1)
+               printf("calling '%s'\n", command);
+
+       cmd_res = system(command);
+
+       /* If it's OK and we are using xmlconfig then call ccs_sync to 
distribute it */
+       if (cmd_res == 0 && strstr(config_value, "xmlconfig")) {
+               if (comline->verbose > 1)
+                       printf("calling ccs_sync\n");
+
+               cmd_res = system("/usr/bin/ccs_sync");
+               /*
+                * if this succeeds then it will tell cman the new version,
+                * so we don't have to.
+                */
+       }
+       else {
+               /* Tell the caller to inform cman of the new version */
+               *setversion = 1;
+       }
+
+       return cmd_res;
+}
+
 static void version(commandline_t *comline)
 {
        struct cman_version ver;
        cman_handle_t h;
        int result;
+       int need_setversion=1;
 
        h = open_cman_handle(1);
 
@@ -659,10 +723,23 @@ static void version(commandline_t *comline)
                goto out;
        }
 
-       ver.cv_config = comline->config_version;
+       /* By default we validate the configuration first */
+       if (!comline->config_novalidate_opt) {
+               if (comline->verbose)
+                       printf("Validating configuration\n");
+               if (validate_config(comline, &need_setversion))
+                       die("Not reloading, configuration is not valid\n");
+       }
 
-       if ((result = cman_set_version(h, &ver)))
-               die("can't set version: %s", cman_error(errno));
+       if (need_setversion) {
+               if (comline->verbose)
+                       printf("Telling cman the new version number\n");
+
+               ver.cv_config = comline->config_version;
+
+               if ((result = cman_set_version(h, &ver)))
+                       die("can't set version: %s", cman_error(errno));
+       }
  out:
        cman_finish(h);
 }
@@ -767,6 +844,10 @@ static void decode_arguments(int argc, char *argv[], 
commandline_t *comline)
                        comline->addresses_opt = 1;
                        break;
 
+               case 'D':
+                       comline->config_novalidate_opt = 1;
+                       break;
+
                case 'n':
                        i = comline->num_nodenames;
                        if (i >= MAX_INTERFACES)
diff --git a/cman/man/cman_tool.8 b/cman/man/cman_tool.8
index 8d45048..a257cc3 100644
--- a/cman/man/cman_tool.8
+++ b/cman/man/cman_tool.8
@@ -69,12 +69,11 @@ with -r to tell cluster members to update.
 .br
 The argument to -r is the version number that cman should look for. If 
 that version is not currently available then cman will poll for it. If
-a version of 0 is specified then cman will simply re-read the configuration
-and use the version number it finds there. 
+a version of 0 is specified then cman will read the configuration file,
+validate it, distribute it around the cluster (if necessary) and
+activate it.
 .br
-NOTE: this happens cluster-wide and the highest version number in the
-cluster will be the one everyone looks for. version -r0 is not a way
-to have different config versions across nodes in the cluster!
+The -D flag will disable the validation stage. This is NOT recommended.
 
 .TP
 .I wait 

Reply via email to