ws_workunitsHelpers.cpp 143 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "jlib.hpp"
  14. #include "ws_workunitsHelpers.hpp"
  15. #include "exception_util.hpp"
  16. #include "daclient.hpp"
  17. #include "dalienv.hpp"
  18. #include "daaudit.hpp"
  19. #include "portlist.h"
  20. #include "dadfs.hpp"
  21. #include "fileview.hpp"
  22. #include "wuwebview.hpp"
  23. #include "dllserver.hpp"
  24. #include "wujobq.hpp"
  25. #include "hqlexpr.hpp"
  26. #include "rmtsmtp.hpp"
  27. #include "LogicFileWrapper.hpp"
  28. #include "TpWrapper.hpp"
  29. #ifndef _NO_LDAP
  30. #include "ldapsecurity.ipp"
  31. #endif
  32. #ifdef _USE_ZLIB
  33. #include "zcrypt.hpp"
  34. #endif
  35. namespace ws_workunits {
  36. const char * const timerFilterText = "measure[time],source[global],depth[1,]"; // Does not include hthor subgraph timings
  37. const char* zipFolder = "tempzipfiles" PATHSEPSTR;
  38. SecAccessFlags chooseWuAccessFlagsByOwnership(const char *user, const char *owner, SecAccessFlags accessOwn, SecAccessFlags accessOthers)
  39. {
  40. return (isEmpty(owner) || (user && streq(user, owner))) ? accessOwn : accessOthers;
  41. }
  42. SecAccessFlags chooseWuAccessFlagsByOwnership(const char *user, IConstWorkUnitInfo& cw, SecAccessFlags accessOwn, SecAccessFlags accessOthers)
  43. {
  44. return chooseWuAccessFlagsByOwnership(user, cw.queryUser(), accessOwn, accessOthers);
  45. }
  46. const char *getWuAccessType(const char *owner, const char *user)
  47. {
  48. return (isEmpty(owner) || (user && streq(user, owner))) ? OWN_WU_ACCESS : OTHERS_WU_ACCESS;
  49. }
  50. const char *getWuAccessType(IConstWorkUnit& cw, const char *user)
  51. {
  52. return getWuAccessType(cw.queryUser(), user);
  53. }
  54. void getUserWuAccessFlags(IEspContext& context, SecAccessFlags& accessOwn, SecAccessFlags& accessOthers, bool except)
  55. {
  56. if (!context.authorizeFeature(OWN_WU_ACCESS, accessOwn))
  57. accessOwn = SecAccess_None;
  58. if (!context.authorizeFeature(OTHERS_WU_ACCESS, accessOthers))
  59. accessOthers = SecAccess_None;
  60. if (except && (accessOwn == SecAccess_None) && (accessOthers == SecAccess_None))
  61. {
  62. context.setAuthStatus(AUTH_STATUS_NOACCESS);
  63. AuditSystemAccess(context.queryUserId(), false, "Access Denied: User can't view any workunits");
  64. VStringBuffer msg("Access Denied: User %s does not have rights to access workunits.", context.queryUserId());
  65. throw MakeStringException(ECLWATCH_ECL_WU_ACCESS_DENIED, "%s", msg.str());
  66. }
  67. }
  68. SecAccessFlags getWsWorkunitAccess(IEspContext& ctx, IConstWorkUnit& cw)
  69. {
  70. SecAccessFlags accessFlag = SecAccess_None;
  71. ctx.authorizeFeature(getWuAccessType(cw, ctx.queryUserId()), accessFlag);
  72. return accessFlag;
  73. }
  74. bool validateWsWorkunitAccess(IEspContext& ctx, const char* wuid, SecAccessFlags minAccess)
  75. {
  76. Owned<IWorkUnitFactory> wf = getWorkUnitFactory(ctx.querySecManager(), ctx.queryUser());
  77. Owned<IConstWorkUnit> cw = wf->openWorkUnit(wuid);
  78. if (!cw)
  79. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT, "Failed to open workunit %s when validating workunit access", wuid);
  80. return ctx.validateFeatureAccess(getWuAccessType(*cw, ctx.queryUserId()), minAccess, false);
  81. }
  82. bool validateWsWorkunitAccessByOwnerId(IEspContext& ctx, const char* owner, SecAccessFlags minAccess)
  83. {
  84. return ctx.validateFeatureAccess(getWuAccessType(owner, ctx.queryUserId()), minAccess, false);
  85. }
  86. void ensureWsWorkunitAccessByOwnerId(IEspContext& ctx, const char* owner, SecAccessFlags minAccess)
  87. {
  88. if (!ctx.validateFeatureAccess(getWuAccessType(owner, ctx.queryUserId()), minAccess, false))
  89. {
  90. ctx.setAuthStatus(AUTH_STATUS_NOACCESS);
  91. throw MakeStringException(ECLWATCH_ECL_WU_ACCESS_DENIED, "Failed to access workunit. Permission denied.");
  92. }
  93. }
  94. void ensureWsWorkunitAccess(IEspContext& ctx, IConstWorkUnit& cw, SecAccessFlags minAccess)
  95. {
  96. if (!ctx.validateFeatureAccess(getWuAccessType(cw, ctx.queryUserId()), minAccess, false))
  97. {
  98. ctx.setAuthStatus(AUTH_STATUS_NOACCESS);
  99. throw MakeStringException(ECLWATCH_ECL_WU_ACCESS_DENIED, "Failed to access workunit. Permission denied.");
  100. }
  101. }
  102. void ensureWsWorkunitAccess(IEspContext& context, const char* wuid, SecAccessFlags minAccess)
  103. {
  104. Owned<IWorkUnitFactory> wf = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  105. Owned<IConstWorkUnit> cw = wf->openWorkUnit(wuid);
  106. if (!cw)
  107. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT, "Failed to open workunit %s when ensuring workunit access", wuid);
  108. ensureWsWorkunitAccess(context, *cw, minAccess);
  109. }
  110. void ensureWsCreateWorkunitAccess(IEspContext& ctx)
  111. {
  112. if (!ctx.validateFeatureAccess(OWN_WU_ACCESS, SecAccess_Write, false))
  113. {
  114. ctx.setAuthStatus(AUTH_STATUS_NOACCESS);
  115. throw MakeStringException(ECLWATCH_ECL_WU_ACCESS_DENIED, "Failed to create workunit. Permission denied.");
  116. }
  117. }
  118. StringBuffer &getWuidFromLogicalFileName(IEspContext &context, const char *logicalName, StringBuffer &wuid)
  119. {
  120. Owned<IDistributedFile> df = lookupLogicalName(context, logicalName, AccessMode::tbdRead, false, false, nullptr, defaultPrivilegedUser);
  121. if (!df)
  122. throw makeStringExceptionV(ECLWATCH_FILE_NOT_EXIST, "Cannot find file %s.", logicalName);
  123. return wuid.append(df->queryAttributes().queryProp("@workunit"));
  124. }
  125. void formatDuration(StringBuffer &s, unsigned ms)
  126. {
  127. unsigned days = ms / (1000*60*60*24);
  128. ms %= (1000*60*60*24);
  129. unsigned hours = ms / (1000*60*60);
  130. ms %= (1000*60*60);
  131. unsigned mins = ms / (1000*60);
  132. ms %= (1000*60);
  133. unsigned secs = ms / 1000;
  134. ms %= 1000;
  135. if (days)
  136. s.appendf("%d days ", days);
  137. if (hours || s.length())
  138. s.appendf("%d:", hours);
  139. if (mins || s.length())
  140. s.appendf("%d:", mins);
  141. if (s.length())
  142. s.appendf("%02d.%03d", secs, ms);
  143. else
  144. s.appendf("%d.%03d", secs, ms);
  145. }
  146. WsWUExceptions::WsWUExceptions(IConstWorkUnit& wu): numerr(0), numwrn(0), numinf(0), numalert(0)
  147. {
  148. Owned<IConstWUExceptionIterator> it = &wu.getExceptions();
  149. ForEach(*it)
  150. {
  151. IConstWUException & cur = it->query();
  152. SCMStringBuffer src, msg, file;
  153. Owned<IEspECLException> e= createECLException("","");
  154. e->setCode(cur.getExceptionCode());
  155. e->setSource(cur.getExceptionSource(src).str());
  156. e->setMessage(cur.getExceptionMessage(msg).str());
  157. e->setFileName(cur.getExceptionFileName(file).str());
  158. e->setLineNo(cur.getExceptionLineNo());
  159. e->setColumn(cur.getExceptionColumn());
  160. if (cur.getActivityId())
  161. e->setActivity(cur.getActivityId());
  162. if (cur.getPriority())
  163. e->setPriority(cur.getPriority());
  164. e->setScope(cur.queryScope());
  165. const char * label = "";
  166. switch (cur.getSeverity())
  167. {
  168. default:
  169. case SeverityError: label = "Error"; numerr++; break;
  170. case SeverityWarning: label = "Warning"; numwrn++; break;
  171. case SeverityInformation: label = "Info"; numinf++; break;
  172. case SeverityAlert: label = "Alert"; numalert++; break;
  173. }
  174. e->setSeverity(label);
  175. errors.append(*e.getLink());
  176. }
  177. }
  178. void WsWuInfo::getSourceFiles(IEspECLWorkunit &info, unsigned long flags)
  179. {
  180. if (!(flags & WUINFO_IncludeSourceFiles))
  181. return;
  182. try
  183. {
  184. Owned<IUserDescriptor> userdesc;
  185. StringBuffer username;
  186. context.getUserID(username);
  187. const char* passwd = context.queryPassword();
  188. userdesc.setown(createUserDescriptor());
  189. userdesc->set(username.str(), passwd, context.querySignature());
  190. IArrayOf<IEspECLSourceFile> files;
  191. if (version < 1.27)
  192. {
  193. Owned<IPropertyTreeIterator> f=&cw->getFilesReadIterator();
  194. ForEach(*f)
  195. {
  196. IPropertyTree &query = f->query();
  197. const char *clusterName = query.queryProp("@cluster");
  198. const char *fileName = query.queryProp("@name");
  199. int fileCount = query.getPropInt("@useCount");
  200. Owned<IEspECLSourceFile> file= createECLSourceFile("","");
  201. if(clusterName && *clusterName)
  202. {
  203. file->setFileCluster(clusterName);
  204. }
  205. if (version > 1.11)
  206. {
  207. Owned<IPropertyTreeIterator> filetrees= query.getElements("Subfile");
  208. if (filetrees->first())
  209. file->setIsSuperFile(true);
  210. }
  211. if (fileName && *fileName)
  212. {
  213. file->setName(fileName);
  214. }
  215. file->setCount(fileCount);
  216. files.append(*file.getLink());
  217. }
  218. }
  219. else
  220. {
  221. StringArray fileNames;
  222. Owned<IPropertyTreeIterator> f=&cw->getFilesReadIterator();
  223. ForEach(*f)
  224. {
  225. IPropertyTree &query = f->query();
  226. const char *clusterName = query.queryProp("@cluster");
  227. const char *fileName = query.queryProp("@name");
  228. int fileCount = query.getPropInt("@useCount");
  229. bool bFound = false;
  230. if (fileName && *fileName && (fileNames.length() > 0))
  231. {
  232. for (unsigned i = 0; i < fileNames.length(); i++ ) // MORE - unnecessary n^2 process
  233. {
  234. const char *fileName0 = fileNames.item(i);
  235. if (!stricmp(fileName, fileName0))
  236. {
  237. bFound = true;
  238. break;
  239. }
  240. }
  241. }
  242. if (bFound)
  243. continue;
  244. Owned<IEspECLSourceFile> file= createECLSourceFile("","");
  245. if(clusterName && *clusterName)
  246. {
  247. file->setFileCluster(clusterName);
  248. }
  249. if (fileName && *fileName)
  250. {
  251. file->setName(fileName);
  252. }
  253. file->setCount(fileCount);
  254. Owned<IPropertyTreeIterator> filetrees= query.getElements("Subfile");
  255. if (filetrees->first())
  256. {
  257. file->setIsSuperFile(true);
  258. getSubFiles(filetrees, file, fileNames);
  259. }
  260. files.append(*file.getLink());
  261. }
  262. }
  263. info.setSourceFiles(files);
  264. }
  265. catch(IException* e)
  266. {
  267. StringBuffer eMsg;
  268. IERRLOG("%s", e->errorMessage(eMsg).str());
  269. info.setSourceFilesDesc(eMsg.str());
  270. e->Release();
  271. }
  272. }
  273. void WsWuInfo::getExceptions(IEspECLWorkunit &info, unsigned long flags)
  274. {
  275. if ((flags & WUINFO_IncludeExceptions) || version > 1.16)
  276. {
  277. WsWUExceptions errors(*cw);
  278. if (version > 1.16)
  279. {
  280. info.setErrorCount(errors.ErrCount());
  281. info.setWarningCount(errors.WrnCount());
  282. info.setInfoCount(errors.InfCount());
  283. info.setAlertCount(errors.AlertCount());
  284. }
  285. if ((flags & WUINFO_IncludeExceptions))
  286. info.setExceptions(errors);
  287. }
  288. }
  289. void WsWuInfo::getVariables(IEspECLWorkunit &info, unsigned long flags)
  290. {
  291. if (!(flags & WUINFO_IncludeVariables))
  292. return;
  293. try
  294. {
  295. IArrayOf<IEspECLResult> results;
  296. Owned<IConstWUResultIterator> vars = &cw->getVariables();
  297. ForEach(*vars)
  298. getResult(vars->query(), results, flags);
  299. info.setVariables(results);
  300. results.kill();
  301. }
  302. catch(IException* e)
  303. {
  304. StringBuffer eMsg;
  305. IERRLOG("%s", e->errorMessage(eMsg).str());
  306. info.setVariablesDesc(eMsg.str());
  307. e->Release();
  308. }
  309. }
  310. void WsWuInfo::addTimerToList(SCMStringBuffer& name, const char * scope, IConstWUStatistic & stat, IArrayOf<IEspECLTimer>& timers)
  311. {
  312. StringBuffer fd;
  313. formatStatistic(fd, stat.getValue(), stat.getMeasure());
  314. Owned<IEspECLTimer> t= createECLTimer("","");
  315. name.s.replace('_', ' '); // yuk!
  316. t->setName(name.str());
  317. t->setValue(fd.str());
  318. //Theoretically this could overflow, in practice it is unlikely - fix in the new stats interface when implemented
  319. t->setCount((unsigned)stat.getCount());
  320. if (version > 1.19)
  321. {
  322. StringAttr graphName;
  323. unsigned graphNum;
  324. unsigned subGraphNum = 0;
  325. unsigned subId = 0;
  326. if (parseGraphScope(scope, graphName, graphNum, subId) ||
  327. parseGraphTimerLabel(name.str(), graphName, graphNum, subGraphNum, subId)) // leacy
  328. {
  329. if (graphName.length() > 0)
  330. t->setGraphName(graphName);
  331. if (subId > 0)
  332. t->setSubGraphId((int)subId);
  333. }
  334. }
  335. if (version >= 1.72)
  336. {
  337. StringBuffer tsText;
  338. unsigned __int64 ts = stat.getTimestamp();
  339. formatStatistic(tsText, ts, SMeasureTimestampUs);
  340. t->setTimestamp(ts);
  341. t->setWhen(tsText.str());
  342. }
  343. timers.append(*t.getLink());
  344. }
  345. void WsWuInfo::doGetTimers(IArrayOf<IEspECLTimer>& timers)
  346. {
  347. class TimingVisitor : public WuScopeVisitorBase
  348. {
  349. public:
  350. TimingVisitor(WsWuInfo & _wuInfo, IArrayOf<IEspECLTimer>& _timers) : wuInfo(_wuInfo), timers(_timers) {}
  351. virtual void noteStatistic(StatisticKind kind, unsigned __int64 value, IConstWUStatistic & extra) override
  352. {
  353. SCMStringBuffer name;
  354. extra.getDescription(name, true);
  355. const char * scope = extra.queryScope();
  356. wuInfo.addTimerToList(name, scope, extra, timers);
  357. //Aggregate all the times spent executing graphs
  358. if ((kind == StTimeElapsed) && (extra.getScopeType() == SSTgraph))
  359. totalGraphTime.noteValue(value);
  360. }
  361. void addSummary()
  362. {
  363. if (totalGraphTime.getCount())
  364. {
  365. StringBuffer totalThorTimeText;
  366. formatStatistic(totalThorTimeText, totalGraphTime.getSum(), SMeasureTimeNs);
  367. Owned<IEspECLTimer> t= createECLTimer("","");
  368. if (wuInfo.version > 1.52)
  369. t->setName(TOTALCLUSTERTIME);
  370. else
  371. t->setName(TOTALTHORTIME);
  372. t->setValue(totalThorTimeText.str());
  373. t->setCount((unsigned)totalGraphTime.getCount());
  374. timers.append(*t.getClear());
  375. }
  376. }
  377. protected:
  378. WsWuInfo & wuInfo;
  379. IArrayOf<IEspECLTimer>& timers;
  380. StatsAggregation totalGraphTime;
  381. } visitor(*this, timers);
  382. WuScopeFilter filter(timerFilterText);
  383. Owned<IConstWUScopeIterator> it = &cw->getScopeIterator(filter);
  384. ForEach(*it)
  385. it->playProperties(visitor);
  386. visitor.addSummary();
  387. }
  388. void WsWuInfo::getTimers(IEspECLWorkunit &info, unsigned long flags)
  389. {
  390. if (!(flags & WUINFO_IncludeTimers))
  391. return;
  392. try
  393. {
  394. IArrayOf<IEspECLTimer> timers;
  395. doGetTimers(timers);
  396. info.setTimers(timers);
  397. }
  398. catch(IException* e)
  399. {
  400. StringBuffer eMsg;
  401. IERRLOG("%s", e->errorMessage(eMsg).str());
  402. info.setTimersDesc(eMsg.str());
  403. e->Release();
  404. }
  405. }
  406. class TimingCounter : public WuScopeVisitorBase
  407. {
  408. public:
  409. virtual void noteStatistic(StatisticKind kind, unsigned __int64 value, IConstWUStatistic & extra) override
  410. {
  411. numTimers++;
  412. if ((kind == StTimeElapsed) && (extra.getScopeType() == SSTgraph))
  413. hasGraphTiming = true;
  414. }
  415. unsigned getNumTimers() const
  416. {
  417. return numTimers + (hasGraphTiming ? 1 : 0);
  418. }
  419. protected:
  420. bool hasGraphTiming = false;
  421. unsigned numTimers = 0;
  422. };
  423. unsigned WsWuInfo::getTimerCount()
  424. {
  425. TimingCounter visitor;
  426. try
  427. {
  428. WuScopeFilter filter(timerFilterText);
  429. Owned<IConstWUScopeIterator> it = &cw->getScopeIterator(filter);
  430. ForEach(*it)
  431. it->playProperties(visitor);
  432. }
  433. catch(IException* e)
  434. {
  435. StringBuffer eMsg;
  436. IERRLOG("%s", e->errorMessage(eMsg).str());
  437. e->Release();
  438. }
  439. return visitor.getNumTimers();
  440. }
  441. void WsWuInfo::getHelpers(IEspECLWorkunit &info, unsigned long flags)
  442. {
  443. try
  444. {
  445. IArrayOf<IEspECLHelpFile> helpers;
  446. unsigned helpersCount = 2; // ECL + Workunit XML are also helpers...
  447. Owned <IConstWUQuery> query = cw->getQuery();
  448. if(!query)
  449. {
  450. IERRLOG("Cannot get Query for this workunit.");
  451. info.setHelpersDesc("Cannot get Query for this workunit.");
  452. }
  453. else
  454. {
  455. if (flags & WUINFO_IncludeECL)
  456. {
  457. SCMStringBuffer queryText;
  458. query->getQueryShortText(queryText);
  459. if (queryText.length())
  460. {
  461. if((flags & WUINFO_TruncateEclTo64k) && (queryText.length() > 64000))
  462. queryText.setLen(queryText.str(), 64000);
  463. IEspECLQuery* q=&info.updateQuery();
  464. q->setText(queryText.str());
  465. }
  466. }
  467. if (version > 1.34)
  468. {
  469. SCMStringBuffer mainDefinition;
  470. query->getQueryMainDefinition(mainDefinition);
  471. if(mainDefinition.length())
  472. {
  473. IEspECLQuery* q=&info.updateQuery();
  474. q->setQueryMainDefinition(mainDefinition.str());
  475. }
  476. }
  477. if (version > 1.30)
  478. {
  479. info.setHasArchiveQuery(query->hasArchive());
  480. }
  481. for (unsigned i = 0; i < FileTypeSize; i++)
  482. getHelpFiles(query, (WUFileType) i, helpers, flags, helpersCount);
  483. }
  484. #ifndef _CONTAINERIZED
  485. getWorkunitThorLogInfo(helpers, info, flags, helpersCount);
  486. if (cw->getWuidVersion() > 0)
  487. {
  488. Owned<IPropertyTreeIterator> eclAgents = cw->getProcesses("EclAgent", NULL);
  489. ForEach (*eclAgents)
  490. {
  491. StringBuffer logName;
  492. IPropertyTree& eclAgent = eclAgents->query();
  493. eclAgent.getProp("@log",logName);
  494. if (!logName.length())
  495. continue;
  496. helpersCount++;
  497. if (!(flags & WUINFO_IncludeHelpers))
  498. continue;
  499. Owned<IEspECLHelpFile> h= createECLHelpFile("","");
  500. h->setName(logName.str());
  501. h->setType(File_EclAgentLog);
  502. if (version >= 1.43)
  503. {
  504. offset_t fileSize;
  505. if (getFileSize(logName.str(), NULL, fileSize))
  506. h->setFileSize(fileSize);
  507. if (version >= 1.44)
  508. {
  509. if (eclAgent.hasProp("@pid"))
  510. h->setPID(eclAgent.getPropInt("@pid"));
  511. else
  512. h->setPID(cw->getAgentPID());
  513. }
  514. }
  515. helpers.append(*h.getLink());
  516. }
  517. }
  518. else // legacy wuid
  519. {
  520. Owned<IStringIterator> eclAgentLogs = cw->getLogs("EclAgent");
  521. ForEach (*eclAgentLogs)
  522. {
  523. SCMStringBuffer name;
  524. eclAgentLogs->str(name);
  525. if (name.length() < 1)
  526. continue;
  527. helpersCount++;
  528. if (!(flags & WUINFO_IncludeHelpers))
  529. break;
  530. Owned<IEspECLHelpFile> h= createECLHelpFile("","");
  531. h->setName(name.str());
  532. h->setType(File_EclAgentLog);
  533. if (version >= 1.43)
  534. {
  535. offset_t fileSize;
  536. if (getFileSize(name.str(), NULL, fileSize))
  537. h->setFileSize(fileSize);
  538. }
  539. helpers.append(*h.getLink());
  540. break;
  541. }
  542. }
  543. #endif
  544. info.setHelpers(helpers);
  545. info.setHelpersCount(helpersCount);
  546. }
  547. catch(IException* e)
  548. {
  549. StringBuffer eMsg;
  550. IERRLOG("%s", e->errorMessage(eMsg).str());
  551. info.setHelpersDesc(eMsg.str());
  552. e->Release();
  553. }
  554. }
  555. void WsWuInfo::getApplicationValues(IEspECLWorkunit &info, unsigned long flags)
  556. {
  557. if (!(flags & WUINFO_IncludeApplicationValues))
  558. return;
  559. try
  560. {
  561. IArrayOf<IEspApplicationValue> av;
  562. Owned<IConstWUAppValueIterator> app(&cw->getApplicationValues());
  563. ForEach(*app)
  564. {
  565. IConstWUAppValue& val=app->query();
  566. Owned<IEspApplicationValue> t= createApplicationValue("","");
  567. t->setApplication(val.queryApplication());
  568. t->setName(val.queryName());
  569. t->setValue(val.queryValue());
  570. av.append(*t.getLink());
  571. }
  572. info.setApplicationValues(av);
  573. }
  574. catch(IException* e)
  575. {
  576. StringBuffer eMsg;
  577. IERRLOG("%s", e->errorMessage(eMsg).str());
  578. info.setApplicationValuesDesc(eMsg.str());
  579. e->Release();
  580. }
  581. }
  582. void WsWuInfo::getDebugValues(IEspECLWorkunit &info, unsigned long flags)
  583. {
  584. if (!(flags & WUINFO_IncludeDebugValues))
  585. {
  586. if (version >= 1.50)
  587. {
  588. unsigned debugValueCount = 0;
  589. Owned<IStringIterator> debugs(&cw->getDebugValues());
  590. ForEach(*debugs)
  591. debugValueCount++;
  592. info.setDebugValueCount(debugValueCount);
  593. }
  594. return;
  595. }
  596. try
  597. {
  598. IArrayOf<IEspDebugValue> dv;
  599. Owned<IStringIterator> debugs(&cw->getDebugValues());
  600. ForEach(*debugs)
  601. {
  602. SCMStringBuffer name, val;
  603. debugs->str(name);
  604. cw->getDebugValue(name.str(),val);
  605. Owned<IEspDebugValue> t= createDebugValue("","");
  606. t->setName(name.str());
  607. t->setValue(val.str());
  608. dv.append(*t.getLink());
  609. }
  610. if (version >= 1.50)
  611. info.setDebugValueCount(dv.length());
  612. info.setDebugValues(dv);
  613. }
  614. catch(IException* e)
  615. {
  616. StringBuffer eMsg;
  617. IERRLOG("%s", e->errorMessage(eMsg).str());
  618. info.setDebugValuesDesc(eMsg.str());
  619. e->Release();
  620. }
  621. }
  622. const char *getGraphNum(const char *s,unsigned &num)
  623. {
  624. while (*s && !isdigit(*s))
  625. s++;
  626. num = 0;
  627. while (isdigit(*s))
  628. {
  629. num = num*10+*s-'0';
  630. s++;
  631. }
  632. return s;
  633. }
  634. bool WsWuInfo::hasSubGraphTimings()
  635. {
  636. try
  637. {
  638. WuScopeFilter filter("depth[3],stype[subgraph],stat[TimeElapsed],nested[0]");
  639. Owned<IConstWUScopeIterator> it = &cw->getScopeIterator(filter);
  640. ForEach(*it)
  641. {
  642. stat_type value;
  643. if (it->getStat(StTimeElapsed, value))
  644. return true;
  645. }
  646. }
  647. catch(IException* e)
  648. {
  649. StringBuffer eMsg;
  650. IERRLOG("%s", e->errorMessage(eMsg).str());
  651. e->Release();
  652. }
  653. return false;
  654. }
  655. void WsWuInfo::doGetGraphs(IArrayOf<IEspECLGraph>& graphs)
  656. {
  657. SCMStringBuffer runningGraph;
  658. WUGraphIDType id;
  659. WUState st = cw->getState();
  660. bool running = (!(st==WUStateFailed || st==WUStateAborted || st==WUStateCompleted) && cw->getRunningGraph(runningGraph,id));
  661. Owned<IConstWUGraphMetaIterator> it = &cw->getGraphsMeta(GraphTypeAny);
  662. ForEach(*it)
  663. {
  664. IConstWUGraphMeta &graph = it->query();
  665. SCMStringBuffer name, label, type;
  666. graph.getName(name);
  667. graph.getLabel(label);
  668. graph.getTypeName(type);
  669. WUGraphState graphState = graph.getState();
  670. Owned<IEspECLGraph> g= createECLGraph();
  671. g->setName(name.str());
  672. g->setLabel(label.str());
  673. g->setType(type.str());
  674. if (WUGraphComplete == graphState)
  675. g->setComplete(true);
  676. else if (running && (WUGraphRunning == graphState))
  677. {
  678. g->setRunning(true);
  679. g->setRunningId(id);
  680. }
  681. else if (WUGraphFailed == graphState)
  682. g->setFailed(true);
  683. if (version >= 1.53)
  684. {
  685. //MORE: Will need to be prefixed with the wfid
  686. StringBuffer scope;
  687. scope.append(name);
  688. StringBuffer s;
  689. stat_type timeStamp;
  690. if (cw->getStatistic(timeStamp, scope.str(), StWhenStarted) ||
  691. cw->getStatistic(timeStamp, name.str(), StWhenGraphStarted))
  692. {
  693. g->setWhenStarted(formatStatistic(s.clear(), timeStamp, SMeasureTimestampUs));
  694. }
  695. if (cw->getStatistic(timeStamp, scope.str(), StWhenFinished) ||
  696. cw->getStatistic(timeStamp, name.str(), StWhenGraphFinished))
  697. {
  698. g->setWhenFinished(formatStatistic(s.clear(), timeStamp, SMeasureTimestampUs));
  699. }
  700. }
  701. graphs.append(*g.getLink());
  702. }
  703. }
  704. void WsWuInfo::getGraphInfo(IEspECLWorkunit &info, unsigned long flags)
  705. {
  706. if ((version > 1.01) && (version < 1.71))
  707. {
  708. info.setHaveSubGraphTimings(false);
  709. if (hasSubGraphTimings())
  710. info.setHaveSubGraphTimings(true);
  711. }
  712. if (!(flags & WUINFO_IncludeGraphs))
  713. return;
  714. try
  715. {
  716. IArrayOf<IEspECLGraph> graphs;
  717. doGetGraphs(graphs);
  718. info.setGraphs(graphs);
  719. }
  720. catch(IException* e)
  721. {
  722. StringBuffer eMsg;
  723. IERRLOG("%s", e->errorMessage(eMsg).str());
  724. info.setGraphsDesc(eMsg.str());
  725. e->Release();
  726. }
  727. }
  728. void WsWuInfo::getWUGraphNameAndTypes(WUGraphType graphType, IArrayOf<IEspNameAndType>& graphNameAndTypes)
  729. {
  730. Owned<IConstWUGraphMetaIterator> it = &cw->getGraphsMeta(graphType);
  731. ForEach(*it)
  732. {
  733. SCMStringBuffer name, type;
  734. IConstWUGraphMeta &graph = it->query();
  735. Owned<IEspNameAndType> nameAndType = createNameAndType();
  736. nameAndType->setName(graph.getName(name).str());
  737. nameAndType->setType(graph.getTypeName(type).str());
  738. graphNameAndTypes.append(*nameAndType.getLink());
  739. }
  740. }
  741. void WsWuInfo::getGraphTimingData(IArrayOf<IConstECLTimingData> &timingData)
  742. {
  743. class TimingVisitor : public WuScopeVisitorBase
  744. {
  745. public:
  746. TimingVisitor(WsWuInfo & _wuInfo, IArrayOf<IConstECLTimingData> & _timingData) : wuInfo(_wuInfo), timingData(_timingData) {}
  747. virtual void noteStatistic(StatisticKind kind, unsigned __int64 value, IConstWUStatistic & cur) override
  748. {
  749. const char * scope = cur.queryScope();
  750. StringAttr graphName;
  751. unsigned graphNum;
  752. unsigned subGraphId;
  753. if (parseGraphScope(scope, graphName, graphNum, subGraphId))
  754. {
  755. unsigned time = (unsigned)nanoToMilli(value);
  756. SCMStringBuffer name;
  757. cur.getDescription(name, true);
  758. Owned<IEspECLTimingData> g = createECLTimingData();
  759. g->setName(name.str());
  760. g->setGraphNum(graphNum);
  761. g->setSubGraphNum(subGraphId); // Use the Id - the number is not known
  762. g->setGID(subGraphId);
  763. g->setMS(time);
  764. g->setMin(time/60000);
  765. timingData.append(*g.getClear());
  766. }
  767. }
  768. protected:
  769. WsWuInfo & wuInfo;
  770. IArrayOf<IConstECLTimingData> & timingData;
  771. } visitor(*this, timingData);
  772. WuScopeFilter filter("stype[subgraph],stat[TimeElapsed],nested[0]");
  773. Owned<IConstWUScopeIterator> it = &cw->getScopeIterator(filter);
  774. ForEach(*it)
  775. it->playProperties(visitor);
  776. }
  777. void WsWuInfo::getServiceNames(IEspECLWorkunit &info, unsigned long flags)
  778. {
  779. if (!(flags & WUINFO_IncludeServiceNames))
  780. return;
  781. StringArray serviceNames;
  782. WuScopeFilter filter;
  783. filter.addScopeType("activity");
  784. filter.addOutputAttribute(WaServiceName);
  785. filter.addRequiredAttr(WaServiceName);
  786. filter.finishedFilter();
  787. Owned<IConstWUScopeIterator> it = &cw->getScopeIterator(filter);
  788. ForEach(*it)
  789. {
  790. StringBuffer serviceName;
  791. const char *value = it->queryAttribute(WaServiceName, serviceName);
  792. if (!isEmptyString(value))
  793. serviceNames.append(value);
  794. }
  795. info.setServiceNames(serviceNames);
  796. }
  797. void WsWuInfo::getEventScheduleFlag(IEspECLWorkunit &info)
  798. {
  799. info.setEventSchedule(0);
  800. if (info.getState() && !stricmp(info.getState(), "wait"))
  801. {
  802. info.setEventSchedule(2); //Can deschedule
  803. }
  804. else
  805. {
  806. Owned<IConstWorkflowItemIterator> it = cw->getWorkflowItems();
  807. if (it)
  808. {
  809. ForEach(*it)
  810. {
  811. IConstWorkflowItem *r = it->query();
  812. if (!r)
  813. continue;
  814. Owned<IWorkflowEvent> wfevent = r->getScheduleEvent();
  815. if (!wfevent)
  816. continue;
  817. if ((!r->hasScheduleCount() || (r->queryScheduleCountRemaining() > 0))
  818. && info.getState() && !strieq(info.getState(), "scheduled")
  819. && !strieq(info.getState(), "aborting") && !strieq(info.getState(), "aborted")
  820. && !strieq(info.getState(), "failed") && !strieq(info.getState(), "archived"))
  821. {
  822. info.setEventSchedule(1); //Can reschedule
  823. break;
  824. }
  825. }
  826. }
  827. }
  828. }
  829. void WsWuInfo::getCommon(IEspECLWorkunit &info, unsigned long flags)
  830. {
  831. info.setWuid(cw->queryWuid());
  832. info.setProtected(cw->isProtected() ? 1 : 0);
  833. info.setJobname(cw->queryJobName());
  834. info.setOwner(cw->queryUser());
  835. clusterName.set(cw->queryClusterName());
  836. info.setCluster(clusterName.str());
  837. SCMStringBuffer s;
  838. info.setSnapshot(cw->getSnapshot(s).str());
  839. if ((cw->getState() == WUStateScheduled) && cw->aborting())
  840. {
  841. info.setStateID(WUStateAborting);
  842. info.setState("aborting");
  843. }
  844. else
  845. {
  846. info.setStateID(cw->getState());
  847. info.setState(cw->queryStateDesc());
  848. }
  849. if (cw->isPausing())
  850. info.setIsPausing(true);
  851. getEventScheduleFlag(info);
  852. //The TotalClusterTime should always be returned between versions 1.27 and 1.73.
  853. //After version 1.73, it should be returned only if IncludeTotalClusterTime is true.
  854. if ((version > 1.27) && ((version < 1.73) || (flags & WUINFO_IncludeTotalClusterTime)))
  855. {
  856. unsigned totalThorTimeMS = cw->getTotalThorTime();
  857. if (totalThorTimeMS)
  858. {
  859. StringBuffer totalThorTimeStr;
  860. formatDuration(totalThorTimeStr, totalThorTimeMS);
  861. if (version > 1.52)
  862. info.setTotalClusterTime(totalThorTimeStr.str());
  863. else
  864. info.setTotalThorTime(totalThorTimeStr.str());
  865. }
  866. }
  867. WsWuDateTime dt;
  868. cw->getTimeScheduled(dt);
  869. if(dt.isValid())
  870. info.setDateTimeScheduled(dt.getString(s).str());
  871. if (version>=1.84)
  872. info.setExecuteCost(cost_type2money(cw->getExecuteCost()));
  873. if (version>=1.85)
  874. info.setFileAccessCost(cost_type2money(cw->getFileAccessCost()));
  875. if (version>=1.87)
  876. info.setCompileCost(cost_type2money(cw->getCompileCost()));
  877. }
  878. void WsWuInfo::setWUAbortTime(IEspECLWorkunit &info, unsigned __int64 abortTS)
  879. {
  880. StringBuffer abortTimeStr;
  881. formatStatistic(abortTimeStr, abortTS, SMeasureTimestampUs);
  882. if ((abortTimeStr.length() > 19) && (abortTimeStr.charAt(10) == 'T') && (abortTimeStr.charAt(19) == '.'))
  883. {
  884. abortTimeStr.setCharAt(10, ' ');
  885. abortTimeStr.setLength(19);
  886. }
  887. info.setAbortTime(abortTimeStr.str());
  888. }
  889. void WsWuInfo::getInfo(IEspECLWorkunit &info, unsigned long flags)
  890. {
  891. getCommon(info, flags);
  892. SecAccessFlags accessFlag = getWsWorkunitAccess(context, *cw);
  893. info.setAccessFlag(accessFlag);
  894. SCMStringBuffer s;
  895. info.setStateEx(cw->getStateEx(s).str());
  896. WUState state = cw->getState();
  897. if ((state == WUStateAborting) || (state == WUStateAborted))
  898. {
  899. unsigned __int64 abortTS = cw->getAbortTimeStamp();
  900. if (abortTS > 0) //AbortTimeStamp may not be set in old wu
  901. {
  902. setWUAbortTime(info, abortTS);
  903. cw->getAbortBy(s);
  904. if (s.length())
  905. info.setAbortBy(s.str());
  906. }
  907. }
  908. info.setPriorityClass(cw->getPriority());
  909. info.setPriorityLevel(cw->getPriorityLevel());
  910. if (context.querySecManager())
  911. info.setScope(cw->queryWuScope());
  912. info.setActionEx(cw->queryActionDesc());
  913. info.setDescription(cw->getDebugValue("description", s).str());
  914. if (version > 1.21)
  915. info.setXmlParams(cw->getXmlParams(s, true).str());
  916. info.setResultLimit(cw->getResultLimit());
  917. info.setArchived(false);
  918. info.setGraphCount(cw->getGraphCount());
  919. info.setSourceFileCount(cw->getSourceFileCount());
  920. info.setResultCount(cw->getResultCount());
  921. info.setWorkflowCount(cw->queryEventScheduledCount());
  922. info.setVariableCount(cw->getVariableCount());
  923. info.setTimerCount(getTimerCount());
  924. info.setSourceFileCount(cw->getSourceFileCount());
  925. info.setApplicationValueCount(cw->getApplicationValueCount());
  926. info.setHasDebugValue(cw->hasDebugValue("__calculated__complexity__"));
  927. if(version>=1.84)
  928. info.setExecuteCost(cost_type2money(cw->getExecuteCost()));
  929. if(version>=1.85)
  930. info.setFileAccessCost(cost_type2money(cw->getFileAccessCost()));
  931. if (version>=1.87)
  932. info.setCompileCost(cost_type2money(cw->getCompileCost()));
  933. getClusterInfo(info, flags);
  934. getExceptions(info, flags);
  935. getHelpers(info, flags);
  936. getGraphInfo(info, flags);
  937. getSourceFiles(info, flags);
  938. getResults(info, flags);
  939. getVariables(info, flags);
  940. getTimers(info, flags);
  941. getDebugValues(info, flags);
  942. getApplicationValues(info, flags);
  943. getWorkflow(info, flags);
  944. getServiceNames(info, flags);
  945. }
  946. #ifndef _CONTAINERIZED
  947. unsigned WsWuInfo::getWorkunitThorLogInfo(IArrayOf<IEspECLHelpFile>& helpers, IEspECLWorkunit &info, unsigned long flags, unsigned& helpersCount)
  948. {
  949. unsigned countThorLog = 0;
  950. IArrayOf<IConstThorLogInfo> thorLogList;
  951. if (cw->getWuidVersion() > 0)
  952. {
  953. StringAttr clusterName(cw->queryClusterName());
  954. if (!clusterName.length()) //Cluster name may not be set yet
  955. return countThorLog;
  956. Owned<IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(clusterName.str());
  957. if (!clusterInfo)
  958. {
  959. IWARNLOG("Cannot find TargetClusterInfo for workunit %s", cw->queryWuid());
  960. return countThorLog;
  961. }
  962. unsigned numberOfSlaveLogs = clusterInfo->getNumberOfSlaveLogs();
  963. BoolHash uniqueProcesses;
  964. Owned<IStringIterator> thorInstances = cw->getProcesses("Thor");
  965. ForEach (*thorInstances)
  966. {
  967. SCMStringBuffer processName;
  968. thorInstances->str(processName);
  969. if (processName.length() < 1)
  970. continue;
  971. bool* found = uniqueProcesses.getValue(processName.str());
  972. if (found && *found)
  973. continue;
  974. uniqueProcesses.setValue(processName.str(), true);
  975. StringBuffer groupName;
  976. getClusterThorGroupName(groupName, processName.str());
  977. Owned<IStringIterator> thorLogs = cw->getLogs("Thor", processName.str());
  978. ForEach (*thorLogs)
  979. {
  980. SCMStringBuffer logName;
  981. thorLogs->str(logName);
  982. if (logName.length() < 1)
  983. continue;
  984. countThorLog++;
  985. StringBuffer fileType;
  986. if (countThorLog < 2)
  987. fileType.append(File_ThorLog);
  988. else
  989. fileType.appendf("%s%d", File_ThorLog, countThorLog);
  990. helpersCount++;
  991. if (flags & WUINFO_IncludeHelpers)
  992. {
  993. Owned<IEspECLHelpFile> h= createECLHelpFile("","");
  994. h->setName(logName.str());
  995. h->setDescription(processName.str());
  996. h->setType(fileType.str());
  997. if (version >= 1.43)
  998. {
  999. offset_t fileSize;
  1000. if (getFileSize(logName.str(), NULL, fileSize))
  1001. h->setFileSize(fileSize);
  1002. }
  1003. helpers.append(*h.getLink());
  1004. }
  1005. if (version < 1.38)
  1006. continue;
  1007. const char* pStr = logName.str();
  1008. const char* ppStr = strstr(pStr, "/thormaster.");
  1009. if (!ppStr)
  1010. {
  1011. IWARNLOG("Invalid thorlog entry in workunit xml: %s", logName.str());
  1012. continue;
  1013. }
  1014. ppStr += 12;
  1015. StringBuffer logDate(ppStr);
  1016. logDate.setLength(10);
  1017. Owned<IEspThorLogInfo> thorLog = createThorLogInfo("","");
  1018. thorLog->setProcessName(processName.str());
  1019. thorLog->setClusterGroup(groupName.str());
  1020. thorLog->setLogDate(logDate.str());
  1021. thorLog->setNumberSlaves(numberOfSlaveLogs);
  1022. thorLogList.append(*thorLog.getLink());
  1023. }
  1024. }
  1025. }
  1026. else //legacy wuid
  1027. {
  1028. Owned<IStringIterator> thorLogs = cw->getLogs("Thor");
  1029. ForEach (*thorLogs)
  1030. {
  1031. SCMStringBuffer name;
  1032. thorLogs->str(name);
  1033. if (name.length() < 1)
  1034. continue;
  1035. countThorLog++;
  1036. StringBuffer fileType;
  1037. if (countThorLog < 2)
  1038. fileType.append(File_ThorLog);
  1039. else
  1040. fileType.appendf("%s%d", File_ThorLog, countThorLog);
  1041. helpersCount++;
  1042. if (flags & WUINFO_IncludeHelpers)
  1043. {
  1044. Owned<IEspECLHelpFile> h= createECLHelpFile("","");
  1045. h->setName(name.str());
  1046. h->setType(fileType.str());
  1047. if (version >= 1.43)
  1048. {
  1049. offset_t fileSize;
  1050. if (getFileSize(name.str(), NULL, fileSize))
  1051. h->setFileSize(fileSize);
  1052. }
  1053. helpers.append(*h.getLink());
  1054. }
  1055. }
  1056. StringBuffer logDir;
  1057. Owned<IEnvironmentFactory> envFactory = getEnvironmentFactory(true);
  1058. Owned<IConstEnvironment> constEnv = envFactory->openEnvironment();
  1059. Owned<IPropertyTree> logTree = &constEnv->getPTree();
  1060. if (logTree)
  1061. logTree->getProp("EnvSettings/log", logDir);
  1062. if (logDir.length() > 0)
  1063. {
  1064. Owned<IStringIterator> debugs = cw->getLogs("Thor");
  1065. ForEach(*debugs)
  1066. {
  1067. SCMStringBuffer val;
  1068. debugs->str(val);
  1069. if (val.length() < 1)
  1070. continue;
  1071. const char* pStr = val.str();
  1072. const char* ppStr = strstr(pStr, logDir.str());
  1073. if (!ppStr)
  1074. {
  1075. IWARNLOG("Invalid thorlog entry in workunit xml: %s", val.str());
  1076. continue;
  1077. }
  1078. const char* pProcessName = ppStr + logDir.length();
  1079. char sep = pProcessName[0];
  1080. StringBuffer processName(pProcessName + 1);
  1081. ppStr = strchr(pProcessName + 1, sep);
  1082. if (!ppStr)
  1083. {
  1084. IWARNLOG("Invalid thorlog entry in workunit xml: %s", val.str());
  1085. continue;
  1086. }
  1087. processName.setLength(ppStr - pProcessName - 1);
  1088. StringBuffer groupName;
  1089. getClusterThorGroupName(groupName, processName.str());
  1090. StringBuffer logDate(ppStr + 12);
  1091. logDate.setLength(10);
  1092. Owned<IEspThorLogInfo> thorLog = createThorLogInfo("","");
  1093. thorLog->setProcessName(processName.str());
  1094. thorLog->setClusterGroup(groupName.str());
  1095. thorLog->setLogDate(logDate.str());
  1096. //for legacy wuid, the log name does not contain slaveNum. So, a user may not specify
  1097. //a slaveNum and we only display the first slave log if > 1 per IP.
  1098. thorLog->setNumberSlaves(0);
  1099. thorLogList.append(*thorLog.getLink());
  1100. }
  1101. }
  1102. }
  1103. if (thorLogList.length() > 0)
  1104. info.setThorLogList(thorLogList);
  1105. thorLogList.kill();
  1106. return countThorLog;
  1107. }
  1108. #endif
  1109. bool WsWuInfo::getClusterInfo(IEspECLWorkunit &info, unsigned long flags)
  1110. {
  1111. if ((flags & WUINFO_IncludeAllowedClusters) && (version > 1.04))
  1112. {
  1113. StringArray allowedClusters;
  1114. SCMStringBuffer val;
  1115. cw->getAllowedClusters(val);
  1116. if (val.length() > 0)
  1117. {
  1118. const char* ptr = val.str();
  1119. while(*ptr != '\0')
  1120. {
  1121. StringBuffer onesub;
  1122. while(*ptr != '\0' && *ptr != ',')
  1123. {
  1124. onesub.append((char)(*ptr));
  1125. ptr++;
  1126. }
  1127. if(onesub.length() > 0)
  1128. allowedClusters.append(onesub.str());
  1129. if(*ptr != '\0')
  1130. ptr++;
  1131. }
  1132. }
  1133. if (allowedClusters.length() > 0)
  1134. info.setAllowedClusters(allowedClusters);
  1135. }
  1136. if (version > 1.23 && clusterName.length())
  1137. {
  1138. int clusterTypeFlag = 0;
  1139. Owned<IConstWUClusterInfo> clusterInfo = getWUClusterInfoByName(clusterName.str());
  1140. if (clusterInfo.get())
  1141. {//Set thor flag or roxie flag in order to display some options for thor or roxie
  1142. ClusterType platform = clusterInfo->getPlatform();
  1143. if (isThorCluster(platform))
  1144. {
  1145. clusterTypeFlag=1;
  1146. if (version > 1.29)
  1147. info.setThorLCR(ThorLCRCluster == platform);
  1148. }
  1149. else if (RoxieCluster == platform)
  1150. clusterTypeFlag=2;
  1151. }
  1152. info.setClusterFlag(clusterTypeFlag);
  1153. }
  1154. return true;
  1155. }
  1156. void WsWuInfo::getWorkflow(IEspECLWorkunit &info, unsigned long flags)
  1157. {
  1158. if (!(flags & WUINFO_IncludeWorkflows))
  1159. return;
  1160. try
  1161. {
  1162. Owned<IConstWorkflowItemIterator> it = cw->getWorkflowItems();
  1163. if (!it)
  1164. return;
  1165. IArrayOf<IConstECLWorkflow> workflows;
  1166. ForEach(*it)
  1167. {
  1168. IConstWorkflowItem* r = it->query();
  1169. if (!r)
  1170. continue;
  1171. IWorkflowEvent* wfevent = r->getScheduleEvent();
  1172. if (!wfevent)
  1173. continue;
  1174. StringBuffer id;
  1175. Owned<IEspECLWorkflow> g = createECLWorkflow();
  1176. g->setWFID(id.appendf("%d", r->queryWfid()).str());
  1177. g->setEventName(wfevent->queryName());
  1178. g->setEventText(wfevent->queryText());
  1179. if (r->hasScheduleCount())
  1180. {
  1181. g->setCount(r->queryScheduleCount());
  1182. g->setCountRemaining(r->queryScheduleCountRemaining());
  1183. }
  1184. workflows.append(*g.getLink());
  1185. }
  1186. if (workflows.length() > 0)
  1187. info.setWorkflows(workflows);
  1188. }
  1189. catch(IException* e)
  1190. {
  1191. StringBuffer eMsg;
  1192. IERRLOG("%s", e->errorMessage(eMsg).str());
  1193. info.setWorkflowsDesc(eMsg.str());
  1194. e->Release();
  1195. }
  1196. }
  1197. IDistributedFile* WsWuInfo::getLogicalFileData(IEspContext& context, const char* logicalName, bool& showFileContent)
  1198. {
  1199. Owned<IDistributedFile> df = lookupLogicalName(context, logicalName, AccessMode::tbdRead, false, false, nullptr, defaultPrivilegedUser);
  1200. if (!df)
  1201. return nullptr;
  1202. bool blocked;
  1203. if (df->isCompressed(&blocked) && !blocked)
  1204. return df.getClear();
  1205. IPropertyTree& properties = df->queryAttributes();
  1206. const char * format = properties.queryProp("@format");
  1207. if (format && (stricmp(format,"csv")==0 || memicmp(format, "utf", 3) == 0))
  1208. {
  1209. showFileContent = true;
  1210. return df.getClear();
  1211. }
  1212. const char * recordEcl = properties.queryProp("ECL");
  1213. if (!recordEcl)
  1214. return df.getClear();
  1215. MultiErrorReceiver errs;
  1216. Owned<IHqlExpression> ret = ::parseQuery(recordEcl, &errs);
  1217. showFileContent = errs.errCount() == 0;
  1218. return df.getClear();
  1219. }
  1220. void WsWuInfo::getEclSchemaChildFields(IArrayOf<IEspECLSchemaItem>& schemas, IHqlExpression * expr, bool isConditional)
  1221. {
  1222. if(!expr)
  1223. return;
  1224. ForEachChild(idx, expr)
  1225. getEclSchemaFields(schemas, expr->queryChild(idx), isConditional);
  1226. }
  1227. void WsWuInfo::getEclSchemaFields(IArrayOf<IEspECLSchemaItem>& schemas, IHqlExpression * expr, bool isConditional)
  1228. {
  1229. if(!expr)
  1230. return;
  1231. int ret = expr->getOperator();
  1232. switch (ret)
  1233. {
  1234. case no_record:
  1235. getEclSchemaChildFields(schemas, expr, isConditional);
  1236. break;
  1237. case no_ifblock:
  1238. {
  1239. getEclSchemaChildFields(schemas, expr->queryChild(1), true);
  1240. break;
  1241. }
  1242. case no_field:
  1243. {
  1244. if (expr->hasAttribute(__ifblockAtom))
  1245. break;
  1246. ITypeInfo * type = expr->queryType();
  1247. IAtom * name = expr->queryName();
  1248. IHqlExpression * nameAttr = expr->queryAttribute(namedAtom);
  1249. StringBuffer outname;
  1250. if (nameAttr && nameAttr->queryChild(0) && nameAttr->queryChild(0)->queryValue())
  1251. nameAttr->queryChild(0)->queryValue()->getStringValue(outname);
  1252. else
  1253. outname.append(name).toLowerCase();
  1254. if(type)
  1255. {
  1256. type_t tc = type->getTypeCode();
  1257. if (tc == type_row)
  1258. {
  1259. getEclSchemaChildFields(schemas, expr->queryRecord(), isConditional);
  1260. }
  1261. else
  1262. {
  1263. if (type->getTypeCode() == type_alien)
  1264. {
  1265. IHqlAlienTypeInfo * alien = queryAlienType(type);
  1266. type = alien->queryPhysicalType();
  1267. }
  1268. Owned<IEspECLSchemaItem> schema = createECLSchemaItem("","");
  1269. StringBuffer eclType;
  1270. type->getECLType(eclType);
  1271. schema->setColumnName(outname);
  1272. schema->setColumnType(eclType.str());
  1273. schema->setColumnTypeCode(tc);
  1274. schema->setIsConditional(isConditional);
  1275. schemas.append(*schema.getClear());
  1276. }
  1277. }
  1278. break;
  1279. }
  1280. }
  1281. }
  1282. bool WsWuInfo::getResultEclSchemas(IConstWUResult &r, IArrayOf<IEspECLSchemaItem>& schemas)
  1283. {
  1284. SCMStringBuffer schema;
  1285. r.getResultEclSchema(schema);
  1286. if (!schema.length())
  1287. return false;
  1288. MultiErrorReceiver errs;
  1289. Owned<IHqlExpression> expr = ::parseQuery(schema.str(), &errs);
  1290. if (errs.errCount() != 0)
  1291. return false;
  1292. getEclSchemaFields(schemas, expr, false);
  1293. return true;
  1294. }
  1295. void WsWuInfo::getResult(IConstWUResult &r, IArrayOf<IEspECLResult>& results, unsigned long flags)
  1296. {
  1297. SCMStringBuffer name;
  1298. r.getResultName(name);
  1299. SCMStringBuffer filename;
  1300. r.getResultLogicalName(filename);
  1301. bool showFileContent = false;
  1302. Owned<IDistributedFile> df = NULL;
  1303. if (filename.length())
  1304. df.setown(getLogicalFileData(context, filename.str(), showFileContent));
  1305. StringBuffer value, link;
  1306. if (r.getResultStatus() == ResultStatusUndefined)
  1307. value.set("[undefined]");
  1308. else if (r.isResultScalar())
  1309. {
  1310. try
  1311. {
  1312. SCMStringBuffer xml;
  1313. r.getResultXml(xml, true);
  1314. Owned<IPropertyTree> props = createPTreeFromXMLString(xml.str(), ipt_caseInsensitive);
  1315. IPropertyTree *val = props->queryPropTree("Row/*");
  1316. if(val)
  1317. value.set(val->queryProp(NULL));
  1318. else
  1319. {
  1320. Owned<IResultSetFactory> resultSetFactory = getSecResultSetFactory(context.querySecManager(), context.queryUser(), context.queryUserId(), context.queryPassword());
  1321. Owned<INewResultSet> result;
  1322. result.setown(resultSetFactory->createNewResultSet(&r, wuid.str()));
  1323. Owned<IResultSetCursor> cursor(result->createCursor());
  1324. cursor->first();
  1325. if (r.getResultIsAll())
  1326. {
  1327. value.set("<All/>");
  1328. }
  1329. else
  1330. {
  1331. Owned<IResultSetCursor> childCursor = cursor->getChildren(0);
  1332. if (childCursor)
  1333. {
  1334. ForEach(*childCursor)
  1335. {
  1336. StringBuffer out;
  1337. StringBufferAdaptor adaptor(out);
  1338. childCursor->getDisplayText(adaptor, 0);
  1339. if (!value.length())
  1340. value.append('[');
  1341. else
  1342. value.append(", ");
  1343. value.append('\'').append(out.str()).append('\'');
  1344. }
  1345. if (value.length())
  1346. value.append(']');
  1347. }
  1348. }
  1349. }
  1350. }
  1351. catch(...)
  1352. {
  1353. value.append("[value not available]");
  1354. }
  1355. }
  1356. else
  1357. {
  1358. value.append('[').append(r.getResultTotalRowCount()).append(" rows]");
  1359. if((r.getResultSequence()>=0) && (!filename.length() || (df && df->queryAttributes().hasProp("ECL"))))
  1360. link.append(r.getResultSequence());
  1361. }
  1362. Owned<IEspECLResult> result= createECLResult("","");
  1363. if (flags & WUINFO_IncludeEclSchemas)
  1364. {
  1365. IArrayOf<IEspECLSchemaItem> schemas;
  1366. if (getResultEclSchemas(r, schemas))
  1367. result->setECLSchemas(schemas);
  1368. }
  1369. if (flags & WUINFO_IncludeXmlSchema)
  1370. {
  1371. Owned<IResultSetFactory> resultSetFactory = getSecResultSetFactory(context.querySecManager(), context.queryUser(), context.queryUserId(), context.queryPassword());
  1372. Owned<INewResultSet> rs = resultSetFactory->createNewResultSet(&r, wuid.str());
  1373. Owned<IResultSetCursor> cursor(rs->createCursor());
  1374. SCMStringBuffer xsd;
  1375. const IResultSetMetaData & meta = cursor->queryResultSet()->getMetaData();
  1376. meta.getXmlXPathSchema(xsd, false);
  1377. result->setXmlSchema(xsd.str());
  1378. }
  1379. if (filename.length())
  1380. result->setShowFileContent(showFileContent);
  1381. result->setName(name.str());
  1382. result->setLink(link.str());
  1383. result->setSequence(r.getResultSequence());
  1384. result->setValue(value.str());
  1385. result->setFileName(filename.str());
  1386. result->setIsSupplied(r.getResultStatus() == ResultStatusSupplied);
  1387. result->setTotal(r.getResultTotalRowCount());
  1388. results.append(*result.getLink());
  1389. }
  1390. void WsWuInfo::getResults(IEspECLWorkunit &info, unsigned long flags)
  1391. {
  1392. if (!(flags & WUINFO_IncludeResults))
  1393. return;
  1394. try
  1395. {
  1396. IArrayOf<IEspECLResult> results;
  1397. Owned<IConstWUResultIterator> it = &(cw->getResults());
  1398. ForEach(*it)
  1399. {
  1400. IConstWUResult &r = it->query();
  1401. if(r.getResultSequence()>=0)
  1402. getResult(r, results, flags);
  1403. }
  1404. if (results.length())
  1405. info.setResults(results);
  1406. results.kill();
  1407. }
  1408. catch(IException* e)
  1409. {
  1410. StringBuffer eMsg;
  1411. IERRLOG("%s", e->errorMessage(eMsg).str());
  1412. info.setResultsDesc(eMsg.str());
  1413. e->Release();
  1414. }
  1415. }
  1416. class FilteredStatisticsVisitor : public WuScopeVisitorBase
  1417. {
  1418. public:
  1419. FilteredStatisticsVisitor(WsWuInfo & _wuInfo, bool _createDescriptions, IArrayOf<IEspWUStatisticItem>& _statistics, const StatisticsFilter& _statsFilter)
  1420. : wuInfo(_wuInfo), statistics(_statistics), statsFilter(_statsFilter), createDescriptions(_createDescriptions) {}
  1421. virtual void noteStatistic(StatisticKind curKind, unsigned __int64 value, IConstWUStatistic & cur) override
  1422. {
  1423. StringBuffer xmlBuf, tsValue;
  1424. SCMStringBuffer curCreator, curDescription, curFormattedValue;
  1425. StatisticCreatorType curCreatorType = cur.getCreatorType();
  1426. StatisticScopeType curScopeType = cur.getScopeType();
  1427. StatisticMeasure curMeasure = cur.getMeasure();
  1428. unsigned __int64 count = cur.getCount();
  1429. unsigned __int64 max = cur.getMax();
  1430. unsigned __int64 ts = cur.getTimestamp();
  1431. const char * curScope = cur.queryScope();
  1432. cur.getCreator(curCreator);
  1433. cur.getDescription(curDescription, createDescriptions);
  1434. cur.getFormattedValue(curFormattedValue);
  1435. Owned<IEspWUStatisticItem> wuStatistic = createWUStatisticItem();
  1436. if (!statsFilter.matches(curCreatorType, curCreator.str(), curScopeType, curScope, curMeasure, curKind, value))
  1437. return;
  1438. if (wuInfo.version > 1.61)
  1439. wuStatistic->setWuid(wuInfo.wuid);
  1440. if (curCreatorType != SCTnone)
  1441. wuStatistic->setCreatorType(queryCreatorTypeName(curCreatorType));
  1442. if (curCreator.length())
  1443. wuStatistic->setCreator(curCreator.str());
  1444. if (curScopeType != SSTnone)
  1445. wuStatistic->setScopeType(queryScopeTypeName(curScopeType));
  1446. if (!isEmpty(curScope))
  1447. wuStatistic->setScope(curScope);
  1448. if (curMeasure != SMeasureNone)
  1449. wuStatistic->setMeasure(queryMeasureName(curMeasure));
  1450. if (curKind != StKindNone)
  1451. wuStatistic->setKind(queryStatisticName(curKind));
  1452. wuStatistic->setRawValue(value);
  1453. wuStatistic->setValue(curFormattedValue.str());
  1454. if (count != 1)
  1455. wuStatistic->setCount(count);
  1456. if (max)
  1457. wuStatistic->setMax(max);
  1458. if (ts)
  1459. {
  1460. formatStatistic(tsValue, ts, SMeasureTimestampUs);
  1461. wuStatistic->setTimeStamp(tsValue.str());
  1462. }
  1463. if (curDescription.length())
  1464. wuStatistic->setDescription(curDescription.str());
  1465. statistics.append(*wuStatistic.getClear());
  1466. }
  1467. protected:
  1468. WsWuInfo & wuInfo;
  1469. const StatisticsFilter& statsFilter;
  1470. IArrayOf<IEspWUStatisticItem>& statistics;
  1471. bool createDescriptions;
  1472. };
  1473. void WsWuInfo::getStats(const WuScopeFilter & filter, const StatisticsFilter& statsFilter, bool createDescriptions, IArrayOf<IEspWUStatisticItem>& statistics)
  1474. {
  1475. FilteredStatisticsVisitor visitor(*this, createDescriptions, statistics, statsFilter);
  1476. Owned<IConstWUScopeIterator> it = &cw->getScopeIterator(filter);
  1477. ForEach(*it)
  1478. it->playProperties(visitor);
  1479. }
  1480. bool WsWuInfo::getFileSize(const char* fileName, const char* IPAddress, offset_t& fileSize)
  1481. {
  1482. if (!fileName || !*fileName)
  1483. return false;
  1484. Owned<IFile> aFile;
  1485. if (!IPAddress || !*IPAddress)
  1486. {
  1487. aFile.setown(createIFile(fileName));
  1488. }
  1489. else
  1490. {
  1491. RemoteFilename rfn;
  1492. rfn.setRemotePath(fileName);
  1493. SocketEndpoint ep(IPAddress);
  1494. rfn.setIp(ep);
  1495. aFile.setown(createIFile(rfn));
  1496. }
  1497. if (!aFile)
  1498. return false;
  1499. bool isDir;
  1500. CDateTime modtime;
  1501. if (!aFile->getInfo(isDir, fileSize, modtime) || isDir)
  1502. return false;
  1503. return true;
  1504. }
  1505. void WsWuInfo::getHelpFiles(IConstWUQuery* query, WUFileType type, IArrayOf<IEspECLHelpFile>& helpers, unsigned long flags, unsigned& helpersCount)
  1506. {
  1507. if (!query)
  1508. return;
  1509. Owned<IConstWUAssociatedFileIterator> iter = &query->getAssociatedFiles();
  1510. ForEach(*iter)
  1511. {
  1512. SCMStringBuffer name, Ip, description;
  1513. IConstWUAssociatedFile & cur = iter->query();
  1514. if (cur.getType() != type)
  1515. continue;
  1516. helpersCount++;
  1517. if (!(flags & WUINFO_IncludeHelpers))
  1518. continue;
  1519. cur.getName(name);
  1520. Owned<IEspECLHelpFile> h= createECLHelpFile("","");
  1521. h->setName(name.str());
  1522. h->setType(getEnumText(type, queryFileTypes));
  1523. if (version > 1.31)
  1524. {
  1525. cur.getIp(Ip);
  1526. h->setIPAddress(Ip.str());
  1527. cur.getDescription(description);
  1528. if ((description.length() < 1) && (name.length() > 0))
  1529. {
  1530. const char* desc = pathTail(name.str());
  1531. if (desc && *desc)
  1532. description.set(desc);
  1533. }
  1534. if (description.length() < 1)
  1535. description.set("Help File");
  1536. h->setDescription(description.str());
  1537. if (version >= 1.43)
  1538. {
  1539. offset_t fileSize;
  1540. if (getFileSize(name.str(), Ip.str(), fileSize))
  1541. h->setFileSize(fileSize);
  1542. }
  1543. if (version >= 1.58)
  1544. {
  1545. h->setMinActivityId(cur.getMinActivityId());
  1546. h->setMaxActivityId(cur.getMaxActivityId());
  1547. }
  1548. }
  1549. helpers.append(*h.getLink());
  1550. }
  1551. }
  1552. void WsWuInfo::getSubFiles(IPropertyTreeIterator* f, IEspECLSourceFile* eclSuperFile, StringArray& fileNames)
  1553. {
  1554. IArrayOf<IEspECLSourceFile> files;
  1555. ForEach(*f)
  1556. {
  1557. IPropertyTree &query = f->query();
  1558. const char *clusterName = query.queryProp("@cluster");
  1559. const char *fileName = query.queryProp("@name");
  1560. int fileCount = query.getPropInt("@useCount");
  1561. bool bFound = false;
  1562. if (fileName && *fileName && (fileNames.length() > 0)) // MORE - this is an n^2 process and as far as I can tell unnecessary as there will be no dups
  1563. {
  1564. for (unsigned i = 0; i < fileNames.length(); i++ )
  1565. {
  1566. const char *fileName0 = fileNames.item(i);
  1567. if (!stricmp(fileName, fileName0))
  1568. {
  1569. bFound = true;
  1570. break;
  1571. }
  1572. }
  1573. }
  1574. if (bFound)
  1575. continue;
  1576. Owned<IEspECLSourceFile> file= createECLSourceFile("","");
  1577. if(clusterName && *clusterName)
  1578. {
  1579. file->setFileCluster(clusterName);
  1580. }
  1581. if (fileName && *fileName)
  1582. {
  1583. file->setName(fileName);
  1584. fileNames.append(fileName);
  1585. }
  1586. file->setCount(fileCount);
  1587. Owned<IPropertyTreeIterator> filetrees= query.getElements("Subfile"); // We do not store subfiles of subfiles like this - so this code will never be triggered
  1588. if (filetrees->first())
  1589. {
  1590. file->setIsSuperFile(true);
  1591. getSubFiles(filetrees, file, fileNames);
  1592. }
  1593. files.append(*file.getLink());
  1594. }
  1595. eclSuperFile->setECLSourceFiles(files);
  1596. return;
  1597. }
  1598. bool WsWuInfo::getResourceInfo(StringArray &viewnames, StringArray &urls, unsigned long flags)
  1599. {
  1600. if (!(flags & (WUINFO_IncludeResultsViewNames | WUINFO_IncludeResourceURLs)))
  1601. return true;
  1602. try
  1603. {
  1604. Owned<IWuWebView> wv = createWuWebView(*cw, NULL, NULL, NULL, false, nullptr);
  1605. if (wv)
  1606. {
  1607. if (flags & WUINFO_IncludeResultsViewNames)
  1608. wv->getResultViewNames(viewnames);
  1609. if (flags & WUINFO_IncludeResourceURLs)
  1610. wv->getResourceURLs(urls, NULL);
  1611. }
  1612. return true;
  1613. }
  1614. catch(IException* e)
  1615. {
  1616. StringBuffer eMsg;
  1617. IERRLOG("%s", e->errorMessage(eMsg).str());
  1618. e->Release();
  1619. }
  1620. return false;
  1621. }
  1622. unsigned WsWuInfo::getResourceURLCount()
  1623. {
  1624. try
  1625. {
  1626. Owned<IWuWebView> wv = createWuWebView(*cw, NULL, NULL, NULL, false, nullptr);
  1627. if (wv)
  1628. return wv->getResourceURLCount();
  1629. }
  1630. catch(IException* e)
  1631. {
  1632. StringBuffer eMsg;
  1633. IERRLOG("%s", e->errorMessage(eMsg).str());
  1634. e->Release();
  1635. }
  1636. return 0;
  1637. }
  1638. void WsWuInfo::copyContentFromRemoteFile(const char* sourceFileName, const char* sourceIPAddress,
  1639. const char* sourceAlias, const char *outFileName)
  1640. {
  1641. RemoteFilename rfn;
  1642. rfn.setRemotePath(sourceFileName);
  1643. SocketEndpoint ep(sourceIPAddress);
  1644. rfn.setIp(ep);
  1645. OwnedIFile source = createIFile(rfn);
  1646. if (!source)
  1647. throw MakeStringException(ECLWATCH_CANNOT_OPEN_FILE, "Cannot open %s.", sourceAlias);
  1648. OwnedIFile target = createIFile(outFileName);
  1649. if (!target)
  1650. throw MakeStringException(ECLWATCH_CANNOT_OPEN_FILE, "Cannot open %s.", outFileName);
  1651. copyFile(target, source);
  1652. }
  1653. void WsWuInfo::readFileContent(const char* sourceFileName, const char* sourceIPAddress,
  1654. const char* sourceAlias, MemoryBuffer &mb, bool forDownload)
  1655. {
  1656. RemoteFilename rfn;
  1657. rfn.setRemotePath(sourceFileName);
  1658. SocketEndpoint ep(sourceIPAddress);
  1659. rfn.setIp(ep);
  1660. OwnedIFile source = createIFile(rfn);
  1661. if (!source)
  1662. throw MakeStringException(ECLWATCH_CANNOT_OPEN_FILE, "Cannot open %s.", sourceAlias);
  1663. OwnedIFileIO sourceIO = source->openShared(IFOread,IFSHfull);
  1664. if (!sourceIO)
  1665. throw MakeStringException(ECLWATCH_CANNOT_READ_FILE, "Cannot open %s.", sourceAlias);
  1666. offset_t len = source->size();
  1667. if (!forDownload && (len > 640000))
  1668. len = 640000;
  1669. if (read(sourceIO, 0, len, mb) != len)
  1670. throw MakeStringException(ECLWATCH_CANNOT_READ_FILE, "Cannot read %s.", sourceAlias);
  1671. }
  1672. #ifndef _CONTAINERIZED
  1673. void WsWuInfo::getWorkunitEclAgentLog(const char* processName, const char* fileName, const char* agentPid, MemoryBuffer& buf, const char* outFile)
  1674. {
  1675. if (isEmptyString(processName) && isEmptyString(fileName))
  1676. throw makeStringException(ECLWATCH_ECLAGENT_LOG_NOT_FOUND, "Log file or process name has to be specified");
  1677. Owned<IFileIOStream> outIOS;
  1678. if (!isEmptyString(outFile))
  1679. {
  1680. CWsWuFileHelper helper(nullptr);
  1681. outIOS.setown(helper.createIOStreamWithFileName(outFile, IFOcreate));
  1682. }
  1683. StringBuffer line;
  1684. bool wuidFound = false;
  1685. bool wuFinish = false;
  1686. StringBuffer pidstr;
  1687. if (agentPid && *agentPid)
  1688. pidstr.appendf(" %s ", agentPid);
  1689. else
  1690. pidstr.appendf(" %5d ", cw->getAgentPID());
  1691. char const* pidchars = pidstr.str();
  1692. size32_t pidLen = pidstr.length();
  1693. unsigned pidOffset = 0;//offset of PID in logfile entry
  1694. //If a WU runs into another day, the WU information is stored in multiple log files.
  1695. //Find out the logSpec for each log file based on the given processName or fileName.
  1696. StringArray logSpecs;
  1697. getWUProcessLogSpecs(processName, fileName, nullptr, true, logSpecs);
  1698. ForEachItemIn(i, logSpecs)
  1699. {
  1700. if (wuFinish)
  1701. break;
  1702. Owned<IFile> rFile = createIFile(logSpecs.item(i));
  1703. if (!rFile)
  1704. throw makeStringExceptionV(ECLWATCH_CANNOT_OPEN_FILE, "Cannot open file %s.", logSpecs.item(i));
  1705. OwnedIFileIO rIO = rFile->openShared(IFOread,IFSHfull);
  1706. if (!rIO)
  1707. throw makeStringExceptionV(ECLWATCH_CANNOT_READ_FILE, "Cannot read file %s.", logSpecs.item(i));
  1708. OwnedIFileIOStream ios = createIOStream(rIO);
  1709. Owned<IStreamLineReader> lineReader = createLineReader(ios, true);
  1710. /*
  1711. Scan the master daily logfile for given PID/WUID. We make the following assumptions
  1712. Column ordering (time, date, pid) is unknown, but we must assume it is constant throughout the logfile.
  1713. It is assumed that the first column is the 8 digit workunit logfile line number.
  1714. Rows from concurrent workunits are intermixed.
  1715. Logfiles are searched via PID and WUID. You are not assured of a match until you have both.
  1716. PIDS and TIDS can and are reused. Beware that a TID could match the search PID.
  1717. Once you have both, you know the offset of the PID column. It is assumed this offset remains constant.
  1718. Search stops at EOF, or early exit if the search PID reappears on different WUID.
  1719. */
  1720. while (!lineReader->readLine(line.clear()))
  1721. {
  1722. if (pidOffset > line.length())
  1723. continue;
  1724. //Retain all rows that match a unique program instance - by retaining all rows that match a pid
  1725. const char* pPid = strstr(line.str() + pidOffset, pidchars);
  1726. if (isEmptyString(pPid))
  1727. continue;
  1728. //Check if this is a new instance using line sequence number (PIDs are often reused)
  1729. if (strncmp(line.str(), "00000000", 8) == 0)
  1730. {
  1731. if (wuidFound) //If the correct instance has been found, return that instance before the next instance.
  1732. {
  1733. wuFinish = true;
  1734. break;
  1735. }
  1736. //The last instance is not a correct instance. Clean the buf in order to start a new instance.
  1737. if (isEmptyString(outFile))
  1738. buf.clear();
  1739. }
  1740. //If we spot the workunit id anywhere in the tracing for this pid then assume it is the correct instance.
  1741. if(!wuidFound && strstr(line.str(), wuid.str()))
  1742. {
  1743. pidOffset = pPid - line.str();//remember offset of PID within line
  1744. wuidFound = true;
  1745. }
  1746. if (pidOffset && 0 == strncmp(line.str() + pidOffset, pidchars, pidLen))//this makes sure the match was the PID and not the TID or something else
  1747. outputALine(line.length(), line.str(), buf, outIOS);
  1748. }
  1749. }
  1750. if (!wuidFound)
  1751. {
  1752. const char * msg = "(No logfile entries found for this workunit)";
  1753. outputALine(strlen(msg), msg, buf, outIOS);
  1754. }
  1755. }
  1756. void WsWuInfo::getWorkunitThorMasterLog(const char* processName, const char* fileName, MemoryBuffer& buf, const char* outFile)
  1757. {
  1758. readWorkunitThorLog(processName, fileName, nullptr, 0, buf, outFile);
  1759. }
  1760. void WsWuInfo::getWorkunitThorSlaveLog(IGroup *nodeGroup, const char *ipAddress, const char* processName, const char* logDate,
  1761. const char* logDir, int slaveNum, MemoryBuffer& buf, const char* outFile, bool forDownload)
  1762. {
  1763. if (isEmpty(logDir))
  1764. throw MakeStringException(ECLWATCH_INVALID_INPUT,"ThorSlave log path not specified.");
  1765. StringBuffer slaveIPAddress;
  1766. if (slaveNum > 0)
  1767. {
  1768. nodeGroup->queryNode(slaveNum-1).endpoint().getIpText(slaveIPAddress);
  1769. if (slaveIPAddress.length() < 1)
  1770. throw makeStringException(ECLWATCH_INVALID_INPUT, "ThorSlave log network address not found.");
  1771. readWorkunitThorLog(processName, logDir, slaveIPAddress, slaveNum, buf, outFile);
  1772. }
  1773. else
  1774. {//legacy wuid: a user types in an IP address for a thor slave
  1775. if (isEmpty(logDate))
  1776. throw makeStringException(ECLWATCH_INVALID_INPUT,"ThorSlave log date not specified.");
  1777. if (isEmpty(ipAddress))
  1778. throw MakeStringException(ECLWATCH_INVALID_INPUT,"ThorSlave address not specified.");
  1779. StringBuffer logName(logDir);
  1780. addPathSepChar(logName);
  1781. //thorslave.10.239.219.6_20100.2012_05_23.log
  1782. logName.appendf("thorslave.%s*.%s.log", ipAddress, logDate);
  1783. const char* portPtr = strchr(ipAddress, '_');
  1784. if (!portPtr)
  1785. slaveIPAddress.append(ipAddress);
  1786. else
  1787. {
  1788. StringBuffer ipAddressStr(ipAddress);
  1789. ipAddressStr.setLength(portPtr - ipAddress);
  1790. slaveIPAddress.append(ipAddressStr.str());
  1791. }
  1792. readFileContent(logName, slaveIPAddress.str(), logName, buf, forDownload);
  1793. }
  1794. }
  1795. void WsWuInfo::getWorkunitThorSlaveLog(IPropertyTree* directories, const char *process,
  1796. const char* instanceName, const char *ipAddress, const char* logDate, int slaveNum,
  1797. MemoryBuffer& buf, const char* outFile, bool forDownload)
  1798. {
  1799. StringBuffer logDir, groupName;
  1800. getConfigurationDirectory(directories, "log", "thor", process, logDir);
  1801. getClusterThorGroupName(groupName, instanceName);
  1802. if (groupName.isEmpty())
  1803. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Failed to get Thor Group Name for %s", instanceName);
  1804. Owned<IGroup> nodeGroup = queryNamedGroupStore().lookup(groupName);
  1805. if (!nodeGroup || (nodeGroup->ordinality() == 0))
  1806. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Node group %s not found", groupName.str());
  1807. getWorkunitThorSlaveLog(nodeGroup, ipAddress, process, logDate, logDir.str(), slaveNum, buf, outFile, forDownload);
  1808. }
  1809. void WsWuInfo::readWorkunitThorLog(const char* processName, const char* log, const char* slaveIPAddress, unsigned slaveNum, MemoryBuffer& buf, const char* outFile)
  1810. {
  1811. Owned<IFileIOStream> outIOS;
  1812. if (!isEmptyString(outFile))
  1813. {
  1814. CWsWuFileHelper helper(nullptr);
  1815. outIOS.setown(helper.createIOStreamWithFileName(outFile, IFOcreate));
  1816. }
  1817. StringArray logSpecs;
  1818. if (slaveIPAddress) //thor slave
  1819. getWUProcessLogSpecs(processName, nullptr, log, false, logSpecs); //log: logDir
  1820. else
  1821. getWUProcessLogSpecs(processName, log, nullptr, false, logSpecs); //log: logSpec
  1822. unsigned processID = 0; //The processID is unknown at the begining of the first day.
  1823. ForEachItemIn(i, logSpecs)
  1824. {
  1825. const char* logSpec = logSpecs.item(i);
  1826. Owned<IFile> rFile;
  1827. if (slaveIPAddress)
  1828. {
  1829. StringBuffer thorMasterLog, ext;
  1830. splitFilename(logSpec, nullptr, nullptr, &thorMasterLog, &ext);
  1831. StringBuffer logSpecStr(log);
  1832. addPathSepChar(logSpecStr);
  1833. //Append the file name of the slave log to logSpecStr.
  1834. //The pattern of the file name is: thorslave.SLAVENUM.LOGDATE.log.
  1835. //ex. thorslave.2.2020_09_16.log
  1836. //The LOGDATE is parsed from the thorMasterLog (ex. thormaster.2020_09_16).
  1837. logSpecStr.appendf("thorslave.%u%s%s", slaveNum, thorMasterLog.str() + strlen("thormaster"), ext.str());
  1838. RemoteFilename rfn;
  1839. rfn.setRemotePath(logSpecStr);
  1840. SocketEndpoint ep(slaveIPAddress);
  1841. rfn.setIp(ep);
  1842. rFile.setown(createIFile(rfn));
  1843. if (!rFile)
  1844. throw MakeStringException(ECLWATCH_CANNOT_OPEN_FILE, "Cannot open file %s on %s.", logSpecStr.str(), slaveIPAddress);
  1845. }
  1846. else
  1847. {
  1848. rFile.setown(createIFile(logSpec));
  1849. if (!rFile)
  1850. throw MakeStringException(ECLWATCH_CANNOT_OPEN_FILE, "Cannot open file %s.", logSpec);
  1851. }
  1852. readWorkunitThorLogOneDay(rFile, processID, buf, outIOS);
  1853. }
  1854. }
  1855. void WsWuInfo::readWorkunitThorLogOneDay(IFile* sourceFile, unsigned& processID, MemoryBuffer& buf, IFileIOStream* outIOS)
  1856. {
  1857. OwnedIFileIO sourceIO = sourceFile->openShared(IFOread,IFSHfull);
  1858. if (!sourceIO)
  1859. throw MakeStringException(ECLWATCH_CANNOT_READ_FILE,"Cannot read file %s.", sourceFile->queryFilename());
  1860. Owned<IFileIOStream> ios = createIOStream(sourceIO);
  1861. VStringBuffer startwuid("Started wuid=%s", wuid.str());
  1862. VStringBuffer endwuid("Finished wuid=%s", wuid.str());
  1863. StringBuffer line;
  1864. Owned<IStreamLineReader> lineReader = createLineReader(ios, true);
  1865. bool eof = lineReader->readLine(line.clear());
  1866. if (eof)
  1867. return;
  1868. // Process header for log file format
  1869. unsigned logfields = getMessageFieldsFromHeader(line);
  1870. if (logfields==0) // No header line, so must be in legacy format
  1871. logfields = MSGFIELD_LEGACY;
  1872. else
  1873. eof = lineReader->readLine(line.clear());
  1874. const unsigned columnNumPID = getPositionOfField(logfields, MSGFIELD_process);
  1875. bool outputThisLine = false;
  1876. if (processID > 0) //after the 1st page of the log
  1877. outputThisLine = true;
  1878. bool foundEndWUID = false;
  1879. while (!eof)
  1880. {
  1881. if (outputThisLine)
  1882. {
  1883. //If the slave is restarted before WU is finished, we cannot find out the "Finished wuid=...".
  1884. //So, we should check whether the slave is restarting or not.
  1885. unsigned pID = 0;
  1886. foundEndWUID = parseLogLine(line.str(), endwuid, pID, columnNumPID);
  1887. if ((pID > 0) && (pID != processID))
  1888. break;
  1889. outputALine(line.length(), line.str(), buf, outIOS);
  1890. if (foundEndWUID)
  1891. outputThisLine = false;
  1892. }
  1893. else if (strstr(line.str(), startwuid))
  1894. {
  1895. outputThisLine = true;
  1896. foundEndWUID = false;
  1897. outputALine(line.length(), line.str(), buf, outIOS);
  1898. if (processID == 0)
  1899. parseLogLine(line.str(), nullptr, processID, columnNumPID);
  1900. }
  1901. eof = lineReader->readLine(line.clear());
  1902. }
  1903. }
  1904. bool WsWuInfo::parseLogLine(const char* line, const char* endWUID, unsigned& processID, const unsigned columnNumPID)
  1905. {
  1906. const char* bptr = line;
  1907. for (unsigned cur=0; cur < columnNumPID && *bptr; ++cur)
  1908. {
  1909. while(*bptr && *bptr!=' ') ++bptr; // Skip field
  1910. while(*bptr && *bptr==' ') ++bptr; // Skip spaces
  1911. }
  1912. if (!*bptr) return false;
  1913. const char* eptr = bptr + 1;
  1914. while (*eptr && isdigit(*eptr)) //Read ProcessID
  1915. eptr++;
  1916. if (*eptr != ' ')
  1917. return false;
  1918. processID = (unsigned) atoi_l(bptr, eptr - bptr);
  1919. return (endWUID && strstr(eptr+1, endWUID));
  1920. }
  1921. void WsWuInfo::getWUProcessLogSpecs(const char* processName, const char* logSpec, const char* logDir, bool eclAgent, StringArray& logSpecs)
  1922. {
  1923. Owned<IStringIterator> logs;
  1924. if (eclAgent)
  1925. logs.setown(cw->getLogs("EclAgent"));
  1926. else
  1927. { //Thor
  1928. if (!isEmptyString(processName))
  1929. logs.setown(cw->getLogs("Thor", processName));
  1930. else
  1931. {
  1932. //Parse the process name from the logSpec or logDir.
  1933. if (isEmptyString(logSpec) && isEmptyString(logDir))
  1934. throw makeStringException(ECLWATCH_ECLAGENT_LOG_NOT_FOUND, "Process name and log file not specified");
  1935. StringBuffer path, process;
  1936. if (!isEmptyString(logDir))
  1937. path.set(logDir);
  1938. else
  1939. {
  1940. //Parse the path from the logSpec (ex.: //10.173.123.208/mnt/disk1/var/log/HPCCSystems/mythor/thormaster.2020_01_16.log)
  1941. splitFilename(logSpec, nullptr, &path, nullptr, nullptr);
  1942. }
  1943. //Parse the process name (ex. mythor) from the path (ex.: //10.173.123.208/mnt/disk1/var/log/HPCCSystems/mythor/)
  1944. removeTrailingPathSepChar(path);
  1945. splitFilename(path, nullptr, nullptr, &process, nullptr);
  1946. logs.setown(cw->getLogs("Thor", process));
  1947. }
  1948. }
  1949. ForEach (*logs)
  1950. {
  1951. SCMStringBuffer logStr;
  1952. logs->str(logStr);
  1953. if (logStr.length() < 1)
  1954. continue;
  1955. logSpecs.append(logStr.str());
  1956. }
  1957. if (logSpecs.length() > 1)
  1958. logSpecs.sortAscii(false); //Sort the logSpecs from old to new
  1959. }
  1960. #endif
  1961. bool WsWuInfo::validateWUProcessLog(const char* file, bool eclAgent)
  1962. {
  1963. Owned<IStringIterator> logs = cw->getLogs(eclAgent ? "EclAgent" : "Thor");
  1964. ForEach (*logs)
  1965. {
  1966. SCMStringBuffer logName;
  1967. logs->str(logName);
  1968. if (logName.length() < 1)
  1969. continue;
  1970. if (strieq(file, logName.str()))
  1971. return true;
  1972. }
  1973. return false;
  1974. }
  1975. bool WsWuInfo::validateWUAssociatedFile(const char* file, WUFileType type)
  1976. {
  1977. Owned<IConstWUQuery> query = cw->getQuery();
  1978. if (!query)
  1979. return false;
  1980. Owned<IConstWUAssociatedFileIterator> iter = &query->getAssociatedFiles();
  1981. ForEach(*iter)
  1982. {
  1983. IConstWUAssociatedFile & cur = iter->query();
  1984. if (cur.getType() != type)
  1985. continue;
  1986. SCMStringBuffer name;
  1987. cur.getName(name);
  1988. if (name.length() < 1)
  1989. continue;
  1990. if (strieq(file, name.str()))
  1991. return true;
  1992. }
  1993. return false;
  1994. }
  1995. void WsWuInfo::getWorkunitResTxt(MemoryBuffer& buf)
  1996. {
  1997. Owned<IConstWUQuery> query = cw->getQuery();
  1998. if(!query)
  1999. throw MakeStringException(ECLWATCH_QUERY_NOT_FOUND_FOR_WU,"No query for workunit %s.",wuid.str());
  2000. SCMStringBuffer resname;
  2001. queryDllServer().getDll(query->getQueryResTxtName(resname).str(), buf);
  2002. }
  2003. void WsWuInfo::getWorkunitArchiveQuery(StringBuffer& str)
  2004. {
  2005. Owned<IConstWUQuery> query = cw->getQuery();
  2006. if(!query)
  2007. throw MakeStringException(ECLWATCH_QUERY_NOT_FOUND_FOR_WU,"No query for workunit %s.",wuid.str());
  2008. StringBufferAdaptor istr(str);
  2009. query->getQueryText(istr);
  2010. if ((str.length() < 1) || !isArchiveQuery(str.str()))
  2011. {
  2012. if (!query->hasArchive())
  2013. throw MakeStringException(ECLWATCH_CANNOT_GET_WORKUNIT, "Archive query not found for workunit %s.", wuid.str());
  2014. Owned<IWuWebView> wv = createWuWebView(*cw, NULL, NULL, NULL, false, nullptr);
  2015. if (!wv)
  2016. throw MakeStringException(ECLWATCH_CANNOT_GET_WORKUNIT, "Cannot create webview for workunit %s.", wuid.str());
  2017. if (!wv->getEmbeddedArchive(str) || (str.length() < 1) || !isArchiveQuery(str.str()))
  2018. throw MakeStringException(ECLWATCH_CANNOT_GET_WORKUNIT, "Archive query not found for workunit %s.", wuid.str());
  2019. }
  2020. }
  2021. void WsWuInfo::getWorkunitArchiveQuery(MemoryBuffer& buf)
  2022. {
  2023. StringBuffer queryText;
  2024. getWorkunitArchiveQuery(queryText);
  2025. buf.append(queryText.length(), queryText.str());
  2026. }
  2027. void WsWuInfo::getWorkunitQueryShortText(MemoryBuffer& buf, const char* outFile)
  2028. {
  2029. Owned<IConstWUQuery> query = cw->getQuery();
  2030. if(!query)
  2031. throw MakeStringException(ECLWATCH_QUERY_NOT_FOUND_FOR_WU,"No query for workunit %s.",wuid.str());
  2032. SCMStringBuffer queryText;
  2033. query->getQueryShortText(queryText);
  2034. if (queryText.length() < 1)
  2035. throw MakeStringException(ECLWATCH_QUERY_NOT_FOUND_FOR_WU, "No query for workunit %s.",wuid.str());
  2036. if (isEmptyString(outFile))
  2037. buf.append(queryText.length(), queryText.str());
  2038. else
  2039. {
  2040. CWsWuFileHelper helper(nullptr);
  2041. Owned<IFileIOStream> outIOS = helper.createIOStreamWithFileName(outFile, IFOcreate);
  2042. outIOS->write(queryText.length(), queryText.str());
  2043. }
  2044. }
  2045. void WsWuInfo::getWorkunitDll(StringBuffer &dllname, MemoryBuffer& buf)
  2046. {
  2047. Owned<IConstWUQuery> query = cw->getQuery();
  2048. if(!query)
  2049. throw MakeStringException(ECLWATCH_QUERY_NOT_FOUND_FOR_WU,"No query for workunit %s.",wuid.str());
  2050. StringBufferAdaptor isvName(dllname);
  2051. query->getQueryDllName(isvName);
  2052. queryDllServer().getDll(dllname.str(), buf);
  2053. }
  2054. void WsWuInfo::getWorkunitXml(const char* plainText, MemoryBuffer& buf)
  2055. {
  2056. const char* header;
  2057. if (plainText && (!stricmp(plainText, "yes")))
  2058. header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
  2059. else
  2060. header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><?xml-stylesheet href=\"../esp/xslt/xmlformatter.xsl\" type=\"text/xsl\"?>";
  2061. StringBuffer xml;
  2062. exportWorkUnitToXML(cw, xml, true, false, true);
  2063. buf.append(strlen(header), header);
  2064. buf.append(xml.length(), xml.str());
  2065. }
  2066. void WsWuInfo::getWorkunitCpp(const char* cppname, const char* description, const char* ipAddress, MemoryBuffer& buf, bool forDownload, const char* outFile)
  2067. {
  2068. if (isEmpty(description))
  2069. throw MakeStringException(ECLWATCH_INVALID_INPUT, "File not specified.");
  2070. if (isEmpty(ipAddress))
  2071. throw MakeStringException(ECLWATCH_INVALID_INPUT, "File location not specified.");
  2072. if (isEmpty(cppname))
  2073. throw MakeStringException(ECLWATCH_INVALID_FILE_NAME, "File path not specified.");
  2074. if (isEmpty(outFile))
  2075. readFileContent(cppname, ipAddress, description, buf, forDownload);
  2076. else
  2077. copyContentFromRemoteFile(cppname, ipAddress, description, outFile);
  2078. }
  2079. void WsWuInfo::getWorkunitAssociatedXml(const char* name, const char* ipAddress, const char* plainText,
  2080. const char* description, bool forDownload, bool addXMLDeclaration, MemoryBuffer& buf, const char* outFile)
  2081. {
  2082. if (isEmpty(description)) //'File Name' as shown in WU Details page
  2083. throw MakeStringException(ECLWATCH_INVALID_INPUT, "File not specified.");
  2084. if (isEmpty(ipAddress))
  2085. throw MakeStringException(ECLWATCH_INVALID_INPUT, "File location not specified.");
  2086. if (isEmpty(name)) //file name with full path
  2087. throw MakeStringException(ECLWATCH_INVALID_FILE_NAME, "File path not specified.");
  2088. if (addXMLDeclaration)
  2089. {
  2090. const char* header;
  2091. if (plainText && (!stricmp(plainText, "yes")))
  2092. header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
  2093. else
  2094. header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><?xml-stylesheet href=\"../esp/xslt/xmlformatter.xsl\" type=\"text/xsl\"?>";
  2095. buf.append(strlen(header), header);
  2096. }
  2097. if (isEmpty(outFile))
  2098. readFileContent(name, ipAddress, description, buf, forDownload);
  2099. else
  2100. copyContentFromRemoteFile(name, ipAddress, description, outFile);
  2101. }
  2102. IPropertyTree* WsWuInfo::getWorkunitArchive()
  2103. {
  2104. Owned <IConstWUQuery> query = cw->getQuery();
  2105. if(!query)
  2106. return NULL;
  2107. SCMStringBuffer name, ip;
  2108. Owned<IConstWUAssociatedFileIterator> iter = &query->getAssociatedFiles();
  2109. ForEach(*iter)
  2110. {
  2111. IConstWUAssociatedFile& cur = iter->query();
  2112. if (cur.getType() != FileTypeXml)
  2113. continue;
  2114. cur.getName(name);
  2115. if (name.length() < 15)
  2116. continue;
  2117. const char* pStr = name.str() + name.length() - 15;
  2118. if (strieq(pStr, ".archive.eclxml"))
  2119. {
  2120. cur.getIp(ip);
  2121. break;
  2122. }
  2123. }
  2124. if (!ip.length())
  2125. return NULL;
  2126. MemoryBuffer content;
  2127. getWorkunitAssociatedXml(name.str(), ip.str(), "", "WU archive eclxml", true, false, content, nullptr);
  2128. if (!content.length())
  2129. return NULL;
  2130. return createPTreeFromXMLString(content.length(), content.toByteArray());
  2131. }
  2132. IEspWUArchiveFile* WsWuInfo::readArchiveFileAttr(IPropertyTree& fileTree, const char* path)
  2133. {
  2134. const char* fileName = fileTree.queryProp("@name");
  2135. if (isEmpty(fileName))
  2136. return NULL;
  2137. Owned<IEspWUArchiveFile> file= createWUArchiveFile();
  2138. file->setName(fileName);
  2139. if (!isEmpty(path))
  2140. file->setPath(path);
  2141. if (fileTree.hasProp("@key"))
  2142. file->setKey(fileTree.queryProp("@key"));
  2143. if (fileTree.hasProp("@sourcePath"))
  2144. file->setSourcePath(fileTree.queryProp("@sourcePath"));
  2145. return file.getClear();
  2146. }
  2147. IEspWUArchiveModule* WsWuInfo::readArchiveModuleAttr(IPropertyTree& moduleTree, const char* path)
  2148. {
  2149. const char* moduleName = moduleTree.queryProp("@name");
  2150. if (isEmpty(moduleName))
  2151. return NULL;
  2152. Owned<IEspWUArchiveModule> module= createWUArchiveModule();
  2153. module->setName(moduleName);
  2154. if (!isEmpty(path))
  2155. module->setPath(path);
  2156. if (moduleTree.hasProp("@fullName"))
  2157. module->setFullName(moduleTree.queryProp("@fullName"));
  2158. if (moduleTree.hasProp("@key"))
  2159. module->setKey(moduleTree.queryProp("@key"));
  2160. if (moduleTree.hasProp("@plugin"))
  2161. module->setPlugin(moduleTree.queryProp("@plugin"));
  2162. if (moduleTree.hasProp("@version"))
  2163. module->setVersion(moduleTree.queryProp("@version"));
  2164. if (moduleTree.hasProp("@sourcePath"))
  2165. module->setSourcePath(moduleTree.queryProp("@sourcePath"));
  2166. if (moduleTree.hasProp("@flags"))
  2167. module->setFlags(moduleTree.getPropInt("@flags", 0));
  2168. return module.getClear();
  2169. }
  2170. void WsWuInfo::readArchiveFiles(IPropertyTree* archiveTree, const char* path, IArrayOf<IEspWUArchiveFile>& files)
  2171. {
  2172. Owned<IPropertyTreeIterator> iter = archiveTree->getElements("Attribute");
  2173. ForEach(*iter)
  2174. {
  2175. IPropertyTree& item = iter->query();
  2176. Owned<IEspWUArchiveFile> file = readArchiveFileAttr(item, path);
  2177. if (file)
  2178. files.append(*file.getClear());
  2179. }
  2180. }
  2181. void WsWuInfo::listArchiveFiles(IPropertyTree* archiveTree, const char* path, IArrayOf<IEspWUArchiveModule>& modules, IArrayOf<IEspWUArchiveFile>& files)
  2182. {
  2183. if (!archiveTree)
  2184. return;
  2185. Owned<IPropertyTreeIterator> iter = archiveTree->getElements("Module");
  2186. ForEach(*iter)
  2187. {
  2188. IPropertyTree& item = iter->query();
  2189. Owned<IEspWUArchiveModule> module = readArchiveModuleAttr(item, path);
  2190. if (!module)
  2191. continue;
  2192. StringBuffer newPath;
  2193. if (isEmpty(path))
  2194. newPath.set(module->getName());
  2195. else
  2196. newPath.setf("%s/%s", path, module->getName());
  2197. IArrayOf<IEspWUArchiveModule> modulesInModule;
  2198. IArrayOf<IEspWUArchiveFile> filesInModule;
  2199. listArchiveFiles(&item, newPath.str(), modulesInModule, filesInModule);
  2200. if (modulesInModule.length())
  2201. module->setArchiveModules(modulesInModule);
  2202. if (filesInModule.length())
  2203. module->setFiles(filesInModule);
  2204. modules.append(*module.getClear());
  2205. }
  2206. readArchiveFiles(archiveTree, path, files);
  2207. }
  2208. void WsWuInfo::getArchiveFile(IPropertyTree* archive, const char* moduleName, const char* attrName, const char* path, StringBuffer& file)
  2209. {
  2210. StringBuffer xPath;
  2211. if (!isEmpty(path))
  2212. {
  2213. StringArray list;
  2214. list.appendListUniq(path, "/");
  2215. ForEachItemIn(m, list)
  2216. {
  2217. const char* module = list.item(m);
  2218. if (!isEmpty(module))
  2219. xPath.appendf("Module[@name=\"%s\"]/", module);
  2220. }
  2221. }
  2222. if (isEmpty(moduleName))
  2223. xPath.appendf("Attribute[@name=\"%s\"]", attrName);
  2224. else
  2225. xPath.appendf("Module[@name=\"%s\"]/Text", moduleName);
  2226. file.set(archive->queryProp(xPath.str()));
  2227. }
  2228. #ifndef _CONTAINERIZED
  2229. void WsWuInfo::outputALine(size32_t length, const char* content, MemoryBuffer& outputBuf, IFileIOStream* outIOS)
  2230. {
  2231. if (outIOS)
  2232. outIOS->write(length, content);
  2233. else
  2234. outputBuf.append(length, content);
  2235. }
  2236. #endif
  2237. WsWuSearch::WsWuSearch(IEspContext& context,const char* owner,const char* state,const char* cluster,const char* startDate,const char* endDate,const char* jobname)
  2238. {
  2239. SecAccessFlags accessOwn;
  2240. SecAccessFlags accessOthers;
  2241. getUserWuAccessFlags(context, accessOwn, accessOthers, true);
  2242. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  2243. Owned<IConstWorkUnitIterator> it(factory->getWorkUnitsByOwner(owner)); // null owner means fetch all
  2244. StringBuffer wuFrom, wuTo, jobPattern;
  2245. if (startDate && *startDate)
  2246. createWuidFromDate(startDate, wuFrom);
  2247. if (endDate && *endDate)
  2248. createWuidFromDate(endDate, wuTo);
  2249. if (jobname && *jobname)
  2250. jobPattern.appendf("*%s*", jobname);
  2251. ForEach(*it)
  2252. {
  2253. IConstWorkUnitInfo &cw = it->query();
  2254. if (chooseWuAccessFlagsByOwnership(context.queryUserId(), cw, accessOwn, accessOthers) < SecAccess_Read)
  2255. continue;
  2256. if (state && *state && !strieq(cw.queryStateDesc(), state))
  2257. continue;
  2258. if (cluster && *cluster && !strieq(cw.queryClusterName(), cluster))
  2259. continue;
  2260. if (jobPattern.length() && !WildMatch(cw.queryJobName(), jobPattern, true))
  2261. continue;
  2262. const char *wuid = cw.queryWuid();
  2263. if (wuFrom.length() && strcmp(wuid,wuFrom.str())<0)
  2264. continue;
  2265. if (wuTo.length() && strcmp(wuid, wuTo.str())>0)
  2266. continue;
  2267. wuids.push_back(wuid);
  2268. }
  2269. std::sort(wuids.begin(), wuids.end(),std::greater<std::string>());
  2270. }
  2271. StringBuffer& WsWuSearch::createWuidFromDate(const char* timestamp,StringBuffer& s)
  2272. {
  2273. CDateTime wuTime;
  2274. wuTime.setString(timestamp,NULL,true);
  2275. unsigned year, month, day, hour, minute, second, nano;
  2276. wuTime.getDate(year, month, day, true);
  2277. wuTime.getTime(hour, minute, second, nano, true);
  2278. s.appendf("W%4d%02d%02d-%02d%02d%02d",year,month,day,hour,minute,second);
  2279. return s;
  2280. }
  2281. struct CompareData
  2282. {
  2283. CompareData(const char* _filter): filter(_filter) {}
  2284. bool operator()(const Linked<DataCacheElement>& e) const
  2285. {
  2286. return stricmp(e->m_filter.c_str(),filter)==0;
  2287. }
  2288. const char* filter;
  2289. };
  2290. DataCacheElement* DataCache::lookup(IEspContext &context, const char* filter, unsigned timeOutMin)
  2291. {
  2292. CriticalBlock block(crit);
  2293. if (cache.size() < 1)
  2294. return NULL;
  2295. //erase data if it should be
  2296. CDateTime timeNow;
  2297. int timeout = timeOutMin;
  2298. timeNow.setNow();
  2299. timeNow.adjustTime(-timeout);
  2300. while (true)
  2301. {
  2302. std::list<Linked<DataCacheElement> >::iterator list_iter = cache.begin();
  2303. if (list_iter == cache.end())
  2304. break;
  2305. DataCacheElement* awu = list_iter->get();
  2306. if (!awu || (awu->m_timeCached > timeNow))
  2307. break;
  2308. cache.pop_front();
  2309. }
  2310. if (cache.size() < 1)
  2311. return NULL;
  2312. //Check whether we have the data cache for this cluster. If yes, get the version
  2313. std::list<Linked<DataCacheElement> >::iterator it = std::find_if(cache.begin(),cache.end(),CompareData(filter));
  2314. if(it!=cache.end())
  2315. {
  2316. return it->getLink();
  2317. }
  2318. return NULL;
  2319. }
  2320. void DataCache::add(const char* filter, const char* data, const char* name, const char* localName, const char* wuid,
  2321. const char* resultName, unsigned seq, __int64 start, unsigned count, __int64 requested, __int64 total)
  2322. {
  2323. CriticalBlock block(crit);
  2324. //Save new data
  2325. Owned<DataCacheElement> e=new DataCacheElement(filter, data, name, localName, wuid, resultName, seq, start, count, requested, total);
  2326. if (cacheSize > 0)
  2327. {
  2328. if (cache.size() >= cacheSize)
  2329. cache.pop_front();
  2330. cache.push_back(e.get());
  2331. }
  2332. return;
  2333. }
  2334. struct CompareArchivedWUs
  2335. {
  2336. CompareArchivedWUs(const char* _filter): filter(_filter) {}
  2337. bool operator()(const Linked<ArchivedWuCacheElement>& e) const
  2338. {
  2339. return stricmp(e->m_filter.c_str(),filter)==0;
  2340. }
  2341. const char* filter;
  2342. };
  2343. ArchivedWuCacheElement* ArchivedWuCache::lookup(IEspContext &context, const char* filter, const char* sashaUpdatedWhen, unsigned timeOutMin)
  2344. {
  2345. CriticalBlock block(crit);
  2346. if (cache.size() < 1)
  2347. return NULL;
  2348. //erase data if it should be
  2349. CDateTime timeNow;
  2350. int timeout = timeOutMin;
  2351. timeNow.setNow();
  2352. timeNow.adjustTime(-timeout);
  2353. while (true)
  2354. {
  2355. std::list<Linked<ArchivedWuCacheElement> >::iterator list_iter = cache.begin();
  2356. if (list_iter == cache.end())
  2357. break;
  2358. ArchivedWuCacheElement* awu = list_iter->get();
  2359. if (awu && !stricmp(sashaUpdatedWhen, awu->m_sashaUpdatedWhen.c_str()) && (awu->m_timeCached > timeNow))
  2360. break;
  2361. cache.pop_front();
  2362. }
  2363. if (cache.size() < 1)
  2364. return NULL;
  2365. //Check whether we have the data cache for this cluster. If yes, get the version
  2366. std::list<Linked<ArchivedWuCacheElement> >::iterator it = std::find_if(cache.begin(),cache.end(),CompareArchivedWUs(filter));
  2367. if(it!=cache.end())
  2368. return it->getLink();
  2369. return NULL;
  2370. }
  2371. void ArchivedWuCache::add(const char* filter, const char* sashaUpdatedWhen, bool hasNextPage, unsigned numWUsReturned, IArrayOf<IEspECLWorkunit>& wus, IArrayOf<IEspECLWorkunitLW>& lwwus)
  2372. {
  2373. CriticalBlock block(crit);
  2374. //Save new data
  2375. Owned<ArchivedWuCacheElement> e=new ArchivedWuCacheElement(filter, sashaUpdatedWhen, hasNextPage, numWUsReturned, wus, lwwus);
  2376. if (cacheSize > 0)
  2377. {
  2378. if (cache.size() >= cacheSize)
  2379. cache.pop_front();
  2380. cache.push_back(e.get());
  2381. }
  2382. return;
  2383. }
  2384. WsWuJobQueueAuditInfo::WsWuJobQueueAuditInfo(IEspContext &context, const char *cluster, const char *from , const char *to, CHttpResponse* response, const char *xls)
  2385. {
  2386. if(!response)
  2387. return;
  2388. unsigned maxDisplay = 125;
  2389. IArrayOf<IEspThorQueue> items;
  2390. CDateTime fromTime;
  2391. CDateTime toTime;
  2392. StringBuffer fromstr;
  2393. StringBuffer tostr;
  2394. if(from && *from)
  2395. {
  2396. fromTime.setString(from,NULL,false);
  2397. fromTime.getString(fromstr, false);
  2398. }
  2399. if(to && *to)
  2400. {
  2401. toTime.setString(to,NULL,false);
  2402. toTime.getString(tostr, false);
  2403. }
  2404. StringBuffer filter("ThorQueueMonitor");
  2405. if(notEmpty(cluster))
  2406. filter.appendf(",%s", cluster);
  2407. StringAttrArray lines;
  2408. queryAuditLogs(fromTime, toTime, filter.str(), lines);
  2409. unsigned countLines = 0;
  2410. unsigned maxConnected = 0;
  2411. unsigned longestQueue = 0;
  2412. ForEachItemIn(idx, lines)
  2413. {
  2414. const char* line = lines.item(idx).text;
  2415. if(!line || !*line)
  2416. continue;
  2417. if (idx < (lines.length() - 1))
  2418. getAuditLineInfo(line, longestQueue, maxConnected, maxDisplay, 1, items);
  2419. else
  2420. getAuditLineInfo(line, longestQueue, maxConnected, maxDisplay, 2, items);
  2421. countLines++;
  2422. }
  2423. StringBuffer responsebuf;
  2424. if (items.length() < 1)
  2425. {
  2426. responsebuf.append("<script language=\"javascript\">\r\nparent.displayQEnd(\'No data found\')</script>\r\n");
  2427. response->sendChunk(responsebuf.str());
  2428. return;
  2429. }
  2430. unsigned itemCount = items.length();
  2431. if (itemCount > maxDisplay)
  2432. itemCount = maxDisplay;
  2433. responsebuf.append("<script language=\"javascript\">parent.displayQLegend()</script>\r\n");
  2434. response->sendChunk(responsebuf.str());
  2435. responsebuf.clear();
  2436. responsebuf.append("<script language=\"javascript\">parent.displayQBegin(").append(longestQueue).append(",").append(maxConnected).append(",").append(itemCount).append(")</script>\r\n");
  2437. response->sendChunk(responsebuf.str());
  2438. responsebuf.clear();
  2439. responsebuf.append("<script language=\"javascript\">\r\n");
  2440. //bool displayDT = false;
  2441. unsigned count = 0;
  2442. unsigned jobpending=0;
  2443. ForEachItemIn(i,items)
  2444. {
  2445. IEspThorQueue& tq = items.item(i);
  2446. //displayDT = !displayDT;
  2447. count++;
  2448. if (count > maxDisplay)
  2449. break;
  2450. StringBuffer countStr, dtStr;
  2451. countStr.appendulong(count);
  2452. //if (displayDT)
  2453. dtStr = tq.getDT();
  2454. responsebuf.append("parent.displayQueue(\'").append(count).append("\',\'").append(dtStr.str()).append("\',\'").append(tq.getRunningWUs()).append("\',");
  2455. responsebuf.append("\'").append(tq.getQueuedWUs()).append("\',\'").append(tq.getWaitingThors()).append("\',");
  2456. responsebuf.append("\'").append(tq.getConnectedThors()).append("\',\'").append(tq.getIdledThors()).append("\',");
  2457. responsebuf.append("\'").append(tq.getRunningWU1()).append("\',\'").append(tq.getRunningWU2()).append("\')\r\n");
  2458. if(++jobpending>=50)
  2459. {
  2460. responsebuf.append("</script>\r\n");
  2461. response->sendChunk(responsebuf.str());
  2462. responsebuf.clear();
  2463. responsebuf.append("<script language=\"javascript\">\r\n");
  2464. jobpending=0;
  2465. }
  2466. }
  2467. StringBuffer countStr;
  2468. countStr.appendulong(count);
  2469. StringBuffer msg("<table><tr><td>");
  2470. msg.append("Total Records in the Time Period: ").append(items.length()).append(" (<a href=\"/WsWorkunits/WUClusterJobQueueLOG?").append(xls).append("\">txt</a>...<a href=\"/WsWorkunits/WUClusterJobQueueXLS?").append(xls).append("\">xls</a>).");
  2471. msg.append("</td></tr><tr><td>");
  2472. if (count > maxDisplay)
  2473. msg.append("Displayed: First ").append(maxDisplay).append(". ");
  2474. msg.append("Max. Queue Length: ").append(longestQueue).append(".");
  2475. msg.append("</td></tr></table>");
  2476. responsebuf.append("parent.displayQEnd(\'").append(msg).append("\')</script>\r\n");
  2477. response->sendChunk(responsebuf.str());
  2478. }
  2479. void WsWuJobQueueAuditInfo::getAuditLineInfo(const char* line, unsigned& longestQueue, unsigned& maxConnected, unsigned maxDisplay, unsigned showAll, IArrayOf<IEspThorQueue>& items)
  2480. {
  2481. //2009-08-12 02:44:12 ,ThorQueueMonitor,thor400_88_dev,0,0,1,1,114,---,---
  2482. if(!line || !*line)
  2483. return;
  2484. Owned<IEspThorQueue> tq = createThorQueue();
  2485. StringBuffer dt, runningWUs, queuedWUs, waitingThors, connectedThors, idledThors, runningWU1, runningWU2;
  2486. // date/time
  2487. const char* bptr = line;
  2488. const char* eptr = strchr(bptr, ',');
  2489. if(eptr)
  2490. dt.append(eptr - bptr, bptr);
  2491. else
  2492. dt.append(bptr);
  2493. tq->setDT(dt.str());
  2494. if(!eptr)
  2495. {
  2496. if (checkNewThorQueueItem(tq, showAll, items))
  2497. items.append(*tq.getClear());
  2498. return;
  2499. }
  2500. //skip title
  2501. bptr = eptr + 1;
  2502. eptr = strchr(bptr, ',');
  2503. if(!eptr)
  2504. {
  2505. if (checkNewThorQueueItem(tq, showAll, items))
  2506. items.append(*tq.getClear());
  2507. return;
  2508. }
  2509. //skip queue name
  2510. bptr = eptr + 1;
  2511. eptr = strchr(bptr, ',');
  2512. if(!eptr)
  2513. {
  2514. if (checkNewThorQueueItem(tq, showAll, items))
  2515. items.append(*tq.getClear());
  2516. return;
  2517. }
  2518. //running
  2519. bptr = eptr + 1;
  2520. eptr = strchr(bptr, ',');
  2521. if(eptr)
  2522. runningWUs.append(eptr - bptr, bptr);
  2523. else
  2524. runningWUs.append(bptr);
  2525. tq->setRunningWUs(runningWUs.str());
  2526. if(!eptr)
  2527. {
  2528. if (checkNewThorQueueItem(tq, showAll, items))
  2529. items.append(*tq.getClear());
  2530. return;
  2531. }
  2532. //queued
  2533. bptr = eptr + 1;
  2534. eptr = strchr(bptr, ',');
  2535. if(eptr)
  2536. queuedWUs.append(eptr - bptr, bptr);
  2537. else
  2538. queuedWUs.append(bptr);
  2539. if (maxDisplay > items.length())
  2540. {
  2541. unsigned queueLen = atoi(queuedWUs.str());
  2542. if (queueLen > longestQueue)
  2543. longestQueue = queueLen;
  2544. }
  2545. tq->setQueuedWUs(queuedWUs.str());
  2546. if(!eptr)
  2547. {
  2548. if (checkNewThorQueueItem(tq, showAll, items))
  2549. items.append(*tq.getClear());
  2550. return;
  2551. }
  2552. //waiting
  2553. bptr = eptr + 1;
  2554. eptr = strchr(bptr, ',');
  2555. if(eptr)
  2556. waitingThors.append(eptr - bptr, bptr);
  2557. else
  2558. waitingThors.append(bptr);
  2559. tq->setWaitingThors(waitingThors.str());
  2560. if(!eptr)
  2561. {
  2562. if (checkNewThorQueueItem(tq, showAll, items))
  2563. items.append(*tq.getClear());
  2564. return;
  2565. }
  2566. //connected
  2567. bptr = eptr + 1;
  2568. eptr = strchr(bptr, ',');
  2569. if(eptr)
  2570. connectedThors.append(eptr - bptr, bptr);
  2571. else
  2572. connectedThors.append(bptr);
  2573. if (maxDisplay > items.length())
  2574. {
  2575. unsigned connnectedLen = atoi(connectedThors.str());
  2576. if (connnectedLen > maxConnected)
  2577. maxConnected = connnectedLen;
  2578. }
  2579. tq->setConnectedThors(connectedThors.str());
  2580. if(!eptr)
  2581. {
  2582. if (checkNewThorQueueItem(tq, showAll, items))
  2583. items.append(*tq.getClear());
  2584. return;
  2585. }
  2586. //idled
  2587. bptr = eptr + 1;
  2588. eptr = strchr(bptr, ',');
  2589. if(eptr)
  2590. idledThors.append(eptr - bptr, bptr);
  2591. else
  2592. idledThors.append(bptr);
  2593. tq->setIdledThors(idledThors.str());
  2594. if(!eptr)
  2595. {
  2596. items.append(*tq.getClear());
  2597. return;
  2598. }
  2599. //runningWU1
  2600. bptr = eptr + 1;
  2601. eptr = strchr(bptr, ',');
  2602. if(eptr)
  2603. runningWU1.append(eptr - bptr, bptr);
  2604. else
  2605. {
  2606. runningWU1.append(bptr);
  2607. }
  2608. if (!strcmp(runningWU1.str(), "---"))
  2609. runningWU1.clear();
  2610. if (runningWU1.length() > 0)
  2611. tq->setRunningWU1(runningWU1.str());
  2612. if(!eptr)
  2613. {
  2614. if (checkNewThorQueueItem(tq, showAll, items))
  2615. items.append(*tq.getClear());
  2616. return;
  2617. }
  2618. //runningWU2
  2619. bptr = eptr + 1;
  2620. eptr = strchr(bptr, ',');
  2621. if(eptr)
  2622. runningWU2.append(eptr - bptr, bptr);
  2623. else
  2624. {
  2625. runningWU2.append(bptr);
  2626. }
  2627. if (!strcmp(runningWU2.str(), "---"))
  2628. runningWU2.clear();
  2629. if (runningWU2.length() > 0)
  2630. tq->setRunningWU2(runningWU2.str());
  2631. if (checkNewThorQueueItem(tq, showAll, items))
  2632. items.append(*tq.getClear());
  2633. }
  2634. bool WsWuJobQueueAuditInfo::checkSameStrings(const char* s1, const char* s2)
  2635. {
  2636. if (s1)
  2637. {
  2638. if (!s2)
  2639. return false;
  2640. if (strcmp(s1, s2))
  2641. return false;
  2642. }
  2643. else if (s2)
  2644. {
  2645. if (!s1)
  2646. return false;
  2647. }
  2648. return true;
  2649. }
  2650. bool WsWuJobQueueAuditInfo::checkNewThorQueueItem(IEspThorQueue* tq, unsigned showAll, IArrayOf<IEspThorQueue>& items)
  2651. {
  2652. bool bAdd = false;
  2653. if (showAll < 1) //show every lines
  2654. bAdd = true;
  2655. else if (items.length() < 1)
  2656. bAdd = true;
  2657. else if (showAll > 1) //last line now
  2658. {
  2659. IEspThorQueue& tq0 = items.item(items.length()-1);
  2660. if (!checkSameStrings(tq->getDT(), tq0.getDT()))
  2661. bAdd = true;
  2662. }
  2663. else
  2664. {
  2665. IEspThorQueue& tq0 = items.item(items.length()-1);
  2666. if (!checkSameStrings(tq->getRunningWUs(), tq0.getRunningWUs()))
  2667. bAdd = true;
  2668. if (!checkSameStrings(tq->getQueuedWUs(), tq0.getQueuedWUs()))
  2669. bAdd = true;
  2670. if (!checkSameStrings(tq->getConnectedThors(), tq0.getConnectedThors()))
  2671. bAdd = true;
  2672. if (!checkSameStrings(tq->getWaitingThors(), tq0.getWaitingThors()))
  2673. bAdd = true;
  2674. if (!checkSameStrings(tq->getRunningWU1(), tq0.getRunningWU1()))
  2675. bAdd = true;
  2676. if (!checkSameStrings(tq->getRunningWU2(), tq0.getRunningWU2()))
  2677. bAdd = true;
  2678. }
  2679. return bAdd;
  2680. }
  2681. void xsltTransform(const char* xml, const char* sheet, IProperties *params, StringBuffer& ret)
  2682. {
  2683. StringBuffer xsl;
  2684. if(!checkFileExists(sheet))
  2685. throw MakeStringException(ECLWATCH_FILE_NOT_EXIST, "Could not find stylesheet %s.",sheet);
  2686. Owned<IXslProcessor> proc = getXslProcessor();
  2687. Owned<IXslTransform> trans = proc->createXslTransform();
  2688. trans->setXmlSource(xml, strlen(xml));
  2689. trans->loadXslFromFile(sheet);
  2690. trans->copyParameters(params);
  2691. trans->transform(ret);
  2692. }
  2693. bool addToQueryString(StringBuffer &queryString, const char *name, const char *value, const char delim)
  2694. {
  2695. if (isEmpty(name) || isEmpty(value))
  2696. return false;
  2697. if (queryString.length() > 0)
  2698. queryString.append(delim);
  2699. queryString.append(name).append("=").append(value);
  2700. return true;
  2701. }
  2702. int WUSchedule::run()
  2703. {
  2704. PROGLOG("ECLWorkunit WUSchedule Thread started.");
  2705. unsigned int waitTimeMillies = 1000*60;
  2706. while(!stopping)
  2707. {
  2708. if (!m_container)
  2709. {
  2710. DBGLOG("ECLWorkunit WUSchedule Thread is waiting for container to be set.");
  2711. }
  2712. else if (!detached)
  2713. {
  2714. try
  2715. {
  2716. if (waitTimeMillies == (unsigned)-1)
  2717. {
  2718. PROGLOG("ECLWorkunit WUSchedule Thread Re-started.");
  2719. waitTimeMillies = 1000*60;
  2720. }
  2721. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  2722. Owned<IConstWorkUnitIterator> itr = factory->getScheduledWorkUnits();
  2723. if (itr)
  2724. {
  2725. ForEach(*itr)
  2726. {
  2727. try
  2728. {
  2729. IConstWorkUnitInfo & cw = itr->query();
  2730. if (factory->isAborting(cw.queryWuid()))
  2731. {
  2732. WorkunitUpdate wu(factory->updateWorkUnit(cw.queryWuid()));
  2733. wu->setState(WUStateAborted);
  2734. continue;
  2735. }
  2736. WsWuDateTime dt, now;
  2737. now.setNow();
  2738. cw.getTimeScheduled(dt);
  2739. if (now.compare(dt)>=0)
  2740. {
  2741. runWorkUnit(cw.queryWuid(), cw.queryClusterName());
  2742. if (m_container->hasCacheClient())
  2743. {
  2744. StringArray errorMsgs;
  2745. m_container->clearCacheByGroupID("ESPWsWUs", errorMsgs);
  2746. if (errorMsgs.length() > 0)
  2747. {
  2748. ForEachItemIn(i, errorMsgs)
  2749. DBGLOG("%s", errorMsgs.item(i));
  2750. }
  2751. }
  2752. }
  2753. }
  2754. catch(IException *e)
  2755. {
  2756. StringBuffer msg;
  2757. IERRLOG("Exception %d:%s in WsWorkunits Schedule::run while processing WU", e->errorCode(), e->errorMessage(msg).str());
  2758. e->Release();
  2759. }
  2760. }
  2761. }
  2762. }
  2763. catch(IException *e)
  2764. {
  2765. StringBuffer msg;
  2766. IERRLOG("Exception %d:%s in WsWorkunits Schedule::run while fetching scheduled WUs from DALI", e->errorCode(), e->errorMessage(msg).str());
  2767. e->Release();
  2768. }
  2769. catch(...)
  2770. {
  2771. IERRLOG("Unknown exception in WsWorkunits Schedule::run while fetching scheduled WUs from DALI");
  2772. }
  2773. }
  2774. else
  2775. {
  2776. OWARNLOG("Detached from DALI, WSWorkunits schedule interrupted");
  2777. waitTimeMillies = (unsigned)-1;
  2778. }
  2779. semSchedule.wait(waitTimeMillies);
  2780. }
  2781. return 0;
  2782. }
  2783. void WsWuHelpers::setXmlParameters(IWorkUnit *wu, const char *xml, bool setJobname)
  2784. {
  2785. if (!xml || !*xml)
  2786. return;
  2787. Owned<IPropertyTree> tree = createPTreeFromXMLString(xml, ipt_none, (PTreeReaderOptions)(ptr_ignoreWhiteSpace | ptr_ignoreNameSpaces));
  2788. IPropertyTree *root = tree.get();
  2789. if (strieq(root->queryName(), "Envelope"))
  2790. root = root->queryPropTree("Body/*[1]");
  2791. if (!root)
  2792. return;
  2793. if (setJobname)
  2794. {
  2795. const char *name = wu->queryJobName();
  2796. if (!name || !*name)
  2797. wu->setJobName(root->queryName());
  2798. }
  2799. wu->setXmlParams(LINK(root));
  2800. }
  2801. void WsWuHelpers::setXmlParameters(IWorkUnit *wu, const char *xml, IArrayOf<IConstNamedValue> *variables, bool setJobname)
  2802. {
  2803. StringBuffer extParamXml;
  2804. if (variables && variables->length())
  2805. {
  2806. Owned<IPropertyTree> paramTree = (xml && *xml) ? createPTreeFromXMLString(xml) : createPTree("input");
  2807. ForEachItemIn(i, *variables)
  2808. {
  2809. IConstNamedValue &item = variables->item(i);
  2810. const char *name = item.getName();
  2811. const char *value = item.getValue();
  2812. if (!name || !*name)
  2813. continue;
  2814. if (!value)
  2815. {
  2816. size_t len = strlen(name);
  2817. char last = name[len-1];
  2818. if (last == '-' || last == '+')
  2819. {
  2820. StringAttr s(name, len-1);
  2821. paramTree->setPropInt(s.get(), last == '+' ? 1 : 0);
  2822. }
  2823. else
  2824. paramTree->setPropInt(name, 1);
  2825. continue;
  2826. }
  2827. paramTree->setProp(name, value);
  2828. }
  2829. toXML(paramTree, extParamXml);
  2830. xml=extParamXml.str();
  2831. }
  2832. setXmlParameters(wu, xml, setJobname);
  2833. }
  2834. void WsWuHelpers::submitWsWorkunit(IEspContext& context, IConstWorkUnit* cw, const char* cluster, const char* snapshot, int maxruntime, int maxcost, bool compile, bool resetWorkflow, bool resetVariables,
  2835. const char *paramXml, IArrayOf<IConstNamedValue> *variables, IArrayOf<IConstNamedValue> *debugs, IArrayOf<IConstApplicationValue> *applications)
  2836. {
  2837. ensureWsWorkunitAccess(context, *cw, SecAccess_Write);
  2838. #ifndef _NO_LDAP
  2839. CLdapSecManager* secmgr = dynamic_cast<CLdapSecManager*>(context.querySecManager());
  2840. // View Scope is checked only when LDAP secmgr is available AND checkViewPermissions config is also enabled.
  2841. // Otherwise, the view permission check is skipped, and WU is submitted as normal.
  2842. if (secmgr && secmgr->getCheckViewPermissions())
  2843. {
  2844. StringArray filenames, columnnames;
  2845. if (cw->getFieldUsageArray(filenames, columnnames, cluster)) // check view permission only for a query with fieldUsage information
  2846. {
  2847. if (!secmgr->authorizeViewScope(*context.queryUser(), filenames, columnnames))
  2848. throw MakeStringException(ECLWATCH_VIEW_ACCESS_DENIED, "View Access denied for a WU: %s", cw->queryWuid());
  2849. }
  2850. }
  2851. #endif
  2852. switch(cw->getState())
  2853. {
  2854. case WUStateRunning:
  2855. case WUStateDebugPaused:
  2856. case WUStateDebugRunning:
  2857. case WUStateCompiling:
  2858. case WUStateAborting:
  2859. case WUStateBlocked:
  2860. throw MakeStringException(ECLWATCH_CANNOT_SUBMIT_WORKUNIT, "Cannot submit the workunit. Workunit state is '%s'.", cw->queryStateDesc());
  2861. }
  2862. StringAttr wuid(cw->queryWuid());
  2863. WorkunitUpdate wu(&cw->lock());
  2864. if(!wu.get())
  2865. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT, "Cannot update workunit %s.", wuid.str());
  2866. wu->clearExceptions();
  2867. if(notEmpty(cluster))
  2868. wu->setClusterName(cluster);
  2869. if(notEmpty(snapshot))
  2870. wu->setSnapshot(snapshot);
  2871. wu->setState(WUStateSubmitted);
  2872. if (maxruntime)
  2873. wu->setDebugValueInt("maxRunTime",maxruntime,true);
  2874. if (maxcost)
  2875. wu->setDebugValueInt("maxCost", maxcost, true);
  2876. if (debugs && debugs->length())
  2877. {
  2878. ForEachItemIn(i, *debugs)
  2879. {
  2880. IConstNamedValue &item = debugs->item(i);
  2881. const char *name = item.getName();
  2882. const char *value = item.getValue();
  2883. if (!name || !*name)
  2884. continue;
  2885. StringBuffer expanded;
  2886. if (*name=='-')
  2887. name=expanded.append("eclcc").append(name).str();
  2888. if (!value)
  2889. {
  2890. size_t len = strlen(name);
  2891. char last = name[len-1];
  2892. if (last == '-' || last == '+')
  2893. {
  2894. StringAttr s(name, len-1);
  2895. wu->setDebugValueInt(s.get(), last == '+' ? 1 : 0, true);
  2896. }
  2897. else
  2898. wu->setDebugValueInt(name, 1, true);
  2899. continue;
  2900. }
  2901. wu->setDebugValue(name, value, true);
  2902. }
  2903. }
  2904. if (applications)
  2905. {
  2906. ForEachItemIn(ii, *applications)
  2907. {
  2908. IConstApplicationValue& item = applications->item(ii);
  2909. if(notEmpty(item.getApplication()) && notEmpty(item.getName()))
  2910. wu->setApplicationValue(item.getApplication(), item.getName(), item.getValue(), true);
  2911. }
  2912. }
  2913. if (resetWorkflow)
  2914. wu->resetWorkflow();
  2915. if (!compile)
  2916. wu->schedule();
  2917. if (resetVariables)
  2918. {
  2919. SCMStringBuffer varname;
  2920. Owned<IConstWUResultIterator> vars = &wu->getVariables();
  2921. ForEach (*vars)
  2922. {
  2923. vars->query().getResultName(varname);
  2924. Owned<IWUResult> v = wu->updateVariableByName(varname.str());
  2925. if (v)
  2926. v->setResultStatus(ResultStatusUndefined);
  2927. }
  2928. }
  2929. setXmlParameters(wu, paramXml, variables, (wu->getAction()==WUActionExecuteExisting));
  2930. wu->commit();
  2931. wu.clear();
  2932. if (!compile)
  2933. runWorkUnit(wuid.str());
  2934. else if (context.querySecManager())
  2935. secSubmitWorkUnit(wuid.str(), *context.querySecManager(), *context.queryUser());
  2936. else
  2937. submitWorkUnit(wuid.str(), context.queryUserId(), context.queryPassword());
  2938. AuditSystemAccess(context.queryUserId(), true, "Submitted %s", wuid.str());
  2939. }
  2940. void WsWuHelpers::submitWsWorkunit(IEspContext& context, const char *wuid, const char* cluster, const char* snapshot, int maxruntime, int maxcost, bool compile, bool resetWorkflow, bool resetVariables,
  2941. const char *paramXml, IArrayOf<IConstNamedValue> *variables, IArrayOf<IConstNamedValue> *debugs, IArrayOf<IConstApplicationValue> *applications)
  2942. {
  2943. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  2944. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid);
  2945. if(!cw)
  2946. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot open workunit %s.",wuid);
  2947. submitWsWorkunit(context, cw, cluster, snapshot, maxruntime, maxcost, compile, resetWorkflow, resetVariables, paramXml, variables, debugs, applications);
  2948. }
  2949. void WsWuHelpers::copyWsWorkunit(IEspContext &context, IWorkUnit &wu, const char *srcWuid)
  2950. {
  2951. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  2952. Owned<IConstWorkUnit> src(factory->openWorkUnit(srcWuid));
  2953. queryExtendedWU(&wu)->copyWorkUnit(src, false, false);
  2954. wu.commit();
  2955. }
  2956. void WsWuHelpers::runWsWorkunit(IEspContext &context, StringBuffer &wuid, const char *srcWuid, const char *cluster, const char *paramXml,
  2957. IArrayOf<IConstNamedValue> *variables, IArrayOf<IConstNamedValue> *debugs, IArrayOf<IConstApplicationValue> *applications)
  2958. {
  2959. NewWsWorkunit wu(context);
  2960. wuid.set(wu->queryWuid());
  2961. copyWsWorkunit(context, *wu, srcWuid);
  2962. wu.clear();
  2963. submitWsWorkunit(context, wuid.str(), cluster, NULL, 0, 0, false, true, true, paramXml, variables, debugs, applications);
  2964. }
  2965. void WsWuHelpers::runWsWorkunit(IEspContext &context, IConstWorkUnit *cw, const char *srcWuid, const char *cluster, const char *paramXml,
  2966. IArrayOf<IConstNamedValue> *variables, IArrayOf<IConstNamedValue> *debugs, IArrayOf<IConstApplicationValue> *applications)
  2967. {
  2968. WorkunitUpdate wu(&cw->lock());
  2969. copyWsWorkunit(context, *wu, srcWuid);
  2970. wu.clear();
  2971. submitWsWorkunit(context, cw, cluster, NULL, 0, 0, false, true, true, paramXml, variables, debugs, applications);
  2972. }
  2973. IException * WsWuHelpers::noteException(IWorkUnit *wu, IException *e, ErrorSeverity level)
  2974. {
  2975. if (wu)
  2976. {
  2977. Owned<IWUException> we = wu->createException();
  2978. StringBuffer s;
  2979. we->setExceptionMessage(e->errorMessage(s).str());
  2980. we->setExceptionSource("WsWorkunits");
  2981. we->setSeverity(level);
  2982. if (level==SeverityError)
  2983. wu->setState(WUStateFailed);
  2984. }
  2985. return e;
  2986. }
  2987. StringBuffer & WsWuHelpers::resolveQueryWuid(StringBuffer &wuid, const char *queryset, const char *query, bool notSuspended, IWorkUnit *wu)
  2988. {
  2989. Owned<IPropertyTree> qs = getQueryRegistry(queryset, true);
  2990. if (!qs)
  2991. throw noteException(wu, MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "QuerySet '%s' not found", queryset));
  2992. Owned<IPropertyTree> q = resolveQueryAlias(qs, query);
  2993. if (!q)
  2994. throw noteException(wu, MakeStringException(ECLWATCH_QUERYID_NOT_FOUND, "Query '%s/%s' not found", queryset, query));
  2995. if (notSuspended && q->getPropBool("@suspended"))
  2996. throw noteException(wu, MakeStringException(ECLWATCH_QUERY_SUSPENDED, "Query '%s/%s' is suspended", queryset, query));
  2997. return wuid.append(q->queryProp("@wuid"));
  2998. }
  2999. void WsWuHelpers::runWsWuQuery(IEspContext &context, IConstWorkUnit *cw, const char *queryset, const char *query,
  3000. const char *cluster, const char *paramXml, IArrayOf<IConstNamedValue> *variables, IArrayOf<IConstApplicationValue> *applications)
  3001. {
  3002. StringBuffer srcWuid;
  3003. WorkunitUpdate wu(&cw->lock());
  3004. resolveQueryWuid(srcWuid, queryset, query, true, wu);
  3005. copyWsWorkunit(context, *wu, srcWuid);
  3006. wu.clear();
  3007. submitWsWorkunit(context, cw, cluster, NULL, 0, 0, false, true, true, paramXml, variables, NULL, applications);
  3008. }
  3009. void WsWuHelpers::runWsWuQuery(IEspContext &context, StringBuffer &wuid, const char *queryset, const char *query,
  3010. const char *cluster, const char *paramXml, IArrayOf<IConstNamedValue> *variables, IArrayOf<IConstApplicationValue> *applications)
  3011. {
  3012. StringBuffer srcWuid;
  3013. NewWsWorkunit wu(context);
  3014. wuid.set(wu->queryWuid());
  3015. resolveQueryWuid(srcWuid, queryset, query, true, wu);
  3016. copyWsWorkunit(context, *wu, srcWuid);
  3017. wu.clear();
  3018. submitWsWorkunit(context, wuid.str(), cluster, NULL, 0, 0, false, true, true, paramXml, variables, NULL, applications);
  3019. }
  3020. void WsWuHelpers::checkAndTrimWorkunit(const char* methodName, StringBuffer& input)
  3021. {
  3022. const char* trimmedInput = input.trim().str();
  3023. if (isEmpty(trimmedInput))
  3024. throw MakeStringException(ECLWATCH_INVALID_INPUT, "%s: Workunit ID not set", methodName);
  3025. if (!looksLikeAWuid(trimmedInput, 'W'))
  3026. throw MakeStringException(ECLWATCH_INVALID_INPUT, "%s: Invalid Workunit ID: %s", methodName, trimmedInput);
  3027. return;
  3028. }
  3029. IFileIOStream* CWsWuFileHelper::createIOStreamWithFileName(const char* fileNameWithPath, IFOmode mode)
  3030. {
  3031. if (isEmptyString(fileNameWithPath))
  3032. throw MakeStringException(ECLWATCH_CANNOT_COMPRESS_DATA, "File name not specified.");
  3033. Owned<IFile> wuInfoIFile = createIFile(fileNameWithPath);
  3034. Owned<IFileIO> wuInfoIO = wuInfoIFile->open(mode);
  3035. if (!wuInfoIO)
  3036. throw MakeStringException(ECLWATCH_CANNOT_OPEN_FILE, "Failed to open %s.", fileNameWithPath);
  3037. return createIOStream(wuInfoIO);
  3038. }
  3039. void CWsWuFileHelper::writeToFile(const char* fileName, size32_t contentLength, const void* content)
  3040. {
  3041. if (isEmptyString(fileName))
  3042. throw MakeStringException(ECLWATCH_CANNOT_COMPRESS_DATA, "File name not specified.");
  3043. Owned<IFile> wuInfoIFile = createIFile(fileName);
  3044. Owned<IFileIO> wuInfoIO = wuInfoIFile->open(IFOcreate);
  3045. if (wuInfoIO)
  3046. wuInfoIO->write(0, contentLength, content);
  3047. else
  3048. PROGLOG("Failed to open %s.", fileName);
  3049. }
  3050. void CWsWuFileHelper::writeToFileIOStream(const char* folder, const char* file, MemoryBuffer& mb)
  3051. {
  3052. if (isEmptyString(folder))
  3053. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Empty folder name is not allowed to create FileIOStream.");
  3054. if (isEmptyString(file))
  3055. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Empty file name is not allowed to create FileIOStream.");
  3056. VStringBuffer fileNameWithPath("%s%c%s", folder, PATHSEPCHAR, file);
  3057. CWsWuFileHelper helper(nullptr);
  3058. Owned<IFileIOStream> outIOS = helper.createIOStreamWithFileName(fileNameWithPath.str(), IFOcreate);
  3059. if (outIOS)
  3060. outIOS->write(mb.length(), mb.toByteArray());
  3061. else
  3062. PROGLOG("Failed to open FileIOStream for %s.", fileNameWithPath.str());
  3063. }
  3064. void CWsWuFileHelper::cleanFolder(IFile* folder, bool removeFolder)
  3065. {
  3066. if (!folder)
  3067. throw MakeStringException(ECLWATCH_CANNOT_COMPRESS_DATA,"Invalid file interface for the zip folder.");
  3068. Owned<IDirectoryIterator> iter = folder->directoryFiles(NULL,false,false);
  3069. ForEach(*iter)
  3070. {
  3071. OwnedIFile thisFile = createIFile(iter->query().queryFilename());
  3072. if (thisFile->isFile() == fileBool::foundYes)
  3073. thisFile->remove();
  3074. }
  3075. if (removeFolder)
  3076. folder->remove();
  3077. }
  3078. #ifndef _CONTAINERIZED
  3079. void CWsWuFileHelper::createProcessLogfile(IConstWorkUnit* cwu, WsWuInfo& winfo, const char* process, const char* path)
  3080. {
  3081. BoolHash uniqueProcesses;
  3082. Owned<IPropertyTreeIterator> procs = cwu->getProcesses(process, NULL);
  3083. ForEach (*procs)
  3084. {
  3085. StringBuffer logSpec;
  3086. IPropertyTree& proc = procs->query();
  3087. const char* processName = proc.queryName();
  3088. if (isEmpty(processName))
  3089. continue;
  3090. //If a WU runs into another day, the procs contains >1 entries for the same process.
  3091. //Only one entry is needed to find out the process data for creating the new process
  3092. //log file which stores the WU information for multiple days.
  3093. bool* found = uniqueProcesses.getValue(processName);
  3094. if (found && *found)
  3095. continue;
  3096. uniqueProcesses.setValue(processName, true);
  3097. MemoryBuffer mb;
  3098. VStringBuffer fileName("%s%c%s", path, PATHSEPCHAR, processName);
  3099. try
  3100. {
  3101. if (strieq(process, "EclAgent"))
  3102. {
  3103. StringBuffer pid;
  3104. pid.appendf("%d", proc.getPropInt("@pid"));
  3105. fileName.append("_eclagent.log");
  3106. winfo.getWorkunitEclAgentLog(processName, nullptr, pid.str(), mb, fileName.str());
  3107. }
  3108. else if (strieq(process, "Thor"))
  3109. {
  3110. fileName.append("_thormaster.log");
  3111. winfo.getWorkunitThorMasterLog(processName, nullptr, mb, fileName.str());
  3112. }
  3113. }
  3114. catch(IException* e)
  3115. {
  3116. StringBuffer s;
  3117. e->errorMessage(s);
  3118. IERRLOG("Error accessing Process Log file %s: %s", logSpec.str(), s.str());
  3119. writeToFile(fileName.str(), s.length(), s.str());
  3120. e->Release();
  3121. }
  3122. }
  3123. }
  3124. void CWsWuFileHelper::createThorSlaveLogfile(IConstWorkUnit* cwu, WsWuInfo& winfo, const char* path)
  3125. {
  3126. if (cwu->getWuidVersion() == 0)
  3127. return;
  3128. const char* clusterName = cwu->queryClusterName();
  3129. if (isEmptyString(clusterName)) //Cluster name may not be set yet
  3130. return;
  3131. Owned<IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(clusterName);
  3132. if (!clusterInfo)
  3133. {
  3134. OWARNLOG("Cannot find TargetClusterInfo for workunit %s", cwu->queryWuid());
  3135. return;
  3136. }
  3137. Owned<IThreadFactory> threadFactory = new CGetThorSlaveLogToFileThreadFactory();
  3138. Owned<IThreadPool> threadPool = createThreadPool("WsWuFileHelper GetThorSlaveLogToFile Thread Pool",
  3139. threadFactory, NULL, thorSlaveLogThreadPoolSize, INFINITE);
  3140. unsigned numberOfSlaveLogs = clusterInfo->getNumberOfSlaveLogs();
  3141. BoolHash uniqueProcesses;
  3142. Owned<IStringIterator> thorInstances = cwu->getProcesses("Thor");
  3143. ForEach (*thorInstances)
  3144. {
  3145. SCMStringBuffer processName;
  3146. thorInstances->str(processName);
  3147. if (processName.length() == 0)
  3148. continue;
  3149. bool* found = uniqueProcesses.getValue(processName.str());
  3150. if (found && *found)
  3151. continue;
  3152. uniqueProcesses.setValue(processName.str(), true);
  3153. StringBuffer groupName, logDir;
  3154. getClusterThorGroupName(groupName, processName.str());
  3155. if (groupName.isEmpty())
  3156. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Failed to get Thor Group Name for %s", processName.str());
  3157. Owned<IGroup> nodeGroup = queryNamedGroupStore().lookup(groupName);
  3158. if (!nodeGroup || (nodeGroup->ordinality() == 0))
  3159. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Node group %s not found", groupName.str());
  3160. getConfigurationDirectory(directories, "log", "thor", processName.str(), logDir);
  3161. for (unsigned i = 0; i < numberOfSlaveLogs; i++)
  3162. {
  3163. VStringBuffer fileName("%s%c%s_thorslave.%u.log", path, PATHSEPCHAR, processName.str(), i+1);
  3164. Owned<CGetThorSlaveLogToFileThreadParam> threadParam = new CGetThorSlaveLogToFileThreadParam(
  3165. &winfo, nodeGroup, processName.str(), logDir, i+1, fileName);
  3166. threadPool->start(threadParam.getClear());
  3167. }
  3168. }
  3169. threadPool->joinAll();
  3170. }
  3171. #endif
  3172. void CWsWuFileHelper::createZAPInfoFile(const char* url, const char* espIP, const char* thorIP, const char* problemDesc,
  3173. const char* whatChanged, const char* timing, IConstWorkUnit* cwu, const char* pathNameStr)
  3174. {
  3175. VStringBuffer fileName("%s.txt", pathNameStr);
  3176. Owned<IFileIOStream> outFile = createIOStreamWithFileName(fileName.str(), IFOcreate);
  3177. StringBuffer sb;
  3178. sb.set("Workunit: ").append(cwu->queryWuid()).append("\r\n");
  3179. sb.append("User: ").append(cwu->queryUser()).append("\r\n");
  3180. sb.append("Build Version:").append(getBuildVersion()).append("\r\n");
  3181. sb.append("Cluster: ").append(cwu->queryClusterName()).append("\r\n");
  3182. if (!isEmptyString(espIP))
  3183. sb.append("ESP: ").append(espIP).append("\r\n");
  3184. else
  3185. {
  3186. StringBuffer espIPAddr;
  3187. IpAddress ipaddr = queryHostIP();
  3188. ipaddr.getIpText(espIPAddr);
  3189. sb.append("ESP: ").append(espIPAddr.str()).append("\r\n");
  3190. }
  3191. if (!isEmptyString(url))
  3192. sb.append("URL: ").append(url).append("\r\n");
  3193. if (!isEmptyString(thorIP))
  3194. sb.append("Thor: ").append(thorIP).append("\r\n");
  3195. outFile->write(sb.length(), sb.str());
  3196. //Exceptions/Warnings/Info
  3197. Owned<IConstWUExceptionIterator> exceptions = &cwu->getExceptions();
  3198. StringBuffer info, warn, err, alert;
  3199. ForEach(*exceptions)
  3200. {
  3201. const char* severityString = nullptr;
  3202. switch (exceptions->query().getSeverity())
  3203. {
  3204. case SeverityInformation:
  3205. severityString = "Information: ";
  3206. break;
  3207. case SeverityWarning:
  3208. severityString = "Warnings: ";
  3209. break;
  3210. case SeverityError:
  3211. severityString = "Exceptions: ";
  3212. break;
  3213. case SeverityAlert:
  3214. severityString = "Alert: ";
  3215. break;
  3216. }
  3217. if (!severityString)
  3218. continue;
  3219. SCMStringBuffer temp;
  3220. exceptions->query().getExceptionMessage(temp);
  3221. writeZAPWUInfoToIOStream(outFile, severityString, temp);
  3222. }
  3223. //User provided Information
  3224. writeZAPWUInfoToIOStream(outFile, "Problem: ", problemDesc);
  3225. writeZAPWUInfoToIOStream(outFile, "What Changed: ", whatChanged);
  3226. writeZAPWUInfoToIOStream(outFile, "Timing: ", timing);
  3227. }
  3228. void CWsWuFileHelper::writeZAPWUInfoToIOStream(IFileIOStream* outFile, const char* name, SCMStringBuffer& value)
  3229. {
  3230. outFile->write(strlen(name), name);
  3231. outFile->write(3, "\r\n\t");
  3232. outFile->write(value.length(), value.str());
  3233. outFile->write(4, "\r\n\r\n");
  3234. }
  3235. void CWsWuFileHelper::writeZAPWUInfoToIOStream(IFileIOStream* outFile, const char* name, const char* value)
  3236. {
  3237. outFile->write(strlen(name), name);
  3238. outFile->write(strlen(value), value);
  3239. outFile->write(4, "\r\n\r\n");
  3240. }
  3241. void CWsWuFileHelper::createZAPWUXMLFile(WsWuInfo& winfo, const char* pathNameStr)
  3242. {
  3243. MemoryBuffer mb;
  3244. winfo.getWorkunitXml(NULL, mb);
  3245. VStringBuffer fileName("%s.xml", pathNameStr);
  3246. writeToFile(fileName.str(), mb.length(), mb.bufferBase());
  3247. }
  3248. void CWsWuFileHelper::createZAPECLQueryArchiveFiles(IConstWorkUnit* cwu, const char* pathNameStr)
  3249. {
  3250. Owned<IConstWUQuery> query = cwu->getQuery();
  3251. if(!query)
  3252. return;
  3253. //Add archive if present
  3254. Owned<IConstWUAssociatedFileIterator> iter = &query->getAssociatedFiles();
  3255. ForEach(*iter)
  3256. {
  3257. IConstWUAssociatedFile& cur = iter->query();
  3258. SCMStringBuffer ssb, ip;
  3259. cur.getDescription(ssb);
  3260. if (!strieq(ssb.str(), "archive"))
  3261. continue;
  3262. cur.getName(ssb);
  3263. cur.getIp(ip);
  3264. if (!ssb.length() || !ip.length())
  3265. continue;
  3266. StringBuffer fileName, archiveContents;
  3267. try
  3268. {
  3269. SocketEndpoint ep(ip.str());
  3270. RemoteFilename rfn;
  3271. rfn.setRemotePath(ssb.str());
  3272. rfn.setIp(ep);
  3273. Owned<IFile> rFile = createIFile(rfn);
  3274. if (!rFile)
  3275. {
  3276. OERRLOG("Cannot open %s on %s", ssb.str(), ip.str());
  3277. continue;
  3278. }
  3279. archiveContents.loadFile(rFile);
  3280. }
  3281. catch (IException *e)
  3282. {
  3283. StringBuffer s;
  3284. e->errorMessage(s);
  3285. OERRLOG("Error accessing archive file %s: %s", ssb.str(), s.str());
  3286. archiveContents.insert(0, "Error accessing archive file ").appendf("%s: %s\r\n\r\n", ssb.str(), s.str());
  3287. e->Release();
  3288. }
  3289. fileName.setf("%s.archive", pathNameStr);
  3290. writeToFile(fileName.str(), archiveContents.length(), archiveContents.str());
  3291. break;
  3292. }
  3293. //Add Query
  3294. SCMStringBuffer temp;
  3295. query->getQueryText(temp);
  3296. if (temp.length())
  3297. {
  3298. VStringBuffer fileName("%s.ecl", pathNameStr);
  3299. writeToFile(fileName.str(), temp.length(), temp.str());
  3300. }
  3301. }
  3302. void CWsWuFileHelper::createZAPWUGraphProgressFile(const char* wuid, const char* pathNameStr)
  3303. {
  3304. Owned<IPropertyTree> graphProgress = getWUGraphProgress(wuid, true);
  3305. if (!graphProgress)
  3306. return;
  3307. StringBuffer graphProgressXML;
  3308. toXML(graphProgress, graphProgressXML, 1, XML_Format);
  3309. VStringBuffer fileName("%s.graphprogress", pathNameStr);
  3310. writeToFile(fileName.str(), graphProgressXML.length(), graphProgressXML.str());
  3311. }
  3312. int CWsWuFileHelper::zipAFolder(const char* folder, const char* passwordReq, const char* zipFileNameWithPath)
  3313. {
  3314. VStringBuffer archiveInPath("%s%c*", folder, PATHSEPCHAR);
  3315. StringBuffer zipCommand;
  3316. if (!isEmptyString(passwordReq))
  3317. zipCommand.setf("zip -j --password %s %s %s", passwordReq, zipFileNameWithPath, archiveInPath.str());
  3318. else
  3319. zipCommand.setf("zip -j %s %s", zipFileNameWithPath, archiveInPath.str());
  3320. return (system(zipCommand.str()));
  3321. }
  3322. int CWsWuFileHelper::zipAFolder(const char* folder, bool gzip, const char* zipFileNameWithPath)
  3323. {
  3324. StringBuffer zipCommand;
  3325. VStringBuffer archiveInPath("%s%c*", folder, PATHSEPCHAR);
  3326. if (!gzip)
  3327. zipCommand.appendf("zip -j %s %s", zipFileNameWithPath, archiveInPath.str());
  3328. else
  3329. zipCommand.appendf("tar -czf %s %s", zipFileNameWithPath, archiveInPath.str());
  3330. return (system(zipCommand.str()));
  3331. }
  3332. void CWsWuFileHelper::createWUZAPFile(IEspContext& context, IConstWorkUnit* cwu, CWsWuZAPInfoReq& request,
  3333. StringBuffer& zipFileName, StringBuffer& zipFileNameWithPath, unsigned _thorSlaveLogThreadPoolSize)
  3334. {
  3335. StringBuffer zapReportNameStr, folderToZIP, inFileNamePrefixWithPath;
  3336. Owned<IFile> zipDir = createWorkingFolder(context, request.wuid.str(), "ZAPReport_", zapReportNameStr, folderToZIP);
  3337. setZAPFile(request.zapFileName.str(), zapReportNameStr.str(), zipFileName, zipFileNameWithPath);
  3338. thorSlaveLogThreadPoolSize = _thorSlaveLogThreadPoolSize;
  3339. //create WU ZAP files
  3340. inFileNamePrefixWithPath.set(folderToZIP.str()).append(PATHSEPCHAR).append(zapReportNameStr.str());
  3341. createZAPInfoFile(request.url.str(), request.espIP.str(), request.thorIP.str(), request.problemDesc.str(), request.whatChanged.str(),
  3342. request.whereSlow.str(), cwu, inFileNamePrefixWithPath.str());
  3343. createZAPECLQueryArchiveFiles(cwu, inFileNamePrefixWithPath.str());
  3344. WsWuInfo winfo(context, cwu);
  3345. createZAPWUXMLFile(winfo, inFileNamePrefixWithPath.str());
  3346. createZAPWUGraphProgressFile(request.wuid.str(), inFileNamePrefixWithPath.str());
  3347. createZAPWUQueryAssociatedFiles(cwu, folderToZIP);
  3348. #ifndef _CONTAINERIZED
  3349. createProcessLogfile(cwu, winfo, "EclAgent", folderToZIP.str());
  3350. createProcessLogfile(cwu, winfo, "Thor", folderToZIP.str());
  3351. if (request.includeThorSlaveLog.isEmpty() || strieq(request.includeThorSlaveLog.str(), "on"))
  3352. createThorSlaveLogfile(cwu, winfo, folderToZIP.str());
  3353. #endif
  3354. //Write out to ZIP file
  3355. int zipRet = zipAFolder(folderToZIP.str(), request.password.str(), zipFileNameWithPath);
  3356. //Remove the temporary files and the folder
  3357. cleanFolder(zipDir, true);
  3358. if (zipRet != 0)
  3359. throw MakeStringException(ECLWATCH_CANNOT_COMPRESS_DATA,"Failed to execute system command 'zip'. Please make sure that zip utility is installed.");
  3360. }
  3361. void CWsWuFileHelper::createZAPWUQueryAssociatedFiles(IConstWorkUnit* cwu, const char* pathToCreate)
  3362. {
  3363. Owned<IConstWUQuery> query = cwu->getQuery();
  3364. if (!query)
  3365. {
  3366. IERRLOG("Cannot get Query for workunit %s.", cwu->queryWuid());
  3367. return;
  3368. }
  3369. Owned<IConstWUAssociatedFileIterator> iter = &query->getAssociatedFiles();
  3370. ForEach(*iter)
  3371. {
  3372. SCMStringBuffer name, ip;
  3373. IConstWUAssociatedFile& cur = iter->query();
  3374. cur.getName(name);
  3375. cur.getIp(ip);
  3376. RemoteFilename rfn;
  3377. SocketEndpoint ep(ip.str());
  3378. rfn.setPath(ep, name.str());
  3379. OwnedIFile sourceFile = createIFile(rfn);
  3380. if (!sourceFile)
  3381. {
  3382. IERRLOG("Cannot open %s on %s.", name.str(), ip.str());
  3383. continue;
  3384. }
  3385. StringBuffer fileName(name.str());
  3386. getFileNameOnly(fileName, false);
  3387. StringBuffer outFileName(pathToCreate);
  3388. outFileName.append(PATHSEPCHAR).append(fileName);
  3389. OwnedIFile outFile = createIFile(outFileName);
  3390. if (!outFile)
  3391. {
  3392. IERRLOG("Cannot create %s.", outFileName.str());
  3393. continue;
  3394. }
  3395. copyFile(outFile, sourceFile);
  3396. }
  3397. }
  3398. void CWsWuFileHelper::setZAPFile(const char* zipFileNameReq, const char* zipFileNamePrefix,
  3399. StringBuffer& zipFileName, StringBuffer& zipFileNameWithPath)
  3400. {
  3401. StringBuffer outFileNameReq(zipFileNameReq);
  3402. //Clean zipFileNameReq. The zipFileNameReq should not end with PATHSEPCHAR.
  3403. while (!outFileNameReq.isEmpty() && (outFileNameReq.charAt(outFileNameReq.length() - 1) == PATHSEPCHAR))
  3404. outFileNameReq.setLength(outFileNameReq.length() - 1);
  3405. if (outFileNameReq.isEmpty())
  3406. zipFileName.set(zipFileNamePrefix).append(".zip");
  3407. else
  3408. {
  3409. zipFileName.set(outFileNameReq.str());
  3410. const char* ext = pathExtension(zipFileName.str());
  3411. if (!ext || !strieq(ext, ".zip"))
  3412. zipFileName.append(".zip");
  3413. }
  3414. zipFileNameWithPath.set(zipFolder);
  3415. Owned<IFile> workingDir = createIFile(zipFileNameWithPath.str());
  3416. if (!workingDir->exists())
  3417. workingDir->createDirectory();
  3418. zipFileNameWithPath.append(PATHSEPCHAR).append(zipFileName);
  3419. OwnedIFile thisFile = createIFile(zipFileNameWithPath.str());
  3420. if (thisFile->isFile() == fileBool::foundYes)
  3421. thisFile->remove();
  3422. }
  3423. IFile* CWsWuFileHelper::createWorkingFolder(IEspContext& context, const char* wuid, const char* namePrefix,
  3424. StringBuffer& namePrefixStr, StringBuffer& folderName)
  3425. {
  3426. StringBuffer userName;
  3427. if (context.queryUser())
  3428. userName.append(context.queryUser()->getName());
  3429. namePrefixStr.set(namePrefix).append(wuid).append('_').append(userName.str());
  3430. folderName.append(zipFolder).append(namePrefixStr.str());
  3431. Owned<IFile> workingDir = createIFile(folderName.str());
  3432. if (!workingDir->exists())
  3433. workingDir->createDirectory();
  3434. else
  3435. cleanFolder(workingDir, false);
  3436. return workingDir.getClear();
  3437. }
  3438. IFileIOStream* CWsWuFileHelper::createWUZAPFileIOStream(IEspContext& context, IConstWorkUnit* cwu,
  3439. CWsWuZAPInfoReq& request, unsigned thorSlaveLogThreadPoolSize)
  3440. {
  3441. StringBuffer zapFileName, zapFileNameWithPath;
  3442. createWUZAPFile(context, cwu, request, zapFileName, zapFileNameWithPath, thorSlaveLogThreadPoolSize);
  3443. if (request.sendEmail)
  3444. {
  3445. CWsWuEmailHelper emailHelper(request.emailFrom.str(), request.emailTo.str(), request.emailServer.str(), request.port);
  3446. StringBuffer subject(request.emailSubject.str());
  3447. if (subject.isEmpty())
  3448. subject.append(request.wuid.str()).append(" ZAP Report");
  3449. emailHelper.setSubject(subject.str());
  3450. PROGLOG("Sending WU ZAP email (%s): from %s to %s", request.emailServer.str(), request.emailFrom.str(), request.emailTo.str());
  3451. StringArray warnings;
  3452. if (!request.attachZAPReportToEmail)
  3453. emailHelper.send(request.emailBody.str(), "", 0, warnings);
  3454. else
  3455. {
  3456. Owned<IFile> f = createIFile(zapFileNameWithPath.str());
  3457. Owned<IFileIO> io = f->open(IFOread);
  3458. unsigned zapFileSize = (unsigned) io->size();
  3459. if (zapFileSize > request.maxAttachmentSize)
  3460. {
  3461. request.emailBody.appendf("\n\n(Failed to attach the ZAP report. The size limit is %u bytes.)", request.maxAttachmentSize);
  3462. emailHelper.send(request.emailBody.str(), "", 0, warnings);
  3463. }
  3464. else
  3465. {
  3466. MemoryBuffer mb;
  3467. void * data = mb.reserve(zapFileSize);
  3468. size32_t read = io->read(0, zapFileSize, data);
  3469. mb.setLength(read);
  3470. emailHelper.setAttachmentName(zapFileName.str());
  3471. emailHelper.setMimeType("application/zip, application/octet-stream");
  3472. emailHelper.send(request.emailBody.str(), mb.toByteArray(), mb.length(), warnings);
  3473. }
  3474. }
  3475. }
  3476. VStringBuffer headerStr("attachment;filename=%s", zapFileName.str());
  3477. context.addCustomerHeader("Content-disposition", headerStr.str());
  3478. return createIOStreamWithFileName(zapFileNameWithPath.str(), IFOread);
  3479. }
  3480. IFileIOStream* CWsWuFileHelper::createWUFileIOStream(IEspContext& context, const char* wuid, IArrayOf<IConstWUFileOption>& wuFileOptions,
  3481. CWUFileDownloadOption& downloadOptions, StringBuffer& contentType)
  3482. {
  3483. StringBuffer fileName, fileNameStr, workingFolder, zipFileNameWithPath;
  3484. Owned<IFile> zipDir;
  3485. bool doZIP = (downloadOptions == CWUFileDownloadOption_ZIP) || (downloadOptions == CWUFileDownloadOption_GZIP);
  3486. if (doZIP)
  3487. {
  3488. zipDir.setown(createWorkingFolder(context, wuid, "WUFiles_", fileNameStr, workingFolder));
  3489. }
  3490. else
  3491. {
  3492. StringBuffer userName;
  3493. if (context.queryUser())
  3494. userName.append(context.queryUser()->getName());
  3495. fileName.set("WUFiles_").append(wuid).append('_').append(userName.str());
  3496. }
  3497. WsWuInfo winfo(context, wuid);
  3498. ForEachItemIn(i, wuFileOptions)
  3499. {
  3500. if (!doZIP)
  3501. {//If no zip, only return one file. If > 1 files, the caller throws exception.
  3502. readWUFile(wuid, zipFolder, winfo, wuFileOptions.item(i), fileName, contentType);
  3503. break;
  3504. }
  3505. StringBuffer aFileName, aFileMimeType;//Not used
  3506. readWUFile(wuid, workingFolder.str(), winfo, wuFileOptions.item(i), aFileName, aFileMimeType);
  3507. }
  3508. if (!doZIP)
  3509. {
  3510. if (downloadOptions != CWUFileDownloadOption_OriginalText)
  3511. {
  3512. VStringBuffer headerStr("attachment;filename=%s", fileName.str());
  3513. context.addCustomerHeader("Content-disposition", headerStr.str());
  3514. }
  3515. zipFileNameWithPath.set(zipFolder).append(fileName.str());
  3516. return createIOStreamWithFileName(zipFileNameWithPath.str(), IFOread);
  3517. }
  3518. if (downloadOptions == CWUFileDownloadOption_ZIP)
  3519. fileName.set(fileNameStr).append(".zip");
  3520. else
  3521. fileName.set(fileNameStr).append(".gzip");
  3522. zipFileNameWithPath.set(zipFolder).append(fileName.str());
  3523. {
  3524. OwnedIFile oldFile = createIFile(zipFileNameWithPath.str());
  3525. if (oldFile->isFile() == fileBool::foundYes)
  3526. oldFile->remove();
  3527. }
  3528. int zipRet = zipAFolder(workingFolder.str(), downloadOptions == CWUFileDownloadOption_GZIP, zipFileNameWithPath);
  3529. //Remove the temporary files and the folder
  3530. cleanFolder(zipDir, true);
  3531. if (zipRet != 0)
  3532. throw MakeStringException(ECLWATCH_CANNOT_COMPRESS_DATA, "Failed to execute system command 'zip'. Please make sure that zip utility is installed.");
  3533. contentType.set(HTTP_TYPE_OCTET_STREAM);
  3534. VStringBuffer headerStr("attachment;filename=%s", fileName.str());
  3535. context.addCustomerHeader("Content-disposition", headerStr.str());
  3536. return createIOStreamWithFileName(zipFileNameWithPath.str(), IFOread);
  3537. }
  3538. void CWsWuFileHelper::validateFilePath(const char* file, WsWuInfo& winfo, CWUFileType wuFileType, bool UNCFileName, const char* fileType, const char* compType, const char* compName)
  3539. {
  3540. if (validateWUFile(file, winfo, wuFileType))
  3541. return;
  3542. StringBuffer actualPath;
  3543. if (UNCFileName)
  3544. splitUNCFilename(file, nullptr, &actualPath, nullptr, nullptr);
  3545. else
  3546. splitFilename(file, nullptr, &actualPath, nullptr, nullptr);
  3547. if (containsRelPaths(actualPath)) //Detect a path like: /home/lexis/runtime/var/log/HPCCSystems/myesp/../../../
  3548. throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Invalid file path %s", actualPath.str());
  3549. if (!validateConfigurationDirectory(nullptr, fileType, compType, compName, actualPath))
  3550. throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Invalid file path %s", actualPath.str());
  3551. }
  3552. bool CWsWuFileHelper::validateWUFile(const char* file, WsWuInfo& winfo, CWUFileType wuFileType)
  3553. {
  3554. bool valid = false;
  3555. switch (wuFileType)
  3556. {
  3557. case CWUFileType_ThorLog:
  3558. {
  3559. valid = winfo.validateWUProcessLog(file, false);
  3560. break;
  3561. }
  3562. case CWUFileType_EclAgentLog:
  3563. {
  3564. valid = winfo.validateWUProcessLog(file, true);
  3565. break;
  3566. }
  3567. case CWUFileType_CPP:
  3568. {
  3569. valid = winfo.validateWUAssociatedFile(file, FileTypeCpp);
  3570. break;
  3571. }
  3572. case CWUFileType_LOG:
  3573. {
  3574. valid = winfo.validateWUAssociatedFile(file, FileTypeLog);
  3575. break;
  3576. }
  3577. case CWUFileType_XML:
  3578. {
  3579. valid = winfo.validateWUAssociatedFile(file, FileTypeXml);
  3580. break;
  3581. }
  3582. default:
  3583. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Unsupported file type %d.", wuFileType);
  3584. }
  3585. return valid;
  3586. }
  3587. void CWsWuFileHelper::readWUFile(const char* wuid, const char* workingFolder, WsWuInfo& winfo, IConstWUFileOption& item,
  3588. StringBuffer& fileName, StringBuffer& fileMimeType)
  3589. {
  3590. MemoryBuffer mb;
  3591. StringBuffer fileNameWithPath;
  3592. CWUFileType fileType = item.getFileType();
  3593. switch (fileType)
  3594. {
  3595. case CWUFileType_ArchiveQuery:
  3596. winfo.getWorkunitArchiveQuery(mb);
  3597. fileName.set("ArchiveQuery.xml");
  3598. fileMimeType.set(HTTP_TYPE_APPLICATION_XML);
  3599. writeToFileIOStream(workingFolder, "ArchiveQuery.xml", mb);
  3600. break;
  3601. case CWUFileType_CPP:
  3602. case CWUFileType_LOG:
  3603. {
  3604. const char *file=item.getName();
  3605. #ifndef _CONTAINERIZED
  3606. validateFilePath(file, winfo, fileType, false, "run", nullptr, nullptr);
  3607. #else
  3608. validateFilePath(file, winfo, fileType, false, "query", nullptr, nullptr);
  3609. #endif
  3610. const char *tail=pathTail(file);
  3611. fileName.set(tail ? tail : file);
  3612. fileMimeType.set(HTTP_TYPE_TEXT_PLAIN);
  3613. fileNameWithPath.set(workingFolder).append(PATHSEPCHAR).append(fileName.str());
  3614. winfo.getWorkunitCpp(file, item.getDescription(), item.getIPAddress(), mb, true, fileNameWithPath.str());
  3615. break;
  3616. }
  3617. case CWUFileType_DLL:
  3618. {
  3619. const char *tail=pathTail(item.getName());
  3620. fileName.set(tail ? tail : item.getName());
  3621. fileMimeType.set(HTTP_TYPE_OCTET_STREAM);
  3622. StringBuffer name;
  3623. winfo.getWorkunitDll(name, mb);
  3624. writeToFileIOStream(workingFolder, fileName.str(), mb);
  3625. break;
  3626. }
  3627. case CWUFileType_Res:
  3628. fileName.set("res.txt");
  3629. fileMimeType.set(HTTP_TYPE_TEXT_PLAIN);
  3630. winfo.getWorkunitResTxt(mb);
  3631. writeToFileIOStream(workingFolder, fileName.str(), mb);
  3632. break;
  3633. #ifndef _CONTAINERIZED
  3634. case CWUFileType_ThorLog:
  3635. {
  3636. const char *file=item.getName();
  3637. validateFilePath(file, winfo, fileType, true, "log", nullptr, nullptr);
  3638. fileName.set("thormaster.log");
  3639. fileMimeType.set(HTTP_TYPE_TEXT_PLAIN);
  3640. fileNameWithPath.set(workingFolder).append(PATHSEPCHAR).append(fileName.str());
  3641. winfo.getWorkunitThorMasterLog(nullptr, file, mb, fileNameWithPath.str());
  3642. break;
  3643. }
  3644. case CWUFileType_ThorSlaveLog:
  3645. {
  3646. fileName.set("ThorSlave.log");
  3647. fileMimeType.set(HTTP_TYPE_TEXT_PLAIN);
  3648. fileNameWithPath.set(workingFolder).append(PATHSEPCHAR).append(fileName.str());
  3649. winfo.getWorkunitThorSlaveLog(directories, item.getProcess(), item.getClusterGroup(), item.getIPAddress(),
  3650. item.getLogDate(), item.getSlaveNumber(), mb, fileNameWithPath.str(), false);
  3651. break;
  3652. }
  3653. case CWUFileType_EclAgentLog:
  3654. {
  3655. const char *file=item.getName();
  3656. validateFilePath(file, winfo, fileType, true, "log", nullptr, nullptr);
  3657. fileName.set("eclagent.log");
  3658. fileMimeType.set(HTTP_TYPE_TEXT_PLAIN);
  3659. fileNameWithPath.set(workingFolder).append(PATHSEPCHAR).append(fileName.str());
  3660. winfo.getWorkunitEclAgentLog(nullptr, file, item.getProcess(), mb, fileNameWithPath.str());
  3661. break;
  3662. }
  3663. #endif
  3664. case CWUFileType_XML:
  3665. {
  3666. StringBuffer name(item.getName());
  3667. if (!name.isEmpty())
  3668. {
  3669. const char *tail=pathTail(name.str());
  3670. fileName.set(tail ? tail : name.str());
  3671. fileNameWithPath.set(workingFolder).append(PATHSEPCHAR).append(fileName.str());
  3672. winfo.getWorkunitAssociatedXml(fileName.str(), item.getIPAddress(), item.getPlainText(), item.getDescription(), true, true, mb, fileNameWithPath.str());
  3673. }
  3674. else
  3675. {
  3676. fileName.setf("%s.xml", wuid);
  3677. winfo.getWorkunitXml(item.getPlainText(), mb);
  3678. writeToFileIOStream(workingFolder, fileName.str(), mb);
  3679. }
  3680. const char* plainText = item.getPlainText();
  3681. if (plainText && strieq(plainText, "yes"))
  3682. fileMimeType.set(HTTP_TYPE_TEXT_PLAIN);
  3683. else
  3684. fileMimeType.set(HTTP_TYPE_APPLICATION_XML);
  3685. break;
  3686. }
  3687. case CWUFileType_WUECL:
  3688. fileName.setf("%s.ecl", wuid);
  3689. fileMimeType.set(HTTP_TYPE_TEXT_PLAIN);
  3690. fileNameWithPath.set(workingFolder).append(PATHSEPCHAR).append(fileName.str());
  3691. winfo.getWorkunitQueryShortText(mb, fileNameWithPath.str());
  3692. break;
  3693. default:
  3694. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Unsupported file type %d.", fileType);
  3695. }
  3696. }
  3697. void CWsWuEmailHelper::send(const char* body, const void* attachment, size32_t lenAttachment, StringArray& warnings)
  3698. {
  3699. if (lenAttachment == 0)
  3700. sendEmail(to.get(), subject.get(), body, mailServer.get(), port, sender.get(), &warnings);
  3701. else
  3702. sendEmailAttachData(to.get(), subject.get(), body, lenAttachment, attachment, mimeType.get(),
  3703. attachmentName.get(), mailServer.get(), port, sender.get(), &warnings);
  3704. }
  3705. }