/* Copyright (C) 2003 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <ndb_global.h> #include <my_sys.h> #include "MgmtSrvr.hpp" #include "EventLogger.hpp" #include <Config.hpp> #include "InitConfigFileParser.hpp" #include <SocketServer.hpp> #include "Services.hpp" #include <version.h> #include <kernel_types.h> #include <Properties.hpp> #include <NdbOut.hpp> #include <NdbMain.h> #include <NdbDaemon.h> #include <NdbConfig.h> #include <NdbHost.h> #include <ndb_version.h> #include <ConfigRetriever.hpp> #include <mgmapi_config_parameters.h> #include <getarg.h> #include <NdbAutoPtr.hpp> #if defined NDB_OSE || defined NDB_SOFTOSE #include <efs.h> #else #include "CommandInterpreter.hpp" #endif #undef DEBUG #define DEBUG(x) ndbout << x << endl; const char progname[] = "mgmtsrvr"; /** * @struct MgmGlobals * @brief Global Variables used in the management server ******************************************************************************/ struct MgmGlobals { MgmGlobals(); ~MgmGlobals(); /** Command line arguments */ int daemon; // NOT bool, bool need not be int int non_interactive; int interactive; const char * config_filename; const char * local_config_filename; /** Stuff found in environment or in local config */ NodeId localNodeId; bool use_specific_ip; char * interface_name; int port; int port_stats; /** The configuration of the cluster */ Config * cluster_config; /** The Mgmt Server */ MgmtSrvr * mgmObject; /** The Socket Server */ SocketServer * socketServer; }; static MgmGlobals glob; /****************************************************************************** * Function prototypes ******************************************************************************/ static bool readLocalConfig(); static bool readGlobalConfig(); /** * Global variables */ bool g_StopServer; extern EventLogger g_EventLogger; extern int global_mgmt_server_check; int _print_version = 0; #ifndef DBUG_OFF const char *debug_option= 0; #endif struct getargs args[] = { { "version", 'v', arg_flag, &_print_version, "Print ndb_mgmd version"}, { "config-file", 'c', arg_string, &glob.config_filename, "Specify cluster configuration file", "filename" }, #ifndef DBUG_OFF { "debug", 0, arg_string, &debug_option, "Specify debug options e.g. d:t:i:o,out.trace", "options" }, #endif { "daemon", 'd', arg_flag, &glob.daemon, "Run ndb_mgmd in daemon mode (default)" }, { NULL, 'l', arg_string, &glob.local_config_filename, "Specify configuration file connect string (will default use Ndb.cfg if available)", "filename" }, { "interactive", 0, arg_flag, &glob.interactive, "Run interactive. Not supported but provided for testing purposes", "" }, { "nodaemon", 0, arg_flag, &glob.non_interactive, "Don't run as daemon, but don't read from stdin", "non-interactive" } }; int num_args = sizeof(args) / sizeof(args[0]); /* * MAIN */ NDB_MAIN(mgmsrv){ /** * OSE specific. Enable shared ownership of file system resources. * This is needed in order to use the cluster log since the events * from the cluster is written from the 'ndb_receive'(NDBAPI) thread/process. */ #if defined NDB_OSE || defined NDB_SOFTOSE efs_segment_share(); #endif global_mgmt_server_check = 1; int optind = 0; if(getarg(args, num_args, argc, argv, &optind)) { arg_printusage(args, num_args, progname, ""); exit(1); } if (glob.interactive || glob.non_interactive) { glob.daemon= 0; } #ifndef DBUG_OFF my_init(); if (debug_option) DBUG_PUSH(debug_option); #endif if (_print_version) { ndbPrintVersion(); exit(0); } if(glob.config_filename == NULL) { glob.config_filename= "config.ini"; } glob.socketServer = new SocketServer(); MgmApiService * mapi = new MgmApiService(); MgmStatService * mstat = new MgmStatService(); /**************************** * Read configuration files * ****************************/ if (!readLocalConfig()) goto error_end; if (!readGlobalConfig()) goto error_end; glob.mgmObject = new MgmtSrvr(glob.localNodeId, BaseString(glob.config_filename), BaseString(glob.local_config_filename == 0 ? "" : glob.local_config_filename), glob.cluster_config); chdir(NdbConfig_get_path(0)); glob.cluster_config = 0; glob.localNodeId= glob.mgmObject->getOwnNodeId(); if (glob.localNodeId == 0) { goto error_end; } glob.port= glob.mgmObject->getPort(); if (glob.port == 0) goto error_end; glob.interface_name = 0; glob.use_specific_ip = false; if(!glob.use_specific_ip){ if(!glob.socketServer->tryBind(glob.port, glob.interface_name)){ ndbout_c("Unable to setup port: %s:%d!\n" "Please check if the port is already used,\n" "(perhaps a mgmtsrvr is already running),\n" "and if you are executing on the correct computer", (glob.interface_name ? glob.interface_name : "*"), glob.port); goto error_end; } free(glob.interface_name); glob.interface_name = 0; } if(!glob.socketServer->setup(mapi, glob.port, glob.interface_name)){ ndbout_c("Unable to setup management port: %d!\n" "Please check if the port is already used,\n" "(perhaps a mgmtsrvr is already running),\n" "and if you are executing on the correct computer", glob.port); delete mapi; goto error_end; } if(!glob.socketServer->setup(mstat, glob.port_stats, glob.interface_name)){ ndbout_c("Unable to setup statistic port: %d!\nPlease check if the port" " is already used.", glob.port_stats); delete mstat; goto error_end; } if(!glob.mgmObject->check_start()){ ndbout_c("Unable to check start management server."); ndbout_c("Probably caused by illegal initial configuration file."); goto error_end; } if (glob.daemon) { // Become a daemon char *lockfile= NdbConfig_PidFileName(glob.localNodeId); char *logfile= NdbConfig_StdoutFileName(glob.localNodeId); NdbAutoPtr<char> tmp_aptr1(lockfile), tmp_aptr2(logfile); if (NdbDaemon_Make(lockfile, logfile, 0) == -1) { ndbout << "Cannot become daemon: " << NdbDaemon_ErrorText << endl; return 1; } } signal(SIGPIPE, SIG_IGN); if(!glob.mgmObject->start()){ ndbout_c("Unable to start management server."); ndbout_c("Probably caused by illegal initial configuration file."); goto error_end; } //glob.mgmObject->saveConfig(); mstat->setMgm(glob.mgmObject); mapi->setMgm(glob.mgmObject); glob.mgmObject->setStatisticsListner(mstat); char msg[256]; snprintf(msg, sizeof(msg), "NDB Cluster Management Server. %s", NDB_VERSION_STRING); ndbout_c(msg); g_EventLogger.info(msg); snprintf(msg, 256, "Id: %d, Command port: %d, Statistics port: %d", glob.localNodeId, glob.port, glob.port_stats); ndbout_c(msg); g_EventLogger.info(msg); g_StopServer = false; glob.socketServer->startServer(); #if ! defined NDB_OSE && ! defined NDB_SOFTOSE if(glob.interactive) { CommandInterpreter com(* glob.mgmObject); while(com.readAndExecute()); } else #endif { while(g_StopServer != true) NdbSleep_MilliSleep(500); } g_EventLogger.info("Shutting down server..."); glob.socketServer->stopServer(); glob.socketServer->stopSessions(); g_EventLogger.info("Shutdown complete"); return 0; error_end: return 1; } MgmGlobals::MgmGlobals(){ // Default values port = 0; port_stats = 0; config_filename = NULL; local_config_filename = NULL; interface_name = 0; cluster_config = 0; daemon = 1; non_interactive = 0; interactive = 0; socketServer = 0; mgmObject = 0; } MgmGlobals::~MgmGlobals(){ if (socketServer) delete socketServer; if (mgmObject) delete mgmObject; if (cluster_config) delete cluster_config; if (interface_name) free(interface_name); } /** * @fn readLocalConfig * @param glob : Global variables * @return true if success, false otherwise. * * How to get LOCAL CONFIGURATION FILE: * 1. Use local config file name (-l) * 2. Use environment NDB_HOME + Ndb.cfg * If NDB_HOME is not set this results in reading from local dir */ static bool readLocalConfig(){ // Read local config file LocalConfig lc; if(!lc.init(glob.local_config_filename)) return false; glob.localNodeId = lc._ownNodeId; return true; } /** * @fn readGlobalConfig * @param glob : Global variables * @return true if success, false otherwise. * * How to get the GLOBAL CONFIGURATION: * 1. Use config file name (this is a text file)(-c) * 2. Use name from line 2 of local config file, ex: file:///c/ndb/Ndb_cfg.bin */ static bool readGlobalConfig() { if(glob.config_filename == NULL) return false; /* Use config file */ InitConfigFileParser parser; glob.cluster_config = parser.parseConfig(glob.config_filename); if(glob.cluster_config == 0){ return false; } return true; }