|
|
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1999-2001 Microsoft Corporation
//
// Module Name:
// CClusDBForm.cpp
//
// Description:
// Contains the definition of the CClusDBForm class.
//
// Maintained By:
// David Potter (DavidP) 14-JUN-2001
// Vij Vasu (Vvasu) 08-MAR-2000
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Include Files
//////////////////////////////////////////////////////////////////////////////
// The precompiled header.
#include "Pch.h"
// The header for this file
#include "CClusDBForm.h"
// For the CBaseClusterForm class.
#include "CBaseClusterForm.h"
// For UUID related utilities.
#include "CUuid.h"
// For CEnableThreadPrivilege
#include "CEnableThreadPrivilege.h"
// For the CStr class.
#include "CStr.h"
// For sending status reports.
#include "CStatusReport.h"
// For DwRemoveDirectory()
#include "Common.h"
// For inet_ntoa
#include <winsock2.h>
//////////////////////////////////////////////////////////////////////////
// Macros definitions
//////////////////////////////////////////////////////////////////////////
// Section in the INF file that deals with populating the cluster hive.
#define CLUSDB_POPULATE_INF_SECTION_NAME L"ClusDB_Form"
// A placeholder for the cluster group key name in the cluster registry.
#define CLUSREG_KEYNAME_CLUSTERGROUP_PLACEHOLDER L"ClusterGroupGUIDPlaceholder"
// A placeholder for the cluster name resource key name in the cluster registry.
#define CLUSREG_KEYNAME_CLUSTERNAME_RES_PLACEHOLDER L"ClusterNameResGUIDPlaceHolder"
// A placeholder for the cluster IP address resource key name in the cluster registry.
#define CLUSREG_KEYNAME_CLUSTERIP_RES_PLACEHOLDER L"ClusterIPAddrResGUIDPlaceHolder"
// A placeholder for the local quorum resource key name in the cluster registry.
#define CLUSREG_KEYNAME_LOCALQUORUM_RES_PLACEHOLDER L"LocalQuorumResGUIDPlaceHolder"
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusDBForm::CClusDBForm
//
// Description:
// Constructor of the CClusDBForm class
//
// Arguments:
// pfaParentActionIn
// Pointer to the base cluster action of which this action is a part.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any exceptions thrown by underlying functions
//
//--
//////////////////////////////////////////////////////////////////////////////
CClusDBForm::CClusDBForm( CBaseClusterForm * pfaParentActionIn ) : BaseClass( pfaParentActionIn ) {
TraceFunc( "" );
SetRollbackPossible( true );
TraceFuncExit();
} //*** CClusDBForm::CClusDBForm
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusDBForm::~CClusDBForm
//
// Description:
// Destructor of the CClusDBForm class.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any exceptions thrown by underlying functions
//
//--
//////////////////////////////////////////////////////////////////////////////
CClusDBForm::~CClusDBForm( void ) { TraceFunc( "" ); TraceFuncExit();
} //*** CClusDBForm::~CClusDBForm
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusDBForm::Commit
//
// Description:
// Create the cluster database. If anything goes wrong with the creation,
// cleanup the tasks already done.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any that are thrown by the contained actions.
//
//--
//////////////////////////////////////////////////////////////////////////////
void CClusDBForm::Commit( void ) { TraceFunc( "" );
// Call the base class commit method.
BaseClass::Commit();
//
// Perform a ClusDB cleanup just to make sure that we do not use some files left over
// from a previous install, aborted uninstall, etc.
//
LogMsg( "[BC-ClusDB-Commit] Cleaning up old cluster database files that may already exist before starting creation." );
{ CStatusReport srCleanDB( PbcaGetParent()->PBcaiGetInterfacePointer() , TASKID_Major_Configure_Cluster_Services , TASKID_Minor_Cleaning_Up_Cluster_Database , 0, 1 , IDS_TASK_CLEANINGUP_CLUSDB );
// Send the next step of this status report.
srCleanDB.SendNextStep( S_OK );
CleanupHive();
// Send the last step of this status report.
srCleanDB.SendNextStep( S_OK ); }
try { // Create the cluster database
Create(); } // try:
catch( ... ) { // If we are here, then something went wrong with the create.
LogMsg( "[BC-ClusDB-Commit] Caught exception during commit." );
//
// Cleanup anything that the failed create operation might have done.
// Catch any exceptions thrown during Cleanup to make sure that there
// is no collided unwind.
//
try { CleanupHive(); } catch( ... ) { //
// The rollback of the committed action has failed.
// There is nothing that we can do.
// We certainly cannot rethrow this exception, since
// the exception that caused the rollback is more important.
//
HRESULT_FROM_WIN32( TW32( ERROR_CLUSCFG_ROLLBACK_FAILED ) );
LogMsg( "[BC-ClusDB-Commit] THIS COMPUTER MAY BE IN AN INVALID STATE. Caught an exception during cleanup." ); } // catch: all
// Rethrow the exception thrown by commit.
throw;
} // catch: all
// If we are here, then everything went well.
SetCommitCompleted( true );
TraceFuncExit();
} //*** CClusDBForm::Commit
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusDBForm::Rollback
//
// Description:
// Unload the cluster hive and cleanup any associated files.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any that are thrown by the underlying functions.
//
//--
//////////////////////////////////////////////////////////////////////////////
void CClusDBForm::Rollback( void ) { TraceFunc( "" );
// Call the base class rollback method.
BaseClass::Rollback();
// Cleanup the cluster database.
CleanupHive();
SetCommitCompleted( false );
TraceFuncExit();
} //*** CClusDBForm::Rollback
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusDBForm::Create
//
// Description:
// Create the cluster database.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CAssert
// The parent action of this action is not CBaseClusterForm
//
// CRuntimeError
// If any of the APIs fail.
//
// Any that are thrown by the called functions.
//
//--
//////////////////////////////////////////////////////////////////////////////
void CClusDBForm::Create( void ) { TraceFunc( "" ); LogMsg( "[BC-ClusDB-Create] Attempting to create the cluster database required to create a cluster." );
DWORD sc = ERROR_SUCCESS;
// Get the parent action pointer.
CBaseClusterForm * pcfClusterForm = dynamic_cast< CBaseClusterForm *>( PbcaGetParent() );
CStatusReport srCustomizingDB( PbcaGetParent()->PBcaiGetInterfacePointer() , TASKID_Major_Configure_Cluster_Services , TASKID_Minor_Form_Customizing_Cluster_Database , 0, 1 , IDS_TASK_FORM_CUSTOMIZING_CLUSDB );
// If the parent action of this action is not CBaseClusterForm
if ( pcfClusterForm == NULL ) { THROW_ASSERT( E_POINTER, "The parent action of this action is not CBaseClusterForm." ); } // an invalid pointer was passed in.
// Create the cluster hive.
{ CStatusReport srCreatingDB( PbcaGetParent()->PBcaiGetInterfacePointer() , TASKID_Major_Configure_Cluster_Services , TASKID_Minor_Form_Creating_Cluster_Database , 0, 1 , IDS_TASK_FORM_CREATING_CLUSDB );
// Send the next step of this status report.
srCreatingDB.SendNextStep( S_OK );
// Create an empty cluster hive in the registry.
CreateHive( pcfClusterForm );
// Send the last step of this status report.
srCreatingDB.SendNextStep( S_OK ); }
// Send the next step of this status report.
srCustomizingDB.SendNextStep( S_OK );
// Fill up the newly created hive.
PopulateHive( pcfClusterForm );
//
// Create the quorum directory and set its security attributes.
//
do { HANDLE hQuorumDirHandle; const WCHAR * pcszQuorumDir = pcfClusterForm->RStrGetLocalQuorumDirectory().PszData();
// First, remove the local quorum directory, if it exists.
sc = TW32( DwRemoveDirectory( pcszQuorumDir ) ); if ( sc != ERROR_SUCCESS ) { LogMsg( "[BC-ClusDB-Create] The local quorum directory '%s' already exists, but error %#08x occurred trying to remove it.\n", pcszQuorumDir, sc ); break; } // if: we could not remove the local quorum directory
if ( CreateDirectory( pcszQuorumDir, NULL ) == FALSE ) { sc = TW32( GetLastError() ); LogMsg( "[BC-ClusDB-Create] Error %#08x trying to create directory '%ws'", sc, pcszQuorumDir ); break; } // if: the localquorum directory could not be created
//
// Enable the SE_BACKUP_PRIVILEGE and SE_RESTORE_PRIVILEGE.
//
// What we are doing here is that we are creating an object of
// type CEnableThreadPrivilege. This object enables the privilege
// in the constructor and restores it to its original state in the destructor.
//
CEnableThreadPrivilege etpAcquireBackupPrivilege( SE_BACKUP_NAME ); CEnableThreadPrivilege etpAcquireRestorePrivilege( SE_RESTORE_NAME );
//
// Open a handle to the quorum directory. The calling thread should have SE_BACKUP_PRIVILEGE and
// SE_RESTORE_PRIVILEGE enabled.
//
hQuorumDirHandle = CreateFile( pcszQuorumDir , GENERIC_ALL , FILE_SHARE_WRITE , NULL , OPEN_EXISTING , FILE_FLAG_BACKUP_SEMANTICS , NULL );
if ( hQuorumDirHandle == INVALID_HANDLE_VALUE ) { // The directory does not exist. This is an error.
sc = TW32( GetLastError() ); LogMsg( "[BC-ClusDB-Create] The directory '%ws' does not exist.", pcszQuorumDir ); break; } // if: the quorum directory does not exist.
// Set the security for this directory.
sc = TW32( ClRtlSetObjSecurityInfo( hQuorumDirHandle , SE_FILE_OBJECT , GENERIC_ALL , GENERIC_ALL , 0 ) );
// First close the handle we opened.
CloseHandle( hQuorumDirHandle );
if ( sc != ERROR_SUCCESS ) { // ClRtlSetObjSecurityInfo() failed.
LogMsg( "[BC-ClusDB-Create] Error %#08x from ClRtlSetObjSecurityInfo().", sc ); break; } // if: ClRtlSetObjSecurityInfo() failed
} while( false ); // dummy do-while loop to avoid gotos.
if ( sc != ERROR_SUCCESS ) { LogMsg( "[BC-ClusDB-Create] Error %#08x occurred while trying to create the local quorum directory. Throwing an exception.", sc ); THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_QUORUM_DIR_CREATE ); } // if: something went wrong.
// Send the last step of this status report.
srCustomizingDB.SendNextStep( S_OK );
TraceFuncExit();
} //*** CClusDBForm::Create
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusDBForm::PopulateHive
//
// Description:
// Make the entries required by the cluster service in the hive.
//
// Arguments:
// pcfClusterFormIn
// Pointer to the CBaseClusterForm object which contains this object.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CRuntimeError
// If any of the APIs fail.
//
// Any that are thrown by the called functions.
//
//--
//////////////////////////////////////////////////////////////////////////////
void CClusDBForm::PopulateHive( CBaseClusterForm * pcfClusterFormIn ) { TraceFunc( "" ); LogMsg( "[BC] Populating the cluster hive." );
DWORD sc = ERROR_SUCCESS;
do { DWORD dwSDSize = 0;
CRegistryKey rkClusterHiveRoot( HKEY_LOCAL_MACHINE , CLUSREG_KEYNAME_CLUSTER , KEY_ALL_ACCESS );
if ( SetupInstallFromInfSection( NULL // optional, handle of a parent window
, pcfClusterFormIn->HGetMainInfFileHandle() // handle to the INF file
, CLUSDB_POPULATE_INF_SECTION_NAME // name of the Install section
, SPINST_REGISTRY // which lines to install from section
, rkClusterHiveRoot.HGetKey() // optional, key for registry installs
, NULL // optional, path for source files
, 0 // optional, specifies copy behavior
, NULL // optional, specifies callback routine
, NULL // optional, callback routine context
, NULL // optional, device information set
, NULL // optional, device info structure
) == FALSE ) { sc = TW32( GetLastError() ); LogMsg( "[BC] Error %#08x returned from SetupInstallFromInfSection while trying to populate the cluster hive.", sc ); break; } // if: SetupInstallServicesFromInfSection failed
LogMsg( "[BC] Basic hive structure created." );
// Set the cluster name.
rkClusterHiveRoot.SetValue( CLUSREG_NAME_CLUS_NAME , REG_SZ , reinterpret_cast< const BYTE * >( pcfClusterFormIn->RStrGetClusterNetBIOSName().PszData() ) , ( pcfClusterFormIn->RStrGetClusterNetBIOSName().NGetLen() + 1 ) * sizeof( WCHAR ) );
//
// Set the default cluster security descriptor.
//
{ SECURITY_DESCRIPTOR * psdSecurityDescriptor = NULL;
// Build the security descriptor.
sc = TW32( ClRtlBuildDefaultClusterSD( pcfClusterFormIn->PSidGetServiceAccountSID() , reinterpret_cast< void ** >( &psdSecurityDescriptor ) , &dwSDSize ) );
// Assign it to a smart pointer for safe release.
CSmartResource< CHandleTrait< HLOCAL , HLOCAL , LocalFree > > smartSD( reinterpret_cast< HLOCAL >( psdSecurityDescriptor ) );
if ( sc != ERROR_SUCCESS ) { LogMsg( "[BC] Error %#08x returned from ClRtlBuildDefaultClusterSD().", sc ); break; } // if: ClRtlBuildDefaultClusterSD() failed.
// Set the security descriptor in the registry.
rkClusterHiveRoot.SetValue( CLUSREG_NAME_CLUS_SD , REG_BINARY , reinterpret_cast< const BYTE * >( psdSecurityDescriptor ) , dwSDSize );
// Set the NT4 version of the security descriptor in the registry.
rkClusterHiveRoot.SetValue( CLUSREG_NAME_CLUS_SECURITY , REG_BINARY , reinterpret_cast< const BYTE * >( psdSecurityDescriptor ) , dwSDSize ); }
LogMsg( "[BC] Cluster common properties set." );
//
// Set the values under the HKLM\Cluster\Nodes key.
//
{ DWORD dwTemp;
CRegistryKey rkNodesKey( rkClusterHiveRoot.HGetKey() , CLUSREG_KEYNAME_NODES , KEY_WRITE );
CRegistryKey rkThisNodeKey;
// Create a subkey for this node.
rkThisNodeKey.CreateKey( rkNodesKey.HGetKey() , pcfClusterFormIn->PszGetNodeIdString() );
// Set the node name.
rkThisNodeKey.SetValue( CLUSREG_NAME_NODE_NAME , REG_SZ , reinterpret_cast< const BYTE *>( pcfClusterFormIn->PszGetNodeName() ) , ( pcfClusterFormIn->DwGetNodeNameLength() + 1 ) * sizeof( WCHAR ) );
// Set the node highest version.
dwTemp = pcfClusterFormIn->DwGetNodeHighestVersion(); rkThisNodeKey.SetValue( CLUSREG_NAME_NODE_HIGHEST_VERSION , REG_DWORD , reinterpret_cast< const BYTE *>( &dwTemp ) , sizeof( dwTemp ) );
// Set the node lowest version.
dwTemp = pcfClusterFormIn->DwGetNodeLowestVersion(); rkThisNodeKey.SetValue( CLUSREG_NAME_NODE_LOWEST_VERSION , REG_DWORD , reinterpret_cast< const BYTE *>( &dwTemp ) , sizeof( dwTemp ) ); }
LogMsg( "[BC] Cluster node subtree customized." );
// Customize the cluster group and the core resources.
CustomizeClusterGroup( pcfClusterFormIn, rkClusterHiveRoot );
// Flush the changes to the registry.
RegFlushKey( rkClusterHiveRoot.HGetKey() );
LogMsg( "[BC] Cluster hive successfully populated." ); } while( false ); // dummy do-while loop to avoid gotos.
if ( sc != ERROR_SUCCESS ) { LogMsg( "[BC] Error %#08x occurred while trying to populate the cluster hive. Throwing an exception.", sc ); THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_CLUSDB_POPULATE_HIVE ); } // if: something went wrong.
TraceFuncExit();
} //*** CClusDBForm::PopulateHive
//////////////////////////////////////////////////////////////////////////////
//++
//
// CClusDBForm::CustomizeClusterGroup
//
// Description:
// Customize the cluster group and the core resources.
//
// Arguments:
// pcfClusterFormIn
// Pointer to the CBaseClusterForm object which contains this object.
//
// rkClusterHiveRootIn
// A CRegistryKey object representing the root of the cluster hive.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CRuntimeError
// If any of the APIs fail.
//
// Any that are thrown by the called functions.
//
//--
//////////////////////////////////////////////////////////////////////////////
void CClusDBForm::CustomizeClusterGroup( CBaseClusterForm * pcfClusterFormIn , CRegistryKey & rkClusterHiveRootIn ) { TraceFunc( "" );
// UUIDs of the cluster group and core resources.
CUuid uuidClusterGroupUuid; CUuid uuidClusterIPAddressResourceUuid; CUuid uuidClusterNameResourceUuid; CUuid uuidLocalQuorumResourceUuid;
// The lengths of the string versions of the above UUIDs.
UINT uiIPUuidLen = (UINT) wcslen( uuidClusterIPAddressResourceUuid.PszGetUuidString() ); UINT uiNameUuidLen = (UINT) wcslen( uuidClusterNameResourceUuid.PszGetUuidString() ); UINT uiLocalQuorumUuidLen = (UINT) wcslen( uuidLocalQuorumResourceUuid.PszGetUuidString() );
UINT uiUuidLen;
// Length of the multisz string that can hold the above resource UUIDs.
uiUuidLen = ( ( uiIPUuidLen + 1 ) + ( uiNameUuidLen + 1 ) + ( uiLocalQuorumUuidLen + 1 ) + 1 );
// Allocate a buffer for this multisz string.
SmartSz sszResourceUuids( new WCHAR[ uiUuidLen ] );
// Was the memory successfully allocated?
if ( sszResourceUuids.FIsEmpty() ) { LogMsg( "[BC] Could not allocate %d character in memory. Throwing an exception.", uiUuidLen ); THROW_RUNTIME_ERROR( E_OUTOFMEMORY , IDS_ERROR_CUSTOMIZE_CLUSTER_GROUP ); } // if: memory allocation failed.
//
// Fill this buffer with the uuids of the core resources.
//
// Make sure that the IP address uuid is the first string in this multisz string.
// This is buffer is reused during setting of the network name dependency on the
// IP address resource.
CopyMemory( sszResourceUuids.PMem() , uuidClusterIPAddressResourceUuid.PszGetUuidString() , ( uiIPUuidLen + 1 ) * sizeof( WCHAR ) );
CopyMemory( sszResourceUuids.PMem() + uiIPUuidLen + 1 , uuidClusterNameResourceUuid.PszGetUuidString() , ( uiNameUuidLen + 1 ) * sizeof( WCHAR ) );
CopyMemory( sszResourceUuids.PMem() + uiIPUuidLen + uiNameUuidLen + 2 , uuidLocalQuorumResourceUuid.PszGetUuidString() , ( uiLocalQuorumUuidLen + 1 ) * sizeof( WCHAR ) );
( sszResourceUuids.PMem() )[ uiUuidLen - 1 ] = L'\0';
//
// Customize the cluster group.
//
{ CRegistryKey rkClusterGroupKey( rkClusterHiveRootIn.HGetKey() , CLUSREG_KEYNAME_GROUPS L"\\" CLUSREG_KEYNAME_CLUSTERGROUP_PLACEHOLDER , KEY_WRITE );
// Replace the placeholder for the cluster group key with an actual UUID.
rkClusterGroupKey.RenameKey( uuidClusterGroupUuid.PszGetUuidString() );
// Set the list of contained resources uuids.
rkClusterGroupKey.SetValue( CLUSREG_NAME_GRP_CONTAINS , REG_MULTI_SZ , reinterpret_cast< const BYTE * >( sszResourceUuids.PMem() ) , uiUuidLen * sizeof( WCHAR ) );
LogMsg( "[BC] Cluster group customized." ); }
//
// Customize the localquorum resource and update the HKLM\Quorum key.
//
{ CRegistryKey rkLocalQuorumResourceKey( rkClusterHiveRootIn.HGetKey() , CLUSREG_KEYNAME_RESOURCES L"\\" CLUSREG_KEYNAME_LOCALQUORUM_RES_PLACEHOLDER , KEY_WRITE );
CRegistryKey rkQuorumKey( rkClusterHiveRootIn.HGetKey() , CLUSREG_KEYNAME_QUORUM , KEY_WRITE );
// Replace the placeholder for the localquorum resource key with an actual UUID.
rkLocalQuorumResourceKey.RenameKey( uuidLocalQuorumResourceUuid.PszGetUuidString() );
// Set the uuid of the localquorum resource under the HKLM\Quorum key
rkQuorumKey.SetValue( CLUSREG_NAME_QUORUM_RESOURCE , REG_SZ , reinterpret_cast< const BYTE * >( uuidLocalQuorumResourceUuid.PszGetUuidString() ) , ( uiLocalQuorumUuidLen + 1 ) * sizeof( WCHAR ) );
LogMsg( "[BC] Localquorum resource customized." ); }
//
// Set the cluster IP address resource private properties.
//
{ CRegistryKey rkClusterIPResourceKey( rkClusterHiveRootIn.HGetKey() , CLUSREG_KEYNAME_RESOURCES L"\\" CLUSREG_KEYNAME_CLUSTERIP_RES_PLACEHOLDER , KEY_WRITE );
LPSTR pszAddr; // don't free!
WCHAR szIPBuffer[ 3 + 1 + 3 + 1 + 3 + 1 + 3 + 1 ]; // "xxx.xxx.xxx.xxx\0"
DWORD dwTemp; int cchWideFormat = 0;
// Replace the placeholder for the cluster IP address resource key with an actual UUID.
rkClusterIPResourceKey.RenameKey( uuidClusterIPAddressResourceUuid.PszGetUuidString() );
// Create the cluster IP address parameters registry key.
CRegistryKey rkIPResParams; rkIPResParams.CreateKey( rkClusterIPResourceKey.HGetKey() , CLUSREG_KEYNAME_PARAMETERS );
// Format the cluster IP address into a dotted quad.
dwTemp = pcfClusterFormIn->DwGetIPAddress(); pszAddr = inet_ntoa( * (struct in_addr *) &dwTemp ); if ( pszAddr == NULL ) { LogMsg( "[BC] inet_ntoa() returned NULL. Mapping it to E_OUTOFMEMORY." ); THROW_RUNTIME_ERROR( E_OUTOFMEMORY, IDS_ERROR_CLUSDB_POPULATE_HIVE ); } cchWideFormat = MultiByteToWideChar( CP_ACP , 0 , pszAddr , -1 , szIPBuffer , ARRAYSIZE( szIPBuffer ) ); if ( cchWideFormat == 0 ) { DWORD sc = TW32( GetLastError() ); LogMsg( "[BC] MultiByteToWideChar failed with error %#08x .", sc ); THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_CUSTOMIZE_CLUSTER_GROUP ); } // Write the IP address to the registry.
rkIPResParams.SetValue( CLUSREG_NAME_IPADDR_ADDRESS , REG_SZ , reinterpret_cast< const BYTE * >( szIPBuffer ) , ( (UINT) wcslen( szIPBuffer ) + 1 ) * sizeof(WCHAR) );
// Format the cluster IP subnet mask into a dotted quad.
dwTemp = pcfClusterFormIn->DwGetIPSubnetMask(); pszAddr = inet_ntoa( * (struct in_addr *) &dwTemp ); if ( pszAddr == NULL ) { LogMsg( "[BC] inet_ntoa() returned NULL. Mapping it to E_OUTOFMEMORY." ); THROW_RUNTIME_ERROR( E_OUTOFMEMORY, IDS_ERROR_CLUSDB_POPULATE_HIVE ); } cchWideFormat = MultiByteToWideChar( CP_ACP , 0 , pszAddr , -1 , szIPBuffer , ARRAYSIZE( szIPBuffer ) ); if ( cchWideFormat == 0 ) { DWORD sc = TW32( GetLastError() ); LogMsg( "[BC] MultiByteToWideChar failed with error %#08x .", sc ); THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_CUSTOMIZE_CLUSTER_GROUP ); }
// Write the IP subnet mask to the registry.
rkIPResParams.SetValue( CLUSREG_NAME_IPADDR_SUBNET_MASK , REG_SZ , reinterpret_cast< const BYTE * >( szIPBuffer ) , ( (UINT) wcslen( szIPBuffer ) + 1 ) * sizeof(WCHAR) );
// Write the IP address network to the registry.
rkIPResParams.SetValue( CLUSREG_NAME_IPADDR_NETWORK , REG_SZ , reinterpret_cast< const BYTE * >( pcfClusterFormIn->RStrGetClusterIPNetwork().PszData() ) , ( pcfClusterFormIn->RStrGetClusterIPNetwork().NGetLen() + 1 ) * sizeof( WCHAR ) );
LogMsg( "[BC] IP address resource customized." ); }
//
// Set the cluster network name resource private properties and dependencies.
//
{ CRegistryKey rkClusterNameResourceKey( rkClusterHiveRootIn.HGetKey() , CLUSREG_KEYNAME_RESOURCES L"\\" CLUSREG_KEYNAME_CLUSTERNAME_RES_PLACEHOLDER , KEY_WRITE );
// Replace the placeholder for the network name resource key with an actual UUID.
rkClusterNameResourceKey.RenameKey( uuidClusterNameResourceUuid.PszGetUuidString() );
//
// Indicate that the network name resource depends on the IP address resource.
//
( sszResourceUuids.PMem() )[ uiIPUuidLen + 1 ] = L'\0';
rkClusterNameResourceKey.SetValue( CLUSREG_NAME_RES_DEPENDS_ON , REG_MULTI_SZ , reinterpret_cast< const BYTE * >( sszResourceUuids.PMem() ) , ( uiIPUuidLen + 2 ) * sizeof( WCHAR ) );
//
// Create the cluster name parameters registry key.
//
CRegistryKey rkNetNameResParams; rkNetNameResParams.CreateKey( rkClusterNameResourceKey.HGetKey() , CLUSREG_KEYNAME_PARAMETERS );
// Write the cluster name to the registry.
rkNetNameResParams.SetValue( CLUSREG_NAME_NETNAME_NAME , REG_SZ , reinterpret_cast< const BYTE * >( pcfClusterFormIn->RStrGetClusterNetBIOSName().PszData() ) , ( pcfClusterFormIn->RStrGetClusterNetBIOSName().NGetLen() + 1 ) * sizeof( WCHAR ) );
// Store the UUID of the network name resource under HKLM\Cluster\ClusterNameResource.
rkClusterHiveRootIn.SetValue( CLUSREG_NAME_CLUS_CLUSTER_NAME_RES , REG_SZ , reinterpret_cast< const BYTE * >( uuidClusterNameResourceUuid.PszGetUuidString() ) , ( uiNameUuidLen + 1 ) * sizeof( WCHAR ) );
LogMsg( "[BC] Network name resource customized." ); }
LogMsg( "[BC] Cluster group and core resources customized." );
TraceFuncExit();
} //*** CClusDBForm::CustomizeClusterGroup
|