1 /*
2    Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
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  * Description of config variables, including their min, max, default
27  * values can be printed (--configinfo). This can also be printed
28  * in xml format (--xml).
29  *
30  * Config can be retrieved from only one of the following sources:
31  ** 1) config stored at mgmd (default)
32  ** 2) config stored at a data node (--config_from_node=<data node id>)
33  *** (Note:
34  ***  Node numbers less than 1 give error:
35  ***  "Given value <node id> is not a valid node number."
36  ***  Non-data node numbers give error:
37  ***  "Node <node id> is not a data node.")
38  ** 3) my.cnf (--mycnf=<fullPath/mycnfFileName>)
39  ** 4) config.file (--config_file=<fullPath/configFileName>
40  *
41  * Config variables are displayed from only one of the following
42  * sections of the retrieved config:
43  ** CFG_SECTION_NODE (default, or --nodes)
44  ** CFG_SECTION_CONNECTION (--connections)
45  ** CFG_SECTION_SYSTEM (--system)
46  */
47 
48 /**
49  * Examples:
50  * Get config from mgmd (default):
51  ** Display results from section CFG_SECTION_NODE (default)
52  *** ndb_config --nodes --query=nodeid --type=ndbd --host=local1
53  *** ndb_config  --query=nodeid,host
54  *
55  ** Display results from section CFG_SECTION_SYSTEM
56  *** ndb_config --system --query=ConfigGenerationNumber
57  *
58  ** Display results from section CFG_SECTION_CONNECTION
59  *** ndb_config --connections --query=type
60  *
61  * Get config from eg. node 2, which is a data node:
62  *
63  ** ndb_config --config_from_node=2 --system --query=ConfigGenerationNumber
64  ** ndb_config --config_from_node=2 --connections --query=type
65  ** ndb_config --config_from_node=2 --query=id,NoOfFragmentLogFiles
66  *
67  **  Get config from eg. node 2 and display results for node 2 only:
68  *** ndb_config --config_from_node=2 --query=id,NoOfFragmentLogFiles --nodeid=2
69  */
70 
71 #include <ndb_global.h>
72 #include <ndb_opts.h>
73 
74 #include <my_sys.h>
75 #include <my_getopt.h>
76 #include <mysql_version.h>
77 
78 #include <NdbOut.hpp>
79 #include <mgmapi.h>
80 #include "../src/mgmapi/mgmapi_configuration.hpp"
81 #include "../src/mgmsrv/ConfigInfo.hpp"
82 #include <NdbAutoPtr.hpp>
83 #include <NdbTCP.h>
84 
85 static int g_verbose = 0;
86 static int try_reconnect = 3;
87 
88 static int g_nodes, g_connections, g_system, g_section;
89 static const char * g_query = 0;
90 
91 static int g_nodeid = 0;
92 static const char * g_type = 0;
93 static const char * g_host = 0;
94 static const char * g_field_delimiter=",";
95 static const char * g_row_delimiter=" ";
96 static const char * g_config_file = 0;
97 static int g_mycnf = 0;
98 static int g_configinfo = 0;
99 static int g_xml = 0;
100 static int g_config_from_node = 0;
101 
102 const char *load_default_groups[]= { "mysql_cluster",0 };
103 
104 typedef ndb_mgm_configuration_iterator Iter;
105 
106 static struct my_option my_long_options[] =
107 {
108   NDB_STD_OPTS("ndb_config"),
109   { "nodes", NDB_OPT_NOSHORT, "Print nodes",
110     (uchar**) &g_nodes, (uchar**) &g_nodes,
111     0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
112   { "connections", NDB_OPT_NOSHORT, "Print connections",
113     (uchar**) &g_connections, (uchar**) &g_connections,
114     0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
115   { "system", NDB_OPT_NOSHORT, "Print system",
116     (uchar**) &g_system, (uchar**) &g_system,
117     0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
118   { "query", 'q', "Query option(s)",
119     (uchar**) &g_query, (uchar**) &g_query,
120     0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
121   { "host", NDB_OPT_NOSHORT, "Host",
122     (uchar**) &g_host, (uchar**) &g_host,
123     0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
124   { "type", NDB_OPT_NOSHORT, "Type of node/connection",
125     (uchar**) &g_type, (uchar**) &g_type,
126     0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
127   { "id", NDB_OPT_NOSHORT, "Nodeid",
128     (uchar**) &g_nodeid, (uchar**) &g_nodeid,
129     0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
130   { "nodeid", NDB_OPT_NOSHORT, "Nodeid",
131     (uchar**) &g_nodeid, (uchar**) &g_nodeid,
132     0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
133   { "fields", 'f', "Field separator",
134     (uchar**) &g_field_delimiter, (uchar**) &g_field_delimiter,
135     0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
136   { "rows", 'r', "Row separator",
137     (uchar**) &g_row_delimiter, (uchar**) &g_row_delimiter,
138     0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
139   { "config-file", NDB_OPT_NOSHORT, "Path to config.ini",
140     (uchar**) &g_config_file, (uchar**) &g_config_file,
141     0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
142   { "mycnf", NDB_OPT_NOSHORT, "Read config from my.cnf",
143     (uchar**) &g_mycnf, (uchar**) &g_mycnf,
144     0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
145   { "configinfo", NDB_OPT_NOSHORT, "Print configinfo",
146     (uchar**) &g_configinfo, (uchar**) &g_configinfo,
147     0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
148   { "xml", NDB_OPT_NOSHORT, "Print configinfo in xml format",
149     (uchar**) &g_xml, (uchar**) &g_xml,
150     0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
151   { "config_from_node", NDB_OPT_NOSHORT, "Use current config from node with given nodeid",
152     (uchar**) &g_config_from_node, (uchar**) &g_config_from_node,
153     0, GET_INT, REQUIRED_ARG, INT_MIN, INT_MIN, 0, 0, 0, 0},
154   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
155 };
156 
short_usage_sub(void)157 static void short_usage_sub(void)
158 {
159   ndb_short_usage_sub(NULL);
160 }
161 
usage()162 static void usage()
163 {
164   char desc[] =
165     "This program will retreive config options for a ndb cluster\n";
166   puts(desc);
167   ndb_usage(short_usage_sub, load_default_groups, my_long_options);
168 }
169 
170 /**
171  * Match/Apply framework
172  */
173 struct Match
174 {
175   int m_key;
176   BaseString m_value;
MatchMatch177   Match() {}
178   virtual int eval(const Iter&);
~MatchMatch179   virtual ~Match() {}
180 };
181 
182 struct HostMatch : public Match
183 {
HostMatchHostMatch184   HostMatch() {}
185   virtual int eval(const Iter&);
186 };
187 
188 struct Apply
189 {
ApplyApply190   Apply() {}
ApplyApply191   Apply(int val) { m_key = val;}
192   int m_key;
193   virtual int apply(const Iter&);
~ApplyApply194   virtual ~Apply() {}
195 };
196 
197 struct NodeTypeApply : public Apply
198 {
NodeTypeApplyNodeTypeApply199   NodeTypeApply() {}
200   virtual int apply(const Iter&);
201 };
202 
203 struct ConnectionTypeApply : public Apply
204 {
ConnectionTypeApplyConnectionTypeApply205   ConnectionTypeApply() {}
206   virtual int apply(const Iter&);
207 };
208 
209 static int parse_query(Vector<Apply*>&, int &argc, char**& argv);
210 static int parse_where(Vector<Match*>&, int &argc, char**& argv);
211 static int eval(const Iter&, const Vector<Match*>&);
212 static int apply(const Iter&, const Vector<Apply*>&);
213 static ndb_mgm_configuration* fetch_configuration(int from_node);
214 static ndb_mgm_configuration* load_configuration();
215 
216 
217 int
main(int argc,char ** argv)218 main(int argc, char** argv){
219   NDB_INIT(argv[0]);
220   ndb_opt_set_usage_funcs(short_usage_sub, usage);
221   load_defaults("my",load_default_groups,&argc,&argv);
222   int ho_error;
223   if ((ho_error=handle_options(&argc, &argv, my_long_options,
224 			       ndb_std_get_one_option)))
225     exit(255);
226 
227   if (g_configinfo)
228   {
229     ConfigInfo info;
230     if (g_xml)
231       info.print_xml();
232     else
233       info.print();
234     exit(0);
235   }
236 
237   if ((g_nodes && g_connections) ||
238       (g_system && (g_nodes || g_connections)))
239   {
240     fprintf(stderr,
241 	    "Error: Only one of the section-options: --nodes, --connections, --system is allowed.\n");
242     exit(255);
243   }
244 
245   /* There is no explicit option for the user to set
246    * 'retrieving config from mgmd', but this is the default.
247    * Therefore will not contradict with other sources.
248    */
249 
250   if ((g_config_file && g_mycnf) ||
251       ((g_config_from_node != INT_MIN) && (g_config_file || g_mycnf)))
252   {
253     fprintf(stderr,
254 	    "Error: Config should be retrieved from only one of the following sources:\n");
255     fprintf(stderr,
256             "\tconfig stored at mgmd (default),\n");
257     fprintf(stderr,
258             "\tconfig stored at a data node (--config_from_node=<nodeid>), \n");
259     fprintf(stderr,
260             "\tmy.cnf(--mycnf=<my.cnf file>),\n");
261     fprintf(stderr,
262              "\tconfig.file (--config_file=<config file>).\n");
263     exit(255);
264   }
265 
266   g_section = CFG_SECTION_NODE; //default
267   if (g_connections)
268     g_section = CFG_SECTION_CONNECTION;
269   else if (g_system)
270     g_section = CFG_SECTION_SYSTEM;
271 
272   ndb_mgm_configuration * conf = 0;
273 
274   if (g_config_file || g_mycnf)
275     conf = load_configuration();
276   else
277     conf = fetch_configuration(g_config_from_node);
278 
279   if (conf == 0)
280   {
281     exit(255);
282   }
283 
284   Vector<Apply*> select_list;
285   Vector<Match*> where_clause;
286 
287   if(strcmp(g_row_delimiter, "\\n") == 0)
288     g_row_delimiter = "\n";
289   if(strcmp(g_field_delimiter, "\\n") == 0)
290     g_field_delimiter = "\n";
291 
292   if(parse_query(select_list, argc, argv))
293   {
294     exit(0);
295   }
296 
297   if(parse_where(where_clause, argc, argv))
298   {
299     exit(0);
300   }
301 
302   Iter iter(* conf, g_section);
303   bool prev= false;
304   iter.first();
305   for(iter.first(); iter.valid(); iter.next())
306   {
307     if(eval(iter, where_clause))
308     {
309       if(prev)
310 	printf("%s", g_row_delimiter);
311       prev= true;
312       apply(iter, select_list);
313     }
314   }
315   printf("\n");
316   return 0;
317 }
318 
319 static
320 int
parse_query(Vector<Apply * > & select,int & argc,char ** & argv)321 parse_query(Vector<Apply*>& select, int &argc, char**& argv)
322 {
323   if(g_query)
324   {
325     BaseString q(g_query);
326     Vector<BaseString> list;
327     q.split(list, ",");
328     for(unsigned i = 0; i<list.size(); i++)
329     {
330       const char * str= list[i].c_str();
331       if(g_section == CFG_SECTION_NODE)
332       {
333 	if(strcasecmp(str, "id") == 0 || strcasecmp(str, "nodeid") == 0)
334 	{
335 	  select.push_back(new Apply(CFG_NODE_ID));
336 	  continue;
337 	}
338 	else if(strncasecmp(str, "host", 4) == 0)
339 	{
340 	  select.push_back(new Apply(CFG_NODE_HOST));
341 	  continue;
342 	}
343 	else if(strcasecmp(str, "type") == 0)
344 	{
345 	  select.push_back(new NodeTypeApply());
346 	  continue;
347 	}
348       }
349       else if (g_section == CFG_SECTION_CONNECTION)
350       {
351 	if(strcasecmp(str, "type") == 0)
352 	{
353 	  select.push_back(new ConnectionTypeApply());
354 	  continue;
355 	}
356       }
357       {
358 	bool found = false;
359 	for(int p = 0; p<ConfigInfo::m_NoOfParams; p++)
360 	{
361 	  if(0)ndbout_c("%s %s",
362 			ConfigInfo::m_ParamInfo[p]._section,
363 			ConfigInfo::m_ParamInfo[p]._fname);
364 	  if((g_section == CFG_SECTION_CONNECTION &&
365               (strcmp(ConfigInfo::m_ParamInfo[p]._section, "TCP") == 0 ||
366                strcmp(ConfigInfo::m_ParamInfo[p]._section, "SCI") == 0 ||
367                strcmp(ConfigInfo::m_ParamInfo[p]._section, "SHM") == 0))
368              ||
369 	     (g_section == CFG_SECTION_NODE &&
370               (strcmp(ConfigInfo::m_ParamInfo[p]._section, "DB") == 0 ||
371                strcmp(ConfigInfo::m_ParamInfo[p]._section, "API") == 0 ||
372                strcmp(ConfigInfo::m_ParamInfo[p]._section, "MGM") == 0))
373              ||
374 	     (g_section == CFG_SECTION_SYSTEM))
375 	  {
376 	    if(strcasecmp(ConfigInfo::m_ParamInfo[p]._fname, str) == 0)
377 	    {
378 	      select.push_back(new Apply(ConfigInfo::m_ParamInfo[p]._paramId));
379 	      found = true;
380 	      break;
381 	    }
382 	  }
383 	}
384 	if(!found)
385 	{
386 	  fprintf(stderr, "Unknown query option: %s\n", str);
387 	  return 1;
388 	}
389       }
390     }
391   }
392   return 0;
393 }
394 
395 static
396 int
parse_where(Vector<Match * > & where,int & argc,char ** & argv)397 parse_where(Vector<Match*>& where, int &argc, char**& argv)
398 {
399   Match m;
400   if(g_host)
401   {
402     HostMatch *tmp = new HostMatch;
403     tmp->m_key = CFG_NODE_HOST;
404     tmp->m_value.assfmt("%s", g_host);
405     where.push_back(tmp);
406   }
407 
408   if(g_type)
409   {
410     m.m_key = CFG_TYPE_OF_SECTION;
411     m.m_value.assfmt("%d", ndb_mgm_match_node_type(g_type));
412     where.push_back(new Match(m));
413   }
414 
415   if(g_nodeid)
416   {
417     m.m_key = CFG_NODE_ID;
418     m.m_value.assfmt("%d", g_nodeid);
419     where.push_back(new Match(m));
420   }
421   return 0;
422 }
423 
424 template class Vector<Apply*>;
425 template class Vector<Match*>;
426 
427 static
428 int
eval(const Iter & iter,const Vector<Match * > & where)429 eval(const Iter& iter, const Vector<Match*>& where)
430 {
431   for(unsigned i = 0; i<where.size(); i++)
432   {
433     if(where[i]->eval(iter) == 0)
434       return 0;
435   }
436 
437   return 1;
438 }
439 
440 static
441 int
apply(const Iter & iter,const Vector<Apply * > & list)442 apply(const Iter& iter, const Vector<Apply*>& list)
443 {
444   for(unsigned i = 0; i<list.size(); i++)
445   {
446     list[i]->apply(iter);
447     if(i + 1 != list.size())
448       printf("%s", g_field_delimiter);
449   }
450   return 0;
451 }
452 
453 int
eval(const Iter & iter)454 Match::eval(const Iter& iter)
455 {
456   Uint32 val32;
457   Uint64 val64;
458   const char* valc;
459   if (iter.get(m_key, &val32) == 0)
460   {
461     if(atoi(m_value.c_str()) != (int)val32)
462       return 0;
463   }
464   else if(iter.get(m_key, &val64) == 0)
465   {
466     if(strtoll(m_value.c_str(), (char **)NULL, 10) != (long long)val64)
467       return 0;
468   }
469   else if(iter.get(m_key, &valc) == 0)
470   {
471     if(strcmp(m_value.c_str(), valc) != 0)
472       return 0;
473   }
474   else
475   {
476     return 0;
477   }
478   return 1;
479 }
480 
481 int
eval(const Iter & iter)482 HostMatch::eval(const Iter& iter)
483 {
484   const char* valc;
485 
486   if(iter.get(m_key, &valc) == 0)
487   {
488 	  struct hostent *h1, *h2, copy1;
489 	  char *addr1;
490 
491 	  h1 = gethostbyname(m_value.c_str());
492 	  if (h1 == NULL) {
493 		  return 0;
494 	  }
495 
496 	  // gethostbyname returns a pointer to a static structure
497 	  // so we need to copy the results before doing the next call
498 	  memcpy(&copy1, h1, sizeof(struct hostent));
499 	  addr1 = (char *)malloc(copy1.h_length);
500 	  NdbAutoPtr<char> tmp_aptr(addr1);
501 	  memcpy(addr1, h1->h_addr, copy1.h_length);
502 
503 	  h2 = gethostbyname(valc);
504 	  if (h2 == NULL) {
505 		  return 0;
506 	  }
507 
508 	  if (copy1.h_addrtype != h2->h_addrtype) {
509 		  return 0;
510 	  }
511 
512 	  if (copy1.h_length != h2->h_length)
513 	  {
514 		  return 0;
515 	  }
516 
517 	  return 0 ==  memcmp(addr1, h2->h_addr, copy1.h_length);
518   }
519 
520   return 0;
521 }
522 
523 int
apply(const Iter & iter)524 Apply::apply(const Iter& iter)
525 {
526   Uint32 val32;
527   Uint64 val64;
528   const char* valc;
529   if (iter.get(m_key, &val32) == 0)
530   {
531     printf("%u", val32);
532   }
533   else if(iter.get(m_key, &val64) == 0)
534   {
535     printf("%llu", val64);
536   }
537   else if(iter.get(m_key, &valc) == 0)
538   {
539     printf("%s", valc);
540   }
541   return 0;
542 }
543 
544 int
apply(const Iter & iter)545 NodeTypeApply::apply(const Iter& iter)
546 {
547   Uint32 val32;
548   if (iter.get(CFG_TYPE_OF_SECTION, &val32) == 0)
549   {
550     printf("%s", ndb_mgm_get_node_type_alias_string((ndb_mgm_node_type)val32, 0));
551   }
552   return 0;
553 }
554 
555 int
apply(const Iter & iter)556 ConnectionTypeApply::apply(const Iter& iter)
557 {
558   Uint32 val32;
559   if (iter.get(CFG_TYPE_OF_SECTION, &val32) == 0)
560   {
561     switch (val32)
562     {
563     case CONNECTION_TYPE_TCP:
564       printf("tcp");
565       break;
566     case CONNECTION_TYPE_SCI:
567       printf("sci");
568       break;
569     case CONNECTION_TYPE_SHM:
570       printf("shm");
571       break;
572     default:
573       printf("<unknown>");
574       break;
575     }
576   }
577   return 0;
578 }
579 
580 static ndb_mgm_configuration*
fetch_configuration(int from_node)581 fetch_configuration(int from_node)
582 {
583   ndb_mgm_configuration* conf = 0;
584   NdbMgmHandle mgm = ndb_mgm_create_handle();
585   if(mgm == NULL) {
586     fprintf(stderr, "Cannot create handle to management server.\n");
587     return 0;
588   }
589 
590   ndb_mgm_set_error_stream(mgm, stderr);
591 
592   if (ndb_mgm_set_connectstring(mgm, opt_ndb_connectstring))
593   {
594     fprintf(stderr, "* %5d: %s\n",
595 	    ndb_mgm_get_latest_error(mgm),
596 	    ndb_mgm_get_latest_error_msg(mgm));
597     fprintf(stderr,
598 	    "*        %s", ndb_mgm_get_latest_error_desc(mgm));
599     goto noconnect;
600   }
601 
602   if(ndb_mgm_connect(mgm, try_reconnect-1, 5, 1))
603   {
604     fprintf(stderr, "Connect failed");
605     fprintf(stderr, " code: %d, msg: %s\n",
606 	    ndb_mgm_get_latest_error(mgm),
607 	    ndb_mgm_get_latest_error_msg(mgm));
608     goto noconnect;
609   }
610   else if(g_verbose)
611   {
612     fprintf(stderr, "Connected to %s:%d\n",
613 	    ndb_mgm_get_connected_host(mgm),
614 	    ndb_mgm_get_connected_port(mgm));
615   }
616 
617   if (from_node == INT_MIN)
618   {
619     // from_node option is not requested.
620     // Retrieve config from the default src: mgmd
621     conf = ndb_mgm_get_configuration(mgm, 0);
622   }
623   else if (from_node < 1)
624   {
625     fprintf(stderr, "Invalid node number %d is given for --config_from_node.\n", from_node);
626     goto noconnect;
627   }
628   else
629   {
630     // Retrieve config from the given data node
631      conf = ndb_mgm_get_configuration_from_node(mgm, from_node);
632   }
633 
634   if(conf == 0)
635   {
636     fprintf(stderr, "Could not get configuration, ");
637     fprintf(stderr, "error code: %d, error msg: %s\n",
638 	    ndb_mgm_get_latest_error(mgm),
639 	    ndb_mgm_get_latest_error_msg(mgm));
640   }
641   else if(g_verbose)
642   {
643     fprintf(stderr, "Fetched configuration\n");
644   }
645 
646   ndb_mgm_disconnect(mgm);
647 noconnect:
648   ndb_mgm_destroy_handle(&mgm);
649 
650   return conf;
651 }
652 
653 #include "../src/mgmsrv/Config.hpp"
654 #include <EventLogger.hpp>
655 
656 extern EventLogger *g_eventLogger;
657 
658 static ndb_mgm_configuration*
load_configuration()659 load_configuration()
660 {
661   g_eventLogger->removeAllHandlers();
662   g_eventLogger->createConsoleHandler(ndberr);
663   g_eventLogger->setCategory("ndb_config");
664   InitConfigFileParser parser;
665   if (g_config_file)
666   {
667     if (g_verbose)
668       fprintf(stderr, "Using config.ini : %s\n", g_config_file);
669 
670     Config* conf = parser.parseConfig(g_config_file);
671     if (conf)
672       return conf->m_configValues;
673     return 0;
674   }
675 
676   if (g_verbose)
677     fprintf(stderr, "Using my.cnf\n");
678 
679   Config* conf = parser.parse_mycnf();
680   if (conf)
681     return conf->m_configValues;
682 
683   return 0;
684 }
685