SWProcess.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2018 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 "SWProcess.hpp"
  14. #include "deployutils.hpp"
  15. #include "configenvhelper.hpp"
  16. #include "buildset.hpp"
  17. #include "Hardware.hpp"
  18. namespace ech
  19. {
  20. SWProcess::SWProcess(const char* name, EnvHelper * envHelper):SWComponentBase(name, envHelper)
  21. {
  22. m_instanceElemName.clear().append("Instance");
  23. m_ipAttribute.clear().append("@netAddress");
  24. m_notifyTopologyList.append("eclagent");
  25. m_notifyTopologyList.append("eclccserver");
  26. m_notifyTopologyList.append("eclscheduler");
  27. m_notifyTopologyList.append("esp");
  28. m_notifyTopologyList.append("thor");
  29. m_notifyTopologyList.append("roxie");
  30. m_singleInstanceList.append("dali");
  31. }
  32. IPropertyTree * SWProcess::addComponent(IPropertyTree *params)
  33. {
  34. IPropertyTree * pCompTree;
  35. const char* clone = params->queryProp("@clone");
  36. if (clone)
  37. {
  38. pCompTree = SWComponentBase::cloneComponent(params);
  39. }
  40. else
  41. {
  42. pCompTree = SWComponentBase::addComponent(params);
  43. if (pCompTree->hasProp("@daliServers") && !strcmp(pCompTree->queryProp("@daliServers"), ""))
  44. {
  45. IPropertyTree * envTree = m_envHelper->getEnvTree();
  46. StringBuffer xpath;
  47. xpath.clear().appendf(XML_TAG_SOFTWARE "/DaliServerProcess/@name");
  48. const char *daliName = envTree->queryProp(xpath.str());
  49. if (daliName)
  50. {
  51. pCompTree->setProp("@daliServers", daliName);
  52. }
  53. }
  54. }
  55. removeInstancesFromComponent(pCompTree);
  56. return pCompTree;
  57. }
  58. void SWProcess::create(IPropertyTree *params)
  59. {
  60. SWComponentBase::create(params);
  61. IPropertyTree * envTree = m_envHelper->getEnvTree();
  62. StringBuffer xpath;
  63. xpath.clear().appendf(XML_TAG_SOFTWARE "/%s[@name=\"my%s\"]", m_processName.str(), m_name.str());
  64. IPropertyTree * pCompTree = envTree->queryPropTree(xpath.str());
  65. assert(pCompTree);
  66. //create instance
  67. }
  68. unsigned SWProcess::add(IPropertyTree *params)
  69. {
  70. unsigned rc = SWComponentBase::add(params);
  71. IPropertyTree * envTree = m_envHelper->getEnvTree();
  72. const char* key = params->queryProp("@key");
  73. StringBuffer xpath;
  74. xpath.clear().appendf(XML_TAG_SOFTWARE "/%s[@name=\"%s\"]", m_processName.str(), key);
  75. IPropertyTree * compTree = envTree->queryPropTree(xpath.str());
  76. assert(compTree);
  77. const char* selector = params->queryProp("@selector");
  78. if (selector)
  79. {
  80. String str(selector);
  81. if (str.startsWith("instance"))
  82. {
  83. addInstances(compTree, params);
  84. }
  85. else
  86. {
  87. // Following method can be overwritten.
  88. // For example, NodeGroup in BackupNodeProcess, EspBinding in EspProcess
  89. addOtherSelector(compTree, params);
  90. }
  91. }
  92. else
  93. {
  94. IPropertyTree* pAttrs = params->queryPropTree("Attributes");
  95. updateNode(compTree, pAttrs);
  96. }
  97. return rc;
  98. }
  99. void SWProcess::addOtherSelector(IPropertyTree *compTree, IPropertyTree *params)
  100. {
  101. const char* selector = params->queryProp("@selector");
  102. IPropertyTree* selectorTree = compTree->queryPropTree(selector);
  103. if (!selectorTree)
  104. {
  105. selectorTree = createPTree(selector);
  106. compTree->addPropTree(selector, selectorTree);
  107. }
  108. IPropertyTree* pAttrs = params->queryPropTree("Attributes");
  109. if (pAttrs)
  110. updateNode(selectorTree, pAttrs);
  111. }
  112. //int SWProcess::addNode(IPropertyTree *params, const char* xpath, bool merge)
  113. //{
  114. // return 0;
  115. //}
  116. void SWProcess::modify(IPropertyTree *params)
  117. {
  118. SWComponentBase::modify(params);
  119. const char * selector = params->queryProp("@selector");
  120. if ( selector )
  121. {
  122. IPropertyTree * envTree = m_envHelper->getEnvTree();
  123. const char* key = params->queryProp("@key");
  124. StringBuffer xpath;
  125. xpath.clear().appendf(XML_TAG_SOFTWARE "/%s[@name=\"%s\"]", m_processName.str(), key);
  126. IPropertyTree * compTree = envTree->queryPropTree(xpath.str());
  127. if (!compTree)
  128. throw MakeStringException(CfgEnvErrorCode::InvalidParams, "Selector should matche one element in modify.");
  129. String str(selector);
  130. if (str.startsWith("instance"))
  131. modifyInstance(compTree, params);
  132. return;
  133. }
  134. if (!(params->queryPropTree("Attributes/Attribute[@name=\"name\"]"))) return;
  135. //notify topoploy for component name change
  136. const char *oldName = params->queryProp("@key");
  137. const char *newName = params->queryProp("Attributes/Attribute[@name=\"name\"]/@value");
  138. if (m_notifyTopologyList.find(m_name.str()) != NotFound)
  139. {
  140. ((SWProcess*)m_envHelper->getEnvSWComp("topology"))->processNameChanged(m_name.str(), newName, oldName);
  141. }
  142. }
  143. IConfigComp* SWProcess::getInstanceNetAddresses(StringArray& ipList, const char* clusterName)
  144. {
  145. IPropertyTree * envTree = m_envHelper->getEnvTree();
  146. StringBuffer xpath;
  147. if (clusterName)
  148. xpath.clear().appendf(XML_TAG_SOFTWARE "/%s[@name=\"%s\"]", m_processName.str(), clusterName);
  149. else
  150. xpath.clear().appendf(XML_TAG_SOFTWARE "/%s[1]", m_processName.str());
  151. IPropertyTree *compTree = envTree->queryPropTree(xpath.str());
  152. Owned<IPropertyTreeIterator> iter = compTree->getElements(m_instanceElemName.str());
  153. ForEach (*iter)
  154. {
  155. IPropertyTree *instance = &iter->query();
  156. ipList.append(instance->queryProp("@netAddress"));
  157. }
  158. return (IConfigComp*)this;
  159. }
  160. unsigned SWProcess::getInstanceCount(const char* clusterName)
  161. {
  162. StringBuffer xpath;
  163. if (clusterName && *clusterName)
  164. xpath.clear().appendf("%s[@name=\"%s\"]", m_processName.str(), clusterName);
  165. else
  166. xpath.clear().appendf("%s[1]", m_processName.str());
  167. //IPropertyTree * comp = m_envHelper->getEnvTree()->getPropTree(xpath);
  168. IPropertyTree * comp = m_envHelper->getEnvTree()->queryPropTree(xpath);
  169. return comp->getCount(m_instanceElemName.str());
  170. }
  171. void SWProcess::addInstances(IPropertyTree *parent, IPropertyTree *params)
  172. {
  173. IPropertyTree* pAttrs = params->queryPropTree("Attributes");
  174. if (!pAttrs)
  175. throw MakeStringException(CfgEnvErrorCode::InvalidParams, "Miss instance attributes input");
  176. const char * instanceXMLTagName = getInstanceXMLTagName(params->queryProp("@selector"));
  177. Owned<IPropertyTreeIterator> iter = pAttrs->getElements("Attribute");
  178. ForEach (*iter)
  179. {
  180. IPropertyTree *attr = &iter->query();
  181. const char* propName = attr->queryProp("@name");
  182. if (!stricmp(propName, "ip") || !stricmp(propName, "ipfile"))
  183. {
  184. bool isFile = false;
  185. if (!stricmp(propName, "ipfile")) isFile = true;
  186. StringArray ips;
  187. m_envHelper->processNodeAddress(attr->queryProp("@value"), ips, isFile);
  188. for ( unsigned i = 0; i < ips.ordinality() ; i++)
  189. {
  190. IPropertyTree * computerNode = addComputer(ips.item(i));
  191. addInstance(computerNode, parent, pAttrs, instanceXMLTagName);
  192. }
  193. }
  194. }
  195. }
  196. IPropertyTree * SWProcess::addComputer(const char* ip)
  197. {
  198. Hardware *hd = (Hardware*) m_envHelper->getEnvComp("hardware");
  199. StringBuffer sbTask;
  200. sbTask.clear().append("<Task operation=\"add\" category=\"hardware\" component=\"Computer\">");
  201. sbTask.appendf("<Attributes><Attribute name=\"ip\" value=\"%s\"/></Attributes></Task>", ip);
  202. Owned<IPropertyTree> params = createPTreeFromXMLString(sbTask.str());
  203. IPropertyTree * pComputer = hd->addComputer(params);
  204. return pComputer;
  205. }
  206. void SWProcess::addInstance(IPropertyTree *computerNode, IPropertyTree *parent, IPropertyTree *attrs, const char* instanceXMLTagName)
  207. {
  208. IPropertyTree *instanceNode = NULL;
  209. StringBuffer xpath;
  210. if (m_singleInstanceList.find(m_name.str()) != NotFound)
  211. {
  212. xpath.clear().appendf("%s[1]", instanceXMLTagName);
  213. instanceNode = parent->queryPropTree(xpath.str());
  214. }
  215. else
  216. {
  217. instanceNode = findInstance(parent, computerNode);
  218. }
  219. if (!instanceNode)
  220. {
  221. // create instance
  222. instanceNode = createPTree(instanceXMLTagName);
  223. instanceNode->addProp("@computer", computerNode->queryProp(XML_ATTR_NAME));
  224. // get unique name
  225. StringBuffer sbName;
  226. if (String(instanceXMLTagName).indexOf("Master") > 0)
  227. sbName.append("m");
  228. else
  229. sbName.append("s");
  230. instanceNode->addProp(XML_ATTR_NAME, getUniqueName(parent, sbName, instanceXMLTagName, ""));
  231. instanceNode->addProp(m_ipAttribute.str(), computerNode->queryProp(XML_ATTR_NETADDRESS));
  232. parent->addPropTree(instanceXMLTagName, instanceNode);
  233. }
  234. StringArray excludeList;
  235. excludeList.append("ip");
  236. excludeList.append("ipfile");
  237. if (attrs)
  238. updateNode(instanceNode, attrs, &excludeList);
  239. checkInstanceAttributes(instanceNode, parent);
  240. }
  241. void SWProcess::modifyInstance(IPropertyTree *parent, IPropertyTree *params)
  242. {
  243. IPropertyTree* pAttrs = params->queryPropTree("Attributes");
  244. if (!pAttrs)
  245. throw MakeStringException(CfgEnvErrorCode::InvalidParams, "Miss instance attributes input");
  246. const char * instanceXMLTagName = getInstanceXMLTagName(pAttrs->queryProp("@selector"));
  247. Owned<IPropertyTreeIterator> iter = pAttrs->getElements("Attribute");
  248. ForEach (*iter)
  249. {
  250. IPropertyTree *attr = &iter->query();
  251. const char* propName = attr->queryProp("@name");
  252. if (stricmp(propName, "ip"))
  253. continue;
  254. StringBuffer xpath;
  255. IPropertyTree *instanceToModify;
  256. const char* oldIp = attr->queryProp("@oldValue");
  257. if ((!oldIp || !(*oldIp)) && m_singleInstanceList.find(m_name.str()) == NotFound)
  258. throw MakeStringException(CfgEnvErrorCode::InvalidParams, "Miss instance current ip to change");
  259. else if (oldIp && *oldIp)
  260. {
  261. xpath.clear().appendf("%s[%s=\"%s\"]", instanceXMLTagName, m_ipAttribute.str(), oldIp);
  262. instanceToModify = parent->queryPropTree(xpath.str());
  263. }
  264. else
  265. {
  266. xpath.clear().appendf("%s[1]", instanceXMLTagName);
  267. instanceToModify = parent->queryPropTree(xpath.str());
  268. }
  269. if (!instanceToModify)
  270. throw MakeStringException(CfgEnvErrorCode::InvalidParams, "Cannot find instance node to modify");
  271. IPropertyTree * computerNode = addComputer(attr->queryProp("@value"));
  272. instanceToModify->setProp("@computer", computerNode->queryProp(XML_ATTR_NAME));
  273. instanceToModify->setProp(m_ipAttribute.str(), computerNode->queryProp(XML_ATTR_NETADDRESS));
  274. }
  275. }
  276. void SWProcess::checkInstanceAttributes(IPropertyTree *instanceNode, IPropertyTree *parent)
  277. {
  278. assert(instanceNode);
  279. if (portIsRequired() && !instanceNode->hasProp("@port"))
  280. {
  281. int port = getDefaultPort();
  282. if (!port)
  283. throw MakeStringException(CfgEnvErrorCode::InvalidParams, "Miss port attribute in instance");
  284. instanceNode->addPropInt("@port", port);
  285. }
  286. StringBuffer xpath;
  287. xpath.clear().appendf("xs:element/xs:complexType/xs:sequence/xs:element[@name=\"%s\"]",m_instanceElemName.str());
  288. IPropertyTree * instanceSchemaNode = m_pSchema->queryPropTree(xpath.str());
  289. if (!instanceSchemaNode) return;
  290. bool needDirProp = false;
  291. Owned<IPropertyTreeIterator> attrIter = instanceSchemaNode->getElements("xs:complexType/xs:attribute");
  292. ForEach(*attrIter)
  293. {
  294. IPropertyTree * attr = &attrIter->query();
  295. const char *attrName = attr->queryProp("@name");
  296. if (!stricmp(attrName, "directory"))
  297. {
  298. needDirProp = true;
  299. continue;
  300. }
  301. const char *defaultValue = attr->queryProp("@default");
  302. if (!defaultValue) continue;
  303. xpath.clear().appendf("@%s", attrName);
  304. if (instanceNode->hasProp(xpath.str())) continue;
  305. const char *use = attr->queryProp("@use");
  306. if (!use || !stricmp(use, "required") || !stricmp(use, "optional"))
  307. {
  308. StringBuffer sbDefaultValue;
  309. sbDefaultValue.clear().append(defaultValue);
  310. sbDefaultValue.replaceString("\\", "\\\\");
  311. instanceNode->addProp(xpath.str(), sbDefaultValue.str());
  312. }
  313. }
  314. if (needDirProp && !instanceNode->hasProp("@directory"))
  315. {
  316. const IProperties *props = m_envHelper->getEnvConfigOptions().getProperties();
  317. StringBuffer sb;
  318. sb.clear().appendf("%s/%s",
  319. props->queryProp("runtime"), parent->queryProp(XML_ATTR_NAME));
  320. instanceNode->addProp("@directory", sb.str());
  321. }
  322. }
  323. void SWProcess::computerAdded(IPropertyTree *computerNode, const char *instanceXMLTagName)
  324. {
  325. StringBuffer sb;
  326. sb.clear().appendf("%s/%s[1]", XML_TAG_SOFTWARE, m_processName.str());
  327. IPropertyTree * comp = m_envHelper->getEnvTree()->queryPropTree(sb.str());
  328. assert(comp);
  329. const char *instance = (instanceXMLTagName)? instanceXMLTagName: m_instanceElemName.str();
  330. addInstance(computerNode, comp, NULL, instance);
  331. }
  332. void SWProcess::computerUpdated(IPropertyTree *computerNode, const char* oldName,
  333. const char* oldIp, const char* instanceXMLTagName)
  334. {
  335. IPropertyTree *software = m_envHelper->getEnvTree()->queryPropTree("Software");
  336. Owned<IPropertyTreeIterator> compIter = software->getElements(m_processName);
  337. const char *instance = (instanceXMLTagName)? instanceXMLTagName: m_instanceElemName.str();
  338. synchronized block(mutex);
  339. ForEach (*compIter)
  340. {
  341. IPropertyTree *comp = &compIter->query();
  342. Owned<IPropertyTreeIterator> instanceIter = comp->getElements(instance);
  343. ForEach (*instanceIter)
  344. {
  345. IPropertyTree *instance = &instanceIter->query();
  346. if (instance->hasProp(XML_ATTR_NAME) && !stricmp(instance->queryProp(XML_ATTR_NAME), oldName))
  347. {
  348. if (stricmp(computerNode->queryProp(XML_ATTR_NAME), instance->queryProp(XML_ATTR_NAME)))
  349. instance->setProp(XML_ATTR_NAME, computerNode->queryProp(XML_ATTR_NAME));
  350. if (instance->hasProp(m_ipAttribute.str()) && stricmp(computerNode->queryProp(XML_ATTR_NETADDRESS), instance->queryProp(m_ipAttribute.str())))
  351. instance->setProp(m_ipAttribute.str(), computerNode->queryProp(XML_ATTR_NETADDRESS));
  352. if (instance->hasProp("@computer") && stricmp(computerNode->queryProp(XML_ATTR_NAME), instance->queryProp("@computer")))
  353. instance->setProp("@computer", computerNode->queryProp(XML_ATTR_NAME));
  354. }
  355. else if (instance->hasProp(m_ipAttribute.str()) && !stricmp(instance->queryProp(m_ipAttribute.str()), oldIp))
  356. {
  357. instance->setProp(m_ipAttribute.str(), computerNode->queryProp(XML_ATTR_NETADDRESS));
  358. }
  359. }
  360. }
  361. }
  362. void SWProcess::computerDeleted(const char* ipAddress, const char* computerName, const char *instanceXMLTagName)
  363. {
  364. IPropertyTree * software = m_envHelper->getEnvTree()->queryPropTree(XML_TAG_SOFTWARE);
  365. Owned<IPropertyTreeIterator> compIter = software->getElements(m_processName);
  366. const char *instance = (instanceXMLTagName)? instanceXMLTagName: m_instanceElemName.str();
  367. synchronized block(mutex);
  368. ForEach (*compIter)
  369. {
  370. IPropertyTree * comp = &compIter->query();
  371. Owned<IPropertyTreeIterator> instanceIter = comp->getElements(instance);
  372. ForEach (*instanceIter)
  373. {
  374. IPropertyTree * instance = &instanceIter->query();
  375. if ((instance->hasProp(m_ipAttribute.str()) && stricmp(instance->queryProp(m_ipAttribute.str()), ipAddress)) ||
  376. (instance->hasProp("@computer") && stricmp(instance->queryProp("@computer"), computerName)))
  377. comp->removeTree(instance);
  378. }
  379. }
  380. }
  381. IPropertyTree * SWProcess::getPortDefinition()
  382. {
  383. StringBuffer xpath;
  384. xpath.clear().appendf("xs:element[@name=\"%s\"]", m_instanceElemName.str());
  385. IPropertyTree * instanceNode = m_pSchema->queryPropTree(xpath.str());
  386. if (!instanceNode) return NULL;
  387. xpath.clear().append("xs:attribute[@name=\"port\"]");
  388. return instanceNode->queryPropTree(xpath.str());
  389. }
  390. bool SWProcess::portIsRequired()
  391. {
  392. IPropertyTree * portAttrNode = getPortDefinition();
  393. if (!portAttrNode) return false;
  394. const char* portUseAttr = portAttrNode->queryProp("@use");
  395. if (portUseAttr && stricmp(portUseAttr, "required"))
  396. return false;
  397. return true;
  398. }
  399. int SWProcess::getDefaultPort()
  400. {
  401. IPropertyTree * portAttrNode = getPortDefinition();
  402. if (!portAttrNode) return 0;
  403. int defaultValue = portAttrNode->getPropInt("@default");
  404. if (!defaultValue) return 0;
  405. return defaultValue;
  406. }
  407. IPropertyTree * SWProcess::cloneComponent(IPropertyTree *params)
  408. {
  409. IPropertyTree * targetNode = SWComponentBase::cloneComponent(params);
  410. removeInstancesFromComponent(targetNode);
  411. return targetNode;
  412. }
  413. void SWProcess::processNameChanged(const char* process, const char *newName, const char* oldName)
  414. {
  415. StringBuffer xpath;
  416. xpath.clear().appendf("@%s", process);
  417. IPropertyTree * swTree = m_envHelper->getEnvTree()->queryPropTree("/Software");
  418. Owned<IPropertyTreeIterator> compIter = swTree->getElements(m_envHelper->getXMLTagName(m_name.str()));
  419. synchronized block(mutex);
  420. ForEach(*compIter)
  421. {
  422. IPropertyTree * compTree = &compIter->query();
  423. if ((oldName != NULL) && strcmp(oldName, compTree->queryProp(xpath.str())))
  424. continue;
  425. if (compTree->queryProp(xpath.str()))
  426. compTree->setProp(xpath.str(), newName);
  427. }
  428. }
  429. void SWProcess::resolveSelector(const char* selector, const char* key, StringBuffer &out)
  430. {
  431. String lwSelector(selector);
  432. if ((lwSelector.toLowerCase())->startsWith("instance"))
  433. out.clear().appendf("%s[@%s=\"%s\"]", m_instanceElemName.str(), m_ipAttribute.str(), key);
  434. else
  435. ComponentBase::resolveSelector(selector, key, out);
  436. }
  437. void SWProcess::removeInstancesFromComponent(IPropertyTree *compNode)
  438. {
  439. Owned<IPropertyTreeIterator> instanceIter = compNode->getElements(m_instanceElemName);
  440. ForEach(*instanceIter)
  441. {
  442. compNode->removeTree(&instanceIter->query());
  443. }
  444. }
  445. IPropertyTree * SWProcess::findInstance(IPropertyTree *comp, IPropertyTree *computerNode)
  446. {
  447. Owned<IPropertyTreeIterator> instanceIter = comp->getElements(m_instanceElemName);
  448. ForEach (*instanceIter)
  449. {
  450. IPropertyTree * instance = &instanceIter->query();
  451. if (!stricmp(instance->queryProp("@computer"), computerNode->queryProp(XML_ATTR_NAME)))
  452. return instance;
  453. }
  454. return NULL;
  455. }
  456. }