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, &section))
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, &section))
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