ws_dfuXRefService.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #pragma warning (disable : 4786)
  14. #include "ws_dfuXRefService.hpp"
  15. #include "dadfs.hpp"
  16. #include "daft.hpp"
  17. #include "dautils.hpp"
  18. #include "wshelpers.hpp"
  19. #include "exception_util.hpp"
  20. #include "package.h"
  21. #include "roxiecontrol.hpp"
  22. static const char* FEATURE_URL = "DfuXrefAccess";
  23. static void appendReplyMessage(bool json, StringBuffer &reply, const char *href,const char *format,...) __attribute__((format(printf, 4, 5)));
  24. static void appendReplyMessage(bool json, StringBuffer &reply, const char *href,const char *format,...)
  25. {
  26. va_list args;
  27. va_start(args, format);
  28. StringBuffer msg;
  29. msg.valist_appendf(format, args);
  30. va_end(args);
  31. StringBuffer fmsg;
  32. const char *s=msg.str();
  33. for (;;) {
  34. char c=*(s++);
  35. if (!c||(c=='\n')) {
  36. Owned<IPropertyTree> tree = createPTree("Message");
  37. tree->addProp("Value",fmsg.str());
  38. if (href) {
  39. tree->addProp("href",href);
  40. href = NULL;
  41. }
  42. if (json)
  43. toJSON(tree,reply);
  44. else
  45. toXML(tree,reply);
  46. if (!c)
  47. break;
  48. fmsg.clear();
  49. }
  50. else
  51. fmsg.append(c);
  52. }
  53. }
  54. static void dfuXrefXMLToJSON(StringBuffer& buf)
  55. {
  56. try
  57. {
  58. Owned<IPropertyTree> result = createPTreeFromXMLString(buf.str());
  59. if (result)
  60. toJSON(result, buf.clear());
  61. else
  62. PROGLOG("dfuXrefXMLToJSON() failed in creating PTree.");
  63. }
  64. catch (IException *e)
  65. {
  66. EXCLOG(e,"dfuXrefXMLToJSON() failed");
  67. e->Release();
  68. }
  69. }
  70. const char* CWsDfuXRefEx::formatResult(IEspContext& context, StringBuffer& result, StringBuffer& encodedResult)
  71. {
  72. if (context.getResponseFormat() == ESPSerializationJSON)
  73. {
  74. dfuXrefXMLToJSON(result);
  75. return result;
  76. }
  77. if (context.getClientVersion() < 1.02)
  78. return result;
  79. return encodeXML(result, encodedResult);
  80. }
  81. const char* CWsDfuXRefEx::formatResult(IEspContext& context, IPropertyTree* result, StringBuffer& formatedResult)
  82. {
  83. if (context.getResponseFormat() == ESPSerializationJSON)
  84. return toJSON(result, formatedResult);
  85. if (context.getClientVersion() < 1.02)
  86. return toXML(result, formatedResult);
  87. StringBuffer tmp;
  88. toXML(result, tmp);
  89. return encodeXML(tmp, formatedResult);
  90. }
  91. void CWsDfuXRefEx::init(IPropertyTree *cfg, const char *process, const char *service)
  92. {
  93. DBGLOG("Initializing %s service [process = %s]", service, process);
  94. if (!daliClientActive())
  95. {
  96. OERRLOG("No Dali Connection Active.");
  97. throw MakeStringException(-1, "No Dali Connection Active. Please Specify a Dali to connect to in you configuration file");
  98. }
  99. XRefNodeManager.setown(CreateXRefNodeFactory());
  100. //Start out builder thread......
  101. m_XRefbuilder.setown(new CXRefExBuilderThread());
  102. m_XRefbuilder->start();
  103. }
  104. bool CWsDfuXRefEx::onDFUXRefArrayAction(IEspContext &context, IEspDFUXRefArrayActionRequest &req, IEspDFUXRefArrayActionResponse &resp)
  105. {
  106. try
  107. {
  108. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Full, ECLWATCH_DFU_XREF_ACCESS_DENIED, "WsDfuXRef::DFUXRefArrayAction: Permission denied.");
  109. const char *action = req.getAction();
  110. const char *type = req.getType();
  111. if (isEmptyString(action) || isEmptyString(type))
  112. throw MakeStringExceptionDirect(ECLWATCH_INVALID_INPUT, "Action or Type not defined.");
  113. if (!streq("Attach", action) && !streq("Delete", action) && !streq("DeleteLogical", action))
  114. throw MakeStringExceptionDirect(ECLWATCH_INVALID_INPUT, "Invalid DFUXRefArrayAction: only Attach, Delete or DeleteLogical allowed.");
  115. StringArray &xrefFiles = req.getXRefFiles();
  116. if (xrefFiles.ordinality() == 0)
  117. throw MakeStringExceptionDirect(ECLWATCH_INVALID_INPUT, "XRefFile not defined.");
  118. const char *cluster = req.getCluster();
  119. Owned<IXRefNode> xRefNode = getXRefNodeByCluster(cluster);
  120. Owned<IXRefFilesNode> fileNode = getFileNodeInterface(*xRefNode, type);
  121. if (!fileNode)
  122. {
  123. IERRLOG("Unable to find a suitable IXRefFilesNode interface for %s", type);
  124. throw MakeStringException(ECLWATCH_CANNOT_FIND_IXREFFILESNODE, "Unable to find a suitable IXRefFilesNode interface for %s", type);
  125. }
  126. StringBuffer returnStr;
  127. ESPSerializationFormat fmt = context.getResponseFormat();
  128. Owned<IUserDescriptor> userDesc = getUserDescriptor(context);
  129. ForEachItemIn(i, xrefFiles)
  130. {
  131. StringBuffer err;
  132. const char *file = xrefFiles.item(i);
  133. if (streq("Attach", action))
  134. {
  135. if(fileNode->AttachPhysical(file, userDesc, cluster, err))
  136. appendReplyMessage(fmt==ESPSerializationJSON, returnStr, nullptr,
  137. "Reattached Physical part %s", file);
  138. else
  139. appendReplyMessage(fmt==ESPSerializationJSON, returnStr, nullptr,
  140. "Error(s) attaching physical part %s\n%s", file, err.str());
  141. }
  142. else if (streq("Delete", action))
  143. {
  144. if (fileNode->RemovePhysical(file, userDesc, cluster, err))
  145. appendReplyMessage(fmt==ESPSerializationJSON, returnStr, nullptr,
  146. "Removed Physical part %s", file);
  147. else
  148. appendReplyMessage(fmt==ESPSerializationJSON, returnStr, nullptr,
  149. "Error(s) removing physical part %s\n%s", file, err.str());
  150. }
  151. else
  152. { // DeleteLogical:
  153. // Note we don't want to physically delete 'lost' files - this will end up with orphans on next time round but that is safer
  154. if (fileNode->RemoveLogical(file, userDesc, cluster, err))
  155. appendReplyMessage(fmt==ESPSerializationJSON, returnStr, nullptr,
  156. "Removed Logical File %s", file);
  157. else
  158. appendReplyMessage(fmt==ESPSerializationJSON, returnStr, nullptr,
  159. "Error(s) removing File %s\n%s", file, err.str());
  160. }
  161. }
  162. xRefNode->commit();
  163. if ((fmt == ESPSerializationJSON) || (context.getClientVersion() < 1.02))
  164. resp.setDFUXRefArrayActionResult(returnStr);
  165. else
  166. {
  167. StringBuffer encodedReturnStr;
  168. resp.setDFUXRefArrayActionResult(encodeXML(returnStr, encodedReturnStr));
  169. }
  170. }
  171. catch(IException *e)
  172. {
  173. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  174. }
  175. return true;
  176. }
  177. IXRefFilesNode *CWsDfuXRefEx::getFileNodeInterface(IXRefNode &XRefNode, const char *nodeType)
  178. {
  179. if (strieq("Found", nodeType))
  180. return XRefNode.getFoundFiles();
  181. else if (strieq("Lost", nodeType))
  182. return XRefNode.getLostFiles();
  183. else if (strieq("Orphan", nodeType))
  184. return XRefNode.getOrphanFiles();
  185. OWARNLOG("Unrecognized file node type %s", nodeType);
  186. return nullptr;
  187. }
  188. void CWsDfuXRefEx::readLostFileQueryResult(IEspContext &context, StringBuffer &buf)
  189. {
  190. Owned<IPropertyTree> lostFilesQueryResult = createPTreeFromXMLString(buf);
  191. if (!lostFilesQueryResult)
  192. throw MakeStringException(ECLWATCH_CANNOT_FIND_IXREFFILESNODE, "readLostFileQueryResult() failed in creating PTree.");
  193. Owned<IUserDescriptor> userDesc = getUserDescriptor(context);
  194. Owned<IPropertyTreeIterator> iter = lostFilesQueryResult->getElements("File");
  195. ForEach(*iter)
  196. {
  197. IPropertyTree &item = iter->query();
  198. const char *fileName = item.queryProp("Name");
  199. if (isEmptyString(fileName))
  200. continue;
  201. try
  202. {
  203. Owned<IDistributedFile> df = queryDistributedFileDirectory().lookup(fileName, userDesc, AccessMode::tbdRead, false, false, NULL, defaultPrivilegedUser, 0);
  204. if (df)
  205. item.addPropInt64("Size", df->getFileSize(true, false));
  206. }
  207. catch(IException *e)
  208. {
  209. item.addProp("Status", "Warning: this file may be locked now. It can't be recovered as locked.");
  210. StringBuffer eMsg;
  211. IERRLOG("Exception in readLostFileQueryResult(): %s", e->errorMessage(eMsg).str());
  212. e->Release();
  213. }
  214. }
  215. formatResult(context, lostFilesQueryResult, buf.clear());
  216. }
  217. bool CWsDfuXRefEx::onDFUXRefLostFiles(IEspContext &context, IEspDFUXRefLostFilesQueryRequest &req, IEspDFUXRefLostFilesQueryResponse &resp)
  218. {
  219. try
  220. {
  221. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Read, ECLWATCH_DFU_XREF_ACCESS_DENIED, "WsDfuXRef::DFUXRefLostFiles: Permission denied.");
  222. Owned<IXRefNode> xRefNode = getXRefNodeByCluster(req.getCluster());
  223. Owned<IXRefFilesNode> lostFiles = xRefNode->getLostFiles();
  224. if (!lostFiles)
  225. return true;
  226. StringBuffer buf;
  227. lostFiles->Serialize(buf);
  228. if (buf.isEmpty())
  229. return true;
  230. readLostFileQueryResult(context, buf);
  231. resp.setDFUXRefLostFilesQueryResult(buf);
  232. }
  233. catch(IException *e)
  234. {
  235. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  236. }
  237. return true;
  238. }
  239. bool CWsDfuXRefEx::onDFUXRefFoundFiles(IEspContext &context, IEspDFUXRefFoundFilesQueryRequest &req, IEspDFUXRefFoundFilesQueryResponse &resp)
  240. {
  241. try
  242. {
  243. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Read, ECLWATCH_DFU_XREF_ACCESS_DENIED, "WsDfuXRef::DFUXRefFoundFiles: Permission denied.");
  244. Owned<IXRefNode> xRefNode = getXRefNodeByCluster(req.getCluster());
  245. Owned<IXRefFilesNode> foundFiles = xRefNode->getFoundFiles();
  246. if (!foundFiles)
  247. return true;
  248. StringBuffer buf;
  249. foundFiles->Serialize(buf);
  250. if (buf.isEmpty())
  251. return true;
  252. StringBuffer encodedXML;
  253. resp.setDFUXRefFoundFilesQueryResult(formatResult(context, buf, encodedXML));
  254. }
  255. catch(IException *e)
  256. {
  257. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  258. }
  259. return true;
  260. }
  261. bool CWsDfuXRefEx::onDFUXRefOrphanFiles(IEspContext &context, IEspDFUXRefOrphanFilesQueryRequest &req, IEspDFUXRefOrphanFilesQueryResponse &resp)
  262. {
  263. try
  264. {
  265. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Read, ECLWATCH_DFU_XREF_ACCESS_DENIED, "WsDfuXRef::DFUXRefOrphanFiles: Permission denied.");
  266. Owned<IXRefNode> xRefNode = getXRefNodeByCluster(req.getCluster());
  267. Owned<IXRefFilesNode> orphanFiles = xRefNode->getOrphanFiles();
  268. if (!orphanFiles)
  269. return true;
  270. StringBuffer buf;
  271. orphanFiles->Serialize(buf);
  272. if (buf.isEmpty())
  273. return true;
  274. StringBuffer encodedXML;
  275. resp.setDFUXRefOrphanFilesQueryResult(formatResult(context, buf, encodedXML));
  276. }
  277. catch(IException *e)
  278. {
  279. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  280. }
  281. return true;
  282. }
  283. bool CWsDfuXRefEx::onDFUXRefMessages(IEspContext &context, IEspDFUXRefMessagesQueryRequest &req, IEspDFUXRefMessagesQueryResponse &resp)
  284. {
  285. try
  286. {
  287. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Read, ECLWATCH_DFU_XREF_ACCESS_DENIED, "WsDfuXRef::DFUXRefMessages: Permission denied.");
  288. StringBuffer buf;
  289. Owned<IXRefNode> xRefNode = getXRefNodeByCluster(req.getCluster());
  290. xRefNode->serializeMessages(buf);
  291. if (buf.isEmpty())
  292. return true;
  293. StringBuffer encodedXML;
  294. resp.setDFUXRefMessagesQueryResult(formatResult(context, buf, encodedXML));
  295. }
  296. catch(IException *e)
  297. {
  298. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  299. }
  300. return true;
  301. }
  302. bool CWsDfuXRefEx::onDFUXRefCleanDirectories(IEspContext &context, IEspDFUXRefCleanDirectoriesRequest &req, IEspDFUXRefCleanDirectoriesResponse &resp)
  303. {
  304. try
  305. {
  306. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Write, ECLWATCH_DFU_XREF_ACCESS_DENIED, "WsDfuXRef::DFUXRefCleanDirectories: Permission denied.");
  307. StringBuffer err;
  308. Owned<IXRefNode> xRefNode = getXRefNodeByCluster(req.getCluster());
  309. xRefNode->removeEmptyDirectories(err);
  310. if (!err.isEmpty())
  311. throw MakeStringException(ECLWATCH_INTERNAL_ERROR, "Failed in DFUXRefCleanDirectories: %s", err.str());
  312. resp.setRedirectUrl(StringBuffer("/WsDFUXRef/DFUXRefDirectories?Cluster=").append(req.getCluster()));
  313. }
  314. catch(IException *e)
  315. {
  316. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  317. }
  318. return true;
  319. }
  320. bool CWsDfuXRefEx::onDFUXRefDirectories(IEspContext &context, IEspDFUXRefDirectoriesQueryRequest &req, IEspDFUXRefDirectoriesQueryResponse &resp)
  321. {
  322. try
  323. {
  324. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Read, ECLWATCH_DFU_XREF_ACCESS_DENIED, "WsDfuXRef::DFUXRefDirectories: Permission denied.");
  325. StringBuffer buf;
  326. Owned<IXRefNode> xRefNode = getXRefNodeByCluster(req.getCluster());
  327. xRefNode->serializeDirectories(buf);
  328. if (buf.isEmpty())
  329. return true;
  330. Owned<IPropertyTree> dirs = createPTreeFromXMLString(buf);
  331. if (!dirs)
  332. throw MakeStringException(ECLWATCH_INVALID_COMPONENT_INFO,
  333. "Failed in creating PTree for XRefNode Directories: %s.", req.getCluster());
  334. Owned<IPropertyTreeIterator> iter = dirs->getElements("Directory");
  335. ForEach(*iter)
  336. updateSkew(iter->query());
  337. resp.setDFUXRefDirectoriesQueryResult(formatResult(context, dirs, buf.clear()));
  338. }
  339. catch(IException *e)
  340. {
  341. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  342. }
  343. return true;
  344. }
  345. void CWsDfuXRefEx::updateSkew(IPropertyTree &node)
  346. {
  347. char *skew = (char*) node.queryProp("Skew");
  348. if (isEmptyString(skew))
  349. return;
  350. StringBuffer positive, negative;
  351. char *skewPtr = strchr(skew, '/');
  352. if (skewPtr)
  353. {
  354. if (skew[0] == '+' && (strlen(skew) > 1))
  355. positive.append(skewPtr - skew - 1, skew+1);
  356. else
  357. positive.append(skewPtr - skew, skew);
  358. skewPtr++;
  359. if (skewPtr)
  360. {
  361. if (skewPtr[0] == '-')
  362. negative.append(skewPtr+1);
  363. else
  364. negative.append(skewPtr);
  365. }
  366. }
  367. else
  368. {
  369. if (skew[0] == '+' && (strlen(skew) > 1))
  370. positive.append(skew+1);
  371. else
  372. positive.append(skew);
  373. }
  374. node.removeProp("Skew");
  375. node.addProp("PositiveSkew", positive);
  376. node.addProp("NegativeSkew", negative);
  377. }
  378. bool CWsDfuXRefEx::onDFUXRefBuild(IEspContext &context, IEspDFUXRefBuildRequest &req, IEspDFUXRefBuildResponse &resp)
  379. {
  380. try
  381. {
  382. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Full, ECLWATCH_DFU_XREF_ACCESS_DENIED, "WsDfuXRef::DFUXRefBuild: Permission denied.");
  383. const char *cluster = req.getCluster();
  384. if (isEmptyString(cluster))
  385. throw MakeStringExceptionDirect(ECLWATCH_INVALID_INPUT, "Cluster not defined.");
  386. StringBuffer returnStr;
  387. ESPSerializationFormat fmt = context.getResponseFormat();
  388. if (m_XRefbuilder->isQueued(cluster))
  389. { //The XRef build request for this cluster has been queued. No need to queue again.
  390. appendReplyMessage(fmt == ESPSerializationJSON, returnStr, "/WsDFUXRef/DFUXRefList",
  391. "An XRef build for cluster %s is in process. Click here to return to the main XRef List.", cluster);
  392. }
  393. else
  394. {
  395. //create the node if it doesn;t exist
  396. Owned<IXRefNode> xRefNode = XRefNodeManager->getXRefNode(cluster);
  397. if (!xRefNode)
  398. xRefNode.setown(XRefNodeManager->CreateXRefNode(cluster));
  399. if (!xRefNode)
  400. throw MakeStringException(ECLWATCH_CANNOT_FIND_IXREFFILESNODE, "XRefNode not created for %s.", cluster);
  401. if (!m_XRefbuilder->isRunning())
  402. appendReplyMessage(fmt == ESPSerializationJSON, returnStr, "/WsDFUXRef/DFUXRefList",
  403. "Running XRef Process. Click here to return to the main XRef List.");
  404. else
  405. appendReplyMessage(fmt == ESPSerializationJSON, returnStr, "/WsDFUXRef/DFUXRefList",
  406. "Someone is currently running a Xref build. Your request will be added to the queue. Please click here to return to the main page.");
  407. m_XRefbuilder->queueRequest(xRefNode, cluster);
  408. }
  409. if ((fmt == ESPSerializationJSON) || (context.getClientVersion() < 1.02))
  410. resp.setDFUXRefActionResult(returnStr);
  411. else
  412. {
  413. StringBuffer encodedReturnStr;
  414. resp.setDFUXRefActionResult(encodeXML(returnStr, encodedReturnStr));
  415. }
  416. }
  417. catch(IException *e)
  418. {
  419. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  420. }
  421. return true;
  422. }
  423. bool CWsDfuXRefEx::onDFUXRefBuildCancel(IEspContext &context, IEspDFUXRefBuildCancelRequest &req, IEspDFUXRefBuildCancelResponse &resp)
  424. {
  425. try
  426. {
  427. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Full, ECLWATCH_DFU_XREF_ACCESS_DENIED, "WsDfuXRef::DFUXRefBuildCancel: Permission denied.");
  428. m_XRefbuilder->cancel();
  429. StringBuffer returnStr;
  430. if (context.getResponseFormat() == ESPSerializationJSON)
  431. {
  432. returnStr.append("{ \"Message\": { \"Value\": ");
  433. returnStr.append("\"All Queued items have been cleared. The current running job will continue to execute.\",");
  434. returnStr.append("\"href\": \"/WsDFUXRef/DFUXRefList\" } }");
  435. resp.setDFUXRefBuildCancelResult(returnStr);
  436. return true;
  437. }
  438. returnStr.append("<Message><Value>All Queued items have been cleared. The current running job will continue to execute.</Value><href>/WsDFUXRef/DFUXRefList</href></Message>");
  439. if (context.getClientVersion() < 1.02)
  440. resp.setDFUXRefBuildCancelResult(returnStr);
  441. else
  442. {
  443. StringBuffer encodedReturnStr;
  444. resp.setDFUXRefBuildCancelResult(encodeXML(returnStr, encodedReturnStr));
  445. }
  446. }
  447. catch(IException *e)
  448. {
  449. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  450. }
  451. return true;
  452. }
  453. void CWsDfuXRefEx::addXRefNode(const char* name, IPropertyTree* pXRefNodeTree)
  454. {
  455. IPropertyTree* XRefTreeNode = pXRefNodeTree->addPropTree("XRefNode", createPTree(ipt_caseInsensitive));
  456. XRefTreeNode->setProp("Name",name);
  457. Owned<IXRefNode> xRefNode = XRefNodeManager->getXRefNode(name);
  458. if (!xRefNode)
  459. {
  460. XRefTreeNode->setProp("Modified","");
  461. XRefTreeNode->setProp("Status","Not Run");
  462. }
  463. else
  464. {
  465. StringBuffer modified, status;
  466. XRefTreeNode->setProp("Modified",xRefNode->getLastModified(modified).str());
  467. XRefTreeNode->setProp("Status",xRefNode->getStatus(status).str());
  468. }
  469. }
  470. bool CWsDfuXRefEx::addUniqueXRefNode(const char *processName, BoolHash &uniqueProcesses, IPropertyTree *xrefNodeTree)
  471. {
  472. if (isEmptyString(processName))
  473. return false;
  474. bool *found = uniqueProcesses.getValue(processName);
  475. if (found && *found)
  476. return false;
  477. uniqueProcesses.setValue(processName, true);
  478. addXRefNode(processName, xrefNodeTree);
  479. return true;
  480. }
  481. bool CWsDfuXRefEx::onDFUXRefList(IEspContext &context, IEspDFUXRefListRequest &req, IEspDFUXRefListResponse &resp)
  482. {
  483. try
  484. {
  485. #ifdef _CONTAINERIZED
  486. IERRLOG("CONTAINERIZED(CWsDfuXRefEx::onDFUXRefList)");
  487. #else
  488. context.ensureFeatureAccess(FEATURE_URL, SecAccess_Read, ECLWATCH_DFU_XREF_ACCESS_DENIED, "WsDfuXRef::DFUXRefList: Permission denied.");
  489. CConstWUClusterInfoArray clusters;
  490. getEnvironmentClusterInfo(clusters);
  491. BoolHash uniqueProcesses;
  492. Owned<IPropertyTree> xrefNodeTree = createPTree("XRefNodes");
  493. ForEachItemIn(c, clusters)
  494. {
  495. IConstWUClusterInfo &cluster = clusters.item(c);
  496. switch (cluster.getPlatform())
  497. {
  498. case ThorLCRCluster:
  499. {
  500. const StringArray &primaryThorProcesses = cluster.getPrimaryThorProcesses();
  501. ForEachItemIn(i, primaryThorProcesses)
  502. addUniqueXRefNode(primaryThorProcesses.item(i), uniqueProcesses, xrefNodeTree);
  503. }
  504. break;
  505. case RoxieCluster:
  506. SCMStringBuffer roxieProcess;
  507. addUniqueXRefNode(cluster.getRoxieProcess(roxieProcess).str(), uniqueProcesses, xrefNodeTree);
  508. break;
  509. }
  510. }
  511. addXRefNode("SuperFiles", xrefNodeTree);
  512. StringBuffer buf;
  513. resp.setDFUXRefListResult(formatResult(context, xrefNodeTree, buf));
  514. #endif
  515. }
  516. catch(IException *e)
  517. {
  518. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  519. }
  520. return true;
  521. }
  522. inline void addLfnToUsedFileMap(MapStringTo<bool> &usedFileMap, const char *fileName)
  523. {
  524. //Normalize file name, including remove the leading tilda.
  525. CDfsLogicalFileName lfn;
  526. lfn.set(fileName);
  527. if (lfn.get())
  528. usedFileMap.setValue(lfn.get(), true);
  529. }
  530. void addUsedFilesFromPackageMaps(MapStringTo<bool> &usedFileMap, const char *process)
  531. {
  532. Owned<IPropertyTree> packageSet = resolvePackageSetRegistry(process, true);
  533. if (!packageSet)
  534. throw MakeStringException(ECLWATCH_PACKAGEMAP_NOTRESOLVED, "Unable to retrieve package information from dali /PackageMaps");
  535. StringArray pmids;
  536. #ifdef _CONTAINERIZED
  537. Owned<IStringIterator> targets = getContainerTargetClusters("roxie", process);
  538. #else
  539. Owned<IStringIterator> targets = getTargetClusters("RoxieCluster", process);
  540. #endif
  541. ForEach(*targets)
  542. {
  543. SCMStringBuffer target;
  544. VStringBuffer xpath("PackageMap[@querySet='%s']", targets->str(target).str());
  545. Owned<IPropertyTreeIterator> activeMaps = packageSet->getElements(xpath);
  546. //Add files referenced in all active maps, for all targets configured for this process cluster
  547. ForEach(*activeMaps)
  548. {
  549. const char *pmid = activeMaps->query().queryProp("@id");
  550. if (!pmids.appendUniq(pmid))
  551. continue;
  552. Owned<IPropertyTree> packageMap = getPackageMapById(pmid, true);
  553. if (packageMap)
  554. {
  555. Owned<IPropertyTreeIterator> subFiles = packageMap->getElements("//SubFile");
  556. ForEach(*subFiles)
  557. addLfnToUsedFileMap(usedFileMap, subFiles->query().queryProp("@value"));
  558. }
  559. }
  560. }
  561. }
  562. void findUnusedFilesInDFS(StringArray &unusedFiles, const char *process, const MapStringTo<bool> &usedFileMap)
  563. {
  564. Owned<IRemoteConnection> globalLock = querySDS().connect("/Files/", myProcessSession(), RTM_LOCK_READ, SDS_LOCK_TIMEOUT);
  565. Owned<IPropertyTree> root = globalLock->getRoot();
  566. VStringBuffer xpath("//File[Cluster/@name='%s']/OrigName", process);
  567. Owned<IPropertyTreeIterator> files = root->getElements(xpath);
  568. ForEach(*files)
  569. {
  570. CDfsLogicalFileName lfn;
  571. lfn.set(files->query().queryProp(nullptr));
  572. if (lfn.get() && !usedFileMap.getValue(lfn.get()))
  573. unusedFiles.append(lfn.get());
  574. }
  575. }
  576. IDFAttributesIterator *CWsDfuXRefEx::getAllLogicalFilesInCluster(IEspContext &context, const char *cluster, bool &allMatchingFilesReceived)
  577. {
  578. StringBuffer filterBuf;
  579. //The filterBuf is sent to dali to retrieve the logical files whose @group attribute contains this cluster.
  580. WsDFUHelpers::appendDFUQueryFilter(getDFUQFilterFieldName(DFUQFFgroup), DFUQFTcontainString, cluster, ",", filterBuf);
  581. DFUQResultField localFilters[2];
  582. MemoryBuffer localFilterBuf;
  583. unsigned short localFilterCount = 0;
  584. //If a logical file is for >1 clusters, the localFilterBuf is used to pick up the logical file which is for this cluster.
  585. WsDFUHelpers::addDFUQueryFilter(localFilters, localFilterCount, localFilterBuf, cluster, DFUQRFnodegroup);
  586. localFilters[localFilterCount] = DFUQRFterm;
  587. DFUQResultField sortOrder[2] = {DFUQRFname, DFUQRFterm};
  588. __int64 cacheHint = 0; //No paging is needed.
  589. unsigned totalFiles = 0, pageStart = 0, pageSize = ITERATE_FILTEREDFILES_LIMIT;
  590. Owned<IUserDescriptor> userDesc = getUserDescriptor(context);
  591. PROGLOG("getLogicalFilesSorted() called");
  592. Owned<IDFAttributesIterator> it = queryDistributedFileDirectory().getLogicalFilesSorted(userDesc, sortOrder, filterBuf,
  593. localFilters, localFilterBuf.bufferBase(), pageStart, pageSize, &cacheHint, &totalFiles, &allMatchingFilesReceived);
  594. PROGLOG("getLogicalFilesSorted() done");
  595. return it.getClear();
  596. }
  597. void CWsDfuXRefEx::findUnusedFilesWithDetailsInDFS(IEspContext &context, const char *process, const MapStringTo<bool> &usedFileMap, IArrayOf<IEspDFULogicalFile> &unusedFiles)
  598. {
  599. //Collect information about logical files in dali for the given cluster.
  600. bool allMatchingFilesReceived = true;
  601. Owned<IDFAttributesIterator> it = getAllLogicalFilesInCluster(context, process, allMatchingFilesReceived);
  602. if (!it)
  603. throw MakeStringException(ECLWATCH_CANNOT_GET_FILE_ITERATOR, "Failed to retrieve logical files for %s.", process);
  604. if (!allMatchingFilesReceived)
  605. throw MakeStringException(ECLWATCH_INVALID_INPUT, "WsDfu::DFURoxieUnusedFiles not supported for %s: too many files.", process);
  606. //Find out unused Roxie logical files
  607. double version = context.getClientVersion();
  608. ForEach(*it)
  609. {
  610. IPropertyTree &file = it->query();
  611. const char *fileName = file.queryProp(getDFUQResultFieldName(DFUQRFname));
  612. if (!isEmptyString(fileName) && !usedFileMap.getValue(fileName))
  613. WsDFUHelpers::addToLogicalFileList(file, nullptr, version, unusedFiles);
  614. }
  615. }
  616. bool CWsDfuXRefEx::onDFUXRefUnusedFiles(IEspContext &context, IEspDFUXRefUnusedFilesRequest &req, IEspDFUXRefUnusedFilesResponse &resp)
  617. {
  618. #ifdef _CONTAINERIZED
  619. UNIMPLEMENTED_X("CONTAINERIZED(CWsDfuXRefEx::onDFUXRefUnusedFiles)");
  620. #else
  621. const char *process = req.getProcessCluster();
  622. if (isEmptyString(process))
  623. throw MakeStringExceptionDirect(ECLWATCH_INVALID_INPUT, "process cluster not specified.");
  624. SocketEndpointArray servers;
  625. getRoxieProcessServers(process, servers);
  626. if (!servers.length())
  627. throw MakeStringExceptionDirect(ECLWATCH_INVALID_CLUSTER_INFO, "process cluster, not found.");
  628. Owned<ISocket> sock = ISocket::connect_timeout(servers.item(0), ROXIECONNECTIONTIMEOUT);
  629. Owned<IPropertyTree> controlXrefInfo = sendRoxieControlQuery(sock, "<control:getQueryXrefInfo/>", ROXIECONTROLXREFTIMEOUT);
  630. if (!controlXrefInfo)
  631. throw MakeStringExceptionDirect(ECLWATCH_INTERNAL_ERROR, "roxie cluster, not responding.");
  632. MapStringTo<bool> usedFileMap;
  633. Owned<IPropertyTreeIterator> roxieFiles = controlXrefInfo->getElements("//File");
  634. ForEach(*roxieFiles)
  635. addLfnToUsedFileMap(usedFileMap, roxieFiles->query().queryProp("@name"));
  636. if (req.getCheckPackageMaps())
  637. addUsedFilesFromPackageMaps(usedFileMap, process);
  638. if (!req.getGetFileDetails())
  639. {
  640. StringArray unusedFiles;
  641. findUnusedFilesInDFS(unusedFiles, process, usedFileMap);
  642. resp.setUnusedFileCount(unusedFiles.length());
  643. resp.setUnusedFiles(unusedFiles);
  644. }
  645. else
  646. {
  647. IArrayOf<IEspDFULogicalFile> unusedLFs;
  648. findUnusedFilesWithDetailsInDFS(context, process, usedFileMap, unusedLFs);
  649. resp.setUnusedFileCount(unusedLFs.length());
  650. resp.setUnusedFilesWithDetails(unusedLFs);
  651. }
  652. return true;
  653. #endif
  654. }
  655. IXRefNode *CWsDfuXRefEx::getXRefNodeByCluster(const char* cluster)
  656. {
  657. if (isEmptyString(cluster))
  658. throw MakeStringExceptionDirect(ECLWATCH_INVALID_INPUT, "Cluster not defined.");
  659. Owned<IXRefNode> xRefNode = XRefNodeManager->getXRefNode(cluster);
  660. if (!xRefNode)
  661. throw MakeStringException(ECLWATCH_CANNOT_FIND_IXREFFILESNODE, "XRefNode not found for %s.", cluster);
  662. return xRefNode.getClear();
  663. }
  664. IUserDescriptor *CWsDfuXRefEx::getUserDescriptor(IEspContext &context)
  665. {
  666. StringBuffer userName;
  667. context.getUserID(userName);
  668. if (userName.isEmpty())
  669. return nullptr;
  670. Owned<IUserDescriptor> userDesc = createUserDescriptor();
  671. userDesc->set(userName, context.queryPassword(), context.querySignature());
  672. return userDesc.getClear();
  673. }