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.
3058 lines
82 KiB
3058 lines
82 KiB
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 2000-2002 Microsoft Corporation
|
|
//
|
|
// Module Name:
|
|
// CClusCfgServer.cpp
|
|
//
|
|
// Description:
|
|
// This file contains the definition of the CClusCfgServer class.
|
|
//
|
|
// The class CClusCfgServer is the implementations of the
|
|
// IClusCfgServer interface.
|
|
//
|
|
// Maintained By:
|
|
// Galen Barbee (GalenB) 03-FEB-2000
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Include Files
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
#include "Pch.h"
|
|
#include <ClusRTL.h>
|
|
#include "CClusCfgServer.h"
|
|
#include "PrivateInterfaces.h"
|
|
#include "CClusCfgNodeInfo.h"
|
|
#include "CEnumClusCfgManagedResources.h"
|
|
#include "CClusCfgCallback.h"
|
|
#include "EventName.h"
|
|
#include <ClusRtl.h>
|
|
#include <windns.h>
|
|
#include <ClusterUtils.h>
|
|
#include <clusudef.h>
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Constant Definitions
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
DEFINE_THISCLASS( "CClusCfgServer" );
|
|
|
|
#define CLEANUP_LOCK_NAME L"Global\\Microsoft Cluster Configuration Cleanup Lock"
|
|
|
|
|
|
//*************************************************************************//
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CClusCfgServer class
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::S_HrCreateInstance
|
|
//
|
|
// Description:
|
|
// Create a CClusCfgServer instance.
|
|
//
|
|
// Arguments:
|
|
// ppunkOut -
|
|
//
|
|
// Return Values:
|
|
// Pointer to CClusCfgServer instance.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CClusCfgServer::S_HrCreateInstance( IUnknown ** ppunkOut )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_OK;
|
|
CClusCfgServer * pccs = NULL;
|
|
|
|
if ( ppunkOut == NULL )
|
|
{
|
|
hr = THR( E_POINTER );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// KB: Since this is usually the start of the "server" thread,
|
|
// we will cause it to read its thread settings here.
|
|
//
|
|
TraceInitializeThread( L"ServerThread" );
|
|
|
|
pccs = new CClusCfgServer();
|
|
if ( pccs == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Cleanup;
|
|
} // if: error allocating object
|
|
|
|
hr = THR( pccs->HrInit() );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: HrInit() failed
|
|
|
|
hr = THR( pccs->TypeSafeQI( IUnknown, ppunkOut ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: QI failed
|
|
|
|
Cleanup:
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
LogMsg( L"[SRV] CClusCfgServer::S_HrCreateInstance() failed. (hr = %#08x)", hr );
|
|
} // if:
|
|
|
|
if ( pccs != NULL )
|
|
{
|
|
pccs->Release();
|
|
} // if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::S_HrCreateInstance
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::CClusCfgServer
|
|
//
|
|
// Description:
|
|
// Constructor of the CClusCfgServer class. This initializes
|
|
// the m_cRef variable to 1 instead of 0 to account of possible
|
|
// QueryInterface failure in DllGetClassObject.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
CClusCfgServer::CClusCfgServer( void )
|
|
: m_cRef( 1 )
|
|
, m_pIWbemServices( NULL )
|
|
, m_lcid( LOCALE_NEUTRAL )
|
|
, m_fCanBeClustered( TRUE )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
// Increment the count of components in memory so the DLL hosting this
|
|
// object cannot be unloaded.
|
|
InterlockedIncrement( &g_cObjects );
|
|
|
|
Assert( m_picccCallback == NULL );
|
|
Assert( m_punkNodeInfo == NULL );
|
|
Assert( m_punkEnumResources == NULL );
|
|
Assert( m_punkNetworksEnum == NULL );
|
|
Assert( m_bstrNodeName == NULL );
|
|
Assert( !m_fUsePolling );
|
|
Assert( m_bstrBindingString == NULL );
|
|
|
|
TraceFuncExit();
|
|
|
|
} //*** CClusCfgServer::CClusCfgServer
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::~CClusCfgServer
|
|
//
|
|
// Description:
|
|
// Destructor of the CClusCfgServer class.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
CClusCfgServer::~CClusCfgServer( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
TraceSysFreeString( m_bstrNodeName );
|
|
TraceSysFreeString( m_bstrBindingString );
|
|
|
|
if ( m_pIWbemServices != NULL )
|
|
{
|
|
m_pIWbemServices->Release();
|
|
} // if:
|
|
|
|
if ( m_punkNodeInfo != NULL )
|
|
{
|
|
m_punkNodeInfo->Release();
|
|
} // if:
|
|
|
|
if ( m_punkEnumResources != NULL )
|
|
{
|
|
m_punkEnumResources->Release();
|
|
} // if:
|
|
|
|
if ( m_punkNetworksEnum != NULL )
|
|
{
|
|
m_punkNetworksEnum->Release();
|
|
} // if:
|
|
|
|
if ( m_picccCallback != NULL )
|
|
{
|
|
m_picccCallback->Release();
|
|
} // if:
|
|
|
|
// There's going to be one less component in memory. Decrement component count.
|
|
InterlockedDecrement( &g_cObjects );
|
|
|
|
TraceFuncExit();
|
|
|
|
} //*** CClusCfgServer::~CClusCfgServer
|
|
|
|
|
|
//*************************************************************************//
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CClusCfgServer -- IUknkown interface.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::AddRef
|
|
//
|
|
// Description:
|
|
// Increment the reference count of this object by one.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// The new reference count.
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP_( ULONG )
|
|
CClusCfgServer::AddRef( void )
|
|
{
|
|
TraceFunc( "[IUnknown]" );
|
|
|
|
InterlockedIncrement( &m_cRef );
|
|
|
|
CRETURN( m_cRef );
|
|
|
|
} //*** CClusCfgServer::AddRef
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::Release
|
|
//
|
|
// Description:
|
|
// Decrement the reference count of this object by one.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// The new reference count.
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP_( ULONG )
|
|
CClusCfgServer::Release( void )
|
|
{
|
|
TraceFunc( "[IUnknown]" );
|
|
|
|
LONG cRef;
|
|
|
|
cRef = InterlockedDecrement( &m_cRef );
|
|
if ( cRef == 0 )
|
|
{
|
|
TraceDo( delete this );
|
|
} // if: reference count equal to zero
|
|
|
|
CRETURN( cRef );
|
|
|
|
} //*** CClusCfgServer::Release
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::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.
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CClusCfgServer::QueryInterface(
|
|
REFIID riidIn
|
|
, void ** ppvOut
|
|
)
|
|
{
|
|
TraceQIFunc( riidIn, ppvOut );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Validate arguments.
|
|
//
|
|
|
|
Assert( ppvOut != NULL );
|
|
if ( ppvOut == NULL )
|
|
{
|
|
hr = THR( E_POINTER );
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Handle known interfaces.
|
|
//
|
|
|
|
if ( IsEqualIID( riidIn, IID_IUnknown ) )
|
|
{
|
|
*ppvOut = static_cast< IClusCfgServer * >( this );
|
|
} // if: IUnknown
|
|
else if ( IsEqualIID( riidIn, IID_IClusCfgServer ) )
|
|
{
|
|
*ppvOut = TraceInterface( __THISCLASS__, IClusCfgServer, this, 0 );
|
|
} // else if: IClusCfgServer
|
|
else if ( IsEqualIID( riidIn, IID_IClusCfgInitialize ) )
|
|
{
|
|
*ppvOut = TraceInterface( __THISCLASS__, IClusCfgInitialize, this, 0 );
|
|
} // else if: IClusCfgInitialize
|
|
else if ( IsEqualIID( riidIn, IID_IClusCfgCapabilities ) )
|
|
{
|
|
*ppvOut = TraceInterface( __THISCLASS__, IClusCfgCapabilities, this, 0 );
|
|
} // else if: IClusCfgCapabilities
|
|
else if ( IsEqualIID( riidIn, IID_IClusCfgPollingCallbackInfo ) )
|
|
{
|
|
*ppvOut = TraceInterface( __THISCLASS__, IClusCfgPollingCallbackInfo, this, 0 );
|
|
} // else if: IClusCfgPollingCallbackInfo
|
|
else if ( IsEqualIID( riidIn, IID_IClusCfgVerify ) )
|
|
{
|
|
*ppvOut = TraceInterface( __THISCLASS__, IClusCfgVerify, this, 0 );
|
|
} // else if: IClusCfgVerify
|
|
else
|
|
{
|
|
*ppvOut = NULL;
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
|
|
//
|
|
// Add a reference to the interface if successful.
|
|
//
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
((IUnknown *) *ppvOut)->AddRef();
|
|
} // if: success
|
|
|
|
Cleanup:
|
|
|
|
QIRETURN_IGNORESTDMARSHALLING( hr, riidIn );
|
|
|
|
} //*** CClusCfgServer::QueryInterface
|
|
|
|
|
|
//*************************************************************************//
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CClusCfgServer -- IClusCfgInitialize interface.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::Initialize
|
|
//
|
|
// Description:
|
|
// Initialize this component.
|
|
//
|
|
// Arguments:
|
|
// IN IUknown * punkCallbackIn
|
|
//
|
|
// IN LCID lcidIn
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success
|
|
//
|
|
// E_POINTER
|
|
// The punkCallbackIn param is NULL.
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CClusCfgServer::Initialize(
|
|
IUnknown * punkCallbackIn,
|
|
LCID lcidIn
|
|
)
|
|
{
|
|
TraceFunc( "[IClusCfgInitialize]" );
|
|
Assert( m_picccCallback != NULL );
|
|
|
|
TraceInitializeThread( L"ClusCfgServerFlags" );
|
|
|
|
HRESULT hr = S_OK;
|
|
IUnknown * punk = NULL;
|
|
IClusCfgCallback * piccc = NULL; // this is NULL when we are polling callback
|
|
IClusCfgNodeInfo * piccni = NULL;
|
|
IClusCfgClusterInfo * piccci = NULL;
|
|
|
|
// hr = STHR( HrCheckSecurity() );
|
|
// if ( FAILED( hr ) )
|
|
// {
|
|
// goto Cleanup;
|
|
// } // if:
|
|
|
|
m_lcid = lcidIn;
|
|
|
|
//
|
|
// If we are passed a callback object then we need to get its IClusCfgCallback
|
|
// interface so we can pass it into our callback object when it's initialized
|
|
// below.
|
|
//
|
|
if ( punkCallbackIn != NULL )
|
|
{
|
|
Assert( !m_fUsePolling );
|
|
|
|
hr = THR( punkCallbackIn->TypeSafeQI( IClusCfgCallback, &piccc ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
} // if:
|
|
else
|
|
{
|
|
Assert( m_fUsePolling );
|
|
|
|
if ( m_fUsePolling == FALSE )
|
|
{
|
|
hr = THR( E_INVALIDARG );
|
|
goto Cleanup;
|
|
} // if:
|
|
} // else:
|
|
|
|
//
|
|
// Initialize our internal callback object passing it either the passed in
|
|
// callback object's callback interface or NULL if we are polling.
|
|
//
|
|
hr = THR( m_picccCallback->TypeSafeQI( IUnknown, &punk ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
hr = THR( HrSetInitialize( punk, piccc, m_lcid ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// KB: 24-JUL-2000 GalenB
|
|
//
|
|
// If we are being initialized on this interface then we are going to run this server local
|
|
// to the node.
|
|
//
|
|
hr = THR( HrInitializeForLocalServer() );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Precreate the node info so we can get the cluster info object and determine if the cluster service
|
|
// is running on this node or not.
|
|
//
|
|
hr = THR( HrCreateClusterNodeInfo() );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
hr = THR( m_punkNodeInfo->TypeSafeQI( IClusCfgNodeInfo, &piccni ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// This could return HRESUTL_FROM_WIN32( ERROR_CLUSTER_NODE_DOWN ) and that
|
|
// tells us that the cluster service is not running on this node. The
|
|
// middletier needs to know this so it doesn't call us on this node
|
|
// anymore.
|
|
//
|
|
hr = THR( piccni->GetClusterConfigInfo( &piccci ) );
|
|
|
|
Cleanup:
|
|
|
|
if ( m_picccCallback != NULL )
|
|
{
|
|
STATUS_REPORT( TASKID_Major_Establish_Connection, TASKID_Minor_Server_Initialized, IDS_NOTIFY_SERVER_INITIALIZED, hr );
|
|
} // if:
|
|
|
|
if ( piccci != NULL )
|
|
{
|
|
piccci->Release();
|
|
} // if:
|
|
|
|
if ( piccni != NULL )
|
|
{
|
|
piccni->Release();
|
|
} // if:
|
|
|
|
if ( piccc != NULL )
|
|
{
|
|
piccc->Release();
|
|
} // if:
|
|
|
|
if ( punk != NULL )
|
|
{
|
|
punk->Release();
|
|
} // if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::Initialize
|
|
|
|
|
|
//*************************************************************************//
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CClusCfgServer -- IClusCfgServer interface.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::GetClusterNodeInfo
|
|
//
|
|
// Description:
|
|
// Get information about the computer on which this object is present.
|
|
//
|
|
// Arguments:
|
|
// OUT IClusCfgNodeInfo ** ppClusterNodeInfoOut
|
|
// Catches the node info object.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success
|
|
//
|
|
// E_POINTER
|
|
// The out param was NULL.
|
|
//
|
|
// E_OUTOFMEMORY
|
|
// The IClusCfgNodeInfo object could not be allocated.
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CClusCfgServer::GetClusterNodeInfo(
|
|
IClusCfgNodeInfo ** ppClusterNodeInfoOut
|
|
)
|
|
{
|
|
TraceFunc( "[IClusCfgServer]" );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( ppClusterNodeInfoOut == NULL )
|
|
{
|
|
hr = THR( E_POINTER );
|
|
STATUS_REPORT_REF(
|
|
TASKID_Major_Check_Node_Feasibility
|
|
, TASKID_Minor_GetClusterNodeInfo
|
|
, IDS_ERROR_NULL_POINTER
|
|
, IDS_ERROR_NULL_POINTER_REF
|
|
, hr
|
|
);
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
if ( m_punkNodeInfo != NULL )
|
|
{
|
|
hr = S_OK;
|
|
goto SkipCreate;
|
|
} // if:
|
|
|
|
hr = THR( HrCreateClusterNodeInfo() );
|
|
|
|
SkipCreate:
|
|
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
Assert( m_punkNodeInfo != NULL );
|
|
hr = THR( m_punkNodeInfo->TypeSafeQI( IClusCfgNodeInfo, ppClusterNodeInfoOut ) );
|
|
} // if:
|
|
|
|
Cleanup:
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
STATUS_REPORT_REF(
|
|
TASKID_Major_Check_Node_Feasibility
|
|
, TASKID_Minor_Server_GetClusterNodeInfo
|
|
, IDS_ERROR_NODE_INFO_CREATE
|
|
, IDS_ERROR_NODE_INFO_CREATE_REF
|
|
, hr
|
|
);
|
|
} // if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::GetClusterNodeInfo
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::GetManagedResourcesEnum
|
|
//
|
|
// Description:
|
|
// Get an enumeration of the devices on this computer that can be
|
|
// managed by the cluster service.
|
|
//
|
|
// Arguments:
|
|
// OUT IEnumClusCfgManagedResources ** ppEnumManagedResourcesOut
|
|
// Catches the CEnumClusCfgManagedResources object.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success
|
|
//
|
|
// E_POINTER
|
|
// The out param was NULL.
|
|
//
|
|
// E_OUTOFMEMORY
|
|
// The CEnumClusCfgManagedResources object could not be allocated.
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CClusCfgServer::GetManagedResourcesEnum(
|
|
IEnumClusCfgManagedResources ** ppEnumManagedResourcesOut
|
|
)
|
|
{
|
|
TraceFunc( "[IClusCfgServer]" );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( ppEnumManagedResourcesOut == NULL )
|
|
{
|
|
hr = THR( E_POINTER );
|
|
STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_GetManagedResourcesEnum, IDS_ERROR_NULL_POINTER, IDS_ERROR_NULL_POINTER_REF, hr );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
if ( m_punkEnumResources != NULL )
|
|
{
|
|
m_punkEnumResources->Release();
|
|
m_punkEnumResources = NULL;
|
|
} // if:
|
|
|
|
hr = THR( CEnumClusCfgManagedResources::S_HrCreateInstance( &m_punkEnumResources ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
m_punkEnumResources = TraceInterface( L"CEnumClusCfgManagedResources", IUnknown, m_punkEnumResources, 1 );
|
|
|
|
hr = THR( HrSetInitialize( m_punkEnumResources, m_picccCallback, m_lcid ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
hr = THR( HrSetWbemServices( m_punkEnumResources, m_pIWbemServices ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
hr = THR( m_punkEnumResources->TypeSafeQI( IEnumClusCfgManagedResources, ppEnumManagedResourcesOut ) );
|
|
|
|
Cleanup:
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
STATUS_REPORT_REF(
|
|
TASKID_Major_Find_Devices
|
|
, TASKID_Minor_Server_GetManagedResourcesEnum
|
|
, IDS_ERROR_MANAGED_RESOURCE_ENUM_CREATE
|
|
, IDS_ERROR_MANAGED_RESOURCE_ENUM_CREATE_REF
|
|
, hr
|
|
);
|
|
} // if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::GetManagedResourcesEnum
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::GetNetworksEnum
|
|
//
|
|
// Description:
|
|
// Get an enumeration of all the networks on this computer.
|
|
//
|
|
// Arguments:
|
|
// OUT IEnumClusCfgNetworks ** ppEnumNetworksOut
|
|
// Catches the CEnumClusCfgNetworks object.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success
|
|
//
|
|
// E_POINTER
|
|
// The out param was NULL.
|
|
//
|
|
// E_OUTOFMEMORY
|
|
// The CEnumClusCfgNetworks object could not be allocated.
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CClusCfgServer::GetNetworksEnum(
|
|
IEnumClusCfgNetworks ** ppEnumNetworksOut
|
|
)
|
|
{
|
|
TraceFunc( "[IClusCfgServer]" );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( ppEnumNetworksOut == NULL )
|
|
{
|
|
hr = THR( E_POINTER );
|
|
STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_GetNetworksEnum, IDS_ERROR_NULL_POINTER, IDS_ERROR_NULL_POINTER_REF, hr );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
if ( m_punkNetworksEnum != NULL )
|
|
{
|
|
m_punkNetworksEnum->Release();
|
|
m_punkNetworksEnum = NULL;
|
|
} // if:
|
|
|
|
hr = THR( HrCreateNetworksEnum( m_picccCallback, m_lcid, m_pIWbemServices, &m_punkNetworksEnum ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
hr = THR( m_punkNetworksEnum->TypeSafeQI( IEnumClusCfgNetworks, ppEnumNetworksOut ) );
|
|
|
|
Cleanup:
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
STATUS_REPORT_REF(
|
|
TASKID_Major_Find_Devices
|
|
, TASKID_Minor_Server_GetNetworksEnum
|
|
, IDS_ERROR_NETWORKS_ENUM_CREATE
|
|
, IDS_ERROR_NETWORKS_ENUM_CREATE_REF
|
|
, hr
|
|
);
|
|
} // if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::GetNetworksEnum
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::CommitChanges
|
|
//
|
|
// Description:
|
|
// Commit the changes to the node.
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CClusCfgServer::CommitChanges( void )
|
|
{
|
|
TraceFunc( "[IClusCfgServer]" );
|
|
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrTemp = S_OK;
|
|
IClusCfgInitialize * pcci = NULL;
|
|
IClusCfgClusterInfo * pClusCfgClusterInfo = NULL;
|
|
ECommitMode ecmCommitChangesMode = cmUNKNOWN;
|
|
IClusCfgNodeInfo * piccni = NULL;
|
|
IPostCfgManager * ppcm = NULL;
|
|
IUnknown * punkCallback = NULL;
|
|
HANDLE heventPostCfgCompletion = NULL;
|
|
IEnumClusCfgManagedResources * peccmr = NULL;
|
|
DWORD sc = ERROR_SUCCESS;
|
|
|
|
MULTI_QI mqiInterfaces[] =
|
|
{
|
|
{ &IID_IClusCfgBaseCluster, NULL, S_OK },
|
|
{ &IID_IClusCfgInitialize, NULL, S_OK }
|
|
};
|
|
|
|
hr = THR( m_picccCallback->TypeSafeQI( IUnknown, &punkCallback ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// KB: First, get a pointer to the IClusCfgNodeInfo interface. Use this to get
|
|
// a pointer to the IClusCfgClusterInfo interface to see what action needs
|
|
// to be committed.
|
|
//
|
|
if ( m_punkNodeInfo == NULL )
|
|
{
|
|
hr = THR( GetClusterNodeInfo( &piccni ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
} // if:
|
|
else
|
|
{
|
|
hr = THR( m_punkNodeInfo->TypeSafeQI( IClusCfgNodeInfo, &piccni ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get the pointer to the IClusCfgNodeInfo interface
|
|
} // else:
|
|
|
|
hr = THR( piccni->GetClusterConfigInfo( &pClusCfgClusterInfo ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get the pointer to the IClusCfgClusterInfo interface
|
|
|
|
hr = STHR( pClusCfgClusterInfo->GetCommitMode( &ecmCommitChangesMode ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
Assert( ecmCommitChangesMode != cmUNKNOWN );
|
|
|
|
//
|
|
// Create and initialize the BaseClusterAction component
|
|
//
|
|
|
|
hr = THR( HrCoCreateInternalInstanceEx( CLSID_ClusCfgBaseCluster, NULL, CLSCTX_SERVER, NULL, ARRAYSIZE( mqiInterfaces ), mqiInterfaces ) );
|
|
if ( FAILED( hr ) && ( hr != CO_S_NOTALLINTERFACES ) )
|
|
{
|
|
LOG_STATUS_REPORT( L"Failed to CoCreate Base Cluster Actions", hr );
|
|
goto Cleanup;
|
|
} // if: CoCreateInstanceEx() failed
|
|
|
|
hr = THR( mqiInterfaces[ 0 ].hr );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get a pointer to the IClusCfgBaseCluster interface
|
|
|
|
//
|
|
// Check if we got a pointer to the IClusCfgInitialize interface
|
|
hr = mqiInterfaces[ 1 ].hr;
|
|
if ( hr == S_OK )
|
|
{
|
|
hr = THR( ((IClusCfgInitialize *) mqiInterfaces[ 1 ].pItf)->Initialize( punkCallback, m_lcid ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: something went wrong during initialization
|
|
|
|
} // if: we got a pointer to the IClusCfgInitialize interface
|
|
else
|
|
{
|
|
if ( hr != E_NOINTERFACE )
|
|
{
|
|
goto Cleanup;
|
|
} // if: the interface is supported, but something else went wrong.
|
|
|
|
} // if: we did not get a pointer to the IClusCfgInitialize interface
|
|
|
|
//
|
|
// Create and initialize the Post configuration manager
|
|
//
|
|
|
|
hr = THR( HrCoCreateInternalInstance( CLSID_ClusCfgPostConfigManager, NULL, CLSCTX_SERVER, TypeSafeParams( IPostCfgManager, &ppcm ) ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
STATUS_REPORT_REF(
|
|
TASKID_Major_Configure_Cluster_Services
|
|
, TASKID_Minor_Cannot_Create_PostCfg_Mgr
|
|
, IDS_ERROR_CANNOT_CREATE_POSTCFG_MGR
|
|
, IDS_ERROR_CANNOT_CREATE_POSTCFG_MGR_REF
|
|
, hr
|
|
);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Check if this component supports the callback interface.
|
|
hrTemp = THR( ppcm->TypeSafeQI( IClusCfgInitialize, &pcci ) );
|
|
if ( FAILED( hrTemp ) )
|
|
{
|
|
LOG_STATUS_REPORT( L"Could not get a pointer to the IClusCfgInitialize interface. This post configuration manager does not support initialization", hr );
|
|
} // if: the callback interface is not supported
|
|
else
|
|
{
|
|
// Initialize this component.
|
|
hr = THR( pcci->Initialize( punkCallback, m_lcid ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
LOG_STATUS_REPORT( L"Could not initialize the post configuration manager", hr );
|
|
goto Cleanup;
|
|
} // if: the initialization failed
|
|
} // else: the callback interface is supported
|
|
|
|
if ( m_punkEnumResources != NULL )
|
|
{
|
|
hr = THR( m_punkEnumResources->TypeSafeQI( IEnumClusCfgManagedResources, &peccmr ) );
|
|
} // if: resource enum is not NULL
|
|
else
|
|
{
|
|
//
|
|
// If the enumerator is NULL then we are most likely cleaning up a
|
|
// node. That also means that we are not creating a cluster or
|
|
// adding nodes to a cluster.
|
|
//
|
|
|
|
Assert( ( ecmCommitChangesMode != cmCREATE_CLUSTER ) && ( ecmCommitChangesMode != cmADD_NODE_TO_CLUSTER) );
|
|
|
|
hr = GetManagedResourcesEnum( &peccmr );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
//
|
|
// If we are cleaning up a node then we don't really care if this
|
|
// enum loads 100% correctly or not. Any resources in the enum
|
|
// that fail to load will simply not participate in the clean up.
|
|
//
|
|
|
|
if ( ecmCommitChangesMode == cmCLEANUP_NODE_AFTER_EVICT )
|
|
{
|
|
hr = S_OK;
|
|
} // if: cleaning up a node
|
|
else
|
|
{
|
|
THR( hr );
|
|
goto Cleanup;
|
|
} // else: not cleaning up a node
|
|
} // if: loading the resource enum failed
|
|
} // else: resource enum is NULL
|
|
|
|
|
|
//
|
|
// If we are here, then the BaseCluster and Post configuration components were successfully
|
|
// created and initialized. Now perform the desired action.
|
|
//
|
|
|
|
if ( ( ecmCommitChangesMode == cmCREATE_CLUSTER ) || ( ecmCommitChangesMode == cmADD_NODE_TO_CLUSTER ) )
|
|
{
|
|
if ( !m_fCanBeClustered )
|
|
{
|
|
//
|
|
// TODO: 01-JUN-2000 GalenB
|
|
//
|
|
// Need better error code... What is the major and minor taskids?
|
|
//
|
|
|
|
hr = S_FALSE;
|
|
LOG_STATUS_REPORT( L"It was previously determined that this node cannot be clustered.", hr );
|
|
goto Cleanup;
|
|
} // if: this node cannot be part of a cluster
|
|
|
|
//
|
|
// If the cluster service is being started for the first time, as a part
|
|
// of adding this node to a cluster (forming or joining), then we have
|
|
// to wait till the post-configuration steps are completed before we
|
|
// can send out notifications. Create an event that indicates that post configuration
|
|
// has completed.
|
|
//
|
|
|
|
TraceFlow1( "Trying to create an event named '%s'.", POSTCONFIG_COMPLETE_EVENT_NAME );
|
|
|
|
//
|
|
// Create an event in the unsignalled state.
|
|
//
|
|
|
|
heventPostCfgCompletion = CreateEvent(
|
|
NULL // event security attributes
|
|
, TRUE // manual-reset event
|
|
, FALSE // create in unsignaled state
|
|
, POSTCONFIG_COMPLETE_EVENT_NAME
|
|
);
|
|
|
|
if ( heventPostCfgCompletion == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
|
|
LogMsg( L"[SRV] Error %#08x occurred trying to create an event named '%ws'.", hr, POSTCONFIG_COMPLETE_EVENT_NAME );
|
|
goto Cleanup;
|
|
} // if: we could not get a handle to the event
|
|
|
|
sc = TW32( ClRtlSetObjSecurityInfo(
|
|
heventPostCfgCompletion
|
|
, SE_KERNEL_OBJECT
|
|
, EVENT_ALL_ACCESS
|
|
, EVENT_ALL_ACCESS
|
|
, 0
|
|
) );
|
|
|
|
if ( sc != ERROR_SUCCESS )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( sc );
|
|
LogMsg( "[BC] Error %#08x occurred trying set %s event security.", sc, POSTCONFIG_COMPLETE_EVENT_NAME);
|
|
goto Cleanup;
|
|
} // if: ClRtlSetObjSecurityInfo failed
|
|
|
|
//
|
|
// Reset the event, just as a safetly measure, in case the event already existed before the call above.
|
|
//
|
|
|
|
if ( ResetEvent( heventPostCfgCompletion ) == 0 )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
|
|
LogMsg( L"[SRV] Error %#08x occurred trying to unsignal an event named '%ws'.", hr, POSTCONFIG_COMPLETE_EVENT_NAME );
|
|
goto Cleanup;
|
|
} // if: ResetEvent() failed()
|
|
} // if: we are forming or joining
|
|
|
|
if ( ecmCommitChangesMode == cmCREATE_CLUSTER )
|
|
{
|
|
//
|
|
// Commit the base cluster
|
|
//
|
|
|
|
hr = THR( HrFormCluster( pClusCfgClusterInfo, (( IClusCfgBaseCluster * ) mqiInterfaces[ 0 ].pItf) ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Point of no return: Send a special message so that CCommitPage::SendStatusReport will "display error messages as warnings".
|
|
//
|
|
|
|
if ( m_picccCallback != NULL )
|
|
{
|
|
hr = THR(
|
|
m_picccCallback->SendStatusReport(
|
|
NULL
|
|
, TASKID_Major_Configure_Cluster_Services
|
|
, TASKID_Minor_Errors_To_Warnings_Point
|
|
, 0
|
|
, 1
|
|
, 1
|
|
, hr
|
|
, NULL
|
|
, NULL
|
|
, NULL
|
|
)
|
|
);
|
|
} // if: the callback pointer is not NULL
|
|
|
|
//
|
|
// Commit the post configuration steps
|
|
//
|
|
|
|
hr = THR( ppcm->CommitChanges( peccmr, pClusCfgClusterInfo ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Signal the event to indicate that post configuration is complete.
|
|
//
|
|
|
|
if ( SetEvent( heventPostCfgCompletion ) == 0 )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
|
|
LogMsg( L"[SRV] Error %#08x occurred trying to signal an event named '%ws'.", hr, POSTCONFIG_COMPLETE_EVENT_NAME );
|
|
goto Cleanup;
|
|
} // if: SetEvent() failed()
|
|
} // if: we are forming a cluster.
|
|
else if ( ecmCommitChangesMode == cmADD_NODE_TO_CLUSTER )
|
|
{
|
|
//
|
|
// Commit the base cluster
|
|
//
|
|
|
|
hr = THR( HrJoinToCluster( pClusCfgClusterInfo, (( IClusCfgBaseCluster * ) mqiInterfaces[ 0 ].pItf) ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Point of no return: Send a special message so that CCommitPage::SendStatusReport will "display error messages as warnings".
|
|
//
|
|
|
|
if ( m_picccCallback != NULL )
|
|
{
|
|
hr = THR(
|
|
m_picccCallback->SendStatusReport(
|
|
NULL
|
|
, TASKID_Major_Configure_Cluster_Services
|
|
, TASKID_Minor_Errors_To_Warnings_Point
|
|
, 0
|
|
, 1
|
|
, 1
|
|
, hr
|
|
, NULL
|
|
, NULL
|
|
, NULL
|
|
)
|
|
);
|
|
} // if: the callback pointer is not NULL
|
|
|
|
//
|
|
// Commit the post configuration steps
|
|
//
|
|
|
|
hr = THR( ppcm->CommitChanges( peccmr, pClusCfgClusterInfo ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Signal the event to indicate that post configuration is complete.
|
|
//
|
|
|
|
if ( SetEvent( heventPostCfgCompletion ) == 0 )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
|
|
LogMsg( L"[SRV] Error %#08x occurred trying to signal an event named '%ws'.", hr, POSTCONFIG_COMPLETE_EVENT_NAME );
|
|
goto Cleanup;
|
|
} // if: SetEvent() failed()
|
|
} // else if: we are joining a cluster
|
|
else if ( ecmCommitChangesMode == cmCLEANUP_NODE_AFTER_EVICT )
|
|
{
|
|
//
|
|
// This node has been evicted - clean it up.
|
|
//
|
|
|
|
hr = THR( HrEvictedFromCluster( ppcm, peccmr, pClusCfgClusterInfo, (( IClusCfgBaseCluster * ) mqiInterfaces[ 0 ].pItf) ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
} // else if: we have just been evicted from a cluster
|
|
|
|
Cleanup:
|
|
|
|
if ( punkCallback != NULL )
|
|
{
|
|
punkCallback->Release();
|
|
} // if:
|
|
|
|
if ( pcci != NULL )
|
|
{
|
|
pcci->Release();
|
|
} // if:
|
|
|
|
if ( ppcm != NULL )
|
|
{
|
|
ppcm->Release();
|
|
} // if:
|
|
|
|
if ( peccmr != NULL )
|
|
{
|
|
peccmr->Release();
|
|
} // if:
|
|
|
|
if ( mqiInterfaces[ 0 ].pItf != NULL )
|
|
{
|
|
mqiInterfaces[ 0 ].pItf->Release();
|
|
} // if:
|
|
|
|
if ( mqiInterfaces[ 1 ].pItf != NULL )
|
|
{
|
|
mqiInterfaces[ 1 ].pItf->Release();
|
|
} // if:
|
|
|
|
if ( pClusCfgClusterInfo != NULL )
|
|
{
|
|
pClusCfgClusterInfo->Release();
|
|
} // if:
|
|
|
|
if ( piccni != NULL )
|
|
{
|
|
piccni->Release();
|
|
} // if:
|
|
|
|
if ( heventPostCfgCompletion != NULL )
|
|
{
|
|
//
|
|
// If we had created this event, then signal this event to let the
|
|
// startup notification thread proceed.
|
|
//
|
|
|
|
SetEvent( heventPostCfgCompletion );
|
|
CloseHandle( heventPostCfgCompletion );
|
|
} // if:
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
STATUS_REPORT_REF(
|
|
TASKID_Major_Configure_Cluster_Services
|
|
, TASKID_Minor_Server_CommitChanges
|
|
, IDS_ERROR_COMMIT_CHANGES
|
|
, IDS_ERROR_COMMIT_CHANGES_REF
|
|
, hr
|
|
);
|
|
} // if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::CommitChanges
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::GetBindingString
|
|
//
|
|
// Description:
|
|
// Get the binding string for this server.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CClusCfgServer::GetBindingString( BSTR * pbstrBindingStringOut )
|
|
{
|
|
TraceFunc( "[IClusCfgServer]" );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( pbstrBindingStringOut == NULL )
|
|
{
|
|
hr = THR( E_POINTER );
|
|
STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_Server_GetBindingString_Pointer, IDS_ERROR_NULL_POINTER, IDS_ERROR_NULL_POINTER_REF, hr );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
if ( m_bstrBindingString == NULL )
|
|
{
|
|
hr = S_FALSE;
|
|
LOG_STATUS_REPORT_MINOR( TASKID_Minor_Server_GetBindingString_NULL, L"Binding string is NULL. Must be a local connection.", hr );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
*pbstrBindingStringOut = SysAllocString( m_bstrBindingString );
|
|
if ( *pbstrBindingStringOut == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_Server_GetBindingString_Memory, IDS_ERROR_OUTOFMEMORY, IDS_ERROR_OUTOFMEMORY_REF, hr );
|
|
} // if:
|
|
|
|
Cleanup:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::GetBindingString
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::SetBindingString
|
|
//
|
|
// Description:
|
|
// Set the binding string of this server.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CClusCfgServer::SetBindingString( LPCWSTR pcszBindingStringIn )
|
|
{
|
|
TraceFunc1( "[IClusCfgServer] pcszBindingStringIn = '%ws'", pcszBindingStringIn == NULL ? L"<null>" : pcszBindingStringIn );
|
|
|
|
HRESULT hr = S_OK;
|
|
BSTR bstr = NULL;
|
|
|
|
if ( pcszBindingStringIn == NULL )
|
|
{
|
|
hr = THR( E_INVALIDARG );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
bstr = TraceSysAllocString( pcszBindingStringIn );
|
|
if ( bstr == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
STATUS_REPORT_REF( TASKID_Major_Find_Devices, TASKID_Minor_SetBindingString_Server, IDS_ERROR_OUTOFMEMORY, IDS_ERROR_OUTOFMEMORY_REF, hr );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
TraceSysFreeString( m_bstrBindingString );
|
|
m_bstrBindingString = bstr;
|
|
|
|
Cleanup:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::SetBindingString
|
|
|
|
|
|
//*************************************************************************//
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CClusCfgServer class -- IClusCfgCapabilities interfaces.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::CanNodeBeClustered
|
|
//
|
|
// Description:
|
|
// Can this node be added to a cluster?
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Node can be clustered.
|
|
//
|
|
// S_FALSE
|
|
// Node cannot be clustered.
|
|
//
|
|
// other HRESULTs
|
|
// The call failed.
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CClusCfgServer::CanNodeBeClustered( void )
|
|
{
|
|
TraceFunc( "[IClusCfgServer]" );
|
|
|
|
HRESULT hr;
|
|
ICatInformation * pici = NULL;
|
|
CATID rgCatIds[ 1 ];
|
|
IEnumCLSID * pieclsids = NULL;
|
|
IClusCfgCapabilities * piccc = NULL;
|
|
CLSID clsid;
|
|
ULONG cFetched;
|
|
IUnknown * punk = NULL;
|
|
|
|
//
|
|
// KB: 10-SEP-2000 GalenB
|
|
//
|
|
// Last ditch effort to clean up a node that is in a bad state before trying
|
|
// to add it into a cluster.
|
|
//
|
|
hr = STHR( HrHasNodeBeenEvicted() );
|
|
if ( hr == S_OK )
|
|
{
|
|
hr = THR( HrCleanUpNode() ) ;
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
} // if:
|
|
else if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // else if:
|
|
|
|
rgCatIds[ 0 ] = CATID_ClusCfgCapabilities;
|
|
|
|
hr = THR( CoCreateInstance( CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatInformation, (void **) &pici ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
LOG_STATUS_REPORT( L"Failed to CoCreate CLSID_StdComponentCategoriesMgr component", hr );
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = THR( pici->EnumClassesOfCategories( 1, rgCatIds, 0, NULL, &pieclsids ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
LOG_STATUS_REPORT( L"Failed to get enumerator for the IClusCfgClusterCapabilites components", hr );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
for ( ; ; )
|
|
{
|
|
hr = STHR( pieclsids->Next( 1, &clsid, &cFetched ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
LOG_STATUS_REPORT( L"IClusCfgClusterCapabilites component enumerator failed", hr );
|
|
break;
|
|
} // if:
|
|
|
|
if ( ( hr == S_FALSE ) && ( cFetched == 0 ) )
|
|
{
|
|
hr = S_OK;
|
|
break;
|
|
} // if:
|
|
|
|
hr = THR( HrCoCreateInternalInstance( clsid, NULL, CLSCTX_ALL, IID_IClusCfgCapabilities, (void **) &piccc ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
LOG_STATUS_REPORT( L"Failed to CoCreate IClusCfgClusterCapabilites component", hr );
|
|
continue;
|
|
} // if:
|
|
|
|
hr = THR( piccc->TypeSafeQI( IUnknown, &punk ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
LOG_STATUS_REPORT( L"Failed to QI IClusCfgClusterCapabilites component for IUnknown", hr );
|
|
piccc->Release();
|
|
piccc = NULL;
|
|
continue;
|
|
} // if:
|
|
|
|
hr = THR( HrSetInitialize( punk, m_picccCallback, m_lcid ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
LOG_STATUS_REPORT( L"Failed to initialize IClusCfgClusterCapabilites component", hr );
|
|
piccc->Release();
|
|
piccc = NULL;
|
|
punk->Release();
|
|
punk = NULL;
|
|
continue;
|
|
} // if:
|
|
|
|
punk->Release();
|
|
punk = NULL;
|
|
|
|
hr = STHR( piccc->CanNodeBeClustered() );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
LOG_STATUS_REPORT( L"IClusCfgClusterCapabilites component failed in CanNodeBeClustered()", hr );
|
|
piccc->Release();
|
|
piccc = NULL;
|
|
continue;
|
|
} // if:
|
|
|
|
if ( hr == S_FALSE )
|
|
{
|
|
m_fCanBeClustered = false;
|
|
} // if:
|
|
|
|
piccc->Release();
|
|
piccc = NULL;
|
|
} // for:
|
|
|
|
if ( !m_fCanBeClustered )
|
|
{
|
|
hr = S_FALSE;
|
|
} // if:
|
|
|
|
Cleanup:
|
|
|
|
if ( punk != NULL )
|
|
{
|
|
punk->Release();
|
|
} // if:
|
|
|
|
if ( piccc != NULL )
|
|
{
|
|
piccc->Release();
|
|
} // if:
|
|
|
|
if ( pieclsids != NULL )
|
|
{
|
|
pieclsids->Release();
|
|
} // if:
|
|
|
|
if ( pici != NULL )
|
|
{
|
|
pici->Release();
|
|
} // if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::CanNodeBeClustered
|
|
|
|
|
|
//*************************************************************************//
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CClusCfgServer class -- IClusCfgPollingCallbackInfo interface.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::GetCallback
|
|
//
|
|
// Description:
|
|
// Return the pointer to the embedded polling callback object.
|
|
//
|
|
// Arguments:
|
|
// ppiccpcOut
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CClusCfgServer::GetCallback( IClusCfgPollingCallback ** ppiccpcOut )
|
|
{
|
|
TraceFunc( "[IClusCfgServer]" );
|
|
Assert( m_picccCallback != NULL );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( ppiccpcOut == NULL )
|
|
{
|
|
hr = THR( E_POINTER );
|
|
STATUS_REPORT_REF( TASKID_Major_Establish_Connection, TASKID_Minor_GetCallback, IDS_ERROR_NULL_POINTER, IDS_ERROR_NULL_POINTER_REF, hr );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
hr = THR( m_picccCallback->TypeSafeQI( IClusCfgPollingCallback, ppiccpcOut ) );
|
|
|
|
Cleanup:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::GetCallback
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::SetPollingMode
|
|
//
|
|
// Description:
|
|
// Set the polling mode of the callback.
|
|
//
|
|
// Arguments:
|
|
// fPollingModeIn
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CClusCfgServer::SetPollingMode( BOOL fPollingModeIn )
|
|
{
|
|
TraceFunc( "[IClusCfgServer]" );
|
|
Assert( m_picccCallback != NULL );
|
|
|
|
HRESULT hr = S_OK;
|
|
IClusCfgSetPollingCallback * piccspc = NULL;
|
|
|
|
m_fUsePolling = fPollingModeIn;
|
|
|
|
hr = THR( m_picccCallback->TypeSafeQI( IClusCfgSetPollingCallback, &piccspc ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
hr = THR( piccspc->SetPollingMode( m_fUsePolling ) );
|
|
|
|
Cleanup:
|
|
|
|
if ( piccspc != NULL )
|
|
{
|
|
piccspc->Release();
|
|
} // if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::SetPollingMode
|
|
|
|
|
|
//*************************************************************************//
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CClusCfgServer class -- IClusCfgVerify interface.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::VerifyCredentials
|
|
//
|
|
// Description:
|
|
// Validate the passed in credentials.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// The credentials are valid.
|
|
//
|
|
// other HRESULTs
|
|
// The call failed.
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CClusCfgServer::VerifyCredentials(
|
|
LPCWSTR pcszNameIn,
|
|
LPCWSTR pcszDomainIn,
|
|
LPCWSTR pcszPasswordIn
|
|
)
|
|
{
|
|
TraceFunc( "[IClusCfgVerify]" );
|
|
|
|
HRESULT hr = S_OK;
|
|
HANDLE hToken = NULL;
|
|
DWORD dwSidSize = 0;
|
|
DWORD dwDomainSize = 0;
|
|
SID_NAME_USE snuSidNameUse;
|
|
DWORD sc;
|
|
BSTR bstrDomainName = NULL;
|
|
|
|
//
|
|
// Try to find out how much space is required by the SID. If we don't fail with
|
|
// insufficient buffer then we know the account exists.
|
|
//
|
|
|
|
hr = THR( HrFormatStringIntoBSTR( L"%1!ws!\\%2!ws!", &bstrDomainName, pcszDomainIn, pcszNameIn ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
if ( LookupAccountName( NULL, bstrDomainName, NULL, &dwSidSize, NULL, &dwDomainSize, &snuSidNameUse ) == FALSE )
|
|
{
|
|
sc = GetLastError();
|
|
|
|
if ( sc != ERROR_INSUFFICIENT_BUFFER )
|
|
{
|
|
TW32( sc );
|
|
hr = HRESULT_FROM_WIN32( sc );
|
|
|
|
STATUS_REPORT_STRING2_REF(
|
|
TASKID_Minor_Validating_Credentials
|
|
, TASKID_Minor_Invalid_Domain_User
|
|
, IDS_ERROR_INVALID_DOMAIN_USER
|
|
, pcszNameIn
|
|
, pcszDomainIn
|
|
, IDS_ERROR_INVALID_DOMAIN_USER_REF
|
|
, hr
|
|
);
|
|
goto Cleanup;
|
|
} // if:
|
|
} // if:
|
|
|
|
//
|
|
// Logon the passed in user to ensure that it is valid.
|
|
//
|
|
|
|
if ( !LogonUserW(
|
|
const_cast< LPWSTR >( pcszNameIn )
|
|
, const_cast< LPWSTR >( pcszDomainIn )
|
|
, const_cast< LPWSTR >( pcszPasswordIn )
|
|
, LOGON32_LOGON_NETWORK
|
|
, LOGON32_PROVIDER_DEFAULT
|
|
, &hToken
|
|
) )
|
|
{
|
|
sc = TW32( GetLastError() );
|
|
hr = HRESULT_FROM_WIN32( sc );
|
|
|
|
STATUS_REPORT_STRING2_REF(
|
|
TASKID_Minor_Validating_Credentials
|
|
, TASKID_Minor_Invalid_Credentials
|
|
, IDS_ERROR_INVALID_CREDENTIALS
|
|
, pcszNameIn
|
|
, pcszDomainIn
|
|
, IDS_ERROR_INVALID_CREDENTIALS_REF
|
|
, hr
|
|
);
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
Cleanup:
|
|
|
|
TraceSysFreeString( bstrDomainName );
|
|
|
|
if ( hToken != NULL )
|
|
{
|
|
CloseHandle( hToken );
|
|
} // if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::VerifyCredentials
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::VerifyConnectionToCluster
|
|
//
|
|
// Description:
|
|
// Verify that that this server is the same as the passed in server.
|
|
//
|
|
// Arguments:
|
|
// pcszClusterNameIn
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// This is the server.
|
|
//
|
|
// S_FALSE
|
|
// This is not the server.
|
|
//
|
|
// other HRESULTs
|
|
// The call failed.
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CClusCfgServer::VerifyConnectionToCluster(
|
|
LPCWSTR pcszClusterNameIn
|
|
)
|
|
{
|
|
TraceFunc1( "[IClusCfgVerify] pcszClusterNameIn = '%ws'", pcszClusterNameIn );
|
|
|
|
DWORD sc;
|
|
DWORD dwClusterState;
|
|
HRESULT hr = S_OK;
|
|
HCLUSTER hCluster = NULL;
|
|
BSTR bstrClusterName = NULL;
|
|
BSTR bstrLocalFQDN = NULL;
|
|
BSTR bstrGivenHostname = NULL;
|
|
size_t idxGivenDomain = 0;
|
|
size_t idxLocalDomain = 0;
|
|
|
|
//
|
|
// Test arguments
|
|
//
|
|
|
|
if ( pcszClusterNameIn == NULL )
|
|
{
|
|
hr = THR( E_INVALIDARG );
|
|
STATUS_REPORT_REF( TASKID_Minor_Connecting, TASKID_Minor_VerifyConnection_InvalidArg, IDS_ERROR_INVALIDARG, IDS_ERROR_INVALIDARG_REF, hr );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Gather names necessary for informative status reports.
|
|
//
|
|
hr = THR( HrGetComputerName(
|
|
ComputerNamePhysicalDnsFullyQualified
|
|
, &bstrLocalFQDN
|
|
, FALSE // fBestEffortIn
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = THR( HrFindDomainInFQN( bstrLocalFQDN, &idxLocalDomain ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = THR( HrFindDomainInFQN( pcszClusterNameIn, &idxGivenDomain ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Get the hostname label from the given name.
|
|
//
|
|
|
|
hr = THR( HrExtractPrefixFromFQN( pcszClusterNameIn, &bstrGivenHostname ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// See if we are clustered.
|
|
//
|
|
|
|
sc = TW32( GetNodeClusterState( NULL, &dwClusterState ) );
|
|
if ( sc != ERROR_SUCCESS )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( sc );
|
|
goto Cleanup;
|
|
} // if : GetClusterState() failed
|
|
|
|
//
|
|
// If the current cluster node state is neither "running" nor "not running,"
|
|
// then this node is not part of a cluster.
|
|
//
|
|
|
|
if ( ( dwClusterState != ClusterStateNotRunning ) && ( dwClusterState != ClusterStateRunning ) )
|
|
{
|
|
hr = S_FALSE;
|
|
STATUS_REPORT_STRING3(
|
|
TASKID_Minor_Connecting
|
|
, TASKID_Minor_VerifyConnection_MachineNotInCluster
|
|
, IDS_WARN_MACHINE_NOT_IN_CLUSTER
|
|
, bstrGivenHostname
|
|
, pcszClusterNameIn + idxGivenDomain
|
|
, bstrLocalFQDN
|
|
, hr
|
|
);
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// If given name is an FQDN, its hostname label needs to match the cluster's.
|
|
//
|
|
|
|
hr = STHR( HrFQNIsFQDN( pcszClusterNameIn ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
else if ( hr == S_OK )
|
|
{
|
|
//
|
|
// Open the cluster to get the cluster's name.
|
|
//
|
|
|
|
hCluster = OpenCluster( NULL );
|
|
if ( hCluster == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
|
|
STATUS_REPORT_REF(
|
|
TASKID_Minor_Connecting
|
|
, TASKID_Minor_VerifyConnection_OpenCluster
|
|
, IDS_ERROR_OPEN_CLUSTER_FAILED
|
|
, IDS_ERROR_OPEN_CLUSTER_FAILED_REF
|
|
, hr
|
|
);
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Try to get the cluster's name.
|
|
//
|
|
|
|
hr = THR( HrGetClusterInformation( hCluster, &bstrClusterName, NULL ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// If they don't match, the client has connected to an unexpected place.
|
|
//
|
|
|
|
if ( NBSTRCompareNoCase( bstrGivenHostname, bstrClusterName ) != 0 )
|
|
{
|
|
hr = S_FALSE;
|
|
STATUS_REPORT_STRING3(
|
|
TASKID_Minor_Connecting
|
|
, TASKID_Minor_VerifyConnection_Cluster_Name_Mismatch
|
|
, IDS_WARN_CLUSTER_NAME_MISMATCH
|
|
, bstrGivenHostname
|
|
, pcszClusterNameIn + idxGivenDomain
|
|
, bstrClusterName
|
|
, hr
|
|
);
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else if ( hr == S_FALSE )
|
|
{
|
|
//
|
|
// pcszClusterNameIn is an FQIP. Nothing to do regarding the hostname prefix in this case,
|
|
// but reset hr to S_OK to avoid returning bogus errors.
|
|
hr = S_OK;
|
|
}
|
|
|
|
//
|
|
// Make sure we are in the expected domain.
|
|
//
|
|
if ( ClRtlStrICmp( pcszClusterNameIn + idxGivenDomain, bstrLocalFQDN + idxLocalDomain ) != 0 )
|
|
{
|
|
hr = S_FALSE;
|
|
STATUS_REPORT_NODESTRING2(
|
|
pcszClusterNameIn
|
|
, TASKID_Minor_Connecting
|
|
, TASKID_Minor_VerifyConnection_Cluster_Domain_Mismatch
|
|
, IDS_WARN_CLUSTER_DOMAIN_MISMATCH
|
|
, pcszClusterNameIn + idxGivenDomain
|
|
, bstrLocalFQDN + idxLocalDomain
|
|
, hr
|
|
);
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
Assert( hr == S_OK );
|
|
goto Cleanup;
|
|
|
|
Cleanup:
|
|
|
|
if ( hr == S_FALSE )
|
|
{
|
|
LOG_STATUS_REPORT( L"Server name does not match what client is expecting.", hr );
|
|
} // if:
|
|
else if ( hr == S_OK )
|
|
{
|
|
LOG_STATUS_REPORT( L"Server name matches what client is expecting.", hr );
|
|
} // else if:
|
|
|
|
if ( hCluster != NULL )
|
|
{
|
|
CloseCluster( hCluster );
|
|
} // if:
|
|
|
|
TraceSysFreeString( bstrClusterName );
|
|
TraceSysFreeString( bstrLocalFQDN );
|
|
TraceSysFreeString( bstrGivenHostname );
|
|
|
|
HRETURN( hr );
|
|
|
|
} // ClusCfgServer::VerifyConnection
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::VerifyConnectionToNode
|
|
//
|
|
// Description:
|
|
// Verify that that this server is the same as the passed in server.
|
|
//
|
|
// Arguments:
|
|
// pcszNodeNameIn
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// This is the server.
|
|
//
|
|
// S_FALSE
|
|
// This is not the server.
|
|
//
|
|
// other HRESULTs
|
|
// The call failed.
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CClusCfgServer::VerifyConnectionToNode(
|
|
LPCWSTR pcszNodeNameIn
|
|
)
|
|
{
|
|
TraceFunc1( "[IClusCfgVerify] pcszNodeNameIn = '%ws'", pcszNodeNameIn );
|
|
|
|
HRESULT hr = S_FALSE;
|
|
|
|
Assert( m_bstrNodeName != NULL );
|
|
|
|
//
|
|
// Test arguments
|
|
//
|
|
|
|
if ( pcszNodeNameIn == NULL )
|
|
{
|
|
hr = THR( E_INVALIDARG );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
hr = STHR( HrFQNIsFQDN( pcszNodeNameIn ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
if ( hr == S_OK )
|
|
{
|
|
if ( ClRtlStrICmp( pcszNodeNameIn, m_bstrNodeName ) != 0 )
|
|
{
|
|
hr = S_FALSE;
|
|
STATUS_REPORT_STRING2(
|
|
TASKID_Minor_Connecting
|
|
, TASKID_Minor_VerifyConnection_Node_FQDN_Mismatch
|
|
, IDS_WARN_NODE_FQDN_MISMATCH
|
|
, pcszNodeNameIn
|
|
, m_bstrNodeName
|
|
, hr
|
|
);
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else // pcszNodeNameIn is an FQIP, so compare only domains.
|
|
{
|
|
//
|
|
// pcszNodeNameIn is an FQIP, so compare only domains.
|
|
//
|
|
|
|
size_t idxGivenDomain = 0;
|
|
size_t idxThisDomain = 0;
|
|
|
|
hr = THR( HrFindDomainInFQN( pcszNodeNameIn, &idxGivenDomain ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
hr = THR( HrFindDomainInFQN( m_bstrNodeName, &idxThisDomain ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
if ( ClRtlStrICmp( pcszNodeNameIn + idxGivenDomain, m_bstrNodeName + idxThisDomain ) == 0 )
|
|
{
|
|
hr = S_OK;
|
|
} // if:
|
|
else
|
|
{
|
|
hr = S_FALSE;
|
|
STATUS_REPORT_NODESTRING2(
|
|
pcszNodeNameIn
|
|
, TASKID_Minor_Connecting
|
|
, TASKID_Minor_VerifyConnection_Node_Domain_Mismatch
|
|
, IDS_WARN_NODE_DOMAIN_MISMATCH
|
|
, pcszNodeNameIn + idxGivenDomain
|
|
, m_bstrNodeName
|
|
, hr
|
|
);
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if ( hr == S_FALSE )
|
|
{
|
|
LogMsg( L"[SRV] VerifyConnection - Server name does not match what client is expecting." );
|
|
} // if:
|
|
else if ( hr == S_OK )
|
|
{
|
|
LogMsg( L"[SRV] VerifyConnection - Server name matches what client is expecting." );
|
|
} // else if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** ClusCfgServer::VerifyConnectionToNode
|
|
|
|
|
|
//*************************************************************************//
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CClusCfgServer class -- Private Methods.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::HrInit
|
|
//
|
|
// Description:
|
|
// Initialize this component.
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CClusCfgServer::HrInit( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_FALSE;
|
|
IUnknown * punk = NULL;
|
|
|
|
// IUnknown
|
|
Assert( m_cRef == 1 );
|
|
|
|
hr = THR( CClusCfgCallback::S_HrCreateInstance( &punk ) );
|
|
if ( FAILED ( hr ) )
|
|
{
|
|
LogMsg( L"[SRV] Could not create CClusCfgCallback. (hr = %#08x)", hr );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
hr = THR( punk->TypeSafeQI( IClusCfgCallback, &m_picccCallback ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
LogMsg( L"[SRV] Could not QI callback for a punk. (hr = %#08x)", hr );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Save off the local computer name.
|
|
// If we can't get the fully-qualified name, just get the NetBIOS name.
|
|
//
|
|
|
|
hr = THR( HrGetComputerName(
|
|
ComputerNameDnsFullyQualified
|
|
, &m_bstrNodeName
|
|
, TRUE // fBestEffortIn
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
THR( hr );
|
|
LogMsg( L"[SRV] An error occurred trying to get the fully-qualified Dns name for the local machine during initialization. (hr = %#08x)", hr );
|
|
goto Cleanup;
|
|
} // if: error getting computer name
|
|
|
|
Cleanup:
|
|
|
|
if ( punk != NULL )
|
|
{
|
|
punk->Release();
|
|
} // if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::HrInit
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::HrInitializeForLocalServer
|
|
//
|
|
// Description:
|
|
// Initialize this component.
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CClusCfgServer::HrInitializeForLocalServer( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_OK;
|
|
IWbemLocator * pIWbemLocator = NULL;
|
|
BSTR bstrNameSpace = NULL;
|
|
|
|
hr = CoCreateInstance( CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pIWbemLocator );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
STATUS_REPORT_REF(
|
|
TASKID_Major_Establish_Connection
|
|
, TASKID_Minor_HrInitializeForLocalServer_WbemLocator
|
|
, IDS_ERROR_WBEM_LOCATOR_CREATE_FAILED
|
|
, IDS_ERROR_WBEM_LOCATOR_CREATE_FAILED_REF
|
|
, hr
|
|
);
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
bstrNameSpace = TraceSysAllocString( L"\\\\.\\root\\cimv2" );
|
|
if ( bstrNameSpace == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
STATUS_REPORT_REF(
|
|
TASKID_Major_Establish_Connection
|
|
, TASKID_Minor_HrInitializeForLocalServer_Memory
|
|
, IDS_ERROR_OUTOFMEMORY
|
|
, IDS_ERROR_OUTOFMEMORY_REF
|
|
, hr
|
|
);
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
hr = THR( pIWbemLocator->ConnectServer(
|
|
bstrNameSpace,
|
|
NULL, // using current account for simplicity
|
|
NULL, // using current password for simplicity
|
|
NULL, // locale
|
|
0L, // securityFlags, reserved must be 0
|
|
NULL, // authority (domain for NTLM)
|
|
NULL, // context
|
|
&m_pIWbemServices
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
STATUS_REPORT_REF(
|
|
TASKID_Major_Establish_Connection
|
|
, TASKID_Minor_WBEM_Connection_Failure
|
|
, IDS_ERROR_WBEM_CONNECTION_FAILURE
|
|
, IDS_ERROR_WBEM_CONNECTION_FAILURE_REF
|
|
, hr
|
|
);
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
hr = THR( HrSetBlanket() );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
LOG_STATUS_REPORT_MINOR(
|
|
TASKID_Minor_HrInitializeForLocalServer_Blanket
|
|
, L"[SRV] The security rights and impersonation levels cannot be set on the connection to the Windows Management Instrumentation service."
|
|
, hr
|
|
);
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
Cleanup:
|
|
|
|
TraceSysFreeString( bstrNameSpace );
|
|
|
|
if ( pIWbemLocator != NULL )
|
|
{
|
|
pIWbemLocator->Release();
|
|
} // if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::HrInitializeForLocalServer
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::HrSetBlanket
|
|
//
|
|
// Description:
|
|
// Adjusts the security blanket on the IWbemServices pointer.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
//
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CClusCfgServer::HrSetBlanket( void )
|
|
{
|
|
TraceFunc( "" );
|
|
Assert( m_pIWbemServices != NULL );
|
|
|
|
HRESULT hr = S_FALSE;
|
|
|
|
if ( m_pIWbemServices )
|
|
{
|
|
IClientSecurity * pCliSec;
|
|
|
|
hr = THR( m_pIWbemServices->TypeSafeQI( IClientSecurity, &pCliSec ) );
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
hr = THR( pCliSec->SetBlanket(
|
|
m_pIWbemServices,
|
|
RPC_C_AUTHN_WINNT,
|
|
RPC_C_AUTHZ_NONE,
|
|
NULL,
|
|
RPC_C_AUTHN_LEVEL_CONNECT,
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
NULL,
|
|
EOAC_NONE
|
|
) );
|
|
|
|
pCliSec->Release();
|
|
} // if:
|
|
} // if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::HrSetBlanket
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::HrFormCluster
|
|
//
|
|
// Description:
|
|
// Form a new cluster.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
//
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CClusCfgServer::HrFormCluster(
|
|
IClusCfgClusterInfo * piccciIn,
|
|
IClusCfgBaseCluster * piccbcaIn
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr;
|
|
BSTR bstrClusterName = NULL;
|
|
BSTR bstrClusterBindingString = NULL;
|
|
BSTR bstrClusterIPNetwork = NULL;
|
|
ULONG ulClusterIPAddress = 0;
|
|
ULONG ulClusterIPSubnetMask = 0;
|
|
IClusCfgCredentials * picccServiceAccount = NULL;
|
|
IClusCfgNetworkInfo * piccni = NULL;
|
|
|
|
//
|
|
// Get the parameters required to form a cluster.
|
|
//
|
|
|
|
hr = THR( piccciIn->GetName( &bstrClusterName ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get the name of the cluster
|
|
|
|
TraceMemoryAddBSTR( bstrClusterName );
|
|
|
|
hr = STHR( piccciIn->GetBindingString( &bstrClusterBindingString ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get the binding string of the cluster.
|
|
|
|
TraceMemoryAddBSTR( bstrClusterBindingString );
|
|
|
|
hr = THR( piccciIn->GetClusterServiceAccountCredentials( &picccServiceAccount ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get the cluster service account credentials
|
|
|
|
hr = THR( piccciIn->GetIPAddress( &ulClusterIPAddress ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get the cluster IP address
|
|
|
|
hr = THR( piccciIn->GetSubnetMask( &ulClusterIPSubnetMask ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get the cluster subnet mask
|
|
|
|
hr = THR( piccciIn->GetNetworkInfo( &piccni ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get the network info of the network the cluster name should be on.
|
|
|
|
hr = THR( piccni->GetName( &bstrClusterIPNetwork ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get the name of the cluster name network.
|
|
|
|
TraceMemoryAddBSTR( bstrClusterIPNetwork );
|
|
|
|
//
|
|
// Indicate that a cluster should be created when Commit() is called.
|
|
//
|
|
hr = THR( piccbcaIn->SetCreate(
|
|
bstrClusterName
|
|
, bstrClusterBindingString
|
|
, picccServiceAccount
|
|
, ulClusterIPAddress
|
|
, ulClusterIPSubnetMask
|
|
, bstrClusterIPNetwork
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: SetCreate() failed.
|
|
|
|
// Initiate cluster creation.
|
|
hr = THR( piccbcaIn->Commit() );
|
|
|
|
Cleanup:
|
|
|
|
TraceSysFreeString( bstrClusterName );
|
|
TraceSysFreeString( bstrClusterBindingString );
|
|
TraceSysFreeString( bstrClusterIPNetwork );
|
|
|
|
if ( piccni != NULL )
|
|
{
|
|
piccni->Release();
|
|
} // if:
|
|
|
|
if ( picccServiceAccount != NULL )
|
|
{
|
|
picccServiceAccount->Release();
|
|
} // if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::HrFormCluster
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::HrJoinToCluster
|
|
//
|
|
// Description:
|
|
// Join a node to a cluster.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
//
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CClusCfgServer::HrJoinToCluster(
|
|
IClusCfgClusterInfo * piccciIn,
|
|
IClusCfgBaseCluster * piccbcaIn
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr;
|
|
BSTR bstrClusterName = NULL;
|
|
BSTR bstrClusterBindingString = NULL;
|
|
IClusCfgCredentials * picccServiceAccount = NULL;
|
|
|
|
//
|
|
// Get the parameters required to form a cluster.
|
|
//
|
|
|
|
hr = THR( piccciIn->GetName( &bstrClusterName ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get the name of the cluster
|
|
|
|
TraceMemoryAddBSTR( bstrClusterName );
|
|
|
|
hr = THR( piccciIn->GetBindingString( &bstrClusterBindingString ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get the cluster binding string.
|
|
|
|
TraceMemoryAddBSTR( bstrClusterBindingString );
|
|
|
|
hr = THR( piccciIn->GetClusterServiceAccountCredentials( &picccServiceAccount ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not get the cluster service account credentials
|
|
|
|
//
|
|
// Indicate that a cluster should be formed when Commit() is called.
|
|
//
|
|
hr = THR( piccbcaIn->SetAdd( bstrClusterName, bstrClusterBindingString, picccServiceAccount ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: SetAdd() failed.
|
|
|
|
// Initiate joining of the node to the cluster.
|
|
hr = THR( piccbcaIn->Commit() );
|
|
|
|
Cleanup:
|
|
|
|
TraceSysFreeString( bstrClusterName );
|
|
TraceSysFreeString( bstrClusterBindingString );
|
|
|
|
if ( picccServiceAccount != NULL )
|
|
{
|
|
picccServiceAccount->Release();
|
|
} // if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::HrJoinToCluster
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::HrEvictedFromCluster
|
|
//
|
|
// Description:
|
|
// Cleanup after a node has been evicted from a cluster. If another cleanup
|
|
// session is in progress, wait for it to complete and then attempt cleanup.
|
|
// In this way, if the other cleanup failed, this will retry it. If it had
|
|
// suceeded, this will do nothing.
|
|
//
|
|
// This function first calls the CommitChanges() method of the PostConfigManager
|
|
// (which will inform resource types and memberset listeners that this node
|
|
// has been evicted). It then cleans up the base cluster.
|
|
//
|
|
// Arguments:
|
|
// ppcmIn
|
|
// Pointer to the IPostCfgManager interface
|
|
//
|
|
// peccmrIn
|
|
// Argument needed by the IPostCfgManager::CommitChanges()
|
|
//
|
|
// piccciIn
|
|
// Pointer to the cluster info
|
|
//
|
|
// piccbcaIn
|
|
// Pointer to the IClusCfgBaseCluster interface that is used to clean up
|
|
// the base cluster.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// If everything went well
|
|
//
|
|
// other HRESULTs
|
|
// If the call failed
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CClusCfgServer::HrEvictedFromCluster(
|
|
IPostCfgManager * ppcmIn,
|
|
IEnumClusCfgManagedResources * peccmrIn,
|
|
IClusCfgClusterInfo * piccciIn,
|
|
IClusCfgBaseCluster * piccbcaIn
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_OK;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
HANDLE hsCleanupLock = NULL;
|
|
HANDLE heventCleanupComplete = NULL;
|
|
bool fLockAcquired = false;
|
|
DWORD dwClusterState;
|
|
HKEY hNodeStateKey = NULL;
|
|
DWORD dwEvictState = 1;
|
|
|
|
LogMsg( "[SRV] Creating cleanup lock." );
|
|
|
|
// First, try and acquire a lock, so that two cleanup operations cannot overlap.
|
|
hsCleanupLock = CreateSemaphore( NULL, 1, 1, CLEANUP_LOCK_NAME );
|
|
if ( hsCleanupLock == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
|
|
LogMsg( "[SRV] Error %#08x occurred trying to create the cleanup lock.", hr );
|
|
goto Cleanup;
|
|
} // CreateSemaphore() failed
|
|
|
|
LogMsg( "[SRV] Acquiring cleanup lock." );
|
|
|
|
do
|
|
{
|
|
// Wait for any message sent or posted to this queue
|
|
// or for our lock to be released.
|
|
dwStatus = MsgWaitForMultipleObjects( 1, &hsCleanupLock, FALSE, CC_DEFAULT_TIMEOUT, QS_ALLINPUT );
|
|
|
|
// The result tells us the type of event we have.
|
|
if ( dwStatus == ( WAIT_OBJECT_0 + 1 ) )
|
|
{
|
|
MSG msg;
|
|
|
|
// Read all of the messages in this next loop,
|
|
// removing each message as we read it.
|
|
while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) != 0 )
|
|
{
|
|
// If it is a quit message, we are done pumping messages.
|
|
if ( msg.message == WM_QUIT)
|
|
{
|
|
TraceFlow( "Get a WM_QUIT message. Cleanup message pump loop." );
|
|
break;
|
|
} // if: we got a WM_QUIT message
|
|
|
|
// Otherwise, dispatch the message.
|
|
DispatchMessage( &msg );
|
|
} // while: there are still messages in the window message queue
|
|
|
|
} // if: we have a message in the window message queue
|
|
else
|
|
{
|
|
if ( dwStatus == WAIT_OBJECT_0 )
|
|
{
|
|
fLockAcquired = true;
|
|
LogMsg( "[SRV] Cleanup lock acquired." );
|
|
break;
|
|
} // else if: our lock is signaled
|
|
else
|
|
{
|
|
if ( dwStatus == -1 )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
|
|
LogMsg( "[SRV] Error %#08x occurred trying to wait for our lock to be granted.", hr );
|
|
} // if: MsgWaitForMultipleObjects() returned an error
|
|
else
|
|
{
|
|
hr = THR( HRESULT_FROM_WIN32( dwStatus ) );
|
|
LogMsg( "[SRV] An error occurred trying to wait for our lock to be granted. Status code is %#08x.", dwStatus );
|
|
} // else: an unexpected value was returned by MsgWaitForMultipleObjects()
|
|
|
|
break;
|
|
} // else: an unexpected result
|
|
} // else: MsgWaitForMultipleObjects() exited for a reason other than a waiting message
|
|
}
|
|
while( true ); // do-while: loop infinitely
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: we could not acquire the cleanup lock
|
|
|
|
|
|
// Check if the install state is correct before invoking post configuration manager.
|
|
// Ignore the case where the service does not exist so that we can do our job.
|
|
dwStatus = GetNodeClusterState( NULL, &dwClusterState );
|
|
if ( dwStatus == ERROR_SERVICE_DOES_NOT_EXIST )
|
|
{
|
|
LogMsg( "[SRV] GetNodeClusterState() determined that the cluster service does not exist." );
|
|
}
|
|
else if ( dwStatus != ERROR_SUCCESS )
|
|
{
|
|
LogMsg( "[SRV] Error %#08x occurred trying to determine the installation state of this node.", dwStatus );
|
|
hr = HRESULT_FROM_WIN32( TW32( dwStatus ) );
|
|
goto Cleanup;
|
|
} // if : GetClusterState() failed
|
|
|
|
// Check if this node is part of a cluster.
|
|
if ( ( dwClusterState != ClusterStateNotRunning ) && ( dwClusterState != ClusterStateRunning ) )
|
|
{
|
|
LogMsg( "[SRV] This node is not part of a cluster - no cleanup is necessary." );
|
|
goto Cleanup;
|
|
} // if: this node is not part of a cluster
|
|
|
|
|
|
//
|
|
// Set a registry value indicating that this node has been evicted.
|
|
// If, for some reason, the cleanup could not be completed, the cluster
|
|
// service will check this flag the next time it comes up and restarts
|
|
// cleanup.
|
|
//
|
|
|
|
dwStatus = TW32(
|
|
RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE
|
|
, CLUSREG_KEYNAME_NODE_DATA
|
|
, 0
|
|
, KEY_ALL_ACCESS
|
|
, &hNodeStateKey
|
|
)
|
|
);
|
|
|
|
if ( dwStatus != ERROR_SUCCESS )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( dwStatus );
|
|
LogMsg( "[SRV] Error %#08x occurred trying to open a registry key to set a value indicating that this node has been evicted.", dwStatus );
|
|
goto Cleanup;
|
|
} // if: RegOpenKeyEx() has failed
|
|
|
|
dwStatus = TW32(
|
|
RegSetValueEx(
|
|
hNodeStateKey
|
|
, CLUSREG_NAME_EVICTION_STATE
|
|
, 0
|
|
, REG_DWORD
|
|
, reinterpret_cast< const BYTE * >( &dwEvictState )
|
|
, sizeof( dwEvictState )
|
|
)
|
|
);
|
|
|
|
if ( dwStatus != ERROR_SUCCESS )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( dwStatus );
|
|
LogMsg( "[SRV] Error %#08x occurred trying to set a registry value indicating that this node has been evicted.", dwStatus );
|
|
goto Cleanup;
|
|
} // if: RegSetValueEx() has failed
|
|
|
|
// Commit the post configuration steps first
|
|
hr = THR( ppcmIn->CommitChanges( peccmrIn, piccciIn ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
LogMsg( "[SRV] Error %#08x occurred during the post configuration step of cleanup.", hr );
|
|
goto Cleanup;
|
|
} // if: post configuration failed
|
|
|
|
TraceFlow( "IPostCfgManager::CommitChanges() completed successfully during cleanup." );
|
|
|
|
hr = THR( piccbcaIn->SetCleanup() );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
LogMsg( "[SRV] Error %#08x occurred initiating cleanup of the base cluster.", hr );
|
|
goto Cleanup;
|
|
} // if: SetCleanup() failed
|
|
|
|
// Initiate the cleanup
|
|
hr = THR( piccbcaIn->Commit() );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
LogMsg( "[SRV] Error %#08x occurred trying to cleanup the base cluster.", hr );
|
|
goto Cleanup;
|
|
} // if: base cluster cleanup failed
|
|
|
|
LogMsg( "[SRV] Base cluster successfully cleaned up." );
|
|
|
|
// If we are here, then cleanup has completed successfully. If some other process is waiting
|
|
// for cleanup to complete, release that process by signaling an event.
|
|
|
|
// Open the event. Note, if this event does not already exist, then it means that nobody is
|
|
// waiting on this event. So, it is ok for OpenEvent to fail.
|
|
heventCleanupComplete = OpenEvent( EVENT_ALL_ACCESS, FALSE, SUCCESSFUL_CLEANUP_EVENT_NAME );
|
|
if ( heventCleanupComplete == NULL )
|
|
{
|
|
dwStatus = GetLastError();
|
|
LogMsg( "[SRV] Status %#08x was returned trying to open the cleanup completion event. This just means that no process is waiting on this event.", dwStatus );
|
|
goto Cleanup;
|
|
} // if: OpenEvent() failed
|
|
|
|
if ( PulseEvent( heventCleanupComplete ) == FALSE )
|
|
{
|
|
// Error, but not fatal. hr should still be S_OK.
|
|
dwStatus = TW32( GetLastError() );
|
|
LogMsg( "[SRV] Error %#08x occurred trying to pulse the cleanup completion event. This is not a fatal error.", dwStatus );
|
|
goto Cleanup;
|
|
} // if: PulseEvent() failed
|
|
|
|
TraceFlow( "Cleanup completion event has been set." );
|
|
|
|
Cleanup:
|
|
|
|
if ( heventCleanupComplete == NULL )
|
|
{
|
|
CloseHandle( heventCleanupComplete );
|
|
} // if: we had opened the cleanup complete event
|
|
|
|
if ( hsCleanupLock != NULL )
|
|
{
|
|
if ( fLockAcquired )
|
|
{
|
|
ReleaseSemaphore( hsCleanupLock, 1, NULL );
|
|
|
|
LogMsg( "[SRV] Cleanup lock released." );
|
|
} // if: we have acquired the semaphore but not released it yet
|
|
|
|
CloseHandle( hsCleanupLock );
|
|
} // if: we had created a cleanup lock
|
|
|
|
if ( hNodeStateKey != NULL )
|
|
{
|
|
RegCloseKey( hNodeStateKey );
|
|
} // if: we had opened the node state registry key
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::HrEvictedFromCluster
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::HrHasNodeBeenEvicted
|
|
//
|
|
// Description:
|
|
// Has this node been evicted?
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// The node needs to be cleanedup.
|
|
//
|
|
// S_FALSE
|
|
// The node does not need to be cleanup.
|
|
//
|
|
// Win32 error as HRESULT.
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CClusCfgServer::HrHasNodeBeenEvicted( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_FALSE;
|
|
DWORD sc;
|
|
DWORD dwClusterState;
|
|
BOOL fEvicted = false;
|
|
|
|
sc = TW32( GetNodeClusterState( NULL, &dwClusterState ) );
|
|
if ( sc != ERROR_SUCCESS )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( sc );
|
|
goto Cleanup;
|
|
} // if : GetClusterState() failed
|
|
|
|
//
|
|
// If the cluster service is not running then we need to check if we should
|
|
// clean it up or not.
|
|
//
|
|
if ( dwClusterState == ClusterStateNotRunning )
|
|
{
|
|
sc = TW32( ClRtlHasNodeBeenEvicted( &fEvicted ) );
|
|
if ( sc != ERROR_SUCCESS )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( sc );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
if ( fEvicted )
|
|
{
|
|
hr = S_OK;
|
|
} // if:
|
|
} // if:
|
|
|
|
Cleanup:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::HrHasNodeBeenEvicted
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::HrCleanUpNode
|
|
//
|
|
// Description:
|
|
// Cleanup this node because it was evicted.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success.
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CClusCfgServer::HrCleanUpNode( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_OK;
|
|
IClusCfgEvictCleanup * pcceEvict = NULL;
|
|
|
|
hr = THR(
|
|
CoCreateInstance(
|
|
CLSID_ClusCfgEvictCleanup
|
|
, NULL
|
|
, CLSCTX_LOCAL_SERVER
|
|
, __uuidof( pcceEvict )
|
|
, reinterpret_cast< void ** >( &pcceEvict )
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: the ClusCfgEvictCleanup object could not be created
|
|
|
|
hr = THR( pcceEvict->CleanupLocalNode( 0 ) ); // 0 means "cleanup immediately"
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if: an error occurred during cleanup
|
|
|
|
Cleanup:
|
|
|
|
if ( pcceEvict != NULL )
|
|
{
|
|
pcceEvict->Release();
|
|
} // if:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::HrCleanUpNode
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CClusCfgServer::HrCreateClusterNodeInfo
|
|
//
|
|
// Description:
|
|
// Create the cluster node info object and store it in the member
|
|
// variable.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// S_OK
|
|
// Success.
|
|
//
|
|
// Remarks:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CClusCfgServer::HrCreateClusterNodeInfo( void )
|
|
{
|
|
TraceFunc( "" );
|
|
Assert( m_punkNodeInfo == NULL );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = THR( CClusCfgNodeInfo::S_HrCreateInstance( &m_punkNodeInfo ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
m_punkNodeInfo = TraceInterface( L"CClusCfgNodeInfo", IUnknown, m_punkNodeInfo, 1 );
|
|
|
|
hr = THR( HrSetInitialize( m_punkNodeInfo, m_picccCallback, m_lcid ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
hr = THR( HrSetWbemServices( m_punkNodeInfo, m_pIWbemServices ) );
|
|
|
|
Cleanup:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CClusCfgServer::HrCreateClusterNodeInfo
|