SWProcess.cpp 18 KB

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