#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; iQuery( 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(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(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 ); }