4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
25
def output_from_command(command):
26
test = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
29
return test.communicate()[0].split("\n")
32
def __init__(self, name, description, verbose = 0, with_cpg = 0):
34
self.description = description
36
self.verbose = verbose
39
self.cmd_tool_output = ""
40
self.result_exitcode = 0;
42
self.stonith_options = "-s"
43
self.enable_corosync = 0
46
self.stonith_options = "-c"
47
self.enable_corosync = 1
49
self.stonith_process = None
50
self.stonith_output = ""
51
self.stonith_patterns = []
52
self.negative_stonith_patterns = []
56
rsc_classes = output_from_command("crm_resource --list-standards")
58
def __new_cmd(self, cmd, args, exitcode, stdout_match = "", no_wait = 0, stdout_negative_match = "", kill=None):
64
"expected_exitcode" : exitcode,
65
"stdout_match" : stdout_match,
66
"stdout_negative_match" : stdout_negative_match,
71
def stop_pacemaker(self):
72
cmd = shlex.split("killall -9 -q pacemakerd")
73
test = subprocess.Popen(cmd, stdout=subprocess.PIPE)
76
def start_environment(self):
77
### make sure we are in full control here ###
80
cmd = shlex.split("killall -9 -q stonithd")
81
test = subprocess.Popen(cmd, stdout=subprocess.PIPE)
85
print "Starting stonithd with %s" % self.stonith_options
87
self.stonith_process = subprocess.Popen(
88
shlex.split("@CRM_DAEMON_DIR@/stonithd %s -V" % self.stonith_options),
89
stdout=subprocess.PIPE,
90
stderr=subprocess.PIPE)
94
def clean_environment(self):
95
if self.stonith_process:
96
self.stonith_process.terminate()
98
self.stonith_output = self.stonith_process.communicate()[1]
99
self.stonith_process = None
102
print self.stonith_output
104
def add_stonith_log_pattern(self, pattern):
105
self.stonith_patterns.append(pattern)
107
def add_stonith_negative_log_pattern(self, pattern):
108
self.negative_stonith_patterns.append(pattern)
110
def add_cmd(self, cmd, args):
111
self.__new_cmd(cmd, args, 0, "")
113
def add_cmd_no_wait(self, cmd, args):
114
self.__new_cmd(cmd, args, 0, "", 1)
116
def add_cmd_check_stdout(self, cmd, args, match, no_match = ""):
117
self.__new_cmd(cmd, args, 0, match, 0, no_match)
119
def add_expected_fail_cmd(self, cmd, args, exitcode = 255):
120
self.__new_cmd(cmd, args, exitcode, "")
122
def get_exitcode(self):
123
return self.result_exitcode
125
def print_result(self, filler):
126
print "%s%s" % (filler, self.result_txt)
128
def run_cmd(self, args):
129
cmd = shlex.split(args['args'])
130
cmd.insert(0, args['cmd'])
133
print "\n\nRunning: "+" ".join(cmd)
134
test = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
138
print "Also running: "+args['kill']
139
subprocess.Popen(shlex.split(args['kill']))
141
if args['no_wait'] == 0:
146
output_res = test.communicate()
147
output = output_res[0] + output_res[1]
152
if args['stdout_match'] != "" and output.count(args['stdout_match']) == 0:
154
print "STDOUT string '%s' was not found in cmd output: %s" % (args['stdout_match'], output)
156
if args['stdout_negative_match'] != "" and output.count(args['stdout_negative_match']) != 0:
158
print "STDOUT string '%s' was found in cmd output: %s" % (args['stdout_negative_match'], output)
160
return test.returncode;
163
def count_negative_matches(self, outline):
165
for line in self.negative_stonith_patterns:
166
if outline.count(line):
169
print "This pattern should not have matched = '%s" % (line)
172
def match_stonith_patterns(self):
175
pats = self.stonith_patterns
176
total_patterns = len(self.stonith_patterns)
178
if len(self.stonith_patterns) == 0:
181
for line in self.stonith_output.split("\n"):
182
negative_matches = negative_matches + self.count_negative_matches(line)
188
if line.count(pats[cur]):
192
if len(pats) > 0 or negative_matches:
195
print "Pattern Not Matched = '%s'" % p
197
self.result_txt = "FAILURE - '%s' failed. %d patterns out of %d not matched. %d negative matches." % (self.name, len(pats), total_patterns, negative_matches)
198
self.result_exitcode = -1
203
self.start_environment()
206
print "\n--- START TEST - %s" % self.name
208
self.result_txt = "SUCCESS - '%s'" % (self.name)
209
self.result_exitcode = 0
210
for cmd in self.cmds:
211
res = self.run_cmd(cmd)
212
if res != cmd['expected_exitcode']:
213
print "Step %d FAILED - command returned %d, expected %d" % (i, res, cmd['expected_exitcode'])
214
self.result_txt = "FAILURE - '%s' failed at step %d. Command: %s %s" % (self.name, i, cmd['cmd'], cmd['args'])
215
self.result_exitcode = -1
219
print "Step %d SUCCESS" % (i)
221
self.clean_environment()
223
if self.result_exitcode == 0:
224
self.match_stonith_patterns()
226
print self.result_txt
228
print "--- END TEST - %s\n" % self.name
234
def __init__(self, verbose = 0):
236
self.verbose = verbose
237
self.autogen_corosync_cfg = 0
238
if not os.path.exists("/etc/corosync/corosync.conf"):
239
self.autogen_corosync_cfg = 1
241
def new_test(self, name, description, with_cpg = 0):
242
test = Test(name, description, self.verbose, with_cpg)
243
self.tests.append(test)
246
def print_list(self):
247
print "\n==== %d TESTS FOUND ====" % (len(self.tests))
248
print "%35s - %s" % ("TEST NAME", "TEST DESCRIPTION")
249
print "%35s - %s" % ("--------------------", "--------------------")
250
for test in self.tests:
251
print "%35s - %s" % (test.name, test.description)
252
print "==== END OF LIST ====\n"
255
def start_corosync(self):
257
print "Starting corosync"
259
test = subprocess.Popen("corosync", stdout=subprocess.PIPE)
263
def stop_corosync(self):
264
cmd = shlex.split("killall -9 -q corosync")
265
test = subprocess.Popen(cmd, stdout=subprocess.PIPE)
268
def run_single(self, name):
269
for test in self.tests:
270
if test.name == name:
274
def run_tests_matching(self, pattern):
275
for test in self.tests:
276
if test.name.count(pattern) != 0:
279
def run_cpg_only(self):
280
for test in self.tests:
281
if test.enable_corosync:
284
def run_no_cpg(self):
285
for test in self.tests:
286
if not test.enable_corosync:
290
for test in self.tests:
294
for test in self.tests:
295
if test.executed == 0:
298
if test.get_exitcode() != 0:
303
def print_results(self):
306
print "\n\n======= FINAL RESULTS =========="
307
print "\n--- FAILURE RESULTS:"
308
for test in self.tests:
309
if test.executed == 0:
312
if test.get_exitcode() != 0:
313
failures = failures + 1
314
test.print_result(" ")
316
success = success + 1
321
print "\n--- TOTALS\n Pass:%d\n Fail:%d\n" % (success, failures)
322
def build_api_sanity_tests(self):
327
test = self.new_test("standalone_low_level_api_test", "Sanity test client api in standalone mode.")
328
test.add_cmd("@CRM_DAEMON_DIR@/stonith-test", "-t %s" % (verbose_arg))
330
test = self.new_test("cpg_low_level_api_test", "Sanity test client api using mainloop and cpg.", 1)
331
test.add_cmd("@CRM_DAEMON_DIR@/stonith-test", "-m %s" % (verbose_arg))
333
def build_custom_timeout_tests(self):
334
# custom timeout without topology
335
test = self.new_test("cpg_custom_timeout_1",
336
"Verify per device timeouts work as expected without using topology.", 1)
337
test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=node1 node2 node3\"")
338
test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node3\" -o \"pcmk_off_timeout=1\"")
339
test.add_cmd("stonith_admin", "-R false2 -a fence_false -o \"pcmk_host_list=node3\" -o \"pcmk_off_timeout=4\"")
340
test.add_cmd("stonith_admin", "-F node3 -t 2")
341
# timeout is 2+1+4 = 7
342
test.add_stonith_log_pattern("remote op timeout set to 7")
344
# custom timeout _WITH_ topology
345
test = self.new_test("cpg_custom_timeout_2",
346
"Verify per device timeouts work as expected _WITH_ topology.", 1)
347
test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=node1 node2 node3\"")
348
test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node3\" -o \"pcmk_off_timeout=1\"")
349
test.add_cmd("stonith_admin", "-R false2 -a fence_false -o \"pcmk_host_list=node3\" -o \"pcmk_off_timeout=4000\"")
350
test.add_cmd("stonith_admin", "-r node3 -i 1 -v false1")
351
test.add_cmd("stonith_admin", "-r node3 -i 2 -v true1")
352
test.add_cmd("stonith_admin", "-r node3 -i 3 -v false2")
353
test.add_cmd("stonith_admin", "-F node3 -t 2")
354
# timeout is 2+1+4000 = 4003
355
test.add_stonith_log_pattern("remote op timeout set to 4003")
357
def build_fence_merge_tests(self):
359
### Simple test that overlapping fencing operations get merged
360
test = self.new_test("cpg_custom_merge_single",
361
"Verify overlapping identical fencing operations are merged, no fencing levels used.", 1)
362
test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=node3\"")
363
test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node3\" ")
364
test.add_cmd("stonith_admin", "-R false2 -a fence_false -o \"pcmk_host_list=node3\"")
365
test.add_cmd_no_wait("stonith_admin", "-F node3 -t 10")
366
test.add_cmd("stonith_admin", "-F node3 -t 10")
367
### one merger will happen
368
test.add_stonith_log_pattern("Merging stonith action off for node node3 originating from client")
369
### the pattern below signifies that both the original and duplicate operation completed
370
test.add_stonith_log_pattern("Operation off of node3 by")
371
test.add_stonith_log_pattern("Operation off of node3 by")
373
### Test that multiple mergers occur
374
test = self.new_test("cpg_custom_merge_multiple",
375
"Verify multiple overlapping identical fencing operations are merged", 1)
376
test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=node3\"")
377
test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node3\" ")
378
test.add_cmd("stonith_admin", "-R false2 -a fence_false -o \"pcmk_host_list=node3\"")
379
test.add_cmd_no_wait("stonith_admin", "-F node3 -t 10")
380
test.add_cmd_no_wait("stonith_admin", "-F node3 -t 10")
381
test.add_cmd_no_wait("stonith_admin", "-F node3 -t 10")
382
test.add_cmd_no_wait("stonith_admin", "-F node3 -t 10")
383
test.add_cmd("stonith_admin", "-F node3 -t 10")
384
### 4 mergers should occur
385
test.add_stonith_log_pattern("Merging stonith action off for node node3 originating from client")
386
test.add_stonith_log_pattern("Merging stonith action off for node node3 originating from client")
387
test.add_stonith_log_pattern("Merging stonith action off for node node3 originating from client")
388
test.add_stonith_log_pattern("Merging stonith action off for node node3 originating from client")
389
### the pattern below signifies that both the original and duplicate operation completed
390
test.add_stonith_log_pattern("Operation off of node3 by")
391
test.add_stonith_log_pattern("Operation off of node3 by")
392
test.add_stonith_log_pattern("Operation off of node3 by")
393
test.add_stonith_log_pattern("Operation off of node3 by")
394
test.add_stonith_log_pattern("Operation off of node3 by")
396
### Test that multiple mergers occur with topologies used
397
test = self.new_test("cpg_custom_merge_with_topology",
398
"Verify multiple overlapping identical fencing operations are merged with fencing levels.", 1)
399
test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=node3\"")
400
test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node3\" ")
401
test.add_cmd("stonith_admin", "-R false2 -a fence_false -o \"pcmk_host_list=node3\"")
402
test.add_cmd("stonith_admin", "-r node3 -i 1 -v false1")
403
test.add_cmd("stonith_admin", "-r node3 -i 1 -v false2")
404
test.add_cmd("stonith_admin", "-r node3 -i 2 -v true1")
405
test.add_cmd_no_wait("stonith_admin", "-F node3 -t 10")
406
test.add_cmd_no_wait("stonith_admin", "-F node3 -t 10")
407
test.add_cmd_no_wait("stonith_admin", "-F node3 -t 10")
408
test.add_cmd_no_wait("stonith_admin", "-F node3 -t 10")
409
test.add_cmd("stonith_admin", "-F node3 -t 10")
410
### 4 mergers should occur
411
test.add_stonith_log_pattern("Merging stonith action off for node node3 originating from client")
412
test.add_stonith_log_pattern("Merging stonith action off for node node3 originating from client")
413
test.add_stonith_log_pattern("Merging stonith action off for node node3 originating from client")
414
test.add_stonith_log_pattern("Merging stonith action off for node node3 originating from client")
415
### the pattern below signifies that both the original and duplicate operation completed
416
test.add_stonith_log_pattern("Operation off of node3 by")
417
test.add_stonith_log_pattern("Operation off of node3 by")
418
test.add_stonith_log_pattern("Operation off of node3 by")
419
test.add_stonith_log_pattern("Operation off of node3 by")
420
test.add_stonith_log_pattern("Operation off of node3 by")
423
test = self.new_test("cpg_custom_no_merge",
424
"Verify differing fencing operations are not merged", 1)
425
test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=node3 node2\"")
426
test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node3 node2\" ")
427
test.add_cmd("stonith_admin", "-R false2 -a fence_false -o \"pcmk_host_list=node3 node2\"")
428
test.add_cmd("stonith_admin", "-r node3 -i 1 -v false1")
429
test.add_cmd("stonith_admin", "-r node3 -i 1 -v false2")
430
test.add_cmd("stonith_admin", "-r node3 -i 2 -v true1")
431
test.add_cmd_no_wait("stonith_admin", "-F node2 -t 10")
432
test.add_cmd("stonith_admin", "-F node3 -t 10")
433
test.add_stonith_negative_log_pattern("Merging stonith action off for node node3 originating from client")
435
def build_standalone_tests(self):
438
"prefix" : "standalone" ,
447
# test what happens when all devices timeout
448
for test_type in test_types:
449
test = self.new_test("%s_fence_multi_device_failure" % test_type["prefix"],
450
"Verify that all devices timeout, a fencing failure is returned.", test_type["use_cpg"])
451
test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=node1 node2 node3\"")
452
test.add_cmd("stonith_admin", "-R false2 -a fence_false -o \"pcmk_host_list=node1 node2 node3\"")
453
test.add_cmd("stonith_admin", "-R false3 -a fence_false -o \"pcmk_host_list=node1 node2 node3\"")
454
test.add_expected_fail_cmd("stonith_admin", "-F node3 -t 2", 194)
456
if test_type["use_cpg"] == 1:
457
test.add_stonith_log_pattern("remote op timeout set to 6")
459
test.add_stonith_log_pattern("for host 'node3' with device 'false1' returned: -62")
460
test.add_stonith_log_pattern("for host 'node3' with device 'false2' returned: -62")
461
test.add_stonith_log_pattern("for host 'node3' with device 'false3' returned: -62")
463
# test what happens when multiple devices can fence a node, but the first device fails.
464
for test_type in test_types:
465
test = self.new_test("%s_fence_device_failure_rollover" % test_type["prefix"],
466
"Verify that when one fence device fails for a node, the others are tried.", test_type["use_cpg"])
467
test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=node1 node2 node3\"")
468
test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"")
469
test.add_cmd("stonith_admin", "-R false2 -a fence_false -o \"pcmk_host_list=node1 node2 node3\"")
470
test.add_cmd("stonith_admin", "-F node3 -t 2")
472
if test_type["use_cpg"] == 1:
473
test.add_stonith_log_pattern("remote op timeout set to 6")
475
# simple topology test for one device
476
for test_type in test_types:
477
if test_type["use_cpg"] == 0:
480
test = self.new_test("%s_topology_simple" % test_type["prefix"],
481
"Verify all fencing devices at a level are used.", test_type["use_cpg"])
482
test.add_cmd("stonith_admin", "-R true -a fence_true -o \"pcmk_host_list=node1 node2 node3\"")
484
test.add_cmd("stonith_admin", "-r node3 -i 1 -v true")
485
test.add_cmd("stonith_admin", "-F node3 -t 2")
487
test.add_stonith_log_pattern("remote op timeout set to 2")
488
test.add_stonith_log_pattern("for host 'node3' with device 'true' returned: 0")
490
# test what happens when the first fencing level has multiple devices.
491
for test_type in test_types:
492
if test_type["use_cpg"] == 0:
495
test = self.new_test("%s_topology_device_fails" % test_type["prefix"],
496
"Verify if one device in a level fails, the other is tried.", test_type["use_cpg"])
497
test.add_cmd("stonith_admin", "-R false -a fence_false -o \"pcmk_host_list=node1 node2 node3\"")
498
test.add_cmd("stonith_admin", "-R true -a fence_true -o \"pcmk_host_list=node1 node2 node3\"")
500
test.add_cmd("stonith_admin", "-r node3 -i 1 -v false")
501
test.add_cmd("stonith_admin", "-r node3 -i 2 -v true")
502
test.add_cmd("stonith_admin", "-F node3 -t 20")
504
test.add_stonith_log_pattern("remote op timeout set to 4")
505
test.add_stonith_log_pattern("for host 'node3' with device 'false' returned: -62")
506
test.add_stonith_log_pattern("for host 'node3' with device 'true' returned: 0")
508
# test what happens when the first fencing level fails.
509
for test_type in test_types:
510
if test_type["use_cpg"] == 0:
513
test = self.new_test("%s_topology_multi_level_fails" % test_type["prefix"],
514
"Verify if one level fails, the next leve is tried.", test_type["use_cpg"])
515
test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"")
516
test.add_cmd("stonith_admin", "-R true2 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"")
517
test.add_cmd("stonith_admin", "-R true3 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"")
518
test.add_cmd("stonith_admin", "-R true4 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"")
519
test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=node1 node2 node3\"")
520
test.add_cmd("stonith_admin", "-R false2 -a fence_false -o \"pcmk_host_list=node1 node2 node3\"")
522
test.add_cmd("stonith_admin", "-r node3 -i 1 -v false1")
523
test.add_cmd("stonith_admin", "-r node3 -i 1 -v true1")
524
test.add_cmd("stonith_admin", "-r node3 -i 2 -v true2")
525
test.add_cmd("stonith_admin", "-r node3 -i 2 -v false2")
526
test.add_cmd("stonith_admin", "-r node3 -i 3 -v true3")
527
test.add_cmd("stonith_admin", "-r node3 -i 3 -v true4")
529
test.add_cmd("stonith_admin", "-F node3 -t 2")
531
test.add_stonith_log_pattern("remote op timeout set to 12")
532
test.add_stonith_log_pattern("for host 'node3' with device 'false1' returned: -62")
533
test.add_stonith_log_pattern("for host 'node3' with device 'false2' returned: -62")
534
test.add_stonith_log_pattern("for host 'node3' with device 'true3' returned: 0")
535
test.add_stonith_log_pattern("for host 'node3' with device 'true4' returned: 0")
538
# test what happens when the first fencing level had devices that no one has registered
539
for test_type in test_types:
540
if test_type["use_cpg"] == 0:
543
test = self.new_test("%s_topology_missing_devices" % test_type["prefix"],
544
"Verify topology can continue with missing devices.", test_type["use_cpg"])
545
test.add_cmd("stonith_admin", "-R true2 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"")
546
test.add_cmd("stonith_admin", "-R true3 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"")
547
test.add_cmd("stonith_admin", "-R true4 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"")
548
test.add_cmd("stonith_admin", "-R false2 -a fence_false -o \"pcmk_host_list=node1 node2 node3\"")
550
test.add_cmd("stonith_admin", "-r node3 -i 1 -v false1")
551
test.add_cmd("stonith_admin", "-r node3 -i 1 -v true1")
552
test.add_cmd("stonith_admin", "-r node3 -i 2 -v true2")
553
test.add_cmd("stonith_admin", "-r node3 -i 2 -v false2")
554
test.add_cmd("stonith_admin", "-r node3 -i 3 -v true3")
555
test.add_cmd("stonith_admin", "-r node3 -i 3 -v true4")
557
test.add_cmd("stonith_admin", "-F node3 -t 2")
559
# Test what happens if multiple fencing levels are defined, and then the first one is removed.
560
for test_type in test_types:
561
if test_type["use_cpg"] == 0:
564
test = self.new_test("%s_topology_level_removal" % test_type["prefix"],
565
"Verify level removal works.", test_type["use_cpg"])
566
test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"")
567
test.add_cmd("stonith_admin", "-R true2 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"")
568
test.add_cmd("stonith_admin", "-R true3 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"")
569
test.add_cmd("stonith_admin", "-R true4 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"")
570
test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=node1 node2 node3\"")
571
test.add_cmd("stonith_admin", "-R false2 -a fence_false -o \"pcmk_host_list=node1 node2 node3\"")
573
test.add_cmd("stonith_admin", "-r node3 -i 1 -v false1")
574
test.add_cmd("stonith_admin", "-r node3 -i 1 -v true1")
576
test.add_cmd("stonith_admin", "-r node3 -i 2 -v true2")
577
test.add_cmd("stonith_admin", "-r node3 -i 2 -v false2")
579
test.add_cmd("stonith_admin", "-r node3 -i 3 -v true3")
580
test.add_cmd("stonith_admin", "-r node3 -i 3 -v true4")
582
# Now remove level 2, verify none of the devices in level two are hit.
583
test.add_cmd("stonith_admin", "-d node3 -i 2")
585
test.add_cmd("stonith_admin", "-F node3 -t 20")
587
test.add_stonith_log_pattern("remote op timeout set to 8")
588
test.add_stonith_log_pattern("for host 'node3' with device 'false1' returned: -62")
589
test.add_stonith_negative_log_pattern("for host 'node3' with device 'false2' returned: -62")
590
test.add_stonith_negative_log_pattern("for host 'node3' with device 'false2' returned: -1001")
591
test.add_stonith_log_pattern("for host 'node3' with device 'true3' returned: 0")
592
test.add_stonith_log_pattern("for host 'node3' with device 'true4' returned: 0")
594
# test the stonith builds the correct list of devices that can fence a node.
595
for test_type in test_types:
596
test = self.new_test("%s_list_devices" % test_type["prefix"],
597
"Verify list of devices that can fence a node is correct", test_type["use_cpg"])
598
test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node3\"")
599
test.add_cmd("stonith_admin", "-R true2 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"")
600
test.add_cmd("stonith_admin", "-R true3 -a fence_true -o \"pcmk_host_list=node1 node2 node3\"")
602
test.add_cmd_check_stdout("stonith_admin", "-l node1 -V", "true2", "true1")
603
test.add_cmd_check_stdout("stonith_admin", "-l node1 -V", "true3", "true1")
605
# simple test of device monitor
606
for test_type in test_types:
607
test = self.new_test("%s_monitor" % test_type["prefix"],
608
"Verify device is reachable", test_type["use_cpg"])
609
test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node3\"")
610
test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=node3\"")
612
test.add_cmd("stonith_admin", "-Q true1")
613
test.add_cmd("stonith_admin", "-Q false1")
614
test.add_expected_fail_cmd("stonith_admin", "-Q true2", 237)
616
# Verify monitor occurs for duration of timeout period on failure
617
for test_type in test_types:
618
test = self.new_test("%s_monitor_timeout" % test_type["prefix"],
619
"Verify monitor uses duration of timeout period given.", test_type["use_cpg"])
620
test.add_cmd("stonith_admin", "-R true1 -a fence_dummy_monitor_fail -o \"pcmk_host_list=node3\"")
621
test.add_expected_fail_cmd("stonith_admin", "-Q true1 -t 5", 23)
622
test.add_stonith_log_pattern("Attempt 2 to execute")
624
# Verify monitor occurs for duration of timeout period on failure, but stops at max retries
625
for test_type in test_types:
626
test = self.new_test("%s_monitor_timeout_max_retries" % test_type["prefix"],
627
"Verify monitor retries until max retry value or timeout is hit.", test_type["use_cpg"])
628
test.add_cmd("stonith_admin", "-R true1 -a fence_dummy_monitor_fail -o \"pcmk_host_list=node3\"")
629
test.add_expected_fail_cmd("stonith_admin", "-Q true1 -t 15", 23)
630
test.add_stonith_log_pattern("Attempted to execute agent fence_dummy_monitor_fail (list) the maximum number of times")
632
# simple register test
633
for test_type in test_types:
634
test = self.new_test("%s_register" % test_type["prefix"],
635
"Verify devices can be registered and un-registered", test_type["use_cpg"])
636
test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node3\"")
638
test.add_cmd("stonith_admin", "-Q true1")
640
test.add_cmd("stonith_admin", "-D true1")
642
test.add_expected_fail_cmd("stonith_admin", "-Q true1", 237)
646
for test_type in test_types:
647
test = self.new_test("%s_reboot" % test_type["prefix"],
648
"Verify devices can be rebooted", test_type["use_cpg"])
649
test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node3\"")
651
test.add_cmd("stonith_admin", "-B node3 -t 2")
653
test.add_cmd("stonith_admin", "-D true1")
655
test.add_expected_fail_cmd("stonith_admin", "-Q true1", 237)
657
# test fencing history.
658
for test_type in test_types:
659
if test_type["use_cpg"] == 0:
661
test = self.new_test("%s_fence_history" % test_type["prefix"],
662
"Verify last fencing operation is returned.", test_type["use_cpg"])
663
test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node3\"")
665
test.add_cmd("stonith_admin", "-F node3 -t 2 -V")
667
test.add_cmd_check_stdout("stonith_admin", "-H node3", "was able to turn off node node3", "")
669
# simple test of dynamic list query
670
for test_type in test_types:
671
test = self.new_test("%s_dynamic_list_query" % test_type["prefix"],
672
"Verify dynamic list of fencing devices can be retrieved.", test_type["use_cpg"])
673
test.add_cmd("stonith_admin", "-R true1 -a fence_true")
674
test.add_cmd("stonith_admin", "-R true2 -a fence_true")
675
test.add_cmd("stonith_admin", "-R true3 -a fence_true")
677
test.add_cmd_check_stdout("stonith_admin", "-l fake_port_1", "3 devices found")
680
# fence using dynamic list query
681
for test_type in test_types:
682
test = self.new_test("%s_fence_dynamic_list_query" % test_type["prefix"],
683
"Verify dynamic list of fencing devices can be retrieved.", test_type["use_cpg"])
684
test.add_cmd("stonith_admin", "-R true1 -a fence_true")
685
test.add_cmd("stonith_admin", "-R true2 -a fence_true")
686
test.add_cmd("stonith_admin", "-R true3 -a fence_true")
688
test.add_cmd("stonith_admin", "-F fake_port_1 -t 5 -V");
690
# simple test of query using status action
691
for test_type in test_types:
692
test = self.new_test("%s_status_query" % test_type["prefix"],
693
"Verify dynamic list of fencing devices can be retrieved.", test_type["use_cpg"])
694
test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_check=status\"")
695
test.add_cmd("stonith_admin", "-R true2 -a fence_true -o \"pcmk_host_check=status\"")
696
test.add_cmd("stonith_admin", "-R true3 -a fence_true -o \"pcmk_host_check=status\"")
698
test.add_cmd_check_stdout("stonith_admin", "-l fake_port_1", "3 devices found")
701
def build_nodeid_tests(self):
702
our_uname = output_from_command("uname -n")
704
our_uname = our_uname[0]
706
### verify nodeid is supplied when nodeid is in the metadata parameters
707
test = self.new_test("cpg_supply_nodeid",
708
"Verify nodeid is given when fence agent has nodeid as parameter", 1)
710
test.add_cmd("stonith_admin", "-R true1 -a fence_dummy_metadata_helper -o \"pcmk_host_list=%s\"" % (our_uname))
711
test.add_cmd("stonith_admin", "-F %s -t 3" % (our_uname))
712
test.add_stonith_log_pattern("For stonith action (off) for victim %s, adding nodeid" % (our_uname))
714
### verify nodeid is _NOT_ supplied when nodeid is not in the metadata parameters
715
test = self.new_test("cpg_do_not_supply_nodeid",
716
"Verify nodeid is _NOT_ given when fence agent does not have nodeid as parameter", 1)
718
test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=%s\"" % (our_uname))
719
test.add_cmd("stonith_admin", "-F %s -t 3" % (our_uname))
720
test.add_stonith_negative_log_pattern("For stonith action (off) for victim %s, adding nodeid" % (our_uname))
722
### verify nodeid use doesn't explode standalone mode
723
test = self.new_test("standalone_do_not_supply_nodeid",
724
"Verify nodeid in metadata parameter list doesn't kill standalone mode", 0)
726
test.add_cmd("stonith_admin", "-R true1 -a fence_dummy_metadata_helper -o \"pcmk_host_list=%s\"" % (our_uname))
727
test.add_cmd("stonith_admin", "-F %s -t 3" % (our_uname))
728
test.add_stonith_negative_log_pattern("For stonith action (off) for victim %s, adding nodeid" % (our_uname))
731
def build_unfence_tests(self):
732
our_uname = output_from_command("uname -n")
734
our_uname = our_uname[0]
736
### Simple test unfencing works
737
test = self.new_test("cpg_unfence_simple",
738
"Verify simple unfencing.", 1)
739
test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=node3\"")
740
test.add_cmd("stonith_admin", "-R true1 -a fence_true -o \"pcmk_host_list=node3\" ")
741
test.add_cmd("stonith_admin", "-R false2 -a fence_false -o \"pcmk_host_list=node3\"")
742
test.add_cmd("stonith_admin", "-U node3 -t 3")
744
### verify unfencing using on_target device
745
test = self.new_test("cpg_unfence_on_target_1",
746
"Verify unfencing with on_target = true", 1)
747
test.add_cmd("stonith_admin", "-R true1 -a fence_dummy_metadata_helper -o \"pcmk_host_list=%s\"" % (our_uname))
748
test.add_cmd("stonith_admin", "-U %s -t 3" % (our_uname))
749
test.add_stonith_log_pattern("(on) to be executed on the target node")
752
### verify failure of unfencing using on_target device
753
test = self.new_test("cpg_unfence_on_target_2",
754
"Verify failure unfencing with on_target = true", 1)
755
test.add_cmd("stonith_admin", "-R true1 -a fence_dummy_metadata_helper -o \"pcmk_host_list=%s node_fake_1234\"" % (our_uname))
756
test.add_expected_fail_cmd("stonith_admin", "-U node_fake_1234 -t 3", 194)
757
test.add_stonith_log_pattern("(on) to be executed on the target node")
760
### verify unfencing using on_target device with topology
761
test = self.new_test("cpg_unfence_on_target_3",
762
"Verify unfencing with on_target = true using topology", 1)
764
test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=%s node3\"" % (our_uname))
765
test.add_cmd("stonith_admin", "-R false2 -a fence_false -o \"pcmk_host_list=%s node3\"" % (our_uname))
766
test.add_cmd("stonith_admin", "-R true1 -a fence_dummy_metadata_helper -o \"pcmk_host_list=%s node3\"" % (our_uname))
768
test.add_cmd("stonith_admin", "-r %s -i 1 -v false1" % (our_uname))
769
test.add_cmd("stonith_admin", "-r %s -i 2 -v false2" % (our_uname))
770
test.add_cmd("stonith_admin", "-r %s -i 3 -v true1" % (our_uname))
772
test.add_cmd("stonith_admin", "-U %s -t 3" % (our_uname))
773
test.add_stonith_log_pattern("(on) to be executed on the target node")
775
### verify unfencing using on_target device with topology fails
776
test = self.new_test("cpg_unfence_on_target_4",
777
"Verify unfencing failure with on_target = true using topology", 1)
779
test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=%s node_fake\"" % (our_uname))
780
test.add_cmd("stonith_admin", "-R false2 -a fence_false -o \"pcmk_host_list=%s node_fake\"" % (our_uname))
781
test.add_cmd("stonith_admin", "-R true1 -a fence_dummy_metadata_helper -o \"pcmk_host_list=%s node_fake\"" % (our_uname))
783
test.add_cmd("stonith_admin", "-r node_fake -i 1 -v false1")
784
test.add_cmd("stonith_admin", "-r node_fake -i 2 -v false2")
785
test.add_cmd("stonith_admin", "-r node_fake -i 3 -v true1")
787
test.add_expected_fail_cmd("stonith_admin", "-U node_fake -t 3", 194)
788
test.add_stonith_log_pattern("(on) to be executed on the target node")
791
### verify use of on_target = true for "on" action does not interfere with "off" action
792
test = self.new_test("cpg_unfence_on_target_ignored",
793
"Verify on target is ignored for other actions", 1)
794
test.add_cmd("stonith_admin", "-R false1 -a fence_false -o \"pcmk_host_list=%s node_fake\"" % (our_uname))
795
test.add_cmd("stonith_admin", "-R false2 -a fence_false -o \"pcmk_host_list=%s node_fake\"" % (our_uname))
796
test.add_cmd("stonith_admin", "-R true1 -a fence_dummy_metadata_helper -o \"pcmk_host_list=%s node_fake\"" % (our_uname))
797
test.add_cmd("stonith_admin", "-r node_fake -i 1 -v false1")
798
test.add_cmd("stonith_admin", "-r node_fake -i 2 -v false2")
799
test.add_cmd("stonith_admin", "-r node_fake -i 3 -v true1")
800
test.add_cmd("stonith_admin", "-F node_fake -t 3")
801
test.add_stonith_log_pattern("(on) to be executed on the target node")
803
def setup_environment(self, use_corosync):
804
if self.autogen_corosync_cfg and use_corosync:
818
mcastaddr: 226.94.1.1
819
bindnetaddr: 127.0.0.1
828
syslog_facility: daemon
831
logfile: /var/log/corosync.log
832
logfile_priority: info
836
os.system("cat <<-END >>/etc/corosync/corosync.conf\n%s\nEND" % (corosync_conf))
840
### make sure we are in control ###
842
self.start_corosync()
844
monitor_fail_agent = ("""#!/usr/bin/python
847
for line in sys.stdin.readlines():
848
if line.count("monitor") > 0:
851
if __name__ == "__main__":
854
on_target_agent = ("""#!/usr/bin/python
857
for line in sys.stdin.readlines():
860
if line.count("monitor") > 0:
862
if line.count("metadata") > 0:
863
print '<resource-agent name="fence_dummy_metadata_helper" shortdesc="Dummy Fence agent for testing">'
864
print ' <longdesc>dummy description.</longdesc>'
865
print ' <vendor-url>http://www.example.com</vendor-url>'
866
print ' <parameters>'
867
print ' <parameter name="action" unique="0" required="1">'
868
print ' <getopt mixed="-o, --action=[action]"/>'
869
print ' <content type="string" default="reboot"/>'
870
print ' <shortdesc lang="en">Fencing Action</shortdesc>'
871
print ' </parameter>'
872
print ' <parameter name="nodeid" unique="0" required="0">'
873
print ' <content type="string"/>'
874
print ' <shortdesc lang="en">Corosync nodeid of the fence victim</shortdesc>'
875
print ' </parameter>'
876
print ' <parameter name="port" unique="0" required="0">'
877
print ' <getopt mixed="-n, --plug=[id]"/>'
878
print ' <content type="string"/>'
879
print ' <shortdesc lang="en">Physical plug number or name of virtual machine</shortdesc>'
880
print ' </parameter>'
881
print ' </parameters>'
883
print ' <action name="on" on_target="1"/>'
884
print ' <action name="off"/>'
885
print ' <action name="monitor"/>'
886
print ' <action name="metadata"/>'
888
print '</resource-agent>'
890
if line.count("on") > 0:
892
if line.count("off") > 0:
894
if line.count("nodeid") > 0:
897
if off_hit and nodeid_found:
900
if __name__ == "__main__":
904
os.system("cat <<-END >>/usr/sbin/fence_dummy_metadata_helper\n%s\nEND" % (on_target_agent))
905
os.system("chmod 711 /usr/sbin/fence_dummy_metadata_helper")
907
os.system("cat <<-END >>/usr/sbin/fence_dummy_monitor_fail\n%s\nEND" % (monitor_fail_agent))
908
os.system("chmod 711 /usr/sbin/fence_dummy_monitor_fail")
909
os.system("cp /usr/share/pacemaker/tests/cts/fence_false /usr/sbin/fence_false")
910
os.system("cp /usr/share/pacemaker/tests/cts/fence_true /usr/sbin/fence_true")
912
def cleanup_environment(self, use_corosync):
916
if self.verbose and os.path.exists('/var/log/corosync.log'):
917
print "Daemon output"
918
f = open('/var/log/corosync.log', 'r')
919
for line in f.readlines():
921
os.remove('/var/log/corosync.log')
923
if self.autogen_corosync_cfg:
924
os.system("rm -f /etc/corosync/corosync.conf")
926
os.system("rm -f /usr/sbin/fence_dummy_metadata_helper")
927
os.system("rm -f /usr/sbin/fence_dummy_monitor_fail")
932
self.options['list-tests'] = 0
933
self.options['run-all'] = 1
934
self.options['run-only'] = ""
935
self.options['run-only-pattern'] = ""
936
self.options['verbose'] = 0
937
self.options['invalid-arg'] = ""
938
self.options['cpg-only'] = 0
939
self.options['no-cpg'] = 0
940
self.options['show-usage'] = 0
942
def build_options(self, argv):
945
for i in range(0, len(args)):
949
elif args[i] == "-h" or args[i] == "--help":
950
self.options['show-usage'] = 1
951
elif args[i] == "-l" or args[i] == "--list-tests":
952
self.options['list-tests'] = 1
953
elif args[i] == "-V" or args[i] == "--verbose":
954
self.options['verbose'] = 1
955
elif args[i] == "-n" or args[i] == "--no-cpg":
956
self.options['no-cpg'] = 1
957
elif args[i] == "-c" or args[i] == "--cpg-only":
958
self.options['cpg-only'] = 1
959
elif args[i] == "-r" or args[i] == "--run-only":
960
self.options['run-only'] = args[i+1]
962
elif args[i] == "-p" or args[i] == "--run-only-pattern":
963
self.options['run-only-pattern'] = args[i+1]
966
def show_usage(self):
967
print "usage: " + sys.argv[0] + " [options]"
968
print "If no options are provided, all tests will run"
970
print "\t [--help | -h] Show usage"
971
print "\t [--list-tests | -l] Print out all registered tests."
972
print "\t [--cpg-only | -c] Only run tests that require corosync."
973
print "\t [--no-cpg | -n] Only run tests that do not require corosync"
974
print "\t [--run-only | -r 'testname'] Run a specific test"
975
print "\t [--verbose | -V] Verbose output"
976
print "\t [--run-only-pattern | -p 'string'] Run only tests containing the string value"
977
print "\n\tExample: Run only the test 'start_top'"
978
print "\t\t python ./regression.py --run-only start_stop"
979
print "\n\tExample: Run only the tests with the string 'systemd' present in them"
980
print "\t\t python ./regression.py --run-only-pattern systemd"
984
o.build_options(argv)
988
tests = Tests(o.options['verbose'])
989
tests.build_standalone_tests()
990
tests.build_custom_timeout_tests()
991
tests.build_api_sanity_tests()
992
tests.build_fence_merge_tests()
993
tests.build_unfence_tests()
994
tests.build_nodeid_tests()
996
if o.options['list-tests']:
999
elif o.options['show-usage']:
1003
print "Starting ..."
1005
if o.options['no-cpg']:
1008
tests.setup_environment(use_corosync)
1010
if o.options['run-only-pattern'] != "":
1011
tests.run_tests_matching(o.options['run-only-pattern'])
1012
tests.print_results()
1013
elif o.options['run-only'] != "":
1014
tests.run_single(o.options['run-only'])
1015
tests.print_results()
1016
elif o.options['no-cpg']:
1018
tests.print_results()
1019
elif o.options['cpg-only']:
1020
tests.run_cpg_only()
1021
tests.print_results()
1024
tests.print_results()
1026
tests.cleanup_environment(use_corosync)
1028
if __name__=="__main__":