configenvhelper.cpp 38 KB

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