diff --git a/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java b/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java index 75bd9d21d1b..15072ca9a4f 100644 --- a/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/address/AssociateIPAddrCmd.java @@ -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()); diff --git a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java index 07c5a2dfcaa..3e522f6be4f 100644 --- a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java +++ b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java @@ -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; } diff --git a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/ElementChildTestConfiguration.java b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/ElementChildTestConfiguration.java index 212dd94b3aa..c233f12c3d5 100644 --- a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/ElementChildTestConfiguration.java +++ b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbelement/ElementChildTestConfiguration.java @@ -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); diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index 4cc44c40478..01bded0eff2 100644 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -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> 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 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 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 rules = new ArrayList(); @@ -409,7 +314,7 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ if (routers == null || routers.isEmpty()) { return true; } - return validateHAProxyLBRule(rule); + return _networkHelper.validateHAProxyLBRule(rule); } return true; } diff --git a/server/src/com/cloud/network/router/NetworkHelper.java b/server/src/com/cloud/network/router/NetworkHelper.java index 380cecdafcf..04604e19d78 100644 --- a/server/src/com/cloud/network/router/NetworkHelper.java +++ b/server/src/com/cloud/network/router/NetworkHelper.java @@ -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> configureGuestNic(RouterDeploymentDefinition routerDeploymentDefinition) throws ConcurrentOperationException, InsufficientAddressCapacityException; -} \ No newline at end of file + + public boolean validateHAProxyLBRule(final LoadBalancingRule rule); +} diff --git a/server/src/com/cloud/network/router/NetworkHelperImpl.java b/server/src/com/cloud/network/router/NetworkHelperImpl.java index 12ef0f9995e..f83c2495a61 100644 --- a/server/src/com/cloud/network/router/NetworkHelperImpl.java +++ b/server/src/com/cloud/network/router/NetworkHelperImpl.java @@ -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> 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> 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 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 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; + } }