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.
429 lines
16 KiB
429 lines
16 KiB
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 1999-2002 Microsoft Corporation
|
|
//
|
|
// Module Name:
|
|
// CNode.cpp
|
|
//
|
|
// Description:
|
|
// Contains the definition of the CNode class.
|
|
//
|
|
// Maintained By:
|
|
// David Potter (DavidP) 14-JU-2001
|
|
// Vij Vasu (Vvasu) 08-MAR-2000
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Include Files
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
// The precompiled header.
|
|
#include "Pch.h"
|
|
|
|
// The header for this file
|
|
#include "CNode.h"
|
|
|
|
// For the CRegistryKey class
|
|
#include "CRegistryKey.h"
|
|
|
|
// For the CStr class
|
|
#include "CStr.h"
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Macros
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Names of the sections in the main INF file which deal with node configuration
|
|
// and cleanup.
|
|
#define NODE_CONFIG_INF_SECTION L"Node_Create"
|
|
#define NODE_CLEANUP_INF_SECTION L"Node_Cleanup"
|
|
|
|
// Registry key storing the list of connections for the cluster administrator
|
|
#define CLUADMIN_CONNECTIONS_KEY_NAME L"Software\\Microsoft\\Cluster Administrator\\Connections"
|
|
|
|
// Name of the registry value storing the list of connections for the cluster administrator
|
|
#define CLUADMIN_CONNECTIONS_VALUE_NAME L"Connections"
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CNode::CNode
|
|
//
|
|
// Description:
|
|
// Constructor of the CNode class
|
|
//
|
|
// Arguments:
|
|
// pbcaParentActionIn
|
|
// Pointer to the base cluster action of which this action is a part.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
// Exceptions Thrown:
|
|
// CAssert
|
|
// If the parameters are incorrect.
|
|
//
|
|
// Any exceptions thrown by underlying functions
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
CNode::CNode(
|
|
CBaseClusterAction * pbcaParentActionIn
|
|
)
|
|
: m_pbcaParentAction( pbcaParentActionIn )
|
|
, m_fChangedConnectionsList( false )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
if ( m_pbcaParentAction == NULL)
|
|
{
|
|
LogMsg( "[BC] Pointers to the parent action is NULL. Throwing an exception." );
|
|
THROW_ASSERT(
|
|
E_INVALIDARG
|
|
, "CNode::CNode() => Required input pointer in NULL"
|
|
);
|
|
} // if: the parent action pointer is NULL
|
|
|
|
TraceFuncExit();
|
|
|
|
} //*** CNode::CNode
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CNode::~CNode
|
|
//
|
|
// Description:
|
|
// Destructor of the CNode class.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
// Exceptions Thrown:
|
|
// Any exceptions thrown by underlying functions
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
CNode::~CNode( void )
|
|
{
|
|
TraceFunc( "" );
|
|
TraceFuncExit();
|
|
|
|
} //*** CNode::~CNode
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CNode::Configure
|
|
//
|
|
// Description:
|
|
// Make the changes that need to be made when a node becomes part of a
|
|
// cluster.
|
|
//
|
|
// Arguments:
|
|
// rcstrClusterNameIn
|
|
// Name of the cluster being configured.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
// Exceptions Thrown:
|
|
// CRuntimeError
|
|
// If any of the APIs fail.
|
|
//
|
|
// Any that are thrown by the underlying functions.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
CNode::Configure( const CStr & rcstrClusterNameIn )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
WCHAR * pszConnectionsValue = NULL;
|
|
DWORD cbConnectionsValueSize = 0;
|
|
DWORD cchOldListLen = 0;
|
|
CRegistryKey rkConnectionsKey;
|
|
|
|
//
|
|
// Validate the parameter
|
|
//
|
|
if ( rcstrClusterNameIn.FIsEmpty() )
|
|
{
|
|
LogMsg( "[BC] The name of the cluster is empty. Throwing an exception." );
|
|
THROW_ASSERT( E_INVALIDARG, "The name of the cluster cannot be empty." );
|
|
} // if: the cluster name is not valid
|
|
|
|
LogMsg( "[BC] Attempting to make miscellaneous changes to the node." );
|
|
|
|
// Process the registry keys.
|
|
if ( SetupInstallFromInfSection(
|
|
NULL // optional, handle of a parent window
|
|
, m_pbcaParentAction->HGetMainInfFileHandle() // handle to the INF file
|
|
, NODE_CONFIG_INF_SECTION // name of the Install section
|
|
, SPINST_REGISTRY // which lines to install from section
|
|
, NULL // optional, key for registry installs
|
|
, NULL // optional, path for source files
|
|
, NULL // optional, specifies copy behavior
|
|
, NULL // optional, specifies callback routine
|
|
, NULL // optional, callback routine context
|
|
, NULL // optional, device information set
|
|
, NULL // optional, device info structure
|
|
) == FALSE
|
|
)
|
|
{
|
|
DWORD sc = TW32( GetLastError() );
|
|
|
|
LogMsg( "[BC] Error %#08x returned from SetupInstallFromInfSection() while trying to make miscellaneous changes to the node. Throwing an exception.", sc );
|
|
|
|
THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_NODE_CONFIG );
|
|
} // if: SetupInstallFromInfSection failed
|
|
|
|
//
|
|
// Add the name of the cluster that this node is a part of to the list of connections
|
|
// that will be opened when the cluster administrator is started on this node.
|
|
// The list of connections is a comma separated list of cluster names.
|
|
//
|
|
|
|
LogMsg( "[BC] Adding the cluster name '%s' to the list of cluadmin connections.", rcstrClusterNameIn.PszData() );
|
|
|
|
// Reset the state.
|
|
m_fChangedConnectionsList = false;
|
|
m_sszOldConnectionsList.PRelease();
|
|
|
|
LogMsg( "[BC] Trying to read the existing Cluster Administrator remembered connections list." );
|
|
|
|
// Open the cluster administrator connections key. Create it if it does not exist.
|
|
rkConnectionsKey.CreateKey(
|
|
HKEY_CURRENT_USER
|
|
, CLUADMIN_CONNECTIONS_KEY_NAME
|
|
);
|
|
|
|
try
|
|
{
|
|
// Try and get the current value
|
|
rkConnectionsKey.QueryValue(
|
|
CLUADMIN_CONNECTIONS_VALUE_NAME
|
|
, reinterpret_cast< LPBYTE * >( &pszConnectionsValue )
|
|
, &cbConnectionsValueSize
|
|
);
|
|
|
|
} // try: to read the "Connections" value
|
|
catch( CRuntimeError & crte )
|
|
{
|
|
// Check if this error occurred because the value did not exist
|
|
if ( crte.HrGetErrorCode() == HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) )
|
|
{
|
|
LogMsg( "[BC] The registry value '%s' does not exist. This is ok and is not an error.", CLUADMIN_CONNECTIONS_VALUE_NAME );
|
|
cchOldListLen = 0;
|
|
} // if: the value does not exist
|
|
else
|
|
{
|
|
throw;
|
|
} // else: something else is wrong - rethrow the exception
|
|
|
|
} // catch: the run time error that occurred
|
|
|
|
// Number of characters in the old list, including the terminating NULL.
|
|
cchOldListLen = cbConnectionsValueSize / sizeof( *pszConnectionsValue );
|
|
|
|
if ( cchOldListLen <= 1 )
|
|
{
|
|
LogMsg( "[BC] There are no existing Cluster Administrator remembered connections. Creating a new list with just one name in it." );
|
|
|
|
// Write the cluster name to the value
|
|
rkConnectionsKey.SetValue(
|
|
CLUADMIN_CONNECTIONS_VALUE_NAME
|
|
, REG_SZ
|
|
, reinterpret_cast< const BYTE * >( rcstrClusterNameIn.PszData() )
|
|
, ( rcstrClusterNameIn.NGetLen() + 1 ) * sizeof( WCHAR )
|
|
);
|
|
|
|
// We have changed the connections list.
|
|
m_fChangedConnectionsList = true;
|
|
} // if: there are no existing connections
|
|
else
|
|
{
|
|
WCHAR * pszSubString = NULL;
|
|
bool fIsInList = false;
|
|
|
|
LogMsg( "[BC] The existing list of Cluster Administrator remembered connections is '%s'.", pszConnectionsValue );
|
|
|
|
//
|
|
// Is the cluster name already in the list of connections?
|
|
//
|
|
|
|
pszSubString = wcsstr( pszConnectionsValue, rcstrClusterNameIn.PszData() );
|
|
while ( pszSubString != NULL )
|
|
{
|
|
//
|
|
// The cluster name is a substring of the list.
|
|
// Make sure that the cluster name is not a proper substring of an cluster name already in the list.
|
|
//
|
|
if ( (
|
|
( pszSubString == pszConnectionsValue ) // the substring was found at the beginning of the string
|
|
|| ( *( pszSubString - 1 ) == L',' ) // or the character before the substring is a comma
|
|
) // AND
|
|
&& ( ( *( pszSubString + rcstrClusterNameIn.NGetLen() ) == L'\0' ) // the character after the substring is a '\0'
|
|
|| ( *( pszSubString + rcstrClusterNameIn.NGetLen() ) == L',' ) // or character after the substring is a comma
|
|
)
|
|
)
|
|
{
|
|
fIsInList = true;
|
|
break;
|
|
} // if: the cluster name is not a proper substring of a cluster name that is already in the list
|
|
|
|
// Continue searching.
|
|
pszSubString = wcsstr( pszSubString + rcstrClusterNameIn.NGetLen(), rcstrClusterNameIn.PszData() );
|
|
} // while: the cluster name is a substring of the list of existing connections
|
|
|
|
if ( fIsInList )
|
|
{
|
|
// Nothing more to be done.
|
|
LogMsg( "[BC] The '%s' cluster is already in the list of remembered Cluster Administrator connections.", rcstrClusterNameIn.PszData() );
|
|
goto Cleanup;
|
|
} // if: the cluster name is already in the list
|
|
|
|
LogMsg( "[BC] The '%s' cluster is not in the list of remembered Cluster Administrator connections.", rcstrClusterNameIn.PszData() );
|
|
|
|
// Store the current value in the member variable for restoration in case of error.
|
|
m_sszOldConnectionsList.Assign( pszConnectionsValue );
|
|
|
|
// Set the new connections value.
|
|
{
|
|
// Define a string to hold the new connections value. Preallocate its buffer.
|
|
CStr strNewConnectionsValue(
|
|
cchOldListLen // length of the old list ( including terminating '\0' )
|
|
+ 1 // for the comma
|
|
+ rcstrClusterNameIn.NGetLen() // length of the cluster name( including terminating '\0' )
|
|
);
|
|
|
|
//
|
|
// Construct the new list
|
|
//
|
|
strNewConnectionsValue = rcstrClusterNameIn;
|
|
strNewConnectionsValue += L",";
|
|
strNewConnectionsValue += m_sszOldConnectionsList.PMem();
|
|
|
|
LogMsg( "[BC] Writing the new list of remembered Cluster Administrator connections '%s'.", strNewConnectionsValue.PszData() );
|
|
|
|
// Write the new list.
|
|
rkConnectionsKey.SetValue(
|
|
CLUADMIN_CONNECTIONS_VALUE_NAME
|
|
, REG_SZ
|
|
, reinterpret_cast< const BYTE * >( strNewConnectionsValue.PszData() )
|
|
, ( strNewConnectionsValue.NGetLen() + 1 ) * sizeof( WCHAR )
|
|
);
|
|
|
|
// We have changed the connections list.
|
|
m_fChangedConnectionsList = true;
|
|
}
|
|
|
|
} // else: there are existing connections
|
|
|
|
Cleanup:
|
|
|
|
LogMsg( "[BC] The changes were made successfully." );
|
|
|
|
TraceFuncExit();
|
|
|
|
} //*** CNode::Configure
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CNode::Cleanup
|
|
//
|
|
// Description:
|
|
// Clean up the changes made to this node when it became part of a cluster.
|
|
// Note that the changes made during Configure() are not really undone here -
|
|
// we just bring the node back to an acceptable state. This is because,
|
|
// without a transactional registry, it will be very diffult to get
|
|
// the registry back to the exact state it was in before Configure() was
|
|
// called.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
// Exceptions Thrown:
|
|
// Any that are thrown by the underlying functions.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
CNode::Cleanup( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
LogMsg( "[BC] Attempting to cleanup changes made when this node was made a part of a cluster." );
|
|
|
|
// Process the registry keys.
|
|
if ( SetupInstallFromInfSection(
|
|
NULL // optional, handle of a parent window
|
|
, m_pbcaParentAction->HGetMainInfFileHandle() // handle to the INF file
|
|
, NODE_CLEANUP_INF_SECTION // name of the Install section
|
|
, SPINST_REGISTRY // which lines to install from section
|
|
, NULL // optional, key for registry installs
|
|
, NULL // optional, path for source files
|
|
, NULL // optional, specifies copy behavior
|
|
, NULL // optional, specifies callback routine
|
|
, NULL // optional, callback routine context
|
|
, NULL // optional, device information set
|
|
, NULL // optional, device info structure
|
|
) == FALSE
|
|
)
|
|
{
|
|
DWORD sc = TW32( GetLastError() );
|
|
|
|
LogMsg( "[BC] Error %#08x was returned from SetupInstallFromInfSection() while trying to clean up miscellaneous changes. Throwing an exception.", sc );
|
|
|
|
THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( sc ), IDS_ERROR_NODE_CLEANUP );
|
|
} // if: SetupInstallFromInfSection failed
|
|
|
|
if ( m_fChangedConnectionsList )
|
|
{
|
|
LogMsg( "[BC] Restoring the list of remembered Cluster Administrator connections to '%s'", m_sszOldConnectionsList.PMem() );
|
|
|
|
// Open the cluster administrator connections key.
|
|
CRegistryKey rkConnectionsKey(
|
|
HKEY_CURRENT_USER
|
|
, CLUADMIN_CONNECTIONS_KEY_NAME
|
|
);
|
|
|
|
// If there wasn't a previous value, delete the value we set.
|
|
// Otherwise, set the value back to the old value.
|
|
if ( m_sszOldConnectionsList.PMem() == NULL )
|
|
{
|
|
// Delete the value.
|
|
rkConnectionsKey.DeleteValue( CLUADMIN_CONNECTIONS_VALUE_NAME );
|
|
} // if: no old value existed
|
|
else
|
|
{
|
|
// Write the old list back.
|
|
rkConnectionsKey.SetValue(
|
|
CLUADMIN_CONNECTIONS_VALUE_NAME
|
|
, REG_SZ
|
|
, reinterpret_cast< const BYTE * >( m_sszOldConnectionsList.PMem() )
|
|
, ( (UINT) wcslen( m_sszOldConnectionsList.PMem() ) + 1 ) * sizeof( WCHAR )
|
|
);
|
|
} // else: old value existed
|
|
|
|
} // if: we changed the list of cluadmin connections
|
|
|
|
LogMsg( "[BC] The cleanup was successfully." );
|
|
|
|
TraceFuncExit();
|
|
|
|
} //*** CNode::Cleanup
|