computerpicker.cpp 15 KB

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