ws_dfuXRefService.cpp 27 KB

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