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