windows-nt/Source/XPSP1/NT/net/wlbs/wmi/wlbs_cluster.cpp
2020-09-26 16:20:57 +08:00

834 lines
23 KiB
C++

#include "WLBS_Provider.h"
#include "WLBS_Cluster.h"
#include "ClusterWrapper.h"
#include "ControlWrapper.h"
#include "utils.h"
#include "param.h"
#include "wlbsutil.h"
#include "wlbs_cluster.tmh" // for event tracing
////////////////////////////////////////////////////////////////////////////////
//
// CWLBS_Cluster::CWLBS_Cluster
//
// Purpose: Constructor
//
////////////////////////////////////////////////////////////////////////////////
CWLBS_Cluster::CWLBS_Cluster( CWbemServices* a_pNameSpace,
IWbemObjectSink* a_pResponseHandler)
: CWlbs_Root( a_pNameSpace, a_pResponseHandler )
{
}
////////////////////////////////////////////////////////////////////////////////
//
// CWLBS_Cluster::Create
//
// Purpose: This instantiates this class and is invoked from an array of
// function pointers.
//
////////////////////////////////////////////////////////////////////////////////
CWlbs_Root* CWLBS_Cluster::Create
(
CWbemServices* a_pNameSpace,
IWbemObjectSink* a_pResponseHandler
)
{
g_pWlbsControl->CheckMembership();
CWlbs_Root* pRoot = new CWLBS_Cluster( a_pNameSpace, a_pResponseHandler );
if( !pRoot )
throw _com_error( WBEM_E_OUT_OF_MEMORY );
return pRoot;
}
////////////////////////////////////////////////////////////////////////////////
//
// CWLBS_Cluster::GetInstance
//
// Purpose: This function retrieves an instance of a MOF Cluster class.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT CWLBS_Cluster::GetInstance
(
const ParsedObjectPath* a_pParsedPath,
long /*a_lFlags*/,
IWbemContext* a_pIContex
)
{
IWbemClassObject* pWlbsInstance = NULL;
HRESULT hRes = 0;
try {
//get the name key property and convert to wstring
//throws _com_error
const WCHAR* wstrRequestedClusterName = (*a_pParsedPath->m_paKeys)->m_vValue.bstrVal;
DWORD dwNumHosts = 0;
//check to see if the requested cluster name matches the configured value
// The name does not have host id in it.
DWORD dwClusterIpOrIndex = IpAddressFromAbcdWsz(wstrRequestedClusterName);
CWlbsClusterWrapper* pCluster = g_pWlbsControl->GetClusterFromIpOrIndex(dwClusterIpOrIndex);
if (pCluster == NULL)
throw _com_error( WBEM_E_NOT_FOUND );
BOOL bGetStatus = TRUE;
//this is an optimization check
//if WinMgMt is calling this prior to an Exec call, then this
//routine will not perform a cluster query call since the
//status of the cluster is not required in this case
if (a_pIContex) {
VARIANT v;
VariantInit( &v );
HRESULT hRes = a_pIContex->GetValue(L"__GET_EXT_KEYS_ONLY", 0, &v);
if ( FAILED( hRes ) ) {
throw _com_error( WBEM_E_FAILED );
}
bGetStatus = FALSE;
// CLD: Need to check return code for error
if (S_OK != VariantClear( &v ))
throw _com_error( WBEM_E_FAILED );
}
//call the API query function
//dwStatus contains a cluster-wide status number
DWORD dwStatus = 0;
if ( bGetStatus )
{
dwStatus = g_pWlbsControl->Query( pCluster ,
WLBS_ALL_HOSTS ,
NULL ,
&dwNumHosts ,
NULL );
if( !ClusterStatusOK( dwStatus ) )
throw _com_error( WBEM_E_FAILED );
}
//get the Wbem class instance
SpawnInstance( MOF_CLUSTER::szName, &pWlbsInstance );
//Convert status to string description
FillWbemInstance( pWlbsInstance, pCluster, dwStatus );
//Send results to Wbem
m_pResponseHandler->Indicate( 1, &pWlbsInstance );
if( pWlbsInstance ) {
pWlbsInstance->Release();
pWlbsInstance = NULL;
}
m_pResponseHandler->SetStatus( 0, WBEM_S_NO_ERROR, NULL, NULL );
hRes = WBEM_S_NO_ERROR;
}
catch(CErrorWlbsControl Err) {
IWbemClassObject* pWbemExtStat = NULL;
CreateExtendedStatus( m_pNameSpace,
&pWbemExtStat,
Err.Error(),
(PWCHAR)(Err.Description()) );
m_pResponseHandler->SetStatus(0, WBEM_E_FAILED, NULL, pWbemExtStat);
if( pWbemExtStat )
pWbemExtStat->Release();
if( pWlbsInstance ) {
pWlbsInstance->Release();
pWlbsInstance = NULL;
}
//do not return WBEM_E_FAILED, this causes a race condition
hRes = WBEM_S_NO_ERROR;
}
catch(_com_error HResErr ) {
m_pResponseHandler->SetStatus(0, HResErr.Error(), NULL, NULL);
if( pWlbsInstance ) {
pWlbsInstance->Release();
pWlbsInstance = NULL;
}
hRes = HResErr.Error();
//transform Win32 error to a WBEM error
if( hRes == ERROR_FILE_NOT_FOUND )
hRes = WBEM_E_NOT_FOUND;
}
catch(...) {
if( pWlbsInstance ) {
pWlbsInstance->Release();
pWlbsInstance = NULL;
}
throw;
}
return hRes;
}
////////////////////////////////////////////////////////////////////////////////
//
// CWLBS_Cluster::EnumInstances
//
// Purpose: This function determines if the current host is in the cluster
// and then obtains the configuration information for the cluster.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT CWLBS_Cluster::EnumInstances
(
BSTR /*a_bstrClass*/,
long /*a_lFlags*/,
IWbemContext* a_pIContex
)
{
IWbemClassObject* pWlbsInstance = NULL;
HRESULT hRes = 0;
try {
DWORD dwNumClusters = 0;
CWlbsClusterWrapper** ppCluster = NULL;
g_pWlbsControl->EnumClusters(ppCluster, &dwNumClusters);
if (dwNumClusters == 0)
{
throw _com_error( WBEM_E_NOT_FOUND );
}
BOOL bGetStatus = TRUE;
//this is an optimization check
//if WinMgMt is calling this prior to an Exec call, then this
//routine will not perform a cluster query call since the
//status of the cluster is not required in this case
if (a_pIContex) {
VARIANT v;
VariantInit( &v );
HRESULT hRes = a_pIContex->GetValue(L"__GET_EXT_KEYS_ONLY", 0, &v);
if ( FAILED( hRes ) ) {
throw _com_error( WBEM_E_FAILED );
}
bGetStatus = FALSE;
// CLD: Need to check return code for error
if (S_OK != VariantClear( &v ))
throw _com_error( WBEM_E_FAILED );
}
for (DWORD i=0; i<dwNumClusters; i++)
{
//call the API query function
//dwStatus contains a cluster-wide status number
DWORD dwStatus = 0;
if ( bGetStatus )
{
DWORD dwNumHosts = 0;
try {
dwStatus = g_pWlbsControl->Query( ppCluster[i],
WLBS_ALL_HOSTS ,
NULL ,
&dwNumHosts ,
NULL);
} catch (CErrorWlbsControl Err)
{
//
// Skip this cluster
//
TRACE_ERROR1("CWLBS_Cluster::EnumInstances skiped cluster %x",
ppCluster[i]->GetClusterIP());
continue;
}
if( !ClusterStatusOK( dwStatus ) )
{
//
// Skip this cluster
//
TRACE_ERROR1("CWLBS_Cluster::EnumInstances skiped cluster %x",
ppCluster[i]->GetClusterIP());
continue;
}
}
//get the Wbem class instance
SpawnInstance( MOF_CLUSTER::szName, &pWlbsInstance );
//Convert status to string description
FillWbemInstance( pWlbsInstance, ppCluster[i], dwStatus );
//send the results back to WinMgMt
m_pResponseHandler->Indicate( 1, &pWlbsInstance );
if( pWlbsInstance )
pWlbsInstance->Release();
}
m_pResponseHandler->SetStatus( 0, WBEM_S_NO_ERROR, NULL, NULL );
hRes = WBEM_S_NO_ERROR;
}
catch(CErrorWlbsControl Err) {
IWbemClassObject* pWbemExtStat = NULL;
CreateExtendedStatus( m_pNameSpace,
&pWbemExtStat,
Err.Error(),
(PWCHAR)(Err.Description()) );
m_pResponseHandler->SetStatus(0, WBEM_E_FAILED, NULL, pWbemExtStat);
if( pWbemExtStat )
pWbemExtStat->Release();
if( pWlbsInstance )
pWlbsInstance->Release();
//do not return WBEM_E_FAILED, this causes a race condition
hRes = WBEM_S_NO_ERROR;
}
catch( _com_error HResErr ) {
m_pResponseHandler->SetStatus(0, HResErr.Error(), NULL, NULL);
if( pWlbsInstance )
{
pWlbsInstance->Release();
pWlbsInstance = NULL;
}
hRes = HResErr.Error();
//transform Win32 error to a WBEM error
if( hRes == ERROR_FILE_NOT_FOUND )
hRes = WBEM_E_NOT_FOUND ;
}
catch(...) {
if( pWlbsInstance )
{
pWlbsInstance->Release();
pWlbsInstance = NULL;
}
throw;
}
return hRes;
}
////////////////////////////////////////////////////////////////////////////////
//
// CWLBS_Cluster::ExecMethod
//
// Purpose: This executes the methods associated with the MOF
// Cluster class.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT CWLBS_Cluster::ExecMethod
(
const ParsedObjectPath* a_pParsedPath,
const BSTR& a_strMethodName,
long /*a_lFlags*/,
IWbemContext* /*a_pIContex*/,
IWbemClassObject* a_pIInParams
)
{
IWbemClassObject* pOutputInstance = NULL;
HRESULT hRes = 0;
BSTR strPortNumber = NULL;
BSTR strNumNodes = NULL;
VARIANT vValue;
CNodeConfiguration NodeConfig;
VariantInit( &vValue );
TRACE_VERB(L"-> CWLBS_Cluster::ExecMethod(%ws)", (WCHAR *) a_strMethodName);
try {
CWlbsClusterWrapper* pCluster = NULL;
if (a_pParsedPath->m_paKeys == NULL)
{
//
// No cluster IP specified
//
throw _com_error( WBEM_E_INVALID_PARAMETER );
}
else
{
const wchar_t* wstrRequestedClusterName = (*a_pParsedPath->m_paKeys)->m_vValue.bstrVal;
//check to see if the requested cluster name matches the configured value
// The name does not have host id in it.
DWORD dwClusterIpOrIndex = IpAddressFromAbcdWsz(wstrRequestedClusterName);
pCluster = g_pWlbsControl->GetClusterFromIpOrIndex(dwClusterIpOrIndex);
}
if (pCluster == NULL)
throw _com_error( WBEM_E_NOT_FOUND );
DWORD dwNumHosts = WLBS_MAX_HOSTS;
DWORD dwReturnValue;
DWORD dwClustIP;
strPortNumber = SysAllocString( MOF_PARAM::PORT_NUMBER );
strNumNodes = SysAllocString( MOF_PARAM::NUM_NODES );
if( !strPortNumber || !strNumNodes )
throw _com_error( WBEM_E_OUT_OF_MEMORY );
dwClustIP = pCluster->GetClusterIpOrIndex(g_pWlbsControl);
//get the output object instance
GetMethodOutputInstance( MOF_CLUSTER::szName,
a_strMethodName,
&pOutputInstance);
//*************************************************************************
//
//Determine and execute the MOF method
//
//*************************************************************************
if( _wcsicmp( a_strMethodName, MOF_CLUSTER::pMethods[MOF_CLUSTER::DISABLE] ) == 0) {
if( !a_pIInParams )
throw _com_error( WBEM_E_INVALID_PARAMETER );
// The "Disable" method does NOT take vip as a parameter, so, if there is any port rule
// that is specific to a vip (other than the "all vip"), we fail this method.
// The "EffectiveVersion" registry value is checked for a value of CVY_VERSION_FULL to
// see of there is any port rule that is specific to a vip
pCluster->GetNodeConfig(NodeConfig);
if(NodeConfig.dwEffectiveVersion == CVY_VERSION_FULL)
throw _com_error( WBEM_E_INVALID_OPERATION );
//get the port number
hRes = a_pIInParams->Get
( strPortNumber,
0,
&vValue,
NULL,
NULL
);
if( FAILED( hRes ) )
throw _com_error( hRes );
//range checking is done by the API
if( vValue.vt != VT_I4 )
throw _com_error( WBEM_E_INVALID_PARAMETER );
//call Disable method
dwReturnValue = g_pWlbsControl->Disable
(
dwClustIP,
WLBS_ALL_HOSTS,
NULL,
dwNumHosts,
IpAddressFromAbcdWsz(CVY_DEF_ALL_VIP), // "All Vip"
vValue.lVal
);
} else if(_wcsicmp( a_strMethodName, MOF_CLUSTER::pMethods[MOF_CLUSTER::ENABLE] ) == 0) {
if( !a_pIInParams )
throw _com_error( WBEM_E_INVALID_PARAMETER );
// The "Enable" method does NOT take vip as a parameter, so, if there is any port rule
// that is specific to a vip (other than the "all vip"), we fail this method.
// The "EffectiveVersion" registry value is checked for a value of CVY_VERSION_FULL to
// see of there is any port rule that is specific to a vip
pCluster->GetNodeConfig(NodeConfig);
if(NodeConfig.dwEffectiveVersion == CVY_VERSION_FULL)
throw _com_error( WBEM_E_INVALID_OPERATION );
//get the port number
hRes = a_pIInParams->Get
(
strPortNumber,
0,
&vValue,
NULL,
NULL
);
if( FAILED( hRes ) )
throw _com_error( hRes );
//range checking is done by the API
if( vValue.vt != VT_I4 )
throw _com_error( WBEM_E_INVALID_PARAMETER );
//call Enable method
dwReturnValue = g_pWlbsControl->Enable
(
dwClustIP,
WLBS_ALL_HOSTS,
NULL,
dwNumHosts,
IpAddressFromAbcdWsz(CVY_DEF_ALL_VIP), // "All Vip"
vValue.lVal
);
} else if( _wcsicmp( a_strMethodName, MOF_CLUSTER::pMethods[MOF_CLUSTER::DRAIN] ) == 0 ) {
if( !a_pIInParams )
throw _com_error( WBEM_E_INVALID_PARAMETER );
// The "Drain" method does NOT take vip as a parameter, so, if there is any port rule
// that is specific to a vip (other than the "all vip"), we fail this method.
// The "EffectiveVersion" registry value is checked for a value of CVY_VERSION_FULL to
// see of there is any port rule that is specific to a vip
pCluster->GetNodeConfig(NodeConfig);
if(NodeConfig.dwEffectiveVersion == CVY_VERSION_FULL)
throw _com_error( WBEM_E_INVALID_OPERATION );
//get the port number
hRes = a_pIInParams->Get
(
strPortNumber,
0,
&vValue,
NULL,
NULL
);
if( FAILED( hRes ) )
throw _com_error( hRes );
//range checking is done by the API
if( vValue.vt != VT_I4 )
throw _com_error( WBEM_E_INVALID_PARAMETER );
//call Drain method
dwReturnValue = g_pWlbsControl->Drain
(
dwClustIP,
WLBS_ALL_HOSTS,
NULL,
dwNumHosts,
IpAddressFromAbcdWsz(CVY_DEF_ALL_VIP), // "All Vip"
vValue.lVal
);
} else if(_wcsicmp(a_strMethodName, MOF_CLUSTER::pMethods[MOF_CLUSTER::DRAINSTOP]) == 0) {
//call DrainStop method
dwReturnValue = g_pWlbsControl->DrainStop(dwClustIP, WLBS_ALL_HOSTS, NULL, dwNumHosts);
} else if(_wcsicmp(a_strMethodName, MOF_CLUSTER::pMethods[MOF_CLUSTER::RESUME] ) == 0) {
//call Resume method
dwReturnValue = g_pWlbsControl->Resume(dwClustIP, WLBS_ALL_HOSTS, NULL, dwNumHosts);
} else if(_wcsicmp(a_strMethodName, MOF_CLUSTER::pMethods[MOF_CLUSTER::START] ) == 0) {
//call Start method
dwReturnValue = g_pWlbsControl->Start(dwClustIP, WLBS_ALL_HOSTS, NULL, dwNumHosts);
} else if(_wcsicmp(a_strMethodName, MOF_CLUSTER::pMethods[MOF_CLUSTER::STOP] ) == 0) {
//call Stop method
dwReturnValue = g_pWlbsControl->Stop(dwClustIP, WLBS_ALL_HOSTS, NULL, dwNumHosts);
} else if(_wcsicmp(a_strMethodName, MOF_CLUSTER::pMethods[MOF_CLUSTER::SUSPEND] ) == 0) {
//call Suspend method
dwReturnValue = g_pWlbsControl->Suspend(dwClustIP, WLBS_ALL_HOSTS, NULL, dwNumHosts);
} else {
throw _com_error( WBEM_E_METHOD_NOT_IMPLEMENTED );
}
//*************************************************************************
//
//Output Results
//
//*************************************************************************
// CLD: Need to check return code for error
if (S_OK != VariantClear( &vValue ))
throw _com_error( WBEM_E_FAILED );
//set the return value
vValue.vt = VT_I4;
vValue.lVal = static_cast<long>(dwReturnValue);
hRes = pOutputInstance->Put(_bstr_t(L"ReturnValue"), 0, &vValue, 0);
if( FAILED( hRes ) ) {
throw _com_error( hRes );
}
//set the number of hosts property
vValue.vt = VT_I4;
vValue.lVal = static_cast<long>(dwNumHosts);
hRes = pOutputInstance->Put(strNumNodes, 0, &vValue, 0);
if( FAILED( hRes ) )
throw _com_error( hRes );
//send the results back to WinMgMt
hRes = m_pResponseHandler->Indicate(1, &pOutputInstance);
if( FAILED( hRes ) )
throw _com_error( hRes );
m_pResponseHandler->SetStatus(0, WBEM_S_NO_ERROR, NULL, NULL);
//*************************************************************************
//
//Release Resources
//
//*************************************************************************
//COM Interfaces
if( pOutputInstance ) {
pOutputInstance->Release();
pOutputInstance = NULL;
}
//**** BSTRs ****
if( strPortNumber ) {
SysFreeString( strPortNumber );
strPortNumber = NULL;
}
if( strNumNodes ) {
SysFreeString( strNumNodes );
strNumNodes = NULL;
}
//**** VARIANTs ****
// CLD: Need to check return code for error
if (S_OK != VariantClear( &vValue ))
throw _com_error( WBEM_E_FAILED );
hRes = WBEM_S_NO_ERROR;
}
catch(CErrorWlbsControl Err) {
IWbemClassObject* pWbemExtStat = NULL;
CreateExtendedStatus( m_pNameSpace,
&pWbemExtStat,
Err.Error(),
(PWCHAR)(Err.Description()) );
m_pResponseHandler->SetStatus(0, WBEM_E_FAILED, NULL, pWbemExtStat);
if( pWbemExtStat )
pWbemExtStat->Release();
//COM Interfaces
if( pOutputInstance ) {
pOutputInstance->Release();
pOutputInstance = NULL;
}
//**** BSTRs ****
if( strPortNumber ) {
SysFreeString( strPortNumber );
strPortNumber = NULL;
}
if( strNumNodes ) {
SysFreeString( strNumNodes );
strNumNodes = NULL;
}
//**** VARIANTs ****
// CLD: Need to check return code for error
// No throw here since we are already throwing an exception. Also, given the comment below, not sure
// what exception we'd return...
VariantClear( &vValue );
//do not return WBEM_E_FAILED, this causes a race condition
hRes = WBEM_S_NO_ERROR;
}
catch( _com_error HResErr ) {
//COM Interfaces
if( pOutputInstance ) {
pOutputInstance->Release();
pOutputInstance = NULL;
}
//**** BSTRs ****
if( strPortNumber ) {
SysFreeString( strPortNumber );
strPortNumber = NULL;
}
if( strNumNodes ) {
SysFreeString( strNumNodes );
strNumNodes = NULL;
}
//**** VARIANTs ****
// CLD: Need to check return code for error
// No throw here since we are already throwing an exception.
VariantClear( &vValue );
m_pResponseHandler->SetStatus(0, HResErr.Error(), NULL, NULL);
hRes = HResErr.Error();
}
catch(...) {
//COM Interfaces
if( pOutputInstance ) {
pOutputInstance->Release();
pOutputInstance = NULL;
}
//**** BSTRs ****
if( strPortNumber ) {
SysFreeString( strPortNumber );
strPortNumber = NULL;
}
if( strNumNodes ) {
SysFreeString( strNumNodes );
strNumNodes = NULL;
}
//**** VARIANTs ****
// CLD: Need to check return code for error
// No throw here since we are already throwing an exception
VariantClear( &vValue );
throw;
}
TRACE_VERB(L"<- CWLBS_Cluster::ExecMethod(%ws) returns 0x%08lx",
(WCHAR *) a_strMethodName, (UINT) hRes);
return hRes;
}
////////////////////////////////////////////////////////////////////////////////
//
// CWLBS_Cluster::FillWbemInstance
//
// Purpose: This function copies all of the data from a cluster configuration
// structure to a WBEM instance.
//
////////////////////////////////////////////////////////////////////////////////
void CWLBS_Cluster::FillWbemInstance
(
IWbemClassObject* a_pWbemInstance,
CWlbsClusterWrapper* pCluster,
const DWORD a_dwStatus
)
{
namespace CLUSTER = MOF_CLUSTER;
ASSERT( a_pWbemInstance );
ASSERT(pCluster);
CClusterConfiguration ClusterConfig;
pCluster->GetClusterConfig( ClusterConfig );
//InterconnectAddress
wstring wstrClusterIp;
AddressToString( pCluster->GetClusterIP(), wstrClusterIp );
a_pWbemInstance->Put
(
_bstr_t( CLUSTER::pProperties[CLUSTER::IPADDRESS] ),
0 ,
&_variant_t(wstrClusterIp.c_str()),
NULL
);
//Name
wstring wstrClusterIndex;
AddressToString( pCluster->GetClusterIpOrIndex(g_pWlbsControl), wstrClusterIndex );
a_pWbemInstance->Put
(
_bstr_t( CLUSTER::pProperties[CLUSTER::NAME] ),
0 ,
&_variant_t(wstrClusterIndex.c_str()),
NULL
);
//MaxNodes
a_pWbemInstance->Put
(
_bstr_t( CLUSTER::pProperties[CLUSTER::MAXNODES] ),
0 ,
&_variant_t(ClusterConfig.nMaxNodes),
NULL
);
//ClusterState
a_pWbemInstance->Put
(
_bstr_t( CLUSTER::pProperties[CLUSTER::CLUSSTATE] ),
0 ,
&_variant_t((short)a_dwStatus),
NULL
);
//CREATCLASS
a_pWbemInstance->Put
(
_bstr_t( CLUSTER::pProperties[CLUSTER::CREATCLASS] ),
0 ,
&_variant_t(CLUSTER::szName),
NULL
);
}