[PATCH 2/2] SAM integration of quorum

Jan Friesse jfriesse at redhat.com
Fri Apr 30 00:49:12 PDT 2010


Patch adds integration of SAM and quorum, so it's now possible to use
SAM_RECOVERY_POLICY_QUORUM_QUIT or SAM_RECOVERY_POLICY_QUORUM_RESTART
recovery policy. With these policies, sam_start will block until
corosync is quorate. If quorum is lost during health checking, recovery
action is taken.
---
 trunk/include/corosync/sam.h |    3 +
 trunk/lib/Makefile.am        |    1 +
 trunk/lib/libsam.verso       |    2 +-
 trunk/lib/sam.c              |  303 +++++++++++++++++++++++++++++++++---------
 trunk/man/sam_initialize.3   |   18 +++-
 trunk/man/sam_overview.8     |   15 ++-
 trunk/man/sam_start.3        |   12 ++-
 trunk/test/Makefile.am       |    2 +-
 trunk/test/testsam.c         |  153 +++++++++++++++++++++-
 9 files changed, 437 insertions(+), 72 deletions(-)

diff --git a/trunk/include/corosync/sam.h b/trunk/include/corosync/sam.h
index 4e60e17..41727c2 100644
--- a/trunk/include/corosync/sam.h
+++ b/trunk/include/corosync/sam.h
@@ -43,6 +43,9 @@ extern "C" {
 typedef enum {
 	SAM_RECOVERY_POLICY_QUIT = 1,
 	SAM_RECOVERY_POLICY_RESTART = 2,
+	SAM_RECOVERY_POLICY_QUORUM = 0x08,
+	SAM_RECOVERY_POLICY_QUORUM_QUIT = SAM_RECOVERY_POLICY_QUORUM | SAM_RECOVERY_POLICY_QUIT,
+	SAM_RECOVERY_POLICY_QUORUM_RESTART = SAM_RECOVERY_POLICY_QUORUM | SAM_RECOVERY_POLICY_RESTART,
 } sam_recovery_policy_t;
 
 /*
diff --git a/trunk/lib/Makefile.am b/trunk/lib/Makefile.am
index 2fde2af..e3236f0 100644
--- a/trunk/lib/Makefile.am
+++ b/trunk/lib/Makefile.am
@@ -62,6 +62,7 @@ libvotequorum_a_SOURCES	= votequorum.c
 libconfdb_a_SOURCES	= confdb.c sa-confdb.c
 libconfdb_a_LIBADD	= ../lcr/lcr_ifact.o
 CONFDB_LINKER_ADD	= $(OS_DYFLAGS) $(OS_LDL)
+SAM_LINKER_ADD		= -L. -lquorum
 libcoroipcc_a_SOURCES	= coroipcc.c
 libsam_a_SOURCES	= sam.c
 
diff --git a/trunk/lib/libsam.verso b/trunk/lib/libsam.verso
index fae6e3d..8089590 100644
--- a/trunk/lib/libsam.verso
+++ b/trunk/lib/libsam.verso
@@ -1 +1 @@
-4.2.1
+4.3.0
diff --git a/trunk/lib/sam.c b/trunk/lib/sam.c
index 95654e7..f9433bd 100644
--- a/trunk/lib/sam.c
+++ b/trunk/lib/sam.c
@@ -51,6 +51,7 @@
 #include <corosync/coroipcc.h>
 #include <corosync/corodefs.h>
 #include <corosync/hdb.h>
+#include <corosync/quorum.h>
 
 #include <corosync/sam.h>
 
@@ -107,20 +108,62 @@ static struct {
 	void *user_data;
 	size_t user_data_size;
 	size_t user_data_allocated;
+
+	quorum_handle_t quorum_handle;
+	uint32_t quorate;
+	int quorum_fd;
 } sam_internal_data;
 
+static void quorum_notification_fn (
+        quorum_handle_t handle,
+        uint32_t quorate,
+        uint64_t ring_id,
+        uint32_t view_list_entries,
+        uint32_t *view_list)
+{
+	sam_internal_data.quorate = quorate;
+}
+
 cs_error_t sam_initialize (
 	int time_interval,
 	sam_recovery_policy_t recovery_policy)
 {
+	quorum_callbacks_t quorum_callbacks;
+	cs_error_t err;
+
 	if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_NOT_INITIALIZED) {
 		return (CS_ERR_BAD_HANDLE);
 	}
 
-	if (recovery_policy != SAM_RECOVERY_POLICY_QUIT && recovery_policy != SAM_RECOVERY_POLICY_RESTART) {
+	if (recovery_policy != SAM_RECOVERY_POLICY_QUIT && recovery_policy != SAM_RECOVERY_POLICY_RESTART &&
+	    recovery_policy != SAM_RECOVERY_POLICY_QUORUM_QUIT && recovery_policy != SAM_RECOVERY_POLICY_QUORUM_RESTART) {
 		return (CS_ERR_INVALID_PARAM);
 	}
 
+	if (recovery_policy & SAM_RECOVERY_POLICY_QUORUM) {
+		/*
+		 * Initialize quorum
+		 */
+		quorum_callbacks.quorum_notify_fn = quorum_notification_fn;
+		if ((err = quorum_initialize (&sam_internal_data.quorum_handle, &quorum_callbacks)) != CS_OK) {
+			goto exit_error;
+		}
+
+		if ((err = quorum_trackstart (sam_internal_data.quorum_handle, CS_TRACK_CHANGES)) != CS_OK) {
+			goto exit_error_quorum;
+		}
+
+		if ((err = quorum_fd_get (sam_internal_data.quorum_handle, &sam_internal_data.quorum_fd)) != CS_OK) {
+			goto exit_error_quorum;
+		}
+
+		/*
+		 * Dispatch initial quorate state
+		 */
+		if ((err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ONE)) != CS_OK) {
+			goto exit_error_quorum;
+		}
+	}
 	sam_internal_data.recovery_policy = recovery_policy;
 
 	sam_internal_data.time_interval = time_interval;
@@ -136,6 +179,11 @@ cs_error_t sam_initialize (
 	sam_internal_data.user_data_allocated = 0;
 
 	return (CS_OK);
+
+exit_error_quorum:
+	quorum_finalize (sam_internal_data.quorum_handle);
+exit_error:
+	return (err);
 }
 
 /*
@@ -350,6 +398,7 @@ cs_error_t sam_data_store (
 cs_error_t sam_start (void)
 {
 	char command;
+	cs_error_t err;
 
 	if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED) {
 		return (CS_ERR_BAD_HANDLE);
@@ -360,6 +409,15 @@ cs_error_t sam_start (void)
 	if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command))
 		return (CS_ERR_LIBRARY);
 
+	if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_QUORUM) {
+		/*
+		 * Wait for parent reply
+		 */
+		if ((err = sam_read_reply (sam_internal_data.child_fd_in)) != CS_OK) {
+			return (err);
+		}
+	}
+
 	if (sam_internal_data.hc_callback)
 		if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, sizeof (command)) != sizeof (command))
 			return (CS_ERR_LIBRARY);
@@ -515,6 +573,109 @@ error_reply:
 	return (err);
 }
 
+static cs_error_t sam_parent_wait_for_quorum (
+	int parent_fd_in,
+	int parent_fd_out)
+{
+	char reply;
+	cs_error_t err;
+	struct pollfd pfds[2];
+	int poll_err;
+
+	/*
+	 * Update current quorum
+	 */
+	if ((err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ALL)) != CS_OK) {
+		goto error_reply;
+	}
+
+	/*
+	 * Wait for quorum
+	 */
+	while (!sam_internal_data.quorate) {
+		pfds[0].fd = parent_fd_in;
+		pfds[0].events = 0;
+		pfds[0].revents = 0;
+
+		pfds[1].fd = sam_internal_data.quorum_fd;
+		pfds[1].events = POLLIN;
+		pfds[1].revents = 0;
+
+		poll_err = poll (pfds, 2, -1);
+
+		if (poll_err == -1) {
+			/*
+			 *  Error in poll
+			 *  If it is EINTR, continue, otherwise QUIT
+			 */
+			if (errno != EINTR) {
+				err = CS_ERR_LIBRARY;
+				goto error_reply;
+			}
+		}
+
+		if (pfds[0].revents != 0) {
+			if (pfds[0].revents == POLLERR || pfds[0].revents == POLLHUP ||pfds[0].revents == POLLNVAL) {
+				/*
+				 * Child has exited
+				 */
+				return (CS_OK);
+			}
+		}
+
+		if (pfds[1].revents != 0) {
+			if ((err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ONE)) != CS_OK) {
+				goto error_reply;
+			}
+		}
+	}
+
+	reply = SAM_REPLY_OK;
+	if (sam_safe_write (parent_fd_out, &reply, sizeof (reply)) != sizeof (reply)) {
+		err = CS_ERR_LIBRARY;
+		goto error_reply;
+	}
+
+	return (CS_OK);
+
+error_reply:
+	reply = SAM_REPLY_ERROR;
+	if (sam_safe_write (parent_fd_out, &reply, sizeof (reply)) != sizeof (reply)) {
+		return (CS_ERR_LIBRARY);
+	}
+	if (sam_safe_write (parent_fd_out, &err, sizeof (err)) != sizeof (err)) {
+		return (CS_ERR_LIBRARY);
+	}
+
+	return (err);
+}
+
+static cs_error_t sam_parent_kill_child (
+	int *action,
+	pid_t child_pid)
+{
+	/*
+	 *  Kill child process
+	 */
+	if (!sam_internal_data.term_send) {
+		/*
+		 * We didn't send warn_signal yet.
+		 */
+		kill (child_pid, sam_internal_data.warn_signal);
+
+		sam_internal_data.term_send = 1;
+	} else {
+		/*
+		 * We sent child warning. Now, we will not be so nice
+		 */
+		kill (child_pid, SIGKILL);
+		*action = SAM_PARENT_ACTION_RECOVERY;
+	}
+
+	return (CS_OK);
+}
+
+
 static cs_error_t sam_parent_data_store (
 	int parent_fd_in,
 	int parent_fd_out)
@@ -585,16 +746,18 @@ static enum sam_parent_action_t sam_parent_handler (
 	ssize_t bytes_read;
 	char command;
 	int time_interval;
-	struct pollfd pfds;
+	struct pollfd pfds[2];
+	nfds_t nfds;
 
 	status = 0;
 
 	action = SAM_PARENT_ACTION_CONTINUE;
 
 	while (action == SAM_PARENT_ACTION_CONTINUE) {
-		pfds.fd = parent_fd_in;
-		pfds.events = POLLIN;
-		pfds.revents = 0;
+		pfds[0].fd = parent_fd_in;
+		pfds[0].events = POLLIN;
+		pfds[0].revents = 0;
+		nfds = 1;
 
 		if (status == 1 && sam_internal_data.time_interval != 0) {
 			time_interval = sam_internal_data.time_interval;
@@ -602,7 +765,14 @@ static enum sam_parent_action_t sam_parent_handler (
 			time_interval = -1;
 		}
 
-		poll_error = poll (&pfds, 1, time_interval);
+		if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_QUORUM) {
+			pfds[nfds].fd = sam_internal_data.quorum_fd;
+			pfds[nfds].events = POLLIN;
+			pfds[nfds].revents = 0;
+			nfds++;
+		}
+
+		poll_error = poll (pfds, nfds, time_interval);
 
 		if (poll_error == -1) {
 			/*
@@ -621,75 +791,80 @@ static enum sam_parent_action_t sam_parent_handler (
 			if (status == 0) {
 				action = SAM_PARENT_ACTION_QUIT;
 			} else {
+				sam_parent_kill_child (&action, child_pid);
+			}
+		}
+
+		if (poll_error > 0) {
+			if (pfds[0].revents != 0) {
 				/*
-				 *  Kill child process
+				 *  We have EOF or command in pipe
 				 */
-				if (!sam_internal_data.term_send) {
-					/*
-					 * We didn't send warn_signal yet.
-					 */
-					kill (child_pid, sam_internal_data.warn_signal);
+				bytes_read = sam_safe_read (parent_fd_in, &command, 1);
 
-					sam_internal_data.term_send = 1;
-				} else {
+				if (bytes_read == 0) {
 					/*
-					 * We sent child warning. Now, we will not be so nice
+					 *  Handle EOF -> Take recovery action or quit if sam_start wasn't called
 					 */
-					kill (child_pid, SIGKILL);
-					action = SAM_PARENT_ACTION_RECOVERY;
+					if (status == 0)
+						action = SAM_PARENT_ACTION_QUIT;
+					else
+						action = SAM_PARENT_ACTION_RECOVERY;
+
+					continue;
 				}
-			}
-		}
 
-		if (poll_error > 0) {
-			/*
-			 *  We have EOF or command in pipe
-			 */
-			bytes_read = sam_safe_read (parent_fd_in, &command, 1);
+				if (bytes_read == -1) {
+					action = SAM_PARENT_ACTION_ERROR;
+					goto action_exit;
+				}
 
-			if (bytes_read == 0) {
 				/*
-				 *  Handle EOF -> Take recovery action or quit if sam_start wasn't called
+				 * We have read command
 				 */
-				if (status == 0)
-					action = SAM_PARENT_ACTION_QUIT;
-				else
-					action = SAM_PARENT_ACTION_RECOVERY;
-
-				continue;
-			}
+				switch (command) {
+				case SAM_COMMAND_START:
+					if (status == 0) {
+						/*
+						 *  Not started yet
+						 */
+						if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_QUORUM) {
+							if (sam_parent_wait_for_quorum (parent_fd_in,
+							    parent_fd_out) != CS_OK) {
+								continue;
+							}
+						}
+
+						status = 1;
+					}
+					break;
+				case SAM_COMMAND_STOP:
+					if (status == 1) {
+						/*
+						 *  Started
+						 */
+						status = 0;
+					}
+					break;
+				case SAM_COMMAND_DATA_STORE:
+					sam_parent_data_store (parent_fd_in, parent_fd_out);
+					break;
+				case SAM_COMMAND_WARN_SIGNAL_SET:
+					sam_parent_warn_signal_set (parent_fd_in, parent_fd_out);
+					break;
+				}
+			} /* if (pfds[0].revents != 0) */
 
-			if (bytes_read == -1) {
-				action = SAM_PARENT_ACTION_ERROR;
-				goto action_exit;
-			}
+			if ((sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_QUORUM) &&
+			    pfds[1].revents != 0) {
+				/*
+				 * Handle quorum change
+				 */
+				quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ALL);
 
-			/*
-			 * We have read command
-			 */
-			switch (command) {
-			case SAM_COMMAND_START:
-				if (status == 0) {
-					/*
-					 *  Not started yet
-					 */
-					status = 1;
-				}
-				break;
-			case SAM_COMMAND_STOP:
-				if (status == 1) {
-					/*
-					 *  Started
-					 */
-					status = 0;
+				if (!sam_internal_data.quorate) {
+					sam_parent_kill_child (&action, child_pid);
 				}
-				break;
-			case SAM_COMMAND_DATA_STORE:
-				sam_parent_data_store (parent_fd_in, parent_fd_out);
-				break;
-			case SAM_COMMAND_WARN_SIGNAL_SET:
-				sam_parent_warn_signal_set (parent_fd_in, parent_fd_out);
-				break;
 			}
 		} /* select_error > 0 */
 	} /* action == SAM_PARENT_ACTION_CONTINUE */
@@ -790,6 +965,10 @@ cs_error_t sam_register (
 			}
 
 			if (action == SAM_PARENT_ACTION_QUIT) {
+				if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_QUORUM) {
+					quorum_finalize (sam_internal_data.quorum_handle);
+				}
+
 				exit (WEXITSTATUS (child_status));
 			}
 
diff --git a/trunk/man/sam_initialize.3 b/trunk/man/sam_initialize.3
index fc771df..1043954 100644
--- a/trunk/man/sam_initialize.3
+++ b/trunk/man/sam_initialize.3
@@ -1,5 +1,5 @@
 .\"/*
-.\" * Copyright (c) 2009 Red Hat, Inc.
+.\" * Copyright (c) 2009-2010 Red Hat, Inc.
 .\" *
 .\" * All rights reserved.
 .\" *
@@ -31,7 +31,7 @@
 .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 .\" * THE POSSIBILITY OF SUCH DAMAGE.
 .\" */
-.TH "SAM_INITIALIZE" 3 "12/01/2009" "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+.TH "SAM_INITIALIZE" 3 "30/04/2010" "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
 
 .SH NAME
 .P
@@ -68,6 +68,9 @@ The \fIrecovery_policy\fR is defined as type:
   typedef enum {
   	SAM_RECOVERY_POLICY_QUIT = 1,
   	SAM_RECOVERY_POLICY_RESTART = 2,
+        SAM_RECOVERY_POLICY_QUORUM = 0x08,
+        SAM_RECOVERY_POLICY_QUORUM_QUIT = SAM_RECOVERY_POLICY_QUORUM | SAM_RECOVERY_POLICY_QUIT,
+        SAM_RECOVERY_POLICY_QUORUM_RESTART = SAM_RECOVERY_POLICY_QUORUM | SAM_RECOVERY_POLICY_RESTART,
   } sam_recovery_policy_t;
 .fi
 
@@ -80,6 +83,17 @@ on failure, the process will terminate.
 .TP
 SAM_RECOVERY_POLICY_RESTART
 on failure, the process will restart.
+.TP
+SAM_RECOVERY_POLICY_QUORUM
+is not policy. Used only as flag meaning quorum integration
+.TP
+SAM_RECOVERY_POLICY_QUORUM_QUIT
+same as \fISAM_RECOVERY_POLICY_QUIT\fR but \fBsam_start (3)\fR will block until corosync becomes
+quorate and process will be terminated if quorum is lost.
+.TP
+SAM_RECOVERY_POLICY_QUORUM_RESTART
+same as \fISAM_RECOVERY_POLICY_RESTART\fR but \fBsam_start (3)\fR will block until corosync becomes
+quorate and process will be restarted if quorum is lost.
 
 .P
 To perform event driven healthchecking, \fBsam_register(3)\fR and
diff --git a/trunk/man/sam_overview.8 b/trunk/man/sam_overview.8
index b670723..d521a8a 100644
--- a/trunk/man/sam_overview.8
+++ b/trunk/man/sam_overview.8
@@ -1,5 +1,5 @@
 .\"/*
-.\" * Copyright (c) 2009 Red Hat, Inc.
+.\" * Copyright (c) 2009-2010 Red Hat, Inc.
 .\" *
 .\" * All rights reserved.
 .\" *
@@ -32,7 +32,7 @@
 .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 .\" * THE POSSIBILITY OF SUCH DAMAGE.
 .\" */
-.TH "SAM_OVERVIEW" 8 "12/01/2009" "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+.TH "SAM_OVERVIEW" 8 "30/04/2010" "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
 
 .SH NAME
 .P
@@ -115,6 +115,17 @@ or add timers to the active process to signal a healthcheck operation is
 successful.  To use event driven healthchecking,
 the \fBsam_hc_callback_register(3)\fR function should be executed.
 
+.SH Quorum integration
+.P
+SAM has special policies (\fISAM_RECOVERY_POLICY_QUIT\fR and \fISAM_RECOVERY_POLICY_RESTART\fR)
+for integration with quorum service. This policies changes SAM behaviour in two aspects.
+.RS
+.IP \(bu 3
+Call of \fBsam_start(3)\fR blocks until corosync becomes quorate
+.IP \(bu 3
+User selected recovery action is taken immediately after lost of quorum.
+.RE
+
 .SH Storing user data
 .P
 Sometimes there is need to store some data, which survives between instances.
diff --git a/trunk/man/sam_start.3 b/trunk/man/sam_start.3
index 1ed6c04..c49f230 100644
--- a/trunk/man/sam_start.3
+++ b/trunk/man/sam_start.3
@@ -1,5 +1,5 @@
 .\"/*
-.\" * Copyright (c) 2009 Red Hat, Inc.
+.\" * Copyright (c) 2009-2010 Red Hat, Inc.
 .\" *
 .\" * All rights reserved.
 .\" *
@@ -31,7 +31,7 @@
 .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 .\" * THE POSSIBILITY OF SUCH DAMAGE.
 .\" */
-.TH "SAM_START" 3 "12/01/2009" "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
+.TH "SAM_START" 3 "30/04/2010" "corosync Man Page" "Corosync Cluster Engine Programmer's Manual"
 
 .SH NAME
 .P
@@ -61,9 +61,15 @@ function can be called.
 An application can always stop health checking by calling the \fBsam_stop(3)\fR
 function.
 
+.P
+If SAM is initialized with quorum policy \fISAM_RECOVERY_POLICY_QUIT\fR or
+\fISAM_RECOVERY_POLICY_RESTART\fR \fBsam_start\fR will block until corosync
+becomes quorate.
+
 .SH RETURN VALUE
 .P
-This call return CS_OK value if successful, otherwise and error is returned.
+This call return CS_OK value if successful, otherwise and error is returned. If
+SAM is initialized with quorum policy, returned error can also be quorum error.
 
 .SH ERRORS
 .TP
diff --git a/trunk/test/Makefile.am b/trunk/test/Makefile.am
index d87ceef..946a37c 100644
--- a/trunk/test/Makefile.am
+++ b/trunk/test/Makefile.am
@@ -85,7 +85,7 @@ logsys_t1_LDADD		= -llogsys
 logsys_t1_LDFLAGS	= -L../exec
 logsys_t2_LDADD		= -llogsys
 logsys_t2_LDFLAGS	= -L../exec
-testsam_LDADD		= -lsam
+testsam_LDADD		= -lsam -lconfdb
 testsam_LDFLAGS		= -L../lib
 
 LINT_FILES1:=$(filter-out sa_error.c, $(wildcard *.c))
diff --git a/trunk/test/testsam.c b/trunk/test/testsam.c
index 6941b32..95d8e12 100644
--- a/trunk/test/testsam.c
+++ b/trunk/test/testsam.c
@@ -44,6 +44,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <corosync/corotypes.h>
+#include <corosync/confdb.h>
 #include <corosync/sam.h>
 #include <signal.h>
 #include <string.h>
@@ -735,12 +736,141 @@ static int test6 (void) {
 	return 1;
 }
 
+static void *test7_thread (void *arg)
+{
+	/* Wait 5s */
+	sleep (5);
+	exit (0);
+}
+
+/*
+ * Test quorum
+ */
+static int test7 (void) {
+	confdb_handle_t cdb_handle;
+	cs_error_t err;
+	hdb_handle_t quorum_handle;
+	size_t value_len;
+	char key_value[256];
+	unsigned int instance_id;
+	pthread_t kill_thread;
+
+	err = confdb_initialize (&cdb_handle, NULL);
+	if (err != CS_OK) {
+		printf ("Could not initialize Cluster Configuration Database API instance error %d. Test skipped\n", err);
+		return (1);
+	}
+
+	err = confdb_object_find_start(cdb_handle, OBJECT_PARENT_HANDLE);
+	if (err != CS_OK) {
+		printf ("Could not start object_find %d. Test skipped\n", err);
+		return (1);
+        }
+
+	err = confdb_object_find(cdb_handle, OBJECT_PARENT_HANDLE, "quorum", strlen("quorum"), &quorum_handle);
+	if (err != CS_OK) {
+		printf ("Could not object_find \"quorum\": %d. Test skipped\n", err);
+		return (1);
+	}
+
+	err = confdb_key_get(cdb_handle, quorum_handle, "provider", strlen("provider"), key_value, &value_len);
+	if (err != CS_OK) {
+		printf ("Could not get \"provider\" key: %d. Test skipped\n", err);
+		return (1);
+	}
+
+        if (!(value_len - 1 == strlen ("testquorum") && memcmp (key_value, "testquorum", value_len - 1) == 0)) {
+		printf ("Provider is not testquorum. Test skipped\n");
+		return (1);
+        }
+
+	/*
+	 * Set to not quorate
+	 */
+	err = confdb_key_create(cdb_handle, quorum_handle, "quorate", strlen("quorate"), "0", strlen("0"));
+	if (err != CS_OK) {
+		printf ("Can't create confdb key. Error %d\n", err);
+		return (2);
+	}
+
+	printf ("%s: initialize\n", __FUNCTION__);
+	err = sam_initialize (2000, SAM_RECOVERY_POLICY_QUORUM_RESTART);
+	if (err != CS_OK) {
+		fprintf (stderr, "Can't initialize SAM API. Error %d\n", err);
+		return 2;
+	}
+
+	printf ("%s: register\n", __FUNCTION__);
+	err = sam_register (&instance_id);
+	if (err != CS_OK) {
+		fprintf (stderr, "Can't register. Error %d\n", err);
+		return 2;
+	}
+
+	if (instance_id == 1) {
+		/*
+		 * Sam start should block forever, but 10s for us should be enough
+		 */
+		pthread_create (&kill_thread, NULL, test7_thread, NULL);
+
+		printf ("%s iid %d: start - should block forever (waiting 5s)\n", __FUNCTION__, instance_id);
+		err = sam_start ();
+		if (err != CS_OK) {
+			fprintf (stderr, "Can't start hc. Error %d\n", err);
+			return 2;
+		}
+
+		printf ("%s iid %d: wasn't killed\n", __FUNCTION__, instance_id);
+		return (2);
+	}
+
+	if (instance_id == 2) {
+		/*
+		 * Set to quorate
+		 */
+		err = confdb_key_create(cdb_handle, quorum_handle, "quorate", strlen("quorate"), "1", strlen("1"));
+		if (err != CS_OK) {
+			printf ("Can't create confdb key. Error %d\n", err);
+			return (2);
+		}
+
+		printf ("%s iid %d: start\n", __FUNCTION__, instance_id);
+		err = sam_start ();
+		if (err != CS_OK) {
+			fprintf (stderr, "Can't start hc. Error %d\n", err);
+			return 2;
+		}
+
+		/*
+		 * Set corosync unquorate
+		 */
+		err = confdb_key_create(cdb_handle, quorum_handle, "quorate", strlen("quorate"), "0", strlen("0"));
+		if (err != CS_OK) {
+			printf ("Can't create confdb key. Error %d\n", err);
+			return (2);
+		}
+
+		printf ("%s iid %d: sleep 3\n", __FUNCTION__, instance_id);
+		sleep (3);
+
+		printf ("%s iid %d: wasn't killed\n", __FUNCTION__, instance_id);
+		return (2);
+	}
+
+	if (instance_id == 3) {
+		return (0);
+	}
+
+	return (2);
+}
+
 int main(int argc, char *argv[])
 {
 	pid_t pid;
 	int err;
 	int stat;
 	int all_passed = 1;
+	int no_skipped = 0;
 
 	pid = fork ();
 
@@ -856,8 +986,29 @@ int main(int argc, char *argv[])
 	if (WEXITSTATUS (stat) != 0)
 		all_passed = 0;
 
+	pid = fork ();
+
+	if (pid == -1) {
+		fprintf (stderr, "Can't fork\n");
+		return 1;
+	}
+
+	if (pid == 0) {
+		err = test7 ();
+		sam_finalize ();
+		return (err);
+	}
+
+	waitpid (pid, &stat, 0);
+	fprintf (stderr, "test7 %s\n", (WEXITSTATUS (stat) == 0 ? "passed" : (WEXITSTATUS (stat) == 1 ? "skipped" : "failed")));
+	if (WEXITSTATUS (stat) == 1)
+		no_skipped++;
+
+	if (WEXITSTATUS (stat) > 1)
+		all_passed = 0;
+
 	if (all_passed)
-		fprintf (stderr, "All tests passed\n");
+		fprintf (stderr, "All tests passed (%d skipped)\n", no_skipped);
 
 	return (all_passed ? 0 : 1);
 }
-- 
1.6.2.5


--------------040505040001040204000608--


More information about the Openais mailing list