ws_workunitsService.cpp 209 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "ws_workunitsService.hpp"
  14. #include "ws_fs.hpp"
  15. #include "jlib.hpp"
  16. #include "jflz.hpp"
  17. #include "daclient.hpp"
  18. #include "dadfs.hpp"
  19. #include "daaudit.hpp"
  20. #include "dautils.hpp"
  21. #include "exception_util.hpp"
  22. #include "wujobq.hpp"
  23. #include "eventqueue.hpp"
  24. #include "fileview.hpp"
  25. #include "hqlerror.hpp"
  26. #include "sacmd.hpp"
  27. #include "wuwebview.hpp"
  28. #include "portlist.h"
  29. #include "dllserver.hpp"
  30. #include "schedulectrl.hpp"
  31. #include "scheduleread.hpp"
  32. #include "dadfs.hpp"
  33. #include "dfuwu.hpp"
  34. #include "thorplugin.hpp"
  35. #include "roxiecontrol.hpp"
  36. #include "deftype.hpp"
  37. #include "thorcommon.hpp"
  38. #include "thorxmlwrite.hpp"
  39. #include "fvdatasource.hpp"
  40. #include "fvresultset.ipp"
  41. #include "ws_wudetails.hpp"
  42. #include "wuerror.hpp"
  43. #include "TpWrapper.hpp"
  44. #include "LogicFileWrapper.hpp"
  45. #include "rtlformat.hpp"
  46. #include "package.h"
  47. #include "build-config.h"
  48. #ifdef _USE_ZLIB
  49. #include "zcrypt.hpp"
  50. #endif
  51. #define ESP_WORKUNIT_DIR "workunits/"
  52. static constexpr const char* zipFolder = "tempzipfiles" PATHSEPSTR;
  53. #define WU_SDS_LOCK_TIMEOUT (5*60*1000) // 5 mins
  54. const unsigned CHECK_QUERY_STATUS_THREAD_POOL_SIZE = 25;
  55. const unsigned MAX_ZAP_BUFFER_SIZE = 10000000; //10M
  56. class ExecuteExistingQueryInfo
  57. {
  58. public:
  59. ExecuteExistingQueryInfo(IConstWorkUnit *cw)
  60. {
  61. const char *name = cw->queryJobName();
  62. const char *div = strchr(name, '.');
  63. if (div)
  64. {
  65. queryset.set(name, div-name);
  66. query.set(div+1);
  67. }
  68. }
  69. public:
  70. StringAttr queryset;
  71. StringAttr query;
  72. };
  73. //The ECLWUActionNames[] has to match with the ESPenum ECLWUActions in the ecm file.
  74. static unsigned NumOfECLWUActionNames = 12;
  75. static const char *ECLWUActionNames[] = { "Abort", "Delete", "Deschedule", "Reschedule", "Pause",
  76. "PauseNow", "Protect", "Unprotect", "Restore", "Resume", "SetToFailed", "Archive", nullptr };
  77. class CECLWUActionsEx : public SoapEnumParamNew<CECLWUActions>
  78. {
  79. public:
  80. CECLWUActionsEx() : SoapEnumParamNew<CECLWUActions>() { init("ECLWUActions","string", ECLWUActionNames); }
  81. };
  82. static CECLWUActionsEx eclWUActionType;
  83. void setActionResult(const char* wuid, CECLWUActions action, const char* result, const char* strAction, IArrayOf<IConstWUActionResult>* results)
  84. {
  85. if (!results || !wuid || !*wuid || !result || !*result)
  86. return;
  87. Owned<IEspWUActionResult> res = createWUActionResult("", "");
  88. res->setWuid(wuid);
  89. res->setAction(strAction);
  90. res->setResult(result);
  91. results->append(*res.getClear());
  92. }
  93. bool doAction(IEspContext& context, StringArray& wuids, CECLWUActions action, IProperties* params, IArrayOf<IConstWUActionResult>* results)
  94. {
  95. if (!wuids.length())
  96. return true;
  97. if ((action == CECLWUActions_Restore) || (action == CECLWUActions_Archive))
  98. {
  99. StringBuffer msg;
  100. ForEachItemIn(i, wuids)
  101. {
  102. StringBuffer wuidStr(wuids.item(i));
  103. const char* wuid = wuidStr.trim().str();
  104. if (isEmpty(wuid))
  105. {
  106. msg.appendf("Empty Workunit ID at %u. ", i);
  107. continue;
  108. }
  109. if ((action == CECLWUActions_Archive) && !validateWsWorkunitAccess(context, wuid, SecAccess_Full))
  110. msg.appendf("Access denied for Workunit %s. ", wuid);
  111. }
  112. if (!msg.isEmpty())
  113. throw makeStringException(ECLWATCH_INVALID_INPUT, msg);
  114. Owned<ISashaCommand> cmd = archiveOrRestoreWorkunits(wuids, params, action == CECLWUActions_Archive, false);
  115. ForEachItemIn(idx, wuids)
  116. {
  117. StringBuffer reply;
  118. cmd->getId(idx, reply);
  119. const char* wuid = wuids.item(idx);
  120. if ((action == CECLWUActions_Restore) && !validateWsWorkunitAccess(context, wuid, SecAccess_Full))
  121. reply.appendf("Access denied for Workunit %s. ", wuid);
  122. AuditSystemAccess(context.queryUserId(), true, "%s", reply.str());
  123. }
  124. return true;
  125. }
  126. bool bAllSuccess = true;
  127. const char* strAction = (action < NumOfECLWUActionNames) ? ECLWUActionNames[action] : "Unknown Action";
  128. for(aindex_t i=0; i<wuids.length();i++)
  129. {
  130. StringBuffer wuidStr(wuids.item(i));
  131. const char* wuid = wuidStr.trim().str();
  132. if (isEmpty(wuid))
  133. {
  134. UWARNLOG("Empty Workunit ID");
  135. continue;
  136. }
  137. try
  138. {
  139. if (!looksLikeAWuid(wuid, 'W'))
  140. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid Workunit ID: %s", wuid);
  141. PROGLOG("%s %s", strAction, wuid);
  142. if (action == CECLWUActions_EventDeschedule)
  143. {
  144. if (!context.validateFeatureAccess(OWN_WU_ACCESS, SecAccess_Full, false)
  145. || !context.validateFeatureAccess(OTHERS_WU_ACCESS, SecAccess_Full, false))
  146. ensureWsWorkunitAccess(context, wuid, SecAccess_Full);
  147. descheduleWorkunit(wuid);
  148. AuditSystemAccess(context.queryUserId(), true, "Updated %s", wuid);
  149. }
  150. else
  151. {
  152. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  153. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid);
  154. if(!cw)
  155. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot open workunit %s.",wuid);
  156. if ((action == CECLWUActions_Delete) && (cw->getState() == WUStateWait))
  157. throw MakeStringException(ECLWATCH_CANNOT_DELETE_WORKUNIT,"Cannot delete a workunit which is in a 'Wait' status.");
  158. switch(action)
  159. {
  160. case CECLWUActions_Pause:
  161. {
  162. ensureWsWorkunitAccess(context, *cw, SecAccess_Full);
  163. WorkunitUpdate wu(&cw->lock());
  164. wu->setAction(WUActionPause);
  165. break;
  166. }
  167. case CECLWUActions_PauseNow:
  168. {
  169. ensureWsWorkunitAccess(context, *cw, SecAccess_Full);
  170. WorkunitUpdate wu(&cw->lock());
  171. wu->setAction(WUActionPauseNow);
  172. break;
  173. }
  174. case CECLWUActions_Resume:
  175. {
  176. ensureWsWorkunitAccess(context, *cw, SecAccess_Full);
  177. WorkunitUpdate wu(&cw->lock());
  178. wu->setAction(WUActionResume);
  179. break;
  180. }
  181. case CECLWUActions_Delete:
  182. ensureWsWorkunitAccess(context, *cw, SecAccess_Full);
  183. {
  184. cw.clear();
  185. factory->deleteWorkUnitEx(wuid, true),
  186. AuditSystemAccess(context.queryUserId(), true, "Deleted %s", wuid);
  187. }
  188. break;
  189. case CECLWUActions_Abort:
  190. ensureWsWorkunitAccess(context, *cw, SecAccess_Full);
  191. {
  192. if (cw->getState() == WUStateWait)
  193. {
  194. WorkunitUpdate wu(&cw->lock());
  195. wu->deschedule();
  196. wu->setState(WUStateAborted);
  197. }
  198. else
  199. abortWorkUnit(wuid, context.querySecManager(), context.queryUser());
  200. AuditSystemAccess(context.queryUserId(), true, "Aborted %s", wuid);
  201. }
  202. break;
  203. case CECLWUActions_Protect:
  204. case CECLWUActions_Unprotect:
  205. ensureWsWorkunitAccess(context, *cw, SecAccess_Write);
  206. cw->protect((action == CECLWUActions_Protect) ? true:false);
  207. AuditSystemAccess(context.queryUserId(), true, "Updated %s", wuid);
  208. break;
  209. case CECLWUActions_SetToFailed:
  210. {
  211. ensureWsWorkunitAccess(context, *cw, SecAccess_Write);
  212. WorkunitUpdate wu(&cw->lock());
  213. wu->setState(WUStateFailed);
  214. AuditSystemAccess(context.queryUserId(), true, "Updated %s", wuid);
  215. }
  216. break;
  217. case CECLWUActions_EventReschedule:
  218. {
  219. ensureWsWorkunitAccess(context, *cw, SecAccess_Full);
  220. WorkunitUpdate wu(&cw->lock());
  221. wu->schedule();
  222. AuditSystemAccess(context.queryUserId(), true, "Updated %s", wuid);
  223. }
  224. break;
  225. }
  226. }
  227. PROGLOG("%s %s done", strAction, wuid);
  228. setActionResult(wuid, action, "Success", strAction, results);
  229. }
  230. catch (IException *e)
  231. {
  232. bAllSuccess = false;
  233. StringBuffer eMsg;
  234. StringBuffer failedMsg("Failed: ");
  235. setActionResult(wuid, action, failedMsg.append(e->errorMessage(eMsg)).str(), strAction, results);
  236. OWARNLOG("Failed to %s for workunit: %s, %s", strAction, wuid, eMsg.str());
  237. AuditSystemAccess(context.queryUserId(), false, "Failed to %s %s", strAction, wuid);
  238. e->Release();
  239. continue;
  240. }
  241. catch (...)
  242. {
  243. bAllSuccess = false;
  244. StringBuffer failedMsg;
  245. failedMsg.appendf("Unknown exception");
  246. setActionResult(wuid, action, failedMsg.str(), strAction, results);
  247. IWARNLOG("Failed to %s for workunit: %s, %s", strAction, wuid, failedMsg.str());
  248. AuditSystemAccess(context.queryUserId(), false, "Failed to %s %s", strAction, wuid);
  249. continue;
  250. }
  251. }
  252. int timeToWait = 0;
  253. if (params)
  254. timeToWait = params->getPropInt("BlockTillFinishTimer");
  255. if (timeToWait != 0)
  256. {
  257. for(aindex_t i=0; i<wuids.length();i++)
  258. {
  259. const char* wuid=wuids.item(i);
  260. if (isEmpty(wuid))
  261. continue;
  262. waitForWorkUnitToComplete(wuid, timeToWait);
  263. }
  264. }
  265. return bAllSuccess;
  266. }
  267. bool doProtectWorkunits(IEspContext& context, StringArray& wuids, IArrayOf<IConstWUActionResult>* results)
  268. {
  269. Owned<IProperties> params(createProperties(true));
  270. params->setProp("BlockTillFinishTimer", 0);
  271. return doAction(context, wuids, CECLWUActions_Protect, params, results);
  272. }
  273. bool doUnProtectWorkunits(IEspContext& context, StringArray& wuids, IArrayOf<IConstWUActionResult>* results)
  274. {
  275. Owned<IProperties> params(createProperties(true));
  276. params->setProp("BlockTillFinishTimer", 0);
  277. return doAction(context, wuids, CECLWUActions_Unprotect, params, results);
  278. }
  279. static void checkUpdateQuerysetLibraries()
  280. {
  281. Owned<IRemoteConnection> globalLock = querySDS().connect("/QuerySets/", myProcessSession(), RTM_LOCK_WRITE|RTM_CREATE_QUERY, WU_SDS_LOCK_TIMEOUT);
  282. if (!globalLock)
  283. return;
  284. IPropertyTree *root = globalLock->queryRoot();
  285. if (!root)
  286. return;
  287. Owned<IWorkUnitFactory> factory = getWorkUnitFactory();
  288. Owned<IPropertyTreeIterator> querySets = root->getElements("QuerySet");
  289. ForEach(*querySets)
  290. {
  291. IPropertyTree &querySet = querySets->query();
  292. if (querySet.hasProp("@updatedLibraries")) //only need to do this once, then publish and copy will keep up to date
  293. continue;
  294. Owned<IPropertyTreeIterator> queries = querySet.getElements("Query");
  295. ForEach(*queries)
  296. {
  297. IPropertyTree &query = queries->query();
  298. if (query.hasProp("@libCount"))
  299. continue;
  300. const char *wuid = query.queryProp("@wuid");
  301. if (!wuid || !*wuid)
  302. continue;
  303. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid);
  304. if (!cw)
  305. continue;
  306. checkAddLibrariesToQueryEntry(&query, cw);
  307. }
  308. querySet.setPropBool("@updatedLibraries", true);
  309. }
  310. }
  311. void CWsWorkunitsEx::init(IPropertyTree *cfg, const char *process, const char *service)
  312. {
  313. if (!daliClientActive())
  314. {
  315. OERRLOG("No Dali Connection Active.");
  316. throw MakeStringException(-1, "No Dali Connection Active. Please Specify a Dali to connect to in you configuration file");
  317. }
  318. DBGLOG("Initializing %s service [process = %s]", service, process);
  319. checkUpdateQuerysetLibraries();
  320. refreshValidClusters();
  321. daliServers.set(cfg->queryProp("Software/EspProcess/@daliServers"));
  322. const char *computer = cfg->queryProp("Software/EspProcess/@computer");
  323. if (daliServers.isEmpty() || !computer || streq(computer, "localhost")) //otherwise can't assume environment "." netAddresses are the same as my address
  324. queryHostIP().getIpText(envLocalAddress);
  325. else
  326. {
  327. //a bit weird, but other netAddresses in the environment are not the same localhost as this server
  328. //use the address of the DALI
  329. const char *finger = daliServers.get();
  330. while (*finger && !strchr(":;,", *finger))
  331. envLocalAddress.append(*finger++);
  332. }
  333. awusCacheMinutes = AWUS_CACHE_MIN_DEFAULT;
  334. VStringBuffer xpath("Software/EspProcess[@name=\"%s\"]/EspService[@name=\"%s\"]/AWUsCacheMinutes", process, service);
  335. cfg->getPropInt(xpath.str(), awusCacheMinutes);
  336. xpath.setf("Software/EspProcess[@name=\"%s\"]/@PageCacheTimeoutSeconds", process);
  337. if (cfg->hasProp(xpath.str()))
  338. setPageCacheTimeoutMilliSeconds(cfg->getPropInt(xpath.str()));
  339. xpath.setf("Software/EspProcess[@name=\"%s\"]/@MaxPageCacheItems", process);
  340. if (cfg->hasProp(xpath.str()))
  341. setMaxPageCacheItems(cfg->getPropInt(xpath.str()));
  342. xpath.setf("Software/EspProcess[@name=\"%s\"]/EspService[@name=\"%s\"]/serverForArchivedECLWU/@netAddress", process, service);
  343. if (cfg->hasProp(xpath.str()))
  344. {
  345. sashaServerIp.set(cfg->queryProp(xpath.str()));
  346. xpath.setf("Software/EspProcess[@name=\"%s\"]/EspService[@name=\"%s\"]/serverForArchivedECLWU/@port", process, service);
  347. sashaServerPort = cfg->getPropInt(xpath.str(), DEFAULT_SASHA_PORT);
  348. }
  349. xpath.setf("Software/EspProcess[@name=\"%s\"]/EspService[@name=\"%s\"]/ThorSlaveLogThreadPoolSize", process, service);
  350. thorSlaveLogThreadPoolSize = cfg->getPropInt(xpath, THOR_SLAVE_LOG_THREAD_POOL_SIZE);
  351. xpath.setf("Software/EspProcess[@name=\"%s\"]/EspService[@name=\"%s\"]/WUResultMaxSizeMB", process, service);
  352. unsigned wuResultMaxSizeMB = cfg->getPropInt(xpath);
  353. if (wuResultMaxSizeMB > 0)
  354. wuResultMaxSize = wuResultMaxSizeMB * 0x100000;
  355. xpath.setf("Software/EspProcess[@name=\"%s\"]/EspService[@name=\"%s\"]/ZAPEmail", process, service);
  356. IPropertyTree *zapEmail = cfg->queryPropTree(xpath.str());
  357. if (zapEmail)
  358. {
  359. zapEmailTo = zapEmail->queryProp("@to");
  360. if (zapEmailTo.isEmpty())
  361. throw MakeStringException(-1, "ZAPEmail: EmailTo not specified.");
  362. zapEmailFrom = zapEmail->queryProp("@from");
  363. if (zapEmailFrom.isEmpty())
  364. throw MakeStringException(-1, "ZAPEmail: EmailFrom not specified.");
  365. zapEmailServer = zapEmail->queryProp("@serverURL");
  366. if (zapEmailServer.isEmpty())
  367. throw MakeStringException(-1, "ZAPEmail: EmailServer not specified.");
  368. zapEmailServerPort = zapEmail->getPropInt("@serverPort", WUDEFAULT_ZAPEMAILSERVER_PORT);
  369. zapEmailMaxAttachmentSize = zapEmail->getPropInt("@maxAttachmentSize", MAX_ZAP_BUFFER_SIZE);
  370. }
  371. maxRequestEntityLength = cfg->getPropInt("Software[1]/EspProcess[1]/EspProtocol[@type='http_protocol'][1]/@maxRequestEntityLength");
  372. directories.set(cfg->queryPropTree("Software/Directories"));
  373. const char *name = cfg->queryProp("Software/EspProcess/@name");
  374. getConfigurationDirectory(directories, "query", "esp", name ? name : "esp", queryDirectory);
  375. recursiveCreateDirectory(queryDirectory.str());
  376. dataCache.setown(new DataCache(DATA_SIZE));
  377. archivedWuCache.setown(new ArchivedWuCache(AWUS_CACHE_SIZE));
  378. wuArchiveCache.setown(new WUArchiveCache(WUARCHIVE_CACHE_SIZE));
  379. //Create a folder for temporarily holding gzip files by WUResultBin()
  380. Owned<IFile> tmpdir = createIFile(TEMPZIPDIR);
  381. if(!tmpdir->exists())
  382. tmpdir->createDirectory();
  383. recursiveCreateDirectory(ESP_WORKUNIT_DIR);
  384. getConfigurationDirectory(directories, "data", "esp", process, dataDirectory);
  385. wuFactory.setown(getWorkUnitFactory());
  386. m_sched.start();
  387. filesInUse.subscribe();
  388. //Start thread pool
  389. xpath.setf("Software/EspProcess[@name=\"%s\"]/EspService[@name=\"%s\"]/ClusterQueryStateThreadPoolSize", process, service);
  390. Owned<CClusterQueryStateThreadFactory> threadFactory = new CClusterQueryStateThreadFactory();
  391. clusterQueryStatePool.setown(createThreadPool("CheckAndSetClusterQueryState Thread Pool", threadFactory, NULL,
  392. cfg->getPropInt(xpath.str(), CHECK_QUERY_STATUS_THREAD_POOL_SIZE)));
  393. }
  394. void CWsWorkunitsEx::refreshValidClusters()
  395. {
  396. validClusters.kill();
  397. #ifdef _CONTAINERIZED
  398. // discovered from generated cluster names
  399. Owned<IPropertyTreeIterator> iter = queryComponentConfig().getElements("queues");
  400. ForEach(*iter)
  401. {
  402. IPropertyTree &queue = iter->query();
  403. const char *qName = queue.queryProp("@name");
  404. bool* found = validClusters.getValue(qName);
  405. if (!found || !*found)
  406. {
  407. validClusters.setValue(qName, true);
  408. PROGLOG("adding valid cluster: %s", qName);
  409. }
  410. }
  411. #else
  412. Owned<IStringIterator> it = getTargetClusters(NULL, NULL);
  413. ForEach(*it)
  414. {
  415. SCMStringBuffer s;
  416. IStringVal &val = it->str(s);
  417. bool* found = validClusters.getValue(val.str());
  418. if (!found || !*found)
  419. validClusters.setValue(val.str(), true);
  420. }
  421. #endif
  422. }
  423. bool CWsWorkunitsEx::isValidCluster(const char *cluster)
  424. {
  425. if (!cluster || !*cluster)
  426. return false;
  427. CriticalBlock block(crit);
  428. bool* found = validClusters.getValue(cluster);
  429. if (found && *found)
  430. return true;
  431. if (validateTargetClusterName(cluster))
  432. {
  433. refreshValidClusters();
  434. return true;
  435. }
  436. return false;
  437. }
  438. bool CWsWorkunitsEx::onWUCreate(IEspContext &context, IEspWUCreateRequest &req, IEspWUCreateResponse &resp)
  439. {
  440. try
  441. {
  442. ensureWsCreateWorkunitAccess(context);
  443. NewWsWorkunit wu(context);
  444. resp.updateWorkunit().setWuid(wu->queryWuid());
  445. AuditSystemAccess(context.queryUserId(), true, "Updated %s", wu->queryWuid());
  446. }
  447. catch(IException* e)
  448. {
  449. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  450. }
  451. return true;
  452. }
  453. bool origValueChanged(const char *newValue, const char *origValue, StringBuffer &s, bool nillable)
  454. {
  455. if (!nillable && isEmpty(newValue))
  456. return false;
  457. if(newValue && origValue)
  458. {
  459. if (!streq(origValue, newValue))
  460. {
  461. s.append(newValue).trim();
  462. return true;
  463. }
  464. return false;
  465. }
  466. if (newValue)
  467. {
  468. s.append(newValue).trim();
  469. return true;
  470. }
  471. return (origValue!=NULL);
  472. }
  473. bool CWsWorkunitsEx::onWUUpdate(IEspContext &context, IEspWUUpdateRequest &req, IEspWUUpdateResponse &resp)
  474. {
  475. try
  476. {
  477. StringBuffer wuid(req.getWuid());
  478. WsWuHelpers::checkAndTrimWorkunit("WUUpdate", wuid);
  479. ensureWsWorkunitAccess(context, wuid.str(), SecAccess_Write);
  480. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  481. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  482. if(!cw)
  483. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT,"Cannot open workunit %s.",wuid.str());
  484. PROGLOG("WUUpdate: %s", wuid.str());
  485. if(req.getProtected() != req.getProtectedOrig())
  486. {
  487. cw->protect(req.getProtected());
  488. cw.clear();
  489. cw.setown(factory->openWorkUnit(wuid.str()));
  490. if(!cw)
  491. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT,"Cannot open workunit %s.",wuid.str());
  492. }
  493. if ((req.getState() == WUStateRunning)||(req.getState() == WUStateDebugPaused)||(req.getState() == WUStateDebugRunning))
  494. {
  495. WsWuInfo winfo(context, cw);
  496. winfo.getInfo(resp.updateWorkunit(), WUINFO_All);
  497. resp.setRedirectUrl(StringBuffer("/WsWorkunits/WUInfo?Wuid=").append(wuid).str());
  498. AuditSystemAccess(context.queryUserId(), true, "Updated %s", wuid.str());
  499. return true;
  500. }
  501. WorkunitUpdate wu(&cw->lock());
  502. if(!req.getState_isNull() && (req.getStateOrig_isNull() || req.getState() != req.getStateOrig()))
  503. {
  504. if (!req.getStateOrig_isNull() && cw->getState() != (WUState) req.getStateOrig())
  505. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT, "Cannot update workunit %s because its state has been changed internally. Please refresh the page and try again.", wuid.str());
  506. WUState state = (WUState) req.getState();
  507. if(state < WUStateSize)
  508. wu->setState(state);
  509. }
  510. StringBuffer s;
  511. if (origValueChanged(req.getJobname(), req.getJobnameOrig(), s))
  512. wu->setJobName(s.trim().str());
  513. if (origValueChanged(req.getDescription(), req.getDescriptionOrig(), s.clear()))
  514. wu->setDebugValue("description", (req.getDescription() && *req.getDescription()) ? s.trim().str() : NULL, true);
  515. double version = context.getClientVersion();
  516. if (version > 1.04)
  517. {
  518. if (origValueChanged(req.getClusterSelection(), req.getClusterOrig(), s.clear(), false))
  519. {
  520. if (!isValidCluster(s.str()))
  521. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid cluster name: %s", s.str());
  522. if (req.getState() == WUStateBlocked)
  523. switchWorkUnitQueue(wu.get(), s.str());
  524. else if ((req.getState() != WUStateSubmitted) && (req.getState() != WUStateRunning) && (req.getState() != WUStateDebugPaused) && (req.getState() != WUStateDebugRunning))
  525. wu->setClusterName(s.str());
  526. }
  527. }
  528. WsWuHelpers::setXmlParameters(wu, req.getXmlParams(), (req.getAction()==WUActionExecuteExisting));
  529. if (notEmpty(req.getQueryText()))
  530. {
  531. Owned<IWUQuery> query=wu->updateQuery();
  532. query->setQueryText(req.getQueryText());
  533. }
  534. if (version > 1.34 && notEmpty(req.getQueryMainDefinition()))
  535. {
  536. Owned<IWUQuery> query=wu->updateQuery();
  537. query->setQueryMainDefinition(req.getQueryMainDefinition());
  538. }
  539. if (!req.getResultLimit_isNull())
  540. wu->setResultLimit(req.getResultLimit());
  541. if (!req.getAction_isNull())
  542. {
  543. WUAction action = (WUAction) req.getAction();
  544. if(action < WUActionSize)
  545. wu->setAction(action);
  546. }
  547. if (!req.getPriorityClass_isNull())
  548. {
  549. WUPriorityClass priority = (WUPriorityClass) req.getPriorityClass();
  550. if(priority<PriorityClassSize)
  551. wu->setPriority(priority);
  552. }
  553. if (!req.getPriorityLevel_isNull())
  554. wu->setPriorityLevel(req.getPriorityLevel());
  555. if (origValueChanged(req.getScope(), req.getScopeOrig(), s.clear(), false))
  556. wu->setWuScope(s.str());
  557. ForEachItemIn(di, req.getDebugValues())
  558. {
  559. IConstDebugValue& item=req.getDebugValues().item(di);
  560. const char *debugName = item.getName();
  561. if (notEmpty(debugName))
  562. {
  563. StringBuffer expanded;
  564. if (*debugName=='-')
  565. debugName=expanded.append("eclcc").append(debugName).str();
  566. wu->setDebugValue(debugName, item.getValue(), true);
  567. }
  568. }
  569. ForEachItemIn(ai, req.getApplicationValues())
  570. {
  571. IConstApplicationValue& item=req.getApplicationValues().item(ai);
  572. if(notEmpty(item.getApplication()) && notEmpty(item.getName()))
  573. wu->setApplicationValue(item.getApplication(), item.getName(), item.getValue(), true);
  574. }
  575. wu->commit();
  576. wu.clear();
  577. WsWuInfo winfo(context, cw);
  578. winfo.getInfo(resp.updateWorkunit(), WUINFO_All);
  579. StringBuffer thorSlaveIP;
  580. if (version > 1.24 && notEmpty(req.getThorSlaveIP()))
  581. thorSlaveIP = req.getThorSlaveIP();
  582. if (thorSlaveIP.length() > 0)
  583. {
  584. StringBuffer url;
  585. url.appendf("/WsWorkunits/WUInfo?Wuid=%s&ThorSlaveIP=%s", wuid.str(), thorSlaveIP.str());
  586. resp.setRedirectUrl(url.str());
  587. }
  588. else
  589. resp.setRedirectUrl(StringBuffer("/WsWorkunits/WUInfo?Wuid=").append(wuid).str());
  590. AuditSystemAccess(context.queryUserId(), true, "Updated %s", wuid.str());
  591. }
  592. catch(IException* e)
  593. {
  594. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  595. }
  596. return true;
  597. }
  598. bool CWsWorkunitsEx::onWUCreateAndUpdate(IEspContext &context, IEspWUUpdateRequest &req, IEspWUUpdateResponse &resp)
  599. {
  600. try
  601. {
  602. const char* wuid = req.getWuid();
  603. if (!wuid || !*wuid)
  604. {
  605. ensureWsCreateWorkunitAccess(context);
  606. NewWsWorkunit wu(context);
  607. req.setWuid(wu->queryWuid());
  608. }
  609. }
  610. catch(IException* e)
  611. {
  612. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  613. }
  614. return onWUUpdate(context, req, resp);
  615. }
  616. static inline StringBuffer &appendUrlParameter(StringBuffer &url, const char *name, const char *value, bool &first)
  617. {
  618. if (notEmpty(value))
  619. {
  620. url.append(first ? '?' : '&').append(name).append('=').append(value);
  621. first=false;
  622. }
  623. return url;
  624. }
  625. bool CWsWorkunitsEx::onWUAction(IEspContext &context, IEspWUActionRequest &req, IEspWUActionResponse &resp)
  626. {
  627. try
  628. {
  629. CECLWUActions action;
  630. double version = context.getClientVersion();
  631. if (version >= 1.57)
  632. action = req.getWUActionType();
  633. else
  634. action = eclWUActionType.toEnum(req.getActionType());
  635. if (action == ECLWUActions_Undefined)
  636. throw MakeStringException(ECLWATCH_INVALID_INPUT,"Action not defined.");
  637. Owned<IProperties> params = createProperties(true);
  638. params->setProp("BlockTillFinishTimer", req.getBlockTillFinishTimer());
  639. if (((action == CECLWUActions_Restore) || (action == CECLWUActions_Archive)) && !sashaServerIp.isEmpty())
  640. {
  641. params->setProp("sashaServerIP", sashaServerIp.get());
  642. params->setProp("sashaServerPort", sashaServerPort);
  643. }
  644. IArrayOf<IConstWUActionResult> results;
  645. if (doAction(context, req.getWuids(), action, params, &results) && (action != CECLWUActions_Delete) && checkRedirect(context))
  646. {
  647. StringBuffer redirect;
  648. if(req.getPageFrom() && strieq(req.getPageFrom(), "wuid"))
  649. redirect.append("/WsWorkunits/WUInfo?Wuid=").append(req.getWuids().item(0));
  650. else if (req.getPageFrom() && strieq(req.getPageFrom(), "scheduler"))
  651. {
  652. redirect.set("/WsWorkunits/WUShowScheduled");
  653. bool first=true;
  654. appendUrlParameter(redirect, "Cluster", req.getEventServer(), first);
  655. appendUrlParameter(redirect, "EventName", req.getEventName(), first);
  656. }
  657. else
  658. {
  659. redirect.append("/WsWorkunits/WUQuery");
  660. bool first=true;
  661. appendUrlParameter(redirect, "PageSize", req.getPageSize(), first);
  662. appendUrlParameter(redirect, "PageStartFrom", req.getCurrentPage(), first);
  663. appendUrlParameter(redirect, "Sortby", req.getSortby(), first);
  664. appendUrlParameter(redirect, "Descending", req.getDescending() ? "1" : "0", first);
  665. appendUrlParameter(redirect, "State", req.getState(), first);
  666. appendUrlParameter(redirect, "Cluster", req.getCluster(), first);
  667. appendUrlParameter(redirect, "Owner", req.getOwner(), first);
  668. appendUrlParameter(redirect, "StartDate", req.getStartDate(), first);
  669. appendUrlParameter(redirect, "EndDate", req.getEndDate(), first);
  670. appendUrlParameter(redirect, "ECL", req.getECL(), first);
  671. appendUrlParameter(redirect, "Jobname", req.getJobname(), first);
  672. }
  673. resp.setRedirectUrl(redirect.str());
  674. }
  675. else
  676. resp.setActionResults(results);
  677. }
  678. catch(IException* e)
  679. {
  680. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  681. }
  682. return true;
  683. }
  684. bool CWsWorkunitsEx::onWUDelete(IEspContext &context, IEspWUDeleteRequest &req, IEspWUDeleteResponse &resp)
  685. {
  686. try
  687. {
  688. IArrayOf<IConstWUActionResult> results;
  689. Owned<IProperties> params = createProperties(true);
  690. params->setProp("BlockTillFinishTimer", req.getBlockTillFinishTimer());
  691. if (!doAction(context,req.getWuids(), CECLWUActions_Delete, params, &results))
  692. resp.setActionResults(results);
  693. }
  694. catch(IException* e)
  695. {
  696. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  697. }
  698. return true;
  699. }
  700. bool CWsWorkunitsEx::onWUAbort(IEspContext &context, IEspWUAbortRequest &req, IEspWUAbortResponse &resp)
  701. {
  702. try
  703. {
  704. IArrayOf<IConstWUActionResult> results;
  705. Owned<IProperties> params = createProperties(true);
  706. params->setProp("BlockTillFinishTimer", req.getBlockTillFinishTimer());
  707. if (!doAction(context,req.getWuids(), CECLWUActions_Abort, params, &results))
  708. resp.setActionResults(results);
  709. }
  710. catch(IException* e)
  711. {
  712. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  713. }
  714. return true;
  715. }
  716. bool CWsWorkunitsEx::onWUProtect(IEspContext &context, IEspWUProtectRequest &req, IEspWUProtectResponse &resp)\
  717. {
  718. try
  719. {
  720. IArrayOf<IConstWUActionResult> results;
  721. Owned<IProperties> params(createProperties(true));
  722. params->setProp("BlockTillFinishTimer", 0);
  723. CECLWUActions action = req.getProtect() ? CECLWUActions_Protect : CECLWUActions_Unprotect;
  724. if (!doAction(context,req.getWuids(), action, params, &results))
  725. resp.setActionResults(results);
  726. }
  727. catch(IException* e)
  728. {
  729. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  730. }
  731. return true;
  732. }
  733. bool CWsWorkunitsEx::onWUResubmit(IEspContext &context, IEspWUResubmitRequest &req, IEspWUResubmitResponse &resp)
  734. {
  735. try
  736. {
  737. Owned<IMultiException> me = MakeMultiException();
  738. StringAttr wuid;
  739. StringArray wuids;
  740. double version = context.getClientVersion();
  741. IArrayOf<IEspResubmittedWU> resubmittedWUs;
  742. for(aindex_t i=0; i<req.getWuids().length();i++)
  743. {
  744. StringBuffer requestWuid(req.getWuids().item(i));
  745. WsWuHelpers::checkAndTrimWorkunit("WUResubmit", requestWuid);
  746. ensureWsWorkunitAccess(context, requestWuid.str(), SecAccess_Write);
  747. PROGLOG("WUResubmit: %s", requestWuid.str());
  748. wuid.set(requestWuid.str());
  749. try
  750. {
  751. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  752. if(req.getCloneWorkunit() || req.getRecompile())
  753. {
  754. Owned<IConstWorkUnit> src(factory->openWorkUnit(wuid.str()));
  755. NewWsWorkunit wu(factory, context);
  756. wuid.set(wu->queryWuid());
  757. queryExtendedWU(wu)->copyWorkUnit(src, false, false);
  758. }
  759. wuids.append(wuid.str());
  760. Owned<IConstWorkUnit> cw(factory->openWorkUnit(wuid.str()));
  761. if(!cw)
  762. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot open workunit %s.",wuid.str());
  763. WsWuHelpers::submitWsWorkunit(context, cw, NULL, NULL, 0, req.getRecompile(), req.getResetWorkflow(), false);
  764. if (version < 1.40)
  765. continue;
  766. Owned<IEspResubmittedWU> resubmittedWU = createResubmittedWU();
  767. resubmittedWU->setWUID(wuid.str());
  768. if (!streq(requestWuid.str(), wuid.str()))
  769. resubmittedWU->setParentWUID(requestWuid.str());
  770. resubmittedWUs.append(*resubmittedWU.getClear());
  771. }
  772. catch (IException *E)
  773. {
  774. me->append(*E);
  775. }
  776. catch (...)
  777. {
  778. me->append(*MakeStringException(0,"Unknown exception submitting %s",wuid.str()));
  779. }
  780. }
  781. if(me->ordinality())
  782. throw me.getLink();
  783. int timeToWait = req.getBlockTillFinishTimer();
  784. if (timeToWait != 0)
  785. {
  786. for(aindex_t i=0; i<wuids.length(); i++)
  787. waitForWorkUnitToComplete(wuids.item(i), timeToWait);
  788. }
  789. if (version >= 1.40)
  790. resp.setWUs(resubmittedWUs);
  791. if(wuids.length()==1)
  792. {
  793. resp.setRedirectUrl(StringBuffer("/WsWorkunits/WUInfo?Wuid=").append(wuids.item(0)));
  794. }
  795. }
  796. catch(IException* e)
  797. {
  798. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  799. }
  800. return true;
  801. }
  802. bool CWsWorkunitsEx::onWUPushEvent(IEspContext &context, IEspWUPushEventRequest &req, IEspWUPushEventResponse &resp)
  803. {
  804. try
  805. {
  806. const char *name = req.getEventName();
  807. const char *text = req.getEventText();
  808. const char *target = NULL;
  809. if (notEmpty(name) && notEmpty(text))
  810. {
  811. PROGLOG("WUPushEvent: EventName %s, EventText %s", name, text);
  812. Owned<IScheduleEventPusher> pusher(getScheduleEventPusher());
  813. pusher->push(name, text, target);
  814. StringBuffer redirect("/WsWorkunits/WUShowScheduled");
  815. bool first=true;
  816. appendUrlParameter(redirect, "PushEventName", name, first);
  817. appendUrlParameter(redirect, "PushEventText", text, first);
  818. resp.setRedirectUrl(redirect.str());
  819. return true;
  820. }
  821. }
  822. catch(IException* e)
  823. {
  824. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  825. }
  826. return false;
  827. }
  828. bool CWsWorkunitsEx::onWUSchedule(IEspContext &context, IEspWUScheduleRequest &req, IEspWUScheduleResponse &resp)
  829. {
  830. try
  831. {
  832. StringBuffer wuid(req.getWuid());
  833. WsWuHelpers::checkAndTrimWorkunit("WUSchedule", wuid);
  834. const char* cluster = req.getCluster();
  835. if (isEmpty(cluster))
  836. throw MakeStringException(ECLWATCH_INVALID_INPUT,"No Cluster defined.");
  837. if (!isValidCluster(cluster))
  838. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid cluster name: %s", cluster);
  839. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  840. WorkunitUpdate wu(factory->updateWorkUnit(wuid.str()));
  841. ensureWsWorkunitAccess(context, *wu.get(), SecAccess_Write);
  842. switch(wu->getState())
  843. {
  844. case WUStateDebugPaused:
  845. case WUStateDebugRunning:
  846. case WUStateRunning:
  847. case WUStateAborting:
  848. case WUStateBlocked:
  849. throw MakeStringException(ECLWATCH_CANNOT_SCHEDULE_WORKUNIT, "Cannot schedule the workunit. Workunit state is '%s'.", wu->queryStateDesc());
  850. }
  851. PROGLOG("WUSchedule: %s", wuid.str());
  852. wu->clearExceptions();
  853. wu->setClusterName(cluster);
  854. if (notEmpty(req.getWhen()))
  855. {
  856. WsWuDateTime dt;
  857. dt.setString(req.getWhen());
  858. wu->setTimeScheduled(dt);
  859. }
  860. if(notEmpty(req.getSnapshot()))
  861. wu->setSnapshot(req.getSnapshot());
  862. wu->setState(WUStateScheduled);
  863. if (req.getMaxRunTime())
  864. wu->setDebugValueInt("maxRunTime", req.getMaxRunTime(), true);
  865. AuditSystemAccess(context.queryUserId(), true, "Scheduled %s", wuid.str());
  866. }
  867. catch(IException* e)
  868. {
  869. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  870. }
  871. return true;
  872. }
  873. bool CWsWorkunitsEx::onWUSubmit(IEspContext &context, IEspWUSubmitRequest &req, IEspWUSubmitResponse &resp)
  874. {
  875. try
  876. {
  877. StringBuffer wuid(req.getWuid());
  878. WsWuHelpers::checkAndTrimWorkunit("WUSubmit", wuid);
  879. const char *cluster = req.getCluster();
  880. if (isEmpty(cluster))
  881. throw MakeStringException(ECLWATCH_INVALID_INPUT,"No Cluster defined.");
  882. if (!isValidCluster(cluster))
  883. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid cluster name: %s", cluster);
  884. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  885. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  886. if(!cw)
  887. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot open workunit %s.",wuid.str());
  888. ensureWsWorkunitAccess(context, *cw, SecAccess_Full);
  889. if (cw->getAction()==WUActionExecuteExisting)
  890. {
  891. ExecuteExistingQueryInfo info(cw);
  892. if (info.queryset.isEmpty() || info.query.isEmpty())
  893. {
  894. WorkunitUpdate wu(&cw->lock());
  895. throw WsWuHelpers::noteException(wu, MakeStringException(ECLWATCH_INVALID_INPUT,"Queryset and/or query not specified"));
  896. }
  897. WsWuHelpers::runWsWuQuery(context, cw, info.queryset.str(), info.query.str(), cluster, NULL);
  898. }
  899. else
  900. WsWuHelpers::submitWsWorkunit(context, cw, cluster, req.getSnapshot(), req.getMaxRunTime(), true, false, false);
  901. PROGLOG("WUSubmit: %s", wuid.str());
  902. if (req.getBlockTillFinishTimer() != 0)
  903. waitForWorkUnitToComplete(wuid.str(), req.getBlockTillFinishTimer());
  904. resp.setRedirectUrl(StringBuffer("/WsWorkunits/WUInfo?Wuid=").append(wuid).str());
  905. }
  906. catch(IException* e)
  907. {
  908. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  909. }
  910. return true;
  911. }
  912. ErrorSeverity checkGetExceptionSeverity(CWUExceptionSeverity severity)
  913. {
  914. switch (severity)
  915. {
  916. case CWUExceptionSeverity_INFO:
  917. return SeverityInformation;
  918. case CWUExceptionSeverity_WARNING:
  919. return SeverityWarning;
  920. case CWUExceptionSeverity_ERROR:
  921. return SeverityError;
  922. case CWUExceptionSeverity_ALERT:
  923. return SeverityAlert;
  924. }
  925. throw MakeStringExceptionDirect(ECLWATCH_INVALID_INPUT,"invalid exception severity");
  926. }
  927. bool CWsWorkunitsEx::onWURun(IEspContext &context, IEspWURunRequest &req, IEspWURunResponse &resp)
  928. {
  929. try
  930. {
  931. const char *cluster = req.getCluster();
  932. if (notEmpty(cluster) && !isValidCluster(cluster))
  933. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid cluster name: %s", cluster);
  934. StringBuffer wuidStr(req.getWuid());
  935. const char* runWuid = wuidStr.trim().str();
  936. StringBuffer wuid;
  937. ErrorSeverity severity = checkGetExceptionSeverity(req.getExceptionSeverity());
  938. if (runWuid && *runWuid)
  939. {
  940. if (!looksLikeAWuid(runWuid, 'W'))
  941. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid Workunit ID: %s", runWuid);
  942. ensureWsWorkunitAccess(context, runWuid, SecAccess_Full);
  943. PROGLOG("WURun: %s", runWuid);
  944. if (req.getCloneWorkunit())
  945. WsWuHelpers::runWsWorkunit(context, wuid, runWuid, cluster, req.getInput(), &req.getVariables(),
  946. &req.getDebugValues(), &req.getApplicationValues());
  947. else
  948. {
  949. WsWuHelpers::submitWsWorkunit(context, runWuid, cluster, NULL, 0, false, true, true, req.getInput(),
  950. &req.getVariables(), &req.getDebugValues(), &req.getApplicationValues());
  951. wuid.set(runWuid);
  952. }
  953. }
  954. else if (notEmpty(req.getQuerySet()) && notEmpty(req.getQuery()))
  955. {
  956. PROGLOG("WURun: QuerySet %s, Query %s", req.getQuerySet(), req.getQuery());
  957. WsWuHelpers::runWsWuQuery(context, wuid, req.getQuerySet(), req.getQuery(), cluster, req.getInput(),
  958. &req.getApplicationValues());
  959. }
  960. else
  961. throw MakeStringException(ECLWATCH_MISSING_PARAMS,"Workunit or Query required");
  962. int timeToWait = req.getWait();
  963. if (timeToWait != 0)
  964. waitForWorkUnitToComplete(wuid.str(), timeToWait);
  965. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  966. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  967. if (!cw)
  968. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT,"Cannot open workunit %s.", wuid.str());
  969. resp.setState(cw->queryStateDesc());
  970. resp.setWuid(wuid.str());
  971. switch (cw->getState())
  972. {
  973. case WUStateCompleted:
  974. case WUStateFailed:
  975. case WUStateUnknown:
  976. {
  977. SCMStringBuffer result;
  978. unsigned flags = WorkUnitXML_SeverityTags;
  979. if (req.getNoRootTag())
  980. flags |= WorkUnitXML_NoRoot;
  981. getFullWorkUnitResultsXML(context.queryUserId(), context.queryPassword(), cw.get(), result, flags, severity);
  982. resp.setResults(result.str());
  983. break;
  984. }
  985. default:
  986. break;
  987. }
  988. }
  989. catch(IException* e)
  990. {
  991. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  992. }
  993. return true;
  994. }
  995. bool CWsWorkunitsEx::onWUFullResult(IEspContext &context, IEspWUFullResultRequest &req, IEspWUFullResultResponse &resp)
  996. {
  997. try
  998. {
  999. StringBuffer wuid(req.getWuid());
  1000. WsWuHelpers::checkAndTrimWorkunit("WUFullResult", wuid);
  1001. ErrorSeverity severity = checkGetExceptionSeverity(req.getExceptionSeverity());
  1002. if (!wuid.length())
  1003. throw MakeStringException(ECLWATCH_MISSING_PARAMS,"Workunit or Query required");
  1004. if (!looksLikeAWuid(wuid, 'W'))
  1005. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid Workunit ID: %s", wuid.str());
  1006. PROGLOG("WUFullResults: %s", wuid.str());
  1007. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1008. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  1009. if (!cw)
  1010. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot open workunit %s.", wuid.str());
  1011. ensureWsWorkunitAccess(context, *cw, SecAccess_Read);
  1012. resp.setWuid(wuid.str());
  1013. switch (cw->getState())
  1014. {
  1015. case WUStateCompleted:
  1016. case WUStateFailed:
  1017. case WUStateUnknown:
  1018. {
  1019. SCMStringBuffer result;
  1020. unsigned flags = WorkUnitXML_SeverityTags;
  1021. if (req.getNoRootTag())
  1022. flags |= WorkUnitXML_NoRoot;
  1023. if (context.getResponseFormat()==ESPSerializationJSON)
  1024. getFullWorkUnitResultsJSON(context.queryUserId(), context.queryPassword(), cw.get(), result, flags, severity);
  1025. else
  1026. getFullWorkUnitResultsXML(context.queryUserId(), context.queryPassword(), cw.get(), result, flags, severity);
  1027. resp.setResults(result.str());
  1028. break;
  1029. }
  1030. default:
  1031. throw MakeStringException(ECLWATCH_CANNOT_GET_WU_RESULT, "Cannot get results Workunit %s %s.", wuid.str(), getWorkunitStateStr(cw->getState()));
  1032. }
  1033. }
  1034. catch(IException* e)
  1035. {
  1036. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1037. }
  1038. return true;
  1039. }
  1040. bool CWsWorkunitsEx::onWUWaitCompiled(IEspContext &context, IEspWUWaitRequest &req, IEspWUWaitResponse &resp)
  1041. {
  1042. try
  1043. {
  1044. StringBuffer wuid(req.getWuid());
  1045. WsWuHelpers::checkAndTrimWorkunit("WUWaitCompiled", wuid);
  1046. ensureWsWorkunitAccess(context, wuid.str(), SecAccess_Full);
  1047. PROGLOG("WUWaitCompiled: %s", wuid.str());
  1048. secWaitForWorkUnitToCompile(wuid.str(), *context.querySecManager(), *context.queryUser(), req.getWait());
  1049. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1050. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  1051. if(!cw)
  1052. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot open workunit %s.",wuid.str());
  1053. resp.setStateID(cw->getState());
  1054. }
  1055. catch(IException* e)
  1056. {
  1057. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1058. }
  1059. return true;
  1060. }
  1061. bool CWsWorkunitsEx::onWUWaitComplete(IEspContext &context, IEspWUWaitRequest &req, IEspWUWaitResponse &resp)
  1062. {
  1063. try
  1064. {
  1065. StringBuffer wuid(req.getWuid());
  1066. WsWuHelpers::checkAndTrimWorkunit("WUWaitComplete", wuid);
  1067. ensureWsWorkunitAccess(context, wuid.str(), SecAccess_Full);
  1068. PROGLOG("WUWaitComplete: %s", wuid.str());
  1069. std::list<WUState> expectedStates;
  1070. if (req.getReturnOnWait())
  1071. expectedStates.push_back(WUStateWait);
  1072. resp.setStateID(secWaitForWorkUnitToComplete(wuid.str(), *context.querySecManager(), *context.queryUser(), req.getWait(), expectedStates));
  1073. }
  1074. catch(IException* e)
  1075. {
  1076. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1077. }
  1078. return true;
  1079. }
  1080. bool CWsWorkunitsEx::onWUCDebug(IEspContext &context, IEspWUDebugRequest &req, IEspWUDebugResponse &resp)
  1081. {
  1082. try
  1083. {
  1084. StringBuffer wuid(req.getWuid());
  1085. WsWuHelpers::checkAndTrimWorkunit("WUCDebug", wuid);
  1086. ensureWsWorkunitAccess(context, wuid.str(), SecAccess_Full);
  1087. PROGLOG("WUCDebug: %s", wuid.str());
  1088. StringBuffer result;
  1089. secDebugWorkunit(wuid.str(), *context.querySecManager(), *context.queryUser(), req.getCommand(), result);
  1090. resp.setResult(result);
  1091. }
  1092. catch(IException* e)
  1093. {
  1094. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1095. }
  1096. return true;
  1097. }
  1098. bool CWsWorkunitsEx::onWUSyntaxCheckECL(IEspContext &context, IEspWUSyntaxCheckRequest &req, IEspWUSyntaxCheckResponse &resp)
  1099. {
  1100. try
  1101. {
  1102. ensureWsCreateWorkunitAccess(context);
  1103. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1104. NewWsWorkunit wu(factory, context);
  1105. wu->setAction(WUActionCheck);
  1106. if(notEmpty(req.getModuleName()) && notEmpty(req.getAttributeName()))
  1107. {
  1108. wu->setApplicationValue("SyntaxCheck", "ModuleName", req.getModuleName(), true);
  1109. wu->setApplicationValue("SyntaxCheck", "AttributeName", req.getAttributeName(), true);
  1110. }
  1111. ForEachItemIn(di, req.getDebugValues())
  1112. {
  1113. IConstDebugValue& item=req.getDebugValues().item(di);
  1114. const char *debugName = item.getName();
  1115. if (notEmpty(debugName))
  1116. {
  1117. StringBuffer expanded;
  1118. if (*debugName=='-')
  1119. debugName=expanded.append("eclcc").append(debugName).str();
  1120. wu->setDebugValue(debugName, item.getValue(), true);
  1121. }
  1122. }
  1123. wu.setQueryText(req.getECL());
  1124. StringAttr wuid(wu->queryWuid()); // NB queryWuid() not valid after workunit,clear()
  1125. wu->commit();
  1126. wu.clear();
  1127. WsWuHelpers::submitWsWorkunit(context, wuid.str(), req.getCluster(), req.getSnapshot(), 0, true, false, false);
  1128. waitForWorkUnitToComplete(wuid.str(), req.getTimeToWait());
  1129. Owned<IConstWorkUnit> cw(factory->openWorkUnit(wuid.str()));
  1130. WsWUExceptions errors(*cw);
  1131. resp.setErrors(errors);
  1132. StringBuffer msg;
  1133. WUState st = cw->getState();
  1134. cw.clear();
  1135. switch (st)
  1136. {
  1137. case WUStateAborted:
  1138. case WUStateCompleted:
  1139. case WUStateFailed:
  1140. factory->deleteWorkUnitEx(wuid.str(), true);
  1141. break;
  1142. default:
  1143. abortWorkUnit(wuid.str(), context.querySecManager(), context.queryUser());
  1144. if (!factory->deleteWorkUnit(wuid.str()))
  1145. {
  1146. throw MakeStringException(ECLWATCH_CANNOT_DELETE_WORKUNIT,
  1147. "WUSyntaxCheckECL has timed out. Workunit %s cannot be deleted now. You may delete it when its status changes.", wuid.str());
  1148. }
  1149. if (context.getClientVersion() < 1.57)
  1150. throw MakeStringException(ECLWATCH_CANNOT_DELETE_WORKUNIT, "WUSyntaxCheckECL has timed out.");
  1151. resp.setMessage("WUSyntaxCheckECL has timed out.");
  1152. break;
  1153. }
  1154. }
  1155. catch(IException* e)
  1156. {
  1157. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1158. }
  1159. return true;
  1160. }
  1161. bool CWsWorkunitsEx::onWUCompileECL(IEspContext &context, IEspWUCompileECLRequest &req, IEspWUCompileECLResponse &resp)
  1162. {
  1163. try
  1164. {
  1165. ensureWsCreateWorkunitAccess(context);
  1166. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1167. NewWsWorkunit wu(factory, context);
  1168. if(req.getIncludeComplexity())
  1169. {
  1170. wu->setAction(WUActionCompile);
  1171. wu->setDebugValueInt("calculateComplexity",1,true);
  1172. }
  1173. else
  1174. wu->setAction(WUActionCheck);
  1175. if(req.getModuleName() && req.getAttributeName())
  1176. {
  1177. wu->setApplicationValue("SyntaxCheck","ModuleName",req.getModuleName(),true);
  1178. wu->setApplicationValue("SyntaxCheck","AttributeName",req.getAttributeName(),true);
  1179. }
  1180. if(req.getIncludeDependencies())
  1181. wu->setApplicationValueInt("SyntaxCheck","IncludeDependencies",1,true);
  1182. wu.setQueryText(req.getECL());
  1183. StringAttr wuid(wu->queryWuid()); // NB queryWuid() not valid after workunit,clear() StringAttr wuid(wu->queryWuid());
  1184. WsWuHelpers::submitWsWorkunit(context, wuid.str(), req.getCluster(), req.getSnapshot(), 0, true, false, false);
  1185. waitForWorkUnitToComplete(wuid.str(),req.getTimeToWait());
  1186. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  1187. SCMStringBuffer s;
  1188. cw->getDebugValue("__Calculated__Complexity__",s);
  1189. if(s.length())
  1190. resp.setComplexity(s.str());
  1191. WsWUExceptions errors(*cw);
  1192. resp.setErrors(errors);
  1193. if(!errors.ErrCount())
  1194. {
  1195. IArrayOf<IEspWUECLAttribute> dependencies;
  1196. for(unsigned count=1;;count++)
  1197. {
  1198. SCMStringBuffer xml;
  1199. cw->getApplicationValue("SyntaxCheck",StringBuffer("Dependency").append(count).str(),xml);
  1200. if(!xml.length())
  1201. break;
  1202. Owned<IPropertyTree> dep=createPTreeFromXMLString(xml.str(), ipt_caseInsensitive);
  1203. if(!dep)
  1204. continue;
  1205. Owned<IEspWUECLAttribute> att = createWUECLAttribute("","");
  1206. att->setModuleName(dep->queryProp("@module"));
  1207. att->setAttributeName(dep->queryProp("@name"));
  1208. int flags = dep->getPropInt("@flags",0);
  1209. if(flags & ob_locked)
  1210. {
  1211. if(flags & ob_lockedself)
  1212. att->setIsCheckedOut(true);
  1213. else
  1214. att->setIsLocked(true);
  1215. }
  1216. if(flags & ob_sandbox)
  1217. att->setIsSandbox(true);
  1218. if(flags & ob_orphaned)
  1219. att->setIsOrphaned(true);
  1220. dependencies.append(*att.getLink());
  1221. }
  1222. resp.setDependencies(dependencies);
  1223. }
  1224. cw.clear();
  1225. factory->deleteWorkUnitEx(wuid.str(), true);
  1226. }
  1227. catch(IException* e)
  1228. {
  1229. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1230. }
  1231. return true;
  1232. }
  1233. bool CWsWorkunitsEx::onWUGetDependancyTrees(IEspContext& context, IEspWUGetDependancyTreesRequest& req, IEspWUGetDependancyTreesResponse& resp)
  1234. {
  1235. try
  1236. {
  1237. ensureWsCreateWorkunitAccess(context);
  1238. unsigned int timeMilliSec = 500;
  1239. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1240. NewWsWorkunit wu(factory, context);
  1241. wu->setAction(WUActionCheck);
  1242. if (notEmpty(req.getCluster()))
  1243. wu->setClusterName(req.getCluster());
  1244. if (notEmpty(req.getSnapshot()))
  1245. wu->setSnapshot(req.getSnapshot());
  1246. wu->setDebugValue("gatherDependenciesSelection",notEmpty(req.getItems()) ? req.getItems() : NULL,true);
  1247. if (context.getClientVersion() > 1.12)
  1248. {
  1249. wu->setDebugValueInt("gatherDependencies", 1, true);
  1250. const char *timeout = req.getTimeoutMilliSec();
  1251. if (notEmpty(timeout))
  1252. {
  1253. const char *finger = timeout;
  1254. while (*finger)
  1255. {
  1256. if (!isdigit(*finger++))
  1257. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Incorrect timeout value");
  1258. }
  1259. timeMilliSec = atol(timeout);
  1260. }
  1261. }
  1262. StringAttr wuid(wu->queryWuid()); // NB queryWuid() not valid after workunit,clear()
  1263. wu->commit();
  1264. wu.clear();
  1265. WsWuHelpers::submitWsWorkunit(context, wuid.str(), req.getCluster(), req.getSnapshot(), 0, true, false, false);
  1266. int state = waitForWorkUnitToComplete(wuid.str(), timeMilliSec);
  1267. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  1268. WsWUExceptions errors(*cw);
  1269. resp.setErrors(errors);
  1270. MemoryBuffer temp;
  1271. MemoryBuffer2IDataVal xmlresult(temp);
  1272. Owned<IConstWUResult> result = cw->getResultBySequence(0);
  1273. if (result)
  1274. {
  1275. result->getResultRaw(xmlresult, NULL, NULL);
  1276. resp.setDependancyTrees(temp);
  1277. }
  1278. wu.setown(&cw->lock());
  1279. wu->setState(WUStateAborted);
  1280. wu->commit();
  1281. wu.clear();
  1282. factory->deleteWorkUnitEx(wuid.str(), true);
  1283. }
  1284. catch(IException* e)
  1285. {
  1286. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1287. }
  1288. return true;
  1289. }
  1290. bool getWsWuInfoFromSasha(IEspContext &context, SocketEndpoint &ep, const char* wuid, IEspECLWorkunit *info)
  1291. {
  1292. Owned<INode> node = createINode(ep);
  1293. Owned<ISashaCommand> cmd = createSashaCommand();
  1294. cmd->addId(wuid);
  1295. cmd->setAction(SCA_GET);
  1296. if (!cmd->send(node, 1*60*1000))
  1297. {
  1298. StringBuffer url;
  1299. throw MakeStringException(ECLWATCH_CANNOT_CONNECT_ARCHIVE_SERVER,
  1300. "Sasha (%s) took too long to respond from: Get information for %s.",
  1301. ep.getUrlStr(url).str(), wuid);
  1302. }
  1303. if (cmd->numIds()==0)
  1304. {
  1305. DBGLOG("Could not read archived workunit %s",wuid);
  1306. throw MakeStringException(ECLWATCH_CANNOT_GET_WORKUNIT,"Cannot read workunit %s.",wuid);
  1307. }
  1308. unsigned num = cmd->numResults();
  1309. if (num < 1)
  1310. return false;
  1311. StringBuffer res;
  1312. cmd->getResult(0, res);
  1313. if(res.length() < 1)
  1314. return false;
  1315. Owned<IPropertyTree> wpt = createPTreeFromXMLString(res.str());
  1316. if (!wpt)
  1317. return false;
  1318. const char * owner = wpt->queryProp("@submitID");
  1319. ensureWsWorkunitAccessByOwnerId(context, owner, SecAccess_Read);
  1320. PROGLOG("GetArchivedWUInfo: %s", wuid);
  1321. info->setWuid(wuid);
  1322. info->setArchived(true);
  1323. if (notEmpty(owner))
  1324. info->setOwner(owner);
  1325. const char * state = wpt->queryProp("@state");
  1326. if (notEmpty(state))
  1327. info->setState(state);
  1328. const char * cluster = wpt->queryProp("@clusterName");
  1329. if (notEmpty(cluster))
  1330. info->setCluster(cluster);
  1331. if (context.querySecManager())
  1332. {
  1333. const char * scope = wpt->queryProp("@scope");
  1334. if (notEmpty(scope))
  1335. info->setScope(scope);
  1336. }
  1337. const char * jobName = wpt->queryProp("@jobName");
  1338. if (notEmpty(jobName))
  1339. info->setJobname(jobName);
  1340. const char * description = wpt->queryProp("Debug/description");
  1341. if (notEmpty(description))
  1342. info->setDescription(description);
  1343. const char * queryText = wpt->queryProp("Query/Text");
  1344. if (notEmpty(queryText))
  1345. info->updateQuery().setText(queryText);
  1346. const char * protectedWU = wpt->queryProp("@protected");
  1347. info->setProtected((protectedWU && *protectedWU!='0'));
  1348. return true;
  1349. }
  1350. #define WUDETAILS_REFRESH_MINS 1
  1351. void getArchivedWUInfo(IEspContext &context, const char* sashaServerIP, unsigned sashaServerPort, const char *wuid, IEspWUInfoResponse &resp)
  1352. {
  1353. SocketEndpoint ep;
  1354. if (sashaServerIP && *sashaServerIP)
  1355. ep.set(sashaServerIP, sashaServerPort);
  1356. else
  1357. getSashaNode(ep);
  1358. if (getWsWuInfoFromSasha(context, ep, wuid, &resp.updateWorkunit()))
  1359. {
  1360. resp.setCanCompile(false);
  1361. return;
  1362. }
  1363. throw MakeStringException(ECLWATCH_CANNOT_GET_WORKUNIT, "Cannot find workunit %s.", wuid);
  1364. return;
  1365. }
  1366. #define WUDETAILS_REFRESH_MINS 1
  1367. bool CWsWorkunitsEx::onWUInfo(IEspContext &context, IEspWUInfoRequest &req, IEspWUInfoResponse &resp)
  1368. {
  1369. try
  1370. {
  1371. StringBuffer wuid(req.getWuid());
  1372. WsWuHelpers::checkAndTrimWorkunit("WUInfo", wuid);
  1373. double version = context.getClientVersion();
  1374. if (req.getType() && strieq(req.getType(), "archived workunits"))
  1375. getArchivedWUInfo(context, sashaServerIp.get(), sashaServerPort, wuid.str(), resp);
  1376. else
  1377. {
  1378. try
  1379. {
  1380. //The access is checked here because getArchivedWUInfo() has its own access check.
  1381. ensureWsWorkunitAccess(context, wuid.str(), SecAccess_Read);
  1382. unsigned long flags=0;
  1383. if (req.getTruncateEclTo64k())
  1384. flags|=WUINFO_TruncateEclTo64k;
  1385. if (req.getIncludeExceptions())
  1386. flags|=WUINFO_IncludeExceptions;
  1387. if (req.getIncludeGraphs())
  1388. flags|=WUINFO_IncludeGraphs;
  1389. if (req.getIncludeSourceFiles())
  1390. flags|=WUINFO_IncludeSourceFiles;
  1391. if (req.getIncludeResults())
  1392. flags|=WUINFO_IncludeResults;
  1393. if (req.getIncludeVariables())
  1394. flags|=WUINFO_IncludeVariables;
  1395. if (req.getIncludeTimers())
  1396. flags|=WUINFO_IncludeTimers;
  1397. if (req.getIncludeDebugValues())
  1398. flags|=WUINFO_IncludeDebugValues;
  1399. if (req.getIncludeApplicationValues())
  1400. flags|=WUINFO_IncludeApplicationValues;
  1401. if (req.getIncludeWorkflows())
  1402. flags|=WUINFO_IncludeWorkflows;
  1403. if (!req.getSuppressResultSchemas())
  1404. flags|=WUINFO_IncludeEclSchemas;
  1405. if (req.getIncludeXmlSchemas())
  1406. flags|=WUINFO_IncludeXmlSchema;
  1407. if (req.getIncludeResultsViewNames())
  1408. flags|=WUINFO_IncludeResultsViewNames;
  1409. if (req.getIncludeResourceURLs())
  1410. flags|=WUINFO_IncludeResourceURLs;
  1411. if (req.getIncludeECL())
  1412. flags|=WUINFO_IncludeECL;
  1413. if (req.getIncludeHelpers())
  1414. flags|=WUINFO_IncludeHelpers;
  1415. if (req.getIncludeAllowedClusters())
  1416. flags|=WUINFO_IncludeAllowedClusters;
  1417. if (req.getIncludeTotalClusterTime())
  1418. flags|=WUINFO_IncludeTotalClusterTime;
  1419. if (req.getIncludeServiceNames())
  1420. flags|=WUINFO_IncludeServiceNames;
  1421. PROGLOG("WUInfo: %s %lx", wuid.str(), flags);
  1422. WsWuInfo winfo(context, wuid.str());
  1423. winfo.getInfo(resp.updateWorkunit(), flags);
  1424. if (req.getIncludeResultsViewNames()||req.getIncludeResourceURLs()||(version >= 1.50))
  1425. {
  1426. StringArray views, urls;
  1427. winfo.getResourceInfo(views, urls, WUINFO_IncludeResultsViewNames|WUINFO_IncludeResourceURLs);
  1428. IEspECLWorkunit& eclWU = resp.updateWorkunit();
  1429. if (req.getIncludeResultsViewNames())
  1430. resp.setResultViews(views);
  1431. if (req.getIncludeResourceURLs())
  1432. eclWU.setResourceURLs(urls);
  1433. if (version >= 1.50)
  1434. {
  1435. eclWU.setResultViewCount(views.length());
  1436. eclWU.setResourceURLCount(urls.length());
  1437. }
  1438. }
  1439. }
  1440. catch (IException *e)
  1441. {
  1442. if (e->errorCode() != ECLWATCH_CANNOT_OPEN_WORKUNIT)
  1443. throw e;
  1444. getArchivedWUInfo(context, sashaServerIp.get(), sashaServerPort, wuid.str(), resp);
  1445. e->Release();
  1446. }
  1447. switch (resp.getWorkunit().getStateID())
  1448. {
  1449. case WUStateCompiling:
  1450. case WUStateCompiled:
  1451. case WUStateScheduled:
  1452. case WUStateSubmitted:
  1453. case WUStateRunning:
  1454. case WUStateAborting:
  1455. case WUStateWait:
  1456. case WUStateUploadingFiles:
  1457. case WUStateDebugPaused:
  1458. case WUStateDebugRunning:
  1459. resp.setAutoRefresh(WUDETAILS_REFRESH_MINS);
  1460. break;
  1461. case WUStateBlocked:
  1462. resp.setAutoRefresh(WUDETAILS_REFRESH_MINS*5);
  1463. break;
  1464. }
  1465. resp.setCanCompile(notEmpty(context.queryUserId()));
  1466. if (version > 1.24 && notEmpty(req.getThorSlaveIP()))
  1467. resp.setThorSlaveIP(req.getThorSlaveIP());
  1468. ISecManager* secmgr = context.querySecManager();
  1469. if (!secmgr)
  1470. resp.setSecMethod(NULL);
  1471. else
  1472. resp.setSecMethod(secmgr->querySecMgrTypeName());
  1473. }
  1474. }
  1475. catch(IException* e)
  1476. {
  1477. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1478. }
  1479. return true;
  1480. }
  1481. bool CWsWorkunitsEx::onWUInfoDetails(IEspContext &context, IEspWUInfoRequest &req, IEspWUInfoResponse &resp)
  1482. {
  1483. return onWUInfo(context, req, resp);
  1484. }
  1485. bool CWsWorkunitsEx::onWUResultView(IEspContext &context, IEspWUResultViewRequest &req, IEspWUResultViewResponse &resp)
  1486. {
  1487. StringBuffer wuid(req.getWuid());
  1488. WsWuHelpers::checkAndTrimWorkunit("WUResultView", wuid);
  1489. ensureWsWorkunitAccess(context, wuid.str(), SecAccess_Read);
  1490. PROGLOG("WUResultView: %s", wuid.str());
  1491. Owned<IWuWebView> wv = createWuWebView(wuid.str(), NULL, NULL, getCFD(), true, nullptr);
  1492. StringBuffer html;
  1493. wv->renderSingleResult(req.getViewName(), req.getResultName(), html);
  1494. resp.setResult(html.str());
  1495. resp.setResult_mimetype("text/html");
  1496. return true;
  1497. }
  1498. void doWUQueryBySingleWuid(IEspContext &context, const char *wuid, IEspWUQueryResponse &resp)
  1499. {
  1500. Owned<IEspECLWorkunit> info= createECLWorkunit("","");
  1501. WsWuInfo winfo(context, wuid);
  1502. winfo.getCommon(*info, 0);
  1503. IArrayOf<IEspECLWorkunit> results;
  1504. results.append(*info.getClear());
  1505. resp.setWorkunits(results);
  1506. resp.setPageSize(1);
  1507. resp.setCount(1);
  1508. PROGLOG("getWUInfo: %s", wuid);
  1509. }
  1510. void doWUQueryByFile(IEspContext &context, const char *logicalFile, IEspWUQueryResponse &resp)
  1511. {
  1512. StringBuffer wuid;
  1513. getWuidFromLogicalFileName(context, logicalFile, wuid);
  1514. if (!wuid.length())
  1515. throw MakeStringException(ECLWATCH_CANNOT_GET_WORKUNIT,"Cannot find the workunit for file %s.", logicalFile);
  1516. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1517. Owned<IConstWorkUnit> cw= factory->openWorkUnit(wuid.str());
  1518. if (!cw)
  1519. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot find the workunit for file %s.", logicalFile);
  1520. if (getWsWorkunitAccess(context, *cw) < SecAccess_Read)
  1521. throw MakeStringException(ECLWATCH_ECL_WU_ACCESS_DENIED,"Cannot access the workunit for file %s.",logicalFile);
  1522. doWUQueryBySingleWuid(context, wuid.str(), resp);
  1523. resp.setFirst(false);
  1524. resp.setPageSize(1);
  1525. resp.setCount(1);
  1526. }
  1527. bool addWUQueryFilter(WUSortField *filters, unsigned short &count, MemoryBuffer &buff, const char *name, WUSortField value)
  1528. {
  1529. if (isEmpty(name))
  1530. return false;
  1531. filters[count++] = value;
  1532. if ((value & WUSFwild) != 0 && !containsWildcard(name))
  1533. {
  1534. VStringBuffer s("*%s*", name);
  1535. buff.append(s);
  1536. }
  1537. else
  1538. buff.append(name);
  1539. return true;
  1540. }
  1541. bool addWUQueryFilterTime(WUSortField *filters, unsigned short &count, MemoryBuffer &buff, const char *stime, WUSortField value)
  1542. {
  1543. if (isEmpty(stime))
  1544. return false;
  1545. CDateTime dt;
  1546. dt.setString(stime, NULL, true);
  1547. unsigned year, month, day, hour, minute, second, nano;
  1548. dt.getDate(year, month, day, true);
  1549. dt.getTime(hour, minute, second, nano, true);
  1550. VStringBuffer wuid("W%4d%02d%02d-%02d%02d%02d",year,month,day,hour,minute,second);
  1551. filters[count++] = value;
  1552. buff.append(wuid.str());
  1553. return true;
  1554. }
  1555. bool addWUQueryFilterTotalClusterTime(WUSortField *filters, unsigned short &count, MemoryBuffer &filterBuf, unsigned milliseconds, WUSortField value)
  1556. {
  1557. if (milliseconds == 0)
  1558. return false;
  1559. VStringBuffer vBuf("%u", milliseconds);
  1560. filters[count++] = value;
  1561. filterBuf.append(vBuf);
  1562. return true;
  1563. }
  1564. bool addWUQueryFilterApplication(WUSortField *filters, unsigned short &count, MemoryBuffer &buff, const char *appname, const char *appkey, const char *appdata)
  1565. {
  1566. if (isEmpty(appname))
  1567. return false; // appname must be specified
  1568. if (isEmpty(appkey) && isEmpty(appdata)) //one or other is required ( MORE - see if cassandra can relax that)
  1569. return false;
  1570. VStringBuffer path("%s/%s", appname, appkey && *appkey ? appkey : "*");
  1571. buff.append(path.str());
  1572. buff.append(appdata);
  1573. filters[count++] = WUSFappvalue;
  1574. return true;
  1575. }
  1576. void readWUQuerySortOrder(const char* sortBy, const bool descending, WUSortField& sortOrder)
  1577. {
  1578. if (isEmpty(sortBy))
  1579. {
  1580. sortOrder = (WUSortField) (WUSFwuid | WUSFreverse);
  1581. return;
  1582. }
  1583. if (strieq(sortBy, "Owner"))
  1584. sortOrder = WUSFuser;
  1585. else if (strieq(sortBy, "JobName"))
  1586. sortOrder = WUSFjob;
  1587. else if (strieq(sortBy, "Cluster"))
  1588. sortOrder = WUSFcluster;
  1589. else if (strieq(sortBy, "Protected"))
  1590. sortOrder = WUSFprotected;
  1591. else if (strieq(sortBy, "State"))
  1592. sortOrder = WUSFstate;
  1593. else if (strieq(sortBy, "ClusterTime"))
  1594. sortOrder = (WUSortField) (WUSFtotalthortime+WUSFnumeric);
  1595. else
  1596. sortOrder = WUSFwuid;
  1597. sortOrder = (WUSortField) (sortOrder | WUSFnocase);
  1598. if (descending)
  1599. sortOrder = (WUSortField) (sortOrder | WUSFreverse);
  1600. }
  1601. void doWUQueryWithSort(IEspContext &context, IEspWUQueryRequest & req, IEspWUQueryResponse & resp)
  1602. {
  1603. SecAccessFlags accessOwn;
  1604. SecAccessFlags accessOthers;
  1605. getUserWuAccessFlags(context, accessOwn, accessOthers, true);
  1606. double version = context.getClientVersion();
  1607. IArrayOf<IEspECLWorkunit> results;
  1608. int begin = 0;
  1609. unsigned int count = 100;
  1610. int pagesize = 100;
  1611. if (version > 1.01)
  1612. {
  1613. pagesize = (int)req.getPageSize();
  1614. if (!req.getCount_isNull())
  1615. pagesize = req.getCount();
  1616. if(pagesize < 1)
  1617. pagesize = 100;
  1618. begin = (int)req.getPageStartFrom();
  1619. }
  1620. else
  1621. {
  1622. count=(unsigned)req.getCount();
  1623. if(!count)
  1624. count=100;
  1625. if (notEmpty(req.getAfter()))
  1626. begin=atoi(req.getAfter());
  1627. else if (notEmpty(req.getBefore()))
  1628. begin=atoi(req.getBefore())-count;
  1629. if (begin < 0)
  1630. begin = 0;
  1631. pagesize = count;
  1632. }
  1633. WUSortField sortorder;
  1634. readWUQuerySortOrder(req.getSortby(), req.getDescending(), sortorder);
  1635. WUSortField filters[10];
  1636. unsigned short filterCount = 0;
  1637. MemoryBuffer filterbuf;
  1638. // Query filters should be added in order of expected power - add the most restrictive filters first
  1639. bool bDoubleCheckState = false;
  1640. if(req.getState() && *req.getState())
  1641. {
  1642. filters[filterCount++] = WUSFstate;
  1643. if (!strieq(req.getState(), "unknown"))
  1644. filterbuf.append(req.getState());
  1645. else
  1646. filterbuf.append("");
  1647. if (strieq(req.getState(), "submitted"))
  1648. bDoubleCheckState = true;
  1649. }
  1650. addWUQueryFilter(filters, filterCount, filterbuf, req.getWuid(), WUSFwildwuid);
  1651. addWUQueryFilter(filters, filterCount, filterbuf, req.getCluster(), WUSFcluster);
  1652. addWUQueryFilter(filters, filterCount, filterbuf, req.getLogicalFile(), (WUSortField) (WUSFfileread | WUSFnocase));
  1653. addWUQueryFilter(filters, filterCount, filterbuf, req.getOwner(), (WUSortField) (WUSFuser | WUSFnocase));
  1654. addWUQueryFilter(filters, filterCount, filterbuf, req.getJobname(), (WUSortField) (WUSFjob | WUSFnocase));
  1655. addWUQueryFilter(filters, filterCount, filterbuf, req.getECL(), (WUSortField) (WUSFecl | WUSFwild));
  1656. addWUQueryFilterTotalClusterTime(filters, filterCount, filterbuf, req.getTotalClusterTimeThresholdMilliSec(), WUSFtotalthortime);
  1657. addWUQueryFilterTime(filters, filterCount, filterbuf, req.getStartDate(), WUSFwuid);
  1658. addWUQueryFilterTime(filters, filterCount, filterbuf, req.getEndDate(), WUSFwuidhigh);
  1659. if (version < 1.55)
  1660. addWUQueryFilterApplication(filters, filterCount, filterbuf, req.getApplicationName(), req.getApplicationKey(), req.getApplicationData());
  1661. else
  1662. {
  1663. IArrayOf<IConstApplicationValue>& applicationFilters = req.getApplicationValues();
  1664. ForEachItemIn(i, applicationFilters)
  1665. {
  1666. IConstApplicationValue &item = applicationFilters.item(i);
  1667. addWUQueryFilterApplication(filters, filterCount, filterbuf, item.getApplication(), item.getName(), item.getValue());
  1668. }
  1669. }
  1670. filters[filterCount] = WUSFterm;
  1671. __int64 cacheHint = 0;
  1672. if (!req.getCacheHint_isNull())
  1673. cacheHint = req.getCacheHint();
  1674. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1675. unsigned numWUs;
  1676. PROGLOG("WUQuery: getWorkUnitsSorted");
  1677. Owned<IConstWorkUnitIterator> it = factory->getWorkUnitsSorted(sortorder, filters, filterbuf.bufferBase(), begin, pagesize+1, &cacheHint, &numWUs); // MORE - need security flags here!
  1678. if (version >= 1.41)
  1679. resp.setCacheHint(cacheHint);
  1680. PROGLOG("WUQuery: getWorkUnitsSorted done");
  1681. unsigned actualCount = 0;
  1682. ForEach(*it)
  1683. {
  1684. IConstWorkUnitInfo& cw = it->query();
  1685. if (bDoubleCheckState && (cw.getState() != WUStateSubmitted))
  1686. {
  1687. numWUs--;
  1688. continue;
  1689. }
  1690. // This test is presumably trying to remove the global workunit, though it's not the right way to do so (since it will mess up page counts etc)
  1691. const char* wuid = cw.queryWuid();
  1692. if (!looksLikeAWuid(wuid, 'W'))
  1693. {
  1694. numWUs--;
  1695. continue;
  1696. }
  1697. actualCount++;
  1698. Owned<IEspECLWorkunit> info = createECLWorkunit("","");
  1699. info->setWuid(cw.queryWuid());
  1700. if (chooseWuAccessFlagsByOwnership(context.queryUserId(), cw, accessOwn, accessOthers) < SecAccess_Read)
  1701. {
  1702. info->setState("<Hidden>");
  1703. results.append(*info.getClear());
  1704. continue;
  1705. }
  1706. info->setProtected(cw.isProtected() ? 1 : 0);
  1707. info->setJobname(cw.queryJobName());
  1708. info->setOwner(cw.queryUser());
  1709. info->setCluster(cw.queryClusterName());
  1710. SCMStringBuffer s;
  1711. // info.setSnapshot(cw->getSnapshot(s).str());
  1712. info->setStateID(cw.getState());
  1713. info->setState(cw.queryStateDesc());
  1714. unsigned totalThorTimeMS = cw.getTotalThorTime();
  1715. StringBuffer totalThorTimeStr;
  1716. formatDuration(totalThorTimeStr, totalThorTimeMS);
  1717. if (version > 1.52)
  1718. info->setTotalClusterTime(totalThorTimeStr.str());
  1719. else
  1720. info->setTotalThorTime(totalThorTimeStr.str());
  1721. //if (cw->isPausing())
  1722. // info.setIsPausing(true);
  1723. // getEventScheduleFlag(info);
  1724. WsWuDateTime dt;
  1725. cw.getTimeScheduled(dt);
  1726. if(dt.isValid())
  1727. info->setDateTimeScheduled(dt.getString(s).str());
  1728. if (version >= 1.55)
  1729. {
  1730. IArrayOf<IEspApplicationValue> av;
  1731. Owned<IConstWUAppValueIterator> app(&cw.getApplicationValues());
  1732. ForEach(*app)
  1733. {
  1734. IConstWUAppValue& val=app->query();
  1735. Owned<IEspApplicationValue> t= createApplicationValue("","");
  1736. t->setApplication(val.queryApplication());
  1737. t->setName(val.queryName());
  1738. t->setValue(val.queryValue());
  1739. av.append(*t.getLink());
  1740. }
  1741. info->setApplicationValues(av);
  1742. }
  1743. results.append(*info.getClear());
  1744. }
  1745. if (version > 1.02)
  1746. {
  1747. resp.setPageStartFrom(begin+1);
  1748. resp.setNumWUs(numWUs);
  1749. if (results.length() > (aindex_t)pagesize)
  1750. results.pop();
  1751. if(unsigned (begin + pagesize) < numWUs)
  1752. {
  1753. resp.setNextPage(begin + pagesize);
  1754. resp.setPageEndAt(begin + pagesize);
  1755. int last = begin + pagesize;
  1756. while (numWUs > (unsigned) last + pagesize)
  1757. last += pagesize;
  1758. resp.setLastPage(last);
  1759. }
  1760. else
  1761. {
  1762. resp.setNextPage(-1);
  1763. resp.setPageEndAt(numWUs);
  1764. }
  1765. if(begin > 0)
  1766. {
  1767. resp.setFirst(false);
  1768. if (begin - pagesize > 0)
  1769. resp.setPrevPage(begin - pagesize);
  1770. else
  1771. resp.setPrevPage(0);
  1772. }
  1773. resp.setPageSize(pagesize);
  1774. }
  1775. else
  1776. {
  1777. if(begin>0 && actualCount > 0)
  1778. {
  1779. char buf[10];
  1780. itoa(begin, buf, 10);
  1781. resp.setCurrent(buf);
  1782. }
  1783. if(count<actualCount)
  1784. {
  1785. char buf[10];
  1786. itoa(begin+count, buf, 10);
  1787. resp.setNext(buf);
  1788. resp.setNumWUs(numWUs);
  1789. if (results.length() > count)
  1790. results.pop();
  1791. }
  1792. if(begin == 0 && actualCount <= count)
  1793. resp.setFirst(false);
  1794. resp.setCount(count);
  1795. }
  1796. resp.setWorkunits(results);
  1797. return;
  1798. }
  1799. void doWULightWeightQueryWithSort(IEspContext &context, IEspWULightWeightQueryRequest & req, IEspWULightWeightQueryResponse & resp)
  1800. {
  1801. SecAccessFlags accessOwn;
  1802. SecAccessFlags accessOthers;
  1803. getUserWuAccessFlags(context, accessOwn, accessOthers, true);
  1804. double version = context.getClientVersion();
  1805. int pageStartFrom = 0;
  1806. int pageSize = 100;
  1807. if (!req.getPageStartFrom_isNull())
  1808. pageStartFrom = req.getPageStartFrom();
  1809. if (!req.getPageSize_isNull())
  1810. pageSize = req.getPageSize();
  1811. WUSortField sortOrder;
  1812. readWUQuerySortOrder(req.getSortBy(), req.getDescending(), sortOrder);
  1813. WUSortField filters[10];
  1814. unsigned short filterCount = 0;
  1815. MemoryBuffer filterbuf;
  1816. // Query filters should be added in order of expected power - add the most restrictive filters first
  1817. bool bDoubleCheckState = false;
  1818. if(req.getState() && *req.getState())
  1819. {
  1820. filters[filterCount++] = WUSFstate;
  1821. if (!strieq(req.getState(), "unknown"))
  1822. filterbuf.append(req.getState());
  1823. else
  1824. filterbuf.append("");
  1825. if (strieq(req.getState(), "submitted"))
  1826. bDoubleCheckState = true;
  1827. }
  1828. addWUQueryFilter(filters, filterCount, filterbuf, req.getWuid(), WUSFwildwuid);
  1829. addWUQueryFilter(filters, filterCount, filterbuf, req.getCluster(), WUSFcluster);
  1830. addWUQueryFilter(filters, filterCount, filterbuf, req.getOwner(), (WUSortField) (WUSFuser | WUSFnocase));
  1831. addWUQueryFilter(filters, filterCount, filterbuf, req.getJobName(), (WUSortField) (WUSFjob | WUSFnocase));
  1832. //StartDate example: 2015-08-26T14:26:00
  1833. addWUQueryFilterTime(filters, filterCount, filterbuf, req.getStartDate(), WUSFwuid);
  1834. addWUQueryFilterTime(filters, filterCount, filterbuf, req.getEndDate(), WUSFwuidhigh);
  1835. IArrayOf<IConstApplicationValue>& applicationFilters = req.getApplicationValues();
  1836. ForEachItemIn(i, applicationFilters)
  1837. {
  1838. IConstApplicationValue &item = applicationFilters.item(i);
  1839. addWUQueryFilterApplication(filters, filterCount, filterbuf, item.getApplication(), item.getName(), item.getValue());
  1840. }
  1841. filters[filterCount] = WUSFterm;
  1842. __int64 cacheHint = 0;
  1843. if (!req.getCacheHint_isNull())
  1844. cacheHint = req.getCacheHint();
  1845. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1846. unsigned numWUs;
  1847. PROGLOG("getWorkUnitsSorted(LightWeight)");
  1848. Owned<IConstWorkUnitIterator> it = factory->getWorkUnitsSorted(sortOrder, filters, filterbuf.bufferBase(), pageStartFrom, pageSize+1, &cacheHint, &numWUs); // MORE - need security flags here!
  1849. resp.setCacheHint(cacheHint);
  1850. PROGLOG("getWorkUnitsSorted(LightWeight) done");
  1851. IArrayOf<IEspECLWorkunitLW> results;
  1852. ForEach(*it)
  1853. {
  1854. IConstWorkUnitInfo& cw = it->query();
  1855. if (bDoubleCheckState && (cw.getState() != WUStateSubmitted))
  1856. {
  1857. numWUs--;
  1858. continue;
  1859. }
  1860. // This test is presumably trying to remove the global workunit, though it's not the right way to do so (since it will mess up page counts etc)
  1861. const char* wuid = cw.queryWuid();
  1862. if (!looksLikeAWuid(wuid, 'W'))
  1863. {
  1864. numWUs--;
  1865. continue;
  1866. }
  1867. Owned<IEspECLWorkunitLW> info = createECLWorkunitLW("","");
  1868. info->setWuid(cw.queryWuid());
  1869. if (chooseWuAccessFlagsByOwnership(context.queryUserId(), cw, accessOwn, accessOthers) < SecAccess_Read)
  1870. {
  1871. info->setStateDesc("<Hidden>");
  1872. results.append(*info.getClear());
  1873. continue;
  1874. }
  1875. SCMStringBuffer s;
  1876. info->setIsProtected(cw.isProtected() ? 1 : 0);
  1877. info->setJobName(cw.queryJobName());
  1878. info->setWuScope(cw.queryWuScope());
  1879. info->setOwner(cw.queryUser());
  1880. info->setClusterName(cw.queryClusterName());
  1881. info->setState(cw.getState());
  1882. info->setStateDesc(cw.queryStateDesc());
  1883. info->setAction(cw.getAction());
  1884. info->setActionDesc(cw.queryActionDesc());
  1885. info->setPriority(cw.getPriority());
  1886. info->setPriorityLevel(cw.getPriorityLevel());
  1887. info->setPriorityDesc(cw.queryPriorityDesc());
  1888. info->setTotalClusterTime(cw.getTotalThorTime());
  1889. WsWuDateTime dt;
  1890. cw.getTimeScheduled(dt);
  1891. if(dt.isValid())
  1892. info->setDateTimeScheduled(dt.getString(s).str());
  1893. IArrayOf<IEspApplicationValue> av;
  1894. Owned<IConstWUAppValueIterator> app(&cw.getApplicationValues());
  1895. ForEach(*app)
  1896. {
  1897. IConstWUAppValue& val=app->query();
  1898. Owned<IEspApplicationValue> t= createApplicationValue("","");
  1899. t->setApplication(val.queryApplication());
  1900. t->setName(val.queryName());
  1901. t->setValue(val.queryValue());
  1902. av.append(*t.getClear());
  1903. }
  1904. info->setApplicationValues(av);
  1905. results.append(*info.getClear());
  1906. }
  1907. resp.setNumWUs(numWUs);
  1908. if (results.length() > (aindex_t)pageSize)
  1909. results.pop();
  1910. resp.setWorkunits(results);
  1911. return;
  1912. }
  1913. class CArchivedWUsReader : public CInterface, implements IArchivedWUsReader
  1914. {
  1915. IEspContext& context;
  1916. unsigned pageSize;
  1917. StringAttr sashaServerIP;
  1918. unsigned sashaServerPort;
  1919. unsigned cacheMinutes;
  1920. StringBuffer filterStr;
  1921. ArchivedWuCache& archivedWuCache;
  1922. unsigned numberOfWUsReturned;
  1923. bool hasMoreWU;
  1924. void readDateFilters(const char* startDateReq, const char* endDateReq, StringBuffer& from, StringBuffer& to)
  1925. {
  1926. CDateTime timeFrom, timeTo;
  1927. if(notEmpty(endDateReq))
  1928. {//endDateReq example: 2015-08-26T14:26:00
  1929. unsigned year, month, day, hour, minute, second, nano;
  1930. timeTo.setString(endDateReq, NULL, true);
  1931. timeTo.getDate(year, month, day, true);
  1932. timeTo.getTime(hour, minute, second, nano, true);
  1933. to.setf("%4d%02d%02d-%02d%02d%02d", year, month, day, hour, minute, second);
  1934. }
  1935. if(isEmpty(startDateReq))
  1936. return;
  1937. timeFrom.setString(startDateReq, NULL, true);
  1938. if (timeFrom >= timeTo)
  1939. return;
  1940. unsigned year0, month0, day0, hour0, minute0, second0, nano0;
  1941. timeFrom.getDate(year0, month0, day0, true);
  1942. timeFrom.getTime(hour0, minute0, second0, nano0, true);
  1943. from.setf("%4d%02d%02d-%02d%02d%02d", year0, month0, day0, hour0, minute0, second0);
  1944. return;
  1945. }
  1946. bool addToFilterString(const char *name, const char *value)
  1947. {
  1948. if (isEmpty(name) || isEmpty(value))
  1949. return false;
  1950. filterStr.append(';').append(name).append("=").append(value);
  1951. return true;
  1952. }
  1953. bool addToFilterString(const char *name, unsigned value)
  1954. {
  1955. if (isEmpty(name))
  1956. return false;
  1957. filterStr.append(';').append(name).append("=").append(value);
  1958. return true;
  1959. }
  1960. void setFilterString(IEspWUQueryRequest& req)
  1961. {
  1962. filterStr.set("0");
  1963. addToFilterString("wuid", req.getWuid());
  1964. addToFilterString("cluster", req.getCluster());
  1965. addToFilterString("owner", req.getOwner());
  1966. addToFilterString("jobName", req.getJobname());
  1967. addToFilterString("state", req.getState());
  1968. addToFilterString("timeFrom", req.getStartDate());
  1969. addToFilterString("timeTo", req.getEndDate());
  1970. addToFilterString("beforeWU", req.getBeforeWU());
  1971. addToFilterString("afterWU", req.getAfterWU());
  1972. addToFilterString("descending", req.getDescending());
  1973. addToFilterString("pageSize", pageSize);
  1974. if (sashaServerIP && *sashaServerIP)
  1975. {
  1976. addToFilterString("sashaServerIP", sashaServerIP.get());
  1977. addToFilterString("sashaServerPort", sashaServerPort);
  1978. }
  1979. }
  1980. void setFilterStringLW(IEspWULightWeightQueryRequest& req)
  1981. {
  1982. filterStr.set("1");
  1983. addToFilterString("wuid", req.getWuid());
  1984. addToFilterString("cluster", req.getCluster());
  1985. addToFilterString("owner", req.getOwner());
  1986. addToFilterString("jobName", req.getJobName());
  1987. addToFilterString("state", req.getState());
  1988. addToFilterString("timeFrom", req.getStartDate());
  1989. addToFilterString("timeTo", req.getEndDate());
  1990. addToFilterString("beforeWU", req.getBeforeWU());
  1991. addToFilterString("afterWU", req.getAfterWU());
  1992. addToFilterString("descending", req.getDescending());
  1993. addToFilterString("pageSize", pageSize);
  1994. if (sashaServerIP && *sashaServerIP)
  1995. {
  1996. addToFilterString("sashaServerIP", sashaServerIP.get());
  1997. addToFilterString("sashaServerPort", sashaServerPort);
  1998. }
  1999. }
  2000. void initSashaCommand(ISashaCommand* cmd)
  2001. {
  2002. cmd->setAction(SCA_LIST);
  2003. cmd->setOutputFormat("owner,jobname,cluster,state");
  2004. cmd->setOnline(false);
  2005. cmd->setArchived(true);
  2006. cmd->setLimit(pageSize+1); //read an extra WU to check hasMoreWU
  2007. }
  2008. void setSashaCommand(IEspWUQueryRequest& req, ISashaCommand* cmd)
  2009. {
  2010. if (notEmpty(req.getWuid()))
  2011. cmd->addId(req.getWuid());
  2012. if (notEmpty(req.getCluster()))
  2013. cmd->setCluster(req.getCluster());
  2014. if (notEmpty(req.getOwner()))
  2015. cmd->setOwner(req.getOwner());
  2016. if (notEmpty(req.getJobname()))
  2017. cmd->setJobName(req.getJobname());
  2018. if (notEmpty(req.getState()))
  2019. cmd->setState(req.getState());
  2020. StringBuffer timeFrom, timeTo;
  2021. readDateFilters(req.getStartDate(), req.getEndDate(), timeFrom, timeTo);
  2022. if (timeFrom.length())
  2023. cmd->setAfter(timeFrom.str());
  2024. if (timeTo.length())
  2025. cmd->setBefore(timeTo.str());
  2026. if (notEmpty(req.getBeforeWU()))
  2027. cmd->setBeforeWU(req.getBeforeWU());
  2028. if (notEmpty(req.getAfterWU()))
  2029. cmd->setAfterWU(req.getAfterWU());
  2030. cmd->setSortDescending(req.getDescending());
  2031. return;
  2032. }
  2033. void setSashaCommandLW(IEspWULightWeightQueryRequest& req, ISashaCommand* cmd)
  2034. {
  2035. if (notEmpty(req.getWuid()))
  2036. cmd->addId(req.getWuid());
  2037. if (notEmpty(req.getCluster()))
  2038. cmd->setCluster(req.getCluster());
  2039. if (notEmpty(req.getOwner()))
  2040. cmd->setOwner(req.getOwner());
  2041. if (notEmpty(req.getJobName()))
  2042. cmd->setJobName(req.getJobName());
  2043. if (notEmpty(req.getState()))
  2044. cmd->setState(req.getState());
  2045. StringBuffer timeFrom, timeTo;
  2046. readDateFilters(req.getStartDate(), req.getEndDate(), timeFrom, timeTo);
  2047. if (timeFrom.length())
  2048. cmd->setAfter(timeFrom.str());
  2049. if (timeTo.length())
  2050. cmd->setBefore(timeTo.str());
  2051. if (notEmpty(req.getBeforeWU()))
  2052. cmd->setBeforeWU(req.getBeforeWU());
  2053. if (notEmpty(req.getAfterWU()))
  2054. cmd->setAfterWU(req.getAfterWU());
  2055. cmd->setSortDescending(req.getDescending());
  2056. return;
  2057. }
  2058. IEspECLWorkunit *createArchivedWUEntry(StringArray& wuDataArray, bool canAccess)
  2059. {
  2060. Owned<IEspECLWorkunit> info= createECLWorkunit();
  2061. info->setWuid(wuDataArray.item(0));
  2062. if (!canAccess)
  2063. {
  2064. info->setState("<Hidden>");
  2065. return info.getClear();
  2066. }
  2067. const char* owner = wuDataArray.item(1);
  2068. const char* jobName = wuDataArray.item(2);
  2069. const char* cluster = wuDataArray.item(3);
  2070. const char* state = wuDataArray.item(4);
  2071. if (notEmpty(owner))
  2072. info->setOwner(owner);
  2073. if (notEmpty(jobName))
  2074. info->setJobname(jobName);
  2075. if (notEmpty(cluster))
  2076. info->setCluster(cluster);
  2077. if (notEmpty(state))
  2078. info->setState(state);
  2079. return info.getClear();
  2080. }
  2081. IEspECLWorkunitLW *createArchivedLWWUEntry(StringArray& wuDataArray, bool canAccess)
  2082. {
  2083. Owned<IEspECLWorkunitLW> info= createECLWorkunitLW();
  2084. info->setWuid(wuDataArray.item(0));
  2085. if (!canAccess)
  2086. {
  2087. info->setStateDesc("<Hidden>");
  2088. return info.getClear();
  2089. }
  2090. const char* owner = wuDataArray.item(1);
  2091. const char* jobName = wuDataArray.item(2);
  2092. const char* cluster = wuDataArray.item(3);
  2093. const char* state = wuDataArray.item(4);
  2094. if (notEmpty(owner))
  2095. info->setOwner(owner);
  2096. if (notEmpty(jobName))
  2097. info->setJobName(jobName);
  2098. if (notEmpty(cluster))
  2099. info->setClusterName(cluster);
  2100. if (notEmpty(state))
  2101. info->setStateDesc(state);
  2102. return info.getClear();
  2103. }
  2104. static int compareWuids(IInterface * const *_a, IInterface * const *_b)
  2105. {
  2106. IEspECLWorkunit *a = *(IEspECLWorkunit **)_a;
  2107. IEspECLWorkunit *b = *(IEspECLWorkunit **)_b;
  2108. return strcmp(b->getWuid(), a->getWuid());
  2109. }
  2110. static int compareLWWuids(IInterface * const *_a, IInterface * const *_b)
  2111. {
  2112. IEspECLWorkunitLW *a = *(IEspECLWorkunitLW **)_a;
  2113. IEspECLWorkunitLW *b = *(IEspECLWorkunitLW **)_b;
  2114. return strcmp(b->getWuid(), a->getWuid());
  2115. }
  2116. public:
  2117. IMPLEMENT_IINTERFACE_USING(CInterface);
  2118. CArchivedWUsReader(IEspContext& _context, const char* _sashaServerIP, unsigned _sashaServerPort, ArchivedWuCache& _archivedWuCache,
  2119. unsigned _cacheMinutes, unsigned _pageSize)
  2120. : context(_context), sashaServerIP(_sashaServerIP), sashaServerPort(_sashaServerPort),
  2121. archivedWuCache(_archivedWuCache), cacheMinutes(_cacheMinutes), pageSize(_pageSize)
  2122. {
  2123. hasMoreWU = false;
  2124. numberOfWUsReturned = 0;
  2125. }
  2126. void getArchivedWUs(bool lightWeight, IEspWUQueryRequest& req, IEspWULightWeightQueryRequest& reqLW, IArrayOf<IEspECLWorkunit>& archivedWUs, IArrayOf<IEspECLWorkunitLW>& archivedLWWUs)
  2127. {
  2128. if (!lightWeight)
  2129. setFilterString(req);
  2130. else
  2131. setFilterStringLW(reqLW);
  2132. Owned<ArchivedWuCacheElement> cachedResults = archivedWuCache.lookup(context, filterStr, "AddWhenAvailable", cacheMinutes);
  2133. if (cachedResults)
  2134. {
  2135. hasMoreWU = cachedResults->m_hasNextPage;
  2136. numberOfWUsReturned = cachedResults->numWUsReturned;
  2137. if (!lightWeight && cachedResults->m_results.length())
  2138. {
  2139. ForEachItemIn(i, cachedResults->m_results)
  2140. archivedWUs.append(*LINK(&cachedResults->m_results.item(i)));
  2141. }
  2142. if (lightWeight && cachedResults->resultsLW.length())
  2143. {
  2144. ForEachItemIn(i, cachedResults->resultsLW)
  2145. archivedLWWUs.append(*LINK(&cachedResults->resultsLW.item(i)));
  2146. }
  2147. return;
  2148. }
  2149. SocketEndpoint ep;
  2150. if (sashaServerIP && *sashaServerIP)
  2151. ep.set(sashaServerIP, sashaServerPort);
  2152. else
  2153. getSashaNode(ep);
  2154. Owned<INode> sashaserver = createINode(ep);
  2155. Owned<ISashaCommand> cmd = createSashaCommand();
  2156. initSashaCommand(cmd);
  2157. if (!lightWeight)
  2158. setSashaCommand(req, cmd);
  2159. else
  2160. setSashaCommandLW(reqLW, cmd);
  2161. if (!cmd->send(sashaserver))
  2162. {
  2163. StringBuffer url;
  2164. throw MakeStringException(ECLWATCH_CANNOT_CONNECT_ARCHIVE_SERVER,
  2165. "Sasha (%s) took too long to respond from: Get archived workUnits.",
  2166. ep.getUrlStr(url).str());
  2167. }
  2168. numberOfWUsReturned = cmd->numIds();
  2169. hasMoreWU = (numberOfWUsReturned > pageSize);
  2170. if (hasMoreWU)
  2171. numberOfWUsReturned--;
  2172. if (numberOfWUsReturned == 0)
  2173. return;
  2174. SecAccessFlags accessOwn, accessOthers;
  2175. getUserWuAccessFlags(context, accessOwn, accessOthers, true);
  2176. for (unsigned i=0; i<numberOfWUsReturned; i++)
  2177. {
  2178. const char *csline = cmd->queryId(i);
  2179. if (!csline || !*csline)
  2180. continue;
  2181. StringArray wuDataArray;
  2182. wuDataArray.appendList(csline, ",");
  2183. const char* wuid = wuDataArray.item(0);
  2184. if (isEmpty(wuid))
  2185. {
  2186. IWARNLOG("Empty WUID in SCA_LIST response"); // JCS->KW - have u ever seen this happen?
  2187. continue;
  2188. }
  2189. const char* owner = wuDataArray.item(1);
  2190. bool canAccess = chooseWuAccessFlagsByOwnership(context.queryUserId(), owner, accessOwn, accessOthers) >= SecAccess_Read;
  2191. if (!lightWeight)
  2192. {
  2193. Owned<IEspECLWorkunit> info = createArchivedWUEntry(wuDataArray, canAccess);
  2194. archivedWUs.append(*info.getClear());
  2195. }
  2196. else
  2197. {
  2198. Owned<IEspECLWorkunitLW> info = createArchivedLWWUEntry(wuDataArray, canAccess);
  2199. archivedLWWUs.append(*info.getClear());
  2200. }
  2201. }
  2202. archivedWuCache.add(filterStr, "AddWhenAvailable", hasMoreWU, numberOfWUsReturned, archivedWUs, archivedLWWUs);
  2203. return;
  2204. };
  2205. bool getHasMoreWU() { return hasMoreWU; };
  2206. unsigned getNumberOfWUsReturned() { return numberOfWUsReturned; };
  2207. };
  2208. void doWUQueryFromArchive(IEspContext &context, const char* sashaServerIP, unsigned sashaServerPort,
  2209. ArchivedWuCache &archivedWuCache, unsigned cacheMinutes, IEspWUQueryRequest & req, IEspWUQueryResponse & resp)
  2210. {
  2211. //Sasha server does noy support the PageStartFrom due to inefficient access to archived workunits for pages>1.
  2212. unsigned pageSize = (unsigned) req.getPageSize();
  2213. if(pageSize < 1)
  2214. pageSize=500;
  2215. Owned<IArchivedWUsReader> archiveWUsReader = new CArchivedWUsReader(context, sashaServerIP, sashaServerPort, archivedWuCache,
  2216. cacheMinutes, pageSize);
  2217. IArrayOf<IEspECLWorkunit> archivedWUs;
  2218. IArrayOf<IEspECLWorkunitLW> dummyWUs;
  2219. Owned<CWULightWeightQueryRequest> dummyReq = new CWULightWeightQueryRequest("WsWorkunits");
  2220. PROGLOG("getWorkUnitsFromArchive");
  2221. archiveWUsReader->getArchivedWUs(false, req, *dummyReq, archivedWUs, dummyWUs);
  2222. PROGLOG("getWorkUnitsFromArchive done");
  2223. resp.setWorkunits(archivedWUs);
  2224. resp.setNumWUs(archiveWUsReader->getNumberOfWUsReturned());
  2225. resp.setType("archived only");
  2226. resp.setPageSize(pageSize);
  2227. return;
  2228. }
  2229. void doWULightWeightQueryFromArchive(IEspContext &context, const char* sashaServerIP, unsigned sashaServerPort,
  2230. ArchivedWuCache &archivedWuCache, unsigned cacheMinutes, IEspWULightWeightQueryRequest & req, IEspWULightWeightQueryResponse & resp)
  2231. {
  2232. int pageSize = req.getPageSize_isNull()? 500 : req.getPageSize();
  2233. Owned<IArchivedWUsReader> archiveWUsReader = new CArchivedWUsReader(context, sashaServerIP, sashaServerPort, archivedWuCache,
  2234. cacheMinutes, pageSize);
  2235. Owned<CWUQueryRequest> dummyReq = new CWUQueryRequest("WsWorkunits");
  2236. IArrayOf<IEspECLWorkunit> dummyWUs;
  2237. IArrayOf<IEspECLWorkunitLW> archivedWUs;
  2238. PROGLOG("getWorkUnitsFromArchive(LightWeight)");
  2239. archiveWUsReader->getArchivedWUs(true, *dummyReq, req, dummyWUs, archivedWUs);
  2240. PROGLOG("getWorkUnitsFromArchive(LightWeight) done");
  2241. resp.setWorkunits(archivedWUs);
  2242. resp.setNumWUs(archiveWUsReader->getNumberOfWUsReturned());
  2243. return;
  2244. }
  2245. bool CWsWorkunitsEx::onWUQuery(IEspContext &context, IEspWUQueryRequest & req, IEspWUQueryResponse & resp)
  2246. {
  2247. try
  2248. {
  2249. StringBuffer wuidStr(req.getWuid());
  2250. const char* wuid = wuidStr.trim().str();
  2251. if (req.getType() && strieq(req.getType(), "archived workunits"))
  2252. doWUQueryFromArchive(context, sashaServerIp.get(), sashaServerPort, *archivedWuCache, awusCacheMinutes, req, resp);
  2253. else if(notEmpty(wuid) && looksLikeAWuid(wuid, 'W'))
  2254. doWUQueryBySingleWuid(context, wuid, resp);
  2255. else if (notEmpty(req.getLogicalFile()) && req.getLogicalFileSearchType() && strieq(req.getLogicalFileSearchType(), "Created"))
  2256. doWUQueryByFile(context, req.getLogicalFile(), resp);
  2257. else
  2258. doWUQueryWithSort(context, req, resp);
  2259. resp.setState(req.getState());
  2260. resp.setCluster(req.getCluster());
  2261. resp.setRoxieCluster(req.getRoxieCluster());
  2262. resp.setOwner(req.getOwner());
  2263. resp.setStartDate(req.getStartDate());
  2264. resp.setEndDate(req.getEndDate());
  2265. double version = context.getClientVersion();
  2266. StringBuffer basicQuery;
  2267. addToQueryString(basicQuery, "State", req.getState());
  2268. addToQueryString(basicQuery, "Cluster", req.getCluster());
  2269. addToQueryString(basicQuery, "Owner", req.getOwner());
  2270. addToQueryString(basicQuery, "StartDate", req.getStartDate());
  2271. addToQueryString(basicQuery, "EndDate", req.getEndDate());
  2272. if (version >= 1.26 && version < 1.72 && req.getLastNDays() > -1)
  2273. addToQueryString(basicQuery, "LastNDays", StringBuffer().append(req.getLastNDays()).str());
  2274. addToQueryString(basicQuery, "ECL", req.getECL());
  2275. addToQueryString(basicQuery, "Jobname", req.getJobname());
  2276. addToQueryString(basicQuery, "Type", req.getType());
  2277. if (addToQueryString(basicQuery, "LogicalFile", req.getLogicalFile()))
  2278. addToQueryString(basicQuery, "LogicalFileSearchType", req.getLogicalFileSearchType());
  2279. resp.setFilters(basicQuery.str());
  2280. if (notEmpty(req.getSortby()) && !strstr(basicQuery.str(), StringBuffer(req.getSortby()).append('=').str()))
  2281. {
  2282. resp.setSortby(req.getSortby());
  2283. addToQueryString(basicQuery, "Sortby", req.getSortby());
  2284. if (req.getDescending())
  2285. {
  2286. resp.setDescending(req.getDescending());
  2287. addToQueryString(basicQuery, "Descending", "1");
  2288. }
  2289. }
  2290. resp.setBasicQuery(basicQuery.str());
  2291. StringBuffer s;
  2292. if(notEmpty(req.getECL()))
  2293. resp.setECL(Utils::url_encode(req.getECL(), s).str());
  2294. if(notEmpty(req.getJobname()))
  2295. resp.setJobname(Utils::url_encode(req.getJobname(), s.clear()).str());
  2296. }
  2297. catch(IException* e)
  2298. {
  2299. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  2300. }
  2301. return true;
  2302. }
  2303. bool CWsWorkunitsEx::onWULightWeightQuery(IEspContext &context, IEspWULightWeightQueryRequest & req, IEspWULightWeightQueryResponse & resp)
  2304. {
  2305. try
  2306. {
  2307. if (req.getType() && strieq(req.getType(), "archived workunits"))
  2308. doWULightWeightQueryFromArchive(context, sashaServerIp.get(), sashaServerPort, *archivedWuCache, awusCacheMinutes, req, resp);
  2309. else
  2310. doWULightWeightQueryWithSort(context, req, resp);
  2311. }
  2312. catch(IException* e)
  2313. {
  2314. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  2315. }
  2316. return true;
  2317. }
  2318. ITypeInfo * containsSingleSimpleFieldBlankXPath(IResultSetMetaData * meta)
  2319. {
  2320. if (meta->getColumnCount() != 1)
  2321. return NULL;
  2322. CResultSetMetaData * castMeta = static_cast<CResultSetMetaData *>(meta);
  2323. const char * xpath = castMeta->queryXPath(0);
  2324. if (xpath && (*xpath == 0))
  2325. {
  2326. return castMeta->queryType(0);
  2327. }
  2328. return NULL;
  2329. }
  2330. void csvSplitXPath(const char *xpath, StringBuffer &s, const char *&name, const char **childname=NULL)
  2331. {
  2332. if (!xpath)
  2333. return;
  2334. const char * slash = strchr(xpath, '/');
  2335. if (!slash)
  2336. {
  2337. name = xpath;
  2338. if (childname)
  2339. *childname = NULL;
  2340. }
  2341. else
  2342. {
  2343. if (!childname || strchr(slash+1, '/')) //output ignores xpaths that are too deep
  2344. return;
  2345. name = s.clear().append(slash-xpath, xpath).str();
  2346. *childname = slash+1;
  2347. }
  2348. }
  2349. void getCSVHeaders(const IResultSetMetaData& metaIn, CommonCSVWriter* writer, unsigned& layer)
  2350. {
  2351. StringBuffer xname;
  2352. const CResultSetMetaData& cMeta = static_cast<const CResultSetMetaData &>(metaIn);
  2353. IFvDataSourceMetaData* meta = cMeta.getMeta();
  2354. int columnCount = metaIn.getColumnCount();
  2355. for (unsigned idx = 0; idx < columnCount; idx++)
  2356. {
  2357. const CResultSetColumnInfo& column = cMeta.getColumn(idx);
  2358. unsigned flag = column.flag;
  2359. const char * name = meta->queryName(idx);
  2360. const char * childname = NULL;
  2361. switch (flag)
  2362. {
  2363. case FVFFbeginif:
  2364. case FVFFendif:
  2365. break;
  2366. case FVFFbeginrecord:
  2367. csvSplitXPath(meta->queryXPath(idx), xname, name);
  2368. writer->outputBeginNested(name, false, true);
  2369. break;
  2370. case FVFFendrecord:
  2371. csvSplitXPath(meta->queryXPath(idx), xname, name);
  2372. writer->outputEndNested(name, true);
  2373. break;
  2374. case FVFFdataset:
  2375. {
  2376. childname = "Row";
  2377. csvSplitXPath(meta->queryXPath(idx), xname, name, &childname);
  2378. ITypeInfo* singleFieldType = (name && *name && childname && *childname)
  2379. ? containsSingleSimpleFieldBlankXPath(column.childMeta.get()) : NULL;
  2380. if (!singleFieldType)
  2381. {
  2382. bool nameValid = (name && *name);
  2383. if (nameValid || (childname && *childname))
  2384. {
  2385. if (nameValid)
  2386. writer->outputBeginNested(name, false, true);
  2387. if (childname && *childname)
  2388. writer->outputBeginNested(childname, false, !nameValid);
  2389. const CResultSetMetaData *childMeta = static_cast<const CResultSetMetaData *>(column.childMeta.get());
  2390. getCSVHeaders(*childMeta, writer, ++layer);
  2391. layer--;
  2392. if (childname && *childname)
  2393. writer->outputEndNested(childname, !nameValid);
  2394. if (nameValid)
  2395. writer->outputEndNested(name, true);
  2396. }
  2397. }
  2398. break;
  2399. }
  2400. case FVFFblob: //for now FileViewer will output the string "[blob]"
  2401. {
  2402. Owned<ITypeInfo> stringType = makeStringType(UNKNOWN_LENGTH, NULL, NULL);
  2403. csvSplitXPath(meta->queryXPath(idx), xname, name);
  2404. StringBuffer eclTypeName;
  2405. stringType->getECLType(eclTypeName);
  2406. writer->outputCSVHeader(name, eclTypeName.str());
  2407. }
  2408. break;
  2409. default:
  2410. {
  2411. ITypeInfo & type = *column.type;
  2412. if (type.getTypeCode() == type_set)
  2413. {
  2414. childname = "Item";
  2415. csvSplitXPath(meta->queryXPath(idx), xname, name, &childname);
  2416. writer->outputBeginNested(name, true, true);
  2417. writer->outputEndNested(name, true);
  2418. }
  2419. else
  2420. {
  2421. csvSplitXPath(meta->queryXPath(idx), xname, name);
  2422. StringBuffer eclTypeName;
  2423. type.getECLType(eclTypeName);
  2424. writer->outputCSVHeader(name, eclTypeName.str());
  2425. }
  2426. break;
  2427. }
  2428. }
  2429. }
  2430. }
  2431. unsigned getResultCSV(IStringVal& ret, INewResultSet* result, const char* name, __int64 start, unsigned& count)
  2432. {
  2433. unsigned headerLayer = 0;
  2434. CSVOptions csvOptions;
  2435. csvOptions.delimiter.set(",");
  2436. csvOptions.terminator.set("\n");
  2437. csvOptions.includeHeader = true;
  2438. Owned<CommonCSVWriter> writer = new CommonCSVWriter(XWFtrim, csvOptions);
  2439. const IResultSetMetaData & meta = result->getMetaData();
  2440. getCSVHeaders(meta, writer, headerLayer);
  2441. writer->finishCSVHeaders();
  2442. Owned<IResultSetCursor> cursor = result->createCursor();
  2443. count = writeResultCursorXml(*writer, cursor, name, start, count, NULL);
  2444. ret.set(writer->str());
  2445. return count;
  2446. }
  2447. void appendResultSet(MemoryBuffer& mb, INewResultSet* result, const char *name, __int64 start, unsigned& count, __int64& total, bool bin, bool xsd, ESPSerializationFormat fmt, const IProperties *xmlns)
  2448. {
  2449. if (!result)
  2450. return;
  2451. total=result->getNumRows();
  2452. if(bin)
  2453. count = getResultBin(mb, result, (unsigned)start, count);
  2454. else
  2455. {
  2456. struct MemoryBuffer2IStringVal : public CInterface, implements IStringVal
  2457. {
  2458. MemoryBuffer2IStringVal(MemoryBuffer & _buffer) : buffer(_buffer) {}
  2459. IMPLEMENT_IINTERFACE;
  2460. virtual const char * str() const { UNIMPLEMENTED; }
  2461. virtual void set(const char *val) { buffer.append(strlen(val),val); }
  2462. virtual void clear() { } // support appending only
  2463. virtual void setLen(const char *val, unsigned length) { buffer.append(length, val); }
  2464. virtual unsigned length() const { return buffer.length(); };
  2465. MemoryBuffer & buffer;
  2466. } adaptor(mb);
  2467. if (fmt==ESPSerializationCSV)
  2468. count = getResultCSV(adaptor, result, name, (unsigned) start, count);
  2469. else if (fmt==ESPSerializationJSON)
  2470. count = getResultJSON(adaptor, result, name, (unsigned) start, count, (xsd) ? "myschema" : NULL);
  2471. else
  2472. count = getResultXml(adaptor, result, name, (unsigned) start, count, (xsd) ? "myschema" : NULL, xmlns);
  2473. }
  2474. }
  2475. INewResultSet* createFilteredResultSet(INewResultSet* result, IArrayOf<IConstNamedValue>* filterBy)
  2476. {
  2477. if (!result || !filterBy || !filterBy->length())
  2478. return NULL;
  2479. Owned<IFilteredResultSet> filter = result->createFiltered();
  2480. const IResultSetMetaData &meta = result->getMetaData();
  2481. unsigned columnCount = meta.getColumnCount();
  2482. ForEachItemIn(i, *filterBy)
  2483. {
  2484. IConstNamedValue &item = filterBy->item(i);
  2485. const char *name = item.getName();
  2486. const char *value = item.getValue();
  2487. if (!name || !*name || !value || !*value)
  2488. continue;
  2489. for(unsigned col = 0; col < columnCount; col++)
  2490. {
  2491. SCMStringBuffer scmbuf;
  2492. meta.getColumnLabel(scmbuf, col);
  2493. if (strieq(scmbuf.str(), name))
  2494. {
  2495. filter->addFilter(col, value);
  2496. break;
  2497. }
  2498. }
  2499. }
  2500. return filter->create();
  2501. }
  2502. static bool isResultRequestSzTooBig(unsigned __int64 start, unsigned requestCount, unsigned __int64 resultSz, unsigned resultRows, unsigned __int64 limitSz)
  2503. {
  2504. if ((0 == requestCount) || (0 == resultRows))
  2505. return resultSz > limitSz;
  2506. else
  2507. {
  2508. if (start+requestCount > resultRows)
  2509. requestCount = resultRows-start;
  2510. unsigned __int64 avgRecSize = resultSz / resultRows;
  2511. unsigned __int64 estSize = requestCount * avgRecSize;
  2512. return estSize > limitSz;
  2513. }
  2514. }
  2515. void CWsWorkunitsEx::getWsWuResult(IEspContext &context, const char *wuid, const char *name, const char *logical, unsigned index, __int64 start,
  2516. unsigned &count, __int64 &total, IStringVal &resname, bool bin, IArrayOf<IConstNamedValue> *filterBy, MemoryBuffer &mb,
  2517. WUState &wuState, bool xsd)
  2518. {
  2519. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  2520. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid);
  2521. if(!cw)
  2522. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot open workunit %s.",wuid);
  2523. Owned<IConstWUResult> result;
  2524. if (notEmpty(name))
  2525. result.setown(cw->getResultByName(name));
  2526. else if (notEmpty(logical))
  2527. {
  2528. Owned<IConstWUResultIterator> it = &cw->getResults();
  2529. ForEach(*it)
  2530. {
  2531. IConstWUResult &r = it->query();
  2532. SCMStringBuffer filename;
  2533. if(strieq(r.getResultLogicalName(filename).str(), logical))
  2534. {
  2535. result.setown(LINK(&r));
  2536. break;
  2537. }
  2538. }
  2539. }
  2540. else
  2541. result.setown(cw->getResultBySequence(index));
  2542. if (!result)
  2543. throw MakeStringException(ECLWATCH_CANNOT_GET_WU_RESULT,"Cannot open the workunit result.");
  2544. if (!resname.length())
  2545. result->getResultName(resname);
  2546. Owned<IResultSetFactory> resultSetFactory = getSecResultSetFactory(context.querySecManager(), context.queryUser(), context.queryUserId(), context.queryPassword());
  2547. SCMStringBuffer logicalName;
  2548. result->getResultLogicalName(logicalName);
  2549. Owned<INewResultSet> rs;
  2550. if (logicalName.length())
  2551. {
  2552. rs.setown(resultSetFactory->createNewFileResultSet(logicalName.str(), cw->queryClusterName())); //MORE is this wrong cluster?
  2553. }
  2554. else
  2555. rs.setown(resultSetFactory->createNewResultSet(result, wuid));
  2556. if (!filterBy || !filterBy->length())
  2557. {
  2558. unsigned __int64 resultSz;
  2559. if (0 == logicalName.length()) // could be a workunit owned file (OUTPUT, THOR)
  2560. result->getResultFilename(logicalName);
  2561. if (logicalName.length())
  2562. {
  2563. Owned<IDistributedFile> df = lookupLogicalName(context, logicalName.str(), false, false, false, nullptr, defaultPrivilegedUser);
  2564. if (!df)
  2565. throw makeStringExceptionV(ECLWATCH_FILE_NOT_EXIST, "Cannot find file %s.", logicalName.str());
  2566. resultSz = df->getDiskSize(true, false);
  2567. }
  2568. else
  2569. resultSz = result->getResultRawSize(nullptr, nullptr);
  2570. if (isResultRequestSzTooBig(start, count, resultSz, rs->getNumRows(), wuResultMaxSize))
  2571. {
  2572. throw makeStringExceptionV(ECLWATCH_INVALID_ACTION, "Failed to get the result for %s. The size is bigger than %lld MB.",
  2573. wuid, wuResultMaxSize/0x100000);
  2574. }
  2575. appendResultSet(mb, rs, name, start, count, total, bin, xsd, context.getResponseFormat(), result->queryResultXmlns());
  2576. }
  2577. else
  2578. {
  2579. Owned<INewResultSet> filteredResult = createFilteredResultSet(rs, filterBy);
  2580. appendResultSet(mb, filteredResult, name, start, count, total, bin, xsd, context.getResponseFormat(), result->queryResultXmlns());
  2581. }
  2582. wuState = cw->getState();
  2583. }
  2584. void checkFileSizeLimit(unsigned long xmlSize, unsigned long sizeLimit)
  2585. {
  2586. if ((sizeLimit > 0) && (xmlSize > sizeLimit))
  2587. throw MakeStringException(ECLWATCH_CANNOT_OPEN_FILE,
  2588. "The file size (%ld bytes) exceeds the size limit (%ld bytes). You may set 'Option > 1' or use 'Download_XML' link to get compressed file.",
  2589. xmlSize, sizeLimit);
  2590. }
  2591. void openSaveFile(IEspContext &context, int opt, __int64 sizeLimit, const char* filename, const char* origMimeType, MemoryBuffer& buf, IEspWULogFileResponse &resp)
  2592. {
  2593. if (opt < 1)
  2594. {
  2595. checkFileSizeLimit(buf.length(), sizeLimit);
  2596. resp.setThefile(buf);
  2597. resp.setThefile_mimetype(origMimeType);
  2598. }
  2599. else if (opt < 2)
  2600. {
  2601. checkFileSizeLimit(buf.length(), sizeLimit);
  2602. StringBuffer headerStr("attachment;");
  2603. if (filename && *filename)
  2604. {
  2605. const char* pFileName = strrchr(filename, PATHSEPCHAR);
  2606. if (pFileName)
  2607. headerStr.appendf("filename=%s", pFileName+1);
  2608. else
  2609. headerStr.appendf("filename=%s", filename);
  2610. }
  2611. MemoryBuffer buf0;
  2612. unsigned i = 0;
  2613. char* p = (char*) buf.toByteArray();
  2614. while (i < buf.length())
  2615. {
  2616. if (p[0] != 10)
  2617. buf0.append(p[0]);
  2618. else
  2619. buf0.append(0x0d);
  2620. p++;
  2621. i++;
  2622. }
  2623. resp.setThefile(buf);
  2624. resp.setThefile_mimetype(origMimeType);
  2625. context.addCustomerHeader("Content-disposition", headerStr.str());
  2626. }
  2627. else
  2628. {
  2629. #ifndef _USE_ZLIB
  2630. throw MakeStringException(ECLWATCH_CANNOT_COMPRESS_DATA,"The data cannot be compressed.");
  2631. #else
  2632. StringBuffer fileNameStr, headerStr("attachment;");
  2633. if (notEmpty(filename))
  2634. {
  2635. fileNameStr.append(filename);
  2636. headerStr.append("filename=").append(filename).append((opt>2) ? ".gz" : ".zip");
  2637. }
  2638. else
  2639. fileNameStr.append("file");
  2640. StringBuffer ifname;
  2641. ifname.appendf("%s%sT%xAT%x", TEMPZIPDIR, PATHSEPSTR, (unsigned)(memsize_t)GetCurrentThreadId(), msTick()).append((opt>2)? "" : ".zip");
  2642. IZZIPor* Zipor = createZZIPor();
  2643. int ret = 0;
  2644. if (opt > 2)
  2645. ret = Zipor->gzipToFile(buf.length(), (void*)buf.toByteArray(), ifname.str());
  2646. else
  2647. ret = Zipor->zipToFile(buf.length(), (void*)buf.toByteArray(), fileNameStr.str(), ifname.str());
  2648. releaseIZ(Zipor);
  2649. if (ret < 0)
  2650. {
  2651. Owned<IFile> rFile = createIFile(ifname.str());
  2652. if (rFile->exists())
  2653. rFile->remove();
  2654. throw MakeStringException(ECLWATCH_CANNOT_COMPRESS_DATA,"The data cannot be compressed.");
  2655. }
  2656. Owned <IFile> rf = createIFile(ifname.str());
  2657. if (!rf->exists())
  2658. throw MakeStringException(ECLWATCH_CANNOT_COMPRESS_DATA,"The data cannot be compressed.");
  2659. MemoryBuffer out;
  2660. Owned <IFileIO> fio = rf->open(IFOread);
  2661. read(fio, 0, (size32_t) rf->size(), out);
  2662. resp.setThefile(out);
  2663. fio.clear();
  2664. rf->remove();
  2665. resp.setThefile_mimetype((opt > 2) ? "application/x-gzip" : "application/zip");
  2666. context.addCustomerHeader("Content-disposition", headerStr.str());
  2667. #endif
  2668. }
  2669. }
  2670. bool CWsWorkunitsEx::onWUFile(IEspContext &context,IEspWULogFileRequest &req, IEspWULogFileResponse &resp)
  2671. {
  2672. try
  2673. {
  2674. StringBuffer wuidStr(req.getWuid());
  2675. const char* wuidIn = wuidStr.trim().str();
  2676. if (wuidIn && *wuidIn)
  2677. {
  2678. if (!looksLikeAWuid(wuidIn, 'W'))
  2679. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid Workunit ID");
  2680. ensureWsWorkunitAccess(context, wuidIn, SecAccess_Read);
  2681. }
  2682. StringAttr wuid(wuidIn);
  2683. if (wuid.isEmpty() && notEmpty(req.getQuerySet()) && notEmpty(req.getQuery()))
  2684. {
  2685. Owned<IPropertyTree> registry = getQueryRegistry(req.getQuerySet(), false);
  2686. if (!registry)
  2687. throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "Queryset %s not found", req.getQuerySet());
  2688. Owned<IPropertyTree> query = resolveQueryAlias(registry, req.getQuery());
  2689. if (!query)
  2690. throw MakeStringException(ECLWATCH_QUERYID_NOT_FOUND, "Query %s not found", req.getQuery());
  2691. resp.setQuerySet(req.getQuerySet());
  2692. resp.setQueryName(query->queryProp("@name"));
  2693. resp.setQueryId(query->queryProp("@id"));
  2694. wuid.set(query->queryProp("@wuid"));
  2695. }
  2696. int opt = req.getOption();
  2697. if (!wuid.isEmpty())
  2698. {
  2699. VStringBuffer logMsg("WUFile: %s", wuid.str());
  2700. if (notEmpty(req.getType()))
  2701. logMsg.append(", ").append(req.getType());
  2702. if (opt > 1)
  2703. logMsg.append(", download gzip");
  2704. else if (opt > 0)
  2705. logMsg.append(", download");
  2706. PROGLOG("%s", logMsg.str());
  2707. resp.setWuid(wuid.get());
  2708. MemoryBuffer mb;
  2709. WsWuInfo winfo(context, wuid);
  2710. if (strieq(File_ArchiveQuery, req.getType()))
  2711. {
  2712. winfo.getWorkunitArchiveQuery(mb);
  2713. openSaveFile(context, opt, req.getSizeLimit(), "ArchiveQuery.xml", HTTP_TYPE_APPLICATION_XML, mb, resp);
  2714. }
  2715. else if ((strieq(File_Cpp,req.getType()) || strieq(File_Log,req.getType())) && notEmpty(req.getName()))
  2716. {
  2717. winfo.getWorkunitCpp(req.getName(), req.getDescription(), req.getIPAddress(),mb, opt > 0, nullptr);
  2718. openSaveFile(context, opt, req.getSizeLimit(), req.getName(), HTTP_TYPE_TEXT_PLAIN, mb, resp);
  2719. }
  2720. else if (strieq(File_DLL,req.getType()))
  2721. {
  2722. StringBuffer name;
  2723. winfo.getWorkunitDll(name, mb);
  2724. resp.setFileName(name.str());
  2725. resp.setDaliServer(daliServers.get());
  2726. openSaveFile(context, opt, req.getSizeLimit(), req.getName(), HTTP_TYPE_OCTET_STREAM, mb, resp);
  2727. }
  2728. else if (strieq(File_Res,req.getType()))
  2729. {
  2730. winfo.getWorkunitResTxt(mb);
  2731. openSaveFile(context, opt, req.getSizeLimit(), "res.txt", HTTP_TYPE_TEXT_PLAIN, mb, resp);
  2732. }
  2733. else if (strncmp(req.getType(), File_ThorLog, 7) == 0)
  2734. {
  2735. winfo.getWorkunitThorMasterLog(nullptr, req.getName(), mb, nullptr);
  2736. openSaveFile(context, opt, req.getSizeLimit(), "thormaster.log", HTTP_TYPE_TEXT_PLAIN, mb, resp);
  2737. }
  2738. else if (strieq(File_ThorSlaveLog,req.getType()))
  2739. {
  2740. winfo.getWorkunitThorSlaveLog(directories, req.getProcess(), req.getClusterGroup(), req.getIPAddress(),
  2741. req.getLogDate(), req.getSlaveNumber(), mb, nullptr, false);
  2742. openSaveFile(context, opt, req.getSizeLimit(), "ThorSlave.log", HTTP_TYPE_TEXT_PLAIN, mb, resp);
  2743. }
  2744. else if (strieq(File_EclAgentLog,req.getType()))
  2745. {
  2746. winfo.getWorkunitEclAgentLog(nullptr, req.getName(), req.getProcess(), mb, nullptr);
  2747. openSaveFile(context, opt, req.getSizeLimit(), "eclagent.log", HTTP_TYPE_TEXT_PLAIN, mb, resp);
  2748. }
  2749. else if (strieq(File_XML,req.getType()) && notEmpty(req.getName()))
  2750. {
  2751. const char* name = req.getName();
  2752. const char* ptr = strrchr(name, '/');
  2753. if (ptr)
  2754. ptr++;
  2755. else
  2756. ptr = name;
  2757. winfo.getWorkunitAssociatedXml(name, req.getIPAddress(), req.getPlainText(), req.getDescription(), opt > 0, true, mb, nullptr);
  2758. openSaveFile(context, opt, req.getSizeLimit(), ptr, HTTP_TYPE_APPLICATION_XML, mb, resp);
  2759. }
  2760. else if (strieq(File_XML,req.getType()) || strieq(File_WUECL,req.getType()))
  2761. {
  2762. StringBuffer mimeType, fileName;
  2763. if (strieq(File_WUECL,req.getType()))
  2764. {
  2765. fileName.setf("%s.ecl", wuid.get());
  2766. winfo.getWorkunitQueryShortText(mb, nullptr);
  2767. mimeType.set(HTTP_TYPE_TEXT_PLAIN);
  2768. }
  2769. else
  2770. {
  2771. fileName.setf("%s.xml", wuid.get());
  2772. winfo.getWorkunitXml(req.getPlainText(), mb);
  2773. if (opt < 2)
  2774. {
  2775. const char* plainText = req.getPlainText();
  2776. if (plainText && (!stricmp(plainText, "yes")))
  2777. mimeType.set(HTTP_TYPE_TEXT_PLAIN);
  2778. else
  2779. mimeType.set(HTTP_TYPE_APPLICATION_XML);
  2780. }
  2781. else
  2782. {
  2783. mimeType.set(HTTP_TYPE_APPLICATION_XML);
  2784. }
  2785. }
  2786. openSaveFile(context, opt, req.getSizeLimit(), fileName.str(), mimeType.str(), mb, resp);
  2787. }
  2788. PROGLOG("%s -- done", logMsg.str());
  2789. }
  2790. }
  2791. catch(IException* e)
  2792. {
  2793. CErrorMessageFormat errorMessageFormat = req.getErrorMessageFormat();
  2794. if (errorMessageFormat == CErrorMessageFormat_XML)
  2795. context.setResponseFormat(ESPSerializationXML);
  2796. else if (errorMessageFormat == CErrorMessageFormat_JSON)
  2797. context.setResponseFormat(ESPSerializationJSON);
  2798. else if (errorMessageFormat == CErrorMessageFormat_Text)
  2799. context.setResponseFormat(ESPSerializationTEXT);
  2800. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  2801. }
  2802. return true;
  2803. }
  2804. IPropertyTree *getArchivedWorkUnitProperties(const char *wuid, bool dfuWU)
  2805. {
  2806. SocketEndpoint ep;
  2807. getSashaNode(ep);
  2808. Owned<INode> node = createINode(ep);
  2809. if (!node)
  2810. throw MakeStringException(ECLWATCH_INODE_NOT_FOUND, "INode not found.");
  2811. StringBuffer tmp;
  2812. Owned<ISashaCommand> cmd = createSashaCommand();
  2813. cmd->addId(wuid);
  2814. cmd->setAction(SCA_GET);
  2815. cmd->setArchived(true);
  2816. if (dfuWU)
  2817. cmd->setDFU(true);
  2818. if (!cmd->send(node, 1*60*1000))
  2819. throw MakeStringException(ECLWATCH_CANNOT_CONNECT_ARCHIVE_SERVER,
  2820. "Sasha (%s) took too long to respond from: Get workUnit properties for %s.",
  2821. ep.getUrlStr(tmp).str(), wuid);
  2822. if ((cmd->numIds() < 1) || (cmd->numResults() < 1))
  2823. return nullptr;
  2824. cmd->getResult(0, tmp.clear());
  2825. if(tmp.length() < 1)
  2826. return nullptr;
  2827. Owned<IPropertyTree> wu = createPTreeFromXMLString(tmp.str());
  2828. if (!wu)
  2829. return nullptr;
  2830. return wu.getClear();
  2831. }
  2832. void getWorkunitCluster(IEspContext &context, const char *wuid, SCMStringBuffer &cluster, bool checkArchiveWUs)
  2833. {
  2834. if (isEmpty(wuid))
  2835. return;
  2836. if ('W' == wuid[0])
  2837. {
  2838. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  2839. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid);
  2840. if (cw)
  2841. cluster.set(cw->queryClusterName());
  2842. else if (checkArchiveWUs)
  2843. {
  2844. Owned<IPropertyTree> wuProps = getArchivedWorkUnitProperties(wuid, false);
  2845. if (wuProps)
  2846. cluster.set(wuProps->queryProp("@clusterName"));
  2847. }
  2848. }
  2849. else
  2850. {
  2851. Owned<IDFUWorkUnitFactory> factory = getDFUWorkUnitFactory();
  2852. Owned<IConstDFUWorkUnit> cw = factory->openWorkUnit(wuid, false);
  2853. if(cw)
  2854. {
  2855. StringBuffer tmp;
  2856. if (cw->getClusterName(tmp).length()!=0)
  2857. cluster.set(tmp.str());
  2858. }
  2859. else if (checkArchiveWUs)
  2860. {
  2861. Owned<IPropertyTree> wuProps = getArchivedWorkUnitProperties(wuid, true);
  2862. if (wuProps)
  2863. cluster.set(wuProps->queryProp("@clusterName"));
  2864. }
  2865. }
  2866. }
  2867. void CWsWorkunitsEx::getFileResults(IEspContext &context, const char *logicalName, const char *cluster, __int64 start, unsigned &count, __int64 &total,
  2868. IStringVal &resname, bool bin, IArrayOf<IConstNamedValue> *filterBy, MemoryBuffer &buf, bool xsd)
  2869. {
  2870. Owned<IDistributedFile> df = lookupLogicalName(context, logicalName, false, false, false, nullptr, defaultPrivilegedUser);
  2871. if (!df)
  2872. throw makeStringExceptionV(ECLWATCH_FILE_NOT_EXIST, "Cannot find file %s.", logicalName);
  2873. Owned<IResultSetFactory> resultSetFactory = getSecResultSetFactory(context.querySecManager(), context.queryUser(), context.queryUserId(), context.queryPassword());
  2874. Owned<INewResultSet> result(resultSetFactory->createNewFileResultSet(df, cluster));
  2875. if (!filterBy || !filterBy->length())
  2876. {
  2877. if (isResultRequestSzTooBig(start, count, df->getDiskSize(true, false), result->getNumRows(), wuResultMaxSize))
  2878. {
  2879. throw makeStringExceptionV(ECLWATCH_INVALID_ACTION, "Failed to get the result from file %s. The size is bigger than %lld MB.",
  2880. logicalName, wuResultMaxSize/0x100000);
  2881. }
  2882. appendResultSet(buf, result, resname.str(), start, count, total, bin, xsd, context.getResponseFormat(), NULL);
  2883. }
  2884. else
  2885. {
  2886. // NB: this could be still be very big, appendResultSet should be changed to ensure filtered result doesn't grow bigger than wuResultMaxSize
  2887. Owned<INewResultSet> filteredResult = createFilteredResultSet(result, filterBy);
  2888. appendResultSet(buf, filteredResult, resname.str(), start, count, total, bin, xsd, context.getResponseFormat(), NULL);
  2889. }
  2890. }
  2891. bool CWsWorkunitsEx::onWUResultBin(IEspContext &context,IEspWUResultBinRequest &req, IEspWUResultBinResponse &resp)
  2892. {
  2893. try
  2894. {
  2895. StringBuffer wuidStr(req.getWuid());
  2896. const char* wuidIn = wuidStr.trim().str();
  2897. if (wuidIn && *wuidIn)
  2898. {
  2899. if (!looksLikeAWuid(wuidIn, 'W'))
  2900. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid Workunit ID: %s", wuidIn);
  2901. ensureWsWorkunitAccess(context, wuidIn, SecAccess_Read);
  2902. }
  2903. MemoryBuffer mb;
  2904. __int64 total=0;
  2905. __int64 start = req.getStart() > 0 ? req.getStart() : 0;
  2906. unsigned count = req.getCount(), requested=count;
  2907. IArrayOf<IConstNamedValue>* filterBy = &req.getFilterBy();
  2908. SCMStringBuffer name;
  2909. if(strieq(req.getFormat(),"csv"))
  2910. context.setResponseFormat(ESPSerializationCSV);
  2911. WUState wuState = WUStateUnknown;
  2912. bool bin = (req.getFormat() && strieq(req.getFormat(),"raw"));
  2913. if (notEmpty(wuidIn) && notEmpty(req.getResultName()))
  2914. {
  2915. PROGLOG("WUResultBin: wuid %s, ResultName %s", wuidIn, req.getResultName());
  2916. getWsWuResult(context, wuidIn, req.getResultName(), NULL, 0, start, count, total, name, bin, filterBy, mb, wuState);
  2917. }
  2918. else if (notEmpty(wuidIn) && (req.getSequence() >= 0))
  2919. {
  2920. PROGLOG("WUResultBin: wuid %s, Sequence %d", wuidIn, req.getSequence());
  2921. getWsWuResult(context, wuidIn, NULL, NULL, req.getSequence(), start, count, total, name, bin,filterBy, mb, wuState);
  2922. }
  2923. else if (notEmpty(req.getLogicalName()))
  2924. {
  2925. const char* logicalName = req.getLogicalName();
  2926. const char* clusterIn = req.getCluster();
  2927. if (!isEmptyString(clusterIn))
  2928. getFileResults(context, logicalName, clusterIn, start, count, total, name, false, filterBy, mb, true);
  2929. else
  2930. {
  2931. StringBuffer wuid;
  2932. getWuidFromLogicalFileName(context, logicalName, wuid);
  2933. if (!wuid.length())
  2934. throw MakeStringException(ECLWATCH_CANNOT_GET_WORKUNIT,"Cannot find the workunit for file %s.",logicalName);
  2935. SCMStringBuffer cluster;
  2936. getWorkunitCluster(context, wuid.str(), cluster, true);
  2937. if (cluster.length() > 0)
  2938. getFileResults(context, logicalName, cluster.str(), start, count, total, name, false, filterBy, mb, true);
  2939. else
  2940. getWsWuResult(context, wuid.str(), NULL, logicalName, 0, start, count, total, name, bin, filterBy, mb, wuState);
  2941. }
  2942. }
  2943. else
  2944. throw MakeStringException(ECLWATCH_CANNOT_GET_WU_RESULT,"Cannot open the workunit result.");
  2945. if(strieq(req.getFormat(),"csv"))
  2946. {
  2947. resp.setResult(mb);
  2948. resp.setResult_mimetype("text/csv");
  2949. context.addCustomerHeader("Content-disposition", "attachment;filename=WUResult.csv");
  2950. }
  2951. else if(stricmp(req.getFormat(),"xls")==0)
  2952. {
  2953. Owned<IProperties> params(createProperties());
  2954. params->setProp("showCount",0);
  2955. StringBuffer xml;
  2956. xml.append("<WUResultExcel><Result>").append(mb.length(), mb.toByteArray()).append("</Result></WUResultExcel>");
  2957. if (xml.length() > MAXXLSTRANSFER)
  2958. throw MakeStringException(ECLWATCH_TOO_BIG_DATA_SET, "The data set is too big to be converted to an Excel file. Please use the gzip link to download a compressed XML data file.");
  2959. StringBuffer xls;
  2960. xsltTransform(xml.str(), StringBuffer(getCFD()).append("./smc_xslt/result.xslt").str(), params, xls);
  2961. MemoryBuffer out;
  2962. out.setBuffer(xls.length(), (void*)xls.str());
  2963. resp.setResult(out);
  2964. resp.setResult_mimetype("application/vnd.ms-excel");
  2965. }
  2966. #ifdef _USE_ZLIB
  2967. else if(strieq(req.getFormat(),"zip") || strieq(req.getFormat(),"gzip"))
  2968. {
  2969. bool gzip = strieq(req.getFormat(),"gzip");
  2970. StringBuffer xml("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
  2971. xml.append("<Result>").append(mb.length(),mb.toByteArray()).append("</Result>");
  2972. VStringBuffer ifname("%s%sT%xAT%x%s", TEMPZIPDIR, PATHSEPSTR, (unsigned)(memsize_t)GetCurrentThreadId(), msTick(), gzip ? "" : ".zip");
  2973. IZZIPor* Zipor = createZZIPor();
  2974. int ret = 0;
  2975. if (gzip)
  2976. ret = Zipor->gzipToFile(xml.length(), (void*)xml.str(), ifname.str());
  2977. else
  2978. ret = Zipor->zipToFile(xml.length(), (void*)xml.str(), "WUResult.xml", ifname.str());
  2979. releaseIZ(Zipor);
  2980. if (ret < 0)
  2981. {
  2982. Owned<IFile> rFile = createIFile(ifname.str());
  2983. if (rFile->exists())
  2984. rFile->remove();
  2985. throw MakeStringException(ECLWATCH_CANNOT_COMPRESS_DATA, "The data cannot be compressed.");
  2986. }
  2987. MemoryBuffer out;
  2988. Owned <IFile> rf = createIFile(ifname.str());
  2989. if (rf->exists())
  2990. {
  2991. Owned <IFileIO> fio = rf->open(IFOread);
  2992. read(fio, 0, (size32_t) rf->size(), out);
  2993. resp.setResult(out);
  2994. }
  2995. if (gzip)
  2996. {
  2997. resp.setResult_mimetype("application/x-gzip");
  2998. context.addCustomerHeader("Content-disposition", "attachment;filename=WUResult.xml.gz");
  2999. }
  3000. else
  3001. {
  3002. resp.setResult_mimetype("application/zip");
  3003. context.addCustomerHeader("Content-disposition", "attachment;filename=WUResult.xml.zip");
  3004. }
  3005. Owned<IFile> rFile = createIFile(ifname.str());
  3006. if (rFile->exists())
  3007. rFile->remove();
  3008. }
  3009. #endif
  3010. else
  3011. {
  3012. resp.setResult(mb);
  3013. }
  3014. resp.setName(name.str());
  3015. resp.setWuid(wuidIn);
  3016. resp.setSequence(req.getSequence());
  3017. resp.setStart(start);
  3018. if (requested > total)
  3019. requested = (unsigned)total;
  3020. resp.setRequested(requested);
  3021. resp.setCount(count);
  3022. resp.setTotal(total);
  3023. resp.setFormat(req.getFormat());
  3024. }
  3025. catch(IException* e)
  3026. {
  3027. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  3028. }
  3029. return true;
  3030. }
  3031. bool CWsWorkunitsEx::onWUResultSummary(IEspContext &context, IEspWUResultSummaryRequest &req, IEspWUResultSummaryResponse &resp)
  3032. {
  3033. try
  3034. {
  3035. StringBuffer wuid(req.getWuid());
  3036. WsWuHelpers::checkAndTrimWorkunit("WUResultSummary", wuid);
  3037. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  3038. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  3039. if(!cw)
  3040. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot open workunit %s.",wuid.str());
  3041. ensureWsWorkunitAccess(context, *cw, SecAccess_Read);
  3042. PROGLOG("WUResultSummary: %s", wuid.str());
  3043. resp.setWuid(wuid.str());
  3044. resp.setSequence(req.getSequence());
  3045. IArrayOf<IEspECLResult> results;
  3046. Owned<IConstWUResult> r = cw->getResultBySequence(req.getSequence());
  3047. if (r)
  3048. {
  3049. WsWuInfo winfo(context, cw);
  3050. winfo.getResult(*r, results, 0);
  3051. resp.setFormat(r->getResultFormat());
  3052. resp.setResult(results.item(0));
  3053. }
  3054. }
  3055. catch(IException* e)
  3056. {
  3057. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  3058. }
  3059. return true;
  3060. }
  3061. bool CWsWorkunitsEx::onWUResult(IEspContext &context, IEspWUResultRequest &req, IEspWUResultResponse &resp)
  3062. {
  3063. try
  3064. {
  3065. StringBuffer wuidStr(req.getWuid());
  3066. const char* wuid = wuidStr.trim().str();
  3067. if (wuid && *wuid)
  3068. {
  3069. if (!looksLikeAWuid(wuid, 'W'))
  3070. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid Workunit ID: %s", wuid);
  3071. ensureWsWorkunitAccess(context, wuid, SecAccess_Read);
  3072. }
  3073. MemoryBuffer mb;
  3074. SCMStringBuffer name;
  3075. __int64 total=0;
  3076. __int64 start = req.getStart() > 0 ? req.getStart() : 0;
  3077. unsigned count=req.getCount() ? req.getCount() : 100, requested=count;
  3078. unsigned seq = req.getSequence();
  3079. bool inclXsd = !req.getSuppressXmlSchema();
  3080. VStringBuffer filter("start=%" I64F "d;count=%d", start, count);
  3081. addToQueryString(filter, "clusterName", req.getCluster(), ';');
  3082. addToQueryString(filter, "logicalName", req.getLogicalName(), ';');
  3083. if (wuid && *wuid)
  3084. addToQueryString(filter, "wuid", wuid, ';');
  3085. addToQueryString(filter, "resultName", req.getResultName(), ';');
  3086. filter.appendf(";seq=%d;", seq);
  3087. if (inclXsd)
  3088. filter.append("xsd;");
  3089. if (context.getResponseFormat()==ESPSerializationJSON)
  3090. filter.append("json;");
  3091. IArrayOf<IConstNamedValue>* filterBy = &req.getFilterBy();
  3092. ForEachItemIn(i, *filterBy)
  3093. {
  3094. IConstNamedValue &item = filterBy->item(i);
  3095. const char *name = item.getName();
  3096. const char *value = item.getValue();
  3097. if (name && *name && value && *value)
  3098. addToQueryString(filter, name, value, ';');
  3099. }
  3100. const char* logicalName = req.getLogicalName();
  3101. const char* clusterName = req.getCluster();
  3102. const char* resultName = req.getResultName();
  3103. Owned<DataCacheElement> data;
  3104. if (!req.getBypassCachedResult())
  3105. data.setown(dataCache->lookup(context, filter, awusCacheMinutes));
  3106. if (data)
  3107. {
  3108. PROGLOG("Retrieving Cached WUResult: %s", filter.str());
  3109. mb.append(data->m_data.c_str());
  3110. name.set(data->m_name.c_str());
  3111. logicalName = data->m_logicalName.c_str();
  3112. wuid = data->m_wuid.c_str();
  3113. resultName = data->m_resultName.c_str();
  3114. seq = data->m_seq;
  3115. start = data->m_start;
  3116. count = data->m_rowcount;
  3117. requested = (unsigned)data->m_requested;
  3118. total = data->m_total;
  3119. if (notEmpty(logicalName))
  3120. resp.setLogicalName(logicalName);
  3121. else
  3122. {
  3123. if (notEmpty(wuid))
  3124. resp.setWuid(wuid);
  3125. resp.setSequence(seq);
  3126. }
  3127. }
  3128. else
  3129. {
  3130. PROGLOG("Retrieving WUResult: %s", filter.str());
  3131. WUState wuState = WUStateUnknown;
  3132. if(logicalName && *logicalName)
  3133. {
  3134. StringBuffer lwuid;
  3135. getWuidFromLogicalFileName(context, logicalName, lwuid);
  3136. SCMStringBuffer cluster;
  3137. if (lwuid.length())
  3138. getWorkunitCluster(context, lwuid.str(), cluster, true);
  3139. if (cluster.length())
  3140. {
  3141. getFileResults(context, logicalName, cluster.str(), start, count, total, name, false, filterBy, mb, inclXsd);
  3142. resp.setLogicalName(logicalName);
  3143. }
  3144. else if (notEmpty(clusterName))
  3145. {
  3146. getFileResults(context, logicalName, clusterName, start, count, total, name, false, filterBy, mb, inclXsd);
  3147. resp.setLogicalName(logicalName);
  3148. }
  3149. else
  3150. throw MakeStringException(ECLWATCH_INVALID_INPUT,"Need valid target cluster to browse file %s.",logicalName);
  3151. Owned<IWorkUnitFactory> wf = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  3152. Owned<IConstWorkUnit> cw = wf->openWorkUnit(lwuid.str());
  3153. if (cw)
  3154. wuState = cw->getState();
  3155. }
  3156. else if (notEmpty(wuid) && notEmpty(resultName))
  3157. {
  3158. name.set(resultName);
  3159. getWsWuResult(context, wuid, resultName, NULL, 0, start, count, total, name, false, filterBy, mb, wuState, inclXsd);
  3160. resp.setWuid(wuid);
  3161. resp.setSequence(seq);
  3162. }
  3163. else
  3164. {
  3165. getWsWuResult(context, wuid, NULL, NULL, seq, start, count, total, name, false, filterBy, mb, wuState, inclXsd);
  3166. resp.setWuid(wuid);
  3167. resp.setSequence(seq);
  3168. }
  3169. mb.append(0);
  3170. if (requested > total)
  3171. requested = (unsigned)total;
  3172. switch (wuState)
  3173. {
  3174. case WUStateCompleted:
  3175. case WUStateAborted:
  3176. case WUStateFailed:
  3177. case WUStateArchived:
  3178. dataCache->add(filter, mb.toByteArray(), name.str(), logicalName, wuid, resultName, seq, start, count, requested, total);
  3179. break;
  3180. }
  3181. }
  3182. resp.setName(name.str());
  3183. resp.setStart(start);
  3184. if (clusterName && *clusterName)
  3185. resp.setCluster(clusterName);
  3186. resp.setRequested(requested);
  3187. resp.setCount(count);
  3188. resp.setTotal(total);
  3189. resp.setResult(mb.toByteArray());
  3190. context.queryXslParameters()->setProp("escapeResults","1");
  3191. }
  3192. catch(IException* e)
  3193. {
  3194. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  3195. }
  3196. return true;
  3197. }
  3198. void getScheduledWUs(IEspContext &context, WUShowScheduledFilters *filters, const char *serverName, IArrayOf<IEspScheduledWU> & results)
  3199. {
  3200. double version = context.getClientVersion();
  3201. if (notEmpty(serverName))
  3202. {
  3203. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  3204. Owned<IScheduleReader> reader;
  3205. try
  3206. {
  3207. reader.setown(getScheduleReader(serverName, filters->eventName));
  3208. }
  3209. catch (IException *e)
  3210. {
  3211. StringBuffer eMsg;
  3212. e->errorMessage(eMsg);
  3213. e->Release();
  3214. IWARNLOG("Failed to getScheduleReader for %s: %s", serverName, eMsg.str());
  3215. return;
  3216. }
  3217. Owned<IScheduleReaderIterator> it(reader->getIterator());
  3218. while(it->isValidEventName())
  3219. {
  3220. StringBuffer ieventName;
  3221. it->getEventName(ieventName);
  3222. while(it->isValidEventText())
  3223. {
  3224. StringBuffer ieventText;
  3225. it->getEventText(ieventText);
  3226. while(it->isValidWuid())
  3227. {
  3228. StringBuffer wuid;
  3229. it->getWuid(wuid);
  3230. if (wuid.length())
  3231. {
  3232. bool match = true;
  3233. unsigned stateID = WUStateUnknown;
  3234. StringBuffer jobName, owner;
  3235. SCMStringBuffer state;
  3236. try
  3237. {
  3238. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  3239. if (cw)
  3240. {
  3241. jobName.set(cw->queryJobName());
  3242. owner.set(cw->queryUser());
  3243. }
  3244. if (!filters->jobName.isEmpty() && (jobName.isEmpty() || !WildMatch(jobName.str(), filters->jobName, true)))
  3245. match = false;
  3246. else if (!filters->owner.isEmpty() && (owner.isEmpty() || !WildMatch(owner, filters->owner, true)))
  3247. match = false;
  3248. else if (!filters->eventText.isEmpty() && (ieventText.isEmpty() || !WildMatch(ieventText, filters->eventText, true)))
  3249. match = false;
  3250. else if (!filters->state.isEmpty())
  3251. {
  3252. if (!cw)
  3253. match = false;
  3254. else
  3255. {
  3256. if ((cw->getState() == WUStateScheduled) && cw->aborting())
  3257. {
  3258. stateID = WUStateAborting;
  3259. state.set("aborting");
  3260. }
  3261. else
  3262. {
  3263. stateID = cw->getState();
  3264. state.set(cw->queryStateDesc());
  3265. }
  3266. if (!strieq(filters->state, state.str()))
  3267. match = false;
  3268. }
  3269. }
  3270. }
  3271. catch (IException *e)
  3272. {
  3273. EXCLOG(e, "Get scheduled WUs");
  3274. e->Release();
  3275. match = false;
  3276. }
  3277. if (!match)
  3278. {
  3279. it->nextWuid();
  3280. continue;
  3281. }
  3282. Owned<IEspScheduledWU> scheduledWU = createScheduledWU("");
  3283. scheduledWU->setWuid(wuid.str());
  3284. scheduledWU->setCluster(serverName);
  3285. if (ieventName.length())
  3286. scheduledWU->setEventName(ieventName.str());
  3287. if (ieventText.str())
  3288. scheduledWU->setEventText(ieventText.str());
  3289. if (jobName.length())
  3290. scheduledWU->setJobName(jobName.str());
  3291. if (version >= 1.51)
  3292. {
  3293. if (owner.length())
  3294. scheduledWU->setOwner(owner.str());
  3295. if (state.length())
  3296. {
  3297. scheduledWU->setStateID(stateID);
  3298. scheduledWU->setState(state.str());
  3299. }
  3300. }
  3301. results.append(*scheduledWU.getLink());
  3302. }
  3303. it->nextWuid();
  3304. }
  3305. it->nextEventText();
  3306. }
  3307. it->nextEventName();
  3308. }
  3309. }
  3310. return;
  3311. }
  3312. bool CWsWorkunitsEx::onWUShowScheduled(IEspContext &context, IEspWUShowScheduledRequest & req, IEspWUShowScheduledResponse & resp)
  3313. {
  3314. try
  3315. {
  3316. WUShowScheduledFilters filters(req.getCluster(), req.getState(), req.getOwner(),
  3317. req.getJobName(), req.getEventName(), req.getEventText());
  3318. IArrayOf<IEspScheduledWU> results;
  3319. if(notEmpty(req.getPushEventName()))
  3320. resp.setPushEventName(req.getPushEventName());
  3321. if(notEmpty(req.getPushEventText()))
  3322. resp.setPushEventText(req.getPushEventText());
  3323. Owned<IEnvironmentFactory> factory = getEnvironmentFactory(true);
  3324. Owned<IConstEnvironment> environment = factory->openEnvironment();
  3325. Owned<IPropertyTree> root = &environment->getPTree();
  3326. unsigned i = 0;
  3327. Owned<IPropertyTreeIterator> ic = root->getElements("Software/Topology/Cluster");
  3328. IArrayOf<IEspServerInfo> servers;
  3329. ForEach(*ic)
  3330. {
  3331. IPropertyTree &cluster = ic->query();
  3332. const char *iclusterName = cluster.queryProp("@name");
  3333. if (isEmpty(iclusterName))
  3334. continue;
  3335. if (filters.cluster.isEmpty())
  3336. getScheduledWUs(context, &filters, iclusterName, results);
  3337. else if (strieq(filters.cluster, iclusterName))
  3338. {
  3339. getScheduledWUs(context, &filters, filters.cluster, results);
  3340. resp.setClusterSelected(i+1);
  3341. }
  3342. Owned<IEspServerInfo> server = createServerInfo("");
  3343. server->setName(iclusterName);
  3344. servers.append(*server.getLink());
  3345. i++;
  3346. }
  3347. if (servers.length())
  3348. resp.setClusters(servers);
  3349. if (results.length())
  3350. resp.setWorkunits(results);
  3351. bool first=false;
  3352. StringBuffer Query("PageFrom=Scheduler");
  3353. appendUrlParameter(Query, "EventName", filters.eventName, first);
  3354. appendUrlParameter(Query, "ECluster", filters.cluster, first);
  3355. resp.setQuery(Query.str());
  3356. }
  3357. catch(IException* e)
  3358. {
  3359. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  3360. }
  3361. return true;
  3362. }
  3363. bool CWsWorkunitsEx::onWUExport(IEspContext &context, IEspWUExportRequest &req, IEspWUExportResponse &resp)
  3364. {
  3365. try
  3366. {
  3367. if (req.getECL() && *req.getECL())
  3368. throw makeStringException(0, "WUExport no longer supports filtering by ECL text");
  3369. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  3370. WsWuSearch ws(context, req.getOwner(), req.getState(), req.getCluster(), req.getStartDate(), req.getEndDate(), req.getJobname());
  3371. StringBuffer xml("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Workunits>");
  3372. for(WsWuSearch::iterator it=ws.begin(); it!=ws.end(); it++)
  3373. {
  3374. Owned<IConstWorkUnit> cw = factory->openWorkUnit(it->c_str());
  3375. if (cw)
  3376. exportWorkUnitToXML(cw, xml, true, false, true);
  3377. }
  3378. xml.append("</Workunits>");
  3379. MemoryBuffer mb;
  3380. mb.setBuffer(xml.length(),(void*)xml.str());
  3381. resp.setExportData(mb);
  3382. resp.setExportData_mimetype(HTTP_TYPE_APPLICATION_XML);
  3383. }
  3384. catch(IException* e)
  3385. {
  3386. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  3387. }
  3388. return true;
  3389. }
  3390. bool CWsWorkunitsEx::onWUListLocalFileRequired(IEspContext& context, IEspWUListLocalFileRequiredRequest& req, IEspWUListLocalFileRequiredResponse& resp)
  3391. {
  3392. try
  3393. {
  3394. StringBuffer wuid(req.getWuid());
  3395. WsWuHelpers::checkAndTrimWorkunit("WUListLocalFileRequired", wuid);
  3396. ensureWsWorkunitAccess(context, wuid.str(), SecAccess_Read);
  3397. PROGLOG("WUListLocalFileRequired: %s", wuid.str());
  3398. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  3399. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  3400. if (!cw)
  3401. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT, "Workunit %s not found.", wuid.str());
  3402. IArrayOf<IEspLogicalFileUpload> localFiles;
  3403. Owned<IConstLocalFileUploadIterator> it = cw->getLocalFileUploads();
  3404. ForEach(*it)
  3405. {
  3406. Owned<IConstLocalFileUpload> file = it->get();
  3407. if(!file)
  3408. continue;
  3409. Owned<IEspLogicalFileUpload> up = createLogicalFileUpload();
  3410. SCMStringBuffer s;
  3411. up->setType(file->queryType());
  3412. up->setSource(file->getSource(s).str());
  3413. up->setDestination(file->getDestination(s).str());
  3414. up->setEventTag(file->getEventTag(s).str());
  3415. localFiles.append(*up.getLink());
  3416. }
  3417. resp.setLocalFileUploads(localFiles);
  3418. }
  3419. catch(IException* e)
  3420. {
  3421. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  3422. }
  3423. return true;
  3424. }
  3425. typedef enum wsEclTypes_
  3426. {
  3427. wsEclTypeUnknown,
  3428. xsdString,
  3429. xsdBoolean,
  3430. xsdDecimal,
  3431. xsdFloat,
  3432. xsdDouble,
  3433. xsdDuration,
  3434. xsdDateTime,
  3435. xsdTime,
  3436. xsdDate,
  3437. xsdYearMonth,
  3438. xsdYear,
  3439. xsdMonthDay,
  3440. xsdDay,
  3441. xsdMonth,
  3442. xsdHexBinary,
  3443. xsdBase64Binary,
  3444. xsdAnyURI,
  3445. xsdQName,
  3446. xsdNOTATION,
  3447. xsdNormalizedString,
  3448. xsdToken,
  3449. xsdLanguage,
  3450. xsdNMTOKEN,
  3451. xsdNMTOKENS,
  3452. xsdName,
  3453. xsdNCName,
  3454. xsdID,
  3455. xsdIDREF,
  3456. xsdIDREFS,
  3457. xsdENTITY,
  3458. xsdENTITIES,
  3459. xsdInteger,
  3460. xsdNonPositiveInteger,
  3461. xsdNegativeInteger,
  3462. xsdLong,
  3463. xsdInt,
  3464. xsdShort,
  3465. xsdByte,
  3466. xsdNonNegativeInteger,
  3467. xsdUnsignedLong,
  3468. xsdUnsignedInt,
  3469. xsdUnsignedShort,
  3470. xsdUnsignedByte,
  3471. xsdPositiveInteger,
  3472. tnsRawDataFile,
  3473. tnsCsvDataFile,
  3474. tnsEspStringArray,
  3475. tnsEspIntArray,
  3476. tnsXmlDataSet,
  3477. maxWsEclType
  3478. } wsEclType;
  3479. bool CWsWorkunitsEx::onWUAddLocalFileToWorkunit(IEspContext& context, IEspWUAddLocalFileToWorkunitRequest& req, IEspWUAddLocalFileToWorkunitResponse& resp)
  3480. {
  3481. try
  3482. {
  3483. StringBuffer wuid(req.getWuid());
  3484. WsWuHelpers::checkAndTrimWorkunit("WUAddLocalFileToWorkunit", wuid);
  3485. ensureWsWorkunitAccess(context, wuid.str(), SecAccess_Write);
  3486. resp.setWuid(wuid.str());
  3487. const char* varname = req.getName();
  3488. if (isEmpty(varname))
  3489. {
  3490. resp.setResult("Name is not defined!");
  3491. return true;
  3492. }
  3493. resp.setName(varname);
  3494. PROGLOG("WUAddLocalFileToWorkunit: %s, name %s", wuid.str(), varname);
  3495. wsEclType type = (wsEclType) req.getType();
  3496. const char *val = req.getVal();
  3497. unsigned len = req.getLength();
  3498. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  3499. WorkunitUpdate wu(factory->updateWorkUnit(wuid.str()));
  3500. if (!wu)
  3501. {
  3502. resp.setResult("Workunit not found!");
  3503. return true;
  3504. }
  3505. Owned<IWUResult> wuRslt = wu->updateResultByName(varname);
  3506. if (isEmpty(val))
  3507. val=req.getDefVal();
  3508. if (notEmpty(val))
  3509. {
  3510. switch (type)
  3511. {
  3512. case xsdBoolean:
  3513. wuRslt->setResultBool((strieq(val, "1") || strieq(val, "true") || strieq(val, "on")));
  3514. wuRslt->setResultStatus(ResultStatusSupplied);
  3515. break;
  3516. case xsdDecimal:
  3517. case xsdFloat:
  3518. case xsdDouble:
  3519. wuRslt->setResultReal(atof(val));
  3520. wuRslt->setResultStatus(ResultStatusSupplied);
  3521. break;
  3522. case xsdInteger:
  3523. case xsdNonPositiveInteger:
  3524. case xsdNegativeInteger:
  3525. case xsdLong:
  3526. case xsdInt:
  3527. case xsdShort:
  3528. case xsdByte:
  3529. case xsdNonNegativeInteger:
  3530. case xsdUnsignedLong:
  3531. case xsdUnsignedInt:
  3532. case xsdUnsignedShort:
  3533. case xsdUnsignedByte:
  3534. case xsdPositiveInteger:
  3535. wuRslt->setResultInt(_atoi64(val));
  3536. wuRslt->setResultStatus(ResultStatusSupplied);
  3537. break;
  3538. case tnsEspIntArray:
  3539. case tnsEspStringArray:
  3540. wuRslt->setResultRaw(len, val, ResultFormatXmlSet);
  3541. break;
  3542. case tnsRawDataFile:
  3543. wuRslt->setResultRaw(len, val, ResultFormatRaw);
  3544. break;
  3545. case tnsXmlDataSet:
  3546. wuRslt->setResultRaw(len, val, ResultFormatXml);
  3547. break;
  3548. case tnsCsvDataFile:
  3549. case xsdBase64Binary: //tbd
  3550. case xsdHexBinary:
  3551. break;
  3552. default:
  3553. wuRslt->setResultString(val, len);
  3554. wuRslt->setResultStatus(ResultStatusSupplied);
  3555. break;
  3556. }
  3557. }
  3558. resp.setResult("Result has been set as required!");
  3559. }
  3560. catch(IException* e)
  3561. {
  3562. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  3563. }
  3564. return true;
  3565. }
  3566. bool CWsWorkunitsEx::onWUGetGraphNameAndTypes(IEspContext &context,IEspWUGetGraphNameAndTypesRequest &req, IEspWUGetGraphNameAndTypesResponse &resp)
  3567. {
  3568. try
  3569. {
  3570. StringBuffer wuid(req.getWuid());
  3571. WsWuHelpers::checkAndTrimWorkunit("WUGraphQuery", wuid);
  3572. ensureWsWorkunitAccess(context, wuid.str(), SecAccess_Read);
  3573. PROGLOG("WUGetGraphNameAndTypes: %s", wuid.str());
  3574. StringBuffer type(req.getType());
  3575. WUGraphType graphType = GraphTypeAny;
  3576. if (type.trim().length())
  3577. graphType = getGraphTypeFromString(type.str());
  3578. IArrayOf<IEspNameAndType> graphNameAndTypes;
  3579. WsWuInfo winfo(context, wuid.str());
  3580. winfo.getWUGraphNameAndTypes(graphType, graphNameAndTypes);
  3581. resp.setGraphNameAndTypes(graphNameAndTypes);
  3582. }
  3583. catch(IException* e)
  3584. {
  3585. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  3586. }
  3587. return true;
  3588. }
  3589. bool CWsWorkunitsEx::onWUProcessGraph(IEspContext &context,IEspWUProcessGraphRequest &req, IEspWUProcessGraphResponse &resp)
  3590. {
  3591. try
  3592. {
  3593. StringBuffer wuid(req.getWuid());
  3594. WsWuHelpers::checkAndTrimWorkunit("WUProcessGraph", wuid);
  3595. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  3596. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  3597. if(!cw)
  3598. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot open workunit %s.",wuid.str());
  3599. ensureWsWorkunitAccess(context, *cw, SecAccess_Read);
  3600. if (isEmpty(req.getName()))
  3601. throw MakeStringException(ECLWATCH_GRAPH_NOT_FOUND, "Please specify a graph name.");
  3602. Owned<IConstWUGraph> graph = cw->getGraph(req.getName());
  3603. if (!graph)
  3604. throw MakeStringException(ECLWATCH_GRAPH_NOT_FOUND, "Invalid graph name: %s for %s", req.getName(), wuid.str());
  3605. PROGLOG("WUProcessGraph: %s, Graph Name %s", wuid.str(), req.getName());
  3606. StringBuffer xml;
  3607. Owned<IPropertyTree> xgmml = graph->getXGMMLTree(true); // merge in graph progress information
  3608. toXML(xgmml.get(), xml);
  3609. resp.setTheGraph(xml.str());
  3610. }
  3611. catch(IException* e)
  3612. {
  3613. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  3614. }
  3615. return true;
  3616. }
  3617. bool isRunning(IConstWorkUnit &cw)
  3618. {
  3619. // MORE - move into workunit interface
  3620. switch (cw.getState())
  3621. {
  3622. case WUStateFailed:
  3623. case WUStateAborted:
  3624. case WUStateCompleted:
  3625. return false;
  3626. default:
  3627. return true;
  3628. }
  3629. }
  3630. void CWsWorkunitsEx::readGraph(IEspContext& context, const char* subGraphId, WUGraphIDType& id, bool running,
  3631. IConstWUGraph* graph, IArrayOf<IEspECLGraphEx>& graphs)
  3632. {
  3633. SCMStringBuffer name, label, type;
  3634. graph->getName(name);
  3635. graph->getLabel(label);
  3636. graph->getTypeName(type);
  3637. Owned<IEspECLGraphEx> g = createECLGraphEx("","");
  3638. g->setName(name.str());
  3639. g->setLabel(label.str());
  3640. g->setType(type.str());
  3641. WUGraphState graphState = graph->getState();
  3642. if (running && (WUGraphRunning == graphState))
  3643. {
  3644. g->setRunning(true);
  3645. g->setRunningId(id);
  3646. }
  3647. else if (context.getClientVersion() > 1.20)
  3648. {
  3649. if (WUGraphComplete == graphState)
  3650. g->setComplete(true);
  3651. else if (WUGraphFailed == graphState)
  3652. g->setFailed(true);
  3653. }
  3654. Owned<IPropertyTree> xgmml = graph->getXGMMLTree(true);
  3655. // New functionality, if a subgraph id is specified and we only want to load the xgmml for that subgraph
  3656. // then we need to conditionally pull a propertytree from the xgmml graph one and use that for the xgmml.
  3657. //JCSMORE this should be part of the API and therefore allow *only* the subtree to be pulled from the backend.
  3658. StringBuffer xml;
  3659. if (notEmpty(subGraphId))
  3660. {
  3661. VStringBuffer xpath("//node[@id='%s']", subGraphId);
  3662. toXML(xgmml->queryPropTree(xpath.str()), xml);
  3663. }
  3664. else
  3665. toXML(xgmml, xml);
  3666. g->setGraph(xml.str());
  3667. graphs.append(*g.getClear());
  3668. }
  3669. bool CWsWorkunitsEx::onWUGetGraph(IEspContext& context, IEspWUGetGraphRequest& req, IEspWUGetGraphResponse& resp)
  3670. {
  3671. try
  3672. {
  3673. StringBuffer wuid(req.getWuid());
  3674. WsWuHelpers::checkAndTrimWorkunit("WUGetGraph", wuid);
  3675. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  3676. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  3677. if(!cw)
  3678. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot open workunit %s.",wuid.str());
  3679. ensureWsWorkunitAccess(context, *cw, SecAccess_Read);
  3680. WUGraphIDType id;
  3681. SCMStringBuffer runningGraph;
  3682. bool running = (isRunning(*cw) && cw->getRunningGraph(runningGraph,id));
  3683. IArrayOf<IEspECLGraphEx> graphs;
  3684. if (isEmpty(req.getGraphName())) // JCS->GS - is this really required??
  3685. {
  3686. PROGLOG("WUGetGraph: %s", wuid.str());
  3687. Owned<IConstWUGraphIterator> it = &cw->getGraphs(GraphTypeAny);
  3688. ForEach(*it)
  3689. readGraph(context, req.getSubGraphId(), id, running, &it->query(), graphs);
  3690. }
  3691. else
  3692. {
  3693. PROGLOG("WUGetGraph: %s, Graph Name %s", wuid.str(), req.getGraphName());
  3694. Owned<IConstWUGraph> graph = cw->getGraph(req.getGraphName());
  3695. if (graph)
  3696. readGraph(context, req.getSubGraphId(), id, running, graph, graphs);
  3697. }
  3698. resp.setGraphs(graphs);
  3699. }
  3700. catch(IException* e)
  3701. {
  3702. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  3703. }
  3704. return true;
  3705. }
  3706. bool CWsWorkunitsEx::onGVCAjaxGraph(IEspContext &context, IEspGVCAjaxGraphRequest &req, IEspGVCAjaxGraphResponse &resp)
  3707. {
  3708. try
  3709. {
  3710. resp.setName(req.getName());
  3711. resp.setGraphName(req.getGraphName());
  3712. resp.setGraphType("eclwatch");
  3713. double version = context.getClientVersion();
  3714. if (version > 1.19)
  3715. resp.setSubGraphId(req.getSubGraphId());
  3716. if (version > 1.20)
  3717. resp.setSubGraphOnly(req.getSubGraphOnly());
  3718. }
  3719. catch(IException* e)
  3720. {
  3721. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  3722. }
  3723. return true;
  3724. }
  3725. bool CWsWorkunitsEx::onWUDetails(IEspContext &context, IEspWUDetailsRequest &req, IEspWUDetailsResponse &resp)
  3726. {
  3727. try
  3728. {
  3729. StringBuffer wuid(req.getWUID());
  3730. WsWuHelpers::checkAndTrimWorkunit("WUDetails", wuid);
  3731. PROGLOG("WUDetails: %s", wuid.str());
  3732. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  3733. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  3734. if(!cw)
  3735. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot open workunit %s.",wuid.str());
  3736. ensureWsWorkunitAccess(context, *cw, SecAccess_Read);
  3737. WUDetails wuDetails(cw, wuid);
  3738. wuDetails.processRequest(req, resp);
  3739. }
  3740. catch(IException* e)
  3741. {
  3742. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  3743. }
  3744. return true;
  3745. }
  3746. static void getWUDetailsMetaProperties(IArrayOf<IEspWUDetailsMetaProperty> & properties)
  3747. {
  3748. for (unsigned sk=StKindAll+1; sk<StMax;++sk)
  3749. {
  3750. const char * s = queryStatisticName((StatisticKind)sk);
  3751. if (s && *s)
  3752. {
  3753. Owned<IEspWUDetailsMetaProperty> property = createWUDetailsMetaProperty("","");
  3754. property->setName(s);
  3755. property->setValueType(CWUDetailsAttrValueType_Single);
  3756. properties.append(*property.getClear());
  3757. }
  3758. }
  3759. for (WuAttr attr=WaKind; attr<WaMax; ++attr)
  3760. {
  3761. Owned<IEspWUDetailsMetaProperty> property = createWUDetailsMetaProperty("","");
  3762. const char * s = queryWuAttributeName(attr);
  3763. assertex(s && *s);
  3764. property->setName(s);
  3765. if (isListAttribute(attr))
  3766. property->setValueType(CWUDetailsAttrValueType_List);
  3767. else if (isMultiAttribute(attr))
  3768. property->setValueType(CWUDetailsAttrValueType_Multi);
  3769. else
  3770. property->setValueType(CWUDetailsAttrValueType_Single);
  3771. properties.append(*property.getClear());
  3772. }
  3773. }
  3774. static void getWUDetailsMetaScopeTypes(StringArray & scopeTypes)
  3775. {
  3776. for (unsigned sst=SSTall+1; sst<SSTmax; ++sst)
  3777. {
  3778. const char * s = queryScopeTypeName((StatisticScopeType)sst);
  3779. if (s && *s)
  3780. scopeTypes.append(s);
  3781. }
  3782. }
  3783. static void getWUDetailsMetaMeasures(StringArray & measures)
  3784. {
  3785. for (unsigned measure=SMeasureAll+1; measure<SMeasureMax; ++measure)
  3786. {
  3787. const char *s = queryMeasureName((StatisticMeasure)measure);
  3788. if (s && *s)
  3789. measures.append(s);
  3790. }
  3791. }
  3792. static void getWUDetailsMetaActivities(IArrayOf<IConstWUDetailsActivityInfo> & activities)
  3793. {
  3794. for (unsigned kind=((unsigned)ThorActivityKind::TAKnone)+1; kind< TAKlast; ++kind)
  3795. {
  3796. Owned<IEspWUDetailsActivityInfo> activity = createWUDetailsActivityInfo("","");
  3797. const char * name = getActivityText(static_cast<ThorActivityKind>(kind));
  3798. assertex(name && *name);
  3799. activity->setKind(kind);
  3800. activity->setName(name);
  3801. activity->setIsSink(isActivitySink(static_cast<ThorActivityKind>(kind)));
  3802. activity->setIsSource(isActivitySource(static_cast<ThorActivityKind>(kind)));
  3803. activities.append(*activity.getClear());
  3804. }
  3805. }
  3806. bool CWsWorkunitsEx::onWUDetailsMeta(IEspContext &context, IEspWUDetailsMetaRequest &req, IEspWUDetailsMetaResponse &resp)
  3807. {
  3808. try
  3809. {
  3810. IArrayOf<IEspWUDetailsMetaProperty> properties;
  3811. getWUDetailsMetaProperties(properties);
  3812. resp.setProperties(properties);
  3813. StringArray scopeTypes;
  3814. getWUDetailsMetaScopeTypes(scopeTypes);
  3815. resp.setScopeTypes(scopeTypes);
  3816. StringArray measures;
  3817. getWUDetailsMetaMeasures(measures);
  3818. resp.setMeasures(measures);
  3819. IArrayOf<IConstWUDetailsActivityInfo> activities;
  3820. getWUDetailsMetaActivities(activities);
  3821. resp.setActivities(activities);
  3822. }
  3823. catch(IException* e)
  3824. {
  3825. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  3826. }
  3827. return true;
  3828. }
  3829. #ifdef _USE_CPPUNIT
  3830. #include "unittests.hpp"
  3831. class WUDetailsMetaTest : public CppUnit::TestFixture
  3832. {
  3833. CPPUNIT_TEST_SUITE( WUDetailsMetaTest );
  3834. CPPUNIT_TEST(testWUDetailsMeta);
  3835. CPPUNIT_TEST_SUITE_END();
  3836. void testWUDetailsMeta()
  3837. {
  3838. // These calls also check that all the calls required to build WUDetailsMeta
  3839. // are successful.
  3840. IArrayOf<IEspWUDetailsMetaProperty> properties;
  3841. getWUDetailsMetaProperties(properties);
  3842. unsigned expectedOrdinalityProps = StMax - (StKindAll + 1) + (WaMax-WaKind);
  3843. ASSERT(properties.ordinality()==expectedOrdinalityProps);
  3844. StringArray scopeTypes;
  3845. getWUDetailsMetaScopeTypes(scopeTypes);
  3846. unsigned expectedOrdinalityScopeTypes = SSTmax - (SSTall+1);
  3847. ASSERT(scopeTypes.ordinality()==expectedOrdinalityScopeTypes);
  3848. StringArray measures;
  3849. getWUDetailsMetaMeasures(measures);
  3850. unsigned expectedOrdinalityMeasures = SMeasureMax - (SMeasureAll+1);
  3851. ASSERT(measures.ordinality()==expectedOrdinalityMeasures);
  3852. IArrayOf<IConstWUDetailsActivityInfo> activities;
  3853. getWUDetailsMetaActivities(activities);
  3854. unsigned expectedOrdinalityActivities = TAKlast - (TAKnone+1);
  3855. ASSERT(activities.ordinality()==expectedOrdinalityActivities);
  3856. }
  3857. };
  3858. CPPUNIT_TEST_SUITE_REGISTRATION( WUDetailsMetaTest );
  3859. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( WUDetailsMetaTest, "WUDetailsMetaTest" );
  3860. #endif // _USE_CPPUNIT
  3861. bool CWsWorkunitsEx::onWUGraphInfo(IEspContext &context,IEspWUGraphInfoRequest &req, IEspWUGraphInfoResponse &resp)
  3862. {
  3863. try
  3864. {
  3865. StringBuffer wuid(req.getWuid());
  3866. WsWuHelpers::checkAndTrimWorkunit("WUGraphInfo", wuid);
  3867. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  3868. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  3869. if(!cw)
  3870. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT,"Cannot open workunit %s.",wuid.str());
  3871. ensureWsWorkunitAccess(context, *cw, SecAccess_Write);
  3872. resp.setWuid(wuid.str());
  3873. resp.setName(req.getName());
  3874. resp.setRunning(isRunning(*cw));
  3875. if (notEmpty(req.getGID()))
  3876. resp.setGID(req.getGID());
  3877. if(!req.getBatchWU_isNull())
  3878. resp.setBatchWU(req.getBatchWU());
  3879. }
  3880. catch(IException* e)
  3881. {
  3882. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  3883. }
  3884. return true;
  3885. }
  3886. bool CWsWorkunitsEx::onWUGVCGraphInfo(IEspContext &context,IEspWUGVCGraphInfoRequest &req, IEspWUGVCGraphInfoResponse &resp)
  3887. {
  3888. try
  3889. {
  3890. StringBuffer wuid(req.getWuid());
  3891. WsWuHelpers::checkAndTrimWorkunit("WUGVCGraphInfo", wuid);
  3892. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  3893. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  3894. if(!cw)
  3895. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT,"Cannot open workunit %s.",wuid.str());
  3896. ensureWsWorkunitAccess(context, *cw, SecAccess_Read);
  3897. resp.setWuid(wuid.str());
  3898. resp.setName(req.getName());
  3899. resp.setRunning(isRunning(*cw));
  3900. if (notEmpty(req.getGID()))
  3901. resp.setGID(req.getGID());
  3902. if(!req.getBatchWU_isNull())
  3903. resp.setBatchWU(req.getBatchWU());
  3904. StringBuffer xml("<Control><Endpoint><Query id=\"Gordon.Extractor.0\">");
  3905. xml.appendf("<Graph id=\"%s\">", req.getName());
  3906. if (context.getClientVersion() > 1.17)
  3907. {
  3908. xml.append("<Subgraph>");
  3909. xml.append(req.getSubgraphId_isNull() ? 0 : req.getSubgraphId());
  3910. xml.append("</Subgraph>");
  3911. }
  3912. xml.append("</Graph></Query></Endpoint></Control>");
  3913. resp.setTheGraph(xml.str());
  3914. }
  3915. catch(IException* e)
  3916. {
  3917. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  3918. }
  3919. return true;
  3920. }
  3921. bool CWsWorkunitsEx::onWUGraphTiming(IEspContext &context, IEspWUGraphTimingRequest &req, IEspWUGraphTimingResponse &resp)
  3922. {
  3923. try
  3924. {
  3925. StringBuffer wuid(req.getWuid());
  3926. WsWuHelpers::checkAndTrimWorkunit("WUGraphTiming", wuid);
  3927. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  3928. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str());
  3929. if(!cw)
  3930. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT,"Cannot open workunit %s.",wuid.str());
  3931. ensureWsWorkunitAccess(context, *cw, SecAccess_Read);
  3932. PROGLOG("WUGraphTiming: %s", wuid.str());
  3933. resp.updateWorkunit().setWuid(wuid.str());
  3934. WsWuInfo winfo(context, cw);
  3935. IArrayOf<IConstECLTimingData> timingData;
  3936. winfo.getGraphTimingData(timingData);
  3937. resp.updateWorkunit().setTimingData(timingData);
  3938. }
  3939. catch(IException* e)
  3940. {
  3941. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  3942. }
  3943. return true;
  3944. }
  3945. int CWsWorkunitsSoapBindingEx::onGetForm(IEspContext &context, CHttpRequest* request, CHttpResponse* response, const char *service, const char *method)
  3946. {
  3947. try
  3948. {
  3949. StringBuffer xml;
  3950. StringBuffer xslt;
  3951. if(strieq(method,"WUQuery") || strieq(method,"WUJobList"))
  3952. {
  3953. Owned<IEnvironmentFactory> factory = getEnvironmentFactory(true);
  3954. Owned<IConstEnvironment> environment = factory->openEnvironment();
  3955. Owned<IPropertyTree> root = &environment->getPTree();
  3956. if(strieq(method,"WUQuery"))
  3957. {
  3958. SecAccessFlags accessOwn;
  3959. SecAccessFlags accessOthers;
  3960. getUserWuAccessFlags(context, accessOwn, accessOthers, false);
  3961. xml.append("<WUQuery>");
  3962. if ((accessOwn == SecAccess_None) && (accessOthers == SecAccess_None))
  3963. {
  3964. context.setAuthStatus(AUTH_STATUS_NOACCESS);
  3965. xml.appendf("<ErrorMessage>Access to workunit is denied.</ErrorMessage>");
  3966. }
  3967. else
  3968. {
  3969. MapStringTo<bool> added;
  3970. Owned<IPropertyTreeIterator> it = root->getElements("Software/Topology/Cluster");
  3971. ForEach(*it)
  3972. {
  3973. const char *name = it->query().queryProp("@name");
  3974. if (notEmpty(name) && !added.getValue(name))
  3975. {
  3976. added.setValue(name, true);
  3977. appendXMLTag(xml, "Cluster", name);
  3978. }
  3979. }
  3980. }
  3981. xml.append("</WUQuery>");
  3982. xslt.append(getCFD()).append("./smc_xslt/wuid_search.xslt");
  3983. }
  3984. else if (strieq(method,"WUJobList"))
  3985. {
  3986. StringBuffer cluster, defaultProcess, range;
  3987. request->getParameter("Cluster", cluster);
  3988. request->getParameter("Process",defaultProcess);
  3989. request->getParameter("Range",range);
  3990. Owned<IConstWUClusterInfo> clusterInfo = getTargetClusterInfo(cluster);
  3991. xml.append("<WUJobList>");
  3992. SecAccessFlags accessOwn;
  3993. SecAccessFlags accessOthers;
  3994. getUserWuAccessFlags(context, accessOwn, accessOthers, false);
  3995. if ((accessOwn == SecAccess_None) && (accessOthers == SecAccess_None))
  3996. {
  3997. context.setAuthStatus(AUTH_STATUS_NOACCESS);
  3998. xml.appendf("<ErrorMessage>Access to workunit is denied.</ErrorMessage>");
  3999. }
  4000. else
  4001. {
  4002. if (range.length())
  4003. appendXMLTag(xml, "Range", range.str());
  4004. if (clusterInfo)
  4005. {
  4006. const StringArray &thorInstances = clusterInfo->getThorProcesses();
  4007. ForEachItemIn(i, thorInstances)
  4008. {
  4009. const char* instance = thorInstances.item(i);
  4010. if (defaultProcess.length() && strieq(instance, defaultProcess.str()))
  4011. xml.append("<Cluster selected=\"1\">").append(instance).append("</Cluster>");
  4012. else
  4013. xml.append("<Cluster>").append(instance).append("</Cluster>");
  4014. }
  4015. }
  4016. xml.append("<TargetCluster>").append(cluster).append("</TargetCluster>");
  4017. }
  4018. xml.append("</WUJobList>");
  4019. xslt.append(getCFD()).append("./smc_xslt/jobs_search.xslt");
  4020. response->addHeader("Expires", "0");
  4021. }
  4022. }
  4023. if (xslt.length() && xml.length())
  4024. {
  4025. StringBuffer html;
  4026. xsltTransform(xml.str(), xslt.str(), NULL, html);
  4027. response->setContent(html.str());
  4028. response->setContentType(HTTP_TYPE_TEXT_HTML_UTF8);
  4029. response->send();
  4030. return 0;
  4031. }
  4032. }
  4033. catch(IException* e)
  4034. {
  4035. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  4036. }
  4037. return onGetNotFound(context, request, response, service);
  4038. }
  4039. int CWsWorkunitsSoapBindingEx::onStartUpload(IEspContext &ctx, CHttpRequest* request, CHttpResponse* response, const char *serv, const char *method)
  4040. {
  4041. StringArray fileNames, files;
  4042. StringBuffer source;
  4043. Owned<IMultiException> me = MakeMultiException(source.setf("WsWorkunits::%s()", method).str());
  4044. try
  4045. {
  4046. if (strieq(method, "ImportWUZAPFile"))
  4047. {
  4048. SecAccessFlags accessOwn, accessOthers;
  4049. getUserWuAccessFlags(ctx, accessOwn, accessOthers, false);
  4050. if ((accessOwn != SecAccess_Full) || (accessOthers != SecAccess_Full))
  4051. throw MakeStringException(-1, "Permission denied.");
  4052. StringBuffer password;
  4053. request->getParameter("Password", password);
  4054. request->readContentToFiles(nullptr, zipFolder, fileNames);
  4055. unsigned count = fileNames.ordinality();
  4056. if (count == 0)
  4057. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Failed to read upload content.");
  4058. //For now, we only support importing 1 ZAP report per ImportWUZAPFile request for a better response time.
  4059. //Some ZAP report could be very big. It may take a log time to import.
  4060. if (count > 1)
  4061. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Only one WU ZAP report is allowed.");
  4062. VStringBuffer fileName("%s%s", zipFolder, fileNames.item(0));
  4063. wswService->queryWUFactory()->importWorkUnit(fileName, password,
  4064. wswService->getDataDirectory(), "ws_workunits", ctx.queryUserId(), ctx.querySecManager(), ctx.queryUser());
  4065. }
  4066. else
  4067. throw MakeStringException(ECLWATCH_INVALID_INPUT, "WsWorkunits::%s does not support the upload_ option.", method);
  4068. }
  4069. catch (IException* e)
  4070. {
  4071. me->append(*e);
  4072. }
  4073. catch (...)
  4074. {
  4075. me->append(*MakeStringExceptionDirect(ECLWATCH_INTERNAL_ERROR, "Unknown Exception"));
  4076. }
  4077. return onFinishUpload(ctx, request, response, serv, method, fileNames, files, me);
  4078. }
  4079. bool isDeploymentTypeCompressed(const char *type)
  4080. {
  4081. if (type && *type)
  4082. return (0==strncmp(type, "compressed_", strlen("compressed_")));
  4083. return false;
  4084. }
  4085. const char *skipCompressedTypeQualifier(const char *type)
  4086. {
  4087. if (isDeploymentTypeCompressed(type))
  4088. type += strlen("compressed_");
  4089. return type;
  4090. }
  4091. void deployEclOrArchive(IEspContext &context, IEspWUDeployWorkunitRequest & req, IEspWUDeployWorkunitResponse & resp)
  4092. {
  4093. NewWsWorkunit wu(context);
  4094. StringAttr wuid(wu->queryWuid()); // NB queryWuid() not valid after workunit,clear()
  4095. wu->setAction(WUActionCompile);
  4096. StringBuffer name(req.getName());
  4097. if (!name.trim().length() && notEmpty(req.getFileName()))
  4098. splitFilename(req.getFileName(), NULL, NULL, &name, NULL);
  4099. if (name.length())
  4100. wu->setJobName(name.str());
  4101. if (req.getObject().length())
  4102. {
  4103. MemoryBuffer mb;
  4104. const MemoryBuffer *uncompressed = &req.getObject();
  4105. if (isDeploymentTypeCompressed(req.getObjType()))
  4106. {
  4107. fastLZDecompressToBuffer(mb, req.getObject().bufferBase());
  4108. uncompressed = &mb;
  4109. }
  4110. StringBuffer text(uncompressed->length(), uncompressed->toByteArray());
  4111. wu.setQueryText(text.str());
  4112. }
  4113. if (req.getQueryMainDefinition())
  4114. wu.setQueryMain(req.getQueryMainDefinition());
  4115. if (req.getSnapshot())
  4116. wu->setSnapshot(req.getSnapshot());
  4117. if (!req.getResultLimit_isNull())
  4118. wu->setResultLimit(req.getResultLimit());
  4119. wu->commit();
  4120. wu.clear();
  4121. WsWuHelpers::submitWsWorkunit(context, wuid.str(), req.getCluster(), NULL, 0, true, false, false, NULL, NULL, &req.getDebugValues());
  4122. waitForWorkUnitToCompile(wuid.str(), req.getWait());
  4123. WsWuInfo winfo(context, wuid.str());
  4124. winfo.getCommon(resp.updateWorkunit(), WUINFO_All);
  4125. winfo.getExceptions(resp.updateWorkunit(), WUINFO_All);
  4126. name.clear();
  4127. if (notEmpty(resp.updateWorkunit().getJobname()))
  4128. origValueChanged(req.getName(), resp.updateWorkunit().getJobname(), name, false);
  4129. if (name.length()) //non generated user specified name, so override #Workunit('name')
  4130. {
  4131. WorkunitUpdate wx(&winfo.cw->lock());
  4132. wx->setJobName(name.str());
  4133. resp.updateWorkunit().setJobname(name.str());
  4134. }
  4135. PROGLOG("WUDeploy generates: %s", wuid.str());
  4136. AuditSystemAccess(context.queryUserId(), true, "Updated %s", wuid.str());
  4137. }
  4138. StringBuffer &sharedObjectFileName(StringBuffer &filename, const char *name, const char *ext, unsigned copy)
  4139. {
  4140. filename.append((name && *name) ? name : "workunit");
  4141. if (copy)
  4142. filename.append('_').append(copy);
  4143. if (notEmpty(ext))
  4144. filename.append(ext);
  4145. return filename;
  4146. }
  4147. inline StringBuffer &buildFullDllPath(StringBuffer &dllpath, StringBuffer &dllname, const char *dir, const char *name, const char *ext, unsigned copy)
  4148. {
  4149. return addPathSepChar(dllpath.set(dir)).append(sharedObjectFileName(dllname, name, ext, copy));
  4150. }
  4151. void writeTempSharedObject(const MemoryBuffer &obj, const char *dir, StringBuffer &filename)
  4152. {
  4153. OwnedIFileIO io = createUniqueFile(dir, "query_copy_dll_", NULL, filename);
  4154. io->write(0, obj.length(), obj.toByteArray());
  4155. }
  4156. void writeSharedObject(const char *srcpath, const MemoryBuffer &obj, const char *dir, StringBuffer &dllpath, StringBuffer &dllname)
  4157. {
  4158. StringBuffer name, ext;
  4159. if (srcpath && *srcpath)
  4160. splitFilename(srcpath, NULL, NULL, &name, &ext);
  4161. unsigned copy=0;
  4162. buildFullDllPath(dllpath.clear(), dllname.clear(), dir, name.str(), ext.str(), copy);
  4163. unsigned crc=0;
  4164. StringBuffer tempDllName;
  4165. const unsigned attempts = 3; // max attempts
  4166. for (unsigned i=0; i<attempts; i++)
  4167. {
  4168. while (checkFileExists(dllpath.str()))
  4169. {
  4170. if (crc==0)
  4171. crc = crc32(obj.toByteArray(), obj.length(), 0);
  4172. if (crc == crc_file(dllpath.str()))
  4173. {
  4174. DBGLOG("Workunit dll already exists: %s", dllpath.str());
  4175. if (tempDllName.length())
  4176. removeFileTraceIfFail(tempDllName);
  4177. return;
  4178. }
  4179. buildFullDllPath(dllpath.clear(), dllname.clear(), dir, name.str(), ext.str(), ++copy);
  4180. }
  4181. if (!tempDllName.length())
  4182. writeTempSharedObject(obj, dir, tempDllName);
  4183. try
  4184. {
  4185. renameFile(dllpath, tempDllName, false);
  4186. return;
  4187. }
  4188. catch (IException *e)
  4189. {
  4190. EXCLOG(e, "writeSharedObject"); //pretty small window for another copy of this dll to sneak by
  4191. e->Release();
  4192. }
  4193. }
  4194. throw MakeStringException(ECLWATCH_CANNOT_COPY_DLL, "Failed copying shared object %s", srcpath);
  4195. }
  4196. void deploySharedObject(IEspContext &context, StringBuffer &wuid, const char *filename, const char *cluster, const char *name, const MemoryBuffer &obj, const char *dir, const char *xml)
  4197. {
  4198. StringBuffer dllpath, dllname;
  4199. StringBuffer srcname(filename);
  4200. unsigned crc = 0;
  4201. Owned<IPropertyTree> srcxml;
  4202. if (xml && *xml)
  4203. {
  4204. srcxml.setown(createPTreeFromXMLString(xml));
  4205. if (srcxml && wuid.length())
  4206. {
  4207. crc = srcxml->getPropInt("Query[1]/Associated[1]/File[@type='dll'][1]/@crc", 0);
  4208. if (crc)
  4209. {
  4210. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  4211. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid);
  4212. if (cw)
  4213. {
  4214. //is this a previous copy of same query, or a WUID collision?
  4215. if (cw->getHash() == (unsigned) srcxml->getPropInt64("@hash", 0))
  4216. {
  4217. Owned<IConstWUQuery> query = cw->getQuery();
  4218. if (query && crc == query->getQueryDllCrc())
  4219. return;
  4220. }
  4221. }
  4222. }
  4223. }
  4224. }
  4225. if (!srcname.length())
  4226. srcname.append(name).append(SharedObjectExtension);
  4227. writeSharedObject(srcname.str(), obj, dir, dllpath, dllname);
  4228. NewWsWorkunit wu(context, wuid); //duplicate wuid made unique
  4229. wuid.set(wu->queryWuid());
  4230. wu->setClusterName(cluster);
  4231. wu->commit();
  4232. StringBuffer dllXML;
  4233. if (getWorkunitXMLFromFile(dllpath.str(), dllXML))
  4234. {
  4235. Owned<ILocalWorkUnit> embeddedWU = createLocalWorkUnit(dllXML.str());
  4236. queryExtendedWU(wu)->copyWorkUnit(embeddedWU, true, true);
  4237. }
  4238. wu.associateDll(dllpath.str(), dllname.str());
  4239. if (name && *name)
  4240. wu->setJobName(name);
  4241. //clean slate, copy only select items from processed workunit xml
  4242. if (srcxml)
  4243. {
  4244. if (srcxml->hasProp("@jobName"))
  4245. wu->setJobName(srcxml->queryProp("@jobName"));
  4246. if (srcxml->hasProp("Query/Text"))
  4247. wu.setQueryText(srcxml->queryProp("Query/Text"));
  4248. }
  4249. wu->setState(WUStateCompiled);
  4250. wu->commit();
  4251. wu.clear();
  4252. AuditSystemAccess(context.queryUserId(), true, "Updated %s", wuid.str());
  4253. }
  4254. void CWsWorkunitsEx::deploySharedObjectReq(IEspContext &context, IEspWUDeployWorkunitRequest & req, IEspWUDeployWorkunitResponse & resp, const char *dir, const char *xml)
  4255. {
  4256. if (isEmpty(req.getFileName()))
  4257. throw MakeStringException(ECLWATCH_INVALID_INPUT, "File name required when deploying a shared object.");
  4258. const char *cluster = req.getCluster();
  4259. if (isEmpty(cluster))
  4260. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Cluster name required when deploying a shared object.");
  4261. const MemoryBuffer *uncompressed = &req.getObject();
  4262. MemoryBuffer mb;
  4263. if (isDeploymentTypeCompressed(req.getObjType()))
  4264. {
  4265. fastLZDecompressToBuffer(mb, req.getObject().bufferBase());
  4266. uncompressed = &mb;
  4267. }
  4268. StringBuffer wuid;
  4269. deploySharedObject(context, wuid, req.getFileName(), cluster, req.getName(), *uncompressed, dir, xml);
  4270. WsWuInfo winfo(context, wuid.str());
  4271. winfo.getCommon(resp.updateWorkunit(), WUINFO_All);
  4272. PROGLOG("WUDeploy generates: %s", wuid.str());
  4273. AuditSystemAccess(context.queryUserId(), true, "Updated %s", wuid.str());
  4274. }
  4275. bool CWsWorkunitsEx::onWUDeployWorkunit(IEspContext &context, IEspWUDeployWorkunitRequest & req, IEspWUDeployWorkunitResponse & resp)
  4276. {
  4277. const char *type = skipCompressedTypeQualifier(req.getObjType());
  4278. try
  4279. {
  4280. ensureWsCreateWorkunitAccess(context);
  4281. if (notEmpty(req.getCluster()) && !isValidCluster(req.getCluster()))
  4282. throw MakeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "Invalid cluster name: %s", req.getCluster());
  4283. if (!type || !*type)
  4284. throw MakeStringExceptionDirect(ECLWATCH_INVALID_INPUT, "WUDeployWorkunit unspecified object type.");
  4285. if (strieq(type, "archive")|| strieq(type, "ecl_text"))
  4286. deployEclOrArchive(context, req, resp);
  4287. else if (strieq(type, "shared_object"))
  4288. deploySharedObjectReq(context, req, resp, queryDirectory.str());
  4289. else
  4290. throw MakeStringException(ECLWATCH_INVALID_INPUT, "WUDeployWorkunit '%s' unknown object type.", type);
  4291. }
  4292. catch(IException* e)
  4293. {
  4294. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  4295. }
  4296. return true;
  4297. }
  4298. bool CWsWorkunitsEx::onWUCreateZAPInfo(IEspContext &context, IEspWUCreateZAPInfoRequest &req, IEspWUCreateZAPInfoResponse &resp)
  4299. {
  4300. try
  4301. {
  4302. CWsWuZAPInfoReq zapInfoReq;
  4303. zapInfoReq.wuid = req.getWuid();
  4304. WsWuHelpers::checkAndTrimWorkunit("WUCreateZAPInfo", zapInfoReq.wuid);
  4305. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  4306. Owned<IConstWorkUnit> cwu = factory->openWorkUnit(zapInfoReq.wuid.str());
  4307. if(!cwu.get())
  4308. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT, "Cannot open workunit %s.", zapInfoReq.wuid.str());
  4309. ensureWsWorkunitAccess(context, *cwu, SecAccess_Read);
  4310. PROGLOG("WUCreateZAPInfo(): %s", zapInfoReq.wuid.str());
  4311. zapInfoReq.espIP = req.getESPIPAddress();
  4312. zapInfoReq.thorIP = req.getThorIPAddress();
  4313. zapInfoReq.problemDesc = req.getProblemDescription();
  4314. zapInfoReq.whatChanged = req.getWhatChanged();
  4315. zapInfoReq.whereSlow = req.getWhereSlow();
  4316. zapInfoReq.includeThorSlaveLog = req.getIncludeThorSlaveLog();
  4317. zapInfoReq.zapFileName = req.getZAPFileName();
  4318. zapInfoReq.password = req.getZAPPassword();
  4319. StringBuffer zipFileName, zipFileNameWithPath;
  4320. //CWsWuFileHelper may need ESP's <Directories> settings to locate log files.
  4321. CWsWuFileHelper helper(directories);
  4322. helper.createWUZAPFile(context, cwu, zapInfoReq, zipFileName, zipFileNameWithPath, thorSlaveLogThreadPoolSize);
  4323. //Download ZIP file to user
  4324. Owned<IFile> f = createIFile(zipFileNameWithPath.str());
  4325. Owned<IFileIO> io = f->open(IFOread);
  4326. unsigned zapFileSize = (unsigned) io->size();
  4327. if (zapFileSize > MAX_ZAP_BUFFER_SIZE)
  4328. throw MakeStringException(ECLWATCH_INVALID_INPUT, "WUCreateZAPInfo: ZAP file size is too big (>10M) to be retrieved. Please call /WsWorkunits/WUCreateAndDownloadZAPInfo using HTTP GET.");
  4329. MemoryBuffer mb;
  4330. void * data = mb.reserve(zapFileSize);
  4331. size32_t read = io->read(0, zapFileSize, data);
  4332. mb.setLength(read);
  4333. resp.setThefile(mb);
  4334. resp.setThefile_mimetype(HTTP_TYPE_OCTET_STREAM);
  4335. resp.setZAPFileName(zipFileName.str());
  4336. StringBuffer headerStr("attachment;filename=");
  4337. headerStr.append(zipFileName.str());
  4338. context.addCustomerHeader("Content-disposition", headerStr.str());
  4339. io->close();
  4340. f->remove();
  4341. }
  4342. catch(IException* e)
  4343. {
  4344. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  4345. }
  4346. return true;
  4347. }
  4348. bool CWsWorkunitsEx::onWUGetZAPInfo(IEspContext &context, IEspWUGetZAPInfoRequest &req, IEspWUGetZAPInfoResponse &resp)
  4349. {
  4350. try
  4351. {
  4352. StringBuffer wuid(req.getWUID());
  4353. WsWuHelpers::checkAndTrimWorkunit("WUGetZAPInfo", wuid);
  4354. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  4355. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid);
  4356. if(!cw)
  4357. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot open workunit %s.",wuid.str());
  4358. ensureWsWorkunitAccess(context, *cw, SecAccess_Read);
  4359. PROGLOG("WUGetZAPInfo: %s", wuid.str());
  4360. StringBuffer EspIP, ThorIP;
  4361. resp.setWUID(wuid.str());
  4362. resp.setBuildVersion(getBuildVersion());
  4363. IpAddress ipaddr = queryHostIP();
  4364. ipaddr.getIpText(EspIP);
  4365. resp.setESPIPAddress(EspIP.str());
  4366. //Get Archive
  4367. Owned<IConstWUQuery> query = cw->getQuery();
  4368. if(query)
  4369. {
  4370. SCMStringBuffer queryText;
  4371. query->getQueryText(queryText);
  4372. if (queryText.length() && isArchiveQuery(queryText.str()))
  4373. resp.setArchive(queryText.str());
  4374. }
  4375. //Get Thor IP
  4376. BoolHash uniqueProcesses;
  4377. Owned<IStringIterator> thorInstances = cw->getProcesses("Thor");
  4378. ForEach (*thorInstances)
  4379. {
  4380. SCMStringBuffer processName;
  4381. thorInstances->str(processName);
  4382. if (processName.length() < 1)
  4383. continue;
  4384. bool* found = uniqueProcesses.getValue(processName.str());
  4385. if (found && *found)
  4386. continue;
  4387. uniqueProcesses.setValue(processName.str(), true);
  4388. Owned<IStringIterator> thorLogs = cw->getLogs("Thor", processName.str());
  4389. ForEach (*thorLogs)
  4390. {
  4391. SCMStringBuffer logName;
  4392. thorLogs->str(logName);
  4393. if (!logName.length())
  4394. continue;
  4395. const char* thorIPPtr = NULL;
  4396. const char* ptr = logName.str();
  4397. while (ptr)
  4398. {
  4399. if (!thorIPPtr && (*ptr != '/'))
  4400. thorIPPtr = ptr;
  4401. else if (thorIPPtr && (*ptr == '/'))
  4402. break;
  4403. ptr++;
  4404. }
  4405. if (!thorIPPtr)
  4406. continue;
  4407. //Found a thor IP
  4408. if (ThorIP.length())
  4409. ThorIP.append(",");
  4410. if (!*ptr)
  4411. ThorIP.append(thorIPPtr);
  4412. else
  4413. ThorIP.append(ptr-thorIPPtr, thorIPPtr);
  4414. }
  4415. }
  4416. if (ThorIP.length())
  4417. resp.setThorIPAddress(ThorIP.str());
  4418. double version = context.getClientVersion();
  4419. if (version >= 1.73)
  4420. {
  4421. resp.setEmailTo(zapEmailTo.get());
  4422. resp.setEmailFrom(zapEmailFrom.get());
  4423. }
  4424. }
  4425. catch(IException* e)
  4426. {
  4427. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  4428. }
  4429. return true;
  4430. }
  4431. bool CWsWorkunitsEx::onWUCheckFeatures(IEspContext &context, IEspWUCheckFeaturesRequest &req, IEspWUCheckFeaturesResponse &resp)
  4432. {
  4433. resp.setBuildVersionMajor(BUILD_VERSION_MAJOR);
  4434. resp.setBuildVersionMinor(BUILD_VERSION_MINOR);
  4435. resp.setBuildVersionPoint(BUILD_VERSION_POINT);
  4436. resp.setMaxRequestEntityLength(maxRequestEntityLength);
  4437. resp.updateDeployment().setUseCompression(true);
  4438. return true;
  4439. }
  4440. static const char * checkGetStatsNullInput(const char * s)
  4441. {
  4442. if (!s || !*s)
  4443. return nullptr;
  4444. return s;
  4445. }
  4446. static const char * checkGetStatsInput(const char * s)
  4447. {
  4448. if (!s || !*s)
  4449. return "*";
  4450. return s;
  4451. }
  4452. bool CWsWorkunitsEx::onWUGetStats(IEspContext &context, IEspWUGetStatsRequest &req, IEspWUGetStatsResponse &resp)
  4453. {
  4454. //This function is deprecated for 7.x and will be removed shortly afterwards.
  4455. //Anything that cannot be implemented with the scope iterator is implemented as a post filter
  4456. try
  4457. {
  4458. const char* creatorType = checkGetStatsNullInput(req.getCreatorType());
  4459. const char* creator = checkGetStatsNullInput(req.getCreator());
  4460. const char* scopeType = checkGetStatsNullInput(req.getScopeType());
  4461. const char* scope = checkGetStatsNullInput(req.getScope());
  4462. const char* kind = checkGetStatsNullInput(req.getKind());
  4463. const char* measure = req.getMeasure();
  4464. WuScopeFilter filter;
  4465. StatisticsFilter statsFilter(creatorType, creator, "*", "*", "*", "*");
  4466. filter.addOutputProperties(PTstatistics);
  4467. if (scopeType)
  4468. filter.addScopeType(scopeType);
  4469. if (scope)
  4470. filter.addScope(scope);
  4471. if (kind)
  4472. filter.addOutputStatistic(kind);
  4473. if (measure)
  4474. filter.setMeasure(measure);
  4475. if (!req.getMinScopeDepth_isNull() && !req.getMaxScopeDepth_isNull())
  4476. filter.setDepth(req.getMinScopeDepth(), req.getMaxScopeDepth());
  4477. else if (!req.getMinScopeDepth_isNull())
  4478. filter.setDepth(req.getMinScopeDepth(), req.getMinScopeDepth());
  4479. if (!req.getMinValue_isNull() || !req.getMaxValue_isNull())
  4480. {
  4481. unsigned __int64 lowValue = 0;
  4482. unsigned __int64 highValue = MaxStatisticValue;
  4483. if (!req.getMinValue_isNull())
  4484. lowValue = (unsigned __int64)req.getMinValue();
  4485. if (!req.getMaxValue_isNull())
  4486. highValue = (unsigned __int64)req.getMaxValue();
  4487. statsFilter.setValueRange(lowValue, highValue);
  4488. }
  4489. const char * textFilter = req.getFilter();
  4490. if (textFilter)
  4491. statsFilter.setFilter(textFilter);
  4492. filter.setIncludeNesting(0).finishedFilter();
  4493. bool createDescriptions = false;
  4494. if (!req.getCreateDescriptions_isNull())
  4495. createDescriptions = req.getCreateDescriptions();
  4496. StringBuffer wuid(req.getWUID());
  4497. PROGLOG("WUGetStats: %s", wuid.str());
  4498. IArrayOf<IEspWUStatisticItem> statistics;
  4499. if (strchr(wuid, '*'))
  4500. {
  4501. WUSortField filters[2];
  4502. MemoryBuffer filterbuf;
  4503. filters[0] = WUSFwildwuid;
  4504. filterbuf.append(wuid.str());
  4505. filters[1] = WUSFterm;
  4506. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  4507. Owned<IConstWorkUnitIterator> iter = factory->getWorkUnitsSorted((WUSortField) (WUSFwuid), filters, filterbuf.bufferBase(), 0, INT_MAX, NULL, NULL);
  4508. ForEach(*iter)
  4509. {
  4510. Owned<IConstWorkUnit> workunit = factory->openWorkUnit(iter->query().queryWuid());
  4511. if (workunit)
  4512. {
  4513. //No need to check for access since the list is already filtered
  4514. WsWuInfo winfo(context, workunit->queryWuid());
  4515. winfo.getStats(filter, statsFilter, createDescriptions, statistics);
  4516. }
  4517. }
  4518. }
  4519. else
  4520. {
  4521. WsWuHelpers::checkAndTrimWorkunit("WUInfo", wuid);
  4522. ensureWsWorkunitAccess(context, wuid, SecAccess_Read);
  4523. WsWuInfo winfo(context, wuid);
  4524. winfo.getStats(filter, statsFilter, createDescriptions, statistics);
  4525. }
  4526. resp.setStatistics(statistics);
  4527. resp.setWUID(wuid.str());
  4528. }
  4529. catch(IException* e)
  4530. {
  4531. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  4532. }
  4533. return true;
  4534. }
  4535. IPropertyTree* CWsWorkunitsEx::getWorkunitArchive(IEspContext &context, WsWuInfo& winfo, const char* wuid, unsigned cacheMinutes)
  4536. {
  4537. Owned<WUArchiveCacheElement> wuArchive = wuArchiveCache->lookup(context, wuid, cacheMinutes);
  4538. if (wuArchive)
  4539. return wuArchive->archive.getLink();
  4540. Owned<IPropertyTree> archive = winfo.getWorkunitArchive();
  4541. if (!archive)
  4542. return NULL;
  4543. wuArchiveCache->add(wuid, archive.getLink());
  4544. return archive.getClear();
  4545. }
  4546. bool CWsWorkunitsEx::onWUListArchiveFiles(IEspContext &context, IEspWUListArchiveFilesRequest &req, IEspWUListArchiveFilesResponse &resp)
  4547. {
  4548. try
  4549. {
  4550. const char* wuid = req.getWUID();
  4551. if (isEmpty(wuid))
  4552. throw MakeStringException(ECLWATCH_NO_WUID_SPECIFIED, "No workunit defined.");
  4553. ensureWsWorkunitAccess(context, wuid, SecAccess_Read);
  4554. PROGLOG("WUListArchiveFiles: %s", wuid);
  4555. WsWuInfo winfo(context, wuid);
  4556. Owned<IPropertyTree> archive = getWorkunitArchive(context, winfo, wuid, WUARCHIVE_CACHE_MINITES);
  4557. if (!archive)
  4558. throw MakeStringException(ECLWATCH_INVALID_INPUT,"No workunit archive found for %s.", wuid);
  4559. IArrayOf<IEspWUArchiveModule> modules;
  4560. IArrayOf<IEspWUArchiveFile> files;
  4561. winfo.listArchiveFiles(archive, "", modules, files);
  4562. if (modules.length())
  4563. resp.setArchiveModules(modules);
  4564. if (files.length())
  4565. resp.setFiles(files);
  4566. if (!modules.length() && !files.length())
  4567. resp.setMessage("Files not found");
  4568. }
  4569. catch(IException* e)
  4570. {
  4571. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  4572. }
  4573. return true;
  4574. }
  4575. bool CWsWorkunitsEx::onWUGetArchiveFile(IEspContext &context, IEspWUGetArchiveFileRequest &req, IEspWUGetArchiveFileResponse &resp)
  4576. {
  4577. try
  4578. {
  4579. const char* wuid = req.getWUID();
  4580. const char* moduleName = req.getModuleName();
  4581. const char* attrName = req.getFileName();
  4582. if (isEmpty(wuid))
  4583. throw MakeStringException(ECLWATCH_NO_WUID_SPECIFIED, "No workunit defined.");
  4584. if (isEmpty(moduleName) && isEmpty(attrName))
  4585. throw MakeStringException(ECLWATCH_INVALID_INPUT, "No file name defined.");
  4586. ensureWsWorkunitAccess(context, wuid, SecAccess_Read);
  4587. PROGLOG("WUGetArchiveFile: %s", wuid);
  4588. WsWuInfo winfo(context, wuid);
  4589. Owned<IPropertyTree> archive = getWorkunitArchive(context, winfo, wuid, WUARCHIVE_CACHE_MINITES);
  4590. if (!archive)
  4591. throw MakeStringException(ECLWATCH_INVALID_INPUT,"No workunit archive found for %s.", wuid);
  4592. StringBuffer file;
  4593. winfo.getArchiveFile(archive, moduleName, attrName, req.getPath(), file);
  4594. if (file.length())
  4595. resp.setFile(file.str());
  4596. else
  4597. resp.setMessage("File not found");
  4598. }
  4599. catch(IException* e)
  4600. {
  4601. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  4602. }
  4603. return true;
  4604. }
  4605. const char *CWsWorkunitsEx::gatherQueryFileCopyErrors(IArrayOf<IConstLogicalFileError> &errors, StringBuffer &errorMsg)
  4606. {
  4607. if (!errors.ordinality())
  4608. return errorMsg.str();
  4609. errorMsg.append("Query File Copy Error(s):");
  4610. ForEachItemIn(i, errors)
  4611. {
  4612. IConstLogicalFileError &error = errors.item(i);
  4613. errorMsg.append(" ").append(error.getLogicalName()).append(": ");
  4614. errorMsg.append(error.getError()).append(";");
  4615. }
  4616. return errorMsg.str();
  4617. }
  4618. const char *CWsWorkunitsEx::gatherExceptionMessage(const IMultiException &me, StringBuffer &exceptionMsg)
  4619. {
  4620. exceptionMsg.append("Exception(s):");
  4621. aindex_t count = me.ordinality();
  4622. for (aindex_t i=0; i<count; i++)
  4623. {
  4624. IException& e = me.item(i);
  4625. StringBuffer errMsg;
  4626. exceptionMsg.append(" ").append(e.errorCode()).append(": ");
  4627. exceptionMsg.append(e.errorMessage(errMsg).str()).append(";");
  4628. }
  4629. exceptionMsg.append("\n");
  4630. return exceptionMsg.str();
  4631. }
  4632. const char *CWsWorkunitsEx::gatherWUException(IConstWUExceptionIterator &it, StringBuffer &exceptionMsg)
  4633. {
  4634. unsigned numErr = 0, numWRN = 0, numInf = 0, numAlert = 0;
  4635. ForEach(it)
  4636. {
  4637. IConstWUException & cur = it.query();
  4638. SCMStringBuffer src, msg, file;
  4639. exceptionMsg.append(" Exception: Code: ").append(cur.getExceptionCode());
  4640. exceptionMsg.append(" Source: ").append(cur.getExceptionSource(src).str());
  4641. exceptionMsg.append(" Message: ").append(cur.getExceptionMessage(msg).str());
  4642. exceptionMsg.append(" FileName: ").append(cur.getExceptionFileName(file).str());
  4643. exceptionMsg.append(" LineNo: ").append(cur.getExceptionLineNo());
  4644. exceptionMsg.append(" Column: ").append(cur.getExceptionColumn());
  4645. if (cur.getActivityId())
  4646. exceptionMsg.append(" ActivityId: ").append(cur.getActivityId());
  4647. if (cur.getPriority())
  4648. exceptionMsg.append(" Priority: ").append(cur.getPriority());
  4649. exceptionMsg.append(" Scope: ").append(cur.queryScope());
  4650. const char * label = "";
  4651. switch (cur.getSeverity())
  4652. {
  4653. default:
  4654. case SeverityError: label = "Error"; numErr++; break;
  4655. case SeverityWarning: label = "Warning"; numWRN++; break;
  4656. case SeverityInformation: label = "Info"; numInf++; break;
  4657. case SeverityAlert: label = "Alert"; numAlert++; break;
  4658. }
  4659. exceptionMsg.append(" Severity: ").append(label);
  4660. }
  4661. exceptionMsg.append(" Total error: ").append(numErr);
  4662. exceptionMsg.append(" warning: ").append(numWRN);
  4663. exceptionMsg.append(" info: ").append(numInf);
  4664. exceptionMsg.append(" alert: ").append(numAlert);
  4665. exceptionMsg.append("\n");
  4666. return exceptionMsg.str();
  4667. }
  4668. const char *CWsWorkunitsEx::gatherECLException(IArrayOf<IConstECLException> &exceptions, StringBuffer &exceptionMsg)
  4669. {
  4670. unsigned errorCount = 0, warningCount = 0;
  4671. ForEachItemIn(i, exceptions)
  4672. {
  4673. IConstECLException &e = exceptions.item(i);
  4674. if (strieq(e.getSeverity(), "warning"))
  4675. {
  4676. warningCount++;
  4677. exceptionMsg.append(" Warning: ");
  4678. }
  4679. else if (strieq(e.getSeverity(), "error"))
  4680. {
  4681. errorCount++;
  4682. exceptionMsg.append(" Error: ");
  4683. }
  4684. if (e.getSource())
  4685. exceptionMsg.append(e.getSource()).append(": ");
  4686. if (e.getFileName())
  4687. exceptionMsg.append(e.getFileName());
  4688. if (!e.getLineNo_isNull() && !e.getColumn_isNull())
  4689. exceptionMsg.appendf("(%d,%d): ", e.getLineNo(), e.getColumn());
  4690. exceptionMsg.appendf("%s C%d: %s;", e.getSeverity(), e.getCode(), e.getMessage());
  4691. }
  4692. exceptionMsg.append(" Total error: ").append(errorCount);
  4693. exceptionMsg.append(" warning: ").append(warningCount);
  4694. exceptionMsg.append("\n");
  4695. return exceptionMsg.str();
  4696. }
  4697. bool CWsWorkunitsEx::readDeployWUResponse(CWUDeployWorkunitResponse* deployResponse, StringBuffer &wuid, StringBuffer &result)
  4698. {
  4699. const IMultiException &me = deployResponse->getExceptions();
  4700. if (me.ordinality())
  4701. gatherExceptionMessage(me, result);
  4702. const char *w = deployResponse->getWorkunit().getWuid();
  4703. if (isEmptyString(w))
  4704. {
  4705. result.appendf("Error: no workunit ID!");
  4706. return false;
  4707. }
  4708. wuid.set(w);
  4709. const char *state = deployResponse->getWorkunit().getState();
  4710. bool isCompiled = (strieq(state, "compiled") || strieq(state, "completed"));
  4711. if (!isCompiled)
  4712. result.appendf("state: %s;", state);
  4713. gatherECLException(deployResponse->getWorkunit().getExceptions(), result);
  4714. return isCompiled;
  4715. }
  4716. void CWsWorkunitsEx::addEclDefinitionActionResult(const char *eclDefinition, const char *result, const char *wuid,
  4717. const char *queryID, const char* strAction, bool logResult, IArrayOf<IConstWUEclDefinitionActionResult> &results)
  4718. {
  4719. Owned<IEspWUEclDefinitionActionResult> res = createWUEclDefinitionActionResult();
  4720. if (!isEmptyString(eclDefinition))
  4721. res->setEclDefinition(eclDefinition);
  4722. res->setAction(strAction);
  4723. res->setResult(result);
  4724. if (!isEmptyString(wuid))
  4725. res->setWUID(wuid);
  4726. if (!isEmptyString(queryID))
  4727. res->setQueryID(queryID);
  4728. results.append(*res.getClear());
  4729. if (logResult)
  4730. PROGLOG("%s", result);
  4731. }
  4732. void CWsWorkunitsEx::checkEclDefinitionSyntax(IEspContext &context, const char *target, const char *eclDefinition,
  4733. int msToWait, IArrayOf<IConstWUEclDefinitionActionResult> &results)
  4734. {
  4735. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  4736. NewWsWorkunit wu(factory, context);
  4737. wu->setAction(WUActionCheck);
  4738. wu.setQueryMain(eclDefinition);
  4739. StringAttr wuid(wu->queryWuid()); // NB queryWuid() not valid after workunit.clear()
  4740. wu->commit();
  4741. wu.clear();
  4742. WsWuHelpers::submitWsWorkunit(context, wuid.str(), target, nullptr, 0, true, false, false);
  4743. waitForWorkUnitToComplete(wuid.str(), msToWait);
  4744. Owned<IConstWorkUnit> cw(factory->openWorkUnit(wuid.str()));
  4745. WUState st = cw->getState();
  4746. bool wuTimeout = (st != WUStateAborted) && (st != WUStateCompleted) && (st != WUStateFailed);
  4747. VStringBuffer result(" WUSyntaxCheckECL for %s:", eclDefinition);
  4748. if (wuTimeout)
  4749. result.append(" timed out.");
  4750. gatherWUException(cw->getExceptions(), result);
  4751. addEclDefinitionActionResult(eclDefinition, result.str(), wuid.str(), nullptr, "SyntaxCheck", true, results);
  4752. cw.clear();
  4753. if (wuTimeout)
  4754. abortWorkUnit(wuid.str(), context.querySecManager(), context.queryUser());
  4755. if (!factory->deleteWorkUnit(wuid.str()))
  4756. {
  4757. result.setf(" Workunit %s cannot be deleted now. You may delete it when its status changes.", wuid.str());
  4758. addEclDefinitionActionResult(eclDefinition, result.str(), wuid.str(), nullptr, "SyntaxCheck", true, results);
  4759. }
  4760. }
  4761. bool CWsWorkunitsEx::deployEclDefinition(IEspContext &context, const char *target, const char *eclDefinition,
  4762. int msToWait, StringBuffer &wuid, StringBuffer &result)
  4763. {
  4764. Owned<CWUDeployWorkunitRequest> deployReq = new CWUDeployWorkunitRequest("WsWorkunits");
  4765. deployReq->setName(eclDefinition);
  4766. deployReq->setQueryMainDefinition(eclDefinition);
  4767. deployReq->setObjType("compressed_ecl_text");
  4768. deployReq->setCluster(target);
  4769. deployReq->setWait(msToWait);
  4770. deployReq->setFileName("");
  4771. Owned<CWUDeployWorkunitResponse> deployResponse = new CWUDeployWorkunitResponse("WsWorkunits");
  4772. onWUDeployWorkunit(context, *deployReq, *deployResponse);
  4773. return readDeployWUResponse(deployResponse, wuid, result);
  4774. }
  4775. void CWsWorkunitsEx::deployEclDefinition(IEspContext &context, const char *target, const char *eclDefinition,
  4776. int msToWait, IArrayOf<IConstWUEclDefinitionActionResult> &results)
  4777. {
  4778. StringBuffer wuid, finalResult;
  4779. deployEclDefinition(context, target, eclDefinition, msToWait, wuid, finalResult);
  4780. addEclDefinitionActionResult(eclDefinition, finalResult.str(), wuid.str(), nullptr, "Deploy", true, results);
  4781. }
  4782. void CWsWorkunitsEx::publishEclDefinition(IEspContext &context, const char *target, const char *eclDefinition,
  4783. int msToWait, IEspWUEclDefinitionActionRequest &req, IArrayOf<IConstWUEclDefinitionActionResult> &results)
  4784. {
  4785. StringBuffer priorityReq(req.getPriority());
  4786. if (priorityReq.trim().length() && !isValidPriorityValue(priorityReq.str()))
  4787. {
  4788. VStringBuffer msg("Invalid Priority: %s", priorityReq.str());
  4789. addEclDefinitionActionResult(eclDefinition, msg.str(), nullptr, nullptr, "Publish", true, results);
  4790. return;
  4791. }
  4792. StringBuffer memoryLimitReq(req.getMemoryLimit());
  4793. if (memoryLimitReq.trim().length() && !isValidMemoryValue(memoryLimitReq.str()))
  4794. {
  4795. VStringBuffer msg("Invalid MemoryLimit: %s", memoryLimitReq.str());
  4796. addEclDefinitionActionResult(eclDefinition, msg.str(), nullptr, nullptr, "Publish", true, results);
  4797. return;
  4798. }
  4799. time_t timenow;
  4800. int startTime = time(&timenow);
  4801. //Do deploy first
  4802. StringBuffer wuid, finalResult;
  4803. if (!deployEclDefinition(context, target, eclDefinition, msToWait, wuid, finalResult))
  4804. {
  4805. addEclDefinitionActionResult(eclDefinition, finalResult.str(), wuid.str(), nullptr, "Publish", true, results);
  4806. return;
  4807. }
  4808. int timeLeft = msToWait - (time(&timenow) - startTime);
  4809. if (timeLeft <= 0)
  4810. {
  4811. addEclDefinitionActionResult(eclDefinition, "Timed out after deployment", wuid.str(), nullptr, "Publish", true, results);
  4812. return;
  4813. }
  4814. //Do publish now
  4815. StringBuffer comment(req.getComment());
  4816. StringBuffer remoteDali(req.getRemoteDali());
  4817. StringBuffer sourceProcess(req.getSourceProcess());
  4818. int timeLimit = req.getTimeLimit();
  4819. int warnTimeLimit = req.getWarnTimeLimit();
  4820. Owned<CWUPublishWorkunitRequest> publishReq = new CWUPublishWorkunitRequest("WsWorkunits");
  4821. publishReq->setWuid(wuid.str());
  4822. publishReq->setCluster(target);
  4823. publishReq->setJobName(eclDefinition);
  4824. if (!remoteDali.trim().isEmpty())
  4825. publishReq->setRemoteDali(remoteDali.str());
  4826. if (!sourceProcess.trim().isEmpty())
  4827. publishReq->setSourceProcess(sourceProcess.str());
  4828. if (!priorityReq.isEmpty())
  4829. publishReq->setPriority(priorityReq.str());
  4830. if (comment.str()) //allow empty
  4831. publishReq->setComment(comment.str());
  4832. if (req.getDeletePrevious())
  4833. publishReq->setActivate(CWUQueryActivationMode_ActivateDeletePrevious);
  4834. else if (req.getSuspendPrevious())
  4835. publishReq->setActivate(CWUQueryActivationMode_ActivateSuspendPrevious);
  4836. else
  4837. publishReq->setActivate(req.getNoActivate() ? CWUQueryActivationMode_NoActivate : CWUQueryActivationMode_Activate);
  4838. publishReq->setWait(timeLeft);
  4839. publishReq->setNoReload(req.getNoReload());
  4840. publishReq->setDontCopyFiles(req.getDontCopyFiles());
  4841. publishReq->setAllowForeignFiles(req.getAllowForeign());
  4842. publishReq->setUpdateDfs(req.getUpdateDfs());
  4843. publishReq->setUpdateSuperFiles(req.getUpdateSuperfiles());
  4844. publishReq->setUpdateCloneFrom(req.getUpdateCloneFrom());
  4845. publishReq->setAppendCluster(!req.getDontAppendCluster());
  4846. publishReq->setIncludeFileErrors(true);
  4847. if (timeLimit != -1)
  4848. publishReq->setTimeLimit(timeLimit);
  4849. if (warnTimeLimit != (unsigned) -1)
  4850. publishReq->setWarnTimeLimit(warnTimeLimit);
  4851. if (!memoryLimitReq.isEmpty())
  4852. publishReq->setMemoryLimit(memoryLimitReq.str());
  4853. Owned<CWUPublishWorkunitResponse> publishResponse = new CWUPublishWorkunitResponse("WsWorkunits");
  4854. onWUPublishWorkunit(context, *publishReq, *publishResponse);
  4855. const char *id = publishResponse->getQueryId();
  4856. if (!isEmptyString(id))
  4857. {
  4858. const char *qs = publishResponse->getQuerySet();
  4859. finalResult.append(" ").append(qs ? qs : "").append('/').append(id).append(" published. ");
  4860. }
  4861. if (publishResponse->getReloadFailed())
  4862. finalResult.append(" Added to target, but request to reload queries on cluster failed.");
  4863. const IMultiException &me = publishResponse->getExceptions();
  4864. if (me.ordinality())
  4865. gatherExceptionMessage(me, finalResult);
  4866. gatherQueryFileCopyErrors(publishResponse->getFileErrors(), finalResult);
  4867. addEclDefinitionActionResult(eclDefinition, finalResult.str(), wuid.str(), id, "Publish", true, results);
  4868. }
  4869. bool CWsWorkunitsEx::onWUEclDefinitionAction(IEspContext &context, IEspWUEclDefinitionActionRequest &req, IEspWUEclDefinitionActionResponse &resp)
  4870. {
  4871. try
  4872. {
  4873. CEclDefinitionActions action = req.getActionType();
  4874. if (action == EclDefinitionActions_Undefined)
  4875. throw MakeStringException(ECLWATCH_INVALID_INPUT,"Action not defined in onWUEclDefinitionAction.");
  4876. ensureWsCreateWorkunitAccess(context);
  4877. StringBuffer target(req.getTarget());
  4878. if (target.trim().isEmpty())
  4879. throw MakeStringException(ECLWATCH_INVALID_INPUT,"Target not defined in onWUEclDefinitionAction.");
  4880. IArrayOf<IConstWUEclDefinitionActionResult> results;
  4881. StringArray &eclDefinitions = req.getEclDefinitions();
  4882. int msToWait = req.getMsToWait();
  4883. for (aindex_t i = 0; i < eclDefinitions.length(); i++)
  4884. {
  4885. StringBuffer eclDefinitionName(eclDefinitions.item(i));
  4886. if (eclDefinitionName.trim().isEmpty())
  4887. UWARNLOG("Empty ECL Definition name in WUEclDefinitionAction request");
  4888. else if (action == CEclDefinitionActions_SyntaxCheck)
  4889. checkEclDefinitionSyntax(context, target.str(), eclDefinitionName.str(), msToWait, results);
  4890. else if (action == CEclDefinitionActions_Deploy)
  4891. deployEclDefinition(context, target.str(), eclDefinitionName.str(), msToWait, results);
  4892. else
  4893. publishEclDefinition(context, target.str(), eclDefinitionName.str(), msToWait, req, results);
  4894. }
  4895. resp.setActionResults(results);
  4896. }
  4897. catch(IException* e)
  4898. {
  4899. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  4900. }
  4901. return true;
  4902. }
  4903. static const char *eclccPluginPath = "ECLCC_PLUGIN_PATH=";
  4904. static unsigned eclccPluginPathLength = strlen(eclccPluginPath);
  4905. //Run 'eclcc -showpaths' command which returns something like:
  4906. //
  4907. //...
  4908. //ECLCC_PLUGIN_PATH=/opt/HPCCSystems/plugins:/opt/HPCCSystems/versioned/python2
  4909. //...
  4910. //
  4911. //Find out the file paths after the ECLCC_PLUGIN_PATH=
  4912. //In each file path, find out all of the .ecllib files and qualified .so files.
  4913. bool CWsWorkunitsEx::onWUGetPlugins(IEspContext &context, IEspWUGetPluginsRequest &req, IEspWUGetPluginsResponse &resp)
  4914. {
  4915. try
  4916. {
  4917. StringBuffer eclccPaths, error;
  4918. unsigned ret = runExternalCommand(eclccPaths, error, "eclcc -showpaths", nullptr);
  4919. if (ret != 0)
  4920. throw MakeStringException(ECLWATCH_INTERNAL_ERROR, "Failed to run 'eclcc -showpaths': %s", error.str());
  4921. if (eclccPaths.isEmpty())
  4922. {
  4923. IWARNLOG("The 'eclcc -showpaths' returns empty response.");
  4924. return true;
  4925. }
  4926. StringArray pluginFolders;
  4927. readPluginFolders(eclccPaths, pluginFolders);
  4928. IArrayOf<IConstWUEclPluginsInFolder> plugins;
  4929. ForEachItemIn(i, pluginFolders)
  4930. {
  4931. const char *pluginFolder = pluginFolders.item(i);
  4932. Owned<IEspWUEclPluginsInFolder> folder = createWUEclPluginsInFolder();
  4933. folder->setPath(pluginFolder);
  4934. findPlugins(pluginFolder, false, folder->getPlugins());
  4935. findPlugins(pluginFolder, true, folder->getPlugins());
  4936. plugins.append(*folder.getClear());
  4937. }
  4938. resp.setPlugins(plugins);
  4939. }
  4940. catch(IException *e)
  4941. {
  4942. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  4943. }
  4944. return true;
  4945. }
  4946. void CWsWorkunitsEx::readPluginFolders(StringBuffer &eclccPaths, StringArray &pluginFolders)
  4947. {
  4948. int lineLength = 0;
  4949. int curPos = 0;
  4950. int eclccPathsLength = eclccPaths.length();
  4951. const char *eclccPathsPtr = eclccPaths.str();
  4952. while (true)
  4953. {
  4954. __int64 nextPos = Utils::getLine(eclccPathsLength, curPos, eclccPathsPtr, lineLength);
  4955. if (strnicmp(eclccPathsPtr + curPos, eclccPluginPath, eclccPluginPathLength) != 0)
  4956. {
  4957. curPos = nextPos;
  4958. continue;
  4959. }
  4960. //ex: ECLCC_PLUGIN_PATH=/opt/HPCCSystems/plugins:/opt/HPCCSystems/versioned/python2
  4961. if (lineLength > eclccPluginPathLength)
  4962. {
  4963. StringBuffer eclccPluginPathBuf;
  4964. eclccPluginPathBuf.append(lineLength - eclccPluginPathLength, eclccPathsPtr + curPos + eclccPluginPathLength);
  4965. pluginFolders.appendList(eclccPluginPathBuf, ":");
  4966. }
  4967. break;
  4968. }
  4969. }
  4970. void CWsWorkunitsEx::findPlugins(const char *pluginFolder, bool dotSoFile, StringArray &plugins)
  4971. {
  4972. Owned<IFile> pluginDir = createIFile(pluginFolder);
  4973. Owned<IDirectoryIterator> pluginFiles = pluginDir->directoryFiles(dotSoFile ? "*.so" : "*.ecllib", false, false);
  4974. ForEach(*pluginFiles)
  4975. {
  4976. const char *pluginFile = pluginFiles->query().queryFilename();
  4977. StringBuffer fileName;
  4978. splitFilename(pluginFile, nullptr, nullptr, &fileName, &fileName);
  4979. //The ecllib files should be reported as plugins.
  4980. //.so files are reported as plugins if getSharedProcedure("getECLPluginDefinition")->ECL is non null
  4981. if (!dotSoFile || checkPluginECLAttr(pluginFile))
  4982. plugins.append(fileName);
  4983. }
  4984. }
  4985. bool CWsWorkunitsEx::checkPluginECLAttr(const char *fileNameWithPath)
  4986. {
  4987. HINSTANCE h = LoadSharedObject(fileNameWithPath, true, false);
  4988. if (!h)
  4989. throw makeStringExceptionV(ECLWATCH_INTERNAL_ERROR, "can't load library %s", fileNameWithPath);
  4990. EclPluginDefinition p = (EclPluginDefinition) GetSharedProcedure(h, "getECLPluginDefinition");
  4991. if (p)
  4992. {
  4993. ECLPluginDefinitionBlock pb;
  4994. pb.size = sizeof(pb);
  4995. if (p(&pb) && pb.ECL)
  4996. return true;
  4997. }
  4998. return false;
  4999. }