eclcmd_core.cpp 74 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073
  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 <stdio.h>
  14. #include "jlog.hpp"
  15. #include "jfile.hpp"
  16. #include "jargv.hpp"
  17. #include "jflz.hpp"
  18. #include "httpclient.hpp"
  19. #include "workunit.hpp"
  20. #include "ws_workunits.hpp"
  21. #include "eclcmd_common.hpp"
  22. #include "eclcmd_core.hpp"
  23. #include "eclcmd_sign.hpp"
  24. size32_t getMaxRequestEntityLength(EclCmdCommon &cmd)
  25. {
  26. if(cmd.optServer.isEmpty())
  27. throw MakeStringException(-1, "Server IP not specified");
  28. EclCmdURL url("?config_", cmd.optServer, cmd.optPort, cmd.optSSL);
  29. Owned<IHttpClientContext> httpCtx = getHttpClientContext();
  30. StringBuffer request; //empty
  31. StringBuffer response;
  32. StringBuffer status;
  33. Owned<IHttpClient> httpclient = httpCtx->createHttpClient(NULL, url);
  34. if (cmd.optUsername.length())
  35. httpclient->setUserID(cmd.optUsername);
  36. if (cmd.optPassword.length())
  37. httpclient->setPassword(cmd.optPassword);
  38. if (0 > httpclient->sendRequest("GET", NULL, request, response, status) || !response.length() || strncmp("200", status, 3))
  39. throw MakeStringException(-1, "Error checking ESP configuration: %s:%s %s", cmd.optServer.str(), cmd.optPort.str(), status.str());
  40. Owned<IPropertyTree> config = createPTreeFromXMLString(response);
  41. return config->getPropInt("Software[1]/EspProcess[1]/EspProtocol[@type='http_protocol'][1]/@maxRequestEntityLength");
  42. }
  43. void expandDefintionsAsDebugValues(const IArrayOf<IEspNamedValue> & definitions, IArrayOf<IEspNamedValue> & debugValues)
  44. {
  45. ForEachItemIn(i, definitions)
  46. {
  47. IEspNamedValue &item = definitions.item(i);
  48. const char *name = item.getName();
  49. const char *value = item.getValue();
  50. StringBuffer passThroughName;
  51. passThroughName.append("eclcc-D").append(name).append("-").append(i);
  52. addNamedValue(passThroughName, value, debugValues);
  53. }
  54. }
  55. void checkFeatures(IClientWsWorkunits *client, bool &useCompression, int &major, int &minor, int &point, unsigned waitMs, unsigned waitConnectMs, unsigned waitReadSec)
  56. {
  57. try
  58. {
  59. Owned<IClientWUCheckFeaturesRequest> req = client->createWUCheckFeaturesRequest();
  60. setCmdRequestTimeouts(req->rpc(), waitMs, waitConnectMs, waitReadSec);
  61. Owned<IClientWUCheckFeaturesResponse> resp = client->WUCheckFeatures(req);
  62. useCompression = resp->getDeployment().getUseCompression();
  63. major = resp->getBuildVersionMajor();
  64. minor = resp->getBuildVersionMinor();
  65. point = resp->getBuildVersionPoint();
  66. }
  67. catch(IException *E) //most likely an older ESP
  68. {
  69. E->Release();
  70. }
  71. catch(...)
  72. {
  73. }
  74. }
  75. bool doDeploy(EclCmdWithEclTarget &cmd, IClientWsWorkunits *client, unsigned waitMs, const char *cluster, const char *name, StringBuffer *wuid, StringBuffer *wucluster, bool noarchive, bool displayWuid=true, bool compress=true)
  76. {
  77. int major = 0;
  78. int minor = 0;
  79. int point = 0;
  80. bool useCompression = false;
  81. checkFeatures(client, useCompression, major, minor, point, 0, cmd.optWaitConnectMs, cmd.optWaitReadSec);
  82. bool compressed = false;
  83. if (useCompression)
  84. {
  85. MemoryBuffer mb;
  86. fastLZCompressToBuffer(mb, cmd.optObj.mb.length(), cmd.optObj.mb.bufferBase());
  87. cmd.optObj.mb.swapWith(mb);
  88. compressed=true;
  89. }
  90. StringBuffer s;
  91. if (cmd.optVerbose)
  92. fprintf(stdout, "\nDeploying %s\n", cmd.optObj.getDescription(s).str());
  93. StringBuffer objType(compressed ? "compressed_" : ""); //change compressed type string so old ESPs will fail gracefully
  94. Owned<IClientWUDeployWorkunitRequest> req = client->createWUDeployWorkunitRequest();
  95. setCmdRequestTimeouts(req->rpc(), waitMs, cmd.optWaitConnectMs, cmd.optWaitReadSec);
  96. switch (cmd.optObj.type)
  97. {
  98. case eclObjArchive:
  99. req->setObjType(objType.append("archive"));
  100. break;
  101. case eclObjSharedObject:
  102. req->setObjType(objType.append("shared_object"));
  103. break;
  104. case eclObjSource:
  105. {
  106. if (noarchive)
  107. req->setObjType(objType.append("ecl_text"));
  108. else
  109. {
  110. fprintf(stderr, "Failed to create archive from ECL Text\n");
  111. return false;
  112. }
  113. break;
  114. }
  115. default:
  116. fprintf(stderr, "Cannot deploy %s\n", cmd.optObj.queryTypeName());
  117. return false;
  118. }
  119. if (name && *name)
  120. req->setName(name);
  121. if (cluster && *cluster)
  122. req->setCluster(cluster);
  123. req->setObject(cmd.optObj.mb);
  124. req->setFileName(cmd.optObj.value.str());
  125. if ((int)cmd.optResultLimit > 0)
  126. req->setResultLimit(cmd.optResultLimit);
  127. if (cmd.optAttributePath.length())
  128. req->setQueryMainDefinition(cmd.optAttributePath);
  129. if (cmd.optSnapshot.length())
  130. req->setSnapshot(cmd.optSnapshot);
  131. expandDefintionsAsDebugValues(cmd.definitions, cmd.debugValues);
  132. if (cmd.debugValues.length())
  133. {
  134. req->setDebugValues(cmd.debugValues);
  135. cmd.debugValues.kill();
  136. }
  137. Owned<IClientWUDeployWorkunitResponse> resp;
  138. try
  139. {
  140. resp.setown(client->WUDeployWorkunit(req));
  141. }
  142. catch (IException *E)
  143. {
  144. StringBuffer msg;
  145. int code = E->errorCode();
  146. //ESP doesn't want to process requests that are too large, and so disconnects before reading
  147. // this causes issues capturing the error returned... check if that may have been the issue
  148. if (code==SOAP_AUTHENTICATION_ERROR || (code==SOAP_SERVER_ERROR && streq(E->errorMessage(msg).str(), "401: Unauthorized Access")))
  149. throw;
  150. if (useCompression) //newer build, not a maxRequestEntityLength issue
  151. throw;
  152. size32_t maxEntity = getMaxRequestEntityLength(cmd); //only do the work to grab max buffersize if we've failed
  153. if (maxEntity > 1000)
  154. {
  155. size32_t maxBufferSize = ((maxEntity - 999) / 4) * 3; //account for soap, other parameters, and base64 encoding (n / 4 * 3)
  156. if (maxBufferSize && cmd.optObj.mb.length() > maxBufferSize)
  157. {
  158. fprintf(stderr, "\nError: %s is larger than maxRequestEntityLength configured for ESP allows.\n", objType.str());
  159. E->Release();
  160. return false;
  161. }
  162. }
  163. throw;
  164. }
  165. outputMultiExceptionsEx(resp->getExceptions()); //ignore error returned, no wuid is error
  166. const char *w = resp->getWorkunit().getWuid();
  167. if (w && *w)
  168. {
  169. if (wuid)
  170. wuid->clear().append(w);
  171. if (wucluster)
  172. wucluster->clear().append(resp->getWorkunit().getCluster());
  173. fprintf(stdout, "\n");
  174. if (cmd.optVerbose)
  175. fprintf(stdout, "Deployed\n wuid: ");
  176. const char *state = resp->getWorkunit().getState();
  177. bool isCompiled = (strieq(state, "compiled")||strieq(state, "completed"));
  178. if (displayWuid || cmd.optVerbose || !isCompiled)
  179. fprintf(stdout, "%s\n", w);
  180. if (cmd.optVerbose || !isCompiled)
  181. fprintf(stdout, " state: %s\n\n", state);
  182. unsigned errorCount=0;
  183. unsigned warningCount=0;
  184. IArrayOf<IConstECLException> &exceptions = resp->getWorkunit().getExceptions();
  185. ForEachItemIn(i, exceptions)
  186. {
  187. IConstECLException &e = exceptions.item(i);
  188. if (e.getSource())
  189. fprintf(stderr, "%s: ", e.getSource());
  190. if (e.getFileName())
  191. fputs(e.getFileName(), stderr);
  192. if (!e.getLineNo_isNull() && !e.getColumn_isNull())
  193. fprintf(stderr, "(%d,%d): ", e.getLineNo(), e.getColumn());
  194. fprintf(stderr, "%s C%d: %s\n", e.getSeverity(), e.getCode(), e.getMessage());
  195. if (strieq(e.getSeverity(), "warning"))
  196. warningCount++;
  197. else if (strieq(e.getSeverity(), "error"))
  198. errorCount++;
  199. }
  200. if (errorCount || warningCount)
  201. fprintf(stderr, "%d error(s), %d warning(s)\n\n", errorCount, warningCount);
  202. return isCompiled;
  203. }
  204. return false;
  205. }
  206. class EclCmdDeploy : public EclCmdWithEclTarget
  207. {
  208. public:
  209. EclCmdDeploy()
  210. {
  211. optObj.accept = eclObjWuid | eclObjArchive | eclObjSharedObject;
  212. }
  213. virtual eclCmdOptionMatchIndicator parseCommandLineOptions(ArgvIterator &iter)
  214. {
  215. if (iter.done())
  216. return EclCmdOptionNoMatch;
  217. for (; !iter.done(); iter.next())
  218. {
  219. const char *arg = iter.query();
  220. if (iter.matchOption(optName, ECLOPT_NAME)||iter.matchOption(optName, ECLOPT_NAME_S))
  221. continue;
  222. eclCmdOptionMatchIndicator ind = EclCmdWithEclTarget::matchCommandLineOption(iter, true);
  223. if (ind != EclCmdOptionMatch)
  224. return ind;
  225. }
  226. return EclCmdOptionMatch;
  227. }
  228. virtual bool finalizeOptions(IProperties *globals)
  229. {
  230. if (!EclCmdWithEclTarget::finalizeOptions(globals))
  231. return false;
  232. if (optObj.type==eclObjWuid)
  233. {
  234. StringBuffer s;
  235. fprintf(stderr, "\nWUID (%s) cannot be the target for deployment\n", optObj.getDescription(s).str());
  236. return false;
  237. }
  238. return true;
  239. }
  240. virtual int processCMD()
  241. {
  242. Owned<IClientWsWorkunits> client = createCmdClientExt(WsWorkunits, *this, "?upload_"); //upload_ disables maxRequestEntityLength
  243. return doDeploy(*this, client, 0, optTargetCluster.get(), optName.get(), NULL, NULL, optNoArchive) ? 0 : 1;
  244. }
  245. virtual void usage()
  246. {
  247. fputs("\nUsage:\n"
  248. "\n"
  249. "The 'deploy' command creates a workunit on the HPCC system from the given ECL\n"
  250. "text, file, archive, shared object, or dll. The workunit will be created in\n"
  251. "the 'compiled' state.\n"
  252. "\n"
  253. "ecl deploy <target> <file> [--name=<val>]\n"
  254. "ecl deploy <target> <archive> [--name=<val>]\n"
  255. "ecl deploy <target> <so|dll> [--name=<val>]\n"
  256. "ecl deploy <target> - [--name=<val>]\n\n"
  257. " - specifies object should be read from stdin\n"
  258. " <file> ecl text file to deploy\n"
  259. " <archive> ecl archive to deploy\n"
  260. " <so|dll> workunit dll or shared object to deploy\n"
  261. " Options:\n"
  262. " -n, --name=<val> workunit job name\n",
  263. stdout);
  264. EclCmdWithEclTarget::usage();
  265. }
  266. private:
  267. StringAttr optName;
  268. };
  269. class EclCmdPublish : public EclCmdWithEclTarget
  270. {
  271. public:
  272. EclCmdPublish() : optNoActivate(false), optSuspendPrevious(false), optDeletePrevious(false),
  273. activateSet(false), optNoReload(false), optDontCopyFiles(false), optMsToWait(300000), optAllowForeign(false), optUpdateDfs(false),
  274. optUpdateSuperfiles(false), optUpdateCloneFrom(false), optDontAppendCluster(false)
  275. {
  276. optObj.accept = eclObjWuid | eclObjArchive | eclObjSharedObject;
  277. optTimeLimit = (unsigned) -1;
  278. optWarnTimeLimit = (unsigned) -1;
  279. }
  280. virtual eclCmdOptionMatchIndicator parseCommandLineOptions(ArgvIterator &iter)
  281. {
  282. if (iter.done())
  283. return EclCmdOptionNoMatch;
  284. for (; !iter.done(); iter.next())
  285. {
  286. if (iter.matchOption(optObj.value, ECLOPT_WUID)||iter.matchOption(optObj.value, ECLOPT_WUID_S))
  287. continue;
  288. if (iter.matchOption(optName, ECLOPT_NAME)||iter.matchOption(optName, ECLOPT_NAME_S))
  289. continue;
  290. if (iter.matchOption(optDaliIP, ECLOPT_DALIIP))
  291. continue;
  292. if (iter.matchOption(optSourceProcess, ECLOPT_SOURCE_PROCESS))
  293. continue;
  294. if (iter.matchOption(optMsToWait, ECLOPT_WAIT))
  295. continue;
  296. if (iter.matchOption(optTimeLimit, ECLOPT_TIME_LIMIT))
  297. continue;
  298. if (iter.matchOption(optWarnTimeLimit, ECLOPT_WARN_TIME_LIMIT))
  299. continue;
  300. if (iter.matchOption(optMemoryLimit, ECLOPT_MEMORY_LIMIT))
  301. continue;
  302. if (iter.matchOption(optPriority, ECLOPT_PRIORITY))
  303. continue;
  304. if (iter.matchOption(optComment, ECLOPT_COMMENT))
  305. continue;
  306. if (iter.matchFlag(optDontCopyFiles, ECLOPT_DONT_COPY_FILES))
  307. continue;
  308. if (iter.matchFlag(optAllowForeign, ECLOPT_ALLOW_FOREIGN))
  309. continue;
  310. if (iter.matchFlag(optNoActivate, ECLOPT_NO_ACTIVATE))
  311. {
  312. activateSet=true;
  313. continue;
  314. }
  315. if (iter.matchFlag(optNoReload, ECLOPT_NORELOAD))
  316. continue;
  317. bool activate; //also supports "-A-"
  318. if (iter.matchFlag(activate, ECLOPT_ACTIVATE)||iter.matchFlag(activate, ECLOPT_ACTIVATE_S))
  319. {
  320. activateSet=true;
  321. optNoActivate=!activate;
  322. continue;
  323. }
  324. if (iter.matchFlag(optSuspendPrevious, ECLOPT_SUSPEND_PREVIOUS)||iter.matchFlag(optSuspendPrevious, ECLOPT_SUSPEND_PREVIOUS_S))
  325. continue;
  326. if (iter.matchFlag(optDeletePrevious, ECLOPT_DELETE_PREVIOUS)||iter.matchFlag(optDeletePrevious, ECLOPT_DELETE_PREVIOUS_S))
  327. continue;
  328. if (iter.matchFlag(optUpdateDfs, ECLOPT_UPDATE_DFS))
  329. continue;
  330. if (iter.matchFlag(optUpdateSuperfiles, ECLOPT_UPDATE_SUPER_FILES))
  331. continue;
  332. if (iter.matchFlag(optUpdateCloneFrom, ECLOPT_UPDATE_CLONE_FROM))
  333. continue;
  334. if (iter.matchFlag(optDontAppendCluster, ECLOPT_DONT_APPEND_CLUSTER))
  335. continue;
  336. eclCmdOptionMatchIndicator ind = EclCmdWithEclTarget::matchCommandLineOption(iter, true);
  337. if (ind != EclCmdOptionMatch)
  338. return ind;
  339. }
  340. return EclCmdOptionMatch;
  341. }
  342. virtual bool finalizeOptions(IProperties *globals)
  343. {
  344. if (!EclCmdWithEclTarget::finalizeOptions(globals))
  345. return false;
  346. if (!activateSet)
  347. {
  348. bool activate;
  349. if (extractEclCmdOption(activate, globals, ECLOPT_ACTIVATE_ENV, ECLOPT_ACTIVATE_INI, true))
  350. optNoActivate=!activate;
  351. }
  352. if (optNoActivate && (optSuspendPrevious || optDeletePrevious))
  353. {
  354. fputs("invalid --suspend-prev and --delete-prev require activation.\n", stderr);
  355. return false;
  356. }
  357. if (!optSuspendPrevious && !optDeletePrevious)
  358. {
  359. extractEclCmdOption(optDeletePrevious, globals, ECLOPT_DELETE_PREVIOUS_ENV, ECLOPT_DELETE_PREVIOUS_INI, false);
  360. if (!optDeletePrevious)
  361. extractEclCmdOption(optSuspendPrevious, globals, ECLOPT_SUSPEND_PREVIOUS_ENV, ECLOPT_SUSPEND_PREVIOUS_INI, false);
  362. }
  363. if (optSuspendPrevious && optDeletePrevious)
  364. {
  365. fputs("invalid --suspend-prev and --delete-prev are mutually exclusive options.\n", stderr);
  366. return false;
  367. }
  368. if (optMemoryLimit.length() && !isValidMemoryValue(optMemoryLimit))
  369. {
  370. fprintf(stderr, "invalid --memoryLimit value of %s.\n", optMemoryLimit.get());
  371. return false;
  372. }
  373. if (optPriority.length() && !isValidPriorityValue(optPriority))
  374. {
  375. fprintf(stderr, "invalid --priority value of %s.\n", optPriority.get());
  376. return false;
  377. }
  378. return true;
  379. }
  380. virtual int processCMD()
  381. {
  382. CTimeMon mon(optMsToWait);
  383. Owned<IClientWsWorkunits> client = createCmdClientExt(WsWorkunits, *this, "?upload_"); //upload_ disables maxRequestEntityLength
  384. StringBuffer wuid;
  385. if (optObj.type==eclObjWuid)
  386. wuid.set(optObj.value.get());
  387. else if (!doDeploy(*this, client, optMsToWait, optTargetCluster.get(), optName.get(), &wuid, NULL, optNoArchive))
  388. return 1;
  389. unsigned remaining = 0;
  390. if (mon.timedout(&remaining))
  391. {
  392. fputs("\nTimed out during deployment, query not published\n", stderr);
  393. return 1;
  394. }
  395. StringBuffer descr;
  396. if (optVerbose)
  397. fprintf(stdout, "\nPublishing %s\n", wuid.str());
  398. unsigned clientRemaining = remaining + 100; //give the ESP method time to return from timeout before hard client stop
  399. Owned<IClientWUPublishWorkunitRequest> req = client->createWUPublishWorkunitRequest();
  400. setCmdRequestTimeouts(req->rpc(), clientRemaining, optWaitConnectMs, optWaitReadSec);
  401. req->setWuid(wuid.str());
  402. if (optDeletePrevious)
  403. req->setActivate(CWUQueryActivationMode_ActivateDeletePrevious);
  404. else if (optSuspendPrevious)
  405. req->setActivate(CWUQueryActivationMode_ActivateSuspendPrevious);
  406. else
  407. req->setActivate(optNoActivate ? CWUQueryActivationMode_NoActivate : CWUQueryActivationMode_Activate);
  408. if (optName.length())
  409. req->setJobName(optName.get());
  410. if (optTargetCluster.length())
  411. req->setCluster(optTargetCluster.get());
  412. req->setRemoteDali(optDaliIP.get());
  413. req->setSourceProcess(optSourceProcess);
  414. req->setWait(remaining);
  415. req->setNoReload(optNoReload);
  416. req->setDontCopyFiles(optDontCopyFiles);
  417. req->setAllowForeignFiles(optAllowForeign);
  418. req->setUpdateDfs(optUpdateDfs);
  419. req->setUpdateSuperFiles(optUpdateSuperfiles);
  420. req->setUpdateCloneFrom(optUpdateCloneFrom);
  421. req->setAppendCluster(!optDontAppendCluster);
  422. req->setIncludeFileErrors(true);
  423. if (optTimeLimit != (unsigned) -1)
  424. req->setTimeLimit(optTimeLimit);
  425. if (optWarnTimeLimit != (unsigned) -1)
  426. req->setWarnTimeLimit(optWarnTimeLimit);
  427. if (!optMemoryLimit.isEmpty())
  428. req->setMemoryLimit(optMemoryLimit);
  429. if (!optPriority.isEmpty())
  430. req->setPriority(optPriority);
  431. if (optComment.get()) //allow empty
  432. req->setComment(optComment);
  433. Owned<IClientWUPublishWorkunitResponse> resp = client->WUPublishWorkunit(req);
  434. const char *id = resp->getQueryId();
  435. if (id && *id)
  436. {
  437. const char *qs = resp->getQuerySet();
  438. fprintf(stdout, "\n%s/%s\n", qs ? qs : "", resp->getQueryId());
  439. }
  440. if (resp->getReloadFailed())
  441. fputs("\nAdded to Queryset, but request to reload queries on cluster failed\n", stderr);
  442. int ret = outputMultiExceptionsEx(resp->getExceptions());
  443. if (outputQueryFileCopyErrors(resp->getFileErrors()))
  444. ret = 1;
  445. return ret;
  446. }
  447. virtual void usage()
  448. {
  449. fputs("\nUsage:\n"
  450. "\n"
  451. "The 'publish' command creates a query in a queryset. The query is created\n"
  452. "by adding a workunit to a queryset and assigning it a query name.\n"
  453. "\n"
  454. "If the query is being created from an ECL file, archive, shared object, dll,\n"
  455. "or text, a workunit is first created and then published to the queryset.\n"
  456. "\n"
  457. "ecl publish <target> <file> --name=<val>\n"
  458. "ecl publish <target> <wuid> --name=<val>\n"
  459. "ecl publish <target> <so|dll> --name=<val>\n"
  460. "ecl publish <target> <archive> --name=<val>\n"
  461. "ecl publish <target> - --name=<val>\n\n"
  462. " - specifies object should be read from stdin\n"
  463. " <wuid> workunit to publish\n"
  464. " <archive> archive to publish\n"
  465. " <file> ECL text file to publish\n"
  466. " <so|dll> workunit dll or shared object to publish\n"
  467. " Options:\n"
  468. " -n, --name=<val> query name to use for published workunit\n"
  469. " -A, --activate Activate query when published (default)\n"
  470. " -sp, --suspend-prev Suspend previously active query\n"
  471. " -dp, --delete-prev Delete previously active query\n"
  472. " -A-, --no-activate Do not activate query when published\n"
  473. " --no-reload Do not request a reload of the (roxie) cluster\n"
  474. " --no-files Do not copy DFS file information for referenced files\n"
  475. " --allow-foreign Do not fail if foreign files are used in query (roxie)\n"
  476. " --daliip=<IP> The IP of the DALI to be used to locate remote files\n"
  477. " -O, --overwrite Completely replace existing DFS file information (dangerous)\n"
  478. " --update-super-files Update local DFS super-files if remote DALI has changed\n"
  479. " --update-clone-from Update local clone from location if remote DALI has changed\n"
  480. " --dont-append-cluster Only use to avoid locking issues due to adding cluster to file\n"
  481. " --source-process Process cluster to copy files from\n"
  482. " --timeLimit=<ms> Value to set for query timeLimit configuration\n"
  483. " --warnTimeLimit=<ms> Value to set for query warnTimeLimit configuration\n"
  484. " --memoryLimit=<mem> Value to set for query memoryLimit configuration\n"
  485. " format <mem> as 500000B, 550K, 100M, 10G, 1T etc.\n"
  486. " --priority=<val> set the priority for this query. Value can be LOW,\n"
  487. " HIGH, SLA, NONE. NONE will clear current setting.\n"
  488. " --comment=<string> Set the comment associated with this query\n"
  489. " --wait=<ms> Max time to wait in milliseconds\n",
  490. stdout);
  491. EclCmdWithEclTarget::usage();
  492. }
  493. private:
  494. StringAttr optName;
  495. StringAttr optDaliIP;
  496. StringAttr optSourceProcess;
  497. StringAttr optMemoryLimit;
  498. StringAttr optPriority;
  499. StringAttr optComment;
  500. unsigned optMsToWait;
  501. unsigned optTimeLimit;
  502. unsigned optWarnTimeLimit;
  503. bool optNoActivate;
  504. bool activateSet;
  505. bool optNoReload;
  506. bool optDontCopyFiles;
  507. bool optSuspendPrevious;
  508. bool optDeletePrevious;
  509. bool optAllowForeign;
  510. bool optUpdateDfs;
  511. bool optUpdateSuperfiles;
  512. bool optUpdateCloneFrom;
  513. bool optDontAppendCluster; //Undesirable but here temporarily because DALI may have locking issues
  514. };
  515. inline unsigned nextWait(unsigned wait, unsigned waited)
  516. {
  517. if (waited < 5000)
  518. return 1000;
  519. if (waited < 30000)
  520. return 5000;
  521. if (waited < 60000)
  522. return 10000;
  523. if (waited < 120000)
  524. return 30000;
  525. return 60000;
  526. }
  527. class EclCmdRun : public EclCmdWithEclTarget
  528. {
  529. public:
  530. EclCmdRun() : optWaitTime((unsigned)-1), optNoRoot(false), optExceptionSeverity("info")
  531. {
  532. optObj.accept = eclObjWuid | eclObjArchive | eclObjSharedObject | eclObjWuid | eclObjQuery;
  533. }
  534. virtual eclCmdOptionMatchIndicator parseCommandLineOptions(ArgvIterator &iter)
  535. {
  536. if (iter.done())
  537. return EclCmdOptionNoMatch;
  538. for (; !iter.done(); iter.next())
  539. {
  540. if (matchVariableOption(iter, 'X', variables, false))
  541. continue;
  542. if (iter.matchOption(optObj.value, ECLOPT_WUID)||iter.matchOption(optObj.value, ECLOPT_WUID_S))
  543. continue;
  544. if (iter.matchOption(optName, ECLOPT_NAME)||iter.matchOption(optName, ECLOPT_NAME_S))
  545. continue;
  546. if (iter.matchOption(optInput, ECLOPT_INPUT)||iter.matchOption(optInput, ECLOPT_INPUT_S))
  547. continue;
  548. if (iter.matchOption(optWaitTime, ECLOPT_WAIT))
  549. continue;
  550. if (iter.matchFlag(optNoRoot, ECLOPT_NOROOT))
  551. continue;
  552. if (iter.matchFlag(optPoll, ECLOPT_POLL))
  553. continue;
  554. if (iter.matchFlag(optPre64, "--pre64")) //only for troubleshooting, do not document
  555. continue;
  556. if (iter.matchOption(optExceptionSeverity, ECLOPT_EXCEPTION_LEVEL))
  557. continue;
  558. eclCmdOptionMatchIndicator ind = EclCmdWithEclTarget::matchCommandLineOption(iter, true);
  559. if (ind != EclCmdOptionMatch)
  560. return ind;
  561. }
  562. return EclCmdOptionMatch;
  563. }
  564. virtual bool finalizeOptions(IProperties *globals)
  565. {
  566. if (!EclCmdWithEclTarget::finalizeOptions(globals))
  567. return false;
  568. if (optInput.length())
  569. {
  570. const char *in = optInput.get();
  571. while (*in && isspace(*in)) in++;
  572. if (*in!='<')
  573. {
  574. StringBuffer content;
  575. content.loadFile(in);
  576. optInput.set(content.str());
  577. }
  578. }
  579. return true;
  580. }
  581. inline bool isSoapRpcException(IException *E)
  582. {
  583. StringBuffer msg;
  584. const char *finger = E->errorMessage(msg).str();
  585. if (strncmp(finger, "SOAP ", 5))
  586. return false;
  587. finger+=5;
  588. if (!strncmp(finger, "rpc error", 9))
  589. return true;
  590. if (!strncmp(finger, "Connection error", 16))
  591. return true;
  592. return false;
  593. }
  594. int checkComplete(IClientWsWorkunits* client, IClientWUWaitRequest* req)
  595. {
  596. try
  597. {
  598. Owned<IClientWUWaitResponse> resp = client->WUWaitComplete(req);
  599. if (resp->getExceptions().ordinality())
  600. throw LINK(&resp->getExceptions());
  601. return resp->getStateID();
  602. }
  603. catch (IJSOCK_Exception *E)
  604. {
  605. outputExceptionEx(*E);
  606. E->Release();
  607. }
  608. catch (IException *E)
  609. {
  610. if (!isSoapRpcException(E))
  611. throw E;
  612. outputExceptionEx(*E);
  613. E->Release();
  614. }
  615. fputs("Still polling...\n", stderr);
  616. return WUStateUnknown; //socket issue, keep polling
  617. }
  618. int checkComplete(IClientWsWorkunits* client, IClientWUInfoRequest* req)
  619. {
  620. try
  621. {
  622. Owned<IClientWUInfoResponse> resp = client->WUInfo(req);
  623. if (resp->getExceptions().ordinality())
  624. throw LINK(&resp->getExceptions());
  625. int state = resp->getWorkunit().getStateID();
  626. switch (state)
  627. {
  628. case WUStateCompleted:
  629. case WUStateFailed:
  630. case WUStateAborted:
  631. return state;
  632. }
  633. }
  634. catch (IJSOCK_Exception *E)
  635. {
  636. outputExceptionEx(*E);
  637. E->Release();
  638. fputs("Still polling...\n", stderr);
  639. }
  640. catch (IException *E)
  641. {
  642. if (!isSoapRpcException(E))
  643. throw E;
  644. outputExceptionEx(*E);
  645. E->Release();
  646. fputs("Still polling...\n", stderr);
  647. }
  648. return WUStateUnknown; //emulate result from waitForWorkUnit which will be called for non-legacy builds
  649. }
  650. void initPollRequest(Owned<IClientWUInfoRequest> &req, IClientWsWorkunits* client, const char *wuid)
  651. {
  652. req.setown(client->createWUInfoRequest());
  653. req->setWuid(wuid);
  654. req->setTruncateEclTo64k(true);
  655. req->setIncludeExceptions(false);
  656. req->setIncludeGraphs(false);
  657. req->setIncludeSourceFiles(false);
  658. req->setIncludeResults(false);
  659. req->setIncludeResultsViewNames(false);
  660. req->setIncludeVariables(false);
  661. req->setIncludeTimers(false);
  662. req->setIncludeDebugValues(false);
  663. req->setIncludeApplicationValues(false);
  664. req->setIncludeWorkflows(false);
  665. req->setIncludeXmlSchemas(false);
  666. req->setIncludeResourceURLs(false);
  667. req->setSuppressResultSchemas(true);
  668. }
  669. void initPollRequest(Owned<IClientWUWaitRequest> &req, IClientWsWorkunits* client, const char *wuid)
  670. {
  671. req.setown(client->createWUWaitCompleteRequest());
  672. req->setWuid(wuid);
  673. req->setWait(0); //Just return the current state
  674. }
  675. int pollForCompletion(IClientWsWorkunits* client, const char *wuid, bool optimized)
  676. {
  677. Owned<IClientWUInfoRequest> reqInfo;
  678. Owned<IClientWUWaitRequest> reqQuick;
  679. if (optimized)
  680. initPollRequest(reqQuick, client, wuid);
  681. else
  682. initPollRequest(reqInfo, client, wuid);
  683. if (optVerbose)
  684. fputs("Polling for completion...\n", stdout);
  685. int state = WUStateUnknown;
  686. for(;;)
  687. {
  688. if (optimized)
  689. state = checkComplete(client, reqQuick);
  690. else
  691. state = checkComplete(client, reqInfo);
  692. if (state != WUStateUnknown)
  693. break;
  694. unsigned waited = msTick() - startTimeMs;
  695. if (optWaitTime!=(unsigned)-1 && waited>=optWaitTime)
  696. return WUStateUnknown;
  697. Sleep(nextWait(optWaitTime, waited));
  698. }
  699. return state;
  700. }
  701. void gatherLegacyServerResults(IClientWsWorkunits* client, const char *wuid)
  702. {
  703. if (optVerbose)
  704. fputs("Getting Workunit Information\n", stdout);
  705. Owned<IClientWUInfoRequest> req = client->createWUInfoRequest();
  706. setCmdRequestTimeouts(req->rpc(), optWaitTime, optWaitConnectMs, optWaitReadSec);
  707. req->setWuid(wuid);
  708. req->setIncludeExceptions(true);
  709. req->setIncludeGraphs(false);
  710. req->setIncludeSourceFiles(false);
  711. req->setIncludeResults(false); //ECL layout results, not xml
  712. req->setIncludeResultsViewNames(false);
  713. req->setIncludeVariables(false);
  714. req->setIncludeTimers(false);
  715. req->setIncludeDebugValues(false);
  716. req->setIncludeApplicationValues(false);
  717. req->setIncludeWorkflows(false);
  718. req->setIncludeXmlSchemas(false);
  719. req->setIncludeResourceURLs(false);
  720. req->setSuppressResultSchemas(true);
  721. Owned<IClientWUInfoResponse> resp = client->WUInfo(req);
  722. IConstECLWorkunit &wu = resp->getWorkunit();
  723. IArrayOf<IConstECLException> &exceptions = wu.getExceptions();
  724. unsigned count = wu.getResultCount();
  725. if (count<=0 && exceptions.ordinality()<=0)
  726. return;
  727. if (optVerbose)
  728. fputs("Getting Results\n", stdout);
  729. fputs("<Result>\n", stdout);
  730. ForEachItemIn(pos, exceptions)
  731. {
  732. IConstECLException &e = exceptions.item(pos);
  733. fprintf(stdout, " <Exception><Code>%d</Code><Source>%s</Source><Message>%s</Message></Exception>\n", e.getCode(), e.getSource(), e.getMessage());
  734. }
  735. Owned<IClientWUResultRequest> resReq = client->createWUResultRequest();
  736. resReq->setWuid(wuid);
  737. resReq->setSuppressXmlSchema(true);
  738. for (unsigned seq=0; seq<count; seq++)
  739. {
  740. resReq->setSequence(seq);
  741. Owned<IClientWUResultResponse> resp = client->WUResult(resReq);
  742. if (resp->getExceptions().ordinality())
  743. throw LINK(&resp->getExceptions());
  744. fwrite(resp->getResult(), 8, 1, stdout);
  745. //insert name attribute into <Dataset> tag
  746. fprintf(stdout, " name='%s'", resp->getName());
  747. fputs(resp->getResult()+8, stdout);
  748. }
  749. fputs("</Result>\n", stdout);
  750. }
  751. void getAndOutputResults(IClientWsWorkunits* client, const char *wuid)
  752. {
  753. if (optVerbose)
  754. fputs("Retrieving Results\n", stdout);
  755. Owned<IClientWUFullResultRequest> req = client->createWUFullResultRequest();
  756. setCmdRequestTimeouts(req->rpc(), optWaitTime, optWaitConnectMs, optWaitReadSec);
  757. req->setWuid(wuid);
  758. req->setNoRootTag(optNoRoot);
  759. req->setExceptionSeverity(optExceptionSeverity);
  760. Owned<IClientWUFullResultResponse> resp = client->WUFullResult(req);
  761. if (resp->getResults())
  762. fprintf(stdout, "%s\n", resp->getResults());
  763. }
  764. void processResults(IClientWsWorkunits* client, const char *wuid, bool optimized)
  765. {
  766. if (optimized)
  767. getAndOutputResults(client, wuid);
  768. else
  769. gatherLegacyServerResults(client, wuid);
  770. }
  771. int pollForResults(IClientWsWorkunits* client, const char *wuid)
  772. {
  773. int major = 0;
  774. int minor = 0;
  775. int point = 0;
  776. bool useCompression = false;
  777. checkFeatures(client, useCompression, major, minor, point, optWaitTime, optWaitConnectMs, optWaitReadSec);
  778. bool optimized = !optPre64 && (major>=6 && minor>=3);
  779. try
  780. {
  781. int state = pollForCompletion(client, wuid, optimized);
  782. switch (state)
  783. {
  784. case WUStateCompleted:
  785. processResults(client, wuid, optimized);
  786. return 0;
  787. case WUStateUnknown:
  788. fprintf(stderr, "Timed out waiting for %s to complete, workunit is still running.\n", wuid);
  789. break;
  790. case WUStateFailed:
  791. case WUStateAborted:
  792. fprintf(stderr, "%s %s.\n", wuid, getWorkunitStateStr((WUState)state));
  793. break;
  794. default:
  795. fprintf(stderr, "%s in unrecognized state.\n", wuid);
  796. break;
  797. }
  798. }
  799. catch (IMultiException *ME)
  800. {
  801. outputMultiExceptionsEx(*ME);
  802. ME->Release();
  803. }
  804. catch (IException *E)
  805. {
  806. StringBuffer msg;
  807. fprintf(stderr, "Exception polling for results: %d: %s\n", E->errorCode(), E->errorMessage(msg).str());
  808. E->Release();
  809. }
  810. return 1;
  811. }
  812. int getInitialRunWait()
  813. {
  814. if (!optPoll)
  815. return optWaitTime;
  816. return (optWaitTime < 10000) ? optWaitTime : 10000; //stay connected for the first 10 seconds even if polling
  817. }
  818. bool isFinalState(WUState state)
  819. {
  820. switch (state)
  821. {
  822. case WUStateUnknown:
  823. case WUStateArchived:
  824. case WUStateAborting:
  825. case WUStateCompleted:
  826. case WUStateFailed:
  827. case WUStateAborted:
  828. return true;
  829. }
  830. return false;
  831. }
  832. virtual int processCMD()
  833. {
  834. Owned<IClientWsWorkunits> client = createCmdClientExt(WsWorkunits, *this, "?upload_"); //upload_ disables maxRequestEntityLength
  835. Owned<IClientWURunRequest> req = client->createWURunRequest();
  836. setCmdRequestTimeouts(req->rpc(), optWaitTime, optWaitConnectMs, optWaitReadSec);
  837. req->setCloneWorkunit(true);
  838. req->setNoRootTag(optNoRoot);
  839. // Add a debug value to indicate that Roxie variable filenames are ok
  840. // We put it at front of list so that it can be overridden explicitly by user.
  841. Owned<IEspNamedValue> nv = createNamedValue();
  842. nv->setName("allowVariableRoxieFileNames");
  843. nv->setValue("1");
  844. debugValues.add(*nv.getClear(), 0);
  845. StringBuffer wuid;
  846. StringBuffer wuCluster;
  847. StringBuffer query;
  848. if (optObj.type==eclObjWuid)
  849. {
  850. req->setWuid(wuid.set(optObj.value.get()).str());
  851. if (optVerbose)
  852. fprintf(stdout, "Running workunit %s\n", wuid.str());
  853. }
  854. else if (optObj.type==eclObjQuery)
  855. {
  856. req->setQuerySet(optTargetCluster);
  857. req->setQuery(query.set(optObj.query.get()).str());
  858. if (optVerbose)
  859. fprintf(stdout, "Running %s/%s\n", optTargetCluster.str(), query.str());
  860. }
  861. else
  862. {
  863. req->setCloneWorkunit(false);
  864. if (!doDeploy(*this, client, optWaitTime, optTargetCluster.get(), optName.get(), &wuid, &wuCluster, optNoArchive, optVerbose))
  865. return 1;
  866. req->setWuid(wuid.str());
  867. if (optVerbose)
  868. fprintf(stdout, "Running deployed workunit %s\n", wuid.str());
  869. }
  870. if (wuCluster.length())
  871. req->setCluster(wuCluster.str());
  872. else if (optTargetCluster.length())
  873. req->setCluster(optTargetCluster.get());
  874. req->setWait(getInitialRunWait());
  875. if (optInput.length())
  876. req->setInput(optInput.get());
  877. req->setExceptionSeverity(optExceptionSeverity); //throws exception if invalid value
  878. expandDefintionsAsDebugValues(definitions, debugValues);
  879. if (debugValues.length())
  880. req->setDebugValues(debugValues);
  881. if (variables.length())
  882. req->setVariables(variables);
  883. startTimeMs = msTick();
  884. Owned<IClientWURunResponse> resp;
  885. try
  886. {
  887. resp.setown(client->WURun(req));
  888. }
  889. catch (IJSOCK_Exception *E)
  890. {
  891. if (optPoll)
  892. fputs("Socket error, no WUID, can't continue but workunit may still be running...\n", stderr);
  893. throw E;
  894. }
  895. catch (IException *E)
  896. {
  897. if (optPoll && isSoapRpcException(E))
  898. fputs("SOAP error, no WUID, can't continue but workunit may still be running...\n", stderr);
  899. throw E;
  900. }
  901. if (checkMultiExceptionsQueryNotFound(resp->getExceptions()))
  902. {
  903. //checking if it was a query was last resort. may not have been after all, use generic language
  904. fprintf(stderr, "\n%s not found\n", optObj.query.str());
  905. return 1;
  906. }
  907. int ret = outputMultiExceptionsEx(resp->getExceptions());
  908. StringBuffer respwuid(resp->getWuid());
  909. if (!respwuid.length()) //everything below requires workunit
  910. return ret;
  911. if (optVerbose && respwuid.length() && !streq(wuid.str(), respwuid.str()))
  912. fprintf(stdout, "As %s\n", respwuid.str());
  913. WUState state = getWorkUnitState(resp->getState());
  914. if (optPoll && !isFinalState(state))
  915. return pollForResults(client, respwuid);
  916. switch (state)
  917. {
  918. case WUStateCompleted:
  919. break;
  920. case WUStateCompiled:
  921. case WUStateSubmitted:
  922. case WUStateCompiling:
  923. case WUStateUploadingFiles:
  924. case WUStateScheduled:
  925. case WUStateWait:
  926. case WUStateDebugPaused:
  927. case WUStateDebugRunning:
  928. case WUStatePaused:
  929. case WUStateBlocked:
  930. case WUStateRunning:
  931. fprintf(stderr, "%s %s\n", respwuid.str(), resp->getState());
  932. fprintf(stderr, "Timed out waiting for %s to complete, workunit may still be running.\n", wuid.str()); //server side waiting timed out
  933. ret = 2;
  934. break;
  935. case WUStateUnknown:
  936. case WUStateFailed:
  937. case WUStateArchived:
  938. case WUStateAborting:
  939. case WUStateAborted:
  940. default:
  941. fprintf(stderr, "%s %s\n", respwuid.str(), resp->getState());
  942. ret = 4;
  943. }
  944. if (resp->getResults())
  945. fprintf(stdout, "%s\n", resp->getResults());
  946. return ret;
  947. }
  948. virtual void usage()
  949. {
  950. fputs("\nUsage:\n"
  951. "\n"
  952. "The 'run' command executes an ECL workunit, text, file, archive, query,\n"
  953. "shared object, or dll on the specified HPCC target cluster.\n"
  954. "\n"
  955. "Query input can be provided in xml form via the --input parameter. Input\n"
  956. "xml can be provided directly or by referencing a file\n"
  957. "\n"
  958. "ecl run <target> <file> --name=<val> [--input=<file|xml>][--wait=<i>]\n"
  959. "ecl run <target> <wuid> [--input=<file|xml>][--wait=<ms>]\n"
  960. "ecl run <target> <query> [--input=<file|xml>][--wait=<ms>]\n"
  961. "ecl run <target> <so|dll> [--name=<val>][--input=<file|xml>][--wait=<ms>]\n"
  962. "ecl run <target> <archive> --name=<val> [--input=<file|xml>][--wait=<ms>]\n"
  963. "ecl run <target> - --name=<val> [--input=<file|xml>][--wait=<ms>]\n\n"
  964. " - specifies object should be read from stdin\n"
  965. " <wuid> workunit to publish\n"
  966. " <archive> archive to publish\n"
  967. " <eclfile> ECL text file to publish\n"
  968. " <so|dll> workunit dll or shared object to publish\n"
  969. " Options:\n"
  970. " -n, --name=<val> job name\n"
  971. " -in,--input=<file|xml> file or xml content to use as query input\n"
  972. " -X<name>=<value> sets the stored input value (stored('name'))\n"
  973. " --wait=<ms> time to wait for completion\n"
  974. " --poll poll for results, rather than remain connected\n"
  975. " --exception-level=<level> minimum severity level for exceptions\n"
  976. " values: 'info', 'warning', 'error'\n",
  977. stdout);
  978. EclCmdWithEclTarget::usage();
  979. }
  980. private:
  981. StringAttr optName;
  982. StringAttr optInput;
  983. StringAttr optExceptionSeverity;
  984. IArrayOf<IEspNamedValue> variables;
  985. unsigned optWaitTime = 0;
  986. unsigned startTimeMs = 0;
  987. bool optNoRoot = false;
  988. bool optPoll = false;
  989. bool optPre64 = false; //only for troubleshooting, do not document
  990. };
  991. class EclCmdResults : public EclCmdCommon
  992. {
  993. public:
  994. EclCmdResults() : optExceptionSeverity("info")
  995. {
  996. }
  997. virtual eclCmdOptionMatchIndicator parseCommandLineOptions(ArgvIterator &iter)
  998. {
  999. if (iter.done())
  1000. return EclCmdOptionNoMatch;
  1001. for (; !iter.done(); iter.next())
  1002. {
  1003. const char *arg = iter.query();
  1004. if (*arg!='-')
  1005. {
  1006. if (optWuid.length())
  1007. {
  1008. fprintf(stderr, "\nunrecognized argument %s\n", arg);
  1009. return EclCmdOptionCompletion;
  1010. }
  1011. if (!looksLikeAWuid(arg, 'W'))
  1012. {
  1013. fprintf(stderr, "\nargument should be a workunit id: %s\n", arg);
  1014. return EclCmdOptionCompletion;
  1015. }
  1016. optWuid.set(arg);
  1017. continue;
  1018. }
  1019. if (iter.matchFlag(optNoRoot, ECLOPT_NOROOT))
  1020. continue;
  1021. if (iter.matchOption(optExceptionSeverity, ECLOPT_EXCEPTION_LEVEL))
  1022. continue;
  1023. if (iter.matchFlag(optPre64, "--pre64")) //only for troubleshooting, do not document
  1024. continue;
  1025. eclCmdOptionMatchIndicator ind = EclCmdCommon::matchCommandLineOption(iter, true);
  1026. if (ind != EclCmdOptionMatch)
  1027. return ind;
  1028. }
  1029. return EclCmdOptionMatch;
  1030. }
  1031. virtual bool finalizeOptions(IProperties *globals)
  1032. {
  1033. if (optWuid.isEmpty())
  1034. {
  1035. fprintf(stderr, "No WUID provided.\n");
  1036. return 0;
  1037. }
  1038. if (!EclCmdCommon::finalizeOptions(globals))
  1039. return false;
  1040. return true;
  1041. }
  1042. int gatherLegacyServerResults(IClientWsWorkunits* client, const char *wuid)
  1043. {
  1044. Owned<IClientWUInfoRequest> req = client->createWUInfoRequest();
  1045. setCmdRequestTimeouts(req->rpc(), 0, optWaitConnectMs, optWaitReadSec);
  1046. req->setWuid(wuid);
  1047. req->setIncludeExceptions(true);
  1048. req->setIncludeGraphs(false);
  1049. req->setIncludeSourceFiles(false);
  1050. req->setIncludeResults(false); //ECL layout results, not xml
  1051. req->setIncludeResultsViewNames(false);
  1052. req->setIncludeVariables(false);
  1053. req->setIncludeTimers(false);
  1054. req->setIncludeDebugValues(false);
  1055. req->setIncludeApplicationValues(false);
  1056. req->setIncludeWorkflows(false);
  1057. req->setIncludeXmlSchemas(false);
  1058. req->setIncludeResourceURLs(false);
  1059. req->setSuppressResultSchemas(true);
  1060. Owned<IClientWUInfoResponse> resp = client->WUInfo(req);
  1061. int ret = outputMultiExceptionsEx(resp->getExceptions());
  1062. IConstECLWorkunit &wu = resp->getWorkunit();
  1063. IArrayOf<IConstECLException> &exceptions = wu.getExceptions();
  1064. fputs("<Result>\n", stdout);
  1065. ForEachItemIn(pos, exceptions)
  1066. {
  1067. IConstECLException &e = exceptions.item(pos);
  1068. fprintf(stdout, " <Exception><Code>%d</Code><Source>%s</Source><Message>%s</Message></Exception>\n", e.getCode(), e.getSource(), e.getMessage());
  1069. }
  1070. Owned<IClientWUResultRequest> resReq = client->createWUResultRequest();
  1071. resReq->setWuid(wuid);
  1072. resReq->setSuppressXmlSchema(true);
  1073. unsigned count = wu.getResultCount();
  1074. for (unsigned seq=0; seq<count; seq++)
  1075. {
  1076. resReq->setSequence(seq);
  1077. Owned<IClientWUResultResponse> resp = client->WUResult(resReq);
  1078. if (resp->getExceptions().ordinality())
  1079. throw LINK(&resp->getExceptions());
  1080. fwrite(resp->getResult(), 8, 1, stdout);
  1081. //insert name attribute into <Dataset> tag
  1082. fprintf(stdout, " name='%s'", resp->getName());
  1083. fputs(resp->getResult()+8, stdout);
  1084. }
  1085. fputs("</Result>\n", stdout);
  1086. return ret;
  1087. }
  1088. int getAndOutputResults(IClientWsWorkunits* client, const char *wuid)
  1089. {
  1090. Owned<IClientWUFullResultRequest> req = client->createWUFullResultRequest();
  1091. setCmdRequestTimeouts(req->rpc(), 0, optWaitConnectMs, optWaitReadSec);
  1092. req->setWuid(wuid);
  1093. req->setNoRootTag(optNoRoot);
  1094. req->setExceptionSeverity(optExceptionSeverity);
  1095. Owned<IClientWUFullResultResponse> resp = client->WUFullResult(req);
  1096. int ret = outputMultiExceptionsEx(resp->getExceptions());
  1097. if (resp->getResults())
  1098. fprintf(stdout, "%s\n", resp->getResults());
  1099. return ret;
  1100. }
  1101. virtual int processCMD()
  1102. {
  1103. Owned<IClientWsWorkunits> client = createCmdClient(WsWorkunits, *this); //upload_ disables maxRequestEntityLength
  1104. int major = 0;
  1105. int minor = 0;
  1106. int point = 0;
  1107. bool useCompression = false;
  1108. checkFeatures(client, useCompression, major, minor, point, 0, optWaitConnectMs, optWaitReadSec);
  1109. if (!optPre64 && (major>=6 && minor>=3))
  1110. return getAndOutputResults(client, optWuid);
  1111. return gatherLegacyServerResults(client, optWuid);
  1112. }
  1113. virtual void usage()
  1114. {
  1115. fputs("\nUsage:\n"
  1116. "\n"
  1117. "The 'results' command displays the full results of a workunit in xml form.\n"
  1118. "\n"
  1119. "ecl results <wuid>\n"
  1120. "ecl results <wuid> --noroot\n"
  1121. " <wuid> workunit to get results from\n"
  1122. " Options:\n"
  1123. " --exception-level=<level> minimum severity level for exceptions\n"
  1124. " values: 'info', 'warning', 'error'\n"
  1125. " --noroot output result xml without root tag\n",
  1126. stdout);
  1127. EclCmdCommon::usage();
  1128. }
  1129. private:
  1130. StringAttr optWuid;
  1131. StringAttr optExceptionSeverity;
  1132. bool optNoRoot = false;
  1133. bool optPre64 = false; //only for troubleshooting gathering results from old servers, do not document
  1134. };
  1135. void outputQueryActionResults(const IArrayOf<IConstQuerySetQueryActionResult> &results, const char *act, const char *qs)
  1136. {
  1137. ForEachItemIn(i, results)
  1138. {
  1139. IConstQuerySetQueryActionResult &item = results.item(i);
  1140. const char *id = item.getQueryId();
  1141. if (item.getSuccess())
  1142. fprintf(stdout, "\n%s %s/%s\n", act, qs, id ? id : "");
  1143. else if (item.getCode()|| item.getMessage())
  1144. {
  1145. const char *msg = item.getMessage();
  1146. fprintf(stderr, "Query %s Error (%d) %s\n", id ? id : "", item.getCode(), msg ? msg : "");
  1147. }
  1148. }
  1149. }
  1150. class EclCmdActivate : public EclCmdWithQueryTarget
  1151. {
  1152. public:
  1153. EclCmdActivate()
  1154. {
  1155. }
  1156. virtual int processCMD()
  1157. {
  1158. Owned<IClientWsWorkunits> client = createCmdClient(WsWorkunits, *this);
  1159. Owned<IClientWUQuerySetQueryActionRequest> req = client->createWUQuerysetQueryActionRequest();
  1160. setCmdRequestTimeouts(req->rpc(), 0, optWaitConnectMs, optWaitReadSec);
  1161. IArrayOf<IEspQuerySetQueryActionItem> queries;
  1162. Owned<IEspQuerySetQueryActionItem> item = createQuerySetQueryActionItem();
  1163. item->setQueryId(optQuery.get());
  1164. queries.append(*item.getClear());
  1165. req->setQueries(queries);
  1166. req->setAction("Activate");
  1167. req->setQuerySetName(optQuerySet.get());
  1168. Owned<IClientWUQuerySetQueryActionResponse> resp = client->WUQuerysetQueryAction(req);
  1169. IArrayOf<IConstQuerySetQueryActionResult> &results = resp->getResults();
  1170. int ret = outputMultiExceptionsEx(resp->getExceptions());
  1171. if (ret != 0)
  1172. return ret;
  1173. if (results.empty())
  1174. fprintf(stderr, "\nError Empty Result!\n");
  1175. else
  1176. outputQueryActionResults(results, "Activated", optQuerySet.str());
  1177. return 0;
  1178. }
  1179. virtual void usage()
  1180. {
  1181. fputs("\nUsage:\n"
  1182. "\n"
  1183. "The 'activate' command assigns a query to the active alias with the same\n"
  1184. "name as the query.\n"
  1185. "\n"
  1186. "ecl activate <target> <query_id>\n"
  1187. " Options:\n"
  1188. " <target> name of target queryset containing query to activate\n"
  1189. " <query_id> query to activate\n",
  1190. stdout);
  1191. EclCmdWithQueryTarget::usage();
  1192. }
  1193. };
  1194. class EclCmdUnPublish : public EclCmdWithQueryTarget
  1195. {
  1196. public:
  1197. EclCmdUnPublish()
  1198. {
  1199. }
  1200. virtual int processCMD()
  1201. {
  1202. Owned<IClientWsWorkunits> client = createCmdClient(WsWorkunits, *this);
  1203. Owned<IClientWUQuerySetQueryActionRequest> req = client->createWUQuerysetQueryActionRequest();
  1204. setCmdRequestTimeouts(req->rpc(), 0, optWaitConnectMs, optWaitReadSec);
  1205. req->setQuerySetName(optQuerySet.get());
  1206. req->setAction("Delete");
  1207. IArrayOf<IEspQuerySetQueryActionItem> queries;
  1208. Owned<IEspQuerySetQueryActionItem> item = createQuerySetQueryActionItem();
  1209. item->setQueryId(optQuery.get());
  1210. queries.append(*item.getClear());
  1211. req->setQueries(queries);
  1212. Owned<IClientWUQuerySetQueryActionResponse> resp = client->WUQuerysetQueryAction(req);
  1213. IArrayOf<IConstQuerySetQueryActionResult> &results = resp->getResults();
  1214. int ret = outputMultiExceptionsEx(resp->getExceptions());
  1215. if (ret != 0)
  1216. return ret;
  1217. if (results.empty())
  1218. fprintf(stderr, "\nError Empty Result!\n");
  1219. else
  1220. outputQueryActionResults(results, "Unpublished", optQuerySet.str());
  1221. return 0;
  1222. }
  1223. virtual void usage()
  1224. {
  1225. fputs("\nUsage:\n"
  1226. "\n"
  1227. "The 'unpublish' command removes a query from a target queryset.\n"
  1228. "\n"
  1229. "ecl unpublish <target> <query_id>\n"
  1230. " Options:\n"
  1231. " <target> name of target queryset containing the query to remove\n"
  1232. " <query_id> query to remove from the queryset\n",
  1233. stdout);
  1234. EclCmdWithQueryTarget::usage();
  1235. }
  1236. };
  1237. class EclCmdDeactivate : public EclCmdWithQueryTarget
  1238. {
  1239. public:
  1240. EclCmdDeactivate()
  1241. {
  1242. }
  1243. virtual int processCMD()
  1244. {
  1245. StringBuffer s;
  1246. Owned<IClientWsWorkunits> client = createCmdClient(WsWorkunits, *this);
  1247. Owned<IClientWUQuerySetAliasActionRequest> req = client->createWUQuerysetAliasActionRequest();
  1248. setCmdRequestTimeouts(req->rpc(), 0, optWaitConnectMs, optWaitReadSec);
  1249. IArrayOf<IEspQuerySetAliasActionItem> aliases;
  1250. Owned<IEspQuerySetAliasActionItem> item = createQuerySetAliasActionItem();
  1251. item->setName(optQuery.get());
  1252. aliases.append(*item.getClear());
  1253. req->setAliases(aliases);
  1254. req->setAction("Deactivate");
  1255. req->setQuerySetName(optQuerySet.get());
  1256. Owned<IClientWUQuerySetAliasActionResponse> resp = client->WUQuerysetAliasAction(req);
  1257. IArrayOf<IConstQuerySetAliasActionResult> &results = resp->getResults();
  1258. int ret = outputMultiExceptionsEx(resp->getExceptions());
  1259. if (ret != 0)
  1260. return ret;
  1261. if (results.empty())
  1262. fprintf(stderr, "\nError Empty Result!\n");
  1263. else
  1264. {
  1265. IConstQuerySetAliasActionResult &item = results.item(0);
  1266. if (item.getSuccess())
  1267. fprintf(stdout, "Deactivated alias %s/%s\n", optQuerySet.str(), optQuery.str());
  1268. else if (item.getCode()|| item.getMessage())
  1269. fprintf(stderr, "Error (%d) %s\n", item.getCode(), item.getMessage());
  1270. }
  1271. return 0;
  1272. }
  1273. virtual void usage()
  1274. {
  1275. fputs("\nUsage:\n"
  1276. "\n"
  1277. "The 'deactivate' command removes an active query alias from the given target.\n"
  1278. "\n"
  1279. "ecl deactivate <target> <active_alias>\n"
  1280. "\n"
  1281. " Options:\n"
  1282. " <target> target queryset containing alias to deactivate\n"
  1283. " <active_alias> active alias to be removed from the queryset\n",
  1284. stdout);
  1285. EclCmdWithQueryTarget::usage();
  1286. }
  1287. };
  1288. class EclCmdAbort : public EclCmdCommon
  1289. {
  1290. public:
  1291. EclCmdAbort()
  1292. {
  1293. optObj.accept = eclObjWuid;
  1294. }
  1295. virtual eclCmdOptionMatchIndicator parseCommandLineOptions(ArgvIterator &iter)
  1296. {
  1297. eclCmdOptionMatchIndicator retVal = EclCmdOptionNoMatch;
  1298. if (iter.done())
  1299. return EclCmdOptionNoMatch;
  1300. for (; !iter.done(); iter.next())
  1301. {
  1302. const char *arg = iter.query();
  1303. if (iter.matchOption(optName, ECLOPT_WUID)||iter.matchOption(optName, ECLOPT_WUID_S))
  1304. {
  1305. optObj.type = eclObjWuid;
  1306. retVal = EclCmdOptionMatch;
  1307. continue;
  1308. }
  1309. if (iter.matchOption(optName, ECLOPT_NAME)||iter.matchOption(optName, ECLOPT_NAME_S))
  1310. {
  1311. optObj.type = eclObjQuery;
  1312. retVal = EclCmdOptionMatch;
  1313. continue;
  1314. }
  1315. eclCmdOptionMatchIndicator ind = EclCmdCommon::matchCommandLineOption(iter, true);
  1316. if (ind != EclCmdOptionMatch)
  1317. return ind;
  1318. }
  1319. return retVal;
  1320. }
  1321. virtual bool finalizeOptions(IProperties *globals)
  1322. {
  1323. if (!EclCmdCommon::finalizeOptions(globals))
  1324. return false;
  1325. return true;
  1326. }
  1327. virtual int processCMD()
  1328. {
  1329. StringArray wuids;
  1330. Owned<IClientWsWorkunits> client = createCmdClient(WsWorkunits, *this);
  1331. Owned<IClientWUQueryRequest> reqQ = client->createWUQueryRequest();
  1332. if (optObj.type == eclObjQuery)
  1333. {
  1334. reqQ->setJobname(optName.get());
  1335. Owned<IClientWUQueryResponse> respQ = client->WUQuery(reqQ);
  1336. int res = respQ->queryClientStatus();
  1337. if (!respQ->getCount_isNull())
  1338. {
  1339. IArrayOf<IConstECLWorkunit>& wus = respQ->getWorkunits();
  1340. ForEachItemIn(idx, wus)
  1341. {
  1342. wuids.append(wus.item(idx).getWuid());
  1343. }
  1344. }
  1345. }
  1346. else
  1347. {
  1348. wuids.append(optName.get());
  1349. }
  1350. if (wuids.empty())
  1351. return 0;
  1352. // Abort
  1353. Owned<IClientWUAbortRequest> req = client->createWUAbortRequest();
  1354. setCmdRequestTimeouts(req->rpc(), 0, optWaitConnectMs, optWaitReadSec);
  1355. req->setWuids(wuids);
  1356. Owned<IClientWUAbortResponse> resp = client->WUAbort(req);
  1357. int ret = outputMultiExceptionsEx(resp->getExceptions());
  1358. // Get status of WU(s)
  1359. if (optObj.type == eclObjQuery)
  1360. {
  1361. reqQ->setJobname(optName.get());
  1362. }
  1363. else
  1364. {
  1365. reqQ->setWuid(optName.get());
  1366. }
  1367. Owned<IClientWUQueryResponse> respQ = client->WUQuery(reqQ);
  1368. if (!respQ->getCount_isNull())
  1369. {
  1370. IArrayOf<IConstECLWorkunit>& wus = respQ->getWorkunits();
  1371. if (!wus.empty())
  1372. {
  1373. if (wus.ordinality() > 1)
  1374. {
  1375. ForEachItemIn(idx, wus)
  1376. {
  1377. fprintf(stdout, "%s,%s\n", wus.item(idx).getWuid(), getWorkunitStateStr((WUState) wus.item(idx).getStateID()) );
  1378. }
  1379. }
  1380. else
  1381. {
  1382. fprintf(stdout, "%s\n", getWorkunitStateStr((WUState) wus.item(0).getStateID()) );
  1383. }
  1384. }
  1385. }
  1386. return ret;
  1387. }
  1388. virtual void usage()
  1389. {
  1390. fputs("\nUsage:\n"
  1391. "\n"
  1392. "The 'abort' command aborts one or more workunit on the HPCC system from the given WUID or job name\n"
  1393. "The workunit(s) abort requests and the current status returns\n"
  1394. "\n"
  1395. "ecl abort -wu <WUID>| -n <job name>\n"
  1396. " WUID workunit ID\n"
  1397. " job name workunit job name\n",
  1398. stdout);
  1399. EclCmdCommon::usage();
  1400. }
  1401. private:
  1402. StringAttr optName;
  1403. EclObjectParameter optObj;
  1404. };
  1405. class EclCmdGetName : public EclCmdCommon
  1406. {
  1407. public:
  1408. EclCmdGetName() : optListLimit(100)
  1409. {
  1410. optObj.accept = eclObjWuid;
  1411. }
  1412. virtual eclCmdOptionMatchIndicator parseCommandLineOptions(ArgvIterator &iter)
  1413. {
  1414. eclCmdOptionMatchIndicator retVal = EclCmdOptionNoMatch;
  1415. if (iter.done())
  1416. return EclCmdOptionNoMatch;
  1417. for (; !iter.done(); iter.next())
  1418. {
  1419. const char *arg = iter.query();
  1420. if (iter.matchOption(optName, ECLOPT_WUID)||iter.matchOption(optName, ECLOPT_WUID_S))
  1421. {
  1422. optObj.type = eclObjWuid;
  1423. retVal = EclCmdOptionMatch;
  1424. continue;
  1425. }
  1426. if (iter.matchOption(optListLimit, ECLOPT_RESULT_LIMIT))
  1427. {
  1428. continue;
  1429. }
  1430. eclCmdOptionMatchIndicator ind = EclCmdCommon::matchCommandLineOption(iter, true);
  1431. if (ind != EclCmdOptionMatch)
  1432. return ind;
  1433. }
  1434. return retVal;
  1435. }
  1436. virtual bool finalizeOptions(IProperties *globals)
  1437. {
  1438. if (!EclCmdCommon::finalizeOptions(globals))
  1439. return false;
  1440. return true;
  1441. }
  1442. virtual int processCMD()
  1443. {
  1444. Owned<IClientWsWorkunits> client = createCmdClient(WsWorkunits, *this);
  1445. Owned<IClientWUQueryRequest> req = client->createWUQueryRequest();
  1446. setCmdRequestTimeouts(req->rpc(), 0, optWaitConnectMs, optWaitReadSec);
  1447. if (optName.isEmpty())
  1448. return 0;
  1449. req->setWuid(optName.get());
  1450. if (optListLimit)
  1451. req->setCount(optListLimit);
  1452. Owned<IClientWUQueryResponse> resp = client->WUQuery(req);
  1453. if (!resp->getCount_isNull())
  1454. {
  1455. IArrayOf<IConstECLWorkunit>& wus = resp->getWorkunits();
  1456. ForEachItemIn(idx, wus)
  1457. {
  1458. fprintf(stdout, "%s\n", wus.item(idx).getJobname());
  1459. }
  1460. }
  1461. return 0;
  1462. }
  1463. virtual void usage()
  1464. {
  1465. fputs("\nUsage:\n"
  1466. "\n"
  1467. "The 'getname' command returns with the workunit name from the given workunit id.\n"
  1468. "\n"
  1469. "ecl getname --wuid <WUID>\n"
  1470. "\n"
  1471. " WUID workunit ID\n"
  1472. " Options:\n"
  1473. " --limit=<limit> Sets the result limit for the query, defaults to 100\n",
  1474. stdout);
  1475. EclCmdCommon::usage();
  1476. }
  1477. private:
  1478. StringAttr optName;
  1479. EclObjectParameter optObj;
  1480. unsigned int optListLimit;
  1481. };
  1482. class EclCmdGetWuid : public EclCmdCommon
  1483. {
  1484. public:
  1485. EclCmdGetWuid() : optListLimit(100)
  1486. {
  1487. }
  1488. virtual eclCmdOptionMatchIndicator parseCommandLineOptions(ArgvIterator &iter)
  1489. {
  1490. eclCmdOptionMatchIndicator retVal = EclCmdOptionNoMatch;
  1491. if (iter.done())
  1492. return EclCmdOptionNoMatch;
  1493. for (; !iter.done(); iter.next())
  1494. {
  1495. const char *arg = iter.query();
  1496. if (iter.matchOption(optName, ECLOPT_NAME)||iter.matchOption(optName, ECLOPT_NAME_S))
  1497. {
  1498. retVal = EclCmdOptionMatch;
  1499. continue;
  1500. }
  1501. if (iter.matchOption(optListLimit, ECLOPT_RESULT_LIMIT))
  1502. {
  1503. continue;
  1504. }
  1505. eclCmdOptionMatchIndicator ind = EclCmdCommon::matchCommandLineOption(iter, true);
  1506. if (ind != EclCmdOptionMatch)
  1507. return ind;
  1508. }
  1509. return retVal;
  1510. }
  1511. virtual bool finalizeOptions(IProperties *globals)
  1512. {
  1513. if (!EclCmdCommon::finalizeOptions(globals))
  1514. return false;
  1515. return true;
  1516. }
  1517. virtual int processCMD()
  1518. {
  1519. Owned<IClientWsWorkunits> client = createCmdClient(WsWorkunits, *this);
  1520. Owned<IClientWUQueryRequest> req = client->createWUQueryRequest();
  1521. setCmdRequestTimeouts(req->rpc(), 0, optWaitConnectMs, optWaitReadSec);
  1522. if (optName.isEmpty())
  1523. return 0;
  1524. req->setJobname(optName.get());
  1525. Owned<IClientWUQueryResponse> resp = client->WUQuery(req);
  1526. if (!resp->getCount_isNull())
  1527. {
  1528. IArrayOf<IConstECLWorkunit>& wus = resp->getWorkunits();
  1529. ForEachItemIn(idx, wus)
  1530. {
  1531. if (idx == optListLimit)
  1532. break;
  1533. fprintf(stdout, "%s\n", wus.item(idx).getWuid());
  1534. }
  1535. }
  1536. return 0;
  1537. }
  1538. virtual void usage()
  1539. {
  1540. fputs("\nUsage:\n"
  1541. "\n"
  1542. "The 'getwuid' command returns with WUID(s) of the given workunit job name.\n"
  1543. "\n"
  1544. "ecl getwuid -n <job name> [--limit=<limit>]\n"
  1545. "\n"
  1546. " job name workunit job name\n"
  1547. " Options:\n"
  1548. " --limit=<limit> Sets the result limit for the query, defaults to 100\n",
  1549. stdout);
  1550. EclCmdCommon::usage();
  1551. }
  1552. private:
  1553. StringAttr optName;
  1554. EclObjectParameter optObj;
  1555. unsigned int optListLimit;
  1556. };
  1557. class EclCmdStatus : public EclCmdCommon
  1558. {
  1559. public:
  1560. EclCmdStatus() : optListLimit(100)
  1561. {
  1562. optObj.accept = eclObjWuid;
  1563. }
  1564. virtual eclCmdOptionMatchIndicator parseCommandLineOptions(ArgvIterator &iter)
  1565. {
  1566. eclCmdOptionMatchIndicator retVal = EclCmdOptionNoMatch;
  1567. if (iter.done())
  1568. return EclCmdOptionNoMatch;
  1569. for (; !iter.done(); iter.next())
  1570. {
  1571. const char *arg = iter.query();
  1572. if (iter.matchOption(optName, ECLOPT_WUID)||iter.matchOption(optName, ECLOPT_WUID_S))
  1573. {
  1574. optObj.type = eclObjWuid;
  1575. retVal = EclCmdOptionMatch;
  1576. continue;
  1577. }
  1578. if (iter.matchOption(optName, ECLOPT_NAME)||iter.matchOption(optName, ECLOPT_NAME_S))
  1579. {
  1580. optObj.type = eclObjQuery;
  1581. retVal = EclCmdOptionMatch;
  1582. continue;
  1583. }
  1584. if (iter.matchOption(optListLimit, ECLOPT_RESULT_LIMIT))
  1585. {
  1586. continue;
  1587. }
  1588. eclCmdOptionMatchIndicator ind = EclCmdCommon::matchCommandLineOption(iter, true);
  1589. if (ind != EclCmdOptionMatch)
  1590. return ind;
  1591. }
  1592. return retVal;
  1593. }
  1594. virtual bool finalizeOptions(IProperties *globals)
  1595. {
  1596. if (!EclCmdCommon::finalizeOptions(globals))
  1597. return false;
  1598. return true;
  1599. }
  1600. virtual int processCMD()
  1601. {
  1602. Owned<IClientWsWorkunits> client = createCmdClient(WsWorkunits, *this);
  1603. Owned<IClientWUQueryRequest> req = client->createWUQueryRequest();
  1604. setCmdRequestTimeouts(req->rpc(), 0, optWaitConnectMs, optWaitReadSec);
  1605. if (optName.isEmpty())
  1606. {
  1607. fprintf(stdout, "No WUID or job name.\n");
  1608. return 0;
  1609. }
  1610. if ( optObj.type ==eclObjWuid )
  1611. req->setWuid(optName.get());
  1612. else
  1613. req->setJobname(optName.get());
  1614. Owned<IClientWUQueryResponse> resp = client->WUQuery(req);
  1615. int res = resp->queryClientStatus();
  1616. IArrayOf<IConstECLWorkunit>& wus = resp->getWorkunits();
  1617. if (wus.ordinality() == 1)
  1618. {
  1619. if (optVerbose)
  1620. {
  1621. fprintf(stdout, "ID: %-18s, job name: %s, state:", wus.item(0).getWuid(), wus.item(0).getJobname());
  1622. }
  1623. fprintf(stdout, "%s\n", getWorkunitStateStr((WUState) wus.item(0).getStateID()) );
  1624. }
  1625. else
  1626. {
  1627. ForEachItemIn(idx, wus)
  1628. {
  1629. if (idx == optListLimit)
  1630. break;
  1631. if (optVerbose)
  1632. fprintf(stdout, "ID: %s, job name: %s, state: %s\n", wus.item(idx).getWuid(), wus.item(idx).getJobname(), getWorkunitStateStr((WUState) wus.item(idx).getStateID()) );
  1633. else
  1634. fprintf(stdout, "%s,%s,%s\n", wus.item(idx).getWuid(), wus.item(idx).getJobname(), getWorkunitStateStr((WUState) wus.item(idx).getStateID()) );
  1635. }
  1636. }
  1637. return 0;
  1638. }
  1639. virtual void usage()
  1640. {
  1641. fputs("\nUsage:\n"
  1642. "\n"
  1643. "The 'status' command returns the status of the given workunit or job name.\n"
  1644. "If there are more than one result it generates a CSV list with wuid, name and state.\n"
  1645. "\n"
  1646. "ecl status -wu <WUID>|-n <job name> \n"
  1647. "\n"
  1648. " WUID workunit ID\n"
  1649. " name workunit job name\n"
  1650. " Options:\n"
  1651. " --limit=<limit> Sets the result limit for the query, defaults to 100\n"
  1652. " --verbose Add field names\n",
  1653. stdout);
  1654. EclCmdCommon::usage();
  1655. }
  1656. private:
  1657. StringAttr optName;
  1658. EclObjectParameter optObj;
  1659. unsigned int optListLimit;
  1660. };
  1661. class EclCmdZapGen : public EclCmdCommon
  1662. {
  1663. public:
  1664. EclCmdZapGen()
  1665. {
  1666. }
  1667. virtual eclCmdOptionMatchIndicator parseCommandLineOptions(ArgvIterator &iter)
  1668. {
  1669. eclCmdOptionMatchIndicator retVal = EclCmdOptionNoMatch;
  1670. if (iter.done())
  1671. return EclCmdOptionNoMatch;
  1672. for (; !iter.done(); iter.next())
  1673. {
  1674. const char *arg = iter.query();
  1675. if (*arg != '-') //parameters don't start with '-'
  1676. {
  1677. if (optWuid.length())
  1678. {
  1679. fprintf(stderr, "\nunrecognized argument %s\n", arg);
  1680. return EclCmdOptionCompletion;
  1681. }
  1682. if (!looksLikeAWuid(arg, 'W'))
  1683. {
  1684. fprintf(stderr, "\nargument should be a workunit id: %s\n", arg);
  1685. return EclCmdOptionCompletion;
  1686. }
  1687. optWuid.set(arg);
  1688. continue;
  1689. }
  1690. if (iter.matchOption(optPath, ECLOPT_PATH))
  1691. {
  1692. if ((optPath.length() > 0) && (*optPath.str() != '-'))
  1693. {
  1694. retVal = EclCmdOptionMatch;
  1695. continue;
  1696. }
  1697. else
  1698. {
  1699. fprintf(stderr, "\nPath should not be empty.\n");
  1700. return EclCmdOptionCompletion;
  1701. }
  1702. }
  1703. if (iter.matchFlag(optIncThorSlave, ECLOPT_INC_THOR_SLAVE_LOGS))
  1704. {
  1705. retVal = EclCmdOptionMatch;
  1706. continue;
  1707. }
  1708. if (iter.matchFlag(optCreateDirs,ECLOPT_CREATE_DIRS))
  1709. {
  1710. retVal = EclCmdOptionMatch;
  1711. continue;
  1712. }
  1713. if (iter.matchOption(optProblemDesc, ECLOPT_PROBLEM_DESC))
  1714. {
  1715. if ((optProblemDesc.length() > 0) && (*optProblemDesc.str() != '-'))
  1716. {
  1717. retVal = EclCmdOptionMatch;
  1718. continue;
  1719. }
  1720. else
  1721. {
  1722. fprintf(stderr, "\nDescription should not be empty.\n");
  1723. return EclCmdOptionCompletion;
  1724. }
  1725. }
  1726. eclCmdOptionMatchIndicator ind = EclCmdCommon::matchCommandLineOption(iter, true);
  1727. if (ind != EclCmdOptionMatch)
  1728. return ind;
  1729. }
  1730. return retVal;
  1731. }
  1732. virtual bool finalizeOptions(IProperties *globals)
  1733. {
  1734. if (!EclCmdCommon::finalizeOptions(globals))
  1735. return false;
  1736. if(optServer.isEmpty())
  1737. {
  1738. fprintf(stderr, "\nError: Server IP not specified\n");
  1739. return false;
  1740. }
  1741. if(optWuid.isEmpty())
  1742. {
  1743. fprintf(stderr, "\nError: WUID not specified\n");
  1744. return false;
  1745. }
  1746. return true;
  1747. }
  1748. virtual int processCMD()
  1749. {
  1750. //Create the file name for the output
  1751. StringBuffer outputFile;
  1752. if (!optPath.isEmpty())
  1753. {
  1754. outputFile.set(optPath.get());
  1755. const char *p = outputFile.str();
  1756. p = (p + strlen(p) - 1);
  1757. if (!streq(p, PATHSEPSTR))
  1758. outputFile.append(PATHSEPSTR);
  1759. }
  1760. else
  1761. outputFile.set(".").append(PATHSEPSTR);
  1762. outputFile.append("ZAPReport_").append(optWuid.get());
  1763. if (!optUsername.isEmpty())
  1764. outputFile.append('_').append(optUsername.get());
  1765. outputFile.append(".zip");
  1766. //Create command URL
  1767. StringBuffer urlTail("/WUCreateAndDownloadZAPInfo?Wuid=");
  1768. urlTail.append(optWuid.get());
  1769. if (optIncThorSlave)
  1770. urlTail.append("&IncludeThorSlaveLog=on");
  1771. if (!optProblemDesc.isEmpty())
  1772. urlTail.append("&ProblemDescription=").append(optProblemDesc.get());
  1773. EclCmdURL eclCmdURL("WsWorkunits", !streq(optServer, ".") ? optServer : "localhost", optPort, optSSL, urlTail.str());
  1774. //Create CURL command
  1775. StringBuffer curlCommand("curl -v -X post");
  1776. if (!optUsername.isEmpty())
  1777. {
  1778. curlCommand.append(" -u ").append(optUsername.get());
  1779. if (!optPassword.isEmpty())
  1780. curlCommand.append(":").append(optPassword.get());
  1781. }
  1782. if (optCreateDirs)
  1783. curlCommand.append(" --create-dirs");
  1784. curlCommand.appendf(" -o %s %s", outputFile.str(), eclCmdURL.str());
  1785. Owned<IPipeProcess> pipe = createPipeProcess();
  1786. if (!pipe->run(optVerbose ? "EXEC" : NULL, curlCommand.str(), NULL, false, true, true))
  1787. {
  1788. fprintf(stderr, "Failed to run zapgen command %s\n", curlCommand.str());
  1789. return false;
  1790. }
  1791. bool isOk = true;
  1792. bool removeOutFile = false;
  1793. if (pipe->hasError())
  1794. {
  1795. StringBuffer errMsg;
  1796. const unsigned errBuffSize = 64;
  1797. char err[errBuffSize];
  1798. size32_t len = 0;
  1799. while ((len = pipe->readError(errBuffSize, err)) > 0)
  1800. errMsg.append(err, 0, len);
  1801. if ((strstr(errMsg.str(), "Warning") != nullptr) || (strstr(errMsg.str(), "* Failed to connect to") != nullptr))
  1802. {
  1803. fprintf(stderr, "Zapgen command returns with error:\n%s\n", errMsg.str());
  1804. isOk = false;
  1805. removeOutFile = true; // It contains the authentication error message only
  1806. }
  1807. else if (strstr(errMsg.str(), "Authentication problem") != nullptr)
  1808. {
  1809. fprintf(stderr, "\nZapgen command returned with an authentication problem. Please check your credentials.\n");
  1810. isOk = false;
  1811. removeOutFile = true; // It contains the authentication error message only
  1812. }
  1813. else if (strstr(errMsg.str(), "401 Unauthorized") != nullptr)
  1814. {
  1815. fprintf(stderr, "Zapgen command needs to authenticate, please provide credentials.\n");
  1816. isOk = false;
  1817. removeOutFile = true; // It contains the authentication error message only
  1818. }
  1819. if (optVerbose)
  1820. fprintf(stderr, "Zapgen command returned with:\n%s\n", errMsg.str());
  1821. }
  1822. if (isOk)
  1823. {
  1824. fprintf(stdout, "ZAP file written to %s.\n", outputFile.str());
  1825. return 0;
  1826. }
  1827. else
  1828. {
  1829. Owned<IFile> file = createIFile(outputFile.str());
  1830. if (file->exists() && (removeOutFile || (0 == file->size())))
  1831. file->remove();
  1832. return 1;
  1833. }
  1834. }
  1835. virtual void usage()
  1836. {
  1837. fputs("\nUsage:\n"
  1838. "\n"
  1839. "Create and store ZAP file of the given workunit.\n"
  1840. "\n"
  1841. "ecl zapgen <WUID> --path <zap_file_path>\n"
  1842. "\n"
  1843. " WUID workunit ID\n"
  1844. " path path to store ZAP file\n"
  1845. " Options:\n"
  1846. " --inc-thor-slave-logs include Thor slave(s) log into the ZAP file\n"
  1847. " --description <text> problem description string\n"
  1848. " --create-dirs create necesary directory tree\n",
  1849. stdout);
  1850. EclCmdCommon::usage();
  1851. }
  1852. private:
  1853. StringAttr optWuid;
  1854. StringAttr optPath;
  1855. bool optIncThorSlave = false;
  1856. bool optCreateDirs = false;
  1857. StringAttr optProblemDesc;
  1858. };
  1859. //=========================================================================================
  1860. IEclCommand *createCoreEclCommand(const char *cmdname)
  1861. {
  1862. if (!cmdname || !*cmdname)
  1863. return NULL;
  1864. if (strieq(cmdname, "deploy"))
  1865. return new EclCmdDeploy();
  1866. if (strieq(cmdname, "publish"))
  1867. return new EclCmdPublish();
  1868. if (strieq(cmdname, "unpublish"))
  1869. return new EclCmdUnPublish();
  1870. if (strieq(cmdname, "run"))
  1871. return new EclCmdRun();
  1872. if (strieq(cmdname, "results"))
  1873. return new EclCmdResults();
  1874. if (strieq(cmdname, "activate"))
  1875. return new EclCmdActivate();
  1876. if (strieq(cmdname, "deactivate"))
  1877. return new EclCmdDeactivate();
  1878. if (strieq(cmdname, "abort"))
  1879. return new EclCmdAbort();
  1880. if (strieq(cmdname, "getname"))
  1881. return new EclCmdGetName();
  1882. if (strieq(cmdname, "getwuid"))
  1883. return new EclCmdGetWuid();
  1884. if (strieq(cmdname, "status"))
  1885. return new EclCmdStatus();
  1886. if (strieq(cmdname, "zapgen"))
  1887. return new EclCmdZapGen();
  1888. if (strieq(cmdname, "sign"))
  1889. return createSignEclCommand();
  1890. if (strieq(cmdname, "listkeyuid"))
  1891. return createListKeyUidCommand();
  1892. return NULL;
  1893. }