ws_machineService.cpp 136 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534
  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. #include "workunit.hpp"
  18. #include "roxiecommlib.hpp"
  19. #include "componentstatus.hpp"
  20. #include "rmtssh.hpp"
  21. #include "platform.h"
  22. #include "TpWrapper.hpp"
  23. static const int THREAD_POOL_SIZE = 40;
  24. static const int THREAD_POOL_STACK_SIZE = 64000;
  25. static const char* FEATURE_URL = "MachineInfoAccess";
  26. const unsigned ROXIECONTROLSTATETIMEOUT = 5000; //5 second
  27. class CMachineInfoThreadParam : public CWsMachineThreadParam
  28. {
  29. public:
  30. IMPLEMENT_IINTERFACE;
  31. IEspContext& m_context;
  32. CGetMachineInfoUserOptions& m_options; //From request
  33. CMachineData& m_machineData; //From request
  34. IArrayOf<IEspMachineInfoEx>& m_machineInfoTable; //For response
  35. StringArray& m_machineInfoColumns; //For response
  36. MapStringTo<int>& channelsMap; //For response
  37. CMachineInfoThreadParam(Cws_machineEx* pService, IEspContext& context, CGetMachineInfoUserOptions& options,
  38. CMachineData& machineData, IArrayOf<IEspMachineInfoEx>& machineInfoTable, StringArray& machineInfoColumns,
  39. MapStringTo<int>& _channelsMap)
  40. : CWsMachineThreadParam(NULL, NULL, NULL, pService),
  41. m_context(context),
  42. m_options(options),
  43. m_machineData(machineData),
  44. m_machineInfoTable(machineInfoTable),
  45. m_machineInfoColumns(machineInfoColumns),
  46. channelsMap(_channelsMap)
  47. {
  48. }
  49. virtual void doWork()
  50. {
  51. m_pService->doGetMachineInfo(m_context, this);
  52. }
  53. void addColumn(const char* columnName)
  54. {
  55. synchronized block(s_mutex);
  56. if (m_machineInfoColumns.find(columnName) == NotFound)
  57. m_machineInfoColumns.append(columnName);
  58. }
  59. int* getChannels(const char* key) { return channelsMap.getValue(key); };
  60. private:
  61. static Mutex s_mutex;
  62. };
  63. Mutex CMachineInfoThreadParam::s_mutex;
  64. class CRoxieStateInfoThreadParam : public CWsMachineThreadParam
  65. {
  66. public:
  67. StringAttr clusterName;
  68. IArrayOf<IEspMachineInfoEx>& machineInfoTable; //For response
  69. MapStringTo<int>& channelsMap; //For response
  70. CRoxieStateInfoThreadParam(Cws_machineEx* pService, const char* _clusterName,
  71. IArrayOf<IEspMachineInfoEx>& _machineInfoTable, MapStringTo<int>& _channelsMap)
  72. : CWsMachineThreadParam(pService), clusterName(_clusterName), machineInfoTable(_machineInfoTable),
  73. channelsMap(_channelsMap)
  74. {
  75. }
  76. virtual void doWork()
  77. {
  78. m_pService->getRoxieStateInfo(this);
  79. }
  80. int* getChannels(const char* key) { return channelsMap.getValue(key); };
  81. };
  82. class CGetMachineUsageThreadParam : public CWsMachineThreadParam
  83. {
  84. public:
  85. IEspContext& espContext;
  86. IPropertyTree* request;
  87. CGetMachineUsageThreadParam(Cws_machineEx* pService, IEspContext& _espContext, IPropertyTree* _request)
  88. : CWsMachineThreadParam(pService), espContext(_espContext), request(_request) {}
  89. virtual void doWork()
  90. {
  91. m_pService->getMachineUsage(espContext, this);
  92. }
  93. };
  94. const char* findComponentTypeFromProcessType(const char* ProcessType)
  95. {
  96. if (strieq(ProcessType, eqDali))
  97. return "dali";
  98. if (strieq(ProcessType, eqEclAgent))
  99. return "eclagent";
  100. if (strieq(ProcessType, eqDfu))
  101. return "dfuserver";
  102. if (strieq(ProcessType, eqEsp))
  103. return "esp";
  104. if (strieq(ProcessType, eqEclCCServer) || strieq(ProcessType, eqEclServer))
  105. return "eclserver";
  106. if (strieq(ProcessType, eqEclScheduler))
  107. return "eclscheduler";
  108. if (strieq(ProcessType, eqSashaServer))
  109. return "sasha";
  110. return nullptr;
  111. }
  112. void Cws_machineEx::init(IPropertyTree *cfg, const char *process, const char *service)
  113. {
  114. //Read settings from esp.xml
  115. StringBuffer xpath;
  116. xpath.appendf("Software/EspProcess[@name=\"%s\"]/EspService[@name=\"%s\"]", process, service);
  117. Owned<IPropertyTree> pServiceNode = cfg->getPropTree(xpath.str());
  118. m_bMonitorDaliFileServer = pServiceNode->getPropBool("@monitorDaliFileServer", false);
  119. m_processFilters.setown( pServiceNode->getPropTree("ProcessFilters") );
  120. const char* pchExcludePartitions = pServiceNode->queryProp("@excludePartitions");
  121. if (pchExcludePartitions && *pchExcludePartitions)
  122. {
  123. StringArray sPartitions;
  124. sPartitions.appendList(pchExcludePartitions, ", ;");
  125. unsigned int numOfPartitions = sPartitions.ordinality();
  126. for (unsigned int i=0; i<numOfPartitions; i++)
  127. {
  128. const char* partition = sPartitions.item(i);
  129. if (!partition || !*partition)
  130. continue;
  131. if (strchr(partition, '*'))
  132. m_excludePartitionPatterns.insert( partition );
  133. else
  134. m_excludePartitions.insert( partition );
  135. }
  136. }
  137. m_useDefaultHPCCInit = pServiceNode->getPropBool("UseDefaultHPCCInit", true);//Still used by Rexec for now
  138. m_SSHConnectTimeoutSeconds = pServiceNode->getPropInt("SSHConnectTimeoutSeconds", 5);
  139. const char* machineInfoScript = pServiceNode->queryProp("MachineInfoFile");
  140. if (machineInfoScript && *machineInfoScript)
  141. m_machineInfoFile.append(machineInfoScript);
  142. else
  143. m_machineInfoFile.append("preflight");
  144. //Read settings from environment.xml
  145. Owned<IEnvironmentFactory> envFactory = getEnvironmentFactory(true);
  146. Owned<IConstEnvironment> constEnv = envFactory->openEnvironment();
  147. Owned<IPropertyTree> pEnvironmentRoot = &constEnv->getPTree();
  148. Owned<IPropertyTree> pEnvSettings = pEnvironmentRoot->getPropTree("EnvSettings");
  149. if (pEnvSettings)
  150. {
  151. pEnvSettings->getProp("configs", environmentConfData.m_configsPath.clear());
  152. pEnvSettings->getProp("path", environmentConfData.m_executionPath.clear());
  153. pEnvSettings->getProp("runtime", environmentConfData.m_runtimePath.clear());
  154. pEnvSettings->getProp("lock", environmentConfData.m_lockPath.clear());
  155. pEnvSettings->getProp("pid", environmentConfData.m_pidPath.clear());
  156. pEnvSettings->getProp("user", environmentConfData.m_user.clear());
  157. }
  158. m_threadPoolSize = pServiceNode->getPropInt("ThreadPoolSize", THREAD_POOL_SIZE);
  159. m_threadPoolStackSize = pServiceNode->getPropInt("ThreadPoolStackSize", THREAD_POOL_STACK_SIZE);
  160. //Start thread pool
  161. Owned<IThreadFactory> pThreadFactory = new CWsMachineThreadFactory();
  162. m_threadPool.setown(createThreadPool("WsMachine Thread Pool", pThreadFactory,
  163. NULL, m_threadPoolSize, 10000, m_threadPoolStackSize)); //10 sec timeout for available thread; use stack size of 2MB
  164. setupLegacyFilters();
  165. Owned<IComponentStatusFactory> factory = getComponentStatusFactory();
  166. factory->init(pServiceNode);
  167. unsigned machineUsageCacheForceRebuildMinutes = pServiceNode->getPropInt("MachineUsageCacheMinutes", machineUsageCacheMinutes);
  168. unsigned machineUsageCacheAutoRebuildMinutes = pServiceNode->getPropInt("MachineUsageCacheAutoRebuildMinutes", defaultMachineUsageCacheAutoBuildMinutes);
  169. usageCacheReader.setown(new CUsageCacheReader(this, "Usage Reader", machineUsageCacheAutoRebuildMinutes*60, machineUsageCacheForceRebuildMinutes*60));
  170. }
  171. StringBuffer& Cws_machineEx::getAcceptLanguage(IEspContext& context, StringBuffer& acceptLanguage)
  172. {
  173. context.getAcceptLanguage(acceptLanguage);
  174. if (!acceptLanguage.length())
  175. {
  176. acceptLanguage.set("en");
  177. return acceptLanguage;
  178. }
  179. acceptLanguage.setLength(2);
  180. VStringBuffer languageFile("%ssmc_xslt/nls/%s/hpcc.xml", getCFD(), acceptLanguage.str());
  181. if (!checkFileExists(languageFile.str()))
  182. acceptLanguage.set("en");
  183. return acceptLanguage;
  184. }
  185. bool Cws_machineEx::onGetMachineInfo(IEspContext &context, IEspGetMachineInfoRequest & req,
  186. IEspGetMachineInfoResponse & resp)
  187. {
  188. try
  189. {
  190. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Read, ECLWATCH_MACHINE_INFO_ACCESS_DENIED, "Failed to Get Machine Information. Permission denied.");
  191. StringArray& addresses = req.getAddresses();
  192. if (addresses.empty())
  193. throw MakeStringException(ECLWATCH_INVALID_IP_OR_COMPONENT, "No network address specified.");
  194. CGetMachineInfoData machineInfoData;
  195. readMachineInfoRequest(context, req.getGetProcessorInfo(), req.getGetStorageInfo(), req.getLocalFileSystemsOnly(), req.getGetSoftwareInfo(),
  196. req.getApplyProcessFilter(), addresses, req.getAddProcessesToFilter(), machineInfoData);
  197. getMachineInfo(context, machineInfoData);
  198. setMachineInfoResponse(context, req, machineInfoData, resp);
  199. }
  200. catch(IException* e)
  201. {
  202. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  203. }
  204. return true;
  205. }
  206. bool Cws_machineEx::onGetMachineInfoEx(IEspContext &context, IEspGetMachineInfoRequestEx & req, IEspGetMachineInfoResponseEx & resp)
  207. {
  208. try
  209. {
  210. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Read, ECLWATCH_MACHINE_INFO_ACCESS_DENIED, "Failed to Get Machine Information. Permission denied.");
  211. StringArray& addresses = req.getAddresses();
  212. if (addresses.empty())
  213. throw MakeStringException(ECLWATCH_INVALID_IP_OR_COMPONENT, "No network address specified.");
  214. double version = context.getClientVersion();
  215. CGetMachineInfoData machineInfoData;
  216. readMachineInfoRequest(context, true, true, true, true, true, addresses, NULL, machineInfoData);
  217. getMachineInfo(context, machineInfoData);
  218. if (machineInfoData.getMachineInfoTable().ordinality())
  219. resp.setMachines(machineInfoData.getMachineInfoTable());
  220. if (version >= 1.12)
  221. {
  222. StringBuffer acceptLanguage;
  223. resp.setAcceptLanguage(getAcceptLanguage(context, acceptLanguage).str());
  224. }
  225. }
  226. catch(IException* e)
  227. {
  228. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  229. }
  230. return true;
  231. }
  232. bool Cws_machineEx::onGetTargetClusterInfo(IEspContext &context, IEspGetTargetClusterInfoRequest & req,
  233. IEspGetTargetClusterInfoResponse & resp)
  234. {
  235. try
  236. {
  237. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Read, ECLWATCH_MACHINE_INFO_ACCESS_DENIED, "Failed to Get Target Cluster Information. Permission denied.");
  238. StringArray& targetClusters = req.getTargetClusters();
  239. if (targetClusters.empty())
  240. throw MakeStringException(ECLWATCH_INVALID_IP_OR_COMPONENT, "No target cluster specified.");
  241. CGetMachineInfoData machineInfoData;
  242. Owned<IPropertyTree> targetClustersOut = createPTreeFromXMLString("<Root/>");
  243. readMachineInfoRequest(context, req.getGetProcessorInfo(), req.getGetStorageInfo(), req.getLocalFileSystemsOnly(), req.getGetSoftwareInfo(),
  244. req.getApplyProcessFilter(), req.getAddProcessesToFilter(), targetClusters, machineInfoData, targetClustersOut);
  245. getMachineInfo(context, machineInfoData);
  246. setTargetClusterInfoResponse(context, req, machineInfoData, targetClustersOut, resp);
  247. }
  248. catch(IException* e)
  249. {
  250. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  251. }
  252. return true;
  253. }
  254. void Cws_machineEx::addChannels(CGetMachineInfoData& machineInfoData, IPropertyTree* envRoot,
  255. const char* componentType, const char* componentName)
  256. {
  257. VStringBuffer key("%s|%s", componentType, componentName);
  258. int* channels = machineInfoData.getChannels(key);
  259. if (channels)
  260. return;
  261. StringBuffer path("Software/");
  262. if (strieq(componentType, eqThorSlaveProcess))
  263. path.append(eqThorCluster);
  264. else if (strieq(componentType, eqRoxieServerProcess))
  265. path.append(eqRoxieCluster);
  266. else
  267. throw MakeStringException(ECLWATCH_INVALID_COMPONENT_TYPE, "Invalid %s in Cws_machineEx::addChannels().", componentType);
  268. path.appendf("[@name=\"%s\"]", componentName);
  269. Owned<IPropertyTree> component;
  270. if (envRoot)
  271. {
  272. component.setown(envRoot->getPropTree(path));
  273. }
  274. else
  275. {
  276. Owned<IEnvironmentFactory> envFactory = getEnvironmentFactory(true);
  277. Owned<IConstEnvironment> constEnv = envFactory->openEnvironment();
  278. Owned<IPropertyTree> root = &constEnv->getPTree();
  279. component.setown(root->getPropTree(path));
  280. }
  281. if (!component)
  282. throw MakeStringException(ECLWATCH_INVALID_IP_OR_COMPONENT, "%s not found.", componentName);
  283. StringAttr attr;
  284. if (strieq(componentType, eqThorSlaveProcess))
  285. attr.set("@channelsPerSlave");
  286. else
  287. attr.set("@channelsPerNode");
  288. if (component->hasProp(attr.get()))
  289. machineInfoData.addToChannelsMap(key, component->getPropInt(attr.get()));
  290. }
  291. ////////////////////////////////////////////////////////////////////////////////////////
  292. // Read Machine Infomation request and collect related settings from environment.xml //
  293. ////////////////////////////////////////////////////////////////////////////////////////
  294. void Cws_machineEx::readMachineInfoRequest(IEspContext& context, bool getProcessorInfo, bool getStorageInfo, bool localFileSystemsOnly, bool getSoftwareInfo, bool applyProcessFilter,
  295. StringArray& processes, const char* addProcessesToFilters, CGetMachineInfoData& machineInfoData)
  296. {
  297. double version = context.getClientVersion();
  298. StringBuffer userID, password;
  299. context.getUserID(userID);
  300. context.getPassword(password);
  301. machineInfoData.getOptions().setUserName(userID.str());
  302. machineInfoData.getOptions().setPassword(password.str());
  303. machineInfoData.getOptions().setGetProcessorInfo(getProcessorInfo);
  304. machineInfoData.getOptions().setGetStorageInfo(getStorageInfo);
  305. machineInfoData.getOptions().setLocalFileSystemsOnly(localFileSystemsOnly);
  306. machineInfoData.getOptions().setGetSoftwareInfo(getSoftwareInfo);
  307. machineInfoData.getOptions().setApplyProcessFilter(applyProcessFilter);
  308. machineInfoData.getOptions().getAdditionalProcessFilters().appendList(addProcessesToFilters, " ,\t");
  309. BoolHash uniqueProcesses;
  310. for (unsigned i=0; i<processes.ordinality(); i++)
  311. {
  312. StringArray address;
  313. address.appendList(processes.item(i), ":");
  314. StringBuffer address1, address2, processType, compName, path;
  315. unsigned processNumber = 0;
  316. if (!machineInfoData.getOptions().getGetSoftwareInfo())
  317. {
  318. parseAddresses(address.item(0), address1, address2);
  319. }
  320. else
  321. {
  322. if (address.ordinality() < 5)
  323. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Invalid address format in '%s'.", processes.item(i));
  324. parseProcessString(address, address1, address2, processType, compName, path, processNumber);
  325. }
  326. setProcessRequest(machineInfoData, uniqueProcesses, address1.str(), address2.str(), processType.str(), compName.str(), path.str(), processNumber);
  327. if (strieq(processType.str(), eqRoxieServerProcess))
  328. machineInfoData.appendRoxieClusters(compName.str());
  329. if ((version >= 1.16) && (strieq(processType, eqThorSlaveProcess) || strieq(processType, eqRoxieServerProcess)))
  330. addChannels(machineInfoData, nullptr, processType, compName);
  331. }
  332. }
  333. void Cws_machineEx::readMachineInfoRequest(IEspContext& context, bool getProcessorInfo, bool getStorageInfo, bool localFileSystemsOnly, bool getSoftwareInfo, bool applyProcessFilter,
  334. const char* addProcessesToFilters, StringArray& targetClustersIn, CGetMachineInfoData& machineInfoData, IPropertyTree* targetClusterTreeOut)
  335. {
  336. StringBuffer userID, password;
  337. context.getUserID(userID);
  338. context.getPassword(password);
  339. machineInfoData.getOptions().setUserName(userID.str());
  340. machineInfoData.getOptions().setPassword(password.str());
  341. machineInfoData.getOptions().setGetProcessorInfo(getProcessorInfo);
  342. machineInfoData.getOptions().setGetStorageInfo(getStorageInfo);
  343. machineInfoData.getOptions().setLocalFileSystemsOnly(localFileSystemsOnly);
  344. machineInfoData.getOptions().setGetSoftwareInfo(getSoftwareInfo);
  345. machineInfoData.getOptions().setApplyProcessFilter(applyProcessFilter);
  346. machineInfoData.getOptions().getAdditionalProcessFilters().appendList(addProcessesToFilters, " ,\t");
  347. readSettingsForTargetClusters(context, targetClustersIn, machineInfoData, targetClusterTreeOut);
  348. }
  349. //Parses address request from machine information request in the form "192.168.1.4-6|."
  350. //The second address is the address retrieved from environment setting (could be a '.').
  351. void Cws_machineEx::parseAddresses(const char *address, StringBuffer& address1, StringBuffer& address2)
  352. {
  353. address1 = address;
  354. address2.clear();
  355. const char* props1 = strchr(address, '|');
  356. if (props1)
  357. {
  358. address2 = props1+1;
  359. address1.setLength(props1 - address);
  360. }
  361. address1.trim();
  362. address2.trim();
  363. }
  364. //Parses machine information request for each process in the form "192.168.1.4-6|.:ThorSlaveProcess:thor1:2:/var/lib/..."
  365. void Cws_machineEx::parseProcessString(StringArray& process, StringBuffer& address1, StringBuffer& address2,
  366. StringBuffer& processType, StringBuffer& compName, StringBuffer& path, unsigned& processNumber)
  367. {
  368. parseAddresses(process.item(0), address1, address2);
  369. processType.clear().append( process.item(1) ).trim();
  370. compName.clear().append( process.item(2) ).trim();
  371. EnvMachineOS os = (EnvMachineOS) atoi( process.item(3) );
  372. path.clear().append( process.item(4) ).trim();
  373. if (path.length())
  374. {
  375. char pat1, pat2;
  376. char rep1, rep2;
  377. if (os == MachineOsLinux)
  378. {
  379. pat1 = ':'; rep1 = '$';
  380. pat2 = '\\';rep2 = '/';
  381. }
  382. else
  383. {
  384. pat1 = '$'; rep1 = ':';
  385. pat2 = '/';rep2 = '\\';
  386. }
  387. path.replace( pat1, rep1 );
  388. path.replace( pat2, rep2 );
  389. if ((os == MachineOsLinux) && (path.charAt(0) != '/'))
  390. path.insert(0, '/');
  391. }
  392. if (process.ordinality() < 6)
  393. return;
  394. processNumber = atoi( process.item(5) );
  395. }
  396. void Cws_machineEx::setProcessRequest(CGetMachineInfoData& machineInfoData, BoolHash& uniqueProcesses, const char* address1, const char* address2,
  397. const char* processType, const char* compName, const char* path, unsigned processNumber)
  398. {
  399. IpAddress ipAddr;
  400. unsigned numIps = ipAddr.ipsetrange(address1);
  401. //address is like 192.168.1.4-6
  402. //so process each address in the range
  403. if (!ipAddr.isIp4())
  404. IPV6_NOT_IMPLEMENTED();
  405. //Always use "EclAgentProcess" to retrieve machine info for "AgentExecProcess"
  406. StringBuffer processTypeStr;
  407. if (processType && *processType)
  408. {
  409. if (strieq(processType, eqAgentExec))
  410. processTypeStr.append(eqEclAgent);
  411. else
  412. processTypeStr = processType;
  413. }
  414. while (numIps--)
  415. {
  416. unsigned numAddr;
  417. if (ipAddr.getNetAddress(sizeof(numAddr),&numAddr)!=sizeof(numAddr))
  418. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid network address.");
  419. ipAddr.ipincrement(1);
  420. //Clean possible duplication
  421. StringBuffer valuesToBeChecked;
  422. valuesToBeChecked.append(numAddr);
  423. if (machineInfoData.getOptions().getGetSoftwareInfo())
  424. valuesToBeChecked.appendf(":%s:%s:%d", processTypeStr.str(), compName, processNumber);
  425. bool* found = uniqueProcesses.getValue(valuesToBeChecked.str());
  426. if (found && *found)
  427. continue;
  428. uniqueProcesses.setValue(valuesToBeChecked.str(), true);
  429. addProcessRequestToMachineInfoData(machineInfoData, address1, address2, processTypeStr.str(), compName, path, processNumber);
  430. }
  431. }
  432. void Cws_machineEx::addProcessRequestToMachineInfoData(CGetMachineInfoData& machineInfoData, const char* address1, const char* address2,
  433. const char* processType, const char* compName, const char* path, unsigned processNumber)
  434. {
  435. CIArrayOf<CMachineData>& machines = machineInfoData.getMachineData();
  436. ForEachItemIn(idx, machines)
  437. {
  438. CMachineData& machine = machines.item(idx);
  439. if (streq(address1, machine.getNetworkAddress()))
  440. {
  441. addProcessData(&machine, processType, compName, path, processNumber);
  442. return;
  443. }
  444. }
  445. char pathSep;
  446. EnvMachineOS os;
  447. Owned<IConstEnvironment> constEnv = getConstEnvironment();
  448. Owned<IConstMachineInfo> pMachineInfo = constEnv->getMachineByAddress(address1);
  449. if (pMachineInfo.get())
  450. os = pMachineInfo->getOS();
  451. else
  452. os = MachineOsUnknown;
  453. if (os == MachineOsW2K)
  454. pathSep = '\\';
  455. else
  456. pathSep = '/';
  457. if (!m_processFilters)
  458. return;
  459. Owned<CMachineData> machineNew = new CMachineData(address1, address2, os, pathSep);
  460. //Read possible dependencies for all processes
  461. set<string>& dependenciesForAllProcesses = machineNew->getDependencies();
  462. StringBuffer xPath;
  463. xPath.appendf("Platform[@name='%s']/ProcessFilter[@name='any']/Process", machineNew->getOS() == MachineOsW2K ? "Windows" : "Linux");
  464. Owned<IPropertyTreeIterator> processes = m_processFilters->getElements(xPath.str());
  465. ForEach (*processes)
  466. {
  467. StringBuffer processName;
  468. processes->query().getProp("@name", processName);
  469. processName.toLowerCase().replaceString(".exe", "");
  470. if ((processName.length() > 0) && (!streq(processName.str(), "hoagentd"))) //hoagentd is not needed anymore
  471. dependenciesForAllProcesses.insert(processName.str());
  472. }
  473. if (m_bMonitorDaliFileServer && (dependenciesForAllProcesses.find("dafilesrv") == dependenciesForAllProcesses.end()))
  474. dependenciesForAllProcesses.insert("dafilesrv");
  475. addProcessData(machineNew, processType, compName, path, processNumber);
  476. machines.append(*machineNew.getClear());
  477. }
  478. //Create a CProcessData object and add it to CMachineData
  479. void Cws_machineEx::addProcessData(CMachineData* machine, const char* processType, const char* compName,
  480. const char* path, unsigned processNumber)
  481. {
  482. if (!machine)
  483. return;
  484. StringBuffer pathStr(path);
  485. if (pathStr.length() > 0)
  486. {
  487. char pathSep = machine->getPathSep();
  488. if (pathStr.charAt(pathStr.length() - 1) != pathSep)
  489. pathStr.append(pathSep);
  490. }
  491. Owned<CProcessData> process = new CProcessData(compName, processType, pathStr.str(), processNumber);
  492. //Copy dependencies for all processes
  493. set<string>& dependenciesForThisProcess = process->getDependencies();
  494. set<string>& dependenciesForAllProcesses = machine->getDependencies();
  495. set<string>::const_iterator it = dependenciesForAllProcesses.begin();
  496. set<string>::const_iterator iEnd = dependenciesForAllProcesses.end();
  497. for (; it != iEnd; it++) //add in sorted order simply by traversing the map
  498. dependenciesForThisProcess.insert((*it).c_str());
  499. //now collect "process-specific" dependencies
  500. IPropertyTree* processFilterNode = nullptr;
  501. if (m_processFilters)
  502. {
  503. VStringBuffer xPath("Platform[@name='%s']/ProcessFilter[@name='%s']", machine->getOS() == MachineOsW2K ? "Windows" : "Linux", processType);
  504. processFilterNode = m_processFilters->queryPropTree( xPath.str() );
  505. }
  506. if (!processFilterNode)
  507. {
  508. machine->getProcesses().append(*process.getClear());
  509. return;
  510. }
  511. Owned<IPropertyTreeIterator> processes = processFilterNode->getElements("Process");
  512. ForEach (*processes)
  513. {
  514. IPropertyTree* pProcess = &processes->query();
  515. const char* name = pProcess->queryProp("@name");
  516. if (!name || streq(name, "."))
  517. continue;
  518. StringBuffer processName(name);
  519. processName.toLowerCase().replaceString(".exe", "");
  520. if (processName.length() < 1)
  521. continue;
  522. //Environment.xml may contain old filter settings.
  523. if (isLegacyFilter(processType, processName.str()))
  524. continue;
  525. if (pProcess->getPropBool("@remove", false))
  526. dependenciesForThisProcess.erase(processName.str());
  527. else
  528. dependenciesForThisProcess.insert(processName.str());
  529. }
  530. process->setMultipleInstances(machine->getOS() == MachineOsLinux && processFilterNode->getPropBool("@multipleInstances", false));
  531. machine->getProcesses().append(*process.getClear());
  532. }
  533. //Collect process settings for the requested target clusters
  534. void Cws_machineEx::readSettingsForTargetClusters(IEspContext& context, StringArray& targetClusters, CGetMachineInfoData& machineInfoData, IPropertyTree* targetClustersOut)
  535. {
  536. unsigned ordinality= targetClusters.ordinality();
  537. if (ordinality < 1)
  538. return;
  539. Owned<IConstEnvironment> constEnv = getConstEnvironment();
  540. Owned<IPropertyTree> pEnvironmentRoot = &constEnv->getPTree();
  541. if (!pEnvironmentRoot)
  542. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get environment information.");
  543. BoolHash uniqueProcesses;
  544. for (unsigned index=0; index<ordinality; index++)
  545. {
  546. StringBuffer clusterType;
  547. const char* clusterName = targetClusters.item(index);
  548. const char* pClusterName = strchr(clusterName, ':');
  549. if (pClusterName)
  550. {
  551. clusterType.append(clusterName, 0, pClusterName - clusterName);
  552. pClusterName++;
  553. }
  554. if (!pClusterName || !*pClusterName)
  555. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Cluster name not specified.");
  556. if (clusterType.length() < 1)
  557. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Cluster type not specified.");
  558. StringBuffer path;
  559. path.appendf("Software/Topology/Cluster[@name='%s']", pClusterName);
  560. IPropertyTree* pCluster = pEnvironmentRoot->queryPropTree(path.str());
  561. if (!pCluster)
  562. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Cluster %s not found in environment setting.", pClusterName);
  563. Owned<IPropertyTreeIterator> clusterProcesses;
  564. if (strieq(clusterType.str(), eqThorCluster) || strieq(clusterType.str(), eqRoxieCluster))
  565. {
  566. clusterProcesses.setown(pCluster->getElements(clusterType.str()));
  567. if (!clusterProcesses->first())
  568. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Cluster %s not found in environment setting.", clusterType.str());
  569. }
  570. Owned<IPropertyTreeIterator> eclCCServerProcesses= pCluster->getElements(eqEclCCServer);
  571. Owned<IPropertyTreeIterator> eclServerProcesses= pCluster->getElements(eqEclServer);
  572. Owned<IPropertyTreeIterator> eclAgentProcesses= pCluster->getElements(eqEclAgent);
  573. Owned<IPropertyTreeIterator> eclSchedulerProcesses= pCluster->getElements(eqEclScheduler);
  574. IPropertyTree *targetClusterOut = targetClustersOut->addPropTree("TargetCluster", createPTree("TargetCluster"));
  575. targetClusterOut->setProp("@Name", pClusterName);
  576. targetClusterOut->setProp("@Type", clusterType.str());
  577. //Read Cluster processes
  578. if (clusterProcesses && clusterProcesses->first())
  579. ForEach(*clusterProcesses)
  580. readTargetClusterProcesses(context, clusterProcesses->query(), clusterType.str(), uniqueProcesses, machineInfoData, targetClusterOut);
  581. //Read eclCCServer process
  582. if (eclCCServerProcesses->first())
  583. readTargetClusterProcesses(context, eclCCServerProcesses->query(), eqEclCCServer, uniqueProcesses, machineInfoData, targetClusterOut);
  584. //Read eclServer process
  585. if (eclServerProcesses->first())
  586. readTargetClusterProcesses(context, eclServerProcesses->query(), eqEclServer, uniqueProcesses, machineInfoData, targetClusterOut);
  587. //Read eclAgent process
  588. if (eclAgentProcesses->first())
  589. readTargetClusterProcesses(context, eclAgentProcesses->query(), eqEclAgent, uniqueProcesses, machineInfoData, targetClusterOut);
  590. //Read eclScheduler process
  591. if (eclSchedulerProcesses->first())
  592. readTargetClusterProcesses(context, eclSchedulerProcesses->query(), eqEclScheduler, uniqueProcesses, machineInfoData, targetClusterOut);
  593. }
  594. }
  595. //Collect settings for one group of target cluster processes
  596. void Cws_machineEx::readTargetClusterProcesses(IEspContext& context, IPropertyTree &processNode, const char* nodeType, BoolHash& uniqueProcesses, CGetMachineInfoData& machineInfoData,
  597. IPropertyTree* targetClustersOut)
  598. {
  599. const char* process = processNode.queryProp("@process");
  600. if (!process || !*process)
  601. throw MakeStringException(ECLWATCH_INTERNAL_ERROR, "Process attribute not set for ECLCCServer in environment setting.");
  602. Owned<IConstEnvironment> constEnv = getConstEnvironment();
  603. Owned<IPropertyTree> pEnvironmentRoot = &constEnv->getPTree();
  604. if (!pEnvironmentRoot)
  605. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get environment information.");
  606. IPropertyTree* pEnvironmentSoftware = pEnvironmentRoot->queryPropTree("Software");
  607. if (!pEnvironmentSoftware)
  608. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get environment information.");
  609. double version = context.getClientVersion();
  610. IPropertyTree* pClusterProcess = NULL;
  611. if (strieq(nodeType, eqThorCluster) || strieq(nodeType, eqRoxieCluster))
  612. {
  613. StringBuffer path;
  614. path.appendf("Software/%s[@name='%s']", nodeType, process);
  615. pClusterProcess = pEnvironmentRoot->queryPropTree(path.str());
  616. if (!pClusterProcess)
  617. throw MakeStringException(ECLWATCH_INTERNAL_ERROR, "Process not set for %s in environment setting.", path.str());
  618. if (strieq(nodeType, eqRoxieCluster))
  619. machineInfoData.appendRoxieClusters(process);
  620. }
  621. IPropertyTree *pInfo = targetClustersOut->addPropTree("Process", createPTree("Process"));
  622. pInfo->setProp("@Name", process);
  623. pInfo->setProp("@Type", nodeType);
  624. StringBuffer dirStr;
  625. IPropertyTree* pEnvironmentDirectories = pEnvironmentSoftware->queryPropTree("Directories");
  626. if (!pClusterProcess)
  627. {
  628. if (!pEnvironmentDirectories || !getConfigurationDirectory(pEnvironmentDirectories, "run", nodeType, process, dirStr))
  629. dirStr.clear().append(processNode.queryProp("@directory"));
  630. getProcesses(constEnv, pEnvironmentSoftware, process, nodeType, dirStr.str(), machineInfoData, false, uniqueProcesses);
  631. return;
  632. }
  633. if (!pEnvironmentDirectories || !getConfigurationDirectory(pEnvironmentDirectories, "run", nodeType, process, dirStr))
  634. dirStr.clear().append(pClusterProcess->queryProp("@directory"));
  635. if (strieq(nodeType, eqThorCluster))
  636. {
  637. getProcesses(constEnv, pClusterProcess, process, eqThorMasterProcess, dirStr.str(), machineInfoData, true, uniqueProcesses);
  638. getThorProcesses(constEnv, pClusterProcess, process, eqThorSlaveProcess, dirStr.str(), machineInfoData, uniqueProcesses);
  639. getThorProcesses(constEnv, pClusterProcess, process, eqThorSpareProcess, dirStr.str(), machineInfoData, uniqueProcesses);
  640. if (version >= 1.16)
  641. addChannels(machineInfoData, pEnvironmentRoot, eqThorSlaveProcess, process);
  642. }
  643. else if (strieq(nodeType, eqRoxieCluster))
  644. {
  645. BoolHash uniqueRoxieProcesses;
  646. getProcesses(constEnv, pClusterProcess, process, eqRoxieServerProcess, dirStr.str(), machineInfoData, true, uniqueProcesses, &uniqueRoxieProcesses);
  647. if (version >= 1.16)
  648. addChannels(machineInfoData, pEnvironmentRoot, eqRoxieServerProcess, process);
  649. }
  650. }
  651. void Cws_machineEx::getThorProcesses(IConstEnvironment* constEnv, IPropertyTree* cluster, const char* processName,
  652. const char* processType, const char* directory, CGetMachineInfoData& machineInfoData, BoolHash& uniqueProcesses)
  653. {
  654. if (!constEnv || !cluster)
  655. return;
  656. Owned<IGroup> nodeGroup;
  657. StringBuffer groupName;
  658. if (strieq(processType, eqThorSlaveProcess))
  659. {
  660. getClusterGroupName(*cluster, groupName);
  661. if (groupName.length() < 1)
  662. {
  663. OWARNLOG("Cannot find group name for %s", processName);
  664. return;
  665. }
  666. nodeGroup.setown(getClusterProcessNodeGroup(processName, eqThorCluster));
  667. }
  668. else
  669. {
  670. getClusterSpareGroupName(*cluster, groupName);
  671. if (groupName.length() < 1)
  672. {
  673. OWARNLOG("Cannot find group name for %s", processName);
  674. return;
  675. }
  676. nodeGroup.setown(queryNamedGroupStore().lookup(groupName.str()));
  677. }
  678. if (!nodeGroup || (nodeGroup->ordinality() == 0))
  679. {
  680. OWARNLOG("Cannot find node group for %s", processName);
  681. return;
  682. }
  683. int slavesPerNode = cluster->getPropInt("@slavesPerNode");
  684. Owned<INodeIterator> gi = nodeGroup->getIterator();
  685. ForEach(*gi)
  686. {
  687. StringBuffer addressRead;
  688. gi->query().endpoint().getIpText(addressRead);
  689. if (addressRead.length() == 0)
  690. {
  691. OWARNLOG("Network address not found for a node in node group %s", groupName.str());
  692. continue;
  693. }
  694. StringBuffer netAddress;
  695. const char* ip = addressRead.str();
  696. if (!streq(ip, "."))
  697. {
  698. netAddress.append(ip);
  699. }
  700. else
  701. {
  702. IpAddress ipaddr = queryHostIP();
  703. ipaddr.getIpText(netAddress);
  704. }
  705. if (netAddress.length() == 0)
  706. {
  707. OWARNLOG("Network address not found for a node in node group %s", groupName.str());
  708. continue;
  709. }
  710. Owned<IConstMachineInfo> pMachineInfo = constEnv->getMachineByAddress(addressRead.str());
  711. if (!pMachineInfo.get())
  712. {
  713. OWARNLOG("Machine not found at network address %s", addressRead.str());
  714. continue;
  715. }
  716. //Each thor slave is a process. The i is used to check whether the process is running or not.
  717. for (unsigned i = 1; i <= slavesPerNode; i++)
  718. setProcessRequest(machineInfoData, uniqueProcesses, netAddress.str(), addressRead.str(),
  719. processType, processName, directory, i);
  720. }
  721. return;
  722. }
  723. void Cws_machineEx::getProcesses(IConstEnvironment* constEnv, IPropertyTree* environment, const char* processName,
  724. const char* processType, const char* directory, CGetMachineInfoData& machineInfoData,
  725. bool isThorOrRoxieProcess, BoolHash& uniqueProcesses, BoolHash* uniqueRoxieProcesses)
  726. {
  727. Owned<IPropertyTreeIterator> processes= environment->getElements(processType);
  728. ForEach(*processes)
  729. {
  730. StringArray processInstances, directories;
  731. IPropertyTree &process = processes->query();
  732. //Thor master and roxie server has been checked before this call.
  733. if (!isThorOrRoxieProcess)
  734. {
  735. const char* name = process.queryProp("@name");
  736. if (!name || !*name || !streq(name, processName))
  737. continue;
  738. }
  739. const char* computerName = process.queryProp("@computer");
  740. if (computerName && *computerName)
  741. appendProcessInstance(computerName, directory, NULL, processInstances, directories);
  742. else
  743. {
  744. Owned<IPropertyTreeIterator> instances= process.getElements("Instance");
  745. ForEach(*instances)
  746. {
  747. IPropertyTree &instance = instances->query();
  748. appendProcessInstance(instance.queryProp("@computer"), directory, instance.queryProp("@directory"), processInstances, directories);
  749. }
  750. }
  751. if (processInstances.length() < 1)
  752. continue;
  753. for (unsigned i = 0; i < processInstances.length(); i++)
  754. {
  755. const char* name0 = processInstances.item(i);
  756. const char* directory0 = directories.item(i);
  757. if (uniqueRoxieProcesses)//to avoid duplicate entries for roxie (one machine has only one roxie process).
  758. {
  759. bool* found = uniqueRoxieProcesses->getValue(name0);
  760. if (found && *found)
  761. continue;
  762. uniqueRoxieProcesses->setValue(name0, true);
  763. }
  764. Owned<IConstMachineInfo> pMachineInfo = constEnv->getMachine(name0);
  765. if (!pMachineInfo.get())
  766. {
  767. OWARNLOG("Machine %s not found in environment setting", name0);
  768. continue;
  769. }
  770. SCMStringBuffer ep;
  771. pMachineInfo->getNetAddress(ep);
  772. const char* ip = ep.str();
  773. if (!ip)
  774. {
  775. OWARNLOG("Network address not found for machine %s", name0);
  776. continue;
  777. }
  778. StringBuffer netAddress;
  779. StringBuffer configNetAddress(ip);
  780. if (!streq(ip, "."))
  781. {
  782. netAddress.set(ip);
  783. }
  784. else
  785. {
  786. IpAddress ipaddr = queryHostIP();
  787. ipaddr.getIpText(netAddress);
  788. }
  789. setProcessRequest(machineInfoData, uniqueProcesses, netAddress.str(), configNetAddress.str(), processType, processName, directory0);
  790. }
  791. }
  792. return;
  793. }
  794. void Cws_machineEx::setupLegacyFilters()
  795. {
  796. unsigned idx = 0;
  797. while (legacyFilterStrings[idx])
  798. {
  799. m_legacyFilters.setValue(legacyFilterStrings[idx], true);
  800. idx++;
  801. }
  802. return;
  803. }
  804. bool Cws_machineEx::isLegacyFilter(const char* processType, const char* dependency)
  805. {
  806. if (!processType || !*processType || !dependency || !*dependency)
  807. return false;
  808. StringBuffer filterString;
  809. filterString.appendf("%s:%s", processType, dependency);
  810. bool* found = m_legacyFilters.getValue(filterString.str());
  811. if (found && *found)
  812. return true;
  813. return false;
  814. }
  815. //The stateHashes stores different state hashes in one roxie cluster.
  816. //It also stores how many roxie nodes have the same state hashes.
  817. unsigned Cws_machineEx::addRoxieStateHash(const char* hash, StateHashes& stateHashes, unsigned& totalUniqueHashes)
  818. {
  819. if (!hash || !*hash)
  820. return -1;
  821. unsigned hashID = 0;
  822. IStateHash* stateHash = stateHashes.getValue(hash);
  823. if (stateHash)
  824. {
  825. //if the stateHashes already has the same 'hash', increases the count for the 'stateHash'.
  826. //The 'StateHash' with the highest count will be the 'Major StateHash'.
  827. //If a roxie node does not contain the 'Major StateHash', it has a 'mismatch' state hash.
  828. hashID = stateHash->queryID();
  829. stateHash->incrementCount();
  830. }
  831. else
  832. {
  833. //Add a new 'StateHash'. Set its hashID to totalUniqueHashes and set its count to 1.
  834. hashID = totalUniqueHashes;
  835. Owned<IStateHash> newStateHash = new CStateHash(hashID, 1);
  836. stateHashes.setValue(hash, newStateHash);
  837. totalUniqueHashes++;
  838. }
  839. return hashID;
  840. }
  841. void Cws_machineEx::updateMajorRoxieStateHash(StateHashes& stateHashes, CIArrayOf<CRoxieStateData>& roxieStates)
  842. {
  843. //Find out which state hash is for the most of the roxie nodes inside this roxie cluster.
  844. unsigned majorHashID = 0;
  845. unsigned majorHashCount = 0;
  846. HashIterator hashes(stateHashes);
  847. ForEach(hashes)
  848. {
  849. IStateHash *hash = stateHashes.mapToValue(&hashes.query());
  850. unsigned hashCount = hash->queryCount();
  851. if (majorHashCount >= hashCount)
  852. continue;
  853. majorHashCount = hashCount;
  854. majorHashID = hash->queryID();
  855. }
  856. //Set the MajorHash to false if the roxie node's HashID() != majorHashID.
  857. ForEachItemIn(ii, roxieStates)
  858. {
  859. CRoxieStateData& roxieState = roxieStates.item(ii);
  860. if (roxieState.getHashID() != majorHashID)
  861. roxieState.setMajorHash(false);
  862. }
  863. }
  864. void Cws_machineEx::readRoxieStatus(const Owned<IPropertyTree> controlResp, CIArrayOf<CRoxieStateData>& roxieStates)
  865. {
  866. StateHashes stateHashes;
  867. unsigned totalUniqueHashes = 0;
  868. Owned<IPropertyTreeIterator> roxieEndpoints = controlResp->getElements("Endpoint");
  869. ForEach(*roxieEndpoints)
  870. {
  871. IPropertyTree& roxieEndpoint = roxieEndpoints->query();
  872. const char *ep = roxieEndpoint.queryProp("@ep");
  873. if (!ep || !*ep)
  874. continue;
  875. bool ok = false, attached = false, detached = false;
  876. const char *status = roxieEndpoint.queryProp("Status");
  877. if (status && strieq(status, "ok"))
  878. ok = true;
  879. const char *stateHash = roxieEndpoint.queryProp("State/@hash");
  880. if (roxieEndpoint.hasProp("Dali/@connected"))
  881. {
  882. if (roxieEndpoint.getPropBool("Dali/@connected"))
  883. attached = true;
  884. else
  885. detached = true;
  886. }
  887. StringArray locations;
  888. locations.appendListUniq(ep, ":");
  889. Owned<CRoxieStateData> roxieState = new CRoxieStateData(locations.item(0), addRoxieStateHash(stateHash, stateHashes, totalUniqueHashes));
  890. roxieState->setState(ok, attached, detached, stateHash);
  891. roxieStates.append(*roxieState.getClear());
  892. }
  893. if (totalUniqueHashes > 1)
  894. updateMajorRoxieStateHash(stateHashes, roxieStates);
  895. }
  896. void Cws_machineEx::getRoxieStateInfo(CRoxieStateInfoThreadParam* param)
  897. {
  898. const char* clusterName = param->clusterName.get();
  899. if (!clusterName || !*clusterName)
  900. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Roxie cluster not specified.");
  901. SocketEndpointArray servers;
  902. getRoxieProcessServers(clusterName, servers);
  903. if (!servers.length())
  904. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Roxie Process server not found.");
  905. Owned<IRoxieCommunicationClient> roxieClient = createRoxieCommunicationClient(servers.item(0), ROXIECONTROLSTATETIMEOUT);
  906. Owned<IPropertyTree> controlResp = roxieClient->sendRoxieControlAllNodes("<control:state/>", true);
  907. if (!controlResp)
  908. throw MakeStringException(ECLWATCH_INTERNAL_ERROR, "Failed to get control response from roxie %s.", clusterName);
  909. CIArrayOf<CRoxieStateData> roxieStates;
  910. readRoxieStatus(controlResp, roxieStates);
  911. ForEachItemIn(i, param->machineInfoTable)
  912. {
  913. IEspMachineInfoEx& machineInfo = param->machineInfoTable.item(i);
  914. if (!streq(machineInfo.getProcessType(), eqRoxieServerProcess) || !streq(machineInfo.getComponentName(), clusterName))
  915. continue;
  916. //This method is thread safe because each machineInfo (for one roxie node) belongs to only one Roxie cluster.
  917. //It is impossible for different threads to update the same machineInfo.
  918. bool foundRoxieState = false;
  919. ForEachItemIn(ii, roxieStates)
  920. {
  921. CRoxieStateData& roxieState = roxieStates.item(ii);
  922. if (!roxieState.matchIPAddress(machineInfo.getAddress()))
  923. continue;
  924. StringBuffer state, stateDetails;
  925. roxieState.reportState(state, stateDetails);
  926. machineInfo.setRoxieState(state.str());
  927. machineInfo.setRoxieStateDetails(stateDetails.str());
  928. foundRoxieState = true;
  929. }
  930. if (!foundRoxieState)
  931. {
  932. machineInfo.setRoxieState("??");
  933. machineInfo.setRoxieStateDetails("Roxie state not found");
  934. }
  935. }
  936. }
  937. void Cws_machineEx::getMachineInfo(IEspContext& context, bool getRoxieState, CGetMachineInfoData& machineInfoData)
  938. {
  939. UnsignedArray threadHandles;
  940. if (!getRoxieState)
  941. {
  942. CIArrayOf<CMachineData>& machines = machineInfoData.getMachineData();
  943. ForEachItemIn(idx, machines)
  944. {
  945. Owned<CMachineInfoThreadParam> pThreadReq = new CMachineInfoThreadParam(this, context, machineInfoData.getOptions(),
  946. machines.item(idx), machineInfoData.getMachineInfoTable(), machineInfoData.getMachineInfoColumns(),
  947. machineInfoData.getChannelsMap());
  948. PooledThreadHandle handle = m_threadPool->start( pThreadReq.getClear());
  949. threadHandles.append(handle);
  950. }
  951. }
  952. else
  953. {
  954. StringArray& roxieClusters = machineInfoData.getRoxieClusters();
  955. ForEachItemIn(i, roxieClusters)
  956. {
  957. Owned<CRoxieStateInfoThreadParam> pThreadReq = new CRoxieStateInfoThreadParam(this, roxieClusters.item(i),
  958. machineInfoData.getMachineInfoTable(), machineInfoData.getChannelsMap());
  959. PooledThreadHandle handle = m_threadPool->start( pThreadReq.getClear());
  960. threadHandles.append(handle);
  961. }
  962. machineInfoData.getMachineInfoColumns().append("Roxie State");
  963. }
  964. //Block for worker threads to finish, if necessary and then collect results
  965. //Not use joinAll() because multiple threads may call this method. Each call uses the pool to create
  966. //its own threads of checking query state. Each call should only join the ones created by that call.
  967. ForEachItemIn(i, threadHandles)
  968. m_threadPool->join(threadHandles.item(i));
  969. }
  970. ////////////////////////////////////////////////////////////////////
  971. // Get Machine Information based on Machine Information request //
  972. ////////////////////////////////////////////////////////////////////
  973. void Cws_machineEx::getMachineInfo(IEspContext& context, CGetMachineInfoData& machineInfoData)
  974. {
  975. double version = context.getClientVersion();
  976. getMachineInfo(context, false, machineInfoData);
  977. if ((version >= 1.13) && !machineInfoData.getRoxieClusters().empty())
  978. getMachineInfo(context, true, machineInfoData);
  979. }
  980. // the following method is invoked on worker threads of CMachineInfoThreadParam
  981. void Cws_machineEx::doGetMachineInfo(IEspContext& context, CMachineInfoThreadParam* pParam)
  982. {
  983. #ifdef DETECT_WS_MC_MEM_LEAKS
  984. static bool firstTime = true;
  985. if (firstTime)
  986. {
  987. firstTime = false;
  988. unsigned t = setAllocHook(true);
  989. }
  990. #endif //DETECT_WS_MC_MEM_LEAKS
  991. int error = 0;
  992. StringBuffer preflightCommand, response;
  993. buildPreflightCommand(context, pParam, preflightCommand);
  994. if (preflightCommand.length() < 1)
  995. {
  996. response.append("Failed in creating Machine Information command.\n");
  997. error = -1;
  998. }
  999. else
  1000. {
  1001. 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);
  1002. if ((error == 0) && (response.length() > 0))
  1003. readPreflightResponse(context, pParam, response.str(), error);
  1004. }
  1005. //Set IArrayOf<IEspMachineInfoEx> based on Preflight Response
  1006. setMachineInfo(context, pParam, response.str(), error);
  1007. #ifdef DETECT_WS_MC_MEM_LEAKS
  1008. DBGLOG("Allocated=%d", setAllocHook(false));
  1009. #endif //DETECT_WS_MC_MEM_LEAKS
  1010. }
  1011. void Cws_machineEx::buildPreflightCommand(IEspContext& context, CMachineInfoThreadParam* pParam, StringBuffer& preflightCommand)
  1012. {
  1013. preflightCommand.clear().appendf("/%s/sbin/%s -p=%s", environmentConfData.m_executionPath.str(),
  1014. m_machineInfoFile.str(), environmentConfData.m_pidPath.str());
  1015. if (preflightCommand.charAt(preflightCommand.length() - 1) == pParam->m_machineData.getPathSep())
  1016. preflightCommand.remove(preflightCommand.length()-1, 1);
  1017. bool checkDependency = false;
  1018. CIArrayOf<CProcessData>& processes = pParam->m_machineData.getProcesses();
  1019. ForEachItemIn(idx, processes)
  1020. {
  1021. CProcessData& process = processes.item(idx);
  1022. if (!process.getName() || !*process.getName())
  1023. continue;
  1024. StringBuffer procName;
  1025. if (streq(process.getType(), eqThorSlaveProcess))
  1026. procName.appendf("thorslave_%s_%d,%s_slave_%d", process.getName(), process.getProcessNumber(), process.getName(), process.getProcessNumber());
  1027. else if (streq(process.getType(), eqThorMasterProcess))
  1028. procName.appendf("%s,%s_master", process.getName(), process.getName());
  1029. else
  1030. procName.append(process.getName());
  1031. if (idx < 1)
  1032. preflightCommand.appendf(" -n=%s", procName.str());
  1033. else
  1034. preflightCommand.appendf(",%s", procName.str());
  1035. if (!process.getDependencies().empty())
  1036. checkDependency = true;
  1037. }
  1038. if (checkDependency || !pParam->m_options.getApplyProcessFilter())
  1039. preflightCommand.append(" -d=ALL");
  1040. if (pParam->m_options.getGetStorageInfo() && !pParam->m_options.getLocalFileSystemsOnly())
  1041. preflightCommand.append(" -m=YES");
  1042. }
  1043. int Cws_machineEx::runCommand(IEspContext& context, const char* sAddress, const char* sConfigAddress, EnvMachineOS os,
  1044. const char* sCommand, const char* sUserId, const char* sPassword, StringBuffer& response)
  1045. {
  1046. int exitCode = -1;
  1047. try
  1048. {
  1049. StringBuffer command(sCommand);
  1050. StringBuffer userId;
  1051. StringBuffer password;
  1052. bool bLinux;
  1053. if (sConfigAddress && *sConfigAddress)
  1054. getAccountAndPlatformInfo(sConfigAddress, userId, password, bLinux);
  1055. else
  1056. getAccountAndPlatformInfo(sAddress, userId, password, bLinux);
  1057. if (!sUserId || !*sUserId || !sPassword ||!*sPassword)
  1058. {
  1059. //BUG: 9825 - remote execution on linux needs to use individual accounts
  1060. //use userid/password in ESP context for remote execution...
  1061. if (bLinux)
  1062. {
  1063. userId.clear();
  1064. password.clear();
  1065. context.getUserID(userId);
  1066. context.getPassword(password);
  1067. }
  1068. }
  1069. else
  1070. {
  1071. userId.clear().append(sUserId);
  1072. password.clear().append(sPassword);
  1073. }
  1074. // make sure there actually is something in command before we run a remote connection
  1075. if (command.length() < 1)
  1076. return exitCode;
  1077. Owned<IFRunSSH> connection = createFRunSSH();
  1078. connection->init(command.str(),NULL,NULL,NULL,m_SSHConnectTimeoutSeconds,0);
  1079. // executed as single connection
  1080. connection->exec(IpAddress(sAddress),NULL,false);
  1081. response.append(connection->getReplyText()[0]);
  1082. exitCode = connection->getReply()[0];
  1083. int len = response.length();
  1084. if (len > 0 && response.charAt(--len) == '\n') // strip newline
  1085. response.setLength(len);
  1086. if (response.length() && !exitCode)
  1087. response.insert(0, "Response: ");
  1088. else if (!exitCode)
  1089. response.insert(0, "No response recieved.\n");
  1090. }
  1091. // CFRunSSH uses a MakeStringExceptionDirect throw to pass code and result string
  1092. catch(IException* e)
  1093. {
  1094. exitCode = e->errorCode();
  1095. // errorCode == -1 on successful CFRunSSH execution
  1096. if(exitCode == -1)
  1097. exitCode = 0;
  1098. StringBuffer buf;
  1099. e->errorMessage(buf);
  1100. response.append(buf.str());
  1101. int len = response.length();
  1102. if (len > 0 && response.charAt(--len) == '\n') // strip newline
  1103. response.setLength(len);
  1104. // on successful connection
  1105. if (response.length() && !exitCode)
  1106. response.insert(0,"Response: ");
  1107. else if (!exitCode)
  1108. response.insert(0, "No response recieved.\n");
  1109. e->Release();
  1110. }
  1111. #ifndef NO_CATCHALL
  1112. catch(...)
  1113. {
  1114. response.append("An unknown exception occurred!");
  1115. exitCode = -1;
  1116. }
  1117. #endif
  1118. return exitCode;
  1119. }
  1120. int Cws_machineEx::invokeProgram(const char *command_line, StringBuffer& response)
  1121. {
  1122. char buffer[128];
  1123. FILE *fp;
  1124. // Run the command so that it writes its output to a pipe. Open this
  1125. // pipe with read text attribute so that we can read it
  1126. // like a text file.
  1127. if (getEspLogLevel()>LogNormal)
  1128. {
  1129. DBGLOG("command_line=<%s>", command_line);
  1130. }
  1131. #ifndef NO_CONNECTION_DEBUG
  1132. if( (fp = popen( command_line, "r" )) == NULL )
  1133. return -1;
  1134. #else
  1135. if( (fp = fopen( "c:\\temp\\preflight_result.txt", "r" )) == NULL )
  1136. return -1;
  1137. #endif
  1138. // Read pipe until end of file. End of file indicates that
  1139. //the stream closed its standard out (probably meaning it
  1140. //terminated).
  1141. while ( !feof(fp) )
  1142. if ( fgets( buffer, 128, fp) )
  1143. response.append( buffer );
  1144. if (getEspLogLevel()>LogNormal)
  1145. {
  1146. DBGLOG("response=<%s>", response.str());
  1147. }
  1148. // Close pipe and print return value of CHKDSK.
  1149. #ifndef NO_CONNECTION_DEBUG
  1150. return pclose( fp );
  1151. #else
  1152. return fclose( fp );
  1153. #endif
  1154. }
  1155. void Cws_machineEx::readPreflightResponse(IEspContext& context, CMachineInfoThreadParam* pParam, const char* response, int error)
  1156. {
  1157. if (!response || !*response)
  1158. return;
  1159. StringBuffer computerUpTime;
  1160. readALineFromResult(response, "ComputerUpTime:", computerUpTime, true);
  1161. if (computerUpTime.length() < 1)
  1162. computerUpTime.append("-");
  1163. else
  1164. {
  1165. const char* pStr = strchr(computerUpTime.str(), ' ');
  1166. if (pStr)
  1167. {
  1168. pStr++;
  1169. pStr = strchr(pStr, ' ');
  1170. if (pStr)
  1171. {
  1172. pStr++;
  1173. if (pStr)
  1174. pParam->m_machineData.setComputerUpTime(pStr);
  1175. }
  1176. }
  1177. if (!pStr)
  1178. pParam->m_machineData.setComputerUpTime(computerUpTime);
  1179. }
  1180. if (pParam->m_options.getGetProcessorInfo())
  1181. {
  1182. StringBuffer CPUIdle;
  1183. readALineFromResult(response, "CPU-Idle:", CPUIdle, true);
  1184. if (CPUIdle.length() < 1)
  1185. pParam->m_machineData.setCPULoad(0);
  1186. else
  1187. {
  1188. if (CPUIdle.charAt(CPUIdle.length() - 1) == '%')
  1189. CPUIdle.setLength(CPUIdle.length() - 1);
  1190. pParam->m_machineData.setCPULoad(100-atoi(CPUIdle.str()));
  1191. }
  1192. }
  1193. if (pParam->m_options.getGetStorageInfo())
  1194. readStorageData(response, pParam);
  1195. if (pParam->m_options.getGetSoftwareInfo())
  1196. readProcessData(response, pParam);
  1197. }
  1198. void Cws_machineEx::readALineFromResult(const char *result, const char *start, StringBuffer& value, bool trim)
  1199. {
  1200. if (!result || !*result)
  1201. return;
  1202. const char* pStr = strstr(result, start);
  1203. if (!pStr)
  1204. return;
  1205. pStr += strlen(start);
  1206. if (!pStr)
  1207. return;
  1208. const char* pStr1 = strchr(pStr, 0x0a);
  1209. if (pStr1)
  1210. value.append(pStr, 0, pStr1 - pStr);
  1211. else
  1212. value.append(pStr);
  1213. if (trim)
  1214. value.trim();
  1215. }
  1216. void Cws_machineEx::readStorageData(const char* response, CMachineInfoThreadParam* pParam)
  1217. {
  1218. if (!response || !*response)
  1219. return;
  1220. const char* pStr = strstr(response, "---SpaceUsedAndFree---");
  1221. if (!pStr)
  1222. DBGLOG("Storage information not found on %s", pParam->m_machineData.getNetworkAddress());
  1223. bool isTitleLine = true;
  1224. CIArrayOf<CStorageData>& storage = pParam->m_machineData.getStorage();
  1225. while (pStr)
  1226. {
  1227. StringBuffer buf;
  1228. const char* pStr1 = strchr(pStr, 0x0a);
  1229. if (pStr1)
  1230. {
  1231. buf.append(pStr, 0, pStr1 - pStr);
  1232. pStr = pStr1+1;
  1233. }
  1234. else
  1235. {
  1236. buf.append(pStr);
  1237. pStr = NULL;
  1238. }
  1239. if (isTitleLine)
  1240. {
  1241. isTitleLine = false;
  1242. continue;
  1243. }
  1244. if (buf.length() > 0)
  1245. {
  1246. StringBuffer diskSpaceTitle;
  1247. int diskSpacePercentAvail = 0;
  1248. __int64 diskSpaceAvailable = 0, diskSpaceTotal = 0;
  1249. if (!readStorageSpace(buf.str(), diskSpaceTitle, diskSpaceAvailable, diskSpaceTotal, diskSpacePercentAvail))
  1250. DBGLOG("Invalid storage information on %s: %s", pParam->m_machineData.getNetworkAddress(), buf.str());
  1251. else if ((diskSpaceTitle.length() > 0) && !excludePartition(diskSpaceTitle.str()))
  1252. {
  1253. Owned<CStorageData> diskData = new CStorageData(diskSpaceTitle, diskSpaceAvailable, diskSpaceTotal, diskSpacePercentAvail);
  1254. storage.append(*diskData.getClear());
  1255. }
  1256. }
  1257. if (!pStr || (strnicmp(pStr, "---ProcessList1---", 18)==0))
  1258. break;
  1259. }
  1260. }
  1261. bool Cws_machineEx::readStorageSpace(const char *line, StringBuffer& title, __int64& free, __int64& total, int& percentAvail)
  1262. {
  1263. if (!line || !*line)
  1264. return false;
  1265. StringBuffer freeStr, usedStr;
  1266. const char* pStr = line;
  1267. const char* pStr1 = strchr(pStr, ':');
  1268. if (!pStr1)
  1269. return false;
  1270. title.clear().append(pStr, 0, pStr1 - pStr);
  1271. pStr = pStr1 + 2;
  1272. pStr1 = (char*) strchr(pStr, ' ');
  1273. if (!pStr1)
  1274. return false;
  1275. usedStr.append(pStr, 0, pStr1 - pStr);
  1276. pStr = pStr1 + 1;
  1277. if (!pStr)
  1278. return false;
  1279. freeStr.append(pStr);
  1280. __int64 factor1 = 1;
  1281. if (freeStr.length() > 9)
  1282. {
  1283. freeStr.setLength(freeStr.length()-6);
  1284. factor1 = 1000000;
  1285. }
  1286. free = atol(freeStr.str())*factor1;
  1287. __int64 factor2 = 1;
  1288. if (usedStr.length() > 9)
  1289. {
  1290. usedStr.setLength(usedStr.length()-6);
  1291. factor2 = 1000000;
  1292. }
  1293. __int64 used = atol(usedStr.str())*factor2;
  1294. total = free + used;
  1295. if (total > 0)
  1296. percentAvail = (int) ((free*100)/total);
  1297. free = (__int64) free /1000; //MByte
  1298. total = (__int64) total /1000; //MByte
  1299. return true;
  1300. }
  1301. void Cws_machineEx::buildProcessPath(StringBuffer &processPath, const char * processName, CMachineInfoThreadParam * pParam)
  1302. {
  1303. if (environmentConfData.m_pidPath.charAt(environmentConfData.m_pidPath.length() - 1) != pParam->m_machineData.getPathSep())
  1304. processPath.setf("%s%c%s:", environmentConfData.m_pidPath.str(), pParam->m_machineData.getPathSep(), processName);
  1305. else
  1306. processPath.setf("%s%s:", environmentConfData.m_pidPath.str(), processName);
  1307. }
  1308. void Cws_machineEx::readProcessData(const char* response, CMachineInfoThreadParam* pParam)
  1309. {
  1310. if (!response || !*response)
  1311. return;
  1312. CIArrayOf<CProcessData>& processes = pParam->m_machineData.getProcesses();
  1313. ForEachItemIn(idx, processes)
  1314. {
  1315. CProcessData& process = processes.item(idx);
  1316. if (!process.getName() || !*process.getName())
  1317. continue;
  1318. StringBuffer procName, catError, processPath, processData;
  1319. if (streq(process.getType(), eqThorSlaveProcess))
  1320. {
  1321. procName.appendf("thorslave_%s_%d", process.getName(), process.getProcessNumber());
  1322. buildProcessPath(processPath,procName.str(),pParam);
  1323. catError.setf("cat: %s",processPath.str());
  1324. catError.insert(catError.length()-1,".pid");
  1325. if (!strstr(response,catError.str()))
  1326. readALineFromResult(response, processPath.str(), processData, true);
  1327. else
  1328. {
  1329. procName.setf("%s_slave_%d", process.getName(), process.getProcessNumber());
  1330. buildProcessPath(processPath,procName.str(),pParam);
  1331. readALineFromResult(response, processPath.str(), processData, true);
  1332. }
  1333. }
  1334. else if (streq(process.getType(), eqThorMasterProcess))
  1335. {
  1336. procName.appendf("%s", process.getName());
  1337. buildProcessPath(processPath,procName.str(),pParam);
  1338. catError.setf("cat: %s",processPath.str());
  1339. catError.insert(catError.length()-1,".pid");
  1340. if (!strstr(response,catError.str()))
  1341. readALineFromResult(response, processPath.str(), processData, true);
  1342. else
  1343. {
  1344. procName.setf("%s_master", process.getName());
  1345. buildProcessPath(processPath,procName.str(),pParam);
  1346. readALineFromResult(response, processPath.str(), processData, true);
  1347. }
  1348. }
  1349. else
  1350. {
  1351. procName.append(process.getName());
  1352. buildProcessPath(processPath,procName.str(),pParam);
  1353. readALineFromResult(response, processPath.str(), processData, true);
  1354. }
  1355. if (processData.length() < 1)
  1356. {
  1357. DBGLOG("Information for process %s not found", processPath.str());
  1358. continue;
  1359. }
  1360. const char* pStr = strchr(processData.str(), ' ');
  1361. if (!pStr)
  1362. {
  1363. DBGLOG("incorrect data for process %s: %s", processPath.str(), processData.str());
  1364. continue;
  1365. }
  1366. unsigned len = pStr - processData.str();
  1367. StringBuffer pid, upTime;
  1368. pid.append(processData.str(), 0, len);
  1369. len++;
  1370. upTime.append(processData.str(), len, processData.length() - len);
  1371. upTime.replaceString("-", " day(s) ");
  1372. process.setPID(pid.str());
  1373. process.setUpTime(upTime.str());
  1374. }
  1375. readRunningProcesses(response, pParam);
  1376. }
  1377. void Cws_machineEx::readRunningProcesses(const char* response, CMachineInfoThreadParam* pParam)
  1378. {
  1379. if (!response || !*response)
  1380. return;
  1381. const char* pStr = strstr(response, "---ProcessList2---");
  1382. if (!pStr)
  1383. DBGLOG("Running process not found on %s", pParam->m_machineData.getNetworkAddress());
  1384. IArrayOf<IEspProcessInfo>& runningProcesses = pParam->m_machineData.getRunningProcesses();
  1385. while (pStr)
  1386. {
  1387. //read a line
  1388. StringBuffer lineStr;
  1389. const char* pStr1 = strchr(pStr, 0x0a);
  1390. if (!pStr1)
  1391. {
  1392. lineStr.append(pStr);
  1393. pStr = NULL;
  1394. }
  1395. else
  1396. {
  1397. lineStr.append(pStr, 0, pStr1 - pStr);
  1398. pStr = pStr1+1;
  1399. }
  1400. if (lineStr.length() < 1)
  1401. continue;
  1402. StringBuffer pidStr, desc, param;
  1403. pStr1 = lineStr.str();
  1404. const char* pStr2 = strchr(pStr1, ' ');
  1405. if (!pStr2)
  1406. continue;
  1407. pidStr.append(pStr1, 0, pStr2 - pStr1);
  1408. param.append(pStr2+1);
  1409. if (param.length() < 1)
  1410. continue;
  1411. if (streq(param.str(), "ps"))
  1412. continue;
  1413. bool isNumber = true;
  1414. for (unsigned i = 0; i < pidStr.length(); i++)
  1415. {
  1416. if (!isdigit(pidStr.charAt(i)))
  1417. {
  1418. isNumber = false;
  1419. break;
  1420. }
  1421. }
  1422. if (!isNumber)
  1423. continue;
  1424. int pid = atoi(pidStr.str());
  1425. desc = param;
  1426. if ((desc.charAt(0) == '.') && (param.charAt(1) == '/'))
  1427. desc.remove(0, 2);
  1428. if (desc.charAt(desc.length() - 1) == '/')
  1429. desc.remove(desc.length() - 1, 1);
  1430. if (desc.charAt(0) == '[')
  1431. {
  1432. desc.remove(0, 1);
  1433. if (desc.charAt(desc.length() - 1) == ']')
  1434. desc.remove(desc.length() - 1, 1);
  1435. }
  1436. Owned<IEspProcessInfo> info = createProcessInfo("","");
  1437. info->setPID(pid);
  1438. info->setParameter(param.str());
  1439. info->setDescription(desc.str());
  1440. runningProcesses.append(*info.getClear());
  1441. }
  1442. }
  1443. void Cws_machineEx::setMachineInfo(IEspContext& context, CMachineInfoThreadParam* pParam, const char* response, int error)
  1444. {
  1445. //Read additionalProcessFilters which will be used in setProcessInfo()/setProcessComponent()
  1446. set<string>& additionalProcesses = pParam->m_machineData.getAdditinalProcessFilters();
  1447. StringArray& additionalProcessFilters = pParam->m_options.getAdditionalProcessFilters();
  1448. if (pParam->m_options.getApplyProcessFilter() && !additionalProcessFilters.empty())
  1449. {
  1450. int len = additionalProcessFilters.length();
  1451. for (int i=0; i<len; i++)
  1452. {
  1453. StringBuffer processName(additionalProcessFilters.item(i));
  1454. processName.toLowerCase().replaceString(".exe", "");
  1455. if (processName.length() > 0)
  1456. additionalProcesses.insert(processName.str());
  1457. }
  1458. }
  1459. CIArrayOf<CProcessData>& processes = pParam->m_machineData.getProcesses();
  1460. ForEachItemIn(idx, processes)
  1461. {
  1462. CProcessData& process = processes.item(idx);
  1463. Owned<IEspMachineInfoEx> pMachineInfo = static_cast<IEspMachineInfoEx*>(new CMachineInfoEx(""));
  1464. setProcessInfo(context, pParam, response, error, process, idx<1, pMachineInfo);
  1465. synchronized block(mutex_machine_info_table);
  1466. pParam->m_machineInfoTable.append(*pMachineInfo.getLink());
  1467. }
  1468. }
  1469. void Cws_machineEx::setProcessInfo(IEspContext& context, CMachineInfoThreadParam* pParam, const char* response,
  1470. int error, CProcessData& process, bool firstProcess, IEspMachineInfoEx* pMachineInfo)
  1471. {
  1472. double version = context.getClientVersion();
  1473. bool isEclAgentProcess = process.getType() && strieq(process.getType(), eqEclAgent);
  1474. pMachineInfo->setAddress(pParam->m_machineData.getNetworkAddress());
  1475. pMachineInfo->setConfigAddress(pParam->m_machineData.getNetworkAddressInEnvSetting());
  1476. pMachineInfo->setOS(pParam->m_machineData.getOS());
  1477. if (process.getName() && *process.getName())
  1478. pMachineInfo->setComponentName(process.getName());
  1479. if (process.getPath() && *process.getPath())
  1480. pMachineInfo->setComponentPath(process.getPath());
  1481. //set DisplayType
  1482. if (process.getType() && *process.getType())
  1483. {
  1484. if (isEclAgentProcess)
  1485. {
  1486. pMachineInfo->setProcessType(eqAgentExec);
  1487. pMachineInfo->setDisplayType("Agent Exec");
  1488. }
  1489. else
  1490. {
  1491. pMachineInfo->setProcessType(process.getType());
  1492. StringBuffer displayName;
  1493. getProcessDisplayName(process.getType(), displayName);
  1494. pMachineInfo->setDisplayType(displayName.str());
  1495. }
  1496. }
  1497. else if (process.getName() && *process.getName())
  1498. {
  1499. pMachineInfo->setDisplayType(process.getName());
  1500. }
  1501. if ((version > 1.09) && process.getType() && strieq(process.getType(), eqThorSlaveProcess))
  1502. {
  1503. pMachineInfo->setProcessNumber(process.getProcessNumber());
  1504. }
  1505. if ((version >= 1.16) && (strieq(process.getType(), eqThorSlaveProcess) || strieq(process.getType(), eqRoxieServerProcess)))
  1506. {
  1507. VStringBuffer key("%s|%s", process.getType(), process.getName());
  1508. int* channels = pParam->getChannels(key);
  1509. if (channels)
  1510. pMachineInfo->setChannels(*channels);
  1511. }
  1512. if (error != 0 || !response || !*response)
  1513. {
  1514. StringBuffer description;
  1515. if (!response || !*response)
  1516. description.append("Failed in getting Machine Information");
  1517. else
  1518. description = response;
  1519. if (version < 1.17)
  1520. pMachineInfo->setDescription(description.str());
  1521. else
  1522. pMachineInfo->setException(description.str());
  1523. }
  1524. else
  1525. {
  1526. //Now, add more columns based on 'response'
  1527. pMachineInfo->setUpTime(pParam->m_machineData.getComputerUpTime());
  1528. pParam->addColumn("Up Time");
  1529. if (pParam->m_options.getGetStorageInfo())
  1530. {
  1531. IArrayOf<IEspStorageInfo> storageArray;
  1532. CIArrayOf<CStorageData>& storage = pParam->m_machineData.getStorage();
  1533. ForEachItemIn(idx, storage)
  1534. {
  1535. CStorageData& diskData = storage.item(idx);
  1536. Owned<IEspStorageInfo> info = static_cast<IEspStorageInfo*>(new CStorageInfo(""));
  1537. info->setDescription(diskData.getDiskSpaceTitle());
  1538. info->setTotal(diskData.getDiskSpaceTotal());
  1539. info->setAvailable(diskData.getDiskSpaceAvailable());
  1540. info->setPercentAvail(diskData.getDiskSpacePercentAvail());
  1541. storageArray.append(*info.getLink());
  1542. pParam->addColumn(diskData.getDiskSpaceTitle());
  1543. }
  1544. pMachineInfo->setStorage(storageArray);
  1545. storageArray.kill();
  1546. }
  1547. if (pParam->m_options.getGetProcessorInfo())
  1548. {
  1549. IArrayOf<IEspProcessorInfo> processorArray;
  1550. Owned<IEspProcessorInfo> info = static_cast<IEspProcessorInfo*>(new CProcessorInfo(""));
  1551. info->setLoad(pParam->m_machineData.getCPULoad());
  1552. processorArray.append(*info.getLink());
  1553. pMachineInfo->setProcessors(processorArray);
  1554. processorArray.kill();
  1555. pParam->addColumn("CPU Load");
  1556. }
  1557. if (pParam->m_options.getGetSoftwareInfo())
  1558. {
  1559. IArrayOf<IEspSWRunInfo> processArray;
  1560. IEspComponentInfo* pComponentInfo = &pMachineInfo->updateComponentInfo();
  1561. setProcessComponent(context, pParam, process, firstProcess, processArray, pComponentInfo);
  1562. if (processArray.ordinality())
  1563. {
  1564. //Set running processes if ApplyProcessFilter is set to false
  1565. //Set processes not running if ApplyProcessFilter is set to true
  1566. pMachineInfo->setRunning(processArray);
  1567. }
  1568. pParam->addColumn("Processes");
  1569. pParam->addColumn("Condition");
  1570. pParam->addColumn("State");
  1571. pParam->addColumn("UpTime");
  1572. }
  1573. }
  1574. }
  1575. void Cws_machineEx::setProcessComponent(IEspContext& context, CMachineInfoThreadParam* pParam, CProcessData& process,
  1576. bool firstProcess, IArrayOf<IEspSWRunInfo>& processArray, IEspComponentInfo* pComponentInfo)
  1577. {
  1578. const char* procType = process.getType();
  1579. const char* procPID = process.getPID();
  1580. //If a component (ex. dropzone) has no process type, it is not a process and does not have a PID.
  1581. //FTSlaveProcess may not have a PID since it is launched dynamically during a spray.
  1582. if (pParam->m_options.getApplyProcessFilter() && (isEmptyString(procPID) &&
  1583. !isEmptyString(procType) && !strieq(procType, "FTSlaveProcess")))
  1584. {
  1585. Owned<IEspSWRunInfo> info = static_cast<IEspSWRunInfo*>(new CSWRunInfo(""));
  1586. info->setName(process.getName());
  1587. info->setInstances(0);
  1588. processArray.append( *info.getLink() );
  1589. }
  1590. set<string>& additionalProcesses = pParam->m_machineData.getAdditinalProcessFilters();
  1591. map<string, Linked<IEspSWRunInfo> > runningProcessMap; //save only one description of each process
  1592. set<string>& dependencies = process.getDependencies();
  1593. IArrayOf<IEspProcessInfo>& runningProcesses = pParam->m_machineData.getRunningProcesses();
  1594. if (runningProcesses.length() > 0)
  1595. {
  1596. if (!pParam->m_options.getApplyProcessFilter()) //need to display all of the running processes
  1597. enumerateRunningProcesses( pParam, process, &runningProcessMap, firstProcess);
  1598. else if (!dependencies.empty() || !additionalProcesses.empty())
  1599. enumerateRunningProcesses(pParam, process, NULL, firstProcess);
  1600. }
  1601. map<string, Linked<IEspSWRunInfo> >::const_iterator it = runningProcessMap.begin();
  1602. map<string, Linked<IEspSWRunInfo> >::const_iterator iEnd = runningProcessMap.end();
  1603. for (; it != iEnd; it++) //add in sorted order simply by traversing the map
  1604. {
  1605. Linked<IEspSWRunInfo> info( (*it).second );
  1606. processArray.append( *info.getLink() );
  1607. }
  1608. bool dependencyDown = false;
  1609. if (!dependencies.empty())
  1610. {
  1611. dependencyDown = true;
  1612. if (pParam->m_options.getApplyProcessFilter())
  1613. {
  1614. set<string>::const_iterator it = dependencies.begin();
  1615. set<string>::const_iterator iEnd = dependencies.end();
  1616. for (; it != iEnd; it++)
  1617. {
  1618. Owned<IEspSWRunInfo> info = static_cast<IEspSWRunInfo*>(new CSWRunInfo(""));
  1619. info->setName(it->c_str());
  1620. info->setInstances(0);
  1621. processArray.append( *info.getLink() );
  1622. }
  1623. }
  1624. }
  1625. if (pParam->m_options.getApplyProcessFilter() && !additionalProcesses.empty())
  1626. {
  1627. set<string>::const_iterator it = additionalProcesses.begin();
  1628. set<string>::const_iterator iEnd = additionalProcesses.end();
  1629. for (; it != iEnd; it++)
  1630. {
  1631. Owned<IEspSWRunInfo> info = static_cast<IEspSWRunInfo*>(new CSWRunInfo(""));
  1632. info->setName(it->c_str());
  1633. info->setInstances(0);
  1634. processArray.append( *info.getLink() );
  1635. }
  1636. }
  1637. if (!dependencyDown && (!isEmptyString(procPID) || isEmptyString(procType) || strieq(procType, "FTSlaveProcess")))
  1638. {
  1639. //conditions: unknown, normal, warning, minor, major, critical, fatal
  1640. pComponentInfo->setCondition( 1 );
  1641. pComponentInfo->setState(5);
  1642. if (process.getUpTime() && *process.getUpTime())
  1643. pComponentInfo->setUpTime( process.getUpTime() );
  1644. }
  1645. else
  1646. {
  1647. pComponentInfo->setCondition(2); //Warnning
  1648. pComponentInfo->setState(0);
  1649. }
  1650. }
  1651. //Erase this process from dependencies and, if firstProcess, additionalProcesses;
  1652. //If processMap is not NULL, add this process to processMap
  1653. void Cws_machineEx::enumerateRunningProcesses(CMachineInfoThreadParam* pParam, CProcessData& process, map<string, Linked<IEspSWRunInfo> >* runningProcessMap, bool firstProcess)
  1654. {
  1655. set<string>& dependencies = process.getDependencies();
  1656. set<string>& additionalProcesses = pParam->m_machineData.getAdditinalProcessFilters();
  1657. IArrayOf<IEspProcessInfo>& runningProcesses = pParam->m_machineData.getRunningProcesses();
  1658. ForEachItemIn(k, runningProcesses)
  1659. {
  1660. IEspProcessInfo& processInfo = runningProcesses.item(k);
  1661. //Erase this process from dependencies and, if firstProcess, additionalProcesses
  1662. const char* pName = processInfo.getDescription();
  1663. if (pParam->m_machineData.getOS() == MachineOsW2K)
  1664. {
  1665. StringBuffer sName(pName);
  1666. pName = sName.toLowerCase().replaceString(".exe", "").str();
  1667. if (!dependencies.empty())
  1668. dependencies.erase(pName);
  1669. if (pParam->m_options.getApplyProcessFilter() && firstProcess && !additionalProcesses.empty())
  1670. additionalProcesses.erase(pName);
  1671. }
  1672. else
  1673. {
  1674. //dafilesrv would probably be running from a global directory
  1675. //and not component's installation directory so ignore their paths
  1676. const char* pPath = pName;
  1677. if ( !strieq(pName, "dafilesrv"))
  1678. {
  1679. const char* param = processInfo.getParameter();
  1680. if (param && *param)
  1681. {
  1682. if (strncmp(param, "bash ", 5))
  1683. pPath = param;
  1684. else
  1685. pPath = param + 5;
  1686. if (!pPath || !*pPath)
  1687. continue;
  1688. //params typically is like "/c$/esp_dir/esp [parameters...]"
  1689. //so just pick the full path
  1690. const char* pch = strchr(pPath, ' ');
  1691. if (pch)
  1692. {
  1693. StringBuffer sPath(pPath);
  1694. sPath.setLength( pch - pPath );
  1695. pPath = sPath.str();
  1696. }
  1697. }
  1698. }
  1699. if (!dependencies.empty())
  1700. {
  1701. const char* pProcessName;
  1702. if (process.getType() && !strncmp(process.getType(), "Thor", 4) && !strnicmp(pName, "thor", 4))
  1703. {
  1704. const char* pch = strrchr(pPath, pParam->m_machineData.getPathSep());
  1705. pProcessName = pch ? pch+1 : pName;
  1706. }
  1707. else
  1708. {
  1709. const char* pName0 = process.getMultipleInstances() ? pPath : pName;
  1710. const char* pch = strrchr(pName0, pParam->m_machineData.getPathSep());
  1711. pProcessName = pch ? pch+1 : pName0;
  1712. }
  1713. dependencies.erase(pProcessName);
  1714. if (pParam->m_options.getApplyProcessFilter() && firstProcess && !additionalProcesses.empty())
  1715. additionalProcesses.erase(pProcessName);
  1716. }
  1717. pName = pPath;
  1718. }
  1719. if (!runningProcessMap)
  1720. continue;
  1721. //Add this process to runningProcessMap
  1722. map<string, Linked<IEspSWRunInfo> >::iterator it = runningProcessMap->find(pName);
  1723. if ( it != runningProcessMap->end()) //not in the set
  1724. {
  1725. Linked<IEspSWRunInfo>& linkedPtr = (*it).second;
  1726. linkedPtr->setInstances( linkedPtr->getInstances() + 1);
  1727. }
  1728. else
  1729. {
  1730. Owned<IEspSWRunInfo> info = static_cast<IEspSWRunInfo*>(new CSWRunInfo(""));
  1731. info->setName(pName);
  1732. info->setInstances(1);
  1733. runningProcessMap->insert(pair<string, Linked<IEspSWRunInfo> >(pName, info));
  1734. }
  1735. }
  1736. }
  1737. void Cws_machineEx::getProcessDisplayName(const char* processName, StringBuffer& displayName)
  1738. {
  1739. //produces "LDAPServerProcess" as "LDAP Server" and "EspService" as "Esp Service", etc.
  1740. const char* end = strstr(processName, "Process");
  1741. if (!end)
  1742. end = processName + strlen(processName);
  1743. displayName.append(*processName);
  1744. processName++;
  1745. bool bLower = false;
  1746. while (processName < end)
  1747. {
  1748. char ch = *processName;
  1749. if (!isupper(ch))
  1750. bLower = true;
  1751. else
  1752. {
  1753. if (bLower || //last char was uppercase or the following character is lowercase?
  1754. ((processName+1 < end) && islower(*(processName+1))))
  1755. {
  1756. displayName.append(' ');
  1757. }
  1758. bLower = false;
  1759. }
  1760. displayName.append(*processName);
  1761. processName++;
  1762. }
  1763. displayName.append('\0');
  1764. return;
  1765. }
  1766. bool Cws_machineEx::excludePartition(const char* partition) const
  1767. {
  1768. //first see if this partition is meant to be excluded as is - for instance
  1769. //if partition is /dev and /dev is one of the predefined partitions to be excluded
  1770. set<string>::const_iterator it = m_excludePartitions.find( partition );
  1771. set<string>::const_iterator itEnd = m_excludePartitions.end();
  1772. bool found = false;
  1773. if (it != itEnd)
  1774. found = true;
  1775. else
  1776. {
  1777. //now check if /dev* is one of the partitions to be excluded
  1778. set<string>::const_iterator itBegin = m_excludePartitionPatterns.begin();
  1779. itEnd = m_excludePartitionPatterns.end();
  1780. unsigned int partitionLen = strlen(partition);
  1781. for (it=itBegin; it != itEnd; it++)
  1782. {
  1783. const string& pattern = *it;
  1784. if ((found = ::WildMatch(partition, partitionLen, pattern.c_str(), pattern.length(), false)))
  1785. break;
  1786. }
  1787. }
  1788. return found;
  1789. }
  1790. void Cws_machineEx::appendProcessInstance(const char* name, const char* directory1, const char* directory2, StringArray& processInstances, StringArray& directories)
  1791. {
  1792. if (!name || !*name)
  1793. return;
  1794. processInstances.append(name);
  1795. if (directory1 && *directory1)
  1796. directories.append(directory1);
  1797. else if (directory2 && *directory2)
  1798. directories.append(directory2);
  1799. else
  1800. directories.append("Setting not found");
  1801. }
  1802. //////////////////////////////////////////////////////////////////
  1803. // Set Machine Infomation for response //
  1804. //////////////////////////////////////////////////////////////////
  1805. void Cws_machineEx::setMachineInfoResponse(IEspContext& context, IEspGetMachineInfoRequest& req,
  1806. CGetMachineInfoData& machineInfoData, IEspGetMachineInfoResponse& resp)
  1807. {
  1808. IEspRequestInfoStruct& reqInfo = resp.updateRequestInfo();
  1809. #if 0
  1810. StringBuffer user;
  1811. StringBuffer pw;
  1812. context.getUserID(user);
  1813. context.getPassword(pw);
  1814. reqInfo.setUserName(user.str());
  1815. reqInfo.setPassword(pw.str());
  1816. #endif
  1817. reqInfo.setSecurityString(req.getSecurityString());
  1818. reqInfo.setGetProcessorInfo(req.getGetProcessorInfo());
  1819. reqInfo.setGetStorageInfo(req.getGetStorageInfo());
  1820. double version = context.getClientVersion();
  1821. if (version > 1.10)
  1822. reqInfo.setLocalFileSystemsOnly(req.getLocalFileSystemsOnly());
  1823. reqInfo.setGetSoftwareInfo(req.getGetSoftwareInfo());
  1824. reqInfo.setAutoRefresh( req.getAutoRefresh() );
  1825. reqInfo.setMemThreshold(req.getMemThreshold());
  1826. reqInfo.setDiskThreshold(req.getDiskThreshold());
  1827. reqInfo.setCpuThreshold(req.getCpuThreshold());
  1828. reqInfo.setMemThresholdType(req.getMemThresholdType());
  1829. reqInfo.setDiskThresholdType(req.getDiskThresholdType());
  1830. reqInfo.setApplyProcessFilter( req.getApplyProcessFilter() );
  1831. reqInfo.setClusterType( req.getClusterType() );
  1832. reqInfo.setCluster( req.getCluster() );
  1833. reqInfo.setAddProcessesToFilter( req.getAddProcessesToFilter() );
  1834. reqInfo.setOldIP( req.getOldIP() );
  1835. reqInfo.setPath( req.getPath() );
  1836. reqInfo.setSortBy("Address");
  1837. if (machineInfoData.getMachineInfoColumns().ordinality())
  1838. resp.setColumns(machineInfoData.getMachineInfoColumns());
  1839. if (machineInfoData.getMachineInfoTable().ordinality())
  1840. resp.setMachines(machineInfoData.getMachineInfoTable());
  1841. char timeStamp[32];
  1842. getTimeStamp(timeStamp);
  1843. resp.setTimeStamp( timeStamp );
  1844. if (version >= 1.12)
  1845. {
  1846. StringBuffer acceptLanguage;
  1847. resp.setAcceptLanguage(getAcceptLanguage(context, acceptLanguage).str());
  1848. }
  1849. }
  1850. void Cws_machineEx::getTimeStamp(char* timeStamp)
  1851. {
  1852. //set time stamp in the result for this machine
  1853. time_t tNow;
  1854. time(&tNow);
  1855. #ifdef _WIN32
  1856. struct tm *ltNow;
  1857. ltNow = localtime(&tNow);
  1858. strftime(timeStamp, 32, "%m/%d/%y %H:%M:%S", ltNow);
  1859. #else
  1860. struct tm ltNow;
  1861. localtime_r(&tNow, &ltNow);
  1862. strftime(timeStamp, 32, "%m/%d/%y %H:%M:%S", &ltNow);
  1863. #endif
  1864. }
  1865. void Cws_machineEx::setTargetClusterInfoResponse(IEspContext& context, IEspGetTargetClusterInfoRequest& req,
  1866. CGetMachineInfoData& machineInfoData, IPropertyTree* targetClusterTree, IEspGetTargetClusterInfoResponse& resp)
  1867. {
  1868. IEspRequestInfoStruct& reqInfo = resp.updateRequestInfo();
  1869. #if 0
  1870. StringBuffer user;
  1871. StringBuffer pw;
  1872. context.getUserID(user);
  1873. context.getPassword(pw);
  1874. reqInfo.setUserName(user.str());
  1875. reqInfo.setPassword(pw.str());
  1876. #endif
  1877. reqInfo.setGetProcessorInfo(req.getGetProcessorInfo());
  1878. reqInfo.setGetStorageInfo(req.getGetStorageInfo());
  1879. double version = context.getClientVersion();
  1880. if (version > 1.10)
  1881. reqInfo.setLocalFileSystemsOnly(req.getLocalFileSystemsOnly());
  1882. reqInfo.setGetSoftwareInfo(req.getGetSoftwareInfo());
  1883. reqInfo.setAutoRefresh( req.getAutoRefresh() );
  1884. reqInfo.setMemThreshold(req.getMemThreshold());
  1885. reqInfo.setDiskThreshold(req.getDiskThreshold());
  1886. reqInfo.setCpuThreshold(req.getCpuThreshold());
  1887. reqInfo.setMemThresholdType(req.getMemThresholdType());
  1888. reqInfo.setDiskThresholdType(req.getDiskThresholdType());
  1889. reqInfo.setApplyProcessFilter( req.getApplyProcessFilter() );
  1890. reqInfo.setAddProcessesToFilter( req.getAddProcessesToFilter() );
  1891. reqInfo.setSortBy("Address");
  1892. if (machineInfoData.getMachineInfoColumns().ordinality())
  1893. resp.setColumns(machineInfoData.getMachineInfoColumns());
  1894. if (machineInfoData.getMachineInfoTable().ordinality())
  1895. {
  1896. IArrayOf<IEspTargetClusterInfo> targetClusterInfoList;
  1897. setTargetClusterInfo(targetClusterTree, machineInfoData.getMachineInfoTable(), targetClusterInfoList);
  1898. if (targetClusterInfoList.ordinality())
  1899. resp.setTargetClusterInfoList(targetClusterInfoList);
  1900. }
  1901. char timeStamp[32];
  1902. getTimeStamp(timeStamp);
  1903. resp.setTimeStamp( timeStamp );
  1904. if (version >= 1.12)
  1905. {
  1906. StringBuffer acceptLanguage;
  1907. resp.setAcceptLanguage(getAcceptLanguage(context, acceptLanguage).str());
  1908. }
  1909. }
  1910. void Cws_machineEx::setTargetClusterInfo(IPropertyTree* pTargetClusterTree, IArrayOf<IEspMachineInfoEx>& machineArray, IArrayOf<IEspTargetClusterInfo>& targetClusterInfoList)
  1911. {
  1912. if (!pTargetClusterTree)
  1913. return;
  1914. unsigned machineCount = machineArray.ordinality();
  1915. if (machineCount < 1)
  1916. return;
  1917. Owned<IPropertyTreeIterator> targetClusters = pTargetClusterTree->getElements("TargetCluster");
  1918. ForEach(*targetClusters)
  1919. {
  1920. IPropertyTree& targetCluster = targetClusters->query();
  1921. StringBuffer targetName, targetType;
  1922. targetCluster.getProp("@Name", targetName);
  1923. targetCluster.getProp("@Type", targetType);
  1924. Owned<IEspTargetClusterInfo> targetClusterInfo = static_cast<IEspTargetClusterInfo*>(new CTargetClusterInfo(""));
  1925. targetClusterInfo->setName( targetName.str() );
  1926. targetClusterInfo->setType( targetType.str() );
  1927. IArrayOf<IEspMachineInfoEx> machineArrayNew;
  1928. Owned<IPropertyTreeIterator> processes = targetCluster.getElements("Process");
  1929. ForEach(*processes)
  1930. {
  1931. IPropertyTree& process = processes->query();
  1932. StringBuffer processName, processType;
  1933. process.getProp("@Name", processName);
  1934. process.getProp("@Type", processType);
  1935. for (unsigned i = 0; i < machineCount; i++)
  1936. {
  1937. IEspMachineInfoEx& machineInfoEx = machineArray.item(i);
  1938. const char* name = machineInfoEx.getComponentName();
  1939. const char* type = machineInfoEx.getProcessType();
  1940. if (!name || !type || !strieq(name, processName.str()) || !strieq(getProcessTypeFromMachineType(type), processType.str()))
  1941. continue;
  1942. Owned<IEspMachineInfoEx> pMachineInfo = static_cast<IEspMachineInfoEx*>(new CMachineInfoEx(""));
  1943. pMachineInfo->copy(machineInfoEx);
  1944. machineArrayNew.append(*pMachineInfo.getLink());
  1945. //Cannot break here because more than one processes match (ex. EclAgent/AgentExec)
  1946. }
  1947. }
  1948. if (machineArrayNew.ordinality())
  1949. targetClusterInfo->setProcesses(machineArrayNew);
  1950. targetClusterInfoList.append(*targetClusterInfo.getLink());
  1951. }
  1952. }
  1953. const char* Cws_machineEx::getProcessTypeFromMachineType(const char* machineType)
  1954. {
  1955. const char* processType ="Unknown";
  1956. if (!machineType || !*machineType)
  1957. return processType;
  1958. if (strieq(machineType, eqThorMasterProcess) || strieq(machineType, eqThorSlaveProcess) || strieq(machineType, eqThorSpareProcess))
  1959. {
  1960. processType = eqThorCluster;
  1961. }
  1962. else if (strieq(machineType, eqRoxieServerProcess))
  1963. {
  1964. processType = eqRoxieCluster;
  1965. }
  1966. else if (strieq(machineType, eqAgentExec))
  1967. {
  1968. processType = eqEclAgent;
  1969. }
  1970. else
  1971. {
  1972. processType = machineType;
  1973. }
  1974. return processType;
  1975. }
  1976. IConstEnvironment* Cws_machineEx::getConstEnvironment()
  1977. {
  1978. Owned<IEnvironmentFactory> envFactory = getEnvironmentFactory(true);
  1979. Owned<IConstEnvironment> constEnv = envFactory->openEnvironment();
  1980. if (!constEnv)
  1981. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get environment information.");
  1982. return constEnv.getLink();
  1983. }
  1984. //Used in Rexec
  1985. IPropertyTree* Cws_machineEx::getComponent(const char* compType, const char* compName)
  1986. {
  1987. StringBuffer xpath;
  1988. xpath.append("Software/").append(compType).append("[@name='").append(compName).append("']");
  1989. Owned<IConstEnvironment> constEnv = getConstEnvironment();
  1990. Owned<IPropertyTree> pEnvRoot = &constEnv->getPTree();
  1991. return pEnvRoot->getPropTree( xpath.str() );
  1992. }
  1993. void Cws_machineEx::getAccountAndPlatformInfo(const char* address, StringBuffer& userId, StringBuffer& password, bool& bLinux)
  1994. {
  1995. Owned<IConstEnvironment> constEnv = getConstEnvironment();
  1996. Owned<IConstMachineInfo> machine = constEnv->getMachineByAddress(address);
  1997. if (!machine && strieq(address, "."))
  1998. {
  1999. machine.setown(constEnv->getMachineByAddress("127.0.0.1"));
  2000. }
  2001. if (!machine)
  2002. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Machine %s is not defined in environment!", address);
  2003. Owned<IConstDomainInfo> domain = machine->getDomain();
  2004. if (!domain)
  2005. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Machine %s does not have any domain information!", address);
  2006. userId.clear();
  2007. password.clear();
  2008. StringBufferAdaptor strval1(userId);
  2009. StringBufferAdaptor strval2(password);
  2010. domain->getAccountInfo(strval1, strval2);
  2011. StringBuffer domainName;
  2012. StringBufferAdaptor strval3(domainName);
  2013. domain->getName(strval3);
  2014. if ((machine->getOS() == MachineOsW2K) && domainName.length())
  2015. {
  2016. domainName.append('\\');
  2017. userId.insert(0, domainName);
  2018. }
  2019. bLinux = machine->getOS() == MachineOsLinux;
  2020. }
  2021. IPropertyTree* Cws_machineEx::createDiskUsageReq(IPropertyTree* envDirectories, const char* pathName,
  2022. const char* componentType, const char* componentName)
  2023. {
  2024. StringBuffer path;
  2025. if (!getConfigurationDirectory(envDirectories, pathName, componentType, componentName, path))
  2026. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get %s Disk Path for component %s", pathName, componentName);
  2027. Owned<IPropertyTree> diskReq = createPTree("Folder");
  2028. diskReq->addProp("@name", pathName);
  2029. diskReq->addProp("@path", path);
  2030. return diskReq.getClear();
  2031. }
  2032. IPropertyTree* Cws_machineEx::createMachineUsageReq(IConstEnvironment* constEnv, const char* computer)
  2033. {
  2034. Owned<IConstMachineInfo> machine = constEnv->getMachine(computer);
  2035. if (!machine)
  2036. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get machine %s", computer);
  2037. Owned<IPropertyTree> machineReq = createPTree("Machine");
  2038. machineReq->addProp("@name", computer);
  2039. SCMStringBuffer netAddress;
  2040. machine->getNetAddress(netAddress);
  2041. machineReq->addProp("@netAddress", netAddress.str());
  2042. machineReq->addPropInt("@OS", machine->getOS());
  2043. return machineReq.getClear();
  2044. }
  2045. void Cws_machineEx::readThorUsageReq(const char* name, IConstEnvironment* constEnv, IPropertyTree* usageReq)
  2046. {
  2047. if (isEmptyString(name))
  2048. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Empty Thor name");
  2049. Owned<IPropertyTree> componentReq = createPTree("Component");
  2050. componentReq->addProp("@name", name);
  2051. componentReq->addProp("@type", eqThorCluster);
  2052. Owned<IPropertyTree> envRoot = &constEnv->getPTree();
  2053. IPropertyTree* envDirectories = envRoot->queryPropTree("Software/Directories");
  2054. Owned<IPropertyTree> logFolder = createDiskUsageReq(envDirectories, "log", "thor", name);
  2055. Owned<IPropertyTree> dataFolder = createDiskUsageReq(envDirectories, "data", "thor", name);
  2056. Owned<IPropertyTree> repFolder = createDiskUsageReq(envDirectories, "mirror", "thor", name);
  2057. VStringBuffer xpath("Software/ThorCluster[@name='%s']/ThorSlaveProcess", name);
  2058. Owned<IPropertyTreeIterator> slaveProcesses= envRoot->getElements(xpath);
  2059. ForEach(*slaveProcesses)
  2060. {
  2061. IPropertyTree& slaveProcess = slaveProcesses->query();
  2062. const char* computer = slaveProcess.queryProp("@computer");
  2063. if (isEmptyString(computer))
  2064. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get @computer for %s", xpath.str());
  2065. Owned<IPropertyTree> newMachineReq = createMachineUsageReq(constEnv, computer);
  2066. //Not sure we need those folders here. Add them just in case.
  2067. if (logFolder)
  2068. newMachineReq->addPropTree(logFolder->queryName(), LINK(logFolder));
  2069. if (dataFolder)
  2070. newMachineReq->addPropTree(dataFolder->queryName(), LINK(dataFolder));
  2071. if (repFolder)
  2072. newMachineReq->addPropTree(repFolder->queryName(), LINK(repFolder));
  2073. componentReq->addPropTree(newMachineReq->queryName(), LINK(newMachineReq));
  2074. }
  2075. //Read ThorMasterProcess in case it is on a different machine
  2076. xpath.setf("Software/ThorCluster[@name='%s']/ThorMasterProcess/@computer", name);
  2077. const char* computer = envRoot->queryProp(xpath);
  2078. if (isEmptyString(computer))
  2079. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get %s", xpath.str());
  2080. Owned<IPropertyTree> machineReq = createMachineUsageReq(constEnv, computer);
  2081. xpath.setf("Machine[@netAddress='%s']", machineReq->queryProp("@netAddress"));
  2082. if (componentReq->queryPropTree(xpath))
  2083. { //ThorMasterProcess is running on one of the ThorSlaveProcess machines.
  2084. //So, we do not add this machine again.
  2085. usageReq->addPropTree(componentReq->queryName(), LINK(componentReq));
  2086. return;
  2087. }
  2088. //Not sure we need those folders here. Add them just in case.
  2089. if (logFolder)
  2090. machineReq->addPropTree(logFolder->queryName(), LINK(logFolder));
  2091. if (dataFolder)
  2092. machineReq->addPropTree(dataFolder->queryName(), LINK(dataFolder));
  2093. if (repFolder)
  2094. machineReq->addPropTree(repFolder->queryName(), LINK(repFolder));
  2095. componentReq->addPropTree(machineReq->queryName(), LINK(machineReq));
  2096. usageReq->addPropTree(componentReq->queryName(), LINK(componentReq));
  2097. }
  2098. void Cws_machineEx::readRoxieUsageReq(const char* name, IConstEnvironment* constEnv, IPropertyTree* usageReq)
  2099. {
  2100. if (isEmptyString(name))
  2101. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Empty Roxie name");
  2102. Owned<IPropertyTree> componentReq = createPTree("Component");
  2103. componentReq->addProp("@name", name);
  2104. componentReq->addProp("@type", eqRoxieCluster);
  2105. Owned<IPropertyTree> envRoot = &constEnv->getPTree();
  2106. IPropertyTree* envDirectories = envRoot->queryPropTree("Software/Directories");
  2107. Owned<IPropertyTree> logFolder = createDiskUsageReq(envDirectories, "log", "roxie", name);
  2108. Owned<IPropertyTree> dataFolder = createDiskUsageReq(envDirectories, "data", "roxie", name);
  2109. VStringBuffer xpath("Software/RoxieCluster[@name='%s']/RoxieServerProcess", name);
  2110. Owned<IPropertyTreeIterator> slaveProcesses= envRoot->getElements(xpath);
  2111. ForEach(*slaveProcesses)
  2112. {
  2113. IPropertyTree& slaveProcess = slaveProcesses->query();
  2114. const char* computer = slaveProcess.queryProp("@computer");
  2115. if (isEmptyString(computer))
  2116. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get @computer for %s", xpath.str());
  2117. Owned<IPropertyTree> newMachineReq = createMachineUsageReq(constEnv, computer);
  2118. //Not sure we need those folders here. Add them just in case.
  2119. if (logFolder)
  2120. newMachineReq->addPropTree(logFolder->queryName(), LINK(logFolder));
  2121. if (dataFolder)
  2122. newMachineReq->addPropTree(dataFolder->queryName(), LINK(dataFolder));
  2123. componentReq->addPropTree(newMachineReq->queryName(), LINK(newMachineReq));
  2124. }
  2125. usageReq->addPropTree(componentReq->queryName(), LINK(componentReq));
  2126. }
  2127. void Cws_machineEx::readDropZoneUsageReq(const char* name, IConstEnvironment* constEnv, IPropertyTree* usageReq)
  2128. {
  2129. if (isEmptyString(name))
  2130. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Empty DropZone name");
  2131. Owned<IConstDropZoneInfo> envDropZone = constEnv->getDropZone(name);
  2132. if (!envDropZone || !envDropZone->isECLWatchVisible())
  2133. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Dropzone %s not found", name);
  2134. SCMStringBuffer directory;
  2135. envDropZone->getDirectory(directory);
  2136. if (directory.length() == 0)
  2137. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get directory for DropZone %s", name);
  2138. Owned<IPropertyTree> dataFolder = createPTree("Folder");
  2139. dataFolder->addProp("@name", "data");
  2140. dataFolder->addProp("@path", directory.str());
  2141. Owned<IPropertyTree> componentReq = createPTree("Component");
  2142. componentReq->addProp("@name", name);
  2143. componentReq->addProp("@type", eqDropZone);
  2144. SCMStringBuffer computerName;
  2145. envDropZone->getComputerName(computerName);
  2146. if (computerName.length() == 0)
  2147. {
  2148. OS_TYPE os = (getPathSepChar(directory.str()) == '/') ? OS_LINUX : OS_WINDOWS;
  2149. Owned<IConstDropZoneServerInfoIterator> servers = envDropZone->getServers();
  2150. ForEach(*servers)
  2151. {
  2152. IConstDropZoneServerInfo &server = servers->query();
  2153. StringBuffer serverNetAddress;
  2154. server.getServer(serverNetAddress.clear());
  2155. Owned<IPropertyTree> machineReq = createPTree("Machine");
  2156. machineReq->addProp("@name", serverNetAddress.str());
  2157. machineReq->addProp("@netAddress", serverNetAddress.str());
  2158. machineReq->addPropInt("@OS", os);
  2159. machineReq->addPropTree(dataFolder->queryName(), LINK(dataFolder));
  2160. componentReq->addPropTree(machineReq->queryName(), LINK(machineReq));
  2161. }
  2162. }
  2163. else
  2164. { //legacy dropzone settings
  2165. Owned<IPropertyTree> machineReq = createMachineUsageReq(constEnv, computerName.str());
  2166. machineReq->addPropTree(dataFolder->queryName(), LINK(dataFolder));
  2167. componentReq->addPropTree(machineReq->queryName(), LINK(machineReq));
  2168. }
  2169. usageReq->addPropTree(componentReq->queryName(), LINK(componentReq));
  2170. }
  2171. void Cws_machineEx::readOtherComponentUsageReq(const char* name, const char* type, IConstEnvironment* constEnv, IPropertyTree* usageReq)
  2172. {
  2173. if (isEmptyString(name))
  2174. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Empty Component name");
  2175. const char* componentType = findComponentTypeFromProcessType(type);
  2176. if (!componentType)
  2177. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Component usage function is not supported for %s", type);
  2178. Owned<IPropertyTree> componentReq = createPTree("Component");
  2179. componentReq->addProp("@name", name);
  2180. componentReq->addProp("@type", type);
  2181. Owned<IPropertyTree> envRoot = &constEnv->getPTree();
  2182. VStringBuffer xpath("Software/%s[@name='%s']/Instance", type, name);
  2183. Owned<IPropertyTreeIterator> it = envRoot->getElements(xpath);
  2184. ForEach(*it)
  2185. {
  2186. IPropertyTree& instance = it->query();
  2187. const char* computer = instance.queryProp("@computer");
  2188. if (isEmptyString(computer))
  2189. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get %s", xpath.str());
  2190. Owned<IPropertyTree> machineReq = createMachineUsageReq(constEnv, computer);
  2191. IPropertyTree* envDirectories = envRoot->queryPropTree("Software/Directories");
  2192. Owned<IPropertyTree> logFolder = createDiskUsageReq(envDirectories, "log", type, name);
  2193. if (logFolder)
  2194. machineReq->addPropTree(logFolder->queryName(), LINK(logFolder));
  2195. Owned<IPropertyTree> dataFolder = createDiskUsageReq(envDirectories, "data", componentType, name);
  2196. if (dataFolder)
  2197. machineReq->addPropTree(dataFolder->queryName(), LINK(dataFolder));
  2198. if (strieq(type, eqDali))
  2199. {
  2200. Owned<IPropertyTree> repFolder = createDiskUsageReq(envDirectories, "mirror", "dali", name);
  2201. if (repFolder)
  2202. machineReq->addPropTree(repFolder->queryName(), LINK(repFolder));
  2203. }
  2204. componentReq->addPropTree(machineReq->queryName(), LINK(machineReq));
  2205. }
  2206. usageReq->addPropTree(componentReq->queryName(), LINK(componentReq));
  2207. }
  2208. void Cws_machineEx::setUniqueMachineUsageReq(IPropertyTree* usageReq, IPropertyTree* uniqueUsages)
  2209. {
  2210. Owned<IPropertyTreeIterator> components= usageReq->getElements("Component");
  2211. ForEach(*components)
  2212. {
  2213. IPropertyTree& component = components->query();
  2214. Owned<IPropertyTreeIterator> machines= component.getElements("Machine");
  2215. ForEach(*machines)
  2216. {
  2217. IPropertyTree& machine = machines->query();
  2218. const char* netAddress = machine.queryProp("@netAddress");
  2219. VStringBuffer xpath("Machine[@netAddress='%s']", netAddress);
  2220. IPropertyTree* uniqueMachineReqTree = uniqueUsages->queryPropTree(xpath);
  2221. if (!uniqueMachineReqTree)
  2222. {
  2223. uniqueUsages->addPropTree(machine.queryName(), LINK(&machine));
  2224. continue;
  2225. }
  2226. //Add unique disk folders from the usageReq.
  2227. Owned<IPropertyTreeIterator> folders = machine.getElements("Folder");
  2228. ForEach(*folders)
  2229. {
  2230. IPropertyTree& folder = folders->query();
  2231. const char* aDiskPath = folder.queryProp("@path");
  2232. xpath.setf("Folder[@path='%s']", aDiskPath);
  2233. IPropertyTree* uniqueFolderReqTree = uniqueMachineReqTree->queryPropTree(xpath);
  2234. if (!uniqueFolderReqTree)
  2235. {
  2236. Owned<IPropertyTree> folderReq = createPTree("Folder");
  2237. folderReq->addProp("@name", folder.queryProp("@name"));
  2238. folderReq->addProp("@path", aDiskPath);
  2239. uniqueMachineReqTree->addPropTree(folderReq->queryName(), LINK(folderReq));
  2240. }
  2241. }
  2242. }
  2243. }
  2244. }
  2245. IArrayOf<IConstComponent>& Cws_machineEx::listComponentsByType(IPropertyTree* envRoot,
  2246. const char* componentType, IArrayOf<IConstComponent>& componentList)
  2247. {
  2248. VStringBuffer xpath("Software/%s", componentType);
  2249. Owned<IPropertyTreeIterator> components= envRoot->getElements(xpath);
  2250. ForEach(*components)
  2251. {
  2252. Owned<IEspComponent> component = createComponent();
  2253. component->setName(components->query().queryProp("@name"));
  2254. component->setType(componentType);
  2255. componentList.append(*component.getClear());
  2256. }
  2257. return componentList;
  2258. }
  2259. IArrayOf<IConstComponent>& Cws_machineEx::listComponentsForCheckingUsage(IConstEnvironment* constEnv,
  2260. IArrayOf<IConstComponent>& componentList)
  2261. {
  2262. Owned<IPropertyTree> envRoot = &constEnv->getPTree();
  2263. listComponentsByType(envRoot, eqThorCluster, componentList);
  2264. listComponentsByType(envRoot, eqRoxieCluster, componentList);
  2265. listComponentsByType(envRoot, eqDali, componentList);
  2266. listComponentsByType(envRoot, eqEclAgent, componentList);
  2267. listComponentsByType(envRoot, eqSashaServer, componentList);
  2268. listComponentsByType(envRoot, eqDropZone, componentList);
  2269. listComponentsByType(envRoot, eqDfu, componentList);
  2270. listComponentsByType(envRoot, eqEclCCServer, componentList);
  2271. listComponentsByType(envRoot, eqEclServer, componentList);
  2272. listComponentsByType(envRoot, eqEclScheduler, componentList);
  2273. listComponentsByType(envRoot, eqEsp, componentList);
  2274. return componentList;
  2275. }
  2276. IPropertyTree* Cws_machineEx::getComponentUsageReq(IEspGetComponentUsageRequest& req, IConstEnvironment* constEnv)
  2277. {
  2278. IArrayOf<IConstComponent>& componentList = req.getComponents();
  2279. if (!componentList.length())
  2280. listComponentsForCheckingUsage(constEnv, componentList);
  2281. Owned<IPropertyTree> usageReq = createPTree("Req");
  2282. ForEachItemIn(i, componentList)
  2283. {
  2284. IConstComponent& component = componentList.item(i);
  2285. const char* type = component.getType();
  2286. if (isEmptyString(type))
  2287. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Empty Component Type");
  2288. if (strieq(type, eqThorCluster))
  2289. readThorUsageReq(component.getName(), constEnv, usageReq);
  2290. else if (strieq(type, eqRoxieCluster))
  2291. readRoxieUsageReq(component.getName(), constEnv, usageReq);
  2292. else if (strieq(type, eqDropZone))
  2293. readDropZoneUsageReq(component.getName(), constEnv, usageReq);
  2294. else
  2295. readOtherComponentUsageReq(component.getName(), type, constEnv, usageReq);
  2296. }
  2297. return usageReq.getClear();
  2298. }
  2299. void Cws_machineEx::getMachineUsages(IEspContext& context, IPropertyTree* uniqueUsages)
  2300. {
  2301. UnsignedArray threadHandles;
  2302. Owned<IPropertyTreeIterator> requests= uniqueUsages->getElements("Machine");
  2303. ForEach(*requests)
  2304. {
  2305. Owned<CGetMachineUsageThreadParam> threadParam = new CGetMachineUsageThreadParam(this, context, &requests->query());
  2306. PooledThreadHandle handle = m_threadPool->start(threadParam.getClear());
  2307. threadHandles.append(handle);
  2308. }
  2309. ForEachItemIn(i, threadHandles)
  2310. m_threadPool->join(threadHandles.item(i));
  2311. }
  2312. bool Cws_machineEx::readDiskSpaceResponse(const char* response, __int64& free, __int64& used, int& percentAvail, StringBuffer& pathUsed)
  2313. {
  2314. if (isEmptyString(response))
  2315. return false;
  2316. StringArray data;
  2317. data.appendList(response, " ");
  2318. if (data.length() < 2)
  2319. return false;
  2320. used = atol(data.item(0));
  2321. free = atol(data.item(1));
  2322. __int64 total = free + used;
  2323. if (total > 0)
  2324. percentAvail = (int) ((free*100)/total);
  2325. //The given path (ex. /var/lib/HPCCSystems/hpcc-mirror/thor) in the usage request does not exist.
  2326. //The data.item(2) is the path (ex. /var/lib/HPCCSystems/hpcc-mirror/) the usage script is used
  2327. //to read the DiskSpace.
  2328. if (data.length() > 2)
  2329. pathUsed.set(data.item(2));
  2330. return true;
  2331. }
  2332. void Cws_machineEx::getMachineUsage(IEspContext& context, CGetMachineUsageThreadParam* param)
  2333. {
  2334. VStringBuffer command("/%s/sbin/usage -d=", environmentConfData.m_executionPath.str());
  2335. unsigned pathCount = 0;
  2336. Owned<IPropertyTreeIterator> diskPathList = param->request->getElements("Folder");
  2337. ForEach(*diskPathList)
  2338. {
  2339. IPropertyTree& t = diskPathList->query();
  2340. if (pathCount > 0)
  2341. command.append(",");
  2342. command.appendf("%s", t.queryProp("@path"));
  2343. pathCount++;
  2344. }
  2345. ESPLOG(LogMax, "command(%s)", command.str());
  2346. StringBuffer response;
  2347. int error = runCommand(context, param->request->queryProp("@netAddress"), nullptr,
  2348. (EnvMachineOS) param->request->getPropInt("@OS", MachineOsLinux), command.str(), nullptr, nullptr, response);
  2349. if (error != 0 || isEmptyString(response))
  2350. {
  2351. if (isEmptyString(response))
  2352. param->request->addProp("@error", "Failed in getting component usage.");
  2353. else
  2354. param->request->addProp("@error", response);
  2355. return;
  2356. }
  2357. ESPLOG(LogMax, "response(%s)", response.str());
  2358. ForEach(*diskPathList)
  2359. {
  2360. IPropertyTree& diskPathTree = diskPathList->query();
  2361. StringBuffer aDiskPathResp, pathUsed;
  2362. VStringBuffer diskPath("%s:", diskPathTree.queryProp("@path"));
  2363. readALineFromResult(response, diskPath, aDiskPathResp, true);
  2364. int percentAvail = 0;
  2365. __int64 diskSpaceAvailable = 0, diskSpaceUsed = 0;
  2366. if (!readDiskSpaceResponse(aDiskPathResp.str(), diskSpaceAvailable, diskSpaceUsed, percentAvail, pathUsed))
  2367. {
  2368. DBGLOG("Failed to read disc space on %s: %s", param->request->queryProp("@netAddress"), aDiskPathResp.str());
  2369. diskPathTree.addProp("@error", "Failed to read disc space.");
  2370. continue;
  2371. }
  2372. diskPathTree.addPropInt64("@used", diskSpaceUsed);
  2373. diskPathTree.addPropInt64("@available", diskSpaceAvailable);
  2374. diskPathTree.addPropInt("@percentAvail", percentAvail);
  2375. if (!pathUsed.isEmpty())
  2376. diskPathTree.addProp("@pathUsed", pathUsed);
  2377. }
  2378. }
  2379. void Cws_machineEx::readComponentUsageResult(IEspContext& context, IPropertyTree* usageReq,
  2380. const IPropertyTree* uniqueUsages, IArrayOf<IEspComponentUsage>& componentUsages)
  2381. {
  2382. double version = context.getClientVersion();
  2383. Owned<IPropertyTreeIterator> components= usageReq->getElements("Component");
  2384. ForEach(*components)
  2385. {
  2386. IPropertyTree& component = components->query();
  2387. Owned<IEspComponentUsage> componentUsage = createComponentUsage();
  2388. componentUsage->setName(component.queryProp("@name"));
  2389. componentUsage->setType(component.queryProp("@type"));
  2390. IArrayOf<IEspMachineUsage> machineUsages;
  2391. Owned<IPropertyTreeIterator> machines= component.getElements("Machine");
  2392. ForEach(*machines)
  2393. {
  2394. IPropertyTree& machine = machines->query();
  2395. const char* netAddress = machine.queryProp("@netAddress");
  2396. Owned<IEspMachineUsage> machineUsage = createMachineUsage();
  2397. machineUsage->setName(machine.queryProp("@name"));
  2398. machineUsage->setNetAddress(netAddress);
  2399. VStringBuffer xpath("Machine[@netAddress='%s']", netAddress);
  2400. IPropertyTree* uniqueMachineReqTree = uniqueUsages->queryPropTree(xpath);
  2401. if (!uniqueMachineReqTree)
  2402. {
  2403. if (version < 1.17)
  2404. machineUsage->setDescription("No data returns.");
  2405. else
  2406. machineUsage->setException("No data returns.");
  2407. machineUsages.append(*machineUsage.getClear());
  2408. continue;
  2409. }
  2410. const char* error = uniqueMachineReqTree->queryProp("@error");
  2411. if (!isEmptyString(error))
  2412. {
  2413. if (version < 1.17)
  2414. machineUsage->setDescription(error);
  2415. else
  2416. machineUsage->setException(error);
  2417. machineUsages.append(*machineUsage.getClear());
  2418. continue;
  2419. }
  2420. IArrayOf<IEspDiskUsage> diskUsages;
  2421. Owned<IPropertyTreeIterator> folders = machine.getElements("Folder");
  2422. ForEach(*folders)
  2423. {
  2424. IPropertyTree& folder = folders->query();
  2425. const char* aDiskPath = folder.queryProp("@path");
  2426. Owned<IEspDiskUsage> diskUsage = createDiskUsage();
  2427. diskUsage->setName(folder.queryProp("@name"));
  2428. diskUsage->setPath(aDiskPath);
  2429. xpath.setf("Folder[@path='%s']", aDiskPath);
  2430. IPropertyTree* folderTree = uniqueMachineReqTree->queryPropTree(xpath);
  2431. if (!folderTree)
  2432. {
  2433. if (version < 1.17)
  2434. diskUsage->setDescription("No data returns.");
  2435. else
  2436. diskUsage->setException("No data returns.");
  2437. }
  2438. else
  2439. {
  2440. const char* error = folderTree->queryProp("@error");
  2441. if (!isEmptyString(error))
  2442. {
  2443. if (version < 1.17)
  2444. diskUsage->setDescription(error);
  2445. else
  2446. diskUsage->setException(error);
  2447. }
  2448. else
  2449. {
  2450. diskUsage->setAvailable(folderTree->getPropInt64("@available"));
  2451. diskUsage->setInUse(folderTree->getPropInt64("@used"));
  2452. diskUsage->setPercentAvailable(folderTree->getPropInt("@percentAvail"));
  2453. const char* pathUsed = folderTree->queryProp("@pathUsed");
  2454. if (!isEmptyString(pathUsed))
  2455. {
  2456. VStringBuffer desc("%s not found. Read disk usage from %s", aDiskPath, pathUsed);
  2457. diskUsage->setDescription(desc);
  2458. }
  2459. }
  2460. }
  2461. diskUsages.append(*diskUsage.getClear());
  2462. }
  2463. machineUsage->setDiskUsages(diskUsages);
  2464. machineUsages.append(*machineUsage.getClear());
  2465. }
  2466. componentUsage->setMachineUsages(machineUsages);
  2467. componentUsages.append(*componentUsage.getClear());
  2468. }
  2469. }
  2470. StringBuffer& Cws_machineEx::setUsageTimeStr(CUsageCache* usageCache, StringBuffer& timeStr)
  2471. {
  2472. if (usageCache)
  2473. usageCache->queryTimeCached(timeStr);
  2474. else
  2475. {
  2476. CDateTime timeNow;
  2477. timeNow.setNow();
  2478. timeNow.getString(timeStr, true);
  2479. }
  2480. return timeStr;
  2481. }
  2482. bool Cws_machineEx::onGetComponentUsage(IEspContext& context, IEspGetComponentUsageRequest& req,
  2483. IEspGetComponentUsageResponse& resp)
  2484. {
  2485. try
  2486. {
  2487. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Read, ECLWATCH_MACHINE_INFO_ACCESS_DENIED, "Failed to Get Machine Information. Permission denied.");
  2488. double version = context.getClientVersion();
  2489. StringBuffer timeStr;
  2490. IArrayOf<IEspComponentUsage> componentUsages;
  2491. Owned<IEnvironmentFactory> envFactory = getEnvironmentFactory(true);
  2492. Owned<IConstEnvironment> constEnv = envFactory->openEnvironment();
  2493. Owned<IPropertyTree> usageReq = getComponentUsageReq(req, constEnv);
  2494. Owned<CUsageCache> usage;
  2495. Owned<const IPropertyTree> uniqueUsages;
  2496. if (req.getBypassCachedResult())
  2497. {
  2498. Owned<IPropertyTree> tmpUniqueUsages = createPTree("Usage");
  2499. //Add unique machines from the usageReq to uniqueUsages.
  2500. setUniqueMachineUsageReq(usageReq, tmpUniqueUsages);
  2501. getMachineUsages(context, tmpUniqueUsages);
  2502. uniqueUsages.setown(tmpUniqueUsages.getClear());
  2503. }
  2504. else
  2505. {
  2506. usage.setown((CUsageCache*) usageCacheReader->getCachedInfo());
  2507. if (!usage)
  2508. throw MakeStringException(ECLWATCH_INTERNAL_ERROR, "Failed to get usage. Please try later.");
  2509. ESPLOG(LogMax, "GetComponentUsage: found UsageCache.");
  2510. uniqueUsages.set(usage->queryUsages());
  2511. }
  2512. readComponentUsageResult(context, usageReq, uniqueUsages, componentUsages);
  2513. if (version >= 1.17)
  2514. resp.setUsageTime(setUsageTimeStr(usage, timeStr));
  2515. resp.setComponentUsages(componentUsages);
  2516. }
  2517. catch(IException* e)
  2518. {
  2519. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  2520. }
  2521. return true;
  2522. }
  2523. StringArray& Cws_machineEx::listTargetClusterNames(IConstEnvironment* constEnv, StringArray& targetClusters)
  2524. {
  2525. #ifdef _CONTAINERIZED
  2526. Owned<IStringIterator> targets = getContainerTargetClusters(nullptr, nullptr);
  2527. #else
  2528. Owned<IStringIterator> targets = getTargetClusters(nullptr, nullptr);
  2529. #endif
  2530. ForEach(*targets)
  2531. {
  2532. SCMStringBuffer target;
  2533. targetClusters.append(targets->str(target).str());
  2534. }
  2535. return targetClusters;
  2536. }
  2537. IPropertyTree* Cws_machineEx::getTargetClusterUsageReq(IEspGetTargetClusterUsageRequest& req, IConstEnvironment* constEnv)
  2538. {
  2539. StringArray& targetClusters = req.getTargetClusters();
  2540. if (targetClusters.empty())
  2541. listTargetClusterNames(constEnv, targetClusters);
  2542. Owned<IPropertyTree> usageReq = createPTree("Req");
  2543. Owned<IPropertyTree> envRoot = &constEnv->getPTree();
  2544. ForEachItemIn(i, targetClusters)
  2545. {
  2546. const char* targetClusterName = targetClusters.item(i);
  2547. if (isEmptyString(targetClusterName))
  2548. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Empty Target Cluster specified.");
  2549. Owned<IConstWUClusterInfo> targetClusterInfo = getTargetClusterInfo(targetClusterName);
  2550. if (!targetClusterInfo)
  2551. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Could not find information about target cluster %s ", targetClusterName);
  2552. Owned<IPropertyTree> targetClusterTree = createPTree("TargetCluster");
  2553. targetClusterTree->addProp("@name", targetClusterName);
  2554. const StringArray& thors = targetClusterInfo->getThorProcesses();
  2555. ForEachItemIn(i, thors)
  2556. {
  2557. const char* thor = thors.item(i);
  2558. if (!isEmptyString(thor))
  2559. readThorUsageReq(thor, constEnv, targetClusterTree);
  2560. }
  2561. SCMStringBuffer roxie;
  2562. targetClusterInfo->getRoxieProcess(roxie);
  2563. if (roxie.length())
  2564. readRoxieUsageReq(roxie.str(), constEnv, targetClusterTree);
  2565. SCMStringBuffer eclAgent, eclScheduler;
  2566. targetClusterInfo->getAgentName(eclAgent);
  2567. if (eclAgent.length())
  2568. readOtherComponentUsageReq(eclAgent.str(), eqEclAgent, constEnv, targetClusterTree);
  2569. targetClusterInfo->getECLSchedulerName(eclScheduler);
  2570. if (eclScheduler.length())
  2571. readOtherComponentUsageReq(eclScheduler.str(), eqEclScheduler, constEnv, targetClusterTree);
  2572. const StringArray& eclServers = targetClusterInfo->getECLServerNames();
  2573. ForEachItemIn(j, eclServers)
  2574. readOtherComponentUsageReq(eclServers.item(j), targetClusterInfo->isLegacyEclServer() ? eqEclServer : eqEclCCServer, constEnv, targetClusterTree);
  2575. usageReq->addPropTree(targetClusterTree->queryName(), LINK(targetClusterTree));
  2576. }
  2577. return usageReq.getClear();
  2578. }
  2579. void Cws_machineEx::readTargetClusterUsageResult(IEspContext& context, IPropertyTree* usageReq,
  2580. const IPropertyTree* uniqueUsages, IArrayOf<IEspTargetClusterUsage>& targetClusterUsages)
  2581. {
  2582. Owned<IPropertyTreeIterator> targetClusters= usageReq->getElements("TargetCluster");
  2583. ForEach(*targetClusters)
  2584. {
  2585. IPropertyTree& targetCluster = targetClusters->query();
  2586. Owned<IEspTargetClusterUsage> targetClusterUsage = createTargetClusterUsage();
  2587. targetClusterUsage->setName(targetCluster.queryProp("@name"));
  2588. IArrayOf<IEspComponentUsage> componentUsages;
  2589. readComponentUsageResult(context, &targetCluster, uniqueUsages, componentUsages);
  2590. targetClusterUsage->setComponentUsages(componentUsages);
  2591. targetClusterUsages.append(*targetClusterUsage.getClear());
  2592. }
  2593. }
  2594. bool Cws_machineEx::onGetTargetClusterUsage(IEspContext& context, IEspGetTargetClusterUsageRequest& req,
  2595. IEspGetTargetClusterUsageResponse& resp)
  2596. {
  2597. try
  2598. {
  2599. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Read, ECLWATCH_MACHINE_INFO_ACCESS_DENIED, "Failed to Get Machine Information. Permission denied.");
  2600. double version = context.getClientVersion();
  2601. StringBuffer timeStr;
  2602. IArrayOf<IEspTargetClusterUsage> targetClusterUsages;
  2603. Owned<IEnvironmentFactory> envFactory = getEnvironmentFactory(true);
  2604. Owned<IConstEnvironment> constEnv = envFactory->openEnvironment();
  2605. Owned<IPropertyTree> usageReq = getTargetClusterUsageReq(req, constEnv);
  2606. Owned<CUsageCache> usage;
  2607. Owned<const IPropertyTree> uniqueUsages;
  2608. if (req.getBypassCachedResult())
  2609. {
  2610. Owned<IPropertyTree> tmpUniqueUsages = createPTree("Usage");
  2611. Owned<IPropertyTreeIterator> targetClusterItr= usageReq->getElements("TargetCluster");
  2612. ForEach(*targetClusterItr)
  2613. {
  2614. IPropertyTree& targetCluster = targetClusterItr->query();
  2615. setUniqueMachineUsageReq(&targetCluster, tmpUniqueUsages);
  2616. }
  2617. getMachineUsages(context, tmpUniqueUsages);
  2618. uniqueUsages.setown(tmpUniqueUsages.getClear());
  2619. }
  2620. else
  2621. {
  2622. usage.setown((CUsageCache*) usageCacheReader->getCachedInfo());
  2623. if (!usage)
  2624. throw MakeStringException(ECLWATCH_INTERNAL_ERROR, "Failed to get usage. Please try later.");
  2625. ESPLOG(LogMax, "GetTargetClusterUsage: found UsageCache.");
  2626. uniqueUsages.set(usage->queryUsages());
  2627. }
  2628. readTargetClusterUsageResult(context, usageReq, uniqueUsages, targetClusterUsages);
  2629. if (version >= 1.17)
  2630. resp.setUsageTime(setUsageTimeStr(usage, timeStr));
  2631. resp.setTargetClusterUsages(targetClusterUsages);
  2632. }
  2633. catch(IException* e)
  2634. {
  2635. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  2636. }
  2637. return true;
  2638. }
  2639. bool Cws_machineEx::getEclAgentNameFromNodeGroupName(const char* nodeGroupName, StringBuffer& agentName)
  2640. {
  2641. //Node group name for an eclagent should be: 'hthor__' + ECLAgentName[ + '_' + a number]
  2642. if ((strlen(nodeGroupName) <= 7) || strnicmp(nodeGroupName, "hthor__", 7))
  2643. return false;
  2644. agentName.set(nodeGroupName + 7);
  2645. const char* ptr = strrchr(agentName.str(), '_');
  2646. if (isEmptyString(ptr) || isEmptyString(++ptr))
  2647. return true;
  2648. const char* ptrSuffix = ptr - 1;
  2649. do
  2650. {
  2651. if (!isdigit(ptr[0]))
  2652. return true;
  2653. ptr++;
  2654. } while(!isEmptyString(ptr));
  2655. agentName.setLength(agentName.length() - (ptr - ptrSuffix));
  2656. return true;
  2657. }
  2658. void Cws_machineEx::getThorClusterNamesByGroupName(IPropertyTree* envRoot, const char* group, StringArray& thorClusterNames)
  2659. {
  2660. Owned<IPropertyTreeIterator> thorClusters= envRoot->getElements("Software/ThorCluster");
  2661. ForEach(*thorClusters)
  2662. {
  2663. IPropertyTree& thorCluster = thorClusters->query();
  2664. const char *nodeGroupName = thorCluster.queryProp("@nodeGroup");
  2665. if (!isEmptyString(nodeGroupName) && !strieq(nodeGroupName, group))
  2666. continue;
  2667. if (!isEmptyString(nodeGroupName))
  2668. thorClusterNames.append(nodeGroupName);
  2669. else
  2670. {
  2671. const char *name = thorCluster.queryProp("@name");
  2672. if (strieq(name, group))
  2673. thorClusterNames.append(name);
  2674. }
  2675. }
  2676. }
  2677. StringArray& Cws_machineEx::listThorHThorNodeGroups(IConstEnvironment* constEnv, StringArray& nodeGroups)
  2678. {
  2679. BoolHash uniqueThorClusterGroupNames;
  2680. Owned<IPropertyTree> envRoot = &constEnv->getPTree();
  2681. Owned<IPropertyTreeIterator> it =envRoot->getElements("Software/ThorCluster");
  2682. ForEach(*it)
  2683. {
  2684. IPropertyTree& cluster = it->query();
  2685. StringBuffer thorClusterGroupName;
  2686. getClusterGroupName(cluster, thorClusterGroupName);
  2687. if (!thorClusterGroupName.length())
  2688. continue;
  2689. bool* found = uniqueThorClusterGroupNames.getValue(thorClusterGroupName);
  2690. if (found && *found)
  2691. continue;
  2692. nodeGroups.append(thorClusterGroupName);
  2693. uniqueThorClusterGroupNames.setValue(thorClusterGroupName, true);
  2694. }
  2695. it.setown(envRoot->getElements("Software/EclAgentProcess"));
  2696. ForEach(*it)
  2697. {
  2698. IPropertyTree &cluster = it->query();
  2699. const char* name = cluster.queryProp("@name");
  2700. if (!name||!*name)
  2701. continue;
  2702. unsigned ins = 0;
  2703. Owned<IPropertyTreeIterator> insts = cluster.getElements("Instance");
  2704. ForEach(*insts)
  2705. {
  2706. ins++;
  2707. StringBuffer gname("hthor__");
  2708. gname.append(name);
  2709. if (ins>1)
  2710. gname.append('_').append(ins);
  2711. nodeGroups.append(gname);
  2712. }
  2713. }
  2714. return nodeGroups;
  2715. }
  2716. IPropertyTree* Cws_machineEx::getNodeGroupUsageReq(IEspGetNodeGroupUsageRequest& req, IConstEnvironment* constEnv)
  2717. {
  2718. StringArray& nodeGroups = req.getNodeGroups();
  2719. if (nodeGroups.empty())
  2720. listThorHThorNodeGroups(constEnv, nodeGroups);
  2721. if (nodeGroups.empty())
  2722. throw MakeStringException(ECLWATCH_INVALID_INPUT, "No node group found.");
  2723. Owned<IPropertyTree> usageReq = createPTree("Req");
  2724. Owned<IPropertyTree> envRoot = &constEnv->getPTree();
  2725. ForEachItemIn(i, nodeGroups)
  2726. {
  2727. const char* nodeGroupName = nodeGroups.item(i);
  2728. if (isEmptyString(nodeGroupName))
  2729. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Empty node group specified.");
  2730. Owned<IPropertyTree> nodeGroupTree = createPTree("NodeGroup");
  2731. nodeGroupTree->addProp("@name", nodeGroupName);
  2732. StringBuffer agentName;
  2733. if (getEclAgentNameFromNodeGroupName(nodeGroupName, agentName))
  2734. readOtherComponentUsageReq(agentName.str(), eqEclAgent, constEnv, nodeGroupTree);
  2735. else
  2736. {
  2737. StringArray thorNames;
  2738. getThorClusterNamesByGroupName(envRoot, nodeGroupName, thorNames);
  2739. if (thorNames.length() == 0)
  2740. throw MakeStringException(ECLWATCH_INVALID_INPUT, "No thor/hthor can be found for node group name %s.", nodeGroupName);
  2741. ForEachItemIn(ii, thorNames)
  2742. readThorUsageReq(thorNames.item(ii), constEnv, nodeGroupTree);
  2743. }
  2744. usageReq->addPropTree(nodeGroupTree->queryName(), LINK(nodeGroupTree));
  2745. }
  2746. return usageReq.getClear();
  2747. }
  2748. void Cws_machineEx::readNodeGroupUsageResult(IEspContext& context, IPropertyTree* usageReq,
  2749. const IPropertyTree* uniqueUsages, IArrayOf<IEspNodeGroupUsage>& nodeGroupUsages)
  2750. {
  2751. Owned<IPropertyTreeIterator> nodeGroups= usageReq->getElements("NodeGroup");
  2752. ForEach(*nodeGroups)
  2753. {
  2754. IPropertyTree& nodeGroup = nodeGroups->query();
  2755. Owned<IEspNodeGroupUsage> nodeGroupUsage = createNodeGroupUsage();
  2756. nodeGroupUsage->setName(nodeGroup.queryProp("@name"));
  2757. IArrayOf<IEspComponentUsage> componentUsages;
  2758. readComponentUsageResult(context, &nodeGroup, uniqueUsages, componentUsages);
  2759. nodeGroupUsage->setComponentUsages(componentUsages);
  2760. nodeGroupUsages.append(*nodeGroupUsage.getClear());
  2761. }
  2762. }
  2763. bool Cws_machineEx::onGetNodeGroupUsage(IEspContext& context, IEspGetNodeGroupUsageRequest& req,
  2764. IEspGetNodeGroupUsageResponse& resp)
  2765. {
  2766. try
  2767. {
  2768. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Read, ECLWATCH_MACHINE_INFO_ACCESS_DENIED, "Failed to Get Machine Information. Permission denied.");
  2769. double version = context.getClientVersion();
  2770. StringBuffer timeStr;
  2771. IArrayOf<IEspNodeGroupUsage> nodeGroupUsages;
  2772. Owned<IEnvironmentFactory> envFactory = getEnvironmentFactory(true);
  2773. Owned<IConstEnvironment> constEnv = envFactory->openEnvironment();
  2774. Owned<IPropertyTree> usageReq = getNodeGroupUsageReq(req, constEnv);
  2775. Owned<CUsageCache> usage;
  2776. Owned<const IPropertyTree> uniqueUsages;
  2777. if (req.getBypassCachedResult())
  2778. {
  2779. Owned<IPropertyTree> tmpUniqueUsages = createPTree("Usage");
  2780. Owned<IPropertyTreeIterator> nodeGroupItr= usageReq->getElements("NodeGroup");
  2781. ForEach(*nodeGroupItr)
  2782. {
  2783. IPropertyTree& nodeGroup = nodeGroupItr->query();
  2784. setUniqueMachineUsageReq(&nodeGroup, tmpUniqueUsages);
  2785. }
  2786. getMachineUsages(context, tmpUniqueUsages);
  2787. uniqueUsages.setown(tmpUniqueUsages.getClear());
  2788. }
  2789. else
  2790. {
  2791. usage.setown((CUsageCache*) usageCacheReader->getCachedInfo());
  2792. if (!usage)
  2793. throw MakeStringException(ECLWATCH_INTERNAL_ERROR, "Failed to get usage. Please try later.");
  2794. ESPLOG(LogMax, "GetNodeGroupUsage: found UsageCache.");
  2795. uniqueUsages.set(usage->queryUsages());
  2796. }
  2797. readNodeGroupUsageResult(context, usageReq, uniqueUsages, nodeGroupUsages);
  2798. if (version >= 1.17)
  2799. resp.setUsageTime(setUsageTimeStr(usage, timeStr));
  2800. resp.setNodeGroupUsages(nodeGroupUsages);
  2801. }
  2802. catch(IException* e)
  2803. {
  2804. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  2805. }
  2806. return true;
  2807. }
  2808. bool Cws_machineEx::onGetComponentStatus(IEspContext &context, IEspGetComponentStatusRequest &req, IEspGetComponentStatusResponse &resp)
  2809. {
  2810. try
  2811. {
  2812. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Read, ECLWATCH_MACHINE_INFO_ACCESS_DENIED, "Failed to Get Component Status. Permission denied.");
  2813. Owned<IComponentStatusFactory> factory = getComponentStatusFactory();
  2814. Owned<IESPComponentStatusInfo> status = factory->getComponentStatus();
  2815. if (!status) //Should never happen
  2816. return false;
  2817. int statusID = status->getComponentStatusID();
  2818. if (statusID < 0)
  2819. {
  2820. resp.setStatus("Not reported");
  2821. }
  2822. else
  2823. {
  2824. resp.setComponentType(status->getComponentType());
  2825. resp.setEndPoint(status->getEndPoint());
  2826. resp.setReporter(status->getReporter());
  2827. resp.setComponentStatus(status->getComponentStatus());
  2828. resp.setTimeReportedStr(status->getTimeReportedStr());
  2829. IConstStatusReport* componentStatus = status->getStatusReport();
  2830. if (componentStatus)
  2831. resp.setStatusReport(*componentStatus);
  2832. resp.setComponentStatusList(status->getComponentStatusList());
  2833. }
  2834. resp.setComponentStatusID(statusID);
  2835. resp.setStatusCode(0);
  2836. }
  2837. catch(IException* e)
  2838. {
  2839. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  2840. }
  2841. return true;
  2842. }
  2843. bool Cws_machineEx::onUpdateComponentStatus(IEspContext &context, IEspUpdateComponentStatusRequest &req, IEspUpdateComponentStatusResponse &resp)
  2844. {
  2845. try
  2846. {
  2847. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Write, ECLWATCH_MACHINE_INFO_ACCESS_DENIED, "Failed to Update Component Status. Permission denied.");
  2848. const char* reporter = req.getReporter();
  2849. if (!reporter || !*reporter)
  2850. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Report not specified.");
  2851. Owned<IComponentStatusFactory> factory = getComponentStatusFactory();
  2852. factory->updateComponentStatus(reporter, req.getComponentStatusList());
  2853. resp.setStatusCode(0);
  2854. }
  2855. catch(IException* e)
  2856. {
  2857. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  2858. }
  2859. return true;
  2860. }
  2861. CInfoCache* CUsageCacheReader::read()
  2862. {
  2863. Owned<IPropertyTree> uniqueUsages = getUsageReqAllMachines();
  2864. //Send usage command to each machine
  2865. Owned<IEspContext> espContext = createEspContext();
  2866. servicePtr->getMachineUsages(*espContext, uniqueUsages);
  2867. Owned<CUsageCache> usageCache = new CUsageCache();
  2868. usageCache->setUsages(uniqueUsages.getClear());
  2869. return usageCache.getClear();
  2870. }
  2871. IPropertyTree* CUsageCacheReader::getUsageReqAllMachines()
  2872. {
  2873. //Collect network addresses and HPCC folders for all HPCC machines.
  2874. Owned<IEnvironmentFactory> envFactory = getEnvironmentFactory(true);
  2875. Owned<IConstEnvironment> constEnv = envFactory->openEnvironment();
  2876. IArrayOf<IConstComponent> componentList;
  2877. servicePtr->listComponentsForCheckingUsage(constEnv, componentList);
  2878. //Create a PTree which will be used to store the usages of all HPCC machines.
  2879. Owned<IPropertyTree> uniqueUsages = createPTree("Usage");
  2880. //Store the network addresses and HPCC folders into the PTree.
  2881. //Their usages may be added by calling servicePtr->getMachineUsages().
  2882. ForEachItemIn(i, componentList)
  2883. {
  2884. IConstComponent& component = componentList.item(i);
  2885. const char* type = component.getType();
  2886. if (isEmptyString(type))
  2887. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Empty Component Type");
  2888. if (strieq(type, eqThorCluster))
  2889. addClusterUsageReq(constEnv, component.getName(), true, uniqueUsages);
  2890. else if (strieq(type, eqRoxieCluster))
  2891. addClusterUsageReq(constEnv, component.getName(), false, uniqueUsages);
  2892. else if (strieq(type, eqDropZone))
  2893. addDropZoneUsageReq(constEnv, component.getName(), uniqueUsages);
  2894. else
  2895. addOtherComponentUsageReq(constEnv, component.getName(), type, uniqueUsages);
  2896. }
  2897. return uniqueUsages.getClear();
  2898. }
  2899. void CUsageCacheReader::addClusterUsageReq(IConstEnvironment* constEnv, const char* name, bool thorCluster, IPropertyTree* usageReq)
  2900. {
  2901. if (isEmptyString(name))
  2902. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Empty cluster name");
  2903. Owned<IPropertyTree> envRoot = &constEnv->getPTree();
  2904. IPropertyTree* envDirectories = envRoot->queryPropTree("Software/Directories");
  2905. Owned<IPropertyTree> logFolderReq = servicePtr->createDiskUsageReq(envDirectories, "log", thorCluster ? "thor" : "roxie", name);
  2906. Owned<IPropertyTree> dataFolderReq = servicePtr->createDiskUsageReq(envDirectories, "data", thorCluster ? "thor" : "roxie", name);
  2907. Owned<IPropertyTree> repFolderReq;
  2908. if (thorCluster)
  2909. repFolderReq.setown(servicePtr->createDiskUsageReq(envDirectories, "mirror", "thor", name));
  2910. StringBuffer xpath;
  2911. if (thorCluster)
  2912. xpath.setf("Software/ThorCluster[@name='%s']/ThorSlaveProcess", name);
  2913. else
  2914. xpath.setf("Software/RoxieCluster[@name='%s']/RoxieServerProcess", name);
  2915. Owned<IPropertyTreeIterator> processes= envRoot->getElements(xpath);
  2916. ForEach(*processes)
  2917. {
  2918. IPropertyTree& process = processes->query();
  2919. const char* computer = process.queryProp("@computer");
  2920. if (isEmptyString(computer))
  2921. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get @computer for %s", xpath.str());
  2922. checkAndAddMachineUsageReq(constEnv, computer, logFolderReq, dataFolderReq, repFolderReq, usageReq);
  2923. }
  2924. if (!thorCluster)
  2925. return;
  2926. //Read ThorMasterProcess in case it is on a different machine
  2927. xpath.setf("Software/ThorCluster[@name='%s']/ThorMasterProcess/@computer", name);
  2928. const char* computer = envRoot->queryProp(xpath);
  2929. if (isEmptyString(computer))
  2930. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get %s", xpath.str());
  2931. checkAndAddMachineUsageReq(constEnv, computer, logFolderReq, dataFolderReq, repFolderReq, usageReq);
  2932. }
  2933. void CUsageCacheReader::checkAndAddMachineUsageReq(IConstEnvironment* constEnv, const char* computer, IPropertyTree* logFolderReq,
  2934. IPropertyTree* dataFolderReq, IPropertyTree* repFolderReq, IPropertyTree* usageReq)
  2935. {
  2936. Owned<IPropertyTree> machineReq = servicePtr->createMachineUsageReq(constEnv, computer);
  2937. VStringBuffer xpath("Machine[@netAddress='%s']", machineReq->queryProp("@netAddress"));
  2938. IPropertyTree* foundMachineReqTree = usageReq->queryPropTree(xpath);
  2939. if (!foundMachineReqTree)
  2940. {
  2941. //Not sure we need those folders here. Add them just in case.
  2942. if (logFolderReq)
  2943. machineReq->addPropTree(logFolderReq->queryName(), LINK(logFolderReq));
  2944. if (dataFolderReq)
  2945. machineReq->addPropTree(dataFolderReq->queryName(), LINK(dataFolderReq));
  2946. if (repFolderReq)
  2947. machineReq->addPropTree(repFolderReq->queryName(), LINK(repFolderReq));
  2948. usageReq->addPropTree(machineReq->queryName(), LINK(machineReq));
  2949. return;
  2950. }
  2951. //Add unique disk folders
  2952. checkAndAddFolderReq(logFolderReq, foundMachineReqTree);
  2953. checkAndAddFolderReq(dataFolderReq, foundMachineReqTree);
  2954. checkAndAddFolderReq(repFolderReq, foundMachineReqTree);
  2955. }
  2956. void CUsageCacheReader::checkAndAddFolderReq(IPropertyTree* folderReq, IPropertyTree* machineReqTree)
  2957. {
  2958. if (!folderReq)
  2959. return;
  2960. //Add unique disk folders
  2961. VStringBuffer xpath("Folder[@path='%s']", folderReq->queryProp("@path"));
  2962. if (!machineReqTree->queryPropTree(xpath))
  2963. machineReqTree->addPropTree(folderReq->queryName(), LINK(folderReq));
  2964. }
  2965. void CUsageCacheReader::addDropZoneUsageReq(IConstEnvironment* constEnv, const char* name, IPropertyTree* usageReq)
  2966. {
  2967. if (isEmptyString(name))
  2968. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Empty DropZone name");
  2969. Owned<IConstDropZoneInfo> envDropZone = constEnv->getDropZone(name);
  2970. if (!envDropZone)
  2971. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Dropzone %s not found", name);
  2972. if (!envDropZone->isECLWatchVisible())
  2973. return;
  2974. SCMStringBuffer directory;
  2975. envDropZone->getDirectory(directory);
  2976. if (directory.length() == 0)
  2977. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get directory for DropZone %s", name);
  2978. Owned<IPropertyTree> dataFolder = createPTree("Folder");
  2979. dataFolder->addProp("@name", "data");
  2980. dataFolder->addProp("@path", directory.str());
  2981. SCMStringBuffer computerName;
  2982. envDropZone->getComputerName(computerName);
  2983. if (computerName.length() == 0)
  2984. {
  2985. OS_TYPE os = (getPathSepChar(directory.str()) == '/') ? OS_LINUX : OS_WINDOWS;
  2986. Owned<IConstDropZoneServerInfoIterator> servers = envDropZone->getServers();
  2987. ForEach(*servers)
  2988. {
  2989. IConstDropZoneServerInfo& server = servers->query();
  2990. StringBuffer serverNetAddress;
  2991. server.getServer(serverNetAddress.clear());
  2992. VStringBuffer xpath("Machine[@netAddress='%s']", serverNetAddress.str());
  2993. IPropertyTree* foundMachineReqTree = usageReq->queryPropTree(xpath);
  2994. if (foundMachineReqTree)
  2995. {
  2996. checkAndAddFolderReq(dataFolder, foundMachineReqTree);
  2997. continue;
  2998. }
  2999. Owned<IPropertyTree> machineReq = createPTree("Machine");
  3000. machineReq->addProp("@name", serverNetAddress.str());
  3001. machineReq->addProp("@netAddress", serverNetAddress.str());
  3002. machineReq->addPropInt("@OS", os);
  3003. machineReq->addPropTree(dataFolder->queryName(), LINK(dataFolder));
  3004. usageReq->addPropTree(machineReq->queryName(), LINK(machineReq));
  3005. }
  3006. }
  3007. else
  3008. { //legacy dropzone settings
  3009. checkAndAddMachineUsageReq(constEnv, computerName.str(), nullptr, dataFolder, nullptr, usageReq);
  3010. }
  3011. }
  3012. void CUsageCacheReader::addOtherComponentUsageReq(IConstEnvironment* constEnv, const char* name, const char* type, IPropertyTree* usageReq)
  3013. {
  3014. if (isEmptyString(name))
  3015. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Empty Component name");
  3016. const char* componentType = findComponentTypeFromProcessType(type);
  3017. if (!componentType)
  3018. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Component usage function is not supported for %s", type);
  3019. //Find disk folders for log, data, etc.
  3020. Owned<IPropertyTree> envRoot = &constEnv->getPTree();
  3021. IPropertyTree* envDirectories = envRoot->queryPropTree("Software/Directories");
  3022. Owned<IPropertyTree> dataFolder = servicePtr->createDiskUsageReq(envDirectories, "data", componentType, name);
  3023. Owned<IPropertyTree> logFolder = servicePtr->createDiskUsageReq(envDirectories, "log", componentType, name);
  3024. Owned<IPropertyTree> repFolder;
  3025. if (strieq(type, eqDali))
  3026. repFolder.setown(servicePtr->createDiskUsageReq(envDirectories, "mirror", "dali", name));
  3027. VStringBuffer xpath("Software/%s[@name='%s']/Instance", type, name);
  3028. Owned<IPropertyTreeIterator> it = envRoot->getElements(xpath);
  3029. ForEach(*it)
  3030. {
  3031. IPropertyTree& instance = it->query();
  3032. const char* computer = instance.queryProp("@computer");
  3033. if (isEmptyString(computer))
  3034. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Failed to get @computer for %s", xpath.str());
  3035. checkAndAddMachineUsageReq(constEnv, computer, logFolder, dataFolder, repFolder, usageReq);
  3036. }
  3037. }