configenvhelper.cpp 47 KB

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