[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Cluster-devel] [PATCH] STABLE3: enhance cman_tool to validate and distribute configuration files



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 

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]