CLOUDSTACK-9922 Unable to use 8081 port for Load balancing

This commit is contained in:
SowjanyaPatha 2017-07-27 06:12:51 -04:00 committed by Sowjanya
commit f66bbb9521
6 changed files with 133 additions and 106 deletions

View File

@ -57,7 +57,7 @@ import com.cloud.offering.NetworkOffering;
import com.cloud.projects.Project;
import com.cloud.user.Account;
@APICommand(name = "associateIpAddress", description = "Acquires and associates a public IP to an account.", responseObject = IPAddressResponse.class, responseView = ResponseView.Restricted,
@APICommand(name = "associateIpAddress", description = "Acquires and associates a public IP to an account. Either of the parameters are required, i.e. either zoneId, or networkId, or vpcId ", responseObject = IPAddressResponse.class, responseView = ResponseView.Restricted,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class AssociateIPAddrCmd extends BaseAsyncCreateCmd {
public static final Logger s_logger = Logger.getLogger(AssociateIPAddrCmd.class.getName());

View File

@ -26,6 +26,8 @@ import java.util.Set;
import javax.inject.Inject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.command.admin.internallb.ConfigureInternalLoadBalancerElementCmd;
@ -81,6 +83,7 @@ import com.cloud.vm.ReservationContext;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.network.router.NetworkHelper;
public class InternalLoadBalancerElement extends AdapterBase implements LoadBalancingServiceProvider, InternalLoadBalancerElementService, IpDeployer {
private static final Logger s_logger = Logger.getLogger(InternalLoadBalancerElement.class);
@ -107,6 +110,9 @@ public class InternalLoadBalancerElement extends AdapterBase implements LoadBala
ApplicationLoadBalancerRuleDao _appLbDao;
@Inject
EntityManager _entityMgr;
@Autowired
@Qualifier("networkHelper")
protected NetworkHelper _networkHelper;
protected InternalLoadBalancerElement() {
}
@ -413,7 +419,7 @@ public class InternalLoadBalancerElement extends AdapterBase implements LoadBala
if (routers == null || routers.isEmpty()) {
return true;
}
return VirtualRouterElement.validateHAProxyLBRule(rule);
return _networkHelper.validateHAProxyLBRule(rule);
}
return true;
}

View File

@ -44,6 +44,7 @@ import com.cloud.user.AccountManager;
import com.cloud.utils.db.EntityManager;
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.network.router.NetworkHelper;
@Configuration
@ComponentScan(basePackageClasses = {NetUtils.class},
@ -61,6 +62,11 @@ public class ElementChildTestConfiguration {
return Mockito.mock(DomainRouterDao.class);
}
@Bean
public NetworkHelper networkHelper() {
return Mockito.mock(NetworkHelper.class);
}
@Bean
public VirtualRouterProviderDao virtualRouterProviderDao() {
return Mockito.mock(VirtualRouterProviderDao.class);

View File

@ -23,7 +23,9 @@ import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import com.cloud.network.router.NetworkHelper;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import org.cloud.network.router.deployment.RouterDeploymentDefinition;
@ -78,7 +80,6 @@ import com.cloud.network.dao.NetworkDetailsDao;
import com.cloud.network.dao.OvsProviderDao;
import com.cloud.network.dao.VirtualRouterProviderDao;
import com.cloud.network.lb.LoadBalancingRule;
import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy;
import com.cloud.network.lb.LoadBalancingRulesManager;
import com.cloud.network.router.VirtualRouter;
import com.cloud.network.router.VirtualRouter.Role;
@ -95,13 +96,11 @@ import com.cloud.offerings.NetworkOfferingVO;
import com.cloud.offerings.dao.NetworkOfferingDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.utils.Pair;
import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.crypt.DBEncryptionUtil;
import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.DomainRouterVO;
import com.cloud.vm.NicProfile;
import com.cloud.vm.ReservationContext;
@ -171,6 +170,10 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ
@Inject
protected RouterDeploymentDefinitionBuilder routerDeploymentDefinitionBuilder;
@Autowired
@Qualifier("networkHelper")
protected NetworkHelper _networkHelper;
protected boolean canHandle(final Network network, final Service service) {
final Long physicalNetworkId = _networkMdl.getPhysicalNetworkId(network);
if (physicalNetworkId == null) {
@ -302,104 +305,6 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ
return result;
}
/*
* This function detects numbers like 12 ,32h ,42m .. etc,. 1) plain number
* like 12 2) time or tablesize like 12h, 34m, 45k, 54m , here last
* character is non-digit but from known characters .
*/
private static boolean containsOnlyNumbers(final String str, final String endChar) {
if (str == null) {
return false;
}
String number = str;
if (endChar != null) {
boolean matchedEndChar = false;
if (str.length() < 2) {
return false; // at least one numeric and one char. example:
}
// 3h
final char strEnd = str.toCharArray()[str.length() - 1];
for (final char c : endChar.toCharArray()) {
if (strEnd == c) {
number = str.substring(0, str.length() - 1);
matchedEndChar = true;
break;
}
}
if (!matchedEndChar) {
return false;
}
}
try {
Integer.parseInt(number);
} catch (final NumberFormatException e) {
return false;
}
return true;
}
public static boolean validateHAProxyLBRule(final LoadBalancingRule rule) {
final String timeEndChar = "dhms";
if (rule.getSourcePortStart() == NetUtils.HAPROXY_STATS_PORT) {
s_logger.debug("Can't create LB on port 8081, haproxy is listening for LB stats on this port");
return false;
}
for (final LbStickinessPolicy stickinessPolicy : rule.getStickinessPolicies()) {
final List<Pair<String, String>> paramsList = stickinessPolicy.getParams();
if (StickinessMethodType.LBCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
} else if (StickinessMethodType.SourceBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
String tablesize = "200k"; // optional
String expire = "30m"; // optional
/* overwrite default values with the stick parameters */
for (final Pair<String, String> paramKV : paramsList) {
final String key = paramKV.first();
final String value = paramKV.second();
if ("tablesize".equalsIgnoreCase(key)) {
tablesize = value;
}
if ("expire".equalsIgnoreCase(key)) {
expire = value;
}
}
if (expire != null && !containsOnlyNumbers(expire, timeEndChar)) {
throw new InvalidParameterValueException("Failed LB in validation rule id: " + rule.getId() + " Cause: expire is not in timeformat: " + expire);
}
if (tablesize != null && !containsOnlyNumbers(tablesize, "kmg")) {
throw new InvalidParameterValueException("Failed LB in validation rule id: " + rule.getId() + " Cause: tablesize is not in size format: " + tablesize);
}
} else if (StickinessMethodType.AppCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
String length = null; // optional
String holdTime = null; // optional
for (final Pair<String, String> paramKV : paramsList) {
final String key = paramKV.first();
final String value = paramKV.second();
if ("length".equalsIgnoreCase(key)) {
length = value;
}
if ("holdtime".equalsIgnoreCase(key)) {
holdTime = value;
}
}
if (length != null && !containsOnlyNumbers(length, null)) {
throw new InvalidParameterValueException("Failed LB in validation rule id: " + rule.getId() + " Cause: length is not a number: " + length);
}
if (holdTime != null && !containsOnlyNumbers(holdTime, timeEndChar) && !containsOnlyNumbers(holdTime, null)) {
throw new InvalidParameterValueException("Failed LB in validation rule id: " + rule.getId() + " Cause: holdtime is not in timeformat: " + holdTime);
}
}
}
return true;
}
@Override
public boolean validateLBRule(final Network network, final LoadBalancingRule rule) {
final List<LoadBalancingRule> rules = new ArrayList<LoadBalancingRule>();
@ -409,7 +314,7 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ
if (routers == null || routers.isEmpty()) {
return true;
}
return validateHAProxyLBRule(rule);
return _networkHelper.validateHAProxyLBRule(rule);
}
return true;
}

View File

@ -21,6 +21,7 @@ import java.util.List;
import java.util.Map;
import org.cloud.network.router.deployment.RouterDeploymentDefinition;
import com.cloud.network.lb.LoadBalancingRule;
import com.cloud.agent.api.to.NicTO;
import com.cloud.agent.manager.Commands;
@ -89,4 +90,6 @@ public interface NetworkHelper {
public abstract LinkedHashMap<Network, List<? extends NicProfile>> configureGuestNic(RouterDeploymentDefinition routerDeploymentDefinition)
throws ConcurrentOperationException, InsufficientAddressCapacityException;
public boolean validateHAProxyLBRule(final LoadBalancingRule rule);
}

View File

@ -27,6 +27,12 @@ import java.util.Map;
import javax.annotation.PostConstruct;
import javax.ejb.Local;
import javax.inject.Inject;
import com.cloud.configuration.Config;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.network.lb.LoadBalancingRule;
import com.cloud.network.rules.LbStickinessMethod;
import com.cloud.utils.Pair;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
@ -147,6 +153,8 @@ public class NetworkHelperImpl implements NetworkHelper {
protected VirtualMachineManager _itMgr;
@Inject
protected IpAddressManager _ipAddrMgr;
@Inject
ConfigurationDao _configDao;
protected final Map<HypervisorType, ConfigKey<String>> hypervisorsMap = new HashMap<>();
@ -771,4 +779,103 @@ public class NetworkHelperImpl implements NetworkHelper {
public static void setVMInstanceName(final String vmInstanceName) {
s_vmInstanceName = vmInstanceName;
}
public boolean validateHAProxyLBRule(final LoadBalancingRule rule) {
final String timeEndChar = "dhms";
int haproxy_stats_port = Integer.parseInt(_configDao.getValue(Config.NetworkLBHaproxyStatsPort.key()));
if (rule.getSourcePortStart() == haproxy_stats_port) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Can't create LB on port "+ haproxy_stats_port +", haproxy is listening for LB stats on this port");
}
return false;
}
for (final LoadBalancingRule.LbStickinessPolicy stickinessPolicy : rule.getStickinessPolicies()) {
final List<Pair<String, String>> paramsList = stickinessPolicy.getParams();
if (LbStickinessMethod.StickinessMethodType.LBCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
} else if (LbStickinessMethod.StickinessMethodType.SourceBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
String tablesize = "200k"; // optional
String expire = "30m"; // optional
/* overwrite default values with the stick parameters */
for (final Pair<String, String> paramKV : paramsList) {
final String key = paramKV.first();
final String value = paramKV.second();
if ("tablesize".equalsIgnoreCase(key)) {
tablesize = value;
}
if ("expire".equalsIgnoreCase(key)) {
expire = value;
}
}
if (expire != null && !containsOnlyNumbers(expire, timeEndChar)) {
throw new InvalidParameterValueException("Failed LB in validation rule id: " + rule.getId() + " Cause: expire is not in timeformat: " + expire);
}
if (tablesize != null && !containsOnlyNumbers(tablesize, "kmg")) {
throw new InvalidParameterValueException("Failed LB in validation rule id: " + rule.getId() + " Cause: tablesize is not in size format: " + tablesize);
}
} else if (LbStickinessMethod.StickinessMethodType.AppCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) {
String length = null; // optional
String holdTime = null; // optional
for (final Pair<String, String> paramKV : paramsList) {
final String key = paramKV.first();
final String value = paramKV.second();
if ("length".equalsIgnoreCase(key)) {
length = value;
}
if ("holdtime".equalsIgnoreCase(key)) {
holdTime = value;
}
}
if (length != null && !containsOnlyNumbers(length, null)) {
throw new InvalidParameterValueException("Failed LB in validation rule id: " + rule.getId() + " Cause: length is not a number: " + length);
}
if (holdTime != null && !containsOnlyNumbers(holdTime, timeEndChar) && !containsOnlyNumbers(holdTime, null)) {
throw new InvalidParameterValueException("Failed LB in validation rule id: " + rule.getId() + " Cause: holdtime is not in timeformat: " + holdTime);
}
}
}
return true;
}
/*
* This function detects numbers like 12 ,32h ,42m .. etc,. 1) plain number
* like 12 2) time or tablesize like 12h, 34m, 45k, 54m , here last
* character is non-digit but from known characters .
*/
private static boolean containsOnlyNumbers(final String str, final String endChar) {
if (str == null) {
return false;
}
String number = str;
if (endChar != null) {
boolean matchedEndChar = false;
if (str.length() < 2) {
return false; // at least one numeric and one char. example:
}
// 3h
final char strEnd = str.toCharArray()[str.length() - 1];
for (final char c : endChar.toCharArray()) {
if (strEnd == c) {
number = str.substring(0, str.length() - 1);
matchedEndChar = true;
break;
}
}
if (!matchedEndChar) {
return false;
}
}
try {
Integer.parseInt(number);
} catch (final NumberFormatException e) {
return false;
}
return true;
}
}