1 /*
2 Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
3
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License, version 2.0,
7 as published by the Free Software Foundation.
8
9 This program is also distributed with certain software (including
10 but not limited to OpenSSL) that is licensed under separate terms,
11 as designated in a particular file or component or in included license
12 documentation. The authors of MySQL hereby grant you an additional
13 permission to link the program and your derivative works with the
14 separately licensed software that they have included with MySQL.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License, version 2.0, for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26 #include <NDBT.hpp>
27 #include <NDBT_Test.hpp>
28 #include <portlib/NdbDir.hpp>
29 #include "ConfigFactory.hpp"
30 #include <NdbMgmd.hpp>
31 #include <NdbProcess.hpp>
32 #include <NDBT_Find.hpp>
33 #include <NDBT_Workingdir.hpp>
34
file_exists(const char * path,Uint32 timeout=1)35 static bool file_exists(const char* path, Uint32 timeout = 1)
36 {
37 g_info << "File '" << path << "' ";
38 /**
39 * ndb_mgmd does currently not fsync the directory
40 * after committing config-bin,
41 * which means that it can be on disk, wo/ being visible
42 * remedy this by retrying some
43 */
44 for (Uint32 i = 0; i < 10 * timeout; i++)
45 {
46 if (access(path, F_OK) == 0)
47 {
48 g_info << "exists" << endl;
49 return true;
50 }
51 if (i == 0)
52 {
53 g_info << "does not exist, retrying...";
54 }
55 NdbSleep_MilliSleep(100);
56 }
57 g_info << "does not exist" << endl;
58 return false;
59 }
60
61 // Util function that concatenate strings to form a path
62
path(const char * first,...)63 static BaseString path(const char* first, ...)
64 {
65 BaseString path;
66 path.assign(first);
67
68 const char* str;
69 va_list args;
70 va_start(args, first);
71 while ((str = va_arg(args, const char*)) != NULL)
72 {
73 path.appfmt("%s%s", DIR_SEPARATOR, str);
74 }
75 va_end(args);
76 return path;
77 }
78
79 class Mgmd
80 {
81 NdbProcess* m_proc;
82 int m_nodeid;
83 BaseString m_name;
84 BaseString m_exe;
85 NdbMgmd m_mgmd_client;
86
87 Mgmd(const Mgmd& other); // Not implemented
88 public:
89
Mgmd(int nodeid)90 Mgmd(int nodeid) :
91 m_proc(NULL),
92 m_nodeid(nodeid)
93 {
94 m_name.assfmt("ndb_mgmd_%d", nodeid);
95
96 NDBT_find_ndb_mgmd(m_exe);
97 }
98
~Mgmd()99 ~Mgmd()
100 {
101 if (m_proc)
102 {
103 //stop the proces
104 stop();
105 }
106
107 }
108
name(void) const109 const char* name(void) const
110 {
111 return m_name.c_str();
112 }
113
exe(void) const114 const char* exe(void) const
115 {
116 return m_exe.c_str();
117 }
118
start(const char * working_dir,NdbProcess::Args & args)119 bool start(const char* working_dir, NdbProcess::Args& args)
120 {
121 g_info << "Starting " << name() << " ";
122 for (unsigned i = 0; i < args.args().size(); i++)
123 g_info << args.args()[i].c_str() << " ";
124 g_info << endl;
125
126 m_proc = NdbProcess::create(name(),
127 exe(),
128 working_dir,
129 args);
130 return (m_proc != NULL);
131 }
132
start_from_config_ini(const char * working_dir,const char * first_extra_arg=NULL,...)133 bool start_from_config_ini(const char* working_dir,
134 const char* first_extra_arg = NULL, ...)
135 {
136 NdbProcess::Args args;
137 args.add("--configdir=.");
138 args.add("-f config.ini");
139 args.add("--ndb-nodeid=", m_nodeid);
140 args.add("--nodaemon");
141 args.add("--log-name=", name());
142 args.add("--verbose");
143
144 if (first_extra_arg)
145 {
146 // Append any extra args
147 va_list extra_args;
148 const char* str = first_extra_arg;
149 va_start(extra_args, first_extra_arg);
150 do
151 {
152 args.add(str);
153 } while ((str = va_arg(extra_args, const char*)) != NULL);
154 va_end(extra_args);
155 }
156
157 return start(working_dir, args);
158 }
159
start(const char * working_dir,const char * first_extra_arg=NULL,...)160 bool start(const char* working_dir,
161 const char* first_extra_arg = NULL, ...)
162 {
163 NdbProcess::Args args;
164 args.add("--configdir=.");
165 args.add("--ndb-nodeid=", m_nodeid);
166 args.add("--nodaemon");
167 args.add("--log-name=", name());
168 args.add("--verbose");
169
170 if (first_extra_arg)
171 {
172 // Append any extra args
173 va_list extra_args;
174 const char* str = first_extra_arg;
175 va_start(extra_args, first_extra_arg);
176 do
177 {
178 args.add(str);
179 } while ((str = va_arg(extra_args, const char*)) != NULL);
180 va_end(extra_args);
181 }
182
183 return start(working_dir, args);
184 }
185
stop(void)186 bool stop(void)
187 {
188 g_info << "Stopping " << name() << endl;
189
190 // Diconnect and close our "builtin" client
191 m_mgmd_client.close();
192
193 if (m_proc == 0 || !m_proc->stop())
194 {
195 fprintf(stderr, "Failed to stop process %s\n", name());
196 return false; // Can't kill with -9 -> fatal error
197 }
198 int ret;
199 if (!m_proc->wait(ret, 300))
200 {
201 fprintf(stderr, "Failed to wait for process %s\n", name());
202 return false; // Can't wait after kill with -9 -> fatal error
203 }
204
205 if (ret != 9)
206 {
207 fprintf(stderr, "stop ret: %u\n", ret);
208 return false; // Can't wait after kill with -9 -> fatal error
209 }
210
211 delete m_proc;
212 m_proc = 0;
213
214 return true;
215
216 }
217
wait(int & ret,int timeout=300)218 bool wait(int& ret, int timeout = 300)
219 {
220 g_info << "Waiting for " << name() << endl;
221
222 if (m_proc == 0 || !m_proc->wait(ret, timeout))
223 {
224 fprintf(stderr, "Failed to wait for process %s\n", name());
225 return false;
226 }
227 delete m_proc;
228 m_proc = 0;
229
230 return true;
231
232 }
233
connectstring(const Properties & config)234 const BaseString connectstring(const Properties& config)
235 {
236 const char* hostname;
237 if (!get_section_string(config, m_name.c_str(), "HostName", &hostname))
238 return false;
239
240 Uint32 port;
241 if (!get_section_uint32(config, m_name.c_str(), "PortNumber", &port))
242 return false;
243
244 BaseString constr;
245 constr.assfmt("%s:%d", hostname, port);
246 return constr;
247 }
248
connect(const Properties & config,int num_retries=60,int retry_delay_in_seconds=1)249 bool connect(const Properties& config,
250 int num_retries = 60, int retry_delay_in_seconds = 1)
251 {
252 BaseString constr = connectstring(config);
253 g_info << "Connecting to " << name() << " @ " << constr.c_str() << endl;
254
255 return m_mgmd_client.connect(constr.c_str(),
256 num_retries,
257 retry_delay_in_seconds);
258 }
259
wait_confirmed_config(int timeout=30)260 bool wait_confirmed_config(int timeout = 30)
261 {
262 if (!m_mgmd_client.is_connected())
263 {
264 g_err << "wait_confirmed_config: not connected!" << endl;
265 return false;
266 }
267
268 int retries = 0;
269 Config conf;
270 while (!m_mgmd_client.get_config(conf))
271 {
272 retries++;
273
274 if (retries == timeout * 10)
275 {
276 g_err << "wait_confirmed_config: Failed to get config within "
277 << timeout << " seconds" << endl;
278 return false;
279 }
280
281 g_err << "Failed to get config, sleeping" << endl;
282 NdbSleep_MilliSleep(100);
283
284 }
285 g_info << "wait_confirmed_config: ok" << endl;
286 return true;
287
288 }
289
handle()290 NdbMgmHandle handle() { return m_mgmd_client.handle(); }
291
292 private:
293
get_section_string(const Properties & config,const char * section_name,const char * key,const char ** value) const294 bool get_section_string(const Properties& config,
295 const char* section_name,
296 const char* key,
297 const char** value) const
298 {
299 const Properties* section;
300 if (!config.get(section_name, §ion))
301 return false;
302
303 if (!section->get(key, value))
304 return false;
305 return true;
306 }
307
get_section_uint32(const Properties & config,const char * section_name,const char * key,Uint32 * value) const308 bool get_section_uint32(const Properties& config,
309 const char* section_name,
310 const char* key,
311 Uint32* value) const
312 {
313 const Properties* section;
314 if (!config.get(section_name, §ion))
315 return false;
316
317 if (!section->get(key, value))
318 return false;
319 return true;
320 }
321
322 };
323
324 class MgmdProcessList : public Vector<Mgmd*>
325 {
326 public:
327
~MgmdProcessList()328 ~MgmdProcessList()
329 {
330 // Delete and thus stop the mgmd(s)
331 for (unsigned i = 0; i < size(); i++)
332 {
333 Mgmd* mgmd = this->operator[](i);
334 delete mgmd;
335 }
336 // delete this->[i];
337 clear();
338 }
339 };
340
341
342 #define CHECK(x) \
343 if (!(x)) { \
344 fprintf(stderr, "CHECK(" #x ") failed at line: %d\n", \
345 __LINE__); \
346 return NDBT_FAILED; \
347 }
348
runTestBasic2Mgm(NDBT_Context * ctx,NDBT_Step * step)349 int runTestBasic2Mgm(NDBT_Context* ctx, NDBT_Step* step)
350 {
351 NDBT_Workingdir wd("test_mgmd"); // temporary working directory
352
353 // Create config.ini
354 Properties config = ConfigFactory::create(2);
355 CHECK(ConfigFactory::write_config_ini(config,
356 path(wd.path(),
357 "config.ini",
358 NULL).c_str()));
359 // Start ndb_mgmd(s)
360 MgmdProcessList mgmds;
361 for (int i = 1; i <= 2; i++)
362 {
363 Mgmd* mgmd = new Mgmd(i);
364 mgmds.push_back(mgmd);
365 CHECK(mgmd->start_from_config_ini(wd.path()));
366 }
367
368 // Connect the ndb_mgmd(s)
369 for (unsigned i = 0; i < mgmds.size(); i++)
370 CHECK(mgmds[i]->connect(config));
371
372 // wait for confirmed config
373 for (unsigned i = 0; i < mgmds.size(); i++)
374 CHECK(mgmds[i]->wait_confirmed_config());
375
376 // Check binary config files created
377 CHECK(file_exists(path(wd.path(),
378 "ndb_1_config.bin.1",
379 NULL).c_str()));
380 CHECK(file_exists(path(wd.path(),
381 "ndb_2_config.bin.1",
382 NULL).c_str()));
383
384 // Stop the ndb_mgmd(s)
385 for (unsigned i = 0; i < mgmds.size(); i++)
386 CHECK(mgmds[i]->stop());
387
388 // Start up the mgmd(s) again from config.bin
389 for (unsigned i = 0; i < mgmds.size(); i++)
390 CHECK(mgmds[i]->start_from_config_ini(wd.path()));
391
392 // Connect the ndb_mgmd(s)
393 for (unsigned i = 0; i < mgmds.size(); i++)
394 CHECK(mgmds[i]->connect(config));
395
396 // check ndb_X_config.bin.1 still exists but not ndb_X_config.bin.2
397 CHECK(file_exists(path(wd.path(),
398 "ndb_1_config.bin.1",
399 NULL).c_str()));
400 CHECK(file_exists(path(wd.path(),
401 "ndb_2_config.bin.1",
402 NULL).c_str()));
403
404 CHECK(!file_exists(path(wd.path(),
405 "ndb_1_config.bin.2",
406 NULL).c_str()));
407 CHECK(!file_exists(path(wd.path(),
408 "ndb_2_config.bin.2",
409 NULL).c_str()));
410
411 return NDBT_OK;
412
413 }
414
runTestBug45495(NDBT_Context * ctx,NDBT_Step * step)415 int runTestBug45495(NDBT_Context* ctx, NDBT_Step* step)
416 {
417 NDBT_Workingdir wd("test_mgmd"); // temporary working directory
418
419 g_err << "** Create config.ini" << endl;
420 Properties config = ConfigFactory::create(2);
421 CHECK(ConfigFactory::write_config_ini(config,
422 path(wd.path(),
423 "config.ini",
424 NULL).c_str()));
425 // Start ndb_mgmd(s)
426 MgmdProcessList mgmds;
427 for (int i = 1; i <= 2; i++)
428 {
429 Mgmd* mgmd = new Mgmd(i);
430 mgmds.push_back(mgmd);
431 CHECK(mgmd->start_from_config_ini(wd.path()));
432 }
433
434 // Connect the ndb_mgmd(s)
435 for (unsigned i = 0; i < mgmds.size(); i++)
436 CHECK(mgmds[i]->connect(config));
437
438 // wait for confirmed config
439 for (unsigned i = 0; i < mgmds.size(); i++)
440 CHECK(mgmds[i]->wait_confirmed_config());
441
442 // Check binary config files created
443 CHECK(file_exists(path(wd.path(),
444 "ndb_1_config.bin.1",
445 NULL).c_str()));
446 CHECK(file_exists(path(wd.path(),
447 "ndb_2_config.bin.1",
448 NULL).c_str()));
449
450 g_err << "** Restart one ndb_mgmd at a time --reload + --initial" << endl;
451 for (unsigned i = 0; i < mgmds.size(); i++)
452 {
453 CHECK(mgmds[i]->stop());
454 CHECK(mgmds[i]->start_from_config_ini(wd.path(),
455 "--reload", "--initial", NULL));
456 CHECK(mgmds[i]->connect(config));
457 CHECK(mgmds[i]->wait_confirmed_config());
458
459 // check ndb_X_config.bin.1 still exists but not ndb_X_config.bin.2
460 CHECK(file_exists(path(wd.path(),
461 "ndb_1_config.bin.1",
462 NULL).c_str()));
463 CHECK(file_exists(path(wd.path(),
464 "ndb_2_config.bin.1",
465 NULL).c_str()));
466
467 CHECK(!file_exists(path(wd.path(),
468 "ndb_1_config.bin.2",
469 NULL).c_str()));
470 CHECK(!file_exists(path(wd.path(),
471 "ndb_2_config.bin.2",
472 NULL).c_str()));
473 }
474
475 g_err << "** Restart one ndb_mgmd at a time --initial" << endl;
476 for (unsigned i = 0; i < mgmds.size(); i++)
477 {
478 CHECK(mgmds[i]->stop());
479 CHECK(mgmds[i]->start_from_config_ini(wd.path(),
480 "--initial", NULL));
481 CHECK(mgmds[i]->connect(config));
482 CHECK(mgmds[i]->wait_confirmed_config());
483
484 // check ndb_X_config.bin.1 still exists but not ndb_X_config.bin.2
485 CHECK(file_exists(path(wd.path(),
486 "ndb_1_config.bin.1",
487 NULL).c_str()));
488 CHECK(file_exists(path(wd.path(),
489 "ndb_2_config.bin.1",
490 NULL).c_str()));
491
492 CHECK(!file_exists(path(wd.path(),
493 "ndb_1_config.bin.2",
494 NULL).c_str()));
495 CHECK(!file_exists(path(wd.path(),
496 "ndb_2_config.bin.2",
497 NULL).c_str()));
498 }
499
500 g_err << "** Create config2.ini" << endl;
501 CHECK(ConfigFactory::put(config, "ndb_mgmd", 1, "ArbitrationDelay", 100));
502 CHECK(ConfigFactory::write_config_ini(config,
503 path(wd.path(),
504 "config2.ini",
505 NULL).c_str()));
506
507 g_err << "** Restart one ndb_mgmd at a time --initial should not work" << endl;
508 for (unsigned i = 0; i < mgmds.size(); i++)
509 {
510 CHECK(mgmds[i]->stop());
511 // Start from config2.ini
512 CHECK(mgmds[i]->start_from_config_ini(wd.path(),
513 "-f config2.ini",
514 "--initial", NULL));
515
516 // Wait for mgmd to exit and check return status
517 int ret;
518 CHECK(mgmds[i]->wait(ret));
519 CHECK(ret == 1);
520
521 // check config files exist only for the still running mgmd(s)
522 for (unsigned j = 0; j < mgmds.size(); j++)
523 {
524 BaseString tmp;
525 tmp.assfmt("ndb_%d_config.bin.1", j+1);
526 CHECK(file_exists(path(wd.path(),
527 tmp.c_str(),
528 NULL).c_str()) == (j != i));
529 }
530
531 // Start from config.ini again
532 CHECK(mgmds[i]->start_from_config_ini(wd.path(),
533 "--initial",
534 "--reload",
535 NULL));
536 CHECK(mgmds[i]->connect(config));
537 CHECK(mgmds[i]->wait_confirmed_config());
538 }
539
540 g_err << "** Reload from config2.ini" << endl;
541 for (unsigned i = 0; i < mgmds.size(); i++)
542 {
543 CHECK(mgmds[i]->stop());
544 // Start from config2.ini
545 CHECK(mgmds[i]->start_from_config_ini(wd.path(),
546 "-f config2.ini",
547 "--reload", NULL));
548 CHECK(mgmds[i]->connect(config));
549 CHECK(mgmds[i]->wait_confirmed_config());
550 }
551
552 CHECK(file_exists(path(wd.path(),
553 "ndb_1_config.bin.1",
554 NULL).c_str()));
555 CHECK(file_exists(path(wd.path(),
556 "ndb_2_config.bin.1",
557 NULL).c_str()));
558
559 Uint32 timeout = 30;
560 CHECK(file_exists(path(wd.path(),
561 "ndb_1_config.bin.2",
562 NULL).c_str(), timeout));
563 CHECK(file_exists(path(wd.path(),
564 "ndb_2_config.bin.2",
565 NULL).c_str(), timeout));
566
567 g_err << "** Reload mgmd initial(from generation=2)" << endl;
568 for (unsigned i = 0; i < mgmds.size(); i++)
569 {
570 CHECK(mgmds[i]->stop());
571 CHECK(mgmds[i]->start_from_config_ini(wd.path(),
572 "-f config2.ini",
573 "--reload", "--initial", NULL));
574
575 CHECK(mgmds[i]->connect(config));
576 CHECK(mgmds[i]->wait_confirmed_config());
577
578 // check config files exist
579 for (unsigned j = 0; j < mgmds.size(); j++)
580 {
581 BaseString tmp;
582 tmp.assfmt("ndb_%d_config.bin.1", j+1);
583 CHECK(file_exists(path(wd.path(),
584 tmp.c_str(),
585 NULL).c_str()) == (i < j));
586
587 tmp.assfmt("ndb_%d_config.bin.2", j+1);
588 CHECK(file_exists(path(wd.path(),
589 tmp.c_str(),
590 NULL).c_str(),
591 timeout));
592 }
593 }
594
595 return NDBT_OK;
596 }
597
598
599
runTestBug42015(NDBT_Context * ctx,NDBT_Step * step)600 int runTestBug42015(NDBT_Context* ctx, NDBT_Step* step)
601 {
602 NDBT_Workingdir wd("test_mgmd"); // temporary working directory
603
604 g_err << "** Create config.ini" << endl;
605 Properties config = ConfigFactory::create(2);
606 CHECK(ConfigFactory::write_config_ini(config,
607 path(wd.path(),
608 "config.ini",
609 NULL).c_str()));
610
611 MgmdProcessList mgmds;
612 // Start ndb_mgmd 1 from config.ini
613 Mgmd* mgmd = new Mgmd(1);
614 mgmds.push_back(mgmd);
615 CHECK(mgmd->start_from_config_ini(wd.path()));
616
617 // Start ndb_mgmd 2 by fetching from first
618 Mgmd* mgmd2 = new Mgmd(2);
619 mgmds.push_back(mgmd2);
620 CHECK(mgmd2->start(wd.path(),
621 "--ndb-connectstring",
622 mgmd->connectstring(config).c_str(),
623 NULL));
624
625 // Connect the ndb_mgmd(s)
626 for (unsigned i = 0; i < mgmds.size(); i++)
627 CHECK(mgmds[i]->connect(config));
628
629 // wait for confirmed config
630 for (unsigned i = 0; i < mgmds.size(); i++)
631 CHECK(mgmds[i]->wait_confirmed_config());
632
633 // Check binary config files created
634 CHECK(file_exists(path(wd.path(),
635 "ndb_1_config.bin.1",
636 NULL).c_str()));
637 CHECK(file_exists(path(wd.path(),
638 "ndb_2_config.bin.1",
639 NULL).c_str()));
640
641 return NDBT_OK;
642
643 }
644
645 /* Test for bug 53008: --skip-config-cache */
runTestNoConfigCache(NDBT_Context * ctx,NDBT_Step * step)646 int runTestNoConfigCache(NDBT_Context* ctx, NDBT_Step* step)
647 {
648 NDBT_Workingdir wd("test_mgmd"); // temporary working directory
649
650 g_err << "** Create config.ini" << endl;
651 Properties config = ConfigFactory::create();
652 CHECK(ConfigFactory::write_config_ini(config,
653 path(wd.path(),
654 "config.ini",
655 NULL).c_str()));
656
657 // Start ndb_mgmd from config.ini
658 Mgmd* mgmd = new Mgmd(1);
659 CHECK(mgmd->start_from_config_ini(wd.path(), "--skip-config-cache", NULL));
660
661 // Connect the ndb_mgmd(s)
662 CHECK(mgmd->connect(config));
663
664 // wait for confirmed config
665 CHECK(mgmd->wait_confirmed_config());
666
667 // Check binary config files *not* created
668 bool bin_conf_file = file_exists(path(wd.path(),
669 "ndb_1_config.bin.1",
670 NULL).c_str());
671 CHECK(bin_conf_file == false);
672
673 mgmd->stop();
674 return NDBT_OK;
675 }
676
677
runTestNowaitNodes(NDBT_Context * ctx,NDBT_Step * step)678 int runTestNowaitNodes(NDBT_Context* ctx, NDBT_Step* step)
679 {
680 MgmdProcessList mgmds;
681 NDBT_Workingdir wd("test_mgmd"); // temporary working directory
682
683 // Create config.ini
684 Properties config = ConfigFactory::create(2);
685 CHECK(ConfigFactory::write_config_ini(config,
686 path(wd.path(),
687 "config.ini",
688 NULL).c_str()));
689 // Start first ndb_mgmd
690 Mgmd* mgmd1 = new Mgmd(1);
691 {
692 mgmds.push_back(mgmd1);
693 CHECK(mgmd1->start_from_config_ini(wd.path(),
694 "--initial",
695 "--nowait-nodes=2",
696 NULL));
697
698 // Connect the ndb_mgmd
699 CHECK(mgmd1->connect(config));
700
701 // wait for confirmed config
702 CHECK(mgmd1->wait_confirmed_config());
703
704 // Check binary config file created
705 CHECK(file_exists(path(wd.path(),
706 "ndb_1_config.bin.1",
707 NULL).c_str()));
708 }
709
710 // Start second ndb_mgmd
711 {
712 Mgmd* mgmd2 = new Mgmd(2);
713 mgmds.push_back(mgmd2);
714 CHECK(mgmd2->start_from_config_ini(wd.path(),
715 "--initial",
716 NULL));
717
718 // Connect the ndb_mgmd
719 CHECK(mgmd2->connect(config));
720
721 // wait for confirmed config
722 CHECK(mgmd2->wait_confirmed_config());
723
724 // Check binary config file created
725 CHECK(file_exists(path(wd.path(),
726 "ndb_2_config.bin.1",
727 NULL).c_str()));
728
729 }
730
731 // Create new config.ini
732 g_err << "** Create config2.ini" << endl;
733 CHECK(ConfigFactory::put(config, "ndb_mgmd", 1, "ArbitrationDelay", 100));
734 CHECK(ConfigFactory::write_config_ini(config,
735 path(wd.path(),
736 "config2.ini",
737 NULL).c_str()));
738
739 g_err << "** Reload second mgmd from config2.ini" << endl;
740 {
741 Mgmd* mgmd2 = mgmds[1];
742 CHECK(mgmd2->stop());
743 // Start from config2.ini
744 CHECK(mgmd2->start_from_config_ini(wd.path(),
745 "-f config2.ini",
746 "--reload", NULL));
747 CHECK(mgmd2->connect(config));
748 CHECK(mgmd1->wait_confirmed_config());
749 CHECK(mgmd2->wait_confirmed_config());
750
751 CHECK(file_exists(path(wd.path(),
752 "ndb_1_config.bin.1",
753 NULL).c_str()));
754 CHECK(file_exists(path(wd.path(),
755 "ndb_2_config.bin.1",
756 NULL).c_str()));
757
758 // Both ndb_mgmd(s) should have reloaded and new binary config exist
759 CHECK(file_exists(path(wd.path(),
760 "ndb_1_config.bin.2",
761 NULL).c_str()));
762 CHECK(file_exists(path(wd.path(),
763 "ndb_2_config.bin.2",
764 NULL).c_str()));
765 }
766
767 // Stop the ndb_mgmd(s)
768 for (unsigned i = 0; i < mgmds.size(); i++)
769 CHECK(mgmds[i]->stop());
770
771 return NDBT_OK;
772 }
773
774
runTestNowaitNodes2(NDBT_Context * ctx,NDBT_Step * step)775 int runTestNowaitNodes2(NDBT_Context* ctx, NDBT_Step* step)
776 {
777 int ret;
778 NDBT_Workingdir wd("test_mgmd"); // temporary working directory
779
780 // Create config.ini
781 Properties config = ConfigFactory::create(2);
782 CHECK(ConfigFactory::write_config_ini(config,
783 path(wd.path(),
784 "config.ini",
785 NULL).c_str()));
786
787 g_err << "** Start mgmd1 from config.ini" << endl;
788 MgmdProcessList mgmds;
789 Mgmd* mgmd1 = new Mgmd(1);
790 mgmds.push_back(mgmd1);
791 CHECK(mgmd1->start_from_config_ini(wd.path(),
792 "--initial",
793 "--nowait-nodes=1-255",
794 NULL));
795 CHECK(mgmd1->connect(config));
796 CHECK(mgmd1->wait_confirmed_config());
797
798 // check config files exist
799 CHECK(file_exists(path(wd.path(),
800 "ndb_1_config.bin.1",
801 NULL).c_str()));
802
803 g_err << "** Create config2.ini" << endl;
804 CHECK(ConfigFactory::put(config, "ndb_mgmd", 1, "ArbitrationDelay", 100));
805 CHECK(ConfigFactory::write_config_ini(config,
806 path(wd.path(),
807 "config2.ini",
808 NULL).c_str()));
809
810 g_err << "** Start mgmd2 from config2.ini" << endl;
811 Mgmd* mgmd2 = new Mgmd(2);
812 mgmds.push_back(mgmd2);
813 CHECK(mgmd2->start_from_config_ini(wd.path(),
814 "-f config2.ini",
815 "--initial",
816 "--nowait-nodes=1-255",
817 NULL));
818 CHECK(mgmd2->wait(ret));
819 CHECK(ret == 1);
820
821 CHECK(mgmd1->stop());
822
823 g_err << "** Start mgmd2 again from config2.ini" << endl;
824 CHECK(mgmd2->start_from_config_ini(wd.path(),
825 "-f config2.ini",
826 "--initial",
827 "--nowait-nodes=1-255",
828 NULL));
829
830
831 CHECK(mgmd2->connect(config));
832 CHECK(mgmd2->wait_confirmed_config());
833
834 // check config files exist
835 CHECK(file_exists(path(wd.path(),
836 "ndb_2_config.bin.1",
837 NULL).c_str()));
838
839 g_err << "** Start mgmd1 from config.ini, mgmd2 should shutdown" << endl;
840 CHECK(mgmd1->start_from_config_ini(wd.path(),
841 "--initial",
842 "--nowait-nodes=1-255",
843 NULL));
844 CHECK(mgmd2->wait(ret));
845 CHECK(ret == 1);
846
847 CHECK(mgmd1->stop());
848
849 return NDBT_OK;
850 }
851
852 int
runBug56844(NDBT_Context * ctx,NDBT_Step * step)853 runBug56844(NDBT_Context* ctx, NDBT_Step* step)
854 {
855 NDBT_Workingdir wd("test_mgmd"); // temporary working directory
856
857 g_err << "** Create config.ini" << endl;
858 Properties config = ConfigFactory::create(2);
859 CHECK(ConfigFactory::write_config_ini(config,
860 path(wd.path(),
861 "config.ini",
862 NULL).c_str()));
863 // Start ndb_mgmd(s)
864 MgmdProcessList mgmds;
865 for (int i = 1; i <= 2; i++)
866 {
867 Mgmd* mgmd = new Mgmd(i);
868 mgmds.push_back(mgmd);
869 CHECK(mgmd->start_from_config_ini(wd.path()));
870 }
871
872 // Connect the ndb_mgmd(s)
873 for (unsigned i = 0; i < mgmds.size(); i++)
874 {
875 CHECK(mgmds[i]->connect(config));
876 }
877
878 // wait for confirmed config
879 for (unsigned i = 0; i < mgmds.size(); i++)
880 {
881 CHECK(mgmds[i]->wait_confirmed_config());
882 }
883
884 // stop them
885 for (unsigned i = 0; i < mgmds.size(); i++)
886 {
887 CHECK(mgmds[i]->stop());
888 }
889
890 // Check binary config files created
891 CHECK(file_exists(path(wd.path(),
892 "ndb_1_config.bin.1",
893 NULL).c_str()));
894 CHECK(file_exists(path(wd.path(),
895 "ndb_2_config.bin.1",
896 NULL).c_str()));
897
898 CHECK(ConfigFactory::put(config, "ndb_mgmd", 1, "ArbitrationDelay", 100));
899 CHECK(ConfigFactory::write_config_ini(config,
900 path(wd.path(),
901 "config2.ini",
902 NULL).c_str()));
903 Uint32 no = 2;
904 int loops = ctx->getNumLoops();
905 for (int l = 0; l < loops; l++, no++)
906 {
907 g_err << l << ": *** Reload from config.ini" << endl;
908 for (unsigned i = 0; i < mgmds.size(); i++)
909 {
910 // Start from config2.ini
911 CHECK(mgmds[i]->start_from_config_ini(wd.path(),
912 (l & 1) == 1 ?
913 "-f config.ini" :
914 "-f config2.ini",
915 "--reload", NULL));
916 }
917 for (unsigned i = 0; i < mgmds.size(); i++)
918 {
919 CHECK(mgmds[i]->connect(config));
920 CHECK(mgmds[i]->wait_confirmed_config());
921 }
922
923 /**
924 * Since it will first be confirmed...
925 * and then once connected to other ndb_nmgmd start a config
926 * change, it can take a bit until new config exists...
927 * allow 30s
928 */
929 Uint32 timeout = 30;
930 for (unsigned i = 0; i < mgmds.size(); i++)
931 {
932 BaseString p = path(wd.path(), "", NULL);
933 p.appfmt("ndb_%u_config.bin.%u", i+1, no);
934 g_err << "CHECK(" << p.c_str() << ")" << endl;
935 CHECK(file_exists(p.c_str(), timeout));
936 }
937
938 for (unsigned i = 0; i < mgmds.size(); i++)
939 {
940 CHECK(mgmds[i]->stop());
941 }
942 }
943 return NDBT_OK;
944 }
945
946 static bool
get_status(const char * connectstring,Properties & status)947 get_status(const char* connectstring,
948 Properties& status)
949 {
950 NdbMgmd ndbmgmd;
951 if (!ndbmgmd.connect(connectstring))
952 return false;
953
954 Properties args;
955 if (!ndbmgmd.call("get status", args,
956 "node status", status, NULL, true))
957 {
958 g_err << "fetch_mgmd_status: mgmd.call failed" << endl;
959 return false;
960 }
961 return true;
962 }
963
964 static bool
value_equal(Properties & status,int nodeid,const char * name,const char * expected_value)965 value_equal(Properties& status,
966 int nodeid, const char* name,
967 const char* expected_value)
968 {
969 const char* value;
970 BaseString key;
971 key.assfmt("node.%d.%s", nodeid, name);
972 if (!status.get(key.c_str(), &value))
973 {
974 g_err << "value_equal: no value found for '" << name
975 << "." << nodeid << "'" << endl;
976 return false;
977 }
978
979 if (strcmp(value, expected_value))
980 {
981 g_err << "value_equal: found unexpected value: '" << value
982 << "', expected: '" << expected_value << "'" <<endl;
983 return false;
984 }
985 g_info << "'" << value << "'=='" << expected_value << "'" << endl;
986 return true;
987 }
988
989 #include <ndb_version.h>
990
runTestBug12352191(NDBT_Context * ctx,NDBT_Step * step)991 int runTestBug12352191(NDBT_Context* ctx, NDBT_Step* step)
992 {
993 BaseString version;
994 version.assfmt("%u", NDB_VERSION_D);
995 BaseString mysql_version;
996 mysql_version.assfmt("%u", NDB_MYSQL_VERSION_D);
997 BaseString address("127.0.0.1");
998
999 NDBT_Workingdir wd("test_mgmd"); // temporary working directory
1000
1001 g_err << "** Create config.ini" << endl;
1002 Properties config = ConfigFactory::create(2);
1003 CHECK(ConfigFactory::write_config_ini(config,
1004 path(wd.path(),
1005 "config.ini",
1006 NULL).c_str()));
1007
1008 MgmdProcessList mgmds;
1009 const int nodeid1 = 1;
1010 Mgmd* mgmd1 = new Mgmd(nodeid1);
1011 mgmds.push_back(mgmd1);
1012
1013 const int nodeid2 = 2;
1014 Mgmd* mgmd2 = new Mgmd(nodeid2);
1015 mgmds.push_back(mgmd2);
1016
1017 // Start first mgmd
1018 CHECK(mgmd1->start_from_config_ini(wd.path()));
1019 CHECK(mgmd1->connect(config));
1020
1021 Properties status1;
1022 CHECK(get_status(mgmd1->connectstring(config).c_str(), status1));
1023 //status1.print();
1024 // Check status for own mgm node, always CONNECTED
1025 CHECK(value_equal(status1, nodeid1, "type", "MGM"));
1026 CHECK(value_equal(status1, nodeid1, "status", "CONNECTED"));
1027 CHECK(value_equal(status1, nodeid1, "version", version.c_str()));
1028 CHECK(value_equal(status1, nodeid1, "mysql_version", mysql_version.c_str()));
1029 CHECK(value_equal(status1, nodeid1, "address", address.c_str()));
1030 CHECK(value_equal(status1, nodeid1, "startphase", "0"));
1031 CHECK(value_equal(status1, nodeid1, "dynamic_id", "0"));
1032 CHECK(value_equal(status1, nodeid1, "node_group", "0"));
1033 CHECK(value_equal(status1, nodeid1, "connect_count", "0"));
1034
1035 // Check status for other mgm node
1036 // not started yet -> NO_CONTACT, no address, no versions
1037 CHECK(value_equal(status1, nodeid2, "type", "MGM"));
1038 CHECK(value_equal(status1, nodeid2, "status", "NO_CONTACT"));
1039 CHECK(value_equal(status1, nodeid2, "version", "0"));
1040 CHECK(value_equal(status1, nodeid2, "mysql_version", "0"));
1041 CHECK(value_equal(status1, nodeid2, "address", ""));
1042 CHECK(value_equal(status1, nodeid2, "startphase", "0"));
1043 CHECK(value_equal(status1, nodeid2, "dynamic_id", "0"));
1044 CHECK(value_equal(status1, nodeid2, "node_group", "0"));
1045 CHECK(value_equal(status1, nodeid2, "connect_count", "0"));
1046
1047 // Start second mgmd
1048 CHECK(mgmd2->start_from_config_ini(wd.path()));
1049 CHECK(mgmd2->connect(config));
1050
1051 // wait for confirmed config
1052 for (unsigned i = 0; i < mgmds.size(); i++)
1053 CHECK(mgmds[i]->wait_confirmed_config());
1054
1055 Properties status2;
1056 CHECK(get_status(mgmd2->connectstring(config).c_str(), status2));
1057 //status2.print();
1058 // Check status for own mgm node, always CONNECTED
1059 CHECK(value_equal(status2, nodeid2, "type", "MGM"));
1060 CHECK(value_equal(status2, nodeid2, "status", "CONNECTED"));
1061 CHECK(value_equal(status2, nodeid2, "version", version.c_str()));
1062 CHECK(value_equal(status2, nodeid2, "mysql_version", mysql_version.c_str()));
1063 CHECK(value_equal(status2, nodeid2, "address", address.c_str()));
1064 CHECK(value_equal(status2, nodeid2, "startphase", "0"));
1065 CHECK(value_equal(status2, nodeid2, "dynamic_id", "0"));
1066 CHECK(value_equal(status2, nodeid2, "node_group", "0"));
1067 CHECK(value_equal(status2, nodeid2, "connect_count", "0"));
1068
1069 // Check status for other mgm node
1070 // both started now -> CONNECTED, address and versions filled in
1071 CHECK(value_equal(status2, nodeid1, "type", "MGM"));
1072 CHECK(value_equal(status2, nodeid1, "status", "CONNECTED"));
1073 CHECK(value_equal(status2, nodeid1, "version", version.c_str()));
1074 CHECK(value_equal(status2, nodeid1, "mysql_version", mysql_version.c_str()));
1075 CHECK(value_equal(status2, nodeid1, "address", address.c_str()));
1076 CHECK(value_equal(status2, nodeid1, "startphase", "0"));
1077 CHECK(value_equal(status2, nodeid1, "dynamic_id", "0"));
1078 CHECK(value_equal(status2, nodeid1, "node_group", "0"));
1079 CHECK(value_equal(status2, nodeid1, "connect_count", "0"));
1080
1081 Properties status3;
1082 CHECK(get_status(mgmd1->connectstring(config).c_str(), status3));
1083 //status3.print();
1084 // Check status for own mgm node, always CONNECTED
1085 CHECK(value_equal(status3, nodeid1, "type", "MGM"));
1086 CHECK(value_equal(status3, nodeid1, "status", "CONNECTED"));
1087 CHECK(value_equal(status3, nodeid1, "version", version.c_str()));
1088 CHECK(value_equal(status3, nodeid1, "mysql_version", mysql_version.c_str()));
1089 CHECK(value_equal(status3, nodeid1, "address", address.c_str()));
1090 CHECK(value_equal(status3, nodeid1, "startphase", "0"));
1091 CHECK(value_equal(status3, nodeid1, "dynamic_id", "0"));
1092 CHECK(value_equal(status3, nodeid1, "node_group", "0"));
1093 CHECK(value_equal(status3, nodeid1, "connect_count", "0"));
1094
1095 // Check status for other mgm node
1096 // both started now -> CONNECTED, address and versions filled in
1097 CHECK(value_equal(status3, nodeid2, "type", "MGM"));
1098 CHECK(value_equal(status3, nodeid2, "status", "CONNECTED"));
1099 CHECK(value_equal(status3, nodeid2, "version", version.c_str()));
1100 CHECK(value_equal(status3, nodeid2, "mysql_version", mysql_version.c_str()));
1101 CHECK(value_equal(status3, nodeid2, "address", address.c_str()));
1102 CHECK(value_equal(status3, nodeid2, "startphase", "0"));
1103 CHECK(value_equal(status3, nodeid2, "dynamic_id", "0"));
1104 CHECK(value_equal(status3, nodeid2, "node_group", "0"));
1105 CHECK(value_equal(status3, nodeid2, "connect_count", "0"));
1106
1107 return NDBT_OK;
1108
1109 }
1110
1111 int
runBug61607(NDBT_Context * ctx,NDBT_Step * step)1112 runBug61607(NDBT_Context* ctx, NDBT_Step* step)
1113 {
1114 NDBT_Workingdir wd("test_mgmd"); // temporary working directory
1115
1116 // Create config.ini
1117 const int cnt_mgmd = 1;
1118 Properties config = ConfigFactory::create(cnt_mgmd);
1119 CHECK(ConfigFactory::write_config_ini(config,
1120 path(wd.path(),
1121 "config.ini",
1122 NULL).c_str()));
1123 // Start ndb_mgmd(s)
1124 MgmdProcessList mgmds;
1125 for (int i = 1; i <= cnt_mgmd; i++)
1126 {
1127 Mgmd* mgmd = new Mgmd(i);
1128 mgmds.push_back(mgmd);
1129 CHECK(mgmd->start_from_config_ini(wd.path()));
1130 }
1131
1132 // Connect the ndb_mgmd(s)
1133 for (unsigned i = 0; i < mgmds.size(); i++)
1134 CHECK(mgmds[i]->connect(config));
1135
1136 // wait for confirmed config
1137 for (unsigned i = 0; i < mgmds.size(); i++)
1138 CHECK(mgmds[i]->wait_confirmed_config());
1139
1140 // Check binary config files created
1141 CHECK(file_exists(path(wd.path(),
1142 "ndb_1_config.bin.1",
1143 NULL).c_str()));
1144
1145 int no_of_nodes = 0;
1146 int * node_ids = 0;
1147 int initialstart = 0;
1148 int nostart = 0;
1149 int abort = 0;
1150 int force = 0;
1151 int need_disconnect = 0;
1152 int res = ndb_mgm_restart4(mgmds[0]->handle(), no_of_nodes, node_ids,
1153 initialstart, nostart, abort, force,
1154 &need_disconnect);
1155
1156
1157 return res == 0 ? NDBT_OK : NDBT_FAILED;
1158 }
1159
1160 NDBT_TESTSUITE(testMgmd);
1161 DRIVER(DummyDriver); /* turn off use of NdbApi */
1162
1163 TESTCASE("Basic2Mgm",
1164 "Basic test with two mgmd")
1165 {
1166 INITIALIZER(runTestBasic2Mgm);
1167 }
1168
1169 TESTCASE("Bug42015",
1170 "Test that mgmd can fetch configuration from another mgmd")
1171 {
1172 INITIALIZER(runTestBug42015);
1173 }
1174 TESTCASE("NowaitNodes",
1175 "Test that one mgmd(of 2) can start alone with usage "
1176 "of --nowait-nodes, then start the second mgmd and it should join")
1177 {
1178 INITIALIZER(runTestNowaitNodes);
1179 }
1180 TESTCASE("NowaitNodes2",
1181 "Test that one mgmd(of 2) can start alone with usage "
1182 "of --nowait-nodes, then start the second mgmd from different "
1183 "configuration and the one with lowest nodeid should shutdown")
1184 {
1185 INITIALIZER(runTestNowaitNodes2);
1186 }
1187
1188 TESTCASE("NoCfgCache",
1189 "Test that when an mgmd is started with --skip-config-cache, "
1190 "no ndb_xx_config.xx.bin file is created, but you can "
1191 "connect to the mgm node and retrieve the config.")
1192 {
1193 INITIALIZER(runTestNoConfigCache);
1194 }
1195
1196 TESTCASE("Bug45495",
1197 "Test that mgmd can be restarted in any order")
1198 {
1199 INITIALIZER(runTestBug45495);
1200 }
1201
1202 TESTCASE("Bug56844",
1203 "Test that mgmd can be reloaded in parallel")
1204 {
1205 INITIALIZER(runBug56844);
1206 }
1207 TESTCASE("Bug12352191",
1208 "Test mgmd status for other mgmd")
1209 {
1210 INITIALIZER(runTestBug12352191);
1211 }
1212 TESTCASE("Bug61607", "")
1213 {
1214 INITIALIZER(runBug61607);
1215 }
1216
1217 NDBT_TESTSUITE_END(testMgmd);
1218
main(int argc,const char ** argv)1219 int main(int argc, const char** argv)
1220 {
1221 ndb_init();
1222 NDBT_TESTSUITE_INSTANCE(testMgmd);
1223 testMgmd.setCreateTable(false);
1224 testMgmd.setRunAllTables(true);
1225 testMgmd.setConnectCluster(false);
1226 return testMgmd.execute(argc, argv);
1227 }
1228
1229 template class Vector<Mgmd*>;
1230
1231