Gitweb:
http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=82ff946b955...
Commit: 82ff946b955f9c6b7856b5831d5603f70aaf974f
Parent: 80b7f2cc7bc5eaa52cdeb89e53a0c5be1ae9a1e9
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Aug 27 14:13:10 2012 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Thu Sep 6 09:36:58 2012 -0500
fence_node/libfence: status
fence_node -S to run status on a node, via
libfence fence_node_status().
Signed-off-by: David Teigland <teigland(a)redhat.com>
---
fence/fence_node/fence_node.c | 71 ++++++-
fence/libfence/agent.c | 461 +++++++++++++++++++++++++++++++++++++++++
fence/libfence/libfence.h | 26 +++
3 files changed, 550 insertions(+), 8 deletions(-)
diff --git a/fence/fence_node/fence_node.c b/fence/fence_node/fence_node.c
index a98962a..f926825 100644
--- a/fence/fence_node/fence_node.c
+++ b/fence/fence_node/fence_node.c
@@ -14,13 +14,16 @@ static char *prog_name;
static char our_name[CMAN_MAX_NODENAME_LEN+1];
static int verbose;
static int unfence;
+static int status;
+static int call_fenced = 1;
+static int use_method_num;
#define FL_SIZE 32
static struct fence_log flog[FL_SIZE];
static int flog_count;
static const char *action = "fence";
-#define OPTION_STRING "UvhV"
+#define OPTION_STRING "UvhVSe:m:"
#define die(fmt, args...) \
do \
@@ -39,10 +42,13 @@ static void print_usage(void)
printf("\n");
printf("Options:\n");
printf("\n");
- printf(" -U Unfence the node, default local node name\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");
+ printf(" -U Unfence the node, default local node name\n");
+ printf(" -S Run status on node name\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");
+ printf(" -e 0|1 Enable/disable fenced_external notification\n");
+ printf(" -m <num> Method number, starting from 1\n");
printf("\n");
}
@@ -104,6 +110,14 @@ static const char *fe_str(int r)
return "error config method";
case FE_READ_DEVICE:
return "error config device";
+ case FE_NUM_METHOD:
+ return "error method number";
+ case FE_AGENT_STATUS_ON:
+ return "status on";
+ case FE_AGENT_STATUS_OFF:
+ return "status off";
+ case FE_AGENT_STATUS_ERROR:
+ return "status error";
default:
return "error unknown";
}
@@ -126,6 +140,19 @@ int main(int argc, char *argv[])
action = "unfence";
break;
+ case 'S':
+ status = 1;
+ action = "status";
+ break;
+
+ case 'e':
+ call_fenced = atoi(optarg);
+ break;
+
+ case 'm':
+ use_method_num = atoi(optarg);
+ break;
+
case 'v':
verbose++;
break;
@@ -178,11 +205,17 @@ int main(int argc, char *argv[])
memset(&flog, 0, sizeof(flog));
flog_count = 0;
- if (unfence)
+ if (status)
+ error = fence_node_status(victim, flog, FL_SIZE, &flog_count,
+ use_method_num);
+ else if (unfence)
error = unfence_node(victim, flog, FL_SIZE, &flog_count);
else
error = fence_node(victim, flog, FL_SIZE, &flog_count);
+ if (status && !verbose && error < 0)
+ verbose = 1;
+
if (!verbose)
goto skip;
@@ -211,7 +244,28 @@ int main(int argc, char *argv[])
logt_init("fence_node", LOG_MODE_OUTPUT_SYSLOG, SYSLOGFACILITY,
SYSLOGLEVEL, 0, NULL);
- if (unfence) {
+ if (status) {
+ if (error == -2) {
+ fprintf(stderr, "status %s undefined\n", victim);
+ rv = 2;
+ } else if (error < 0) {
+ fprintf(stderr, "status %s failed %d\n", victim, error);
+ logt_print(LOG_ERR, "status %s failed %d\n", victim, error);
+ rv = EXIT_FAILURE;
+ } else if (error == 2) {
+ fprintf(stderr, "status %s success off\n", victim);
+ logt_print(LOG_ERR, "status %s success off\n", victim);
+ rv = EXIT_SUCCESS;
+ } else if (!error) {
+ fprintf(stderr, "status %s success on\n", victim);
+ logt_print(LOG_ERR, "status %s success on\n", victim);
+ rv = EXIT_SUCCESS;
+ } else {
+ fprintf(stderr, "status %s failed invalid %d\n", victim, error);
+ logt_print(LOG_ERR, "status %s failed invalid %d\n", victim, error);
+ rv = EXIT_FAILURE;
+ }
+ } else if (unfence) {
if (error == -2) {
fprintf(stderr, "unfence %s undefined\n", victim);
rv = 2;
@@ -241,7 +295,8 @@ int main(int argc, char *argv[])
/* Tell fenced what we've done so that it can avoid
fencing this node again if the fence_node() rebooted
it. */
- fenced_external(victim);
+ if (call_fenced)
+ fenced_external(victim);
}
}
diff --git a/fence/libfence/agent.c b/fence/libfence/agent.c
index 5577fda..fac6c92 100644
--- a/fence/libfence/agent.c
+++ b/fence/libfence/agent.c
@@ -679,3 +679,464 @@ int unfence_node(char *victim, struct fence_log *log, int log_size,
return error;
}
+/*
+ * Returns:
+ * < 0: internal error
+ * 0: agent exited with 0
+ * 1: agent exited with 1
+ * 2: agent exited with 2
+ */
+
+static int run_agent_status(char *agent, char *args, int *agent_result)
+{
+ int pid, status, len, rv;
+ int pw_fd = -1; /* parent write file descriptor */
+ int cr_fd = -1; /* child read file descriptor */
+ int pfd[2];
+
+ if (args == NULL || agent == NULL) {
+ rv = -1;
+ goto fail;
+ }
+ len = strlen(args);
+
+ if (pipe(pfd)) {
+ rv = -errno;
+ goto fail;
+ }
+ cr_fd = pfd[0];
+ pw_fd = pfd[1];
+
+ pid = fork();
+ if (pid < 0) {
+ rv = -errno;
+ *agent_result = FE_AGENT_FORK;
+ goto fail;
+ }
+
+ if (pid) {
+ /* parent */
+ int ret;
+
+ do {
+ ret = write(pw_fd, args, len);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret != len) {
+ rv = -1;
+ goto fail;
+ }
+
+ close(cr_fd);
+ close(pw_fd);
+
+ rv = waitpid(pid, &status, 0);
+
+ if (rv < 0) {
+ /* shouldn't happen */
+ rv = -errno;
+ goto out;
+ }
+
+ if (rv != pid) {
+ /* shouldn't happen */
+ rv = -1;
+ goto out;
+ }
+
+ if (WIFEXITED(status)) {
+ /* pid exited properly with an exit code */
+ rv = WEXITSTATUS(status);
+
+ if (rv == 0)
+ *agent_result = FE_AGENT_STATUS_ON;
+ else if (rv == 2)
+ *agent_result = FE_AGENT_STATUS_OFF;
+ else
+ *agent_result = FE_AGENT_STATUS_ERROR;
+ } else if (WIFSIGNALED(status)) {
+ /* pid terminated due to a signal */
+ rv = -1;
+ *agent_result = FE_AGENT_STATUS_ERROR;
+ } else {
+ /* something else happened, not sure what */
+ rv = -1;
+ *agent_result = FE_AGENT_STATUS_ERROR;
+ }
+ goto out;
+
+ } else {
+ /* child */
+ int c_stdout, c_stderr;
+
+ /* redirect agent stdout/stderr to /dev/null */
+ close(1);
+ c_stdout = open("/dev/null", O_WRONLY);
+ if (c_stdout < 0) {
+ rv = -1;
+ goto fail;
+ }
+ close(2);
+ c_stderr = open("/dev/null", O_WRONLY);
+ if (c_stderr < 0) {
+ rv = -1;
+ goto fail;
+ }
+
+ /* redirect agent stdin from parent */
+ close(0);
+ if (dup(cr_fd) < 0) {
+ rv = -errno;
+ goto fail;
+ }
+
+ close(cr_fd);
+ close(pw_fd);
+
+ execlp(agent, agent, NULL);
+ exit(EXIT_FAILURE);
+ }
+ fail:
+ close(cr_fd);
+ close(pw_fd);
+ out:
+ return rv;
+}
+
+static int make_args_status(int cd, char *victim, char *method, int d,
+ char *device, char **args_out)
+{
+ char path[PATH_MAX];
+ char *args, *str;
+ int error, ret, cnt = 0;
+ size_t len, pos;
+
+ args = malloc(FENCE_AGENT_ARGS_MAX);
+ if (!args)
+ return -ENOMEM;
+ memset(args, 0, FENCE_AGENT_ARGS_MAX);
+
+ len = FENCE_AGENT_ARGS_MAX - 1;
+ pos = 0;
+
+ /* node-specific args for victim */
+
+ memset(path, 0, PATH_MAX);
+ sprintf(path, NODE_FENCE_ARGS_PATH, victim, method, d+1);
+
+ for (;;) {
+ error = ccs_get_list(cd, path, &str);
+ if (error || !str)
+ break;
+ ++cnt;
+
+ if (!strncmp(str, "name=", 5)) {
+ free(str);
+ continue;
+ }
+
+ if (!strncmp(str, "action=", 7)) {
+ free(str);
+ continue;
+ }
+
+ ret = snprintf(args + pos, len - pos, "%s\n", str);
+
+ free(str);
+
+ if (ret >= len - pos) {
+ error = -E2BIG;
+ goto out;
+ }
+ pos += ret;
+ }
+
+ /* add nodename of victim to args */
+
+ if (!strstr(args, "nodename=")) {
+ ret = snprintf(args + pos, len - pos, "nodename=%s\n", victim);
+ if (ret >= len - pos) {
+ error = -E2BIG;
+ goto out;
+ }
+ pos += ret;
+ }
+
+ /* add action=status to args */
+
+ ret = snprintf(args + pos, len - pos, "action=status\n");
+ if (ret >= len - pos) {
+ error = -E2BIG;
+ goto out;
+ }
+ pos += ret;
+
+ /* 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;
+ }
+
+ ret = snprintf(args + pos, len - pos, "%s\n", str);
+
+ free(str);
+
+ if (ret >= len - pos) {
+ error = -E2BIG;
+ goto out;
+ }
+ pos += ret;
+ }
+
+ if (cnt)
+ error = 0;
+ out:
+ if (error) {
+ free(args);
+ args = NULL;
+ }
+
+ *args_out = args;
+ return error;
+}
+
+static int use_device_status(int cd, char *victim, char *method, 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-1);
+
+ error = make_args_status(cd, victim, method, d, device, &args);
+ if (error) {
+ lp->error = FE_READ_ARGS;
+ goto out_agent;
+ }
+
+ strncpy(lp->agent_args, args, FENCE_AGENT_ARGS_MAX-1);
+
+ error = run_agent_status(agent, args, &lp->error);
+
+ free(args);
+ out_agent:
+ free(agent);
+ out:
+ return error;
+}
+
+/* We want to run status on each device in each method, and we need all
+ to succeed in order for status as a whole to succeed. Agent success
+ for status is being either "on" (exit 0) or "off" (exit 2).
Agent
+ failure for status is when the on/off state is unknown (exit 1),
+ i.e. the agent failed to run or ran and cannot connect, or cannot get
+ the on/off state for some reason.
+
+ As soon as any one device in any method fails, we can quit and report
+ failure (rv < 0) for status as a whole. If status of all devices is
+ "on", then status as a whole returns 0. If status of all devices are
+ "off", then status as a whole returns 2. If the status of all devices
+ are mixed on/off, then status as a whole returns 0. */
+
+int fence_node_status(char *victim, struct fence_log *log, int log_size,
+ int *log_count, int use_method_num)
+{
+ struct fence_log stub;
+ struct fence_log *lp = log;
+ char *method = NULL, *device = NULL;
+ char *victim_nodename = NULL;
+ int num_methods, num_devices, m, d, cd, rv;
+ int on_count = 0, off_count = 0;
+ 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_methods = count_methods(cd, victim);
+ if (!num_methods) {
+ if (lp && left) {
+ lp->error = FE_NO_METHOD;
+ lp++;
+ left--;
+ }
+ count++;
+ error = -2; /* No fencing */
+ goto out;
+ }
+
+ if (use_method_num && (use_method_num > num_methods)) {
+ if (lp && left) {
+ lp->error = FE_NUM_METHOD;
+ lp++;
+ left--;
+ }
+ count++;
+ error = -2; /* No fencing */
+ goto out;
+ }
+
+ for (m = 0; m < num_methods; m++) {
+
+ if (use_method_num && (m + 1 != use_method_num))
+ continue;
+
+ rv = get_method(cd, victim, m, &method);
+ if (rv) {
+ if (lp && left) {
+ lp->error = FE_READ_METHOD;
+ lp->method_num = m;
+ lp++;
+ left--;
+ }
+ count++;
+ error = -1;
+ break;
+ }
+
+ num_devices = count_devices(cd, victim, method);
+ if (!num_devices) {
+ if (lp && left) {
+ lp->error = FE_NO_DEVICE;
+ lp->method_num = m;
+ lp++;
+ left--;
+ }
+ count++;
+ continue;
+ }
+
+ for (d = 0; d < num_devices; d++) {
+ rv = get_device(cd, victim, method, d, &device);
+ if (rv) {
+ if (lp && left) {
+ lp->error = FE_READ_DEVICE;
+ lp->method_num = m;
+ lp->device_num = d;
+ lp++;
+ left--;
+ }
+ count++;
+ error = -1;
+ break;
+ }
+
+ /* every call to use_device generates a log entry,
+ whether success or fail */
+
+ error = use_device_status(cd, victim, method, d, device,
+ (lp && left) ? lp : &stub);
+ count++;
+ if (lp && left) {
+ /* error, name, args already set */
+ lp->method_num = m;
+ lp->device_num = d;
+ lp++;
+ left--;
+ }
+
+ /*
+ * error values:
+ * < 0: internal error from use_device_status,
+ * internal error from run_agent_status,
+ * run_agent_status failed to fork agent
+ * 0: agent exited with 0 (success, status is on)
+ * 2: agent exited with 2 (success, status is off)
+ * 1: agent exited with 1 (error, status is unknown)
+ */
+
+ /* internal error: status fail */
+ if (error < 0)
+ break;
+
+ /* agent error: status fail */
+ if (error == 1) {
+ error = -1;
+ break;
+ }
+
+ if (!error) {
+ /* agent success "on": status success */
+ on_count++;
+ } else if (error == 2) {
+ /* agent success "off": status success */
+ error = 0;
+ off_count++;
+ } else {
+ /* some other error */
+ error = -1;
+ break;
+ }
+
+ free(device);
+ device = NULL;
+ }
+
+ if (device)
+ free(device);
+
+ free(method);
+
+ /* if any device failed in this method, return failure
+ for the status */
+
+ if (error)
+ break;
+ }
+
+ if (error < 0)
+ goto out;
+
+ /* All devices are either on or off, none are unknown/inaccessible,
+ so status as a whole is a success. Decide which of the two
+ success values to return: 2 if all devices are off, or 0 if
+ all devices are on, 0 if mixed on/off. */
+
+ if (!on_count)
+ error = 2;
+ else
+ error = 0;
+
+ out:
+ if (victim_nodename)
+ free(victim_nodename);
+
+ 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 33f493a..10d00f0 100644
--- a/fence/libfence/libfence.h
+++ b/fence/libfence/libfence.h
@@ -15,6 +15,10 @@ extern "C" {
#define FE_READ_ARGS 8 /* read (ccs) error on node/dev args */
#define FE_READ_METHOD 9 /* read (ccs) error on method */
#define FE_READ_DEVICE 10 /* read (ccs) error on method/device */
+#define FE_NUM_METHOD 11 /* method number does not exist */
+#define FE_AGENT_STATUS_ON 12
+#define FE_AGENT_STATUS_OFF 13
+#define FE_AGENT_STATUS_ERROR 14
#define FENCE_AGENT_NAME_MAX 256 /* including terminating \0 */
#define FENCE_AGENT_ARGS_MAX 4096 /* including terminating \0 */
@@ -32,6 +36,28 @@ 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);
+/*
+ * use_method_num == 0: run status on all devices of all methods
+ * use_method_num > 0: run status on all devices of given method number,
+ * where first method is use_method_num = 1
+ *
+ * Returns 0 on success: status is successful on all devices of all methods
+ * (or all devices of specified method). All devices are in the "on" state,
+ * or some devices are on and some are off.
+ *
+ * Returns 2 on success: status is successful on all devices of all methods
+ * (or all devices of a specified method). All devices are in the "off"
state.
+ *
+ * Returns -2 if no fencing methods are defined for the node, or if
+ * use_method_num was specified and the specified method number does
+ * not exist.
+ *
+ * Returns -EXXX for other failures.
+ */
+
+int fence_node_status(char *victim, struct fence_log *log, int log_size,
+ int *log_count, int use_method_num);
+
#ifdef __cplusplus
}
#endif