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