diff --git a/fencing/fence_false b/fencing/fence_false index af9409e893..ae7c2d15e2 100644 --- a/fencing/fence_false +++ b/fencing/fence_false @@ -1,75 +1,76 @@ #!/usr/bin/python # The Following Agent Has Been Tested On: # # Virsh 0.3.3 on RHEL 5.2 with xen-3.0.3-51 # import sys, time sys.path.append("/usr/share/fence") from fencing import * #BEGIN_VERSION_GENERATION RELEASE_VERSION="3.1.6" BUILD_DATE="(built Mon Oct 24 12:14:08 UTC 2011)" REDHAT_COPYRIGHT="Copyright (C) Red Hat, Inc. 2004-2010 All rights reserved." #END_VERSION_GENERATION plug_status="on" def get_outlets_status(conn, options): result={} # This fake agent has no port data to list, so we have to make # something up for the list action. if options.has_key("-o") and options["-o"] == "list": result["fake_port_1"]=[plug_status, "fake"] result["fake_port_2"]=[plug_status, "fake"] elif (options.has_key("-n") == 0): fail_usage("Failed: You have to enter existing machine!") else: port=options["-n"] result[port]=[plug_status, "fake"] return result def get_power_status(conn, options): outlets=get_outlets_status(conn,options) if len(outlets) == 0 or options.has_key("-n") == 0: fail_usage("Failed: You have to enter existing machine!") else: return outlets[options["-n"]][0] def set_power_status(conn, options): global plug_status plug_status = "unknown" + exit(1) def main(): device_opt = [ "help", "version", "agent", "quiet", "verbose", "debug", "action", "port", "no_password", "power_wait", "power_timeout", ] atexit.register(atexit_handler) pinput = process_input(device_opt) # Fake options to keep the library happy #pinput["-p"] = "none" pinput["-a"] = "localhost" pinput["-C"] = "," options = check_input(device_opt, pinput) if options.has_key("-o") and (options["-o"] == "monitor"): sys.exit(0) ## Defaults for fence agent docs = { } docs["shortdesc"] = "Fake fence agent" docs["longdesc"] = "fence_true is a fake Fencing agent which always reports success without doing anything." show_docs(options, docs) ## Operate the fencing device result = fence_action(None, options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fencing/regression.py.in b/fencing/regression.py.in index 793f1f2999..ea508b7c96 100644 --- a/fencing/regression.py.in +++ b/fencing/regression.py.in @@ -1,310 +1,496 @@ #!/usr/bin/python # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. import os import sys import subprocess import shlex import time def output_from_command(command): - test = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE) + test = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.PIPE) test.wait() return test.communicate()[0].split("\n") class Test: - def __init__(self, name, description, verbose = 0): + def __init__(self, name, description, verbose = 0, with_cpg = 0): self.name = name self.description = description self.cmds = [] self.verbose = verbose self.result_txt = "" self.cmd_tool_output = "" self.result_exitcode = 0; + self.stonith_options = "-s" + self.enable_corosync = 0 + if with_cpg: + self.stonith_options = "-c" + self.enable_corosync = 1 + self.stonith_process = None + self.stonith_output = "" + self.stonith_patterns = [] self.executed = 0 rsc_classes = output_from_command("crm_resource --list-standards") self.has_systemd = 0 if "systemd" in rsc_classes: self.has_systemd = 1 def __new_cmd(self, cmd, args, exitcode, stdout_match = "", no_wait = 0, stdout_negative_match = "", kill=None): self.cmds.append( { "cmd" : cmd, "kill" : kill, "args" : args, "expected_exitcode" : exitcode, "stdout_match" : stdout_match, "stdout_negative_match" : stdout_negative_match, "no_wait" : no_wait, - "cmd_output" : "", } ) - def start_environment(self): + def start_corosync(self): + if self.enable_corosync == 0: + return - ### make sure we are in full control here ### if self.has_systemd: - cmd = shlex.split("systemctl stop pacemaker.service") + cmd = shlex.split("systemctl start corosync.service") else: - cmd = shlex.split("service pacemaker stop") + cmd = shlex.split("service corosync start") test = subprocess.Popen(cmd, stdout=subprocess.PIPE) test.wait() + def stop_corosync(self): + if self.enable_corosync == 0: + return + if self.has_systemd: cmd = shlex.split("systemctl stop corosync.service") else: cmd = shlex.split("service corosync stop") test = subprocess.Popen(cmd, stdout=subprocess.PIPE) test.wait() + def stop_pacemaker(self): + if self.has_systemd: + cmd = shlex.split("systemctl stop pacemaker.service") + else: + cmd = shlex.split("service pacemaker stop") + test = subprocess.Popen(cmd, stdout=subprocess.PIPE) + test.wait() + + def start_environment(self): + ### make sure we are in full control here ### + self.stop_pacemaker() + self.stop_corosync() + cmd = shlex.split("killall -q -9 stonithd") test = subprocess.Popen(cmd, stdout=subprocess.PIPE) test.wait() - self.stonith_process = subprocess.Popen(shlex.split("@CRM_DAEMON_DIR@/stonithd -s")) + self.start_corosync() + + self.stonith_process = subprocess.Popen( + shlex.split("@CRM_DAEMON_DIR@/stonithd %s -V" % self.stonith_options), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) time.sleep(1) def clean_environment(self): if self.stonith_process: self.stonith_process.kill() + self.stonith_output = self.stonith_process.communicate()[1] self.stonith_process = None + self.stop_corosync() + + def add_stonith_log_pattern(self, pattern): + self.stonith_patterns.append(pattern) + def add_cmd(self, cmd, args): self.__new_cmd(cmd, args, 0, "") def add_cmd_no_wait(self, cmd, args): self.__new_cmd(cmd, args, 0, "", 1) def add_cmd_check_stdout(self, cmd, args, match, no_match = ""): self.__new_cmd(cmd, args, 0, match, 0, no_match) - def add_expected_fail_cmd(self, cmd, args): - self.__new_cmd(cmd, args, 255, "") + def add_expected_fail_cmd(self, cmd, args, exitcode = 255): + self.__new_cmd(cmd, args, exitcode, "") def get_exitcode(self): return self.result_exitcode def print_result(self, filler): print "%s%s" % (filler, self.result_txt) def run_cmd(self, args): cmd = shlex.split(args['args']) cmd.insert(0, args['cmd']) if self.verbose: print "\n\nRunning: "+" ".join(cmd) - test = subprocess.Popen(cmd, stdout=subprocess.PIPE) + test = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if args['kill']: if self.verbose: print "Also running: "+args['kill'] subprocess.Popen(shlex.split(args['kill'])) if args['no_wait'] == 0: test.wait() else: return 0 output = test.communicate()[0] if args['stdout_match'] != "" and output.count(args['stdout_match']) == 0: test.returncode = -2 - print "STDOUT string '%s' was not found in cmd output" % (args['stdout_match']) + print "STDOUT string '%s' was not found in cmd output: %s" % (args['stdout_match'], output) if args['stdout_negative_match'] != "" and output.count(args['stdout_negative_match']) != 0: test.returncode = -2 - print "STDOUT string '%s' was found in cmd output" % (args['stdout_negative_match']) - - args['cmd_output'] = output + print "STDOUT string '%s' was found in cmd output: %s" % (args['stdout_negative_match'], output) return test.returncode; + def match_stonith_patterns(self): + cur = 0 + total_patterns = len(self.stonith_patterns) + + if len(self.stonith_patterns) == 0: + return + + for line in self.stonith_output.split("\n"): + if line.count(self.stonith_patterns[cur]): + cur = cur + 1 + if cur == total_patterns: + break + + if cur != len(self.stonith_patterns): + for item in range(total_patterns): + if self.verbose and item > (cur -1): + print "Pattern Not Matched = '%s'" % self.stonith_patterns[item] + + self.result_txt = "FAILURE - '%s' failed. %d patterns out of %d not matched" % (self.name, total_patterns - cur, total_patterns) + self.result_exitcode = -1 + def run(self): res = 0 i = 1 self.start_environment() if self.verbose: print "\n--- START TEST - %s" % self.name self.result_txt = "SUCCESS - '%s'" % (self.name) self.result_exitcode = 0 for cmd in self.cmds: res = self.run_cmd(cmd) if res != cmd['expected_exitcode']: - print cmd['cmd_output'] print "Step %d FAILED - command returned %d, expected %d" % (i, res, cmd['expected_exitcode']) self.result_txt = "FAILURE - '%s' failed at step %d. Command: lrmd_test %s" % (self.name, i, cmd['args']) self.result_exitcode = -1 break else: if self.verbose: - print cmd['cmd_output'].strip() print "Step %d SUCCESS" % (i) i = i + 1 self.clean_environment() + if self.result_exitcode == 0: + self.match_stonith_patterns() + print self.result_txt if self.verbose: print "--- END TEST - %s\n" % self.name self.executed = 1 return res class Tests: def __init__(self, verbose = 0): self.tests = [] self.verbose = verbose - def new_test(self, name, description): - test = Test(name, description, self.verbose) + def new_test(self, name, description, with_cpg = 0): + test = Test(name, description, self.verbose, with_cpg) self.tests.append(test) return test def print_list(self): print "\n==== %d TESTS FOUND ====" % (len(self.tests)) print "%35s - %s" % ("TEST NAME", "TEST DESCRIPTION") print "%35s - %s" % ("--------------------", "--------------------") for test in self.tests: print "%35s - %s" % (test.name, test.description) print "==== END OF LIST ====\n" def run_single(self, name): for test in self.tests: if test.name == name: test.run() break; def run_tests_matching(self, pattern): for test in self.tests: if test.name.count(pattern) != 0: test.run() def run_tests(self): for test in self.tests: test.run() def print_results(self): failures = 0; success = 0; print "\n\n======= FINAL RESULTS ==========" print "\n--- FAILURE RESULTS:" for test in self.tests: if test.executed == 0: continue if test.get_exitcode() != 0: failures = failures + 1 test.print_result(" ") else: success = success + 1 if failures == 0: print " None" print "\n--- TOTALS\n Pass:%d\n Fail:%d\n" % (success, failures) def build_api_sanity_tests(self): verbose_arg = "" if self.verbose: verbose_arg = "-V" test = self.new_test("api_sanity_test", "Sanity test client api.") test.add_cmd("@CRM_DAEMON_DIR@/stonith-test", "-t %s" % (verbose_arg)) + def build_standalone_tests(self): + test_types = [ + { + "prefix" : "standalone" , + "use_cpg" : 0, + }, + { + "prefix" : "cpg" , + "use_cpg" : 1, + }, + ] + + # test what happens when multiple devices can fence a node, but the first device fails. + for test_type in test_types: + test = self.new_test("%s_fence_device_failure" % test_type["prefix"], + "Verify that when one fence device fails for a node, the others are tried.", test_type["use_cpg"]) + test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=node1 node2 node3\"") + test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"") + test.add_cmd("stonith_admin", "-R false2 -a fence_false -o \"pcmk_host_list=node1 node2 node3\"") + test.add_cmd("stonith_admin", "-F node3 -t 5") + + # simple topology test for one device + for test_type in test_types: + if test_type["use_cpg"] == 0: + continue + + test = self.new_test("%s_topology_simple" % test_type["prefix"], + "Verify all fencing devices at a level are used.", test_type["use_cpg"]) + test.add_cmd("stonith_admin", "-R true -a fence_true -o \"pcmk_host_list=node1 node2 node3\"") + + test.add_cmd("stonith_admin", "-r node3 -i 1 -v true") + test.add_cmd("stonith_admin", "-F node3 -t 5") + + test.add_stonith_log_pattern("for host 'node3' with device 'true' returned: 0") + + # test what happens when the first fencing level has multiple devices. + for test_type in test_types: + if test_type["use_cpg"] == 0: + continue + + test = self.new_test("%s_topology_device_fails" % test_type["prefix"], + "Verify if one device in a level fails, the other is tried.", test_type["use_cpg"]) + test.add_cmd("stonith_admin", "-R false -a fence_false -o \"pcmk_host_list=node1 node2 node3\"") + test.add_cmd("stonith_admin", "-R true -a fence_true -o \"pcmk_host_list=node1 node2 node3\"") + + test.add_cmd("stonith_admin", "-r node3 -i 1 -v false") + test.add_cmd("stonith_admin", "-r node3 -i 2 -v true") + test.add_cmd("stonith_admin", "-F node3 -t 5") + + test.add_stonith_log_pattern("for host 'node3' with device 'false' returned: -1001") + test.add_stonith_log_pattern("for host 'node3' with device 'true' returned: 0") + + # test what happens when the first fencing level fails. + for test_type in test_types: + if test_type["use_cpg"] == 0: + continue + + test = self.new_test("%s_topology_multi_level_fails" % test_type["prefix"], + "Verify if one level fails, the next leve is tried.", test_type["use_cpg"]) + test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"") + test.add_cmd("stonith_admin", "-R true2 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"") + test.add_cmd("stonith_admin", "-R true3 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"") + test.add_cmd("stonith_admin", "-R true4 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"") + test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=node1 node2 node3\"") + test.add_cmd("stonith_admin", "-R false2 -a fence_false -o \"pcmk_host_list=node1 node2 node3\"") + + test.add_cmd("stonith_admin", "-r node3 -i 1 -v false1") + test.add_cmd("stonith_admin", "-r node3 -i 1 -v true1") + test.add_cmd("stonith_admin", "-r node3 -i 2 -v true2") + test.add_cmd("stonith_admin", "-r node3 -i 2 -v false2") + test.add_cmd("stonith_admin", "-r node3 -i 3 -v true3") + test.add_cmd("stonith_admin", "-r node3 -i 3 -v true4") + + test.add_cmd("stonith_admin", "-F node3 -t 5") + + + test.add_stonith_log_pattern("for host 'node3' with device 'false1' returned: -1001") + test.add_stonith_log_pattern("for host 'node3' with device 'false2' returned: -1001") + test.add_stonith_log_pattern("for host 'node3' with device 'true3' returned: 0") + test.add_stonith_log_pattern("for host 'node3' with device 'true4' returned: 0") + + # test the stonith builds the correct list of devices that can fence a node. + for test_type in test_types: + test = self.new_test("%s_list_devices" % test_type["prefix"], + "Verify list of devices that can fence a node is correct", test_type["use_cpg"]) + test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node3\"") + test.add_cmd("stonith_admin", "-R true2 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"") + test.add_cmd("stonith_admin", "-R true3 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"") + + test.add_cmd_check_stdout("stonith_admin", "-l node1 -V", "true2", "true1") + test.add_cmd_check_stdout("stonith_admin", "-l node1 -V", "true3", "true1") + + # simple test of device monitor + for test_type in test_types: + test = self.new_test("%s_monitor" % test_type["prefix"], + "Verify device is reachable", test_type["use_cpg"]) + test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node3\"") + test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=node3\"") + + test.add_cmd("stonith_admin", "-Q true1") + test.add_cmd("stonith_admin", "-Q false1") + test.add_expected_fail_cmd("stonith_admin", "-Q true2", 237) + + # simple register test + for test_type in test_types: + test = self.new_test("%s_register" % test_type["prefix"], + "Verify devices can be registered and un-registered", test_type["use_cpg"]) + test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node3\"") + + test.add_cmd("stonith_admin", "-Q true1") + + test.add_cmd("stonith_admin", "-D true1") + + test.add_expected_fail_cmd("stonith_admin", "-Q true1", 237) + + # test fencing history. + for test_type in test_types: + if test_type["use_cpg"] == 0: + continue + test = self.new_test("%s_fence_history" % test_type["prefix"], + "Verify last fencing operation is returned.", test_type["use_cpg"]) + test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node3\"") + + test.add_cmd("stonith_admin", "-F node3 -t 5 -V") + + test.add_cmd_check_stdout("stonith_admin", "-H node3", "was able to turn off node node3", "") + class TestOptions: def __init__(self): self.options = {} self.options['list-tests'] = 0 self.options['run-all'] = 1 self.options['run-only'] = "" self.options['run-only-pattern'] = "" self.options['verbose'] = 0 self.options['invalid-arg'] = "" self.options['show-usage'] = 0 def build_options(self, argv): args = argv[1:] skip = 0 for i in range(0, len(args)): if skip: skip = 0 continue elif args[i] == "-h" or args[i] == "--help": self.options['show-usage'] = 1 elif args[i] == "-l" or args[i] == "--list-tests": self.options['list-tests'] = 1 elif args[i] == "-V" or args[i] == "--verbose": self.options['verbose'] = 1 elif args[i] == "-r" or args[i] == "--run-only": self.options['run-only'] = args[i+1] skip = 1 elif args[i] == "-p" or args[i] == "--run-only-pattern": self.options['run-only-pattern'] = args[i+1] skip = 1 def show_usage(self): print "usage: " + sys.argv[0] + " [options]" print "If no options are provided, all tests will run" print "Options:" print "\t [--help | -h] Show usage" print "\t [--list-tests | -l] Print out all registered tests." print "\t [--run-only | -r 'testname'] Run a specific test" print "\t [--verbose | -V] Verbose output" print "\t [--run-only-pattern | -p 'string'] Run only tests containing the string value" print "\n\tExample: Run only the test 'start_top'" print "\t\t python ./regression.py --run-only start_stop" print "\n\tExample: Run only the tests with the string 'systemd' present in them" print "\t\t python ./regression.py --run-only-pattern systemd" def main(argv): o = TestOptions() o.build_options(argv) tests = Tests(o.options['verbose']) + tests.build_standalone_tests() tests.build_api_sanity_tests() + os.system("cp /usr/share/pacemaker/tests/cts/fence_false /usr/sbin/fence_false") + os.system("cp /usr/share/pacemaker/tests/cts/fence_true /usr/sbin/fence_true") + print "Starting ..." if o.options['list-tests']: tests.print_list() elif o.options['show-usage']: o.show_usage() elif o.options['run-only-pattern'] != "": tests.run_tests_matching(o.options['run-only-pattern']) tests.print_results() elif o.options['run-only'] != "": tests.run_single(o.options['run-only']) tests.print_results() else: tests.run_tests() tests.print_results() - if __name__=="__main__": main(sys.argv) diff --git a/fencing/test.c b/fencing/test.c index cfe80b3448..be9b5df1e8 100644 --- a/fencing/test.c +++ b/fencing/test.c @@ -1,378 +1,378 @@ /* * Copyright (C) 2009 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* *INDENT-OFF* */ enum test_modes { /* class dev test using a very specific environment */ test_standard = 0, /* watch notifications only */ test_passive, /* sanity test stonith client api using fence_true and fence_false */ test_api_sanity, }; static struct crm_option long_options[] = { {"verbose", 0, 0, 'V'}, {"version", 0, 0, '$'}, {"help", 0, 0, '?'}, {"passive", 0, 0, 'p'}, {"api_test", 0, 0, 't'}, {0, 0, 0, 0} }; /* *INDENT-ON* */ stonith_t *st = NULL; struct pollfd pollfd; int st_opts = st_opt_sync_call; int expected_notifications = 0; int verbose = 0; static void dispatch_helper(int timeout) { int rc; crm_debug("Looking for notification"); pollfd.events = POLLIN; while(true) { rc = poll( &pollfd, 1, timeout); /* wait 10 minutes, -1 forever */ if (rc > 0 ) { stonith_dispatch( st ); } else { break; } } } static void st_callback(stonith_t *st, stonith_event_t *e) { if(st->state == stonith_disconnected) { exit(1); } crm_notice("Operation %s requested by %s %s for peer %s. %s reported: %s (ref=%s)", e->operation, e->origin, e->result == pcmk_ok?"completed":"failed", e->target, e->executioner ? e->executioner : "", pcmk_strerror(e->result), e->id); if (expected_notifications) { expected_notifications--; } } static void st_global_callback(stonith_t * stonith, const xmlNode * msg, int call_id, int rc, xmlNode * output, void *userdata) { crm_log_xml_notice((xmlNode*)msg, "Event"); } static void passive_test(void) { st->cmds->register_notification(st, T_STONITH_NOTIFY_DISCONNECT, st_callback); st->cmds->register_notification(st, T_STONITH_NOTIFY_FENCE, st_callback); st->cmds->register_notification(st, STONITH_OP_DEVICE_ADD, st_callback); st->cmds->register_notification(st, STONITH_OP_DEVICE_DEL, st_callback); st->cmds->register_callback(st, 0, 120, FALSE, NULL, "st_global_callback", st_global_callback); dispatch_helper(600 * 1000); } #define single_test(cmd, str, num_notifications, expected_rc) \ { \ int rc = 0; \ rc = cmd; \ expected_notifications = 0; \ if (num_notifications) { \ expected_notifications = num_notifications; \ dispatch_helper(500); \ } \ if (rc != expected_rc) { \ crm_info("FAILURE - expected rc %d != %d(%s) for cmd - %s\n", expected_rc, rc, pcmk_strerror(rc), str); \ exit(-1); \ } else if (expected_notifications) { \ crm_info("FAILURE - expected %d notifications, got only %d for cmd - %s\n", \ num_notifications, num_notifications - expected_notifications, str); \ exit(-1); \ } else { \ if (verbose) { \ crm_info("SUCCESS - %s: %d", str, rc); \ } else { \ crm_debug("SUCCESS - %s: %d", str, rc); \ } \ } \ }\ static void run_fence_failure_test(void) { stonith_key_value_t *params = NULL; params = stonith_key_value_add(params, "pcmk_host_map", "pcmk-1=1,2 pcmk-2=3,4"); single_test(st->cmds->register_device(st, st_opts, "test-id1", "stonith-ng", "fence_false", params), "Register device1 for failure test", 1, 0); single_test(st->cmds->fence(st, st_opts, "pcmk-2", "off", 3), - "Fence failure results off", 1, -62); + "Fence failure results off", 1, -1001); single_test(st->cmds->fence(st, st_opts, "pcmk-2", "reboot", 3), - "Fence failure results reboot", 1, -62); + "Fence failure results reboot", 1, -1001); single_test(st->cmds->remove_device(st, st_opts, "test-id1"), "Remove device1 for failure test", 1, 0); stonith_key_value_freeall(params, 1, 1); } static void run_fence_failure_rollover_test(void) { stonith_key_value_t *params = NULL; params = stonith_key_value_add(params, "pcmk_host_map", "pcmk-1=1,2 pcmk-2=3,4"); single_test(st->cmds->register_device(st, st_opts, "test-id1", "stonith-ng", "fence_false", params), "Register device1 for rollover test", 1, 0); single_test(st->cmds->register_device(st, st_opts, "test-id2", "stonith-ng", "fence_true", params), "Register device2 for rollover test", 1, 0); single_test(st->cmds->fence(st, st_opts, "pcmk-2", "off", 3), "Fence rollover results off", 1, 0); single_test(st->cmds->fence(st, st_opts, "pcmk-2", "on", 3), "Fence rollover results on", 1, 0); single_test(st->cmds->remove_device(st, st_opts, "test-id1"), "Remove device1 for rollover tests", 1, 0); single_test(st->cmds->remove_device(st, st_opts, "test-id2"), "Remove device2 for rollover tests", 1, 0); stonith_key_value_freeall(params, 1, 1); } static void run_standard_test(void) { stonith_key_value_t *params = NULL; params = stonith_key_value_add(params, "pcmk_host_map", "pcmk-1=1,2 pcmk-2=3,4"); single_test(st->cmds->register_device(st, st_opts, "test-id", "stonith-ng", "fence_true", params), "Register", 1, 0); single_test(st->cmds->list(st, st_opts, "test-id", NULL, 1), "list", 1, 0); single_test(st->cmds->monitor(st, st_opts, "test-id", 1), "Monitor", 1, 0); single_test(st->cmds->status(st, st_opts, "test-id", "pcmk-2", 1), "Status pcmk-2", 1, 0); single_test(st->cmds->status(st, st_opts, "test-id", "pcmk-1", 1), "Status pcmk-1", 1, 0); single_test(st->cmds->fence(st, st_opts, "unknown-host", "off", 1), "Fence unknown-host (expected failure)", 0, -113); single_test(st->cmds->fence(st, st_opts, "pcmk-1", "off", 1), "Fence pcmk-1", 1, 0); single_test(st->cmds->fence(st, st_opts, "pcmk-1", "on", 1), "Unfence pcmk-1", 1, 0); single_test(st->cmds->remove_device(st, st_opts, "test-id"), "Remove test-id", 1, 0); stonith_key_value_freeall(params, 1, 1); } static void sanity_tests(void) { st->cmds->register_notification(st, T_STONITH_NOTIFY_DISCONNECT, st_callback); st->cmds->register_notification(st, T_STONITH_NOTIFY_FENCE, st_callback); st->cmds->register_notification(st, STONITH_OP_DEVICE_ADD, st_callback); st->cmds->register_notification(st, STONITH_OP_DEVICE_DEL, st_callback); st->cmds->register_callback(st, 0, 120, FALSE, NULL, "st_global_callback", st_global_callback); crm_info("Starting API Sanity Tests"); run_standard_test(); run_fence_failure_test(); run_fence_failure_rollover_test(); crm_info("Sanity Tests Passed"); } static void standard_dev_test(void) { int rc = 0; char *tmp = NULL; stonith_key_value_t *params = NULL; params = stonith_key_value_add(params, "pcmk_host_map", "some-host=pcmk-7 pcmk-3=3,4"); rc = st->cmds->register_device(st, st_opts, "test-id", "stonith-ng", "fence_xvm", params); crm_debug("Register: %d", rc); rc = st->cmds->list(st, st_opts, "test-id", &tmp, 10); crm_debug("List: %d output: %s\n", rc, tmp ? tmp : ""); rc = st->cmds->monitor(st, st_opts, "test-id", 10); crm_debug("Monitor: %d", rc); rc = st->cmds->status(st, st_opts, "test-id", "pcmk-2", 10); crm_debug("Status pcmk-2: %d", rc); rc = st->cmds->status(st, st_opts, "test-id", "pcmk-1", 10); crm_debug("Status pcmk-1: %d", rc); rc = st->cmds->fence(st, st_opts, "unknown-host", "off", 60); crm_debug("Fence unknown-host: %d", rc); rc = st->cmds->status(st, st_opts, "test-id", "pcmk-1", 10); crm_debug("Status pcmk-1: %d", rc); rc = st->cmds->fence(st, st_opts, "pcmk-1", "off", 60); crm_debug("Fence pcmk-1: %d", rc); rc = st->cmds->status(st, st_opts, "test-id", "pcmk-1", 10); crm_debug("Status pcmk-1: %d", rc); rc = st->cmds->fence(st, st_opts, "pcmk-1", "on", 10); crm_debug("Unfence pcmk-1: %d", rc); rc = st->cmds->status(st, st_opts, "test-id", "pcmk-1", 10); crm_debug("Status pcmk-1: %d", rc); rc = st->cmds->fence(st, st_opts, "some-host", "off", 10); crm_debug("Fence alias: %d", rc); rc = st->cmds->status(st, st_opts, "test-id", "some-host", 10); crm_debug("Status alias: %d", rc); rc = st->cmds->fence(st, st_opts, "pcmk-1", "on", 10); crm_debug("Unfence pcmk-1: %d", rc); rc = st->cmds->remove_device(st, st_opts, "test-id"); crm_debug("Remove test-id: %d", rc); stonith_key_value_freeall(params, 1, 1); } int main(int argc, char ** argv) { int argerr = 0; int flag; int option_index = 0; int rc = 0; enum test_modes mode = test_standard; crm_set_options(NULL, "mode [options]", long_options, "Provides a summary of cluster's current state." "\n\nOutputs varying levels of detail in a number of different formats.\n"); while (1) { flag = crm_get_option(argc, argv, &option_index); if (flag == -1) { break; } switch(flag) { case 'V': verbose = 1; break; case '$': case '?': crm_help(flag, EX_OK); break; case 'p': mode = test_passive; break; case 't': mode = test_api_sanity; break; default: ++argerr; break; } } crm_log_init("stonith-test", LOG_INFO, TRUE, verbose ? TRUE : FALSE, argc, argv, FALSE); if (optind > argc) { ++argerr; } if (argerr) { crm_help('?', EX_USAGE); } crm_debug("Create"); st = stonith_api_new(); rc = st->cmds->connect(st, crm_system_name, &pollfd.fd); crm_debug("Connect: %d", rc); switch (mode) { case test_standard: standard_dev_test(); break; case test_passive: passive_test(); break; case test_api_sanity: sanity_tests(); break; } rc = st->cmds->disconnect(st); crm_debug("Disconnect: %d", rc); crm_debug("Destroy"); stonith_api_delete(st); return rc; }