Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=e1…
Commit: e13925e953da1add1444160d139564e9ef8ba9da
Parent: bec08529b7dad11bdc7c3b18b7f0f4a33642ee1a
Author: Christine Caulfield <ccaulfie(a)redhat.com>
AuthorDate: Wed Sep 30 14:02:06 2009 +0100
Committer: Christine Caulfield <ccaulfie(a)redhat.com>
CommitterDate: Wed Sep 30 14:02:06 2009 +0100
cman: propogate all COROSYNC_* varaibles to validation program.
cman_tool now puts all COROSYNC_* environment variables into objdb so
that they are available to pass to ccs_config_validate.
Some of these variables are essential to collecting the new configuration
eg: LDAP needs them for BASEDN and (optionally) URL.
Signed-off-by: Christine Caulfield <ccaulfie(a)redhat.com>
---
cman/cman_tool/join.c | 21 ++++++++++--
cman/cman_tool/main.c | 90 ++++++++++++++++++++++++++++++++++--------------
2 files changed, 82 insertions(+), 29 deletions(-)
diff --git a/cman/cman_tool/join.c b/cman/cman_tool/join.c
index 697e944..fa3efb7 100644
--- a/cman/cman_tool/join.c
+++ b/cman/cman_tool/join.c
@@ -335,16 +335,31 @@ int join(commandline_t *comline, char *main_envp[])
cman_finish(h);
- /* Save the configuration information in corosync's objdb so we know where we came from */
+ /* Copy all COROSYNC_* environment variables into objdb so they can be used to validate new configurations later */
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));
-
+ int envnum = 0;
+ const char *envvar = main_envp[envnum];
+ const char *equal;
+
+ while (envvar) {
+ if (strncmp("COROSYNC_", envvar, 9) == 0) {
+ equal = strchr(envvar, '=');
+ if (equal) {
+ res = confdb_key_create(confdb_handle, object_handle, envvar, equal-envvar,
+ equal+1, strlen(equal+1));
+ }
+ }
+ envvar = main_envp[++envnum];
+ }
}
+ res = confdb_key_create(confdb_handle, object_handle,
+ "COROSYNC_DEFAULT_CONFIG_IFACE", strlen("COROSYNC_DEFAULT_CONFIG_IFACE"),
+ config_modules, strlen(config_modules));
confdb_finalize (confdb_handle);
join_exit:
diff --git a/cman/cman_tool/main.c b/cman/cman_tool/main.c
index d5cfe17..8a416eb 100644
--- a/cman/cman_tool/main.c
+++ b/cman/cman_tool/main.c
@@ -2,7 +2,7 @@
#include <unistd.h>
#include <signal.h>
#include <time.h>
-#include <ccs.h>
+#include <corosync/confdb.h>
#include <netinet/in.h>
#include "copyright.cf"
#include "libcman.h"
@@ -673,30 +673,62 @@ static int validate_config(commandline_t *comline, char *config_value)
return cmd_res;
}
-
-static int get_config_variable(commandline_t *comline, char **config_modules)
+/* Here we set the COROSYNC_ variables that might be needed by the corosync
+ configuration modules. We just put them into the environment and leave
+ them for the sub-process to pick up.
+ 'config_modules' is returned separately because it's needed internally to
+ and it saves the caller from extracting it all over again.
+ We only return 0 (success) if config_modules is returned as without that
+ the caller can't really do anything at all.
+*/
+static int get_config_variables(commandline_t *comline, char **config_modules)
{
- int ccs_handle;
- int ccs_res;
- char *config_value;
-
- /* 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;
- }
+ int res;
+ int got_iface = 1;
+ char key_name[1024];
+ size_t key_name_len;
+ char key_value[1024];
+ size_t key_value_len;
+ hdb_handle_t confdb_handle;
+ hdb_handle_t cmanp_handle;
+ confdb_callbacks_t callbacks = {
+ .confdb_key_change_notify_fn = NULL,
+ .confdb_object_create_change_notify_fn = NULL,
+ .confdb_object_delete_change_notify_fn = NULL
+ };
+
+ *config_modules = NULL;
+ res = confdb_initialize (&confdb_handle, &callbacks);
+ if (res != CS_OK)
+ return 0;
+
+ res = confdb_object_find_start(confdb_handle, OBJECT_PARENT_HANDLE);
+ if (res != CS_OK)
+ goto finish;
+
+ res = confdb_object_find(confdb_handle, OBJECT_PARENT_HANDLE, "cman_private", strlen("cman_private"), &cmanp_handle);
+ if (res != CS_OK)
+ goto finish;
- 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;
+ res = confdb_key_iter_start(confdb_handle, cmanp_handle);
+ if (res != CS_OK)
+ goto finish;
+
+ while ( (res = confdb_key_iter(confdb_handle, cmanp_handle, key_name, &key_name_len,
+ key_value, &key_value_len)) == CS_OK) {
+ key_name[key_name_len] = '\0';
+ key_value[key_value_len] = '\0';
+
+ setenv(key_name, key_value, 1);
+ if (strcmp(key_name, "COROSYNC_DEFAULT_CONFIG_IFACE") == 0) {
+ *config_modules = strdup(key_value);
+ got_iface = 0;
+ }
}
- *config_modules = config_value;
- return 0;
+
+finish:
+ confdb_finalize(confdb_handle);
+ return got_iface;
}
static void version(commandline_t *comline)
@@ -719,8 +751,8 @@ static void version(commandline_t *comline)
if (comline->verbose)
printf("Getting config variables\n");
- if (get_config_variable(comline, &config_modules))
- die("");
+ if (get_config_variables(comline, &config_modules))
+ die("cannot get COROSYNC_DEFAULT_CONFIG_IFACE");
/* By default we validate the configuration first */
if (comline->config_validate_opt != VALIDATE_NONE) {
@@ -732,6 +764,12 @@ static void version(commandline_t *comline)
die("Not reloading, configuration is not valid\n");
}
+ /* We don't bother looking for ccs_sync here - just assume it's in /usr/bin and
+ that it exists. If this is not true then then user can choose to bypass
+ the disibution and do it themselves.
+ Note that ccs_sync might prompt on stderr for passwords the first time it is
+ run.
+ */
if (strstr(config_modules, "xmlconfig") && !comline->nosync_opt) {
if (comline->verbose > 1)
printf("calling ccs_sync\n");
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=be…
Commit: bec08529b7dad11bdc7c3b18b7f0f4a33642ee1a
Parent: 305b7f1c01f195d0df069eadf805433d522e789e
Author: Lon Hohberger <lhh(a)redhat.com>
AuthorDate: Tue Sep 29 17:10:09 2009 -0400
Committer: Lon Hohberger <lhh(a)redhat.com>
CommitterDate: Tue Sep 29 17:10:09 2009 -0400
rgmanager: Fix clusvcadm help output
Signed-off-by: Lon Hohberger <lhh(a)redhat.com>
---
rgmanager/src/utils/clusvcadm.c | 10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)
diff --git a/rgmanager/src/utils/clusvcadm.c b/rgmanager/src/utils/clusvcadm.c
index 8fe7599..e63e30d 100644
--- a/rgmanager/src/utils/clusvcadm.c
+++ b/rgmanager/src/utils/clusvcadm.c
@@ -150,7 +150,7 @@ printf(" -e <group> -F Enable <group> according to failover\n"
" case when using central processing)\n");
printf(" -e <group> -m <member> Enable <group> on <member>\n");
printf(" -r <group> -m <member> Relocate <group> [to <member>]\n"
- " Stops a group and starts it on another"
+ " Stops a group and starts it on another\n"
" cluster member.\n");
printf(" -M <group> -m <member> Migrate <group> to <member>\n");
printf(" (e.g. for live migration of VMs)\n");
@@ -160,6 +160,14 @@ printf(" -s <group> Stop <group>. This temporarily stops\n"
" a group. After the next group or\n"
" or cluster member transition, the group\n"
" will be restarted (if possible).\n");
+printf(" -Z <group> Freeze resource group. This prevents\n"
+ " transitions and status checks, and is \n"
+ " useful if an administrator needs to \n"
+ " administer part of a service without \n"
+ " stopping the whole service.\n");
+printf(" -U <group> Unfreeze (thaw) resource group. Restores\n"
+ " a group to normal operation.\n");
+
printf("Resource Group Locking (for cluster Shutdown / Debugging):\n");
printf(" -l Lock local resource group managers.\n"
" This prevents resource groups from\n"
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=71…
Commit: 710af80f016ce390f957c3726c1825411598d2c8
Parent: 66747c23e6791b7a3360c85f36ad4c865ebea7d4
Author: Eduardo Damato <edamato(a)redhat.com>
AuthorDate: Tue Sep 29 10:03:09 2009 -0400
Committer: Lon Hohberger <lhh(a)redhat.com>
CommitterDate: Tue Sep 29 10:05:01 2009 -0400
qdisk: Disable max_error_cycles when using io_timeout
Signed-off-by: Eduardo Damato <edamato(a)redhat.com>
Signed-off-by: Lon Hohberger <lhh(a)redhat.com>
---
cman/man/qdisk.5 | 5 +++--
cman/qdisk/main.c | 5 ++++-
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/cman/man/qdisk.5 b/cman/man/qdisk.5
index b28390e..7a00a25 100644
--- a/cman/man/qdisk.5
+++ b/cman/man/qdisk.5
@@ -298,7 +298,8 @@ while qdiskd is running.
.in 12
If set to 1 (on), qdiskd will watch internal timers and reboot the node
if qdisk is not able to write to disk after (interval * tko) seconds.
-The default for this value is 0 (off).
+The default for this value is 0 (off). If io_timeout is active
+max_error_cycles is overridden and set to off.
.in 9
\fIscheduler\fP\fB="\fPrr\fB"\fP
@@ -366,7 +367,7 @@ If we receive an I/O error during a cycle, we do not poll CMAN and tell
it we are alive. If specified, this value will cause qdiskd to exit
after the specified number of consecutive cycles during which I/O errors
occur. The default is 0 (no maximum). This option can be changed while
-qdiskd is running.
+qdiskd is running. This option is ignored if io_timeout is set to 1.
.in 8
\fB/>\fP
diff --git a/cman/qdisk/main.c b/cman/qdisk/main.c
index 3b09b28..950a2d2 100644
--- a/cman/qdisk/main.c
+++ b/cman/qdisk/main.c
@@ -1428,12 +1428,15 @@ get_dynamic_config_data(qd_ctx *ctx, int ccsfd)
/*
* How many consecutive error cycles do we allow before
* giving up?
+ *
+ * Notice that max_error_cycles is disabled if io_timeout is
+ * active.
*/
/* default = no max */
snprintf(query, sizeof(query), "/cluster/quorumd/@max_error_cycles");
if (ccs_get(ccsfd, query, &val) == 0) {
ctx->qc_max_error_cycles = atoi(val);
- if (ctx->qc_max_error_cycles <= 0)
+ if ((ctx->qc_max_error_cycles <= 0) || (ctx->qc_flags & RF_IOTIMEOUT))
ctx->qc_max_error_cycles = 0;
free(val);
}
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=51…
Commit: 51049be41e3c3f198f7b39173bddb2d31786bc5b
Parent: 6e91a44cfb2d6baa1a639a2f6e6023bf82ab3cb7
Author: Eduardo Damato <edamato(a)redhat.com>
AuthorDate: Tue Sep 29 10:03:09 2009 -0400
Committer: Lon Hohberger <lhh(a)redhat.com>
CommitterDate: Tue Sep 29 10:08:20 2009 -0400
qdisk: Disable max_error_cycles when using io_timeout
Signed-off-by: Eduardo Damato <edamato(a)redhat.com>
Signed-off-by: Lon Hohberger <lhh(a)redhat.com>
---
cman/man/qdisk.5 | 5 +++--
cman/qdisk/main.c | 5 ++++-
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/cman/man/qdisk.5 b/cman/man/qdisk.5
index b28390e..7a00a25 100644
--- a/cman/man/qdisk.5
+++ b/cman/man/qdisk.5
@@ -298,7 +298,8 @@ while qdiskd is running.
.in 12
If set to 1 (on), qdiskd will watch internal timers and reboot the node
if qdisk is not able to write to disk after (interval * tko) seconds.
-The default for this value is 0 (off).
+The default for this value is 0 (off). If io_timeout is active
+max_error_cycles is overridden and set to off.
.in 9
\fIscheduler\fP\fB="\fPrr\fB"\fP
@@ -366,7 +367,7 @@ If we receive an I/O error during a cycle, we do not poll CMAN and tell
it we are alive. If specified, this value will cause qdiskd to exit
after the specified number of consecutive cycles during which I/O errors
occur. The default is 0 (no maximum). This option can be changed while
-qdiskd is running.
+qdiskd is running. This option is ignored if io_timeout is set to 1.
.in 8
\fB/>\fP
diff --git a/cman/qdisk/main.c b/cman/qdisk/main.c
index e4bcb60..8016295 100644
--- a/cman/qdisk/main.c
+++ b/cman/qdisk/main.c
@@ -1431,12 +1431,15 @@ get_dynamic_config_data(qd_ctx *ctx, int ccsfd)
/*
* How many consecutive error cycles do we allow before
* giving up?
+ *
+ * Notice that max_error_cycles is disabled if io_timeout is
+ * active.
*/
/* default = no max */
snprintf(query, sizeof(query), "/cluster/quorumd/@max_error_cycles");
if (ccs_get(ccsfd, query, &val) == 0) {
ctx->qc_max_error_cycles = atoi(val);
- if (ctx->qc_max_error_cycles <= 0)
+ if ((ctx->qc_max_error_cycles <= 0) || (ctx->qc_flags & RF_IOTIMEOUT))
ctx->qc_max_error_cycles = 0;
free(val);
}
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=e9…
Commit: e966498e955358fa16d5f523b09e84e29d6edd80
Parent: 87212596001faaefb9a10ec8f6678a877dc907bb
Author: Christine Caulfield <ccaulfie(a)redhat.com>
AuthorDate: Tue Sep 29 08:59:49 2009 +0100
Committer: Christine Caulfield <ccaulfie(a)redhat.com>
CommitterDate: Tue Sep 29 08:59:49 2009 +0100
cman: Add a validation step to cman_tool join & version subcommands
cman_tool join & cman_tool version now run the configuration through
the schema validator before continuing. By default they will abandon
the operation if they encounter an error. This behaviour can be changed
wit the -D switch to both subcommands.
In addition cman_tool version will also call ccs_sync to distribute the
configuration file if it sees that xmlconfig is being used. This can be
prevented by adding the -S switch.
As it stands, this only really works with xmlconfig because the other
supported configuration (LDAP) needs additional environment variables
to work and these are currently not stored in the corosync objdb. I will
fix this in a future patch.
Signed-off-by: Christine Caulfield <ccaulfie(a)redhat.com>
---
cman/cman_tool/Makefile | 4 +-
cman/cman_tool/cman_tool.h | 9 ++
cman/cman_tool/join.c | 32 +++++++-
cman/cman_tool/main.c | 174 ++++++++++++++++++++++++++++++++++++++------
cman/man/cman_tool.8 | 23 +++++-
5 files changed, 210 insertions(+), 32 deletions(-)
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..e84b491 100644
--- a/cman/cman_tool/cman_tool.h
+++ b/cman/cman_tool/cman_tool.h
@@ -57,6 +57,13 @@ enum format_opt
FMT_STATE,
};
+enum validate_options
+{
+ VALIDATE_FAIL = 0,
+ VALIDATE_WARN,
+ VALIDATE_NONE,
+};
+
struct commandline
{
int operation;
@@ -82,6 +89,7 @@ struct commandline
unsigned int config_version;
int config_version_opt;
+ int config_validate_opt;
int votes_opt;
int expected_votes_opt;
int port_opt;
@@ -91,6 +99,7 @@ struct commandline
int wait_quorate_opt;
int addresses_opt;
int noconfig_opt;
+ int nosync_opt;
int nosetpri_opt;
int noopenais_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..d5cfe17 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?XD::Sd::")
#define OP_JOIN 1
#define OP_LEAVE 2
#define OP_EXPECTED 3
@@ -22,7 +23,6 @@
#define OP_SERVICES 10
#define OP_DEBUG 11
-
static void print_usage(int subcmd)
{
printf("Usage:\n");
@@ -57,6 +57,9 @@ static void print_usage(int subcmd)
printf(" -P Don't set corosync to realtime priority\n");
printf(" -X Use internal cman defaults for configuration\n");
printf(" -A Don't load openais services\n");
+ printf(" -D <fail,warn,none> What to do about the config. Default (without -D) is to validate\n");
+ printf(" the config. with -D no validation will be done. -Dwarn will print errors\n");
+ printf(" but allow the operation to continue\n");
printf("\n");
}
@@ -116,6 +119,10 @@ 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 <fail,warn,none> What to do about the config. Default (without -D) is to validate\n");
+ printf(" the config. with -D no validation will be done. -Dwarn will print errors\n");
+ printf(" but allow the operation to continue\n");
+ printf(" -S Don't run ccs_sync to distribute cluster.conf (if appropriate)\n");
printf("\n");
}
}
@@ -642,11 +649,62 @@ static void set_votes(commandline_t *comline)
cman_finish(h);
}
+static int validate_config(commandline_t *comline, char *config_value)
+{
+ struct stat st;
+ char command[PATH_MAX];
+ char validator[PATH_MAX];
+ int cmd_res;
+
+ /* 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;
+ }
+
+ snprintf(command, sizeof(command), "%s -C %s", validator, config_value);
+
+ if (comline->verbose > 1)
+ printf("calling '%s'\n", command);
+
+ cmd_res = system(command);
+
+ return cmd_res;
+}
+
+
+static int get_config_variable(commandline_t *comline, char **config_modules)
+{
+ int ccs_handle;
+ int ccs_res;
+ char *config_value;
+
+ /* 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;
+ }
+ *config_modules = config_value;
+ return 0;
+}
+
static void version(commandline_t *comline)
{
struct cman_version ver;
cman_handle_t h;
int result;
+ char *config_modules = NULL;
h = open_cman_handle(1);
@@ -659,10 +717,35 @@ static void version(commandline_t *comline)
goto out;
}
- ver.cv_config = comline->config_version;
+ if (comline->verbose)
+ printf("Getting config variables\n");
+ if (get_config_variable(comline, &config_modules))
+ die("");
- if ((result = cman_set_version(h, &ver)))
- die("can't set version: %s", cman_error(errno));
+ /* By default we validate the configuration first */
+ if (comline->config_validate_opt != VALIDATE_NONE) {
+
+ if (comline->verbose)
+ printf("Validating configuration\n");
+ if (validate_config(comline, config_modules) &&
+ comline->config_validate_opt == VALIDATE_FAIL)
+ die("Not reloading, configuration is not valid\n");
+ }
+
+ if (strstr(config_modules, "xmlconfig") && !comline->nosync_opt) {
+ if (comline->verbose > 1)
+ printf("calling ccs_sync\n");
+ result = system("/usr/bin/ccs_sync");
+ }
+ else {
+ 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);
}
@@ -752,6 +835,7 @@ static void decode_arguments(int argc, char *argv[], commandline_t *comline)
{
int cont = TRUE;
int optchar, i;
+ int suboptchar;
int show_help = 0;
while (cont) {
@@ -767,6 +851,34 @@ static void decode_arguments(int argc, char *argv[], commandline_t *comline)
comline->addresses_opt = 1;
break;
+ case 'D':
+ /* Just look at the upper-cased version of the first letter of the argument */
+ if (optarg) {
+ suboptchar = optarg[0] & 0x5F;
+ switch (suboptchar)
+ {
+ case 'F':
+ comline->config_validate_opt = VALIDATE_FAIL;
+ break;
+ case 'W':
+ comline->config_validate_opt = VALIDATE_WARN;
+ break;
+ case 'N':
+ comline->config_validate_opt = VALIDATE_NONE;
+ break;
+ default:
+ die("invalid option to -D, it should be 'force', 'warn' or 'none'\n");
+ break;
+ }
+ }
+ else {
+ comline->config_validate_opt = VALIDATE_NONE;
+ }
+ break;
+ case 'S':
+ comline->nosync_opt = 1;
+ break;
+
case 'n':
i = comline->num_nodenames;
if (i >= MAX_INTERFACES)
@@ -981,10 +1093,43 @@ static void check_arguments(commandline_t *comline)
die("timeout is only appropriate with wait");
}
+
+static void do_join(commandline_t *comline, char *envp[])
+{
+ int ret;
+
+ check_arguments(comline);
+
+ if (comline->timeout) {
+ signal(SIGALRM, sigalarm_handler);
+ alarm(comline->timeout);
+ }
+
+ /* By default we validate the configuration first */
+ if (comline->config_validate_opt != VALIDATE_NONE) {
+
+ if (comline->verbose)
+ printf("Validating configuration\n");
+
+ if (validate_config(comline, comline->config_lcrso) &&
+ comline->config_validate_opt == VALIDATE_FAIL)
+ die("Not reloading, configuration is not valid\n");
+ }
+
+ join(comline, envp);
+ if (comline->wait_opt || comline->wait_quorate_opt) {
+ do {
+ ret = cluster_wait(comline);
+ if (ret == ENOTCONN)
+ join(comline, envp);
+
+ } while (ret == ENOTCONN);
+ }
+}
+
int main(int argc, char *argv[], char *envp[])
{
commandline_t comline;
- int ret;
prog_name = argv[0];
@@ -994,22 +1139,7 @@ int main(int argc, char *argv[], char *envp[])
switch (comline.operation) {
case OP_JOIN:
- check_arguments(&comline);
-
- if (comline.timeout) {
- signal(SIGALRM, sigalarm_handler);
- alarm(comline.timeout);
- }
-
- join(&comline, envp);
- if (comline.wait_opt || comline.wait_quorate_opt) {
- do {
- ret = cluster_wait(&comline);
- if (ret == ENOTCONN)
- join(&comline, envp);
-
- } while (ret == ENOTCONN);
- }
+ do_join(&comline, envp);
break;
case OP_LEAVE:
diff --git a/cman/man/cman_tool.8 b/cman/man/cman_tool.8
index 8d45048..4d400a6 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 can disable the validation stage. This is NOT recommended.
.TP
.I wait
@@ -151,6 +150,9 @@ cman_tool version on its own will always show the current version
and not the one being looked for. So be aware that the display
will possible not update immediately after you have run
cman_tool version -r.
+.TP
+.I -D<option>
+see "JOIN" options
.SH "WAIT" OPTIONS
.TP
.I -q
@@ -290,6 +292,17 @@ Don't load openais services. Normally cman_tool join will load the configuration
module 'openaisserviceenablestable' which will load the services installed by openais.
If you don't want to use these services or have not installed openais then
this switch will disable them.
+.TP
+.I -D
+Tells cman_tool whether to validate the configuration before loading or reloading it.
+By default the configuration
+.B is
+validated, which is equivalent to -Dfail.
+.br
+-Dwarn will validate the configuration and print any messages arising, but will attempt
+to use it regardless of its validity.
+.br
+-Dnone (or just -D) will skip the validation completely.
.SH "NODES" OPTIONS
.TP
.I -a