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(©1, 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