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.

453 lines
14 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999-2001 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // CBaseClusterForm.cpp
  7. //
  8. // Description:
  9. // Contains the definition of the CBaseClusterForm class.
  10. //
  11. // Maintained By:
  12. // David Potter (DavidP) 14-JUN-2001
  13. // Vij Vasu (Vvasu) 08-MAR-2000
  14. //
  15. //////////////////////////////////////////////////////////////////////////////
  16. //////////////////////////////////////////////////////////////////////////////
  17. // Include Files
  18. //////////////////////////////////////////////////////////////////////////////
  19. // The precompiled header.
  20. #include "Pch.h"
  21. // The header file of this class.
  22. #include "CBaseClusterForm.h"
  23. // For the CClusSvcAccountConfig action
  24. #include "CClusSvcAccountConfig.h"
  25. // For the CClusNetCreate action
  26. #include "CClusNetCreate.h"
  27. // For the CClusDiskForm action
  28. #include "CClusDiskForm.h"
  29. // For the CClusDBForm action
  30. #include "CClusDBForm.h"
  31. // For the CClusSvcCreate action
  32. #include "CClusSvcCreate.h"
  33. // For the CNodeConfig action
  34. #include "CNodeConfig.h"
  35. //////////////////////////////////////////////////////////////////////////
  36. // Macros definitions
  37. //////////////////////////////////////////////////////////////////////////
  38. // The minimum amount of free space in bytes, required by the
  39. // localquorum resource (5 Mb)
  40. #define LOCALQUORUM_MIN_FREE_DISK_SPACE 5242880
  41. // Name of the file system required by the local quorum resource
  42. #define LOCALQUORUM_FILE_SYSTEM L"NTFS"
  43. //////////////////////////////////////////////////////////////////////////////
  44. //++
  45. //
  46. // CBaseClusterForm::CBaseClusterForm
  47. //
  48. // Description:
  49. // Constructor of the CBaseClusterForm class.
  50. //
  51. // This function also stores the parameters that are required for
  52. // creating a cluster.
  53. //
  54. // Arguments:
  55. // pbcaiInterfaceIn
  56. // Pointer to the interface class for this library.
  57. //
  58. // pszClusterNameIn
  59. // Name of the cluster to be formed.
  60. //
  61. // pcccServiceAccountIn
  62. // Specifies the account to be used as the cluster service account.
  63. //
  64. // dwClusterIPAddressIn
  65. // dwClusterIPSubnetMaskIn
  66. // pszClusterIPNetworkIn
  67. // Specifies the IP address and network of the cluster IP address.
  68. //
  69. // Return Value:
  70. // None.
  71. //
  72. // Exceptions Thrown:
  73. // CConfigError
  74. // If the OS version is incorrect or if the installation state
  75. // of the cluster binaries is wrong.
  76. //
  77. // CRuntimeError
  78. // If any of the APIs fail.
  79. //
  80. //--
  81. //////////////////////////////////////////////////////////////////////////////
  82. CBaseClusterForm::CBaseClusterForm(
  83. CBCAInterface * pbcaiInterfaceIn
  84. , const WCHAR * pcszClusterNameIn
  85. , const WCHAR * pszClusterBindingStringIn
  86. , IClusCfgCredentials * pcccServiceAccountIn
  87. , DWORD dwClusterIPAddressIn
  88. , DWORD dwClusterIPSubnetMaskIn
  89. , const WCHAR * pszClusterIPNetworkIn
  90. )
  91. : BaseClass(
  92. pbcaiInterfaceIn
  93. , pcszClusterNameIn
  94. , pszClusterBindingStringIn
  95. , pcccServiceAccountIn
  96. , dwClusterIPAddressIn
  97. )
  98. , m_dwClusterIPAddress( dwClusterIPAddressIn )
  99. , m_dwClusterIPSubnetMask( dwClusterIPSubnetMaskIn )
  100. , m_strClusterIPNetwork( pszClusterIPNetworkIn )
  101. {
  102. TraceFunc( "" );
  103. LogMsg( "[BC] The current cluster configuration task is: Create a Cluster." );
  104. CStatusReport srInitForm(
  105. PBcaiGetInterfacePointer()
  106. , TASKID_Major_Configure_Cluster_Services
  107. , TASKID_Minor_Initializing_Cluster_Form
  108. , 0, 1
  109. , IDS_TASK_FORM_INIT
  110. );
  111. // Send the next step of this status report.
  112. srInitForm.SendNextStep( S_OK );
  113. //
  114. // Write parameters to log file.
  115. //
  116. LogMsg(
  117. "[BC] Cluster IP Address => %d.%d.%d.%d"
  118. , ( m_dwClusterIPAddress & 0x000000FF )
  119. , ( m_dwClusterIPAddress & 0x0000FF00 ) >> 8
  120. , ( m_dwClusterIPAddress & 0x00FF0000 ) >> 16
  121. , ( m_dwClusterIPAddress & 0xFF000000 ) >> 24
  122. );
  123. LogMsg(
  124. "[BC] Subnet Mask => %d.%d.%d.%d"
  125. , ( m_dwClusterIPSubnetMask & 0x000000FF )
  126. , ( m_dwClusterIPSubnetMask & 0x0000FF00 ) >> 8
  127. , ( m_dwClusterIPSubnetMask & 0x00FF0000 ) >> 16
  128. , ( m_dwClusterIPSubnetMask & 0xFF000000 ) >> 24
  129. );
  130. LogMsg( "[BC] Cluster IP Network name => '%s'", m_strClusterIPNetwork.PszData() );
  131. //
  132. // Perform a sanity check on the parameters used by this class
  133. //
  134. if ( ( pszClusterIPNetworkIn == NULL ) || ( *pszClusterIPNetworkIn == L'\0' ) )
  135. {
  136. LogMsg( "[BC] The cluster IP Network name is invalid. Throwing an exception." );
  137. THROW_CONFIG_ERROR( THR( E_INVALIDARG ), IDS_ERROR_INVALID_IP_NET );
  138. } // if: the cluster IP network name is empty
  139. //
  140. // Make sure that there is enough free space under the cluster directory.
  141. // The quorum logs for the localquorum resource will be under this directory.
  142. //
  143. {
  144. BOOL fSuccess;
  145. ULARGE_INTEGER uliFreeBytesAvailToUser;
  146. ULARGE_INTEGER uliTotalBytes;
  147. ULARGE_INTEGER uliTotalFree;
  148. ULARGE_INTEGER uliRequired;
  149. uliRequired.QuadPart = LOCALQUORUM_MIN_FREE_DISK_SPACE;
  150. fSuccess = GetDiskFreeSpaceEx(
  151. RStrGetClusterInstallDirectory().PszData()
  152. , &uliFreeBytesAvailToUser
  153. , &uliTotalBytes
  154. , &uliTotalFree
  155. );
  156. if ( fSuccess == 0 )
  157. {
  158. DWORD sc = TW32( GetLastError() );
  159. LogMsg( "[BC] Error %#08x occurred trying to get free disk space. Throwing an exception.", sc );
  160. THROW_RUNTIME_ERROR(
  161. HRESULT_FROM_WIN32( sc )
  162. , IDS_ERROR_GETTING_FREE_DISK_SPACE
  163. );
  164. } // if: GetDiskFreeSpaceEx failed
  165. LogMsg(
  166. "[BC] Free space required = %#x%08x bytes. Available = %#x%08x bytes."
  167. , uliRequired.HighPart
  168. , uliRequired.LowPart
  169. , uliFreeBytesAvailToUser.HighPart
  170. , uliFreeBytesAvailToUser.LowPart
  171. );
  172. if ( uliFreeBytesAvailToUser.QuadPart < uliRequired.QuadPart )
  173. {
  174. LogMsg( "[BC] There isn't enough free space for the Local Quorum resource. The cluster create operation cannot proceed (throwing an exception)." );
  175. THROW_CONFIG_ERROR(
  176. HRESULT_FROM_WIN32( THR( ERROR_DISK_FULL ) )
  177. , IDS_ERROR_INSUFFICIENT_DISK_SPACE
  178. );
  179. } // if: there isn't enough free space for localquorum.
  180. LogMsg( "[BC] There is enough free space for the Local Quorum resource. The cluster create operation can proceed." );
  181. }
  182. /*
  183. //
  184. // KB: Vij Vasu (VVasu) 07-SEP-2000. Localquorum no longer needs NTFS disks
  185. // The code below has been commented out since it is no longer required that
  186. // localquorum resources use NTFS disks. This was confirmed by SunitaS.
  187. //
  188. //
  189. // Make sure that the drive on which the cluster binaries are installed has NTFS
  190. // on it. This is required by the localquorum resource.
  191. //
  192. {
  193. WCHAR szVolumePathName[ MAX_PATH ];
  194. WCHAR szFileSystemName[ MAX_PATH ];
  195. BOOL fSuccess;
  196. fSuccess = GetVolumePathName(
  197. RStrGetClusterInstallDirectory().PszData()
  198. , szVolumePathName
  199. , ARRAYSIZE( szVolumePathName )
  200. );
  201. if ( fSuccess == 0 )
  202. {
  203. DWORD sc = TW32( GetLastError() );
  204. LogMsg( "[BC] Error %#08x occurred trying to get file system type. The cluster create operation cannot proceed (throwing an exception).", sc );
  205. THROW_RUNTIME_ERROR(
  206. HRESULT_FROM_WIN32( sc )
  207. , IDS_ERROR_GETTING_FILE_SYSTEM
  208. );
  209. } // if: GetVolumePathName failed
  210. LogMsg( "[BC] The volume path name of the disk on which the cluster binaries reside is '%ws'.", szVolumePathName );
  211. fSuccess = GetVolumeInformationW(
  212. szVolumePathName // root directory
  213. , NULL // volume name buffer
  214. , 0 // length of name buffer
  215. , NULL // volume serial number
  216. , NULL // maximum file name length
  217. , NULL // file system options
  218. , szFileSystemName // file system name buffer
  219. , ARRAYSIZE( szFileSystemName ) // length of file system name buffer
  220. );
  221. if ( fSuccess == 0 )
  222. {
  223. DWORD sc = TW32( GetLastError() );
  224. LogMsg( "[BC] Error %#08x occurred trying to get file system type. The cluster create operation cannot proceed (throwing an exception).", sc );
  225. THROW_RUNTIME_ERROR(
  226. HRESULT_FROM_WIN32( sc )
  227. , IDS_ERROR_GETTING_FILE_SYSTEM
  228. );
  229. } // if: GetVolumeInformation failed
  230. LogMsg(
  231. "[BC] The file system on '%ws' is '%ws'. Required file system is '%s'."
  232. , szVolumePathName
  233. , szFileSystemName
  234. , LOCALQUORUM_FILE_SYSTEM
  235. );
  236. if ( NStringCchCompareNoCase( szFileSystemName, RTL_NUMBER_OF( szFileSystemName ), LOCALQUORUM_FILE_SYSTEM, RTL_NUMBER_OF( LOCALQUORUM_FILE_SYSTEM ) ) != 0 )
  237. {
  238. LogMsg( "[BC] LocalQuorum resource cannot be created on non-NTFS disk '%ws'. The cluster create operation cannot proceed (throwing an exception).", szVolumePathName );
  239. // MUSTDO - must define proper HRESULT for this error. ( Vvasu - 10 Mar 2000 )
  240. THROW_CONFIG_ERROR(
  241. HRESULT_FROM_WIN32( TW32( ERROR_UNRECOGNIZED_MEDIA ) )
  242. , IDS_ERROR_INCORRECT_INSTALL_STATE
  243. );
  244. } // if: the file system is not correct.
  245. LogMsg( "[BC] LocalQuorum resource will be created on disk '%ws'. The cluster create operation can proceed.", szVolumePathName );
  246. }
  247. */
  248. //
  249. // Create a list of actions to be performed.
  250. // The order of appending actions is significant.
  251. //
  252. // Add the action to configure the cluster service account.
  253. RalGetActionList().AppendAction( new CClusSvcAccountConfig( this ) );
  254. // Add the action to create the ClusNet service.
  255. RalGetActionList().AppendAction( new CClusNetCreate( this ) );
  256. // Add the action to create the ClusDisk service.
  257. RalGetActionList().AppendAction( new CClusDiskForm( this ) );
  258. // Add the action to create the cluster database.
  259. RalGetActionList().AppendAction( new CClusDBForm( this ) );
  260. // Add the action to perform miscellaneous tasks.
  261. RalGetActionList().AppendAction( new CNodeConfig( this ) );
  262. // Add the action to create the ClusSvc service.
  263. RalGetActionList().AppendAction( new CClusSvcCreate( this ) );
  264. // Indicate if rollback is possible or not.
  265. SetRollbackPossible( RalGetActionList().FIsRollbackPossible() );
  266. // Indicate that a cluster should be formed during commit.
  267. SetAction( eCONFIG_ACTION_FORM );
  268. // Send the last step of a status report.
  269. srInitForm.SendNextStep( S_OK );
  270. LogMsg( "[BC] Initialization for creating a cluster has completed." );
  271. TraceFuncExit();
  272. } //*** CBaseClusterForm::CBaseClusterForm
  273. //////////////////////////////////////////////////////////////////////////////
  274. //++
  275. //
  276. // CBaseClusterForm::~CBaseClusterForm
  277. //
  278. // Description:
  279. // Destructor of the CBaseClusterForm class
  280. //
  281. // Arguments:
  282. // None.
  283. //
  284. // Return Value:
  285. // None.
  286. //
  287. // Exceptions Thrown:
  288. // None.
  289. //
  290. //--
  291. //////////////////////////////////////////////////////////////////////////////
  292. CBaseClusterForm::~CBaseClusterForm( void ) throw()
  293. {
  294. TraceFunc( "" );
  295. TraceFuncExit();
  296. } //*** CBaseClusterForm::~CBaseClusterForm
  297. //////////////////////////////////////////////////////////////////////////////
  298. //++
  299. //
  300. // CBaseClusterForm::Commit
  301. //
  302. // Description:
  303. // Create the cluster.
  304. //
  305. // Arguments:
  306. // None.
  307. //
  308. // Return Value:
  309. // None.
  310. //
  311. // Exceptions Thrown:
  312. // CRuntimeError
  313. // If any of the APIs fail.
  314. //
  315. // Any exceptions thrown by functions called.
  316. //
  317. //--
  318. //////////////////////////////////////////////////////////////////////////////
  319. void
  320. CBaseClusterForm::Commit( void )
  321. {
  322. TraceFunc( "" );
  323. CStatusReport srFormingCluster(
  324. PBcaiGetInterfacePointer()
  325. , TASKID_Major_Configure_Cluster_Services
  326. , TASKID_Minor_Commit_Forming_Node
  327. , 0, 1
  328. , IDS_TASK_FORMING_CLUSTER
  329. );
  330. LogMsg( "[BC] Initiating a cluster create operation." );
  331. // Send the next step of this status report.
  332. srFormingCluster.SendNextStep( S_OK );
  333. // Call the base class commit routine. This commits the action list.
  334. BaseClass::Commit();
  335. // If we are here, then everything went well.
  336. SetCommitCompleted( true );
  337. // Send the last step of this status report.
  338. srFormingCluster.SendLastStep( S_OK );
  339. TraceFuncExit();
  340. } //*** CBaseClusterForm::Commit
  341. //////////////////////////////////////////////////////////////////////////////
  342. //++
  343. //
  344. // void
  345. // CBaseClusterForm::Rollback
  346. //
  347. // Description:
  348. // Performs the rolls back of the action committed by this object.
  349. //
  350. // Arguments:
  351. // None.
  352. //
  353. // Return Value:
  354. // None.
  355. //
  356. // Exceptions Thrown:
  357. // Any exceptions thrown by functions called.
  358. //
  359. //--
  360. //////////////////////////////////////////////////////////////////////////////
  361. void
  362. CBaseClusterForm::Rollback( void )
  363. {
  364. TraceFunc( "" );
  365. // Rollback the actions.
  366. BaseClass::Rollback();
  367. SetCommitCompleted( false );
  368. TraceFuncExit();
  369. } //*** CBaseClusterForm::Rollback