Leaked source code of windows server 2003
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.

1996 lines
57 KiB

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