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.

495 lines
15 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999-2002 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // CClusSvc.cpp
  7. //
  8. // Description:
  9. // Contains the definition of the CClusSvc 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 for this file
  22. #include "CClusSvc.h"
  23. // For DwRemoveDirectory()
  24. #include "Common.h"
  25. // For IDS_ERROR_IP_ADDRESS_IN_USE_REF
  26. #include <CommonStrings.h>
  27. #define SECURITY_WIN32
  28. #include <Security.h>
  29. //////////////////////////////////////////////////////////////////////////////
  30. // Macros
  31. //////////////////////////////////////////////////////////////////////////////
  32. // Name of the NodeId cluster service parameter registry value.
  33. #define CLUSSVC_NODEID_VALUE L"NodeId"
  34. //////////////////////////////////////////////////////////////////////////////
  35. //++
  36. //
  37. // CClusSvc::CClusSvc
  38. //
  39. // Description:
  40. // Constructor of the CClusSvc class
  41. //
  42. // Arguments:
  43. // pbcaParentActionIn
  44. // Pointer to the base cluster action of which this action is a part.
  45. //
  46. // Return Value:
  47. // None.
  48. //
  49. // Exceptions Thrown:
  50. // CAssert
  51. // If the parameters are incorrect.
  52. //
  53. // Any exceptions thrown by underlying functions
  54. //
  55. //--
  56. //////////////////////////////////////////////////////////////////////////////
  57. CClusSvc::CClusSvc(
  58. CBaseClusterAction * pbcaParentActionIn
  59. )
  60. : m_cservClusSvc( CLUSTER_SERVICE_NAME )
  61. , m_pbcaParentAction( pbcaParentActionIn )
  62. {
  63. TraceFunc( "" );
  64. if ( m_pbcaParentAction == NULL)
  65. {
  66. LogMsg( "[BC] Pointers to the parent action is NULL. Throwing an exception." );
  67. THROW_ASSERT(
  68. E_INVALIDARG
  69. , "CClusSvc::CClusSvc() => Required input pointer in NULL"
  70. );
  71. } // if: the parent action pointer is NULL
  72. TraceFuncExit();
  73. } //*** CClusSvc::CClusSvc
  74. //////////////////////////////////////////////////////////////////////////////
  75. //++
  76. //
  77. // CClusSvc::~CClusSvc
  78. //
  79. // Description:
  80. // Destructor of the CClusSvc class.
  81. //
  82. // Arguments:
  83. // None.
  84. //
  85. // Return Value:
  86. // None.
  87. //
  88. // Exceptions Thrown:
  89. // Any exceptions thrown by underlying functions
  90. //
  91. //--
  92. //////////////////////////////////////////////////////////////////////////////
  93. CClusSvc::~CClusSvc( void )
  94. {
  95. TraceFunc( "" );
  96. TraceFuncExit();
  97. } //*** CClusSvc::~CClusSvc
  98. //////////////////////////////////////////////////////////////////////////////
  99. //++
  100. //
  101. // CClusSvc::ConfigureService
  102. //
  103. // Description:
  104. // Create the service, set the failure actions and the service account.
  105. // Then start the service.
  106. //
  107. // Arguments:
  108. // pszClusterDomainAccountNameIn
  109. // pszClusterAccountPwdIn
  110. // Information about the account to be used as the cluster service
  111. // account.
  112. //
  113. // pszNodeIdString
  114. // String containing the Id of this node.
  115. //
  116. // dwClusterIPAddress
  117. // IP address of the cluster
  118. //
  119. // Return Value:
  120. // None.
  121. //
  122. // Exceptions Thrown:
  123. // CRuntimeError
  124. // If any of the APIs fail.
  125. //
  126. // Any that are thrown by the underlying functions.
  127. //
  128. //--
  129. //////////////////////////////////////////////////////////////////////////////
  130. void
  131. CClusSvc::ConfigureService(
  132. const WCHAR * pszClusterDomainAccountNameIn
  133. , const WCHAR * pszClusterAccountPwdIn
  134. , const WCHAR * pszNodeIdStringIn
  135. , bool fIsVersionCheckingDisabledIn
  136. , DWORD dwClusterIPAddressIn
  137. )
  138. {
  139. TraceFunc( "" );
  140. DWORD sc = ERROR_SUCCESS;
  141. CStatusReport srCreatingClusSvc(
  142. PbcaGetParent()->PBcaiGetInterfacePointer()
  143. , TASKID_Major_Configure_Cluster_Services
  144. , TASKID_Minor_Creating_Cluster_Service
  145. , 0, 2
  146. , IDS_TASK_CREATING_CLUSSVC
  147. );
  148. LogMsg( "[BC] Configuring the Cluster service." );
  149. // Send the next step of this status report.
  150. srCreatingClusSvc.SendNextStep( S_OK );
  151. // Create the cluster service.
  152. m_cservClusSvc.Create( m_pbcaParentAction->HGetMainInfFileHandle() );
  153. LogMsg( "[BC] Setting the Cluster service account information." );
  154. // Open a smart handle to the cluster service.
  155. SmartSCMHandle sscmhClusSvcHandle(
  156. OpenService(
  157. m_pbcaParentAction->HGetSCMHandle()
  158. , CLUSTER_SERVICE_NAME
  159. , SERVICE_CHANGE_CONFIG
  160. )
  161. );
  162. if ( sscmhClusSvcHandle.FIsInvalid() )
  163. {
  164. sc = TW32( GetLastError() );
  165. LogMsg( "[BC] Error %#08x opening the '%ws' service.", sc, CLUSTER_SERVICE_NAME );
  166. goto Cleanup;
  167. } // if: we could not open a handle to the cluster service.
  168. //
  169. // Set the service account information.
  170. //
  171. {
  172. if (
  173. ChangeServiceConfig(
  174. sscmhClusSvcHandle
  175. , SERVICE_NO_CHANGE
  176. , SERVICE_NO_CHANGE
  177. , SERVICE_NO_CHANGE
  178. , NULL
  179. , NULL
  180. , NULL
  181. , NULL
  182. , pszClusterDomainAccountNameIn
  183. , pszClusterAccountPwdIn
  184. , NULL
  185. )
  186. == FALSE
  187. )
  188. {
  189. sc = TW32( GetLastError() );
  190. LogMsg(
  191. "[BC] Error %#08x setting the service account information. Account = '%ws'."
  192. , sc
  193. , pszClusterDomainAccountNameIn
  194. );
  195. goto Cleanup;
  196. } // if: we could not set the account information.
  197. }
  198. LogMsg( "[BC] Setting the Cluster service failure actions." );
  199. // Set the failure actions of the cluster service service.
  200. sc = TW32( ClRtlSetSCMFailureActions( NULL ) );
  201. if ( sc != ERROR_SUCCESS )
  202. {
  203. LogMsg( "[BC] Error %#08x setting the failure actions of the cluster service.", sc );
  204. goto Cleanup;
  205. } // if: the service failure actions couldn't be set
  206. LogMsg( "[BC] Setting the Cluster service parameters." );
  207. // Send the next step of this status report.
  208. srCreatingClusSvc.SendNextStep( S_OK );
  209. {
  210. CRegistryKey rkClusSvcParams;
  211. CRegistryKey rkClusterParams;
  212. UUID guid;
  213. LPWSTR pszClusterInstanceId = NULL;
  214. // Open the parameters key or create it if it does not exist.
  215. rkClusSvcParams.CreateKey(
  216. HKEY_LOCAL_MACHINE
  217. , CLUSREG_KEYNAME_CLUSSVC_PARAMETERS
  218. , KEY_WRITE
  219. );
  220. // Set the NodeId string.
  221. rkClusSvcParams.SetValue(
  222. CLUSSVC_NODEID_VALUE
  223. , REG_SZ
  224. , reinterpret_cast< const BYTE * >( pszNodeIdStringIn )
  225. , ( (UINT) wcslen( pszNodeIdStringIn ) + 1 ) * sizeof( *pszNodeIdStringIn )
  226. );
  227. // If version checking has been disabled, set a flag in the service parameters
  228. // to indicate this.
  229. if ( fIsVersionCheckingDisabledIn )
  230. {
  231. DWORD dwNoVersionCheck = 1;
  232. rkClusSvcParams.SetValue(
  233. CLUSREG_NAME_SVC_PARAM_NOVER_CHECK
  234. , REG_DWORD
  235. , reinterpret_cast< const BYTE * >( &dwNoVersionCheck )
  236. , sizeof( dwNoVersionCheck )
  237. );
  238. LogMsg( "[BC] Cluster version checking has been disabled on this computer." );
  239. } // if: version checking has been disabled
  240. //
  241. // If we are creating a new cluster then create the cluster instance ID.
  242. //
  243. if ( m_pbcaParentAction->EbcaGetAction() == eCONFIG_ACTION_FORM )
  244. {
  245. // Generate a GUID for the cluster instance ID.
  246. sc = UuidCreate( &guid );
  247. if ( sc != RPC_S_OK )
  248. {
  249. LogMsg( "[BC] Error %#08x when creating a Uuid for the Cluster Instance ID.", sc );
  250. goto Cleanup;
  251. }
  252. sc = UuidToString( &guid, &pszClusterInstanceId );
  253. if ( sc != RPC_S_OK )
  254. {
  255. LogMsg( "[BC] Error %#08x when converting the uuid of the Cluster Instance ID to a string.", sc );
  256. goto Cleanup;
  257. }
  258. // Open the parameters key in the cluster database or create it if it does not exist.
  259. rkClusterParams.CreateKey(
  260. HKEY_LOCAL_MACHINE
  261. , CLUSREG_KEYNAME_CLUSTER_PARAMETERS
  262. , KEY_WRITE
  263. );
  264. // Set the ClusterInstanceId string.
  265. rkClusterParams.SetValue(
  266. CLUSREG_NAME_CLUS_CLUSTER_INSTANCE_ID
  267. , REG_SZ
  268. , reinterpret_cast< const BYTE * >( pszClusterInstanceId )
  269. , ( (UINT) wcslen( pszClusterInstanceId ) + 1 ) * sizeof( *pszClusterInstanceId )
  270. );
  271. } // if: creating a cluster
  272. }
  273. //
  274. // Set the cluster installation state.
  275. //
  276. if ( ClRtlSetClusterInstallState( eClusterInstallStateConfigured ) == FALSE )
  277. {
  278. sc = TW32( GetLastError() );
  279. LogMsg( "[BC] Could not set the cluster installation state. Throwing an exception." );
  280. goto Cleanup;
  281. } // ClRtlSetClusterInstallState() failed.
  282. Cleanup:
  283. if ( sc != ERROR_SUCCESS )
  284. {
  285. LogMsg( "[BC] Error %#08x occurred trying configure the ClusSvc service. Throwing an exception.", sc );
  286. THROW_RUNTIME_ERROR(
  287. HRESULT_FROM_WIN32( sc )
  288. , IDS_ERROR_CLUSSVC_CONFIG
  289. );
  290. } // if; there was an error getting the handle.
  291. // Send the next step of this status report.
  292. srCreatingClusSvc.SendNextStep( S_OK );
  293. {
  294. UINT cQueryCount = 100;
  295. CStatusReport srStartingClusSvc(
  296. PbcaGetParent()->PBcaiGetInterfacePointer()
  297. , TASKID_Major_Configure_Cluster_Services
  298. , TASKID_Minor_Starting_Cluster_Service
  299. , 0, cQueryCount + 2 // we will send at most cQueryCount reports while waiting for the service to start (the two extra sends are below)
  300. , IDS_TASK_STARTING_CLUSSVC
  301. );
  302. // Send the next step of this status report.
  303. srStartingClusSvc.SendNextStep( S_OK );
  304. try
  305. {
  306. //
  307. // Start the service.
  308. //
  309. m_cservClusSvc.Start(
  310. m_pbcaParentAction->HGetSCMHandle()
  311. , true // wait for the service to start
  312. , 3000 // wait 3 seconds between queries for status.
  313. , cQueryCount // query cQueryCount times
  314. , &srStartingClusSvc // status report to be sent while waiting for the service to start
  315. );
  316. }
  317. catch( ... )
  318. {
  319. //
  320. // If IP Address is not NULL we are creating a new cluster; otherwise we are adding node to a cluster.
  321. //
  322. if ( dwClusterIPAddressIn != 0 )
  323. {
  324. BOOL fRet = FALSE;
  325. fRet = ClRtlIsDuplicateTcpipAddress( dwClusterIPAddressIn );
  326. //
  327. // IP address already in use
  328. //
  329. if ( fRet == TRUE )
  330. {
  331. LogMsg( "[BC] The IP address specified for this cluster is already in use. Throwing an exception.");
  332. THROW_RUNTIME_ERROR_REF( HRESULT_FROM_WIN32( ERROR_CLUSTER_IPADDR_IN_USE ), IDS_ERROR_IP_ADDRESS_IN_USE, IDS_ERROR_IP_ADDRESS_IN_USE_REF );
  333. }
  334. else
  335. {
  336. LogMsg( "[BC] Cluster Service Win32 Exit Code= %#08x", m_cservClusSvc.GetWin32ExitCode() );
  337. LogMsg( "[BC] Cluster Service Specific Exit Code= %#08x", m_cservClusSvc.GetServiceExitCode() );
  338. //
  339. // Throw the error if we don't handle it.
  340. //
  341. throw;
  342. }
  343. } // if: cluster IP address was specified
  344. else
  345. {
  346. LogMsg( "[BC] Cluster Service Win32 Exit Code= %#08x", m_cservClusSvc.GetWin32ExitCode() );
  347. LogMsg( "[BC] Cluster Service Specific Exit Code= %#08x", m_cservClusSvc.GetServiceExitCode() );
  348. //
  349. // Throw the error if we don't handle it.
  350. //
  351. throw;
  352. } // else: cluster IP address was not specified
  353. } // catch: anything
  354. // Send the last step of this status report.
  355. srStartingClusSvc.SendLastStep( S_OK );
  356. }
  357. TraceFuncExit();
  358. } //*** CClusSvc::ConfigureService
  359. //////////////////////////////////////////////////////////////////////////////
  360. //++
  361. //
  362. // CClusSvc::CleanupService
  363. //
  364. // Description:
  365. // Stop, cleanup and remove the service.
  366. //
  367. // Arguments:
  368. // None.
  369. //
  370. // Return Value:
  371. // None.
  372. //
  373. // Exceptions Thrown:
  374. // Any that are thrown by the underlying functions.
  375. //
  376. //--
  377. //////////////////////////////////////////////////////////////////////////////
  378. void
  379. CClusSvc::CleanupService( void )
  380. {
  381. TraceFunc( "" );
  382. LogMsg( "[BC] Trying to stop the Cluster Service." );
  383. // Stop the service.
  384. m_cservClusSvc.Stop(
  385. m_pbcaParentAction->HGetSCMHandle()
  386. , 5000 // wait 5 seconds between queries for status.
  387. , 60 // query 60 times ( 5 minutes )
  388. );
  389. //
  390. // Restore the cluster installation state.
  391. //
  392. if ( ClRtlSetClusterInstallState( eClusterInstallStateFilesCopied ) == FALSE )
  393. {
  394. DWORD sc = GetLastError();
  395. LogMsg( "[BC] Could not set the cluster installation state. Throwing an exception." );
  396. THROW_RUNTIME_ERROR(
  397. HRESULT_FROM_WIN32( sc )
  398. , IDS_ERROR_SETTING_INSTALL_STATE
  399. );
  400. } // ClRtlSetClusterInstallState() failed.
  401. LogMsg( "[BC] Cleaning up Cluster Service." );
  402. m_cservClusSvc.Cleanup( m_pbcaParentAction->HGetMainInfFileHandle() );
  403. //
  404. // KB: ozano 01-18-2002 - We need to sleep here in order to have the service cleanup take place.
  405. // If we don't wait for some time and the user goes back, changes the IP address and hits re-analysis, service
  406. // start fails with Win32ExitCode of ERROR_SERVICE_MARKED_FOR_DELETION.
  407. //
  408. Sleep( 10000 );
  409. // Cleanup the local quorum directory.
  410. {
  411. DWORD sc = ERROR_SUCCESS;
  412. const WCHAR * pcszQuorumDir = m_pbcaParentAction->RStrGetLocalQuorumDirectory().PszData();
  413. sc = TW32( DwRemoveDirectory( pcszQuorumDir ) );
  414. if ( sc != ERROR_SUCCESS )
  415. {
  416. LogMsg( "[BC] The local quorum directory '%s' cannot be removed. Non-fatal error %#08x occurred.\n", pcszQuorumDir, sc );
  417. } // if: we could not remove the local quorum directory
  418. }
  419. TraceFuncExit();
  420. } //*** CClusSvc::CleanupService