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.
 
 
 
 
 
 

931 lines
31 KiB

//////////////////////////////////////////////////////////////////////////////
//
// 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