configenvhelper.cpp 36 KB

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