#include "CommonNLB.h" #include "MNLBCluster.h" #include "MNLBHost.h" #include "MNLBMachine.h" #include "MNLBNetCfg.h" #include "MWmiError.h" #include "MUsingCom.h" #include "MIPAddressAdmin.h" #include "ResourceString.h" #include "resource.h" #include #include #include #include using namespace std; // global only temporarily. // LeftView* g_leftView; CommonNLB::CommonNLB_Error CommonNLB::connectToClusterDirect( const _bstr_t& clusterIP, const _bstr_t& hostMember, ClusterData* p_clusterData, DataSinkI* dataSinkObj ) { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_CONNECTING) + hostMember ); MNLBMachine nlbMachine( hostMember, clusterIP ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE) ); vector hostInfo; dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_FINDING_H ) ); nlbMachine.getPresentHostsInfo( &hostInfo ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE) ); vector< _bstr_t> connectionIPS; for( int i = 0; i < hostInfo.size(); ++i ) { connectionIPS.push_back( hostInfo[i].dedicatedIP ); } #if 1 return connectToClusterIndirect( clusterIP, connectionIPS, p_clusterData, dataSinkObj ); #else vector clusterDataStore; bool clusterPropertiesMatched; connectToClusterIndirectNew( clusterIP, connectionIPS, &clusterDataStore, clusterPropertiesMatched, dataSinkObj ); (*p_clusterData) = clusterDataStore[0]; return CommonNLB_SUCCESS; #endif } CommonNLB::CommonNLB_Error CommonNLB::connectToClusterIndirectNew( const _bstr_t& clusterIP, const vector<_bstr_t>& connectionIPS, vector< ClusterData>* clusterDataStore, bool& clusterPropertiesMatched, DataSinkI* dataSinkObj ) { // connect to each host. // We are doing it here so that if there are any connectivity issues // we do not proceed with any further operation and ask user to // fix all issues before proceeding. // connect to each host. map< bstr_t, auto_ptr > nlbMachine; for( int i = 0; i < connectionIPS.size(); ++i ) { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_CONNECTING) + connectionIPS[i] ); auto_ptr p_nlbMachine = auto_ptr ( new MNLBMachine( connectionIPS[i], clusterIP ) ); nlbMachine[connectionIPS[i] ] = p_nlbMachine; dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE) ); } // get information from each host. // for( int i = 0; i < connectionIPS.size(); ++i ) { ClusterData clusterData; // get cluster properties. dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_FINDING_CL_P ) ); ClusterProperties cp; nlbMachine[connectionIPS[i] ]->getClusterProperties( &cp ); clusterData.cp = cp; dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE) ); // get host properties. dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_FINDING_H_P ) ); HostProperties hp; nlbMachine[connectionIPS[i] ]->getHostProperties( &hp ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE) ); // set the host properties HostData hostData; hostData.hp = hp; // set the connection ip. hostData.connectionIP = connectionIPS[i]; clusterData.hosts[hp.machineName] = hostData; // get port rules dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_FINDING_P ) ); vector portsLB; vector portsF; vector portsD; PortDataULB ulbPortRule; PortDataF fPortRule; PortDataELB elbPortRule; PortDataD dPortRule; nlbMachine[connectionIPS[i] ]->getPortRulesLoadBalanced( &portsLB ); for( int j = 0; j < portsLB.size(); ++j ) { if( portsLB[j]._isEqualLoadBalanced == true ) { // equal load balanced port rule. elbPortRule._startPort = portsLB[j]._startPort; elbPortRule._key = portsLB[j]._startPort; elbPortRule._endPort = portsLB[j]._endPort; elbPortRule._trafficToHandle = portsLB[j]._trafficToHandle; elbPortRule._affinity = portsLB[j]._affinity; clusterData.portELB[portsLB[j]._startPort] = elbPortRule; } else { ulbPortRule._startPort = portsLB[j]._startPort; ulbPortRule._key = portsLB[j]._startPort; ulbPortRule._endPort = portsLB[j]._endPort; ulbPortRule._trafficToHandle = portsLB[j]._trafficToHandle; ulbPortRule._affinity = portsLB[j]._affinity; ulbPortRule.machineMapToLoadWeight[hp.machineName] = portsLB[j]._load; clusterData.portULB[portsLB[j]._startPort] = ulbPortRule; } } portsLB.erase( portsLB.begin(), portsLB.end() ); nlbMachine[connectionIPS[i] ]->getPortRulesFailover( &portsF ); for( int j = 0; j < portsF.size(); ++j ) { fPortRule._startPort = portsF[j]._startPort; fPortRule._key = portsF[j]._startPort; fPortRule._endPort = portsF[j]._endPort; fPortRule._trafficToHandle = portsF[j]._trafficToHandle; fPortRule.machineMapToPriority[ hp.machineName] = portsF[j]._priority; clusterData.portF[portsF[j]._startPort] = fPortRule; } portsF.erase( portsF.begin(), portsF.end() ); // disabled port rules nlbMachine[connectionIPS[i] ]->getPortRulesDisabled( &portsD ); for( int j = 0; j < portsD.size(); ++j ) { dPortRule._startPort = portsD[j]._startPort; dPortRule._key = portsD[j]._startPort; dPortRule._endPort = portsD[j]._endPort; dPortRule._trafficToHandle = portsD[j]._trafficToHandle; clusterData.portD[portsD[j]._startPort] = dPortRule; } portsD.erase( portsD.begin(), portsD.end() ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE) ); // get virtual ips. These have already been got when we got the host properties // Thus here we are storing duplicate data, but this does ease // a lot of data structure manipulation. // clusterData.virtualIPs = clusterData.hosts[hp.machineName].hp.nicInfo.ipsOnNic; clusterData.virtualSubnets = clusterData.hosts[hp.machineName].hp.nicInfo.subnetMasks; clusterData.hosts[hp.machineName] = hostData; clusterDataStore->push_back( clusterData ); } // now we will verify whether the cluster is // converged or there are mismatches. // rules for a converged cluster. // // cluster properties which need to // be same: // cluster ip // cluster subnet // full internet name // cluster mode // remote Control Enabled. // // host properties // host id has to be unique across hosts any // number from 1-32 inclusive. // // port rules // equal load balanced port rules have to be same // disabled port rules have to be same. // unequal load balanced port rules can differ only in load. // single host port rules can differ in priority, which has to be // unique across hosts for a specific port rule any number between 1-32. // // Each machine must have the cluster ip. // // Each machine must have the exactly same ips on the nic. clusterPropertiesMatched = true; // check if cluster ip is added. // if( find( (*clusterDataStore)[0].virtualIPs.begin(), (*clusterDataStore)[0].virtualIPs.end(), (*clusterDataStore)[0].cp.cIP ) == (*clusterDataStore)[0].virtualIPs.end() ) { clusterPropertiesMatched = false; } if( clusterDataStore->size() == 1 ) { // only one host in cluster so only return CommonNLB_SUCCESS; } // sort the virtual ips of the first node. Eases // comparision. sort( (*clusterDataStore)[0].virtualIPs.begin(), (*clusterDataStore)[0].virtualIPs.end() ); for( int i = 1; i < clusterDataStore->size(); ++i ) { // cluster properties must match. // if( (*clusterDataStore)[0].cp != (*clusterDataStore)[i].cp ) { // mismatch in cluster properties. // MISMATCH clusterPropertiesMatched = false; } // the ELB, ULB, F, D port rules have to // match. if ( (*clusterDataStore)[0].portELB.size() != (*clusterDataStore)[i].portELB.size() ) { // mismatch in port rules. // MISMATCH clusterPropertiesMatched = false; } else { // number of port rules are matching. map::iterator top; map::iterator location; for( top = (*clusterDataStore)[i].portELB.begin(); top != (*clusterDataStore)[i].portELB.end(); ++top ) { location = (*clusterDataStore)[0].portELB.find( (*top).first ); if( location == (*clusterDataStore)[0].portELB.end() ) { // no such port exists. // thus mismatch. // MISMATCH clusterPropertiesMatched = false; } else { if( (*location).second._startPort != (*top).second._startPort || (*location).second._endPort != (*top).second._endPort || (*location).second._trafficToHandle != (*top).second._trafficToHandle || (*location).second._affinity != (*top).second._affinity ) { // things other than key which is start port // has been modified. // MISMATCH } } } } if ( (*clusterDataStore)[0].portULB.size() != (*clusterDataStore)[i].portULB.size() ) { // mismatch in port rules. // MISMATCH clusterPropertiesMatched = false; } else { // number of port rules are matching. map::iterator top; map::iterator location; for( top = (*clusterDataStore)[i].portULB.begin(); top != (*clusterDataStore)[i].portULB.end(); ++top ) { location = (*clusterDataStore)[0].portULB.find( (*top).first ); if( location == (*clusterDataStore)[0].portULB.end() ) { // no such port exists. // thus mismatch. // MISMATCH clusterPropertiesMatched = false; } else { if( (*location).second._startPort != (*top).second._startPort || (*location).second._endPort != (*top).second._endPort || (*location).second._trafficToHandle != (*top).second._trafficToHandle || (*location).second._affinity != (*top).second._affinity ) { // things other than key which is start port // has been modified. // MISMATCH clusterPropertiesMatched = false; } } } } if ( (*clusterDataStore)[0].portF.size() != (*clusterDataStore)[i].portF.size() ) { // mismatch in port rules. // MISMATCH clusterPropertiesMatched = false; } else { // number of port rules are matching. map::iterator top; map::iterator location; for( top = (*clusterDataStore)[i].portF.begin(); top != (*clusterDataStore)[i].portF.end(); ++top ) { location = (*clusterDataStore)[0].portF.find( (*top).first ); if( location == (*clusterDataStore)[0].portF.end() ) { // no such port exists. // thus mismatch. // MISMATCH clusterPropertiesMatched = false; } else { if( (*location).second._startPort != (*top).second._startPort || (*location).second._endPort != (*top).second._endPort || (*location).second._trafficToHandle != (*top).second._trafficToHandle ) { // things other than key which is start port // has been modified. // MISMATCH clusterPropertiesMatched = false; } } } } if ( (*clusterDataStore)[0].portD.size() != (*clusterDataStore)[i].portD.size() ) { // mismatch in port rules. // MISMATCH clusterPropertiesMatched = false; } else { // number of port rules are matching. map::iterator top; map::iterator location; for( top = (*clusterDataStore)[i].portD.begin(); top != (*clusterDataStore)[i].portD.end(); ++top ) { location = (*clusterDataStore)[0].portD.find( (*top).first ); if( location == (*clusterDataStore)[0].portD.end() ) { // no such port exists. // thus mismatch. // MISMATCH clusterPropertiesMatched = false; } else { if( (*location).second._startPort != (*top).second._startPort || (*location).second._endPort != (*top).second._endPort || (*location).second._trafficToHandle != (*top).second._trafficToHandle ) { // things other than key which is start port // has been modified. // MISMATCH clusterPropertiesMatched = false; } } } } // check if each machine has the same virtual ips. // sort( (*clusterDataStore)[i].virtualIPs.begin(), (*clusterDataStore)[i].virtualIPs.end() ); if( (*clusterDataStore)[0].virtualIPs != (*clusterDataStore)[i].virtualIPs ) { // MISMATCH clusterPropertiesMatched = false; } } // check if host ids are duplicate. map< _bstr_t, HostData>::iterator onlyHost; set hostIDS; for( int i = 0; i < clusterDataStore->size(); ++i ) { onlyHost = (*clusterDataStore)[i].hosts.begin(); // check if this host id has been used previously. if( hostIDS.find( (*onlyHost).second.hp.hID ) == hostIDS.end() ) { // host id is unused. hostIDS.insert( (*onlyHost).second.hp.hID ); } else { // host id has been used previously. // Thus this is duplicate. // MISMATCH clusterPropertiesMatched = false; } } if( clusterPropertiesMatched == true ) { // combine all the host information. // map<_bstr_t, HostData >::iterator top; for( int i = 1; i < clusterDataStore->size(); ++i ) { top = (*clusterDataStore)[i].hosts.begin(); (*clusterDataStore)[0].hosts[ (*top).first ] = (*top).second; } #if 1 // combine all the port information for ULB and disabled port rules. // this may be a little difficult, but it works. Don't fiddle around // with this part. map::iterator topULB; for( topULB = (*clusterDataStore)[0].portULB.begin(); topULB != (*clusterDataStore)[0].portULB.end(); ++topULB ) { map<_bstr_t, long>& ref = (*topULB).second.machineMapToLoadWeight; for( int i = 1; i < clusterDataStore->size(); ++i ) { // find the machine name for this clusterdata. map<_bstr_t, HostData>::iterator top; top = (*clusterDataStore)[i].hosts.begin(); _bstr_t machineName = (*top).first; ref[machineName] = (*clusterDataStore)[i].portULB[ (*topULB).first ].machineMapToLoadWeight[ machineName]; } } map::iterator topF; for( topF = (*clusterDataStore)[0].portF.begin(); topF != (*clusterDataStore)[0].portF.end(); ++topF ) { map<_bstr_t, long>& ref = (*topF).second.machineMapToPriority; for( int i = 1; i < clusterDataStore->size(); ++i ) { // find the machine name for this clusterdata. map<_bstr_t, HostData>::iterator top; top = (*clusterDataStore)[i].hosts.begin(); _bstr_t machineName = (*top).first; ref[machineName] = (*clusterDataStore)[i].portF[ (*topF).first ].machineMapToPriority[ machineName]; } } #endif } return CommonNLB_SUCCESS; } CommonNLB::CommonNLB_Error CommonNLB::connectToClusterIndirect( const _bstr_t& clusterIP, const vector<_bstr_t>& connectionIPS, ClusterData* p_clusterData, DataSinkI* dataSinkObj ) { // connect to each host. // We are doing it here so that if there are any connectivity issues // we do not proceed with any further operation and ask user to // fix all issues before proceeding. // connect to each host. map< bstr_t, auto_ptr > nlbMachine; for( int i = 0; i < connectionIPS.size(); ++i ) { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_CONNECTING) + connectionIPS[i] ); auto_ptr p_nlbMachine = auto_ptr ( new MNLBMachine( connectionIPS[i], clusterIP ) ); nlbMachine[connectionIPS[i] ] = p_nlbMachine; dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE) ); } // rules for a converged cluster. // // cluster properties which need to // be same: // cluster ip // cluster subnet // full internet name // cluster mode // // host properties // host id has to be unique across hosts any // number from 1-32 inclusive. // // port rules // equal load balanced port rules have to be same // disabled port rules have to be same. // unequal load balanced port rules can differ only in load. // single host port rules can differ in priority, which has to be // unique across hosts for a specific port rule any number between 1-32. // for( int i = 0; i < connectionIPS.size(); ++i ) { // get cluster properties. // cluster properties need to be got only for one host. if( i == 0 ) { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_FINDING_CL_P ) ); ClusterProperties cp; nlbMachine[connectionIPS[i] ]->getClusterProperties( &cp ); p_clusterData->cp = cp; dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE) ); } // get host properties. dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_FINDING_H_P ) ); HostProperties hp; nlbMachine[connectionIPS[i] ]->getHostProperties( &hp ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE) ); // set the host properties HostData hostData; hostData.hp = hp; // set the connection ip. hostData.connectionIP = connectionIPS[i]; p_clusterData->hosts[hp.machineName] = hostData; // get port rules dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_FINDING_P ) ); vector portsLB; vector portsF; vector portsD; PortDataULB ulbPortRule; PortDataF fPortRule; PortDataELB elbPortRule; PortDataD dPortRule; nlbMachine[connectionIPS[i] ]->getPortRulesLoadBalanced( &portsLB ); for( int j = 0; j < portsLB.size(); ++j ) { if( portsLB[j]._isEqualLoadBalanced == true ) { // equal load balanced port rule. elbPortRule._startPort = portsLB[j]._startPort; elbPortRule._key = portsLB[j]._startPort; elbPortRule._endPort = portsLB[j]._endPort; elbPortRule._trafficToHandle = portsLB[j]._trafficToHandle; elbPortRule._affinity = portsLB[j]._affinity; p_clusterData->portELB[portsLB[j]._startPort] = elbPortRule; } else { // unequal load balanced. if( i == 0 ) { ulbPortRule._startPort = portsLB[j]._startPort; ulbPortRule._key = portsLB[j]._startPort; ulbPortRule._endPort = portsLB[j]._endPort; ulbPortRule._trafficToHandle = portsLB[j]._trafficToHandle; ulbPortRule._affinity = portsLB[j]._affinity; ulbPortRule.machineMapToLoadWeight[hp.machineName] = portsLB[j]._load; p_clusterData->portULB[portsLB[j]._startPort] = ulbPortRule; } else { p_clusterData->portULB[portsLB[j]._startPort].machineMapToLoadWeight[ hp.machineName] = portsLB[j]._load; } } } portsLB.erase( portsLB.begin(), portsLB.end() ); nlbMachine[connectionIPS[i] ]->getPortRulesFailover( &portsF ); for( int j = 0; j < portsF.size(); ++j ) { if( i == 0 ) { fPortRule._startPort = portsF[j]._startPort; fPortRule._key = portsF[j]._startPort; fPortRule._endPort = portsF[j]._endPort; fPortRule._trafficToHandle = portsF[j]._trafficToHandle; fPortRule.machineMapToPriority[ hp.machineName] = portsF[j]._priority; p_clusterData->portF[portsF[j]._startPort] = fPortRule; } else { p_clusterData->portF[portsF[j]._startPort].machineMapToPriority[ hp.machineName] = portsF[j]._priority; } } portsF.erase( portsF.begin(), portsF.end() ); // disabled need to be got only once. if( i == 0 ) { nlbMachine[connectionIPS[i] ]->getPortRulesDisabled( &portsD ); for( int j = 0; j < portsD.size(); ++j ) { dPortRule._startPort = portsD[j]._startPort; dPortRule._key = portsD[j]._startPort; dPortRule._endPort = portsD[j]._endPort; dPortRule._trafficToHandle = portsD[j]._trafficToHandle; p_clusterData->portD[portsD[j]._startPort] = dPortRule; } portsD.erase( portsD.begin(), portsD.end() ); } dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE) ); } dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_SUCCESS ) ); return CommonNLB_SUCCESS; } CommonNLB::CommonNLB_Error CommonNLB::connectToMachine( const _bstr_t& machineToConnect, _bstr_t& machineServerName, vector< CommonNLB::NicNLBBound >& nicList, DataSinkI* dataSinkObj ) { // connect to machine. // MWmiObject machine( machineToConnect, L"root\\microsoftnlb", L"administrator", L"" ); // find all nics on machine. // vector instanceStore; machine.getInstances( L"NlbsNic", &instanceStore ); // check if nic has nlb bound. // // input parameters are none. // vector inputParameters; // output parameters which are of interest. // vector outputParameters; MWmiParameter ReturnValue(L"ReturnValue"); outputParameters.push_back( &ReturnValue ); vector parameterStore; MWmiParameter Server(L"__Server"); parameterStore.push_back( &Server ); MWmiParameter FullName(L"FullName"); parameterStore.push_back( &FullName ); MWmiParameter AdapterGuid(L"AdapterGuid"); parameterStore.push_back( &AdapterGuid ); MWmiParameter FriendlyName(L"FriendlyName"); parameterStore.push_back( &FriendlyName ); for( int i = 0; i < instanceStore.size(); ++i ) { // get full name, guid and friendly name. // NicNLBBound temp; instanceStore[i].getParameters( parameterStore ); temp.fullNicName = FullName.getValue(); temp.adapterGuid = AdapterGuid.getValue(); temp.friendlyName = FriendlyName.getValue(); // get machine name. machineServerName = Server.getValue(); // check if nic is bound to nlb or not. instanceStore[i].runMethod( L"isBound", inputParameters, outputParameters ); if( long( ReturnValue.getValue() ) == 1 ) { // this nic is bound. temp.isBoundToNLB = true; } else { temp.isBoundToNLB = false; } // get all the ip's on this nic. MIPAddressAdmin ipAdmin( machineToConnect, temp.fullNicName ); ipAdmin.getIPAddresses( &temp.ipsOnNic, &temp.subnetMasks ); // check if the nic is dhcp. ipAdmin.isDHCPEnabled( temp.dhcpEnabled ); nicList.push_back( temp ); } return CommonNLB_SUCCESS; } CommonNLB::CommonNLB_Error CommonNLB::changeNLBClusterSettings( const ClusterData* oldSettings, const ClusterData* newSettings, DataSinkI* dataSinkObj ) { return CommonNLB_SUCCESS; } CommonNLB::CommonNLB_Error CommonNLB::changeNLBHostSettings( const ClusterData* oldSettings, const ClusterData* newSettings, const _bstr_t& machineName, DataSinkI* dataSinkObj ) { ClusterData* oldSettingsCopy = const_cast ( oldSettings ); ClusterData* newSettingsCopy = const_cast ( newSettings ); map<_bstr_t, HostData>::iterator topOld; map<_bstr_t, HostData>::iterator topNew; // change host properties for host if that have changed. // if( oldSettingsCopy->hosts[machineName].hp != newSettingsCopy->hosts[machineName].hp ) { // connect to machine. // dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_CONNECTING ) + oldSettingsCopy->hosts[machineName].connectionIP ); MNLBMachine nlbMachine( oldSettingsCopy->hosts[machineName].connectionIP, oldSettingsCopy->cp.cIP ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE) ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_MODIFYING_H_P ) ); // host properties have changed. unsigned long returnValue; nlbMachine.setHostProperties( newSettingsCopy->hosts[machineName].hp, &returnValue ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE) ); } return CommonNLB_SUCCESS; } CommonNLB::CommonNLB_Error CommonNLB::changeNLBHostPortSettings( const ClusterData* oldSettings, const ClusterData* newSettings, const _bstr_t& machineName, DataSinkI* dataSinkObj ) { ClusterData* oldSettingsCopy = const_cast ( oldSettings ); ClusterData* newSettingsCopy = const_cast ( newSettings ); map<_bstr_t, HostData>::iterator topOld; map<_bstr_t, HostData>::iterator topNew; // connect to machine. // dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_CONNECTING ) + oldSettingsCopy->hosts[machineName].connectionIP ); MNLBMachine nlbMachine( oldSettingsCopy->hosts[machineName].connectionIP, oldSettingsCopy->cp.cIP ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE ) ); // check if any load weights have changed. // for any unequal load balanced port rule. // map::iterator topOldULB; map::iterator topNewULB; for( topOldULB = oldSettingsCopy->portULB.begin(), topNewULB = newSettingsCopy->portULB.begin(); topOldULB != oldSettingsCopy->portULB.end(); ++topOldULB, ++topNewULB ) { if( (*topOldULB).second.machineMapToLoadWeight[machineName] != (*topNewULB).second.machineMapToLoadWeight[machineName] ) { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_MODIFYING_P_ULB ) ); // load weight has changed. // remove old port rule MNLBPortRuleLoadBalanced portULB = (*topNewULB).second; portULB._load = (*topOldULB).second.machineMapToLoadWeight[machineName]; nlbMachine.removePortRuleLoadBalanced( portULB ); // add this port rule. // only load weight can change. portULB._load = (*topNewULB).second.machineMapToLoadWeight[machineName]; nlbMachine.addPortRuleLoadBalanced( portULB ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE ) ); } } // check if any priorities have changed. // for any failover port rules // map::iterator topOldF; map::iterator topNewF; for( topOldF = oldSettingsCopy->portF.begin(), topNewF = newSettingsCopy->portF.begin(); topOldF != oldSettingsCopy->portF.end(); ++topOldF, ++topNewF ) { if( (*topOldF).second.machineMapToPriority[machineName] != (*topNewF).second.machineMapToPriority[machineName] ) { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_MODIFYING_P_F ) ); // priority has changed. MNLBMachine nlbMachine( newSettingsCopy->hosts[machineName].connectionIP, newSettingsCopy->cp.cIP ); // remove old port rule MNLBPortRuleFailover portF = (*topNewF).second; portF._priority = (*topOldF).second.machineMapToPriority[machineName]; nlbMachine.removePortRuleFailover( portF ); // add new port rule. // only priority has changed. portF._priority = (*topNewF).second.machineMapToPriority[machineName]; nlbMachine.addPortRuleFailover( portF ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE ) ); } } return CommonNLB_SUCCESS; } CommonNLB::CommonNLB_Error CommonNLB::changeNLBClusterAndPortSettings( const ClusterData* oldSettings, const ClusterData* newSettings, DataSinkI* dataSinkObj, bool* pbClusterIpChanged) { ClusterData* oldSettingsCopy = const_cast ( oldSettings ); ClusterData* newSettingsCopy = const_cast ( newSettings ); bool bClusterParametersChanged, bPortRulesChanged, bOnlyClusterNameChanged; // Find out if the cluster parameters have changed. Also, find if the cluster name // is the only parameter that has changed bClusterParametersChanged = newSettingsCopy->cp.HaveClusterPropertiesChanged(oldSettingsCopy->cp, &bOnlyClusterNameChanged, pbClusterIpChanged); vector rulesAddedELB; vector rulesUnchangedELB; vector rulesRemovedELB; findPortRulesAddedUnchangedRemovedELB( oldSettingsCopy, newSettingsCopy, dataSinkObj, rulesAddedELB, rulesUnchangedELB, rulesRemovedELB ); vector rulesAddedULB; vector rulesUnchangedULB; vector rulesRemovedULB; findPortRulesAddedUnchangedRemovedULB( oldSettingsCopy, newSettingsCopy, dataSinkObj, rulesAddedULB, rulesUnchangedULB, rulesRemovedULB ); vector rulesAddedD; vector rulesUnchangedD; vector rulesRemovedD; findPortRulesAddedUnchangedRemovedD( oldSettingsCopy, newSettingsCopy, dataSinkObj, rulesAddedD, rulesUnchangedD, rulesRemovedD ); vector rulesAddedF; vector rulesUnchangedF; vector rulesRemovedF; findPortRulesAddedUnchangedRemovedF( oldSettingsCopy, newSettingsCopy, dataSinkObj, rulesAddedF, rulesUnchangedF, rulesRemovedF ); // check if any port rules have been added or removed // if not we don't want to do anything. if( ( rulesAddedULB.size() == 0 ) && ( rulesRemovedULB.size() == 0 ) && ( rulesAddedELB.size() == 0 ) && ( rulesRemovedELB.size() == 0 ) && ( rulesAddedD.size() == 0 ) && ( rulesRemovedD.size() == 0 ) && ( rulesAddedF.size() == 0 ) && ( rulesRemovedF.size() == 0 ) ) { //return CommonNLB_SUCCESS; //OutputDebugString(_T("No Change to Port Rules\n")); bPortRulesChanged = false; } else { bPortRulesChanged = true; } // Neither the cluster parameters nor the port rules have changed, so return if (!bClusterParametersChanged && !bPortRulesChanged) { //OutputDebugString(_T("No Change to Cluster Parameters or Port Rules\n")); return CommonNLB_SUCCESS; } // connect to each host. // We are doing it here so that if there are any connectivity issues // we do not proceed with any changes and just inform the user. // This is to ensure that we do not cause any convergence. // connect to each host. map<_bstr_t, HostData >::iterator top; map< bstr_t, auto_ptr > nlbMachine; for( top = oldSettingsCopy->hosts.begin(); top != oldSettingsCopy->hosts.end(); ++top ) { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_CONNECTING ) + (*top).second.connectionIP ); auto_ptr p_nlbMachine = auto_ptr ( new MNLBMachine( (*top).second.connectionIP, oldSettingsCopy->cp.cIP ) ); nlbMachine[(*top).first] = p_nlbMachine; dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE ) ); } // for each host in cluster apply the changed port & cluster rules. for( top = oldSettingsCopy->hosts.begin(); top != oldSettingsCopy->hosts.end(); ++top ) { if (bPortRulesChanged) { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_MODIFYING_P ) ); // remove all port rules which need to be erased.. // for( int i = 0; i < rulesRemovedELB.size(); ++i ) { nlbMachine[ (*top).first ]->removePortRuleLoadBalanced( oldSettingsCopy->portELB[ rulesRemovedELB[i] ] ); } for( int i = 0; i < rulesRemovedULB.size(); ++i ) { nlbMachine[ (*top).first ]->removePortRuleLoadBalanced( oldSettingsCopy->portULB[ rulesRemovedULB[i] ] ); } for( int i = 0; i < rulesRemovedD.size(); ++i ) { nlbMachine[ (*top).first ]->removePortRuleDisabled( oldSettingsCopy->portD[ rulesRemovedD[i] ] ); } for( int i = 0; i < rulesRemovedF.size(); ++i ) { nlbMachine[ (*top).first ]->removePortRuleFailover( oldSettingsCopy->portF[rulesRemovedF[i] ] ); } // add all new port rules // for( int i = 0; i < rulesAddedELB.size(); ++i ) { nlbMachine[ (*top).first ]->addPortRuleLoadBalanced( newSettingsCopy->portELB[ rulesAddedELB[i] ] ); } for( int i = 0; i < rulesAddedULB.size(); ++i ) { MNLBPortRuleLoadBalanced portULB = newSettingsCopy->portULB[ rulesAddedULB[i] ]; _bstr_t machineName = (*top).first; portULB._load = newSettingsCopy->portULB[rulesAddedULB[i]].machineMapToLoadWeight[ (*top).first ]; nlbMachine[ (*top).first ]->addPortRuleLoadBalanced( portULB ); } for( int i = 0; i < rulesAddedD.size(); ++i ) { nlbMachine[ (*top).first ]->addPortRuleDisabled( newSettingsCopy->portD[rulesAddedD[i] ] ); } for( int i = 0; i < rulesAddedF.size(); ++i ) { MNLBPortRuleFailover portF = newSettingsCopy->portF[rulesAddedF[i] ]; portF._priority = newSettingsCopy->portF[rulesAddedF[i]].machineMapToPriority[ (*top).first ]; nlbMachine[ (*top).first ]->addPortRuleFailover( portF ); } dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE ) ); } if (bClusterParametersChanged) { if (bOnlyClusterNameChanged) { unsigned long retVal; dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_MODIFYING_CN ) ); nlbMachine[ (*top).first ]->setClusterProperties(newSettingsCopy->cp, &retVal); // if remote control is enabled set the password. // even if password has not changed just making extra call. if( newSettingsCopy->cp.remoteControlEnabled == true ) { nlbMachine[ (*top).first ]->setPassword(newSettingsCopy->cp.password, &retVal); } } else // Cluster Parameters other than Cluster name have changed too { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_REMOVING_CL_IP ) ); MNLBNetCfg nlbNetCfg((*top).second.connectionIP, (*top).second.hp.nicInfo.fullNicName); nlbNetCfg.removeClusterIP(oldSettingsCopy->cp.cIP); } dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE ) ); } } // If Cluster Paraters other than the Cluster Name has changed, call the NLB Manager // provider's "ModifyClusterProperties" (eventually) to modify cluster properties // and add the cluster ip to tcp/ip. Modification of the cluster properties will // result in the disable/re-enable of the nic & hence the WMI DCOM connection might // be lost. So, we are doing this two-step operation locally if (bClusterParametersChanged && !bOnlyClusterNameChanged) { for( top = oldSettingsCopy->hosts.begin(); top != oldSettingsCopy->hosts.end(); ++top ) { //OutputDebugString(_T("Modifying Cluster Parameters and adding cluster ip to tcp-ip !!!\n")); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_MODIFYING_CP_AND_ADD_IP ) ); MNLBNetCfg* p_nlbNetCfg = NULL; ModifyClusterPropertiesParameters* par = NULL; try { p_nlbNetCfg = new MNLBNetCfg((*top).second.connectionIP, (*top).second.hp.nicInfo.fullNicName); par = new ModifyClusterPropertiesParameters; par->nlbNetCfg = p_nlbNetCfg; par->clusterData = NULL; par->clusterData = new ClusterData( *newSettingsCopy ); par->machineName = new _bstr_t( (*top).second.hp.machineName ); g_leftView = (LeftView *) dataSinkObj; } catch(...) { delete par->clusterData; delete par; delete p_nlbNetCfg; dataSinkObj->dataSink(GETRESOURCEIDSTRING(IDS_INFO_NEW_EXCEPTION)); throw; } AfxBeginThread( (AFX_THREADPROC) ModifyClusterPropertiesThread, par ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE ) ); } } return CommonNLB_SUCCESS; } CommonNLB::CommonNLB_Error CommonNLB::findPortRulesAddedUnchangedRemovedELB( const ClusterData* oldSettings, const ClusterData* newSettings, DataSinkI* dataSinkObj, vector& rulesAdded, vector& rulesUnchanged, vector& rulesRemoved ) { map::iterator top; map::iterator location; // find ports which have been newly added or modified. // for( top = newSettings->portELB.begin(); top != newSettings->portELB.end(); ++top ) { rulesAdded.push_back( (*top).first ); } // find ports which have remain unchanged and ports which have // been removed or modified. for( top = oldSettings->portELB.begin(); top != oldSettings->portELB.end(); ++top ) { // check if this port rule has been removed or modified. location = newSettings->portELB.find( (*top).first ); if( location == newSettings->portELB.end() ) { // key has been removed rulesRemoved.push_back( (*top).first ); } else { // may be things other than key are modified or totally // unchanged. if( (*location).second == (*top).second ) { // totally unchanged rulesUnchanged.push_back( (*top).first ); rulesAdded.erase (find( rulesAdded.begin(), rulesAdded.end(), (*top).first ) ); } else { // key is same but the other parts are modified. rulesRemoved.push_back( (*top).first ); } } } return CommonNLB_SUCCESS; } CommonNLB::CommonNLB_Error CommonNLB::findPortRulesAddedUnchangedRemovedULB( const ClusterData* oldSettings, const ClusterData* newSettings, DataSinkI* dataSinkObj, vector& rulesAdded, vector& rulesUnchanged, vector& rulesRemoved ) { map::iterator top; map::iterator location; // find ports which have been newly added or modified. // for( top = newSettings->portULB.begin(); top != newSettings->portULB.end(); ++top ) { rulesAdded.push_back( (*top).first ); } // find ports which have remain unchanged and ports which have // been removed or modified. for( top = oldSettings->portULB.begin(); top != oldSettings->portULB.end(); ++top ) { // check if this port rule has been removed or modified. location = newSettings->portULB.find( (*top).first ); if( location == newSettings->portULB.end() ) { // key has been removed rulesRemoved.push_back( (*top).first ); } else { // may be things other than key are modified or totally // unchanged. if( (*location).second == (*top).second ) { // totally unchanged rulesUnchanged.push_back( (*top).first ); rulesAdded.erase (find( rulesAdded.begin(), rulesAdded.end(), (*top).first ) ); } else { // key is same but the other parts are modified. rulesRemoved.push_back( (*top).first ); } } } return CommonNLB_SUCCESS; } CommonNLB::CommonNLB_Error CommonNLB::findPortRulesAddedUnchangedRemovedD( const ClusterData* oldSettings, const ClusterData* newSettings, DataSinkI* dataSinkObj, vector& rulesAdded, vector& rulesUnchanged, vector& rulesRemoved ) { map::iterator top; map::iterator location; // find ports which have been newly added or modified. // for( top = newSettings->portD.begin(); top != newSettings->portD.end(); ++top ) { rulesAdded.push_back( (*top).first ); } // find ports which have remain unchanged and ports which have // been removed or modified. for( top = oldSettings->portD.begin(); top != oldSettings->portD.end(); ++top ) { // check if this port rule has been removed or modified. location = newSettings->portD.find( (*top).first ); if( location == newSettings->portD.end() ) { // key has been removed rulesRemoved.push_back( (*top).first ); } else { // may be things other than key are modified or totally // unchanged. if( (*location).second == (*top).second ) { // totally unchanged rulesUnchanged.push_back( (*top).first ); rulesAdded.erase (find( rulesAdded.begin(), rulesAdded.end(), (*top).first ) ); } else { // key is same but the other parts are modified. rulesRemoved.push_back( (*top).first ); } } } return CommonNLB_SUCCESS; } CommonNLB::CommonNLB_Error CommonNLB::findPortRulesAddedUnchangedRemovedF( const ClusterData* oldSettings, const ClusterData* newSettings, DataSinkI* dataSinkObj, vector& rulesAdded, vector& rulesUnchanged, vector& rulesRemoved ) { map::iterator top; map::iterator location; // find ports which have been newly added or modified. // for( top = newSettings->portF.begin(); top != newSettings->portF.end(); ++top ) { rulesAdded.push_back( (*top).first ); } // find ports which have remain unchanged and ports which have // been removed or modified. for( top = oldSettings->portF.begin(); top != oldSettings->portF.end(); ++top ) { // check if this port rule has been removed or modified. location = newSettings->portF.find( (*top).first ); if( location == newSettings->portF.end() ) { // key has been removed rulesRemoved.push_back( (*top).first ); } else { // may be things other than key are modified or totally // unchanged. if( (*location).second == (*top).second ) { // totally unchanged rulesUnchanged.push_back( (*top).first ); rulesAdded.erase (find( rulesAdded.begin(), rulesAdded.end(), (*top).first ) ); } else { // key is same but the other parts are modified. rulesRemoved.push_back( (*top).first ); } } } return CommonNLB_SUCCESS; } CommonNLB::CommonNLB_Error CommonNLB::removeCluster( const ClusterData* clusterSettings, DataSinkI* dataSinkObj ) { map<_bstr_t, HostData>::iterator top; for( top = clusterSettings->hosts.begin(); top != clusterSettings->hosts.end(); ++top ) { removeHost( clusterSettings, (*top).first, dataSinkObj ); } return CommonNLB_SUCCESS; } CommonNLB::CommonNLB_Error CommonNLB::removeHost( const ClusterData* clusterSettings, const _bstr_t& machineName, DataSinkI* dataSinkObj ) { ClusterData* clusterSettingsCopy = const_cast ( clusterSettings ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_CONNECTING ) + clusterSettingsCopy->hosts[machineName].connectionIP ); // note that we are not responsible for freeing this pointer // though if the removeClusterIP fails then we do need to free it. // TODO MNLBNetCfg* p_nlbNetCfg = new MNLBNetCfg( clusterSettingsCopy->hosts[machineName].connectionIP, clusterSettingsCopy->hosts[machineName].hp.nicInfo.fullNicName ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE ) ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_REMOVING_CL_IP ) + clusterSettingsCopy->cp.cIP ); // remove cluster ip from machine specified. p_nlbNetCfg->removeClusterIP( clusterSettingsCopy->cp.cIP ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE ) ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_UNBINDING_NLB ) + clusterSettingsCopy->hosts[machineName].hp.nicInfo.fullNicName ); AfxBeginThread( (AFX_THREADPROC ) UnbindThread, p_nlbNetCfg ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_REQUEST ) ); return CommonNLB_SUCCESS; } CommonNLB::CommonNLB_Error CommonNLB::runControlMethodOnCluster( const ClusterData* clusterSettings, DataSinkI* dataSinkObj, const _bstr_t& methodToRun, unsigned long portToAffect ) { map<_bstr_t, HostData>::iterator top; for( top = clusterSettings->hosts.begin(); top != clusterSettings->hosts.end(); ++top ) { runControlMethodOnHost( clusterSettings, (*top).first, dataSinkObj, methodToRun, portToAffect ); } return CommonNLB_SUCCESS; } CommonNLB::CommonNLB_Error CommonNLB::runControlMethodOnHost( const ClusterData* clusterSettings, const _bstr_t& machineName, DataSinkI* dataSinkObj, const _bstr_t& methodToRun, unsigned long portToAffect ) { ClusterData* clusterSettingsCopy = const_cast ( clusterSettings ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_CONNECTING ) + clusterSettingsCopy->hosts[machineName].connectionIP ); MNLBMachine nlbMachine( clusterSettingsCopy->hosts[machineName].connectionIP, clusterSettingsCopy->cp.cIP ); dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_INFO_DONE ) ); unsigned long retVal; if( methodToRun == _bstr_t( L"query" ) ) { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_COMMAND_QUERY ) + clusterSettingsCopy->cp.cIP + L":" + machineName ); // the hoststatus has the current state of the host. HostProperties hp; nlbMachine.getHostProperties( &hp ); retVal = hp.hostStatus; } else if( methodToRun == _bstr_t( L"start" ) ) { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_COMMAND_START ) + clusterSettingsCopy->cp.cIP + L":" + machineName ); nlbMachine.start( Common::THIS_HOST, &retVal ); } else if( methodToRun == _bstr_t( L"stop" ) ) { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_COMMAND_STOP ) + clusterSettingsCopy->cp.cIP + L":" + machineName ); nlbMachine.stop( Common::THIS_HOST, &retVal ); } else if( methodToRun == _bstr_t( L"drainstop" ) ) { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_COMMAND_DRAINSTOP ) + clusterSettingsCopy->cp.cIP + L":" + machineName ); nlbMachine.drainstop( Common::THIS_HOST, &retVal ); } else if( methodToRun == _bstr_t( L"resume" ) ) { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_COMMAND_RESUME ) + clusterSettingsCopy->cp.cIP + L":" + machineName ); nlbMachine.resume( Common::THIS_HOST, &retVal ); } else if( methodToRun == _bstr_t( L"suspend" ) ) { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_COMMAND_SUSPEND ) + clusterSettingsCopy->cp.cIP + L":" + machineName ); nlbMachine.suspend( Common::THIS_HOST, &retVal ); } else if( methodToRun == _bstr_t( L"enable" ) ) { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_COMMAND_ENABLE ) + clusterSettingsCopy->cp.cIP + L":" + machineName ); nlbMachine.enable( Common::THIS_HOST, &retVal, portToAffect ); } else if( methodToRun == _bstr_t( L"disable" ) ) { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_COMMAND_DISABLE ) + clusterSettingsCopy->cp.cIP + L":" + machineName ); nlbMachine.disable( Common::THIS_HOST, &retVal, portToAffect ); } else if( methodToRun == _bstr_t( L"drain" ) ) { dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_COMMAND_DRAIN ) + clusterSettingsCopy->cp.cIP + L":" + machineName ); nlbMachine.drain( Common::THIS_HOST, &retVal, portToAffect ); } else { // unknown method. It has to be one of above. dataSinkObj->dataSink( GETRESOURCEIDSTRING( IDS_WLBS_UNKNOWN ) ); } // decipher the return. _bstr_t errString; getWLBSErrorString( retVal, errString ); dataSinkObj->dataSink( errString ); return CommonNLB_SUCCESS; } // the unbinding is done in a separate thread // as this call though successful, unloads and reloads the nic // when nlb is unbound which can cause the connection to fail. // This failure can occur after a very long time, which causes nlb // manager to hang if this operation is not carried out in // separate thread. // Also note that the ownership of the MNLBNetCfg object is given // to this thread, thus it is deleting this object. Thus caller // needs to create the object on the heap, pass it in AfxBeginThread // and be sure to not delete it. UINT CommonNLB::UnbindThread( LPVOID pParam ) { MUsingCom com; MNLBNetCfg* p_nlbNetCfg = ( MNLBNetCfg *) pParam; try { p_nlbNetCfg->unbind(); } catch( _com_error (e ) ) { // the above call may fail, thus we want // to catch exception. } delete p_nlbNetCfg; return 0; } CommonNLB::CommonNLB_Error CommonNLB::getWLBSErrorString( unsigned long errStatus, // IN _bstr_t& extErrString // OUT ) { switch( errStatus ) { case 1000 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_OK ); break; case 1001 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_ALREADY ); break; case 1002 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_DRAIN_STOP ); break; case 1003 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_BAD_PARAMS ); break; case 1004 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_NOT_FOUND ); break; case 1005 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_STOPPED ); break; case 1006 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_CONVERGING ); break; case 1007 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_CONVERGED ); break; case 1008 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_DEFAULT ); break; case 1009 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_DRAINING ); break; case 1013 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_SUSPENDED ); break; case 1050 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_REBOOT ); break; case 1100 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_INIT_ERROR ); break; case 1101 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_BAD_PASSW ); break; case 1102: extErrString = GETRESOURCEIDSTRING( IDS_WLBS_IO_ERROR ); break; case 1103 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_TIMEOUT ); break; case 1150 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_PORT_OVERLAP ); break; case 1151 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_BAD_PORT_PARAMS ); break; case 1152 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_MAX_PORT_RULES ); break; case 1153 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_TRUNCATED ); break; case 1154 : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_REG_ERROR ); break; default : extErrString = GETRESOURCEIDSTRING( IDS_WLBS_UNKNOWN ); break; } return CommonNLB_SUCCESS; } CommonNLB::CommonNLB_Error CommonNLB::addHostToCluster( const ClusterData* clusterToAddTo, const _bstr_t& machineName, DataSinkI* dataSinkObj ) { ClusterData* clusterToAddToCopy = const_cast ( clusterToAddTo ); MNLBNetCfg* p_nlbNetCfg = NULL; BindAndConfigureParameters* par = NULL; try { p_nlbNetCfg = new MNLBNetCfg(clusterToAddToCopy->hosts[machineName].connectionIP, clusterToAddToCopy->hosts[machineName].hp.nicInfo.fullNicName ); par = new BindAndConfigureParameters; g_leftView = (LeftView *) dataSinkObj; par->nlbNetCfg = p_nlbNetCfg; par->clusterData = NULL; par->machineName = NULL; par->clusterData = new ClusterData( *clusterToAddToCopy ); par->machineName = new _bstr_t( machineName ); } catch(...) { if (par != NULL) { delete par->machineName; delete par->clusterData; delete par; } delete p_nlbNetCfg; dataSinkObj->dataSink(GETRESOURCEIDSTRING(IDS_INFO_NEW_EXCEPTION)); throw; } AfxBeginThread( (AFX_THREADPROC ) BindAndConfigureThread, par ); return CommonNLB_SUCCESS; } // the binding and configuration is done in a separate thread // as this call though successful, unloads and reloads the nic // when nlb is bound which can cause the connection to fail. // This failure can occur after a very long time, which causes nlb // manager to hang if this operation is not carried out in // separate thread. // It is very important to ensure that you are completely sure // that binding and configuration will succeed as this call will // run in its separate thread and does not generate errors even if // failure occurs. // // Also note that the ownership of the MNLBNetCfg object is given // to this thread, thus it is deleting this object. Thus caller // needs to create the object on the heap, pass it in AfxBeginThread // and be sure to not delete it. UINT CommonNLB::BindAndConfigureThread( LPVOID pParam ) { MUsingCom com; BindAndConfigureParameters* parameters = ( BindAndConfigureParameters *) pParam; MNLBNetCfg* p_nlbNetCfg = parameters->nlbNetCfg; ClusterData* p_clusterData = parameters->clusterData; _bstr_t* p_machineName = parameters->machineName; try { p_nlbNetCfg->bindAndConfigure( p_clusterData, *p_machineName ); } catch( _com_error (e ) ) { // the above call may fail, thus we want // to catch exception. } delete p_nlbNetCfg; delete p_clusterData; delete p_machineName; delete parameters; return 0; } // the modification of cluster properties is done in a separate thread // as this call though successful, might unload and reload the nic driver // when nlb is bound which can cause the connection to fail. // This failure can occur after a very long time, which causes nlb // manager to hang if this operation is not carried out in // separate thread. // It is very important to ensure that you are completely sure // that this operation will succeed as this call will // run in its separate thread and does not generate errors even if // failure occurs. // // Also note that the ownership of the MNLBNetCfg object is given // to this thread, thus it is deleting this object. Thus caller // needs to create the object on the heap, pass it in AfxBeginThread // and be sure to not delete it. UINT CommonNLB::ModifyClusterPropertiesThread( LPVOID pParam ) { MUsingCom com; ModifyClusterPropertiesParameters* parameters = ( ModifyClusterPropertiesParameters *) pParam; MNLBNetCfg* p_nlbNetCfg = parameters->nlbNetCfg; ClusterProperties* p_clusterProperties = &(parameters->clusterData->cp); try { p_nlbNetCfg->modifyClusterProperties(p_clusterProperties); } catch( _com_error (e ) ) { // the above call may fail, thus we want // to catch exception. } delete p_nlbNetCfg; delete parameters->clusterData; delete parameters; return 0; } UINT CommonNLB::DummyThread( LPVOID pParam ) { MUsingCom com; Sleep( 1000 ); BindAndConfigureParameters* parameters = ( BindAndConfigureParameters *) pParam; LeftView * leftView = g_leftView; TVINSERTSTRUCT item; item.hParent = leftView->GetTreeCtrl().GetRootItem(); ClusterData* p_clusterDataItem; HTREEITEM hNextItem; HTREEITEM hChildItem; if( leftView->GetTreeCtrl().ItemHasChildren( leftView->GetTreeCtrl().GetRootItem() ) ) { hChildItem = leftView->GetTreeCtrl().GetChildItem(leftView->GetTreeCtrl().GetRootItem() ); while (hChildItem != NULL) { hNextItem = leftView->GetTreeCtrl().GetNextItem(hChildItem, TVGN_NEXT); p_clusterDataItem = ( ClusterData * ) leftView->GetTreeCtrl().GetItemData( hChildItem ); if( p_clusterDataItem->cp.cIP == parameters->clusterData->cp.cIP ) { // the cluster is found. // get the exact host. Change icon of this host. hChildItem = leftView->GetTreeCtrl().GetChildItem( hChildItem ); while( hChildItem != NULL ) { hNextItem = leftView->GetTreeCtrl().GetNextItem(hChildItem, TVGN_NEXT); _bstr_t* machineName = (_bstr_t *) leftView->GetTreeCtrl().GetItemData( hChildItem ); if( *( machineName ) == *(parameters->machineName) ) { // found machine to change icon of. leftView->GetTreeCtrl().SetItemImage( hChildItem, 5, 5 ); goto outofloop; } hChildItem = hNextItem; } } hChildItem = hNextItem; } } outofloop: // loop for around let us say 1 minute. // enable the icon. Sleep( 10000 ); leftView->GetTreeCtrl().SetItemImage( hChildItem, 2, 2 ); return 0; }