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