This is the mail archive of the cluster-cvs@sourceware.org mailing list for the cluster.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

cluster: STABLE3 - libfence/fence_node: unfencing


Gitweb:        http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=9ad630fd9402c1820d758ed12f41bceb8a12eeb6
Commit:        9ad630fd9402c1820d758ed12f41bceb8a12eeb6
Parent:        a934a873dc5f2d28c4e0dd3e696177048aa8196a
Author:        David Teigland <teigland@redhat.com>
AuthorDate:    Wed Feb 25 16:43:42 2009 -0600
Committer:     David Teigland <teigland@redhat.com>
CommitterDate: Wed Feb 25 16:43:42 2009 -0600

libfence/fence_node: unfencing

The new libfence unfence_node() function looks for per node <unfence>
sections.  The <unfence> section contains no methods, only devices.
unfence_node() attempts all devices in the unfence section, regardless
of whether any fail.  The function returns success only if all devices
were successful.

The <device> line within <unfence> would typically require action="on"
or similar, to tell the agent to do the reverse of normal fencing.
The arg string for agents are constructed in the same was as for fencing:
the combination of the per-node unfence/device args and the fencedevice
args.

The fence_node command has a new -U option that causes it to call
unfence_node() rather than fence_node().

Signed-off-by: David Teigland <teigland@redhat.com>
---
 fence/fence_node/fence_node.c |   40 +++++---
 fence/libfence/agent.c        |  220 +++++++++++++++++++++++++++++++++++++++++
 fence/libfence/libfence.h     |    3 +
 3 files changed, 248 insertions(+), 15 deletions(-)

diff --git a/fence/fence_node/fence_node.c b/fence/fence_node/fence_node.c
index 21a9ba2..6cb15e7 100644
--- a/fence/fence_node/fence_node.c
+++ b/fence/fence_node/fence_node.c
@@ -11,12 +11,14 @@
 
 static char *prog_name;
 static int verbose;
+static int unfence;
 
 #define FL_SIZE 32
 static struct fence_log log[FL_SIZE];
 static int log_count;
+static char *action = "fence";
 
-#define OPTION_STRING "hvV"
+#define OPTION_STRING "UvhV"
 
 #define die(fmt, args...) \
 do \
@@ -35,6 +37,7 @@ static void print_usage(void)
 	printf("\n");
 	printf("Options:\n");
 	printf("\n");
+	printf("  -U    Unfence the node\n");
 	printf("  -v    Show fence agent results, -vv for agent args\n");
 	printf("  -h    Print this help, then exit\n");
 	printf("  -V    Print program version information, then exit\n");
@@ -72,7 +75,7 @@ static char *fe_str(int r)
 int main(int argc, char *argv[])
 {
 	char *victim = NULL, *p;
-	int cont = 1, optchar, error, rv, i;
+	int cont = 1, optchar, error, rv, i, c;
 
 	prog_name = argv[0];
 
@@ -81,6 +84,11 @@ int main(int argc, char *argv[])
 
 		switch (optchar) {
 
+		case 'U':
+			unfence = 1;
+			action = "unfence";
+			break;
+
 		case 'v':
 			verbose++;
 			break;
@@ -126,7 +134,10 @@ int main(int argc, char *argv[])
 	memset(&log, 0, sizeof(log));
 	log_count = 0;
 
-	error = fence_node(victim, log, FL_SIZE, &log_count);
+	if (unfence)
+		error = unfence_node(victim, log, FL_SIZE, &log_count);
+	else
+		error = fence_node(victim, log, FL_SIZE, &log_count);
 
 	logt_init("fence_node", LOG_MODE_OUTPUT_SYSLOG, SYSLOGFACILITY,
 		  SYSLOGLEVEL, 0, NULL);
@@ -135,35 +146,34 @@ int main(int argc, char *argv[])
 		goto skip;
 
 	if (log_count > FL_SIZE) {
-		fprintf(stderr, "fence_node log overflow %d", log_count);
+		fprintf(stderr, "%s_node log overflow %d", action, log_count);
 		log_count = FL_SIZE;
 	}
 
 	for (i = 0; i < log_count; i++) {
-		fprintf(stderr, "fence %s dev %d.%d agent %s result: %s\n",
-			victim, log[i].method_num, log[i].device_num,
+		fprintf(stderr, "%s %s dev %d.%d agent %s result: %s\n",
+			action, victim, log[i].method_num, log[i].device_num,
 			log[i].agent_name[0] ?  log[i].agent_name : "none",
 			fe_str(log[i].error));
 
 		if (verbose < 2)
 			continue;
 
-		p = strchr(log[i].agent_args, '\n');
-		if (p)
-			*p = '\0';
+		for (c = 0; c < strlen(log[i].agent_args); c++) {
+			if (log[i].agent_args[c] == '\n')
+				log[i].agent_args[c] = ' ';
+		}
 		fprintf(stderr, "agent args: %s\n", log[i].agent_args);
 	}
 
  skip:
 	if (error) {
-		fprintf(stderr, "Fence of \"%s\" was unsuccessful\n", victim);
-		logt_print(LOG_ERR, "Fence of \"%s\" was unsuccessful\n",
-			   victim);
+		fprintf(stderr, "%s %s failed\n", action, victim);
+		logt_print(LOG_ERR, "%s %s failed\n", action, victim);
 		rv = EXIT_FAILURE;
 	} else {
-		fprintf(stderr, "Fence of \"%s\" was successful\n", victim);
-		logt_print(LOG_NOTICE, "Fence of \"%s\" was successful\n",
-			   victim);
+		fprintf(stderr, "%s %s success\n", action, victim);
+		logt_print(LOG_ERR, "%s %s success\n", action, victim);
 		rv = EXIT_SUCCESS;
 
 		/* Tell fenced what we've done so that it can avoid fencing
diff --git a/fence/libfence/agent.c b/fence/libfence/agent.c
index 51e9371..148be3c 100644
--- a/fence/libfence/agent.c
+++ b/fence/libfence/agent.c
@@ -396,3 +396,223 @@ int fence_node(char *victim, struct fence_log *log, int log_size,
 		*log_count = count;
 	return error;
 }
+
+#define UN_DEVICE_NAME_PATH "/cluster/clusternodes/clusternode[@name=\"%s\"]/unfence/device[%d]/@name"
+#define UN_NODE_FENCE_ARGS_PATH "/cluster/clusternodes/clusternode[@name=\"%s\"]/unfence/device[%d]/@*"
+
+static int make_args_unfence(int cd, char *victim, int d,
+			     char *device, char **args_out)
+{
+	char path[PATH_MAX], *args, *str;
+	int error, cnt = 0;
+
+	args = malloc(FENCE_AGENT_ARGS_MAX);
+	if (!args)
+		return -ENOMEM;
+	memset(args, 0, FENCE_AGENT_ARGS_MAX);
+
+	/* node-specific args for victim */
+
+	memset(path, 0, PATH_MAX);
+	sprintf(path, UN_NODE_FENCE_ARGS_PATH, victim, d+1);
+
+	for (;;) {
+		error = ccs_get_list(cd, path, &str);
+		if (error || !str)
+			break;
+		++cnt;
+
+		if (!strncmp(str, "name=", 5)) {
+			free(str);
+			continue;
+		}
+
+		strcat(args, str);
+		strcat(args, "\n");
+		free(str);
+	}
+
+	/* device-specific args */
+
+	memset(path, 0, PATH_MAX);
+	sprintf(path, FENCE_DEVICE_ARGS_PATH, device);
+
+	for (;;) {
+		error = ccs_get_list(cd, path, &str);
+		if (error || !str)
+			break;
+		++cnt;
+
+		if (!strncmp(str, "name=", 5)) {
+			free(str);
+			continue;
+		}
+
+		strcat(args, str);
+		strcat(args, "\n");
+		free(str);
+	}
+
+	if (cnt)
+		error = 0;
+	if (error) {
+		free(args);
+		args = NULL;
+	}
+
+	*args_out = args;
+	return error;
+}
+
+/* return name of d'th device under nodes/<victim>/unfence/ */
+
+static int get_device_unfence(int cd, char *victim, int d, char **device)
+{
+	char path[PATH_MAX], *str = NULL;
+	int error;
+
+	memset(path, 0, PATH_MAX);
+	sprintf(path, UN_DEVICE_NAME_PATH, victim, d+1);
+
+	error = ccs_get(cd, path, &str);
+	*device = str;
+	return error;
+}
+
+static int count_devices_unfence(int cd, char *victim)
+{
+	char path[PATH_MAX], *name;
+	int error, i;
+
+	for (i = 0; i < MAX_DEVICES; i++) {
+		memset(path, 0, PATH_MAX);
+		sprintf(path, UN_DEVICE_NAME_PATH, victim, i+1);
+
+		error = ccs_get(cd, path, &name);
+		if (error)
+			break;
+		free(name);
+	}
+	return i;
+}
+
+static int use_device_unfence(int cd, char *victim, int d,
+			      char *device, struct fence_log *lp)
+{
+	char path[PATH_MAX], *agent, *args = NULL;
+	int error;
+
+	memset(path, 0, PATH_MAX);
+	sprintf(path, AGENT_NAME_PATH, device);
+
+	error = ccs_get(cd, path, &agent);
+	if (error) {
+		lp->error = FE_READ_AGENT;
+		goto out;
+	}
+
+	strncpy(lp->agent_name, agent, FENCE_AGENT_NAME_MAX);
+
+	error = make_args_unfence(cd, victim, d, device, &args);
+	if (error) {
+		lp->error = FE_READ_ARGS;
+		goto out_agent;
+	}
+
+	strncpy(lp->agent_args, args, FENCE_AGENT_ARGS_MAX);
+
+	error = run_agent(agent, args, &lp->error);
+
+	free(args);
+ out_agent:
+	free(agent);
+ out:
+	return error;
+}
+
+int unfence_node(char *victim, struct fence_log *log, int log_size,
+		 int *log_count)
+{
+	struct fence_log stub;
+	struct fence_log *lp = log;
+	char *device = NULL;
+	char *victim_nodename = NULL;
+	int num_devices, d, cd, rv;
+	int left = log_size;
+	int error = -1;
+	int count = 0;
+
+	cd = ccs_connect();
+	if (cd < 0) {
+		if (lp && left) {
+			lp->error = FE_NO_CONFIG;
+			lp++;
+			left--;
+		}
+		count++;
+		error = -1;
+		goto ret;
+	}
+
+	if (ccs_lookup_nodename(cd, victim, &victim_nodename) == 0)
+		victim = victim_nodename;
+
+	num_devices = count_devices_unfence(cd, victim);
+	if (!num_devices) {
+		if (lp && left) {
+			lp->error = FE_NO_DEVICE;
+			lp++;
+			left--;
+		}
+		count++;
+		error = -1;
+		goto out;
+	}
+
+	/* try to unfence all devices even if some of them fail,
+	   but the final return value is 0 only if all succeed */
+
+	for (d = 0; d < num_devices; d++) {
+		rv = get_device_unfence(cd, victim, d, &device);
+		if (rv) {
+			if (lp && left) {
+				lp->error = FE_READ_DEVICE;
+				lp->device_num = d;
+				lp++;
+				left--;
+			}
+			count++;
+			error = -1;
+			continue;
+		}
+
+		/* every call to use_device generates a log entry,
+		   whether success or fail */
+
+		rv = use_device_unfence(cd, victim, d, device,
+					(lp && left) ? lp : &stub);
+		count++;
+		if (lp && left) {
+			/* error, name, args already set */
+			lp->device_num = d;
+			lp++;
+			left--;
+		}
+
+		if (rv)
+			error = -1;
+
+		free(device);
+		device = NULL;
+	}
+
+	if (victim_nodename)
+		free(victim_nodename);
+ out:
+	ccs_disconnect(cd);
+ ret:
+	if (log_count)
+		*log_count = count;
+	return error;
+}
+
diff --git a/fence/libfence/libfence.h b/fence/libfence/libfence.h
index 677041d..e3d2148 100644
--- a/fence/libfence/libfence.h
+++ b/fence/libfence/libfence.h
@@ -29,6 +29,9 @@ struct fence_log {
 
 int fence_node(char *name, struct fence_log *log, int log_size, int *log_count);
 
+int unfence_node(char *name, struct fence_log *log, int log_size,
+		 int *log_count);
+
 #ifdef __cplusplus
 }
 #endif


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]