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.
1463 lines
45 KiB
1463 lines
45 KiB
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 2000-2002 Microsoft Corporation
|
|
//
|
|
// Module Name:
|
|
// TaskAnalyzeCluster.cpp
|
|
//
|
|
// Description:
|
|
// CTaskAnalyzeCluster implementation.
|
|
//
|
|
// Maintained By:
|
|
// Galen Barbee (GalenB) 03-FEB-2000
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Include Files
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
#include "Pch.h"
|
|
#include "TaskAnalyzeCluster.h"
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Constant Definitions
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
DEFINE_THISCLASS( "CTaskAnalyzeCluster" )
|
|
|
|
|
|
//*************************************************************************//
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CTaskAnalyzeCluster class
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::S_HrCreateInstance
|
|
//
|
|
// Description:
|
|
// Create a CTaskAnalyzeCluster instance.
|
|
//
|
|
// Arguments:
|
|
// ppunkOut
|
|
//
|
|
// Return Values:
|
|
// S_OK
|
|
// Success.
|
|
//
|
|
// Other HRESULT as failure.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskAnalyzeCluster::S_HrCreateInstance(
|
|
IUnknown ** ppunkOut
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
Assert( ppunkOut != NULL );
|
|
|
|
HRESULT hr = S_OK;
|
|
CTaskAnalyzeCluster * ptac = NULL;
|
|
|
|
if ( ppunkOut == NULL )
|
|
{
|
|
hr = THR( E_POINTER );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
ptac = new CTaskAnalyzeCluster;
|
|
if ( ptac == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
hr = THR( ptac->HrInit() );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
hr = THR( ptac->TypeSafeQI( IUnknown, ppunkOut ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
Cleanup:
|
|
|
|
if ( ptac != NULL )
|
|
{
|
|
ptac->Release();
|
|
} // if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskAnalyzeCluster::S_HrCreateInstance
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::CTaskAnalyzeCluster
|
|
//
|
|
// Description:
|
|
// Constructor
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Values:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
CTaskAnalyzeCluster::CTaskAnalyzeCluster( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
TraceFuncExit();
|
|
|
|
} //*** CTaskAnalyzeCluster::CTaskAnalyzeCluster
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::~CTaskAnalyzeCluster
|
|
//
|
|
// Description:
|
|
// Destructor
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Values:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
CTaskAnalyzeCluster::~CTaskAnalyzeCluster( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
TraceFuncExit();
|
|
|
|
} //*** CTaskAnalyzeCluster::~CTaskAnalyzeCluster
|
|
|
|
|
|
//*************************************************************************//
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CTaskAnalyzeCluster - IUknkown interface.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::QueryInterface
|
|
//
|
|
// Description:
|
|
// Query this object for the passed in interface.
|
|
//
|
|
// Arguments:
|
|
// riidIn
|
|
// Id of interface requested.
|
|
//
|
|
// ppvOut
|
|
// Pointer to the requested interface.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// If the interface is available on this object.
|
|
//
|
|
// E_NOINTERFACE
|
|
// If the interface is not available.
|
|
//
|
|
// E_POINTER
|
|
// ppvOut was NULL.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CTaskAnalyzeCluster::QueryInterface(
|
|
REFIID riidIn
|
|
, LPVOID * ppvOut
|
|
)
|
|
{
|
|
TraceQIFunc( riidIn, ppvOut );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Validate arguments.
|
|
//
|
|
|
|
Assert( ppvOut != NULL );
|
|
if ( ppvOut == NULL )
|
|
{
|
|
hr = THR( E_POINTER );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Handle known interfaces.
|
|
//
|
|
|
|
if ( IsEqualIID( riidIn, IID_IUnknown ) )
|
|
{
|
|
*ppvOut = static_cast< ITaskAnalyzeCluster * >( this );
|
|
} // if: IUnknown
|
|
else if ( IsEqualIID( riidIn, IID_ITaskAnalyzeCluster ) )
|
|
{
|
|
*ppvOut = TraceInterface( __THISCLASS__, ITaskAnalyzeCluster, this, 0 );
|
|
} // else if: ITaskAnalyzeCluster
|
|
else if ( IsEqualIID( riidIn, IID_IDoTask ) )
|
|
{
|
|
*ppvOut = TraceInterface( __THISCLASS__, IDoTask, this, 0 );
|
|
} // else if: IDoTask
|
|
else if ( IsEqualIID( riidIn, IID_IClusCfgCallback ) )
|
|
{
|
|
*ppvOut = TraceInterface( __THISCLASS__, IClusCfgCallback, this, 0 );
|
|
} // else if: IClusCfgCallback
|
|
else if ( IsEqualIID( riidIn, IID_INotifyUI ) )
|
|
{
|
|
*ppvOut = TraceInterface( __THISCLASS__, INotifyUI, this, 0 );
|
|
} // else if: INotifyUI
|
|
else
|
|
{
|
|
*ppvOut = NULL;
|
|
hr = E_NOINTERFACE;
|
|
} // else:
|
|
|
|
//
|
|
// Add a reference to the interface if successful.
|
|
//
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
((IUnknown *) *ppvOut)->AddRef();
|
|
} // if: success
|
|
|
|
Cleanup:
|
|
|
|
QIRETURN_IGNORESTDMARSHALLING( hr, riidIn );
|
|
|
|
} //*** CTaskAnalyzeCluster::QueryInterface
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::AddRef
|
|
//
|
|
// Description:
|
|
// Increment the reference count of this object by one.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// The new reference count.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP_( ULONG )
|
|
CTaskAnalyzeCluster::AddRef( void )
|
|
{
|
|
TraceFunc( "[IUnknown]" );
|
|
|
|
ULONG c = UlAddRef();
|
|
|
|
CRETURN( c );
|
|
|
|
} //*** CTaskAnalyzeCluster::AddRef
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::Release
|
|
//
|
|
// Description:
|
|
// Decrement the reference count of this object by one.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// The new reference count.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP_( ULONG )
|
|
CTaskAnalyzeCluster::Release( void )
|
|
{
|
|
TraceFunc( "[IUnknown]" );
|
|
|
|
ULONG c = UlRelease();
|
|
|
|
CRETURN( c );
|
|
|
|
} //*** CTaskAnalyzeCluster::Release
|
|
|
|
|
|
//*************************************************************************//
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CTaskAnalyzeCluster - IDoTask/ITaskAnalyzeCluster interface.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::BeginTask
|
|
//
|
|
// Description:
|
|
// Task entry point.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success
|
|
//
|
|
// HRESULT failure.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CTaskAnalyzeCluster::BeginTask( void )
|
|
{
|
|
TraceFunc( "[IDoTask]" );
|
|
|
|
HRESULT hr = THR( HrBeginTask() );
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskAnalyzeCluster::BeginTask
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::StopTask
|
|
//
|
|
// Description:
|
|
// Stop task entry point.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success
|
|
//
|
|
// HRESULT failure.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CTaskAnalyzeCluster::StopTask( void )
|
|
{
|
|
TraceFunc( "[IDoTask]" );
|
|
|
|
HRESULT hr = THR( HrStopTask() );
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskAnalyzeCluster::StopTask
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::SetJoiningMode
|
|
//
|
|
// Description:
|
|
// Tell this task whether we are joining nodes to the cluster?
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success
|
|
//
|
|
// HRESULT failure.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CTaskAnalyzeCluster::SetJoiningMode( void )
|
|
{
|
|
TraceFunc( "[ITaskAnalyzeCluster]" );
|
|
|
|
HRESULT hr = THR( HrSetJoiningMode() );
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskAnalyzeCluster::SetJoiningMode
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::SetCookie
|
|
//
|
|
// Description:
|
|
// Receive the completion cookier from the task creator.
|
|
//
|
|
// Arguments:
|
|
// cookieIn
|
|
// The completion cookie to send back to the creator when this
|
|
// task is complete.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success
|
|
//
|
|
// HRESULT failure.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CTaskAnalyzeCluster::SetCookie(
|
|
OBJECTCOOKIE cookieIn
|
|
)
|
|
{
|
|
TraceFunc( "[ITaskAnalyzeCluster]" );
|
|
|
|
HRESULT hr = THR( HrSetCookie( cookieIn ) );
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskAnalyzeCluster::SetCookie
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::SetClusterCookie
|
|
//
|
|
// Description:
|
|
// Receive the object manager cookie of the cluster that we are going
|
|
// to analyze.
|
|
//
|
|
// Arguments:
|
|
// cookieClusterIn
|
|
// The cookie for the cluster to work on.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success
|
|
//
|
|
// HRESULT failure.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CTaskAnalyzeCluster::SetClusterCookie(
|
|
OBJECTCOOKIE cookieClusterIn
|
|
)
|
|
{
|
|
TraceFunc( "[ITaskAnalyzeCluster]" );
|
|
|
|
HRESULT hr = THR( HrSetClusterCookie( cookieClusterIn ) );
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskAnalyzeCluster::SetClusterCookie
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::HrCompareDriveLetterMappings
|
|
//
|
|
// Description:
|
|
// Compare the drive letter mappings on each node to make sure there
|
|
// are no conflicts. Specifically, verify that the system disk on each
|
|
// node does not conflict with storage devices that could be failed over
|
|
// to that node.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Values:
|
|
// S_OK - Operation completed successfully.
|
|
// Other HRESULTs.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskAnalyzeCluster::HrCompareDriveLetterMappings( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrDriveConflictError = S_OK;
|
|
HRESULT hrDriveConflictWarning = S_OK;
|
|
OBJECTCOOKIE cookieDummy;
|
|
OBJECTCOOKIE cookieClusterNode;
|
|
DWORD idxCurrentNode;
|
|
DWORD cNodes;
|
|
ULONG celtDummy;
|
|
int idxDLM;
|
|
BSTR bstrOuterNodeName = NULL;
|
|
BSTR bstrInnerNodeName = NULL;
|
|
BSTR bstrMsg = NULL;
|
|
BSTR bstrMsgREF = NULL;
|
|
IUnknown * punk = NULL;
|
|
IEnumCookies * pecNodes = NULL;
|
|
IClusCfgNodeInfo * pccniOuter = NULL;
|
|
IClusCfgNodeInfo * pccniInner = NULL;
|
|
SDriveLetterMapping dlmOuter;
|
|
SDriveLetterMapping dlmInner;
|
|
|
|
hr = THR( HrSendStatusReport(
|
|
CTaskAnalyzeClusterBase::m_bstrClusterName
|
|
, TASKID_Major_Check_Cluster_Feasibility
|
|
, TASKID_Minor_Check_DriveLetter_Mappings
|
|
, 0
|
|
, 1
|
|
, 0
|
|
, hr
|
|
, IDS_TASKID_MINOR_CHECK_DRIVELETTER_MAPPINGS
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Get the node cookie enumerator.
|
|
//
|
|
|
|
hr = THR( CTaskAnalyzeClusterBase::m_pom->FindObject( CLSID_NodeType, CTaskAnalyzeClusterBase::m_cookieCluster, NULL, DFGUID_EnumCookies, &cookieDummy, &punk ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SSR_ANALYSIS_FAILED( TASKID_Major_Check_Cluster_Feasibility, TASKID_Minor_CompareDriveLetterMappings_Find_Object, hr );
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = THR( punk->TypeSafeQI( IEnumCookies, &pecNodes ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SSR_ANALYSIS_FAILED( TASKID_Major_Check_Cluster_Feasibility, TASKID_Minor_CompareDriveLetterMappings_Find_Object_QI, hr );
|
|
goto Cleanup;
|
|
}
|
|
|
|
//pecNodes = TraceInterface( L"CTaskAnalyzeCluster!IEnumCookies", IEnumCookies, pecNodes, 1 );
|
|
|
|
punk->Release();
|
|
punk = NULL;
|
|
|
|
//
|
|
// If there is only one node, just exit this function.
|
|
//
|
|
|
|
hr = THR( pecNodes->Count( &cNodes ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
if ( cNodes == 1 )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Loop through the enumerator to compare each node with every other node.
|
|
// This requires an outer loop and an inner loop.
|
|
//
|
|
|
|
for ( idxCurrentNode = 0 ;; idxCurrentNode++ )
|
|
{
|
|
//
|
|
// Cleanup.
|
|
//
|
|
|
|
if ( pccniOuter != NULL )
|
|
{
|
|
pccniOuter->Release();
|
|
pccniOuter = NULL;
|
|
}
|
|
TraceSysFreeString( bstrOuterNodeName );
|
|
bstrOuterNodeName = NULL;
|
|
|
|
//
|
|
// Skip to the next node. This is necessary since there is only one
|
|
// enumerator for both the outer and inner loop.
|
|
//
|
|
|
|
if ( idxCurrentNode > 0 )
|
|
{
|
|
// Reset back to the first item in the enumerator.
|
|
hr = STHR( pecNodes->Reset() );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SSR_ANALYSIS_FAILED( TASKID_Major_Check_Cluster_Feasibility, TASKID_Minor_Compare_Drive_Letter_Mappings_Reset_Node_Enumerator, hr );
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Skip to the current node.
|
|
hr = STHR( pecNodes->Skip( idxCurrentNode ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SSR_ANALYSIS_FAILED( TASKID_Major_Check_Cluster_Feasibility, TASKID_Minor_Compare_Drive_Letter_Mappings_Skip_To_Node, hr );
|
|
goto Cleanup;
|
|
}
|
|
if ( hr == S_FALSE )
|
|
{
|
|
//
|
|
// Reached the end of the list.
|
|
//
|
|
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
} // if: not at first node
|
|
|
|
//
|
|
// Find the next node.
|
|
//
|
|
|
|
hr = STHR( pecNodes->Next( 1, &cookieClusterNode, &celtDummy ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SSR_ANALYSIS_FAILED( TASKID_Major_Check_Cluster_Feasibility, TASKID_Minor_Compare_Drive_Letter_Mappings_Find_Outer_Node_Next, hr );
|
|
goto Cleanup;
|
|
}
|
|
if ( hr == S_FALSE )
|
|
{
|
|
//
|
|
// Reached the end of the list.
|
|
//
|
|
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Retrieve the node information.
|
|
//
|
|
|
|
hr = THR( CTaskAnalyzeClusterBase::m_pom->GetObject( DFGUID_NodeInformation, cookieClusterNode, &punk ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SSR_ANALYSIS_FAILED( TASKID_Major_Check_Cluster_Feasibility, TASKID_Minor_Compare_Drive_Letter_Mappings_Outer_NodeInfo_FindObject, hr );
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = THR( punk->TypeSafeQI( IClusCfgNodeInfo, &pccniOuter ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SSR_ANALYSIS_FAILED( TASKID_Major_Check_Cluster_Feasibility, TASKID_Minor_Compare_Drive_Letter_Mappings_Outer_NodeInfo_FindObject_QI, hr );
|
|
goto Cleanup;
|
|
}
|
|
|
|
//pccniOuter = TraceInterface( L"CTaskAnalyzeCluster!IClusCfgNodeInfo", IClusCfgNodeInfo, pccni, 1 );
|
|
|
|
punk->Release();
|
|
punk = NULL;
|
|
|
|
//
|
|
// Get the drive letter mappings for the outer node.
|
|
//
|
|
|
|
hr = THR( pccniOuter->GetDriveLetterMappings( &dlmOuter ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SSR_ANALYSIS_FAILED( TASKID_Major_Check_Cluster_Feasibility, TASKID_Minor_Compare_Drive_Letter_Mappings_Outer_NodeInfo_GetDLM, hr );
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Get the name of the node.
|
|
//
|
|
|
|
hr = THR( pccniOuter->GetName( &bstrOuterNodeName ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SSR_ANALYSIS_FAILED( TASKID_Major_Check_Cluster_Feasibility, TASKID_Minor_Compare_Drive_Letter_Mappings_Outer_GetNodeName, hr );
|
|
goto Cleanup;
|
|
}
|
|
|
|
TraceMemoryAddBSTR( bstrOuterNodeName );
|
|
|
|
//
|
|
// Loop through all the other nodes in the cluster.
|
|
//
|
|
|
|
for ( ;; )
|
|
{
|
|
//
|
|
// Cleanup.
|
|
//
|
|
|
|
if ( pccniInner != NULL )
|
|
{
|
|
pccniInner->Release();
|
|
pccniInner = NULL;
|
|
}
|
|
TraceSysFreeString( bstrInnerNodeName );
|
|
bstrInnerNodeName = NULL;
|
|
|
|
//
|
|
// Find the next node.
|
|
//
|
|
|
|
hr = STHR( pecNodes->Next( 1, &cookieClusterNode, &celtDummy ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SSR_ANALYSIS_FAILED( TASKID_Major_Check_Cluster_Feasibility, TASKID_Minor_Compare_Drive_Letter_Mappings_Find_Inner_Node_Next, hr );
|
|
goto Cleanup;
|
|
}
|
|
if ( hr == S_FALSE )
|
|
{
|
|
//
|
|
// Reached the end of the list.
|
|
//
|
|
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Retrieve the node information.
|
|
//
|
|
|
|
hr = THR( CTaskAnalyzeClusterBase::m_pom->GetObject( DFGUID_NodeInformation, cookieClusterNode, &punk ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SSR_ANALYSIS_FAILED( TASKID_Major_Check_Cluster_Feasibility, TASKID_Minor_Compare_Drive_Letter_Mappings_Inner_NodeInfo_FindObject, hr );
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = THR( punk->TypeSafeQI( IClusCfgNodeInfo, &pccniInner ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SSR_ANALYSIS_FAILED( TASKID_Major_Check_Cluster_Feasibility, TASKID_Minor_Compare_Drive_Letter_Mappings_Inner_NodeInfo_FindObject_QI, hr );
|
|
goto Cleanup;
|
|
}
|
|
|
|
//pccniInner = TraceInterface( L"CTaskAnalyzeCluster!IClusCfgNodeInfo", IClusCfgNodeInfo, pccni, 1 );
|
|
|
|
punk->Release();
|
|
punk = NULL;
|
|
|
|
//
|
|
// Get the drive letter mappings for the inner node.
|
|
//
|
|
|
|
hr = THR( pccniInner->GetDriveLetterMappings( &dlmInner ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SSR_ANALYSIS_FAILED( TASKID_Major_Check_Cluster_Feasibility, TASKID_Minor_Compare_Drive_Letter_Mappings_Inner_NodeInfo_GetDLM, hr );
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Get the name of the node.
|
|
//
|
|
|
|
hr = THR( pccniInner->GetName( &bstrInnerNodeName ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SSR_ANALYSIS_FAILED( TASKID_Major_Check_Cluster_Feasibility, TASKID_Minor_Compare_Drive_Letter_Mappings_Inner_GetNodeName, hr );
|
|
goto Cleanup;
|
|
}
|
|
|
|
TraceMemoryAddBSTR( bstrInnerNodeName );
|
|
|
|
//
|
|
// Loop through the drive letter mappings to make sure that there
|
|
// are no conflicts between the two machines.
|
|
//
|
|
|
|
for ( idxDLM = 0 ; idxDLM < 26 ; idxDLM++ )
|
|
{
|
|
if ( dlmOuter.dluDrives[ idxDLM ] == dluSYSTEM )
|
|
{
|
|
CLSID clsidMinorId;
|
|
hr = THR( CoCreateGuid( &clsidMinorId ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
clsidMinorId = IID_NULL;
|
|
}
|
|
|
|
switch ( dlmInner.dluDrives[ idxDLM ] )
|
|
{
|
|
case dluFIXED_DISK:
|
|
case dluREMOVABLE_DISK:
|
|
{
|
|
LPCWSTR pwszMsg;
|
|
LPCWSTR pwszMsgREF;
|
|
|
|
hrDriveConflictError = HRESULT_FROM_WIN32( ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT );
|
|
|
|
hr = THR( HrFormatStringIntoBSTR(
|
|
g_hInstance
|
|
, IDS_TASKID_MINOR_SYSTEM_DRIVE_LETTER_CONFLICT_ERROR
|
|
, &bstrMsg
|
|
, bstrOuterNodeName
|
|
, L'A' + idxDLM // construct the drive letter
|
|
, bstrInnerNodeName
|
|
) );
|
|
if ( bstrMsg == NULL )
|
|
{
|
|
pwszMsg = L"System drive conflicts.";
|
|
}
|
|
else
|
|
{
|
|
pwszMsg = bstrMsg;
|
|
}
|
|
|
|
hr = THR( HrFormatStringIntoBSTR(
|
|
g_hInstance
|
|
, IDS_TASKID_MINOR_SYSTEM_DRIVE_LETTER_CONFLICT_ERROR_REF
|
|
, &bstrMsgREF
|
|
) );
|
|
if ( bstrMsgREF == NULL )
|
|
{
|
|
pwszMsgREF = L"System drive conflicts. Make sure there is no drive letter conflict between these nodes and re-run the cluster setup.";
|
|
}
|
|
else
|
|
{
|
|
pwszMsgREF = bstrMsgREF;
|
|
}
|
|
|
|
hr = THR( SendStatusReport(
|
|
CTaskAnalyzeClusterBase::m_bstrClusterName
|
|
, TASKID_Minor_Check_DriveLetter_Mappings
|
|
, clsidMinorId
|
|
, 0
|
|
, 1
|
|
, 1
|
|
, hrDriveConflictError
|
|
, pwszMsg
|
|
, NULL
|
|
, pwszMsgREF
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
break;
|
|
} // case: fixed disk or removable disk
|
|
|
|
case dluCOMPACT_DISC:
|
|
case dluNETWORK_DRIVE:
|
|
case dluRAM_DISK:
|
|
{
|
|
LPCWSTR pwszMsg;
|
|
LPCWSTR pwszMsgREF;
|
|
UINT ids = 0;
|
|
|
|
hrDriveConflictWarning = MAKE_HRESULT( 0, FACILITY_WIN32, ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT );
|
|
|
|
if ( dlmInner.dluDrives[ idxDLM ] == dluCOMPACT_DISC )
|
|
{
|
|
ids = IDS_TASKID_MINOR_SYSTEM_DRIVE_LETTER_CONFLICT_CD_WARNING;
|
|
} // if: ( dlmInner.dluDrives[ idxDLM ] == dluCOMPACT_DISC )
|
|
else if ( dlmInner.dluDrives[ idxDLM ] == dluNETWORK_DRIVE )
|
|
{
|
|
ids = IDS_TASKID_MINOR_SYSTEM_DRIVE_LETTER_CONFLICT_NET_WARNING;
|
|
} // if: ( dlmInner.dluDrives[ idxDLM ] == dluNETWORK_DRIVE )
|
|
else if ( dlmInner.dluDrives[ idxDLM ] == dluRAM_DISK )
|
|
{
|
|
ids = IDS_TASKID_MINOR_SYSTEM_DRIVE_LETTER_CONFLICT_RAM_WARNING;
|
|
} // if: ( dlmInner.dluDrives[ idxDLM ] == dluRAM_DISK )
|
|
Assert( ids != 0 );
|
|
|
|
hr = THR( HrFormatStringIntoBSTR(
|
|
g_hInstance
|
|
, ids
|
|
, &bstrMsg
|
|
, bstrOuterNodeName
|
|
, L'A' + idxDLM // construct the drive letter
|
|
, bstrInnerNodeName
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( bstrMsg == NULL )
|
|
{
|
|
pwszMsg = L"System drive conflicts.";
|
|
}
|
|
else
|
|
{
|
|
pwszMsg = bstrMsg;
|
|
}
|
|
|
|
hr = THR( HrFormatStringIntoBSTR(
|
|
g_hInstance
|
|
, IDS_TASKID_MINOR_SYSTEM_DRIVE_LETTER_CONFLICT_WARNING_REF
|
|
, &bstrMsgREF
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( bstrMsgREF == NULL )
|
|
{
|
|
pwszMsgREF = L"System drive conflicts. It is recommended not to have any drive letter conflicts between nodes.";
|
|
}
|
|
else
|
|
{
|
|
pwszMsgREF = bstrMsgREF;
|
|
}
|
|
|
|
hr = THR( SendStatusReport(
|
|
CTaskAnalyzeClusterBase::m_bstrClusterName
|
|
, TASKID_Minor_Check_DriveLetter_Mappings
|
|
, clsidMinorId
|
|
, 0
|
|
, 1
|
|
, 1
|
|
, hrDriveConflictWarning
|
|
, pwszMsg
|
|
, NULL
|
|
, pwszMsgREF
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
break;
|
|
} // case: compact disc, network drive, or ram disk
|
|
} // switch: inner drive letter usage
|
|
} // if: outer node drive is a system drive
|
|
|
|
if ( dlmInner.dluDrives[ idxDLM ] == dluSYSTEM )
|
|
{
|
|
CLSID clsidMinorId;
|
|
hr = THR( CoCreateGuid( &clsidMinorId ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
clsidMinorId = IID_NULL;
|
|
}
|
|
|
|
switch ( dlmOuter.dluDrives[ idxDLM ] )
|
|
{
|
|
case dluFIXED_DISK:
|
|
case dluREMOVABLE_DISK:
|
|
{
|
|
LPCWSTR pwszMsg;
|
|
LPCWSTR pwszMsgREF;
|
|
|
|
hrDriveConflictError = HRESULT_FROM_WIN32( ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT );
|
|
|
|
hr = THR( HrFormatStringIntoBSTR(
|
|
g_hInstance
|
|
, IDS_TASKID_MINOR_SYSTEM_DRIVE_LETTER_CONFLICT_ERROR
|
|
, &bstrMsg
|
|
, bstrInnerNodeName
|
|
, L'A' + idxDLM // construct the drive letter
|
|
, bstrOuterNodeName
|
|
) );
|
|
if ( bstrMsg == NULL )
|
|
{
|
|
pwszMsg = L"System drive conflicts.";
|
|
}
|
|
else
|
|
{
|
|
pwszMsg = bstrMsg;
|
|
}
|
|
|
|
hr = THR( HrFormatStringIntoBSTR(
|
|
g_hInstance
|
|
, IDS_TASKID_MINOR_SYSTEM_DRIVE_LETTER_CONFLICT_ERROR_REF
|
|
, &bstrMsgREF
|
|
) );
|
|
if ( bstrMsgREF == NULL )
|
|
{
|
|
pwszMsgREF = L"System drive conflicts. Make sure there is no drive letter conflict between these nodes and re-run the cluster setup.";
|
|
}
|
|
else
|
|
{
|
|
pwszMsgREF = bstrMsgREF;
|
|
}
|
|
|
|
hr = THR( SendStatusReport(
|
|
CTaskAnalyzeClusterBase::m_bstrClusterName
|
|
, TASKID_Minor_Check_DriveLetter_Mappings
|
|
, clsidMinorId
|
|
, 0
|
|
, 1
|
|
, 1
|
|
, hrDriveConflictError
|
|
, pwszMsg
|
|
, NULL
|
|
, pwszMsgREF
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
break;
|
|
} // case: fixed disk or removable disk
|
|
|
|
case dluCOMPACT_DISC:
|
|
case dluNETWORK_DRIVE:
|
|
case dluRAM_DISK:
|
|
{
|
|
LPCWSTR pwszMsg;
|
|
LPCWSTR pwszMsgREF;
|
|
UINT ids = 0;
|
|
|
|
hrDriveConflictWarning = MAKE_HRESULT( 0, FACILITY_WIN32, ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT );
|
|
|
|
if ( dlmOuter.dluDrives[ idxDLM ] == dluCOMPACT_DISC )
|
|
{
|
|
ids = IDS_TASKID_MINOR_SYSTEM_DRIVE_LETTER_CONFLICT_CD_WARNING;
|
|
} // if: ( dlmOuter.dluDrives[ idxDLM ] == dluCOMPACT_DISC )
|
|
else if ( dlmOuter.dluDrives[ idxDLM ] == dluNETWORK_DRIVE )
|
|
{
|
|
ids = IDS_TASKID_MINOR_SYSTEM_DRIVE_LETTER_CONFLICT_NET_WARNING;
|
|
} // if: ( dlmOuter.dluDrives[ idxDLM ] == dluNETWORK_DRIVE )
|
|
else if ( dlmOuter.dluDrives[ idxDLM ] == dluRAM_DISK )
|
|
{
|
|
ids = IDS_TASKID_MINOR_SYSTEM_DRIVE_LETTER_CONFLICT_RAM_WARNING;
|
|
} // if: ( dlmOuter.dluDrives[ idxDLM ] == dluRAM_DISK )
|
|
Assert( ids != 0 );
|
|
|
|
hr = THR( HrFormatStringIntoBSTR(
|
|
g_hInstance
|
|
, ids
|
|
, &bstrMsg
|
|
, bstrInnerNodeName
|
|
, L'A' + idxDLM // construct the drive letter
|
|
, bstrOuterNodeName
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( bstrMsg == NULL )
|
|
{
|
|
pwszMsg = L"System drive conflicts.";
|
|
}
|
|
else
|
|
{
|
|
pwszMsg = bstrMsg;
|
|
}
|
|
|
|
hr = THR( HrFormatStringIntoBSTR(
|
|
g_hInstance
|
|
, IDS_TASKID_MINOR_SYSTEM_DRIVE_LETTER_CONFLICT_WARNING_REF
|
|
, &bstrMsgREF
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( bstrMsgREF == NULL )
|
|
{
|
|
pwszMsgREF = L"System drive conflicts. It is recommended not to have any drive letter conflicts between nodes.";
|
|
}
|
|
else
|
|
{
|
|
pwszMsgREF = bstrMsgREF;
|
|
}
|
|
|
|
hr = THR( SendStatusReport(
|
|
CTaskAnalyzeClusterBase::m_bstrClusterName
|
|
, TASKID_Minor_Check_DriveLetter_Mappings
|
|
, clsidMinorId
|
|
, 0
|
|
, 1
|
|
, 1
|
|
, hrDriveConflictWarning
|
|
, pwszMsg
|
|
, NULL
|
|
, pwszMsgREF
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
break;
|
|
} // case: compact disc, network drive, or ram disk
|
|
} // switch: outer drive letter usage
|
|
} // if: inner node drive is a system drive
|
|
} // for: each drive letter mapping
|
|
} // for ever: inner node loop
|
|
} // for ever: outer node loop
|
|
|
|
Cleanup:
|
|
|
|
THR( HrSendStatusReport(
|
|
CTaskAnalyzeClusterBase::m_bstrClusterName
|
|
, TASKID_Major_Check_Cluster_Feasibility
|
|
, TASKID_Minor_Check_DriveLetter_Mappings
|
|
, 0
|
|
, 1
|
|
, 1
|
|
, hr
|
|
, IDS_TASKID_MINOR_CHECK_DRIVELETTER_MAPPINGS
|
|
) );
|
|
|
|
TraceSysFreeString( bstrOuterNodeName );
|
|
TraceSysFreeString( bstrInnerNodeName );
|
|
TraceSysFreeString( bstrMsg );
|
|
TraceSysFreeString( bstrMsgREF );
|
|
|
|
if ( pecNodes != NULL )
|
|
{
|
|
pecNodes->Release();
|
|
}
|
|
|
|
if ( pccniOuter != NULL )
|
|
{
|
|
pccniOuter->Release();
|
|
}
|
|
|
|
if ( pccniInner != NULL )
|
|
{
|
|
pccniInner->Release();
|
|
}
|
|
|
|
if ( punk != NULL )
|
|
{
|
|
punk->Release();
|
|
}
|
|
|
|
//
|
|
// Set the return value if an error or warning occurred.
|
|
// An error will override a warning.
|
|
//
|
|
if ( hrDriveConflictError != S_OK )
|
|
{
|
|
hr = hrDriveConflictError;
|
|
}
|
|
else if ( hrDriveConflictWarning != S_OK )
|
|
{
|
|
hr = hrDriveConflictWarning;
|
|
}
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskAnalyzeCluster::HrCompareDriveLetterMappings
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::HrCreateNewResourceInCluster
|
|
//
|
|
// Description:
|
|
// Create a new resource in the cluster configuration since there was
|
|
// not a match to the resource already in the cluster.
|
|
//
|
|
// Arguments:
|
|
// pccmriIn
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success.
|
|
//
|
|
// Other HRESULT error.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskAnalyzeCluster::HrCreateNewResourceInCluster(
|
|
IClusCfgManagedResourceInfo * pccmriIn
|
|
, BSTR bstrNodeResNameIn
|
|
, BSTR * pbstrNodeResUIDInout
|
|
, BSTR bstrNodeNameIn
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
Assert( pccmriIn != NULL );
|
|
Assert( pbstrNodeResUIDInout != NULL );
|
|
|
|
HRESULT hr = S_OK;
|
|
IClusCfgManagedResourceInfo * pccmriNew = NULL;
|
|
|
|
//
|
|
// Need to create a new object.
|
|
//
|
|
|
|
hr = THR( HrCreateNewManagedResourceInClusterConfiguration( pccmriIn, &pccmriNew ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Display the name of the node's resource in the log.
|
|
//
|
|
|
|
LogMsg(
|
|
L"[MT] Created object for resource '%ws' ('%ws') from node '%ws' in the cluster configuration."
|
|
, bstrNodeResNameIn
|
|
, *pbstrNodeResUIDInout
|
|
, bstrNodeNameIn
|
|
);
|
|
|
|
//
|
|
// If this is the quorum resource, remember it.
|
|
//
|
|
|
|
hr = STHR( pccmriNew->IsQuorumResource() );
|
|
if ( hr == S_OK )
|
|
{
|
|
//
|
|
// Remember the quorum device's UID.
|
|
//
|
|
|
|
Assert( m_bstrQuorumUID == NULL );
|
|
m_bstrQuorumUID = *pbstrNodeResUIDInout;
|
|
*pbstrNodeResUIDInout = NULL;
|
|
} // if:
|
|
|
|
hr = S_OK;
|
|
|
|
Cleanup:
|
|
|
|
if ( pccmriNew != NULL )
|
|
{
|
|
pccmriNew->Release();
|
|
} // if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskAnalyzeCluster::HrCreateNewResourceInCluster
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::HrCreateNewResourceInCluster
|
|
//
|
|
// Description:
|
|
// Create a new resource in the cluster configuration since there was
|
|
// not a match to the resource already in the cluster.
|
|
//
|
|
// Arguments:
|
|
// pccmriIn
|
|
// The source object.
|
|
//
|
|
// ppccmriOut
|
|
// The new object that was created.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success.
|
|
//
|
|
// Other HRESULT error.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskAnalyzeCluster::HrCreateNewResourceInCluster(
|
|
IClusCfgManagedResourceInfo * pccmriIn
|
|
, IClusCfgManagedResourceInfo ** ppccmriOut
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
Assert( pccmriIn != NULL );
|
|
Assert( ppccmriOut != NULL );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Need to create a new object.
|
|
//
|
|
|
|
hr = THR( HrCreateNewManagedResourceInClusterConfiguration( pccmriIn, ppccmriOut ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// If the resource is manageable in a cluster then we should set it
|
|
// to be managed so it will be created by PostConfig.
|
|
//
|
|
|
|
hr = STHR( (*ppccmriOut)->IsManagedByDefault() );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
if ( hr == S_OK )
|
|
{
|
|
hr = THR( (*ppccmriOut)->SetManaged( TRUE ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
} // if:
|
|
|
|
hr = S_OK;
|
|
|
|
Cleanup:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskAnalyzeCluster::HrCreateNewResourceInCluster
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::HrFixupErrorCode
|
|
//
|
|
// Description:
|
|
// Do any fix ups needed for the passed in error code and return the
|
|
// fixed up value. The default implementation is to do no fixups.
|
|
//
|
|
// Arguments:
|
|
// hrIn
|
|
// The error code to fix up.
|
|
//
|
|
// Return Value:
|
|
// The passed in error code.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskAnalyzeCluster::HrFixupErrorCode(
|
|
HRESULT hrIn
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRETURN( hrIn );
|
|
|
|
} //*** CTaskAnalyzeCluster::HrFixupErrorCode
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::GetNodeCannotVerifyQuorumStringRefId
|
|
//
|
|
// Description:
|
|
// Return the correct string ids for the message that is displayed
|
|
// to the user when there isn't a quorum resource.
|
|
//
|
|
// Arguments:
|
|
// pdwRefIdOut
|
|
// The reference text to show the user.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
CTaskAnalyzeCluster::GetNodeCannotVerifyQuorumStringRefId(
|
|
DWORD * pdwRefIdOut
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
Assert( pdwRefIdOut != NULL );
|
|
|
|
*pdwRefIdOut = IDS_TASKID_MINOR_NODE_CANNOT_ACCESS_QUORUM_ERROR_REF;
|
|
|
|
TraceFuncExit();
|
|
|
|
} //*** CTaskAnalyzeCluster::GetNodeCannotVerifyQuorumStringRefId
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::GetNoCommonQuorumToAllNodesStringIds
|
|
//
|
|
// Description:
|
|
// Return the correct string ids for the message that is displayed
|
|
// to the user when there isn't a common to all nodes quorum resource.
|
|
//
|
|
// Arguments:
|
|
// pdwMessageIdOut
|
|
// The message to show the user.
|
|
//
|
|
// pdwRefIdOut
|
|
// The reference text to show the user.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
CTaskAnalyzeCluster::GetNoCommonQuorumToAllNodesStringIds(
|
|
DWORD * pdwMessageIdOut
|
|
, DWORD * pdwRefIdOut
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
Assert( pdwMessageIdOut != NULL );
|
|
Assert( pdwRefIdOut != NULL );
|
|
|
|
*pdwMessageIdOut = IDS_TASKID_MINOR_MISSING_COMMON_QUORUM_RESOURCE_ERROR;
|
|
*pdwRefIdOut = IDS_TASKID_MINOR_MISSING_COMMON_QUORUM_RESOURCE_ERROR_REF;
|
|
|
|
TraceFuncExit();
|
|
|
|
} //*** CTaskAnalyzeCluster::GetNoCommonQuorumToAllNodesStringIds
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskAnalyzeCluster::HrShowLocalQuorumWarning
|
|
//
|
|
// Description:
|
|
// Send the warning about forcing local quorum to the UI.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// The SSR was done properly.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskAnalyzeCluster::HrShowLocalQuorumWarning( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = THR( HrSendStatusReport(
|
|
CTaskAnalyzeClusterBase::m_bstrClusterName
|
|
, TASKID_Minor_Finding_Common_Quorum_Device
|
|
, TASKID_Minor_Forced_Local_Quorum
|
|
, 1
|
|
, 1
|
|
, 1
|
|
, MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_WIN32, ERROR_QUORUM_DISK_NOT_FOUND )
|
|
, IDS_TASKID_MINOR_FORCED_LOCAL_QUORUM
|
|
) );
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskAnalyzeCluster::HrShowLocalQuorumWarning
|