configenvhelper.cpp 37 KB

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