ws_smcService.cpp 87 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297
  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. #pragma warning (disable : 4786)
  14. #include "build-config.h"
  15. #ifdef _USE_OPENLDAP
  16. #include "ldapsecurity.ipp"
  17. #endif
  18. #include "ws_smcService.hpp"
  19. #include "wshelpers.hpp"
  20. #include "dalienv.hpp"
  21. #include "WUWrapper.hpp"
  22. #include "wujobq.hpp"
  23. #include "dfuwu.hpp"
  24. #include "exception_util.hpp"
  25. #include "roxiecontrol.hpp"
  26. #include "workunit.hpp"
  27. #define STATUS_SERVER_THOR "ThorMaster"
  28. #define STATUS_SERVER_HTHOR "HThorServer"
  29. #define STATUS_SERVER_ROXIE "RoxieServer"
  30. #define STATUS_SERVER_DFUSERVER "DFUserver"
  31. #define STATUS_SERVER_ECLSERVER "ECLserver"
  32. #define STATUS_SERVER_ECLCCSERVER "ECLCCserver"
  33. #define STATUS_SERVER_ECLAGENT "ECLagent"
  34. static const char* FEATURE_URL = "SmcAccess";
  35. const char* THORQUEUE_FEATURE = "ThorQueueAccess";
  36. static const char* ROXIE_CONTROL_URL = "RoxieControlAccess";
  37. static const char* OWN_WU_ACCESS = "OwnWorkunitsAccess";
  38. static const char* OTHERS_WU_ACCESS = "OthersWorkunitsAccess";
  39. const char* PERMISSIONS_FILENAME = "espsmc_permissions.xml";
  40. const unsigned DEFAULTACTIVITYINFOCACHETIMEOUTSECOND = 10;
  41. void AccessSuccess(IEspContext& context, char const * msg,...) __attribute__((format(printf, 2, 3)));
  42. void AccessSuccess(IEspContext& context, char const * msg,...)
  43. {
  44. StringBuffer buf;
  45. buf.appendf("User %s: ",context.queryUserId());
  46. va_list args;
  47. va_start(args, msg);
  48. buf.valist_appendf(msg, args);
  49. va_end(args);
  50. AUDIT(AUDIT_TYPE_ACCESS_SUCCESS,buf.str());
  51. }
  52. void AccessFailure(IEspContext& context, char const * msg,...) __attribute__((format(printf, 2, 3)));
  53. void AccessFailure(IEspContext& context, char const * msg,...)
  54. {
  55. StringBuffer buf;
  56. buf.appendf("User %s: ",context.queryUserId());
  57. va_list args;
  58. va_start(args, msg);
  59. buf.valist_appendf(msg, args);
  60. va_end(args);
  61. AUDIT(AUDIT_TYPE_ACCESS_FAILURE,buf.str());
  62. }
  63. struct QueueWrapper
  64. {
  65. QueueWrapper(const char* targetName, const char* queueExt)
  66. {
  67. StringBuffer name;
  68. name.append(targetName).append('.').append(queueExt);
  69. queue.setown(createJobQueue(name.str()));
  70. }
  71. QueueWrapper(const char* queueName)
  72. {
  73. queue.setown(createJobQueue(queueName));
  74. }
  75. operator IJobQueue*() { return queue.get(); }
  76. IJobQueue* operator->() { return queue.get(); }
  77. Owned<IJobQueue> queue;
  78. };
  79. struct QueueLock
  80. {
  81. QueueLock(IJobQueue* q): queue(q) { queue->lock(); }
  82. ~QueueLock()
  83. {
  84. queue->unlock();
  85. }
  86. Linked<IJobQueue> queue;
  87. };
  88. static int sortTargetClustersByNameDescending(IInterface **L, IInterface **R)
  89. {
  90. IEspTargetCluster *left = (IEspTargetCluster *) *L;
  91. IEspTargetCluster *right = (IEspTargetCluster *) *R;
  92. return strcmp(right->getClusterName(), left->getClusterName());
  93. }
  94. static int sortTargetClustersByNameAscending(IInterface **L, IInterface **R)
  95. {
  96. IEspTargetCluster *left = (IEspTargetCluster *) *L;
  97. IEspTargetCluster *right = (IEspTargetCluster *) *R;
  98. return strcmp(left->getClusterName(), right->getClusterName());
  99. }
  100. static int sortTargetClustersBySizeDescending(IInterface **L, IInterface **R)
  101. {
  102. IEspTargetCluster *left = (IEspTargetCluster *) *L;
  103. IEspTargetCluster *right = (IEspTargetCluster *) *R;
  104. return right->getClusterSize() - left->getClusterSize();
  105. }
  106. static int sortTargetClustersBySizeAscending(IInterface **L, IInterface **R)
  107. {
  108. IEspTargetCluster *left = (IEspTargetCluster *) *L;
  109. IEspTargetCluster *right = (IEspTargetCluster *) *R;
  110. return left->getClusterSize() - right->getClusterSize();
  111. }
  112. void CWsSMCEx::init(IPropertyTree *cfg, const char *process, const char *service)
  113. {
  114. if (!daliClientActive())
  115. {
  116. ERRLOG("No Dali Connection Active.");
  117. throw MakeStringException(-1, "No Dali Connection Active. Please Specify a Dali to connect to in you configuration file");
  118. }
  119. m_BannerAction = 0;
  120. m_EnableChatURL = false;
  121. m_BannerSize = "4";
  122. m_BannerColor = "red";
  123. m_BannerScroll = "2";
  124. StringBuffer xpath;
  125. xpath.appendf("Software/EspProcess[@name='%s']/@portalurl", process);
  126. const char* portalURL = cfg->queryProp(xpath.str());
  127. if (portalURL && *portalURL)
  128. m_PortalURL.append(portalURL);
  129. xpath.setf("Software/EspProcess[@name=\"%s\"]/EspService[@name=\"%s\"]/ActivityInfoCacheSeconds", process, service);
  130. activityInfoCacheSeconds = cfg->getPropInt(xpath.str(), DEFAULTACTIVITYINFOCACHETIMEOUTSECOND);
  131. }
  132. static void countProgress(IPropertyTree *t,unsigned &done,unsigned &total)
  133. {
  134. total = 0;
  135. done = 0;
  136. Owned<IPropertyTreeIterator> it = t->getElements("DFT/progress");
  137. ForEach(*it) {
  138. IPropertyTree &e=it->query();
  139. if (e.getPropInt("@done",0))
  140. done++;
  141. total++;
  142. }
  143. }
  144. struct CActiveWorkunitWrapper: public CActiveWorkunit
  145. {
  146. CActiveWorkunitWrapper(IEspContext &context, const char* wuid,const char* location = NULL,unsigned index=0): CActiveWorkunit("","")
  147. {
  148. CWUWrapper wu(wuid, context);
  149. setActiveWorkunit(wu, wuid, location, index, context.getClientVersion(), false);
  150. }
  151. CActiveWorkunitWrapper(const char* wuid, const char* location = NULL, unsigned index=0): CActiveWorkunit("","")
  152. {
  153. CWUWrapper wu(wuid);
  154. setActiveWorkunit(wu, wuid, location, index, 0.0, true);
  155. }
  156. CActiveWorkunitWrapper(const char* wuid,const char* owner, const char* jobname, const char* state, const char* priority): CActiveWorkunit("","")
  157. {
  158. setWuid(wuid);
  159. setState(state);
  160. setOwner(owner);
  161. setJobname(jobname);
  162. setPriority(priority);
  163. }
  164. void setActiveWorkunit(CWUWrapper& wu, const char* wuid, const char* location, unsigned index, double version, bool notCheckVersion)
  165. {
  166. StringBuffer stateStr;
  167. SCMStringBuffer state, stateEx, owner, jobname;
  168. setWuid(wuid);
  169. wu->getStateDesc(state);
  170. setStateID(wu->getState());
  171. if (wu->getState() == WUStateBlocked)
  172. {
  173. wu->getStateEx(stateEx);
  174. if (notCheckVersion || (version > 1.00))
  175. setExtra(stateEx.str());
  176. }
  177. buildAndSetState(state.str(), stateEx.str(), location, index);
  178. if ((notCheckVersion || (version > 1.09)) && (wu->getState() == WUStateFailed))
  179. setWarning("The job will ultimately not complete. Please check ECLAgent.");
  180. setOwner(wu->getUser(owner).str());
  181. setJobname(wu->getJobName(jobname).str());
  182. setPriorityStr(wu->getPriority());
  183. if ((notCheckVersion || (version > 1.08)) && wu->isPausing())
  184. {
  185. setIsPausing(true);
  186. }
  187. if (notCheckVersion || (version > 1.14))
  188. {
  189. SCMStringBuffer clusterName;
  190. setClusterName(wu->getClusterName(clusterName).str());
  191. }
  192. }
  193. void buildAndSetState(const char* state, const char* stateEx, const char* location, unsigned index)
  194. {
  195. if (!state || !*state)
  196. return;
  197. StringBuffer stateStr;
  198. if(index && location && *location)
  199. stateStr.setf("queued(%d) [%s on %s]", index, state, location);
  200. else if(index)
  201. stateStr.setf("queued(%d) [%s]", index, state);
  202. else if(location && *location)
  203. stateStr.setf("%s [%s]", state, location);
  204. else
  205. stateStr.set(state);
  206. if (stateEx && *stateEx)
  207. stateStr.appendf(" %s", stateEx);
  208. setState(stateStr.str());
  209. }
  210. void setPriorityStr(unsigned priorityType)
  211. {
  212. switch(priorityType)
  213. {
  214. case PriorityClassHigh: setPriority("high"); break;
  215. default:
  216. case PriorityClassNormal: setPriority("normal"); break;
  217. case PriorityClassLow: setPriority("low"); break;
  218. }
  219. return;
  220. }
  221. };
  222. bool CWsSMCEx::onIndex(IEspContext &context, IEspSMCIndexRequest &req, IEspSMCIndexResponse &resp)
  223. {
  224. resp.setRedirectUrl("/");
  225. return true;
  226. }
  227. static int stringcmp(const char **a, const char **b)
  228. {
  229. return strcmp(*a, *b);
  230. }
  231. bool isInWuList(IArrayOf<IEspActiveWorkunit>& aws, const char* wuid)
  232. {
  233. bool bFound = false;
  234. if (wuid && *wuid && (aws.length() > 0))
  235. {
  236. ForEachItemIn(k, aws)
  237. {
  238. IEspActiveWorkunit& wu = aws.item(k);
  239. const char* wuid0 = wu.getWuid();
  240. const char* server0 = wu.getServer();
  241. if (wuid0 && !strcmp(wuid0, wuid) && (!server0 || strcmp(server0, "ECLagent")))
  242. {
  243. bFound = true;
  244. break;
  245. }
  246. }
  247. }
  248. return bFound;
  249. }
  250. void CWsSMCEx::readBannerAndChatRequest(IEspContext& context, IEspActivityRequest &req, IEspActivityResponse& resp)
  251. {
  252. StringBuffer chatURLStr, bannerStr;
  253. const char* chatURL = req.getChatURL();
  254. const char* banner = req.getBannerContent();
  255. //Filter out invalid chars
  256. if (chatURL && *chatURL)
  257. {
  258. const char* pStr = chatURL;
  259. unsigned len = strlen(chatURL);
  260. for (unsigned i = 0; i < len; i++)
  261. {
  262. if (isprint(*pStr))
  263. chatURLStr.append(*pStr);
  264. pStr++;
  265. }
  266. }
  267. if (banner && *banner)
  268. {
  269. const char* pStr = banner;
  270. unsigned len = strlen(banner);
  271. for (unsigned i = 0; i < len; i++)
  272. {
  273. bannerStr.append(isprint(*pStr) ? *pStr : '.');
  274. pStr++;
  275. }
  276. }
  277. chatURLStr.trim();
  278. bannerStr.trim();
  279. if (!req.getBannerAction_isNull() && req.getBannerAction() && (bannerStr.length() < 1))
  280. throw MakeStringException(ECLWATCH_MISSING_BANNER_CONTENT, "If a Banner is enabled, the Banner content must be specified.");
  281. if (!req.getEnableChatURL_isNull() && req.getEnableChatURL() && (chatURLStr.length() < 1))
  282. throw MakeStringException(ECLWATCH_MISSING_CHAT_URL, "If a Chat is enabled, the Chat URL must be specified.");
  283. //Now, store the strings since they are valid.
  284. m_ChatURL = chatURLStr;
  285. m_Banner = bannerStr;
  286. const char* bannerSize = req.getBannerSize();
  287. if (bannerSize && *bannerSize)
  288. m_BannerSize.set(bannerSize);
  289. const char* bannerColor = req.getBannerColor();
  290. if (bannerColor && *bannerColor)
  291. m_BannerColor.set(bannerColor);
  292. const char* bannerScroll = req.getBannerScroll();
  293. if (bannerScroll && *bannerScroll)
  294. m_BannerScroll.set(bannerScroll);
  295. m_BannerAction = req.getBannerAction();
  296. if(!req.getEnableChatURL_isNull())
  297. m_EnableChatURL = req.getEnableChatURL();
  298. }
  299. void CWsSMCEx::setBannerAndChatData(double version, IEspActivityResponse& resp)
  300. {
  301. resp.setShowBanner(m_BannerAction);
  302. resp.setShowChatURL(m_EnableChatURL);
  303. resp.setBannerContent(m_Banner.str());
  304. resp.setBannerSize(m_BannerSize.str());
  305. resp.setBannerColor(m_BannerColor.str());
  306. resp.setChatURL(m_ChatURL.str());
  307. if (version >= 1.08)
  308. resp.setBannerScroll(m_BannerScroll.str());
  309. }
  310. void CWsSMCEx::createActiveWorkUnit(Owned<IEspActiveWorkunit>& ownedWU, IEspContext &context, const char* wuid, const char* location,
  311. unsigned index, const char* serverName, const char* queueName, const char* instanceName, const char* targetClusterName, bool useContext)
  312. {
  313. try
  314. {
  315. if (useContext)
  316. ownedWU.setown(new CActiveWorkunitWrapper(context, wuid, location, index));
  317. else
  318. ownedWU.setown(new CActiveWorkunitWrapper(wuid, location, index));
  319. }
  320. catch (IException *e)
  321. { //if the wu cannot be opened for some reason, the openWorkUnit() inside the CActiveWorkunitWrapper() may throw an exception.
  322. //We do not want the exception stops this process of retrieving/showing all active WUs. And that WU should still be displayed
  323. //with the exception.
  324. StringBuffer msg;
  325. ownedWU.setown(new CActiveWorkunitWrapper(wuid, "", "", e->errorMessage(msg).str(), "normal"));
  326. ownedWU->setStateID(WUStateUnknown);
  327. e->Release();
  328. }
  329. ownedWU->setServer(serverName);
  330. ownedWU->setQueueName(queueName);
  331. if (instanceName && *instanceName)
  332. ownedWU->setInstance(instanceName); // JCSMORE In thor case at least, if queued it is unknown which instance it will run on..
  333. if (targetClusterName && *targetClusterName)
  334. ownedWU->setTargetClusterName(targetClusterName);
  335. }
  336. void CWsSMCEx::readWUsAndStateFromJobQueue(IEspContext& context, CWsSMCTargetCluster& targetCluster,
  337. CWsSMCQueue& jobQueue, const char* queueName, BoolHash& uniqueWUIDs, IArrayOf<IEspActiveWorkunit>& aws)
  338. {
  339. CJobQueueContents contents;
  340. Owned<IJobQueue> queue = createJobQueue(jobQueue.queueName.str());
  341. queue->copyItemsAndState(contents, jobQueue.queueState, jobQueue.queueStateDetails);
  342. Owned<IJobQueueIterator> iter = contents.getIterator();
  343. jobQueue.countQueuedJobs=0;
  344. ForEach(*iter)
  345. {
  346. const char* wuid = iter->query().queryWUID();
  347. if (!wuid || !*wuid || uniqueWUIDs.getValue(wuid))
  348. continue;
  349. uniqueWUIDs.setValue(wuid, true);
  350. const char* queue = NULL;
  351. if (queueName && *queueName)
  352. queue = queueName;
  353. else
  354. queue = targetCluster.clusterName.get();
  355. Owned<IEspActiveWorkunit> wu;
  356. createActiveWorkUnit(wu, context, wuid, jobQueue.queueName.str(), ++jobQueue.countQueuedJobs, targetCluster.statusServerName.str(),
  357. queue, NULL, targetCluster.clusterName.get(), false);
  358. aws.append(*wu.getLink());
  359. }
  360. }
  361. bool CWsSMCEx::findQueueInStatusServer(IEspContext& context, IPropertyTree* serverStatusRoot, const char* serverName, const char* queueName)
  362. {
  363. bool foundServer = false;
  364. VStringBuffer path("Server[@name=\"%s\"]", serverName);
  365. Owned<IPropertyTreeIterator> it(serverStatusRoot->getElements(path.str()));
  366. ForEach(*it)
  367. {
  368. IPropertyTree& serverStatusNode = it->query();
  369. const char* queue = serverStatusNode.queryProp("@queue");
  370. if (!queue || !*queue)
  371. continue;
  372. StringArray qlist;
  373. qlist.appendListUniq(queue, ",");
  374. ForEachItemIn(q, qlist)
  375. {
  376. if (strieq(qlist.item(q), queueName))
  377. {
  378. foundServer = true;
  379. break;
  380. }
  381. }
  382. if (foundServer)
  383. break;
  384. }
  385. return foundServer;
  386. }
  387. void CWsSMCEx::sortTargetClusters(IArrayOf<IEspTargetCluster>& clusters, const char* sortBy, bool descending)
  388. {
  389. if (!sortBy || !*sortBy || strieq(sortBy, "name"))
  390. clusters.sort(descending ? sortTargetClustersByNameDescending : sortTargetClustersByNameAscending);
  391. else
  392. clusters.sort(descending ? sortTargetClustersBySizeDescending : sortTargetClustersBySizeAscending);
  393. }
  394. void CWsSMCEx::setClusterQueueStatus(CWsSMCTargetCluster& targetCluster)
  395. {
  396. CWsSMCQueue& jobQueue = targetCluster.clusterQueue;
  397. if (targetCluster.clusterType != ThorLCRCluster)
  398. jobQueue = targetCluster.agentQueue;
  399. if (!jobQueue.queueName.length())
  400. return;
  401. targetCluster.clusterStatusDetails.appendf("%s: ", jobQueue.queueName.str());
  402. bool queuePausedOrStopped = false;
  403. unsigned countRunningJobs = jobQueue.countRunningJobs;
  404. unsigned countQueuedJobs = jobQueue.countQueuedJobs;
  405. if (targetCluster.clusterType == ThorLCRCluster)
  406. {
  407. countRunningJobs += targetCluster.agentQueue.countRunningJobs;
  408. countQueuedJobs += targetCluster.agentQueue.countQueuedJobs;
  409. }
  410. if (jobQueue.queueState.length())
  411. {
  412. const char* queueState = jobQueue.queueState.str();
  413. const char* queueStateDetails = jobQueue.queueStateDetails.str();
  414. if (queueStateDetails && *queueStateDetails)
  415. targetCluster.clusterStatusDetails.appendf("queue %s; %s;", queueState, queueStateDetails);
  416. else
  417. targetCluster.clusterStatusDetails.appendf("queue %s; ", queueState);
  418. if (strieq(queueState,"stopped") || strieq(queueState,"paused"))
  419. queuePausedOrStopped = true;
  420. }
  421. if (!jobQueue.foundQueueInStatusServer)
  422. {
  423. if (queuePausedOrStopped)
  424. jobQueue.statusType = QueuePausedOrStoppedNotFound;
  425. else
  426. jobQueue.statusType = QueueRunningNotFound;
  427. }
  428. else
  429. {
  430. if (queuePausedOrStopped)
  431. {
  432. if (jobQueue.countRunningJobs > 0)
  433. jobQueue.statusType = QueuePausedOrStoppedWithJobs;
  434. else
  435. jobQueue.statusType = QueuePausedOrStoppedWithNoJob;
  436. }
  437. }
  438. }
  439. void CWsSMCEx::setClusterStatus(IEspContext& context, CWsSMCTargetCluster& targetCluster, IEspTargetCluster* returnCluster)
  440. {
  441. setClusterQueueStatus(targetCluster);
  442. int statusType = (targetCluster.clusterQueue.statusType > targetCluster.agentQueue.statusType) ? targetCluster.clusterQueue.statusType
  443. : targetCluster.agentQueue.statusType;
  444. returnCluster->setClusterStatus(statusType);
  445. //Set 'Warning' which may be displayed beside cluster name
  446. if (statusType == QueueRunningNotFound)
  447. returnCluster->setWarning("Cluster not attached");
  448. else if (statusType == QueuePausedOrStoppedNotFound)
  449. returnCluster->setWarning("Queue paused or stopped - Cluster not attached");
  450. else if (statusType != RunningNormal)
  451. returnCluster->setWarning("Queue paused or stopped");
  452. //Set 'StatusDetails' which may be displayed when a mouse is moved over cluster icon
  453. if (targetCluster.clusterStatusDetails.length())
  454. returnCluster->setStatusDetails(targetCluster.clusterStatusDetails.str());
  455. }
  456. void CWsSMCEx::getWUsNotOnTargetCluster(IEspContext &context, IPropertyTree* serverStatusRoot, IArrayOf<IEspServerJobQueue>& serverJobQueues,
  457. IArrayOf<IEspActiveWorkunit>& aws)
  458. {
  459. BoolHash uniqueServers;
  460. Owned<IPropertyTreeIterator> it(serverStatusRoot->getElements("Server"));
  461. ForEach(*it)
  462. {
  463. IPropertyTree& serverNode = it->query();
  464. const char* serverName = serverNode.queryProp("@name");
  465. const char* instance = serverNode.queryProp("@node");
  466. const char* queueName = serverNode.queryProp("@queue");
  467. unsigned port = serverNode.getPropInt("@mpport", 0);
  468. if (!serverName || !*serverName || !instance || !*instance || strieq(serverName, "DFUserver") ||//DFUServer already handled separately
  469. strieq(serverName, "ThorMaster") || strieq(serverName, "RoxieServer") || strieq(serverName, "HThorServer"))//target clusters already handled separately
  470. continue;
  471. VStringBuffer instanceName("%s_on_%s:%d", serverName, instance, port);
  472. Owned<IPropertyTreeIterator> wuids(serverNode.getElements("WorkUnit"));
  473. ForEach(*wuids)
  474. {
  475. const char* wuid=wuids->query().queryProp(NULL);
  476. if (!wuid || !*wuid)
  477. continue;
  478. if (isInWuList(aws, wuid))
  479. continue;
  480. Owned<IEspActiveWorkunit> wu;
  481. createActiveWorkUnit(wu, context, wuid, NULL, 0, serverName, queueName, instance, NULL, false);
  482. aws.append(*wu.getLink());
  483. }
  484. if (!uniqueServers.getValue(instanceName))
  485. {
  486. uniqueServers.setValue(instanceName, true);
  487. addServerJobQueue(serverJobQueues, queueName, instanceName, serverName, instance, port);
  488. }
  489. }
  490. return;
  491. }
  492. void CWsSMCEx::readDFUWUs(IEspContext &context, const char* queueName, const char* serverName, IArrayOf<IEspActiveWorkunit>& aws)
  493. {
  494. StringAttrArray wulist;
  495. unsigned running = queuedJobs(queueName, wulist);
  496. ForEachItemIn(i, wulist)
  497. {
  498. StringBuffer jname, uname, state, error;
  499. const char *wuid = wulist.item(i).text.get();
  500. if (i<running)
  501. state.set("running");
  502. else
  503. state.set("queued");
  504. try
  505. {
  506. Owned<IConstDFUWorkUnit> dfuwu = getDFUWorkUnitFactory()->openWorkUnit(wuid, false);
  507. dfuwu->getUser(uname);
  508. dfuwu->getJobName(jname);
  509. }
  510. catch (IException *e)
  511. {
  512. e->errorMessage(error);
  513. state.appendf(" (%s)", error.str());
  514. e->Release();
  515. }
  516. Owned<IEspActiveWorkunit> wu(new CActiveWorkunitWrapper(wuid, uname.str(), jname.str(), state.str(), "normal"));
  517. wu->setServer("DFUserver");
  518. wu->setInstance(serverName);
  519. wu->setQueueName(queueName);
  520. aws.append(*wu.getLink());
  521. }
  522. }
  523. void CWsSMCEx::getDFUServersAndWUs(IEspContext &context, IPropertyTree* envRoot, IArrayOf<IEspServerJobQueue>& serverJobQueues, IArrayOf<IEspActiveWorkunit>& aws)
  524. {
  525. if (!envRoot)
  526. return;
  527. VStringBuffer path("Software/%s", eqDfu);
  528. Owned<IPropertyTreeIterator> services = envRoot->getElements(path);
  529. ForEach(*services)
  530. {
  531. IPropertyTree &serviceTree = services->query();
  532. const char *qname = serviceTree.queryProp("@queue");
  533. const char *serverName = serviceTree.queryProp("@name");
  534. if (!qname || !*qname)
  535. continue;
  536. StringArray queues;
  537. queues.appendListUniq(qname, ",");
  538. ForEachItemIn(q, queues)
  539. {
  540. const char *queueName = queues.item(q);
  541. readDFUWUs(context, queueName, serverName, aws);
  542. addServerJobQueue(serverJobQueues, queueName, serverName, "DFUserver", NULL, 0);
  543. }
  544. }
  545. }
  546. void CWsSMCEx::getDFURecoveryJobs(IEspContext &context, const IPropertyTree* dfuRecoveryRoot, IArrayOf<IEspDFUJob>& jobs)
  547. {
  548. if (!dfuRecoveryRoot)
  549. return;
  550. Owned<IPropertyTreeIterator> it(dfuRecoveryRoot->getElements("job"));
  551. ForEach(*it)
  552. {
  553. IPropertyTree &e=it->query();
  554. if (!e.getPropBool("Running",false))
  555. continue;
  556. StringBuffer cmd;
  557. unsigned done, total;
  558. countProgress(&e,done,total);
  559. cmd.append(e.queryProp("@command")).append(" ").append(e.queryProp("@command_parameters"));
  560. Owned<IEspDFUJob> job = new CDFUJob("","");
  561. job->setTimeStarted(e.queryProp("@time_started"));
  562. job->setDone(done);
  563. job->setTotal(total);
  564. job->setCommand(cmd.str());
  565. jobs.append(*job.getLink());
  566. }
  567. }
  568. bool ActivityInfo::isCachedActivityInfoValid(unsigned timeOutSeconds)
  569. {
  570. CDateTime timeNow;
  571. timeNow.setNow();
  572. return timeNow.getSimple() <= timeCached.getSimple() + timeOutSeconds;;
  573. }
  574. void CWsSMCEx::clearActivityInfoCache()
  575. {
  576. CriticalBlock b(getActivityCrit);
  577. activityInfoCache.clear();
  578. }
  579. ActivityInfo* CWsSMCEx::getActivityInfo(IEspContext &context, IEspActivityRequest &req)
  580. {
  581. CriticalBlock b(getActivityCrit);
  582. if (activityInfoCache && activityInfoCache->isCachedActivityInfoValid(activityInfoCacheSeconds))
  583. return activityInfoCache.getLink();
  584. DBGLOG("CWsSMCEx::getActivityInfo - rebuild cached information");
  585. activityInfoCache.setown(createActivityInfo(context, req));
  586. return activityInfoCache.getLink();
  587. }
  588. ActivityInfo* CWsSMCEx::createActivityInfo(IEspContext &context, IEspActivityRequest &req)
  589. {
  590. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  591. Owned<IConstEnvironment> env = factory->openEnvironment();
  592. if (!env)
  593. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO,"Failed to get environment information.");
  594. CConstWUClusterInfoArray clusters;
  595. Owned<IPropertyTree> envRoot= &env->getPTree();
  596. getEnvironmentClusterInfo(envRoot, clusters);
  597. Owned<IRemoteConnection> connStatusServers = querySDS().connect("/Status/Servers",myProcessSession(),RTM_LOCK_READ,30000);
  598. IPropertyTree* serverStatusRoot = connStatusServers->queryRoot();
  599. if (!serverStatusRoot)
  600. throw MakeStringException(ECLWATCH_CANNOT_GET_STATUS_INFO, "Failed to get status server information.");
  601. IPropertyTree* dfuRecoveryRoot = NULL;
  602. Owned<IRemoteConnection> connDFURecovery = querySDS().connect("DFU/RECOVERY",myProcessSession(), RTM_LOCK_READ, 30000);
  603. if (connDFURecovery)
  604. dfuRecoveryRoot = connDFURecovery->queryRoot();
  605. Owned<ActivityInfo> activityInfo = new ActivityInfo();
  606. readTargetClusterInfo(context, clusters, serverStatusRoot, activityInfo);
  607. readRunningWUsAndQueuedWUs(context, envRoot, serverStatusRoot, dfuRecoveryRoot, activityInfo);
  608. return activityInfo.getClear();
  609. }
  610. // This method reads job information from both /Status/Servers and IJobQueue.
  611. //
  612. // Each server component (a thor cluster, a dfuserver, or an eclagent) is one 'Server' branch under
  613. // /Status/Servers. A 'Server' branch has a @queue which indicates the queue name of the server.
  614. // A 'Server' branch also contains the information about running WUs on that 'Server'. This
  615. // method reads the information. Those WUs are displays under that server (identified by its queue name)
  616. // on Activity page.
  617. //
  618. // For the WUs list inside /Status/Servers/Server[@name=ECLagent] but not list under other 'Server', the
  619. // existing code has to find out WUID and @clusterName of the WU. Then, uses @clusterName to find out the
  620. // queue name in IConstWUClusterInfo. Those WUs list under that server (identified by its queue name) with
  621. // a note 'on ECLagent'. TBD: the logic here will be simpler if the /Status/Servers/Server is named the
  622. // instance and/or cluster.
  623. //
  624. // In order to get information about queued WUs, this method gets queue names from both IConstWUClusterInfo
  625. // and other environment functions. Each of those queue names is linked to one IJobQueues. From the
  626. // IJobQueues, this method reads queued jobs for each server component and list them under the server
  627. // component (identified by its queue name).
  628. bool CWsSMCEx::onActivity(IEspContext &context, IEspActivityRequest &req, IEspActivityResponse& resp)
  629. {
  630. context.validateFeatureAccess(FEATURE_URL, SecAccess_Read, true);
  631. try
  632. {
  633. const char* build_ver = getBuildVersion();
  634. resp.setBuild(build_ver);
  635. double version = context.getClientVersion();
  636. bool isSuperUser = true;
  637. #ifdef _USE_OPENLDAP
  638. CLdapSecManager* secmgr = dynamic_cast<CLdapSecManager*>(context.querySecManager());
  639. if(secmgr && !secmgr->isSuperUser(context.queryUser()))
  640. isSuperUser = false;
  641. #endif
  642. if(isSuperUser && req.getFromSubmitBtn())
  643. readBannerAndChatRequest(context, req, resp);
  644. if (version >= 1.12)
  645. resp.setSuperUser(isSuperUser);
  646. if (version >= 1.06)
  647. setBannerAndChatData(version, resp);
  648. Owned<ActivityInfo> activityInfo = getActivityInfo(context, req);
  649. setActivityResponse(context, activityInfo, req, resp);
  650. }
  651. catch(IException* e)
  652. {
  653. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  654. }
  655. return true;
  656. }
  657. const char *CWsSMCEx::getStatusServerTypeName(WsSMCStatusServerType type)
  658. {
  659. return (type < WsSMCSSTterm) ? WsSMCStatusServerTypeNames[type] : NULL;
  660. }
  661. void CWsSMCEx::readTargetClusterInfo(IEspContext &context, CConstWUClusterInfoArray& clusters, IPropertyTree* serverStatusRoot,
  662. ActivityInfo* activityInfo)
  663. {
  664. ForEachItemIn(c, clusters)
  665. {
  666. IConstWUClusterInfo &cluster = clusters.item(c);
  667. Owned<CWsSMCTargetCluster> targetCluster = new CWsSMCTargetCluster();
  668. readTargetClusterInfo(context, cluster, serverStatusRoot, targetCluster);
  669. if (cluster.getPlatform() == ThorLCRCluster)
  670. activityInfo->thorTargetClusters.append(*targetCluster.getClear());
  671. else if (cluster.getPlatform() == RoxieCluster)
  672. activityInfo->roxieTargetClusters.append(*targetCluster.getClear());
  673. else
  674. activityInfo->hthorTargetClusters.append(*targetCluster.getClear());
  675. }
  676. }
  677. void CWsSMCEx::readTargetClusterInfo(IEspContext& context, IConstWUClusterInfo& cluster, IPropertyTree* serverStatusRoot, CWsSMCTargetCluster* targetCluster)
  678. {
  679. SCMStringBuffer clusterName;
  680. cluster.getName(clusterName);
  681. targetCluster->clusterName.set(clusterName.str());
  682. targetCluster->clusterType = cluster.getPlatform();
  683. targetCluster->clusterSize = cluster.getSize();
  684. cluster.getServerQueue(targetCluster->serverQueue.queueName);
  685. cluster.getAgentQueue(targetCluster->agentQueue.queueName);
  686. StringBuffer statusServerName;
  687. CWsSMCQueue* jobQueue = NULL;
  688. if (targetCluster->clusterType == ThorLCRCluster)
  689. {
  690. statusServerName.set(getStatusServerTypeName(WsSMCSSTThorLCRCluster));
  691. jobQueue = &targetCluster->clusterQueue;
  692. cluster.getThorQueue(jobQueue->queueName);
  693. }
  694. else if (targetCluster->clusterType == RoxieCluster)
  695. {
  696. statusServerName.set(getStatusServerTypeName(WsSMCSSTRoxieCluster));
  697. jobQueue = &targetCluster->agentQueue;
  698. }
  699. else
  700. {
  701. statusServerName.set(getStatusServerTypeName(WsSMCSSTHThorCluster));
  702. jobQueue = &targetCluster->agentQueue;
  703. }
  704. targetCluster->statusServerName.set(statusServerName.str());
  705. targetCluster->queueName.set(jobQueue->queueName.str());
  706. if (serverStatusRoot)
  707. {
  708. jobQueue->foundQueueInStatusServer = findQueueInStatusServer(context, serverStatusRoot, statusServerName.str(), targetCluster->queueName.get());
  709. if (!jobQueue->foundQueueInStatusServer)
  710. targetCluster->clusterStatusDetails.appendf("Cluster %s not attached; ", clusterName.str());
  711. }
  712. return;
  713. }
  714. void CWsSMCEx::readRunningWUsAndQueuedWUs(IEspContext &context, IPropertyTree* envRoot, IPropertyTree* serverStatusRoot,
  715. IPropertyTree* dfuRecoveryRoot, ActivityInfo* activityInfo)
  716. {
  717. BoolHash uniqueWUIDs;
  718. readRunningWUsOnStatusServer(context, serverStatusRoot, WsSMCSSTThorLCRCluster, activityInfo->thorTargetClusters, activityInfo->roxieTargetClusters, activityInfo->hthorTargetClusters, uniqueWUIDs, activityInfo->aws);
  719. readWUsAndStateFromJobQueue(context, activityInfo->thorTargetClusters, uniqueWUIDs, activityInfo->aws);
  720. readRunningWUsOnStatusServer(context, serverStatusRoot, WsSMCSSTRoxieCluster, activityInfo->roxieTargetClusters, activityInfo->thorTargetClusters, activityInfo->hthorTargetClusters, uniqueWUIDs, activityInfo->aws);
  721. readWUsAndStateFromJobQueue(context, activityInfo->roxieTargetClusters, uniqueWUIDs, activityInfo->aws);
  722. readRunningWUsOnStatusServer(context, serverStatusRoot, WsSMCSSTHThorCluster, activityInfo->hthorTargetClusters, activityInfo->thorTargetClusters, activityInfo->roxieTargetClusters, uniqueWUIDs, activityInfo->aws);
  723. readWUsAndStateFromJobQueue(context, activityInfo->hthorTargetClusters, uniqueWUIDs, activityInfo->aws);
  724. readRunningWUsOnStatusServer(context, serverStatusRoot, WsSMCSSTECLagent, activityInfo->thorTargetClusters, activityInfo->roxieTargetClusters, activityInfo->hthorTargetClusters, uniqueWUIDs, activityInfo->aws);
  725. getWUsNotOnTargetCluster(context, serverStatusRoot, activityInfo->serverJobQueues, activityInfo->aws);
  726. getDFUServersAndWUs(context, envRoot, activityInfo->serverJobQueues, activityInfo->aws);
  727. getDFURecoveryJobs(context, dfuRecoveryRoot, activityInfo->DFURecoveryJobs);
  728. }
  729. void CWsSMCEx::readRunningWUsOnStatusServer(IEspContext& context, IPropertyTree* serverStatusRoot, WsSMCStatusServerType statusServerType,
  730. CIArrayOf<CWsSMCTargetCluster>& targetClusters, CIArrayOf<CWsSMCTargetCluster>& targetClusters1, CIArrayOf<CWsSMCTargetCluster>& targetClusters2,
  731. BoolHash& uniqueWUIDs, IArrayOf<IEspActiveWorkunit>& aws)
  732. {
  733. const char* serverName = getStatusServerTypeName(statusServerType);
  734. if (!serverName || !*serverName)
  735. return;
  736. bool isECLAgent = (statusServerType == WsSMCSSTECLagent);
  737. VStringBuffer path("Server[@name=\"%s\"]", serverName);
  738. Owned<IPropertyTreeIterator> itrStatusServer(serverStatusRoot->getElements(path.str()));
  739. ForEach(*itrStatusServer)
  740. {
  741. IPropertyTree& serverStatusNode = itrStatusServer->query();
  742. StringBuffer instance;
  743. if ((statusServerType == WsSMCSSTThorLCRCluster) || (statusServerType == WsSMCSSTRoxieCluster))
  744. serverStatusNode.getProp("@cluster", instance);
  745. else
  746. instance.appendf("%s on %s", serverName, serverStatusNode.queryProp("@node"));
  747. const char* graph = NULL;
  748. int sgDuration = -1;
  749. int subgraph = -1;
  750. StringBuffer durationStr, subgraphStr;
  751. if (!isECLAgent)
  752. {
  753. sgDuration = serverStatusNode.getPropInt("@sg_duration", -1);
  754. subgraph = serverStatusNode.getPropInt("@subgraph", -1);
  755. graph = serverStatusNode.queryProp("@graph");
  756. durationStr.appendf("%d min", sgDuration);
  757. subgraphStr.appendf("%d", subgraph);
  758. }
  759. Owned<IPropertyTreeIterator> wuids(serverStatusNode.getElements("WorkUnit"));
  760. ForEach(*wuids)
  761. {
  762. const char* wuid=wuids->query().queryProp(NULL);
  763. if (!wuid || !*wuid || (isECLAgent && uniqueWUIDs.getValue(wuid)))
  764. continue;
  765. CWsSMCTargetCluster* targetCluster = findWUClusterInfo(context, wuid, isECLAgent, targetClusters, targetClusters1, targetClusters2);
  766. if (!targetCluster)
  767. continue;
  768. const char* targetClusterName = targetCluster->clusterName.get();
  769. CWsSMCQueue* jobQueue;
  770. if (statusServerType == WsSMCSSTThorLCRCluster)
  771. jobQueue = &targetCluster->clusterQueue;
  772. else
  773. jobQueue = &targetCluster->agentQueue;
  774. Owned<IEspActiveWorkunit> wu;
  775. if (!isECLAgent)
  776. {
  777. uniqueWUIDs.setValue(wuid, true);
  778. const char *cluster = serverStatusNode.queryProp("Cluster");
  779. StringBuffer queueName;
  780. if (cluster) // backward compat check.
  781. getClusterThorQueueName(queueName, cluster);
  782. else
  783. queueName.append(targetCluster->queueName.get());
  784. createActiveWorkUnit(wu, context, wuid, !strieq(targetClusterName, instance.str()) ? instance.str() : NULL, 0, serverName,
  785. queueName, instance.str(), targetClusterName, false);
  786. if (wu->getStateID() == WUStateRunning) //'aborting' may be another possible status
  787. {
  788. if (subgraph > -1 && sgDuration > -1)
  789. {
  790. wu->setGraphName(graph);
  791. wu->setDuration(durationStr.str());
  792. wu->setGID(subgraphStr.str());
  793. }
  794. if (serverStatusNode.getPropInt("@memoryBlocked ", 0) != 0)
  795. wu->setMemoryBlocked(1);
  796. }
  797. }
  798. else
  799. {
  800. createActiveWorkUnit(wu, context, wuid, instance.str(), 0, serverName, serverName, instance.str(), targetClusterName, false);
  801. if (targetCluster->clusterType == ThorLCRCluster)
  802. wu->setClusterType("Thor");
  803. else if (targetCluster->clusterType == RoxieCluster)
  804. wu->setClusterType("Roxie");
  805. else
  806. wu->setClusterType("HThor");
  807. wu->setClusterQueueName(targetCluster->queueName.get());
  808. if (wu->getStateID() != WUStateRunning)
  809. {
  810. const char *extra = wu->getExtra();
  811. if (wu->getStateID() != WUStateBlocked || !extra || !*extra) // Blocked on persist treated as running here
  812. {
  813. aws.append(*wu.getLink());
  814. jobQueue->countQueuedJobs++;
  815. continue;
  816. }
  817. }
  818. if (serverStatusNode.getPropInt("@memoryBlocked ", 0) != 0)
  819. wu->setMemoryBlocked(1);
  820. }
  821. aws.append(*wu.getLink());
  822. jobQueue->countRunningJobs++;
  823. }
  824. }
  825. }
  826. void CWsSMCEx::readWUsAndStateFromJobQueue(IEspContext& context, CIArrayOf<CWsSMCTargetCluster>& targetClusters, BoolHash& uniqueWUIDs, IArrayOf<IEspActiveWorkunit>& aws)
  827. {
  828. ForEachItemIn(i, targetClusters)
  829. readWUsAndStateFromJobQueue(context, targetClusters.item(i), uniqueWUIDs, aws);
  830. }
  831. void CWsSMCEx::readWUsAndStateFromJobQueue(IEspContext& context, CWsSMCTargetCluster& targetCluster, BoolHash& uniqueWUIDs, IArrayOf<IEspActiveWorkunit>& aws)
  832. {
  833. if (targetCluster.clusterType == ThorLCRCluster)
  834. {
  835. readWUsAndStateFromJobQueue(context, targetCluster, targetCluster.clusterQueue, NULL, uniqueWUIDs, aws);
  836. targetCluster.queueStatus.set(targetCluster.clusterQueue.queueState);
  837. }
  838. if (targetCluster.agentQueue.queueName.length())
  839. {
  840. readWUsAndStateFromJobQueue(context, targetCluster, targetCluster.agentQueue, targetCluster.agentQueue.queueName.str(), uniqueWUIDs, aws);
  841. if (targetCluster.clusterType != ThorLCRCluster)
  842. targetCluster.queueStatus.set(targetCluster.agentQueue.queueState);
  843. }
  844. if (targetCluster.serverQueue.queueName.length())
  845. readWUsAndStateFromJobQueue(context, targetCluster, targetCluster.serverQueue, targetCluster.serverQueue.queueName.str(), uniqueWUIDs, aws);
  846. }
  847. CWsSMCTargetCluster* CWsSMCEx::findTargetCluster(const char* clusterName, CIArrayOf<CWsSMCTargetCluster>& targetClusters)
  848. {
  849. ForEachItemIn(i, targetClusters)
  850. {
  851. CWsSMCTargetCluster& targetCluster = targetClusters.item(i);
  852. if (strieq(targetCluster.clusterName.get(), clusterName))
  853. return &targetCluster;
  854. }
  855. return NULL;
  856. }
  857. CWsSMCTargetCluster* CWsSMCEx::findWUClusterInfo(IEspContext& context, const char* wuid, bool isOnECLAgent, CIArrayOf<CWsSMCTargetCluster>& targetClusters,
  858. CIArrayOf<CWsSMCTargetCluster>& targetClusters1, CIArrayOf<CWsSMCTargetCluster>& targetClusters2)
  859. {
  860. SCMStringBuffer clusterName;
  861. try
  862. {
  863. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  864. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid, false);
  865. if (!cw)
  866. return NULL;
  867. cw->getClusterName(clusterName);
  868. if (!clusterName.length())
  869. return NULL;
  870. }
  871. catch (IException *e)
  872. {//Exception may be thrown when the openWorkUnit() is called inside the CWUWrapper
  873. StringBuffer msg;
  874. WARNLOG("Failed to open workunit %s: %s", wuid, e->errorMessage(msg).str());
  875. e->Release();
  876. return NULL;
  877. }
  878. const char* cluster = clusterName.str();
  879. CWsSMCTargetCluster* targetCluster = findTargetCluster(cluster, targetClusters);
  880. if (targetCluster || !isOnECLAgent)
  881. return targetCluster;
  882. targetCluster = findTargetCluster(cluster, targetClusters1);
  883. if (targetCluster)
  884. return targetCluster;
  885. return findTargetCluster(cluster, targetClusters2);
  886. }
  887. void CWsSMCEx::addWUsToResponse(IEspContext &context, const IArrayOf<IEspActiveWorkunit>& aws, IEspActivityResponse& resp)
  888. {
  889. const char* user = context.queryUserId();
  890. IArrayOf<IEspActiveWorkunit> awsReturned;
  891. ForEachItemIn(i, aws)
  892. {
  893. IEspActiveWorkunit& wu = aws.item(i);
  894. const char* wuid = wu.getWuid();
  895. if (wuid[0] == 'D')//DFU WU
  896. {
  897. awsReturned.append(*LINK(&wu));
  898. continue;
  899. }
  900. try
  901. {
  902. //if no access, throw an exception and go to the 'catch' section.
  903. const char* owner = wu.getOwner();
  904. context.validateFeatureAccess((!owner || !*owner || (user && streq(user, owner))) ? OWN_WU_ACCESS : OTHERS_WU_ACCESS, SecAccess_Read, true);
  905. awsReturned.append(*LINK(&wu));
  906. continue;
  907. }
  908. catch (IException *e)
  909. { //if the wu cannot be opened for some reason, the openWorkUnit() inside the CActiveWorkunitWrapper() may throw an exception.
  910. //We do not want the exception stops this process of retrieving/showing all active WUs. And that WU should still be displayed
  911. //with the exception.
  912. StringBuffer msg;
  913. Owned<IEspActiveWorkunit> cw = new CActiveWorkunitWrapper(wuid, "", "", e->errorMessage(msg).str(), "normal");
  914. cw->setStateID(WUStateUnknown);
  915. cw->setServer(wu.getServer());
  916. cw->setQueueName(wu.getQueueName());
  917. const char* instanceName = wu.getInstance();
  918. const char* targetClusterName = wu.getTargetClusterName();
  919. if (instanceName && *instanceName)
  920. cw->setInstance(instanceName); // JCSMORE In thor case at least, if queued it is unknown which instance it will run on..
  921. if (targetClusterName && *targetClusterName)
  922. cw->setTargetClusterName(targetClusterName);
  923. awsReturned.append(*cw.getLink());
  924. e->Release();
  925. }
  926. }
  927. resp.setRunning(awsReturned);
  928. return;
  929. }
  930. void CWsSMCEx::setActivityResponse(IEspContext &context, ActivityInfo* activityInfo, IEspActivityRequest &req, IEspActivityResponse& resp)
  931. {
  932. double version = context.getClientVersion();
  933. const char* sortBy = req.getSortBy();
  934. bool descending = req.getDescending();
  935. if (version >= 1.16)
  936. {
  937. IArrayOf<IEspTargetCluster> thorClusters;
  938. IArrayOf<IEspTargetCluster> hthorClusters;
  939. IArrayOf<IEspTargetCluster> roxieClusters;
  940. setESPTargetClusters(context, activityInfo->thorTargetClusters, thorClusters);
  941. setESPTargetClusters(context, activityInfo->roxieTargetClusters, roxieClusters);
  942. setESPTargetClusters(context, activityInfo->hthorTargetClusters, hthorClusters);
  943. sortTargetClusters(thorClusters, sortBy, descending);
  944. sortTargetClusters(roxieClusters, sortBy, descending);
  945. SecAccessFlags access;
  946. if (context.authorizeFeature(THORQUEUE_FEATURE, access) && access>=SecAccess_Full)
  947. resp.setAccessRight("Access_Full");
  948. resp.setSortBy(sortBy);
  949. resp.setDescending(descending);
  950. resp.setThorClusterList(thorClusters);
  951. resp.setRoxieClusterList(roxieClusters);
  952. resp.setHThorClusterList(hthorClusters);
  953. resp.setServerJobQueues(activityInfo->serverJobQueues);
  954. }
  955. else
  956. {//for backward compatible
  957. IArrayOf<IEspThorCluster> thorClusters;
  958. ForEachItemIn(i, activityInfo->thorTargetClusters)
  959. {
  960. CWsSMCTargetCluster& targetCluster = activityInfo->thorTargetClusters.item(i);
  961. Owned<IEspThorCluster> respThorCluster = new CThorCluster("", "");
  962. respThorCluster->setClusterName(targetCluster.clusterName.get());
  963. respThorCluster->setQueueStatus(targetCluster.queueStatus.get());
  964. if (version >= 1.03)
  965. respThorCluster->setQueueName(targetCluster.queueName.get());
  966. if (version >= 1.11)
  967. respThorCluster->setClusterSize(targetCluster.clusterSize);
  968. thorClusters.append(*respThorCluster.getClear());
  969. }
  970. resp.setThorClusters(thorClusters);
  971. if (version > 1.06)
  972. {
  973. IArrayOf<IEspRoxieCluster> roxieClusters;
  974. ForEachItemIn(i, activityInfo->roxieTargetClusters)
  975. {
  976. CWsSMCTargetCluster& targetCluster = activityInfo->roxieTargetClusters.item(i);
  977. Owned<IEspRoxieCluster> respRoxieCluster = new CRoxieCluster("", "");
  978. respRoxieCluster->setClusterName(targetCluster.clusterName.get());
  979. respRoxieCluster->setQueueStatus(targetCluster.queueStatus.get());
  980. respRoxieCluster->setQueueName(targetCluster.queueName.get());
  981. if (version >= 1.11)
  982. respRoxieCluster->setClusterSize(targetCluster.clusterSize);
  983. roxieClusters.append(*respRoxieCluster.getClear());
  984. }
  985. resp.setRoxieClusters(roxieClusters);
  986. }
  987. if (version > 1.10)
  988. {
  989. resp.setSortBy(sortBy);
  990. resp.setDescending(req.getDescending());
  991. }
  992. if (version > 1.11)
  993. {
  994. IArrayOf<IEspHThorCluster> hThorClusters;
  995. ForEachItemIn(i, activityInfo->hthorTargetClusters)
  996. {
  997. CWsSMCTargetCluster& targetCluster = activityInfo->hthorTargetClusters.item(i);
  998. Owned<IEspHThorCluster> respHThorCluster = new CHThorCluster("", "");
  999. respHThorCluster->setClusterName(targetCluster.clusterName.get());
  1000. respHThorCluster->setQueueStatus(targetCluster.queueStatus.get());
  1001. respHThorCluster->setQueueName(targetCluster.queueName.get());
  1002. respHThorCluster->setClusterSize(targetCluster.clusterSize);
  1003. hThorClusters.append(*respHThorCluster.getClear());
  1004. }
  1005. resp.setHThorClusters(hThorClusters);
  1006. SecAccessFlags access;
  1007. if (context.authorizeFeature(THORQUEUE_FEATURE, access) && access>=SecAccess_Full)
  1008. resp.setAccessRight("Access_Full");
  1009. }
  1010. if (version > 1.03)
  1011. resp.setServerJobQueues(activityInfo->serverJobQueues);
  1012. }
  1013. resp.setDFUJobs(activityInfo->DFURecoveryJobs);
  1014. addWUsToResponse(context, activityInfo->aws, resp);
  1015. return;
  1016. }
  1017. void CWsSMCEx::setESPTargetClusters(IEspContext& context, CIArrayOf<CWsSMCTargetCluster>& targetClusters, IArrayOf<IEspTargetCluster>& respTargetClusters)
  1018. {
  1019. ForEachItemIn(i, targetClusters)
  1020. {
  1021. CWsSMCTargetCluster& targetCluster = targetClusters.item(i);
  1022. Owned<IEspTargetCluster> respTargetCluster = new CTargetCluster("", "");
  1023. respTargetCluster->setClusterName(targetCluster.clusterName.get());
  1024. respTargetCluster->setClusterSize(targetCluster.clusterSize);
  1025. respTargetCluster->setClusterType(targetCluster.clusterType);
  1026. respTargetCluster->setQueueName(targetCluster.queueName.get());
  1027. respTargetCluster->setQueueStatus(targetCluster.queueStatus.get());
  1028. setClusterStatus(context, targetCluster, respTargetCluster);
  1029. respTargetClusters.append(*respTargetCluster.getClear());
  1030. }
  1031. }
  1032. void CWsSMCEx::addServerJobQueue(IArrayOf<IEspServerJobQueue>& jobQueues, const char* queueName, const char* serverName,
  1033. const char* serverType, const char* networkAddress, unsigned port)
  1034. {
  1035. if (!queueName || !*queueName || !serverName || !*serverName || !serverType || !*serverType)
  1036. return;
  1037. StringBuffer queueState;
  1038. StringBuffer queueStateDetails;
  1039. Owned<IJobQueue> queue = createJobQueue(queueName);
  1040. if (queue->stopped(queueStateDetails))
  1041. queueState.set("stopped");
  1042. else if (queue->paused(queueStateDetails))
  1043. queueState.set("paused");
  1044. else
  1045. queueState.set("running");
  1046. addServerJobQueue(jobQueues, queueName, serverName, serverType, networkAddress, port, queueState.str(), queueStateDetails.str());
  1047. }
  1048. void CWsSMCEx::addServerJobQueue(IArrayOf<IEspServerJobQueue>& jobQueues, const char* queueName, const char* serverName,
  1049. const char* serverType, const char* networkAddress, unsigned port, const char* queueState, const char* queueStateDetails)
  1050. {
  1051. if (!queueName || !*queueName || !serverName || !*serverName || !serverType || !*serverType)
  1052. return;
  1053. if (!queueState || !*queueState)
  1054. queueState = "running";
  1055. Owned<IEspServerJobQueue> jobQueue = createServerJobQueue("", "");
  1056. jobQueue->setQueueName(queueName);
  1057. jobQueue->setServerName(serverName);
  1058. jobQueue->setServerType(serverType);
  1059. if (networkAddress && *networkAddress)
  1060. {
  1061. jobQueue->setNetworkAddress(networkAddress);
  1062. jobQueue->setPort(port);
  1063. }
  1064. setServerJobQueueStatus(jobQueue, queueState, queueStateDetails);
  1065. jobQueues.append(*jobQueue.getClear());
  1066. }
  1067. void CWsSMCEx::setServerJobQueueStatus(double version, IEspServerJobQueue* jobQueue, const char* status, const char* details)
  1068. {
  1069. if (!status || !*status)
  1070. return;
  1071. jobQueue->setQueueStatus(status);
  1072. if (version >= 1.17)
  1073. setServerJobQueueStatusDetails(jobQueue, status, details);
  1074. }
  1075. void CWsSMCEx::setServerJobQueueStatus(IEspServerJobQueue* jobQueue, const char* status, const char* details)
  1076. {
  1077. if (!status || !*status)
  1078. return;
  1079. jobQueue->setQueueStatus(status);
  1080. setServerJobQueueStatusDetails(jobQueue, status, details);
  1081. }
  1082. void CWsSMCEx::setServerJobQueueStatusDetails(IEspServerJobQueue* jobQueue, const char* status, const char* details)
  1083. {
  1084. StringBuffer queueState;
  1085. if (details && *details)
  1086. queueState.appendf("queue %s; %s;", status, details);
  1087. else
  1088. queueState.appendf("queue %s;", status);
  1089. jobQueue->setStatusDetails(queueState.str());
  1090. }
  1091. void CWsSMCEx::addCapabilities(IPropertyTree* pFeatureNode, const char* access,
  1092. IArrayOf<IEspCapability>& capabilities)
  1093. {
  1094. StringBuffer xpath(access);
  1095. xpath.append("/Capability");
  1096. Owned<IPropertyTreeIterator> it = pFeatureNode->getElements(xpath.str());
  1097. ForEach(*it)
  1098. {
  1099. IPropertyTree* pCapabilityNode = &it->query();
  1100. IEspCapability* pCapability = new CCapability("ws_smc");
  1101. pCapability->setName( pCapabilityNode->queryProp("@name") );
  1102. pCapability->setDescription( pCapabilityNode->queryProp("@description") );
  1103. capabilities.append(*pCapability);
  1104. }
  1105. }
  1106. static void checkAccess(IEspContext &context, const char* feature,int level)
  1107. {
  1108. if (!context.validateFeatureAccess(feature, level, false))
  1109. throw MakeStringException(ECLWATCH_THOR_QUEUE_ACCESS_DENIED, "Failed to access the queue functions. Permission denied.");
  1110. }
  1111. bool CWsSMCEx::onMoveJobDown(IEspContext &context, IEspSMCJobRequest &req, IEspSMCJobResponse &resp)
  1112. {
  1113. try
  1114. {
  1115. checkAccess(context,THORQUEUE_FEATURE,SecAccess_Full);
  1116. Owned<IJobQueue> queue = createJobQueue(req.getQueueName());
  1117. QueueLock lock(queue);
  1118. unsigned index=queue->findRank(req.getWuid());
  1119. if(index<queue->ordinality())
  1120. {
  1121. IJobQueueItem * item0 = queue->getItem(index);
  1122. IJobQueueItem * item = queue->getItem(index+1);
  1123. if(item && item0 && (item0->getPriority() == item->getPriority()))
  1124. queue->moveAfter(req.getWuid(),item->queryWUID());
  1125. }
  1126. AccessSuccess(context, "Changed job priority %s",req.getWuid());
  1127. clearActivityInfoCache();
  1128. resp.setRedirectUrl("/WsSMC/");
  1129. }
  1130. catch(IException* e)
  1131. {
  1132. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1133. }
  1134. return true;
  1135. }
  1136. bool CWsSMCEx::onMoveJobUp(IEspContext &context, IEspSMCJobRequest &req, IEspSMCJobResponse &resp)
  1137. {
  1138. try
  1139. {
  1140. checkAccess(context,THORQUEUE_FEATURE,SecAccess_Full);
  1141. Owned<IJobQueue> queue = createJobQueue(req.getQueueName());
  1142. QueueLock lock(queue);
  1143. unsigned index=queue->findRank(req.getWuid());
  1144. if(index>0 && index<queue->ordinality())
  1145. {
  1146. IJobQueueItem * item0 = queue->getItem(index);
  1147. IJobQueueItem * item = queue->getItem(index-1);
  1148. if(item && item0 && (item0->getPriority() == item->getPriority()))
  1149. queue->moveBefore(req.getWuid(),item->queryWUID());
  1150. }
  1151. AccessSuccess(context, "Changed job priority %s",req.getWuid());
  1152. clearActivityInfoCache();
  1153. resp.setRedirectUrl("/WsSMC/");
  1154. }
  1155. catch(IException* e)
  1156. {
  1157. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1158. }
  1159. return true;
  1160. }
  1161. bool CWsSMCEx::onMoveJobBack(IEspContext &context, IEspSMCJobRequest &req, IEspSMCJobResponse &resp)
  1162. {
  1163. try
  1164. {
  1165. checkAccess(context,THORQUEUE_FEATURE,SecAccess_Full);
  1166. Owned<IJobQueue> queue = createJobQueue(req.getQueueName());
  1167. QueueLock lock(queue);
  1168. unsigned index=queue->findRank(req.getWuid());
  1169. if(index<queue->ordinality())
  1170. {
  1171. int priority0 = queue->getItem(index)->getPriority();
  1172. unsigned biggestIndoxInSamePriority = index;
  1173. unsigned nextIndex = biggestIndoxInSamePriority + 1;
  1174. while (nextIndex<queue->ordinality())
  1175. {
  1176. IJobQueueItem * item = queue->getItem(nextIndex);
  1177. if (priority0 != item->getPriority())
  1178. {
  1179. break;
  1180. }
  1181. biggestIndoxInSamePriority = nextIndex;
  1182. nextIndex++;
  1183. }
  1184. if (biggestIndoxInSamePriority != index)
  1185. {
  1186. IJobQueueItem * item = queue->getItem(biggestIndoxInSamePriority);
  1187. queue->moveAfter(req.getWuid(),item->queryWUID());
  1188. }
  1189. }
  1190. AccessSuccess(context, "Changed job priority %s",req.getWuid());
  1191. clearActivityInfoCache();
  1192. resp.setRedirectUrl("/WsSMC/");
  1193. }
  1194. catch(IException* e)
  1195. {
  1196. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1197. }
  1198. return true;
  1199. }
  1200. bool CWsSMCEx::onMoveJobFront(IEspContext &context, IEspSMCJobRequest &req, IEspSMCJobResponse &resp)
  1201. {
  1202. try
  1203. {
  1204. checkAccess(context,THORQUEUE_FEATURE,SecAccess_Full);
  1205. Owned<IJobQueue> queue = createJobQueue(req.getQueueName());
  1206. QueueLock lock(queue);
  1207. unsigned index=queue->findRank(req.getWuid());
  1208. if(index>0 && index<queue->ordinality())
  1209. {
  1210. int priority0 = queue->getItem(index)->getPriority();
  1211. unsigned smallestIndoxInSamePriority = index;
  1212. int nextIndex = smallestIndoxInSamePriority - 1;
  1213. while (nextIndex >= 0)
  1214. {
  1215. IJobQueueItem * item = queue->getItem(nextIndex);
  1216. if (priority0 != item->getPriority())
  1217. {
  1218. break;
  1219. }
  1220. smallestIndoxInSamePriority = nextIndex;
  1221. nextIndex--;
  1222. }
  1223. if (smallestIndoxInSamePriority != index)
  1224. {
  1225. IJobQueueItem * item = queue->getItem(smallestIndoxInSamePriority);
  1226. queue->moveBefore(req.getWuid(),item->queryWUID());
  1227. }
  1228. }
  1229. AccessSuccess(context, "Changed job priority %s",req.getWuid());
  1230. clearActivityInfoCache();
  1231. resp.setRedirectUrl("/WsSMC/");
  1232. }
  1233. catch(IException* e)
  1234. {
  1235. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1236. }
  1237. return true;
  1238. }
  1239. bool CWsSMCEx::onRemoveJob(IEspContext &context, IEspSMCJobRequest &req, IEspSMCJobResponse &resp)
  1240. {
  1241. try
  1242. {
  1243. checkAccess(context,THORQUEUE_FEATURE,SecAccess_Full);
  1244. secAbortWorkUnit(req.getWuid(), *context.querySecManager(), *context.queryUser());
  1245. Owned<IJobQueue> queue = createJobQueue(req.getQueueName());
  1246. QueueLock lock(queue);
  1247. unsigned index=queue->findRank(req.getWuid());
  1248. if(index<queue->ordinality())
  1249. {
  1250. if(!queue->cancelInitiateConversation(req.getWuid()))
  1251. throw MakeStringException(ECLWATCH_CANNOT_DELETE_WORKUNIT,"Failed to remove the workunit %s",req.getWuid());
  1252. }
  1253. AccessSuccess(context, "Removed job %s",req.getWuid());
  1254. clearActivityInfoCache();
  1255. resp.setRedirectUrl("/WsSMC/");
  1256. }
  1257. catch(IException* e)
  1258. {
  1259. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1260. }
  1261. return true;
  1262. }
  1263. bool CWsSMCEx::onStopQueue(IEspContext &context, IEspSMCQueueRequest &req, IEspSMCQueueResponse &resp)
  1264. {
  1265. try
  1266. {
  1267. checkAccess(context,THORQUEUE_FEATURE,SecAccess_Full);
  1268. StringBuffer info;
  1269. Owned<IJobQueue> queue = createJobQueue(req.getQueueName());
  1270. queue->stop(createQueueActionInfo(context, "stopped", req, info));
  1271. AccessSuccess(context, "Stopped queue %s",req.getCluster());
  1272. clearActivityInfoCache();
  1273. double version = context.getClientVersion();
  1274. if (version >= 1.19)
  1275. getStatusServerInfo(context, req.getServerType(), req.getCluster(), req.getNetworkAddress(), req.getPort(), resp.updateStatusServerInfo());
  1276. resp.setRedirectUrl("/WsSMC/");
  1277. }
  1278. catch(IException* e)
  1279. {
  1280. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1281. }
  1282. return true;
  1283. }
  1284. bool CWsSMCEx::onResumeQueue(IEspContext &context, IEspSMCQueueRequest &req, IEspSMCQueueResponse &resp)
  1285. {
  1286. try
  1287. {
  1288. checkAccess(context,THORQUEUE_FEATURE,SecAccess_Full);
  1289. StringBuffer info;
  1290. Owned<IJobQueue> queue = createJobQueue(req.getQueueName());
  1291. queue->resume(createQueueActionInfo(context, "resumed", req, info));
  1292. AccessSuccess(context, "Resumed queue %s",req.getCluster());
  1293. clearActivityInfoCache();
  1294. double version = context.getClientVersion();
  1295. if (version >= 1.19)
  1296. getStatusServerInfo(context, req.getServerType(), req.getCluster(), req.getNetworkAddress(), req.getPort(), resp.updateStatusServerInfo());
  1297. resp.setRedirectUrl("/WsSMC/");
  1298. }
  1299. catch(IException* e)
  1300. {
  1301. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1302. }
  1303. return true;
  1304. }
  1305. const char* CWsSMCEx::createQueueActionInfo(IEspContext &context, const char* state, IEspSMCQueueRequest &req, StringBuffer& info)
  1306. {
  1307. StringBuffer peer, currentTime;
  1308. context.getPeer(peer);
  1309. const char* userId = context.queryUserId();
  1310. if (!userId || !*userId)
  1311. userId = "Unknown user";
  1312. CDateTime now;
  1313. now.setNow();
  1314. now.getString(currentTime);
  1315. info.appendf("%s by <%s> at <%s> from <%s>", state, userId, currentTime.str(), peer.str());
  1316. const char* comment = req.getComment();
  1317. if (comment && *comment)
  1318. info.append(": ' ").append(comment).append("'");
  1319. return info.str();
  1320. }
  1321. bool CWsSMCEx::onPauseQueue(IEspContext &context, IEspSMCQueueRequest &req, IEspSMCQueueResponse &resp)
  1322. {
  1323. try
  1324. {
  1325. checkAccess(context,THORQUEUE_FEATURE,SecAccess_Full);
  1326. StringBuffer info;
  1327. Owned<IJobQueue> queue = createJobQueue(req.getQueueName());
  1328. queue->pause(createQueueActionInfo(context, "paused", req, info));
  1329. AccessSuccess(context, "Paused queue %s",req.getCluster());
  1330. clearActivityInfoCache();
  1331. double version = context.getClientVersion();
  1332. if (version >= 1.19)
  1333. getStatusServerInfo(context, req.getServerType(), req.getCluster(), req.getNetworkAddress(), req.getPort(), resp.updateStatusServerInfo());
  1334. resp.setRedirectUrl("/WsSMC/");
  1335. }
  1336. catch(IException* e)
  1337. {
  1338. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1339. }
  1340. return true;
  1341. }
  1342. bool CWsSMCEx::onClearQueue(IEspContext &context, IEspSMCQueueRequest &req, IEspSMCQueueResponse &resp)
  1343. {
  1344. try
  1345. {
  1346. checkAccess(context,THORQUEUE_FEATURE,SecAccess_Full);
  1347. Owned<IJobQueue> queue = createJobQueue(req.getQueueName());
  1348. {
  1349. QueueLock lock(queue);
  1350. for(unsigned i=0;i<queue->ordinality();i++)
  1351. secAbortWorkUnit(queue->getItem(i)->queryWUID(), *context.querySecManager(), *context.queryUser());
  1352. queue->clear();
  1353. }
  1354. AccessSuccess(context, "Cleared queue %s",req.getCluster());
  1355. clearActivityInfoCache();
  1356. double version = context.getClientVersion();
  1357. if (version >= 1.19)
  1358. getStatusServerInfo(context, req.getServerType(), req.getCluster(), req.getNetworkAddress(), req.getPort(), resp.updateStatusServerInfo());
  1359. resp.setRedirectUrl("/WsSMC/");
  1360. }
  1361. catch(IException* e)
  1362. {
  1363. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1364. }
  1365. return true;
  1366. }
  1367. void CWsSMCEx::setJobPriority(IWorkUnitFactory* factory, const char* wuid, const char* queueName, WUPriorityClass& priority)
  1368. {
  1369. if (!wuid || !*wuid)
  1370. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Workunit ID not specified.");
  1371. if (!queueName || !*queueName)
  1372. throw MakeStringException(ECLWATCH_INVALID_INPUT, "queue not specified.");
  1373. Owned<IWorkUnit> lw = factory->updateWorkUnit(wuid);
  1374. if (!lw)
  1375. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT, "Cannot update Workunit %s", wuid);
  1376. lw->setPriority(priority);
  1377. // set job priority to queue
  1378. int priorityValue = lw->getPriorityValue();
  1379. {
  1380. CriticalBlock b(crit);
  1381. Owned<IJobQueue> queue = createJobQueue(queueName);
  1382. QueueLock lock(queue);
  1383. queue->changePriority(wuid,priorityValue);
  1384. }
  1385. return;
  1386. }
  1387. bool CWsSMCEx::onSetJobPriority(IEspContext &context, IEspSMCPriorityRequest &req, IEspSMCPriorityResponse &resp)
  1388. {
  1389. try
  1390. {
  1391. WUPriorityClass priority = PriorityClassNormal;
  1392. if(strieq(req.getPriority(),"high"))
  1393. priority = PriorityClassHigh;
  1394. else if(strieq(req.getPriority(),"low"))
  1395. priority = PriorityClassLow;
  1396. Owned<IWorkUnitFactory> factory = getSecWorkUnitFactory(*context.querySecManager(), *context.queryUser());
  1397. IArrayOf<IConstSMCJob>& jobs = req.getSMCJobs();
  1398. if (!jobs.length())
  1399. setJobPriority(factory, req.getWuid(), req.getQueueName(), priority);
  1400. else
  1401. {
  1402. ForEachItemIn(i, jobs)
  1403. {
  1404. IConstSMCJob &item = jobs.item(i);
  1405. const char *wuid = item.getWuid();
  1406. const char *queueName = item.getQueueName();
  1407. if (wuid && *wuid && queueName && *queueName)
  1408. setJobPriority(factory, wuid, queueName, priority);
  1409. }
  1410. }
  1411. clearActivityInfoCache();
  1412. resp.setRedirectUrl("/WsSMC/");
  1413. }
  1414. catch(IException* e)
  1415. {
  1416. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1417. }
  1418. return true;
  1419. }
  1420. bool CWsSMCEx::onGetThorQueueAvailability(IEspContext &context, IEspGetThorQueueAvailabilityRequest &req, IEspGetThorQueueAvailabilityResponse& resp)
  1421. {
  1422. try
  1423. {
  1424. if (!context.validateFeatureAccess(FEATURE_URL, SecAccess_Read, false))
  1425. throw MakeStringException(ECLWATCH_SMC_ACCESS_DENIED, "Failed to get Thor Queue availability. Permission denied.");
  1426. StringArray thorNames, groupNames, targetNames, queueNames;
  1427. getEnvironmentThorClusterNames(thorNames, groupNames, targetNames, queueNames);
  1428. IArrayOf<IEspThorCluster> ThorClusters;
  1429. ForEachItemIn(x, thorNames)
  1430. {
  1431. const char* targetName = targetNames.item(x);
  1432. const char* queueName = queueNames.item(x);
  1433. IEspThorCluster* returnCluster = new CThorCluster("","");
  1434. returnCluster->setClusterName(targetName);
  1435. returnCluster->setQueueName(queueName);
  1436. StringBuffer info;
  1437. Owned<IJobQueue> queue = createJobQueue(queueName);
  1438. if(queue->stopped(info))
  1439. returnCluster->setQueueStatus("stopped");
  1440. else if (queue->paused(info))
  1441. returnCluster->setQueueStatus("paused");
  1442. else
  1443. returnCluster->setQueueStatus("running");
  1444. unsigned enqueued=0;
  1445. unsigned connected=0;
  1446. unsigned waiting=0;
  1447. queue->getStats(connected,waiting,enqueued);
  1448. returnCluster->setQueueAvailable(waiting);
  1449. returnCluster->setJobsRunning(connected - waiting);
  1450. returnCluster->setJobsInQueue(enqueued);
  1451. ThorClusters.append(*returnCluster);
  1452. }
  1453. resp.setThorClusters(ThorClusters);
  1454. }
  1455. catch(IException* e)
  1456. {
  1457. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1458. }
  1459. return true;
  1460. }
  1461. bool CWsSMCEx::onSetBanner(IEspContext &context, IEspSetBannerRequest &req, IEspSetBannerResponse& resp)
  1462. {
  1463. try
  1464. {
  1465. #ifdef _USE_OPENLDAP
  1466. CLdapSecManager* secmgr = dynamic_cast<CLdapSecManager*>(context.querySecManager());
  1467. if(!secmgr || !secmgr->isSuperUser(context.queryUser()))
  1468. throw MakeStringException(ECLWATCH_SUPER_USER_ACCESS_DENIED, "access denied, administrators only.");
  1469. #endif
  1470. StringBuffer chatURLStr, bannerStr;
  1471. const char* chatURL = req.getChatURL();
  1472. const char* banner = req.getBannerContent();
  1473. //Only display valid strings
  1474. if (chatURL)
  1475. {
  1476. const char* pStr = chatURL;
  1477. for (unsigned i = 0; i < strlen(chatURL); i++)
  1478. {
  1479. if ((pStr[0] > 31) && (pStr[0] < 127))
  1480. chatURLStr.append(pStr[0]);
  1481. pStr++;
  1482. }
  1483. }
  1484. if (banner)
  1485. {
  1486. const char* pStr = banner;
  1487. for (unsigned i = 0; i < strlen(banner); i++)
  1488. {
  1489. if ((pStr[0] > 31) && (pStr[0] < 127))
  1490. bannerStr.append(pStr[0]);
  1491. pStr++;
  1492. }
  1493. }
  1494. chatURLStr.trim();
  1495. bannerStr.trim();
  1496. if (!req.getBannerAction_isNull() && req.getBannerAction() && (bannerStr.length() < 1))
  1497. {
  1498. throw MakeStringException(ECLWATCH_MISSING_BANNER_CONTENT, "If a Banner is enabled, the Banner content must be specified.");
  1499. }
  1500. if (!req.getEnableChatURL_isNull() && req.getEnableChatURL() && (!req.getChatURL() || !*req.getChatURL()))
  1501. {
  1502. throw MakeStringException(ECLWATCH_MISSING_CHAT_URL, "If a Chat is enabled, the Chat URL must be specified.");
  1503. }
  1504. m_ChatURL = chatURLStr;
  1505. m_Banner = bannerStr;
  1506. const char* bannerSize = req.getBannerSize();
  1507. if (bannerSize && *bannerSize)
  1508. m_BannerSize.clear().append(bannerSize);
  1509. const char* bannerColor = req.getBannerColor();
  1510. if (bannerColor && *bannerColor)
  1511. m_BannerColor.clear().append(bannerColor);
  1512. const char* bannerScroll = req.getBannerScroll();
  1513. if (bannerScroll && *bannerScroll)
  1514. m_BannerScroll.clear().append(bannerScroll);
  1515. m_BannerAction = 0;
  1516. if(!req.getBannerAction_isNull())
  1517. m_BannerAction = req.getBannerAction();
  1518. m_EnableChatURL = 0;
  1519. if(!req.getEnableChatURL_isNull())
  1520. m_EnableChatURL = req.getEnableChatURL();
  1521. resp.setRedirectUrl("/WsSMC/Activity");
  1522. }
  1523. catch(IException* e)
  1524. {
  1525. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1526. }
  1527. return true;
  1528. }
  1529. bool CWsSMCEx::onNotInCommunityEdition(IEspContext &context, IEspNotInCommunityEditionRequest &req, IEspNotInCommunityEditionResponse &resp)
  1530. {
  1531. return true;
  1532. }
  1533. bool CWsSMCEx::onBrowseResources(IEspContext &context, IEspBrowseResourcesRequest & req, IEspBrowseResourcesResponse & resp)
  1534. {
  1535. try
  1536. {
  1537. if (!context.validateFeatureAccess(FEATURE_URL, SecAccess_Read, false))
  1538. throw MakeStringException(ECLWATCH_SMC_ACCESS_DENIED, "Failed to Browse Resources. Permission denied.");
  1539. double version = context.getClientVersion();
  1540. Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
  1541. Owned<IConstEnvironment> constEnv = factory->openEnvironment();
  1542. //The resource files will be downloaded from the same box of ESP (not dali)
  1543. StringBuffer ipStr;
  1544. IpAddress ipaddr = queryHostIP();
  1545. ipaddr.getIpText(ipStr);
  1546. if (ipStr.length() > 0)
  1547. {
  1548. resp.setNetAddress(ipStr.str());
  1549. Owned<IConstMachineInfo> machine = constEnv->getMachineByAddress(ipStr.str());
  1550. if (machine)
  1551. {
  1552. int os = machine->getOS();
  1553. resp.setOS(os);
  1554. }
  1555. }
  1556. if (m_PortalURL.length() > 0)
  1557. resp.setPortalURL(m_PortalURL.str());
  1558. #ifndef USE_RESOURCE
  1559. if (version > 1.12)
  1560. resp.setUseResource(false);
  1561. #else
  1562. if (version > 1.12)
  1563. resp.setUseResource(true);
  1564. //Now, get a list of resources stored inside the ESP box
  1565. IArrayOf<IEspHPCCResourceRepository> resourceRepositories;
  1566. Owned<IPropertyTree> pEnvRoot = &constEnv->getPTree();
  1567. const char* ossInstall = pEnvRoot->queryProp("EnvSettings/path");
  1568. if (!ossInstall || !*ossInstall)
  1569. {
  1570. WARNLOG("Failed to get EnvSettings/Path in environment settings.");
  1571. return true;
  1572. }
  1573. StringBuffer path;
  1574. path.appendf("%s/componentfiles/files/downloads", ossInstall);
  1575. Owned<IFile> f = createIFile(path.str());
  1576. if(!f->exists() || !f->isDirectory())
  1577. {
  1578. WARNLOG("Invalid resource folder");
  1579. return true;
  1580. }
  1581. Owned<IDirectoryIterator> di = f->directoryFiles(NULL, false, true);
  1582. if(di.get() == NULL)
  1583. {
  1584. WARNLOG("Resource folder is empty.");
  1585. return true;
  1586. }
  1587. ForEach(*di)
  1588. {
  1589. if (!di->isDir())
  1590. continue;
  1591. StringBuffer folder, path0, tmpBuf;
  1592. di->getName(folder);
  1593. if (folder.length() == 0)
  1594. continue;
  1595. path0.appendf("%s/%s/description.xml", path.str(), folder.str());
  1596. Owned<IFile> f0 = createIFile(path0.str());
  1597. if(!f0->exists())
  1598. {
  1599. WARNLOG("Description file not found for %s", folder.str());
  1600. continue;
  1601. }
  1602. OwnedIFileIO rIO = f0->openShared(IFOread,IFSHfull);
  1603. if(!rIO)
  1604. {
  1605. WARNLOG("Failed to open the description file for %s", folder.str());
  1606. continue;
  1607. }
  1608. offset_t fileSize = f0->size();
  1609. tmpBuf.ensureCapacity((unsigned)fileSize);
  1610. tmpBuf.setLength((unsigned)fileSize);
  1611. size32_t nRead = rIO->read(0, (size32_t) fileSize, (char*)tmpBuf.str());
  1612. if (nRead != fileSize)
  1613. {
  1614. WARNLOG("Failed to read the description file for %s", folder.str());
  1615. continue;
  1616. }
  1617. Owned<IPropertyTree> desc = createPTreeFromXMLString(tmpBuf.str());
  1618. if (!desc)
  1619. {
  1620. WARNLOG("Invalid description file for %s", folder.str());
  1621. continue;
  1622. }
  1623. Owned<IPropertyTreeIterator> fileIterator = desc->getElements("file");
  1624. if (!fileIterator->first())
  1625. {
  1626. WARNLOG("Invalid description file for %s", folder.str());
  1627. continue;
  1628. }
  1629. IArrayOf<IEspHPCCResource> resourcs;
  1630. do {
  1631. IPropertyTree &fileItem = fileIterator->query();
  1632. const char* filename = fileItem.queryProp("filename");
  1633. if (!filename || !*filename)
  1634. continue;
  1635. const char* name0 = fileItem.queryProp("name");
  1636. const char* description0 = fileItem.queryProp("description");
  1637. const char* version0 = fileItem.queryProp("version");
  1638. Owned<IEspHPCCResource> onefile = createHPCCResource();
  1639. onefile->setFileName(filename);
  1640. if (name0 && *name0)
  1641. onefile->setName(name0);
  1642. if (description0 && *description0)
  1643. onefile->setDescription(description0);
  1644. if (version0 && *version0)
  1645. onefile->setVersion(version0);
  1646. resourcs.append(*onefile.getLink());
  1647. } while (fileIterator->next());
  1648. if (resourcs.ordinality())
  1649. {
  1650. StringBuffer path1;
  1651. path1.appendf("%s/%s", path.str(), folder.str());
  1652. Owned<IEspHPCCResourceRepository> oneRepository = createHPCCResourceRepository();
  1653. oneRepository->setName(folder.str());
  1654. oneRepository->setPath(path1.str());
  1655. oneRepository->setHPCCResources(resourcs);
  1656. resourceRepositories.append(*oneRepository.getLink());
  1657. }
  1658. }
  1659. if (resourceRepositories.ordinality())
  1660. resp.setHPCCResourceRepositories(resourceRepositories);
  1661. #endif
  1662. }
  1663. catch(IException* e)
  1664. {
  1665. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1666. }
  1667. return true;
  1668. }
  1669. int CWsSMCSoapBindingEx::onGetForm(IEspContext &context, CHttpRequest* request, CHttpResponse* response, const char *service, const char *method)
  1670. {
  1671. try
  1672. {
  1673. if(stricmp(method,"NotInCommunityEdition")==0)
  1674. {
  1675. StringBuffer page, url, link;
  1676. request->getParameter("EEPortal", url);
  1677. if (url.length() > 0)
  1678. link.appendf("Further information can be found at <a href=\"%s\" target=\"_blank\">%s</a>.", url.str(), url.str());
  1679. page.append(
  1680. "<html>"
  1681. "<head>"
  1682. "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />"
  1683. "<link rel=\"stylesheet\" type=\"text/css\" href=\"/esp/files/default.css\"/>"
  1684. "<link rel=\"stylesheet\" type=\"text/css\" href=\"/esp/files/yui/build/fonts/fonts-min.css\" />"
  1685. "<title>Advanced feature in Enterprise Edition</title>"
  1686. "</head>"
  1687. "<body>"
  1688. "<h3 style=\"text-align:centre;\">Advanced feature in the Enterprise Edition</h4>"
  1689. "<p style=\"text-align:centre;\">Support for this feature is coming soon. ");
  1690. if (link.length() > 0)
  1691. page.append(link.str());
  1692. page.append("</p></body>"
  1693. "</html>");
  1694. response->setContent(page.str());
  1695. response->setContentType("text/html");
  1696. response->send();
  1697. return 0;
  1698. }
  1699. else if(stricmp(method,"DisabledInThisVersion")==0)
  1700. {
  1701. StringBuffer page;
  1702. page.append(
  1703. "<html>"
  1704. "<head>"
  1705. "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />"
  1706. "<link rel=\"stylesheet\" type=\"text/css\" href=\"/esp/files/default.css\"/>"
  1707. "<link rel=\"stylesheet\" type=\"text/css\" href=\"/esp/files/yui/build/fonts/fonts-min.css\" />"
  1708. "<title>Disabled Feature in This Version</title>"
  1709. "</head>"
  1710. "<body>"
  1711. "<h3 style=\"text-align:centre;\">Disabled Feature in This Version</h4>"
  1712. "<p style=\"text-align:centre;\">This feature is disabled in this version. ");
  1713. page.append("</p></body>"
  1714. "</html>");
  1715. response->setContent(page.str());
  1716. response->setContentType("text/html");
  1717. response->send();
  1718. return 0;
  1719. }
  1720. }
  1721. catch(IException* e)
  1722. {
  1723. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1724. }
  1725. return onGetForm(context, request, response, service, method);
  1726. }
  1727. inline const char *controlCmdMessage(int cmd)
  1728. {
  1729. switch (cmd)
  1730. {
  1731. case CRoxieControlCmd_ATTACH:
  1732. return "<control:unlockDali/>";
  1733. case CRoxieControlCmd_DETACH:
  1734. return "<control:lockDali/>";
  1735. case CRoxieControlCmd_RELOAD:
  1736. return "<control:reload/>";
  1737. case CRoxieControlCmd_STATE:
  1738. return "<control:state/>";
  1739. default:
  1740. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Unknown Roxie Control Command.");
  1741. }
  1742. return NULL;
  1743. }
  1744. bool CWsSMCEx::onRoxieControlCmd(IEspContext &context, IEspRoxieControlCmdRequest &req, IEspRoxieControlCmdResponse &resp)
  1745. {
  1746. if (!context.validateFeatureAccess(ROXIE_CONTROL_URL, SecAccess_Full, false))
  1747. throw MakeStringException(ECLWATCH_SMC_ACCESS_DENIED, "Cannot Access Roxie Control. Permission denied.");
  1748. const char *process = req.getProcessCluster();
  1749. if (!process || !*process)
  1750. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Process cluster not specified.");
  1751. const char *controlReq = controlCmdMessage(req.getCommand());
  1752. SocketEndpointArray addrs;
  1753. getRoxieProcessServers(process, addrs);
  1754. if (!addrs.length())
  1755. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Process cluster not found.");
  1756. Owned<IPropertyTree> controlResp = sendRoxieControlAllNodes(addrs.item(0), controlReq, true, req.getWait());
  1757. if (!controlResp)
  1758. throw MakeStringException(ECLWATCH_INTERNAL_ERROR, "Failed to get control response from roxie.");
  1759. IArrayOf<IEspRoxieControlEndpointInfo> respEndpoints;
  1760. Owned<IPropertyTreeIterator> roxieEndpoints = controlResp->getElements("Endpoint");
  1761. ForEach(*roxieEndpoints)
  1762. {
  1763. IPropertyTree &roxieEndpoint = roxieEndpoints->query();
  1764. Owned<IEspRoxieControlEndpointInfo> respEndpoint = createRoxieControlEndpointInfo();
  1765. respEndpoint->setAddress(roxieEndpoint.queryProp("@ep"));
  1766. respEndpoint->setStatus(roxieEndpoint.queryProp("Status"));
  1767. if (roxieEndpoint.hasProp("Dali/@connected"))
  1768. respEndpoint->setAttached(roxieEndpoint.getPropBool("Dali/@connected"));
  1769. if (roxieEndpoint.hasProp("State/@hash"))
  1770. respEndpoint->setStateHash(roxieEndpoint.queryProp("State/@hash"));
  1771. respEndpoints.append(*respEndpoint.getClear());
  1772. }
  1773. resp.setEndpoints(respEndpoints);
  1774. return true;
  1775. }
  1776. bool CWsSMCEx::onGetStatusServerInfo(IEspContext &context, IEspGetStatusServerInfoRequest &req, IEspGetStatusServerInfoResponse &resp)
  1777. {
  1778. getStatusServerInfo(context, req.getServerType(), req.getServerName(), req.getNetworkAddress(), req.getPort(), resp.updateStatusServerInfo());
  1779. return true;
  1780. }
  1781. void CWsSMCEx::getStatusServerInfo(IEspContext &context, const char *serverType, const char *server, const char *networkAddress, unsigned port,
  1782. IEspStatusServerInfo& statusServerInfo)
  1783. {
  1784. if (!serverType || !*serverType)
  1785. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Server type not specified.");
  1786. if (strieq(serverType,STATUS_SERVER_THOR) || strieq(serverType,STATUS_SERVER_HTHOR) || strieq(serverType,STATUS_SERVER_ROXIE))
  1787. {
  1788. if (!server || !*server)
  1789. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "cluster not specified.");
  1790. getStatusServerInfo(context, server, statusServerInfo);
  1791. }
  1792. else if (!strieq(serverType,STATUS_SERVER_DFUSERVER))
  1793. {
  1794. if (!networkAddress || !*networkAddress)
  1795. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Server network address not specified.");
  1796. getStatusServerInfo(context, serverType, networkAddress, port, statusServerInfo);
  1797. }
  1798. else
  1799. {
  1800. if (!server || !*server)
  1801. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Server not specified.");
  1802. getDFUServerInfo(context, server, statusServerInfo);
  1803. }
  1804. return;
  1805. }
  1806. void CWsSMCEx::getStatusServerInfo(IEspContext &context, const char* clusteName, IEspStatusServerInfo& statusServerInfo)
  1807. {
  1808. double version = context.getClientVersion();
  1809. Owned<IConstWUClusterInfo> info = getTargetClusterInfo(clusteName);
  1810. if (!info)
  1811. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO,"Failed to get target cluster information.");
  1812. CWsSMCTargetCluster targetCluster;
  1813. readTargetClusterInfo(context, *info, NULL, &targetCluster);
  1814. bool foundQueueInStatusServer = false;
  1815. Owned<IPropertyTree> statusServerTree = getStatusServerTree(info);
  1816. if (statusServerTree)
  1817. {
  1818. foundQueueInStatusServer = true;
  1819. BoolHash uniqueWUIDs;
  1820. IArrayOf<IEspActiveWorkunit> aws;
  1821. StringBuffer networkAddress;
  1822. statusServerTree->getProp("@node", networkAddress);
  1823. unsigned port = statusServerTree->getPropInt("@mpport");
  1824. readRunningWUsOnCluster(context, clusteName, networkAddress.str(), port, targetCluster, statusServerTree, uniqueWUIDs, aws);
  1825. readWUsAndStateFromJobQueue(context, targetCluster, uniqueWUIDs, aws);
  1826. statusServerInfo.setWorkunits(aws);
  1827. }
  1828. IEspTargetCluster& clusterInfo = statusServerInfo.updateTargetClusterInfo();
  1829. clusterInfo.setClusterName(targetCluster.clusterName.get());
  1830. clusterInfo.setClusterSize(targetCluster.clusterSize);
  1831. clusterInfo.setClusterType(targetCluster.clusterType);
  1832. clusterInfo.setQueueName(targetCluster.queueName.get());
  1833. clusterInfo.setQueueStatus(targetCluster.queueStatus.get());
  1834. if (targetCluster.clusterType != ThorLCRCluster)
  1835. targetCluster.agentQueue.foundQueueInStatusServer = foundQueueInStatusServer;
  1836. else
  1837. targetCluster.clusterQueue.foundQueueInStatusServer = foundQueueInStatusServer;
  1838. setClusterStatus(context, targetCluster, &clusterInfo);
  1839. }
  1840. void CWsSMCEx::getStatusServerInfo(IEspContext &context, const char* type, const char *networkAddress, unsigned port, IEspStatusServerInfo& statusServerInfo)
  1841. {
  1842. double version = context.getClientVersion();
  1843. Owned<IPropertyTree> statusServerTree = getStatusServerTree(networkAddress, port);
  1844. if (!statusServerTree)
  1845. throw MakeStringException(ECLWATCH_CANNOT_GET_STATUS_INFO, "Server not attached");
  1846. IEspServerJobQueue& serverInfo = statusServerInfo.updateServerInfo();
  1847. serverInfo.setNetworkAddress(networkAddress);
  1848. serverInfo.setPort(port);
  1849. StringBuffer queueName, instance;
  1850. statusServerTree->getProp("@queue", queueName);
  1851. setServerJobQueue(version, type, NULL, queueName.str(), serverInfo);
  1852. instance.appendf("%s on %s:%d", type, networkAddress, port);
  1853. IArrayOf<IEspActiveWorkunit> aws;
  1854. Owned<IPropertyTreeIterator> wuids(statusServerTree->getElements("WorkUnit"));
  1855. ForEach(*wuids)
  1856. {
  1857. const char* wuid=wuids->query().queryProp(NULL);
  1858. if (!wuid || !*wuid)
  1859. continue;
  1860. Owned<IEspActiveWorkunit> wu;
  1861. createActiveWorkUnit(wu, context, wuid, NULL, 0, type, queueName.str(), instance, NULL, true);
  1862. aws.append(*wu.getLink());
  1863. }
  1864. statusServerInfo.setWorkunits(aws);
  1865. }
  1866. void CWsSMCEx::getDFUServerInfo(IEspContext &context, const char* serverName, IEspStatusServerInfo& statusServerInfo)
  1867. {
  1868. double version = context.getClientVersion();
  1869. VStringBuffer xpath("/Environment/Software/%s[@name=\"%s\"]", eqDfu, serverName);
  1870. Owned<IRemoteConnection> connEnv = querySDS().connect(xpath.str(), myProcessSession(), RTM_LOCK_READ, SDS_LOCK_TIMEOUT);
  1871. if (!connEnv)
  1872. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO,"Failed to get environment information.");
  1873. IPropertyTree* serviceTree = connEnv->queryRoot();
  1874. if (!serviceTree)
  1875. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO,"Failed to get environment information.");
  1876. const char *queueName = serviceTree->queryProp("@queue");
  1877. if (!queueName || !*queueName)
  1878. throw MakeStringException(ECLWATCH_CANNOT_GET_ENV_INFO, "Server queue not found.");
  1879. setServerJobQueue(version, "DFUserver", serverName, queueName, statusServerInfo.updateServerInfo());
  1880. IArrayOf<IEspActiveWorkunit> aws;
  1881. readDFUWUs(context, queueName, serverName, aws);
  1882. statusServerInfo.setWorkunits(aws);
  1883. }
  1884. IPropertyTree* CWsSMCEx::getStatusServerTree(IConstWUClusterInfo* info)
  1885. {
  1886. SCMStringBuffer str;
  1887. StringBuffer xpath;
  1888. if (info->getPlatform() != HThorCluster)
  1889. {
  1890. if (info->getPlatform() == ThorLCRCluster)
  1891. xpath.setf("/Status/Servers/Server[@name=\"%s\"][@cluster=\"%s\"]", getStatusServerTypeName(WsSMCSSTThorLCRCluster), info->getThorProcesses().item(0));
  1892. else
  1893. xpath.setf("/Status/Servers/Server[@name=\"%s\"][@cluster=\"%s\"]", getStatusServerTypeName(WsSMCSSTRoxieCluster), info->getRoxieProcess(str).str());
  1894. Owned<IRemoteConnection> connStatusServer = querySDS().connect(xpath.str(),myProcessSession(),RTM_LOCK_READ,SDS_LOCK_TIMEOUT);
  1895. if (!connStatusServer)
  1896. return NULL;
  1897. Owned<IPropertyTree> retServerTree = connStatusServer->queryRoot()->getBranch(NULL);
  1898. return retServerTree.getClear();
  1899. }
  1900. else
  1901. {
  1902. Owned<IRemoteConnection> connStatusServer = querySDS().connect("/Status/Servers",myProcessSession(),RTM_LOCK_READ,SDS_LOCK_TIMEOUT);
  1903. if (!connStatusServer)
  1904. throw MakeStringException(ECLWATCH_CANNOT_GET_STATUS_INFO, "Status servers not found");
  1905. info->getAgentQueue(str);
  1906. xpath.setf("Server[@name=\"%s\"]", getStatusServerTypeName(WsSMCSSTHThorCluster));
  1907. Owned<IPropertyTreeIterator> it(connStatusServer->queryRoot()->getElements(xpath));
  1908. ForEach(*it)
  1909. {
  1910. IPropertyTree &serverTree = it->query();
  1911. const char *queueNames = serverTree.queryProp("@queue");
  1912. if (!queueNames || !*queueNames)
  1913. continue;
  1914. StringArray qlist;
  1915. qlist.appendListUniq(queueNames, ",");
  1916. ForEachItemIn(q, qlist)
  1917. {
  1918. if (!strieq(qlist.item(q), str.str()))
  1919. continue;
  1920. Owned<IPropertyTree> retServerTree = serverTree.getBranch(NULL);
  1921. return retServerTree.getClear();
  1922. }
  1923. }
  1924. }
  1925. return NULL;
  1926. }
  1927. IPropertyTree* CWsSMCEx::getStatusServerTree(const char *networkAddress, unsigned port)
  1928. {
  1929. if (!networkAddress || !*networkAddress)
  1930. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Network Address not specified");
  1931. VStringBuffer xpath("/Status/Servers/Server[@node=\"%s\"][@mpport=\"%d\"]", networkAddress, port);
  1932. Owned<IRemoteConnection> connStatusServer = querySDS().connect(xpath.str(),myProcessSession(),RTM_LOCK_READ,SDS_LOCK_TIMEOUT);
  1933. if (!connStatusServer)
  1934. return NULL;
  1935. Owned<IPropertyTree> retServerTree = connStatusServer->queryRoot()->getBranch(NULL);
  1936. return retServerTree.getClear();
  1937. }
  1938. void CWsSMCEx::readRunningWUsOnCluster(IEspContext& context, const char* serverName, const char* node, unsigned port,
  1939. CWsSMCTargetCluster& targetCluster, IPropertyTree* statusServerNode, BoolHash& uniqueWUIDs, IArrayOf<IEspActiveWorkunit>& aws)
  1940. {
  1941. const char *cluster = statusServerNode->queryProp("Cluster");
  1942. StringBuffer queueName;
  1943. if (cluster) // backward compat check.
  1944. getClusterThorQueueName(queueName, cluster);
  1945. else
  1946. queueName.append(targetCluster.queueName.get());
  1947. CWsSMCQueue* jobQueue;
  1948. if (targetCluster.clusterType == ThorLCRCluster)
  1949. jobQueue = &targetCluster.clusterQueue;
  1950. else
  1951. jobQueue = &targetCluster.agentQueue;
  1952. StringBuffer instance;
  1953. if ((targetCluster.clusterType == ThorLCRCluster) || (targetCluster.clusterType == RoxieCluster))
  1954. statusServerNode->getProp("@cluster", instance);
  1955. else
  1956. instance.appendf("%s on %s:%d", serverName, node, port);
  1957. const char* targetClusterName = targetCluster.clusterName.get();
  1958. Owned<IPropertyTreeIterator> wuids(statusServerNode->getElements("WorkUnit"));
  1959. ForEach(*wuids)
  1960. {
  1961. const char* wuid=wuids->query().queryProp(NULL);
  1962. if (!wuid || !*wuid)
  1963. continue;
  1964. Owned<IEspActiveWorkunit> wu;
  1965. createActiveWorkUnit(wu, context, wuid, !strieq(targetClusterName, instance.str()) ? instance.str() : NULL, 0, serverName,
  1966. queueName, instance.str(), targetClusterName, true);
  1967. if (wu->getStateID() == WUStateRunning) //'aborting' may be another possible status
  1968. {
  1969. StringBuffer durationStr, subgraphStr;
  1970. int sgDuration = statusServerNode->getPropInt("@sg_duration", -1);
  1971. int subgraph = statusServerNode->getPropInt("@subgraph", -1);
  1972. const char* graph = statusServerNode->queryProp("@graph");
  1973. durationStr.appendf("%d min", sgDuration);
  1974. subgraphStr.appendf("%d", subgraph);
  1975. if (subgraph > -1 && sgDuration > -1)
  1976. {
  1977. wu->setGraphName(graph);
  1978. wu->setDuration(durationStr.str());
  1979. wu->setGID(subgraphStr.str());
  1980. }
  1981. if (statusServerNode->getPropInt("@memoryBlocked ", 0) != 0)
  1982. wu->setMemoryBlocked(1);
  1983. }
  1984. aws.append(*wu.getLink());
  1985. jobQueue->countRunningJobs++;
  1986. }
  1987. }
  1988. void CWsSMCEx::setServerJobQueue(double version, const char* serverType, const char* serverName, const char* queueName, IEspServerJobQueue& serverInfo)
  1989. {
  1990. StringBuffer queueState, queueStateDetails;
  1991. Owned<IJobQueue> queue = createJobQueue(queueName);
  1992. if (queue->stopped(queueStateDetails))
  1993. queueState.set("stopped");
  1994. else if (queue->paused(queueStateDetails))
  1995. queueState.set("paused");
  1996. else
  1997. queueState.set("running");
  1998. serverInfo.setQueueName(queueName);
  1999. serverInfo.setServerType(serverType);
  2000. if (serverName && *serverName)
  2001. serverInfo.setServerName(serverName);
  2002. setServerJobQueueStatus(version, &serverInfo, queueState, queueStateDetails);
  2003. }