fountainAdmin.cpp

Go to the documentation of this file.
00001 /* ex: set tabstop=4 expandtab: */
00002 /*                                                             */
00003 /*  (c) 2004-2006 Iowa State University                        */
00004 /*      see the LICENSE file in the top level directory        */
00005 /*                                                             */
00006 /* $Id: fountainAdmin.cpp 630 2006-06-15 20:51:48Z samm $ */
00013 #include "define.h"
00014 #include "FountainWireProt.h"
00015 #include "NodeID.h"
00016 #include "LokiInclude.h"
00017 #include <bamboo/libbamboo.h>
00018 #include <bamboo/qLog.h>
00019 #include <bamboo/SSSXML.h>
00020 #include <bamboo/ConfigReader.h>
00021 #include <bamboo/TypeConvert.h>
00022 #include <bamboo/ServiceDir.h>
00023 #include <memory>
00024 #include <sstream>
00025 #include <cstddef> //for NULL
00026 #include <iostream>
00027 
00028 using namespace BambooLib;
00029 using namespace Loki;
00030 using std::ostringstream;
00031 using std::string;
00032 using std::auto_ptr;
00033 using std::cout;
00034 using std::cerr;
00035 using std::endl;
00036 
00040 enum AdminMode {
00041     invalidMode = 0,
00042     admin,
00043     trace,
00044     bomb,
00045     set,
00046     numAdminModes
00047 };
00048 
00054 bool parseArgs(int argc, char **argv);
00055 
00060 void version(char* name);
00061 
00067 void usage(char** argv, AdminMode mode);
00068 
00073 const char* fountain_convert(AdminMode t);
00074 
00080  bool fountain_convert(const char* s, AdminMode& a);
00081  
00085 void cleanUp();
00086 
00091 void handleAdminResponse(const ParseMsg* responseMessage);
00092 
00097 void handleSetResponse(const ParseMsg* responseMessage);
00098 
00103 void handleTraceResponse(const ParseMsg* responseMessage);
00104 
00109 void handleBombResponse(const ParseMsg* responseMessage);
00110 
00111 //globals
00112 ConfigReader& config(ConfigReader::getInstance());
00113 qLog& qLogger(qLog::getInstance());
00114 ServiceDir& serviceDir(ServiceDir::getInstance());
00115 AdminMode userMode = admin;
00116 
00117 //admin globals
00118 bool killServer = false;
00119 bool stats = false;
00120 bool flushDatabase = false;
00121 bool treeTopology = false;
00122 bool rebuildTree = false;
00123 unsigned int rebuildTreeDegree = 0;
00124 qLog_Levels serverLoggingLevel = badLevel;
00125 bool forceDiscover = false;
00126 bool reloadConfig = false;
00127 
00128 #if ENABLE_NODE_DAEMONS == 1
00129 //trace globals
00130 bool traceExtendedOutput = false;
00131 
00132 //bomb globals
00133 string bombNodeIdValue;
00134 #endif
00135 
00136 //set globals
00137 RMAP_Relation_Operator_Type nodeIdOp;
00138 string nodeIdValue;
00139 string nodeStateValue;
00140 
00141 //main function
00142 int main(int argc, char** argv) {
00143     if (BambooLib::Setup() == FAILURE) {
00144         cerr << "Failed to initialize Bamboo Library\n";
00145         exit(EXIT_FAILURE);
00146     }
00147     
00148     //if anything below throws an exception, this scope guard will call the cleanUp function
00149     ScopeGuard cleanupGuard = MakeGuard(&cleanUp);
00150     
00151     try {
00152         //if parseArgs throws an exception, this scope guard will call the usage function
00153         if (!parseArgs(argc, argv)) {
00154             usage(argv, userMode);
00155             return EXIT_FAILURE;
00156         }
00157         
00158                 auto_ptr<SSSWireProt> wireProt(ENFORCE(serviceDir.ObtainConnection(NodeMonitor))("Could not connect to Fountain"));
00159 
00160         //send message to server
00161         BuildMsg requestMessage(sss_convert(envelopeElement));
00162         requestMessage.NewMasterName(sss_convert(requestElement));
00163         XMLElement* baseElement = requestMessage.getWorkingElement();
00164         if (userMode != set) {
00165             baseElement->addChildElement("Object", sss_convert(serverObject));
00166         } else {
00167             baseElement->addChildElement("Object", sss_convert(nodeObject));
00168         }
00169         XMLElement* requestDataElement = baseElement->addChildElement(sss_convert(dataElement));
00170         if (userMode == admin) {
00171             baseElement->addAttribute("action", FountainMessage::fountain_convert(FountainMessage::admin));
00172             if (killServer) requestDataElement->addChildElement("KillServer", "true");
00173             if (flushDatabase) requestDataElement->addChildElement("FlushDatabase", "true");
00174             if (serverLoggingLevel != badLevel) {
00175                 requestDataElement->addChildElement("ServerLoggingLevel", qLog::levelToText(serverLoggingLevel));
00176             }
00177             if (treeTopology) {
00178                 requestDataElement->addChildElement("TreeTopology", "true");
00179             }
00180             if (stats) {
00181                 requestDataElement->addChildElement("ServerStats", "true");
00182             }
00183             if (rebuildTree) {
00184                 XMLElement* rebuildElement = requestDataElement->addChildElement("RebuildTree", "true");
00185                 if (rebuildTreeDegree != 0) {
00186                     ostringstream temp;
00187                     temp << rebuildTreeDegree;
00188                     rebuildElement->addAttribute("degree", temp.str().c_str());
00189                 }
00190             }
00191             if (reloadConfig) {
00192                 requestDataElement->addChildElement("ReloadConfig", "true");
00193             }
00194             //add the requested discovery
00195             if (forceDiscover) {
00196                 XMLElement* serverDataSourceElement = requestDataElement->addChildElement("ServerData");
00197                 if (forceDiscover) {
00198                     serverDataSourceElement->addChildElement("Discover", "true");
00199                 }
00200             }
00201 #       if ENABLE_NODE_DAEMONS == 1
00202         } else if (userMode == trace) {
00203             baseElement->addAttribute("action", "trace");
00204         } else if (userMode == bomb) {
00205             baseElement->addAttribute("action", "bomb");
00206             if (bombNodeIdValue.empty()) {
00207                requestDataElement->addChildElement("bombRegEx", ".*");
00208             } else {
00209                requestDataElement->addChildElement("bombRegEx", bombNodeIdValue.c_str());
00210             }
00211 #       endif
00212         } else if (userMode == set) {
00213             baseElement->addAttribute("action", "Modify");
00214             //RMAP_Relation_Operator_Type nodeIdOp;
00215             //string nodeIdValue;
00216             //string nodeStateValue;
00217             if (!nodeIdValue.empty()) {
00218                 XMLElement* whereElementPtr = baseElement->addChildElement(sss_convert(whereElement), nodeIdValue.c_str());
00219                 whereElementPtr->addAttribute("name", "NodeId");
00220                 whereElementPtr->addAttribute("op", sss_convert(nodeIdOp));
00221             }
00222             if (!nodeStateValue.empty()) {
00223                 XMLElement* setElementPtr = baseElement->addChildElement(sss_convert(setElement), nodeStateValue.c_str());
00224                 setElementPtr->addAttribute("name", "State");
00225             } else {
00227             }
00228         } else {
00229             ENFORCE(false)("Unknown userMode");
00230         }
00231 
00232         ENFORCE(wireProt->sendMessage(&requestMessage))("Error sending ")(fountain_convert(userMode))(" request to fountain server");
00233         ParseMsg* resultMessage = ENFORCE(wireProt->recvMessage())("Received zero length message response from fountain server");
00234         if ((qLogger.getLevel() != QLOG_MSGDEBUG) && (!resultMessage->getStatus())) {
00235             cout << "Received Failure response from fountain server!" << endl;
00236             if (resultMessage->getResponseMessage()) {
00237                 cout << "Message: " << resultMessage->getResponseMessage() << endl;
00238             }
00239         } else {
00240             if (userMode == admin) {
00241                 handleAdminResponse(resultMessage);
00242             } else if (userMode == set) {
00243                 handleSetResponse(resultMessage);
00244 #           if ENABLE_NODE_DAEMONS == 1
00245             } else if (userMode == trace) {
00246                 handleTraceResponse(resultMessage);
00247             } else if (userMode == bomb) {
00248                 handleBombResponse(resultMessage);
00249 #           endif
00250             } else {
00251                 ENFORCE(false)("Unknown userMode");
00252             }
00253         }
00254     } catch (const FountainException& e) {
00255         DebugMessageStream(QLOG_ERR) << e.what();
00256         exit(EXIT_FAILURE);
00257     }
00258     
00259     //we could let the scope guard call cleanUp() when it goes out of scope, but considering this is
00260     //normal operation of fountainAdmin, it probably doesn't make sense to do that...  So we'll dismiss
00261     //the guard and call cleanUp ourself!
00262     cleanupGuard.Dismiss();
00263     cleanUp();
00264     return EXIT_SUCCESS;
00265 }
00266 
00267 void cleanUp() {
00268     BambooLib::Shutdown();
00269 }
00270 
00271 void handleAdminResponse(const ParseMsg* responseMessage) {
00272     if (qLogger.getLevel() != QLOG_MSGDEBUG) {
00273         XMLElement* dataElement = responseMessage->getDataElement();
00274         if (dataElement == NULL) {
00275             cerr << "Missing <Data> element in Fountain server response" << endl;
00276         } else {
00277             auto_ptr<XMLElementList> serverStatsList(dataElement->getElementsByName("ServerStats"));
00278             if ((serverStatsList.get() != NULL) && (serverStatsList->length() > 0)) {
00279                 cout << "Fountain Statistics:" << endl;
00280                 cout << "===============================" << endl;
00281                 XMLElement* serverStats = serverStatsList->item(0);
00282                 auto_ptr<XMLElementList> uptimeList(serverStats->getElementsByName("Uptime"));
00283                 if ((uptimeList.get() != NULL) && (uptimeList->length() > 0)) {
00284                     const char* uptime = uptimeList->item(0)->getValue();
00285                     if (uptime != NULL) cout << "Server Uptime: " << uptime << endl;
00286                 }
00287                 
00288                 auto_ptr<XMLElementList> serverLoggingList(serverStats->getElementsByName("ServerLoggingLevel"));
00289                 if ((serverLoggingList.get() != NULL) && (serverLoggingList->length() > 0)) {
00290                     const char* serverLoggingLevelValue = serverLoggingList->item(0)->getValue();
00291                     if (serverLoggingLevelValue != NULL) cout << "Server Logging Level: " << serverLoggingLevelValue << endl;
00292                 }
00293                 
00294                 auto_ptr<XMLElementList> managersList(serverStats->getElementsByName("Managers"));
00295                 if ((managersList.get() != NULL) && (managersList->length() > 0)) {
00296                     const char* managers = managersList->item(0)->getValue();
00297                     if (managers != NULL) cout << "List of managers: " << managers << endl;
00298                 }
00299                 
00300                 auto_ptr<XMLElementList> nodesList(serverStats->getElementsByName("Nodes"));
00301                 if ((nodesList.get() != NULL) && (nodesList->length() > 0)) {
00302                     const char* nodes = nodesList->item(0)->getValue();
00303                     if (nodes != NULL) cout << "Number of nodes in monitor database: " << nodes << endl;
00304                 }
00305                 
00306                 auto_ptr<XMLElementList> queryIntervalList(serverStats->getElementsByName("QueryInterval"));
00307                 if ((queryIntervalList.get() != NULL) && (queryIntervalList->length() > 0)) {
00308                     const char* queryInterval = queryIntervalList->item(0)->getValue();
00309                     if (queryInterval != NULL) cout << "Query interval: " << queryInterval << " seconds" << endl;
00310                 }
00311                 
00312                 auto_ptr<XMLElementList> treeRecoveriesList(serverStats->getElementsByName("TreeRecoveries"));
00313                 if ((treeRecoveriesList.get() != NULL) && (treeRecoveriesList->length() > 0)) {
00314                     const char* treeRecoveries = treeRecoveriesList->item(0)->getValue();
00315                     if (treeRecoveries != NULL) cout << "Total tree recoveries: " << treeRecoveries << endl;
00316                 }
00317                 
00318                 auto_ptr<XMLElementList> treeRebuildsList(serverStats->getElementsByName("TreeRebuilds"));
00319                 if ((treeRebuildsList.get() != NULL) && (treeRebuildsList->length() > 0)) {
00320                     const char* treeRebuilds = treeRebuildsList->item(0)->getValue();
00321                     if (treeRebuilds != NULL) cout << "Total tree rebuilds: " << treeRebuilds << endl;
00322                 }
00323 
00324 #                if ENABLE_INFINIBAND == 1
00325                     auto_ptr<XMLElementList> infinibandStatisticsList(serverStats->getElementsByName("Infiniband"));
00326                     if ((infinibandStatisticsList.get() != NULL) && (infinibandStatisticsList->length() > 0)) {
00327                         XMLElement* infinibandElement = infinibandStatisticsList->item(0);
00328                         auto_ptr<XMLElementList> discoveryElementList(infinibandElement->getElementsByName("Discovery"));
00329                         if ((discoveryElementList.get() != NULL) && (discoveryElementList->length() > 0)) {
00330                             XMLElement* discoveryElement = discoveryElementList->item(0);
00331                             auto_ptr<XMLElementList> discoveryIntervalList(discoveryElement->getElementsByName("Interval"));
00332                             if ((discoveryIntervalList.get() != NULL) && (discoveryIntervalList->length() > 0)) {
00333                                 const char* discoveryInterval = discoveryIntervalList->item(0)->getValue();
00334                                 if (discoveryInterval) cout << "Infiniband Network discovery interval: " << discoveryInterval << " seconds" << endl;
00335                             }
00336                             
00337                             auto_ptr<XMLElementList> discoveryTimeList(discoveryElement->getElementsByName("Time"));
00338                             if ((discoveryTimeList.get() != NULL) && (discoveryTimeList->length() > 0)) {
00339                                 const char* discoveryTime = discoveryTimeList->item(0)->getValue();
00340                                 if (discoveryTime) cout << "Infiniband Network discovery time: " << discoveryTime << endl;
00341                             }
00342                         }
00343                         
00344                         auto_ptr<XMLElementList> pollElementList(infinibandElement->getElementsByName("Poll"));
00345                         if ((pollElementList.get() != NULL) && (pollElementList->length() > 0)) {
00346                             XMLElement* pollElement = pollElementList->item(0);
00347                             auto_ptr<XMLElementList> pollIntervalList(pollElement->getElementsByName("Interval"));
00348                             if ((pollIntervalList.get() != NULL) && (pollIntervalList->length() > 0)) {
00349                                 const char* pollInterval = pollIntervalList->item(0)->getValue();
00350                                 if (pollInterval) cout << "Infiniband Network poll interval: " << pollInterval << " seconds" << endl;
00351                             }
00352                             
00353                             auto_ptr<XMLElementList> pollTimeList(pollElement->getElementsByName("Time"));
00354                             if ((pollTimeList.get() != NULL) && (pollTimeList->length() > 0)) {
00355                                 const char* pollTime = pollTimeList->item(0)->getValue();
00356                                 if (pollTime) cout << "Infiniband Network poll time: " << pollTime << endl;
00357                             }
00358                         }
00359                     }
00360 #                endif
00361                 
00362                 auto_ptr<XMLElementList> requestsList(serverStats->getElementsByName("Requests"));
00363                 if ((requestsList.get() != NULL) && (requestsList->length() > 0)) {
00364                     XMLElement* requests = requestsList->item(0);
00365                     auto_ptr<XMLElementList> totalRequests(requests->getElementsByName("TotalRequests"));
00366                     if ((totalRequests.get() != NULL) && (totalRequests->length() > 0)) {
00367                         cout << "Total requests: " << totalRequests->item(0)->getValue() << endl;
00368                     }
00369                     auto_ptr<XMLElementList> totalMalformedRequests(requests->getElementsByName("TotalMalformedRequests"));
00370                     if ((totalMalformedRequests.get() != NULL) && (totalMalformedRequests->length() > 0)) {
00371                         cout << "Total malformed requests: " << totalMalformedRequests->item(0)->getValue() << endl;
00372                     }
00373                     auto_ptr<XMLElementList> adminRequests(requests->getElementsByName("AdminRequests"));
00374                     if ((adminRequests.get() != NULL) && (adminRequests->length() > 0)) {
00375                         cout << "Admin requests: " << adminRequests->item(0)->getValue() << endl;
00376                     }
00377                     auto_ptr<XMLElementList> adminMalformedRequests(requests->getElementsByName("AdminMalformedRequests"));
00378                     if ((adminMalformedRequests.get() != NULL) && (adminMalformedRequests->length() > 0)) {
00379                         cout << "Admin malformed requests: " << adminMalformedRequests->item(0)->getValue() << endl;
00380                     }
00381                     auto_ptr<XMLElementList> nodeMonitorRequests(requests->getElementsByName("NodeMonitorRequests"));
00382                     if ((nodeMonitorRequests.get() != NULL) && (nodeMonitorRequests->length() > 0)) {
00383                         cout << "Node monitor requests: " << nodeMonitorRequests->item(0)->getValue() << endl;
00384                     }
00385                     auto_ptr<XMLElementList> nodeMonitorMalformedRequests(requests->getElementsByName("NodeMonitorMalformedRequests"));
00386                     if ((nodeMonitorMalformedRequests.get() != NULL) && (nodeMonitorMalformedRequests->length() > 0)) {
00387                         cout << "Node monitor malformed requests: " << nodeMonitorMalformedRequests->item(0)->getValue() << endl;
00388                     }
00389                 }
00390                 
00391                 auto_ptr<XMLElementList> buildDateList(serverStats->getElementsByName("BuildDate"));
00392                 if ((buildDateList.get() != NULL) && (buildDateList->length() > 0)) {
00393                     XMLElement* buildDate = buildDateList->item(0);
00394                     if (buildDate->getValue()) {
00395                         cout << "Build date: " << buildDate->getValue() << endl;
00396                     }
00397                 }
00398                 
00399                 auto_ptr<XMLElementList> buildArgumentsList(serverStats->getElementsByName("BuildArguments"));
00400                 if ((buildArgumentsList.get() != NULL) && (buildArgumentsList->length() > 0)) {
00401                     XMLElement* buildArguments = buildArgumentsList->item(0);
00402                     if (buildArguments->getValue()) {
00403                         cout << "Build arguments: " << buildArguments->getValue() << endl;
00404                     }
00405                 }
00406                 
00407                 cout << endl;
00408             } else if (stats) {
00409                 cerr << "Missing <ServerStats> Data element in Fountain server response" << endl;
00410             }
00411             
00412             //print the results from requesting the fountainNode tree structure
00413             auto_ptr<XMLElementList> treeTopologyList(dataElement->getElementsByName("TreeTopology"));
00414             if ((treeTopologyList.get() != NULL) && (treeTopologyList->length() > 0)) {
00415                 cout << "Fountain Tree Structure:" << endl;
00416                 cout << "===============================" << endl;
00417                 XMLElement* treeTopologyXml = treeTopologyList->item(0);
00418                 auto_ptr<XMLElementList> treeTopologyXmlChildren(treeTopologyXml->getElementsByName("Node"));
00419                 if ((treeTopologyXmlChildren.get() != NULL) && (treeTopologyXmlChildren->length() > 0)) {
00420                     for (unsigned int i=0; i < treeTopologyXmlChildren->length(); i++) {
00421                         XMLElement* currNode = treeTopologyXmlChildren->item(i);
00422                         cout << i << " " << currNode->getAttributeValue("ID") << endl;
00423                     }
00424                     cout << endl;
00425                 }
00426             }
00427         }
00428         
00429         if (responseMessage->getResponseMessage() != NULL) {
00430             cout << "Message:" << endl << responseMessage->getResponseMessage() << endl;
00431         }
00432     }
00433     return;
00434 }
00435 
00436 void handleSetResponse(const ParseMsg* responseMessage) {
00437 
00438 }
00439 
00440 #if ENABLE_NODE_DAEMONS == 1
00441 void handleTraceResponse(const ParseMsg* responseMessage) {
00442     if (qLogger.getLevel() != QLOG_MSGDEBUG) {
00443         XMLElement* dataXML = responseMessage->getDataElement();
00444         auto_ptr<XMLElementList> nodeListList(dataXML->getElementsByName("NodeList"));
00445         if ((nodeListList.get() != NULL) && (nodeListList->length() > 0)) {
00446             auto_ptr<XMLElementList> children(nodeListList->item(0)->getChildren());
00447             for (unsigned int i=0; i < children->length(); i++) {
00448                 XMLElement* node = children->item(i);
00449                 const char* ID = node->getAttributeValue("ID");
00450                 if (ID == NULL) continue;
00451                 if (traceExtendedOutput) {
00452                     cout << "Node ID: " << ID << endl;
00453                     auto_ptr<XMLElementList> nodeChildren(node->getChildren());
00454                     for (unsigned int j=0; j < nodeChildren->length(); j++) {
00455                         if (nodeChildren->item(j)->isName("Status")) {
00456                             XMLElement* status = nodeChildren->item(j);
00457                             auto_ptr<XMLElementList> statusValueList(status->getElementsByName("Value"));
00458                             if ((statusValueList.get() != NULL) && (statusValueList->length() > 0)) {
00459                                 const char* statusValue = statusValueList->item(0)->getValue();
00460                                 if (statusValue != NULL) cout << "\tStatus: " << statusValue << endl;
00461                             }
00462                             auto_ptr<XMLElementList> messageList(status->getElementsByName("Message"));
00463                             if ((messageList.get() != NULL) && (messageList->length() > 0)) {
00464                                 const char* message = messageList->item(0)->getValue();
00465                                 if (message != NULL) cout << "\tMessage: " << message << endl;
00466                             }
00467                         } else if (nodeChildren->item(j)->isName("Parent")) {
00468                             XMLElement* parent = nodeChildren->item(j);
00469                             if (parent->getAttributeValue("ID")) {
00470                                 cout << "\tParent: " << parent->getAttributeValue("ID") << endl;
00471                             }
00472                         }
00473                     }
00474                     cout << endl;
00475                 } else {
00476                     cout << ID << endl;
00477                 }
00478             }
00479             cout << endl << endl;
00480         } else {
00481             cout << "Missing NodeList data element in response message!" << endl;
00482         }
00483     }
00484     return;
00485 }
00486 
00487 void handleBombResponse(const ParseMsg* responseMessage) {
00488     if (qLogger.getLevel() != QLOG_MSGDEBUG) {
00489         XMLElement* dataXML = responseMessage->getDataElement();
00490         if (dataXML == NULL) {
00491             cerr << "Missing data element in Fountain server response!" << endl;
00492         } else {
00493             auto_ptr<XMLElementList> nodeList(dataXML->getElementsByName("NodeList"));
00494             if ((nodeList.get() == NULL) || (nodeList->length() <= 0)) {
00495                 cerr << "Missing NodeList element in reply from Fountain server!" << endl;
00496             } else {
00497                 auto_ptr<XMLElementList> nodeListChildren(nodeList->item(0)->getChildren());
00498                 if ((nodeListChildren.get() == NULL) || (nodeListChildren->length() <= 0)) {
00499                     cerr << "Missing NodeList child elements in reply from Fountain server!" << endl;
00500                 } else {
00501                     cout << "The following nodes exited:" << endl;
00502                     for (unsigned int i=0; i < nodeListChildren->length(); i++) {
00503                         const char* node = nodeListChildren->item(i)->getAttributeValue("ID");
00504                         if (node) {
00505                             const char* exitStatus = nodeListChildren->item(i)->getAttributeValue("Exit");
00506                             if ((exitStatus) && (!strcmp(exitStatus, "true"))) {
00507                                 cout << node << " ";
00508                             }
00509                         }
00510                     }
00511                     cout << endl;
00512                 }
00513             }
00514         }
00515     }
00516     
00517     return;
00518 }
00519 #endif
00520 
00521 bool parseArgs(int argc, char** argv) {
00522     int argInd = 1;
00523     char * textpart;
00524     string configFile;
00525     bool dumpWireMsg = false;
00526     
00527     if (argInd < argc) {
00528         //first argument can change the mode of fountainAdmin
00529         if (!fountain_convert(argv[argInd], userMode)) {
00530             cout << "Could not convert \"" << argv[argInd] << "\" into userMode, assuming admin mode" << endl;
00531         } else {
00532             argInd++;
00533         }
00534     }
00535         
00536     while(argInd < argc) {
00537         if (argv[argInd][0] == '-') { //check for arg switch
00538             char arg = argv[argInd][1];
00539             if (arg == 'v') {
00540                 version(argv[0]);
00541                 return false;
00542             } else if (arg == 'h') {
00543                 return false;
00544             } else if (arg == 'd') {
00545                 dumpWireMsg = true;
00546             } else if ((arg != '-') && (userMode == admin)) {
00547                 switch(arg) {
00548 #                   if ENABLE_NODE_DAEMONS == 1
00549                     case 't': //print tree
00550                         treeTopology = true;
00551                         break;
00552 #                   endif
00553                     case 'k'://kill server
00554                         killServer = true;
00555                     break;
00556                     case 's'://report statistical info
00557                         stats = true;
00558                     break;
00559                     case 'f'://flush
00560                         flushDatabase = true;
00561                     break;
00562                     default:
00563                         cerr << "Invalid Argument: " << argv[argInd] << endl;
00564                         return false;
00565                     break;
00566                 }
00567 #           if ENABLE_NODE_DAEMONS == 1
00568             } else if ((arg != '-') && (userMode == trace)) {
00569                 switch(arg) {
00570                     case 'x': //extended output
00571                         traceExtendedOutput = true;
00572                     break;
00573                     default:
00574                         cerr << "Invalid Argument: " << argv[argInd] << endl;
00575                         return false;
00576                     break;
00577                 }
00578 #           endif
00579             } else if (arg == '-') {
00580                 textpart = (argv[argInd]+2);
00581                 if (!strcmp(textpart,"help")) {
00582                     return false;
00583                 } else if (!strcmp(textpart,"version")) {
00584                     version(argv[0]);
00585                     return false;
00586                 } else if (!strcmp(textpart, "debug")) {
00587                     dumpWireMsg = true;
00588                 } else if (!strcmp(textpart,"config")) {
00589                     if ((argInd+1) == argc) {
00590                         return false;
00591                     }
00592                     configFile = argv[argInd+1];
00593                     argInd++;
00594 #               if ENABLE_NODE_DAEMONS == 1
00595                 } else if ((userMode == bomb) && !strcmp(textpart, "node")) {
00596                     if ((argInd+1) == argc) {
00597                         return false;
00598                     }
00599                     bombNodeIdValue = argv[argInd+1];
00600                     argInd++;
00601                 } else if ((userMode == admin) && !strcmp(textpart, "tree")) {
00602                     treeTopology = true;
00603 #               endif
00604                 } else if ((userMode == admin) && !strcmp(textpart, "kill")) {
00605                     killServer = true;
00606                 } else if ((userMode == admin) && !strcmp(textpart, "flush")) {
00607                     flushDatabase = true;
00608 #               if ENABLE_NODE_DAEMONS == 1
00609                 } else if ((userMode == admin) && !strcmp(textpart, "rebuild")) {
00610                     rebuildTree = true;
00611                     //check for optional degree parameter
00612                     if (argInd+1 < argc) {
00613                         //make sure the first character of this parameter is a digit, if it isn't
00614                         //then the degree parameter was probably omitted
00615                         if (isdigit(argv[argInd+1][0])) {
00616                             if (!TypeConvert::fromString(argv[argInd+1], rebuildTreeDegree)) {
00617                                 cerr << "Conversion of string " << argv[argInd+1] << " to unsigned int failed" << endl;
00618                                 return false;
00619                             }
00620                             argInd++;
00621                         }
00622                     }
00623 #               endif
00624                 } else if ((userMode == admin) && !strcmp(textpart, "log")) {
00625                     if (argInd+1 >= argc) {
00626                         cerr << "Please give a logging level after --log" << endl;
00627                         return false;
00628                     }
00629                     serverLoggingLevel = qLog::levelFromText(argv[argInd+1]);
00630                     if (serverLoggingLevel == badLevel) {
00631                         cerr << "The level \"" << argv[argInd+1] << "\" is not a valid logging level!" << endl;
00632                         return false;
00633                     }
00634                     argInd++;
00635                 } else if ((userMode == admin) && !strcmp(textpart, "stats")) {
00636                     stats = true;
00637                 } else if ((userMode == admin) && !strcmp(textpart, "discover")) {
00638                     forceDiscover = true;
00639                 } else if ((userMode == admin) && !strcmp(textpart, "reload")) {
00640                     reloadConfig = true;
00641                 } else if ((userMode == set) && !strcmp(textpart, "node")) {
00642                     if ((argInd+1) < argc)    {
00643                         textpart = argv[argInd+1];
00644                         while (((argInd+1) < argc) && (textpart[0] != '-')) {
00645                             if ((nodeIdOp == RO_Invalid) && (sss_convert(textpart, nodeIdOp))) {
00646                                 if ((nodeIdOp != RO_RegEx) && (nodeIdOp != RO_NotEqual) && (nodeIdOp != RO_Equal)) {
00647                                     cerr << "Please only use like, eq, or ne for --node" << endl;
00648                                     exit(EXIT_FAILURE);
00649                                 }
00650                                 argInd++;
00651                             } else if (nodeIdOp == RO_Invalid) {
00652                                 cerr << "Please give --node op before value \"" << textpart << "\"" << endl;
00653                                 return FAILURE;
00654                             } else {
00655                                 nodeIdValue = textpart;
00656                                 argInd++;
00657                             }
00658                             if ((argInd+1) < argc) textpart = argv[argInd+1];
00659                         }
00660                         if ((nodeIdOp != RO_Invalid) && (nodeIdValue.length() == 0)) {
00661                             cerr << "Please give a value to compare the nodeId with" << endl;
00662                             return FAILURE;
00663                         }
00664                     }
00665                 } else if ((userMode == set) && !strcmp(textpart, "state")) {
00666                     if ((argInd+1) == argc) {
00667                         return false;
00668                     }
00669                     argInd++;
00670                     nodeStateValue = argv[argInd];
00671                     if (!nodeStateValue.compare("Up")) {
00672                         //do nothing
00673                     } else if (!nodeStateValue.compare("Down")) {
00674                         //do nothing
00675                     } else if (!nodeStateValue.compare("Unavailable")) {
00676                         //do nothing
00677                     } else if (!nodeStateValue.compare("Invalid")) {
00678                         //do nothing
00679                     } else {
00680                         cerr << "Use either \"Up\", \"Down\", \"Unavailable\", or \"Invalid\" to set node state" << endl;
00681                         exit(EXIT_FAILURE);
00682                     }
00683                     argInd++;
00684 #               if ENABLE_NODE_DAEMONS == 1
00685                 } else if ((userMode == trace) && !strcmp(textpart, "extended")) {
00686                     traceExtendedOutput = true;
00687 #               endif
00688                 } else {
00689                     cerr << "Invalid Argument: " << argv[argInd] << endl;
00690                     return false;
00691                 }
00692             }
00693         } else {
00694             cerr << "Invalid Argument: " << argv[argInd] << endl;
00695             return false;
00696         }
00697         argInd++;
00698     }
00699     
00700     //read config file
00701     if (configFile.length() == 0) {
00702         configFile.append(DEFAULT_CONFIG_FILE);
00703     }
00704     if (config.readFile(configFile.c_str()) != FAILURE) {
00705         ostringstream msg;
00706         cout << "read config file \"" << configFile << "\"" << endl;
00707     }
00708     config.readEnvVars();
00709     
00710     //setup logger
00711     if (dumpWireMsg) {
00712         qLogger.setThreshold(QLOG_MSGDEBUG);
00713     } else {
00714         qLogger.setThreshold(QLOG_INFO);
00715     }
00716     qLogger.fileOutput(false);
00717     qLogger.screenOutput(true);
00718     
00719     return true;
00720 }
00721 
00722 void usage(char** argv, AdminMode mode) {
00723     switch(mode) {
00724         case admin:
00725             cout << argv[0] << " [admin ";
00726 #           if ENABLE_NODE_DAEMONS == 1
00727             cout << " | trace | bomb ";
00728 #           endif
00729             cout << "| set] ";
00730             cout << "[options]" << endl;
00731             cout << "Options:" << endl;
00732 #           if ENABLE_NODE_DAEMONS == 1
00733                 cout << "\t -t | --tree : Prints the fountain node tree structure." << endl;
00734 #           endif
00735             cout << "\t -k | --kill : Requests the server to shutdown." << endl;
00736             cout << "\t -f | --flush : Requests the server to erase its node monitor database and start over from scratch." << endl;
00737 #           if ENABLE_NODE_DAEMONS == 1
00738                 cout << "\t --rebuild [degree] : Requests the master Fountain node to rebuild the tree topology using the optional degree parameter." << endl;
00739 #           endif
00740             cout << "\t -s | --stats : Requests the server to respond with statistical information." << endl;
00741             cout << "\t --reload : Force the Fountain server to reload its config file." << endl;
00742             cout << "\t --discover : Force a server specific datasource discovery." << endl;
00743             cout << "\t --log <level> : Change the current server logging level." << endl;
00744             cout << "\t          possible values include:\n"
00745                  << "\t          QLOG_EMERG, QLOG_ALERT, QLOG_CRIT, QLOG_ERR, QLOG_WARNING,\n"
00746                  << "\t          QLOG_NOTICE, QLOG_INFO, QLOG_DEBUG, QLOG_MSGDEBUG" << endl;
00747         break;
00748         case trace:
00749             cout << argv[0] << " trace [options]\n";
00750             cout << "\t -x : Display additional information about each node." << endl;
00751         break;
00752         case bomb:
00753             cout << argv[0] << " bomb [options]\n";
00754             cout << "\t --node value : Bomb only the specified node ID(s) using regular expression matching." << endl;
00755         break;
00756         case set:
00757             cout << argv[0] << " set [options]\n";
00758             cout << "\t --node [[op] [value]] : Specify the node to set. Use the \"like\" op for regular expression matching." << endl;
00759             cout << "\t --state <Up | Down | Unavailable | Invalid> : The node state value to set." << endl;
00760         break;
00761         default:
00762             //unknown admin mode
00763         break;
00764     }
00765 
00766     cout << "\t --config <file> : Path to config file, otherwise it's assumed to be " << DEFAULT_CONFIG_FILE << endl;
00767     cout << "\t -d | --debug : Dump raw messages sent to and from the Fountain server. No other output will be displayed." << endl;
00768     cout << "\t -v | --version : Display version information." << endl;
00769     cout << "\t -h | --help : Display this help screen." << endl;    
00770 }
00771 
00772 void version(char* name) {
00773     cout << name << " - Fountain client utility - Version " << FOUNTAIN_VERSION_STRING << endl;
00774 }
00775 
00776 const char* fountain_convert(AdminMode t) {
00777     const char* result =