summaryrefslogtreecommitdiffstats
path: root/rasmgr/rasmgr_config.cc
diff options
context:
space:
mode:
Diffstat (limited to 'rasmgr/rasmgr_config.cc')
-rw-r--r--rasmgr/rasmgr_config.cc601
1 files changed, 601 insertions, 0 deletions
diff --git a/rasmgr/rasmgr_config.cc b/rasmgr/rasmgr_config.cc
new file mode 100644
index 0000000..e0e1f4c
--- /dev/null
+++ b/rasmgr/rasmgr_config.cc
@@ -0,0 +1,601 @@
+/*
+* This file is part of rasdaman community.
+*
+* Rasdaman community 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 3 of the License, or
+* (at your option) any later version.
+*
+* Rasdaman community 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 rasdaman community. If not, see <http://www.gnu.org/licenses/>.
+*
+* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
+rasdaman GmbH.
+*
+* For more information please see <http://www.rasdaman.org>
+* or contact Peter Baumann via <baumann@rasdaman.com>.
+/
+/**
+ * SOURCE: rasmgr_config.cc
+ *
+ * MODULE: rasmgr
+ * CLASS: Configuration, RasmgrLicense
+ *
+ * PURPOSE:
+ * Config info from commandline, environment and license
+ *
+ * COMMENTS:
+ * none
+ *
+*/
+
+using namespace std;
+
+#include "globals.hh" // DEFAULT_HOSTNAME, RMANHOME_VAR, DEFAULT_PORT, RASMGR_CONF_FILE
+
+#include "rasmgr_config.hh"
+#include "rasmgr.hh"
+#include "rasmgr_host.hh"
+#include "rasmgr_dbm.hh"
+#include "rasmgr_srv.hh"
+#include "ras_crypto.hh"
+#include "rasmgr_users.hh"
+#include "rasmgr_comm.hh"
+#include "rasmgr_rascontrol.hh"
+
+#include <stdlib.h> // mkstemp()
+#include <iomanip>
+#include <time.h>
+
+#include "debug.hh"
+
+extern bool hostCmp( const char *h1, const char *h2);
+
+
+Configuration::Configuration():
+ cmlInter (CommandLineParser::getInstance()),
+ cmlName (cmlInter.addStringParameter(CommandLineParser::noShortName, "name", "<name> symbolic name of this rasmgr (slave only, default: the host name)")),
+ cmlHostName (cmlInter.addStringParameter(CommandLineParser::noShortName, "hostname", "<name> the advertized host name (master only, default: same as UNIX command 'hostname')")),
+ cmlPort (cmlInter.addLongParameter(CommandLineParser::noShortName, "port", "<port> listen port number", DEFAULT_PORT)),
+ cmlPollFrequ (cmlInter.addLongParameter(CommandLineParser::noShortName, "poll", "<poll> polling timeout (in seconds) for rasmgr listen port", DEFAULT_POLLING_FREQUENCY )),
+ cmlMaster (cmlInter.addStringParameter(CommandLineParser::noShortName, "master", "<name> host of rasmgr master (slave only)")),
+ cmlMasterPort (cmlInter.addLongParameter(CommandLineParser::noShortName, "mport", "<port> listen port number of rasmgr master (slave only)", DEFAULT_PORT)),
+ cmlQuiet (cmlInter.addFlagParameter( 'q', CommandLineParser::noLongName, "quiet: don't log requests (default: log requests to stdout)")),
+#ifdef NO_OFFICIAL_RELEASE
+ cmlTest (cmlInter.addFlagParameter(CommandLineParser::noShortName, "test", "test mode")),
+ cmlDSup (cmlInter.addFlagParameter(CommandLineParser::noShortName, "dsup", "debug mode")),
+ cmlRandTest (cmlInter.addFlagParameter(CommandLineParser::noShortName, "rgt", "random generator test")),
+ cmlRth (cmlInter.addFlagParameter(CommandLineParser::noShortName, "rth", "disable rthl test")),
+ cmlMultiWT (cmlInter.addFlagParameter(CommandLineParser::noShortName, "amw", "allow multiple write transactions")),
+#endif
+ cmlHelp (cmlInter.addFlagParameter('h', RASMGRCMD_HELP, "print this help"))
+{
+ ENTER( "Configuration::Configuration: enter." );
+
+ int ghnResult = gethostname(hostName, sizeof(hostName) );
+ if (ghnResult != 0) // cannot get hostname?
+ {
+ int ghnErrno = errno;
+ std::cout << "Error: cannot get hostname of my machine: error " << ghnErrno << "; will use '" << DEFAULT_HOSTNAME << "' as heuristic." << endl;
+ strcpy( hostName, DEFAULT_HOSTNAME );
+ }
+ strcpy(slaveName,hostName);
+ strcpy(publicHostName,hostName);
+ listenPort=DEFAULT_PORT;
+ masterPort=DEFAULT_PORT;
+ masterName[0]=0;
+
+ pollFrequency = DEFAULT_POLLING_FREQUENCY;
+
+ configFileName[0]=0;
+ slave = false;
+
+ char *rasHome= CONFDIR;
+ if(rasHome!=0)
+ sprintf(configFileName,"%s/",rasHome);
+
+ strcat( configFileName, RASMGR_CONF_FILE );
+ altConfigFileName[0] = '\0';
+
+ testModus = false;
+ debugSupport = false;
+ rtHlTest = true; // by default RasMgr tests at runtime if it's the only one
+ allowMultiWT = false; // rasmgr doesn't allow multiple write transactions for a db, but for internal use we can try it
+
+ LEAVE( "Configuration::Configuration: leave." );
+}
+
+bool Configuration::readConfigFile()
+{
+ //insert internal host, it's not in config file
+ hostmanager.insertInternalHost();
+
+ char inBuffer[MAXMSG];
+ char outBuffer[MAXMSG];
+ bool result = true;
+ bool fileIsOpen = false;
+
+ ENTER( "Configuration::readConfigFile: enter. Looking for config file " << configFileName );
+
+ VLOG << "Inspecting config file " << configFileName << "...";
+
+ std::ifstream ifs(configFileName); // open config file
+
+ if(ifs)
+ fileIsOpen = true;
+ else
+ {
+ TALK( "Configuration::readConfigFile: cannot open config file." );
+ std::cout << "Warning: cannot open config file " << configFileName << endl;
+ fileIsOpen = false;
+ }
+ result = true; // was: false, but I want to allow a missing file
+
+ if (fileIsOpen)
+ {
+ authorization.startConfigFile();
+
+ while( ! ifs.eof() ) // was: while(1), I simplified this
+ // processRequest() will get an additional empty line at eof, but this is harmless
+ {
+ ifs.getline(inBuffer,MAXMSG);
+ // if(!strlen(inBuffer) && ifs.eof()) // FIXME: what happens if last line in file is empty?
+ // {
+ // TALK( "Configuration::readConfigFile: strlen(inBuffer)=" << strlen(inBuffer) << ", eof=" << ifs.eof());
+ // break;
+ // }
+
+ TALK( "Configuration::readConfigFile: processing line: " << inBuffer );
+ rascontrol.processRequest(inBuffer,outBuffer);
+ }
+
+ authorization.endConfigFile();
+
+ ifs.close(); // close config file handle
+ }
+
+ if (result == true && fileIsOpen)
+ VLOG << "ok" << endl;
+
+ LEAVE( "Configuration::readConfigFile: leave. result=" << result );
+ return true;
+}
+
+// return name of alternate config file;
+// takes value from preceding saveAltConfigFile() call.
+const char *Configuration::getAltConfigFileName()
+{
+ return altConfigFileName;
+}
+
+// in future this is not used directly, but through saveOrigConfigFile() and saveAltConfigFile() wrappers below
+bool Configuration::saveConfigFile()
+{
+ ENTER( "Configuration::saveConfigFile: enter." );
+
+ std::ofstream ofs(configFileName);
+ if(!ofs)
+ {
+ LEAVE( "Configuration::saveConfigFile: leave. cannot open config file " << configFileName << " for writing." );
+ return false;
+ }
+
+ ofs << "# rasmgr config file (v1.1)" << std::endl;
+ ofs << "# warning: do not edit this file, it may be overwritten by rasmgr!" << std::endl;
+ ofs << "#" << std::endl;
+
+ int i;
+ //serverhosts
+ for(i=0;i<hostmanager.countHosts();i++)
+ {
+ ServerHost &xx=hostmanager[i];
+
+ if(i > 0)
+ ofs<<"define host "<<xx.getName()<<" -net "<<xx.getNetworkName()<<" -port "<<xx.getListenPort()<<std::endl;
+ else
+ {
+ //by default the master RasMgr is init with the hostname as name => if we have to we change it here
+ if( ! hostCmp(xx.getName(),config.getHostName()) )
+ ofs << "change host "<<config.getHostName()<<" -name "<<xx.getName()<<std::endl;
+
+ if(xx.useLocalHost()==false)
+ ofs<<"change host "<<xx.getName()<<" -uselocalhost off"<<std::endl;
+ }
+ }
+ //databaseHosts
+ for(i=0;i<dbHostManager.countHosts();i++)
+ {
+ DatabaseHost &xx=dbHostManager[i];
+ ofs<<"define dbh "<<xx.getName()<<" -connect "<<xx.getConnectionString()<<std::endl;
+ }
+ //rasservers
+ for(i=0;i<rasManager.countServers();i++)
+ {
+ RasServer &xx=rasManager[i];
+
+ ofs<<"define srv "<<xx.getName()<<" -host "<<xx.getHostName()<<" -type "<<xx.getType();
+ if(xx.getType()==SERVERTYPE_FLAG_HTTP)
+ ofs<<" -port "<<xx.getPort();
+ else
+ ofs<<" -port 0x"<<std::hex<<xx.getPort()<<std::dec;
+ if(xx.isConnectedToDBHost())
+ ofs<<" -dbh "<<xx.getDBHostName();
+ ofs<<std::endl;
+
+ ofs<<"change srv "<<xx.getName()<<" -countdown "<<xx.getCountDown();
+
+ if(strcmp(xx.getExecutableName(),RASEXECUTABLE))
+ ofs<<" -exec "<<xx.getExecutableName();
+
+ ofs<<" -autorestart "<<(xx.isAutoRestart() ? "on":"off")<<" -xp "<<xx.getExtraParams()<<std::endl;
+ }
+
+ //databases
+ for(i=0;i<dbManager.countDatabases();i++)
+ {
+ Database &xx=dbManager[i];
+
+ for(int j=0;j<xx.countConnectionsToDBHosts();j++)
+ {
+ ofs<<"define db "<<xx.getName()<<" -dbh "<<xx.getDBHostName(j)<<std::endl;
+ }
+ }
+
+ ofs.close(); // this was missing, therefore sometimes the config file was cleared -- PB 2003-jun-06
+ LEAVE( "Configuration::saveConfigFile: leave." );
+ return true;
+} // saveConfigFile()
+
+// save config file at original place, i.e., under the name of configFile
+bool Configuration::saveOrigConfigFile()
+{
+ ENTER( "Configuration::saveOrigConfigFile: enter." );
+
+ bool result = saveConfigFile();
+
+ LEAVE( "Configuration::saveOrigAltConfigFile: leave. result=" << result );
+ return result;
+}
+
+// save configuration file in another file, same dir as config file
+bool Configuration::saveAltConfigFile()
+{
+ ENTER( "Configuration::saveAltConfigFile()" );
+
+ bool result = true;
+ char origFileName[ sizeof(configFileName) ]; // temp copy of origFileName
+
+ // save original file name
+ (void) strcpy( origFileName, configFileName );
+
+ // build temp file by appending a unique string
+ (void) strcpy( altConfigFileName, configFileName );
+ (void) strcat( altConfigFileName, ".XXXXXX" ); // 6 * 'X', see man mkstemp()
+
+ int altFile = mkstemp( altConfigFileName ); // replaces the Xs by unique string
+ if (altFile < 0) // error in creating file name
+ {
+ int tempError = errno;
+ TALK( "Configuration::saveAltConfigFile: error creating alternate file name: " << strerror(tempError) );
+ result = false;
+ }
+
+ if (result == true)
+ {
+ // now we have a valid + open file, but we can't use it like that, because we open down below.
+ // so close it again, being happy that we have a valid file name. bad hack, though.
+ int closeResult = close( altFile );
+ if (closeResult != 0)
+ TALK( "Configuration::saveAltConfigFile: error in temporary closing file, ignoring that." );
+ }
+
+ if (result == true)
+ {
+ (void) strcpy( configFileName, altConfigFileName ); // set file to be written to alternate name
+ result = saveConfigFile(); // save file, name has been substituted successfully
+ (void) strcpy( configFileName, origFileName ); // restore original config file name
+ }
+
+ LEAVE( "Configuration::saveAltConfigFile: leave. result=" << result );
+ return result;
+}
+
+bool Configuration::interpretArguments(int argc, char **argv, char **envp)
+{
+ ENTER( "Configuration::interpretArguments: enter." );
+
+ bool result = true;
+ //errorCode=0;
+
+ //process command line
+ try
+ {
+ cmlInter.processCommandLine(argc, argv);
+ }
+ catch(CmlException& err)
+ {
+ std::cout << "Error parsing command line: " << err.what() << std::endl;
+ printHelp();
+ result = false;
+ }
+
+ SET_OUTPUT( true ); // by default, enable trace (debug) output
+ verbose = true; // by default, be verbose
+ if( (result==true) && cmlQuiet.isPresent() )
+ {
+ SET_OUTPUT( false ); // disable trace (debug) output
+ // debugOutput = true; // done via the above macro
+ verbose = false; // only minimum messages
+ result = true;
+ }
+
+ if( (result==true) && cmlHelp.isPresent() )
+ {
+ printHelp();
+ result = false;
+ }
+
+ if( (result==true) && cmlHostName.isPresent() )
+ {
+ if (sizeof(hostName) > strlen(cmlHostName.getValueAsString()))
+ strcpy(publicHostName,cmlHostName.getValueAsString());
+ else
+ {
+ VLOG << "Error: host name exceeds length limit of " << sizeof(hostName) << " characters." << std::endl;
+ result = false;
+ }
+ }
+
+ if( (result==true) && cmlPort.isPresent() )
+ {
+ try
+ {
+ listenPort = cmlPort.getValueAsLong();
+ }
+ catch(CmlException& err)
+ {
+ VLOG << "Error converting port parameter " << cmlPort.getLongName() << " to integer: " << err.what() << std::endl;
+ result = false;
+ }
+ }
+
+ if( (result==true) && cmlMaster.isPresent() )
+ {
+ slave = true;
+ strcpy(masterName,cmlMaster.getValueAsString());
+ }
+
+ if( (result==true) && cmlMasterPort.isPresent() )
+ {
+ try
+ {
+ masterPort = cmlMasterPort.getValueAsLong();
+ }
+ catch(CmlException& err)
+ {
+ VLOG << "Error converting " << cmlMasterPort.getLongName() << " to integer: " << err.what() << std::endl;
+ result = false;
+ }
+ }
+
+ if( (result==true) && cmlPollFrequ.isPresent() )
+ {
+ try
+ {
+ pollFrequency = cmlPollFrequ.getValueAsLong();
+ }
+ catch(CmlException& err)
+ {
+ VLOG << "Error converting " << cmlPollFrequ.getLongName() << " to integer: " << err.what() << std::endl;
+ result = false;
+ }
+ if (result == true && pollFrequency <= 0)
+ {
+ VLOG << "Error: poll frequency must be a positive integer." << std::endl;
+ result = false;
+ }
+ }
+
+ if( (result==true) && cmlName.isPresent() )
+ {
+ if (sizeof(slaveName) > strlen(cmlName.getValueAsString()))
+ strcpy(slaveName,cmlName.getValueAsString());
+ else
+ {
+ VLOG << "Error: slave name exceeds length limit of " << sizeof(slaveName) << " characters." << std::endl;
+ result = false;
+ }
+ }
+
+#ifdef NO_OFFICIAL_RELEASE
+ testModus = cmlTest.isPresent();
+ debugSupport=cmlDSup.isPresent();
+ rtHlTest=cmlRth.isPresent();
+
+ if( (result==true) && cmlRandTest.isPresent() )
+ {
+ std::cout<<"Random generator test..."<<(randomGenerator.insideTest() ? "PASSED":"FAILED" )<<std::endl;
+ result = false;
+ }
+
+ allowMultiWT = cmlMultiWT.isPresent();
+
+#endif
+
+ LEAVE( "Configuration::interpretArguments: leave. result=" << result );
+ return result;
+}
+
+bool Configuration::allowMultipleWriteTransactions()
+{
+ return allowMultiWT;
+}
+
+bool Configuration::isDebugSupport()
+{
+ return debugSupport;
+}
+
+bool Configuration::isVerbose()
+{
+ return verbose;
+}
+
+bool Configuration::isTestModus()
+{
+ return testModus;
+}
+
+const char* Configuration::getHostName()
+{
+ return hostName;
+}
+
+const char* Configuration::getPublicHostName()
+{
+ return publicHostName;
+}
+
+int Configuration::getListenPort()
+{
+ return listenPort;
+}
+
+const char* Configuration::getMasterName()
+{
+ return masterName;
+}
+int Configuration::getMasterPort()
+{
+ return masterPort;
+}
+
+int Configuration::getPollFrequency()
+{
+ return pollFrequency;
+}
+
+const char* Configuration::getSlaveName()
+{
+ return slaveName[0] ? slaveName:hostName;
+}
+
+
+void Configuration::printHelp()
+{
+ std::cout << "Usage: rasmgr [options]" << std::endl;
+ std::cout << "Options:" << std::endl;
+ cmlInter.printHelp();
+ std::cout << std::endl;
+ return;
+}
+
+void Configuration::printStatus()
+{
+ std::cout << "rasmgr configuration parameter settings:" << std::endl;
+ std::cout << " symb name = " << publicHostName << std::endl;
+ std::cout << " hostname = " << publicHostName << std::endl;
+ std::cout << " port = " << listenPort << std::endl;
+ std::cout << " poll = " << pollFrequency << std::endl;
+ std::cout << " quiet = " << (!verbose) << std::endl;
+ return;
+}
+
+//****************************************************************************************************************
+
+// FIXME: this needs refinement -- PB 2003-jun-09
+BenchmarkTimer::BenchmarkTimer(const char *text)
+{
+ this->text = (char*)text;
+ time_t now = time(NULL);
+ char *n = ctime(&now);
+ n[strlen(n)-1] = '\0'; // delete trailing newline char
+ // cout << "--- rasmgr timer start for \'" << text << "\' at " << n << "." << endl;
+ gettimeofday(&start,NULL);
+}
+
+BenchmarkTimer::~BenchmarkTimer()
+{
+}
+
+void BenchmarkTimer::result()
+{
+ timeval result;
+ gettimeofday(&end,NULL);
+ int r=timeval_subtract(&result,&end,&start);
+ time_t now = time(NULL);
+ char *n = ctime(&now);
+ n[strlen(n)-1] = '\0'; // delete trailing newline char
+ VLOG << "rasmgr timer stop for \'" << text << "\' at " << n << ": " << result.tv_sec << '.' << std::setw(3) << std::setfill('0') << result.tv_usec << " seconds elapsed." << endl;
+}
+
+int BenchmarkTimer::timeval_subtract(timeval *result,timeval *x,timeval *y)
+{
+#define ONE_MILLION 1000000
+ /* Perform the carry for the later subtraction by updating Y. */
+ if (x->tv_usec < y->tv_usec)
+ {
+ int nsec = (y->tv_usec - x->tv_usec) / ONE_MILLION + 1;
+ y->tv_usec -= ONE_MILLION * nsec;
+ y->tv_sec += nsec;
+ }
+ if (x->tv_usec - y->tv_usec > ONE_MILLION)
+ {
+ int nsec = (x->tv_usec - y->tv_usec) / ONE_MILLION;
+ y->tv_usec += ONE_MILLION * nsec;
+ y->tv_sec -= nsec;
+ }
+
+ /* Compute the time remaining to wait.
+ `tv_usec' is certainly positive. */
+ result->tv_sec = x->tv_sec - y->tv_sec;
+ result->tv_usec = x->tv_usec - y->tv_usec;
+
+ /* Return 1 if result is negative. */
+ return x->tv_sec < y->tv_sec;
+}
+
+//####################################
+ /*/
+
+ //read-pacaleala
+ hostmanager.insertNewHost("Ras1","martini",8081);
+ hostmanager.insertNewHost("Ras2","coconutkiss",8082);
+ hostmanager.insertNewHost("Ras3","tequilla",8082);
+
+ dbHostManager.insertNewHost("julep", "rasdec/rasdec@julep.akglocal.de");
+ dbHostManager.insertNewHost("pinacolada","rasdec/rasdec@pinacolada.akglocal.de");
+
+ dbManager.insertNewDatabase("RasDemo");
+ dbManager[0].connectToDBHost("julep");
+ dbManager[0].connectToDBHost("pinacolada");
+
+ dbManager.insertNewDatabase("BLVA");
+ dbManager[1].connectToDBHost("pinacolada");
+
+ rasManager.insertNewServer("RasServer11","Ras1",SERVERTYPE_FLAG_RPC,0x29999998);
+ rasManager[0].connectToDBHost("julep");//,"\\");
+
+ rasManager.insertNewServer("RasServer12","Ras1",SERVERTYPE_FLAG_RPC,0x29999998);
+ rasManager[1].connectToDBHost("pinacolada");//,"\\");
+
+ rasManager.insertNewServer("RasServer21","Ras2",SERVERTYPE_FLAG_HTTP,8085);
+ rasManager[2].connectToDBHost("julep");//,"\\");
+
+ rasManager.insertNewServer("RasServer31","Ras3",SERVERTYPE_FLAG_HTTP,8084);
+ rasManager[3].connectToDBHost("julep");//,"\\");
+
+ rasManager.insertNewServer("RasServer00","RasMaster",SERVERTYPE_FLAG_HTTP,8083);
+ rasManager[4].connectToDBHost("julep");//,"\\");
+
+ dbManager.insertNewDatabase("RasNew");
+ dbManager[2].connectToDBHost("julep");
+
+ return true;
+ // */
+