computerpicker.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. /////////////////////////////////////////////////////////////////////////////
  15. //
  16. // ComputerPicker.cpp : implementation file
  17. //
  18. /////////////////////////////////////////////////////////////////////////////
  19. #include "computerpicker.hpp"
  20. #include "XMLTags.h"
  21. /*static*/MapStrToChar CComputerPicker::s_prefixMap;
  22. //---------------------------------------------------------------------------
  23. // CComputerPicker
  24. //---------------------------------------------------------------------------
  25. CComputerPicker::CComputerPicker()
  26. {
  27. if (s_prefixMap.empty())
  28. CreateComponentTypePrefixMap();
  29. }
  30. CComputerPicker::~CComputerPicker()
  31. {
  32. }
  33. //---------------------------------------------------------------------------
  34. // SetRootNode
  35. //---------------------------------------------------------------------------
  36. void CComputerPicker::SetRootNode(const IPropertyTree* pNode)
  37. {
  38. m_pRootNode = pNode;
  39. CreateComputerFilterTree();
  40. Refresh();
  41. }
  42. //generate a map containing unique prefix char based on component types, which can either
  43. //be process names, "Domain", "ComputerType" or "Subnet".
  44. //
  45. /*static*/
  46. void CComputerPicker::CreateComponentTypePrefixMap()
  47. {
  48. s_prefixMap["RoxieCluster" ] = 'C';
  49. s_prefixMap["DaliServerProcess"] = 'D';
  50. s_prefixMap["EspProcess" ] = 'E';
  51. s_prefixMap["HoleCluster" ] = 'H';
  52. s_prefixMap["LDAPServerProcess"] = 'L';
  53. s_prefixMap["PluginProcess" ] = 'P';
  54. s_prefixMap["SpareProcess" ] = 'S';
  55. s_prefixMap["ThorCluster" ] = 'T';
  56. s_prefixMap["DfuServerProcess" ] = 'U';
  57. s_prefixMap["SybaseProcess" ] = 'Y';
  58. s_prefixMap["EclAgentProcess" ] = 'a';
  59. s_prefixMap["EclServerProcess" ] = 'c';
  60. s_prefixMap["Domain" ] = 'd';
  61. s_prefixMap["ComputerType" ] = 'e';
  62. s_prefixMap["FTSlaveProcess" ] = 'f';
  63. s_prefixMap["EspService" ] = 's';
  64. s_prefixMap["Topology" ] = 't';
  65. s_prefixMap["Subnet" ] = 'u';
  66. }
  67. //returns a unique prefix char based on a component type, which can either
  68. //be a process name, "Domain", "ComputerType" or "Subnet".
  69. //
  70. /*static*/
  71. char CComputerPicker::GetPrefixForComponentType(const char* componType)
  72. {
  73. char prefix = ' ';
  74. MapStrToChar::const_iterator i = s_prefixMap.find(componType);
  75. if (i != s_prefixMap.end())
  76. prefix = (*i).second;
  77. return prefix;
  78. }
  79. const char* CComputerPicker::GetComponentTypeForPrefix(char chPrefix)
  80. {
  81. const char* szCompType = "";
  82. //this is inefficient and should be replaced by another map from prefix
  83. //to component type. However, this is only used for tooltip where time
  84. //is not an issue.
  85. MapStrToChar::const_iterator i = s_prefixMap.begin();
  86. MapStrToChar::const_iterator iEnd = s_prefixMap.end();
  87. for (; i != iEnd; i++)
  88. if ((*i).second == chPrefix)
  89. {
  90. szCompType = (*i).first.c_str();
  91. break;
  92. }
  93. return szCompType;
  94. }
  95. //---------------------------------------------------------------------------
  96. // ResetUsageMap
  97. //---------------------------------------------------------------------------
  98. void CComputerPicker::ResetUsageMap()
  99. {
  100. MapStrToStrArray::iterator i = m_usageMap.begin();
  101. MapStrToStrArray::iterator iEnd = m_usageMap.end();
  102. //empty all vectors keyed by all computers
  103. for (; i != iEnd; i++)
  104. {
  105. stringarray& usage = (*i).second;
  106. stringarray::iterator i2 = usage.begin();
  107. stringarray::iterator iEnd2 = usage.end();
  108. for (; i2 != iEnd2; i2++)
  109. {
  110. std::string& component = *i2;
  111. const char* szComponent = component.c_str();
  112. if (szComponent && *szComponent != '+')
  113. component[0] = '+';
  114. }
  115. }
  116. }
  117. bool CComputerPicker::GetUsage(const char* szComputer, StringBuffer& sUsage,
  118. bool bIncludeComponentType) const
  119. {
  120. MapStrToStrArray::const_iterator iUsage = m_usageMap.find(szComputer);
  121. bool bInclude = false;//computer isn't explicitly requested for by the user
  122. bool bExclude = false;//computer isn't explicitly excluded by the user
  123. if (iUsage != m_usageMap.end())
  124. {
  125. const stringarray& usage = (*iUsage).second;
  126. stringarray::const_iterator i2 = usage.begin();
  127. stringarray::const_iterator iEnd2 = usage.end();
  128. for (; i2 != iEnd2; i2++)
  129. {
  130. const std::string& component = *i2;
  131. const char* szComponent = component.c_str();
  132. if (szComponent)
  133. {
  134. char chStatus = *szComponent++;
  135. if (chStatus == 'I')
  136. bInclude = true;
  137. else
  138. if (chStatus == '-')
  139. bExclude = true;
  140. char chPrefix = *szComponent++;
  141. //gather usage anyway even for excluded components
  142. //since that needs to be shown in case another component
  143. //has explicitly asked this computer to be included
  144. //don't show usage info for domains, computer types and subnets
  145. if (chPrefix != 'd' && chPrefix != 'e' && chPrefix != 'u')
  146. {
  147. //if (!sUsage.IsEmpty())
  148. if (sUsage.length() > 0)
  149. sUsage.append(bIncludeComponentType ? '\n' : ' ');
  150. if (bIncludeComponentType)
  151. {
  152. StringBuffer sType = GetComponentTypeForPrefix(chPrefix);
  153. //if (!sType.IsEmpty())
  154. if (sUsage.length() > 0)
  155. {
  156. sUsage.append(sType);
  157. sUsage.append(" - ");
  158. }
  159. }
  160. sUsage.append(szComponent); //skip status and prefix characters
  161. }
  162. }
  163. }
  164. //if this computer has to be excluded because of some component and
  165. //then don't use it unless it is explicitly included by the user
  166. //for another
  167. if (bExclude && bInclude)
  168. bExclude = false;
  169. }
  170. return !bExclude;
  171. }
  172. //---------------------------------------------------------------------------
  173. // NoteUsage
  174. //---------------------------------------------------------------------------
  175. void CComputerPicker::NoteUsage(const char *computer, const char* componType,
  176. const char *name, char status/*='+'*/)
  177. {
  178. if (computer && *computer && componType && *componType && name && *name)
  179. {
  180. stringarray& usage = m_usageMap[computer];
  181. std::string sName;
  182. sName += status;
  183. sName += GetPrefixForComponentType(componType);
  184. sName += name;
  185. name = sName.c_str() + 1; //skip status
  186. //insert this entry in the array if not present already
  187. stringarray::iterator i = usage.begin();
  188. stringarray::iterator iEnd = usage.end();
  189. for (; i != iEnd; i++)
  190. {
  191. std::string& component = *i;
  192. const char* szCompName = component.c_str();
  193. if (szCompName && *szCompName && !strcmp(szCompName+1, name))
  194. {
  195. if (status != '-' || *szCompName != 'I')//don't mark unused if status is 'I'
  196. component[0] = status;
  197. break;
  198. }
  199. }
  200. if (i == iEnd)
  201. usage.push_back(sName);
  202. }
  203. }
  204. //---------------------------------------------------------------------------
  205. // CreateFilterTree
  206. //---------------------------------------------------------------------------
  207. void CComputerPicker::CreateComputerFilterTree()
  208. {
  209. m_pFilterTree.clear();
  210. m_pFilterTree.setown(createPTree("Filter"));
  211. IPropertyTree* pComponents= m_pFilterTree->addPropTree("Components", createPTree("Components"));
  212. IPropertyTree* pDomains = m_pFilterTree->addPropTree("Domains", createPTree("Domains"));
  213. IPropertyTree* pCompTypes = m_pFilterTree->addPropTree("ComputerTypes", createPTree("ComputerTypes"));
  214. IPropertyTree* pSubnets = m_pFilterTree->addPropTree("Subnets", createPTree("Subnets"));
  215. // Generate computer usage map
  216. if (m_pRootNode)
  217. {
  218. //collect all software components using any computers
  219. Owned<IPropertyTreeIterator> iter = m_pRootNode->getElements("Software/*");
  220. ForEach(*iter)
  221. {
  222. IPropertyTree &component = iter->query();
  223. const char* szProcessName = component.queryName();
  224. const char* szCompName = component.queryProp(XML_ATTR_NAME);
  225. const bool bThorCluster = strcmp(szProcessName, "ThorCluster")==0;
  226. if (bThorCluster || strcmp(szProcessName, "HoleCluster")==0 || strcmp(szProcessName, "RoxieCluster")==0)
  227. {
  228. Owned<IPropertyTreeIterator> instance = component.getElements("*[@computer]");
  229. ForEach(*instance)
  230. {
  231. const char* szComputer = instance->query().queryProp("@computer");
  232. NoteFilter(pComponents, szProcessName, szCompName, szComputer);
  233. NoteUsage(szComputer, szProcessName, szCompName);
  234. }
  235. }
  236. else
  237. {
  238. Owned<IPropertyTreeIterator> instance = component.getElements("Instance");
  239. ForEach(*instance)
  240. {
  241. const char* szComputer = instance->query().queryProp("@computer");
  242. NoteFilter(pComponents, szProcessName, szCompName, szComputer);
  243. NoteUsage(szComputer, szProcessName, szCompName);
  244. }
  245. const char* szComputer = component.queryProp("@computer");
  246. if (szComputer)
  247. {
  248. NoteFilter(pComponents, szProcessName, szCompName, szComputer);
  249. NoteUsage(szComputer, szProcessName, szCompName);
  250. }
  251. //if this is a dali server then get backup computer, if any
  252. if (strcmp(szProcessName, "DaliServerProcess")==0)
  253. {
  254. const char* szBackupComputer = component.queryProp("@backupComputer");
  255. NoteFilter(pComponents, szProcessName, szCompName, szBackupComputer);
  256. NoteUsage(szBackupComputer, szProcessName, szCompName);
  257. }
  258. }
  259. }
  260. iter.setown(m_pRootNode->getElements("Hardware/Domain"));
  261. ForEach(*iter)
  262. {
  263. const char* szDomain = iter->query().queryProp(XML_ATTR_NAME);
  264. StringBuffer xPath;
  265. xPath.appendf("Hardware/Computer[@domain='%s']", szDomain);
  266. //enumerate all computers in this domain
  267. Owned<IPropertyTreeIterator> icomputer = m_pRootNode->getElements(xPath);
  268. ForEach(*icomputer)
  269. {
  270. const char* szComputer = icomputer->query().queryProp("@name");
  271. NoteFilter(pDomains, "Domain", szDomain, szComputer);
  272. NoteUsage(szComputer, "Domain", szDomain);
  273. }
  274. }
  275. iter.setown(m_pRootNode->getElements("Hardware/ComputerType"));
  276. ForEach(*iter)
  277. {
  278. const char* szComputerType = iter->query().queryProp(XML_ATTR_NAME);
  279. StringBuffer xPath;
  280. xPath.appendf("Hardware/Computer[@computerType='%s']", szComputerType);
  281. //enumerate all computers with this computer type
  282. Owned<IPropertyTreeIterator> icomputer = m_pRootNode->getElements(xPath);
  283. ForEach(*icomputer)
  284. {
  285. const char* szComputer = icomputer->query().queryProp("@name");
  286. NoteFilter(pCompTypes, "ComputerType", szComputerType, szComputer);
  287. NoteUsage(szComputer, "ComputerType", szComputerType);
  288. }
  289. }
  290. //enumerate all computers and process their subnets
  291. Owned<IPropertyTreeIterator> icomputer = m_pRootNode->getElements("Hardware/Computer");
  292. ForEach(*icomputer)
  293. {
  294. IPropertyTree* pComputer = &icomputer->query();
  295. const char* szComputer = pComputer->queryProp("@name");
  296. const char* szNetAddress = pComputer->queryProp("@netAddress");
  297. if (szComputer && *szComputer && szNetAddress && *szNetAddress)
  298. {
  299. char szSubnet[128];
  300. strcpy(szSubnet, szNetAddress);
  301. char* pchDot = strrchr(szSubnet, '.');
  302. if (pchDot)
  303. {
  304. strcpy(pchDot+1, "0");
  305. //TRACE3("%s(%s)=> %s\n", szComputer, pComputer->queryProp("@netAddress"), szSubnet);
  306. NoteFilter(pSubnets, "Subnet", szSubnet, szComputer);
  307. NoteUsage(szComputer, "Subnet", szSubnet);
  308. }
  309. }
  310. }
  311. }
  312. }
  313. //---------------------------------------------------------------------------
  314. // NoteFilter
  315. //---------------------------------------------------------------------------
  316. void CComputerPicker::NoteFilter(IPropertyTree* pFilter, const char *componentType,
  317. const char *component, const char* computer)
  318. {
  319. if (component && *component &&
  320. componentType && *componentType)
  321. {
  322. StringBuffer sComponentType(componentType);
  323. const char* psz = strstr(sComponentType.str(), "Process");
  324. if (psz)
  325. sComponentType.remove(psz - sComponentType.str(), strlen("Process"));
  326. StringBuffer xPath;
  327. xPath.appendf("%s[@name='%s']", sComponentType.str(), component);
  328. IPropertyTree* pComponentType = pFilter->queryPropTree(xPath);
  329. if (!pComponentType)
  330. {
  331. pComponentType = pFilter->addPropTree(sComponentType, createPTree(sComponentType));
  332. pComponentType->addProp("@name", component);
  333. }
  334. if (computer && *computer)
  335. {
  336. IPropertyTree* pComputer = pComponentType->addPropTree( "Computer", createPTree() );
  337. pComputer->addProp("@name", computer);
  338. pComputer->addPropBool("@__bHidden", true);
  339. }
  340. }
  341. }
  342. void CComputerPicker::Refresh()
  343. {
  344. // Passed all filters so add the computers left in the usage map
  345. int iItem = 0;
  346. m_pComputerTree.clear();
  347. m_pComputerTree.setown(createPTree("ComputerList"));
  348. Owned<IPropertyTreeIterator> iComputer = m_pRootNode->getElements(XML_TAG_HARDWARE"/"XML_TAG_COMPUTER);
  349. ForEach (*iComputer)
  350. {
  351. // Must have a valid name
  352. IPropertyTree* pNode = &iComputer->query();
  353. const char* szComputer = pNode->queryProp(XML_ATTR_NAME);
  354. StringBuffer sUsage;
  355. if (szComputer && *szComputer && GetUsage(szComputer, sUsage, false))
  356. {
  357. IPropertyTree* pComponentType = m_pComputerTree->addPropTree("Machine", createPTree("Machine"));
  358. pComponentType->addProp("@name", szComputer);
  359. pComponentType->addProp("@netAddress", pNode->queryProp(XML_ATTR_NETADDRESS));
  360. pComponentType->addProp("@usage", sUsage.str());
  361. }
  362. }
  363. }
  364. void CComputerPicker::ApplyFilter(const char* szSubTreeName,
  365. const char* szIncAttrib,
  366. char chStatus,
  367. StringBuffer& sFilterApplied)
  368. {
  369. StringBuffer xPath;
  370. xPath.appendf("%s/*[@%s]", szSubTreeName, szIncAttrib);
  371. Owned<IPropertyTreeIterator> iter = m_pFilterTree->getElements(xPath);
  372. ForEach(*iter)
  373. {
  374. IPropertyTree* pComponent = &iter->query();
  375. const char* szCompType = pComponent->queryName();
  376. const char* szCompName = pComponent->queryProp("@name");
  377. if (sFilterApplied.length() > 0)
  378. sFilterApplied.append(", ");
  379. sFilterApplied.append(szCompName);
  380. Owned<IPropertyTreeIterator> icomputer = pComponent->getElements("Computer[@name]");
  381. ForEach(*icomputer)
  382. {
  383. const char* szComputer = icomputer->query().queryProp("@name");
  384. if (szComputer)
  385. NoteUsage(szComputer, szCompType, szCompName, chStatus);
  386. }
  387. }
  388. }