ws_machineService.cpp 77 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "ws_machineService.hpp"
  14. #include "jarray.hpp"
  15. #include "dadfs.hpp"
  16. #include "exception_util.hpp"
  17. #ifndef eqHoleCluster
  18. #define eqHoleCluster "HoleCluster"
  19. #endif
  20. #ifndef eqThorCluster
  21. #define eqThorCluster "ThorCluster"
  22. #endif
  23. #ifndef eqRoxieCluster
  24. #define eqRoxieCluster "RoxieCluster"
  25. #endif
  26. #ifndef eqEclCCServer
  27. #define eqEclCCServer "EclCCServerProcess"
  28. #endif
  29. #ifndef eqEclServer
  30. #define eqEclServer "EclServerProcess"
  31. #endif
  32. #ifndef eqEclAgent
  33. #define eqEclAgent "EclAgentProcess"
  34. #endif
  35. #ifndef eqAgentExec
  36. #define eqAgentExec "AgentExecProcess"
  37. #endif
  38. #ifndef eqEclScheduler
  39. #define eqEclScheduler "EclSchedulerProcess"
  40. #endif
  41. #ifndef eqThorMasterProcess
  42. #define eqThorMasterProcess "ThorMasterProcess"
  43. #endif
  44. #ifndef eqThorSlaveProcess
  45. #define eqThorSlaveProcess "ThorSlaveProcess"
  46. #endif
  47. #ifndef eqThorSpareProcess
  48. #define eqThorSpareProcess "ThorSpareProcess"
  49. #endif
  50. #ifndef eqRoxieServerProcess
  51. #define eqRoxieServerProcess "RoxieServerProcess"
  52. #endif
  53. static const int THREAD_POOL_SIZE = 40;
  54. static const int THREAD_POOL_STACK_SIZE = 64000;
  55. static const char* FEATURE_URL = "MachineInfoAccess";
  56. class CMachineInfoThreadParam : public CWsMachineThreadParam
  57. {
  58. public:
  59. IMPLEMENT_IINTERFACE;
  60. IEspContext& m_context;
  61. CGetMachineInfoUserOptions& m_options; //From request
  62. CMachineData& m_machineData; //From request
  63. IArrayOf<IEspMachineInfoEx>& m_machineInfoTable; //For response
  64. StringArray& m_machineInfoColumns; //For response
  65. CMachineInfoThreadParam(Cws_machineEx* pService, IEspContext& context, CGetMachineInfoUserOptions& options,
  66. CMachineData& machineData, IArrayOf<IEspMachineInfoEx>& machineInfoTable, StringArray& machineInfoColumns )
  67. : CWsMachineThreadParam(NULL, NULL, NULL, pService),
  68. m_context(context),
  69. m_options(options),
  70. m_machineData(machineData),
  71. m_machineInfoTable(machineInfoTable),
  72. m_machineInfoColumns(machineInfoColumns)
  73. {
  74. }
  75. virtual void doWork()
  76. {
  77. m_pService->doGetMachineInfo(m_context, this);
  78. }
  79. void addColumn(const char* columnName)
  80. {
  81. synchronized block(s_mutex);
  82. if (m_machineInfoColumns.find(columnName) == NotFound)
  83. m_machineInfoColumns.append(columnName);
  84. }
  85. private:
  86. static Mutex s_mutex;
  87. };
  88. Mutex CMachineInfoThreadParam::s_mutex;
  89. void Cws_machineEx::init(IPropertyTree *cfg, const char *process, const char *service)
  90. {
  91. //Read settings from esp.xml
  92. StringBuffer xpath;
  93. xpath.appendf("Software/EspProcess[@name=\"%s\"]/EspService[@name=\"%s\"]", process, service);
  94. Owned<IPropertyTree> pServiceNode = cfg->getPropTree(xpath.str());
  95. m_bMonitorDaliFileServer = pServiceNode->getPropBool("@monitorDaliFileServer", false);
  96. m_processFilters.setown( pServiceNode->getPropTree("ProcessFilters") );
  97. const char* pchExcludePartitions = pServiceNode->queryProp("@excludePartitions");
  98. if (pchExcludePartitions && *pchExcludePartitions)
  99. {
  100. StringArray sPartitions;
  101. sPartitions.appendList(pchExcludePartitions, ", ;");
  102. unsigned int numOfPartitions = sPartitions.ordinality();
  103. for (unsigned int i=0; i<numOfPartitions; i++)
  104. {
  105. const char* partition = sPartitions.item(i);
  106. if (!partition || !*partition)
  107. continue;
  108. if (strchr(partition, '*'))
  109. m_excludePartitionPatterns.insert( partition );
  110. else
  111. m_excludePartitions.insert( partition );
  112. }
  113. }
  114. m_useDefaultHPCCInit = pServiceNode->getPropBool("UseDefaultHPCCInit", true);//Still used by Rexec for now
  115. m_SSHConnectTimeoutSeconds = pServiceNode->getPropInt("SSHConnectTimeoutSeconds", 5);
  116. const char* machineInfoScript = pServiceNode->queryProp("MachineInfoFile");
  117. if (machineInfoScript && *machineInfoScript)
  118. m_machineInfoFile.append(machineInfoScript);
  119. else
  120. m_machineInfoFile.append("preflight");
  121. //Read settings from environment.xml
  122. m_envFactory.setown( getEnvironmentFactory() );
  123. Owned<IConstEnvironment> constEnv = getConstEnvironment();
  124. Owned<IPropertyTree> pEnvironmentRoot = &constEnv->getPTree();
  125. if (!pEnvironmentRoot)
  126. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get environment information.");
  127. Owned<IPropertyTree> pEnvSettings = pEnvironmentRoot->getPropTree("EnvSettings");
  128. if (pEnvSettings)
  129. {
  130. pEnvSettings->getProp("configs", environmentConfData.m_configsPath.clear());
  131. pEnvSettings->getProp("path", environmentConfData.m_executionPath.clear());
  132. pEnvSettings->getProp("runtime", environmentConfData.m_runtimePath.clear());
  133. pEnvSettings->getProp("lock", environmentConfData.m_lockPath.clear());
  134. pEnvSettings->getProp("pid", environmentConfData.m_pidPath.clear());
  135. pEnvSettings->getProp("user", environmentConfData.m_user.clear());
  136. }
  137. m_threadPoolSize = pServiceNode->getPropInt("ThreadPoolSize", THREAD_POOL_SIZE);
  138. m_threadPoolStackSize = pServiceNode->getPropInt("ThreadPoolStackSize", THREAD_POOL_STACK_SIZE);
  139. //Start thread pool
  140. IThreadFactory* pThreadFactory = new CWsMachineThreadFactory();
  141. m_threadPool.setown(createThreadPool("WsMachine Thread Pool", pThreadFactory,
  142. NULL, m_threadPoolSize, 10000, m_threadPoolStackSize)); //10 sec timeout for available thread; use stack size of 2MB
  143. pThreadFactory->Release();
  144. setupLegacyFilters();
  145. }
  146. bool Cws_machineEx::onGetMachineInfo(IEspContext &context, IEspGetMachineInfoRequest & req,
  147. IEspGetMachineInfoResponse & resp)
  148. {
  149. try
  150. {
  151. if (!context.validateFeatureAccess(FEATURE_URL, SecAccess_Read, false))
  152. throw MakeStringException(ECLWATCH_MACHINE_INFO_ACCESS_DENIED, "Failed to Get Machine Information. Permission denied.");
  153. StringArray& addresses = req.getAddresses();
  154. if (addresses.empty())
  155. throw MakeStringException(ECLWATCH_INVALID_IP_OR_COMPONENT, "No network address specified.");
  156. CGetMachineInfoData machineInfoData;
  157. readMachineInfoRequest(context, req.getGetProcessorInfo(), req.getGetStorageInfo(), req.getLocalFileSystemsOnly(), req.getGetSoftwareInfo(),
  158. req.getApplyProcessFilter(), addresses, req.getAddProcessesToFilter(), machineInfoData);
  159. getMachineInfo(context, machineInfoData);
  160. setMachineInfoResponse(context, req, machineInfoData, resp);
  161. }
  162. catch(IException* e)
  163. {
  164. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  165. }
  166. return true;
  167. }
  168. bool Cws_machineEx::onGetMachineInfoEx(IEspContext &context, IEspGetMachineInfoRequestEx & req, IEspGetMachineInfoResponseEx & resp)
  169. {
  170. try
  171. {
  172. if (!context.validateFeatureAccess(FEATURE_URL, SecAccess_Read, false))
  173. throw MakeStringException(ECLWATCH_MACHINE_INFO_ACCESS_DENIED, "Failed to Get Machine Information. Permission denied.");
  174. StringArray& addresses = req.getAddresses();
  175. if (addresses.empty())
  176. throw MakeStringException(ECLWATCH_INVALID_IP_OR_COMPONENT, "No network address specified.");
  177. CGetMachineInfoData machineInfoData;
  178. readMachineInfoRequest(context, true, true, true, true, true, addresses, NULL, machineInfoData);
  179. getMachineInfo(context, machineInfoData);
  180. if (machineInfoData.getMachineInfoTable().ordinality())
  181. resp.setMachines(machineInfoData.getMachineInfoTable());
  182. }
  183. catch(IException* e)
  184. {
  185. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  186. }
  187. return true;
  188. }
  189. bool Cws_machineEx::onGetTargetClusterInfo(IEspContext &context, IEspGetTargetClusterInfoRequest & req,
  190. IEspGetTargetClusterInfoResponse & resp)
  191. {
  192. try
  193. {
  194. if (!context.validateFeatureAccess(FEATURE_URL, SecAccess_Read, false))
  195. throw MakeStringException(ECLWATCH_MACHINE_INFO_ACCESS_DENIED, "Failed to Get Machine Information. Permission denied.");
  196. StringArray& targetClusters = req.getTargetClusters();
  197. if (targetClusters.empty())
  198. throw MakeStringException(ECLWATCH_INVALID_IP_OR_COMPONENT, "No target cluster specified.");
  199. CGetMachineInfoData machineInfoData;
  200. Owned<IPropertyTree> targetClustersOut = createPTreeFromXMLString("<Root/>");
  201. readMachineInfoRequest(context, req.getGetProcessorInfo(), req.getGetStorageInfo(), req.getLocalFileSystemsOnly(), req.getGetSoftwareInfo(),
  202. req.getApplyProcessFilter(), req.getAddProcessesToFilter(), targetClusters, machineInfoData, targetClustersOut);
  203. getMachineInfo(context, machineInfoData);
  204. setTargetClusterInfoResponse(context, req, machineInfoData, targetClustersOut, resp);
  205. }
  206. catch(IException* e)
  207. {
  208. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  209. }
  210. return true;
  211. }
  212. ////////////////////////////////////////////////////////////////////////////////////////
  213. // Read Machine Infomation request and collect related settings from environment.xml //
  214. ////////////////////////////////////////////////////////////////////////////////////////
  215. void Cws_machineEx::readMachineInfoRequest(IEspContext& context, bool getProcessorInfo, bool getStorageInfo, bool localFileSystemsOnly, bool getSoftwareInfo, bool applyProcessFilter,
  216. StringArray& processes, const char* addProcessesToFilters, CGetMachineInfoData& machineInfoData)
  217. {
  218. StringBuffer userID, password;
  219. context.getUserID(userID);
  220. context.getPassword(password);
  221. machineInfoData.getOptions().setUserName(userID.str());
  222. machineInfoData.getOptions().setPassword(password.str());
  223. machineInfoData.getOptions().setGetProcessorInfo(getProcessorInfo);
  224. machineInfoData.getOptions().setGetStorageInfo(getStorageInfo);
  225. machineInfoData.getOptions().setLocalFileSystemsOnly(localFileSystemsOnly);
  226. machineInfoData.getOptions().setGetSoftwareInfo(getSoftwareInfo);
  227. machineInfoData.getOptions().setApplyProcessFilter(applyProcessFilter);
  228. machineInfoData.getOptions().getAdditionalProcessFilters().appendList(addProcessesToFilters, " ,\t");
  229. BoolHash uniqueProcesses;
  230. for (unsigned i=0; i<processes.ordinality(); i++)
  231. {
  232. StringArray address;
  233. address.appendList(processes.item(i), ":");
  234. StringBuffer address1, address2, processType, compName, path;
  235. unsigned processNumber = 0;
  236. if (!machineInfoData.getOptions().getGetSoftwareInfo())
  237. {
  238. parseAddresses(address.item(0), address1, address2);
  239. }
  240. else
  241. {
  242. if (address.ordinality() < 5)
  243. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Invalid address format in '%s'.", processes.item(i));
  244. parseProcessString(address, address1, address2, processType, compName, path, processNumber);
  245. }
  246. setProcessRequest(machineInfoData, uniqueProcesses, address1.str(), address2.str(), processType.str(), compName.str(), path.str(), processNumber);
  247. }
  248. }
  249. void Cws_machineEx::readMachineInfoRequest(IEspContext& context, bool getProcessorInfo, bool getStorageInfo, bool localFileSystemsOnly, bool getSoftwareInfo, bool applyProcessFilter,
  250. const char* addProcessesToFilters, StringArray& targetClustersIn, CGetMachineInfoData& machineInfoData, IPropertyTree* targetClusterTreeOut)
  251. {
  252. StringBuffer userID, password;
  253. context.getUserID(userID);
  254. context.getPassword(password);
  255. machineInfoData.getOptions().setUserName(userID.str());
  256. machineInfoData.getOptions().setPassword(password.str());
  257. machineInfoData.getOptions().setGetProcessorInfo(getProcessorInfo);
  258. machineInfoData.getOptions().setGetStorageInfo(getStorageInfo);
  259. machineInfoData.getOptions().setLocalFileSystemsOnly(localFileSystemsOnly);
  260. machineInfoData.getOptions().setGetSoftwareInfo(getSoftwareInfo);
  261. machineInfoData.getOptions().setApplyProcessFilter(applyProcessFilter);
  262. machineInfoData.getOptions().getAdditionalProcessFilters().appendList(addProcessesToFilters, " ,\t");
  263. readSettingsForTargetClusters(context, targetClustersIn, machineInfoData, targetClusterTreeOut);
  264. }
  265. //Parses address request from machine information request in the form "192.168.1.4-6|."
  266. //The second address is the address retrieved from environment setting (could be a '.').
  267. void Cws_machineEx::parseAddresses(const char *address, StringBuffer& address1, StringBuffer& address2)
  268. {
  269. address1 = address;
  270. address2.clear();
  271. const char* props1 = strchr(address, '|');
  272. if (props1)
  273. {
  274. address2 = props1+1;
  275. address1.setLength(props1 - address);
  276. }
  277. address1.trim();
  278. address2.trim();
  279. }
  280. //Parses machine information request for each process in the form "192.168.1.4-6|.:ThorSlaveProcess:thor1:2:/var/lib/..."
  281. void Cws_machineEx::parseProcessString(StringArray& process, StringBuffer& address1, StringBuffer& address2,
  282. StringBuffer& processType, StringBuffer& compName, StringBuffer& path, unsigned& processNumber)
  283. {
  284. parseAddresses(process.item(0), address1, address2);
  285. processType.clear().append( process.item(1) ).trim();
  286. compName.clear().append( process.item(2) ).trim();
  287. EnvMachineOS os = (EnvMachineOS) atoi( process.item(3) );
  288. path.clear().append( process.item(4) ).trim();
  289. if (path.length())
  290. {
  291. char pat1, pat2;
  292. char rep1, rep2;
  293. if (os == MachineOsLinux)
  294. {
  295. pat1 = ':'; rep1 = '$';
  296. pat2 = '\\';rep2 = '/';
  297. }
  298. else
  299. {
  300. pat1 = '$'; rep1 = ':';
  301. pat2 = '/';rep2 = '\\';
  302. }
  303. path.replace( pat1, rep1 );
  304. path.replace( pat2, rep2 );
  305. if ((os == MachineOsLinux) && (path.charAt(0) != '/'))
  306. path.insert(0, '/');
  307. }
  308. if (process.ordinality() < 6)
  309. return;
  310. processNumber = atoi( process.item(5) );
  311. }
  312. void Cws_machineEx::setProcessRequest(CGetMachineInfoData& machineInfoData, BoolHash& uniqueProcesses, const char* address1, const char* address2,
  313. const char* processType, const char* compName, const char* path, unsigned processNumber)
  314. {
  315. IpAddress ipAddr;
  316. unsigned numIps = ipAddr.ipsetrange(address1);
  317. //address is like 192.168.1.4-6
  318. //so process each address in the range
  319. if (!ipAddr.isIp4())
  320. IPV6_NOT_IMPLEMENTED();
  321. //Always use "EclAgentProcess" to retrieve machine info for "AgentExecProcess"
  322. StringBuffer processTypeStr;
  323. if (processType && *processType)
  324. {
  325. if (strieq(processType, eqAgentExec))
  326. processTypeStr.append(eqEclAgent);
  327. else
  328. processTypeStr = processType;
  329. }
  330. while (numIps--)
  331. {
  332. unsigned numAddr;
  333. if (ipAddr.getNetAddress(sizeof(numAddr),&numAddr)!=sizeof(numAddr))
  334. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid network address.");
  335. ipAddr.ipincrement(1);
  336. //Clean possible duplication
  337. StringBuffer valuesToBeChecked;
  338. valuesToBeChecked.append(numAddr);
  339. if (machineInfoData.getOptions().getGetSoftwareInfo())
  340. valuesToBeChecked.appendf(":%s:%s:%d", processTypeStr.str(), compName, processNumber);
  341. if (uniqueProcesses.getValue(valuesToBeChecked.str()))
  342. continue;
  343. uniqueProcesses.setValue(valuesToBeChecked.str(), true);
  344. addProcessRequestToMachineInfoData(machineInfoData, address1, address2, processTypeStr.str(), compName, path, processNumber);
  345. }
  346. }
  347. void Cws_machineEx::addProcessRequestToMachineInfoData(CGetMachineInfoData& machineInfoData, const char* address1, const char* address2,
  348. const char* processType, const char* compName, const char* path, unsigned processNumber)
  349. {
  350. CIArrayOf<CMachineData>& machines = machineInfoData.getMachineData();
  351. ForEachItemIn(idx, machines)
  352. {
  353. CMachineData& machine = machines.item(idx);
  354. if (streq(address1, machine.getNetworkAddress()))
  355. {
  356. addProcessData(&machine, processType, compName, path, processNumber);
  357. return;
  358. }
  359. }
  360. char pathSep;
  361. EnvMachineOS os;
  362. Owned<IConstEnvironment> constEnv = getConstEnvironment();
  363. Owned<IConstMachineInfo> pMachineInfo = constEnv->getMachineByAddress(address1);
  364. if (pMachineInfo.get())
  365. os = pMachineInfo->getOS();
  366. else
  367. os = MachineOsUnknown;
  368. if (os == MachineOsW2K)
  369. pathSep = '\\';
  370. else
  371. pathSep = '/';
  372. Owned<CMachineData> machineNew = new CMachineData(address1, address2, os, pathSep);
  373. //Read possible dependencies for all processes
  374. set<string>& dependenciesForAllProcesses = machineNew->getDependencies();
  375. StringBuffer xPath;
  376. xPath.appendf("Platform[@name='%s']/ProcessFilter[@name='any']/Process", machineNew->getOS() == MachineOsW2K ? "Windows" : "Linux");
  377. Owned<IPropertyTreeIterator> processes = m_processFilters->getElements(xPath.str());
  378. ForEach (*processes)
  379. {
  380. StringBuffer processName;
  381. processes->query().getProp("@name", processName);
  382. processName.toLowerCase().replaceString(".exe", "");
  383. if ((processName.length() > 0) && (!streq(processName.str(), "hoagentd"))) //hoagentd is not needed anymore
  384. dependenciesForAllProcesses.insert(processName.str());
  385. }
  386. if (m_bMonitorDaliFileServer && (dependenciesForAllProcesses.find("dafilesrv") == dependenciesForAllProcesses.end()))
  387. dependenciesForAllProcesses.insert("dafilesrv");
  388. addProcessData(machineNew, processType, compName, path, processNumber);
  389. machines.append(*machineNew.getClear());
  390. }
  391. //Create a CProcessData object and add it to CMachineData
  392. void Cws_machineEx::addProcessData(CMachineData* machine, const char* processType, const char* compName,
  393. const char* path, unsigned processNumber)
  394. {
  395. if (!machine)
  396. return;
  397. StringBuffer pathStr = path;
  398. if (pathStr.length() > 0)
  399. {
  400. char pathSep = machine->getPathSep();
  401. if (pathStr.charAt(pathStr.length() - 1) != pathSep)
  402. pathStr.append(pathSep);
  403. }
  404. Owned<CProcessData> process = new CProcessData(compName, processType, pathStr.str(), processNumber);
  405. //Copy dependencies for all processes
  406. set<string>& dependenciesForThisProcess = process->getDependencies();
  407. set<string>& dependenciesForAllProcesses = machine->getDependencies();
  408. set<string>::const_iterator it = dependenciesForAllProcesses.begin();
  409. set<string>::const_iterator iEnd = dependenciesForAllProcesses.end();
  410. for (; it != iEnd; it++) //add in sorted order simply by traversing the map
  411. dependenciesForThisProcess.insert((*it).c_str());
  412. //now collect "process-specific" dependencies
  413. StringBuffer xPath;
  414. xPath.appendf("Platform[@name='%s']/ProcessFilter[@name='%s']", machine->getOS() == MachineOsW2K ? "Windows" : "Linux", processType);
  415. IPropertyTree* processFilterNode = m_processFilters->queryPropTree( xPath.str() );
  416. if (!processFilterNode)
  417. {
  418. machine->getProcesses().append(*process.getClear());
  419. return;
  420. }
  421. Owned<IPropertyTreeIterator> processes = processFilterNode->getElements("Process");
  422. ForEach (*processes)
  423. {
  424. IPropertyTree* pProcess = &processes->query();
  425. const char* name = pProcess->queryProp("@name");
  426. if (!name || streq(name, "."))
  427. continue;
  428. StringBuffer processName = name;
  429. processName.toLowerCase().replaceString(".exe", "");
  430. if (processName.length() < 1)
  431. continue;
  432. //Environment.xml may contain old filter settings.
  433. if (isLegacyFilter(processType, processName.str()))
  434. continue;
  435. if (pProcess->getPropBool("@remove", false))
  436. dependenciesForThisProcess.erase(processName.str());
  437. else
  438. dependenciesForThisProcess.insert(processName.str());
  439. }
  440. process->setMultipleInstances(machine->getOS() == MachineOsLinux && processFilterNode->getPropBool("@multipleInstances", false));
  441. machine->getProcesses().append(*process.getClear());
  442. }
  443. //Collect process settings for the requested target clusters
  444. void Cws_machineEx::readSettingsForTargetClusters(IEspContext& context, StringArray& targetClusters, CGetMachineInfoData& machineInfoData, IPropertyTree* targetClustersOut)
  445. {
  446. unsigned ordinality= targetClusters.ordinality();
  447. if (ordinality < 1)
  448. return;
  449. Owned<IConstEnvironment> constEnv = getConstEnvironment();
  450. Owned<IPropertyTree> pEnvironmentRoot = &constEnv->getPTree();
  451. if (!pEnvironmentRoot)
  452. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get environment information.");
  453. BoolHash uniqueProcesses;
  454. for (unsigned index=0; index<ordinality; index++)
  455. {
  456. StringBuffer clusterType;
  457. const char* clusterName = targetClusters.item(index);
  458. const char* pClusterName = strchr(clusterName, ':');
  459. if (pClusterName)
  460. {
  461. clusterType.append(clusterName, 0, pClusterName - clusterName);
  462. pClusterName++;
  463. }
  464. if (!pClusterName || !*pClusterName)
  465. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Cluster name not specified.");
  466. if (clusterType.length() < 1)
  467. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Cluster type not specified.");
  468. StringBuffer path;
  469. path.appendf("Software/Topology/Cluster[@name='%s']", pClusterName);
  470. IPropertyTree* pCluster = pEnvironmentRoot->queryPropTree(path.str());
  471. if (!pCluster)
  472. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Cluster %s not found in environment setting.", pClusterName);
  473. Owned<IPropertyTreeIterator> clusterProcesses;
  474. if (strieq(clusterType.str(), eqThorCluster) || strieq(clusterType.str(), eqRoxieCluster))
  475. {
  476. clusterProcesses.setown(pCluster->getElements(clusterType.str()));
  477. if (!clusterProcesses->first())
  478. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Cluster %s not found in environment setting.", clusterType.str());
  479. }
  480. Owned<IPropertyTreeIterator> eclCCServerProcesses= pCluster->getElements(eqEclCCServer);
  481. Owned<IPropertyTreeIterator> eclServerProcesses= pCluster->getElements(eqEclServer);
  482. Owned<IPropertyTreeIterator> eclAgentProcesses= pCluster->getElements(eqEclAgent);
  483. Owned<IPropertyTreeIterator> eclSchedulerProcesses= pCluster->getElements(eqEclScheduler);
  484. IPropertyTree *targetClusterOut = targetClustersOut->addPropTree("TargetCluster", createPTree("TargetCluster"));
  485. targetClusterOut->setProp("@Name", pClusterName);
  486. targetClusterOut->setProp("@Type", clusterType.str());
  487. //Read Cluster processes
  488. if (clusterProcesses && clusterProcesses->first())
  489. ForEach(*clusterProcesses)
  490. readTargetClusterProcesses(clusterProcesses->query(), clusterType.str(), uniqueProcesses, machineInfoData, targetClusterOut);
  491. //Read eclCCServer process
  492. if (eclCCServerProcesses->first())
  493. readTargetClusterProcesses(eclCCServerProcesses->query(), eqEclCCServer, uniqueProcesses, machineInfoData, targetClusterOut);
  494. //Read eclServer process
  495. if (eclServerProcesses->first())
  496. readTargetClusterProcesses(eclServerProcesses->query(), eqEclServer, uniqueProcesses, machineInfoData, targetClusterOut);
  497. //Read eclAgent process
  498. if (eclAgentProcesses->first())
  499. readTargetClusterProcesses(eclAgentProcesses->query(), eqEclAgent, uniqueProcesses, machineInfoData, targetClusterOut);
  500. //Read eclScheduler process
  501. if (eclSchedulerProcesses->first())
  502. readTargetClusterProcesses(eclSchedulerProcesses->query(), eqEclScheduler, uniqueProcesses, machineInfoData, targetClusterOut);
  503. }
  504. }
  505. //Collect settings for one group of target cluster processes
  506. void Cws_machineEx::readTargetClusterProcesses(IPropertyTree &processNode, const char* nodeType, BoolHash& uniqueProcesses, CGetMachineInfoData& machineInfoData,
  507. IPropertyTree* targetClustersOut)
  508. {
  509. const char* process = processNode.queryProp("@process");
  510. if (!process || !*process)
  511. throw MakeStringException(ECLWATCH_INTERNAL_ERROR, "Process attribute not set for ECLCCServer in environment setting.");
  512. Owned<IConstEnvironment> constEnv = getConstEnvironment();
  513. Owned<IPropertyTree> pEnvironmentRoot = &constEnv->getPTree();
  514. if (!pEnvironmentRoot)
  515. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get environment information.");
  516. IPropertyTree* pEnvironmentSoftware = pEnvironmentRoot->queryPropTree("Software");
  517. if (!pEnvironmentSoftware)
  518. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get environment information.");
  519. IPropertyTree* pClusterProcess = NULL;
  520. if (strieq(nodeType, eqThorCluster) || strieq(nodeType, eqRoxieCluster))
  521. {
  522. StringBuffer path;
  523. path.appendf("Software/%s[@name='%s']", nodeType, process);
  524. pClusterProcess = pEnvironmentRoot->queryPropTree(path.str());
  525. if (!pClusterProcess)
  526. throw MakeStringException(ECLWATCH_INTERNAL_ERROR, "Process not set for %s in environment setting.", path.str());
  527. }
  528. IPropertyTree *pInfo = targetClustersOut->addPropTree("Process", createPTree("Process"));
  529. pInfo->setProp("@Name", process);
  530. pInfo->setProp("@Type", nodeType);
  531. StringBuffer dirStr;
  532. IPropertyTree* pEnvironmentDirectories = pEnvironmentSoftware->queryPropTree("Directories");
  533. if (!pClusterProcess)
  534. {
  535. if (!pEnvironmentDirectories || !getConfigurationDirectory(pEnvironmentDirectories, "run", nodeType, process, dirStr))
  536. dirStr.clear().append(processNode.queryProp("@directory"));
  537. getProcesses(constEnv, pEnvironmentSoftware, process, nodeType, dirStr.str(), machineInfoData, false, uniqueProcesses);
  538. return;
  539. }
  540. if (!pEnvironmentDirectories || !getConfigurationDirectory(pEnvironmentDirectories, "run", nodeType, process, dirStr))
  541. dirStr.clear().append(pClusterProcess->queryProp("@directory"));
  542. if (strieq(nodeType, eqThorCluster))
  543. {
  544. getProcesses(constEnv, pClusterProcess, process, eqThorMasterProcess, dirStr.str(), machineInfoData, true, uniqueProcesses);
  545. getThorProcesses(constEnv, pClusterProcess, process, eqThorSlaveProcess, dirStr.str(), machineInfoData, uniqueProcesses);
  546. getThorProcesses(constEnv, pClusterProcess, process, eqThorSpareProcess, dirStr.str(), machineInfoData, uniqueProcesses);
  547. }
  548. else if (strieq(nodeType, eqRoxieCluster))
  549. {
  550. BoolHash uniqueRoxieProcesses;
  551. getProcesses(constEnv, pClusterProcess, process, eqRoxieServerProcess, dirStr.str(), machineInfoData, true, uniqueProcesses, &uniqueRoxieProcesses);
  552. }
  553. }
  554. void Cws_machineEx::getThorProcesses(IConstEnvironment* constEnv, IPropertyTree* cluster, const char* processName,
  555. const char* processType, const char* directory, CGetMachineInfoData& machineInfoData, BoolHash& uniqueProcesses)
  556. {
  557. if (!constEnv || !cluster)
  558. return;
  559. StringBuffer groupName;
  560. if (strieq(processType, eqThorSlaveProcess))
  561. getClusterGroupName(*cluster, groupName);
  562. else if (strieq(processType, eqThorSpareProcess))
  563. getClusterSpareGroupName(*cluster, groupName);
  564. if (groupName.length() < 1)
  565. return;
  566. Owned<IGroup> nodeGroup = queryNamedGroupStore().lookup(groupName.str());
  567. if (!nodeGroup || (nodeGroup->ordinality() == 0))
  568. return;
  569. unsigned processNumber = 0;
  570. Owned<INodeIterator> gi = nodeGroup->getIterator();
  571. ForEach(*gi)
  572. {
  573. StringBuffer addressRead;
  574. gi->query().endpoint().getIpText(addressRead);
  575. if (addressRead.length() == 0)
  576. {
  577. WARNLOG("Network address not found for a node in node group %s", groupName.str());
  578. continue;
  579. }
  580. processNumber++;
  581. StringBuffer netAddress;
  582. const char* ip = addressRead.str();
  583. if (!streq(ip, "."))
  584. {
  585. netAddress.append(ip);
  586. }
  587. else
  588. {
  589. IpAddress ipaddr = queryHostIP();
  590. ipaddr.getIpText(netAddress);
  591. }
  592. if (netAddress.length() == 0)
  593. {
  594. WARNLOG("Network address not found for a node in node group %s", groupName.str());
  595. continue;
  596. }
  597. Owned<IConstMachineInfo> pMachineInfo = constEnv->getMachineByAddress(addressRead.str());
  598. if (!pMachineInfo.get())
  599. {
  600. WARNLOG("Machine not found at network address %s", addressRead.str());
  601. continue;
  602. }
  603. setProcessRequest(machineInfoData, uniqueProcesses, netAddress.str(), addressRead.str(), processType, processName, directory, processNumber);
  604. }
  605. return;
  606. }
  607. void Cws_machineEx::getProcesses(IConstEnvironment* constEnv, IPropertyTree* environment, const char* processName,
  608. const char* processType, const char* directory, CGetMachineInfoData& machineInfoData,
  609. bool isThorOrRoxieProcess, BoolHash& uniqueProcesses, BoolHash* uniqueRoxieProcesses)
  610. {
  611. Owned<IPropertyTreeIterator> processes= environment->getElements(processType);
  612. ForEach(*processes)
  613. {
  614. StringArray processInstances, directories;
  615. IPropertyTree &process = processes->query();
  616. //Thor master and roxie server has been checked before this call.
  617. if (!isThorOrRoxieProcess)
  618. {
  619. const char* name = process.queryProp("@name");
  620. if (!name || !*name || !streq(name, processName))
  621. continue;
  622. }
  623. const char* computerName = process.queryProp("@computer");
  624. if (computerName && *computerName)
  625. appendProcessInstance(computerName, directory, NULL, processInstances, directories);
  626. else
  627. {
  628. Owned<IPropertyTreeIterator> instances= process.getElements("Instance");
  629. ForEach(*instances)
  630. {
  631. IPropertyTree &instance = instances->query();
  632. appendProcessInstance(instance.queryProp("@computer"), directory, instance.queryProp("@directory"), processInstances, directories);
  633. }
  634. }
  635. if (processInstances.length() < 1)
  636. continue;
  637. for (unsigned i = 0; i < processInstances.length(); i++)
  638. {
  639. const char* name0 = processInstances.item(i);
  640. const char* directory0 = directories.item(i);
  641. if (uniqueRoxieProcesses)//to avoid duplicate entries for roxie (one machine has only one roxie process).
  642. {
  643. if (uniqueRoxieProcesses->getValue(name0))
  644. continue;
  645. uniqueRoxieProcesses->setValue(name0, true);
  646. }
  647. Owned<IConstMachineInfo> pMachineInfo = constEnv->getMachine(name0);
  648. if (!pMachineInfo.get())
  649. {
  650. WARNLOG("Machine %s not found in environment setting", name0);
  651. continue;
  652. }
  653. SCMStringBuffer ep;
  654. pMachineInfo->getNetAddress(ep);
  655. const char* ip = ep.str();
  656. if (!ip)
  657. {
  658. WARNLOG("Network address not found for machine %s", name0);
  659. continue;
  660. }
  661. StringBuffer netAddress, configNetAddress = ip;
  662. if (!streq(ip, "."))
  663. {
  664. netAddress.append(ip);
  665. }
  666. else
  667. {
  668. IpAddress ipaddr = queryHostIP();
  669. ipaddr.getIpText(netAddress);
  670. }
  671. setProcessRequest(machineInfoData, uniqueProcesses, netAddress.str(), configNetAddress.str(), processType, processName, directory0);
  672. }
  673. }
  674. return;
  675. }
  676. void Cws_machineEx::setupLegacyFilters()
  677. {
  678. unsigned idx = 0;
  679. while (legacyFilterStrings[idx])
  680. {
  681. m_legacyFilters.setValue(legacyFilterStrings[idx], true);
  682. idx++;
  683. }
  684. return;
  685. }
  686. bool Cws_machineEx::isLegacyFilter(const char* processType, const char* dependency)
  687. {
  688. if (!processType || !*processType || !dependency || !*dependency)
  689. return false;
  690. StringBuffer filterString;
  691. filterString.appendf("%s:%s", processType, dependency);
  692. if (m_legacyFilters.getValue(filterString.str()))
  693. return true;
  694. return false;
  695. }
  696. //////////////////////////////////////////////////////////////////
  697. // Get Machine Infomation based on Machine Infomation request //
  698. //////////////////////////////////////////////////////////////////
  699. void Cws_machineEx::getMachineInfo(IEspContext& context, CGetMachineInfoData& machineInfoData)
  700. {
  701. UnsignedArray threadHandles;
  702. CIArrayOf<CMachineData>& machines = machineInfoData.getMachineData();
  703. ForEachItemIn(idx, machines)
  704. {
  705. Owned<CMachineInfoThreadParam> pThreadReq = new CMachineInfoThreadParam( this, context, machineInfoData.getOptions(),
  706. machines.item(idx), machineInfoData.getMachineInfoTable(), machineInfoData.getMachineInfoColumns());
  707. PooledThreadHandle handle = m_threadPool->start( pThreadReq.getClear() );
  708. threadHandles.append(handle);
  709. }
  710. //block for worker theads to finish, if necessary and then collect results
  711. PooledThreadHandle* pThreadHandle = threadHandles.getArray();
  712. unsigned i=threadHandles.ordinality();
  713. while (i--)
  714. {
  715. m_threadPool->join(*pThreadHandle);
  716. pThreadHandle++;
  717. }
  718. }
  719. // the following method is invoked on worker threads of CMachineInfoThreadParam
  720. void Cws_machineEx::doGetMachineInfo(IEspContext& context, CMachineInfoThreadParam* pParam)
  721. {
  722. #ifdef DETECT_WS_MC_MEM_LEAKS
  723. static bool firstTime = true;
  724. if (firstTime)
  725. {
  726. firstTime = false;
  727. unsigned t = setAllocHook(true);
  728. }
  729. #endif //DETECT_WS_MC_MEM_LEAKS
  730. int error = 0;
  731. StringBuffer preflightCommand, response;
  732. buildPreflightCommand(context, pParam, preflightCommand);
  733. if (preflightCommand.length() < 1)
  734. {
  735. response.append("Failed in creating Machine Information command.\n");
  736. error = -1;
  737. }
  738. else
  739. {
  740. error = runCommand(context, pParam->m_machineData.getNetworkAddress(), pParam->m_machineData.getNetworkAddressInEnvSetting(), pParam->m_machineData.getOS(), preflightCommand.str(), pParam->m_options.getUserName(), pParam->m_options.getPassword(), response);
  741. if ((error == 0) && (response.length() > 0))
  742. readPreflightResponse(context, pParam, response.str(), error);
  743. }
  744. //Set IArrayOf<IEspMachineInfoEx> based on Preflight Response
  745. setMachineInfo(context, pParam, response.str(), error);
  746. #ifdef DETECT_WS_MC_MEM_LEAKS
  747. DBGLOG("Allocated=%d", setAllocHook(false));
  748. #endif //DETECT_WS_MC_MEM_LEAKS
  749. }
  750. void Cws_machineEx::buildPreflightCommand(IEspContext& context, CMachineInfoThreadParam* pParam, StringBuffer& preflightCommand)
  751. {
  752. preflightCommand.clear().appendf("/%s/sbin/%s -p=%s", environmentConfData.m_executionPath.str(),
  753. m_machineInfoFile.str(), environmentConfData.m_pidPath.str());
  754. if (preflightCommand.charAt(preflightCommand.length() - 1) == pParam->m_machineData.getPathSep())
  755. preflightCommand.remove(preflightCommand.length()-1, 1);
  756. bool checkDependency = false;
  757. CIArrayOf<CProcessData>& processes = pParam->m_machineData.getProcesses();
  758. ForEachItemIn(idx, processes)
  759. {
  760. CProcessData& process = processes.item(idx);
  761. if (!process.getName() || !*process.getName())
  762. continue;
  763. if (idx < 1)
  764. preflightCommand.appendf(" -n=%s", process.getName());
  765. else
  766. preflightCommand.appendf(",%s", process.getName());
  767. if (process.getType() && streq(process.getType(), eqThorMasterProcess))
  768. preflightCommand.append("_master");
  769. else if (process.getType() && streq(process.getType(), eqThorSlaveProcess))
  770. preflightCommand.appendf("_slave_%d", process.getProcessNumber());
  771. if (!process.getDependencies().empty())
  772. checkDependency = true;
  773. }
  774. if (checkDependency || !pParam->m_options.getApplyProcessFilter())
  775. preflightCommand.append(" -d=ALL");
  776. if (pParam->m_options.getGetStorageInfo() && !pParam->m_options.getLocalFileSystemsOnly())
  777. preflightCommand.append(" -m=YES");
  778. }
  779. int Cws_machineEx::runCommand(IEspContext& context, const char* sAddress, const char* sConfigAddress, EnvMachineOS os,
  780. const char* sCommand, const char* sUserId, const char* sPassword, StringBuffer& response)
  781. {
  782. int exitCode = -1;
  783. try
  784. {
  785. StringBuffer command(sCommand);
  786. StringBuffer cmdLine;
  787. #ifdef _WIN32
  788. //Keep this Windows block for now
  789. #ifndef CHECK_LINUX_COMMAND
  790. #define popen _popen
  791. #define pclose _pclose
  792. StringBuffer userId;
  793. StringBuffer password;
  794. bool bLinux;
  795. if (sConfigAddress && *sConfigAddress)
  796. getAccountAndPlatformInfo(sConfigAddress, userId, password, bLinux);
  797. else
  798. getAccountAndPlatformInfo(sAddress, userId, password, bLinux);
  799. if (!sUserId || !*sUserId || !sPassword ||!*sPassword)
  800. {
  801. //BUG: 9825 - remote execution on linux needs to use individual accounts
  802. //use userid/password in ESP context for remote execution...
  803. if (bLinux)
  804. {
  805. userId.clear();
  806. password.clear();
  807. context.getUserID(userId);
  808. context.getPassword(password);
  809. }
  810. }
  811. else
  812. {
  813. userId.clear().append(sUserId);
  814. password.clear().append(sPassword);
  815. }
  816. // Use psexec as default remote control program
  817. if (bLinux)
  818. {
  819. if (!checkFileExists(".\\plink.exe"))
  820. throw MakeStringException(ECLWATCH_PLINK_NOT_INSTALLED, "Invalid ESP installation: missing plink.exe to execute the remote program!");
  821. command.replace('\\', '/');//replace all '\\' by '/'
  822. /*
  823. note that if we use plink (cmd line ssh client) for the first time with a computer,
  824. it generates the following message:
  825. The server's host key is not cached in the registry. You have no guarantee that the
  826. server is the computer you think it is. The server's key fingerprint is:
  827. 1024 aa:bb:cc:dd:ee:ff:gg:hh:ii:jj:kk:ll:mm:nn:oo:pp
  828. If you trust this host, enter "y" to add the key to
  829. PuTTY's cache and carry on connecting. If you want to carry on connecting just once,
  830. without adding the key to the cache, enter "n".If you do not trust this host, press
  831. Return to abandon the connection.
  832. To get around this, we pipe "n" to plink without using its -batch parameter. We need
  833. help from cmd.exe to do this though...
  834. */
  835. cmdLine.appendf("cmd /c \"echo y | .\\plink.exe -ssh -l %s -pw %s %s sudo bash -c '%s' 2>&1\"", environmentConfData.m_user.str(), password.str(), sAddress, command.str());
  836. }
  837. else
  838. {
  839. if (!checkFileExists(".\\psexec.exe"))
  840. throw MakeStringException(ECLWATCH_PSEXEC_NOT_INSTALLED, "Invalid ESP installation: missing psexec.exe to execute the remote program!");
  841. cmdLine.appendf(".\\psexec \\\\%s -u %s -p %s %s cmd /c %s 2>&1", sAddress, userId.str(), password.str(), "", command.str());
  842. }
  843. #else
  844. if (os == MachineOsLinux)
  845. {
  846. command.replace('\\', '/');//replace all '\\' by '/'
  847. cmdLine.appendf("ssh -o StrictHostKeyChecking=no -o ConnectTimeout=%d %s '%s' 2>&1", m_SSHConnectTimeoutSeconds, sAddress, command.str());
  848. }
  849. else
  850. {
  851. response.append("Remote execution from Linux to Windows is not supported!");
  852. exitCode = 1;
  853. }
  854. #endif
  855. #else
  856. if (os == MachineOsLinux)
  857. {
  858. command.replace('\\', '/');//replace all '\\' by '/'
  859. cmdLine.appendf("ssh -o StrictHostKeyChecking=no -o ConnectTimeout=%d %s '%s' 2>&1", m_SSHConnectTimeoutSeconds, sAddress, command.str());
  860. }
  861. else
  862. {
  863. response.append("Remote execution from Linux to Windows is not supported!");
  864. exitCode = 1;
  865. }
  866. #endif
  867. if (cmdLine.length() < 1)
  868. return exitCode;
  869. exitCode = invokeProgram(cmdLine, response);
  870. int len = response.length();
  871. if (len > 0 && response.charAt(--len) == '\n') //remove \n at the end
  872. response.setLength(len);
  873. if (response.length() > 0)
  874. response.insert(0, "Response: ");
  875. else
  876. response.append("No response received.\n");
  877. if (exitCode < 0)
  878. response.insert(0, "Failed in executing Machine Information command.\n");
  879. else
  880. response.insert(0, "Machine Information command(s) has been executed.\n");
  881. }
  882. catch(IException* e)
  883. {
  884. StringBuffer buf;
  885. e->errorMessage(buf);
  886. response.append(buf.str());
  887. exitCode = e->errorCode();
  888. e->Release();
  889. }
  890. #ifndef NO_CATCHALL
  891. catch(...)
  892. {
  893. response.append("An unknown exception occurred!");
  894. exitCode = -1;
  895. }
  896. #endif
  897. return exitCode;
  898. }
  899. int Cws_machineEx::invokeProgram(const char *command_line, StringBuffer& response)
  900. {
  901. char buffer[128];
  902. FILE *fp;
  903. // Run the command so that it writes its output to a pipe. Open this
  904. // pipe with read text attribute so that we can read it
  905. // like a text file.
  906. if (getEspLogLevel()>LogNormal)
  907. {
  908. DBGLOG("command_line=<%s>", command_line);
  909. }
  910. #ifndef NO_CONNECTION_DEBUG
  911. if( (fp = popen( command_line, "r" )) == NULL )
  912. return -1;
  913. #else
  914. if( (fp = fopen( "c:\\temp\\preflight_result.txt", "r" )) == NULL )
  915. return -1;
  916. #endif
  917. // Read pipe until end of file. End of file indicates that
  918. //the stream closed its standard out (probably meaning it
  919. //terminated).
  920. while ( !feof(fp) )
  921. if ( fgets( buffer, 128, fp) )
  922. response.append( buffer );
  923. if (getEspLogLevel()>LogNormal)
  924. {
  925. DBGLOG("response=<%s>", response.str());
  926. }
  927. // Close pipe and print return value of CHKDSK.
  928. #ifndef NO_CONNECTION_DEBUG
  929. return pclose( fp );
  930. #else
  931. return fclose( fp );
  932. #endif
  933. }
  934. void Cws_machineEx::readPreflightResponse(IEspContext& context, CMachineInfoThreadParam* pParam, const char* response, int error)
  935. {
  936. if (!response || !*response)
  937. return;
  938. StringBuffer computerUpTime;
  939. readALineFromResult(response, "ComputerUpTime:", computerUpTime, true);
  940. if (computerUpTime.length() < 1)
  941. computerUpTime.append("-");
  942. else
  943. {
  944. const char* pStr = strchr(computerUpTime.str(), ' ');
  945. if (pStr)
  946. {
  947. pStr++;
  948. pStr = strchr(pStr, ' ');
  949. if (pStr)
  950. {
  951. pStr++;
  952. if (pStr)
  953. pParam->m_machineData.setComputerUpTime(pStr);
  954. }
  955. }
  956. if (!pStr)
  957. pParam->m_machineData.setComputerUpTime(computerUpTime);
  958. }
  959. if (pParam->m_options.getGetProcessorInfo())
  960. {
  961. StringBuffer CPUIdle;
  962. readALineFromResult(response, "CPU-Idle:", CPUIdle, true);
  963. if (CPUIdle.length() < 1)
  964. pParam->m_machineData.setCPULoad(0);
  965. else
  966. {
  967. if (CPUIdle.charAt(CPUIdle.length() - 1) == '%')
  968. CPUIdle.setLength(CPUIdle.length() - 1);
  969. pParam->m_machineData.setCPULoad(100-atoi(CPUIdle.str()));
  970. }
  971. }
  972. if (pParam->m_options.getGetStorageInfo())
  973. readStorageData(response, pParam);
  974. if (pParam->m_options.getGetSoftwareInfo())
  975. readProcessData(response, pParam);
  976. }
  977. void Cws_machineEx::readALineFromResult(const char *result, const char *start, StringBuffer& value, bool trim)
  978. {
  979. if (!result || !*result)
  980. return;
  981. const char* pStr = strstr(result, start);
  982. if (!pStr)
  983. return;
  984. pStr += strlen(start);
  985. if (!pStr)
  986. return;
  987. const char* pStr1 = strchr(pStr, 0x0a);
  988. if (pStr1)
  989. value.append(pStr, 0, pStr1 - pStr);
  990. else
  991. value.append(pStr);
  992. if (trim)
  993. value.trim();
  994. }
  995. void Cws_machineEx::readStorageData(const char* response, CMachineInfoThreadParam* pParam)
  996. {
  997. if (!response || !*response)
  998. return;
  999. const char* pStr = strstr(response, "---SpaceUsedAndFree---");
  1000. if (!pStr)
  1001. DBGLOG("Storage information not found on %s", pParam->m_machineData.getNetworkAddress());
  1002. bool isTitleLine = true;
  1003. CIArrayOf<CStorageData>& storage = pParam->m_machineData.getStorage();
  1004. while (pStr)
  1005. {
  1006. StringBuffer buf;
  1007. const char* pStr1 = strchr(pStr, 0x0a);
  1008. if (pStr1)
  1009. {
  1010. buf.append(pStr, 0, pStr1 - pStr);
  1011. pStr = pStr1+1;
  1012. }
  1013. else
  1014. {
  1015. buf.append(pStr);
  1016. pStr = NULL;
  1017. }
  1018. if (isTitleLine)
  1019. {
  1020. isTitleLine = false;
  1021. continue;
  1022. }
  1023. if (buf.length() > 0)
  1024. {
  1025. StringBuffer diskSpaceTitle;
  1026. int diskSpacePercentAvail = 0;
  1027. __int64 diskSpaceAvailable = 0, diskSpaceTotal = 0;
  1028. if (!readStorageSpace(buf.str(), diskSpaceTitle, diskSpaceAvailable, diskSpaceTotal, diskSpacePercentAvail))
  1029. DBGLOG("Invalid storage information on %s: %s", pParam->m_machineData.getNetworkAddress(), buf.str());
  1030. else if ((diskSpaceTitle.length() > 0) && !excludePartition(diskSpaceTitle.str()))
  1031. {
  1032. Owned<CStorageData> diskData = new CStorageData(diskSpaceTitle, diskSpaceAvailable, diskSpaceTotal, diskSpacePercentAvail);
  1033. storage.append(*diskData.getClear());
  1034. }
  1035. }
  1036. if (!pStr || (strnicmp(pStr, "---ProcessList1---", 18)==0))
  1037. break;
  1038. }
  1039. }
  1040. bool Cws_machineEx::readStorageSpace(const char *line, StringBuffer& title, __int64& free, __int64& total, int& percentAvail)
  1041. {
  1042. if (!line || !*line)
  1043. return false;
  1044. StringBuffer freeStr, usedStr;
  1045. const char* pStr = line;
  1046. const char* pStr1 = strchr(pStr, ':');
  1047. if (!pStr1)
  1048. return false;
  1049. title.clear().append(pStr, 0, pStr1 - pStr);
  1050. pStr = pStr1 + 2;
  1051. pStr1 = (char*) strchr(pStr, ' ');
  1052. if (!pStr1)
  1053. return false;
  1054. usedStr.append(pStr, 0, pStr1 - pStr);
  1055. pStr = pStr1 + 1;
  1056. if (!pStr)
  1057. return false;
  1058. freeStr.append(pStr);
  1059. __int64 factor1 = 1;
  1060. if (freeStr.length() > 9)
  1061. {
  1062. freeStr.setLength(freeStr.length()-6);
  1063. factor1 = 1000000;
  1064. }
  1065. free = atol(freeStr.str())*factor1;
  1066. __int64 factor2 = 1;
  1067. if (usedStr.length() > 9)
  1068. {
  1069. usedStr.setLength(usedStr.length()-6);
  1070. factor2 = 1000000;
  1071. }
  1072. __int64 used = atol(usedStr.str())*factor2;
  1073. total = free + used;
  1074. if (total > 0)
  1075. percentAvail = (int) ((free*100)/total);
  1076. free = (__int64) free /1000; //MByte
  1077. total = (__int64) total /1000; //MByte
  1078. return true;
  1079. }
  1080. void Cws_machineEx::readProcessData(const char* response, CMachineInfoThreadParam* pParam)
  1081. {
  1082. if (!response || !*response)
  1083. return;
  1084. CIArrayOf<CProcessData>& processes = pParam->m_machineData.getProcesses();
  1085. ForEachItemIn(idx, processes)
  1086. {
  1087. CProcessData& process = processes.item(idx);
  1088. if (!process.getName() || !*process.getName())
  1089. continue;
  1090. StringBuffer processData, processPath;
  1091. if (environmentConfData.m_pidPath.charAt(environmentConfData.m_pidPath.length() - 1) != pParam->m_machineData.getPathSep())
  1092. processPath.appendf("%s%c%s", environmentConfData.m_pidPath.str(), pParam->m_machineData.getPathSep(), process.getName());
  1093. else
  1094. processPath.appendf("%s%s", environmentConfData.m_pidPath.str(), process.getName());
  1095. if (process.getType() && streq(process.getType(), eqThorMasterProcess))
  1096. processPath.append("_master");
  1097. else if (process.getType() && streq(process.getType(), eqThorSlaveProcess))
  1098. processPath.appendf("_slave_%d", process.getProcessNumber());
  1099. processPath.append(":");
  1100. readALineFromResult(response, processPath.str(), processData, true);
  1101. if (processData.length() < 1)
  1102. {
  1103. DBGLOG("Information for process %s not found", processPath.str());
  1104. continue;
  1105. }
  1106. const char* pStr = strchr(processData.str(), ' ');
  1107. if (!pStr)
  1108. {
  1109. DBGLOG("incorrect data for process %s: %s", processPath.str(), processData.str());
  1110. continue;
  1111. }
  1112. unsigned len = pStr - processData.str();
  1113. StringBuffer pid, upTime;
  1114. pid.append(processData.str(), 0, len);
  1115. len++;
  1116. upTime.append(processData.str(), len, processData.length() - len);
  1117. upTime.replaceString("-", " day(s) ");
  1118. process.setPID(pid.str());
  1119. process.setUpTime(upTime.str());
  1120. }
  1121. readRunningProcesses(response, pParam);
  1122. }
  1123. void Cws_machineEx::readRunningProcesses(const char* response, CMachineInfoThreadParam* pParam)
  1124. {
  1125. if (!response || !*response)
  1126. return;
  1127. const char* pStr = strstr(response, "---ProcessList2---");
  1128. if (!pStr)
  1129. DBGLOG("Running process not found on %s", pParam->m_machineData.getNetworkAddress());
  1130. IArrayOf<IEspProcessInfo>& runningProcesses = pParam->m_machineData.getRunningProcesses();
  1131. while (pStr)
  1132. {
  1133. //read a line
  1134. StringBuffer lineStr;
  1135. const char* pStr1 = strchr(pStr, 0x0a);
  1136. if (!pStr1)
  1137. {
  1138. lineStr.append(pStr);
  1139. pStr = NULL;
  1140. }
  1141. else
  1142. {
  1143. lineStr.append(pStr, 0, pStr1 - pStr);
  1144. pStr = pStr1+1;
  1145. }
  1146. if (lineStr.length() < 1)
  1147. continue;
  1148. StringBuffer pidStr, desc, param;
  1149. pStr1 = lineStr.str();
  1150. const char* pStr2 = strchr(pStr1, ' ');
  1151. if (!pStr2)
  1152. continue;
  1153. pidStr.append(pStr1, 0, pStr2 - pStr1);
  1154. param.append(pStr2+1);
  1155. if (param.length() < 1)
  1156. continue;
  1157. if (streq(param.str(), "ps"))
  1158. continue;
  1159. bool isNumber = true;
  1160. for (unsigned i = 0; i < pidStr.length(); i++)
  1161. {
  1162. if (!isdigit(pidStr.charAt(i)))
  1163. {
  1164. isNumber = false;
  1165. break;
  1166. }
  1167. }
  1168. if (!isNumber)
  1169. continue;
  1170. int pid = atoi(pidStr.str());
  1171. desc = param;
  1172. if ((desc.charAt(0) == '.') && (param.charAt(1) == '/'))
  1173. desc.remove(0, 2);
  1174. if (desc.charAt(desc.length() - 1) == '/')
  1175. desc.remove(desc.length() - 1, 1);
  1176. if (desc.charAt(0) == '[')
  1177. {
  1178. desc.remove(0, 1);
  1179. if (desc.charAt(desc.length() - 1) == ']')
  1180. desc.remove(desc.length() - 1, 1);
  1181. }
  1182. Owned<IEspProcessInfo> info = createProcessInfo("","");
  1183. info->setPID(pid);
  1184. info->setParameter(param.str());
  1185. info->setDescription(desc.str());
  1186. runningProcesses.append(*info.getClear());
  1187. }
  1188. }
  1189. void Cws_machineEx::setMachineInfo(IEspContext& context, CMachineInfoThreadParam* pParam, const char* response, int error)
  1190. {
  1191. //Read additionalProcessFilters which will be used in setProcessInfo()/setProcessComponent()
  1192. set<string>& additionalProcesses = pParam->m_machineData.getAdditinalProcessFilters();
  1193. StringArray& additionalProcessFilters = pParam->m_options.getAdditionalProcessFilters();
  1194. if (pParam->m_options.getApplyProcessFilter() && !additionalProcessFilters.empty())
  1195. {
  1196. int len = additionalProcessFilters.length();
  1197. for (int i=0; i<len; i++)
  1198. {
  1199. StringBuffer processName = additionalProcessFilters.item(i);
  1200. processName.toLowerCase().replaceString(".exe", "");
  1201. if (processName.length() > 0)
  1202. additionalProcesses.insert(processName.str());
  1203. }
  1204. }
  1205. CIArrayOf<CProcessData>& processes = pParam->m_machineData.getProcesses();
  1206. ForEachItemIn(idx, processes)
  1207. {
  1208. CProcessData& process = processes.item(idx);
  1209. Owned<IEspMachineInfoEx> pMachineInfo = static_cast<IEspMachineInfoEx*>(new CMachineInfoEx(""));
  1210. Owned<IEspMachineInfoEx> pMachineInfo1;
  1211. if (pParam->m_options.getGetSoftwareInfo() && process.getType() && strieq(process.getType(), eqEclAgent))
  1212. pMachineInfo1.setown(static_cast<IEspMachineInfoEx*>(new CMachineInfoEx("")));
  1213. setProcessInfo(context, pParam, response, error, process, idx<1, pMachineInfo, pMachineInfo1);
  1214. synchronized block(mutex_machine_info_table);
  1215. pParam->m_machineInfoTable.append(*pMachineInfo.getLink());
  1216. if (pMachineInfo1)
  1217. pParam->m_machineInfoTable.append(*pMachineInfo1.getLink());
  1218. }
  1219. }
  1220. void Cws_machineEx::setProcessInfo(IEspContext& context, CMachineInfoThreadParam* pParam, const char* response,
  1221. int error, CProcessData& process, bool firstProcess, IEspMachineInfoEx* pMachineInfo, IEspMachineInfoEx* pMachineInfo1)
  1222. {
  1223. double version = context.getClientVersion();
  1224. pMachineInfo->setAddress(pParam->m_machineData.getNetworkAddress());
  1225. pMachineInfo->setConfigAddress(pParam->m_machineData.getNetworkAddressInEnvSetting());
  1226. pMachineInfo->setOS(pParam->m_machineData.getOS());
  1227. if (process.getName() && *process.getName())
  1228. pMachineInfo->setComponentName(process.getName());
  1229. if (process.getPath() && *process.getPath())
  1230. pMachineInfo->setComponentPath(process.getPath());
  1231. //set DisplayType
  1232. if (process.getType() && *process.getType())
  1233. {
  1234. pMachineInfo->setProcessType(process.getType());
  1235. StringBuffer displayName;
  1236. getProcessDisplayName(process.getType(), displayName);
  1237. pMachineInfo->setDisplayType(displayName.str());
  1238. }
  1239. else if (process.getName() && *process.getName())
  1240. {
  1241. pMachineInfo->setDisplayType(process.getName());
  1242. }
  1243. bool isEclAgentProcess = process.getType() && strieq(process.getType(), eqEclAgent);
  1244. if (pMachineInfo1)
  1245. {
  1246. pMachineInfo1->setAddress(pParam->m_machineData.getNetworkAddress());
  1247. pMachineInfo1->setConfigAddress(pParam->m_machineData.getNetworkAddressInEnvSetting());
  1248. pMachineInfo1->setOS(pParam->m_machineData.getOS());
  1249. if (process.getName() && *process.getName())
  1250. pMachineInfo1->setComponentName(process.getName());
  1251. if (process.getPath() && *process.getPath())
  1252. pMachineInfo1->setComponentPath(process.getPath());
  1253. if (isEclAgentProcess)
  1254. {
  1255. pMachineInfo1->setProcessType(eqAgentExec);
  1256. pMachineInfo1->setDisplayType("Agent Exec");
  1257. }
  1258. //Right now, only EclAgent has pMachineInfo1. May add more if needed
  1259. }
  1260. if ((version > 1.09) && process.getType() && strieq(process.getType(), eqThorSlaveProcess))
  1261. {
  1262. pMachineInfo->setProcessNumber(process.getProcessNumber());
  1263. }
  1264. if (error != 0 || !response || !*response)
  1265. {
  1266. StringBuffer description;
  1267. if (!response || !*response)
  1268. description.append("Failed in getting Machine Information");
  1269. else
  1270. description = response;
  1271. pMachineInfo->setDescription(description.str());
  1272. if (pMachineInfo1)
  1273. pMachineInfo1->setDescription(description.str());
  1274. }
  1275. else
  1276. {
  1277. //Now, add more columns based on 'response'
  1278. pMachineInfo->setUpTime(pParam->m_machineData.getComputerUpTime());
  1279. if (pMachineInfo1)
  1280. pMachineInfo1->setUpTime(pParam->m_machineData.getComputerUpTime());
  1281. pParam->addColumn("Up Time");
  1282. if (pParam->m_options.getGetStorageInfo())
  1283. {
  1284. IArrayOf<IEspStorageInfo> storageArray;
  1285. CIArrayOf<CStorageData>& storage = pParam->m_machineData.getStorage();
  1286. ForEachItemIn(idx, storage)
  1287. {
  1288. CStorageData& diskData = storage.item(idx);
  1289. Owned<IEspStorageInfo> info = static_cast<IEspStorageInfo*>(new CStorageInfo(""));
  1290. info->setDescription(diskData.getDiskSpaceTitle());
  1291. info->setTotal(diskData.getDiskSpaceTotal());
  1292. info->setAvailable(diskData.getDiskSpaceAvailable());
  1293. info->setPercentAvail(diskData.getDiskSpacePercentAvail());
  1294. storageArray.append(*info.getLink());
  1295. pParam->addColumn(diskData.getDiskSpaceTitle());
  1296. }
  1297. pMachineInfo->setStorage(storageArray);
  1298. if (pMachineInfo1)
  1299. pMachineInfo1->setStorage(storageArray);
  1300. storageArray.kill();
  1301. }
  1302. if (pParam->m_options.getGetProcessorInfo())
  1303. {
  1304. IArrayOf<IEspProcessorInfo> processorArray;
  1305. Owned<IEspProcessorInfo> info = static_cast<IEspProcessorInfo*>(new CProcessorInfo(""));
  1306. info->setLoad(pParam->m_machineData.getCPULoad());
  1307. processorArray.append(*info.getLink());
  1308. pMachineInfo->setProcessors(processorArray);
  1309. if (pMachineInfo1)
  1310. pMachineInfo1->setProcessors(processorArray);
  1311. processorArray.kill();
  1312. pParam->addColumn("CPU Load");
  1313. }
  1314. if (pParam->m_options.getGetSoftwareInfo())
  1315. {
  1316. IArrayOf<IEspSWRunInfo> processArray;
  1317. IEspComponentInfo* pComponentInfo = &pMachineInfo->updateComponentInfo();
  1318. setProcessComponent(context, pParam, process, firstProcess, processArray, pComponentInfo);
  1319. if (processArray.ordinality())
  1320. {
  1321. //Set running processes if ApplyProcessFilter is set to false
  1322. //Set processes not running if ApplyProcessFilter is set to true
  1323. pMachineInfo->setRunning(processArray);
  1324. if (pMachineInfo1)
  1325. pMachineInfo1->setRunning(processArray);
  1326. }
  1327. if (pMachineInfo1)
  1328. {
  1329. IEspComponentInfo* pComponentInfo1 = &pMachineInfo1->updateComponentInfo();
  1330. pComponentInfo1->setCondition(pComponentInfo->getCondition());
  1331. pComponentInfo1->setState(pComponentInfo->getState());
  1332. pComponentInfo1->setUpTime(pComponentInfo->getUpTime());
  1333. if (isEclAgentProcess)
  1334. pComponentInfo->setUpTime("-"); //for ECL Agent
  1335. }
  1336. pParam->addColumn("Processes");
  1337. pParam->addColumn("Condition");
  1338. pParam->addColumn("State");
  1339. pParam->addColumn("UpTime");
  1340. }
  1341. }
  1342. }
  1343. void Cws_machineEx::setProcessComponent(IEspContext& context, CMachineInfoThreadParam* pParam, CProcessData& process,
  1344. bool firstProcess, IArrayOf<IEspSWRunInfo>& processArray, IEspComponentInfo* pComponentInfo)
  1345. {
  1346. if (pParam->m_options.getApplyProcessFilter() && (!process.getPID() || !*process.getPID()))
  1347. {
  1348. Owned<IEspSWRunInfo> info = static_cast<IEspSWRunInfo*>(new CSWRunInfo(""));
  1349. info->setName(process.getName());
  1350. info->setInstances(0);
  1351. processArray.append( *info.getLink() );
  1352. }
  1353. set<string>& additionalProcesses = pParam->m_machineData.getAdditinalProcessFilters();
  1354. map<string, Linked<IEspSWRunInfo> > runningProcessMap; //save only one description of each process
  1355. set<string>& dependencies = process.getDependencies();
  1356. IArrayOf<IEspProcessInfo>& runningProcesses = pParam->m_machineData.getRunningProcesses();
  1357. if (runningProcesses.length() > 0)
  1358. {
  1359. if (!pParam->m_options.getApplyProcessFilter()) //need to display all of the running processes
  1360. enumerateRunningProcesses( pParam, process, &runningProcessMap, firstProcess);
  1361. else if (!dependencies.empty() || !additionalProcesses.empty())
  1362. enumerateRunningProcesses(pParam, process, NULL, firstProcess);
  1363. }
  1364. map<string, Linked<IEspSWRunInfo> >::const_iterator it = runningProcessMap.begin();
  1365. map<string, Linked<IEspSWRunInfo> >::const_iterator iEnd = runningProcessMap.end();
  1366. for (; it != iEnd; it++) //add in sorted order simply by traversing the map
  1367. {
  1368. Linked<IEspSWRunInfo> info( (*it).second );
  1369. processArray.append( *info.getLink() );
  1370. }
  1371. bool dependencyDown = false;
  1372. if (!dependencies.empty())
  1373. {
  1374. dependencyDown = true;
  1375. if (pParam->m_options.getApplyProcessFilter())
  1376. {
  1377. set<string>::const_iterator it = dependencies.begin();
  1378. set<string>::const_iterator iEnd = dependencies.end();
  1379. for (; it != iEnd; it++)
  1380. {
  1381. Owned<IEspSWRunInfo> info = static_cast<IEspSWRunInfo*>(new CSWRunInfo(""));
  1382. info->setName(it->c_str());
  1383. info->setInstances(0);
  1384. processArray.append( *info.getLink() );
  1385. }
  1386. }
  1387. }
  1388. if (pParam->m_options.getApplyProcessFilter() && !additionalProcesses.empty())
  1389. {
  1390. set<string>::const_iterator it = additionalProcesses.begin();
  1391. set<string>::const_iterator iEnd = additionalProcesses.end();
  1392. for (; it != iEnd; it++)
  1393. {
  1394. Owned<IEspSWRunInfo> info = static_cast<IEspSWRunInfo*>(new CSWRunInfo(""));
  1395. info->setName(it->c_str());
  1396. info->setInstances(0);
  1397. processArray.append( *info.getLink() );
  1398. }
  1399. }
  1400. if (!dependencyDown && process.getPID() && *process.getPID())
  1401. {
  1402. //conditions: unknown, normal, warning, minor, major, critical, fatal
  1403. pComponentInfo->setCondition( 1 );
  1404. pComponentInfo->setState(5);
  1405. if (process.getUpTime() && *process.getUpTime())
  1406. pComponentInfo->setUpTime( process.getUpTime() );
  1407. }
  1408. else
  1409. {
  1410. pComponentInfo->setCondition(2); //Warnning
  1411. pComponentInfo->setState(0);
  1412. }
  1413. }
  1414. //Erase this process from dependencies and, if firstProcess, additionalProcesses;
  1415. //If processMap is not NULL, add this process to processMap
  1416. void Cws_machineEx::enumerateRunningProcesses(CMachineInfoThreadParam* pParam, CProcessData& process, map<string, Linked<IEspSWRunInfo> >* runningProcessMap, bool firstProcess)
  1417. {
  1418. set<string>& dependencies = process.getDependencies();
  1419. set<string>& additionalProcesses = pParam->m_machineData.getAdditinalProcessFilters();
  1420. IArrayOf<IEspProcessInfo>& runningProcesses = pParam->m_machineData.getRunningProcesses();
  1421. ForEachItemIn(k, runningProcesses)
  1422. {
  1423. IEspProcessInfo& processInfo = runningProcesses.item(k);
  1424. //Erase this process from dependencies and, if firstProcess, additionalProcesses
  1425. const char* pName = processInfo.getDescription();
  1426. if (pParam->m_machineData.getOS() == MachineOsW2K)
  1427. {
  1428. StringBuffer sName = pName;
  1429. pName = sName.toLowerCase().replaceString(".exe", "").str();
  1430. if (!dependencies.empty())
  1431. dependencies.erase(pName);
  1432. if (pParam->m_options.getApplyProcessFilter() && firstProcess && !additionalProcesses.empty())
  1433. additionalProcesses.erase(pName);
  1434. }
  1435. else
  1436. {
  1437. //dafilesrv would probably be running from a global directory
  1438. //and not component's installation directory so ignore their paths
  1439. const char* pPath = pName;
  1440. if ( !strieq(pName, "dafilesrv"))
  1441. {
  1442. const char* param = processInfo.getParameter();
  1443. if (param && *param)
  1444. {
  1445. if (strncmp(param, "bash ", 5))
  1446. pPath = param;
  1447. else
  1448. pPath = param + 5;
  1449. if (!pPath || !*pPath)
  1450. continue;
  1451. //params typically is like "/c$/esp_dir/esp [parameters...]"
  1452. //so just pick the full path
  1453. const char* pch = strchr(pPath, ' ');
  1454. if (pch)
  1455. {
  1456. StringBuffer sPath = pPath;
  1457. sPath.setLength( pch - pPath );
  1458. pPath = sPath.str();
  1459. }
  1460. }
  1461. }
  1462. if (!dependencies.empty())
  1463. {
  1464. const char* pProcessName;
  1465. if (process.getType() && !strncmp(process.getType(), "Thor", 4) && !strnicmp(pName, "thor", 4))
  1466. {
  1467. const char* pch = strrchr(pPath, pParam->m_machineData.getPathSep());
  1468. pProcessName = pch ? pch+1 : pName;
  1469. }
  1470. else
  1471. {
  1472. const char* pName0 = process.getMultipleInstances() ? pPath : pName;
  1473. const char* pch = strrchr(pName0, pParam->m_machineData.getPathSep());
  1474. pProcessName = pch ? pch+1 : pName0;
  1475. }
  1476. dependencies.erase(pProcessName);
  1477. if (pParam->m_options.getApplyProcessFilter() && firstProcess && !additionalProcesses.empty())
  1478. additionalProcesses.erase(pProcessName);
  1479. }
  1480. pName = pPath;
  1481. }
  1482. if (!runningProcessMap)
  1483. continue;
  1484. //Add this process to runningProcessMap
  1485. map<string, Linked<IEspSWRunInfo> >::iterator it = runningProcessMap->find(pName);
  1486. if ( it != runningProcessMap->end()) //not in the set
  1487. {
  1488. Linked<IEspSWRunInfo>& linkedPtr = (*it).second;
  1489. linkedPtr->setInstances( linkedPtr->getInstances() + 1);
  1490. }
  1491. else
  1492. {
  1493. Owned<IEspSWRunInfo> info = static_cast<IEspSWRunInfo*>(new CSWRunInfo(""));
  1494. info->setName(pName);
  1495. info->setInstances(1);
  1496. runningProcessMap->insert(pair<string, Linked<IEspSWRunInfo> >(pName, info));
  1497. }
  1498. }
  1499. }
  1500. void Cws_machineEx::getProcessDisplayName(const char* processName, StringBuffer& displayName)
  1501. {
  1502. //produces "LDAPServerProcess" as "LDAP Server" and "EspService" as "Esp Service", etc.
  1503. const char* end = strstr(processName, "Process");
  1504. if (!end)
  1505. end = processName + strlen(processName);
  1506. displayName.append(*processName);
  1507. processName++;
  1508. bool bLower = false;
  1509. while (processName < end)
  1510. {
  1511. char ch = *processName;
  1512. if (!isupper(ch))
  1513. bLower = true;
  1514. else
  1515. {
  1516. if (bLower || //last char was uppercase or the following character is lowercase?
  1517. ((processName+1 < end) && islower(*(processName+1))))
  1518. {
  1519. displayName.append(' ');
  1520. }
  1521. bLower = false;
  1522. }
  1523. displayName.append(*processName);
  1524. processName++;
  1525. }
  1526. displayName.append('\0');
  1527. return;
  1528. }
  1529. bool Cws_machineEx::excludePartition(const char* partition) const
  1530. {
  1531. //first see if this partition is meant to be excluded as is - for instance
  1532. //if partition is /dev and /dev is one of the predefined partitions to be excluded
  1533. set<string>::const_iterator it = m_excludePartitions.find( partition );
  1534. set<string>::const_iterator itEnd = m_excludePartitions.end();
  1535. bool found = false;
  1536. if (it != itEnd)
  1537. found = true;
  1538. else
  1539. {
  1540. //now check if /dev* is one of the partitions to be excluded
  1541. set<string>::const_iterator itBegin = m_excludePartitionPatterns.begin();
  1542. itEnd = m_excludePartitionPatterns.end();
  1543. unsigned int partitionLen = strlen(partition);
  1544. for (it=itBegin; it != itEnd; it++)
  1545. {
  1546. const string& pattern = *it;
  1547. if ((found = ::WildMatch(partition, partitionLen, pattern.c_str(), pattern.length(), false)))
  1548. break;
  1549. }
  1550. }
  1551. return found;
  1552. }
  1553. void Cws_machineEx::appendProcessInstance(const char* name, const char* directory1, const char* directory2, StringArray& processInstances, StringArray& directories)
  1554. {
  1555. if (!name || !*name)
  1556. return;
  1557. processInstances.append(name);
  1558. if (directory1 && *directory1)
  1559. directories.append(directory1);
  1560. else if (directory2 && *directory2)
  1561. directories.append(directory2);
  1562. else
  1563. directories.append("Setting not found");
  1564. }
  1565. //////////////////////////////////////////////////////////////////
  1566. // Set Machine Infomation for response //
  1567. //////////////////////////////////////////////////////////////////
  1568. void Cws_machineEx::setMachineInfoResponse(IEspContext& context, IEspGetMachineInfoRequest& req,
  1569. CGetMachineInfoData& machineInfoData, IEspGetMachineInfoResponse& resp)
  1570. {
  1571. IEspRequestInfoStruct& reqInfo = resp.updateRequestInfo();
  1572. #if 0
  1573. StringBuffer user;
  1574. StringBuffer pw;
  1575. context.getUserID(user);
  1576. context.getPassword(pw);
  1577. reqInfo.setUserName(user.str());
  1578. reqInfo.setPassword(pw.str());
  1579. #endif
  1580. reqInfo.setSecurityString(req.getSecurityString());
  1581. reqInfo.setGetProcessorInfo(req.getGetProcessorInfo());
  1582. reqInfo.setGetStorageInfo(req.getGetStorageInfo());
  1583. double version = context.getClientVersion();
  1584. if (version > 1.10)
  1585. reqInfo.setLocalFileSystemsOnly(req.getLocalFileSystemsOnly());
  1586. reqInfo.setGetSoftwareInfo(req.getGetSoftwareInfo());
  1587. reqInfo.setAutoRefresh( req.getAutoRefresh() );
  1588. reqInfo.setMemThreshold(req.getMemThreshold());
  1589. reqInfo.setDiskThreshold(req.getDiskThreshold());
  1590. reqInfo.setCpuThreshold(req.getCpuThreshold());
  1591. reqInfo.setMemThresholdType(req.getMemThresholdType());
  1592. reqInfo.setDiskThresholdType(req.getDiskThresholdType());
  1593. reqInfo.setApplyProcessFilter( req.getApplyProcessFilter() );
  1594. reqInfo.setClusterType( req.getClusterType() );
  1595. reqInfo.setCluster( req.getCluster() );
  1596. reqInfo.setAddProcessesToFilter( req.getAddProcessesToFilter() );
  1597. reqInfo.setOldIP( req.getOldIP() );
  1598. reqInfo.setPath( req.getPath() );
  1599. reqInfo.setSortBy("Address");
  1600. if (machineInfoData.getMachineInfoColumns().ordinality())
  1601. resp.setColumns(machineInfoData.getMachineInfoColumns());
  1602. if (machineInfoData.getMachineInfoTable().ordinality())
  1603. resp.setMachines(machineInfoData.getMachineInfoTable());
  1604. char timeStamp[32];
  1605. getTimeStamp(timeStamp);
  1606. resp.setTimeStamp( timeStamp );
  1607. }
  1608. void Cws_machineEx::getTimeStamp(char* timeStamp)
  1609. {
  1610. //set time stamp in the result for this machine
  1611. time_t tNow;
  1612. time(&tNow);
  1613. #ifdef _WIN32
  1614. struct tm *ltNow;
  1615. ltNow = localtime(&tNow);
  1616. strftime(timeStamp, 32, "%m/%d/%y %H:%M:%S", ltNow);
  1617. #else
  1618. struct tm ltNow;
  1619. localtime_r(&tNow, &ltNow);
  1620. strftime(timeStamp, 32, "%m/%d/%y %H:%M:%S", &ltNow);
  1621. #endif
  1622. }
  1623. void Cws_machineEx::setTargetClusterInfoResponse(IEspContext& context, IEspGetTargetClusterInfoRequest& req,
  1624. CGetMachineInfoData& machineInfoData, IPropertyTree* targetClusterTree, IEspGetTargetClusterInfoResponse& resp)
  1625. {
  1626. IEspRequestInfoStruct& reqInfo = resp.updateRequestInfo();
  1627. #if 0
  1628. StringBuffer user;
  1629. StringBuffer pw;
  1630. context.getUserID(user);
  1631. context.getPassword(pw);
  1632. reqInfo.setUserName(user.str());
  1633. reqInfo.setPassword(pw.str());
  1634. #endif
  1635. reqInfo.setGetProcessorInfo(req.getGetProcessorInfo());
  1636. reqInfo.setGetStorageInfo(req.getGetStorageInfo());
  1637. double version = context.getClientVersion();
  1638. if (version > 1.10)
  1639. reqInfo.setLocalFileSystemsOnly(req.getLocalFileSystemsOnly());
  1640. reqInfo.setGetSoftwareInfo(req.getGetSoftwareInfo());
  1641. reqInfo.setAutoRefresh( req.getAutoRefresh() );
  1642. reqInfo.setMemThreshold(req.getMemThreshold());
  1643. reqInfo.setDiskThreshold(req.getDiskThreshold());
  1644. reqInfo.setCpuThreshold(req.getCpuThreshold());
  1645. reqInfo.setMemThresholdType(req.getMemThresholdType());
  1646. reqInfo.setDiskThresholdType(req.getDiskThresholdType());
  1647. reqInfo.setApplyProcessFilter( req.getApplyProcessFilter() );
  1648. reqInfo.setAddProcessesToFilter( req.getAddProcessesToFilter() );
  1649. reqInfo.setSortBy("Address");
  1650. if (machineInfoData.getMachineInfoColumns().ordinality())
  1651. resp.setColumns(machineInfoData.getMachineInfoColumns());
  1652. if (machineInfoData.getMachineInfoTable().ordinality())
  1653. {
  1654. IArrayOf<IEspTargetClusterInfo> targetClusterInfoList;
  1655. setTargetClusterInfo(targetClusterTree, machineInfoData.getMachineInfoTable(), targetClusterInfoList);
  1656. if (targetClusterInfoList.ordinality())
  1657. resp.setTargetClusterInfoList(targetClusterInfoList);
  1658. }
  1659. char timeStamp[32];
  1660. getTimeStamp(timeStamp);
  1661. resp.setTimeStamp( timeStamp );
  1662. }
  1663. void Cws_machineEx::setTargetClusterInfo(IPropertyTree* pTargetClusterTree, IArrayOf<IEspMachineInfoEx>& machineArray, IArrayOf<IEspTargetClusterInfo>& targetClusterInfoList)
  1664. {
  1665. if (!pTargetClusterTree)
  1666. return;
  1667. unsigned machineCount = machineArray.ordinality();
  1668. if (machineCount < 1)
  1669. return;
  1670. Owned<IPropertyTreeIterator> targetClusters = pTargetClusterTree->getElements("TargetCluster");
  1671. ForEach(*targetClusters)
  1672. {
  1673. IPropertyTree& targetCluster = targetClusters->query();
  1674. StringBuffer targetName, targetType;
  1675. targetCluster.getProp("@Name", targetName);
  1676. targetCluster.getProp("@Type", targetType);
  1677. Owned<IEspTargetClusterInfo> targetClusterInfo = static_cast<IEspTargetClusterInfo*>(new CTargetClusterInfo(""));
  1678. targetClusterInfo->setName( targetName.str() );
  1679. targetClusterInfo->setType( targetType.str() );
  1680. IArrayOf<IEspMachineInfoEx> machineArrayNew;
  1681. Owned<IPropertyTreeIterator> processes = targetCluster.getElements("Process");
  1682. ForEach(*processes)
  1683. {
  1684. IPropertyTree& process = processes->query();
  1685. StringBuffer processName, processType;
  1686. process.getProp("@Name", processName);
  1687. process.getProp("@Type", processType);
  1688. for (unsigned i = 0; i < machineCount; i++)
  1689. {
  1690. IEspMachineInfoEx& machineInfoEx = machineArray.item(i);
  1691. const char* name = machineInfoEx.getComponentName();
  1692. const char* type = machineInfoEx.getProcessType();
  1693. if (!name || !type || !strieq(name, processName.str()) || !strieq(getProcessTypeFromMachineType(type), processType.str()))
  1694. continue;
  1695. Owned<IEspMachineInfoEx> pMachineInfo = static_cast<IEspMachineInfoEx*>(new CMachineInfoEx(""));
  1696. pMachineInfo->copy(machineInfoEx);
  1697. machineArrayNew.append(*pMachineInfo.getLink());
  1698. //Cannot break here because more than one processes match (ex. EclAgent/AgentExec)
  1699. }
  1700. }
  1701. if (machineArrayNew.ordinality())
  1702. targetClusterInfo->setProcesses(machineArrayNew);
  1703. targetClusterInfoList.append(*targetClusterInfo.getLink());
  1704. }
  1705. }
  1706. const char* Cws_machineEx::getProcessTypeFromMachineType(const char* machineType)
  1707. {
  1708. const char* processType ="Unknown";
  1709. if (!machineType || !*machineType)
  1710. return processType;
  1711. if (strieq(machineType, eqThorMasterProcess) || strieq(machineType, eqThorSlaveProcess) || strieq(machineType, eqThorSpareProcess))
  1712. {
  1713. processType = eqThorCluster;
  1714. }
  1715. else if (strieq(machineType, eqRoxieServerProcess))
  1716. {
  1717. processType = eqRoxieCluster;
  1718. }
  1719. else if (strieq(machineType, eqAgentExec))
  1720. {
  1721. processType = eqEclAgent;
  1722. }
  1723. else
  1724. {
  1725. processType = machineType;
  1726. }
  1727. return processType;
  1728. }
  1729. IConstEnvironment* Cws_machineEx::getConstEnvironment()
  1730. {
  1731. Owned<IEnvironmentFactory> envFactory = getEnvironmentFactory();
  1732. Owned<IConstEnvironment> constEnv = envFactory->openEnvironmentByFile();
  1733. return constEnv.getLink();
  1734. }
  1735. //Used in Rexec
  1736. IPropertyTree* Cws_machineEx::getComponent(const char* compType, const char* compName)
  1737. {
  1738. StringBuffer xpath;
  1739. xpath.append("Software/").append(compType).append("[@name='").append(compName).append("']");
  1740. m_envFactory->validateCache();
  1741. Owned<IConstEnvironment> constEnv = getConstEnvironment();
  1742. Owned<IPropertyTree> pEnvRoot = &constEnv->getPTree();
  1743. return pEnvRoot->getPropTree( xpath.str() );
  1744. }
  1745. void Cws_machineEx::getAccountAndPlatformInfo(const char* address, StringBuffer& userId, StringBuffer& password, bool& bLinux)
  1746. {
  1747. m_envFactory->validateCache();
  1748. Owned<IConstEnvironment> constEnv = getConstEnvironment();
  1749. Owned<IConstMachineInfo> machine = constEnv->getMachineByAddress(address);
  1750. if (!machine && strieq(address, "."))
  1751. {
  1752. machine.setown(constEnv->getMachineByAddress("127.0.0.1"));
  1753. }
  1754. if (!machine)
  1755. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Machine %s is not defined in environment!", address);
  1756. Owned<IConstDomainInfo> domain = machine->getDomain();
  1757. if (!domain)
  1758. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Machine %s does not have any domain information!", address);
  1759. userId.clear();
  1760. password.clear();
  1761. StringBufferAdaptor strval1(userId);
  1762. StringBufferAdaptor strval2(password);
  1763. domain->getAccountInfo(strval1, strval2);
  1764. StringBuffer domainName;
  1765. StringBufferAdaptor strval3(domainName);
  1766. domain->getName(strval3);
  1767. if ((machine->getOS() == MachineOsW2K) && domainName.length())
  1768. {
  1769. domainName.append('\\');
  1770. userId.insert(0, domainName);
  1771. }
  1772. bLinux = machine->getOS() == MachineOsLinux;
  1773. }