configenvhelper.cpp 48 KB

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