1 /*
2 Copyright (c) 2003, 2021, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25
26 #ifdef _WIN32
27 #define DEFAULT_PREFIX "c:/atrt"
28 #endif
29
30 #include "atrt.hpp"
31 #include <NdbOut.hpp>
32 #include <NdbAutoPtr.hpp>
33
34 #include <SysLogHandler.hpp>
35 #include <FileLogHandler.hpp>
36
37 #include <NdbSleep.h>
38
39 #define PATH_SEPARATOR DIR_SEPARATOR
40
41 /** Global variables */
42 static const char progname[] = "ndb_atrt";
43 static const char * g_gather_progname = "atrt-gather-result.sh";
44 static const char * g_analyze_progname = "atrt-analyze-result.sh";
45 static const char * g_setup_progname = "atrt-setup.sh";
46
47 static const char * g_log_filename = 0;
48 static const char * g_test_case_filename = 0;
49 static const char * g_report_filename = 0;
50
51 static int g_do_setup = 0;
52 static int g_do_deploy = 0;
53 static int g_do_sshx = 0;
54 static int g_do_start = 0;
55 static int g_do_quit = 0;
56
57 static int g_help = 0;
58 static int g_verbosity = 1;
59 static FILE * g_report_file = 0;
60 static FILE * g_test_case_file = stdin;
61 static int g_mode = 0;
62
63 Logger g_logger;
64 atrt_config g_config;
65 const char * g_user = 0;
66 int g_baseport = 10000;
67 int g_fqpn = 0;
68 int g_fix_nodeid= 0;
69 int g_default_ports = 0;
70 int g_mt = 0;
71 int g_mt_rr = 0;
72 int g_restart = 0;
73
74 const char * g_cwd = 0;
75 const char * g_basedir = 0;
76 const char * g_my_cnf = 0;
77 const char * g_prefix = 0;
78 const char * g_prefix1 = 0;
79 const char * g_clusters = 0;
80 BaseString g_replicate;
81 const char *save_file = 0;
82 const char *save_group_suffix = 0;
83 const char * g_dummy;
84 char * g_env_path = 0;
85 const char* g_mysqld_host = 0;
86
87 const char * g_ndb_mgmd_bin_path = 0;
88 const char * g_ndbd_bin_path = 0;
89 const char * g_ndbmtd_bin_path = 0;
90 const char * g_mysqld_bin_path = 0;
91 const char * g_mysql_install_db_bin_path = 0;
92 const char * g_libmysqlclient_so_path = 0;
93
94 static struct
95 {
96 bool is_required;
97 const char * exe;
98 const char ** var;
99 } g_binaries[] = {
100 { true, "ndb_mgmd", &g_ndb_mgmd_bin_path},
101 { true, "ndbd", &g_ndbd_bin_path },
102 { false, "ndbmtd", &g_ndbmtd_bin_path },
103 { true, "mysqld", &g_mysqld_bin_path },
104 { true, "mysql_install_db", &g_mysql_install_db_bin_path },
105 #if defined(__MACH__)
106 { true, "libmysqlclient.dylib", &g_libmysqlclient_so_path },
107 #else
108 { true, "libmysqlclient.so", &g_libmysqlclient_so_path },
109 #endif
110 { true, 0, 0 }
111 };
112
113 const char *
114 g_search_path[] =
115 {
116 "bin",
117 "libexec",
118 "sbin",
119 "scripts",
120 "lib",
121 "lib/mysql",
122 0
123 };
124 static bool find_binaries();
125
126 static struct my_option g_options[] =
127 {
128 { "help", '?', "Display this help and exit.",
129 (uchar **) &g_help, (uchar **) &g_help,
130 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
131 { "version", 'V', "Output version information and exit.", 0, 0, 0,
132 GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
133 { "clusters", 256, "Cluster",
134 (uchar **) &g_clusters, (uchar **) &g_clusters,
135 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
136 { "mysqld", 256, "atrt mysqld",
137 (uchar **) &g_mysqld_host, (uchar **) &g_mysqld_host,
138 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
139 { "replicate", 1024, "replicate",
140 (uchar **) &g_dummy, (uchar **) &g_dummy,
141 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
142 { "log-file", 256, "log-file",
143 (uchar **) &g_log_filename, (uchar **) &g_log_filename,
144 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
145 { "testcase-file", 'f', "testcase-file",
146 (uchar **) &g_test_case_filename, (uchar **) &g_test_case_filename,
147 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
148 { "report-file", 'r', "report-file",
149 (uchar **) &g_report_filename, (uchar **) &g_report_filename,
150 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
151 { "basedir", 256, "Base path",
152 (uchar **) &g_basedir, (uchar **) &g_basedir,
153 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
154 { "baseport", 256, "Base port",
155 (uchar **) &g_baseport, (uchar **) &g_baseport,
156 0, GET_INT, REQUIRED_ARG, g_baseport, 0, 0, 0, 0, 0},
157 { "prefix", 256, "mysql install dir",
158 (uchar **) &g_prefix, (uchar **) &g_prefix,
159 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
160 { "prefix1", 256, "mysql install dir 1",
161 (uchar **) &g_prefix1, (uchar **) &g_prefix1,
162 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
163 { "verbose", 'v', "Verbosity",
164 (uchar **) &g_verbosity, (uchar **) &g_verbosity,
165 0, GET_INT, REQUIRED_ARG, g_verbosity, 0, 0, 0, 0, 0},
166 { "configure", 256, "configure",
167 (uchar **) &g_do_setup, (uchar **) &g_do_setup,
168 0, GET_INT, REQUIRED_ARG, g_do_setup, 0, 0, 0, 0, 0 },
169 { "deploy", 256, "deploy",
170 (uchar **) &g_do_deploy, (uchar **) &g_do_deploy,
171 0, GET_INT, REQUIRED_ARG, g_do_deploy, 0, 0, 0, 0, 0 },
172 { "sshx", 256, "sshx",
173 (uchar **) &g_do_sshx, (uchar **) &g_do_sshx,
174 0, GET_INT, REQUIRED_ARG, g_do_sshx, 0, 0, 0, 0, 0 },
175 { "start", 256, "start",
176 (uchar **) &g_do_start, (uchar **) &g_do_start,
177 0, GET_INT, REQUIRED_ARG, g_do_start, 0, 0, 0, 0, 0 },
178 { "fqpn", 256, "Fully qualified path-names ",
179 (uchar **) &g_fqpn, (uchar **) &g_fqpn,
180 0, GET_INT, REQUIRED_ARG, g_fqpn, 0, 0, 0, 0, 0 },
181 { "fix-nodeid", 256, "Fix nodeid for each started process ",
182 (uchar **) &g_fix_nodeid, (uchar **) &g_fix_nodeid,
183 0, GET_INT, REQUIRED_ARG, g_fqpn, 0, 0, 0, 0, 0 },
184 { "default-ports", 256, "Use default ports when possible",
185 (uchar **) &g_default_ports, (uchar **) &g_default_ports,
186 0, GET_INT, REQUIRED_ARG, g_default_ports, 0, 0, 0, 0, 0 },
187 { "mode", 256, "Mode 0=interactive 1=regression 2=bench",
188 (uchar **) &g_mode, (uchar **) &g_mode,
189 0, GET_INT, REQUIRED_ARG, g_mode, 0, 0, 0, 0, 0 },
190 { "quit", 256, "Quit before starting tests",
191 (uchar **) &g_do_quit, (uchar **) &g_do_quit,
192 0, GET_BOOL, NO_ARG, g_do_quit, 0, 0, 0, 0, 0 },
193 { "mt", 256, "Use ndbmtd (0 = never, 1 = round-robin, 2 = only)",
194 (uchar **) &g_mt, (uchar **) &g_mt,
195 0, GET_INT, REQUIRED_ARG, g_mt, 0, 0, 0, 0, 0 },
196 { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
197 };
198
199 const int p_ndb = atrt_process::AP_NDB_MGMD | atrt_process::AP_NDBD;
200 const int p_servers = atrt_process::AP_MYSQLD;
201 const int p_clients = atrt_process::AP_CLIENT | atrt_process::AP_NDB_API;
202
203 static int check_testcase_file_main(int argc, char ** argv);
204 static void print_testcase_file_syntax();
205
206 int
main(int argc,char ** argv)207 main(int argc, char ** argv)
208 {
209 // If program is called with --check-testcase-files as first option
210 // it is assumed that the rest of command line arguments are
211 // testcase-filenames and those files will be syntax checked.
212 if (argc >= 2 && strcmp(argv[1], "--check-testcase-files") == 0)
213 {
214 exit(check_testcase_file_main(argc, argv));
215 }
216
217 ndb_init();
218
219 bool restart = true;
220 int lineno = 1;
221 int test_no = 1;
222 int return_code = 1;
223
224 g_logger.setCategory(progname);
225 g_logger.enable(Logger::LL_ALL);
226 g_logger.createConsoleHandler();
227
228 if(!parse_args(argc, argv))
229 {
230 g_logger.critical("Failed to parse arguments");
231 goto end;
232 }
233
234 g_logger.info("Starting...");
235
236 if (!find_binaries())
237 {
238 goto end;
239 }
240
241 g_config.m_generated = false;
242 g_config.m_replication = g_replicate;
243 if (!setup_config(g_config, g_mysqld_host))
244 {
245 g_logger.critical("Failed to setup configuration");
246 goto end;
247 }
248
249 if (!configure(g_config, g_do_setup))
250 {
251 g_logger.critical("Failed to configure");
252 goto end;
253 }
254
255 g_logger.info("Setting up directories...");
256 if (!setup_directories(g_config, g_do_setup))
257 {
258 g_logger.critical("Failed to set up directories");
259 goto end;
260 }
261
262 if (g_do_setup)
263 {
264 g_logger.info("Setting up files...");
265 if (!setup_files(g_config, g_do_setup, g_do_sshx))
266 {
267 g_logger.critical("Failed to set up files");
268 goto end;
269 }
270 }
271
272 if (g_do_deploy)
273 {
274 if (!deploy(g_do_deploy, g_config))
275 {
276 g_logger.critical("Failed to deploy");
277 goto end;
278 }
279 }
280
281 if (g_do_quit)
282 {
283 return_code = 0;
284 goto end;
285 }
286
287 if(!setup_hosts(g_config))
288 {
289 g_logger.critical("Failed to setup hosts");
290 goto end;
291 }
292
293 if (g_do_sshx)
294 {
295 g_logger.info("Starting xterm-ssh");
296 if (!sshx(g_config, g_do_sshx))
297 {
298 g_logger.critical("Failed to start xterm-ssh");
299 goto end;
300 }
301
302 g_logger.info("Done...sleeping");
303 while(true)
304 {
305 if (!do_command(g_config))
306 {
307 g_logger.critical("Failed to do ssh command");
308 goto end;
309 }
310
311 NdbSleep_SecSleep(1);
312 }
313 return_code = 0;
314 goto end;
315 }
316
317 g_logger.info("Connecting to hosts...");
318 if(!connect_hosts(g_config))
319 {
320 g_logger.critical("Failed to connect to CPCD on hosts");
321 goto end;
322 }
323
324 #ifndef _WIN32
325 if (g_do_start && !g_test_case_filename)
326 {
327 g_logger.info("Starting server processes: %x", g_do_start);
328 if (!start(g_config, g_do_start))
329 {
330 g_logger.critical("Failed to start server processes");
331 goto end;
332 }
333
334 if (!setup_db(g_config))
335 {
336 g_logger.critical("Failed to setup database");
337 goto end;
338 }
339
340 g_logger.info("Done...sleeping");
341 while(true)
342 {
343 if (!do_command(g_config))
344 {
345 g_logger.info("Exiting");
346 goto end;
347 }
348
349 NdbSleep_SecSleep(1);
350 }
351 return_code = 0;
352 goto end;
353 }
354 #endif
355
356 /**
357 * Main loop
358 */
359 g_logger.debug("Entering main loop");
360 while(!feof(g_test_case_file))
361 {
362 /**
363 * Do we need to restart ndb
364 */
365 if(restart)
366 {
367 restart = false;
368 g_logger.info("(Re)starting server processes...");
369
370 if(!stop_processes(g_config, ~0))
371 {
372 g_logger.critical("Failed to stop all processes");
373 goto end;
374 }
375
376 if (!setup_directories(g_config, 2))
377 {
378 g_logger.critical("Failed to setup directories");
379 goto end;
380 }
381
382 if (!setup_files(g_config, 2, 1))
383 {
384 g_logger.critical("Failed to setup files");
385 goto end;
386 }
387
388 if(!setup_hosts(g_config))
389 {
390 g_logger.critical("Failed to setup hosts");
391 goto end;
392 }
393
394 g_logger.debug("Setup complete, starting servers");
395 if (!start(g_config, p_ndb | p_servers))
396 {
397 g_logger.critical("Failed to start server processes");
398 g_logger.info("Gathering logs and saving them as test %u", test_no);
399
400 int tmp;
401 if(!gather_result(g_config, &tmp))
402 {
403 g_logger.critical("Failed to gather results");
404 goto end;
405 }
406
407 if(g_report_file != 0)
408 {
409 fprintf(g_report_file, "%s ; %d ; %d ; %d\n",
410 "start servers", test_no, ERR_FAILED_TO_START, 0);
411 fflush(g_report_file);
412 }
413
414 BaseString resdir;
415 resdir.assfmt("result.%d", test_no);
416 remove_dir(resdir.c_str(), true);
417
418 if(rename("result", resdir.c_str()) != 0)
419 {
420 g_logger.critical("Failed to rename %s as %s",
421 "result", resdir.c_str());
422 goto end;
423 }
424 goto end;
425 }
426
427 if (!setup_db(g_config))
428 {
429 g_logger.critical("Failed to setup database");
430 goto end;
431 }
432
433 g_logger.info("All servers start completed");
434 }
435
436 // const int start_line = lineno;
437 atrt_testcase test_case;
438 if(!read_test_case(g_test_case_file, test_case, lineno))
439 {
440 g_logger.critical("Corrupt testcase at line %d)", lineno);
441 goto end;
442
443 }
444 g_logger.info("#%d - %s",
445 test_no,
446 test_case.m_name.c_str());
447
448 // Assign processes to programs
449 if (!setup_test_case(g_config, test_case))
450 {
451 g_logger.critical("Failed to setup test case");
452 goto end;
453 }
454
455 if(!start_processes(g_config, p_clients))
456 {
457 g_logger.critical("Failed to start client processes");
458 goto end;
459 }
460
461 int result = 0;
462
463 const time_t start = time(0);
464 time_t now = start;
465 do
466 {
467 if(!update_status(g_config, atrt_process::AP_ALL))
468 {
469 g_logger.critical("Failed to get updated status for all processes");
470 goto end;
471 }
472
473 if(is_running(g_config, p_ndb) != 2)
474 {
475 result = ERR_NDB_FAILED;
476 break;
477 }
478
479 if(is_running(g_config, p_servers) != 2)
480 {
481 result = ERR_SERVERS_FAILED;
482 break;
483 }
484
485 if(is_running(g_config, p_clients) == 0)
486 {
487 break;
488 }
489
490 if (!do_command(g_config))
491 {
492 result = ERR_COMMAND_FAILED;
493 break;
494 }
495
496 now = time(0);
497 if(now > (start + test_case.m_max_time))
498 {
499 g_logger.debug("Timed out");
500 result = ERR_MAX_TIME_ELAPSED;
501 g_logger.info("Timeout '%s' after %ld seconds", test_case.m_name.c_str(), test_case.m_max_time);
502 break;
503 }
504 NdbSleep_SecSleep(1);
505 } while(true);
506
507 const time_t elapsed = time(0) - start;
508
509 if(!stop_processes(g_config, p_clients))
510 {
511 g_logger.critical("Failed to stop client processes");
512 goto end;
513 }
514
515 int tmp, *rp = result ? &tmp : &result;
516 if(!gather_result(g_config, rp))
517 {
518 g_logger.critical("Failed to gather result after test run");
519 goto end;
520 }
521
522 g_logger.info("#%d %s(%d)",
523 test_no,
524 (result == 0 ? "OK" : "FAILED"), result);
525
526 if(g_report_file != 0)
527 {
528 fprintf(g_report_file, "%s ; %d ; %d ; %ld\n",
529 test_case.m_name.c_str(), test_no, result, elapsed);
530 fflush(g_report_file);
531 }
532
533 if(g_mode == 0 && result)
534 {
535 g_logger.info
536 ("Encountered failed test in interactive mode - terminating");
537 break;
538 }
539
540 BaseString resdir;
541 resdir.assfmt("result.%d", test_no);
542 remove_dir(resdir.c_str(), true);
543
544 if(test_case.m_report || g_mode == 2 || (g_mode && result))
545 {
546 if(rename("result", resdir.c_str()) != 0)
547 {
548 g_logger.critical("Failed to rename %s as %s",
549 "result", resdir.c_str());
550 goto end;
551 }
552 }
553 else
554 {
555 remove_dir("result", true);
556 }
557
558 if (reset_config(g_config))
559 {
560 restart = true;
561 }
562
563 if(result != 0)
564 {
565 restart = true;
566 }
567 test_no++;
568 }
569 return_code = 0;
570
571 end:
572 if(return_code != 0 && g_report_file != 0)
573 {
574 fprintf(g_report_file, "%s ; %d ; %d ; %d\n",
575 "critical error", test_no, ERR_FAILED_TO_START, 0);
576 fflush(g_report_file);
577 }
578 if(g_report_file != 0){
579 fclose(g_report_file);
580 g_report_file = 0;
581 }
582
583 if(g_test_case_file != 0 && g_test_case_file != stdin){
584 fclose(g_test_case_file);
585 g_test_case_file = 0;
586 }
587
588 g_logger.info("Stopping all processes, result: %d", return_code);
589 stop_processes(g_config, atrt_process::AP_ALL);
590 return return_code;
591 }
592
593 extern "C"
594 my_bool
get_one_option(int arg,const struct my_option * opt,char * value)595 get_one_option(int arg, const struct my_option * opt, char * value)
596 {
597 if (arg == 1024)
598 {
599 if (g_replicate.length())
600 g_replicate.append(";");
601 g_replicate.append(value);
602 return 0;
603 }
604 return 0;
605 }
606
607 bool
parse_args(int argc,char ** argv)608 parse_args(int argc, char** argv)
609 {
610 bool fail_after_help = false;
611 char buf[2048];
612 if (getcwd(buf, sizeof(buf)) == 0)
613 {
614 g_logger.error("Unable to get current working directory");
615 return false;
616 }
617 g_cwd = strdup(buf);
618
619 struct stat sbuf;
620 BaseString mycnf;
621 mycnf.append(g_cwd);
622 mycnf.append(DIR_SEPARATOR);
623
624 if (argc > 1 && lstat(argv[argc-1], &sbuf) == 0)
625 {
626 mycnf.append(argv[argc-1]);
627 }
628 else
629 {
630 mycnf.append("my.cnf");
631 if (lstat(mycnf.c_str(), &sbuf) != 0)
632 {
633 g_logger.error("Could not find out which config file to use! "
634 "Pass it as last argument to atrt: 'atrt <config file>' "
635 "(default: '%s')", mycnf.c_str());
636 fail_after_help = true;
637 }
638 }
639
640 to_fwd_slashes((char*)g_cwd);
641
642 g_logger.info("Bootstrapping using %s", mycnf.c_str());
643
644 const char *groups[] = { "atrt", 0 };
645 int ret = load_defaults(mycnf.c_str(), groups, &argc, &argv);
646
647 if (ret)
648 {
649 g_logger.error("Failed to load defaults, returned (%d)",ret);
650 return false;
651 }
652
653 save_file = my_defaults_file;
654 save_group_suffix = my_defaults_group_suffix;
655
656 if (my_defaults_extra_file)
657 {
658 g_logger.error("--defaults-extra-file(%s) is not supported...",
659 my_defaults_extra_file);
660 return false;
661 }
662
663 ret = handle_options(&argc, &argv, g_options, get_one_option);
664 if (ret)
665 {
666 g_logger.error("handle_options failed, ret: %d, argc: %d, *argv: '%s'",
667 ret, argc, *argv);
668 return false;
669 }
670
671 if (argc >= 2)
672 {
673 const char * arg = argv[argc-2];
674 while(* arg)
675 {
676 switch(* arg){
677 case 'c':
678 g_do_setup = (g_do_setup == 0) ? 1 : g_do_setup;
679 break;
680 case 'C':
681 g_do_setup = 2;
682 break;
683 case 'd':
684 g_do_deploy = 3;
685 break;
686 case 'D':
687 g_do_deploy = 2; // only binaries
688 break;
689 case 'x':
690 g_do_sshx = atrt_process::AP_CLIENT | atrt_process::AP_NDB_API;
691 break;
692 case 'X':
693 g_do_sshx = atrt_process::AP_ALL;
694 break;
695 case 's':
696 g_do_start = p_ndb;
697 break;
698 case 'S':
699 g_do_start = p_ndb | p_servers;
700 break;
701 case 'f':
702 g_fqpn = 1;
703 break;
704 case 'z':
705 g_fix_nodeid = 1;
706 break;
707 case 'q':
708 g_do_quit = 1;
709 break;
710 case 'r':
711 g_restart = 1;
712 break;
713 default:
714 g_logger.error("Unknown switch '%c'", *arg);
715 return false;
716 }
717 arg++;
718 }
719 }
720
721 if(g_log_filename != 0)
722 {
723 g_logger.removeConsoleHandler();
724 g_logger.addHandler(new FileLogHandler(g_log_filename));
725 }
726
727 {
728 int tmp = Logger::LL_WARNING - g_verbosity;
729 tmp = (tmp < Logger::LL_DEBUG ? Logger::LL_DEBUG : tmp);
730 g_logger.disable(Logger::LL_ALL);
731 g_logger.enable(Logger::LL_ON);
732 g_logger.enable((Logger::LoggerLevel)tmp, Logger::LL_ALERT);
733 }
734
735 if(!g_basedir)
736 {
737 g_basedir = g_cwd;
738 g_logger.info("basedir not specified, using %s", g_basedir);
739 }
740 else
741 {
742 g_logger.info("basedir, %s", g_basedir);
743 }
744
745 if (!g_prefix)
746 {
747 g_prefix = DEFAULT_PREFIX;
748 }
749
750 /**
751 * Add path to atrt-*.sh
752 */
753 {
754 BaseString tmp;
755 const char* env = getenv("PATH");
756 if (env && strlen(env))
757 {
758 tmp.assfmt("PATH=%s:%s/mysql-test/ndb",
759 env, g_prefix);
760 }
761 else
762 {
763 tmp.assfmt("PATH=%s/mysql-test/ndb", g_prefix);
764 }
765 to_native(tmp);
766 g_env_path = strdup(tmp.c_str());
767 putenv(g_env_path);
768 }
769
770 if (g_help)
771 {
772 my_print_help(g_options);
773 my_print_variables(g_options);
774 print_testcase_file_syntax();
775 return 0;
776 }
777 if (fail_after_help)
778 {
779 return false;
780 }
781
782 if(g_test_case_filename)
783 {
784 g_test_case_file = fopen(g_test_case_filename, "r");
785 if(g_test_case_file == 0)
786 {
787 g_logger.critical("Unable to open file: %s", g_test_case_filename);
788 return false;
789 }
790 if (g_do_setup == 0)
791 g_do_setup = 2;
792
793 if (g_do_start == 0)
794 g_do_start = p_ndb | p_servers;
795
796 if (g_mode == 0)
797 g_mode = 1;
798
799 if (g_do_sshx)
800 {
801 g_logger.critical("ssx specified...not possible with testfile");
802 return false;
803 }
804 }
805 else {
806 g_logger.info("No test case file given with -f <test file>, "
807 "running in interactive mode from stdin");
808 }
809
810 if (g_do_setup == 0)
811 {
812 BaseString tmp;
813 tmp.append(g_basedir);
814 tmp.append(PATH_SEPARATOR);
815 tmp.append("my.cnf");
816 if (lstat(tmp.c_str(), &sbuf) != 0)
817 {
818 g_logger.error("Could not find a my.cnf file in the basedir '%s', "
819 "you probably need to configure it with "
820 "'atrt --configure=1 <config_file>'", g_basedir);
821 return false;
822 }
823
824 if (!S_ISREG(sbuf.st_mode))
825 {
826 g_logger.error("%s is not a regular file", tmp.c_str());
827 return false;
828 }
829
830 g_my_cnf = strdup(tmp.c_str());
831 g_logger.info("Using %s", tmp.c_str());
832 }
833 else
834 {
835 g_my_cnf = strdup(mycnf.c_str());
836 }
837
838 g_logger.info("Using --prefix=\"%s\"", g_prefix);
839
840 if (g_prefix1)
841 {
842 g_logger.info("Using --prefix1=\"%s\"", g_prefix1);
843 }
844
845
846
847 if(g_report_filename)
848 {
849 g_report_file = fopen(g_report_filename, "w");
850 if(g_report_file == 0)
851 {
852 g_logger.critical("Unable to create report file: %s", g_report_filename);
853 return false;
854 }
855 }
856
857 if (g_clusters == 0)
858 {
859 g_logger.critical("No clusters specified");
860 return false;
861 }
862
863 /* Read username from environment, default to sakila */
864 g_user = strdup(getenv("LOGNAME"));
865 if (g_user == 0)
866 {
867 g_user = "sakila";
868 g_logger.info("No default user specified, will use 'sakila'.");
869 g_logger.info("Please set LOGNAME environment variable for other username");
870 }
871 return true;
872 }
873
874 bool
connect_hosts(atrt_config & config)875 connect_hosts(atrt_config& config){
876 for(unsigned i = 0; i<config.m_hosts.size(); i++)
877 {
878 if (config.m_hosts[i]->m_hostname.length() == 0)
879 continue;
880
881 if(config.m_hosts[i]->m_cpcd->connect() != 0){
882 g_logger.error("Unable to connect to cpc %s:%d",
883 config.m_hosts[i]->m_cpcd->getHost(),
884 config.m_hosts[i]->m_cpcd->getPort());
885 return false;
886 }
887 g_logger.debug("Connected to %s:%d",
888 config.m_hosts[i]->m_cpcd->getHost(),
889 config.m_hosts[i]->m_cpcd->getPort());
890 }
891
892 return true;
893 }
894
895 bool
connect_ndb_mgm(atrt_process & proc)896 connect_ndb_mgm(atrt_process & proc){
897 NdbMgmHandle handle = ndb_mgm_create_handle();
898 if(handle == 0){
899 g_logger.critical("Unable to create mgm handle");
900 return false;
901 }
902 BaseString tmp = proc.m_host->m_hostname;
903 const char * val;
904 proc.m_options.m_loaded.get("--PortNumber=", &val);
905 tmp.appfmt(":%s", val);
906
907 if (ndb_mgm_set_connectstring(handle,tmp.c_str()))
908 {
909 g_logger.critical("Unable to create parse connectstring");
910 return false;
911 }
912
913 if(ndb_mgm_connect(handle, 30, 1, 0) != -1)
914 {
915 proc.m_ndb_mgm_handle = handle;
916 return true;
917 }
918
919 g_logger.critical("Unable to connect to ndb mgm %s", tmp.c_str());
920 return false;
921 }
922
923 bool
connect_ndb_mgm(atrt_config & config)924 connect_ndb_mgm(atrt_config& config){
925 for(unsigned i = 0; i<config.m_processes.size(); i++){
926 atrt_process & proc = *config.m_processes[i];
927 if((proc.m_type & atrt_process::AP_NDB_MGMD) != 0){
928 if(!connect_ndb_mgm(proc)){
929 return false;
930 }
931 }
932 }
933
934 return true;
935 }
936
remap(int i)937 static int remap(int i){
938 if(i == NDB_MGM_NODE_STATUS_NO_CONTACT) return NDB_MGM_NODE_STATUS_UNKNOWN;
939 if(i == NDB_MGM_NODE_STATUS_UNKNOWN) return NDB_MGM_NODE_STATUS_NO_CONTACT;
940 return i;
941 }
942
943 bool
wait_ndb(atrt_config & config,int goal)944 wait_ndb(atrt_config& config, int goal){
945
946 goal = remap(goal);
947
948 size_t cnt = 0;
949 for (unsigned i = 0; i<config.m_clusters.size(); i++)
950 {
951 atrt_cluster* cluster = config.m_clusters[i];
952
953 if (strcmp(cluster->m_name.c_str(), ".atrt") == 0)
954 {
955 /**
956 * skip atrt mysql
957 */
958 cnt++;
959 continue;
960 }
961
962 /**
963 * Get mgm handle for cluster
964 */
965 NdbMgmHandle handle = 0;
966 for(unsigned j = 0; j<cluster->m_processes.size(); j++){
967 atrt_process & proc = *cluster->m_processes[j];
968 if((proc.m_type & atrt_process::AP_NDB_MGMD) != 0){
969 handle = proc.m_ndb_mgm_handle;
970 break;
971 }
972 }
973
974 if(handle == 0){
975 return true;
976 }
977
978 if(goal == NDB_MGM_NODE_STATUS_STARTED){
979 /**
980 * 1) wait NOT_STARTED
981 * 2) send start
982 * 3) wait STARTED
983 */
984 if(!wait_ndb(config, NDB_MGM_NODE_STATUS_NOT_STARTED))
985 return false;
986
987 ndb_mgm_start(handle, 0, 0);
988 }
989
990 struct ndb_mgm_cluster_state * state;
991
992 time_t now = time(0);
993 time_t end = now + 360;
994 int min = remap(NDB_MGM_NODE_STATUS_NO_CONTACT);
995 int min2 = goal;
996
997 while(now < end){
998 /**
999 * 1) retreive current state
1000 */
1001 state = 0;
1002 do {
1003 state = ndb_mgm_get_status(handle);
1004 if(state == 0){
1005 const int err = ndb_mgm_get_latest_error(handle);
1006 g_logger.error("Unable to poll db state: %d %s %s",
1007 ndb_mgm_get_latest_error(handle),
1008 ndb_mgm_get_latest_error_msg(handle),
1009 ndb_mgm_get_latest_error_desc(handle));
1010 if(err == NDB_MGM_SERVER_NOT_CONNECTED && connect_ndb_mgm(config)){
1011 g_logger.error("Reconnected...");
1012 continue;
1013 }
1014 return false;
1015 }
1016 } while(state == 0);
1017 NdbAutoPtr<void> tmp(state);
1018
1019 min2 = goal;
1020 for(int j = 0; j<state->no_of_nodes; j++){
1021 if(state->node_states[j].node_type == NDB_MGM_NODE_TYPE_NDB){
1022 const int s = remap(state->node_states[j].node_status);
1023 min2 = (min2 < s ? min2 : s );
1024
1025 if(s < remap(NDB_MGM_NODE_STATUS_NO_CONTACT) ||
1026 s > NDB_MGM_NODE_STATUS_STARTED){
1027 g_logger.critical("Strange DB status during start: %d %d",
1028 j, min2);
1029 return false;
1030 }
1031
1032 if(min2 < min){
1033 g_logger.critical("wait ndb failed node: %d %d %d %d",
1034 state->node_states[j].node_id, min, min2, goal);
1035 }
1036 }
1037 }
1038
1039 if(min2 < min){
1040 g_logger.critical("wait ndb failed %d %d %d", min, min2, goal);
1041 return false;
1042 }
1043
1044 if(min2 == goal){
1045 cnt++;
1046 goto next;
1047 }
1048
1049 min = min2;
1050 now = time(0);
1051 }
1052
1053 g_logger.critical("wait ndb timed out %d %d %d", min, min2, goal);
1054 break;
1055
1056 next:
1057 ;
1058 }
1059
1060 return cnt == config.m_clusters.size();
1061 }
1062
1063 bool
start_process(atrt_process & proc)1064 start_process(atrt_process & proc){
1065 if(proc.m_proc.m_id != -1){
1066 g_logger.critical("starting already started process: %u",
1067 (unsigned)proc.m_index);
1068 return false;
1069 }
1070
1071 BaseString tmp = g_setup_progname;
1072 tmp.appfmt(" %s %s/ %s",
1073 proc.m_host->m_hostname.c_str(),
1074 proc.m_proc.m_cwd.c_str(),
1075 proc.m_proc.m_cwd.c_str());
1076
1077 g_logger.debug("system(%s)", tmp.c_str());
1078 const int r1 = sh(tmp.c_str());
1079 if(r1 != 0)
1080 {
1081 g_logger.critical("Failed to setup process");
1082 return false;
1083 }
1084
1085 {
1086 Properties reply;
1087 if(proc.m_host->m_cpcd->define_process(proc.m_proc, reply) != 0){
1088 BaseString msg;
1089 reply.get("errormessage", msg);
1090 g_logger.error("Unable to define process: %s", msg.c_str());
1091 return false;
1092 }
1093 }
1094 {
1095 Properties reply;
1096 if(proc.m_host->m_cpcd->start_process(proc.m_proc.m_id, reply) != 0){
1097 BaseString msg;
1098 reply.get("errormessage", msg);
1099 g_logger.error("Unable to start process: %s", msg.c_str());
1100 return false;
1101 }
1102 }
1103 return true;
1104 }
1105
1106 bool
start_processes(atrt_config & config,int types)1107 start_processes(atrt_config& config, int types){
1108 for(unsigned i = 0; i<config.m_processes.size(); i++){
1109 atrt_process & proc = *config.m_processes[i];
1110 if(IF_WIN(!(proc.m_type & atrt_process::AP_MYSQLD), 1)
1111 && (types & proc.m_type) != 0 && proc.m_proc.m_path != ""){
1112 if(!start_process(proc)){
1113 return false;
1114 }
1115 }
1116 }
1117 return true;
1118 }
1119
1120 bool
stop_process(atrt_process & proc)1121 stop_process(atrt_process & proc){
1122 if(proc.m_proc.m_id == -1){
1123 return true;
1124 }
1125
1126 if (proc.m_type == atrt_process::AP_MYSQLD)
1127 {
1128 disconnect_mysqld(proc);
1129 }
1130
1131 {
1132 Properties reply;
1133 if(proc.m_host->m_cpcd->stop_process(proc.m_proc.m_id, reply) != 0){
1134 Uint32 status;
1135 reply.get("status", &status);
1136 if(status != 4){
1137 BaseString msg;
1138 reply.get("errormessage", msg);
1139 g_logger.error("Unable to stop process: %s(%d)", msg.c_str(), status);
1140 return false;
1141 }
1142 }
1143 }
1144 {
1145 Properties reply;
1146 if(proc.m_host->m_cpcd->undefine_process(proc.m_proc.m_id, reply) != 0){
1147 BaseString msg;
1148 reply.get("errormessage", msg);
1149 g_logger.error("Unable to undefine process: %s", msg.c_str());
1150 return false;
1151 }
1152 proc.m_proc.m_id = -1;
1153 }
1154 return true;
1155 }
1156
1157 bool
stop_processes(atrt_config & config,int types)1158 stop_processes(atrt_config& config, int types){
1159 for(unsigned i = 0; i<config.m_processes.size(); i++){
1160 atrt_process & proc = *config.m_processes[i];
1161 if((types & proc.m_type) != 0){
1162 if(!stop_process(proc)){
1163 return false;
1164 }
1165 }
1166 }
1167 return true;
1168 }
1169
1170 bool
update_status(atrt_config & config,int)1171 update_status(atrt_config& config, int){
1172
1173 Vector<Vector<SimpleCpcClient::Process> > m_procs;
1174
1175 Vector<SimpleCpcClient::Process> dummy;
1176 m_procs.fill(config.m_hosts.size(), dummy);
1177 for(unsigned i = 0; i<config.m_hosts.size(); i++)
1178 {
1179 if (config.m_hosts[i]->m_hostname.length() == 0)
1180 continue;
1181
1182 Properties p;
1183 config.m_hosts[i]->m_cpcd->list_processes(m_procs[i], p);
1184 }
1185
1186 for(unsigned i = 0; i<config.m_processes.size(); i++){
1187 atrt_process & proc = *config.m_processes[i];
1188 if(proc.m_proc.m_id != -1){
1189 Vector<SimpleCpcClient::Process> &h_procs= m_procs[proc.m_host->m_index];
1190 bool found = false;
1191 for(unsigned j = 0; j<h_procs.size(); j++){
1192 if(proc.m_proc.m_id == h_procs[j].m_id){
1193 found = true;
1194 proc.m_proc.m_status = h_procs[j].m_status;
1195 break;
1196 }
1197 }
1198 if(!found){
1199 g_logger.error("update_status: not found");
1200 g_logger.error("id: %d host: %s cmd: %s",
1201 proc.m_proc.m_id,
1202 proc.m_host->m_hostname.c_str(),
1203 proc.m_proc.m_path.c_str());
1204 for(unsigned j = 0; j<h_procs.size(); j++){
1205 g_logger.error("found: %d %s", h_procs[j].m_id,
1206 h_procs[j].m_path.c_str());
1207 }
1208 return false;
1209 }
1210 }
1211 }
1212 return true;
1213 }
1214
1215 int
is_running(atrt_config & config,int types)1216 is_running(atrt_config& config, int types){
1217 int found = 0, running = 0;
1218 for(unsigned i = 0; i<config.m_processes.size(); i++){
1219 atrt_process & proc = *config.m_processes[i];
1220 if((types & proc.m_type) != 0){
1221 found++;
1222 if(proc.m_proc.m_status == "running")
1223 running++;
1224 else {
1225 if(IF_WIN(proc.m_type & atrt_process::AP_MYSQLD, 0)) {
1226 running++;
1227 }
1228 }
1229 }
1230 }
1231
1232 if(found == running)
1233 return 2;
1234 if(running == 0)
1235 return 0;
1236 return 1;
1237 }
1238
1239
1240 int
insert(const char * pair,Properties & p)1241 insert(const char * pair, Properties & p){
1242 BaseString tmp(pair);
1243
1244 tmp.trim(" \t\n\r");
1245
1246 Vector<BaseString> split;
1247 tmp.split(split, ":=", 2);
1248
1249 if(split.size() != 2)
1250 return -1;
1251
1252 p.put(split[0].trim().c_str(), split[1].trim().c_str());
1253
1254 return 0;
1255 }
1256
1257 bool
read_test_case(FILE * file,atrt_testcase & tc,int & line)1258 read_test_case(FILE * file, atrt_testcase& tc, int& line){
1259
1260 Properties p;
1261 int elements = 0;
1262 char buf[1024];
1263
1264 while(!feof(file)){
1265 if (file == stdin)
1266 printf("atrt> ");
1267 if(!fgets(buf, 1024, file))
1268 break;
1269
1270 line++;
1271 BaseString tmp = buf;
1272
1273 if(tmp.length() > 0 && tmp.c_str()[0] == '#')
1274 continue;
1275
1276 if(insert(tmp.c_str(), p) != 0)
1277 break;
1278
1279 elements++;
1280 }
1281
1282 if(elements == 0){
1283 if(file == stdin){
1284 BaseString tmp(buf);
1285 tmp.trim(" \t\n\r");
1286 Vector<BaseString> split;
1287 tmp.split(split, " ", 2);
1288 tc.m_cmd.m_exe = split[0];
1289 if(split.size() == 2)
1290 tc.m_cmd.m_args = split[1];
1291 else
1292 tc.m_cmd.m_args = "";
1293 tc.m_max_time = 60000;
1294 return true;
1295 }
1296 return false;
1297 }
1298
1299 int used_elements = 0;
1300
1301 if(!p.get("cmd", tc.m_cmd.m_exe)){
1302 g_logger.critical("Invalid test file: cmd is missing near line: %d", line);
1303 return false;
1304 }
1305 used_elements ++;
1306
1307 if(!p.get("args", tc.m_cmd.m_args))
1308 tc.m_cmd.m_args = "";
1309 else
1310 used_elements ++;
1311
1312 const char * mt = 0;
1313 if(!p.get("max-time", &mt))
1314 tc.m_max_time = 60000;
1315 else
1316 {
1317 tc.m_max_time = atoi(mt);
1318 used_elements ++;
1319 }
1320
1321 if(p.get("type", &mt))
1322 {
1323 tc.m_report= (strcmp(mt, "bench") == 0);
1324 used_elements ++;
1325 }
1326 else
1327 tc.m_report= false;
1328
1329 if(p.get("run-all", &mt))
1330 {
1331 tc.m_run_all = (strcmp(mt, "yes") == 0);
1332 used_elements ++;
1333 }
1334 else
1335 tc.m_run_all= false;
1336
1337 const char * str;
1338 if (p.get("mysqld", &str))
1339 {
1340 tc.m_mysqld_options.assign(str);
1341 used_elements ++;
1342 }
1343 else
1344 {
1345 tc.m_mysqld_options.assign("");
1346 }
1347
1348 tc.m_cmd.m_cmd_type = atrt_process::AP_NDB_API;
1349 if (p.get("cmd-type", &str))
1350 {
1351 if (strcmp(str, "mysql") == 0)
1352 tc.m_cmd.m_cmd_type = atrt_process::AP_CLIENT;
1353 used_elements ++;
1354 }
1355
1356 if (!p.get("name", &mt))
1357 {
1358 tc.m_name.assfmt("%s %s",
1359 tc.m_cmd.m_exe.c_str(),
1360 tc.m_cmd.m_args.c_str());
1361 }
1362 else
1363 {
1364 tc.m_name.assign(mt);
1365 used_elements ++;
1366 }
1367
1368 if (used_elements != elements)
1369 {
1370 g_logger.critical("Invalid test file: unknown properties near line: %d", line);
1371 return false;
1372 }
1373
1374 return true;
1375 }
1376
1377 bool
setup_test_case(atrt_config & config,const atrt_testcase & tc)1378 setup_test_case(atrt_config& config, const atrt_testcase& tc){
1379
1380 if (!remove_dir("result", true))
1381 {
1382 g_logger.critical("setup_test_case: Failed to clear result");
1383 return false;
1384 }
1385
1386 for (unsigned i = 0; i<config.m_processes.size(); i++)
1387 {
1388 atrt_process & proc = *config.m_processes[i];
1389 if (proc.m_type == atrt_process::AP_NDB_API ||
1390 proc.m_type == atrt_process::AP_CLIENT)
1391 {
1392 proc.m_proc.m_path.assign("");
1393 proc.m_proc.m_args.assign("");
1394 }
1395 }
1396
1397 BaseString cmd;
1398 char * p = find_bin_path(tc.m_cmd.m_exe.c_str());
1399 if (p == 0)
1400 {
1401 g_logger.critical("Failed to locate '%s'", tc.m_cmd.m_exe.c_str());
1402 return false;
1403 }
1404 cmd.assign(p);
1405 free(p);
1406
1407 for (unsigned i = 0; i<config.m_processes.size(); i++)
1408 {
1409 atrt_process & proc = *config.m_processes[i];
1410 if (proc.m_type == tc.m_cmd.m_cmd_type &&
1411 proc.m_proc.m_path == "")
1412 {
1413 proc.m_save.m_proc = proc.m_proc;
1414 proc.m_save.m_saved = true;
1415
1416 proc.m_proc.m_env.appfmt(" ATRT_TIMEOUT=%ld", tc.m_max_time);
1417 if (0) // valgrind
1418 {
1419 proc.m_proc.m_path = "/usr/bin/valgrind";
1420 proc.m_proc.m_args.appfmt("%s %s", cmd.c_str(),
1421 tc.m_cmd.m_args.c_str());
1422 }
1423 else
1424 {
1425 proc.m_proc.m_path = cmd;
1426 proc.m_proc.m_args.assign(tc.m_cmd.m_args.c_str());
1427 }
1428 if (!tc.m_run_all)
1429 break;
1430 }
1431 }
1432
1433 if (tc.m_mysqld_options != "")
1434 {
1435 g_logger.info("restarting mysqld with extra options: %s",
1436 tc.m_mysqld_options.c_str());
1437
1438 /**
1439 * Apply testcase specific mysqld options
1440 */
1441 for (unsigned i = 0; i<config.m_processes.size(); i++)
1442 {
1443 atrt_process & proc = *config.m_processes[i];
1444 if (proc.m_type == atrt_process::AP_MYSQLD)
1445 {
1446 proc.m_save.m_proc = proc.m_proc;
1447 proc.m_save.m_saved = true;
1448 proc.m_proc.m_args.appfmt(" %s", tc.m_mysqld_options.c_str());
1449 if (!stop_process(proc))
1450 {
1451 return false;
1452 }
1453
1454 if (!start_process(proc))
1455 {
1456 return false;
1457 }
1458
1459 if (!connect_mysqld(proc))
1460 {
1461 return false;
1462 }
1463 }
1464 }
1465 }
1466
1467 return true;
1468 }
1469
1470 bool
gather_result(atrt_config & config,int * result)1471 gather_result(atrt_config& config, int * result){
1472 BaseString tmp = g_gather_progname;
1473
1474 for(unsigned i = 0; i<config.m_hosts.size(); i++)
1475 {
1476 if (config.m_hosts[i]->m_hostname.length() == 0)
1477 continue;
1478
1479 tmp.appfmt(" %s:%s/*",
1480 config.m_hosts[i]->m_hostname.c_str(),
1481 config.m_hosts[i]->m_basedir.c_str());
1482 }
1483
1484 g_logger.debug("system(%s)", tmp.c_str());
1485 const int r1 = sh(tmp.c_str());
1486 if(r1 != 0)
1487 {
1488 g_logger.critical("Failed to gather result!");
1489 return false;
1490 }
1491
1492 g_logger.debug("system(%s)", g_analyze_progname);
1493 const int r2 = sh(g_analyze_progname);
1494
1495 if(r2 == -1 || r2 == (127 << 8))
1496 {
1497 g_logger.critical("Failed to analyze results");
1498 return false;
1499 }
1500
1501 * result = r2 ;
1502 return true;
1503 }
1504
1505 bool
setup_hosts(atrt_config & config)1506 setup_hosts(atrt_config& config){
1507 if (!remove_dir("result", true))
1508 {
1509 g_logger.critical("setup_hosts: Failed to clear result");
1510 return false;
1511 }
1512
1513 for(unsigned i = 0; i<config.m_hosts.size(); i++)
1514 {
1515 if (config.m_hosts[i]->m_hostname.length() == 0)
1516 continue;
1517 BaseString tmp = g_setup_progname;
1518 tmp.appfmt(" %s %s/ %s/",
1519 config.m_hosts[i]->m_hostname.c_str(),
1520 g_basedir,
1521 config.m_hosts[i]->m_basedir.c_str());
1522
1523 g_logger.debug("system(%s)", tmp.c_str());
1524 const int r1 = sh(tmp.c_str());
1525 if(r1 != 0){
1526 g_logger.critical("Failed to setup %s",
1527 config.m_hosts[i]->m_hostname.c_str());
1528 return false;
1529 }
1530 }
1531 return true;
1532 }
1533
1534 static
1535 bool
do_rsync(const char * dir,const char * dst)1536 do_rsync(const char *dir, const char *dst)
1537 {
1538 BaseString tmp = g_setup_progname;
1539 tmp.appfmt(" %s %s/ %s", dst, dir, dir);
1540
1541 g_logger.info("rsyncing %s to %s", dir, dst);
1542 g_logger.debug("system(%s)", tmp.c_str());
1543 const int r1 = sh(tmp.c_str());
1544 if(r1 != 0)
1545 {
1546 g_logger.critical("Failed to rsync %s to %s", dir, dst);
1547 return false;
1548 }
1549
1550 return true;
1551 }
1552
1553 bool
deploy(int d,atrt_config & config)1554 deploy(int d, atrt_config & config)
1555 {
1556 for (unsigned i = 0; i<config.m_hosts.size(); i++)
1557 {
1558 if (config.m_hosts[i]->m_hostname.length() == 0)
1559 continue;
1560
1561 if (d & 1)
1562 {
1563 if (!do_rsync(g_basedir, config.m_hosts[i]->m_hostname.c_str()))
1564 return false;
1565 }
1566
1567 if (d & 2)
1568 {
1569 if (!do_rsync(g_prefix, config.m_hosts[i]->m_hostname.c_str()))
1570 return false;
1571
1572 if (g_prefix1 &&
1573 !do_rsync(g_prefix1, config.m_hosts[i]->m_hostname.c_str()))
1574 return false;
1575 }
1576 }
1577
1578 return true;
1579 }
1580
1581 bool
sshx(atrt_config & config,unsigned mask)1582 sshx(atrt_config & config, unsigned mask)
1583 {
1584 for (unsigned i = 0; i<config.m_processes.size(); i++)
1585 {
1586 atrt_process & proc = *config.m_processes[i];
1587
1588 BaseString tmp;
1589 const char * type = 0;
1590 switch(proc.m_type){
1591 case atrt_process::AP_NDB_MGMD:
1592 type = (mask & proc.m_type) ? "ndb_mgmd" : 0;
1593 break;
1594 case atrt_process::AP_NDBD:
1595 type = (mask & proc.m_type) ? "ndbd" : 0;
1596 break;
1597 case atrt_process::AP_MYSQLD:
1598 type = (mask & proc.m_type) ? "mysqld" : 0;
1599 break;
1600 case atrt_process::AP_NDB_API:
1601 type = (mask & proc.m_type) ? "ndbapi" : 0;
1602 break;
1603 case atrt_process::AP_CLIENT:
1604 type = (mask & proc.m_type) ? "client" : 0;
1605 break;
1606 default:
1607 type = "<unknown>";
1608 }
1609
1610 if (type == 0)
1611 continue;
1612
1613 #ifdef _WIN32
1614 #define SYS_SSH "bash '-c echo\"%s(%s) on %s\";" \
1615 "ssh -t %s sh %s/ssh-login.sh' &"
1616 #else
1617 #define SYS_SSH "xterm -fg black -title \"%s(%s) on %s\"" \
1618 " -e 'ssh -t -X %s sh %s/ssh-login.sh' &"
1619 #endif
1620
1621 tmp.appfmt(SYS_SSH,
1622 type,
1623 proc.m_cluster->m_name.c_str(),
1624 proc.m_host->m_hostname.c_str(),
1625 proc.m_host->m_hostname.c_str(),
1626 proc.m_proc.m_cwd.c_str());
1627
1628 g_logger.debug("system(%s)", tmp.c_str());
1629 const int r1 = sh(tmp.c_str());
1630 if(r1 != 0)
1631 {
1632 g_logger.critical("Failed sshx (%s)",
1633 tmp.c_str());
1634 return false;
1635 }
1636 NdbSleep_MilliSleep(300); // To prevent xlock problem
1637 }
1638
1639 return true;
1640 }
1641
1642 bool
start(atrt_config & config,unsigned proc_mask)1643 start(atrt_config & config, unsigned proc_mask)
1644 {
1645 if (proc_mask & atrt_process::AP_NDB_MGMD)
1646 if(!start_processes(g_config, atrt_process::AP_NDB_MGMD))
1647 return false;
1648
1649 if (proc_mask & atrt_process::AP_NDBD)
1650 {
1651 if(!connect_ndb_mgm(g_config)){
1652 return false;
1653 }
1654
1655 if(!start_processes(g_config, atrt_process::AP_NDBD))
1656 return false;
1657
1658 if(!wait_ndb(g_config, NDB_MGM_NODE_STATUS_NOT_STARTED))
1659 return false;
1660
1661 for(Uint32 i = 0; i<3; i++)
1662 if(wait_ndb(g_config, NDB_MGM_NODE_STATUS_STARTED))
1663 goto started;
1664 return false;
1665 }
1666
1667 started:
1668 if(!start_processes(g_config, p_servers & proc_mask))
1669 return false;
1670
1671 return true;
1672 }
1673
1674 bool
reset_config(atrt_config & config)1675 reset_config(atrt_config & config)
1676 {
1677 bool changed = false;
1678 for(unsigned i = 0; i<config.m_processes.size(); i++)
1679 {
1680 atrt_process & proc = *config.m_processes[i];
1681 if (proc.m_save.m_saved)
1682 {
1683 if (proc.m_proc.m_status == "running")
1684 {
1685 if (!stop_process(proc))
1686 return false;
1687
1688 changed = true;
1689 }
1690
1691 proc.m_save.m_saved = false;
1692 proc.m_proc = proc.m_save.m_proc;
1693 proc.m_proc.m_id = -1;
1694 }
1695 }
1696 return changed;
1697 }
1698
1699 static
1700 bool
find_binaries()1701 find_binaries()
1702 {
1703 g_logger.info("Locating binaries...");
1704 bool ok = true;
1705 for (int i = 0; g_binaries[i].exe != 0; i++)
1706 {
1707 const char * p = find_bin_path(g_binaries[i].exe);
1708 if (p == 0)
1709 {
1710 if (g_binaries[i].is_required)
1711 {
1712 g_logger.critical("Failed to locate '%s'", g_binaries[i].exe);
1713 ok = false;
1714 }
1715 else
1716 {
1717 g_logger.info("Failed to locate '%s'...ok", g_binaries[i].exe);
1718 }
1719 }
1720 else
1721 {
1722 * g_binaries[i].var = p;
1723 }
1724 }
1725 return ok;
1726 }
1727
1728 template class Vector<Vector<SimpleCpcClient::Process> >;
1729 template class Vector<atrt_host*>;
1730 template class Vector<atrt_cluster*>;
1731 template class Vector<atrt_process*>;
1732
1733 int
check_testcase_file_main(int argc,char ** argv)1734 check_testcase_file_main(int argc, char ** argv)
1735 {
1736 bool ok = true;
1737 int argi = 1;
1738 if (strcmp(argv[argi], "--check-testcase-files") == 0)
1739 {
1740 argi ++;
1741 }
1742 if (argi == argc)
1743 {
1744 ok = false;
1745 fprintf(stderr, "Error: No files to check!\n");
1746 }
1747 else for (; argi < argc; argi ++)
1748 {
1749 FILE* f = fopen(argv[argi], "r");
1750 if (f == NULL)
1751 {
1752 ok = false;
1753 perror(argv[argi]);
1754 continue;
1755 }
1756 atrt_testcase tc_dummy;
1757 int prev_line_num = 0;
1758 int line_num = 0;
1759 int ntests = 0;
1760 while (read_test_case(f, tc_dummy, line_num))
1761 {
1762 prev_line_num = line_num;
1763 ntests ++;
1764 }
1765 // If line count does not change that indicates end of file.
1766 if (line_num == prev_line_num)
1767 {
1768 printf("%s: Contains %d tests in %d lines.\n", argv[argi], ntests, line_num);
1769 }
1770 else
1771 {
1772 ok = false;
1773 fprintf(stderr, "%s: Error at line %d\n", argv[argi], line_num);
1774 }
1775 fclose(f);
1776 }
1777 return ok ? 0 : 1;
1778 }
1779
1780 void
print_testcase_file_syntax()1781 print_testcase_file_syntax()
1782 {
1783 printf("\n"
1784 "Test cases to run are described in files passed with the\n"
1785 "--testcase-file (-f) option.\n"
1786 "\n"
1787 "A testcase is defined with some properties, one property per line,\n"
1788 "and terminated with exactly one empty line. No other empty lines\n"
1789 "are allowed in the file. Lines starting with # are comments and\n"
1790 "are ignored, note they are not counted as empty lines.\n"
1791 "\n"
1792 "The properties are:\n"
1793 "cmd - Names the test executable. The only mandatory property.\n"
1794 "args - The arguments to test executable.\n"
1795 "max-time - Maximum run time for test in seconds (default 60000).\n"
1796 "type - Declare the type of the test. The only recognized value\n"
1797 " is 'bench' which implies that results are stored also for\n"
1798 " successful tests. Normally if this option is not used\n"
1799 " only results from failed tests will be stored.\n"
1800 "run-all - If 'yes' atrt will start the same command for each defined\n"
1801 " api/mysqld, normally it only starts one instance.\n"
1802 "mysqld - Arguments that atrt will use when starting mysqld.\n"
1803 "cmd-type - If 'mysql' change test process type from ndbapi to client.\n"
1804 "name - Change name of test. Default is given by cmd and args.\n"
1805 "\n"
1806 "Example:\n"
1807 "# BASIC FUNCTIONALITY\n"
1808 "max-time: 500\n"
1809 "cmd: testBasic\n"
1810 "args: -n PkRead\n"
1811 "\n"
1812 "# 4k record DD\n"
1813 "max-time: 600\n"
1814 "cmd: flexAsynch\n"
1815 "args: -dd -temp -con 2 -t 8 -r 2 -p 64 -ndbrecord -a 25 -s 40\n"
1816 "type: bench\n"
1817 "\n"
1818 "# sql\n"
1819 "max-time: 600\n"
1820 "cmd: ndb-sql-perf.sh\n"
1821 "args: ndb-sql-perf-select.sh t1 1 64\n"
1822 "mysqld: --ndb-cluster-connection-pool=1\n"
1823 "type: bench\n"
1824 "cmd-type: mysql\n"
1825 "\n"
1826 );
1827 }
1828