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