configenvhelper.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095
  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 "jliball.hpp"
  14. #include "environment.hpp"
  15. #include "XMLTags.h"
  16. #include "configenvhelper.hpp"
  17. #include "deployutils.hpp"
  18. #include "build-config.h"
  19. #include "confighelper.hpp"
  20. bool CConfigEnvHelper::handleRoxieOperation(const char* cmd, const char* xmlStr)
  21. {
  22. bool retVal = false;
  23. if (!strcmp(cmd, "AddRoxieFarm"))
  24. retVal = this->addRoxieServers(xmlStr);
  25. else if (!strcmp(cmd, "DeleteRoxieFarm"))
  26. retVal = this->deleteRoxiePorts(xmlStr);
  27. else if (!strcmp(cmd, "DeleteRoxieServers"))
  28. retVal = this->deleteRoxieServers(xmlStr);
  29. else if (!strcmp(cmd, "RoxieSlaveConfig"))
  30. retVal = this->handleRoxieSlaveConfig(xmlStr);
  31. else if (!strcmp(cmd, "ReplaceRoxieServer"))
  32. retVal = this->handleReplaceRoxieServer(xmlStr);
  33. return retVal;
  34. }
  35. bool CConfigEnvHelper::handleThorTopologyOp(const char* cmd, const char* xmlArg, StringBuffer& sMsg)
  36. {
  37. bool retVal = false;
  38. StringBuffer xpath;
  39. Owned<IPropertyTree> pParams = createPTreeFromXMLString(xmlArg && *xmlArg ? xmlArg : "<ThorData/>");
  40. const char* thorName = pParams->queryProp(XML_ATTR_NAME);
  41. const char* newType = pParams->queryProp(XML_ATTR_TYPE);
  42. const char* validate = pParams->queryProp("@validateComputers");
  43. const char* skip = pParams->queryProp("@skipExisting");
  44. const char* slavesPerNode = pParams->queryProp("@slavesPerNode");
  45. const char* channelsPerSlave = pParams->queryProp("@channelsPerSlave");
  46. bool checkComps = validate && !strcmp(validate, "true");
  47. bool skipExisting = skip && !strcmp(skip, "true");
  48. IPropertyTree* pThor = getSoftwareNode(XML_TAG_THORCLUSTER, thorName);
  49. StringBuffer usageList;
  50. if (!strcmp(cmd, "Add"))
  51. {
  52. Owned<IPropertyTreeIterator> iterComputers = pParams->getElements("Computer");
  53. IPropertyTreePtrArray computers;
  54. ForEach (*iterComputers)
  55. {
  56. IPropertyTree* pComp = &iterComputers->query();
  57. const char* pszCompName = pComp->queryProp(XML_ATTR_NAME);
  58. xpath.clear().appendf(XML_TAG_HARDWARE "/" XML_TAG_COMPUTER "/[" XML_ATTR_NAME "='%s']", pszCompName);
  59. IPropertyTree* pComputer = m_pRoot->queryPropTree(xpath.str());
  60. if (pComputer)
  61. computers.push_back(pComputer);
  62. }
  63. if (!strcmp(newType, "Master") && computers.size() != 1)
  64. throw MakeStringException(-1, "Thor cannot have more than one master. Please choose one computer only!");
  65. int numNodes = 1;
  66. if (slavesPerNode && *slavesPerNode)
  67. numNodes = atoi(slavesPerNode);
  68. if (numNodes < 1)
  69. numNodes = 1;
  70. pThor->setPropInt("@slavesPerNode", numNodes);
  71. int numChannels = 1;
  72. if (channelsPerSlave && *channelsPerSlave)
  73. numChannels = atoi(channelsPerSlave);
  74. if (numChannels < 1)
  75. numChannels = 1;
  76. pThor->setPropInt("@channelsPerSlave", numChannels);
  77. if (!strcmp(newType, "Master"))
  78. retVal = this->AddNewNodes(pThor, XML_TAG_THORMASTERPROCESS, 0, computers, checkComps, skipExisting, usageList);
  79. else if (!strcmp(newType, "Slave"))
  80. retVal = this->AddNewNodes(pThor, XML_TAG_THORSLAVEPROCESS, 0, computers, checkComps, skipExisting, usageList);
  81. else if (!strcmp(newType, "Spare"))
  82. retVal = this->AddNewNodes(pThor, XML_TAG_THORSPAREPROCESS, 0, computers, checkComps, skipExisting, usageList);
  83. if (usageList.length() > 0)
  84. {
  85. sMsg.append("The following computers are already being used.\nDo you want to add/replace them anyway?");
  86. sMsg.append(usageList);
  87. }
  88. }
  89. else if (!strcmp(cmd, "Delete"))
  90. {
  91. Owned<IPropertyTreeIterator> iterComputers = pParams->getElements("Node");
  92. ForEach (*iterComputers)
  93. {
  94. IPropertyTree* pComp = &iterComputers->query();
  95. const char* process = pComp->queryProp(XML_ATTR_PROCESS_NAME);
  96. const char* type = pComp->queryProp(XML_ATTR_TYPE);
  97. // Delete process node
  98. IPropertyTree* pProcessNode = GetProcessNode(pThor, process);
  99. if (pProcessNode)
  100. pThor->removeTree(pProcessNode);
  101. //Remove all slaves from thor
  102. if (!strcmp(type, "Master"))
  103. pThor->removeProp(XML_TAG_THORSLAVEPROCESS);
  104. }
  105. RenameThorInstances(pThor);
  106. UpdateThorAttributes(pThor);
  107. retVal = true;
  108. }
  109. return retVal;
  110. }
  111. IPropertyTree* CConfigEnvHelper::getSoftwareNode(const char* compType, const char* compName)
  112. {
  113. StringBuffer xpath;
  114. xpath.appendf("Software/%s[@name='%s']", compType, compName);
  115. return m_pRoot->queryPropTree(xpath.str());
  116. }
  117. bool CConfigEnvHelper::addRoxieServers(const char* xmlArg)
  118. {
  119. Owned<IPropertyTree> pSrcTree = createPTreeFromXMLString(xmlArg && *xmlArg ? xmlArg : "<RoxieData/>");
  120. const char* pszFarm = pSrcTree->queryProp("@parentName");
  121. const char* pszRoxieCluster = pSrcTree->queryProp("@roxieName");
  122. unsigned int nComputers = 0;//computers.size();
  123. IPropertyTree* pParent = m_pRoot->queryPropTree("Software");
  124. IPropertyTree* pFarm;
  125. bool bNewFarm;
  126. StringBuffer sFarmName;
  127. StringBuffer xpath;
  128. if (pszFarm && strlen(pszFarm))
  129. {
  130. xpath.clear().appendf("RoxieCluster[@name='%s']/" XML_TAG_ROXIE_FARM, pszRoxieCluster);
  131. pFarm = getSoftwareNode(xpath.str(), pszFarm);
  132. if (pFarm == NULL)
  133. return false;
  134. sFarmName = pFarm->queryProp(XML_ATTR_NAME);
  135. bNewFarm = false;
  136. if (!pFarm->hasProp("@port"))
  137. pFarm->addPropInt("@port", 9876);
  138. if (!pFarm->hasProp("@listenQueue"))
  139. pFarm->addPropInt("@listenQueue", 200);
  140. if (!pFarm->hasProp("@numThreads"))
  141. pFarm->getPropInt("@numThreads", 30);
  142. if (!pFarm->hasProp("@requestArrayThreads"))
  143. pFarm->addPropInt("@requestArrayThreads", 5);
  144. if (!pFarm->hasProp("@aclName"))
  145. pFarm->addProp("@aclName", "");
  146. StringBuffer dataDir(pFarm->queryProp(XML_ATTR_LEVEL)); // MORE - this is dead code - variable never used
  147. }
  148. else
  149. {
  150. xpath.clear().appendf("RoxieCluster[@name='%s']/" XML_TAG_ROXIE_FARM, pszRoxieCluster);
  151. createUniqueName("farm", xpath.str(), sFarmName);
  152. bNewFarm = true;
  153. Owned<IPropertyTreeIterator> iter = pSrcTree->getElements(XML_TAG_COMPONENT);
  154. xpath.clear().appendf("RoxieCluster[@name='%s']/" XML_TAG_ROXIE_FARM, pszRoxieCluster);
  155. pFarm = pParent->addPropTree(xpath.str(), createPTree());
  156. pFarm->addProp (XML_ATTR_NAME, sFarmName.str());
  157. pFarm->addPropInt("@port", pSrcTree->getPropInt("@port", 9876));
  158. pFarm->addPropInt("@listenQueue", 200);
  159. pFarm->addPropInt("@numThreads", 30);
  160. pFarm->addPropInt("@requestArrayThreads", 5);
  161. pFarm->addProp("@aclName", "");
  162. }
  163. return true;
  164. }
  165. bool CConfigEnvHelper::handleReplaceRoxieServer(const char* xmlArg)
  166. {
  167. Owned<IPropertyTree> pSrcTree = createPTreeFromXMLString(xmlArg && *xmlArg ? xmlArg : "<RoxieData/>");
  168. const char* pszRoxieCluster = pSrcTree->queryProp("@roxieName");
  169. IPropertyTree* pParent = m_pRoot->queryPropTree("Software");
  170. StringBuffer xpath;
  171. if (pszRoxieCluster && *pszRoxieCluster)
  172. {
  173. StringBuffer xpathNode;
  174. xpathNode.appendf("./%s/%s", XML_TAG_NODES, XML_TAG_NODE);
  175. xpath.clear().appendf("%s[%s='%s']/%s[%s='%s']", XML_TAG_ROXIECLUSTER, XML_ATTR_NAME, pszRoxieCluster, XML_TAG_ROXIE_FARM, XML_ATTR_NAME, pSrcTree->queryPropTree(xpathNode.str())->queryProp(XML_ATTR_FARM));
  176. IPropertyTree* pFarm = pParent->queryPropTree(xpath.str());
  177. if (!pFarm)
  178. throw MakeStringException(-1, "Could not find a RoxieCluster with name '%s'", pszRoxieCluster);
  179. Owned<IPropertyTreeIterator> iter = pSrcTree->getElements("Nodes/Node");
  180. ForEach (*iter)
  181. {
  182. IPropertyTree* pNode = &iter->query();
  183. const char* pszFarm = pNode->queryProp("@farm");
  184. const char* pszName = pNode->queryProp(XML_ATTR_NAME);
  185. const char* pszNewComputer = pNode->queryProp("@newComputer");
  186. xpath.clear().appendf(XML_TAG_ROXIE_SERVER"[@computer='%s']", pszNewComputer);
  187. if (pFarm->queryPropTree(xpath.str()))
  188. return false;
  189. xpath.clear().appendf(XML_TAG_ROXIE_SERVER"[@name='%s']", pszName);
  190. IPropertyTree* pServer = pFarm->queryPropTree(xpath.str());
  191. if (pServer && pszNewComputer && *pszNewComputer)
  192. {
  193. pServer->setProp(XML_ATTR_COMPUTER, pszNewComputer);
  194. xpath.clear().appendf(XML_TAG_ROXIECLUSTER"[@name='%s']/" XML_TAG_ROXIE_SERVER "[@name='%s']", pszRoxieCluster, pszName);
  195. IPropertyTree* pOldVerRoxieServer = pParent->queryPropTree(xpath.str());
  196. if (pOldVerRoxieServer)
  197. {
  198. pOldVerRoxieServer->setProp(XML_ATTR_COMPUTER, pszNewComputer);
  199. xpath.clear().appendf("Hardware/" XML_TAG_COMPUTER "[" XML_ATTR_NAME "='%s']", pszNewComputer);
  200. IPropertyTree* pComputer = m_pRoot->queryPropTree(xpath.str());
  201. if (pComputer)
  202. pOldVerRoxieServer->setProp(XML_ATTR_NETADDRESS, pComputer->queryProp(XML_ATTR_NETADDRESS));
  203. }
  204. }
  205. }
  206. }
  207. return true;
  208. }
  209. //---------------------------------------------------------------------------
  210. // CheckComputerUse - will only prompt once for each element type
  211. //---------------------------------------------------------------------------
  212. bool CConfigEnvHelper::checkComputerUse(/*IPropertyTree* pComputerNode*/ const char* szComputer, IPropertyTree* pParentNode) const
  213. {
  214. StringBuffer xpath;
  215. xpath.append(XML_TAG_ROXIE_SERVER "[@computer='").append( szComputer ).append("']");
  216. Owned<IPropertyTreeIterator> iter = pParentNode->getElements(xpath.str());
  217. return !(iter->first() && iter->isValid());
  218. }
  219. IPropertyTree* CConfigEnvHelper::addLegacyServer(const char* name, IPropertyTree* pServer,
  220. IPropertyTree* pFarm, const char* roxieClusterName)
  221. {
  222. IPropertyTree* pLegacyServer;
  223. StringBuffer xpath;
  224. xpath.clear().appendf("Software/RoxieCluster[@name='%s']", roxieClusterName);
  225. IPropertyTree* pParentNode = m_pRoot->queryPropTree(xpath.str());
  226. if (pParentNode)
  227. {
  228. const char* szComputer = pServer->queryProp(XML_ATTR_COMPUTER);
  229. xpath.clear().appendf("Hardware/Computer/[@name='%s']", szComputer);
  230. IPropertyTree* pComputer= m_pRoot->queryPropTree(xpath.str());
  231. const char* netAddress = pComputer->queryProp(XML_ATTR_NETADDRESS);
  232. //derive the new server from pFarm since it has most of the attributes
  233. pLegacyServer = addNode(XML_TAG_ROXIE_SERVER, pParentNode);
  234. pLegacyServer->setProp( XML_ATTR_NAME, name);
  235. pLegacyServer->setProp( XML_ATTR_COMPUTER, szComputer );
  236. pLegacyServer->setProp( XML_ATTR_NETADDRESS, netAddress);
  237. }
  238. else
  239. pLegacyServer = NULL;
  240. return pLegacyServer;
  241. }
  242. //---------------------------------------------------------------------------
  243. // setComputerState
  244. //---------------------------------------------------------------------------
  245. void CConfigEnvHelper::setComputerState(IPropertyTree* pNode, COMPUTER_STATE state)
  246. {
  247. setAttribute(pNode, XML_ATTR_STATE, g_szComputerState[state]);
  248. }
  249. //---------------------------------------------------------------------------
  250. // setAttribute
  251. //---------------------------------------------------------------------------
  252. void CConfigEnvHelper::setAttribute(IPropertyTree* pNode, const char* szName, const char* szValue)
  253. {
  254. // Check attribute already has specified value
  255. const char* szValueOld = pNode->queryProp(szName);
  256. if (!szValueOld || strcmp(szValueOld, szValue))
  257. {
  258. //UpdateComputerMap(pNode, false);
  259. // ptree does not like missing intermediates...
  260. const char *finger = szName;
  261. StringBuffer subpath;
  262. while (strchr(finger, '/'))
  263. {
  264. while (*finger!='/')
  265. subpath.append(*finger++);
  266. if (!pNode->hasProp(subpath.str()))
  267. pNode->addProp(subpath.str(), "");
  268. subpath.append(*finger++);
  269. }
  270. if (!strcmp(szName, XML_ATTR_BUILD) && !strcmp(pNode->queryName(), XML_TAG_ESPSERVICE))
  271. {
  272. //remove previous Properties, if any, that this component inherited from its
  273. //previous build
  274. IPropertyTree* pProperties = pNode->queryPropTree("Properties");
  275. IPropertyTree* pNewProperties;
  276. //if the new build has any properties then let the node inherit them
  277. const char* buildSet = pNode->queryProp(XML_ATTR_BUILDSET);
  278. if (buildSet)
  279. {
  280. StringBuffer sPath;
  281. sPath.append("Programs/Build[@name='").append(szValue).append("']/BuildSet[@name='")
  282. .append(buildSet).append("']/Properties");
  283. pNewProperties = m_pRoot->queryPropTree(sPath.str());
  284. }
  285. else
  286. pNewProperties = NULL;
  287. //if we just changed build for an ESP service then enumerate all bindings for all
  288. //ESP server processes and if any binding uses this service then replace its
  289. //Authenticate and AuthenticateFeature nodes with those from the properties of
  290. //this service from the new build. However, we only remove the nodes that are
  291. //not in the new build preserving the others (so their attributes are preserved -
  292. //in case they have been changed by the user). We also add new nodes that did
  293. //not exist before. In essence, a merge is needed.
  294. //
  295. if (pProperties || pNewProperties)
  296. {
  297. StringBuffer xpath;
  298. xpath.appendf("Software/EspProcess/EspBinding[@service='%s']", pNode->queryProp(XML_ATTR_NAME));
  299. Owned<IPropertyTreeIterator> iBinding = m_pRoot->getElements(xpath.str());
  300. ForEach(*iBinding)
  301. {
  302. IPropertyTree* pBinding = &iBinding->query();
  303. //remove existing Authenticate and AuthenticateFeature nodes that are not in the new buildset's properties
  304. //
  305. mergeServiceAuthenticationWithBinding(pBinding, pProperties, pNewProperties, "Authenticate");
  306. mergeServiceAuthenticationWithBinding(pBinding, pProperties, pNewProperties, "AuthenticateFeature");
  307. mergeServiceAuthenticationWithBinding(pBinding, pProperties, pNewProperties, "AuthenticateSetting");
  308. }
  309. pNode->removeTree(pProperties);
  310. }
  311. if (pNewProperties)
  312. pNode->addPropTree("Properties", createPTreeFromIPT(pNewProperties));
  313. }
  314. pNode->setProp(szName, szValue);
  315. }
  316. }
  317. void CConfigEnvHelper::mergeServiceAuthenticationWithBinding(IPropertyTree* pBinding,
  318. IPropertyTree* pProperties,
  319. IPropertyTree* pNewProperties,
  320. const char* NodeName)
  321. {
  322. StringBuffer xpath;
  323. //remove existing Authenticate and AuthenticateFeature nodes that are not in the new buildset's properties
  324. //
  325. Owned<IPropertyTreeIterator> iDest = pBinding->getElements(NodeName);
  326. for (iDest->first(); iDest->isValid(); )
  327. {
  328. IPropertyTree* pDest = &iDest->query();
  329. iDest->next();
  330. const char* path = pDest->queryProp("@path");
  331. xpath.clear().appendf("%s[@path='%s']", NodeName, path);
  332. IPropertyTree* pNewPropChild = pNewProperties->queryPropTree(xpath.str());
  333. if (pNewPropChild)
  334. {
  335. IPropertyTree* pPropChild = pProperties->queryPropTree(xpath.str());
  336. if (pPropChild)
  337. {
  338. //same path so merge individual attributes, retaining any that may have been changed by user
  339. //but replacing ones that are different in newer build but not changed by user
  340. Owned<IAttributeIterator> iAttr = pDest->getAttributes();
  341. ForEach(*iAttr)
  342. {
  343. const char* attrName = iAttr->queryName();
  344. if (0 != strcmp(attrName, "@path"))
  345. {
  346. const char* attrDest = iAttr->queryValue();
  347. const char* attrProp = pPropChild->queryProp(attrName);
  348. const char* attrNewProp = pNewPropChild->queryProp(attrName);
  349. if (attrProp && attrNewProp && !strcmp(attrDest, attrProp))
  350. pDest->setProp(attrName, attrNewProp);
  351. }
  352. }
  353. }
  354. }
  355. else
  356. pBinding->removeTree(pDest);
  357. }
  358. //add nodes from buildset properties that are missing in binding
  359. //
  360. bool bAuthenticateFeature = !strcmp(NodeName, "AuthenticateFeature");
  361. bool bAuthenticateSetting = !strcmp(NodeName, "AuthenticateSetting");
  362. Owned<IPropertyTreeIterator> iSrc = pNewProperties->getElements(NodeName);
  363. ForEach(*iSrc)
  364. {
  365. IPropertyTree* pNode = &iSrc->query();
  366. const char* path = pNode->queryProp("@path");
  367. xpath.clear().appendf("%s[@path='%s']", NodeName, path);
  368. if (!pBinding->queryPropTree(xpath.str()))
  369. {
  370. pNode = pBinding->addPropTree(NodeName, createPTreeFromIPT(pNode));
  371. if (bAuthenticateFeature)
  372. pNode->addProp("@authenticate", "Yes");
  373. else if (bAuthenticateSetting)
  374. pNode->addProp("@include", "Yes");
  375. }
  376. }
  377. }
  378. //---------------------------------------------------------------------------
  379. // lookupComputerByName
  380. //---------------------------------------------------------------------------
  381. IPropertyTree* CConfigEnvHelper::lookupComputerByName(const char* szName) const
  382. {
  383. if (!szName || !*szName) return NULL;
  384. Owned<IPropertyTreeIterator> iter = m_pRoot->getElements(XML_TAG_HARDWARE "/" XML_TAG_COMPUTER);
  385. for (iter->first(); iter->isValid(); iter->next())
  386. {
  387. const char* szValue = iter->query().queryProp(XML_ATTR_NAME);
  388. if (szValue && strcmp(szValue, szName) == 0)
  389. return &iter->query();
  390. }
  391. return NULL;
  392. }
  393. void CConfigEnvHelper::createUniqueName(const char* szPrefix, const char* parent, StringBuffer& sbName)
  394. {
  395. sbName.clear().append(szPrefix).append("1");
  396. if (getSoftwareNode(parent, sbName.str()))
  397. {
  398. int iIdx = 2;
  399. do
  400. {
  401. sbName.clear().append(szPrefix).append(iIdx++);
  402. }
  403. while (getSoftwareNode(parent, sbName.str()));
  404. }
  405. }
  406. //---------------------------------------------------------------------------
  407. // addNode
  408. //---------------------------------------------------------------------------
  409. IPropertyTree* CConfigEnvHelper::addNode(const char* szTag, IPropertyTree* pParentNode, IPropertyTree* pInsertAfterNode)
  410. {
  411. IPropertyTree* pNode = createPTree(szTag);
  412. if (pNode)
  413. {
  414. addNode(pNode, pParentNode, pInsertAfterNode);
  415. }
  416. return pNode;
  417. }
  418. //---------------------------------------------------------------------------
  419. // addNode
  420. //---------------------------------------------------------------------------
  421. IPropertyTree* CConfigEnvHelper::addNode(IPropertyTree*& pNode, IPropertyTree* pParentNode, IPropertyTree* pInsertAfterNode)
  422. {
  423. StringBuffer sTag(pNode->queryName()); // need to pass in a copy of the name
  424. // Check is node is to be added at specific location relative to nodes with same name
  425. if (pInsertAfterNode)
  426. {
  427. int idx = 1; // this will insert into first position
  428. if (strcmp(pInsertAfterNode->queryName(), pNode->queryName()) == 0)
  429. {
  430. idx = pParentNode->queryChildIndex(pInsertAfterNode) + 2;
  431. }
  432. // Only append qualifier is not inserting at end position
  433. if (pParentNode->queryPropTree(StringBuffer(sTag).appendf("[%d]", idx).str()))
  434. sTag.appendf("[%d]", idx);
  435. }
  436. pNode = pParentNode->addPropTree(sTag.str(), pNode);
  437. return pNode;
  438. }
  439. //---------------------------------------------------------------------------
  440. // renameInstances
  441. //---------------------------------------------------------------------------
  442. void CConfigEnvHelper::renameInstances(IPropertyTree* pRoxieCluster)
  443. {
  444. // Iterate through farms
  445. int nFarm = 0;
  446. StringBuffer xpath;
  447. Owned<IPropertyTreeIterator> iFarm = pRoxieCluster->getElements(XML_TAG_ROXIE_FARM);
  448. ForEach(*iFarm)
  449. {
  450. IPropertyTree* pFarm = &iFarm->query();
  451. int nServer = 0;
  452. StringBuffer sFarmName("farm");
  453. sFarmName.append(++nFarm);
  454. setAttribute(pFarm, XML_ATTR_NAME, sFarmName.str());
  455. Owned<IPropertyTreeIterator> iServer = pFarm->getElements(XML_TAG_ROXIE_SERVER);
  456. ForEach(*iServer)
  457. {
  458. IPropertyTree* pServer = &iServer->query();
  459. StringBuffer sServerName( sFarmName );
  460. sServerName.append("_s");
  461. sServerName.append(++nServer);
  462. const char* prevName = pServer->queryProp(XML_ATTR_NAME);
  463. if (prevName && *prevName)
  464. {
  465. IPropertyTree* pLegacyServer = findLegacyServer(pRoxieCluster, prevName);
  466. if (pLegacyServer)
  467. setAttribute(pLegacyServer, "@_name", sServerName.str());
  468. }
  469. setAttribute(pServer, XML_ATTR_NAME, sServerName.str());
  470. }
  471. }
  472. Owned<IPropertyTreeIterator> iServer = pRoxieCluster->getElements(XML_TAG_ROXIE_SERVER);
  473. ForEach(*iServer)
  474. {
  475. IPropertyTree* pServer = &iServer->query();
  476. const char* newName = pServer->queryProp("@_name");
  477. if (newName)
  478. {
  479. pServer->setProp(XML_ATTR_NAME, newName);
  480. pServer->removeProp("@_name");
  481. }
  482. }
  483. }
  484. IPropertyTree* CConfigEnvHelper::findLegacyServer(IPropertyTree* pRoxieCluster, const char* pszServer)
  485. {
  486. StringBuffer xpath;
  487. xpath.appendf(XML_TAG_ROXIE_SERVER"[@name='%s']", pszServer);
  488. return pRoxieCluster->queryPropTree( xpath.str() );
  489. }
  490. bool CConfigEnvHelper::deleteRoxieServers(const char* xmlArg)
  491. {
  492. Owned<IPropertyTree> pSrcTree = createPTreeFromXMLString(xmlArg && *xmlArg ? xmlArg : "<RoxieData/>");
  493. const char* pszRoxieCluster = pSrcTree->queryProp("@roxieName");
  494. StringBuffer xpath;
  495. xpath.clear().appendf("Software/RoxieCluster[@name='%s']", pszRoxieCluster);
  496. IPropertyTree* pRoxieCluster = m_pRoot->queryPropTree(xpath.str());
  497. if (pRoxieCluster == NULL)
  498. return false;
  499. IPropertyTree* pChild = NULL;
  500. while ((pChild = pRoxieCluster->queryPropTree( XML_TAG_ROXIE_SERVER_PROCESSS"[1]")) != NULL)
  501. pRoxieCluster->removeTree( pChild );
  502. return true;
  503. }
  504. bool CConfigEnvHelper::deleteRoxiePorts(const char* xmlArg)
  505. {
  506. Owned<IPropertyTree> pSrcTree = createPTreeFromXMLString(xmlArg && *xmlArg ? xmlArg : "<RoxieData/>");
  507. const char* pszRoxieCluster = pSrcTree->queryProp("@roxieName");
  508. const char* pParentName = pSrcTree->queryPropTree(XML_TAG_ROXIE_FARM) != NULL ? pSrcTree->queryPropTree(XML_TAG_ROXIE_FARM)->queryProp("@parent"): "";
  509. const char* pRoxiePortName = pSrcTree->queryPropTree(XML_TAG_ROXIE_FARM) != NULL ? pSrcTree->queryPropTree(XML_TAG_ROXIE_FARM)->queryProp(XML_ATTR_NAME): "";
  510. unsigned int nComputers = 0;
  511. StringBuffer xpath;
  512. xpath.clear().appendf("Software/RoxieCluster[@name='%s']", pszRoxieCluster);
  513. IPropertyTree* pRoxieCluster = m_pRoot->queryPropTree(xpath.str());
  514. if (pRoxiePortName && *pRoxiePortName && pParentName && *pParentName && strcmp(pParentName, "Roxie Ports") == 0)
  515. {
  516. StringBuffer sFarmName;
  517. Owned<IPropertyTreeIterator> iterFarm = pSrcTree->getElements(XML_TAG_ROXIE_FARM);
  518. ForEach (*iterFarm)
  519. {
  520. IPropertyTree* pFarm = &iterFarm->query();
  521. const char* pszFarm = pFarm->queryProp(XML_ATTR_NAME);
  522. if (pszFarm == NULL || *pszFarm == 0)
  523. return false;
  524. if (strcmp(pszFarm, pRoxiePortName) == 0)
  525. {
  526. deleteFarm(pRoxieCluster, pszFarm);
  527. return true;
  528. }
  529. }
  530. return false;
  531. }
  532. Owned<IPropertyTreeIterator> iter = pRoxieCluster->getElements(XML_TAG_ROXIE_SERVER);
  533. IPropertyTree *pTree = NULL;
  534. int count = 1;
  535. do
  536. {
  537. StringBuffer xpath2(XML_TAG_ROXIE_SERVER);
  538. xpath2.appendf("[%d]", count);
  539. count++;
  540. pTree = pRoxieCluster->queryPropTree(xpath2.str());
  541. if (pSrcTree->queryPropTree(XML_TAG_ROXIE_ONLY_SLAVE) == NULL) //probably an old config
  542. throw MakeStringException(-1, "Error modifying roxie cluster! Possible using an old version of the config?" );
  543. if (pTree && (!strcmp(pSrcTree->queryPropTree(XML_TAG_ROXIE_ONLY_SLAVE)->queryProp(XML_ATTR_NAME), "Roxie Cluster") || !strcmp(pTree->queryProp(XML_ATTR_NAME), pSrcTree->queryPropTree(XML_TAG_ROXIE_ONLY_SLAVE)->queryProp(XML_ATTR_NAME))))
  544. {
  545. pRoxieCluster->removeTree(pTree);
  546. count--;
  547. }
  548. } while (pTree);
  549. Owned<IPropertyTreeIterator> iterSlaves = pSrcTree->getElements(XML_TAG_ROXIE_ONLY_SLAVE);
  550. ForEach (*iterSlaves)
  551. {
  552. IPropertyTree* pChild;
  553. //if atleast one slave, delete all slaves
  554. while ((pChild = pRoxieCluster->queryPropTree( "RoxieSlave[1]" )) != NULL)
  555. pRoxieCluster->removeTree( pChild );
  556. while ((pChild = pRoxieCluster->queryPropTree( XML_TAG_ROXIE_SLAVE "[1]" )) != NULL)
  557. pRoxieCluster->removeTree( pChild );
  558. break;
  559. }
  560. renameInstances(pRoxieCluster);
  561. return true;
  562. }
  563. void CConfigEnvHelper::deleteFarm(IPropertyTree* pRoxieCluster, const char* pszFarm)
  564. {
  565. StringBuffer xpath;
  566. xpath.clear().appendf(XML_TAG_ROXIE_FARM"[@name='%s']", pszFarm);
  567. IPropertyTree* pFarm = pRoxieCluster->queryPropTree(xpath.str());
  568. Owned<IPropertyTreeIterator> it = pFarm->getElements(XML_TAG_ROXIE_SERVER);
  569. ForEach(*it)
  570. {
  571. IPropertyTree* pServer = &it->query();
  572. const char* pszServer = pServer->queryProp(XML_ATTR_NAME);
  573. IPropertyTree* pLegacyServer = findLegacyServer(pRoxieCluster, pszServer);
  574. if (pLegacyServer)
  575. pRoxieCluster->removeTree(pLegacyServer);
  576. }
  577. pRoxieCluster->removeTree(pFarm);
  578. }
  579. void CConfigEnvHelper::deleteServer(IPropertyTree* pRoxieCluster, const char* pszFarm, const char* pszServer)
  580. {
  581. StringBuffer xpath;
  582. IPropertyTree* pLegacyServer = findLegacyServer(pRoxieCluster, pszServer);
  583. if (pLegacyServer)
  584. pRoxieCluster->removeTree(pLegacyServer);
  585. xpath.clear().appendf(XML_TAG_ROXIE_FARM"[@name='%s']", pszFarm);
  586. IPropertyTree* pFarm = pRoxieCluster->queryPropTree(xpath.str());
  587. if (pFarm)
  588. {
  589. xpath.clear().appendf(XML_TAG_ROXIE_SERVER"[@name='%s']", pszServer);
  590. IPropertyTree* pServer = pFarm->queryPropTree(xpath.str());
  591. if (pServer)
  592. pFarm->removeTree(pServer);
  593. }
  594. }
  595. void CConfigEnvHelper::addComponent(const char* pszBuildSet, StringBuffer& sbNewName, IPropertyTree* pCompTree)
  596. {
  597. try
  598. {
  599. // NOTE - we are assuming buildSet is unique in a build.
  600. StringBuffer xPath, value;
  601. Owned<IPropertyTreeIterator> buildSet;
  602. const char* buildName = NULL;
  603. xPath.appendf("./Programs/Build/BuildSet[@name=\"%s\"]", pszBuildSet);
  604. CConfigHelper *pConfigHelper = CConfigHelper::getInstance();
  605. if (pConfigHelper != NULL)
  606. {
  607. buildSet.setown(pConfigHelper->getBuildSetTree()->getElements(xPath.str()));
  608. buildName = pConfigHelper->getBuildSetTree()->queryPropTree("./Programs/Build[1]")->queryProp(XML_ATTR_NAME);
  609. }
  610. else
  611. {
  612. buildSet.setown(m_pRoot->getElements(xPath.str()));
  613. buildName = m_pRoot->queryPropTree("./Programs/Build[1]")->queryProp(XML_ATTR_NAME);
  614. }
  615. buildSet->first();
  616. IPropertyTree* pBuildSet = &buildSet->query();
  617. const char* buildSetName = pBuildSet->queryProp(XML_ATTR_NAME);
  618. const char* processName = pBuildSet->queryProp(XML_ATTR_PROCESS_NAME);
  619. if (!processName) //support non-generic components as well
  620. processName = buildSetName;
  621. {
  622. // Use lower case version of type for name prefix
  623. StringBuffer sName(buildSetName);
  624. sName.toLowerCase();
  625. sName.replaceString("process","");
  626. if(sbNewName.length())
  627. value.append(sbNewName.str()).append(getUniqueName(m_pRoot.get(), sName, processName, "Software"));
  628. else
  629. value.append(getUniqueName(m_pRoot.get(), sName, processName, "Software"));
  630. pCompTree->setProp(XML_ATTR_NAME,value);
  631. sbNewName.clear().append(sName);
  632. pCompTree->setProp(XML_ATTR_BUILD, buildName);
  633. pCompTree->setProp(XML_ATTR_BUILDSET,pszBuildSet);
  634. Owned<IPropertyTree> pProperties = pBuildSet->getPropTree("Properties");
  635. if (pProperties)
  636. pCompTree->addPropTree("Properties", createPTreeFromIPT(pProperties));
  637. addNode(pCompTree, m_pRoot->queryPropTree("Software"));
  638. }
  639. }
  640. catch (IException* e)
  641. {
  642. throw e;
  643. }
  644. }
  645. bool CConfigEnvHelper::EnsureInRange(const char* psz, UINT low, UINT high, const char* caption)
  646. {
  647. bool rc = false;
  648. StringBuffer msg;
  649. const UINT x = atoi( psz );
  650. if ( ((low < high) && (x < low || x > high)) || (low == high && x != low) )
  651. {
  652. msg.append(caption).append(" must be ");
  653. if (low == high)
  654. msg.append(low);
  655. else
  656. {
  657. msg.append("between ");
  658. msg.append(low).append(" and ");
  659. msg.append( high );
  660. }
  661. }
  662. else
  663. if (high == 0 && x < low)
  664. msg.append(caption).append(" must be at least ").append(low);
  665. else
  666. rc = true;
  667. if (!rc)
  668. {
  669. msg.append('.');
  670. throw MakeStringException(-1, "%s", msg.str());
  671. }
  672. return rc;
  673. }
  674. bool CConfigEnvHelper::handleRoxieSlaveConfig(const char* xmlArg)
  675. {
  676. try
  677. {
  678. Owned<IPropertyTree> pSrcTree = createPTreeFromXMLString(xmlArg && *xmlArg ? xmlArg : "<RoxieData/>");
  679. const char* pszRoxie = pSrcTree->queryProp("@roxieName");
  680. StringBuffer xpath;
  681. xpath.clear().appendf("%s/%s[%s='%s']", XML_TAG_SOFTWARE, XML_TAG_ROXIECLUSTER, XML_ATTR_NAME, pszRoxie);
  682. IPropertyTree* pRoxie = m_pRoot->queryPropTree(xpath.str());
  683. if (!pRoxie)
  684. throw MakeStringException(-1, "Cannot find roxie with name %s", pszRoxie);
  685. Owned<IPropertyTreeIterator> iterComputers = pSrcTree->getElements(XML_TAG_INSTANCES "/" XML_TAG_INSTANCE);
  686. IPropertyTreePtrArray computers;
  687. ForEach (*iterComputers)
  688. {
  689. IPropertyTree* pComp = &iterComputers->query();
  690. const char* pszCompName = pComp->queryProp(XML_ATTR_NAME);
  691. xpath.clear().appendf(XML_TAG_HARDWARE "/" XML_TAG_COMPUTER "/[" XML_ATTR_NAME "='%s']", pszCompName);
  692. IPropertyTree* pComputer = m_pRoot->queryPropTree(xpath.str());
  693. if (pComputer)
  694. computers.push_back(pComputer);
  695. }
  696. RemoveSlaves(pRoxie, true);
  697. RemoveSlaves(pRoxie, false);
  698. for (unsigned i=0; i<computers.size(); i++)
  699. {
  700. IPropertyTree* pComputer = computers[i];
  701. const char* szComputer = pComputer->queryProp(XML_ATTR_NAME);
  702. const char* netAddress = pComputer->queryProp(XML_ATTR_NETADDRESS);
  703. const char* pCompName = pComputer->queryProp(XML_ATTR_NAME);
  704. IPropertyTree *pTree = addNode(XML_TAG_ROXIE_SERVER, pRoxie);
  705. pTree->setProp(XML_ATTR_NAME, szComputer);
  706. pTree->setProp(XML_ATTR_NETADDRESS, netAddress);
  707. pTree->setProp(XML_ATTR_COMPUTER, pCompName);
  708. }
  709. }
  710. catch (IException *e)
  711. {
  712. StringBuffer msg;
  713. throw MakeStringException(-1, "%s", e->errorMessage(msg).str());
  714. }
  715. catch (...)
  716. {
  717. throw MakeStringException(-1, "Unknown exception adding servers" );
  718. }
  719. return true;
  720. }
  721. void CConfigEnvHelper::RemoveSlaves(IPropertyTree* pRoxie, bool bLegacySlaves/*=false*/)
  722. {
  723. IPropertyTree* pChild;
  724. while ((pChild = pRoxie->queryPropTree( bLegacySlaves ? XML_TAG_ROXIE_SLAVE "[1]" : "RoxieSlave[1]")) != NULL)
  725. pRoxie->removeTree( pChild );
  726. IPropertyTree *pTree = NULL;
  727. do
  728. {
  729. pTree = pRoxie->queryPropTree(XML_TAG_ROXIE_SERVER"[1]");
  730. if (pTree)
  731. pRoxie->removeTree(pTree);
  732. } while (pTree);
  733. }
  734. void CConfigEnvHelper::RenameThorInstances(IPropertyTree* pThor)
  735. {
  736. int nSlave = 1;
  737. int nSpare = 1;
  738. IPropertyTree* pMaster = pThor->queryPropTree(XML_TAG_THORMASTERPROCESS);
  739. if (pMaster)
  740. pMaster->setProp(XML_ATTR_NAME, "m1");
  741. StringBuffer sName;
  742. Owned<IPropertyTreeIterator> iter = pThor->getElements(XML_TAG_THORSLAVEPROCESS);
  743. for (iter->first(); iter->isValid(); iter->next())
  744. {
  745. sName.clear().appendf("s%d", nSlave++);
  746. setAttribute(&iter->query(), XML_ATTR_NAME, sName);
  747. }
  748. iter.setown(pThor->getElements(XML_TAG_THORSPAREPROCESS));
  749. for (iter->first(); iter->isValid(); iter->next())
  750. {
  751. sName.clear().appendf("spare%d", nSpare++);
  752. setAttribute(&iter->query(), XML_ATTR_NAME, sName);
  753. }
  754. //With thor dynamic range changes, we do not need thor topology section
  755. IPropertyTree* pTopology = pThor->queryPropTree(XML_TAG_TOPOLOGY);
  756. if (pTopology)
  757. pThor->removeTree(pTopology);
  758. }
  759. //----------------------------------------------------------------------------
  760. // UpdateAttributes
  761. //----------------------------------------------------------------------------
  762. void CConfigEnvHelper::UpdateThorAttributes(IPropertyTree* pParentNode)
  763. {
  764. const char* masterIp = NULL;
  765. bool localThor = true, multiSlaves = false;
  766. int nSlaves = 0;
  767. IPropertyTree* pNode = pParentNode->queryPropTree(XML_TAG_THORMASTERPROCESS);
  768. if (pNode)
  769. {
  770. const char* szName = pNode->queryProp(XML_ATTR_COMPUTER);
  771. setAttribute(pParentNode, XML_ATTR_COMPUTER, szName);
  772. IPropertyTree* pComputer = lookupComputerByName(szName);
  773. if (pComputer)
  774. masterIp = pComputer->queryProp(XML_ATTR_NETADDRESS);
  775. }
  776. else
  777. {
  778. localThor = false;
  779. }
  780. Owned<IPropertyTreeIterator> iter = pParentNode->getElements(XML_TAG_THORSLAVEPROCESS);
  781. for (iter->first(); iter->isValid(); iter->next())
  782. {
  783. nSlaves++;
  784. if (!localThor && multiSlaves)
  785. continue;
  786. const char* computer = iter->query().queryProp(XML_ATTR_COMPUTER);
  787. if (computer && *computer)
  788. {
  789. if (localThor)
  790. {
  791. IPropertyTree* pNode = lookupComputerByName(computer);
  792. if (pNode && masterIp && *masterIp)
  793. {
  794. const char* ip = pNode->queryProp(XML_ATTR_NETADDRESS);
  795. if (ip && *ip && strcmp(ip, masterIp))
  796. localThor = false;
  797. }
  798. }
  799. if (!multiSlaves)
  800. {
  801. StringBuffer xpath(XML_TAG_THORSLAVEPROCESS);
  802. xpath.appendf("[" XML_ATTR_COMPUTER "='%s']", computer);
  803. Owned<IPropertyTreeIterator> iterNodes = pParentNode->getElements(xpath.str());
  804. int count = 0;
  805. ForEach(*iterNodes)
  806. {
  807. count++;
  808. if (count > 1)
  809. {
  810. multiSlaves = true;
  811. break;
  812. }
  813. }
  814. }
  815. }
  816. }
  817. setAttribute(pParentNode, "@localThor", localThor ? "true" : "false");
  818. }
  819. //---------------------------------------------------------------------------
  820. // AddNewNodes
  821. //---------------------------------------------------------------------------
  822. bool CConfigEnvHelper::AddNewNodes(IPropertyTree* pThor, const char* szType, int nPort, IPropertyTreePtrArray& computers, bool validate, bool skipExisting, StringBuffer& usageList)
  823. {
  824. // Get parent node
  825. IPropertyTree* pParentNode = pThor;
  826. if (validate)
  827. {
  828. for (int i = 0; i < (int) computers.size(); i++)
  829. CheckTopologyComputerUse(computers[i], pThor, usageList);
  830. }
  831. if (usageList.length() > 0)
  832. return false;
  833. // Iterate through computer list
  834. for (int i = 0; i < (int) computers.size(); i++)
  835. {
  836. // Check if we can add this computer
  837. if (skipExisting && !CheckTopologyComputerUse(computers[i], pThor, usageList))
  838. continue;
  839. StringBuffer sName;
  840. StringBuffer sThorMasterProcess;
  841. sThorMasterProcess.appendf("./%s", XML_TAG_THORMASTERPROCESS);
  842. sName.appendf("temp%d", i + 1);
  843. IPropertyTree *pTree = (szType == NULL || strcmp(szType, XML_TAG_THORMASTERPROCESS) != 0) ? NULL : pThor->queryPropTree(sThorMasterProcess.str());
  844. bool bAdd = false;
  845. if (pTree == NULL)
  846. {
  847. bAdd = true;
  848. pTree = createPTree(szType);
  849. }
  850. pTree->setProp(XML_ATTR_NAME,sName);
  851. pTree->setProp(XML_ATTR_COMPUTER, computers[i]->queryProp(XML_ATTR_NAME));
  852. if (nPort != 0)
  853. pTree->setPropInt(XML_ATTR_PORT, nPort);
  854. if (bAdd == true)
  855. addNode(pTree, pThor);
  856. }
  857. RenameThorInstances(pThor);
  858. UpdateThorAttributes(pThor);
  859. return true;
  860. }
  861. bool CConfigEnvHelper::CheckTopologyComputerUse(IPropertyTree* pComputerNode, IPropertyTree* pParentNode, StringBuffer& usageList) const
  862. {
  863. const char* szNetAddress = pComputerNode->queryProp(XML_ATTR_NETADDRESS);
  864. bool retVal = true;
  865. StringArray sElementTypes;
  866. StringBuffer xpath;
  867. Owned<IPropertyTreeIterator> iter = pParentNode->getElements("*");
  868. for (iter->first(); iter->isValid(); iter->next())
  869. {
  870. const char* szTag = iter->query().queryName();
  871. if (sElementTypes.find(szTag) == NotFound)
  872. {
  873. IPropertyTree* pTree = &iter->query();
  874. const char* pszComputer = pTree->queryProp(XML_ATTR_COMPUTER);
  875. xpath.clear().appendf(XML_TAG_HARDWARE "/" XML_TAG_COMPUTER "[" XML_ATTR_NAME "='%s']", pszComputer);
  876. IPropertyTree* pComputer = m_pRoot->queryPropTree(xpath.str());
  877. const char* szNetAddress1 = pComputer?pComputer->queryProp(XML_ATTR_NETADDRESS):NULL;
  878. if (szNetAddress1 && strcmp(szNetAddress1, szNetAddress)==0)
  879. {
  880. usageList.appendf("\n%s:%s - %s",
  881. pComputerNode->queryProp(XML_ATTR_NAME),
  882. pComputerNode->queryProp(XML_ATTR_NETADDRESS),
  883. szTag);
  884. // Save the found type and suppress warnings for those types
  885. sElementTypes.append(szTag);
  886. retVal = false;
  887. }
  888. }
  889. }
  890. return retVal;
  891. }
  892. //---------------------------------------------------------------------------
  893. // GetProcessNode
  894. //---------------------------------------------------------------------------
  895. IPropertyTree* CConfigEnvHelper::GetProcessNode(IPropertyTree* pThor, const char* szProcess) const
  896. {
  897. if (szProcess && *szProcess)
  898. {
  899. Owned<IPropertyTreeIterator> iter = pThor->getElements("*");
  900. ForEach(*iter)
  901. {
  902. const char* szName = iter->query().queryProp(XML_ATTR_NAME);
  903. if (szName && strcmp(szName, szProcess) == 0)
  904. return &iter->query();
  905. }
  906. }
  907. return NULL;
  908. }