Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1442 lines
44 KiB

/////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1996-2002 Microsoft Corporation
//
// Module Name:
// Cluster.cpp
//
// Abstract:
// Implementation of the CCluster class.
//
// Author:
// David Potter (davidp) May 13, 1996
//
// Revision History:
//
// Notes:
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CluAdmin.h"
#include "ConstDef.h"
#include "Cluster.h"
#include "CASvc.h"
#include "ClusDoc.h"
#include "ClusProp.h"
#include "ExcOper.h"
#include "ClusItem.inl"
#include "resource.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// Global Variables
/////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
CTraceTag g_tagCluster( _T("Document"), _T("CLUSTER"), 0 );
#endif
/////////////////////////////////////////////////////////////////////////////
// CCluster
/////////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE( CCluster, CClusterItem )
/////////////////////////////////////////////////////////////////////////////
// Message Maps
/////////////////////////////////////////////////////////////////////////////
BEGIN_MESSAGE_MAP( CCluster, CClusterItem )
//{{AFX_MSG_MAP(CCluster)
ON_UPDATE_COMMAND_UI(ID_FILE_PROPERTIES, OnUpdateProperties)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::CCluster
//
// Routine Description:
// Default construtor.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
CCluster::CCluster( void ) : CClusterItem( NULL, IDS_ITEMTYPE_CLUSTER )
{
m_idmPopupMenu = IDM_CLUSTER_POPUP;
ZeroMemory( &m_cvi, sizeof( m_cvi ) );
m_nMaxQuorumLogSize = 0;
m_plpciNetworkPriority = NULL;
// Set the object type and state images.
m_iimgObjectType = GetClusterAdminApp()->Iimg( IMGLI_CLUSTER );
m_iimgState = m_iimgObjectType;
// Setup the property array.
{
m_rgProps[epropDefaultNetworkRole].Set(CLUSREG_NAME_CLUS_DEFAULT_NETWORK_ROLE, m_nDefaultNetworkRole, m_nDefaultNetworkRole);
m_rgProps[epropDescription].Set(CLUSREG_NAME_CLUS_DESC, m_strDescription, m_strDescription);
m_rgProps[epropEnableEventLogReplication].Set(CLUSREG_NAME_CLUS_EVTLOG_PROPAGATION, m_bEnableEventLogReplication, m_bEnableEventLogReplication);
m_rgProps[epropQuorumArbitrationTimeMax].Set(CLUSREG_NAME_QUORUM_ARBITRATION_TIMEOUT, m_nQuorumArbitrationTimeMax, m_nQuorumArbitrationTimeMax);
m_rgProps[epropQuorumArbitrationTimeMin].Set(CLUSREG_NAME_QUORUM_ARBITRATION_EQUALIZER, m_nQuorumArbitrationTimeMin, m_nQuorumArbitrationTimeMin);
} // Setup the property array
} //*** CCluster::CCluster()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::~CCluster
//
// Routine Description:
// Destructor.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
CCluster::~CCluster( void )
{
Cleanup();
} //*** CCluster::~CCluster()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::Cleanup
//
// Routine Description:
// Cleanup the item.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::Cleanup( void )
{
// Delete the NetworkPriority list.
if ( m_plpciNetworkPriority != NULL )
{
m_plpciNetworkPriority->RemoveAll();
delete m_plpciNetworkPriority;
m_plpciNetworkPriority = NULL;
} // if: NetworkPriority list exists
m_hkey = NULL;
} //*** CCluster::Cleanup()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::Init
//
// Routine Description:
// Initialize the item.
//
// Arguments:
// pdoc [IN OUT] Document to which this item belongs.
// lpszName [IN] Name of the item.
// hOpenedCluster [IN] Handle to cluster to use that is already open.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from OpenCluster(), GetClusterKey(), or
// CreateClusterNotifyPort().
// Any exceptions thrown by CCluster::ReadClusterInfo().
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::Init(
IN OUT CClusterDoc * pdoc,
IN LPCTSTR lpszName,
IN HCLUSTER hOpenedCluster // = NULL
)
{
CWaitCursor wc;
TCHAR szClusterName[ MAX_PATH ];
DWORD scLastError;
ASSERT( Hkey() == NULL );
ASSERT( _tcslen( lpszName ) < RTL_NUMBER_OF( szClusterName ) );
try
{
// If connecting the local machine, get its name.
if ( _tcscmp( lpszName, _T(".") ) == 0 )
{
DWORD nSize = sizeof( szClusterName ) / sizeof( TCHAR );
GetComputerName( szClusterName, &nSize );
} // if: connecting to the local machine
else
{
HRESULT hr = StringCchCopy( szClusterName, RTL_NUMBER_OF( szClusterName ), lpszName );
ASSERT( SUCCEEDED( hr ) );
} // else: not connecting to the local machine
// Open the cluster.
if ( hOpenedCluster == NULL )
{
pdoc->m_hcluster = HOpenCluster( lpszName );
if ( pdoc->m_hcluster == NULL )
{
//
// GPotts - 7/25/2001
//
// HOpenCluster could return NULL and last error = 0 if GetNodeClusterState
// returned either ClusterStateNotInstalled or ClusterStateNotConfigured.
//
scLastError = GetLastError();
ThrowStaticException( scLastError, IDS_OPEN_CLUSTER_ERROR, szClusterName );
} // if: error opening the cluster
} // if: no opened cluster passed in
else
{
pdoc->m_hcluster = hOpenedCluster;
} // if: cluster already opened
// Get the cluster registry key.
pdoc->m_hkeyCluster = GetClusterKey( pdoc->m_hcluster, MAXIMUM_ALLOWED );
if ( pdoc->m_hkeyCluster == NULL )
{
ThrowStaticException( GetLastError(), IDS_GET_CLUSTER_KEY_ERROR, szClusterName );
} // if: error opening the cluster key
// Call the base class method. We can use Hcluster() after calling this.
CClusterItem::Init( pdoc, szClusterName );
// Get the cluster registry key.
m_hkey = pdoc->m_hkeyCluster;
// Register this cluster with the notification port.
{
HCHANGE hchange;
// We want these notifications to go to the document, not us.
ASSERT( Pcnk() != NULL );
m_pcnk->m_cnkt = cnktDoc;
m_pcnk->m_pdoc = pdoc;
Trace( g_tagClusItemNotify, _T("CCluster::Init() - Registering for cluster notifications (%08.8x)"), Pcnk() );
// Create the notification port.
hchange = CreateClusterNotifyPort(
GetClusterAdminApp()->HchangeNotifyPort(),
Hcluster(),
(CLUSTER_CHANGE_NODE_ADDED
| CLUSTER_CHANGE_GROUP_ADDED
| CLUSTER_CHANGE_RESOURCE_ADDED
| CLUSTER_CHANGE_RESOURCE_TYPE_ADDED
| CLUSTER_CHANGE_RESOURCE_TYPE_DELETED
| CLUSTER_CHANGE_RESOURCE_TYPE_PROPERTY
| CLUSTER_CHANGE_NETWORK_ADDED
| CLUSTER_CHANGE_NETINTERFACE_ADDED
| CLUSTER_CHANGE_QUORUM_STATE
| CLUSTER_CHANGE_CLUSTER_STATE
| CLUSTER_CHANGE_CLUSTER_PROPERTY
| CLUSTER_CHANGE_REGISTRY_NAME
| CLUSTER_CHANGE_REGISTRY_ATTRIBUTES
| CLUSTER_CHANGE_REGISTRY_VALUE
| CLUSTER_CHANGE_REGISTRY_SUBTREE),
(DWORD_PTR) Pcnk()
);
if ( hchange == NULL )
{
ThrowStaticException( GetLastError(), IDS_CLUSTER_NOTIF_REG_ERROR, szClusterName );
} // if: error creating the notify port
ASSERT( hchange == GetClusterAdminApp()->HchangeNotifyPort() );
} // Register this cluster with the notification port
// Get the name of the cluster as recorded by the cluster.
ReadClusterInfo();
// Allocate lists.
m_plpciNetworkPriority = new CNetworkList;
if ( m_plpciNetworkPriority == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the network list
// Read the initial state.
UpdateState();
} // try
catch ( CException * )
{
if ( pdoc->m_hkeyCluster != NULL )
{
ClusterRegCloseKey( pdoc->m_hkeyCluster );
pdoc->m_hkeyCluster = NULL;
m_hkey = NULL;
} // if: registry key opened
if ( ( pdoc->m_hcluster != NULL ) && ( pdoc->m_hcluster != hOpenedCluster ) )
{
CloseCluster( pdoc->m_hcluster );
pdoc->m_hcluster = NULL;
} // if: group opened
m_bReadOnly = TRUE;
throw;
} // catch: CException
} //*** CCluster::Init()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::ReadItem
//
// Routine Description:
// Read the item parameters from the cluster database.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from CClusterItem::DwReadValue() or
// CClusterItem::ReadItem().
// Any exceptions thrown by CCluster::ReadExtensions().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::ReadItem( void )
{
DWORD dwStatus;
DWORD dwRetStatus = ERROR_SUCCESS;
CWaitCursor wc;
ASSERT( Hcluster() != NULL );
ASSERT( Hkey() != NULL );
if ( Hcluster() != NULL )
{
m_rgProps[epropDefaultNetworkRole].m_value.pdw = &m_nDefaultNetworkRole;
m_rgProps[epropDescription].m_value.pstr = &m_strDescription;
m_rgProps[epropEnableEventLogReplication].m_value.pb = &m_bEnableEventLogReplication;
m_rgProps[epropQuorumArbitrationTimeMax].m_value.pdw = &m_nQuorumArbitrationTimeMax;
m_rgProps[epropQuorumArbitrationTimeMin].m_value.pdw = &m_nQuorumArbitrationTimeMin;
// Call the base class method.
try
{
CClusterItem::ReadItem();
} // try
catch ( CNTException * pnte )
{
dwRetStatus = pnte->Sc();
pnte->Delete();
} // catch: CNTException
// Get the name of the cluster as recorded by the cluster.
ReadClusterInfo();
// Read and parse the common properties.
{
CClusPropList cpl;
Trace( g_tagCluster, _T("(%x) - CCluster::ReadItem() - Getting common properties"), this );
dwStatus = cpl.ScGetClusterProperties(
Hcluster(),
CLUSCTL_CLUSTER_GET_COMMON_PROPERTIES
);
if (dwStatus == ERROR_SUCCESS)
{
Trace( g_tagCluster, _T("(%x) - CCluster::ReadItem() - Parsing common properties"), this );
dwStatus = DwParseProperties(cpl);
} // if: properties read successfully
if (dwStatus != ERROR_SUCCESS)
{
Trace( g_tagError, _T("(%x) - CCluster::ReadItem() - Error 0x%08.8x getting or parsing common properties"), this, dwStatus );
// PROCNUM_OUT_OF_RANGE occurs when the server side
// (clussvc.exe) doesn't support the ClusterControl( )
// API. In this case, read the data using the cluster
// registry APIs.
if ( dwStatus == RPC_S_PROCNUM_OUT_OF_RANGE )
{
if ( Hkey() != NULL )
{
// Read the Description
dwStatus = DwReadValue( CLUSREG_NAME_CLUS_DESC, m_strDescription );
if ( ( dwStatus != ERROR_SUCCESS )
&& ( dwStatus != ERROR_FILE_NOT_FOUND ) )
{
dwRetStatus = dwStatus;
} // if: error reading the value
} // if: key is available
} // if: must be talking to an NT4 node
else
{
dwRetStatus = dwStatus;
} // else: not talking to an NT4 node
} // if: error reading or parsing properties
} // Read and parse the common properties
// Get quorum resource information.
{
LPWSTR pwszQResName = NULL;
LPWSTR pwszQuorumPath = NULL;
DWORD cchQResName;
DWORD cchQuorumPath;
// Get the size of the resource name.
cchQResName = 0;
cchQuorumPath = 0;
dwStatus = GetClusterQuorumResource(
Hcluster(),
NULL,
&cchQResName,
NULL,
&cchQuorumPath,
&m_nMaxQuorumLogSize
);
if ( ( dwStatus == ERROR_SUCCESS ) || ( dwStatus == ERROR_MORE_DATA ) )
{
// Allocate enough space for the data.
cchQResName++; // Don't forget the final null-terminator.
pwszQResName = new WCHAR[ cchQResName ];
cchQuorumPath++;
pwszQuorumPath = new WCHAR[ cchQuorumPath ];
ASSERT( pwszQResName != NULL && pwszQuorumPath != NULL );
// Read the resource name.
dwStatus = GetClusterQuorumResource(
Hcluster(),
pwszQResName,
&cchQResName,
pwszQuorumPath,
&cchQuorumPath,
&m_nMaxQuorumLogSize
);
} // if: got the size successfully
if ( dwStatus != ERROR_SUCCESS )
{
dwRetStatus = dwStatus;
} // if: error occurred
else
{
m_strQuorumResource = pwszQResName;
m_strQuorumPath = pwszQuorumPath;
ASSERT( m_strQuorumPath[ m_strQuorumPath.GetLength() - 1 ] == _T('\\') );
} // else: quorum resource info retrieved successfully
delete [] pwszQResName;
delete [] pwszQuorumPath;
} // Get the quorum resource name
} // if: cluster is available
// If any errors occurred, throw an exception.
if ( dwRetStatus != ERROR_SUCCESS )
{
ThrowStaticException( dwRetStatus, IDS_READ_CLUSTER_PROPS_ERROR, StrName() );
} // if: error occurred
// Read extension lists.
ReadClusterExtensions();
ReadNodeExtensions();
ReadGroupExtensions();
ReadResourceExtensions();
ReadResTypeExtensions();
ReadNetworkExtensions();
ReadNetInterfaceExtensions();
// Read the initial state.
UpdateState();
MarkAsChanged( FALSE );
} //*** CCluster::ReadItem()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::PlstrExtensions
//
// Routine Description:
// Return the list of admin extensions.
//
// Arguments:
// None.
//
// Return Value:
// plstr List of extensions.
// NULL No extension associated with this object.
//
// Exceptions Thrown:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
const CStringList * CCluster::PlstrExtensions( void ) const
{
return &LstrClusterExtensions();
} //*** CCluster::PlstrExtensions()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::ReadClusterInfo
//
// Routine Description:
// Get the name of the cluster as recorded by the cluster and the
// version of the cluster software.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any exceptions thrown by new.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::ReadClusterInfo( void )
{
CWaitCursor wc;
GetClusterInformation( Hcluster(), m_strName, &m_cvi );
Pdoc()->m_strName = m_strName;
} //*** CCluster::ReadClusterInfo()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::ReadClusterExtensions
//
// Routine Description:
// Read the extension list for the cluster object.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from CClusterItem::DwReadValue().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::ReadClusterExtensions( void )
{
DWORD dwStatus;
CWaitCursor wc;
ASSERT( Hkey() != NULL );
if ( Hkey() != NULL )
{
// Read the Cluster extension string.
dwStatus = DwReadValue( CLUSREG_NAME_ADMIN_EXT, m_lstrClusterExtensions );
if ( ( dwStatus != ERROR_SUCCESS )
&& ( dwStatus != ERROR_FILE_NOT_FOUND ) )
{
ThrowStaticException( dwStatus );
} // if: error reading the value
} // if: key is available
else
{
m_lstrClusterExtensions.RemoveAll();
} // else: key is not available
} //*** CCluster::ReadClusterExtensions()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::ReadNodeExtensions
//
// Routine Description:
// Read the extension list for all nodes.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from CClusterItem::DwReadValue().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::ReadNodeExtensions( void )
{
DWORD dwStatus;
CWaitCursor wc;
ASSERT( Hkey() != NULL );
if ( Hkey() != NULL )
{
// Read the Nodes extension string.
dwStatus = DwReadValue( CLUSREG_NAME_ADMIN_EXT, CLUSREG_KEYNAME_NODES, m_lstrNodeExtensions );
if ( ( dwStatus != ERROR_SUCCESS )
&& ( dwStatus != ERROR_FILE_NOT_FOUND ) )
{
ThrowStaticException( dwStatus );
} // if: error reading the value
} // if: key is available
else
{
m_lstrNodeExtensions.RemoveAll();
} // else: key is not available
} //*** CCluster::ReadNodeExtensions()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::ReadGroupExtensions
//
// Routine Description:
// Read the extension list for all groups.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from CClusterItem::DwReadValue().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::ReadGroupExtensions( void )
{
DWORD dwStatus;
CWaitCursor wc;
ASSERT( Hkey() != NULL );
if ( Hkey() != NULL )
{
// Read the Groups extension string.
dwStatus = DwReadValue( CLUSREG_NAME_ADMIN_EXT, CLUSREG_KEYNAME_GROUPS, m_lstrGroupExtensions );
if ( ( dwStatus != ERROR_SUCCESS )
&& ( dwStatus != ERROR_FILE_NOT_FOUND ) )
{
ThrowStaticException( dwStatus );
} // if: error reading the value
} // if: key is available
else
{
m_lstrGroupExtensions.RemoveAll();
} // else: key is not available
} //*** CCluster::ReadGroupExtensions()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::ReadResourceExtensions
//
// Routine Description:
// Read the extension list for all resources.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from CClusterItem::DwReadValue().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::ReadResourceExtensions( void )
{
DWORD dwStatus;
CWaitCursor wc;
ASSERT( Hkey() != NULL );
if ( Hkey() != NULL )
{
// Read the Resources extension string.
dwStatus = DwReadValue( CLUSREG_NAME_ADMIN_EXT, CLUSREG_KEYNAME_RESOURCES, m_lstrResourceExtensions );
if ( ( dwStatus != ERROR_SUCCESS )
&& ( dwStatus != ERROR_FILE_NOT_FOUND ) )
{
ThrowStaticException( dwStatus );
} // if: error reading the value
} // if: key is available
else
{
m_lstrResourceExtensions.RemoveAll();
} // else: key is not available
} //*** CCluster::ReadResourceExtensions()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::ReadResTypeExtensions
//
// Routine Description:
// Read the extension list for all resouce types.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from CClusterItem::DwReadValue().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::ReadResTypeExtensions( void )
{
DWORD dwStatus;
CWaitCursor wc;
ASSERT( Hkey() != NULL );
if ( Hkey() != NULL )
{
// Read the Resource Types extension string.
dwStatus = DwReadValue( CLUSREG_NAME_ADMIN_EXT, CLUSREG_KEYNAME_RESOURCE_TYPES, m_lstrResTypeExtensions );
if ( ( dwStatus != ERROR_SUCCESS )
&& ( dwStatus != ERROR_FILE_NOT_FOUND ) )
{
ThrowStaticException( dwStatus );
} // if: error reading the value
} // if: key is available
else
{
m_lstrResTypeExtensions.RemoveAll();
} // else: key is not available
} //*** CCluster::ReadResTypeExtensions()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::ReadNetworkExtensions
//
// Routine Description:
// Read the extension list for all networks.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from CClusterItem::DwReadValue().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::ReadNetworkExtensions( void )
{
DWORD dwStatus;
CWaitCursor wc;
ASSERT( Hkey() != NULL );
if ( Hkey() != NULL )
{
// Read the Networks extension string.
dwStatus = DwReadValue( CLUSREG_NAME_ADMIN_EXT, CLUSREG_KEYNAME_NETWORKS, m_lstrNetworkExtensions );
if ( ( dwStatus != ERROR_SUCCESS )
&& ( dwStatus != ERROR_FILE_NOT_FOUND ) )
{
ThrowStaticException( dwStatus );
} // if: error reading the value
} // if: key is available
else
{
m_lstrNetworkExtensions.RemoveAll();
} // else: key is not available
} //*** CCluster::ReadNetworkExtensions()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::ReadNetInterfaceExtensions
//
// Routine Description:
// Read the extension list for all network interfaces.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from CClusterItem::DwReadValue().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::ReadNetInterfaceExtensions( void )
{
DWORD dwStatus;
CWaitCursor wc;
ASSERT( Hkey() != NULL );
if ( Hkey() != NULL )
{
// Read the Network Intefaces extension string.
dwStatus = DwReadValue( CLUSREG_NAME_ADMIN_EXT, CLUSREG_KEYNAME_NETINTERFACES, m_lstrNetInterfaceExtensions );
if ( ( dwStatus != ERROR_SUCCESS )
&& ( dwStatus != ERROR_FILE_NOT_FOUND ) )
{
ThrowStaticException( dwStatus );
} // if: error reading the value
} // if: key is available
else
{
m_lstrNetInterfaceExtensions.RemoveAll();
} // else: key is not available
} //*** CCluster::ReadNetInterfaceExtensions()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::CollecNetworkPriority
//
// Routine Description:
// Construct the network priority list.
//
// Arguments:
// plpci [IN OUT] List to fill.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from ClusterOpenEnum() or ClusterEnum().
// Any exceptions thrown by new or CList::AddTail().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::CollectNetworkPriority( IN OUT CNetworkList * plpci )
{
DWORD dwStatus;
HCLUSENUM hclusenum;
int ienum;
LPWSTR pwszName = NULL;
DWORD cchName;
DWORD cchmacName;
DWORD dwRetType;
CNetwork * pciNet;
CWaitCursor wc;
ASSERT_VALID( Pdoc() );
ASSERT( Hcluster() != NULL );
if ( plpci == NULL )
{
plpci = m_plpciNetworkPriority;
} // if: no list specified
ASSERT( plpci != NULL );
// Remove the previous contents of the list.
plpci->RemoveAll();
if ( Hcluster() != NULL )
{
// Open the enumeration.
hclusenum = ClusterOpenEnum( Hcluster(), (DWORD) CLUSTER_ENUM_INTERNAL_NETWORK );
if ( hclusenum == NULL )
{
ThrowStaticException( GetLastError(), IDS_ENUM_NETWORK_PRIORITY_ERROR, StrName() );
} // if: error opening the enmeration
try
{
// Allocate a name buffer.
cchmacName = 128;
pwszName = new WCHAR[ cchmacName ];
if ( pwszName == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the name buffer
// Loop through the enumeration and add each network to the list.
for ( ienum = 0 ; ; ienum++ )
{
// Get the next item in the enumeration.
cchName = cchmacName;
dwStatus = ClusterEnum( hclusenum, ienum, &dwRetType, pwszName, &cchName );
if ( dwStatus == ERROR_MORE_DATA )
{
delete [] pwszName;
cchmacName = ++cchName;
pwszName = new WCHAR[ cchmacName ];
if ( pwszName == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the name buffer
dwStatus = ClusterEnum( hclusenum, ienum, &dwRetType, pwszName, &cchName );
} // if: name buffer was too small
if ( dwStatus == ERROR_NO_MORE_ITEMS )
{
break;
} // if: done with the enumeraiton
else if ( dwStatus != ERROR_SUCCESS )
{
ThrowStaticException( dwStatus, IDS_ENUM_NETWORK_PRIORITY_ERROR, StrName() );
} // else if: error getting the next enumeration value
ASSERT( dwRetType == CLUSTER_ENUM_INTERNAL_NETWORK );
// Find the item in the list of networks on the document.
pciNet = Pdoc()->LpciNetworks().PciNetworkFromName( pwszName );
ASSERT_VALID( pciNet );
// Add the network to the list.
if ( pciNet != NULL )
{
plpci->AddTail( pciNet );
} // if: found network in list
} // for: each item in the group
ClusterCloseEnum( hclusenum );
} // try
catch ( CException * )
{
delete [] pwszName;
ClusterCloseEnum( hclusenum );
throw;
} // catch: any exception
} // if: cluster is available
delete [] pwszName;
} //*** CCluster::CollecNetworkPriority()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::OnUpdateProperties
//
// Routine Description:
// Determines whether menu items corresponding to ID_FILE_PROPERTIES
// should be enabled or not.
//
// Arguments:
// pCmdUI [IN OUT] Command routing object.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::OnUpdateProperties( CCmdUI * pCmdUI )
{
pCmdUI->Enable(TRUE);
} //*** CCluster::OnUpdateProperties()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::BDisplayProperties
//
// Routine Description:
// Display properties for the object.
//
// Arguments:
// bReadOnly [IN] Don't allow edits to the object properties.
//
// Return Value:
// TRUE OK pressed.
// FALSE OK not pressed.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CCluster::BDisplayProperties( IN BOOL bReadOnly )
{
BOOL bChanged = FALSE;
CClusterPropSheet sht( AfxGetMainWnd() );
// Do this in case this object is deleted while we are operating on it.
AddRef();
// If the object has changed, read it.
if ( BChanged() )
{
ReadItem();
} // if: object changed
// Display the property sheet.
try
{
sht.SetReadOnly( bReadOnly );
if ( sht.BInit( this, IimgObjectType() ) )
{
bChanged = ( ( sht.DoModal() == IDOK ) && ! bReadOnly );
} // if: initialized successfully
} // try
catch ( CException * pe )
{
pe->Delete();
} // catch: CException
Release();
return bChanged;
} //*** CCluster::BDisplayProperties()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::SetName
//
// Routine Description:
// Set the name of the cluster.
//
// Arguments:
// pszName [IN] New name of the cluster.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any exceptions thrown by WriteItem().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::SetName( IN LPCTSTR pszName )
{
Rename( pszName );
} //*** CCluster::SetName()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::SetDescription
//
// Routine Description:
// Set the description in the cluster database.
//
// Arguments:
// pszDesc [IN] Description to set.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any exceptions thrown by WriteItem().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::SetDescription( IN LPCTSTR pszDesc )
{
ASSERT( Hkey() != NULL );
if ( ( Hkey() != NULL ) && ( m_strDescription != pszDesc ) )
{
WriteValue( CLUSREG_NAME_CLUS_DESC, NULL, pszDesc );
m_strDescription = pszDesc;
} // if: a change occured
} //*** CCluster::SetDescription()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::SetQuorumResource
//
// Routine Description:
// Set the quorum resource for the cluster.
//
// Arguments:
// pszResource [IN] Name of resource to make the quorum resource.
// pszQuorumPath [IN] Path for storing cluster files.
// nMaxLogSize [IN] Maximum size of the quorum log.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException IDS_SET_QUORUM_RESOURCE_ERROR - errors from
// SetClusterQuorumResource().
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::SetQuorumResource(
IN LPCTSTR pszResource,
IN LPCTSTR pszQuorumPath,
IN DWORD nMaxLogSize
)
{
DWORD dwStatus;
CResource * pciRes;
CString strRes( pszResource ); // Required if built non-Unicode
CWaitCursor wc;
ASSERT( pszResource != NULL );
if ( ( StrQuorumResource() != pszResource )
|| ( StrQuorumPath() != pszQuorumPath )
|| ( NMaxQuorumLogSize() != nMaxLogSize ) )
{
// Find the resource.
pciRes = Pdoc()->LpciResources().PciResFromName( pszResource );
ASSERT_VALID( pciRes );
ASSERT( pciRes->Hresource() != NULL );
if ( pciRes->Hresource() != NULL )
{
// Change the quorum resource.
dwStatus = SetClusterQuorumResource( pciRes->Hresource(), pszQuorumPath, nMaxLogSize );
if ( dwStatus != ERROR_SUCCESS )
{
ThrowStaticException( dwStatus, IDS_SET_QUORUM_RESOURCE_ERROR, pciRes->StrName() );
} // if: error setting the quorum resource
m_strQuorumResource = pszResource;
m_strQuorumPath = pszQuorumPath;
m_nMaxQuorumLogSize = nMaxLogSize;
} // if: resource is available
} // if: the quorum resource changed
} //*** CCluster::SetQuorumResource()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::SetNetworkPriority
//
// Routine Description:
// Set the network priority list.
//
// Arguments:
// rlpci [IN] List of networks in priority order.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any exceptions thrown by HNETWORK::new.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::SetNetworkPriority( IN const CNetworkList & rlpci )
{
DWORD dwStatus;
CWaitCursor wc;
ASSERT( Hcluster() != NULL );
if ( Hcluster() != NULL )
{
BOOL bChanged = TRUE;
// Determine if the list has changed.
if ( rlpci.GetCount() == LpciNetworkPriority().GetCount() )
{
POSITION posOld;
POSITION posNew;
CNetwork * pciOldNet;
CNetwork * pciNewNet;
bChanged = FALSE;
posOld = LpciNetworkPriority().GetHeadPosition();
posNew = rlpci.GetHeadPosition();
while ( posOld != NULL )
{
pciOldNet = (CNetwork *) LpciNetworkPriority().GetNext( posOld );
ASSERT_VALID( pciOldNet );
ASSERT( posNew != NULL );
pciNewNet = (CNetwork *) rlpci.GetNext( posNew );
ASSERT_VALID( pciNewNet );
if ( pciOldNet->StrName() != pciNewNet->StrName() )
{
bChanged = TRUE;
break;
} // if: name is not the same
} // while: more items in the old list
} // if: same number of items in the list
if ( bChanged )
{
HNETWORK * phnetwork = NULL;
try
{
DWORD ipci;
POSITION posPci;
CNetwork * pciNet;
// Allocate an array for all the node handles.
phnetwork = new HNETWORK[ (DWORD) rlpci.GetCount() ];
if ( phnetwork == NULL )
{
ThrowStaticException( GetLastError() );
} // if: error allocating network handle array
// Copy the handle of all the networks in the networks list to the handle aray.
posPci = rlpci.GetHeadPosition();
for ( ipci = 0 ; posPci != NULL ; ipci++ )
{
pciNet = (CNetwork *) rlpci.GetNext( posPci );
ASSERT_VALID( pciNet );
phnetwork[ ipci ] = pciNet->Hnetwork();
} // while: more networks in the list
// Set the property.
dwStatus = SetClusterNetworkPriorityOrder( Hcluster(), (DWORD) rlpci.GetCount(), phnetwork );
if ( dwStatus != ERROR_SUCCESS )
{
ThrowStaticException( dwStatus, IDS_SET_NET_PRIORITY_ERROR, StrName() );
} // if: error setting network priority
// Update the PCI list.
m_plpciNetworkPriority->RemoveAll();
posPci = rlpci.GetHeadPosition();
while ( posPci != NULL )
{
pciNet = (CNetwork *) rlpci.GetNext( posPci );
m_plpciNetworkPriority->AddTail( pciNet );
} // while: more items in the list
} // try
catch ( CException * )
{
delete [] phnetwork;
throw;
} // catch: CException
delete [] phnetwork;
} // if: list changed
} // if: key is available
} //*** CCluster::SetNetworkPriority(CNetworkList*)
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::Rename
//
// Routine Description:
// Change the name of the cluster..
//
// Arguments:
// pszName [IN] New name to give to the cluster.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors returned from SetClusterName().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::Rename( IN LPCTSTR pszName )
{
DWORD dwStatus;
CWaitCursor wc;
ASSERT( Hcluster() != NULL );
if ( StrName() != pszName )
{
// Set the name.
dwStatus = SetClusterName( Hcluster(), pszName );
if ( dwStatus != ERROR_SUCCESS )
{
if ( dwStatus == ERROR_RESOURCE_PROPERTIES_STORED )
{
AfxMessageBox( IDS_RESTART_CLUSTER_NAME, MB_OK | MB_ICONEXCLAMATION );
} // if: properties stored but not in use yet
else
{
ThrowStaticException( dwStatus, IDS_RENAME_CLUSTER_ERROR, StrName(), pszName );
} // else: error occurred
} // if: error occurred setting cluster name
m_strName = pszName;
} // if: the name changed
} //*** CCluster::Rename()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::BIsLabelEditValueValid
//
// Routine Description:
// Validate the label edit value as a cluster name
//
// Arguments:
// pszName [IN] New name to give to the cluster.
//
// Return Value:
// TRUE name is valid
// FALSE name is invalid
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CCluster::BIsLabelEditValueValid( IN LPCTSTR pszName )
{
BOOL bSuccess = TRUE;
if ( StrName() != pszName )
{
CLRTL_NAME_STATUS cnStatus;
UINT idsError;
// Validate the name.
if ( ! ClRtlIsNetNameValid( pszName, &cnStatus, FALSE /*CheckIfExists*/ ) )
{
switch ( cnStatus )
{
case NetNameTooLong:
idsError = IDS_INVALID_CLUSTER_NAME_TOO_LONG;
break;
case NetNameInvalidChars:
idsError = IDS_INVALID_CLUSTER_NAME_INVALID_CHARS;
break;
case NetNameInUse:
idsError = IDS_INVALID_CLUSTER_NAME_IN_USE;
break;
case NetNameDNSNonRFCChars:
idsError = IDS_INVALID_CLUSTER_NAME_INVALID_DNS_CHARS;
break;
case NetNameSystemError:
{
DWORD scError = GetLastError();
ThrowStaticException( scError, IDS_ERROR_VALIDATING_NETWORK_NAME, pszName );
}
default:
idsError = IDS_INVALID_CLUSTER_NAME;
break;
} // switch: cnStatus
if ( idsError == IDS_INVALID_CLUSTER_NAME_INVALID_DNS_CHARS )
{
int id = AfxMessageBox(IDS_INVALID_CLUSTER_NAME_INVALID_DNS_CHARS, MB_YESNO | MB_DEFBUTTON2 | MB_ICONEXCLAMATION );
if ( id == IDNO )
{
bSuccess = FALSE;
}
}
else
{
bSuccess = FALSE;
}
} // if: error validating the name
} // if: the name changed
return bSuccess;
} //*** CCluster::BIsLabelEditValueValid()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::OnBeginLabelEdit
//
// Routine Description:
// Prepare an edit control in a view for editing the cluster name.
//
// Arguments:
// pedit [IN OUT] Edit control to prepare.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::OnBeginLabelEdit( IN OUT CEdit * pedit )
{
ASSERT_VALID(pedit);
pedit->SetLimitText( MAX_CLUSTERNAME_LENGTH );
pedit->ModifyStyle( 0 /*dwRemove*/, ES_UPPERCASE | ES_OEMCONVERT /*dwAdd*/ );
} //*** CCluster::OnBeginLabelEdit()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CCluster::UpdateState
//
// Routine Description:
// Update the current state of the item.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CCluster::UpdateState( void )
{
// NOTENOTE: not referneced
//CClusterAdminApp * papp = GetClusterAdminApp();
CString strTitle;
GetClusterAdminApp();
Trace( g_tagCluster, _T("(%s) - Updating state"), StrName() );
// Update the title of the document.
ASSERT_VALID( Pdoc() );
try
{
Pdoc()->UpdateTitle();
} // try
catch ( CException * pe )
{
pe->Delete();
} // catch: CException
// Call the base class method.
CClusterItem::UpdateState();
} //*** CCluster::UpdateState()