WindowsXP/base/cluster/mgmt/cluscfg/basecluster/cbaseclusterform.cpp
2025-04-27 07:49:33 -04:00

461 lines
15 KiB
C++

//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1999-2000 Microsoft Corporation
//
// Module Name:
// CBaseClusterForm.cpp
//
// Description:
// Contains the definition of the CBaseClusterForm class.
//
// Documentation:
// TODO: Add pointer to external documentation later.
//
// Maintained By:
// Vij Vasu (Vvasu) 08-MAR-2000
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Include Files
//////////////////////////////////////////////////////////////////////////////
// The precompiled header.
#include "pch.h"
// The header file of this class.
#include "CBaseClusterForm.h"
// For the CClusSvcAccountConfig action
#include "CClusSvcAccountConfig.h"
// For the CClusNetCreate action
#include "CClusNetCreate.h"
// For the CClusDiskForm action
#include "CClusDiskForm.h"
// For the CClusDBForm action
#include "CClusDBForm.h"
// For the CClusSvcCreate action
#include "CClusSvcCreate.h"
// For the CNodeConfig action
#include "CNodeConfig.h"
//////////////////////////////////////////////////////////////////////////
// Macros definitions
//////////////////////////////////////////////////////////////////////////
// The minimum amount of free space in bytes, required by the
// localquorum resource (5 Mb)
#define LOCALQUORUM_MIN_FREE_DISK_SPACE 5242880
// Name of the file system required by the local quorum resource
#define LOCALQUORUM_FILE_SYSTEM L"NTFS"
//////////////////////////////////////////////////////////////////////////////
//++
//
// CBaseClusterForm::CBaseClusterForm
//
// Description:
// Constructor of the CBaseClusterForm class.
//
// This function also stores the parameters that are required for
// cluster formation.
//
// Arguments:
// pbcaiInterfaceIn
// Pointer to the interface class for this library.
//
// pszClusterNameIn
// Name of the cluster to be formed.
//
// pszClusterAccountNameIn
// pszClusterAccountPwdIn
// pszClusterAccountDomainIn
// Specifies the account to be used as the cluster service account.
//
// dwClusterIPAddressIn
// dwClusterIPSubnetMaskIn
// pszClusterIPNetworkIn
// Specifies the IP address and network of the cluster IP address.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CConfigError
// If the OS version is incorrect or if the installation state
// of the cluster binaries is wrong.
//
// CRuntimeError
// If any of the APIs fail.
//
//--
//////////////////////////////////////////////////////////////////////////////
CBaseClusterForm::CBaseClusterForm(
CBCAInterface * pbcaiInterfaceIn
, const WCHAR * pcszClusterNameIn
, const WCHAR * pszClusterBindingStringIn
, const WCHAR * pcszClusterAccountNameIn
, const WCHAR * pcszClusterAccountPwdIn
, const WCHAR * pcszClusterAccountDomainIn
, DWORD dwClusterIPAddressIn
, DWORD dwClusterIPSubnetMaskIn
, const WCHAR * pszClusterIPNetworkIn
)
: BaseClass(
pbcaiInterfaceIn
, pcszClusterNameIn
, pszClusterBindingStringIn
, pcszClusterAccountNameIn
, pcszClusterAccountPwdIn
, pcszClusterAccountDomainIn
)
, m_dwClusterIPAddress( dwClusterIPAddressIn )
, m_dwClusterIPSubnetMask( dwClusterIPSubnetMaskIn )
, m_strClusterIPNetwork( pszClusterIPNetworkIn )
{
BCATraceScope( "" );
LogMsg( "The current cluster configuration task is: Cluster Formation." );
CStatusReport srInitForm(
PBcaiGetInterfacePointer()
, TASKID_Major_Configure_Cluster_Services
, TASKID_Minor_Initializing_Cluster_Form
, 0, 1
, IDS_TASK_FORM_INIT
);
// Send the next step of this status report.
srInitForm.SendNextStep( S_OK );
//
// Write parameters to log file.
//
LogMsg(
"Cluster IP Address => %d.%d.%d.%d"
, ( m_dwClusterIPAddress & 0x000000FF )
, ( m_dwClusterIPAddress & 0x0000FF00 ) >> 8
, ( m_dwClusterIPAddress & 0x00FF0000 ) >> 16
, ( m_dwClusterIPAddress & 0xFF000000 ) >> 24
);
LogMsg(
"Subnet Mask => %d.%d.%d.%d"
, ( m_dwClusterIPSubnetMask & 0x000000FF )
, ( m_dwClusterIPSubnetMask & 0x0000FF00 ) >> 8
, ( m_dwClusterIPSubnetMask & 0x00FF0000 ) >> 16
, ( m_dwClusterIPSubnetMask & 0xFF000000 ) >> 24
);
LogMsg( "Cluster IP Network name => '%s'", m_strClusterIPNetwork.PszData() );
//
// Perform a sanity check on the parameters used by this class
//
if ( ( pszClusterIPNetworkIn == NULL ) || ( *pszClusterIPNetworkIn == L'\0' ) )
{
BCATraceMsg( "The cluster IP Network name is empty. Throwing exception." );
LogMsg( "The cluster IP Network name is invalid." );
THROW_CONFIG_ERROR( THR( E_INVALIDARG ), IDS_ERROR_INVALID_IP_NET );
} // if: the cluster IP network name is empty
//
// Make sure that there is enough free space under the cluster directory.
// The quorum logs for the localquorum resource will be under this directory.
//
{
BOOL fSuccess;
ULARGE_INTEGER uliFreeBytesAvailToUser;
ULARGE_INTEGER uliTotalBytes;
ULARGE_INTEGER uliTotalFree;
ULARGE_INTEGER uliRequired;
uliRequired.QuadPart = LOCALQUORUM_MIN_FREE_DISK_SPACE;
fSuccess = GetDiskFreeSpaceEx(
RStrGetClusterInstallDirectory().PszData()
, &uliFreeBytesAvailToUser
, &uliTotalBytes
, &uliTotalFree
);
if ( fSuccess == 0 )
{
DWORD dwError = TW32( GetLastError() );
LogMsg( "Error %#08x occurred trying to get free disk space.", dwError );
BCATraceMsg1( "Error %#08x occurred trying to get free disk space. Throwing exception.", dwError );
THROW_RUNTIME_ERROR(
HRESULT_FROM_WIN32( dwError )
, IDS_ERROR_GETTING_FREE_DISK_SPACE
);
} // if: GetDiskFreeSpaceEx failed
LogMsg(
"Free space required = %#x%08x bytes. Available = %#x%08x bytes."
, uliRequired.HighPart
, uliRequired.LowPart
, uliFreeBytesAvailToUser.HighPart
, uliFreeBytesAvailToUser.LowPart
);
if ( uliFreeBytesAvailToUser.QuadPart < uliRequired.QuadPart )
{
LogMsg( "There isn't enough free space for the localquorum resource. Form cannot proceed." );
BCATraceMsg( "There isn't enough free space for the localquorum resource. Throwing exception." );
THROW_CONFIG_ERROR(
HRESULT_FROM_WIN32( THR( ERROR_DISK_FULL ) )
, IDS_ERROR_INSUFFICIENT_DISK_SPACE
);
} // if: there isn't enough free space for localquorum.
LogMsg( "There is enough free space for the localquorum resource. Form can proceed." );
}
/*
//
// KB: Vij Vasu (VVasu) 07-SEP-2000. Localquorum no longer needs NTFS disks
// The code below has been commented out since it is no longer required that
// localquorum resources use NTFS disks. This was confirmed by SunitaS.
//
//
// Make sure that the drive on which the cluster binaries are installed has NTFS
// on it. This is required by the localquorum resource.
//
{
WCHAR szVolumePathName[ MAX_PATH ];
WCHAR szFileSystemName[ MAX_PATH ];
BOOL fSuccess;
fSuccess = GetVolumePathName(
RStrGetClusterInstallDirectory().PszData()
, szVolumePathName
, sizeof( szVolumePathName ) / sizeof( szVolumePathName[ 0 ] )
);
if ( fSuccess == 0 )
{
DWORD dwError = TW32( GetLastError() );
LogMsg( "Error %#08x occurred trying to get file system type. Form cannot proceed.", dwError );
BCATraceMsg1( "Error %#08x occurred trying to get file system type. Throwing exception.", dwError );
THROW_RUNTIME_ERROR(
HRESULT_FROM_WIN32( dwError )
, IDS_ERROR_GETTING_FILE_SYSTEM
);
} // if: GetVolumePathName failed
BCATraceMsg1( "The volume path name of the disk on which the cluster binaries reside is '%ws'.", szVolumePathName );
fSuccess = GetVolumeInformation(
szVolumePathName // root directory
, NULL // volume name buffer
, 0 // length of name buffer
, NULL // volume serial number
, NULL // maximum file name length
, NULL // file system options
, szFileSystemName // file system name buffer
, sizeof( szFileSystemName ) / sizeof( szFileSystemName[ 0 ] ) // length of file system name buffer
);
if ( fSuccess == 0 )
{
DWORD dwError = TW32( GetLastError() );
LogMsg( "Error %#08x occurred trying to get file system type. Form cannot proceed.", dwError );
BCATraceMsg1( "Error %#08x occurred trying to get file system type. Throwing exception.", dwError );
THROW_RUNTIME_ERROR(
HRESULT_FROM_WIN32( dwError )
, IDS_ERROR_GETTING_FILE_SYSTEM
);
} // if: GetVolumeInformation failed
BCATraceMsg3(
"The file system on '%ws' is '%ws'. Required file system is '%s'."
, szVolumePathName
, szFileSystemName
, LOCALQUORUM_FILE_SYSTEM
);
if ( _wcsicmp( szFileSystemName, LOCALQUORUM_FILE_SYSTEM ) != 0 )
{
LogMsg( "LocalQuorum resource cannot be created on non-NTFS disk '%ws'. Form cannot proceed.", szVolumePathName );
BCATraceMsg1( "LocalQuorum resource cannot be created on non-NTFS disk '%ws'. Throwing exception.", szVolumePathName );
// MUSTDO - must define proper HRESULT for this error. ( Vvasu - 10 Mar 2000 )
THROW_CONFIG_ERROR(
HRESULT_FROM_WIN32( TW32( ERROR_UNRECOGNIZED_MEDIA ) )
, IDS_ERROR_INCORRECT_INSTALL_STATE
);
} // if: the file system is not correct.
LogMsg( "LocalQuorum resource will be created on disk '%ws'. Form can proceed.", szVolumePathName );
}
*/
//
// Create a list of actions to be performed.
// The order of appending actions is significant.
//
// Add the action to configure the cluster service account.
RalGetActionList().AppendAction( new CClusSvcAccountConfig( this ) );
// Add the action to create the ClusNet service.
RalGetActionList().AppendAction( new CClusNetCreate( this ) );
// Add the action to create the ClusDisk service.
RalGetActionList().AppendAction( new CClusDiskForm( this ) );
// Add the action to create the cluster database.
RalGetActionList().AppendAction( new CClusDBForm( this ) );
// Add the action to create the ClusSvc service.
RalGetActionList().AppendAction( new CClusSvcCreate( this ) );
// Add the action to perform miscellaneous tasks.
RalGetActionList().AppendAction( new CNodeConfig( this ) );
// Indicate if rollback is possible or not.
SetRollbackPossible( RalGetActionList().FIsRollbackPossible() );
// Indicate that a cluster should be formed during commit.
SetAction( eCONFIG_ACTION_FORM );
// Send the last step of a status report.
srInitForm.SendNextStep( S_OK );
LogMsg( "Initialization for cluster formation complete." );
} //*** CBaseClusterForm::CBaseClusterForm()
//////////////////////////////////////////////////////////////////////////////
//++
//
// CBaseClusterForm::~CBaseClusterForm
//
// Description:
// Destructor of the CBaseClusterForm class
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
CBaseClusterForm::~CBaseClusterForm( void ) throw()
{
BCATraceScope( "" );
} //*** CBaseClusterForm::~CBaseClusterForm()
//////////////////////////////////////////////////////////////////////////////
//++
//
// void
// CBaseClusterForm::Commit
//
// Description:
// Form the cluster.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CRuntimeError
// If any of the APIs fail.
//
// Any exceptions thrown by functions called.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
CBaseClusterForm::Commit( void )
{
BCATraceScope( "" );
CStatusReport srFormingCluster(
PBcaiGetInterfacePointer()
, TASKID_Major_Configure_Cluster_Services
, TASKID_Minor_Forming_Node
, 0, 1
, IDS_TASK_FORMING_CLUSTER
);
LogMsg( "Initiating cluster formation." );
// Send the next step of this status report.
srFormingCluster.SendNextStep( S_OK );
// Call the base class commit routine. This commits the action list.
BaseClass::Commit();
// If we are here, then everything went well.
SetCommitCompleted( true );
// Send the last step of this status report.
srFormingCluster.SendNextStep( S_OK );
} //*** CBaseClusterForm::Commit()
//////////////////////////////////////////////////////////////////////////////
//++
//
// void
// CBaseClusterForm::Rollback
//
// Description:
// Performs the rolls back of the action committed by this object.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any exceptions thrown by functions called.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
CBaseClusterForm::Rollback( void )
{
BCATraceScope( "" );
// Rollback the actions.
BaseClass::Rollback();
SetCommitCompleted( false );
} //*** CBaseClusterForm::Rollback()