Add a test service to CTS. This enables us to test sync behaviour better.
-Angus Signed-off-by: Angus Salkeld <[email protected]> --- conf/lenses/corosync.aug | 8 +- cts/agents/Makefile.am | 47 +++++++ cts/agents/syncv2.c | 309 +++++++++++++++++++++++++++++++++++++++++++ cts/corosync.py | 2 + cts/corotests.py | 81 +++++++++++- exec/main.c | 4 +- include/corosync/corodefs.h | 4 +- 7 files changed, 450 insertions(+), 5 deletions(-) create mode 100644 cts/agents/syncv2.c diff --git a/conf/lenses/corosync.aug b/conf/lenses/corosync.aug index 52c613b..e9eff2b 100644 --- a/conf/lenses/corosync.aug +++ b/conf/lenses/corosync.aug @@ -122,6 +122,12 @@ let quorum = qstr /provider/ in section "quorum" setting -let lns = (comment|empty|compatibility|totem|quorum|logging|amf)* +(* The quorum section *) +let service = + let setting = + qstr /name|ver/ in + section "service" setting + +let lns = (comment|empty|compatibility|totem|quorum|logging|amf|service)* let xfm = transform lns (incl "/etc/corosync/corosync.conf") diff --git a/cts/agents/Makefile.am b/cts/agents/Makefile.am index 5c5c211..01dd2ce 100644 --- a/cts/agents/Makefile.am +++ b/cts/agents/Makefile.am @@ -32,15 +32,24 @@ MAINTAINERCLEANFILES = Makefile.in INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include +SOURCES = TEST_AGENTS = cpg_test_agent confdb_test_agent if INSTALL_TESTAGENTS agentdir = $(datadir)/$(PACKAGE)/tests bin_PROGRAMS = $(TEST_AGENTS) dist_agent_SCRIPTS = mem_leak_test.sh net_breaker.sh + +AM_CFLAGS = -fPIC +SERVICE_LCRSO = syncv2 +SOURCES += $(SERVICE_LCRSO:%=%.c) +EXTRA_DIST = $(SOURCES) +LCRSO = $(SERVICE_LCRSO:%=service_%.lcrso) +LCRSO_OBJS = $(SOURCES:%.c=%.o) else noinst_PROGRAMS = $(TEST_AGENTS) noinst_SCRIPTS = mem_leak_test.sh net_breaker.sh +LCRSO = endif noinst_HEADERS = common_test_agent.h @@ -53,6 +62,44 @@ confdb_test_agent_SOURCES = confdb_test_agent.c common_test_agent.c confdb_test_agent_LDADD = -lconfdb -lcoroipcc ../../exec/coropoll.o confdb_test_agent_LDFLAGS = -L../../lib + +if BUILD_DARWIN + +service_%.lcrso: %.o + $(CC) $(CFLAGS) -L$(top_builddir)/exec -llogsys -bundle -bundle_loader $(top_builddir)/exec/corosync $^ -o $@ + +else +if BUILD_SOLARIS + +service_%.lcrso: %.o + $(LD) $(LDFLAGS) -G $^ -o $@ + +else + +service_%.lcrso: %.o + $(CC) $(CFLAGS) $(COVERAGE_LCRSO_EXTRA_LDFLAGS) -shared -Wl,-soname=$@ $^ -o $@ +endif +endif + + + +if INSTALL_TESTAGENTS +all-local: $(LCRSO_OBJS) $(LCRSO) + @echo Built Service Engines + +install-exec-local: + $(INSTALL) -d $(DESTDIR)/$(LCRSODIR) + $(INSTALL) -m 755 $(LCRSO) $(DESTDIR)/$(LCRSODIR) + +uninstall-local: + cd $(DESTDIR)/$(LCRSODIR) && \ + rm -f $(LCRSO) + +endif + +clean-local: + rm -f *.o *.a *.so* *.da *.bb *.bbg *.lcrso + lint: -splint $(LINT_FLAGS) $(CFLAGS) *.c diff --git a/cts/agents/syncv2.c b/cts/agents/syncv2.c new file mode 100644 index 0000000..e5645a4 --- /dev/null +++ b/cts/agents/syncv2.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2010 Red Hat, Inc. + * + * All rights reserved. + * + * Author: Angus Salkeld <[email protected]> + * + * This software licensed under BSD license, the text of which follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the MontaVista Software, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <config.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <sys/uio.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <time.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <string.h> + +#include <corosync/swab.h> +#include <corosync/corotypes.h> +#include <corosync/coroipc_types.h> +#include <corosync/corodefs.h> +#include <corosync/lcr/lcr_comp.h> +#include <corosync/mar_gen.h> +#include <corosync/engine/coroapi.h> +#include <corosync/list.h> +#include <corosync/engine/logsys.h> + +#include "../exec/tlist.h" + +LOGSYS_DECLARE_SUBSYS ("TST2"); + +/* + * Service Interfaces required by service_message_handler struct + */ +static int tst_sv2_exec_init_fn ( + struct corosync_api_v1 *corosync_api); + +static void tst_sv2_confchg_fn ( + enum totem_configuration_type configuration_type, + const unsigned int *member_list, size_t member_list_entries, + const unsigned int *left_list, size_t left_list_entries, + const unsigned int *joined_list, size_t joined_list_entries, + const struct memb_ring_id *ring_id); + +static int tst_sv2_lib_init_fn (void *conn); +static int tst_sv2_lib_exit_fn (void *conn); +static struct corosync_api_v1 *api; + +static void tst_sv2_sync_init_v2 ( + const unsigned int *member_list, + size_t member_list_entries, + const struct memb_ring_id *ring_id); + +static int tst_sv2_sync_process (void); + +static void tst_sv2_sync_activate (void); + +static void tst_sv2_sync_abort (void); + +struct corosync_service_engine tst_sv2_service_engine = { + .name = "corosync test synv2 service", + .id = TST_SV2_SERVICE, + .priority = 1, + .private_data_size = 0, + .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED, + .lib_init_fn = tst_sv2_lib_init_fn, + .lib_exit_fn = tst_sv2_lib_exit_fn, + .lib_engine = NULL, + .lib_engine_count = 0, + .exec_engine = NULL, + .exec_engine_count = 0, + .confchg_fn = tst_sv2_confchg_fn, + .exec_init_fn = tst_sv2_exec_init_fn, + .exec_dump_fn = NULL, + .sync_mode = CS_SYNC_V2, + .sync_init = tst_sv2_sync_init_v2, + .sync_process = tst_sv2_sync_process, + .sync_activate = tst_sv2_sync_activate, + .sync_abort = tst_sv2_sync_abort +}; + +static unsigned int my_member_list[PROCESSOR_COUNT_MAX]; + +static unsigned int my_member_list_entries; + +static unsigned int my_old_member_list[PROCESSOR_COUNT_MAX]; + +static unsigned int my_old_member_list_entries = 0; +static int num_sync_processes = 0; + +static DECLARE_LIST_INIT (confchg_notify); + +/* + * Dynamic loading descriptor + */ + +static struct corosync_service_engine *tst_sv2_get_service_engine_ver0 (void); + +static struct corosync_service_engine_iface_ver0 tst_sv2_service_engine_iface = { + .corosync_get_service_engine_ver0 = tst_sv2_get_service_engine_ver0 +}; + +static struct lcr_iface corosync_tst_sv2_ver0[1] = { + { + .name = "corosync_tst_sv2", + .version = 0, + .versions_replace = 0, + .versions_replace_count = 0, + .dependencies = 0, + .dependency_count = 0, + .constructor = NULL, + .destructor = NULL, + .interfaces = NULL, + } +}; + +static struct lcr_comp tst_sv2_comp_ver0 = { + .iface_count = 1, + .ifaces = corosync_tst_sv2_ver0 +}; + +static struct corosync_service_engine *tst_sv2_get_service_engine_ver0 (void) +{ + return (&tst_sv2_service_engine); +} + +#ifdef COROSYNC_SOLARIS +void corosync_lcr_component_register (void); + +void corosync_lcr_component_register (void) { +#else +__attribute__ ((constructor)) static void corosync_lcr_component_register (void) { +#endif + lcr_interfaces_set (&corosync_tst_sv2_ver0[0], &tst_sv2_service_engine_iface); + + lcr_component_register (&tst_sv2_comp_ver0); +} + +static int tst_sv2_exec_init_fn ( + struct corosync_api_v1 *corosync_api) +{ +#ifdef COROSYNC_SOLARIS + logsys_subsys_init(); +#endif + api = corosync_api; + + return 0; +} + +static void tst_sv2_confchg_fn ( + enum totem_configuration_type configuration_type, + const unsigned int *member_list, size_t member_list_entries, + const unsigned int *left_list, size_t left_list_entries, + const unsigned int *joined_list, size_t joined_list_entries, + const struct memb_ring_id *ring_id) +{ + int j; + for (j = 0; j < left_list_entries; j++) { + log_printf (LOGSYS_LEVEL_INFO, + "Member left: %s", api->totem_ifaces_print (left_list[j])); + } + for (j = 0; j < joined_list_entries; j++) { + log_printf (LOGSYS_LEVEL_INFO, + "Member joined: %s", api->totem_ifaces_print (joined_list[j])); + } +} + +static int tst_sv2_lib_init_fn (void *conn) +{ + return (0); +} + +static int tst_sv2_lib_exit_fn (void *conn) +{ + return (0); +} + + +static void tst_sv2_sync_init_v2 ( + const unsigned int *member_list, + size_t member_list_entries, + const struct memb_ring_id *ring_id) +{ + unsigned int lowest_nodeid = 0xffffffff; + int i, j; + int found; + + num_sync_processes = 0; + + memcpy (my_member_list, member_list, member_list_entries * + sizeof (unsigned int)); + my_member_list_entries = member_list_entries; + + for (i = 0; i < my_member_list_entries; i++) { + if (my_member_list[i] < lowest_nodeid) { + lowest_nodeid = my_member_list[i]; + } + } + + log_printf (LOGSYS_LEVEL_INFO, + "tst_sv2_sync_init_v2 %s", + api->totem_ifaces_print (lowest_nodeid)); + + /* look for new (joined) nodes */ + for (j = 0; j < member_list_entries; j++) { + found = 0; + for (i = 0; i < my_old_member_list_entries; i++) { + if (my_old_member_list[i] == member_list[j]) { + found = 1; + break; + } + } + if (found == 0) { + log_printf (LOGSYS_LEVEL_INFO, + "sync: node joined %s", + api->totem_ifaces_print (member_list[j])); + } + } + /* look for old (left) nodes */ + for (i = 0; i < my_old_member_list_entries; i++) { + found = 0; + for (j = 0; j < member_list_entries; j++) { + if (my_old_member_list[i] == member_list[j]) { + found = 1; + break; + } + } + if (found == 0) { + log_printf (LOGSYS_LEVEL_INFO, + "sync: node left %s", + api->totem_ifaces_print (my_old_member_list[i])); + } + } + +} + +static int tst_sv2_sync_process (void) +{ + num_sync_processes++; + + log_printf (LOGSYS_LEVEL_INFO, "sync: process %d", num_sync_processes); + + if (num_sync_processes > 3) { + return 0; + } else { + return 1; + } +} + +static void tst_sv2_sync_activate (void) +{ + memcpy (my_old_member_list, my_member_list, + my_member_list_entries * sizeof (unsigned int)); + my_old_member_list_entries = my_member_list_entries; + + if (num_sync_processes <= 3) { + log_printf (LOGSYS_LEVEL_ERROR, + "sync: activate called before process is done %d", + num_sync_processes); + } else { + log_printf (LOGSYS_LEVEL_INFO, + "sync: activate correctly %d", + num_sync_processes); + } + + num_sync_processes = 0; +} + +static void tst_sv2_sync_abort (void) +{ + log_printf (LOGSYS_LEVEL_INFO, "sync: abort"); +} + diff --git a/cts/corosync.py b/cts/corosync.py index f54af4d..6962f39 100644 --- a/cts/corosync.py +++ b/cts/corosync.py @@ -141,6 +141,8 @@ class corosync_flatiron(ClusterManager): self.node_to_ip = {} self.new_config = {} + self.new_config['service[0]/name'] = 'corosync_tst_sv2' + self.new_config['service[0]/ver'] = '0' self.applied_config = {} for n in self.Env["nodes"]: ip = socket.gethostbyname(n) diff --git a/cts/corotests.py b/cts/corotests.py index 95bef01..1d80722 100644 --- a/cts/corotests.py +++ b/cts/corotests.py @@ -179,6 +179,83 @@ class CpgCfgChgOnNodeLeave(CpgConfigChangeBase): return self.wait_for_config_change() ################################################################### +class CpgCfgChgOnLowestNodeJoin(CTSTest): + ''' + 1) stop all nodes + 2) start all but the node with the smallest ip address + 3) start recording events + 4) start the last node + ''' + def __init__(self, cm): + CTSTest.__init__(self, cm) + self.name="CpgCfgChgOnLowestNodeJoin" + self.start = StartTest(cm) + self.stop = StopTest(cm) + self.config = {} + self.config['compatibility'] = 'none' + + def lowest_ip_set(self): + self.lowest = None + for n in self.CM.Env["nodes"]: + if self.lowest is None: + self.lowest = n + + self.CM.log("lowest node is " + self.lowest) + + def setup(self, node): + # stop all nodes + for n in self.CM.Env["nodes"]: + self.CM.StopaCM(n) + + self.lowest_ip_set() + + # copy over any new config + for c in self.config: + self.CM.new_config[c] = self.config[c] + + # install the config + self.CM.install_all_config() + + # start all but lowest + self.listener = None + for n in self.CM.Env["nodes"]: + if n is not self.lowest: + if self.listener is None: + self.listener = n + self.incr("started") + self.CM.log("starting " + n) + self.start(n) + self.CM.cpg_agent[n].clean_start() + self.CM.cpg_agent[n].cpg_join(self.name) + + # start recording events + pats = [] + pats.append("%s .*sync: node joined.*" % self.listener) + pats.append("%s .*sync: activate correctly.*" % self.listener) + self.sync_log = self.create_watch(pats, 60) + self.sync_log.setwatch() + + self.CM.log("setup done") + + return CTSTest.setup(self, node) + + + def __call__(self, node): + self.incr("calls") + + self.start(self.lowest) + self.CM.cpg_agent[self.lowest].clean_start() + self.CM.cpg_agent[self.lowest].cpg_join(self.name) + self.wobbly_id = self.CM.cpg_agent[self.lowest].cpg_local_get() + + self.CM.log("waiting for sync events") + if not self.sync_log.lookforall(): + return self.failure("Patterns not found: " + repr(self.sync_log.unmatched)) + else: + return self.success() + + +################################################################### class CpgCfgChgOnExecCrash(CpgConfigChangeBase): def __init__(self, cm): @@ -495,6 +572,7 @@ GenTestClasses.append(CpgCfgChgOnExecCrash) GenTestClasses.append(CpgCfgChgOnGroupLeave) GenTestClasses.append(CpgCfgChgOnNodeLeave) GenTestClasses.append(CpgCfgChgOnNodeIsolate) +GenTestClasses.append(CpgCfgChgOnLowestNodeJoin) AllTestClasses = [] AllTestClasses.append(ConfdbReplaceTest) @@ -585,7 +663,8 @@ def CoroTestList(cm, audits): bound_test = testclass(cm) if bound_test.is_applicable(): bound_test.Audits = audits - bound_test.config = cfg + for c in cfg: + bound_test.config[c] = cfg[c] bound_test.name = bound_test.name + '_' + str(num) result.append(bound_test) num = num + 1 diff --git a/exec/main.c b/exec/main.c index 0b7982a..f109606 100644 --- a/exec/main.c +++ b/exec/main.c @@ -428,12 +428,12 @@ static void confchg_fn ( memcpy (&corosync_ring_id, ring_id, sizeof (struct memb_ring_id)); for (i = 0; i < left_list_entries; i++) { - log_printf (LOGSYS_LEVEL_INFO, + log_printf (LOGSYS_LEVEL_DEBUG, "Member left: %s\n", api->totem_ifaces_print (left_list[i])); member_object_left (left_list[i]); } for (i = 0; i < joined_list_entries; i++) { - log_printf (LOGSYS_LEVEL_INFO, + log_printf (LOGSYS_LEVEL_DEBUG, "Member joined: %s\n", api->totem_ifaces_print (joined_list[i])); member_object_joined (joined_list[i]); } diff --git a/include/corosync/corodefs.h b/include/corosync/corodefs.h index 4af7c8a..57923e2 100644 --- a/include/corosync/corodefs.h +++ b/include/corosync/corodefs.h @@ -57,7 +57,9 @@ enum corosync_service_types { TMR_SERVICE = 14, VOTEQUORUM_SERVICE = 15, NTF_SERVICE = 16, - AMF_V2_SERVICE = 17 + AMF_V2_SERVICE = 17, + TST_SV1_SERVICE = 18, + TST_SV2_SERVICE = 19 }; #ifdef HAVE_SMALL_MEMORY_FOOTPRINT -- 1.6.6.1 _______________________________________________ Openais mailing list [email protected] https://lists.linux-foundation.org/mailman/listinfo/openais
