configenvhelper.cpp 43 KB

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