Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1924 lines
54 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1996-2000 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // Node.cpp
  7. //
  8. // Description:
  9. // Implementation of the CClusNode class.
  10. //
  11. // Maintained By:
  12. // David Potter (davidp) May 3, 1996
  13. //
  14. // Revision History:
  15. //
  16. // Notes:
  17. //
  18. /////////////////////////////////////////////////////////////////////////////
  19. #include "stdafx.h"
  20. #include "CluAdmin.h"
  21. #include "ConstDef.h"
  22. #include "Node.h"
  23. #include "ClusItem.inl"
  24. #include "NodeProp.h"
  25. #include "ExcOper.h"
  26. #include "TraceTag.h"
  27. #include "Cluster.h"
  28. #include "CASvc.h"
  29. #include "ResType.h"
  30. #ifdef _DEBUG
  31. #define new DEBUG_NEW
  32. #undef THIS_FILE
  33. static char THIS_FILE[] = __FILE__;
  34. #endif
  35. /////////////////////////////////////////////////////////////////////////////
  36. // Global Variables
  37. /////////////////////////////////////////////////////////////////////////////
  38. #ifdef _DEBUG
  39. CTraceTag g_tagNode(_T("Document"), _T("NODE"), 0);
  40. CTraceTag g_tagNodeDrag(_T("Drag&Drop"), _T("NODE DRAG"), 0);
  41. CTraceTag g_tagNodeNotify(_T("Notify"), _T("NODE NOTIFY"), 0);
  42. CTraceTag g_tagNodeRegNotify(_T("Notify"), _T("NODE REG NOTIFY"), 0);
  43. #endif
  44. /////////////////////////////////////////////////////////////////////////////
  45. // CClusterNode
  46. /////////////////////////////////////////////////////////////////////////////
  47. IMPLEMENT_DYNCREATE(CClusterNode, CClusterItem)
  48. /////////////////////////////////////////////////////////////////////////////
  49. // Message Maps
  50. /////////////////////////////////////////////////////////////////////////////
  51. BEGIN_MESSAGE_MAP(CClusterNode, CClusterItem)
  52. //{{AFX_MSG_MAP(CClusterNode)
  53. ON_UPDATE_COMMAND_UI(ID_FILE_PAUSE_NODE, OnUpdatePauseNode)
  54. ON_UPDATE_COMMAND_UI(ID_FILE_RESUME_NODE, OnUpdateResumeNode)
  55. ON_UPDATE_COMMAND_UI(ID_FILE_EVICT_NODE, OnUpdateEvictNode)
  56. ON_UPDATE_COMMAND_UI(ID_FILE_START_SERVICE, OnUpdateStartService)
  57. ON_UPDATE_COMMAND_UI(ID_FILE_STOP_SERVICE, OnUpdateStopService)
  58. ON_UPDATE_COMMAND_UI(ID_FILE_PROPERTIES, OnUpdateProperties)
  59. ON_COMMAND(ID_FILE_PAUSE_NODE, OnCmdPauseNode)
  60. ON_COMMAND(ID_FILE_RESUME_NODE, OnCmdResumeNode)
  61. ON_COMMAND(ID_FILE_EVICT_NODE, OnCmdEvictNode)
  62. ON_COMMAND(ID_FILE_START_SERVICE, OnCmdStartService)
  63. ON_COMMAND(ID_FILE_STOP_SERVICE, OnCmdStopService)
  64. //}}AFX_MSG_MAP
  65. END_MESSAGE_MAP()
  66. /////////////////////////////////////////////////////////////////////////////
  67. //++
  68. //
  69. // CClusterNode::CClusterNode
  70. //
  71. // Description:
  72. // Default constructor.
  73. //
  74. // Arguments:
  75. // None.
  76. //
  77. // Return Values:
  78. // None.
  79. //
  80. //--
  81. /////////////////////////////////////////////////////////////////////////////
  82. CClusterNode::CClusterNode(void) : CClusterItem(NULL, IDS_ITEMTYPE_NODE)
  83. {
  84. m_idmPopupMenu = IDM_NODE_POPUP;
  85. m_hnode = NULL;
  86. m_nNodeHighestVersion = 0;
  87. m_nNodeLowestVersion = 0;
  88. m_nMajorVersion = 0;
  89. m_nMinorVersion = 0;
  90. m_nBuildNumber = 0;
  91. m_plpcigrpOnline = NULL;
  92. m_plpciresOnline = NULL;
  93. m_plpciNetInterfaces = NULL;
  94. // Set the object type image.
  95. m_iimgObjectType = GetClusterAdminApp()->Iimg(IMGLI_NODE);
  96. // Setup the property array.
  97. {
  98. m_rgProps[epropName].Set(CLUSREG_NAME_NODE_NAME, m_strName, m_strName);
  99. m_rgProps[epropDescription].Set(CLUSREG_NAME_NODE_DESC, m_strDescription, m_strDescription);
  100. m_rgProps[epropNodeHighestVersion].Set(CLUSREG_NAME_NODE_HIGHEST_VERSION, m_nNodeHighestVersion, m_nNodeHighestVersion);
  101. m_rgProps[epropNodeLowestVersion].Set(CLUSREG_NAME_NODE_LOWEST_VERSION, m_nNodeLowestVersion, m_nNodeLowestVersion);
  102. m_rgProps[epropMajorVersion].Set(CLUSREG_NAME_NODE_MAJOR_VERSION, m_nMajorVersion, m_nMajorVersion);
  103. m_rgProps[epropMinorVersion].Set(CLUSREG_NAME_NODE_MINOR_VERSION, m_nMinorVersion, m_nMinorVersion);
  104. m_rgProps[epropBuildNumber].Set(CLUSREG_NAME_NODE_BUILD_NUMBER, m_nBuildNumber, m_nBuildNumber);
  105. m_rgProps[epropCSDVersion].Set(CLUSREG_NAME_NODE_CSDVERSION, m_strCSDVersion, m_strCSDVersion);
  106. } // Setup the property array
  107. // To keep the application running as long as an OLE automation
  108. // object is active, the constructor calls AfxOleLockApp.
  109. // AfxOleLockApp();
  110. } //*** CClusterNode::CClusterNode()
  111. /////////////////////////////////////////////////////////////////////////////
  112. //++
  113. //
  114. // CClusterNode::~CClusterNode
  115. //
  116. // Description:
  117. // Destructor.
  118. //
  119. // Arguments:
  120. // None.
  121. //
  122. // Return Values:
  123. // None.
  124. //
  125. //--
  126. /////////////////////////////////////////////////////////////////////////////
  127. CClusterNode::~CClusterNode(void)
  128. {
  129. delete m_plpcigrpOnline;
  130. delete m_plpciresOnline;
  131. delete m_plpciNetInterfaces;
  132. // Close the node.
  133. if (Hnode() != NULL)
  134. CloseClusterNode(Hnode());
  135. // To terminate the application when all objects created with
  136. // with OLE automation, the destructor calls AfxOleUnlockApp.
  137. // AfxOleUnlockApp();
  138. } //*** CClusterNode::~CClusterNode()
  139. /////////////////////////////////////////////////////////////////////////////
  140. //++
  141. //
  142. // CClusterNode::Cleanup
  143. //
  144. // Description:
  145. // Cleanup the item.
  146. //
  147. // Arguments:
  148. // None.
  149. //
  150. // Return Values:
  151. // None.
  152. //
  153. // Exceptions Thrown:
  154. // None.
  155. //
  156. //--
  157. /////////////////////////////////////////////////////////////////////////////
  158. void CClusterNode::Cleanup(void)
  159. {
  160. // Delete the Groups Online list.
  161. if (m_plpcigrpOnline != NULL)
  162. m_plpcigrpOnline->RemoveAll();
  163. // Delete the Resources Online list.
  164. if (m_plpciresOnline != NULL)
  165. m_plpciresOnline->RemoveAll();
  166. // Delete the Network Interfaces list.
  167. if (m_plpciNetInterfaces != NULL)
  168. m_plpciNetInterfaces->RemoveAll();
  169. // Remove the item from the node list.
  170. {
  171. POSITION posPci;
  172. posPci = Pdoc()->LpciNodes().Find(this);
  173. if (posPci != NULL)
  174. {
  175. Pdoc()->LpciNodes().RemoveAt(posPci);
  176. } // if: found in the document's list
  177. } // Remove the item from the node list
  178. } //*** CClusterNode::Cleanup()
  179. /////////////////////////////////////////////////////////////////////////////
  180. //++
  181. //
  182. // CClusterNode::Init
  183. //
  184. // Description:
  185. // Initialize the item.
  186. //
  187. // Arguments:
  188. // pdoc [IN OUT] Document to which this item belongs.
  189. // lpszName [IN] Name of the item.
  190. //
  191. // Return Values:
  192. // None.
  193. //
  194. // Exceptions Thrown:
  195. // CNTException Errors from OpenClusterGroup or ClusterRegOpenKey.
  196. //
  197. //--
  198. /////////////////////////////////////////////////////////////////////////////
  199. void CClusterNode::Init(IN OUT CClusterDoc * pdoc, IN LPCTSTR lpszName)
  200. {
  201. DWORD dwStatus = ERROR_SUCCESS;
  202. LONG lResult;
  203. CWaitCursor wc;
  204. ASSERT(Hnode() == NULL);
  205. ASSERT(Hkey() == NULL);
  206. // Call the base class method.
  207. CClusterItem::Init(pdoc, lpszName);
  208. try
  209. {
  210. // Open the node.
  211. m_hnode = OpenClusterNode(Hcluster(), lpszName);
  212. if (Hnode() == NULL)
  213. {
  214. dwStatus = GetLastError();
  215. ThrowStaticException(dwStatus, IDS_OPEN_NODE_ERROR, lpszName);
  216. } // if: error opening the cluster node
  217. // Get the node registry key.
  218. m_hkey = GetClusterNodeKey(Hnode(), MAXIMUM_ALLOWED);
  219. if (Hkey() == NULL)
  220. ThrowStaticException(GetLastError(), IDS_GET_NODE_KEY_ERROR, lpszName);
  221. ASSERT(Pcnk() != NULL);
  222. Trace(g_tagClusItemNotify, _T("CClusterNode::Init() - Registering for node notifications (%08.8x) for '%s'"), Pcnk(), StrName());
  223. // Register for node notifications.
  224. lResult = RegisterClusterNotify(
  225. GetClusterAdminApp()->HchangeNotifyPort(),
  226. (CLUSTER_CHANGE_NODE_STATE
  227. | CLUSTER_CHANGE_NODE_DELETED
  228. | CLUSTER_CHANGE_NODE_PROPERTY),
  229. Hnode(),
  230. (DWORD_PTR) Pcnk()
  231. );
  232. if (lResult != ERROR_SUCCESS)
  233. {
  234. dwStatus = lResult;
  235. ThrowStaticException(dwStatus, IDS_NODE_NOTIF_REG_ERROR, lpszName);
  236. } // if: error registering for node notifications
  237. // Register for registry notifications.
  238. if (Hkey() != NULL)
  239. {
  240. lResult = RegisterClusterNotify(
  241. GetClusterAdminApp()->HchangeNotifyPort(),
  242. (CLUSTER_CHANGE_REGISTRY_NAME
  243. | CLUSTER_CHANGE_REGISTRY_ATTRIBUTES
  244. | CLUSTER_CHANGE_REGISTRY_VALUE
  245. | CLUSTER_CHANGE_REGISTRY_SUBTREE),
  246. Hkey(),
  247. (DWORD_PTR) Pcnk()
  248. );
  249. if (lResult != ERROR_SUCCESS)
  250. {
  251. dwStatus = lResult;
  252. ThrowStaticException(dwStatus, IDS_NODE_NOTIF_REG_ERROR, lpszName);
  253. } // if: error registering for registry notifications
  254. } // if: there is a key
  255. // Allocate lists.
  256. m_plpcigrpOnline = new CGroupList;
  257. if ( m_plpcigrpOnline == NULL )
  258. {
  259. AfxThrowMemoryException();
  260. } // if: error allocating the group list
  261. m_plpciresOnline = new CResourceList;
  262. if ( m_plpciresOnline == NULL )
  263. {
  264. AfxThrowMemoryException();
  265. } // if: error allocating the resource list
  266. m_plpciNetInterfaces = new CNetInterfaceList;
  267. if ( m_plpciNetInterfaces == NULL )
  268. {
  269. AfxThrowMemoryException();
  270. } // if: error allocating the net interface list
  271. // Read the initial state.
  272. UpdateState();
  273. } // try
  274. catch (CException *)
  275. {
  276. if (Hkey() != NULL)
  277. {
  278. ClusterRegCloseKey(Hkey());
  279. m_hkey = NULL;
  280. } // if: registry key opened
  281. if (Hnode() != NULL)
  282. {
  283. CloseClusterNode(Hnode());
  284. m_hnode = NULL;
  285. } // if: node opened
  286. m_bReadOnly = TRUE;
  287. throw;
  288. } // catch: CException
  289. } //*** CClusterNode::Init()
  290. /////////////////////////////////////////////////////////////////////////////
  291. //++
  292. //
  293. // CClusterNode::ReadItem
  294. //
  295. // Description:
  296. // Read the item parameters from the cluster database.
  297. //
  298. // Arguments:
  299. // None.
  300. //
  301. // Return Values:
  302. // None.
  303. //
  304. // Exceptions Thrown:
  305. // Any exceptions from CClusterItem::ReadItem().
  306. //
  307. //--
  308. /////////////////////////////////////////////////////////////////////////////
  309. void CClusterNode::ReadItem(void)
  310. {
  311. DWORD dwStatus;
  312. DWORD dwRetStatus = ERROR_SUCCESS;
  313. CWaitCursor wc;
  314. ASSERT(Hnode() != NULL);
  315. if (Hnode() != NULL)
  316. {
  317. m_rgProps[epropDescription].m_value.pstr = &m_strDescription;
  318. // Call the base class method.
  319. CClusterItem::ReadItem();
  320. // Read and parse the common properties.
  321. {
  322. CClusPropList cpl;
  323. dwStatus = cpl.ScGetNodeProperties(
  324. Hnode(),
  325. CLUSCTL_NODE_GET_COMMON_PROPERTIES
  326. );
  327. if (dwStatus == ERROR_SUCCESS)
  328. dwStatus = DwParseProperties(cpl);
  329. if (dwStatus != ERROR_SUCCESS)
  330. dwRetStatus = dwStatus;
  331. } // Read and parse the common properties
  332. // Read and parse the read-only common properties.
  333. if (dwRetStatus == ERROR_SUCCESS)
  334. {
  335. CClusPropList cpl;
  336. dwStatus = cpl.ScGetNodeProperties(
  337. Hnode(),
  338. CLUSCTL_NODE_GET_RO_COMMON_PROPERTIES
  339. );
  340. if (dwStatus == ERROR_SUCCESS)
  341. dwStatus = DwParseProperties(cpl);
  342. if (dwStatus != ERROR_SUCCESS)
  343. dwRetStatus = dwStatus;
  344. } // if: no error yet
  345. // Read extension lists.
  346. ReadExtensions();
  347. } // if: node is avaialble
  348. // Read the initial state.
  349. UpdateState();
  350. // ConstructActiveGroupList();
  351. // ConstructActiveResourceList();
  352. // If any errors occurred, throw an exception.
  353. if (dwRetStatus != ERROR_SUCCESS)
  354. {
  355. m_bReadOnly = TRUE;
  356. ThrowStaticException(dwRetStatus, IDS_READ_NODE_PROPS_ERROR, StrName());
  357. } // if: error reading properties
  358. MarkAsChanged(FALSE);
  359. } //*** CClusterNode::ReadItem()
  360. /////////////////////////////////////////////////////////////////////////////
  361. //++
  362. //
  363. // CClusterNode::PlstrExtensions
  364. //
  365. // Description:
  366. // Return the list of admin extensions.
  367. //
  368. // Arguments:
  369. // None.
  370. //
  371. // Return Values:
  372. // plstr List of extensions.
  373. // NULL No extension associated with this object.
  374. //
  375. // Exceptions Thrown:
  376. // None.
  377. //
  378. //--
  379. /////////////////////////////////////////////////////////////////////////////
  380. const CStringList * CClusterNode::PlstrExtensions(void) const
  381. {
  382. return &Pdoc()->PciCluster()->LstrNodeExtensions();
  383. } //*** CClusterNode::PlstrExtensions()
  384. /////////////////////////////////////////////////////////////////////////////
  385. //++
  386. //
  387. // CClusterNode::ReadExtensions
  388. //
  389. // Description:
  390. // Read extension lists.
  391. //
  392. // Arguments:
  393. // None.
  394. //
  395. // Return Values:
  396. // None.
  397. //
  398. // Exceptions Thrown:
  399. // None.
  400. //
  401. //--
  402. /////////////////////////////////////////////////////////////////////////////
  403. void CClusterNode::ReadExtensions(void)
  404. {
  405. } //*** CClusterNode::ReadExtensions()
  406. /////////////////////////////////////////////////////////////////////////////
  407. //++
  408. //
  409. // CClusterNode::AddActiveGroup
  410. //
  411. // Description:
  412. // Add a group to the list of active groups.
  413. //
  414. // Arguments:
  415. // pciGroup [IN OUT] New active group.
  416. //
  417. // Return Values:
  418. // None.
  419. //
  420. //--
  421. /////////////////////////////////////////////////////////////////////////////
  422. void CClusterNode::AddActiveGroup(IN OUT CGroup * pciGroup)
  423. {
  424. POSITION posPci;
  425. Trace(g_tagNode, _T("Adding active group '%s' (%x) to node '%s"), (pciGroup ? pciGroup->StrName() : _T("")), pciGroup, StrName());
  426. // Make sure the group is not already in the list.
  427. VERIFY((posPci = LpcigrpOnline().Find(pciGroup)) == NULL);
  428. if (posPci == NULL)
  429. {
  430. POSITION posPtiNode;
  431. CTreeItem * ptiNode;
  432. CTreeItem * ptiGroups;
  433. // Loop through each tree item to update the Active Groups list.
  434. posPtiNode = LptiBackPointers().GetHeadPosition();
  435. while (posPtiNode != NULL)
  436. {
  437. ptiNode = LptiBackPointers().GetNext(posPtiNode);
  438. ASSERT_VALID(ptiNode);
  439. // Find the Active Groups child tree item and add the new group.
  440. ptiGroups = ptiNode->PtiChildFromName(IDS_TREEITEM_ACTIVEGROUPS);
  441. ASSERT_VALID(ptiGroups);
  442. VERIFY(ptiGroups->PliAddChild(pciGroup) != NULL);
  443. } // while: more tree items for this node
  444. m_plpcigrpOnline->AddTail(pciGroup);
  445. } // if: group not in the list yet
  446. } //*** CClusterNode::AddActiveGroup()
  447. /////////////////////////////////////////////////////////////////////////////
  448. //++
  449. //
  450. // CClusterNode::AddActiveResource
  451. //
  452. // Description:
  453. // Add a resource to the list of active resources.
  454. //
  455. // Arguments:
  456. // pciRes [IN OUT] New active resource.
  457. //
  458. // Return Values:
  459. // None.
  460. //
  461. //--
  462. /////////////////////////////////////////////////////////////////////////////
  463. void CClusterNode::AddActiveResource(IN OUT CResource * pciRes)
  464. {
  465. POSITION posPci;
  466. Trace(g_tagNode, _T("Adding active resource '%s' (%x) to node '%s"), (pciRes ? pciRes->StrName() : _T("")), pciRes, StrName());
  467. // Make sure the resource is not already in the list.
  468. VERIFY((posPci = LpciresOnline().Find(pciRes)) == NULL);
  469. if (posPci == NULL)
  470. {
  471. POSITION posPtiNode;
  472. CTreeItem * ptiNode;
  473. CTreeItem * ptiResources;
  474. // Loop through each tree item to update the Active Resources list.
  475. posPtiNode = LptiBackPointers().GetHeadPosition();
  476. while (posPtiNode != NULL)
  477. {
  478. ptiNode = LptiBackPointers().GetNext(posPtiNode);
  479. ASSERT_VALID(ptiNode);
  480. // Find the Active Resources child tree item and add the new resource.
  481. ptiResources = ptiNode->PtiChildFromName(IDS_TREEITEM_ACTIVERESOURCES);
  482. ASSERT_VALID(ptiResources);
  483. VERIFY(ptiResources->PliAddChild(pciRes) != NULL);
  484. } // while: more tree items for this node
  485. m_plpciresOnline->AddTail(pciRes);
  486. } // if: resource not in the list yet
  487. } //*** CClusterNode::AddActiveResource()
  488. /////////////////////////////////////////////////////////////////////////////
  489. //++
  490. //
  491. // CClusterNode::AddNetInterface
  492. //
  493. // Description:
  494. // Add a network interface to the list of interaces installed in this node.
  495. //
  496. // Arguments:
  497. // pciNetIFace [IN OUT] New network interface.
  498. //
  499. // Return Values:
  500. // None.
  501. //
  502. //--
  503. /////////////////////////////////////////////////////////////////////////////
  504. void CClusterNode::AddNetInterface(IN OUT CNetInterface * pciNetIFace)
  505. {
  506. POSITION posPci;
  507. ASSERT_VALID(pciNetIFace);
  508. Trace(g_tagNode, _T("(%s) (%s (%x)) - Adding network interface '%s'"), Pdoc()->StrNode(), StrName(), this, pciNetIFace->StrName());
  509. // Make sure the resource is not already in the list.
  510. VERIFY((posPci = LpciNetInterfaces().Find(pciNetIFace)) == NULL);
  511. if (posPci == NULL)
  512. {
  513. POSITION posPtiNode;
  514. CTreeItem * ptiNode;
  515. CTreeItem * ptiNetIFace;
  516. // Loop through each tree item to update the Network Interfaces list.
  517. posPtiNode = LptiBackPointers().GetHeadPosition();
  518. while (posPtiNode != NULL)
  519. {
  520. ptiNode = LptiBackPointers().GetNext(posPtiNode);
  521. ASSERT_VALID(ptiNode);
  522. // Find the Active Resources child tree item and add the new resource.
  523. ptiNetIFace = ptiNode->PtiChildFromName(IDS_TREEITEM_NETIFACES);
  524. ASSERT_VALID(ptiNetIFace);
  525. VERIFY(ptiNetIFace->PliAddChild(pciNetIFace) != NULL);
  526. } // while: more tree items for this node
  527. m_plpciNetInterfaces->AddTail(pciNetIFace);
  528. } // if: network interface not in the list yet
  529. } //*** CClusterNode::AddNetInterface()
  530. /////////////////////////////////////////////////////////////////////////////
  531. //++
  532. //
  533. // CClusterNode::RemoveActiveGroup
  534. //
  535. // Description:
  536. // Remove a group from the list of active groups.
  537. //
  538. // Arguments:
  539. // pciGroup [IN OUT] Group that is no longer active on this node.
  540. //
  541. // Return Values:
  542. // None.
  543. //
  544. //--
  545. /////////////////////////////////////////////////////////////////////////////
  546. void CClusterNode::RemoveActiveGroup(IN OUT CGroup * pciGroup)
  547. {
  548. POSITION posPci;
  549. Trace(g_tagNode, _T("Removing active group '%s' (%x) from node '%s"), (pciGroup ? pciGroup->StrName() : _T("")), pciGroup, StrName());
  550. // Make sure the group is in the list.
  551. VERIFY((posPci = LpcigrpOnline().Find(pciGroup)) != NULL);
  552. if (posPci != NULL)
  553. {
  554. POSITION posPtiNode;
  555. CTreeItem * ptiNode;
  556. CTreeItem * ptiGroups;
  557. // Loop through each tree item to update the Active Groups list.
  558. posPtiNode = LptiBackPointers().GetHeadPosition();
  559. while (posPtiNode != NULL)
  560. {
  561. ptiNode = LptiBackPointers().GetNext(posPtiNode);
  562. ASSERT_VALID(ptiNode);
  563. // Find the Active Groups child tree item and remove the group.
  564. ptiGroups = ptiNode->PtiChildFromName(IDS_TREEITEM_ACTIVEGROUPS);
  565. ASSERT_VALID(ptiGroups);
  566. ptiGroups->RemoveChild(pciGroup);
  567. } // while: more tree items for this node
  568. m_plpcigrpOnline->RemoveAt(posPci);
  569. } // if: group in the list
  570. } //*** CClusterNode::RemoveActiveGroup()
  571. /////////////////////////////////////////////////////////////////////////////
  572. //++
  573. //
  574. // CClusterNode::RemoveActiveResource
  575. //
  576. // Description:
  577. // Remove a resource from the list of active resources.
  578. //
  579. // Arguments:
  580. // pciRes [IN OUT] Resource that is no longer active on this node.
  581. //
  582. // Return Values:
  583. // None.
  584. //
  585. //--
  586. /////////////////////////////////////////////////////////////////////////////
  587. void CClusterNode::RemoveActiveResource(IN OUT CResource * pciRes)
  588. {
  589. POSITION posPci;
  590. Trace(g_tagNode, _T("Removing active resource '%s' (%x) from node '%s"), (pciRes ? pciRes->StrName() : _T("")), pciRes, StrName());
  591. // Make sure the resource is in the list.
  592. VERIFY((posPci = LpciresOnline().Find(pciRes)) != NULL);
  593. if (posPci != NULL)
  594. {
  595. POSITION posPtiNode;
  596. CTreeItem * ptiNode;
  597. CTreeItem * ptiResources;
  598. // Loop through each tree item to update the Active Resources list.
  599. posPtiNode = LptiBackPointers().GetHeadPosition();
  600. while (posPtiNode != NULL)
  601. {
  602. ptiNode = LptiBackPointers().GetNext(posPtiNode);
  603. ASSERT_VALID(ptiNode);
  604. // Find the Active Resources child tree item and remove the resource.
  605. ptiResources = ptiNode->PtiChildFromName(IDS_TREEITEM_ACTIVERESOURCES);
  606. ASSERT_VALID(ptiResources);
  607. ptiResources->RemoveChild(pciRes);
  608. } // while: more tree items for this node
  609. m_plpciresOnline->RemoveAt(posPci);
  610. } // if: resource in the list
  611. } //*** CClusterNode::RemoveActiveResource()
  612. /////////////////////////////////////////////////////////////////////////////
  613. //++
  614. //
  615. // CClusterNode::RemoveNetInterface
  616. //
  617. // Description:
  618. // Remove a network interface from the list of interaces installed in this node.
  619. //
  620. // Arguments:
  621. // pciNetIFace [IN OUT] Network interface that is no longer
  622. // connected to this network.
  623. //
  624. // Return Values:
  625. // None.
  626. //
  627. //--
  628. /////////////////////////////////////////////////////////////////////////////
  629. void CClusterNode::RemoveNetInterface(IN OUT CNetInterface * pciNetIFace)
  630. {
  631. POSITION posPci;
  632. ASSERT_VALID(pciNetIFace);
  633. Trace(g_tagNode, _T("(%s) (%s (%x)) - Removing network interface '%s'"), Pdoc()->StrNode(), StrName(), this, pciNetIFace->StrName());
  634. // Make sure the network interface is in the list.
  635. VERIFY((posPci = LpciNetInterfaces().Find(pciNetIFace)) != NULL);
  636. if (posPci != NULL)
  637. {
  638. POSITION posPtiNode;
  639. CTreeItem * ptiNode;
  640. CTreeItem * ptiNetIFace;
  641. // Loop through each tree item to update the Network Interfaces list.
  642. posPtiNode = LptiBackPointers().GetHeadPosition();
  643. while (posPtiNode != NULL)
  644. {
  645. ptiNode = LptiBackPointers().GetNext(posPtiNode);
  646. ASSERT_VALID(ptiNode);
  647. // Find the Network Interfaces child tree item and remove the resource.
  648. ptiNetIFace = ptiNode->PtiChildFromName(IDS_TREEITEM_NETIFACES);
  649. ASSERT_VALID(ptiNetIFace);
  650. ptiNetIFace->RemoveChild(pciNetIFace);
  651. } // while: more tree items for this network
  652. m_plpciNetInterfaces->RemoveAt(posPci);
  653. } // if: network interface in the list
  654. } //*** CClusterNode::RemoveNetInterface()
  655. /////////////////////////////////////////////////////////////////////////////
  656. //++
  657. //
  658. // CClusterNode::SetDescription
  659. //
  660. // Description:
  661. // Set the description in the cluster database.
  662. //
  663. // Arguments:
  664. // rstrDesc [IN] Description to set.
  665. // bValidateOnly [IN] Only validate the data.
  666. //
  667. // Return Values:
  668. // None.
  669. //
  670. // Exceptions Thrown:
  671. // Any exceptions thrown by WriteItem().
  672. //
  673. //--
  674. /////////////////////////////////////////////////////////////////////////////
  675. void CClusterNode::SetDescription(
  676. IN const CString & rstrDesc,
  677. IN BOOL bValidateOnly
  678. )
  679. {
  680. CNTException nte(ERROR_SUCCESS, 0, NULL, NULL, FALSE /*bAutoDelete*/);
  681. m_rgProps[epropDescription].m_value.pstr = (CString *) &rstrDesc;
  682. try
  683. {
  684. CClusterItem::SetCommonProperties(bValidateOnly);
  685. } // try
  686. catch (CNTException * pnte)
  687. {
  688. nte.SetOperation(
  689. pnte->Sc(),
  690. pnte->IdsOperation(),
  691. pnte->PszOperArg1(),
  692. pnte->PszOperArg2()
  693. );
  694. } // catch: CNTException
  695. m_rgProps[epropDescription].m_value.pstr = &m_strDescription;
  696. if (nte.Sc() != ERROR_SUCCESS)
  697. ThrowStaticException(
  698. nte.Sc(),
  699. nte.IdsOperation(),
  700. nte.PszOperArg1(),
  701. nte.PszOperArg2()
  702. );
  703. } //*** CClusterNode::SetDescription()
  704. /////////////////////////////////////////////////////////////////////////////
  705. //++
  706. //
  707. // CClusterNode::DwSetCommonProperties
  708. //
  709. // Description:
  710. // Set the common properties for this resource in the cluster database.
  711. //
  712. // Arguments:
  713. // rcpl [IN] Property list to set.
  714. // bValidateOnly [IN] Only validate the data.
  715. //
  716. // Return Values:
  717. // Any status returned by ClusterResourceControl().
  718. //
  719. //--
  720. /////////////////////////////////////////////////////////////////////////////
  721. DWORD CClusterNode::DwSetCommonProperties(
  722. IN const CClusPropList & rcpl,
  723. IN BOOL bValidateOnly
  724. )
  725. {
  726. DWORD dwStatus;
  727. CWaitCursor wc;
  728. ASSERT(Hnode());
  729. if ((rcpl.PbPropList() != NULL) && (rcpl.CbPropList() > 0))
  730. {
  731. DWORD cbProps;
  732. DWORD dwControl;
  733. if (bValidateOnly)
  734. dwControl = CLUSCTL_NODE_VALIDATE_COMMON_PROPERTIES;
  735. else
  736. dwControl = CLUSCTL_NODE_SET_COMMON_PROPERTIES;
  737. // Set private properties.
  738. dwStatus = ClusterNodeControl(
  739. Hnode(),
  740. NULL, // hNode
  741. dwControl,
  742. rcpl.PbPropList(),
  743. rcpl.CbPropList(),
  744. NULL, // lpOutBuffer
  745. 0, // nOutBufferSize
  746. &cbProps
  747. );
  748. } // if: there is data to set
  749. else
  750. dwStatus = ERROR_SUCCESS;
  751. return dwStatus;
  752. } //*** CClusterNode::DwSetCommonProperties()
  753. /////////////////////////////////////////////////////////////////////////////
  754. //++
  755. //
  756. // CClusterNode::BCanBeDropTarget
  757. //
  758. // Description:
  759. // Determine if the specified item can be dropped on this item.
  760. //
  761. // Arguments:
  762. // pci [IN OUT] Item to be dropped on this item.
  763. //
  764. // Return Values:
  765. // TRUE Can be drop target.
  766. // FALSE Can NOT be drop target.
  767. //
  768. //--
  769. /////////////////////////////////////////////////////////////////////////////
  770. BOOL CClusterNode::BCanBeDropTarget(IN const CClusterItem * pci) const
  771. {
  772. BOOL bCan;
  773. // This node can be a drop target only if the specified item
  774. // is a group and it is not already a running on this node.
  775. if ((Cns() == ClusterNodeUp)
  776. && (pci->IdsType() == IDS_ITEMTYPE_GROUP))
  777. {
  778. CGroup * pciGroup = (CGroup *) pci;
  779. ASSERT_KINDOF(CGroup, pciGroup);
  780. if (pciGroup->StrOwner() != StrName())
  781. bCan = TRUE;
  782. else
  783. bCan = FALSE;
  784. Trace(g_tagNodeDrag, _T("BCanBeDropTarget() - Dragging group '%s' (%x) (owner = '%s') over node '%s' (%x)"), pciGroup->StrName(), pciGroup, pciGroup->StrOwner(), StrName(), this);
  785. } // if: node is up and dropping group item
  786. else
  787. bCan = FALSE;
  788. return bCan;
  789. } //*** CClusterNode::BCanBeDropTarget()
  790. /////////////////////////////////////////////////////////////////////////////
  791. //++
  792. //
  793. // CClusterNode::DropItem
  794. //
  795. // Description:
  796. // Process an item being dropped on this item.
  797. //
  798. // Arguments:
  799. // pci [IN OUT] Item dropped on this item.
  800. //
  801. // Return Values:
  802. // None.
  803. //
  804. //--
  805. /////////////////////////////////////////////////////////////////////////////
  806. void CClusterNode::DropItem(IN OUT CClusterItem * pci)
  807. {
  808. // Do this in case this object is deleted while we are operating on it.
  809. AddRef();
  810. do // do-while to prevent goto's
  811. {
  812. if (BCanBeDropTarget(pci))
  813. {
  814. POSITION pos;
  815. UINT imenu;
  816. UINT idMenu;
  817. CClusterNode * pciNode;
  818. CGroup * pciGroup;
  819. // Calculate the ID of this node.
  820. pos = Pdoc()->LpciNodes().GetHeadPosition();
  821. for (imenu = 0, idMenu = ID_FILE_MOVE_GROUP_1
  822. ; pos != NULL
  823. ; idMenu++)
  824. {
  825. pciNode = (CClusterNode *) Pdoc()->LpciNodes().GetNext(pos);
  826. ASSERT_VALID(pciNode);
  827. if (pciNode == this)
  828. break;
  829. } // for: each group
  830. ASSERT(imenu < (UINT) Pdoc()->LpciNodes().GetCount());
  831. // Change the group of the specified resource.
  832. pciGroup = (CGroup *) pci;
  833. ASSERT_KINDOF(CGroup, pci);
  834. ASSERT_VALID(pciGroup);
  835. // Verify that the resource should be moved.
  836. {
  837. CString strMsg;
  838. strMsg.FormatMessage(IDS_VERIFY_MOVE_GROUP, pciGroup->StrName(), pciGroup->StrOwner(), StrName());
  839. if (AfxMessageBox(strMsg, MB_YESNO | MB_ICONEXCLAMATION) != IDYES)
  840. break;
  841. } // Verify that the resource should be moved
  842. // Move the group.
  843. pciGroup->OnCmdMoveGroup(idMenu);
  844. } // if: item can be dropped on this item
  845. else if (pci->IdsType() == IDS_ITEMTYPE_GROUP)
  846. {
  847. CString strMsg;
  848. #ifdef _DEBUG
  849. CGroup * pciGroup = (CGroup *) pci;
  850. ASSERT_KINDOF(CGroup, pci);
  851. ASSERT_VALID(pciGroup);
  852. #endif // _DEBUG
  853. // Format the proper message.
  854. if (Cns() != ClusterNodeUp)
  855. strMsg.FormatMessage(IDS_CANT_MOVE_GROUP_TO_DOWN_NODE, pci->StrName(), StrName());
  856. else
  857. {
  858. ASSERT(pciGroup->StrOwner() == StrName());
  859. strMsg.FormatMessage(IDS_CANT_MOVE_GROUP_TO_SAME_NODE, pci->StrName(), StrName());
  860. } // else: problem is not that the node is not up
  861. AfxMessageBox(strMsg, MB_OK | MB_ICONSTOP);
  862. } // else if: dropped item is a group
  863. else
  864. CClusterItem::DropItem(pci);
  865. } while (0); // do-while to prevent goto's
  866. Release();
  867. } //*** CClusterNode::DropItem()
  868. /////////////////////////////////////////////////////////////////////////////
  869. //++
  870. //
  871. // CClusterNode::UpdateState
  872. //
  873. // Description:
  874. // Update the current state of the item.
  875. //
  876. // Arguments:
  877. // None.
  878. //
  879. // Return Values:
  880. // None.
  881. //
  882. //--
  883. /////////////////////////////////////////////////////////////////////////////
  884. void CClusterNode::UpdateState( void )
  885. {
  886. CClusterAdminApp * papp = GetClusterAdminApp();
  887. CLUSTER_NODE_STATE cnsPrev = m_cns;
  888. // Get the current state of the node.
  889. if ( Hnode() == NULL )
  890. {
  891. m_cns = ClusterNodeStateUnknown;
  892. } // if: node is not valid
  893. else
  894. {
  895. CWaitCursor wc;
  896. m_cns = GetClusterNodeState( Hnode() );
  897. } // else: node is valid
  898. // Save the current state image index.
  899. switch ( Cns() )
  900. {
  901. case ClusterNodeStateUnknown:
  902. m_iimgState = papp->Iimg( IMGLI_NODE_UNKNOWN );
  903. break;
  904. case ClusterNodeUp:
  905. m_iimgState = papp->Iimg( IMGLI_NODE );
  906. if ( cnsPrev == ClusterNodeDown )
  907. {
  908. UpdateResourceTypePossibleOwners();
  909. } // if: node was previously down
  910. break;
  911. case ClusterNodeDown:
  912. m_iimgState = papp->Iimg( IMGLI_NODE_DOWN );
  913. break;
  914. case ClusterNodePaused:
  915. m_iimgState = papp->Iimg( IMGLI_NODE_PAUSED );
  916. break;
  917. case ClusterNodeJoining:
  918. m_iimgState = papp->Iimg( IMGLI_NODE_UNKNOWN );
  919. break;
  920. default:
  921. Trace( g_tagNode, _T("(%s (%x)) - UpdateState: Unknown state '%d' for node '%s'"), StrName(), this, Cns(), StrName() );
  922. m_iimgState = (UINT) -1;
  923. break;
  924. } // switch: Cns()
  925. // Call the base class method.
  926. CClusterItem::UpdateState();
  927. } //*** CClusterNode::UpdateState()
  928. /////////////////////////////////////////////////////////////////////////////
  929. //++
  930. //
  931. // CClusterNode::UpdateResourceTypePossibleOwners
  932. //
  933. // Description:
  934. // Update the possible owner lists of any resource types that have
  935. // faked them because of nodes being down.
  936. //
  937. // Arguments:
  938. // None.
  939. //
  940. // Return Values:
  941. // None.
  942. //
  943. //--
  944. /////////////////////////////////////////////////////////////////////////////
  945. void CClusterNode::UpdateResourceTypePossibleOwners( void )
  946. {
  947. POSITION pos;
  948. CResourceType * pciResType;
  949. pos = Pdoc()->LpciResourceTypes().GetHeadPosition();
  950. while ( pos != NULL )
  951. {
  952. pciResType = (CResourceType *) Pdoc()->LpciResourceTypes().GetNext( pos );
  953. ASSERT_VALID( pciResType );
  954. if ( pciResType->BPossibleOwnersAreFake() )
  955. {
  956. pciResType->CollectPossibleOwners();
  957. } // if: possible owners have been faked
  958. } // while: more resource types
  959. } //*** CClusterNode::UpdateResourceTypePossibleOwners()
  960. /////////////////////////////////////////////////////////////////////////////
  961. //++
  962. //
  963. // CClusterNode::OnFinalRelease
  964. //
  965. // Description:
  966. // Called when the last OLE reference to or from the object is released.
  967. //
  968. // Arguments:
  969. // None.
  970. //
  971. // Return Values:
  972. // None.
  973. //
  974. //--
  975. /////////////////////////////////////////////////////////////////////////////
  976. void CClusterNode::OnFinalRelease(void)
  977. {
  978. // When the last reference for an automation object is released
  979. // OnFinalRelease is called. The base class will automatically
  980. // deletes the object. Add additional cleanup required for your
  981. // object before calling the base class.
  982. CClusterItem::OnFinalRelease();
  983. } //*** CClusterNode::OnFinalRelease()
  984. /////////////////////////////////////////////////////////////////////////////
  985. //++
  986. //
  987. // CClusterNode::BGetColumnData
  988. //
  989. // Description:
  990. // Returns a string with the column data.
  991. //
  992. // Arguments:
  993. // colid [IN] Column ID.
  994. // rstrText [OUT] String in which to return the text for the column.
  995. //
  996. // Return Values:
  997. // TRUE Column data returned.
  998. // FALSE Column ID not recognized.
  999. //
  1000. //--
  1001. /////////////////////////////////////////////////////////////////////////////
  1002. BOOL CClusterNode::BGetColumnData(IN COLID colid, OUT CString & rstrText)
  1003. {
  1004. BOOL bSuccess;
  1005. switch (colid)
  1006. {
  1007. case IDS_COLTEXT_STATE:
  1008. GetStateName(rstrText);
  1009. bSuccess = TRUE;
  1010. break;
  1011. default:
  1012. bSuccess = CClusterItem::BGetColumnData(colid, rstrText);
  1013. break;
  1014. } // switch: colid
  1015. return bSuccess;
  1016. } //*** CClusterNode::BGetColumnData()
  1017. /////////////////////////////////////////////////////////////////////////////
  1018. //++
  1019. //
  1020. // CClusterNode::GetTreeName
  1021. //
  1022. // Description:
  1023. // Returns a string to be used in a tree control.
  1024. //
  1025. // Arguments:
  1026. // rstrName [OUT] String in which to return the name.
  1027. //
  1028. // Return Values:
  1029. // None.
  1030. //
  1031. //--
  1032. /////////////////////////////////////////////////////////////////////////////
  1033. #ifdef _DISPLAY_STATE_TEXT_IN_TREE
  1034. void CClusterNode::GetTreeName(OUT CString & rstrName) const
  1035. {
  1036. CString strState;
  1037. GetStateName(strState);
  1038. rstrName.Format(_T("%s (%s)"), StrName(), strState);
  1039. } //*** CClusterNode::GetTreeName()
  1040. #endif
  1041. /////////////////////////////////////////////////////////////////////////////
  1042. //++
  1043. //
  1044. // CClusterNode::GetStateName
  1045. //
  1046. // Description:
  1047. // Returns a string with the name of the current state.
  1048. //
  1049. // Arguments:
  1050. // rstrState [OUT] String in which to return the name of the current state.
  1051. //
  1052. // Return Values:
  1053. // None.
  1054. //
  1055. //--
  1056. /////////////////////////////////////////////////////////////////////////////
  1057. void CClusterNode::GetStateName(OUT CString & rstrState) const
  1058. {
  1059. switch (Cns())
  1060. {
  1061. case ClusterNodeStateUnknown:
  1062. rstrState.LoadString(IDS_UNKNOWN);
  1063. break;
  1064. case ClusterNodeUp:
  1065. rstrState.LoadString(IDS_UP);
  1066. break;
  1067. case ClusterNodeDown:
  1068. rstrState.LoadString(IDS_DOWN);
  1069. break;
  1070. case ClusterNodePaused:
  1071. rstrState.LoadString(IDS_PAUSED);
  1072. break;
  1073. case ClusterNodeJoining:
  1074. rstrState.LoadString(IDS_JOINING);
  1075. break;
  1076. default:
  1077. rstrState.Empty();
  1078. break;
  1079. } // switch: Cns()
  1080. } //*** CClusterNode::GetStateName()
  1081. /////////////////////////////////////////////////////////////////////////////
  1082. //++
  1083. //
  1084. // CClusterNode::OnUpdatePauseNode
  1085. //
  1086. // Description:
  1087. // Determines whether menu items corresponding to ID_FILE_PAUSE_NODE
  1088. // should be enabled or not.
  1089. //
  1090. // Arguments:
  1091. // pCmdUI [IN OUT] Command routing object.
  1092. //
  1093. // Return Values:
  1094. // None.
  1095. //
  1096. //--
  1097. /////////////////////////////////////////////////////////////////////////////
  1098. void CClusterNode::OnUpdatePauseNode(CCmdUI * pCmdUI)
  1099. {
  1100. if (Cns() == ClusterNodeUp)
  1101. pCmdUI->Enable(TRUE);
  1102. else
  1103. pCmdUI->Enable(FALSE);
  1104. } //*** CClusterNode::OnUpdatePauseNode()
  1105. /////////////////////////////////////////////////////////////////////////////
  1106. //++
  1107. //
  1108. // CClusterNode::OnUpdateResumeNode
  1109. //
  1110. // Description:
  1111. // Determines whether menu items corresponding to ID_FILE_RESUME_NODE
  1112. // should be enabled or not.
  1113. //
  1114. // Arguments:
  1115. // pCmdUI [IN OUT] Command routing object.
  1116. //
  1117. // Return Values:
  1118. // None.
  1119. //
  1120. //--
  1121. /////////////////////////////////////////////////////////////////////////////
  1122. void CClusterNode::OnUpdateResumeNode(CCmdUI * pCmdUI)
  1123. {
  1124. if (Cns() == ClusterNodePaused)
  1125. pCmdUI->Enable(TRUE);
  1126. else
  1127. pCmdUI->Enable(FALSE);
  1128. } //*** CClusterNode::OnUpdateResumeNode()
  1129. /////////////////////////////////////////////////////////////////////////////
  1130. //++
  1131. //
  1132. // CClusterNode::OnUpdateEvictNode
  1133. //
  1134. // Description:
  1135. // Determines whether menu items corresponding to ID_FILE_EVICT_NODE
  1136. // should be enabled or not.
  1137. //
  1138. // Arguments:
  1139. // pCmdUI [IN OUT] Command routing object.
  1140. //
  1141. // Return Values:
  1142. // None.
  1143. //
  1144. //--
  1145. /////////////////////////////////////////////////////////////////////////////
  1146. void CClusterNode::OnUpdateEvictNode( CCmdUI * pCmdUI )
  1147. {
  1148. BOOL fCanEvict;
  1149. fCanEvict = FCanBeEvicted();
  1150. pCmdUI->Enable( fCanEvict );
  1151. } //*** CClusterNode::OnUpdateEvictNode()
  1152. /////////////////////////////////////////////////////////////////////////////
  1153. //++
  1154. //
  1155. // CClusterNode::OnUpdateStartService
  1156. //
  1157. // Description:
  1158. // Determines whether menu items corresponding to ID_FILE_START_SERVICE
  1159. // should be enabled or not.
  1160. //
  1161. // Arguments:
  1162. // pCmdUI [IN OUT] Command routing object.
  1163. //
  1164. // Return Values:
  1165. // None.
  1166. //
  1167. //--
  1168. /////////////////////////////////////////////////////////////////////////////
  1169. void CClusterNode::OnUpdateStartService(CCmdUI * pCmdUI)
  1170. {
  1171. if ((Cns() == ClusterNodeStateUnknown)
  1172. || (Cns() == ClusterNodeDown))
  1173. pCmdUI->Enable(TRUE);
  1174. else
  1175. pCmdUI->Enable(FALSE);
  1176. } //*** CClusterNode::OnUpdateStartService()
  1177. /////////////////////////////////////////////////////////////////////////////
  1178. //++
  1179. //
  1180. // CClusterNode::OnUpdateStopService
  1181. //
  1182. // Description:
  1183. // Determines whether menu items corresponding to ID_FILE_STOP_SERVICE
  1184. // should be enabled or not.
  1185. //
  1186. // Arguments:
  1187. // pCmdUI [IN OUT] Command routing object.
  1188. //
  1189. // Return Values:
  1190. // None.
  1191. //
  1192. //--
  1193. /////////////////////////////////////////////////////////////////////////////
  1194. void CClusterNode::OnUpdateStopService(CCmdUI * pCmdUI)
  1195. {
  1196. if ((Cns() == ClusterNodeStateUnknown)
  1197. || (Cns() == ClusterNodeUp))
  1198. pCmdUI->Enable(TRUE);
  1199. else
  1200. pCmdUI->Enable(FALSE);
  1201. } //*** CClusterNode::OnUpdateStopService()
  1202. /////////////////////////////////////////////////////////////////////////////
  1203. //++
  1204. //
  1205. // CClusterNode::OnCmdPauseNode
  1206. //
  1207. // Description:
  1208. // Processes the ID_FILE_PAUSE_NODE menu command.
  1209. //
  1210. // Arguments:
  1211. // None.
  1212. //
  1213. // Return Values:
  1214. // None.
  1215. //
  1216. //--
  1217. /////////////////////////////////////////////////////////////////////////////
  1218. void CClusterNode::OnCmdPauseNode(void)
  1219. {
  1220. DWORD dwStatus;
  1221. CWaitCursor wc;
  1222. ASSERT(Hnode() != NULL);
  1223. dwStatus = PauseClusterNode(Hnode());
  1224. if (dwStatus != ERROR_SUCCESS)
  1225. {
  1226. CNTException nte(dwStatus, IDS_PAUSE_NODE_ERROR, StrName(), NULL, FALSE /*bAutoDelete*/);
  1227. nte.ReportError();
  1228. } // if: error pausing node
  1229. UpdateState();
  1230. } //*** CClusterNode::OnCmdPauseNode()
  1231. /////////////////////////////////////////////////////////////////////////////
  1232. //++
  1233. //
  1234. // CClusterNode::OnCmdResumeNode
  1235. //
  1236. // Description:
  1237. // Processes the ID_FILE_RESUME_NODE menu command.
  1238. //
  1239. // Arguments:
  1240. // None.
  1241. //
  1242. // Return Values:
  1243. // None.
  1244. //
  1245. //--
  1246. /////////////////////////////////////////////////////////////////////////////
  1247. void CClusterNode::OnCmdResumeNode(void)
  1248. {
  1249. DWORD dwStatus;
  1250. CWaitCursor wc;
  1251. ASSERT(Hnode() != NULL);
  1252. dwStatus = ResumeClusterNode(Hnode());
  1253. if (dwStatus != ERROR_SUCCESS)
  1254. {
  1255. CNTException nte(dwStatus, IDS_RESUME_NODE_ERROR, StrName(), NULL, FALSE /*bAUtoDelete*/);
  1256. nte.ReportError();
  1257. } // if: error resuming node
  1258. UpdateState();
  1259. } //*** CClusterNode::OnCmdResumeNode()
  1260. /////////////////////////////////////////////////////////////////////////////
  1261. //++
  1262. //
  1263. // CClusterNode::OnCmdEvictNode
  1264. //
  1265. // Description:
  1266. // Processes the ID_FILE_EVICT_NODE menu command.
  1267. //
  1268. // Arguments:
  1269. // None.
  1270. //
  1271. // Return Values:
  1272. // None.
  1273. //
  1274. //--
  1275. /////////////////////////////////////////////////////////////////////////////
  1276. void CClusterNode::OnCmdEvictNode(void)
  1277. {
  1278. ASSERT(Hnode() != NULL);
  1279. // Do this in case this object is deleted while we are operating on it.
  1280. AddRef();
  1281. if ( ! FCanBeEvicted() )
  1282. {
  1283. TCHAR szMsg[1024];
  1284. CNTException nte(ERROR_CANT_EVICT_ACTIVE_NODE, 0, NULL, NULL, FALSE /*bAutoDelete*/);
  1285. nte.FormatErrorMessage(szMsg, sizeof(szMsg) / sizeof(TCHAR), NULL, FALSE /*bIncludeID*/);
  1286. AfxMessageBox(szMsg);
  1287. } // if: node can not be evicted
  1288. else
  1289. {
  1290. DWORD dwStatus;
  1291. DWORD dwCleanupStatus;
  1292. HRESULT hrCleanupStatus;
  1293. CString strMsg;
  1294. CWaitCursor wc;
  1295. try
  1296. {
  1297. // Verify that the user really wants to evict this node.
  1298. strMsg.FormatMessage(IDS_VERIFY_EVICT_NODE, StrName());
  1299. if (AfxMessageBox(strMsg, MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON2) == IDYES)
  1300. {
  1301. // Evict the node.
  1302. dwStatus = EvictClusterNodeEx(Hnode(), INFINITE, &hrCleanupStatus);
  1303. // convert any cleanup error from an hresult to a win32 error code
  1304. dwCleanupStatus = HRESULT_CODE( hrCleanupStatus );
  1305. if( ERROR_CLUSTER_EVICT_WITHOUT_CLEANUP == dwStatus )
  1306. {
  1307. //
  1308. // Eviction was successful, but cleanup failed. dwCleanupStatus contains
  1309. // the cleanup error code.
  1310. //
  1311. CNTException nte( dwCleanupStatus, IDS_EVICT_NODE_ERROR_UNAVAILABLE, StrName(), NULL, FALSE /*bAutoDelete*/ );
  1312. nte.ReportError();
  1313. }
  1314. else if( ERROR_SUCCESS != dwStatus )
  1315. {
  1316. //
  1317. // Eviction was not successful. Display the error.
  1318. //
  1319. CNTException nte(dwStatus, IDS_EVICT_NODE_ERROR, StrName(), NULL, FALSE /*bAutoDelete*/);
  1320. nte.ReportError();
  1321. } // if: error evicting the node
  1322. // else: eviction and cleanup successful
  1323. UpdateState();
  1324. } // if: user selected yes from message box (to online resource)
  1325. } // try
  1326. catch (CException * pe)
  1327. {
  1328. pe->ReportError();
  1329. pe->Delete();
  1330. } // catch: CException
  1331. } // else: node is down
  1332. Release();
  1333. } //*** CClusterNode::OnCmdEvictNode()
  1334. /////////////////////////////////////////////////////////////////////////////
  1335. //++
  1336. //
  1337. // CClusterNode::OnCmdStartService
  1338. //
  1339. // Description:
  1340. // Processes the ID_FILE_START_SERVICE menu command.
  1341. //
  1342. // Arguments:
  1343. // None.
  1344. //
  1345. // Return Values:
  1346. // None.
  1347. //
  1348. //--
  1349. /////////////////////////////////////////////////////////////////////////////
  1350. void CClusterNode::OnCmdStartService(void)
  1351. {
  1352. HRESULT hr;
  1353. BOOL bRefresh = FALSE;
  1354. CWaitCursor wc;
  1355. // If all nodes are down or unavailable, we need to refresh.
  1356. if ( Cns() == ClusterNodeStateUnknown )
  1357. {
  1358. bRefresh = TRUE;
  1359. }
  1360. else
  1361. {
  1362. int cNodesUp = 0;
  1363. POSITION pos;
  1364. CClusterNode * pciNode;
  1365. pos = Pdoc()->LpciNodes().GetHeadPosition();
  1366. while ( pos != NULL )
  1367. {
  1368. pciNode = (CClusterNode *) Pdoc()->LpciNodes().GetNext( pos );
  1369. ASSERT_VALID( pciNode );
  1370. if ( pciNode->Cns() == ClusterNodeStateUnknown )
  1371. {
  1372. cNodesUp++;
  1373. }
  1374. } // while: more items in the list
  1375. if ( cNodesUp > 0 )
  1376. {
  1377. bRefresh = TRUE;
  1378. }
  1379. } // else: node state is available
  1380. // Start the service.
  1381. hr = HrStartService( CLUSTER_SERVICE_NAME, StrName() );
  1382. if ( FAILED( hr ) )
  1383. {
  1384. CNTException nte( hr, IDS_START_CLUSTER_SERVICE_ERROR, StrName(), NULL, FALSE /*bAutoDelete*/ );
  1385. nte.ReportError();
  1386. } // if: error starting the service
  1387. else if ( bRefresh )
  1388. {
  1389. Sleep( 2000 );
  1390. Pdoc()->Refresh();
  1391. } // else if: we need to refresh
  1392. } //*** CClusterNode::OnCmdStartService()
  1393. /////////////////////////////////////////////////////////////////////////////
  1394. //++
  1395. //
  1396. // CClusterNode::OnCmdStopService
  1397. //
  1398. // Description:
  1399. // Processes the ID_FILE_STOP_SERVICE menu command.
  1400. //
  1401. // Arguments:
  1402. // None.
  1403. //
  1404. // Return Values:
  1405. // None.
  1406. //
  1407. //--
  1408. /////////////////////////////////////////////////////////////////////////////
  1409. void CClusterNode::OnCmdStopService(void)
  1410. {
  1411. HRESULT hr;
  1412. // Do this in case this object is deleted while we are operating on it.
  1413. AddRef();
  1414. // Stop the service.
  1415. hr = HrStopService( CLUSTER_SERVICE_NAME, StrName() );
  1416. if ( FAILED( hr ) )
  1417. {
  1418. CNTException nte( hr, IDS_STOP_CLUSTER_SERVICE_ERROR, StrName(), NULL, FALSE /*bAutoDelete*/ );
  1419. nte.ReportError();
  1420. }
  1421. Release();
  1422. } //*** CClusterNode::OnCmdStopService()
  1423. /////////////////////////////////////////////////////////////////////////////
  1424. //++
  1425. //
  1426. // CClusterNode::OnUpdateProperties
  1427. //
  1428. // Description:
  1429. // Determines whether menu items corresponding to ID_FILE_PROPERTIES
  1430. // should be enabled or not.
  1431. //
  1432. // Arguments:
  1433. // pCmdUI [IN OUT] Command routing object.
  1434. //
  1435. // Return Values:
  1436. // None.
  1437. //
  1438. //--
  1439. /////////////////////////////////////////////////////////////////////////////
  1440. void CClusterNode::OnUpdateProperties(CCmdUI * pCmdUI)
  1441. {
  1442. pCmdUI->Enable(TRUE);
  1443. } //*** CClusterNode::OnUpdateProperties()
  1444. /////////////////////////////////////////////////////////////////////////////
  1445. //++
  1446. //
  1447. // CClusterNode::BDisplayProperties
  1448. //
  1449. // Description:
  1450. // Display properties for the object.
  1451. //
  1452. // Arguments:
  1453. // bReadOnly [IN] Don't allow edits to the object properties.
  1454. //
  1455. // Return Values:
  1456. // TRUE OK pressed.
  1457. // FALSE OK not pressed.
  1458. //
  1459. //--
  1460. /////////////////////////////////////////////////////////////////////////////
  1461. BOOL CClusterNode::BDisplayProperties(IN BOOL bReadOnly)
  1462. {
  1463. BOOL bChanged = FALSE;
  1464. CNodePropSheet sht(AfxGetMainWnd());
  1465. // Do this in case this object is deleted while we are operating on it.
  1466. AddRef();
  1467. // If the object has changed, read it.
  1468. if (BChanged())
  1469. ReadItem();
  1470. // Display the property sheet.
  1471. try
  1472. {
  1473. sht.SetReadOnly(bReadOnly);
  1474. if (sht.BInit(this, IimgObjectType()))
  1475. bChanged = ((sht.DoModal() == IDOK) && !bReadOnly);
  1476. } // try
  1477. catch (CException * pe)
  1478. {
  1479. pe->Delete();
  1480. } // catch: CException
  1481. Release();
  1482. return bChanged;
  1483. } //*** CClusterNode::BDisplayProperties()
  1484. /////////////////////////////////////////////////////////////////////////////
  1485. //++
  1486. //
  1487. // CClusterNode::OnClusterNotify
  1488. //
  1489. // Description:
  1490. // Handler for the WM_CAM_CLUSTER_NOTIFY message.
  1491. // Processes cluster notifications for this object.
  1492. //
  1493. // Arguments:
  1494. // pnotify [IN OUT] Object describing the notification.
  1495. //
  1496. // Return Values:
  1497. // Value returned from the application method.
  1498. //
  1499. //--
  1500. /////////////////////////////////////////////////////////////////////////////
  1501. LRESULT CClusterNode::OnClusterNotify(IN OUT CClusterNotify * pnotify)
  1502. {
  1503. ASSERT(pnotify != NULL);
  1504. ASSERT_VALID(this);
  1505. try
  1506. {
  1507. switch (pnotify->m_dwFilterType)
  1508. {
  1509. case CLUSTER_CHANGE_NODE_STATE:
  1510. Trace(g_tagNodeNotify, _T("(%s) - Node '%s' (%x) state changed (%s)"), Pdoc()->StrNode(), StrName(), this, pnotify->m_strName);
  1511. UpdateState();
  1512. break;
  1513. case CLUSTER_CHANGE_NODE_DELETED:
  1514. Trace(g_tagNodeNotify, _T("(%s) - Node '%s' (%x) deleted (%s)"), Pdoc()->StrNode(), StrName(), this, pnotify->m_strName);
  1515. if (Pdoc()->BClusterAvailable())
  1516. Delete();
  1517. break;
  1518. case CLUSTER_CHANGE_NODE_PROPERTY:
  1519. Trace(g_tagNodeNotify, _T("(%s) - Node '%s' (%x) properties changed (%s)"), Pdoc()->StrNode(), StrName(), this, pnotify->m_strName);
  1520. if (Pdoc()->BClusterAvailable())
  1521. ReadItem();
  1522. break;
  1523. case CLUSTER_CHANGE_REGISTRY_NAME:
  1524. Trace(g_tagNodeRegNotify, _T("(%s) - Registry namespace '%s' changed (%s %s (%x))"), Pdoc()->StrNode(), pnotify->m_strName, StrType(), StrName(), this);
  1525. MarkAsChanged();
  1526. break;
  1527. case CLUSTER_CHANGE_REGISTRY_ATTRIBUTES:
  1528. Trace(g_tagNodeRegNotify, _T("(%s) - Registry attributes for '%s' changed (%s %s (%x))"), Pdoc()->StrNode(), pnotify->m_strName, StrType(), StrName(), this);
  1529. MarkAsChanged();
  1530. break;
  1531. case CLUSTER_CHANGE_REGISTRY_VALUE:
  1532. Trace(g_tagNodeRegNotify, _T("(%s) - Registry value '%s' changed (%s %s (%x))"), Pdoc()->StrNode(), pnotify->m_strName, StrType(), StrName(), this);
  1533. MarkAsChanged();
  1534. break;
  1535. default:
  1536. Trace(g_tagNodeNotify, _T("(%s) - Unknown node notification (%x) for '%s' (%x) (%s)"), Pdoc()->StrNode(), pnotify->m_dwFilterType, StrName(), this, pnotify->m_strName);
  1537. } // switch: dwFilterType
  1538. } // try
  1539. catch (CException * pe)
  1540. {
  1541. // Don't display anything on notification errors.
  1542. // If it's really a problem, the user will see it when
  1543. // refreshing the view.
  1544. //pe->ReportError();
  1545. pe->Delete();
  1546. } // catch: CException
  1547. delete pnotify;
  1548. return 0;
  1549. } //*** CClusterNode::OnClusterNotify()
  1550. /*
  1551. /////////////////////////////////////////////////////////////////////////////
  1552. //++
  1553. //
  1554. // CClusterNode::Delete
  1555. //
  1556. // Description:
  1557. // Do the CClusterItem::Delete processing unique to this class.
  1558. //
  1559. // Arguments:
  1560. // None.
  1561. //
  1562. // Return Values:
  1563. // None.
  1564. //
  1565. //--
  1566. /////////////////////////////////////////////////////////////////////////////
  1567. void CClusterNode::Delete(void)
  1568. {
  1569. POSITION _pos = NULL;
  1570. CResourceType * _ptype = NULL;
  1571. CResource * _pres = NULL;
  1572. //
  1573. // Remove this node from the resource types possible owners list
  1574. //
  1575. _pos = Pdoc()->LpciResourceTypes().GetHeadPosition();
  1576. while (_pos != NULL)
  1577. {
  1578. _ptype = dynamic_cast<CResourceType *>(Pdoc()->LpciResourceTypes().GetNext(_pos));
  1579. if (_ptype != NULL)
  1580. {
  1581. _ptype->RemoveNodeFromPossibleOwners(NULL, this);
  1582. } // if: _ptype != NULL
  1583. } // while: _pos != NULL
  1584. //
  1585. // Remove this node from the resources possible owners list
  1586. //
  1587. _pos = Pdoc()->LpciResources().GetHeadPosition();
  1588. while (_pos != NULL)
  1589. {
  1590. _pres = dynamic_cast<CResource *>(Pdoc()->LpciResources().GetNext(_pos));
  1591. if (_pres != NULL)
  1592. {
  1593. _pres->RemoveNodeFromPossibleOwners(NULL, this);
  1594. } // if: _pres != NULL
  1595. } // while: _pos != NULL
  1596. CClusterItem::Delete(); // do the old processing
  1597. } //*** CClusterNode::Delete()
  1598. */
  1599. /////////////////////////////////////////////////////////////////////////////
  1600. //++
  1601. //
  1602. // CClusterNode::FCanBeEvicted
  1603. //
  1604. // Description:
  1605. // Determine if the node can be evicted.
  1606. //
  1607. // Arguments:
  1608. // None.
  1609. //
  1610. // Return Values:
  1611. // TRUE Node can be evicted.
  1612. // FALSE Node can not be evicted.
  1613. //
  1614. //--
  1615. /////////////////////////////////////////////////////////////////////////////
  1616. BOOL
  1617. CClusterNode::FCanBeEvicted( void )
  1618. {
  1619. BOOL fCanEvict;
  1620. if ( ( m_nMajorVersion < 5 )
  1621. || ( ( m_nMajorVersion == 5 )
  1622. && ( m_nMinorVersion < 1 ) ) )
  1623. {
  1624. if ( ( Cns() == ClusterNodeDown )
  1625. || ( Pdoc()->LpciNodes().GetCount() > 1 ) )
  1626. {
  1627. fCanEvict = TRUE;
  1628. }
  1629. else
  1630. {
  1631. fCanEvict = FALSE;
  1632. }
  1633. } // if: pre-Whistler node
  1634. else
  1635. {
  1636. if ( ( Cns() == ClusterNodeDown )
  1637. || ( Pdoc()->LpciNodes().GetCount() == 1 ) )
  1638. {
  1639. fCanEvict = TRUE;
  1640. }
  1641. else
  1642. {
  1643. fCanEvict = FALSE;
  1644. }
  1645. } // else: Whistler or higher node
  1646. return fCanEvict;
  1647. } //*** CClusterNode::FCanBeEvicted()
  1648. //*************************************************************************//
  1649. /////////////////////////////////////////////////////////////////////////////
  1650. // Global Functions
  1651. /////////////////////////////////////////////////////////////////////////////
  1652. /////////////////////////////////////////////////////////////////////////////
  1653. //++
  1654. //
  1655. // DeleteAllItemData
  1656. //
  1657. // Description:
  1658. // Deletes all item data in a CList.
  1659. //
  1660. // Arguments:
  1661. // rlp [IN OUT] List whose data is to be deleted.
  1662. //
  1663. // Return Values:
  1664. // None.
  1665. //
  1666. //--
  1667. /////////////////////////////////////////////////////////////////////////////
  1668. #ifdef NEVER
  1669. void DeleteAllItemData(IN OUT CNodeList & rlp)
  1670. {
  1671. POSITION pos;
  1672. CClusterNode * pci;
  1673. // Delete all the items in the Contained list.
  1674. pos = rlp.GetHeadPosition();
  1675. while (pos != NULL)
  1676. {
  1677. pci = rlp.GetNext(pos);
  1678. ASSERT_VALID(pci);
  1679. // Trace(g_tagClusItemDelete, _T("DeleteAllItemData(rlpcinode) - Deleting node cluster item '%s' (%x)"), pci->StrName(), pci);
  1680. pci->Delete();
  1681. } // while: more items in the list
  1682. } //*** DeleteAllItemData()
  1683. #endif