1 /*
2 Copyright (c) 2003, 2021, Oracle and/or its affiliates.
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 #include <ndb_global.h>
26
27 #include <uucode.h>
28 #include <socket_io.h>
29 #include <util/version.h>
30 #include <mgmapi.h>
31 #include <EventLogger.hpp>
32 #include <signaldata/SetLogLevelOrd.hpp>
33 #include <LogLevel.hpp>
34 #include <BaseString.hpp>
35
36 #include <ConfigValues.hpp>
37 #include <mgmapi_configuration.hpp>
38 #include <Vector.hpp>
39 #include "Services.hpp"
40 #include "../mgmapi/ndb_logevent.hpp"
41
42 #include "ndb_mgmd_error.h"
43
44 #include <ndb_base64.h>
45 #include <ndberror.h>
46
47 extern bool g_StopServer;
48 extern bool g_RestartServer;
49 extern EventLogger * g_eventLogger;
50
51 /**
52 const char * name;
53 const char * realName;
54 const Type type;
55 const ArgType argType;
56 const ArgRequired argRequired;
57 const ArgMinMax argMinMax;
58 const int minVal;
59 const int maxVal;
60 void (T::* function)(const class Properties & args);
61 const char * description;
62 */
63
64 #define MGM_CMD(name, fun, desc) \
65 { name, \
66 0, \
67 ParserRow<MgmApiSession>::Cmd, \
68 ParserRow<MgmApiSession>::String, \
69 ParserRow<MgmApiSession>::Optional, \
70 ParserRow<MgmApiSession>::IgnoreMinMax, \
71 0, 0, \
72 fun, \
73 desc, 0 }
74
75 #define MGM_ARG(name, type, opt, desc) \
76 { name, \
77 0, \
78 ParserRow<MgmApiSession>::Arg, \
79 ParserRow<MgmApiSession>::type, \
80 ParserRow<MgmApiSession>::opt, \
81 ParserRow<MgmApiSession>::IgnoreMinMax, \
82 0, 0, \
83 0, \
84 desc, 0 }
85
86 #define MGM_ARG2(name, type, opt, min, max, desc) \
87 { name, \
88 0, \
89 ParserRow<MgmApiSession>::Arg, \
90 ParserRow<MgmApiSession>::type, \
91 ParserRow<MgmApiSession>::opt, \
92 ParserRow<MgmApiSession>::IgnoreMinMax, \
93 min, max, \
94 0, \
95 desc, 0 }
96
97 #define MGM_END() \
98 { 0, \
99 0, \
100 ParserRow<MgmApiSession>::End, \
101 ParserRow<MgmApiSession>::Int, \
102 ParserRow<MgmApiSession>::Optional, \
103 ParserRow<MgmApiSession>::IgnoreMinMax, \
104 0, 0, \
105 0, \
106 0, 0 }
107
108 #define MGM_CMD_ALIAS(name, realName, fun) \
109 { name, \
110 realName, \
111 ParserRow<MgmApiSession>::CmdAlias, \
112 ParserRow<MgmApiSession>::Int, \
113 ParserRow<MgmApiSession>::Optional, \
114 ParserRow<MgmApiSession>::IgnoreMinMax, \
115 0, 0, \
116 0, \
117 0, 0 }
118
119 #define MGM_ARG_ALIAS(name, realName, fun) \
120 { name, \
121 realName, \
122 ParserRow<MgmApiSession>::ArgAlias, \
123 ParserRow<MgmApiSession>::Int, \
124 ParserRow<MgmApiSession>::Optional, \
125 ParserRow<MgmApiSession>::IgnoreMinMax, \
126 0, 0, \
127 0, \
128 0, 0 }
129
130 const
131 ParserRow<MgmApiSession> commands[] = {
132 MGM_CMD("get config", &MgmApiSession::getConfig, ""),
133 MGM_ARG("version", Int, Mandatory, "Configuration version number"),
134 MGM_ARG("node", Int, Optional, "Node ID"),
135 MGM_ARG("nodetype", Int, Optional, "Type of requesting node"),
136 MGM_ARG("from_node", Int, Optional, "Node to get config from"),
137
138 MGM_CMD("get nodeid", &MgmApiSession::get_nodeid, ""),
139 MGM_ARG("version", Int, Mandatory, "Configuration version number"),
140 MGM_ARG("nodetype", Int, Mandatory, "Node type"),
141 MGM_ARG("transporter", String, Optional, "Transporter type"),
142 MGM_ARG("nodeid", Int, Optional, "Node ID"),
143 MGM_ARG("user", String, Mandatory, "Password"),
144 MGM_ARG("password", String, Mandatory, "Password"),
145 MGM_ARG("public key", String, Mandatory, "Public key"),
146 MGM_ARG("endian", String, Optional, "Endianness"),
147 MGM_ARG("name", String, Optional, "Name of connection"),
148 MGM_ARG("timeout", Int, Optional, "Timeout in seconds"),
149 MGM_ARG("log_event", Int, Optional, "Log failure in cluster log"),
150
151 MGM_CMD("get version", &MgmApiSession::getVersion, ""),
152
153 MGM_CMD("get status", &MgmApiSession::getStatus, ""),
154 MGM_ARG("types", String, Optional, "Types"),
155
156 MGM_CMD("get info clusterlog", &MgmApiSession::getInfoClusterLog, ""),
157 MGM_CMD("get cluster loglevel", &MgmApiSession::getClusterLogLevel, ""),
158
159 MGM_CMD("restart node", &MgmApiSession::restart_v1, ""),
160 MGM_ARG("node", String, Mandatory, "Nodes to restart"),
161 MGM_ARG("initialstart", Int, Optional, "Initial start"),
162 MGM_ARG("nostart", Int, Optional, "No start"),
163 MGM_ARG("abort", Int, Optional, "Abort"),
164
165 MGM_CMD("restart node v2", &MgmApiSession::restart_v2, ""),
166 MGM_ARG("node", String, Mandatory, "Nodes to restart"),
167 MGM_ARG("initialstart", Int, Optional, "Initial start"),
168 MGM_ARG("nostart", Int, Optional, "No start"),
169 MGM_ARG("abort", Int, Optional, "Abort"),
170 MGM_ARG("force", Int, Optional, "Force"),
171
172 MGM_CMD("restart all", &MgmApiSession::restartAll, ""),
173 MGM_ARG("initialstart", Int, Optional, "Initial start"),
174 MGM_ARG("nostart", Int, Optional, "No start"),
175 MGM_ARG("abort", Int, Optional, "Abort"),
176
177 MGM_CMD("insert error", &MgmApiSession::insertError, ""),
178 MGM_ARG("node", Int, Mandatory, "Node to receive error"),
179 MGM_ARG("error", Int, Mandatory, "Errorcode to insert"),
180 MGM_ARG("extra", Int, Optional, "Extra info to error insert"),
181
182 MGM_CMD("set trace", &MgmApiSession::setTrace, ""),
183 MGM_ARG("node", Int, Mandatory, "Node"),
184 MGM_ARG("trace", Int, Mandatory, "Trace number"),
185
186 MGM_CMD("log signals", &MgmApiSession::logSignals, ""),
187 MGM_ARG("node", Int, Mandatory, "Node"),
188 MGM_ARG("blocks", String, Mandatory, "Blocks (space separated)"),
189 MGM_ARG("in", Int, Mandatory, "Log input signals"),
190 MGM_ARG("out", Int, Mandatory, "Log output signals"),
191
192 MGM_CMD("start signallog", &MgmApiSession::startSignalLog, ""),
193 MGM_ARG("node", Int, Mandatory, "Node"),
194
195 MGM_CMD("stop signallog", &MgmApiSession::stopSignalLog, ""),
196 MGM_ARG("node", Int, Mandatory, "Node"),
197
198 MGM_CMD("dump state", &MgmApiSession::dumpState, ""),
199 MGM_ARG("node", Int, Mandatory ,"Node"),
200 MGM_ARG("args", String, Mandatory, "Args(space separated int's)"),
201
202 MGM_CMD("start backup", &MgmApiSession::startBackup, ""),
203 MGM_ARG("completed", Int, Optional ,"Wait until completed"),
204 MGM_ARG("backupid", Int, Optional ,"User input backup id"),
205 MGM_ARG("backuppoint", Int, Optional ,"backup snapshot at start time or complete time"),
206
207 MGM_CMD("abort backup", &MgmApiSession::abortBackup, ""),
208 MGM_ARG("id", Int, Mandatory, "Backup id"),
209
210 MGM_CMD("stop", &MgmApiSession::stop_v1, ""),
211 MGM_ARG("node", String, Mandatory, "Node"),
212 MGM_ARG("abort", Int, Mandatory, "Node"),
213
214 MGM_CMD("stop v2", &MgmApiSession::stop_v2, ""),
215 MGM_ARG("node", String, Mandatory, "Node"),
216 MGM_ARG("abort", Int, Mandatory, "Node"),
217 MGM_ARG("force", Int, Optional, "Force"),
218
219 MGM_CMD("stop all", &MgmApiSession::stopAll, ""),
220 MGM_ARG("abort", Int, Mandatory, "Node"),
221 MGM_ARG("stop", String, Optional, "MGM/DB or both"),
222
223 MGM_CMD("enter single user", &MgmApiSession::enterSingleUser, ""),
224 MGM_ARG("nodeId", Int, Mandatory, "Node"),
225
226 MGM_CMD("exit single user", &MgmApiSession::exitSingleUser, ""),
227
228
229 MGM_CMD("start", &MgmApiSession::start, ""),
230 MGM_ARG("node", Int, Mandatory, "Node"),
231
232 MGM_CMD("start all", &MgmApiSession::startAll, ""),
233
234 MGM_CMD("bye", &MgmApiSession::bye, ""),
235
236 MGM_CMD("end session", &MgmApiSession::endSession, ""),
237
238 MGM_CMD("set loglevel", &MgmApiSession::setLogLevel, ""),
239 MGM_ARG("node", Int, Mandatory, "Node"),
240 MGM_ARG("category", Int, Mandatory, "Event category"),
241 MGM_ARG("level", Int, Mandatory, "Log level (0-15)"),
242
243 MGM_CMD("set cluster loglevel", &MgmApiSession::setClusterLogLevel, ""),
244 MGM_ARG("node", Int, Mandatory, "Node"),
245 MGM_ARG("category", Int, Mandatory, "Event category"),
246 MGM_ARG("level", Int, Mandatory, "Log level (0-15)"),
247
248 MGM_CMD("set logfilter", &MgmApiSession::setLogFilter, ""),
249 MGM_ARG("level", Int, Mandatory, "Severety level"),
250 MGM_ARG("enable", Int, Mandatory, "1=disable, 0=enable, -1=toggle"),
251
252 MGM_CMD("set parameter", &MgmApiSession::setParameter, ""),
253 MGM_ARG("node", Int, Mandatory, "Node"),
254 MGM_ARG("parameter", Int, Mandatory, "Parameter"),
255 MGM_ARG("value", String, Mandatory, "Value"),
256
257 MGM_CMD("set connection parameter",
258 &MgmApiSession::setConnectionParameter, ""),
259 MGM_ARG("node1", Int, Mandatory, "Node1 ID"),
260 MGM_ARG("node2", Int, Mandatory, "Node2 ID"),
261 MGM_ARG("param", Int, Mandatory, "Parameter"),
262 MGM_ARG("value", Int, Mandatory, "Value"),
263
264 MGM_CMD("get connection parameter",
265 &MgmApiSession::getConnectionParameter, ""),
266 MGM_ARG("node1", Int, Mandatory, "Node1 ID"),
267 MGM_ARG("node2", Int, Mandatory, "Node2 ID"),
268 MGM_ARG("param", Int, Mandatory, "Parameter"),
269
270 MGM_CMD("listen event", &MgmApiSession::listen_event, ""),
271 MGM_ARG("node", Int, Optional, "Node"),
272 MGM_ARG("parsable", Int, Optional, "Parsable"),
273 MGM_ARG("filter", String, Mandatory, "Event category"),
274
275 MGM_CMD("purge stale sessions", &MgmApiSession::purge_stale_sessions, ""),
276
277 MGM_CMD("check connection", &MgmApiSession::check_connection, ""),
278
279 MGM_CMD("transporter connect", &MgmApiSession::transporter_connect, ""),
280
281 MGM_CMD("get mgmd nodeid", &MgmApiSession::get_mgmd_nodeid, ""),
282
283 MGM_CMD("report event", &MgmApiSession::report_event, ""),
284 MGM_ARG("length", Int, Mandatory, "Length"),
285 MGM_ARG("data", String, Mandatory, "Data"),
286
287 MGM_CMD("list sessions", &MgmApiSession::listSessions, ""),
288
289 MGM_CMD("get session id", &MgmApiSession::getSessionId, ""),
290
291 MGM_CMD("get session", &MgmApiSession::getSession, ""),
292 MGM_ARG("id", Int, Mandatory, "SessionID"),
293
294 MGM_CMD("set config", &MgmApiSession::setConfig, ""),
295 MGM_ARG("Content-Length", Int, Mandatory, "Length of config"),
296 MGM_ARG("Content-Type", String, Mandatory, "Type of config"),
297 MGM_ARG("Content-Transfer-Encoding", String, Mandatory, "encoding"),
298
299 MGM_CMD("create nodegroup", &MgmApiSession::create_nodegroup, ""),
300 MGM_ARG("nodes", String, Mandatory, "Nodes"),
301
302 MGM_CMD("drop nodegroup", &MgmApiSession::drop_nodegroup, ""),
303 MGM_ARG("ng", Int, Mandatory, "Nodegroup"),
304
305 MGM_CMD("show config", &MgmApiSession::showConfig, ""),
306 MGM_ARG("Section", String, Optional, "Section name"),
307 MGM_ARG("NodeId", Int, Optional, "Nodeid"),
308 MGM_ARG("Name", String, Optional, "Parameter name"),
309
310 MGM_CMD("reload config", &MgmApiSession::reloadConfig, ""),
311 MGM_ARG("config_filename", String, Optional, "Reload from path"),
312 MGM_ARG("mycnf", Int, Optional, "Reload from my.cnf"),
313 MGM_ARG("force", Int, Optional, "Force reload"),
314
315 MGM_CMD("show variables", &MgmApiSession::show_variables, ""),
316
317 MGM_CMD("dump events", &MgmApiSession::dump_events, ""),
318 MGM_ARG("type", Int, Mandatory, "Type of event"),
319 MGM_ARG("nodes", String, Optional, "Nodes to include"),
320
321 MGM_CMD("set ports", &MgmApiSession::set_ports, ""),
322 MGM_ARG("node", Int, Mandatory, "Node which port list concerns"),
323 MGM_ARG("num_ports", Int, Mandatory, "Number of ports being set"),
324
325 MGM_END()
326 };
327
328 extern int g_errorInsert;
329 #define ERROR_INSERTED(x) (g_errorInsert == x || m_errorInsert == x)
330
331 #define SLEEP_ERROR_INSERTED(x) if(ERROR_INSERTED(x)){NdbSleep_SecSleep(10);}
332
MgmApiSession(class MgmtSrvr & mgm,NDB_SOCKET_TYPE sock,Uint64 session_id)333 MgmApiSession::MgmApiSession(class MgmtSrvr & mgm, NDB_SOCKET_TYPE sock, Uint64 session_id)
334 : SocketServer::Session(sock), m_mgmsrv(mgm),
335 m_session_id(session_id), m_name("unknown:0")
336 {
337 DBUG_ENTER("MgmApiSession::MgmApiSession");
338 m_input = new SocketInputStream(sock, SOCKET_TIMEOUT);
339 m_output = new BufferedSockOutputStream(sock, SOCKET_TIMEOUT);
340 m_parser = new Parser_t(commands, *m_input);
341 m_stopSelf= 0;
342 m_ctx= NULL;
343 m_mutex= NdbMutex_Create();
344 m_errorInsert= 0;
345
346 struct sockaddr_in addr;
347 SOCKET_SIZE_TYPE addrlen= sizeof(addr);
348 if (my_getpeername(sock, (struct sockaddr*)&addr, &addrlen) == 0)
349 {
350 char addr_buf[NDB_ADDR_STRLEN];
351 char *addr_str = Ndb_inet_ntop(AF_INET,
352 static_cast<void*>(&addr.sin_addr),
353 addr_buf,
354 (socklen_t)sizeof(addr_buf));
355 m_name.assfmt("%s:%d", addr_str, ntohs(addr.sin_port));
356 }
357 DBUG_PRINT("info", ("new connection from: %s", m_name.c_str()));
358
359 DBUG_VOID_RETURN;
360 }
361
~MgmApiSession()362 MgmApiSession::~MgmApiSession()
363 {
364 DBUG_ENTER("MgmApiSession::~MgmApiSession");
365 if (m_input)
366 delete m_input;
367 if (m_output)
368 delete m_output;
369 if (m_parser)
370 delete m_parser;
371 if(my_socket_valid(m_socket))
372 {
373 NDB_CLOSE_SOCKET(m_socket);
374 my_socket_invalidate(&m_socket);
375 }
376 if(m_stopSelf < 0)
377 g_RestartServer= true;
378 if(m_stopSelf)
379 g_StopServer= true;
380 NdbMutex_Destroy(m_mutex);
381 DBUG_VOID_RETURN;
382 }
383
384 void
runSession()385 MgmApiSession::runSession()
386 {
387 DBUG_ENTER("MgmApiSession::runSession");
388
389 g_eventLogger->debug("%s: Connected!", name());
390
391 Parser_t::Context ctx;
392 ctx.m_mutex= m_mutex;
393 m_ctx= &ctx;
394 bool stop= false;
395 while(!stop) {
396 NdbMutex_Lock(m_mutex);
397
398 m_input->reset_timeout();
399 m_output->reset_timeout();
400
401 if (m_parser->run(ctx, *this))
402 {
403 stop= m_stop; // Has session been stopped
404 assert(ctx.m_status == Parser_t::Ok);
405 }
406 else
407 {
408 stop= m_stop; // Has session been stopped
409 const char* msg= NULL;
410 switch(ctx.m_status) {
411 case Parser_t::Eof: // Client disconnected
412 stop= true;
413 g_eventLogger->debug("%s: Eof!", name());
414 break;
415
416 case Parser_t::ExternalStop: // Stopped by other thread
417 stop= true;
418 g_eventLogger->debug("%s: ExternalStop!", name());
419 break;
420
421 case Parser_t::NoLine: // Normal read timeout
422 case Parser_t::EmptyLine:
423 break;
424
425 case Parser_t::UnknownCommand: msg= "Unknown command"; break;
426 case Parser_t::UnknownArgument: msg= "Unknown argument"; break;
427 case Parser_t::TypeMismatch: msg= "Type mismatch"; break;
428 case Parser_t::InvalidArgumentFormat: msg= "Invalid arg. format"; break;
429 case Parser_t::UnknownArgumentType: msg= "Unknown argument type"; break;
430 case Parser_t::ArgumentGivenTwice: msg= "Argument given twice"; break;
431 case Parser_t::MissingMandatoryArgument: msg= "Missing arg."; break;
432
433 case Parser_t::Ok: // Should never happen here
434 case Parser_t::CommandWithoutFunction:
435 abort();
436 break;
437 }
438
439 if (msg){
440 g_eventLogger->debug("%s: %s, '%s'",
441 name(),
442 msg,
443 ctx.m_currentToken != 0 ?
444 ctx.m_currentToken : "<NULL>");
445
446 // Send result to client
447 m_output->println("result: %s, '%s'",
448 msg,
449 ctx.m_currentToken != 0 ?
450 ctx.m_currentToken : "<NULL>");
451 m_output->print("\n");
452 }
453 }
454
455 NdbMutex_Unlock(m_mutex);
456
457 // Send output from command to the client
458 m_output->flush();
459
460 }
461
462 g_eventLogger->debug("%s: Stopped!", name());
463
464 NdbMutex_Lock(m_mutex);
465 m_ctx= NULL;
466 if(my_socket_valid(m_socket))
467 {
468 my_socket_close(m_socket);
469 my_socket_invalidate(&m_socket);
470 }
471 NdbMutex_Unlock(m_mutex);
472
473 g_eventLogger->debug("%s: Disconnected!", name());
474
475 DBUG_VOID_RETURN;
476 }
477
478 void
get_nodeid(Parser_t::Context &,const class Properties & args)479 MgmApiSession::get_nodeid(Parser_t::Context &,
480 const class Properties &args)
481 {
482 Uint32 version, nodeid= 0, nodetype= 0xff;
483 Uint32 timeout= 20; // timeout in seconds
484 const char * endian= NULL;
485 const char * name= NULL;
486 Uint32 log_event= 1;
487
488 args.get("version", &version);
489 args.get("nodetype", &nodetype);
490 // transporter
491 args.get("nodeid", &nodeid);
492 // user
493 // password
494 // public key
495 args.get("endian", &endian);
496 args.get("name", &name);
497 args.get("timeout", &timeout);
498 /* for backwards compatability keep track if client uses new protocol */
499 const bool log_event_version= args.get("log_event", &log_event);
500
501 m_output->println("get nodeid reply");
502
503 // Check that client says it's using same endian
504 {
505 union { long l; char c[sizeof(long)]; } endian_check;
506 endian_check.l = 1;
507 if (endian &&
508 strcmp(endian,(endian_check.c[sizeof(long)-1])?"big":"little")!=0)
509 {
510 m_output->println("result: Node does not have the same "
511 "endianness as the management server.");
512 m_output->println("%s", "");
513 return;
514 }
515 }
516
517 bool compatible;
518 switch (nodetype) {
519 case NODE_TYPE_MGM:
520 case NODE_TYPE_API:
521 compatible = ndbCompatible_mgmt_api(NDB_VERSION, version);
522 break;
523 case NODE_TYPE_DB:
524 compatible = ndbCompatible_mgmt_ndb(NDB_VERSION, version);
525 break;
526 default:
527 m_output->println("result: unknown nodetype %d", nodetype);
528 m_output->println("%s", "");
529 return;
530 }
531
532 struct sockaddr_in addr;
533 {
534 SOCKET_SIZE_TYPE addrlen= sizeof(addr);
535 int r = my_getpeername(m_socket, (struct sockaddr*)&addr, &addrlen);
536 if (r != 0 )
537 {
538 m_output->println("result: getpeername(" MY_SOCKET_FORMAT \
539 ") failed, err= %d",
540 MY_SOCKET_FORMAT_VALUE(m_socket), r);
541 m_output->println("%s", "");
542 return;
543 }
544 }
545
546 /* Check nodeid parameter */
547 if (nodeid > MAX_NODES_ID)
548 {
549 m_output->println("result: illegal nodeid %u", nodeid);
550 m_output->println("%s", "");
551 return;
552 }
553
554 NodeId tmp= nodeid;
555 BaseString error_string;
556 int error_code;
557 if (!m_mgmsrv.alloc_node_id(tmp,
558 (ndb_mgm_node_type)nodetype,
559 (struct sockaddr*)&addr,
560 error_code, error_string,
561 log_event,
562 timeout))
563 {
564 m_output->println("result: %s", error_string.c_str());
565 /* only use error_code in reply if client knows about it */
566 if (log_event_version)
567 m_output->println("error_code: %d", error_code);
568 m_output->println("%s", "");
569 return;
570 }
571
572 m_output->println("nodeid: %u", tmp);
573 m_output->println("result: Ok");
574 m_output->println("%s", "");
575
576 if (name)
577 g_eventLogger->info("Node %d: %s", tmp, name);
578
579 return;
580 }
581
582 void
getConfig(Parser_t::Context &,const class Properties & args)583 MgmApiSession::getConfig(Parser_t::Context &,
584 const class Properties &args)
585 {
586 Uint32 nodetype = NDB_MGM_NODE_TYPE_UNKNOWN;
587 Uint32 from_node = 0;
588
589 // Ignoring mandatory parameter "version"
590 // Ignoring optional parameter "node"
591 args.get("nodetype", &nodetype);
592 args.get("from_node", &from_node);
593
594 SLEEP_ERROR_INSERTED(1);
595 m_output->println("get config reply");
596
597 BaseString pack64, error;
598
599 UtilBuffer packed;
600
601 bool success = (from_node > 0) ?
602 m_mgmsrv.get_packed_config_from_node(from_node,
603 pack64, error) :
604 m_mgmsrv.get_packed_config((ndb_mgm_node_type)nodetype,
605 pack64, error);
606
607 if (!success)
608 {
609 m_output->println("result: %s", error.c_str());
610 m_output->print("\n");
611 return;
612 }
613
614 m_output->println("result: Ok");
615 m_output->println("Content-Length: %u", pack64.length());
616 m_output->println("Content-Type: ndbconfig/octet-stream");
617 SLEEP_ERROR_INSERTED(2);
618 m_output->println("Content-Transfer-Encoding: base64");
619 m_output->print("\n");
620
621 unsigned len = (unsigned)strlen(pack64.c_str());
622 if(ERROR_INSERTED(3))
623 {
624 // Return only half the packed config
625 BaseString half64 = pack64.substr(0, pack64.length());
626 m_output->write(half64.c_str(), (unsigned)strlen(half64.c_str()));
627 m_output->write("\n", 1);
628 return;
629 }
630 m_output->write(pack64.c_str(), len);
631 m_output->write("\n\n", 2);
632 return;
633 }
634
635 void
insertError(Parser<MgmApiSession>::Context &,Properties const & args)636 MgmApiSession::insertError(Parser<MgmApiSession>::Context &,
637 Properties const &args) {
638 Uint32 extra = 0;
639 Uint32 node = 0, error = 0;
640 int result= 0;
641
642 args.get("node", &node);
643 args.get("error", &error);
644 const bool hasExtra = args.get("extra", &extra);
645 Uint32 * extraptr = hasExtra ? &extra : 0;
646
647 if(node==m_mgmsrv.getOwnNodeId()
648 && error < MGM_ERROR_MAX_INJECT_SESSION_ONLY)
649 {
650 m_errorInsert= error;
651 if(error==0)
652 g_errorInsert= error;
653 }
654 else
655 {
656 result= m_mgmsrv.insertError(node, error, extraptr);
657 }
658
659 m_output->println("insert error reply");
660 if(result != 0)
661 m_output->println("result: %s", get_error_text(result));
662 else
663 m_output->println("result: Ok");
664 m_output->println("%s", "");
665 }
666
667 void
setTrace(Parser<MgmApiSession>::Context &,Properties const & args)668 MgmApiSession::setTrace(Parser<MgmApiSession>::Context &,
669 Properties const &args) {
670 Uint32 node = 0, trace = 0;
671
672 args.get("node", &node);
673 args.get("trace", &trace);
674
675 int result = m_mgmsrv.setTraceNo(node, trace);
676
677 m_output->println("set trace reply");
678 if(result != 0)
679 m_output->println("result: %s", get_error_text(result));
680 else
681 m_output->println("result: Ok");
682 m_output->println("%s", "");
683 }
684
685 void
getVersion(Parser<MgmApiSession>::Context &,Properties const &)686 MgmApiSession::getVersion(Parser<MgmApiSession>::Context &,
687 Properties const &) {
688 m_output->println("version");
689 m_output->println("id: %d", NDB_VERSION_D);
690 m_output->println("major: %d", NDB_VERSION_MAJOR);
691 m_output->println("minor: %d", NDB_VERSION_MINOR);
692 m_output->println("build: %d", NDB_VERSION_BUILD);
693 m_output->println("string: %s", m_mgmsrv.get_version_string());
694 m_output->println("mysql_major: %d", NDB_MYSQL_VERSION_MAJOR);
695 m_output->println("mysql_minor: %d", NDB_MYSQL_VERSION_MINOR);
696 m_output->println("mysql_build: %d", NDB_MYSQL_VERSION_BUILD);
697 m_output->println("%s", "");
698 }
699
700 void
startBackup(Parser<MgmApiSession>::Context &,Properties const & args)701 MgmApiSession::startBackup(Parser<MgmApiSession>::Context &,
702 Properties const &args) {
703 DBUG_ENTER("MgmApiSession::startBackup");
704 unsigned backupId;
705 unsigned input_backupId= 0;
706 unsigned backuppoint= 0;
707 Uint32 completed= 2;
708 int result;
709
710 args.get("completed", &completed);
711
712 if(args.contains("backupid"))
713 args.get("backupid", &input_backupId);
714 if(args.contains("backuppoint"))
715 args.get("backuppoint", &backuppoint);
716
717 result = m_mgmsrv.startBackup(backupId, completed, input_backupId, backuppoint);
718
719 m_output->println("start backup reply");
720 if(result != 0)
721 {
722 m_output->println("result: %s", get_error_text(result));
723 }
724 else{
725 m_output->println("result: Ok");
726 if (completed)
727 m_output->println("id: %d", backupId);
728 }
729 m_output->println("%s", "");
730 DBUG_VOID_RETURN;
731 }
732
733 void
abortBackup(Parser<MgmApiSession>::Context &,Properties const & args)734 MgmApiSession::abortBackup(Parser<MgmApiSession>::Context &,
735 Properties const &args) {
736 Uint32 id = 0;
737
738 args.get("id", &id);
739
740 int result = m_mgmsrv.abortBackup(id);
741
742 m_output->println("abort backup reply");
743 if(result != 0)
744 m_output->println("result: %s", get_error_text(result));
745 else
746 m_output->println("result: Ok");
747 m_output->println("%s", "");
748 }
749
750 /*****************************************************************************/
751
752 void
dumpState(Parser<MgmApiSession>::Context &,Properties const & args)753 MgmApiSession::dumpState(Parser<MgmApiSession>::Context &,
754 Properties const &args) {
755 Uint32 node;
756 BaseString args_str;
757
758 args.get("node", &node);
759 args.get("args", args_str);
760
761 int result = m_mgmsrv.dumpState(node, args_str.c_str());
762 m_output->println("dump state reply");
763 if(result != 0)
764 m_output->println("result: %s", get_error_text(result));
765 else
766 m_output->println("result: Ok");
767 m_output->println("%s", "");
768 }
769
770
771 void
bye(Parser<MgmApiSession>::Context &,Properties const &)772 MgmApiSession::bye(Parser<MgmApiSession>::Context &,
773 Properties const &) {
774 m_stop = true;
775 }
776
777 void
endSession(Parser<MgmApiSession>::Context &,Properties const &)778 MgmApiSession::endSession(Parser<MgmApiSession>::Context &,
779 Properties const &)
780 {
781 SLEEP_ERROR_INSERTED(4);
782 m_output->println("end session reply");
783 }
784
785 void
getClusterLogLevel(Parser<MgmApiSession>::Context &,Properties const &)786 MgmApiSession::getClusterLogLevel(Parser<MgmApiSession>::Context & , Properties const &) {
787 const char* names[] = { "startup",
788 "shutdown",
789 "statistics",
790 "checkpoint",
791 "noderestart",
792 "connection",
793 "info",
794 "warning",
795 "error",
796 "congestion",
797 "debug",
798 "backup",
799 "schema" };
800
801 int const loglevel_count = (CFG_MAX_LOGLEVEL - CFG_MIN_LOGLEVEL + 1);
802 NDB_STATIC_ASSERT(NDB_ARRAY_SIZE(names) == loglevel_count);
803 LogLevel::EventCategory category;
804
805 m_output->println("get cluster loglevel");
806 for(int i = 0; i < loglevel_count; i++) {
807 category = (LogLevel::EventCategory) i;
808 m_output->println("%s: %d", names[i], m_mgmsrv.m_event_listner[0].m_logLevel.getLogLevel(category));
809 }
810 m_output->println("%s", "");
811 }
812
813 void
setClusterLogLevel(Parser<MgmApiSession>::Context &,Properties const & args)814 MgmApiSession::setClusterLogLevel(Parser<MgmApiSession>::Context &,
815 Properties const &args) {
816 Uint32 node, level, cat;
817 BaseString errorString;
818 DBUG_ENTER("MgmApiSession::setClusterLogLevel");
819 args.get("node", &node);
820 args.get("category", &cat);
821 args.get("level", &level);
822
823 DBUG_PRINT("enter",("node=%d, category=%d, level=%d", node, cat, level));
824
825 m_output->println("set cluster loglevel reply");
826
827 if(level > NDB_MGM_MAX_LOGLEVEL) {
828 m_output->println("result: Invalid loglevel %d", level);
829 m_output->println("%s", "");
830 DBUG_VOID_RETURN;
831 }
832
833 LogLevel::EventCategory category=
834 (LogLevel::EventCategory)(cat-(int)CFG_MIN_LOGLEVEL);
835
836 m_mgmsrv.m_event_listner.lock();
837 if (m_mgmsrv.m_event_listner[0].m_logLevel.setLogLevel(category,level))
838 {
839 m_output->println("result: Invalid category %d", category);
840 m_output->println("%s", "");
841 m_mgmsrv.m_event_listner.unlock();
842 DBUG_VOID_RETURN;
843 }
844 m_mgmsrv.m_event_listner.unlock();
845
846 {
847 LogLevel tmp;
848 m_mgmsrv.m_event_listner.update_max_log_level(tmp);
849 }
850
851 m_output->println("result: Ok");
852 m_output->println("%s", "");
853 DBUG_VOID_RETURN;
854 }
855
856 void
setLogLevel(Parser<MgmApiSession>::Context &,Properties const & args)857 MgmApiSession::setLogLevel(Parser<MgmApiSession>::Context &,
858 Properties const &args) {
859 Uint32 node = 0, level = 0, cat;
860 BaseString errorString;
861 SetLogLevelOrd logLevel;
862 logLevel.clear();
863 args.get("node", &node);
864 args.get("category", &cat);
865 args.get("level", &level);
866
867 if(level > NDB_MGM_MAX_LOGLEVEL) {
868 m_output->println("set loglevel reply");
869 m_output->println("result: Invalid loglevel: %s", errorString.c_str());
870 m_output->println("%s", "");
871 return;
872 }
873
874 LogLevel::EventCategory category=
875 (LogLevel::EventCategory)(cat-(int)CFG_MIN_LOGLEVEL);
876
877 {
878 LogLevel ll;
879 ll.setLogLevel(category,level);
880 m_mgmsrv.m_event_listner.update_max_log_level(ll);
881 }
882
883 m_output->println("set loglevel reply");
884 m_output->println("result: Ok");
885 m_output->println("%s", "");
886 }
887
888 void
stopSignalLog(Parser<MgmApiSession>::Context &,Properties const & args)889 MgmApiSession::stopSignalLog(Parser<MgmApiSession>::Context &,
890 Properties const &args) {
891 Uint32 node;
892
893 args.get("node", &node);
894
895 int result = m_mgmsrv.stopSignalTracing(node);
896
897 m_output->println("stop signallog");
898 if(result != 0)
899 m_output->println("result: %s", get_error_text(result));
900 else
901 m_output->println("result: Ok");
902 m_output->println("%s", "");
903 }
904
905 void
restart_v1(Parser<MgmApiSession>::Context &,Properties const & args)906 MgmApiSession::restart_v1(Parser<MgmApiSession>::Context &,
907 Properties const &args) {
908 restart(args,1);
909 }
910
911 void
restart_v2(Parser<MgmApiSession>::Context &,Properties const & args)912 MgmApiSession::restart_v2(Parser<MgmApiSession>::Context &,
913 Properties const &args) {
914 restart(args,2);
915 }
916
917 void
restart(Properties const & args,int version)918 MgmApiSession::restart(Properties const &args, int version) {
919 Uint32
920 nostart = 0,
921 initialstart = 0,
922 abort = 0, force = 0;
923 char *nodes_str;
924 Vector<NodeId> nodes;
925
926 args.get("initialstart", &initialstart);
927 args.get("nostart", &nostart);
928 args.get("abort", &abort);
929 args.get("node", (const char **)&nodes_str);
930 args.get("force", &force);
931
932 char *p, *last;
933 for((p = my_strtok_r(nodes_str, " ", &last));
934 p;
935 (p = my_strtok_r(NULL, " ", &last))) {
936 nodes.push_back(atoi(p));
937 }
938
939 int restarted = 0;
940 int result= m_mgmsrv.restartNodes(nodes,
941 &restarted,
942 nostart != 0,
943 initialstart != 0,
944 abort != 0,
945 force != 0,
946 &m_stopSelf);
947
948 if (result == UNSUPPORTED_NODE_SHUTDOWN && nodes.size() > 1 && force)
949 {
950 /**
951 * We don't support multi node graceful shutdown...
952 * add "-a" and try again
953 */
954 abort = 1;
955 result= m_mgmsrv.restartNodes(nodes,
956 &restarted,
957 nostart != 0,
958 initialstart != 0,
959 abort != 0,
960 force != 0,
961 &m_stopSelf);
962 }
963
964 if (force &&
965 (result == NODE_SHUTDOWN_WOULD_CAUSE_SYSTEM_CRASH ||
966 result == UNSUPPORTED_NODE_SHUTDOWN))
967 {
968 // Force restart by restarting all nodes
969 result = m_mgmsrv.restartDB(nostart, initialstart, false, &restarted);
970 }
971
972 m_output->println("restart reply");
973 if(result != 0){
974 m_output->println("result: %d-%s", result, get_error_text(result));
975 } else
976 m_output->println("result: Ok");
977 m_output->println("restarted: %d", restarted);
978 if(version>1)
979 m_output->println("disconnect: %d", (m_stopSelf)?1:0);
980 m_output->println("%s", "");
981 }
982
983 void
restartAll(Parser<MgmApiSession>::Context &,Properties const & args)984 MgmApiSession::restartAll(Parser<MgmApiSession>::Context &,
985 Properties const &args)
986 {
987 Uint32 nostart = 0;
988 Uint32 initialstart = 0;
989 Uint32 abort = 0;
990
991 args.get("initialstart", &initialstart);
992 args.get("abort", &abort);
993 args.get("nostart", &nostart);
994
995 int count = 0;
996 int result = m_mgmsrv.restartDB(nostart, initialstart, abort, &count);
997
998 m_output->println("restart reply");
999 if(result != 0)
1000 m_output->println("result: %s", get_error_text(result));
1001 else
1002 m_output->println("result: Ok");
1003 m_output->println("restarted: %d", count);
1004 m_output->println("%s", "");
1005 }
1006
1007 static void
printNodeStatus(OutputStream * output,MgmtSrvr & mgmsrv,enum ndb_mgm_node_type type)1008 printNodeStatus(OutputStream *output,
1009 MgmtSrvr &mgmsrv,
1010 enum ndb_mgm_node_type type) {
1011 NodeId nodeId = 0;
1012 while(mgmsrv.getNextNodeId(&nodeId, type)) {
1013 enum ndb_mgm_node_status status;
1014 Uint32 startPhase = 0,
1015 version = 0, mysql_version = 0,
1016 dynamicId = 0,
1017 nodeGroup = 0,
1018 connectCount = 0;
1019 bool system;
1020 const char *address= NULL;
1021 char addr_buf[NDB_ADDR_STRLEN];
1022
1023 mgmsrv.status(nodeId, &status, &version, &mysql_version, &startPhase,
1024 &system, &dynamicId, &nodeGroup, &connectCount,
1025 &address,
1026 addr_buf,
1027 sizeof(addr_buf));
1028 output->println("node.%d.type: %s",
1029 nodeId,
1030 ndb_mgm_get_node_type_string(type));
1031 output->println("node.%d.status: %s",
1032 nodeId,
1033 ndb_mgm_get_node_status_string(status));
1034 output->println("node.%d.version: %d", nodeId, version);
1035 output->println("node.%d.mysql_version: %d", nodeId, mysql_version);
1036 output->println("node.%d.startphase: %d", nodeId, startPhase);
1037 output->println("node.%d.dynamic_id: %d", nodeId, dynamicId);
1038 output->println("node.%d.node_group: %d", nodeId, nodeGroup);
1039 output->println("node.%d.connect_count: %d", nodeId, connectCount);
1040 output->println("node.%d.address: %s", nodeId, address ? address : "");
1041 }
1042 }
1043
1044 void
getStatus(Parser<MgmApiSession>::Context &,Properties const & args)1045 MgmApiSession::getStatus(Parser<MgmApiSession>::Context &,
1046 Properties const & args) {
1047 Uint32 i;
1048 int noOfNodes = 0;
1049 BaseString typestring;
1050
1051 enum ndb_mgm_node_type types[10];
1052 if (args.get("types", typestring))
1053 {
1054 Vector<BaseString> tmp;
1055 typestring.split(tmp, " ");
1056 for (i = 0; i < tmp.size(); i++)
1057 {
1058 types[i] = ndb_mgm_match_node_type(tmp[i].c_str());
1059 }
1060 types[i] = NDB_MGM_NODE_TYPE_UNKNOWN;
1061 }
1062 else
1063 {
1064 types[0] = NDB_MGM_NODE_TYPE_NDB;
1065 types[1] = NDB_MGM_NODE_TYPE_MGM;
1066 types[2] = NDB_MGM_NODE_TYPE_API;
1067 types[3] = NDB_MGM_NODE_TYPE_UNKNOWN;
1068 }
1069
1070 for (i = 0; types[i] != NDB_MGM_NODE_TYPE_UNKNOWN; i++)
1071 {
1072 NodeId nodeId = 0;
1073 while(m_mgmsrv.getNextNodeId(&nodeId, types[i]))
1074 noOfNodes++;
1075 }
1076
1077 SLEEP_ERROR_INSERTED(5);
1078 m_output->println("node status");
1079 SLEEP_ERROR_INSERTED(6);
1080 m_output->println("nodes: %d", noOfNodes);
1081 for (i = 0; types[i] != NDB_MGM_NODE_TYPE_UNKNOWN; i++)
1082 {
1083 SLEEP_ERROR_INSERTED(int(7+i));
1084 printNodeStatus(m_output, m_mgmsrv, types[i]);
1085 }
1086 m_output->println("%s", "");
1087 }
1088
1089
1090 static bool
isEventLogFilterEnabled(int severity)1091 isEventLogFilterEnabled(int severity)
1092 {
1093 return g_eventLogger->isEnable((Logger::LoggerLevel)severity);
1094 }
1095
1096 void
getInfoClusterLog(Parser<MgmApiSession>::Context &,Properties const &)1097 MgmApiSession::getInfoClusterLog(Parser<MgmApiSession>::Context &,
1098 Properties const &) {
1099 const char* names[] = { "enabled",
1100 "debug",
1101 "info",
1102 "warning",
1103 "error",
1104 "critical",
1105 "alert" };
1106
1107 m_output->println("clusterlog");
1108 for(int i = 0; i < 7; i++) {
1109 m_output->println("%s: %d",
1110 names[i],
1111 isEventLogFilterEnabled(i));
1112 }
1113 m_output->println("%s", "");
1114 }
1115
1116 void
stop_v1(Parser<MgmApiSession>::Context &,Properties const & args)1117 MgmApiSession::stop_v1(Parser<MgmApiSession>::Context &,
1118 Properties const &args) {
1119 stop(args,1);
1120 }
1121
1122 void
stop_v2(Parser<MgmApiSession>::Context &,Properties const & args)1123 MgmApiSession::stop_v2(Parser<MgmApiSession>::Context &,
1124 Properties const &args) {
1125 stop(args,2);
1126 }
1127
1128 void
stop(Properties const & args,int version)1129 MgmApiSession::stop(Properties const &args, int version) {
1130 Uint32 abort, force = 0;
1131 char *nodes_str;
1132 Vector<NodeId> nodes;
1133
1134 args.get("node", (const char **)&nodes_str);
1135 if(nodes_str == NULL)
1136 {
1137 m_output->println("stop reply");
1138 m_output->println("result: empty node list");
1139 m_output->println("%s", "");
1140 return;
1141 }
1142 args.get("abort", &abort);
1143 args.get("force", &force);
1144
1145 char *p, *last;
1146 for((p = my_strtok_r(nodes_str, " ", &last));
1147 p;
1148 (p = my_strtok_r(NULL, " ", &last))) {
1149 nodes.push_back(atoi(p));
1150 }
1151
1152 int stopped= 0;
1153 int result= 0;
1154 if (nodes.size())
1155 {
1156 result= m_mgmsrv.stopNodes(nodes, &stopped, abort != 0, force != 0,
1157 &m_stopSelf);
1158
1159 if (result == UNSUPPORTED_NODE_SHUTDOWN && nodes.size() > 1 && force)
1160 {
1161 /**
1162 * We don't support multi node graceful shutdown...
1163 * add "-a" and try again
1164 */
1165 abort = 1;
1166 result= m_mgmsrv.stopNodes(nodes, &stopped, abort != 0, force != 0,
1167 &m_stopSelf);
1168 }
1169
1170 if (force &&
1171 (result == NODE_SHUTDOWN_WOULD_CAUSE_SYSTEM_CRASH ||
1172 result == UNSUPPORTED_NODE_SHUTDOWN))
1173 {
1174 // Force stop and shutdown all remaining nodes
1175 result = m_mgmsrv.shutdownDB(&stopped, false);
1176 }
1177 }
1178
1179 m_output->println("stop reply");
1180 if(result != 0)
1181 m_output->println("result: %s", get_error_text(result));
1182 else
1183 m_output->println("result: Ok");
1184 m_output->println("stopped: %d", stopped);
1185 if(version>1)
1186 m_output->println("disconnect: %d", (m_stopSelf)?1:0);
1187 m_output->println("%s", "");
1188 }
1189
1190 void
stopAll(Parser<MgmApiSession>::Context &,Properties const & args)1191 MgmApiSession::stopAll(Parser<MgmApiSession>::Context &,
1192 Properties const &args) {
1193 int stopped[2] = {0,0};
1194 Uint32 abort;
1195 args.get("abort", &abort);
1196
1197 BaseString stop;
1198 const char* tostop= "db";
1199 int ver=1;
1200 if (args.get("stop", stop))
1201 {
1202 tostop= stop.c_str();
1203 ver= 2;
1204 }
1205
1206 int result= 0;
1207 if(strstr(tostop,"db"))
1208 result= m_mgmsrv.shutdownDB(&stopped[0], abort != 0);
1209 if(!result && strstr(tostop,"mgm"))
1210 result= m_mgmsrv.shutdownMGM(&stopped[1], abort!=0, &m_stopSelf);
1211
1212 m_output->println("stop reply");
1213 if(result != 0)
1214 m_output->println("result: %s", get_error_text(result));
1215 else
1216 m_output->println("result: Ok");
1217 m_output->println("stopped: %d", stopped[0]+stopped[1]);
1218 if(ver >1)
1219 m_output->println("disconnect: %d", (m_stopSelf)?1:0);
1220 m_output->println("%s", "");
1221 }
1222
1223 void
enterSingleUser(Parser<MgmApiSession>::Context &,Properties const & args)1224 MgmApiSession::enterSingleUser(Parser<MgmApiSession>::Context &,
1225 Properties const &args) {
1226 int stopped = 0;
1227 Uint32 nodeId = 0;
1228 int result= 0;
1229 args.get("nodeId", &nodeId);
1230
1231 result = m_mgmsrv.enterSingleUser(&stopped, nodeId);
1232 m_output->println("enter single user reply");
1233 if(result != 0) {
1234 m_output->println("result: %s", get_error_text(result));
1235 }
1236 else {
1237 m_output->println("result: Ok");
1238 }
1239 m_output->println("%s", "");
1240 }
1241
1242 void
exitSingleUser(Parser<MgmApiSession>::Context &,Properties const & args)1243 MgmApiSession::exitSingleUser(Parser<MgmApiSession>::Context &,
1244 Properties const &args) {
1245 int stopped = 0;
1246 int result = m_mgmsrv.exitSingleUser(&stopped, false);
1247 m_output->println("exit single user reply");
1248 if(result != 0)
1249 m_output->println("result: %s", get_error_text(result));
1250 else
1251 m_output->println("result: Ok");
1252 m_output->println("%s", "");
1253 }
1254
1255
1256 void
startSignalLog(Parser<MgmApiSession>::Context &,Properties const & args)1257 MgmApiSession::startSignalLog(Parser<MgmApiSession>::Context &,
1258 Properties const &args) {
1259 Uint32 node;
1260
1261 args.get("node", &node);
1262
1263 int result = m_mgmsrv.startSignalTracing(node);
1264
1265 m_output->println("start signallog reply");
1266 if(result != 0)
1267 m_output->println("result: %s", get_error_text(result));
1268 else
1269 m_output->println("result: Ok");
1270 m_output->println("%s", "");
1271 }
1272
1273 void
logSignals(Parser<MgmApiSession>::Context &,Properties const & args)1274 MgmApiSession::logSignals(Parser<MgmApiSession>::Context &,
1275 Properties const &args) {
1276 Uint32 node = 0, in = 0, out = 0;
1277 // BaseString blocks;
1278 BaseString blockList;
1279 char * blockName;
1280 args.get("node", &node);
1281 args.get("in", &in);
1282 args.get("out", &out);
1283 args.get("blocks", blockList);
1284 // fast fix - pekka
1285 char buf[200];
1286 BaseString::snprintf(buf, 200, "%s", blockList.c_str());
1287 Vector<BaseString> blocks;
1288
1289 blockName=strtok(buf,"|");
1290 while( blockName != NULL)
1291 {
1292 blocks.push_back(blockName);
1293 blockName=strtok(NULL,"|");
1294 }
1295
1296
1297 if(in > 1 || out > 1)
1298 return; /* Invalid arguments */
1299
1300 const MgmtSrvr::LogMode modes[] = {
1301 MgmtSrvr::Off,
1302 MgmtSrvr::Out,
1303 MgmtSrvr::In,
1304 MgmtSrvr::InOut,
1305 };
1306 MgmtSrvr::LogMode mode = modes[in<<1 | out];
1307
1308 int result = m_mgmsrv.setSignalLoggingMode(node, mode, blocks);
1309
1310 m_output->println("log signals reply");
1311 if(result != 0)
1312 m_output->println("result: %s", get_error_text(result));
1313 else
1314 m_output->println("result: Ok");
1315 m_output->println("%s", "");
1316 }
1317
1318 void
start(Parser<MgmApiSession>::Context &,Properties const & args)1319 MgmApiSession::start(Parser<MgmApiSession>::Context &,
1320 Properties const &args) {
1321 Uint32 node;
1322
1323 args.get("node", &node);
1324
1325 int result = m_mgmsrv.sendSTART_ORD(node);
1326
1327 m_output->println("start reply");
1328 if(result != 0)
1329 m_output->println("result: %s", get_error_text(result));
1330 else
1331 m_output->println("result: Ok");
1332 m_output->println("%s", "");
1333 }
1334
1335 void
startAll(Parser<MgmApiSession>::Context &,Properties const &)1336 MgmApiSession::startAll(Parser<MgmApiSession>::Context &,
1337 Properties const &) {
1338 NodeId node = 0;
1339 int started = 0;
1340
1341 while(m_mgmsrv.getNextNodeId(&node, NDB_MGM_NODE_TYPE_NDB))
1342 if(m_mgmsrv.sendSTART_ORD(node) == 0)
1343 started++;
1344
1345 m_output->println("start reply");
1346 m_output->println("result: Ok");
1347 m_output->println("started: %d", started);
1348 m_output->println("%s", "");
1349 }
1350
1351
1352 static bool
setEventLogFilter(int severity,int enable)1353 setEventLogFilter(int severity, int enable)
1354 {
1355 Logger::LoggerLevel level = (Logger::LoggerLevel)severity;
1356 if (enable > 0) {
1357 g_eventLogger->enable(level);
1358 } else if (enable == 0) {
1359 g_eventLogger->disable(level);
1360 }
1361 else
1362 {
1363 /* enable is < 0 => toggle the filter value */
1364 if (g_eventLogger->isEnable(level))
1365 g_eventLogger->disable(level);
1366 else
1367 g_eventLogger->enable(level);
1368 }
1369 return g_eventLogger->isEnable(level);
1370 }
1371
1372
1373 void
setLogFilter(Parser_t::Context & ctx,const class Properties & args)1374 MgmApiSession::setLogFilter(Parser_t::Context &ctx,
1375 const class Properties &args) {
1376 Uint32 severity;
1377 Uint32 enable;
1378
1379 args.get("level", &severity);
1380 args.get("enable", &enable);
1381
1382 bool result = setEventLogFilter(severity, enable);
1383
1384 m_output->println("set logfilter reply");
1385 m_output->println("result: %d", result);
1386 m_output->println("%s", "");
1387 }
1388
1389 #ifdef NOT_USED
1390
1391 static NdbOut&
operator <<(NdbOut & out,const LogLevel & ll)1392 operator<<(NdbOut& out, const LogLevel & ll)
1393 {
1394 out << "[LogLevel: ";
1395 for(size_t i = 0; i<LogLevel::LOGLEVEL_CATEGORIES; i++)
1396 out << ll.getLogLevel((LogLevel::EventCategory)i) << " ";
1397 out << "]";
1398 return out;
1399 }
1400 #endif
1401
1402
1403 static void
logevent2str(BaseString & str,int eventType,const Uint32 * theData,Uint32 len,NodeId nodeId,Uint32 timeval,char * pretty_text,size_t pretty_text_size)1404 logevent2str(BaseString& str, int eventType,
1405 const Uint32* theData,
1406 Uint32 len,
1407 NodeId nodeId, Uint32 timeval,
1408 char* pretty_text, size_t pretty_text_size)
1409 {
1410 str.assign("log event reply\n");
1411 str.appfmt("type=%d\n", eventType);
1412 str.appfmt("time=%d\n", timeval);
1413 str.appfmt("source_nodeid=%d\n", nodeId);
1414 unsigned i;
1415 for (i = 0; ndb_logevent_body[i].token; i++)
1416 {
1417 if ( ndb_logevent_body[i].type == eventType)
1418 break;
1419 }
1420
1421 if (ndb_logevent_body[i].token)
1422 {
1423 do {
1424 int val= theData[ndb_logevent_body[i].index];
1425 if (ndb_logevent_body[i].index_fn)
1426 val= (*(ndb_logevent_body[i].index_fn))(val);
1427 str.appfmt("%s=%d\n",ndb_logevent_body[i].token, val);
1428 if(strcmp(ndb_logevent_body[i].token,"error") == 0)
1429 {
1430 int pretty_text_len= (int)strlen(pretty_text);
1431 if(pretty_text_size-pretty_text_len-3 > 0)
1432 {
1433 BaseString::snprintf(pretty_text+pretty_text_len, 4 , " - ");
1434 ndb_error_string(val, pretty_text+(pretty_text_len+3),
1435 (int)(pretty_text_size-pretty_text_len-3));
1436 }
1437 }
1438 } while (ndb_logevent_body[++i].type == eventType);
1439 }
1440 else
1441 {
1442 str.append("data=");
1443 for (i = 1; i<len; i++)
1444 str.appfmt("%u ", theData[i]);
1445 str.append("\n");
1446 }
1447 }
1448
1449
1450 void
log(int eventType,const Uint32 * theData,Uint32 len,NodeId nodeId)1451 Ndb_mgmd_event_service::log(int eventType, const Uint32* theData,
1452 Uint32 len, NodeId nodeId){
1453
1454 Uint32 threshold;
1455 LogLevel::EventCategory cat;
1456 Logger::LoggerLevel severity;
1457 EventLoggerBase::EventTextFunction textF;
1458 int i, n;
1459 DBUG_ENTER("Ndb_mgmd_event_service::log");
1460 DBUG_PRINT("enter",("eventType=%d, nodeid=%d", eventType, nodeId));
1461
1462 if (EventLoggerBase::event_lookup(eventType,cat,threshold,severity,textF))
1463 DBUG_VOID_RETURN;
1464
1465 // Generate the message for pretty format clients
1466 char pretty_text[512];
1467 EventLogger::getText(pretty_text, sizeof(pretty_text),
1468 textF, theData, len, nodeId);
1469
1470 // Generate the message for parseable format clients
1471 // and if there is a field named "error" append the ndb_error_string
1472 // for that error number to the end of the pretty format message
1473 BaseString str;
1474 logevent2str(str, eventType, theData, len, nodeId, 0,
1475 pretty_text, sizeof(pretty_text));
1476
1477 Vector<NDB_SOCKET_TYPE> copy;
1478 m_clients.lock();
1479 for(i = m_clients.size() - 1; i >= 0; i--)
1480 {
1481 if(threshold <= m_clients[i].m_logLevel.getLogLevel(cat))
1482 {
1483 if(!my_socket_valid(m_clients[i].m_socket))
1484 continue;
1485
1486 SocketOutputStream out(m_clients[i].m_socket);
1487
1488 int r;
1489 if (m_clients[i].m_parsable)
1490 {
1491 unsigned len = str.length();
1492 r= out.write(str.c_str(), len);
1493 }
1494 else
1495 {
1496 unsigned len = (unsigned)strlen(pretty_text);
1497 r= out.write(pretty_text, len);
1498 }
1499
1500 if (! (r < 0))
1501 {
1502 r = out.write("\n", 1);
1503 }
1504
1505 if (r<0)
1506 {
1507 copy.push_back(m_clients[i].m_socket);
1508 m_clients.erase(i, false);
1509 }
1510 }
1511 }
1512 m_clients.unlock();
1513
1514 if ((n= (int)copy.size()))
1515 {
1516 for(i= 0; i < n; i++)
1517 NDB_CLOSE_SOCKET(copy[i]);
1518
1519 LogLevel tmp; tmp.clear();
1520 m_clients.lock();
1521 for(i= m_clients.size() - 1; i >= 0; i--)
1522 tmp.set_max(m_clients[i].m_logLevel);
1523 m_clients.unlock();
1524 update_log_level(tmp);
1525 }
1526 DBUG_VOID_RETURN;
1527 }
1528
1529 void
update_max_log_level(const LogLevel & log_level)1530 Ndb_mgmd_event_service::update_max_log_level(const LogLevel &log_level)
1531 {
1532 LogLevel tmp = log_level;
1533 m_clients.lock();
1534 for(int i = m_clients.size() - 1; i >= 0; i--)
1535 tmp.set_max(m_clients[i].m_logLevel);
1536 m_clients.unlock();
1537 update_log_level(tmp);
1538 }
1539
1540 void
update_log_level(const LogLevel & tmp)1541 Ndb_mgmd_event_service::update_log_level(const LogLevel &tmp)
1542 {
1543 m_logLevel = tmp;
1544 EventSubscribeReq req;
1545 req.assign(tmp);
1546 // send update to all nodes
1547 req.blockRef = 0;
1548 m_mgmsrv->m_log_level_requests.push_back(req);
1549 }
1550
1551 void
check_listeners()1552 Ndb_mgmd_event_service::check_listeners()
1553 {
1554 int i, n= 0;
1555 DBUG_ENTER("Ndb_mgmd_event_service::check_listeners");
1556 m_clients.lock();
1557 for(i= m_clients.size() - 1; i >= 0; i--)
1558 {
1559 if(!my_socket_valid(m_clients[i].m_socket))
1560 continue;
1561
1562 SocketOutputStream out(m_clients[i].m_socket);
1563
1564 DBUG_PRINT("info",("%d " MY_SOCKET_FORMAT,
1565 i,
1566 MY_SOCKET_FORMAT_VALUE(m_clients[i].m_socket)));
1567
1568 if(out.println("<PING>") < 0)
1569 {
1570 NDB_CLOSE_SOCKET(m_clients[i].m_socket);
1571 m_clients.erase(i, false);
1572 n=1;
1573 }
1574 }
1575 if (n)
1576 {
1577 LogLevel tmp; tmp.clear();
1578 for(i= m_clients.size() - 1; i >= 0; i--)
1579 tmp.set_max(m_clients[i].m_logLevel);
1580 update_log_level(tmp);
1581 }
1582 m_clients.unlock();
1583 DBUG_VOID_RETURN;
1584 }
1585
1586 void
add_listener(const Event_listener & client)1587 Ndb_mgmd_event_service::add_listener(const Event_listener& client)
1588 {
1589 DBUG_ENTER("Ndb_mgmd_event_service::add_listener");
1590 DBUG_PRINT("enter",("client.m_socket: " MY_SOCKET_FORMAT,
1591 MY_SOCKET_FORMAT_VALUE(client.m_socket)));
1592
1593 check_listeners();
1594
1595 m_clients.push_back(client);
1596 update_max_log_level(client.m_logLevel);
1597
1598 DBUG_VOID_RETURN;
1599 }
1600
1601 void
stop_sessions()1602 Ndb_mgmd_event_service::stop_sessions(){
1603 m_clients.lock();
1604 for(int i = m_clients.size() - 1; i >= 0; i--){
1605 if(my_socket_valid(m_clients[i].m_socket))
1606 {
1607 NDB_CLOSE_SOCKET(m_clients[i].m_socket);
1608 m_clients.erase(i);
1609 }
1610 }
1611 m_clients.unlock();
1612 }
1613
1614 void
setParameter(Parser_t::Context &,Properties const & args)1615 MgmApiSession::setParameter(Parser_t::Context &,
1616 Properties const &args)
1617 {
1618 Uint32 node, param;
1619 BaseString value;
1620 args.get("node", &node);
1621 args.get("parameter", ¶m);
1622 args.get("value", value);
1623
1624 BaseString result;
1625 int ret = m_mgmsrv.setDbParameter(node,
1626 param,
1627 value.c_str(),
1628 result);
1629
1630 m_output->println("set parameter reply");
1631 m_output->println("message: %s", result.c_str());
1632 m_output->println("result: %d", ret);
1633 m_output->println("%s", "");
1634 }
1635
1636 void
setConnectionParameter(Parser_t::Context & ctx,Properties const & args)1637 MgmApiSession::setConnectionParameter(Parser_t::Context &ctx,
1638 Properties const &args)
1639 {
1640 Uint32 node1, node2, param, value;
1641 args.get("node1", &node1);
1642 args.get("node2", &node2);
1643 args.get("param", ¶m);
1644 args.get("value", &value);
1645
1646 BaseString result;
1647 int ret = m_mgmsrv.setConnectionDbParameter(node1,
1648 node2,
1649 param,
1650 value,
1651 result);
1652
1653 m_output->println("set connection parameter reply");
1654 m_output->println("message: %s", result.c_str());
1655 m_output->println("result: %s", (ret>0)?"Ok":"Failed");
1656 m_output->println("%s", "");
1657 }
1658
1659 void
getConnectionParameter(Parser_t::Context & ctx,Properties const & args)1660 MgmApiSession::getConnectionParameter(Parser_t::Context &ctx,
1661 Properties const &args)
1662 {
1663 Uint32 node1, node2, param;
1664 int value = 0;
1665
1666 args.get("node1", &node1);
1667 args.get("node2", &node2);
1668 args.get("param", ¶m);
1669
1670 BaseString result;
1671 int ret = m_mgmsrv.getConnectionDbParameter(node1,
1672 node2,
1673 param,
1674 &value,
1675 result);
1676
1677 m_output->println("get connection parameter reply");
1678 m_output->println("value: %d", value);
1679 m_output->println("result: %s", (ret>0)?"Ok":result.c_str());
1680 m_output->println("%s", "");
1681 }
1682
1683 void
listen_event(Parser<MgmApiSession>::Context & ctx,Properties const & args)1684 MgmApiSession::listen_event(Parser<MgmApiSession>::Context & ctx,
1685 Properties const & args) {
1686 Uint32 parsable= 0;
1687 BaseString node, param, value;
1688 args.get("node", node);
1689 args.get("filter", param);
1690 args.get("parsable", &parsable);
1691
1692 int result = 0;
1693 BaseString msg;
1694
1695 Ndb_mgmd_event_service::Event_listener le;
1696 le.m_parsable = parsable;
1697 le.m_socket = m_socket;
1698
1699 Vector<BaseString> list;
1700 param.trim();
1701 param.split(list, " ,");
1702 for(unsigned i = 0; i<list.size(); i++){
1703 Vector<BaseString> spec;
1704 list[i].trim();
1705 list[i].split(spec, "=:");
1706 if(spec.size() != 2){
1707 msg.appfmt("Invalid filter specification: >%s< >%s< %d",
1708 param.c_str(), list[i].c_str(), spec.size());
1709 result = -1;
1710 goto done;
1711 }
1712
1713 spec[0].trim().ndb_toupper();
1714 int category = ndb_mgm_match_event_category(spec[0].c_str());
1715 if(category == NDB_MGM_ILLEGAL_EVENT_CATEGORY){
1716 category = atoi(spec[0].c_str());
1717 if(category < NDB_MGM_MIN_EVENT_CATEGORY ||
1718 category > NDB_MGM_MAX_EVENT_CATEGORY){
1719 msg.appfmt("Unknown category: >%s<", spec[0].c_str());
1720 result = -1;
1721 goto done;
1722 }
1723 }
1724
1725 int level = atoi(spec[1].c_str());
1726 if(level < 0 || level > NDB_MGM_MAX_LOGLEVEL){
1727 msg.appfmt("Invalid level: >%s<", spec[1].c_str());
1728 result = -1;
1729 goto done;
1730 }
1731 category -= CFG_MIN_LOGLEVEL;
1732 le.m_logLevel.setLogLevel((LogLevel::EventCategory)category, level);
1733 }
1734
1735 if(list.size() == 0){
1736 msg.appfmt("Empty filter specification");
1737 result = -1;
1738 goto done;
1739 }
1740
1741 done:
1742 m_output->println("listen event");
1743 m_output->println("result: %d", result);
1744 if(result != 0)
1745 m_output->println("msg: %s", msg.c_str());
1746 m_output->println("%s", "");
1747
1748 /*
1749 Flush output from command before adding the new event listener.
1750 This makes sure that the client receives the reply before the
1751 loglevel thread starts to check the connection by sending <PING>'s.
1752 The client is expecting <PING>'s but not until after the reply has been
1753 received.
1754 */
1755 NdbMutex_Unlock(m_mutex);
1756 m_output->flush();
1757 NdbMutex_Lock(m_mutex);
1758
1759 if(result==0)
1760 {
1761 m_mgmsrv.m_event_listner.add_listener(le);
1762 m_stop = true;
1763 my_socket_invalidate(&m_socket);
1764 }
1765 }
1766
1767
1768 void
purge_stale_sessions(Parser_t::Context & ctx,const class Properties & args)1769 MgmApiSession::purge_stale_sessions(Parser_t::Context &ctx,
1770 const class Properties &args)
1771 {
1772 m_mgmsrv.get_socket_server()->checkSessions();
1773
1774 m_output->println("purge stale sessions reply");
1775 m_output->println("result: Ok");
1776 m_output->println("%s", "");
1777 }
1778
1779 void
check_connection(Parser_t::Context & ctx,const class Properties & args)1780 MgmApiSession::check_connection(Parser_t::Context &ctx,
1781 const class Properties &args)
1782 {
1783 SLEEP_ERROR_INSERTED(1);
1784 m_output->println("check connection reply");
1785 SLEEP_ERROR_INSERTED(2);
1786 m_output->println("result: Ok");
1787 SLEEP_ERROR_INSERTED(3);
1788 m_output->println("%s", "");
1789 }
1790
1791 void
transporter_connect(Parser_t::Context & ctx,Properties const & args)1792 MgmApiSession::transporter_connect(Parser_t::Context &ctx,
1793 Properties const &args)
1794 {
1795 bool close_with_reset = true;
1796 BaseString errormsg;
1797 if (!m_mgmsrv.transporter_connect(m_socket, errormsg, close_with_reset))
1798 {
1799 // Connection not allowed or failed
1800 g_eventLogger->warning("Failed to convert connection "
1801 "from '%s' to transporter: %s",
1802 name(),
1803 errormsg.c_str());
1804 // Close the socket to indicate failure to client
1805 ndb_socket_close(m_socket, close_with_reset);
1806 my_socket_invalidate(&m_socket); // Already closed
1807 }
1808 else
1809 {
1810 /*
1811 Conversion to transporter suceeded
1812 Stop this session thread and release resources
1813 but don't close the socket, it's been taken over
1814 by the transporter
1815 */
1816 my_socket_invalidate(&m_socket); // so nobody closes it
1817 }
1818
1819 m_stop= true; // Stop the session
1820 }
1821
1822 void
get_mgmd_nodeid(Parser_t::Context & ctx,Properties const & args)1823 MgmApiSession::get_mgmd_nodeid(Parser_t::Context &ctx,
1824 Properties const &args)
1825 {
1826 m_output->println("get mgmd nodeid reply");
1827 m_output->println("nodeid:%u",m_mgmsrv.getOwnNodeId());
1828 SLEEP_ERROR_INSERTED(1);
1829
1830 m_output->println("%s", "");
1831 }
1832
1833 void
report_event(Parser_t::Context & ctx,Properties const & args)1834 MgmApiSession::report_event(Parser_t::Context &ctx,
1835 Properties const &args)
1836 {
1837 Uint32 length;
1838 const char *data_string;
1839 Uint32 data[25];
1840
1841 args.get("length", &length);
1842 args.get("data", &data_string);
1843
1844 BaseString tmp(data_string);
1845 Vector<BaseString> item;
1846 tmp.split(item, " ");
1847 for (int i = 0; (Uint32) i < length ; i++)
1848 {
1849 sscanf(item[i].c_str(), "%u", data+i);
1850 }
1851
1852 m_mgmsrv.eventReport(data, length);
1853 m_output->println("report event reply");
1854 m_output->println("result: ok");
1855 m_output->println("%s", "");
1856 }
1857
1858 void
create_nodegroup(Parser_t::Context & ctx,Properties const & args)1859 MgmApiSession::create_nodegroup(Parser_t::Context &ctx,
1860 Properties const &args)
1861 {
1862 int res = 0;
1863 BaseString nodestr;
1864 BaseString retval;
1865 int ng = -1;
1866 Vector<int> nodes;
1867 BaseString result("Ok");
1868
1869 args.get("nodes", nodestr);
1870 Vector<BaseString> list;
1871 nodestr.split(list, " ");
1872 for (Uint32 i = 0; i < list.size() ; i++)
1873 {
1874 int res;
1875 int node;
1876 if ((res = sscanf(list[i].c_str(), "%u", &node)) != 1)
1877 {
1878 nodes.clear();
1879 result = "FAIL: Invalid format for nodes";
1880 break;
1881 }
1882 nodes.push_back(node);
1883 }
1884
1885 res = m_mgmsrv.createNodegroup(nodes.getBase(), nodes.size(), &ng);
1886
1887 m_output->println("create nodegroup reply");
1888 m_output->println("ng: %d", ng);
1889 if (res)
1890 {
1891 m_output->println("error_code: %d", res);
1892 m_output->println("result: %d-%s", res, get_error_text(res));
1893 }
1894 else
1895 {
1896 m_output->println("result: Ok");
1897 }
1898 m_output->println("%s", "");
1899 }
1900
1901 void
drop_nodegroup(Parser_t::Context & ctx,Properties const & args)1902 MgmApiSession::drop_nodegroup(Parser_t::Context &ctx,
1903 Properties const &args)
1904 {
1905 BaseString result("Ok");
1906
1907 unsigned ng;
1908 args.get("ng", &ng);
1909
1910 int res;
1911 if((res = m_mgmsrv.dropNodegroup(ng)) != 0)
1912 {
1913 result.assfmt("error: %d", res);
1914 }
1915
1916 //end:
1917 m_output->println("drop nodegroup reply");
1918 m_output->println("result: %s", result.c_str());
1919 m_output->println("%s", "");
1920 }
1921
1922 void
list_session(SocketServer::Session * _s,void * data)1923 MgmApiSession::list_session(SocketServer::Session *_s, void *data)
1924 {
1925 MgmApiSession *s= (MgmApiSession *)_s;
1926 MgmApiSession *lister= (MgmApiSession*) data;
1927
1928 if(s!=lister)
1929 NdbMutex_Lock(s->m_mutex);
1930
1931 Uint64 id= s->m_session_id;
1932 lister->m_output->println("session: %llu",id);
1933 lister->m_output->println("session.%llu.m_stopSelf: %d",id,s->m_stopSelf);
1934 lister->m_output->println("session.%llu.m_stop: %d",id,s->m_stop);
1935 if(s->m_ctx)
1936 {
1937 int l= (int)strlen(s->m_ctx->m_tokenBuffer);
1938 char *buf= (char*) malloc(2*l+1);
1939 char *b= buf;
1940 for(int i=0; i<l;i++)
1941 if(s->m_ctx->m_tokenBuffer[i]=='\n')
1942 {
1943 *b++='\\';
1944 *b++='n';
1945 }
1946 else
1947 {
1948 *b++= s->m_ctx->m_tokenBuffer[i];
1949 }
1950 *b= '\0';
1951
1952 lister->m_output->println("session.%llu.parser.buffer.len: %u",id,l);
1953 lister->m_output->println("session.%llu.parser.buffer: %s",id,buf);
1954 lister->m_output->println("session.%llu.parser.status: %d",id,s->m_ctx->m_status);
1955
1956 free(buf);
1957 }
1958
1959 if(s!=lister)
1960 NdbMutex_Unlock(s->m_mutex);
1961 }
1962
1963 void
listSessions(Parser_t::Context & ctx,Properties const & args)1964 MgmApiSession::listSessions(Parser_t::Context &ctx,
1965 Properties const &args) {
1966 m_mgmsrv.get_socket_server()->foreachSession(list_session,(void*)this);
1967
1968 m_output->println("%s", "");
1969 }
1970
1971 void
getSessionId(Parser_t::Context & ctx,Properties const & args)1972 MgmApiSession::getSessionId(Parser_t::Context &ctx,
1973 Properties const &args) {
1974 m_output->println("get session id reply");
1975 m_output->println("id: %llu",m_session_id);
1976 m_output->println("%s", "");
1977 }
1978
1979 struct get_session_param {
1980 MgmApiSession *l;
1981 Uint64 id;
1982 int found;
1983 };
1984
1985 void
get_session(SocketServer::Session * _s,void * data)1986 MgmApiSession::get_session(SocketServer::Session *_s, void *data)
1987 {
1988 struct get_session_param *p= (struct get_session_param*)data;
1989 MgmApiSession *s= (MgmApiSession *)_s;
1990
1991 if(s!=p->l)
1992 NdbMutex_Lock(s->m_mutex);
1993
1994 if(p->id != s->m_session_id)
1995 {
1996 if(s!=p->l)
1997 NdbMutex_Unlock(s->m_mutex);
1998 return;
1999 }
2000
2001 p->found= true;
2002 p->l->m_output->println("id: %llu",s->m_session_id);
2003 p->l->m_output->println("m_stopSelf: %d",s->m_stopSelf);
2004 p->l->m_output->println("m_stop: %d",s->m_stop);
2005 if(s->m_ctx)
2006 {
2007 int l= (int)strlen(s->m_ctx->m_tokenBuffer);
2008 p->l->m_output->println("parser_buffer_len: %u",l);
2009 p->l->m_output->println("parser_status: %d",s->m_ctx->m_status);
2010 }
2011
2012 if(s!=p->l)
2013 NdbMutex_Unlock(s->m_mutex);
2014 }
2015
2016 void
getSession(Parser_t::Context & ctx,Properties const & args)2017 MgmApiSession::getSession(Parser_t::Context &ctx,
2018 Properties const &args) {
2019 Uint64 id;
2020 struct get_session_param p;
2021
2022 args.get("id", &id);
2023
2024 p.l= this;
2025 p.id= id;
2026 p.found= false;
2027
2028 m_output->println("get session reply");
2029 m_mgmsrv.get_socket_server()->foreachSession(get_session,(void*)&p);
2030
2031 if(p.found==false)
2032 m_output->println("id: 0");
2033
2034 m_output->println("%s", "");
2035 }
2036
2037
2038 static bool
clear_dynamic_ports_from_config(Config * config)2039 clear_dynamic_ports_from_config(Config* config)
2040 {
2041 ConfigIter iter(config, CFG_SECTION_CONNECTION);
2042
2043 for(;iter.valid();iter.next()) {
2044 Uint32 n1, n2;
2045 if (iter.get(CFG_CONNECTION_NODE_1, &n1) != 0 &&
2046 iter.get(CFG_CONNECTION_NODE_2, &n2) != 0)
2047 return false;
2048
2049 Uint32 port_value;
2050 if (iter.get(CFG_CONNECTION_SERVER_PORT, &port_value) != 0)
2051 return false;
2052
2053 int port = (int)port_value;
2054 if (port < 0)
2055 {
2056 // Found a dynamic port with value in config, clear it by updating
2057 // the already existing value
2058 Uint32 zero_port = 0;
2059 ConfigValues::Iterator i2(config->m_configValues->m_config,
2060 iter.m_config);
2061 if (!i2.set(CFG_CONNECTION_SERVER_PORT, zero_port))
2062 return false;
2063 }
2064 }
2065 return true;
2066 }
2067
2068
setConfig(Parser_t::Context & ctx,Properties const & args)2069 void MgmApiSession::setConfig(Parser_t::Context &ctx, Properties const &args)
2070 {
2071 BaseString result("Ok");
2072 Uint32 len64 = 0;
2073
2074 {
2075 const char* buf;
2076 args.get("Content-Type", &buf);
2077 if(strcmp(buf, "ndbconfig/octet-stream")) {
2078 result.assfmt("Unhandled content type '%s'", buf);
2079 goto done;
2080 }
2081
2082 args.get("Content-Transfer-Encoding", &buf);
2083 if(strcmp(buf, "base64")) {
2084 result.assfmt("Unhandled content encoding '%s'", buf);
2085 goto done;
2086 }
2087 }
2088
2089 args.get("Content-Length", &len64);
2090 if(len64 ==0 || len64 > (1024*1024)) {
2091 result.assfmt("Illegal config length size %d", len64);
2092 goto done;
2093 }
2094 len64 += 1; // Trailing \n
2095
2096 {
2097 char* buf64 = new char[len64];
2098 int r = 0;
2099 size_t start = 0;
2100 do {
2101 if((r= read_socket(m_socket,
2102 SOCKET_TIMEOUT,
2103 &buf64[start],
2104 (int)(len64-start))) < 1)
2105 {
2106 delete[] buf64;
2107 result.assfmt("read_socket failed, errno: %d", errno);
2108 goto done;
2109 }
2110 start += r;
2111 } while(start < len64);
2112
2113 char* decoded = new char[base64_needed_decoded_length((size_t)len64 - 1)];
2114 int decoded_len= ndb_base64_decode(buf64, len64-1, decoded, NULL);
2115 delete[] buf64;
2116
2117 if (decoded_len == -1)
2118 {
2119 result.assfmt("Failed to unpack config");
2120 delete[] decoded;
2121 goto done;
2122 }
2123
2124 ConfigValuesFactory cvf;
2125 if(!cvf.unpack(decoded, decoded_len))
2126 {
2127 delete[] decoded;
2128 result.assfmt("Failed to unpack config");
2129 goto done;
2130 }
2131 delete[] decoded;
2132
2133 Config new_config(cvf.getConfigValues());
2134
2135 // Remove any dynamic ports from the new config
2136 if (!clear_dynamic_ports_from_config(&new_config))
2137 {
2138 result.assfmt("INTERNAL ERROR: Failed to clear dynamic "
2139 "ports from config");
2140 goto done;
2141 }
2142
2143 (void)m_mgmsrv.change_config(new_config, result);
2144 }
2145
2146 done:
2147
2148 m_output->println("set config reply");
2149 m_output->println("result: %s", result.c_str());
2150 m_output->println("%s", "");
2151 }
2152
2153
showConfig(Parser_t::Context & ctx,Properties const & args)2154 void MgmApiSession::showConfig(Parser_t::Context &ctx, Properties const &args)
2155 {
2156 const char* section = NULL;
2157 const char* name = NULL;
2158 Uint32 nodeid = 0;
2159
2160 args.get("Section", §ion);
2161 args.get("NodeId", &nodeid);
2162 args.get("Name", &name);
2163
2164 NdbOut socket_out(*m_output, false /* turn off autoflush */);
2165 m_output->println("show config reply");
2166 m_mgmsrv.print_config(section, nodeid, name,
2167 socket_out);
2168 m_output->println("%s", "");
2169 }
2170
2171
2172 void
reloadConfig(Parser_t::Context &,const class Properties & args)2173 MgmApiSession::reloadConfig(Parser_t::Context &,
2174 const class Properties &args)
2175 {
2176 const char* config_filename= NULL;
2177 Uint32 mycnf = 0;
2178
2179 args.get("config_filename", &config_filename);
2180 args.get("mycnf", &mycnf);
2181
2182 g_eventLogger->debug("config_filename: %s, mycnf: %s",
2183 str_null(config_filename),
2184 yes_no(mycnf));
2185
2186 m_output->println("reload config reply");
2187
2188 BaseString msg;
2189 if (!m_mgmsrv.reload_config(config_filename, (mycnf != 0), msg))
2190 m_output->println("result: %s", msg.c_str());
2191 else
2192 m_output->println("result: Ok");
2193
2194 m_output->println("%s", "");
2195 }
2196
2197
2198 void
show_variables(Parser_t::Context &,const class Properties & args)2199 MgmApiSession::show_variables(Parser_t::Context &,
2200 const class Properties &args)
2201 {
2202 m_output->println("show variables reply");
2203 NdbOut socket_out(*m_output, false /* turn off autoflush */);
2204 m_mgmsrv.show_variables(socket_out);
2205 m_output->println("%s", "");
2206 }
2207
2208
2209 static bool
valid_nodes(const NdbNodeBitmask & nodes,unsigned max_nodeid)2210 valid_nodes(const NdbNodeBitmask& nodes, unsigned max_nodeid)
2211 {
2212 unsigned nodeid = 0;
2213 while((nodeid = nodes.find(nodeid)) != NdbNodeBitmask::NotFound)
2214 {
2215 if (nodeid == 0 || nodeid > max_nodeid)
2216 return false;
2217 nodeid++;
2218 }
2219 return true;
2220 }
2221
2222
2223 #include <signaldata/DumpStateOrd.hpp>
2224 #include "../common/util/parse_mask.hpp"
2225
2226 static const
2227 struct dump_request {
2228 Ndb_logevent_type type;
2229 DumpStateOrd::DumpStateType dump_type;
2230 // Number of reports to wait for from each node
2231 Uint32 reports_per_node;
2232 } dump_requests [] =
2233 {
2234 { NDB_LE_BackupStatus,
2235 DumpStateOrd::BackupStatus,
2236 1 },
2237
2238 { NDB_LE_MemoryUsage,
2239 DumpStateOrd::DumpPageMemory,
2240 2},
2241
2242 { NDB_LE_SavedEvent,
2243 DumpStateOrd::DumpEventLog,
2244 0},
2245
2246 { NDB_LE_ILLEGAL_TYPE, (DumpStateOrd::DumpStateType)0, 0 }
2247 };
2248
2249 void
dump_events(Parser_t::Context &,const class Properties & args)2250 MgmApiSession::dump_events(Parser_t::Context &,
2251 const class Properties &args)
2252 {
2253 m_output->println("dump events reply");
2254
2255 // Check "type" argument
2256 Uint32 type;
2257 args.get("type", &type);
2258
2259 const dump_request* request = dump_requests;
2260
2261 for (; request->type != NDB_LE_ILLEGAL_TYPE; request++)
2262 {
2263 if (request->type == (Ndb_logevent_type)type)
2264 break;
2265 }
2266
2267 if (request->type == NDB_LE_ILLEGAL_TYPE)
2268 {
2269 m_output->println("result: ndb_logevent_type %u not supported", type);
2270 m_output->println("%s", "");
2271 return;
2272 }
2273
2274 // Check "nodes" argument
2275 NdbNodeBitmask nodes;
2276 const char* nodes_str = NULL;
2277 args.get("nodes", &nodes_str);
2278 if (nodes_str)
2279 {
2280 int res = parse_mask(nodes_str, nodes);
2281 if (res < 0 || !valid_nodes(nodes, MAX_NDB_NODES-1))
2282 {
2283 m_output->println("result: invalid nodes: '%s'", nodes_str);
2284 m_output->println("%s", "");
2285 return;
2286 }
2287 }
2288
2289 // Request the events
2290 Vector<SimpleSignal> events;
2291 if (!m_mgmsrv.request_events(nodes,
2292 request->reports_per_node,
2293 request->dump_type,
2294 events))
2295 {
2296 m_output->println("result: failed to dump events");
2297 m_output->println("%s", "");
2298 return;
2299 }
2300
2301 // Return result
2302 m_output->println("result: Ok");
2303 m_output->println("events: %u", events.size());
2304 m_output->println("%s", ""); // Empty line between header and first event
2305 for (unsigned i = 0; i < events.size(); i++)
2306 {
2307 const EventReport * const event =
2308 (const EventReport*)events[i].getDataPtrSend();
2309 const NodeId nodeid = refToNode(events[i].header.theSendersBlockRef);
2310
2311 // Check correct EVENT_REP type returned
2312 assert(event->getEventType() == request->type);
2313
2314 BaseString str;
2315 char pretty_text[512];
2316 Uint32 tmpData[256];
2317 const Uint32 * dataPtr = events[i].getDataPtr();
2318 Uint32 dataLen = events[i].getLength();
2319 if (events[i].header.m_noOfSections == 1)
2320 {
2321 if (dataLen + events[i].ptr[0].sz > NDB_ARRAY_SIZE(tmpData))
2322 {
2323 events[i].ptr[0].sz = NDB_ARRAY_SIZE(tmpData) - dataLen;
2324 }
2325 memcpy(tmpData, dataPtr, 4 * dataLen);
2326 memcpy(tmpData + dataLen, events[i].ptr[0].p, 4*events[i].ptr[0].sz);
2327 dataPtr = tmpData;
2328 dataLen += events[i].ptr[0].sz;
2329 }
2330 logevent2str(str,
2331 event->getEventType(),
2332 dataPtr,
2333 dataLen,
2334 nodeid, 0,
2335 pretty_text, sizeof(pretty_text));
2336
2337 m_output->println("%s", str.c_str());
2338 }
2339 }
2340
2341
2342 /*
2343 Read and discard the "bulk data" until
2344 - nothing more to read
2345 - empty line found
2346
2347 When error detected, the command part is already read, but the bulk data
2348 is still pending on the socket, it need to be consumed(read and discarded).
2349
2350 Example:
2351 set ports
2352 nodeid: 1 // << Error detected here
2353 num_ports: 2
2354 <new_line> // Parser always reads to first new line
2355 bulk line 1
2356 bulk line 2
2357 <new line> // discard_bulk_data() discards until here
2358 */
2359
2360 static
2361 void
discard_bulk_data(InputStream * in)2362 discard_bulk_data(InputStream* in)
2363 {
2364 char buf[256];
2365 while (true)
2366 {
2367 if (in->gets(buf, sizeof(buf)) == 0)
2368 {
2369 // Nothing more to read
2370 break;
2371 }
2372
2373 if (buf[0] == 0)
2374 {
2375 // Got eof
2376 break;
2377 }
2378
2379 if (buf[0] == '\n')
2380 {
2381 // Found empty line
2382 break;
2383 }
2384 }
2385 return;
2386 }
2387
2388
2389 static
2390 bool
read_dynamic_ports(InputStream * in,Uint32 num_ports,MgmtSrvr::DynPortSpec ports[],Uint32 & ports_read,BaseString & msg)2391 read_dynamic_ports(InputStream* in,
2392 Uint32 num_ports,
2393 MgmtSrvr::DynPortSpec ports[],
2394 Uint32& ports_read,
2395 BaseString& msg)
2396 {
2397 char buf[256];
2398 Uint32 counter = 0;
2399 while (counter < num_ports)
2400 {
2401 if (in->gets(buf, sizeof(buf)) == 0)
2402 {
2403 msg.assign("Read of ports failed");
2404 return false;
2405 }
2406
2407 if (buf[0] == 0)
2408 {
2409 msg.assign("Got eof instead of port");
2410 return false;
2411 }
2412
2413 if (buf[0] == '\n')
2414 {
2415 // Found empty line, list of ports ended too early
2416 msg.assign("Failed to parse line, expected name=value pair");
2417 return false;
2418 }
2419
2420 int node, port;
2421 if (sscanf(buf, "%d=%d", &node, &port) != 2)
2422 {
2423 msg.assign("Failed to parse line, expected name=value pair");
2424 discard_bulk_data(in);
2425 return false;
2426 }
2427
2428 ports[counter].port = port;
2429 ports[counter].node = node;
2430 counter++;
2431 }
2432
2433 // Read ending empty line
2434 if (in->gets(buf, sizeof(buf)) == 0)
2435 {
2436 msg.assign("Read of ending empty line failed");
2437 return false;
2438 }
2439
2440 if (buf[0] == 0)
2441 {
2442 msg.assign("Got eof instead of ending new line");
2443 return false;
2444 }
2445
2446 if (buf[0] != '\n')
2447 {
2448 msg.assign("Failed to parse line, expected empty line");
2449 discard_bulk_data(in);
2450 return false;
2451 }
2452
2453 ports_read= counter;
2454 return true;
2455 }
2456
2457
2458 void
set_ports(Parser_t::Context &,Properties const & args)2459 MgmApiSession::set_ports(Parser_t::Context &,
2460 Properties const &args)
2461 {
2462 m_output->println("set ports reply");
2463
2464 // Check node argument
2465 Uint32 node;
2466 args.get("node", &node);
2467 if (node == 0 || node >= MAX_NODES)
2468 {
2469 m_output->println("result: Illegal value for argument node: %u", node);
2470 m_output->println("%s", "");
2471 discard_bulk_data(m_input);
2472 return;
2473 }
2474
2475 Uint32 num_ports;
2476 args.get("num_ports", &num_ports);
2477 if (num_ports == 0 || num_ports >= MAX_NODES)
2478 {
2479 m_output->println("result: Illegal value for argument num_ports: %u",
2480 num_ports);
2481 m_output->println("%s", "");
2482 discard_bulk_data(m_input);
2483 return;
2484 }
2485
2486 // Read the name value pair list of ports to set from bulk data
2487 MgmtSrvr::DynPortSpec ports[MAX_NODES];
2488 {
2489 Uint32 ports_read;
2490 BaseString msg;
2491 if (!read_dynamic_ports(m_input, num_ports, ports, ports_read, msg))
2492 {
2493 m_output->println("result: %s", msg.c_str());
2494 m_output->println("%s", "");
2495 return;
2496 }
2497
2498 if (ports_read != num_ports)
2499 {
2500 m_output->println("result: Only read %d ports of expected %d",
2501 ports_read, num_ports);
2502 m_output->println("%s", "");
2503 return;
2504 }
2505 }
2506 // All bulk data consumed!
2507
2508 // Set all the received ports
2509 BaseString msg;
2510 if (!m_mgmsrv.setDynamicPorts(node, ports, num_ports, msg))
2511 {
2512 m_output->println("result: %s", msg.c_str());
2513 m_output->println("%s", "");
2514 return;
2515 }
2516
2517 m_output->println("result: Ok");
2518 m_output->println("%s", "");
2519 return;
2520 }
2521
2522 template class MutexVector<int>;
2523 template class Vector<ParserRow<MgmApiSession> const*>;
2524 template class Vector<NDB_SOCKET_TYPE>;
2525 template class Vector<SimpleSignal>;
2526