461 lines
15 KiB
C++
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()
|