configenvhelper.cpp 52 KB

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