configenvhelper.cpp 46 KB

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