From 539ff56a0ffce9d2e2f8f67ceea1adea6e247d44 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 18 May 2020 22:16:56 +0000 Subject: [PATCH 01/75] LB configs: Load Balancer customization --- .../agent/api/to/LoadBalancerConfigTO.java | 42 +++ .../cloud/agent/api/to/LoadBalancerTO.java | 17 + .../main/java/com/cloud/event/EventTypes.java | 4 + .../network/lb/LoadBalancerConfigService.java | 40 +++ .../network/rules/LoadBalancerConfig.java | 49 +++ .../apache/cloudstack/api/ApiConstants.java | 3 + .../org/apache/cloudstack/api/BaseCmd.java | 3 + .../cloudstack/api/ResponseGenerator.java | 4 + .../CreateLoadBalancerConfigCmd.java | 215 +++++++++++ .../DeleteLoadBalancerConfigCmd.java | 147 ++++++++ .../ListLoadBalancerConfigsCmd.java | 146 ++++++++ .../ReplaceLoadBalancerConfigsCmd.java | 181 ++++++++++ .../UpdateLoadBalancerConfigCmd.java | 155 ++++++++ .../response/LoadBalancerConfigResponse.java | 111 ++++++ .../network/lb/LoadBalancerConfigKey.java | 175 +++++++++ .../routing/LoadBalancerConfigCommand.java | 22 ++ .../VirtualRoutingResource.java | 1 + .../cloud/network/HAProxyConfigurator.java | 19 + .../network/lb/LoadBalancerConfigManager.java | 30 ++ .../network/dao/LoadBalancerConfigDao.java | 43 +++ .../dao/LoadBalancerConfigDaoImpl.java | 162 +++++++++ .../network/dao/LoadBalancerConfigVO.java | 167 +++++++++ ...spring-engine-schema-core-daos-context.xml | 1 + .../META-INF/db/schema-41310to41400.sql | 21 ++ .../java/com/cloud/api/ApiResponseHelper.java | 32 ++ .../lb/LoadBalancerConfigManagerImpl.java | 339 ++++++++++++++++++ .../network/router/CommandSetupHelper.java | 6 + .../cloud/server/ManagementServerImpl.java | 10 + .../spring-server-core-managers-context.xml | 2 + ui/index.html | 1 + ui/scripts/network.js | 184 ++++++++++ ui/scripts/ui-custom/lbConfigs.js | 239 ++++++++++++ ui/scripts/ui/widgets/multiEdit.js | 2 + 33 files changed, 2573 insertions(+) create mode 100644 api/src/main/java/com/cloud/agent/api/to/LoadBalancerConfigTO.java create mode 100644 api/src/main/java/com/cloud/network/lb/LoadBalancerConfigService.java create mode 100644 api/src/main/java/com/cloud/network/rules/LoadBalancerConfig.java create mode 100644 api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerConfigCmd.java create mode 100644 api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/DeleteLoadBalancerConfigCmd.java create mode 100644 api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerConfigsCmd.java create mode 100644 api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ReplaceLoadBalancerConfigsCmd.java create mode 100644 api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLoadBalancerConfigCmd.java create mode 100644 api/src/main/java/org/apache/cloudstack/api/response/LoadBalancerConfigResponse.java create mode 100644 api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java create mode 100644 engine/components-api/src/main/java/com/cloud/network/lb/LoadBalancerConfigManager.java create mode 100644 engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDao.java create mode 100644 engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDaoImpl.java create mode 100644 engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigVO.java create mode 100644 server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java create mode 100644 ui/scripts/ui-custom/lbConfigs.js diff --git a/api/src/main/java/com/cloud/agent/api/to/LoadBalancerConfigTO.java b/api/src/main/java/com/cloud/agent/api/to/LoadBalancerConfigTO.java new file mode 100644 index 000000000000..82102426f1be --- /dev/null +++ b/api/src/main/java/com/cloud/agent/api/to/LoadBalancerConfigTO.java @@ -0,0 +1,42 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.agent.api.to; + +import com.cloud.network.rules.LoadBalancerConfig; + +public class LoadBalancerConfigTO { + private String name; + private String value; + + public LoadBalancerConfigTO(String name, String value) { + this.name = name; + this.value = value; + } + + public LoadBalancerConfigTO(LoadBalancerConfig config) { + this.name = config.getName(); + this.value = config.getValue(); + } + + public String getName() { + return name; + } + + public String getValue() { + return value; + } +} diff --git a/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java b/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java index 3a3dfa475021..770c3199cf8b 100644 --- a/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java +++ b/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java @@ -33,6 +33,7 @@ import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; import com.cloud.network.lb.LoadBalancingRule.LbSslCert; import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; +import com.cloud.network.rules.LoadBalancerConfig; import com.cloud.utils.Pair; public class LoadBalancerTO { @@ -50,6 +51,7 @@ public class LoadBalancerTO { String srcIpNetmask; Long networkId; DestinationTO[] destinations; + private LoadBalancerConfigTO[] lbConfigs; private StickinessPolicyTO[] stickinessPolicies; private HealthCheckPolicyTO[] healthCheckPolicies; private LbSslCert sslCert; /* XXX: Should this be SslCertTO? */ @@ -179,6 +181,21 @@ public boolean isInline() { return inline; } + public LoadBalancerConfigTO[] getLbConfigs() { + return this.lbConfigs; + } + + public void setLbConfigs(List lbConfigs) { + if (lbConfigs == null) { + lbConfigs = new ArrayList(); + } + this.lbConfigs = new LoadBalancerConfigTO[lbConfigs.size()]; + int i = 0; + for (LoadBalancerConfig lbConfig : lbConfigs) { + this.lbConfigs[i++] = new LoadBalancerConfigTO(lbConfig); + } + } + public StickinessPolicyTO[] getStickinessPolicies() { return stickinessPolicies; } diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java index 852198b91a7a..374460c4d123 100644 --- a/api/src/main/java/com/cloud/event/EventTypes.java +++ b/api/src/main/java/com/cloud/event/EventTypes.java @@ -174,6 +174,10 @@ public class EventTypes { public static final String EVENT_LB_CERT_DELETE = "LB.CERT.DELETE"; public static final String EVENT_LB_CERT_ASSIGN = "LB.CERT.ASSIGN"; public static final String EVENT_LB_CERT_REMOVE = "LB.CERT.REMOVE"; + public static final String EVENT_LOAD_BALANCER_CONFIG_CREATE = "LB.CONFIG.CREATE"; + public static final String EVENT_LOAD_BALANCER_CONFIG_DELETE = "LB.CONFIG.DELETE"; + public static final String EVENT_LOAD_BALANCER_CONFIG_REPLACE = "LB.CONFIG.REPLACE"; + public static final String EVENT_LOAD_BALANCER_CONFIG_UPDATE = "LB.CONFIG.UPDATE"; // Global Load Balancer rules public static final String EVENT_ASSIGN_TO_GLOBAL_LOAD_BALANCER_RULE = "GLOBAL.LB.ASSIGN"; diff --git a/api/src/main/java/com/cloud/network/lb/LoadBalancerConfigService.java b/api/src/main/java/com/cloud/network/lb/LoadBalancerConfigService.java new file mode 100644 index 000000000000..c650210b3521 --- /dev/null +++ b/api/src/main/java/com/cloud/network/lb/LoadBalancerConfigService.java @@ -0,0 +1,40 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.lb; + +import java.util.List; + +import com.cloud.network.rules.LoadBalancerConfig; + +import org.apache.cloudstack.api.command.user.loadbalancer.CreateLoadBalancerConfigCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.DeleteLoadBalancerConfigCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerConfigsCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ReplaceLoadBalancerConfigsCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLoadBalancerConfigCmd; + +public interface LoadBalancerConfigService { + + List searchForLoadBalancerConfigs(ListLoadBalancerConfigsCmd cmd); + + LoadBalancerConfig createLoadBalancerConfig(CreateLoadBalancerConfigCmd cmd); + + boolean deleteLoadBalancerConfig(DeleteLoadBalancerConfigCmd cmd); + + LoadBalancerConfig updateLoadBalancerConfig(UpdateLoadBalancerConfigCmd cmd); + + List replaceLoadBalancerConfigs(ReplaceLoadBalancerConfigsCmd cmd); +} diff --git a/api/src/main/java/com/cloud/network/rules/LoadBalancerConfig.java b/api/src/main/java/com/cloud/network/rules/LoadBalancerConfig.java new file mode 100644 index 000000000000..41cc96b66454 --- /dev/null +++ b/api/src/main/java/com/cloud/network/rules/LoadBalancerConfig.java @@ -0,0 +1,49 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.rules; + +import java.util.Date; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface LoadBalancerConfig extends Identity, InternalIdentity { + + public enum Scope { + Network, Vpc, LoadBalancerRule; + } + + Scope getScope(); + + Long getNetworkId(); + + Long getVpcId(); + + Long getLoadBalancerId(); + + String getName(); + + String getValue(); + + String getDefaultValue(); + + String getDisplayText(); + + Date getCreated(); + + Date getRemoved(); +} diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 0087fee33402..c5e584786a31 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -80,6 +80,7 @@ public class ApiConstants { public static final String CLUSTER_TYPE = "clustertype"; public static final String CN = "cn"; public static final String COMMAND = "command"; + public static final String CONFIG = "config"; public static final String CMD_EVENT_TYPE = "cmdeventtype"; public static final String COMPONENT = "component"; public static final String CPU_CORE_PER_SOCKET = "cpucorepersocket"; @@ -100,6 +101,7 @@ public class ApiConstants { public static final String MAX_IOPS = "maxiops"; public static final String HYPERVISOR_SNAPSHOT_RESERVE = "hypervisorsnapshotreserve"; public static final String DATADISK_OFFERING_LIST = "datadiskofferinglist"; + public static final String DEFAULT_VALUE = "defaultvalue"; public static final String DESCRIPTION = "description"; public static final String DESTINATION_ZONE_ID = "destzoneid"; public static final String DETAILS = "details"; @@ -539,6 +541,7 @@ public class ApiConstants { public static final String LOAD_BALANCER_DEVICE_STATE = "lbdevicestate"; public static final String LOAD_BALANCER_DEVICE_CAPACITY = "lbdevicecapacity"; public static final String LOAD_BALANCER_DEVICE_DEDICATED = "lbdevicededicated"; + public static final String LOAD_BALANCER_ID = "loadbalancerid"; public static final String LOAD_BALANCER_RULE = "loadbalancerrule"; public static final String LOAD_BALANCER_RULE_LIST = "loadbalancerrulelist"; public static final String FIREWALL_DEVICE_ID = "fwdeviceid"; diff --git a/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java b/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java index c897aad4d4b4..06dc345132f7 100644 --- a/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java @@ -57,6 +57,7 @@ import com.cloud.network.VpcVirtualNetworkApplianceService; import com.cloud.network.as.AutoScaleService; import com.cloud.network.firewall.FirewallService; +import com.cloud.network.lb.LoadBalancerConfigService; import com.cloud.network.lb.LoadBalancingRulesService; import com.cloud.network.rules.RulesService; import com.cloud.network.security.SecurityGroupService; @@ -150,6 +151,8 @@ public static enum CommandType { @Inject public LoadBalancingRulesService _lbService; @Inject + public LoadBalancerConfigService _lbConfigService; + @Inject public RemoteAccessVpnService _ravService; @Inject public ProjectService _projectService; diff --git a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java index 3f0d978b161a..6ec6534ab378 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java @@ -69,6 +69,7 @@ import org.apache.cloudstack.api.response.LBHealthCheckResponse; import org.apache.cloudstack.api.response.LBStickinessResponse; import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.LoadBalancerConfigResponse; import org.apache.cloudstack.api.response.LoadBalancerResponse; import org.apache.cloudstack.api.response.ManagementServerResponse; import org.apache.cloudstack.api.response.NetworkACLItemResponse; @@ -170,6 +171,7 @@ import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.HealthCheckPolicy; import com.cloud.network.rules.LoadBalancer; +import com.cloud.network.rules.LoadBalancerConfig; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.StaticNatRule; import com.cloud.network.rules.StickinessPolicy; @@ -260,6 +262,8 @@ public interface ResponseGenerator { LoadBalancerResponse createLoadBalancerResponse(LoadBalancer loadBalancer); + LoadBalancerConfigResponse createLoadBalancerConfigResponse(LoadBalancerConfig config); + LBStickinessResponse createLBStickinessPolicyResponse(List stickinessPolicies, LoadBalancer lb); LBStickinessResponse createLBStickinessPolicyResponse(StickinessPolicy stickinessPolicy, LoadBalancer lb); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerConfigCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerConfigCmd.java new file mode 100644 index 000000000000..a1ef03b047ff --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerConfigCmd.java @@ -0,0 +1,215 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.loadbalancer; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseAsyncCreateCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.FirewallRuleResponse; +import org.apache.cloudstack.api.response.LoadBalancerConfigResponse; +import org.apache.cloudstack.api.response.NetworkResponse; +import org.apache.cloudstack.api.response.VpcResponse; +import org.apache.log4j.Logger; + +import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.Network; +import com.cloud.network.rules.LoadBalancer; +import com.cloud.network.rules.LoadBalancerConfig; +import com.cloud.network.rules.LoadBalancerConfig.Scope; +import com.cloud.network.vpc.Vpc; + +@APICommand(name = "createLoadBalancerConfig", description = "Creates a load balancer config", + responseObject = LoadBalancerConfigResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) +public class CreateLoadBalancerConfigCmd extends BaseAsyncCreateCmd { + public static final Logger s_logger = Logger.getLogger(CreateLoadBalancerConfigCmd.class.getName()); + + private static final String s_name = "createloadbalancerconfigresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.SCOPE, + type = CommandType.STRING, + required = true, + description = "the scope of the config: network, vpc or rule") + private String scope; + + @Parameter(name = ApiConstants.NETWORK_ID, + type = CommandType.UUID, + entityType = NetworkResponse.class, + description = "the ID of network to update") + private Long networkId; + + @Parameter(name = ApiConstants.VPC_ID, + type = CommandType.UUID, + entityType = VpcResponse.class, + description = "the ID of vpc to update") + private Long vpcId; + + @Parameter(name = ApiConstants.LOAD_BALANCER_ID, + type = CommandType.UUID, + entityType = FirewallRuleResponse.class, + description = "the ID of the load balancer rule to update") + private Long loadBalancerId; + + @Parameter(name = ApiConstants.NAME, + type = CommandType.STRING, + required = true, + description = "name of the load balancer config") + private String name; + + @Parameter(name = ApiConstants.VALUE, + type = CommandType.STRING, + required = true, + description = "value of the load balancer config") + private String value; + + @Parameter(name = ApiConstants.FORCED, + type = CommandType.BOOLEAN, + required = false, + description = "Force add a load balancer config. Existing config will be removed") + private Boolean forced; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getScope() { + return scope; + } + + public Long getVpcId() { + return vpcId; + } + + public Long getNetworkId() { + return networkId; + } + + public Long getLoadBalancerId() { + return loadBalancerId; + } + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + + public boolean isForced() { + return (forced != null) ? forced : false; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public void execute() { + + LoadBalancerConfig config = null; + try { + config = _entityMgr.findById(LoadBalancerConfig.class, getEntityId()); + LoadBalancerConfigResponse lbConfigResponse = new LoadBalancerConfigResponse(); + if (config != null) { + lbConfigResponse = _responseGenerator.createLoadBalancerConfigResponse(config); + setResponseObject(lbConfigResponse); + } + lbConfigResponse.setResponseName(getCommandName()); + } catch (Exception ex) { + s_logger.warn("Failed to create LB config due to exception ", ex); + } + } + + @Override + public void create() { + try { + LoadBalancerConfig result = _lbConfigService.createLoadBalancerConfig(this); + this.setEntityId(result.getId()); + this.setEntityUuid(result.getUuid()); + } catch (InvalidParameterValueException e) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, e.getMessage()); + } + } + + @Override + public String getSyncObjType() { + if (networkId != null) { + return BaseAsyncCmd.networkSyncObject; + } else if (vpcId != null) { + return BaseAsyncCmd.vpcSyncObject; + } + return null; + } + + @Override + public Long getSyncObjId() { + if (networkId != null) { + return getNetworkId(); + } else if (vpcId != null) { + return getVpcId(); + } + return null; + } + + @Override + public long getEntityOwnerId() { + if (Scope.Network.name().equalsIgnoreCase(scope) && networkId != null) { + Network network = _entityMgr.findById(Network.class, networkId); + if (network != null) { + return network.getAccountId(); + } + } else if (Scope.Vpc.name().equalsIgnoreCase(scope) && vpcId != null) { + Vpc vpc = _entityMgr.findById(Vpc.class, vpcId); + if (vpc != null) { + return vpc.getAccountId(); + } + } else if (Scope.LoadBalancerRule.name().equalsIgnoreCase(scope) && loadBalancerId != null) { + LoadBalancer lb = _entityMgr.findById(LoadBalancer.class, loadBalancerId); + if (lb != null) { + return lb.getAccountId(); + } + } + throw new InvalidParameterValueException("Unable to find the entity owner"); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_LOAD_BALANCER_CONFIG_CREATE; + } + + @Override + public String getEventDescription() { + return "creating load balancer: " + getName(); + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/DeleteLoadBalancerConfigCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/DeleteLoadBalancerConfigCmd.java new file mode 100644 index 000000000000..aedd26390017 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/DeleteLoadBalancerConfigCmd.java @@ -0,0 +1,147 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.loadbalancer; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.LoadBalancerConfigResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.log4j.Logger; + +import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.Network; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.LoadBalancerConfig; +import com.cloud.network.vpc.Vpc; + +@APICommand(name = "deleteLoadBalancerConfig", description = "Deletes a load balancer config.", + responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) +public class DeleteLoadBalancerConfigCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(DeleteLoadBalancerConfigCmd.class.getName()); + private static final String s_name = "deleteloadbalancerconfigresponse"; + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, + type = CommandType.UUID, + entityType = LoadBalancerConfigResponse.class, + required = true, + description = "the ID of the load balancer config") + private Long id; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public void execute() { + boolean result = _lbConfigService.deleteLoadBalancerConfig(this); + + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete load balancer config"); + } + } + + @Override + public String getSyncObjType() { + LoadBalancerConfig config = _entityMgr.findById(LoadBalancerConfig.class, getId()); + if (config == null) { + throw new InvalidParameterValueException("Unable to find load balancer config: " + id); + } + if (config.getNetworkId() != null) { + return BaseAsyncCmd.networkSyncObject; + } else if (config.getVpcId() != null) { + return BaseAsyncCmd.vpcSyncObject; + } + return null; + } + + @Override + public Long getSyncObjId() { + LoadBalancerConfig config = _entityMgr.findById(LoadBalancerConfig.class, getId()); + if (config == null) { + throw new InvalidParameterValueException("Unable to find load balancer config: " + id); + } + if (config.getNetworkId() != null) { + return config.getNetworkId(); + } else if (config.getVpcId() != null) { + return config.getVpcId(); + } + return null; + } + + @Override + public long getEntityOwnerId() { + LoadBalancerConfig config = _entityMgr.findById(LoadBalancerConfig.class, getId()); + if (config != null) { + if (config.getNetworkId() != null) { + Network network = _entityMgr.findById(Network.class, config.getNetworkId()); + if (network != null) { + return network.getAccountId(); + } + } else if (config.getVpcId() != null) { + Vpc vpc = _entityMgr.findById(Vpc.class, config.getVpcId()); + if (vpc != null) { + return vpc.getAccountId(); + } + } else if (config.getLoadBalancerId() != null) { + FirewallRule rule = _entityMgr.findById(FirewallRule.class, config.getLoadBalancerId()); + if (rule != null) { + return rule.getAccountId(); + } + } + } + throw new InvalidParameterValueException("Unable to find the entity owner"); + } + + + @Override + public String getEventType() { + return EventTypes.EVENT_LOAD_BALANCER_CONFIG_DELETE; + } + + @Override + public String getEventDescription() { + return "deleting load balancer config: " + getId(); + } + +} diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerConfigsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerConfigsCmd.java new file mode 100644 index 000000000000..e83edbaef926 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerConfigsCmd.java @@ -0,0 +1,146 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.loadbalancer; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.FirewallRuleResponse; +import org.apache.cloudstack.api.response.LoadBalancerConfigResponse; +import org.apache.cloudstack.api.response.NetworkResponse; +import org.apache.cloudstack.api.response.VpcResponse; +import org.apache.log4j.Logger; + +import com.cloud.network.rules.LoadBalancerConfig; + +@APICommand(name = "listLoadBalancerConfigs", description = "Lists load balancer configs.", + responseObject = LoadBalancerConfigResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) +public class ListLoadBalancerConfigsCmd extends BaseListCmd { + public static final Logger s_logger = Logger.getLogger(ListLoadBalancerConfigsCmd.class.getName()); + + private static final String s_name = "listloadbalancerconfigsresponse"; + + // /////////////////////////////////////////////////// + // ////////////// API parameters ///////////////////// + // /////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, + type = CommandType.UUID, + entityType = LoadBalancerConfigResponse.class, + description = "the ID of the load balancer config") + private Long id; + + @Parameter(name = ApiConstants.SCOPE, + type = CommandType.STRING, + required = true, + description = "the scope of the config: network, vpc or rule") + private String scope; + + @Parameter(name = ApiConstants.NETWORK_ID, + type = CommandType.UUID, + entityType = NetworkResponse.class, + description = "the ID of network to update") + private Long networkId; + + @Parameter(name = ApiConstants.VPC_ID, + type = CommandType.UUID, + entityType = VpcResponse.class, + description = "the ID of vpc to update") + private Long vpcId; + + @Parameter(name = ApiConstants.LOAD_BALANCER_ID, + type = CommandType.UUID, + entityType = FirewallRuleResponse.class, + description = "the ID of the load balancer rule to update") + private Long loadBalancerId; + + @Parameter(name = ApiConstants.NAME, + type = CommandType.STRING, + description = "name of the load balancer config") + private String name; + + @Parameter(name = ApiConstants.LIST_ALL, + type = CommandType.BOOLEAN, + description = "If set to true, list all available configs for the scope. Default value is false") + private Boolean listAll; + + // /////////////////////////////////////////////////// + // ///////////////// Accessors /////////////////////// + // /////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + public String getScope() { + return scope; + } + + public Long getVpcId() { + return vpcId; + } + + public Long getNetworkId() { + return networkId; + } + + public Long getLoadBalancerId() { + return loadBalancerId; + } + + public String getName() { + return name; + } + + public boolean listAll() { + return listAll == null ? false : listAll; + } + + // /////////////////////////////////////////////////// + // ///////////// API Implementation/////////////////// + // /////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public void execute() { + List configs = _lbConfigService.searchForLoadBalancerConfigs(this); + ListResponse response = new ListResponse(); + List lbConfigResponses = new ArrayList(); + if (configs != null) { + for (LoadBalancerConfig config : configs) { + LoadBalancerConfigResponse lbConfigResponse = _responseGenerator.createLoadBalancerConfigResponse(config); + lbConfigResponses.add(lbConfigResponse); + } + response.setResponses(lbConfigResponses); + } + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } + +} diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ReplaceLoadBalancerConfigsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ReplaceLoadBalancerConfigsCmd.java new file mode 100644 index 000000000000..8e997f4629a3 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ReplaceLoadBalancerConfigsCmd.java @@ -0,0 +1,181 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.loadbalancer; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.FirewallRuleResponse; +import org.apache.cloudstack.api.response.NetworkResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.api.response.VpcResponse; +import org.apache.commons.collections.MapUtils; +import org.apache.log4j.Logger; + +import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.Network; +import com.cloud.network.rules.LoadBalancerConfig; +import com.cloud.network.vpc.Vpc; + +@APICommand(name = "replaceLoadBalancerConfigs", description = "Replaces load balancer configs of vpc/network/rule", + responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) +public class ReplaceLoadBalancerConfigsCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(ReplaceLoadBalancerConfigsCmd.class.getName()); + private static final String s_name = "replaceloadbalancerconfigsresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.SCOPE, + type = CommandType.STRING, + required = true, + description = "the scope of the config: network, vpc or rule") + private String scope; + + @Parameter(name = ApiConstants.NETWORK_ID, + type = CommandType.UUID, + entityType = NetworkResponse.class, + description = "the ID of network to update") + private Long networkId; + + @Parameter(name = ApiConstants.VPC_ID, + type = CommandType.UUID, + entityType = VpcResponse.class, + description = "the ID of vpc to update") + private Long vpcId; + + @Parameter(name = ApiConstants.LOAD_BALANCER_ID, + type = CommandType.UUID, + entityType = FirewallRuleResponse.class, + description = "the ID of the load balancer rule to update") + private Long loadBalancerId; + + @Parameter(name = ApiConstants.CONFIG, + type = CommandType.MAP, + description = "configs list, Example: config[0].name=timout&config[0].value=60000") + private Map configList; + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getScope() { + return scope; + } + + public Long getVpcId() { + return vpcId; + } + + public Long getNetworkId() { + return networkId; + } + + public Long getLoadBalancerId() { + return loadBalancerId; + } + + public Map getConfigList() { + if (configList == null || configList.isEmpty()) { + return null; + } + + Map configMap = new HashMap<>(); + if (MapUtils.isNotEmpty(configList)) { + for (Map config : (Collection>)configList.values()) { + String name = config.get("name"); + String value = config.get("value"); + configMap.put(name, value); + } + } + return configMap; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public void execute() { + List configs = _lbConfigService.replaceLoadBalancerConfigs(this); + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } + + @Override + public String getSyncObjType() { + if (networkId != null) { + return BaseAsyncCmd.networkSyncObject; + } else if (vpcId != null) { + return BaseAsyncCmd.vpcSyncObject; + } + return null; + } + + @Override + public Long getSyncObjId() { + if (networkId != null) { + return networkId; + } else if (vpcId != null) { + return vpcId; + } + return null; + } + + @Override + public long getEntityOwnerId() { + if (networkId != null) { + Network network = _entityMgr.findById(Network.class, networkId); + if (network != null) { + return network.getAccountId(); + } + } else if (vpcId != null) { + Vpc vpc = _entityMgr.findById(Vpc.class, vpcId); + if (vpc != null) { + return vpc.getAccountId(); + } + } + throw new InvalidParameterValueException("Unable to find the entity owner"); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_LOAD_BALANCER_CONFIG_REPLACE; + } + + @Override + public String getEventDescription() { + return "replacing load balancer config"; + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLoadBalancerConfigCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLoadBalancerConfigCmd.java new file mode 100644 index 000000000000..97c1c1e7b026 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLoadBalancerConfigCmd.java @@ -0,0 +1,155 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.loadbalancer; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.LoadBalancerConfigResponse; +import org.apache.log4j.Logger; + +import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.Network; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.LoadBalancerConfig; +import com.cloud.network.vpc.Vpc; + +@APICommand(name = "updateLoadBalancerConfig", description = "Updates a load balancer config", + responseObject = LoadBalancerConfigResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) +public class UpdateLoadBalancerConfigCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(UpdateLoadBalancerConfigCmd.class.getName()); + private static final String s_name = "updateloadbalancerconfigresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, + type = CommandType.UUID, + entityType = LoadBalancerConfigResponse.class, + required = true, + description = "the ID of the load balancer config to update") + private Long id; + + @Parameter(name = ApiConstants.VALUE, + type = CommandType.STRING, + required = true, + description = "value of the load balancer config") + private String value; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + public String getValue() { + return value; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public void execute() { + LoadBalancerConfig result = _lbConfigService.updateLoadBalancerConfig(this); + if (result != null) { + LoadBalancerConfigResponse response = _responseGenerator.createLoadBalancerConfigResponse(result); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update load balancer config"); + } + } + + @Override + public String getSyncObjType() { + LoadBalancerConfig config = _entityMgr.findById(LoadBalancerConfig.class, getId()); + if (config == null) { + throw new InvalidParameterValueException("Unable to find load balancer config: " + id); + } + if (config.getNetworkId() != null) { + return BaseAsyncCmd.networkSyncObject; + } else if (config.getVpcId() != null) { + return BaseAsyncCmd.vpcSyncObject; + } + return null; + } + + @Override + public Long getSyncObjId() { + LoadBalancerConfig config = _entityMgr.findById(LoadBalancerConfig.class, getId()); + if (config == null) { + throw new InvalidParameterValueException("Unable to find load balancer config: " + id); + } + if (config.getNetworkId() != null) { + return config.getNetworkId(); + } else if (config.getVpcId() != null) { + return config.getVpcId(); + } + return null; + } + + @Override + public long getEntityOwnerId() { + LoadBalancerConfig config = _entityMgr.findById(LoadBalancerConfig.class, getId()); + if (config != null) { + if (config.getNetworkId() != null) { + Network network = _entityMgr.findById(Network.class, config.getNetworkId()); + if (network != null) { + return network.getAccountId(); + } + } else if (config.getVpcId() != null) { + Vpc vpc = _entityMgr.findById(Vpc.class, config.getVpcId()); + if (vpc != null) { + return vpc.getAccountId(); + } + } else if (config.getLoadBalancerId() != null) { + FirewallRule rule = _entityMgr.findById(FirewallRule.class, config.getLoadBalancerId()); + if (rule != null) { + return rule.getAccountId(); + } + } + } + throw new InvalidParameterValueException("Unable to find the entity owner"); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_LOAD_BALANCER_CONFIG_UPDATE; + } + + @Override + public String getEventDescription() { + return "updating load balancer config" + getId(); + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/response/LoadBalancerConfigResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/LoadBalancerConfigResponse.java new file mode 100644 index 000000000000..2ba96fcea84f --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/response/LoadBalancerConfigResponse.java @@ -0,0 +1,111 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.response; + +import java.util.Date; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +import com.cloud.network.rules.LoadBalancerConfig; +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +@EntityReference(value = LoadBalancerConfig.class) +@SuppressWarnings("unused") +public class LoadBalancerConfigResponse extends BaseResponse { + @SerializedName(ApiConstants.ID) + @Param(description = "the load balancer rule ID") + private String id; + + @SerializedName(ApiConstants.NAME) + @Param(description = "the name of the load balancer config") + private String name; + + @SerializedName(ApiConstants.VALUE) + @Param(description = "the value of the load balancer config") + private String value; + + @SerializedName(ApiConstants.SCOPE) + @Param(description = "the scope of the load balancer config") + private String scope; + + @SerializedName(ApiConstants.NETWORK_ID) + @Param(description = "the id of the guest network the lb config belongs to") + private String networkId; + + @SerializedName(ApiConstants.VPC_ID) + @Param(description = "the id of the vpc the lb config belongs to") + private String vpcId; + + @SerializedName(ApiConstants.LOAD_BALANCER_ID) + @Param(description = "the id of the load balancer rule the config belongs to") + private String loadBalancerId; + + @SerializedName(ApiConstants.CREATED) + @Param(description = "the date when the load balancer config is created") + private Date created; + + @SerializedName(ApiConstants.DESCRIPTION) + @Param(description = "the description of the load balancer config") + private String description; + + @SerializedName(ApiConstants.DEFAULT_VALUE) + @Param(description = "the default value of the load balancer config") + private String defaultValue; + + public void setId(String id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + + public void setValue(String value) { + this.value = value; + } + + public void setScope(String scope) { + this.scope = scope; + } + + public void setNetworkId(String networkId) { + this.networkId = networkId; + } + + public void setVpcId(String vpcId) { + this.vpcId = vpcId; + } + + public void setLoadBalancerId(String loadBalancerId) { + this.loadBalancerId = loadBalancerId; + } + + public void setCreated(Date created) { + this.created = created; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setDefaultValue(String defaultValue) { + this.defaultValue = defaultValue; + } +} diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java new file mode 100644 index 000000000000..2b34d338f807 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -0,0 +1,175 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.network.lb; + +import java.util.HashMap; +import java.util.Map; + +import com.cloud.network.rules.LoadBalancerConfig.Scope; +import com.cloud.utils.Pair; + +public enum LoadBalancerConfigKey { + + HAproxyStatsEnable(Category.Stats, Scope.Network, "haproxy.stats.enable", "HAProxy stats enable", Boolean.class, "true", "Enable or Disable HAProxy stats. To access the dashboard, please add firewall rule"), + + HAproxyStatsUri(Category.Stats, Scope.Network, "haproxy.stats.uri", "HAProxy stats URI", String.class, "/admin?stats", "URI of HAProxy stats, default is '/admin?stats'"), + + HAproxyStatsAuth(Category.Stats, Scope.Network, "haproxy.stats.auth", "HAProxy stats auth", String.class, "admin1:AdMiN123", "HAproxy stats username and password, default is 'admin1:AdMiN123'"), + + LbHttp(Category.LoadBalancer, Scope.LoadBalancerRule, "lb.http", "LB http", Boolean.class, "false", "If LB is http, default is 'true' for port 80 and 'false' for others'"), + + LbHttpKeepalive(Category.LoadBalancer, Scope.LoadBalancerRule, "lb.http.keepalive", "LB http keepalive enabled/disabled", Boolean.class, "false", "If LB http is enabled, default is 'false'"), + + LbMaxConn(Category.LoadBalancer, Scope.LoadBalancerRule, "lb.max.conn", "LB max connection", Long.class, "", "LB max connection, default is ''"), + + LbFullConn(Category.LoadBalancer, Scope.LoadBalancerRule, "lb.full.conn", "LB full connection", Long.class, "", "LB full connection, default is 'maxconn/10'"); + + public static enum Category { + General, Advanced, Stats, LoadBalancer + } + + private final Category _category; + private final Scope _scope; + private final String _key; + private final String _displayText; + private final String _description; + private final Class _type; + private final String _defaultValue; + + private LoadBalancerConfigKey(Category category, Scope scope, String key, String displayText, Class type, String defaultValue, String description) { + _category = category; + _scope = scope; + _key = key; + _displayText = displayText; + _type = type; + _defaultValue = defaultValue; + _description = description; + } + + public Category category() { + return _category; + } + + public Class type() { + return _type; + } + + public String key() { + return _key; + } + + public String displayText() { + return _displayText; + } + + public String defaultValue() { + return _defaultValue; + } + + public String description() { + return _description; + } + + public Scope scope() { + return _scope; + } + + @Override + public String toString() { + return _key; + } + + private static final HashMap> Configs = new HashMap>(); + static { + Configs.put(Scope.Network, new HashMap()); + Configs.put(Scope.Vpc, new HashMap()); + Configs.put(Scope.LoadBalancerRule, new HashMap()); + for (LoadBalancerConfigKey c : LoadBalancerConfigKey.values()) { + Scope scope = c.scope(); + Map currentConfigs = Configs.get(scope); + currentConfigs.put(c.key(), c); + Configs.put(scope, currentConfigs); + } + } + + public static Map getConfigsByScope(Scope scope) { + return Configs.get(scope); + } + + public static LoadBalancerConfigKey getConfigsByScopeAndName(Scope scope, String name) { + Map configs = Configs.get(scope); + if (configs.keySet().contains(name)) { + return configs.get(name); + } + return null; + } + + public static Scope getScopeFromString(String scope) { + if (scope == null) { + return null; + } + for (Scope offScope : Scope.values()) { + if (offScope.name().equalsIgnoreCase(scope)) { + return offScope; + } + } + return null; + } + + public static Pair validate(Scope scope, String key, String value) { + Map configs = Configs.get(scope); + if (configs == null) { + return new Pair(null, "Invalid scope " + scope); + } + LoadBalancerConfigKey config = null; + for (LoadBalancerConfigKey c : configs.values()) { + if (c.key().equals(key)) { + config = c; + break; + } + } + if (config == null) { + return new Pair(null, "Invalid key " + key); + } + if (value == null) { + return new Pair(null, "Invalid null value for parameter " + key); + } + Class type = config.type(); + String errMsg = null; + try { + if (type.equals(Integer.class)) { + errMsg = "Please enter a valid integer value for parameter " + key; + Integer.parseInt(value); + } else if (type.equals(Float.class)) { + errMsg = "Please enter a valid float value for parameter " + key; + Float.parseFloat(value); + } else if (type.equals(Long.class)) { + errMsg = "Please enter a valid long value for parameter " + key; + Long.parseLong(value); + } + } catch (final Exception e) { + // catching generic exception as some throws NullPointerException and some throws NumberFormatExcpeion + return new Pair(null, errMsg); + } + if (type.equals(Boolean.class)) { + if (!(value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false"))) { + return new Pair(null, "Please enter either 'true' or 'false' for parameter " + key); + } + } + return new Pair(config, null); + } +} diff --git a/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java b/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java index d8cc74817d7b..99c342fe28d1 100644 --- a/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java +++ b/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java @@ -19,14 +19,20 @@ package com.cloud.agent.api.routing; +import com.cloud.agent.api.to.LoadBalancerConfigTO; import com.cloud.agent.api.to.LoadBalancerTO; import com.cloud.agent.api.to.NicTO; +import com.cloud.network.rules.LoadBalancerConfig; + +import java.util.ArrayList; +import java.util.List; /** * LoadBalancerConfigCommand sends the load balancer configuration */ public class LoadBalancerConfigCommand extends NetworkElementCommand { LoadBalancerTO[] loadBalancers; + LoadBalancerConfigTO[] networkLbConfigs; public String lbStatsVisibility = "guest-network"; public String lbStatsPublicIP; /* load balancer listen on this ips for stats */ public String lbStatsPrivateIP; /* load balancer listen on this ips for stats */ @@ -72,4 +78,20 @@ public LoadBalancerTO[] getLoadBalancers() { public Long getVpcId() { return vpcId; } + + public LoadBalancerConfigTO[] getNetworkLbConfigs() { + return this.networkLbConfigs; + } + + public void setNetworkLbConfigs(List networkLbConfigs) { + if (networkLbConfigs == null) { + networkLbConfigs = new ArrayList(); + } + this.networkLbConfigs = new LoadBalancerConfigTO[networkLbConfigs.size()]; + int i = 0; + for (LoadBalancerConfig lbConfig : networkLbConfigs) { + this.networkLbConfigs[i++] = new LoadBalancerConfigTO(lbConfig); + } + } + } diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java index 839f34ac658d..2d03f2144574 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java @@ -522,6 +522,7 @@ private Answer execute(AggregationControlCommand cmd) { sb.append(c.getAggregateCommand()); } } + s_logger.debug("AggregationControlCommand configuration is :\n" + sb.toString()); // TODO replace with applyConfig with a stop on fail String cfgFileName = "VR-"+ UUID.randomUUID().toString() + ".cfg"; diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 7bf3bb8ca57f..b8526e40febb 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -27,9 +27,11 @@ import java.util.Map; import java.util.Set; +import org.apache.cloudstack.network.lb.LoadBalancerConfigKey; import org.apache.log4j.Logger; import com.cloud.agent.api.routing.LoadBalancerConfigCommand; +import com.cloud.agent.api.to.LoadBalancerConfigTO; import com.cloud.agent.api.to.LoadBalancerTO; import com.cloud.agent.api.to.LoadBalancerTO.DestinationTO; import com.cloud.agent.api.to.LoadBalancerTO.StickinessPolicyTO; @@ -50,6 +52,8 @@ public class HAProxyConfigurator implements LoadBalancerConfigurator { private static String[] defaultListen = {"listen vmops", "\tbind 0.0.0.0:9", "\toption transparent"}; + private final HashMap networkLbConfigsMap = new HashMap(); + @Override public String[] generateConfiguration(final List fwRules) { // Group the rules by publicip:publicport @@ -474,6 +478,14 @@ private List getRulesForPool(final LoadBalancerTO lbTO, final boolean ke final int publicPort = lbTO.getSrcPort(); final String algorithm = lbTO.getAlgorithm(); + final LoadBalancerConfigTO[] lbConfigs = lbTO.getLbConfigs(); + final HashMap lbConfigsMap = new HashMap(); + if (lbConfigs != null) { + for (LoadBalancerConfigTO lbConfig: lbConfigs) { + lbConfigsMap.put(lbConfig.getName(), lbConfig.getValue()); + } + } + final List result = new ArrayList(); // add line like this: "listen 65_37_141_30-80\n\tbind 65.37.141.30:80" sb = new StringBuilder(); @@ -576,6 +588,13 @@ private String generateStatsRule(final LoadBalancerConfigCommand lbCmd, final St @Override public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { + final LoadBalancerConfigTO[] networkLbConfigs = lbCmd.getNetworkLbConfigs(); + if (networkLbConfigs != null) { + for (LoadBalancerConfigTO networkLbConfig: networkLbConfigs) { + networkLbConfigsMap.put(networkLbConfig.getName(), networkLbConfig.getValue()); + } + } + final List result = new ArrayList(); final List gSection = Arrays.asList(globalSection); // note that this is overwritten on the String in the static ArrayList diff --git a/engine/components-api/src/main/java/com/cloud/network/lb/LoadBalancerConfigManager.java b/engine/components-api/src/main/java/com/cloud/network/lb/LoadBalancerConfigManager.java new file mode 100644 index 000000000000..f2ce1dd87ecc --- /dev/null +++ b/engine/components-api/src/main/java/com/cloud/network/lb/LoadBalancerConfigManager.java @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.lb; + +import java.util.List; + +import com.cloud.network.rules.LoadBalancerConfig; + +public interface LoadBalancerConfigManager { + + List getNetworkLbConfigs(Long networkId); + + List getVpcLbConfigs(Long vpcId); + + List getRuleLbConfigs(Long ruleId); +} diff --git a/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDao.java b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDao.java new file mode 100644 index 000000000000..19a318b1750e --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDao.java @@ -0,0 +1,43 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.dao; + +import java.util.List; + +import com.cloud.network.rules.LoadBalancerConfig.Scope; +import com.cloud.utils.db.GenericDao; + +public interface LoadBalancerConfigDao extends GenericDao { + + List listByNetworkId(Long networkId); + + List listByVpcId(Long vpcId); + + List listByLoadBalancerId(Long loadBalancerId); + + void removeByNetworkId(Long networkId); + + void removeByVpcId(Long vpcId); + + void removeByLoadBalancerId(Long loadBalancerId); + + LoadBalancerConfigVO findConfig(Scope scope, Long networkId, Long vpcId, Long loadBalancerId, String name); + + void addConfig(LoadBalancerConfigVO config); + + List saveConfigs(List configs); +} diff --git a/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDaoImpl.java new file mode 100644 index 000000000000..59cb53d0c819 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDaoImpl.java @@ -0,0 +1,162 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.dao; + +import java.util.ArrayList; +import java.util.List; + +import com.cloud.network.rules.LoadBalancerConfig.Scope; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.db.TransactionLegacy; + +public class LoadBalancerConfigDaoImpl extends GenericDaoBase implements LoadBalancerConfigDao { + + final SearchBuilder AllFieldsSearch; + + public LoadBalancerConfigDaoImpl() { + AllFieldsSearch = createSearchBuilder(); + AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), Op.EQ); + AllFieldsSearch.and("ids", AllFieldsSearch.entity().getId(), Op.IN); + AllFieldsSearch.and("uuid", AllFieldsSearch.entity().getUuid(), Op.EQ); + AllFieldsSearch.and("scope", AllFieldsSearch.entity().getScope(), Op.EQ); + AllFieldsSearch.and("networkId", AllFieldsSearch.entity().getNetworkId(), Op.EQ); + AllFieldsSearch.and("vpcId", AllFieldsSearch.entity().getVpcId(), Op.EQ); + AllFieldsSearch.and("loadBalancerId", AllFieldsSearch.entity().getLoadBalancerId(), Op.EQ); + AllFieldsSearch.and("name", AllFieldsSearch.entity().getName(), Op.EQ); + AllFieldsSearch.and("value", AllFieldsSearch.entity().getValue(), Op.EQ); + AllFieldsSearch.done(); + } + + @Override + public List listByNetworkId(Long networkId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("scope", Scope.Network); + sc.setParameters("networkId", networkId); + return listBy(sc); + } + + @Override + public List listByVpcId(Long vpcId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("scope", Scope.Vpc); + sc.setParameters("vpcId", vpcId); + return listBy(sc); + } + + @Override + public List listByLoadBalancerId(Long loadBalancerId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("scope", Scope.LoadBalancerRule); + sc.setParameters("loadBalancerId", loadBalancerId); + return listBy(sc); + } + + @Override + public void removeByNetworkId(Long networkId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("scope", Scope.Network); + sc.setParameters("networkId", networkId); + remove(sc); + } + + @Override + public void removeByVpcId(Long vpcId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("scope", Scope.Vpc); + sc.setParameters("vpcId", vpcId); + remove(sc); + } + + @Override + public void removeByLoadBalancerId(Long loadBalancerId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("scope", Scope.LoadBalancerRule); + sc.setParameters("loadBalancerId", loadBalancerId); + remove(sc); + } + + @Override + public LoadBalancerConfigVO findConfig(Scope scope, Long networkId, Long vpcId, Long loadBalancerId, String name) { + SearchCriteria sc = AllFieldsSearch.create(); + if (scope != null) { + sc.setParameters("scope", scope); + } + if (networkId != null) { + sc.setParameters("networkId", networkId); + } + if (vpcId != null) { + sc.setParameters("vpcId", vpcId); + } + if (loadBalancerId != null) { + sc.setParameters("loadBalancerId", loadBalancerId); + } + if (name != null) { + sc.setParameters("name", name); + } + return findOneBy(sc); + } + + @Override + public void addConfig(LoadBalancerConfigVO config) { + if (config == null) { + return; + } + LoadBalancerConfigVO existingConfig = findConfig(config.getScope(), config.getNetworkId(), config.getVpcId(), config.getLoadBalancerId(), config.getName()); + if (existingConfig != null) { + remove(existingConfig.getId()); + } + persist(config); + } + + @Override + public List saveConfigs(List configs) { + if (configs.isEmpty()) { + return new ArrayList(); + } + TransactionLegacy txn = TransactionLegacy.currentTxn(); + txn.start(); + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("scope", configs.get(0).getScope()); + Long networkId = configs.get(0).getNetworkId(); + if (networkId != null) { + sc.setParameters("networkId", networkId); + } + Long vpcId = configs.get(0).getVpcId(); + if (vpcId != null) { + sc.setParameters("vpcId", vpcId); + } + Long loadBalancerId = configs.get(0).getLoadBalancerId(); + if (loadBalancerId != null) { + sc.setParameters("loadBalancerId", loadBalancerId); + } + expunge(sc); + + List ids = new ArrayList(); + for (LoadBalancerConfigVO config : configs) { + config = persist(config); + ids.add(config.getId()); + } + txn.commit(); + + SearchCriteria sc2 = AllFieldsSearch.create(); + sc2.setParameters("ids", ids.toArray(new Object[ids.size()])); + return listBy(sc2); + } +} diff --git a/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigVO.java b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigVO.java new file mode 100644 index 000000000000..fd0690b33a07 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigVO.java @@ -0,0 +1,167 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.dao; + +import com.cloud.network.rules.LoadBalancerConfig; +import com.cloud.utils.db.GenericDao; + +import java.util.Date; +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; + +import org.apache.cloudstack.api.InternalIdentity; +import org.apache.cloudstack.network.lb.LoadBalancerConfigKey; + +@Entity +@Table(name = "load_balancer_config") +public class LoadBalancerConfigVO implements InternalIdentity, LoadBalancerConfig { + + @Id + @Column(name = "id", updatable = false, nullable = false) + private Long id; + + @Column(name = "uuid") + private String uuid; + + @Column(name = "scope") + private Scope scope; + + @Column(name = "network_id") + private Long networkId; + + @Column(name = "vpc_id") + private Long vpcId; + + @Column(name = "load_balancer_id") + private Long loadBalancerId; + + @Column(name = "name") + private String name; + + @Column(name = "value") + private String value; + + @Transient + private String defaultValue; + + @Transient + private String displayText; + + @Column(name = GenericDao.CREATED_COLUMN) + private Date created; + + @Column(name = GenericDao.REMOVED_COLUMN) + private Date removed; + + public LoadBalancerConfigVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public LoadBalancerConfigVO(Scope scope, Long networkId, Long vpcId, Long loadBalancerId, String name, String value) { + this.scope = scope; + this.networkId = networkId; + this.vpcId = vpcId; + this.loadBalancerId = loadBalancerId; + this.name = name; + this.value = value; + this.uuid = UUID.randomUUID().toString(); + } + + public LoadBalancerConfigVO(Scope scope, Long networkId, Long vpcId, Long loadBalancerId, LoadBalancerConfigKey config, String value) { + this.scope = scope; + this.networkId = networkId; + this.vpcId = vpcId; + this.loadBalancerId = loadBalancerId; + this.name = config.key(); + this.defaultValue = config.defaultValue(); + this.displayText = config.displayText(); + if (value != null) { + this.value = value; + this.uuid = UUID.randomUUID().toString(); + } + } + + // Getters + @Override + public long getId() { + return id; + } + + @Override + public String getUuid() { + return uuid; + } + + @Override + public Scope getScope() { + return scope; + } + + @Override + public Long getNetworkId() { + return networkId; + } + + @Override + public Long getVpcId() { + return vpcId; + } + + @Override + public Long getLoadBalancerId() { + return loadBalancerId; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public String getDefaultValue() { + return defaultValue; + } + + @Override + public String getDisplayText() { + return displayText; + } + + @Override + public Date getCreated() { + return created; + } + + @Override + public Date getRemoved() { + return removed; + } +} diff --git a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index 67b40101d559..da9a8896b348 100644 --- a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -124,6 +124,7 @@ + diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41310to41400.sql b/engine/schema/src/main/resources/META-INF/db/schema-41310to41400.sql index baa7bcf96178..c80f4589219c 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41310to41400.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41310to41400.sql @@ -379,3 +379,24 @@ CREATE TABLE IF NOT EXISTS `cloud`.`kubernetes_cluster_details` ( PRIMARY KEY(`id`), CONSTRAINT `fk_kubernetes_cluster_details__cluster_id` FOREIGN KEY `fk_kubernetes_cluster_details__cluster_id`(`cluster_id`) REFERENCES `kubernetes_cluster`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `cloud`.`load_balancer_config` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `uuid` varchar(40) DEFAULT NULL, + `scope` varchar(20) DEFAULT NULL COMMENT 'The scope of this config, Vpc/Network/LoadBalancer', + `network_id` bigint(20) unsigned DEFAULT NULL, + `vpc_id` bigint(20) unsigned DEFAULT NULL, + `load_balancer_id` bigint(20) unsigned DEFAULT NULL, + `name` varchar(255) NOT NULL, + `value` varchar(255) DEFAULT NULL, + `created` datetime NOT NULL COMMENT 'date created', + `removed` datetime DEFAULT NULL COMMENT 'date removed', + PRIMARY KEY (`id`), + UNIQUE KEY `id_UNIQUE` (`id`), + KEY `fk_load_balancer_config_network_id` (`network_id`), + KEY `fk_load_balancer_config_vpc_id` (`vpc_id`), + KEY `fk_load_balancer_config_loadbalancer_id` (`load_balancer_id`), + CONSTRAINT `fk_load_balancer_config_network_id` FOREIGN KEY (`network_id`) REFERENCES `networks` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_load_balancer_config_vpc_id` FOREIGN KEY (`vpc_id`) REFERENCES `vpc` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_load_balancer_config_loadbalancer_id` FOREIGN KEY (`load_balancer_id`) REFERENCES `load_balancing_rules` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index 51a5436fba54..9748ebd33190 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -87,6 +87,7 @@ import org.apache.cloudstack.api.response.LBStickinessPolicyResponse; import org.apache.cloudstack.api.response.LBStickinessResponse; import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.LoadBalancerConfigResponse; import org.apache.cloudstack.api.response.LoadBalancerResponse; import org.apache.cloudstack.api.response.ManagementServerResponse; import org.apache.cloudstack.api.response.NetworkACLItemResponse; @@ -162,6 +163,7 @@ import org.apache.cloudstack.framework.jobs.AsyncJobManager; import org.apache.cloudstack.management.ManagementServerHost; import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; +import org.apache.cloudstack.network.lb.LoadBalancerConfigKey; import org.apache.cloudstack.region.PortableIp; import org.apache.cloudstack.region.PortableIpRange; import org.apache.cloudstack.region.Region; @@ -270,6 +272,7 @@ import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.HealthCheckPolicy; import com.cloud.network.rules.LoadBalancer; +import com.cloud.network.rules.LoadBalancerConfig; import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.PortForwardingRuleVO; @@ -990,6 +993,35 @@ public LoadBalancerResponse createLoadBalancerResponse(LoadBalancer loadBalancer return lbResponse; } + @Override + public LoadBalancerConfigResponse createLoadBalancerConfigResponse(LoadBalancerConfig config) { + LoadBalancerConfigResponse response = new LoadBalancerConfigResponse(); + if (config.getUuid() != null) { + response.setId(config.getUuid()); + } + response.setName(config.getName()); + response.setValue(config.getValue()); + response.setScope(String.valueOf(config.getScope())); + if (config.getNetworkId() != null) { + response.setNetworkId(String.valueOf(config.getNetworkId())); //TODO SHOULD BE UUID + } + if (config.getVpcId() != null) { + response.setVpcId(String.valueOf(config.getVpcId())); //UUID + } + if (config.getLoadBalancerId() != null) { + response.setLoadBalancerId(String.valueOf(config.getLoadBalancerId())); //UUID + } + response.setCreated(config.getCreated()); + LoadBalancerConfigKey configKey = LoadBalancerConfigKey.getConfigsByScopeAndName(config.getScope(), config.getName()); + if (configKey == null) { + throw new CloudRuntimeException(String.format("Unable to determine the load balancer config for scope %s and name %s", config.getScope(), config.getName())); + } + response.setDescription(configKey.displayText()); + response.setDefaultValue(configKey.defaultValue()); + response.setObjectName("loadbalancerconfig"); + return response; + } + @Override public GlobalLoadBalancerResponse createGlobalLoadBalancerResponse(GlobalLoadBalancerRule globalLoadBalancerRule) { GlobalLoadBalancerResponse response = new GlobalLoadBalancerResponse(); diff --git a/server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java b/server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java new file mode 100644 index 000000000000..44414c39c24d --- /dev/null +++ b/server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java @@ -0,0 +1,339 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.lb; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.dao.LoadBalancerConfigDao; +import com.cloud.network.dao.LoadBalancerConfigVO; +import com.cloud.network.dao.LoadBalancerDao; +import com.cloud.network.dao.LoadBalancerVO; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkServiceMapDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.rules.LoadBalancerConfig; +import com.cloud.network.rules.LoadBalancerConfig.Scope; +import com.cloud.network.rules.LoadBalancerContainer.Scheme; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.utils.Pair; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.db.SearchCriteria; + +import org.apache.cloudstack.api.command.user.loadbalancer.CreateLoadBalancerConfigCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.DeleteLoadBalancerConfigCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerConfigsCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ReplaceLoadBalancerConfigsCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLoadBalancerConfigCmd; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.network.lb.LoadBalancerConfigKey; +import org.apache.log4j.Logger; + +public class LoadBalancerConfigManagerImpl extends ManagerBase implements LoadBalancerConfigService, LoadBalancerConfigManager { + private static final Logger s_logger = Logger.getLogger(LoadBalancerConfigManagerImpl.class); + + @Inject + LoadBalancerConfigDao _lbConfigDao; + @Inject + NetworkDao _networkDao; + @Inject + VpcDao _vpcDao; + @Inject + LoadBalancerDao _lbDao; + @Inject + AccountManager _accountMgr; + @Inject + LoadBalancingRulesManager _lbMgr; + @Inject + NetworkServiceMapDao _ntwkSrvcDao; + + @Override + public List searchForLoadBalancerConfigs(ListLoadBalancerConfigsCmd cmd) { + Long id = cmd.getId(); + String scopeStr = cmd.getScope(); + Long networkId = cmd.getNetworkId(); + Long vpcId = cmd.getVpcId(); + Long loadBalancerId = cmd.getLoadBalancerId(); + String name = cmd.getName(); + + if (id == null && scopeStr == null) { + throw new InvalidParameterValueException("At least one of id/scope is required"); + } + + //validate parameters + Scope scope = null; + if (scopeStr != null) { + scope = LoadBalancerConfigKey.getScopeFromString(scopeStr); + if (scope == null) { + throw new InvalidParameterValueException("Invalid scope " + scopeStr); + } + checkPermission(scope, networkId, vpcId, loadBalancerId); + } + + if (id != null) { + LoadBalancerConfigVO config = _lbConfigDao.findById(id); + if (config == null) { + throw new InvalidParameterValueException("Cannot find load balancer config by id " + id); + } + checkPermission(config); + } + + SearchCriteria sc = _lbConfigDao.createSearchCriteria(); + if (id != null) { + sc.addAnd("id", SearchCriteria.Op.EQ, id); + } + if (scope != null) { + sc.addAnd("scope", SearchCriteria.Op.EQ, scope); + } + if (networkId != null) { + sc.addAnd("networkId", SearchCriteria.Op.EQ, networkId); + } + if (vpcId != null) { + sc.addAnd("vpcId", SearchCriteria.Op.EQ, vpcId); + } + if (loadBalancerId != null) { + sc.addAnd("loadBalancerId", SearchCriteria.Op.EQ, loadBalancerId); + } + if (name != null) { + sc.addAnd("name", SearchCriteria.Op.EQ, name); + } + List configs = _lbConfigDao.search(sc, null); + + if (id == null && name == null && cmd.listAll()) { + s_logger.debug("Adding config keys for scope " + scope); + List names = new ArrayList(); + for (LoadBalancerConfigVO config : configs) { + names.add(config.getName()); + } + Map configKeys = LoadBalancerConfigKey.getConfigsByScope(scope); + for (LoadBalancerConfigKey configKey : configKeys.values()) { + if (names.contains(configKey.key())) { + continue; + } + configs.add(new LoadBalancerConfigVO(scope, null, null, null, configKey, null)); + } + } + + return configs; + } + + @Override + public LoadBalancerConfig createLoadBalancerConfig(CreateLoadBalancerConfigCmd cmd) { + String scopeStr = cmd.getScope(); + Long networkId = cmd.getNetworkId(); + Long vpcId = cmd.getVpcId(); + Long loadBalancerId = cmd.getLoadBalancerId(); + String name = cmd.getName(); + String value = cmd.getValue(); + + //validate parameters + Scope scope = LoadBalancerConfigKey.getScopeFromString(scopeStr); + if (scope == null) { + throw new InvalidParameterValueException("Invalid scope " + scopeStr); + } + Pair res = LoadBalancerConfigKey.validate(scope, name, value); + if (res.second() != null) { + throw new InvalidParameterValueException(res.second()); + } + + checkPermission(scope, networkId, vpcId, loadBalancerId); + + LoadBalancerConfigVO existingConfig = _lbConfigDao.findConfig(scope, networkId, vpcId, loadBalancerId, name); + if (existingConfig != null) { + if (cmd.isForced()) { + _lbConfigDao.remove(existingConfig.getId()); + } else { + throw new InvalidParameterValueException("config " + name + " already exists, please add forced=true or update it instead"); } + } + LoadBalancerConfigVO config = _lbConfigDao.persist(new LoadBalancerConfigVO(scope, networkId, vpcId, loadBalancerId, res.first(), value)); + + applyLbConfigsForNetwork(config.getNetworkId(), config.getVpcId(), config.getLoadBalancerId()); + + return config; + } + + @Override + public boolean deleteLoadBalancerConfig(DeleteLoadBalancerConfigCmd cmd) { + Long id = cmd.getId(); + LoadBalancerConfigVO config = _lbConfigDao.findById(id); + if (config == null) { + throw new InvalidParameterValueException("Cannot find load balancer config by id " + id); + } + checkPermission(config); + + boolean result = _lbConfigDao.remove(id); + + applyLbConfigsForNetwork(config.getNetworkId(), config.getVpcId(), config.getLoadBalancerId()); + + return result; + } + + @Override + public LoadBalancerConfig updateLoadBalancerConfig(UpdateLoadBalancerConfigCmd cmd) { + Long id = cmd.getId(); + String value = cmd.getValue(); + + LoadBalancerConfigVO config = _lbConfigDao.findById(id); + if (config == null) { + throw new InvalidParameterValueException("Cannot find load balancer config by id " + id); + } + //validate parameters + Pair res = LoadBalancerConfigKey.validate(config.getScope(), config.getName(), value); + if (res.second() != null) { + throw new InvalidParameterValueException(res.second()); + } + + checkPermission(config); + config.setValue(value); + + _lbConfigDao.update(config.getId(), config); + + applyLbConfigsForNetwork(config.getNetworkId(), config.getVpcId(), config.getLoadBalancerId()); + + return config; + } + + @Override + public List replaceLoadBalancerConfigs(ReplaceLoadBalancerConfigsCmd cmd) { + String scopeStr = cmd.getScope(); + Long networkId = cmd.getNetworkId(); + Long vpcId = cmd.getVpcId(); + Long loadBalancerId = cmd.getLoadBalancerId(); + Map configList = cmd.getConfigList(); + if (configList == null) { + throw new InvalidParameterValueException("Invalid config list"); + } + + //validate parameters + Scope scope = LoadBalancerConfigKey.getScopeFromString(scopeStr); + if (scope == null) { + throw new InvalidParameterValueException("Invalid scope " + scopeStr); + } + checkPermission(scope, networkId, vpcId, loadBalancerId); + + List configs = new ArrayList(); + for (Object obj : configList.keySet()) { + String name = String.valueOf(obj); + String value = (String) configList.get(name); + Pair res = LoadBalancerConfigKey.validate(scope, name, value); + if (res.second() != null) { + throw new InvalidParameterValueException(res.second()); + } + configs.add(new LoadBalancerConfigVO(scope, networkId, vpcId, loadBalancerId, res.first(), value)); + } + + configs = _lbConfigDao.saveConfigs(configs); + + applyLbConfigsForNetwork(networkId, vpcId, loadBalancerId); + + return configs; + } + + private void checkPermission(LoadBalancerConfigVO config) { + checkPermission(config.getScope(), config.getNetworkId(), config.getVpcId(), config.getLoadBalancerId()); + } + + private void checkPermission(Scope scope, Long networkId, Long vpcId, Long loadBalancerId) { + Account caller = CallContext.current().getCallingAccount(); + if (scope == Scope.Network) { + if (networkId == null) { + throw new InvalidParameterValueException("networkId is required"); + } + if (vpcId != null || loadBalancerId != null) { + throw new InvalidParameterValueException("vpcId and loadBalancerId should be null if scope is Network"); + } + NetworkVO network = _networkDao.findById(networkId); + if (network == null) { + throw new InvalidParameterValueException("Cannot find network by id " + networkId); + } + // Perform permission check + _accountMgr.checkAccess(caller, null, true, network); + } else if (scope == Scope.Vpc) { + if (vpcId == null) { + throw new InvalidParameterValueException("vpcId is required"); + } + if (networkId != null || loadBalancerId != null) { + throw new InvalidParameterValueException("networkId and loadBalancerId should be null if scope is Vpc"); + } + VpcVO vpc = _vpcDao.findById(vpcId); + if (vpc == null) { + throw new InvalidParameterValueException("Cannot find vpc by id " + vpcId); + } + // Perform permission check + _accountMgr.checkAccess(caller, null, true, vpc); + } else if (scope == Scope.LoadBalancerRule) { + if (loadBalancerId == null) { + throw new InvalidParameterValueException("loadBalancerId is required"); + } + if (networkId != null || vpcId != null) { + throw new InvalidParameterValueException("networkId and vpcId should be null if scope is LoadBalancerRule"); + } + LoadBalancerVO rule = _lbDao.findById(loadBalancerId); + if (rule == null) { + throw new InvalidParameterValueException("Cannot find load balancer rule by id " + loadBalancerId); + } + if (networkId != null) { + // Perform permission check + checkPermission(Scope.Network, rule.getNetworkId(), null, null); + } + } + } + + @Override + public List getNetworkLbConfigs(Long networkId) { + return _lbConfigDao.listByNetworkId(networkId); + } + + @Override + public List getVpcLbConfigs(Long vpcId) { + return _lbConfigDao.listByVpcId(vpcId); + } + + @Override + public List getRuleLbConfigs(Long loadBalancerId) { + return _lbConfigDao.listByLoadBalancerId(loadBalancerId); + } + + private void applyLbConfigsForNetwork(Long networkId, Long vpcId, Long loadBalancerId) { + if (loadBalancerId != null) { + LoadBalancerVO rule = _lbDao.findById(loadBalancerId); + networkId = rule.getNetworkId(); + } + if (!_ntwkSrvcDao.canProviderSupportServiceInNetwork(networkId, Service.Lb, Provider.VirtualRouter) && + !_ntwkSrvcDao.canProviderSupportServiceInNetwork(networkId, Service.Lb, Provider.VPCVirtualRouter)) { + s_logger.info("Lb is not supported or not provided by VirtualRouter/VpcVirtualRouter in network " + networkId); + return; + } + try { + if (!_lbMgr.applyLoadBalancersForNetwork(networkId, Scheme.Public)) { + s_logger.warn("Failed to apply LB configs of network id=" + networkId); + } + } catch (ResourceUnavailableException ex) { + s_logger.error("Failed to apply LB configs in virtual router on network: " + networkId, ex); + } + } +} diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index 4adf1406afb2..7f8a46e9449b 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -95,6 +95,7 @@ import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; +import com.cloud.network.lb.LoadBalancerConfigManager; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRuleVO; @@ -188,6 +189,9 @@ public class CommandSetupHelper { @Qualifier("networkHelper") protected NetworkHelper _networkHelper; + @Inject + private LoadBalancerConfigManager _lbConfigMgr; + public void createVmDataCommand(final VirtualRouter router, final UserVm vm, final NicVO nic, final String publicKey, final Commands cmds) { if (vm != null && router != null && nic != null) { final String serviceOffering = _serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId()).getDisplayText(); @@ -315,6 +319,7 @@ public void createApplyLoadBalancingRulesCommands(final List final List stickinessPolicies = rule.getStickinessPolicies(); final LoadBalancerTO lb = new LoadBalancerTO(uuid, srcIp, srcPort, protocol, algorithm, revoked, false, inline, destinations, stickinessPolicies); lb.setLbProtocol(lb_protocol); + lb.setLbConfigs(_lbConfigMgr.getRuleLbConfigs(rule.getId())); lbs[i++] = lb; } String routerPublicIp = null; @@ -342,6 +347,7 @@ public void createApplyLoadBalancingRulesCommands(final List final LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lbs, routerPublicIp, _routerControlHelper.getRouterIpInNetwork(guestNetworkId, router.getId()), router.getPrivateIpAddress(), _itMgr.toNicTO(nicProfile, router.getHypervisorType()), router.getVpcId(), maxconn, offering.isKeepAliveEnabled()); + cmd.setNetworkLbConfigs(_lbConfigMgr.getNetworkLbConfigs(guestNetworkId)); cmd.lbStatsVisibility = _configDao.getValue(Config.NetworkLBHaproxyStatsVisbility.key()); cmd.lbStatsUri = _configDao.getValue(Config.NetworkLBHaproxyStatsUri.key()); cmd.lbStatsAuth = _configDao.getValue(Config.NetworkLBHaproxyStatsAuth.key()); diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index ab68b6141425..11b61a522742 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -363,23 +363,28 @@ import org.apache.cloudstack.api.command.user.loadbalancer.CreateApplicationLoadBalancerCmd; import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBHealthCheckPolicyCmd; import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBStickinessPolicyCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.CreateLoadBalancerConfigCmd; import org.apache.cloudstack.api.command.user.loadbalancer.CreateLoadBalancerRuleCmd; import org.apache.cloudstack.api.command.user.loadbalancer.DeleteApplicationLoadBalancerCmd; import org.apache.cloudstack.api.command.user.loadbalancer.DeleteLBHealthCheckPolicyCmd; import org.apache.cloudstack.api.command.user.loadbalancer.DeleteLBStickinessPolicyCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.DeleteLoadBalancerConfigCmd; import org.apache.cloudstack.api.command.user.loadbalancer.DeleteLoadBalancerRuleCmd; import org.apache.cloudstack.api.command.user.loadbalancer.DeleteSslCertCmd; import org.apache.cloudstack.api.command.user.loadbalancer.ListApplicationLoadBalancersCmd; import org.apache.cloudstack.api.command.user.loadbalancer.ListLBHealthCheckPoliciesCmd; import org.apache.cloudstack.api.command.user.loadbalancer.ListLBStickinessPoliciesCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerConfigsCmd; import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRuleInstancesCmd; import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRulesCmd; import org.apache.cloudstack.api.command.user.loadbalancer.ListSslCertsCmd; import org.apache.cloudstack.api.command.user.loadbalancer.RemoveCertFromLoadBalancerCmd; import org.apache.cloudstack.api.command.user.loadbalancer.RemoveFromLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ReplaceLoadBalancerConfigsCmd; import org.apache.cloudstack.api.command.user.loadbalancer.UpdateApplicationLoadBalancerCmd; import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLBHealthCheckPolicyCmd; import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLBStickinessPolicyCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLoadBalancerConfigCmd; import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLoadBalancerRuleCmd; import org.apache.cloudstack.api.command.user.loadbalancer.UploadSslCertCmd; import org.apache.cloudstack.api.command.user.nat.CreateIpForwardingRuleCmd; @@ -2912,15 +2917,20 @@ public List> getCommands() { cmdList.add(AssignToLoadBalancerRuleCmd.class); cmdList.add(CreateLBStickinessPolicyCmd.class); cmdList.add(CreateLBHealthCheckPolicyCmd.class); + cmdList.add(CreateLoadBalancerConfigCmd.class); cmdList.add(CreateLoadBalancerRuleCmd.class); cmdList.add(DeleteLBStickinessPolicyCmd.class); cmdList.add(DeleteLBHealthCheckPolicyCmd.class); + cmdList.add(DeleteLoadBalancerConfigCmd.class); cmdList.add(DeleteLoadBalancerRuleCmd.class); cmdList.add(ListLBStickinessPoliciesCmd.class); cmdList.add(ListLBHealthCheckPoliciesCmd.class); + cmdList.add(ListLoadBalancerConfigsCmd.class); cmdList.add(ListLoadBalancerRuleInstancesCmd.class); cmdList.add(ListLoadBalancerRulesCmd.class); cmdList.add(RemoveFromLoadBalancerRuleCmd.class); + cmdList.add(ReplaceLoadBalancerConfigsCmd.class); + cmdList.add(UpdateLoadBalancerConfigCmd.class); cmdList.add(UpdateLoadBalancerRuleCmd.class); cmdList.add(CreateIpForwardingRuleCmd.class); cmdList.add(DeleteIpForwardingRuleCmd.class); diff --git a/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml b/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml index 672f7c0d4144..ab0ddcd0dac4 100644 --- a/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml +++ b/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml @@ -139,6 +139,8 @@ + + diff --git a/ui/index.html b/ui/index.html index a4ea2533e638..35dff4d36324 100644 --- a/ui/index.html +++ b/ui/index.html @@ -1935,6 +1935,7 @@

+ diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 47e9e3dd3e76..11a756a39fab 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -1265,6 +1265,7 @@ if (isVPC || isAdvancedSGZone || isSharedNetwork) { hiddenTabs.push('egressRules'); + hiddenTabs.push('lbConfigs'); } if (!isAdmin()) { @@ -1758,6 +1759,181 @@ } }, + lbConfigs: { + title: 'LB Configs', + custom: function(args) { + var context = args.context; + + return $('
').multiEdit({ + context: context, + noSelect: true, + noHeaderActionsColumn: true, + fields: { + 'displayname': { + label: 'label.name', + select: function(args) { + var config_list = []; + $.ajax({ + url: createURL('listLoadBalancerConfigs'), + data: { + listAll: true, + scope: 'Network', + networkid: args.context.networks[0].id + }, + dataType: 'json', + async: false, + success: function(json) { + var configs = json.listloadbalancerconfigsresponse.loadbalancerconfig ? + json.listloadbalancerconfigsresponse.loadbalancerconfig : []; + $(configs).each(function() { + config_list[this.name] = { + desc: this.description, + defaultvalue: this.defaultvalue + } + }); + + args.response.success({ + data: $.map(configs, function(config) { + return { + name: config.name, + description: config.name + }; + }) + }); + } + }); + args.$select.change(function() { + var name = $(this).children(':selected').val(); + var desc = config_list[name].desc; + $(this).parent().parent().find('.description').html(desc); + var dvalue = config_list[name].defaultvalue; + $(this).parent().parent().find('.defaultvalue').html(dvalue); + }); + } + }, + 'description': { + edit: false, + display: true, + label: 'label.description', + isOptional: true + }, + 'defaultvalue': { + edit: false, + display: true, + label: 'default value', + isOptional: true + }, + 'value': { + edit: true, + label: 'value', + isOptional: false + }, + 'add-rule': { + label: 'label.add', + addButton: true + } + }, + add: { + label: 'label.add', + action: function(args) { + var data = { + scope: 'Network', + name: args.data.displayname, + value: args.data.value, + forced: true, + networkid: args.context.networks[0].id + }; + + $.ajax({ + url: createURL('createLoadBalancerConfig'), + data: data, + dataType: 'json', + async: true, + success: function(json) { + var jobId = json.createloadbalancerconfigresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobId + }, + notification: { + label: 'Added load balancer config ' + args.data.displayname, + poll: pollAsyncJobResult + } + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + }, + actions: { + destroy: { + label: 'Remove load balancer config', + action: function(args) { + $.ajax({ + url: createURL('deleteLoadBalancerConfig'), + data: { + id: args.context.multiRule[0].id + }, + dataType: 'json', + async: true, + success: function(data) { + var jobID = data.deleteloadbalancerconfigresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobID + }, + notification: { + label: 'Removed load balancer config ' + args.context.multiRule[0].displayname, + poll: pollAsyncJobResult + } + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } + }, + ignoreEmptyFields: true, + dataProvider: function(args) { + $.ajax({ + url: createURL('listLoadBalancerConfigs'), + data: { + scope: 'Network', + networkid: args.context.networks[0].id + }, + dataType: 'json', + async: false, + success: function(json) { + var configs = json.listloadbalancerconfigsresponse.loadbalancerconfig ? + json.listloadbalancerconfigsresponse.loadbalancerconfig : []; + + + args.response.success({ + data: $.map(configs, function(config) { + $.extend(config, { + displayname: config.name + }); + if (this.defaultvalue == "") { + $.extend(config, { + defaultvalue: "" + }); + } + return config; + }) + }); + } + }); + } + }); + } + }, + virtualRouters: { title: "label.virtual.appliances", listView: cloudStack.sections.system.subsections.virtualRouters.sections.routerNoGroup.listView @@ -3473,6 +3649,14 @@ } }, + 'loadbalancerconfigs': { + label: 'label.configuration', + custom: { + buttonLabel: 'Configure', + action: cloudStack.uiCustom.lbConfigs() + }, + }, + 'sslcertificate': { label: 'label.update.ssl', custom: { diff --git a/ui/scripts/ui-custom/lbConfigs.js b/ui/scripts/ui-custom/lbConfigs.js new file mode 100644 index 000000000000..c95265121209 --- /dev/null +++ b/ui/scripts/ui-custom/lbConfigs.js @@ -0,0 +1,239 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +(function($, cloudStack) { + + cloudStack.uiCustom.lbConfigs = function(args) { + + // Place outer args here as local variables + // i.e, -- var dataProvider = args.dataProvider + + return function(args) { + var context = args.context; + + if (args.context.multiRules == undefined) { //LB rule is not created yet + cloudStack.dialog.notice({ + message: _l('LB configs can only be configured on a created LB rule') + }); + return; + } + + var lbId = args.context.multiRules[0].id; + + var portMultiEdit = function(args) { + return $('
').multiEdit({ + context: context, + noSelect: true, + noHeaderActionsColumn: true, + fields: { + 'displayname': { + label: 'label.name', + select: function(args) { + var config_list = []; + $.ajax({ + url: createURL('listLoadBalancerConfigs'), + data: { + listAll: true, + scope: 'LoadBalancerRule', + loadbalancerid: lbId + }, + dataType: 'json', + async: false, + success: function(json) { + var configs = json.listloadbalancerconfigsresponse.loadbalancerconfig ? + json.listloadbalancerconfigsresponse.loadbalancerconfig : []; + $(configs).each(function() { + config_list[this.name] = { + desc: this.description, + defaultvalue: this.defaultvalue + } + }); + + args.response.success({ + data: $.map(configs, function(config) { + return { + name: config.name, + description: config.name + }; + }) + }); + } + }); + args.$select.change(function() { + var name = $(this).children(':selected').val(); + var desc = config_list[name].desc; + $(this).parent().parent().find('.description').html(desc); + var dvalue = config_list[name].defaultvalue; + $(this).parent().parent().find('.defaultvalue').html(dvalue); + }); + } + }, + 'description': { + edit: false, + display: true, + label: 'label.description', + isOptional: true + }, + 'defaultvalue': { + edit: false, + display: true, + label: 'default value', + isOptional: true + }, + 'value': { + edit: true, + label: 'value', + isOptional: false + }, + 'add-rule': { + label: 'label.add', + addButton: true + } + }, + add: { + label: 'label.add', + action: function(args) { + var data = { + scope: 'LoadBalancerRule', + name: args.data.displayname, + value: args.data.value, + forced: true, + loadbalancerid: lbId + }; + + $.ajax({ + url: createURL('createLoadBalancerConfig'), + data: data, + dataType: 'json', + async: true, + success: function(json) { + var jobId = json.createloadbalancerconfigresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobId + }, + notification: { + label: 'Added load balancer config ' + args.data.displayname, + poll: pollAsyncJobResult + } + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + }, + actions: { + destroy: { + label: 'Remove load balancer config', + action: function(args) { + $.ajax({ + url: createURL('deleteLoadBalancerConfig'), + data: { + id: args.context.multiRule[0].id + }, + dataType: 'json', + async: true, + success: function(data) { + var jobID = data.deleteloadbalancerconfigresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobID + }, + notification: { + label: 'Removed load balancer config ' + args.context.multiRule[0].displayname, + poll: pollAsyncJobResult + } + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } + }, + ignoreEmptyFields: true, + dataProvider: function(args) { + $.ajax({ + url: createURL('listLoadBalancerConfigs'), + data: { + scope: 'LoadBalancerRule', + loadbalancerid: lbId + }, + dataType: 'json', + async: false, + success: function(json) { + var configs = json.listloadbalancerconfigsresponse.loadbalancerconfig ? + json.listloadbalancerconfigsresponse.loadbalancerconfig : []; + + + args.response.success({ + data: $.map(configs, function(config) { + $.extend(config, { + displayname: config.name + }); + if (config.defaultvalue == "") { + $.extend(config, { + defaultvalue: "" + }); + } + return config; + }) + }); + } + }); + } + }); + }; + + var $lbConfigsDesc = $('
' + _l('label.load.balancer') + ' ' + _l('label.configuration') + '
'); + + var $lbConfigsDialog = $('
').addClass('lb-configs'); + $lbConfigsDialog.append($lbConfigsDesc); + var $loadingOnDialog = $('
').addClass('loading-overlay'); + $lbConfigsDialog.append(portMultiEdit(context)); + + var lbConfigsDialog = $lbConfigsDialog.dialog({ + title: _l('label.load.balancer') + ' ' + _l('label.configuration'), + width: 1000, + height: 600, + draggable: true, + closeonEscape: false, + overflow: 'auto', + open: function() { + $("button").each(function() { + $(this).attr("style", "left: 400px; position: relative; margin-right: 5px; "); + }); + }, + buttons: [{ + text: _l('label.done'), + 'class': 'ok', + click: function() { + $lbConfigsDialog.dialog('destroy'); + $('.overlay').remove(); + } + }] + }); + + cloudStack.applyDefaultZindexAndOverlayOnJqueryDialogAndRemoveCloseButton($lbConfigsDialog); + } + } +}(jQuery, cloudStack)); diff --git a/ui/scripts/ui/widgets/multiEdit.js b/ui/scripts/ui/widgets/multiEdit.js index 62ca231465e3..2f6ba1e01c27 100755 --- a/ui/scripts/ui/widgets/multiEdit.js +++ b/ui/scripts/ui/widgets/multiEdit.js @@ -311,6 +311,8 @@ return true; }); $button.appendTo($td); + } else if (field.display) { + $td.append($('').html(_s(data[fieldName]))); } } From 8832d256b3ba3fb39d4821e3a802a3cf86455b50 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 19 May 2020 12:44:44 +0000 Subject: [PATCH 02/75] UI: Remove duplicated tabs for VPC routers --- ui/scripts/network.js | 76 ------------------------------------------- 1 file changed, 76 deletions(-) diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 11a756a39fab..2ad05ae79124 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -5819,7 +5819,6 @@ var hiddenTabs = []; var isRouterOwner = isAdmin(); if (!isRouterOwner) { - hiddenTabs.push("router"); hiddenTabs.push("virtualRouters"); } return hiddenTabs; @@ -5913,81 +5912,6 @@ }); } }, - router: { - title: 'label.vpc.router.details', - fields: [{ - name: { - label: 'label.name' - } - }, { - state: { - label: 'label.state' - }, - hostname: { - label: 'label.host' - }, - linklocalip: { - label: 'label.linklocal.ip' - }, - isredundantrouter: { - label: 'label.redundant.router', - converter: function(booleanValue) { - if (booleanValue == true) { - return "Yes"; - } - return "No"; - } - }, - redundantstate: { - label: 'label.redundant.state' - }, - id: { - label: 'label.id' - }, - serviceofferingname: { - label: 'label.service.offering' - }, - zonename: { - label: 'label.zone' - }, - gateway: { - label: 'label.gateway' - }, - publicip: { - label: 'label.public.ip' - }, - guestipaddress: { - label: 'label.guest.ip' - }, - dns1: { - label: 'label.dns' - }, - account: { - label: 'label.account' - }, - domain: { - label: 'label.domain' - } - }], - - dataProvider: function(args) { - $.ajax({ - url: createURL("listRouters&listAll=true&vpcid=" + args.context.vpc[0].id), - dataType: "json", - async: true, - success: function(json) { - for (var i = 0; i < json.listroutersresponse.router.length; i++) { - var item = json.listroutersresponse.router[i]; - - args.response.success({ - actionFilter: cloudStack.sections.system.routerActionFilter, - data: item - }); - } - } - }); - } - }, virtualRouters: { title: "label.virtual.routers", listView: cloudStack.sections.system.subsections.virtualRouters.sections.routerNoGroup.listView From 2f4d6132330975e031a05cba0bb553209a60238b Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 19 May 2020 15:36:31 +0000 Subject: [PATCH 03/75] LB configs: Customized LB config on VPC --- .../network/lb/LoadBalancerConfigKey.java | 6 + .../lb/LoadBalancerConfigManagerImpl.java | 22 ++- .../network/router/CommandSetupHelper.java | 6 +- ui/scripts/network.js | 175 ++++++++++++++++++ 4 files changed, 207 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index 2b34d338f807..9590eedaaf15 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -103,6 +103,12 @@ public String toString() { Map currentConfigs = Configs.get(scope); currentConfigs.put(c.key(), c); Configs.put(scope, currentConfigs); + if (scope == Scope.Network) { + scope = Scope.Vpc; + currentConfigs = Configs.get(scope); + currentConfigs.put(c.key(), c); + Configs.put(scope, currentConfigs); + } } } diff --git a/server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java b/server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java index 44414c39c24d..efd61b00f4d0 100644 --- a/server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java +++ b/server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java @@ -43,6 +43,7 @@ import com.cloud.utils.Pair; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.exception.CloudRuntimeException; import org.apache.cloudstack.api.command.user.loadbalancer.CreateLoadBalancerConfigCmd; import org.apache.cloudstack.api.command.user.loadbalancer.DeleteLoadBalancerConfigCmd; @@ -272,6 +273,9 @@ private void checkPermission(Scope scope, Long networkId, Long vpcId, Long loadB } // Perform permission check _accountMgr.checkAccess(caller, null, true, network); + if (network.getVpcId() != null) { + throw new InvalidParameterValueException("network " + network.getName() + " is a VPC tier, please add LB configs to VPC instead"); + } } else if (scope == Scope.Vpc) { if (vpcId == null) { throw new InvalidParameterValueException("vpcId is required"); @@ -323,17 +327,33 @@ private void applyLbConfigsForNetwork(Long networkId, Long vpcId, Long loadBalan LoadBalancerVO rule = _lbDao.findById(loadBalancerId); networkId = rule.getNetworkId(); } + if (networkId != null) { + applyLbConfigsForNetwork(networkId); + } else if (vpcId != null) { + List networks = _networkDao.listByVpc(vpcId); + for (NetworkVO network : networks) { + if (applyLbConfigsForNetwork(network.getId())) { + break; + } + } + } + } + + private boolean applyLbConfigsForNetwork(Long networkId) { if (!_ntwkSrvcDao.canProviderSupportServiceInNetwork(networkId, Service.Lb, Provider.VirtualRouter) && !_ntwkSrvcDao.canProviderSupportServiceInNetwork(networkId, Service.Lb, Provider.VPCVirtualRouter)) { s_logger.info("Lb is not supported or not provided by VirtualRouter/VpcVirtualRouter in network " + networkId); - return; + return false; } try { if (!_lbMgr.applyLoadBalancersForNetwork(networkId, Scheme.Public)) { s_logger.warn("Failed to apply LB configs of network id=" + networkId); + return false; } + return true; } catch (ResourceUnavailableException ex) { s_logger.error("Failed to apply LB configs in virtual router on network: " + networkId, ex); + throw new CloudRuntimeException("Failed to apply LB configs in virtual router on network: " + networkId); } } } diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index 7f8a46e9449b..63f83e4b7a15 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -347,7 +347,11 @@ public void createApplyLoadBalancingRulesCommands(final List final LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lbs, routerPublicIp, _routerControlHelper.getRouterIpInNetwork(guestNetworkId, router.getId()), router.getPrivateIpAddress(), _itMgr.toNicTO(nicProfile, router.getHypervisorType()), router.getVpcId(), maxconn, offering.isKeepAliveEnabled()); - cmd.setNetworkLbConfigs(_lbConfigMgr.getNetworkLbConfigs(guestNetworkId)); + if (router.getVpcId() != null) { + cmd.setNetworkLbConfigs(_lbConfigMgr.getVpcLbConfigs(router.getVpcId())); + } else { + cmd.setNetworkLbConfigs(_lbConfigMgr.getNetworkLbConfigs(guestNetworkId)); + } cmd.lbStatsVisibility = _configDao.getValue(Config.NetworkLBHaproxyStatsVisbility.key()); cmd.lbStatsUri = _configDao.getValue(Config.NetworkLBHaproxyStatsUri.key()); cmd.lbStatsAuth = _configDao.getValue(Config.NetworkLBHaproxyStatsAuth.key()); diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 2ad05ae79124..0de2965b07f2 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -5912,6 +5912,181 @@ }); } }, + + lbConfigs: { + title: 'LB Configs', + custom: function(args) { + var context = args.context; + + return $('
').multiEdit({ + context: context, + noSelect: true, + noHeaderActionsColumn: true, + fields: { + 'displayname': { + label: 'label.name', + select: function(args) { + var config_list = []; + $.ajax({ + url: createURL('listLoadBalancerConfigs'), + data: { + listAll: true, + scope: 'Vpc', + vpcid: args.context.vpc[0].id + }, + dataType: 'json', + async: false, + success: function(json) { + var configs = json.listloadbalancerconfigsresponse.loadbalancerconfig ? + json.listloadbalancerconfigsresponse.loadbalancerconfig : []; + $(configs).each(function() { + config_list[this.name] = { + desc: this.description, + defaultvalue: this.defaultvalue + } + }); + + args.response.success({ + data: $.map(configs, function(config) { + return { + name: config.name, + description: config.name + }; + }) + }); + } + }); + args.$select.change(function() { + var name = $(this).children(':selected').val(); + var desc = config_list[name].desc; + $(this).parent().parent().find('.description').html(desc); + var dvalue = config_list[name].defaultvalue; + $(this).parent().parent().find('.defaultvalue').html(dvalue); + }); + } + }, + 'description': { + edit: false, + display: true, + label: 'label.description', + isOptional: true + }, + 'defaultvalue': { + edit: false, + display: true, + label: 'default value', + isOptional: true + }, + 'value': { + edit: true, + label: 'value', + isOptional: false + }, + 'add-rule': { + label: 'label.add', + addButton: true + } + }, + add: { + label: 'label.add', + action: function(args) { + var data = { + scope: 'Vpc', + name: args.data.displayname, + value: args.data.value, + forced: true, + vpcid: args.context.vpc[0].id + }; + + $.ajax({ + url: createURL('createLoadBalancerConfig'), + data: data, + dataType: 'json', + async: true, + success: function(json) { + var jobId = json.createloadbalancerconfigresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobId + }, + notification: { + label: 'Added load balancer config ' + args.data.displayname, + poll: pollAsyncJobResult + } + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + }, + actions: { + destroy: { + label: 'Remove load balancer config', + action: function(args) { + $.ajax({ + url: createURL('deleteLoadBalancerConfig'), + data: { + id: args.context.multiRule[0].id + }, + dataType: 'json', + async: true, + success: function(data) { + var jobID = data.deleteloadbalancerconfigresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobID + }, + notification: { + label: 'Removed load balancer config ' + args.context.multiRule[0].displayname, + poll: pollAsyncJobResult + } + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } + }, + ignoreEmptyFields: true, + dataProvider: function(args) { + $.ajax({ + url: createURL('listLoadBalancerConfigs'), + data: { + scope: 'Vpc', + vpcid: args.context.vpc[0].id + }, + dataType: 'json', + async: false, + success: function(json) { + var configs = json.listloadbalancerconfigsresponse.loadbalancerconfig ? + json.listloadbalancerconfigsresponse.loadbalancerconfig : []; + + + args.response.success({ + data: $.map(configs, function(config) { + $.extend(config, { + displayname: config.name + }); + if (this.defaultvalue == "") { + $.extend(config, { + defaultvalue: "" + }); + } + return config; + }) + }); + } + }); + } + }); + } + }, virtualRouters: { title: "label.virtual.routers", listView: cloudStack.sections.system.subsections.virtualRouters.sections.routerNoGroup.listView From 23cd6fdca00431a13dd6aa12ba2780f77f8a3d20 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 19 May 2020 15:39:50 +0000 Subject: [PATCH 04/75] Add Network/Vpc config: haproxy.stats.enable --- core/src/main/java/com/cloud/network/HAProxyConfigurator.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index b8526e40febb..60b56b0a1a8a 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -568,6 +568,10 @@ private List getRulesForPool(final LoadBalancerTO lbTO, final boolean ke } private String generateStatsRule(final LoadBalancerConfigCommand lbCmd, final String ruleName, final String statsIp) { + String haproxyStatsEnabled = networkLbConfigsMap.get(LoadBalancerConfigKey.HAproxyStatsEnable.key()); + if (haproxyStatsEnabled != null && ! haproxyStatsEnabled.equalsIgnoreCase("true")) { + return ""; + } final StringBuilder rule = new StringBuilder("\nlisten ").append(ruleName).append("\n\tbind ").append(statsIp).append(":").append(lbCmd.lbStatsPort); // TODO DH: write test for this in both cases if (!lbCmd.keepAliveEnabled) { From f1ab7418b13e465c5bbf2d456e82d428d041fe16 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Sun, 24 May 2020 11:46:42 +0000 Subject: [PATCH 05/75] Support multiple scopes in LoadBalancerConfigKey --- .../network/lb/LoadBalancerConfigKey.java | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index 9590eedaaf15..5994fccad2ac 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -24,33 +24,33 @@ public enum LoadBalancerConfigKey { - HAproxyStatsEnable(Category.Stats, Scope.Network, "haproxy.stats.enable", "HAProxy stats enable", Boolean.class, "true", "Enable or Disable HAProxy stats. To access the dashboard, please add firewall rule"), + HAproxyStatsEnable(Category.Stats, "haproxy.stats.enable", "HAProxy stats enable", Boolean.class, "true", "Enable or Disable HAProxy stats. To access the dashboard, please add firewall rule", Scope.Network, Scope.Vpc), - HAproxyStatsUri(Category.Stats, Scope.Network, "haproxy.stats.uri", "HAProxy stats URI", String.class, "/admin?stats", "URI of HAProxy stats, default is '/admin?stats'"), + HAproxyStatsUri(Category.Stats, "haproxy.stats.uri", "HAProxy stats URI", String.class, "/admin?stats", "URI of HAProxy stats, default is '/admin?stats'", Scope.Network, Scope.Vpc), - HAproxyStatsAuth(Category.Stats, Scope.Network, "haproxy.stats.auth", "HAProxy stats auth", String.class, "admin1:AdMiN123", "HAproxy stats username and password, default is 'admin1:AdMiN123'"), + HAproxyStatsAuth(Category.Stats, "haproxy.stats.auth", "HAProxy stats auth", String.class, "admin1:AdMiN123", "HAproxy stats username and password, default is 'admin1:AdMiN123'", Scope.Network, Scope.Vpc), - LbHttp(Category.LoadBalancer, Scope.LoadBalancerRule, "lb.http", "LB http", Boolean.class, "false", "If LB is http, default is 'true' for port 80 and 'false' for others'"), + LbHttp(Category.LoadBalancer, "lb.http", "LB http", Boolean.class, "false", "If LB is http, default is 'true' for port 80 and 'false' for others'", Scope.LoadBalancerRule), - LbHttpKeepalive(Category.LoadBalancer, Scope.LoadBalancerRule, "lb.http.keepalive", "LB http keepalive enabled/disabled", Boolean.class, "false", "If LB http is enabled, default is 'false'"), + LbHttpKeepalive(Category.LoadBalancer, "lb.http.keepalive", "LB http keepalive enabled/disabled", Boolean.class, "false", "If LB http is enabled, default is 'false'", Scope.LoadBalancerRule), - LbMaxConn(Category.LoadBalancer, Scope.LoadBalancerRule, "lb.max.conn", "LB max connection", Long.class, "", "LB max connection, default is ''"), + LbMaxConn(Category.LoadBalancer, "lb.max.conn", "LB max connection", Long.class, "", "LB max connection, default is ''", Scope.LoadBalancerRule), - LbFullConn(Category.LoadBalancer, Scope.LoadBalancerRule, "lb.full.conn", "LB full connection", Long.class, "", "LB full connection, default is 'maxconn/10'"); + LbFullConn(Category.LoadBalancer, "lb.full.conn", "LB full connection", Long.class, "", "LB full connection, default is 'maxconn/10'", Scope.LoadBalancerRule); public static enum Category { General, Advanced, Stats, LoadBalancer } private final Category _category; - private final Scope _scope; + private final Scope[] _scope; private final String _key; private final String _displayText; private final String _description; private final Class _type; private final String _defaultValue; - private LoadBalancerConfigKey(Category category, Scope scope, String key, String displayText, Class type, String defaultValue, String description) { + private LoadBalancerConfigKey(Category category, String key, String displayText, Class type, String defaultValue, String description, Scope... scope) { _category = category; _scope = scope; _key = key; @@ -84,7 +84,7 @@ public String description() { return _description; } - public Scope scope() { + public Scope[] scope() { return _scope; } @@ -99,13 +99,9 @@ public String toString() { Configs.put(Scope.Vpc, new HashMap()); Configs.put(Scope.LoadBalancerRule, new HashMap()); for (LoadBalancerConfigKey c : LoadBalancerConfigKey.values()) { - Scope scope = c.scope(); - Map currentConfigs = Configs.get(scope); - currentConfigs.put(c.key(), c); - Configs.put(scope, currentConfigs); - if (scope == Scope.Network) { - scope = Scope.Vpc; - currentConfigs = Configs.get(scope); + Scope[] scopes = c.scope(); + for (Scope scope : scopes) { + Map currentConfigs = Configs.get(scope); currentConfigs.put(c.key(), c); Configs.put(scope, currentConfigs); } From c435afec2bf6acceeed18ebc13cd19a3f6a381c2 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Sun, 24 May 2020 13:09:16 +0000 Subject: [PATCH 06/75] Move networkLbConfigsMap into method --- .../cloud/network/HAProxyConfigurator.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 60b56b0a1a8a..4dc0cd58ce0f 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -52,8 +52,6 @@ public class HAProxyConfigurator implements LoadBalancerConfigurator { private static String[] defaultListen = {"listen vmops", "\tbind 0.0.0.0:9", "\toption transparent"}; - private final HashMap networkLbConfigsMap = new HashMap(); - @Override public String[] generateConfiguration(final List fwRules) { // Group the rules by publicip:publicport @@ -471,7 +469,7 @@ private String getLbSubRuleForStickiness(final LoadBalancerTO lbTO) { return sb.toString(); } - private List getRulesForPool(final LoadBalancerTO lbTO, final boolean keepAliveEnabled) { + private List getRulesForPool(final LoadBalancerTO lbTO, final boolean keepAliveEnabled, HashMap networkLbConfigsMap) { StringBuilder sb = new StringBuilder(); final String poolName = sb.append(lbTO.getSrcIp().replace(".", "_")).append('-').append(lbTO.getSrcPort()).toString(); final String publicIP = lbTO.getSrcIp(); @@ -567,7 +565,7 @@ private List getRulesForPool(final LoadBalancerTO lbTO, final boolean ke return result; } - private String generateStatsRule(final LoadBalancerConfigCommand lbCmd, final String ruleName, final String statsIp) { + private String generateStatsRule(final LoadBalancerConfigCommand lbCmd, final String ruleName, final String statsIp, HashMap networkLbConfigsMap) { String haproxyStatsEnabled = networkLbConfigsMap.get(LoadBalancerConfigKey.HAproxyStatsEnable.key()); if (haproxyStatsEnabled != null && ! haproxyStatsEnabled.equalsIgnoreCase("true")) { return ""; @@ -593,6 +591,7 @@ private String generateStatsRule(final LoadBalancerConfigCommand lbCmd, final St @Override public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { final LoadBalancerConfigTO[] networkLbConfigs = lbCmd.getNetworkLbConfigs(); + HashMap networkLbConfigsMap = new HashMap(); if (networkLbConfigs != null) { for (LoadBalancerConfigTO networkLbConfig: networkLbConfigs) { networkLbConfigsMap.put(networkLbConfig.getName(), networkLbConfig.getValue()); @@ -631,15 +630,15 @@ public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { if (!lbCmd.lbStatsVisibility.equals("disabled")) { /* new rule : listen admin_page guestip/link-local:8081 */ if (lbCmd.lbStatsVisibility.equals("global")) { - result.add(generateStatsRule(lbCmd, "stats_on_public", lbCmd.lbStatsPublicIP)); + result.add(generateStatsRule(lbCmd, "stats_on_public", lbCmd.lbStatsPublicIP, networkLbConfigsMap)); } else if (lbCmd.lbStatsVisibility.equals("guest-network")) { - result.add(generateStatsRule(lbCmd, "stats_on_guest", lbCmd.lbStatsGuestIP)); + result.add(generateStatsRule(lbCmd, "stats_on_guest", lbCmd.lbStatsGuestIP, networkLbConfigsMap)); } else if (lbCmd.lbStatsVisibility.equals("link-local")) { - result.add(generateStatsRule(lbCmd, "stats_on_private", lbCmd.lbStatsPrivateIP)); + result.add(generateStatsRule(lbCmd, "stats_on_private", lbCmd.lbStatsPrivateIP, networkLbConfigsMap)); } else if (lbCmd.lbStatsVisibility.equals("all")) { - result.add(generateStatsRule(lbCmd, "stats_on_public", lbCmd.lbStatsPublicIP)); - result.add(generateStatsRule(lbCmd, "stats_on_guest", lbCmd.lbStatsGuestIP)); - result.add(generateStatsRule(lbCmd, "stats_on_private", lbCmd.lbStatsPrivateIP)); + result.add(generateStatsRule(lbCmd, "stats_on_public", lbCmd.lbStatsPublicIP, networkLbConfigsMap)); + result.add(generateStatsRule(lbCmd, "stats_on_guest", lbCmd.lbStatsGuestIP, networkLbConfigsMap)); + result.add(generateStatsRule(lbCmd, "stats_on_private", lbCmd.lbStatsPrivateIP, networkLbConfigsMap)); } else { /* * stats will be available on the default http serving port, no @@ -659,7 +658,7 @@ public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { if (lbTO.isRevoked()) { continue; } - final List poolRules = getRulesForPool(lbTO, lbCmd.keepAliveEnabled); + final List poolRules = getRulesForPool(lbTO, lbCmd.keepAliveEnabled, networkLbConfigsMap); result.addAll(poolRules); has_listener = true; } From 9383261ba03a93727214042b551114b1014dec12 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Sun, 24 May 2020 13:54:20 +0000 Subject: [PATCH 07/75] LB configs: List all LB configs by scope (listall must be true) --- .../network/lb/LoadBalancerConfigKey.java | 7 +-- .../lb/LoadBalancerConfigManagerImpl.java | 50 +++++++++++++++---- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index 5994fccad2ac..b6f619dea95b 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.network.lb; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import com.cloud.network.rules.LoadBalancerConfig.Scope; @@ -95,9 +96,9 @@ public String toString() { private static final HashMap> Configs = new HashMap>(); static { - Configs.put(Scope.Network, new HashMap()); - Configs.put(Scope.Vpc, new HashMap()); - Configs.put(Scope.LoadBalancerRule, new HashMap()); + Configs.put(Scope.Network, new LinkedHashMap()); + Configs.put(Scope.Vpc, new LinkedHashMap()); + Configs.put(Scope.LoadBalancerRule, new LinkedHashMap()); for (LoadBalancerConfigKey c : LoadBalancerConfigKey.values()) { Scope[] scopes = c.scope(); for (Scope scope : scopes) { diff --git a/server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java b/server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java index efd61b00f4d0..341262821f7a 100644 --- a/server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java +++ b/server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java @@ -17,6 +17,7 @@ package com.cloud.network.lb; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -92,7 +93,7 @@ public List searchForLoadBalancerConfigs(ListLoadB if (scope == null) { throw new InvalidParameterValueException("Invalid scope " + scopeStr); } - checkPermission(scope, networkId, vpcId, loadBalancerId); + checkPermission(scope, networkId, vpcId, loadBalancerId, cmd.listAll()); } if (id != null) { @@ -103,6 +104,12 @@ public List searchForLoadBalancerConfigs(ListLoadB checkPermission(config); } + if (cmd.listAll()) { + if (id != null || name != null) { + throw new InvalidParameterValueException("id and name must be null if listall is true"); + } + } + SearchCriteria sc = _lbConfigDao.createSearchCriteria(); if (id != null) { sc.addAnd("id", SearchCriteria.Op.EQ, id); @@ -122,24 +129,29 @@ public List searchForLoadBalancerConfigs(ListLoadB if (name != null) { sc.addAnd("name", SearchCriteria.Op.EQ, name); } - List configs = _lbConfigDao.search(sc, null); - - if (id == null && name == null && cmd.listAll()) { + List configs = new ArrayList(); + if (id != null || networkId != null || vpcId != null || loadBalancerId != null) { + configs = _lbConfigDao.search(sc, null); + } + if (cmd.listAll()) { s_logger.debug("Adding config keys for scope " + scope); - List names = new ArrayList(); + Map configsMap = new LinkedHashMap(); for (LoadBalancerConfigVO config : configs) { - names.add(config.getName()); + configsMap.put(config.getName(), config); } + List result = new ArrayList(); Map configKeys = LoadBalancerConfigKey.getConfigsByScope(scope); for (LoadBalancerConfigKey configKey : configKeys.values()) { - if (names.contains(configKey.key())) { - continue; + if (configsMap.get(configKey.key()) != null) { + result.add(configsMap.get(configKey.key())); + } else { + result.add(new LoadBalancerConfigVO(scope, null, null, null, configKey, null)); } - configs.add(new LoadBalancerConfigVO(scope, null, null, null, configKey, null)); } + return result; + } else { + return configs; } - - return configs; } @Override @@ -259,14 +271,24 @@ private void checkPermission(LoadBalancerConfigVO config) { } private void checkPermission(Scope scope, Long networkId, Long vpcId, Long loadBalancerId) { + checkPermission(scope, networkId, vpcId, loadBalancerId, false); + } + + private void checkPermission(Scope scope, Long networkId, Long vpcId, Long loadBalancerId, Boolean listAll) { Account caller = CallContext.current().getCallingAccount(); if (scope == Scope.Network) { if (networkId == null) { + if (listAll) { + return; + } throw new InvalidParameterValueException("networkId is required"); } if (vpcId != null || loadBalancerId != null) { throw new InvalidParameterValueException("vpcId and loadBalancerId should be null if scope is Network"); } + if (networkId == null) { + throw new InvalidParameterValueException("networkId is required"); + } NetworkVO network = _networkDao.findById(networkId); if (network == null) { throw new InvalidParameterValueException("Cannot find network by id " + networkId); @@ -278,6 +300,9 @@ private void checkPermission(Scope scope, Long networkId, Long vpcId, Long loadB } } else if (scope == Scope.Vpc) { if (vpcId == null) { + if (listAll) { + return; + } throw new InvalidParameterValueException("vpcId is required"); } if (networkId != null || loadBalancerId != null) { @@ -291,6 +316,9 @@ private void checkPermission(Scope scope, Long networkId, Long vpcId, Long loadB _accountMgr.checkAccess(caller, null, true, vpc); } else if (scope == Scope.LoadBalancerRule) { if (loadBalancerId == null) { + if (listAll) { + return; + } throw new InvalidParameterValueException("loadBalancerId is required"); } if (networkId != null || vpcId != null) { From d19076e1c0c0adc509762173e3529a4b8d58e2cd Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 26 May 2020 13:45:58 +0000 Subject: [PATCH 08/75] LB configs: Add timeout for global/lb --- .../network/lb/LoadBalancerConfigKey.java | 6 ++++ .../cloud/network/HAProxyConfigurator.java | 32 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index b6f619dea95b..4099e95d99f5 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -31,6 +31,12 @@ public enum LoadBalancerConfigKey { HAproxyStatsAuth(Category.Stats, "haproxy.stats.auth", "HAProxy stats auth", String.class, "admin1:AdMiN123", "HAproxy stats username and password, default is 'admin1:AdMiN123'", Scope.Network, Scope.Vpc), + TimeoutConnect(Category.General, "timeout.connect", "Maximum time (in ms) to wait for a connection to succeed", Long.class, "5000", "Set the maximum time to wait for a connection attempt to a server to succeed.", Scope.Network, Scope.Vpc, Scope.LoadBalancerRule), + + TimeoutServer(Category.General, "timeout.server", "Maximum inactivity time (in ms) on server side", Long.class, "50000", "Set the maximum inactivity time on the server side.", Scope.Network, Scope.Vpc, Scope.LoadBalancerRule), + + TimeoutClient(Category.General, "timeout.client", "Maximum inactivity time (in ms) on client side", Long.class, "50000", "Set the maximum inactivity time on the client side.", Scope.Network, Scope.Vpc, Scope.LoadBalancerRule), + LbHttp(Category.LoadBalancer, "lb.http", "LB http", Boolean.class, "false", "If LB is http, default is 'true' for port 80 and 'false' for others'", Scope.LoadBalancerRule), LbHttpKeepalive(Category.LoadBalancer, "lb.http.keepalive", "LB http keepalive enabled/disabled", Boolean.class, "false", "If LB http is enabled, default is 'false'", Scope.LoadBalancerRule), diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 4dc0cd58ce0f..2aa0c7b61a24 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -496,6 +496,25 @@ private List getRulesForPool(final LoadBalancerTO lbTO, final boolean ke sb.append("\t").append("balance ").append(algorithm); result.add(sb.toString()); + String timeoutConnect = lbConfigsMap.get(LoadBalancerConfigKey.TimeoutConnect.key()); + if (timeoutConnect != null) { + sb = new StringBuilder(); + sb.append("\t").append("timeout connect " + timeoutConnect); + result.add(sb.toString()); + } + String timeoutClient = lbConfigsMap.get(LoadBalancerConfigKey.TimeoutClient.key()); + if (timeoutClient != null) { + sb = new StringBuilder(); + sb.append("\t").append("timeout client " + timeoutClient); + result.add(sb.toString()); + } + String timeoutServer = lbConfigsMap.get(LoadBalancerConfigKey.TimeoutServer.key()); + if (timeoutServer != null) { + sb = new StringBuilder(); + sb.append("\t").append("timeout server " + timeoutServer); + result.add(sb.toString()); + } + int i = 0; Boolean destsAvailable = false; final String stickinessSubRule = getLbSubRuleForStickiness(lbTO); @@ -621,6 +640,19 @@ public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { dSection.set(7, "\tno option forceclose"); } + String timeoutConnect = networkLbConfigsMap.get(LoadBalancerConfigKey.TimeoutConnect.key()); + if (timeoutConnect != null) { + dSection.set(8, "\ttimeout connect " + timeoutConnect); + } + String timeoutClient = networkLbConfigsMap.get(LoadBalancerConfigKey.TimeoutClient.key()); + if (timeoutClient != null) { + dSection.set(9, "\ttimeout client " + timeoutClient); + } + String timeoutServer = networkLbConfigsMap.get(LoadBalancerConfigKey.TimeoutServer.key()); + if (timeoutServer != null) { + dSection.set(10, "\ttimeout server " + timeoutServer); + } + if (s_logger.isDebugEnabled()) { for (final String s : dSection) { s_logger.debug("default section: " + s); From 67b43db9a56af652d0a672c1581df54e34ff8ce3 Mon Sep 17 00:00:00 2001 From: Rakesh Venkatesh Date: Thu, 28 May 2020 09:02:18 +0000 Subject: [PATCH 09/75] LB configs: Add loadbalancer connections settings --- .../network/lb/LoadBalancerConfigKey.java | 14 +++++- .../cloud/network/HAProxyConfigurator.java | 47 +++++++++++++++++-- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index 4099e95d99f5..d9f0a426af5a 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -41,9 +41,19 @@ public enum LoadBalancerConfigKey { LbHttpKeepalive(Category.LoadBalancer, "lb.http.keepalive", "LB http keepalive enabled/disabled", Boolean.class, "false", "If LB http is enabled, default is 'false'", Scope.LoadBalancerRule), - LbMaxConn(Category.LoadBalancer, "lb.max.conn", "LB max connection", Long.class, "", "LB max connection, default is ''", Scope.LoadBalancerRule), + GlobalMaxConn(Category.LoadBalancer, "global.maxconn", "LB max connection", Long.class, "4096", "Maximum per process number of concurrent connections, default is '4096'", Scope.Network, Scope.Vpc), - LbFullConn(Category.LoadBalancer, "lb.full.conn", "LB full connection", Long.class, "", "LB full connection, default is 'maxconn/10'", Scope.LoadBalancerRule); + GlobalMaxPipes(Category.LoadBalancer, "global.maxpipes", "LB max pipes", Long.class, "", "Maximum number of per process pipes, default is 'maxconn/4'", Scope.Network, Scope.Vpc), + + LbMaxConn(Category.LoadBalancer, "lb.maxconn", "LB max connection", Long.class, "", "Maximum per process number of concurrent connections per site/vm", Scope.LoadBalancerRule), + + LbFullConn(Category.LoadBalancer, "lb.fullconn", "LB full connection", Long.class, "", "Specify at what backend load the servers will reach their maxconn, default is 'maxconn/10'", Scope.LoadBalancerRule), + + LbServerMaxConn(Category.LoadBalancer, "lb.server.maxconn", "LB max connection per site/vm", Long.class, "", "LB max connection per site/vm, default is ''", Scope.LoadBalancerRule), + + LbServerMinConn(Category.LoadBalancer, "lb.server.minconn", "LB minimum connection", Long.class, "", "LB minimum connection per site/vm, default is ''", Scope.LoadBalancerRule), + + LbServerMaxQueue(Category.LoadBalancer, "lb.server.maxqueue", "LB max queue", Long.class, "", "Maximum number of connections which will wait in queue for this server, default is ''", Scope.LoadBalancerRule); public static enum Category { General, Advanced, Stats, LoadBalancer diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 2aa0c7b61a24..89a66f378a74 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -515,6 +515,23 @@ private List getRulesForPool(final LoadBalancerTO lbTO, final boolean ke result.add(sb.toString()); } + if (lbConfigsMap.get(LoadBalancerConfigKey.LbMaxConn.key()) != null) { + long maxConnValue = Long.parseLong(lbConfigsMap.get(LoadBalancerConfigKey.LbMaxConn.key())); + if (maxConnValue > 0) { + sb = new StringBuilder(); + sb.append("\tmaxconn ").append(maxConnValue); + result.add(sb.toString()); + } + } + if (lbConfigsMap.get(LoadBalancerConfigKey.LbFullConn.key()) != null) { + long fullConnValue = Long.parseLong(lbConfigsMap.get(LoadBalancerConfigKey.LbFullConn.key())); + if (fullConnValue > 0) { + sb = new StringBuilder(); + sb.append("\tfullconn ").append(fullConnValue); + result.add(sb.toString()); + } + } + int i = 0; Boolean destsAvailable = false; final String stickinessSubRule = getLbSubRuleForStickiness(lbTO); @@ -536,6 +553,25 @@ private List getRulesForPool(final LoadBalancerTO lbTO, final boolean ke .append(":") .append(dest.getDestPort()) .append(" check"); + + if (lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxConn.key()) != null) { + long maxConnEach = Long.parseLong(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxConn.key())); + if (maxConnEach > 0) { + sb.append(" maxconn ").append(maxConnEach); + } + } + if (lbConfigsMap.get(LoadBalancerConfigKey.LbServerMinConn.key()) != null) { + long minConnEach = Long.parseLong(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMinConn.key())); + if (minConnEach > 0) { + sb.append(" minconn ").append(minConnEach); + } + } + if (lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxQueue.key()) != null) { + long maxQueueEach = Long.parseLong(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxQueue.key())); + if (maxQueueEach > 0) { + sb.append(" maxqueue ").append(maxQueueEach); + } + } if(lbTO.getLbProtocol() != null && lbTO.getLbProtocol().equals("tcp-proxy")) { sb.append(" send-proxy"); } @@ -620,10 +656,15 @@ public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { final List result = new ArrayList(); final List gSection = Arrays.asList(globalSection); // note that this is overwritten on the String in the static ArrayList - gSection.set(2, "\tmaxconn " + lbCmd.maxconn); + String maxconn = networkLbConfigsMap.get(LoadBalancerConfigKey.GlobalMaxConn.key()) != null ? + networkLbConfigsMap.get(LoadBalancerConfigKey.GlobalMaxConn.key()) : + lbCmd.maxconn; + gSection.set(2, "\tmaxconn " + maxconn); // TODO DH: write test for this function - final String pipesLine = "\tmaxpipes " + Long.toString(Long.parseLong(lbCmd.maxconn) / 4); - gSection.set(3, pipesLine); + final String maxPipes = networkLbConfigsMap.get(LoadBalancerConfigKey.GlobalMaxPipes.key()) != null ? + networkLbConfigsMap.get(LoadBalancerConfigKey.GlobalMaxPipes.key()) : + Long.toString(Long.parseLong(maxconn) / 4); + gSection.set(3, "\tmaxpipes " + maxPipes); if (s_logger.isDebugEnabled()) { for (final String s : gSection) { s_logger.debug("global section: " + s); From af6ab20c1e8f113de49c926ce0fcb37872d6b4e4 Mon Sep 17 00:00:00 2001 From: Ahmed Raafat Date: Wed, 27 May 2020 17:34:14 +0200 Subject: [PATCH 10/75] LB configs: customized load balancer configuration for lb http/keepalive --- .../com/cloud/network/HAProxyConfigurator.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 89a66f378a74..873a3384d8de 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -607,10 +607,22 @@ private List getRulesForPool(final LoadBalancerTO lbTO, final boolean ke if (stickinessSubRule != null && !destsAvailable) { s_logger.warn("Haproxy stickiness policy for lb rule: " + lbTO.getSrcIp() + ":" + lbTO.getSrcPort() + ": Not Applied, cause: backends are unavailable"); } - if (publicPort == NetUtils.HTTP_PORT && !keepAliveEnabled || httpbasedStickiness) { + Boolean http = false; + String cfgHttp = lbConfigsMap.get(LoadBalancerConfigKey.LbHttp.key()); + if (publicPort == NetUtils.HTTP_PORT && cfgHttp == null) { + http = true; + } else if (cfgHttp != null && cfgHttp.equalsIgnoreCase("true")) { + http = true; + } + if (http || httpbasedStickiness) { sb = new StringBuilder(); sb.append("\t").append("mode http"); result.add(sb.toString()); + } + + String cfgKeepalive = lbConfigsMap.get(LoadBalancerConfigKey.LbHttpKeepalive.key()); + Boolean keepalive = cfgKeepalive != null && cfgKeepalive.equalsIgnoreCase("true"); + if ((http && !keepalive) || httpbasedStickiness) { sb = new StringBuilder(); sb.append("\t").append("option httpclose"); result.add(sb.toString()); From 4a35ee2af96e0eb52050c03d40181f123ae1d763 Mon Sep 17 00:00:00 2001 From: Rakesh Venkatesh Date: Thu, 28 May 2020 12:03:30 +0200 Subject: [PATCH 11/75] Fix build error --- .../cloud/network/HAProxyConfigurator.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 873a3384d8de..9e104532b85f 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -469,7 +469,7 @@ private String getLbSubRuleForStickiness(final LoadBalancerTO lbTO) { return sb.toString(); } - private List getRulesForPool(final LoadBalancerTO lbTO, final boolean keepAliveEnabled, HashMap networkLbConfigsMap) { + private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliveEnabled, HashMap networkLbConfigsMap) { StringBuilder sb = new StringBuilder(); final String poolName = sb.append(lbTO.getSrcIp().replace(".", "_")).append('-').append(lbTO.getSrcPort()).toString(); final String publicIP = lbTO.getSrcIp(); @@ -607,22 +607,23 @@ private List getRulesForPool(final LoadBalancerTO lbTO, final boolean ke if (stickinessSubRule != null && !destsAvailable) { s_logger.warn("Haproxy stickiness policy for lb rule: " + lbTO.getSrcIp() + ":" + lbTO.getSrcPort() + ": Not Applied, cause: backends are unavailable"); } - Boolean http = false; - String cfgHttp = lbConfigsMap.get(LoadBalancerConfigKey.LbHttp.key()); - if (publicPort == NetUtils.HTTP_PORT && cfgHttp == null) { + boolean http = false; + String cfgLbHttp = lbConfigsMap.get(LoadBalancerConfigKey.LbHttp.key()); + if (publicPort == NetUtils.HTTP_PORT && cfgLbHttp == null) { http = true; - } else if (cfgHttp != null && cfgHttp.equalsIgnoreCase("true")) { + } else if (cfgLbHttp != null && cfgLbHttp.equalsIgnoreCase("true")) { http = true; } - if (http || httpbasedStickiness) { + + String cfgLbHttpKeepalive = lbConfigsMap.get(LoadBalancerConfigKey.LbHttpKeepalive.key()); + if (cfgLbHttpKeepalive != null && cfgLbHttpKeepalive.equalsIgnoreCase("true")) { + keepAliveEnabled = true; + } + + if ((http && !keepAliveEnabled) || httpbasedStickiness) { sb = new StringBuilder(); sb.append("\t").append("mode http"); result.add(sb.toString()); - } - - String cfgKeepalive = lbConfigsMap.get(LoadBalancerConfigKey.LbHttpKeepalive.key()); - Boolean keepalive = cfgKeepalive != null && cfgKeepalive.equalsIgnoreCase("true"); - if ((http && !keepalive) || httpbasedStickiness) { sb = new StringBuilder(); sb.append("\t").append("option httpclose"); result.add(sb.toString()); From c759f69d8e7fe3c09d6811447677042d47a89fa1 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Thu, 28 May 2020 14:29:23 +0000 Subject: [PATCH 12/75] Set keepAliveEnabled to false if lb.http.keepalive is false --- core/src/main/java/com/cloud/network/HAProxyConfigurator.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 9e104532b85f..6201dcb1b3c4 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -618,6 +618,8 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv String cfgLbHttpKeepalive = lbConfigsMap.get(LoadBalancerConfigKey.LbHttpKeepalive.key()); if (cfgLbHttpKeepalive != null && cfgLbHttpKeepalive.equalsIgnoreCase("true")) { keepAliveEnabled = true; + } else if (cfgLbHttpKeepalive != null && cfgLbHttpKeepalive.equalsIgnoreCase("false")) { + keepAliveEnabled = false; } if ((http && !keepAliveEnabled) || httpbasedStickiness) { From ffa0a9a105600d740eb6ab6f89dd0443c00a9d04 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Thu, 28 May 2020 16:36:35 +0000 Subject: [PATCH 13/75] VR: compare list instead of set in CsFile.py --- systemvm/debian/opt/cloud/bin/cs/CsFile.py | 5 +++++ systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/systemvm/debian/opt/cloud/bin/cs/CsFile.py b/systemvm/debian/opt/cloud/bin/cs/CsFile.py index 2ee631a89d60..d5fe2b8ca94d 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsFile.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsFile.py @@ -178,3 +178,8 @@ def compare(self, o): result = (isinstance(o, self.__class__) and set(self.config) == set(o.config)) logging.debug("Comparison of CsFiles content is ==> %s" % result) return result + + def compareOrder(self, o): + result = (isinstance(o, self.__class__) and list(self.config) == list(o.config)) + logging.debug("Comparison of CsFiles content (and order) is ==> %s" % result) + return result diff --git a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py index a45d57efe790..d12aa853ed3d 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py @@ -42,7 +42,7 @@ def process(self): file1.commit() file2 = CsFile(HAPROXY_CONF_P) - if not file2.compare(file1): + if not file2.compareOrder(file1): CsHelper.copy(HAPROXY_CONF_T, HAPROXY_CONF_P) proc = CsProcess(['/run/haproxy.pid']) From 7c4da09cfb18c81860a44f85308951e61bb73839 Mon Sep 17 00:00:00 2001 From: Sina Kashipazha Date: Thu, 28 May 2020 17:47:38 +0200 Subject: [PATCH 14/75] LB configs: Add haproxy stats --- .../network/lb/LoadBalancerConfigKey.java | 6 ++-- .../cloud/network/HAProxyConfigurator.java | 30 +++++++++++++------ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index d9f0a426af5a..71cf9f604833 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -25,11 +25,11 @@ public enum LoadBalancerConfigKey { - HAproxyStatsEnable(Category.Stats, "haproxy.stats.enable", "HAProxy stats enable", Boolean.class, "true", "Enable or Disable HAProxy stats. To access the dashboard, please add firewall rule", Scope.Network, Scope.Vpc), + LbStatsEnable(Category.Stats, "lb.stats.enable", "LB stats enable", Boolean.class, "true", "Enable statistics reporting with default settings, default is 'true'", Scope.Network, Scope.Vpc), - HAproxyStatsUri(Category.Stats, "haproxy.stats.uri", "HAProxy stats URI", String.class, "/admin?stats", "URI of HAProxy stats, default is '/admin?stats'", Scope.Network, Scope.Vpc), + LbStatsUri(Category.Stats, "lb.stats.uri", "LB stats URI", String.class, "/admin?stats", "Enable statistics and define the URI prefix to access them, default is '/admin?stats'", Scope.Network, Scope.Vpc), - HAproxyStatsAuth(Category.Stats, "haproxy.stats.auth", "HAProxy stats auth", String.class, "admin1:AdMiN123", "HAproxy stats username and password, default is 'admin1:AdMiN123'", Scope.Network, Scope.Vpc), + LbStatsAuth(Category.Stats, "lb.stats.auth", "LB stats auth", String.class, "admin1:AdMiN123", "Enable statistics with authentication and grant access to an account, default is 'admin1:AdMiN123'", Scope.Network, Scope.Vpc), TimeoutConnect(Category.General, "timeout.connect", "Maximum time (in ms) to wait for a connection to succeed", Long.class, "5000", "Set the maximum time to wait for a connection attempt to a server to succeed.", Scope.Network, Scope.Vpc, Scope.LoadBalancerRule), diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 6201dcb1b3c4..b3599d461255 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.Optional; import org.apache.cloudstack.network.lb.LoadBalancerConfigKey; import org.apache.log4j.Logger; @@ -636,21 +637,28 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv } private String generateStatsRule(final LoadBalancerConfigCommand lbCmd, final String ruleName, final String statsIp, HashMap networkLbConfigsMap) { - String haproxyStatsEnabled = networkLbConfigsMap.get(LoadBalancerConfigKey.HAproxyStatsEnable.key()); - if (haproxyStatsEnabled != null && ! haproxyStatsEnabled.equalsIgnoreCase("true")) { + String lbStatsEnable = networkLbConfigsMap.get(LoadBalancerConfigKey.LbStatsEnable.key()); + if ( lbStatsEnable != null && ! lbStatsEnable.equalsIgnoreCase("true")) { return ""; } + final StringBuilder rule = new StringBuilder("\nlisten ").append(ruleName).append("\n\tbind ").append(statsIp).append(":").append(lbCmd.lbStatsPort); + // TODO DH: write test for this in both cases if (!lbCmd.keepAliveEnabled) { s_logger.info("Haproxy mode http enabled"); rule.append("\n\tmode http\n\toption httpclose"); } + + Optional lbStatsUri = Optional.of(networkLbConfigsMap.get(LoadBalancerConfigKey.LbStatsUri.key())); + Optional lbStatsAuth = Optional.of(networkLbConfigsMap.get(LoadBalancerConfigKey.LbStatsAuth.key())); + rule.append("\n\tstats enable\n\tstats uri ") - .append(lbCmd.lbStatsUri) - .append("\n\tstats realm Haproxy\\ Statistics\n\tstats auth ") - .append(lbCmd.lbStatsAuth); - rule.append("\n"); + .append(lbStatsUri.orElse(lbCmd.lbStatsUri)) + .append("\n\tstats realm Haproxy\\ Statistics\n\tstats auth ") + .append(lbStatsAuth.orElse(lbCmd.lbStatsAuth)) + .append("\n"); + final String result = rule.toString(); if (s_logger.isDebugEnabled()) { s_logger.debug("Haproxystats rule: " + result); @@ -732,10 +740,14 @@ public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { * stats will be available on the default http serving port, no * special stats port */ - final StringBuilder subRule = - new StringBuilder("\tstats enable\n\tstats uri ").append(lbCmd.lbStatsUri) + + Optional lbStatsUri = Optional.of(networkLbConfigsMap.get(LoadBalancerConfigKey.LbStatsUri.key())); + Optional lbStatsAuth = Optional.of(networkLbConfigsMap.get(LoadBalancerConfigKey.LbStatsAuth.key())); + + final StringBuilder subRule = new StringBuilder("\tstats enable\n\tstats uri ") + .append(lbStatsUri.orElse(lbCmd.lbStatsUri)) .append("\n\tstats realm Haproxy\\ Statistics\n\tstats auth ") - .append(lbCmd.lbStatsAuth); + .append(lbStatsAuth.orElse(lbCmd.lbStatsAuth)); result.add(subRule.toString()); } From bfa64dafaa3c7f26fea81d6b7247337b82f303d2 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Thu, 28 May 2020 18:31:08 +0000 Subject: [PATCH 15/75] Use Optional.ofNullable instead of Optional.of to fix NPE --- .../main/java/com/cloud/network/HAProxyConfigurator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index b3599d461255..0e255cbe9668 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -650,8 +650,8 @@ private String generateStatsRule(final LoadBalancerConfigCommand lbCmd, final St rule.append("\n\tmode http\n\toption httpclose"); } - Optional lbStatsUri = Optional.of(networkLbConfigsMap.get(LoadBalancerConfigKey.LbStatsUri.key())); - Optional lbStatsAuth = Optional.of(networkLbConfigsMap.get(LoadBalancerConfigKey.LbStatsAuth.key())); + Optional lbStatsUri = Optional.ofNullable(networkLbConfigsMap.get(LoadBalancerConfigKey.LbStatsUri.key())); + Optional lbStatsAuth = Optional.ofNullable(networkLbConfigsMap.get(LoadBalancerConfigKey.LbStatsAuth.key())); rule.append("\n\tstats enable\n\tstats uri ") .append(lbStatsUri.orElse(lbCmd.lbStatsUri)) @@ -741,8 +741,8 @@ public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { * special stats port */ - Optional lbStatsUri = Optional.of(networkLbConfigsMap.get(LoadBalancerConfigKey.LbStatsUri.key())); - Optional lbStatsAuth = Optional.of(networkLbConfigsMap.get(LoadBalancerConfigKey.LbStatsAuth.key())); + Optional lbStatsUri = Optional.ofNullable(networkLbConfigsMap.get(LoadBalancerConfigKey.LbStatsUri.key())); + Optional lbStatsAuth = Optional.ofNullable(networkLbConfigsMap.get(LoadBalancerConfigKey.LbStatsAuth.key())); final StringBuilder subRule = new StringBuilder("\tstats enable\n\tstats uri ") .append(lbStatsUri.orElse(lbCmd.lbStatsUri)) From 3d0e0123267f975d1c779d7b8bdae0c4f656c4d9 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 29 May 2020 06:07:16 +0000 Subject: [PATCH 16/75] Rename timeout to lb.timeout --- .../cloudstack/network/lb/LoadBalancerConfigKey.java | 6 +++--- .../java/com/cloud/network/HAProxyConfigurator.java | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index 71cf9f604833..100b2757c619 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -31,11 +31,11 @@ public enum LoadBalancerConfigKey { LbStatsAuth(Category.Stats, "lb.stats.auth", "LB stats auth", String.class, "admin1:AdMiN123", "Enable statistics with authentication and grant access to an account, default is 'admin1:AdMiN123'", Scope.Network, Scope.Vpc), - TimeoutConnect(Category.General, "timeout.connect", "Maximum time (in ms) to wait for a connection to succeed", Long.class, "5000", "Set the maximum time to wait for a connection attempt to a server to succeed.", Scope.Network, Scope.Vpc, Scope.LoadBalancerRule), + LbTimeoutConnect(Category.General, "lb.timeout.connect", "Maximum time (in ms) to wait for a connection to succeed", Long.class, "5000", "Set the maximum time to wait for a connection attempt to a server to succeed.", Scope.Network, Scope.Vpc, Scope.LoadBalancerRule), - TimeoutServer(Category.General, "timeout.server", "Maximum inactivity time (in ms) on server side", Long.class, "50000", "Set the maximum inactivity time on the server side.", Scope.Network, Scope.Vpc, Scope.LoadBalancerRule), + LbTimeoutServer(Category.General, "lb.timeout.server", "Maximum inactivity time (in ms) on server side", Long.class, "50000", "Set the maximum inactivity time on the server side.", Scope.Network, Scope.Vpc, Scope.LoadBalancerRule), - TimeoutClient(Category.General, "timeout.client", "Maximum inactivity time (in ms) on client side", Long.class, "50000", "Set the maximum inactivity time on the client side.", Scope.Network, Scope.Vpc, Scope.LoadBalancerRule), + LbTimeoutClient(Category.General, "lb.timeout.client", "Maximum inactivity time (in ms) on client side", Long.class, "50000", "Set the maximum inactivity time on the client side.", Scope.Network, Scope.Vpc, Scope.LoadBalancerRule), LbHttp(Category.LoadBalancer, "lb.http", "LB http", Boolean.class, "false", "If LB is http, default is 'true' for port 80 and 'false' for others'", Scope.LoadBalancerRule), diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 0e255cbe9668..ab27c40fb2f1 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -497,19 +497,19 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv sb.append("\t").append("balance ").append(algorithm); result.add(sb.toString()); - String timeoutConnect = lbConfigsMap.get(LoadBalancerConfigKey.TimeoutConnect.key()); + String timeoutConnect = lbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutConnect.key()); if (timeoutConnect != null) { sb = new StringBuilder(); sb.append("\t").append("timeout connect " + timeoutConnect); result.add(sb.toString()); } - String timeoutClient = lbConfigsMap.get(LoadBalancerConfigKey.TimeoutClient.key()); + String timeoutClient = lbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutClient.key()); if (timeoutClient != null) { sb = new StringBuilder(); sb.append("\t").append("timeout client " + timeoutClient); result.add(sb.toString()); } - String timeoutServer = lbConfigsMap.get(LoadBalancerConfigKey.TimeoutServer.key()); + String timeoutServer = lbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutServer.key()); if (timeoutServer != null) { sb = new StringBuilder(); sb.append("\t").append("timeout server " + timeoutServer); @@ -704,15 +704,15 @@ public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { dSection.set(7, "\tno option forceclose"); } - String timeoutConnect = networkLbConfigsMap.get(LoadBalancerConfigKey.TimeoutConnect.key()); + String timeoutConnect = networkLbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutConnect.key()); if (timeoutConnect != null) { dSection.set(8, "\ttimeout connect " + timeoutConnect); } - String timeoutClient = networkLbConfigsMap.get(LoadBalancerConfigKey.TimeoutClient.key()); + String timeoutClient = networkLbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutClient.key()); if (timeoutClient != null) { dSection.set(9, "\ttimeout client " + timeoutClient); } - String timeoutServer = networkLbConfigsMap.get(LoadBalancerConfigKey.TimeoutServer.key()); + String timeoutServer = networkLbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutServer.key()); if (timeoutServer != null) { dSection.set(10, "\ttimeout server " + timeoutServer); } From 240acfc4adaf9282e99c92b617c4bcf2228204cf Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 29 May 2020 07:57:58 +0000 Subject: [PATCH 17/75] Fix haproxy config is not change when remove timeout --- core/src/main/java/com/cloud/network/HAProxyConfigurator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index ab27c40fb2f1..635a4d9fb83a 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -699,7 +699,7 @@ public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { // result.add("\tnopoll"); result.add(blankLine); - final List dSection = Arrays.asList(defaultsSection); + final List dSection = new ArrayList(Arrays.asList(defaultsSection)); if (lbCmd.keepAliveEnabled) { dSection.set(7, "\tno option forceclose"); } From 7bff80105c0cc98cb570eab0606afae88b70c86a Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 3 Jun 2020 08:08:35 +0000 Subject: [PATCH 18/75] LB configs: Set default value in haproxy for lb configs --- .../network/lb/LoadBalancerConfigKey.java | 16 ++++++++-------- ui/scripts/network.js | 8 ++++---- ui/scripts/ui-custom/lbConfigs.js | 8 +++++--- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index 100b2757c619..2ed34d76c8a6 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -37,23 +37,23 @@ public enum LoadBalancerConfigKey { LbTimeoutClient(Category.General, "lb.timeout.client", "Maximum inactivity time (in ms) on client side", Long.class, "50000", "Set the maximum inactivity time on the client side.", Scope.Network, Scope.Vpc, Scope.LoadBalancerRule), - LbHttp(Category.LoadBalancer, "lb.http", "LB http", Boolean.class, "false", "If LB is http, default is 'true' for port 80 and 'false' for others'", Scope.LoadBalancerRule), + LbHttp(Category.LoadBalancer, "lb.http", "LB http enabled/disabled", Boolean.class, "true for port 80; false for other ports", "If LB is http, default is 'true' for port 80 and 'false' for others'", Scope.LoadBalancerRule), - LbHttpKeepalive(Category.LoadBalancer, "lb.http.keepalive", "LB http keepalive enabled/disabled", Boolean.class, "false", "If LB http is enabled, default is 'false'", Scope.LoadBalancerRule), + LbHttpKeepalive(Category.LoadBalancer, "lb.http.keepalive", "LB http keepalive enabled/disabled", Boolean.class, "", "Enable or disable HTTP keep-alive, default is inherited from network offering", Scope.LoadBalancerRule), GlobalMaxConn(Category.LoadBalancer, "global.maxconn", "LB max connection", Long.class, "4096", "Maximum per process number of concurrent connections, default is '4096'", Scope.Network, Scope.Vpc), - GlobalMaxPipes(Category.LoadBalancer, "global.maxpipes", "LB max pipes", Long.class, "", "Maximum number of per process pipes, default is 'maxconn/4'", Scope.Network, Scope.Vpc), + GlobalMaxPipes(Category.LoadBalancer, "global.maxpipes", "LB max pipes", Long.class, "", "Maximum number of per process pipes, default is 'maxconn/4'", Scope.Network, Scope.Vpc), - LbMaxConn(Category.LoadBalancer, "lb.maxconn", "LB max connection", Long.class, "", "Maximum per process number of concurrent connections per site/vm", Scope.LoadBalancerRule), + LbMaxConn(Category.LoadBalancer, "lb.maxconn", "LB max connection", Long.class, "<2000 in haproxy>", "Maximum per process number of concurrent connections per site/vm", Scope.LoadBalancerRule), - LbFullConn(Category.LoadBalancer, "lb.fullconn", "LB full connection", Long.class, "", "Specify at what backend load the servers will reach their maxconn, default is 'maxconn/10'", Scope.LoadBalancerRule), + LbFullConn(Category.LoadBalancer, "lb.fullconn", "LB full connection", Long.class, "", "Specify at what backend load the servers will reach their maxconn, default is 'maxconn/10'", Scope.LoadBalancerRule), - LbServerMaxConn(Category.LoadBalancer, "lb.server.maxconn", "LB max connection per site/vm", Long.class, "", "LB max connection per site/vm, default is ''", Scope.LoadBalancerRule), + LbServerMaxConn(Category.LoadBalancer, "lb.server.maxconn", "LB max connection per server", Long.class, "<0 means unlimited in haproxy>", "LB max connection per server, default is ''", Scope.LoadBalancerRule), - LbServerMinConn(Category.LoadBalancer, "lb.server.minconn", "LB minimum connection", Long.class, "", "LB minimum connection per site/vm, default is ''", Scope.LoadBalancerRule), + LbServerMinConn(Category.LoadBalancer, "lb.server.minconn", "LB minimum connection per server", Long.class, "", "LB minimum connection per server, default is ''", Scope.LoadBalancerRule), - LbServerMaxQueue(Category.LoadBalancer, "lb.server.maxqueue", "LB max queue", Long.class, "", "Maximum number of connections which will wait in queue for this server, default is ''", Scope.LoadBalancerRule); + LbServerMaxQueue(Category.LoadBalancer, "lb.server.maxqueue", "Max conn wait in queue per server", Long.class, "<0 means unlimited in haproxy>", "Maximum number of connections which will wait in queue for this server, default is ''", Scope.LoadBalancerRule); public static enum Category { General, Advanced, Stats, LoadBalancer diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 0de2965b07f2..ed4e4edb4a5a 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -1805,9 +1805,9 @@ args.$select.change(function() { var name = $(this).children(':selected').val(); var desc = config_list[name].desc; - $(this).parent().parent().find('.description').html(desc); + $(this).parent().parent().find('.description').text(desc); var dvalue = config_list[name].defaultvalue; - $(this).parent().parent().find('.defaultvalue').html(dvalue); + $(this).parent().parent().find('.defaultvalue').text(dvalue); }); } }, @@ -1921,7 +1921,7 @@ }); if (this.defaultvalue == "") { $.extend(config, { - defaultvalue: "" + defaultvalue: "" }); } return config; @@ -6075,7 +6075,7 @@ }); if (this.defaultvalue == "") { $.extend(config, { - defaultvalue: "" + defaultvalue: "" }); } return config; diff --git a/ui/scripts/ui-custom/lbConfigs.js b/ui/scripts/ui-custom/lbConfigs.js index c95265121209..812f79b26f23 100644 --- a/ui/scripts/ui-custom/lbConfigs.js +++ b/ui/scripts/ui-custom/lbConfigs.js @@ -76,9 +76,9 @@ args.$select.change(function() { var name = $(this).children(':selected').val(); var desc = config_list[name].desc; - $(this).parent().parent().find('.description').html(desc); + $(this).parent().parent().find('.description').text(desc); var dvalue = config_list[name].defaultvalue; - $(this).parent().parent().find('.defaultvalue').html(dvalue); + $(this).parent().parent().find('.defaultvalue').text(dvalue); }); } }, @@ -190,9 +190,11 @@ $.extend(config, { displayname: config.name }); +console.log(config.name); +console.log(config.defaultvalue); if (config.defaultvalue == "") { $.extend(config, { - defaultvalue: "" + defaultvalue: "" }); } return config; From 5e3f152b2fd7693f92819618a30fcc4a8197d410 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 3 Jun 2020 16:04:49 +0000 Subject: [PATCH 19/75] LB configs: Add 'mode http' to http LBs --- .../cloud/network/HAProxyConfigurator.java | 24 +++++++++++++------ .../network/HAProxyConfiguratorTest.java | 4 ++-- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 635a4d9fb83a..9ccc99f6f572 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -623,13 +623,19 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv keepAliveEnabled = false; } - if ((http && !keepAliveEnabled) || httpbasedStickiness) { + if (http || httpbasedStickiness) { sb = new StringBuilder(); sb.append("\t").append("mode http"); result.add(sb.toString()); - sb = new StringBuilder(); - sb.append("\t").append("option httpclose"); - result.add(sb.toString()); + if (keepAliveEnabled) { + sb = new StringBuilder(); + sb.append("\t").append("option http-keep-alive"); + result.add(sb.toString()); + } else { + sb = new StringBuilder(); + sb.append("\t").append("option httpclose"); + result.add(sb.toString()); + } } result.add(blankLine); @@ -645,9 +651,13 @@ private String generateStatsRule(final LoadBalancerConfigCommand lbCmd, final St final StringBuilder rule = new StringBuilder("\nlisten ").append(ruleName).append("\n\tbind ").append(statsIp).append(":").append(lbCmd.lbStatsPort); // TODO DH: write test for this in both cases - if (!lbCmd.keepAliveEnabled) { - s_logger.info("Haproxy mode http enabled"); - rule.append("\n\tmode http\n\toption httpclose"); + rule.append("\n\tmode http"); + if (lbCmd.keepAliveEnabled) { + s_logger.info("Haproxy option http-keep-alive enabled"); + rule.append("\n\toption http-keep-alive"); + } else { + s_logger.info("Haproxy option httpclose enabled"); + rule.append("\n\toption httpclose"); } Optional lbStatsUri = Optional.ofNullable(networkLbConfigsMap.get(LoadBalancerConfigKey.LbStatsUri.key())); diff --git a/core/src/test/java/com/cloud/network/HAProxyConfiguratorTest.java b/core/src/test/java/com/cloud/network/HAProxyConfiguratorTest.java index d899d4db4aef..19ac40484298 100644 --- a/core/src/test/java/com/cloud/network/HAProxyConfiguratorTest.java +++ b/core/src/test/java/com/cloud/network/HAProxyConfiguratorTest.java @@ -79,11 +79,11 @@ public void testGenerateConfigurationLoadBalancerConfigCommand() { HAProxyConfigurator hpg = new HAProxyConfigurator(); LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lba, "10.0.0.1", "10.1.0.1", "10.1.1.1", null, 1L, "12", false); String result = genConfig(hpg, cmd); - assertTrue("keepalive disabled should result in 'mode http' in the resulting haproxy config", result.contains("mode http")); + assertTrue("keepalive disabled should result in 'option httpclose' in the resulting haproxy config", result.contains("option httpclose")); cmd = new LoadBalancerConfigCommand(lba, "10.0.0.1", "10.1.0.1", "10.1.1.1", null, 1L, "4", true); result = genConfig(hpg, cmd); - assertTrue("keepalive enabled should not result in 'mode http' in the resulting haproxy config", !result.contains("mode http")); + assertTrue("keepalive enabled should not result in 'option httpclose' in the resulting haproxy config", !result.contains("option httpclose")); // TODO // create lb command // setup tests for From 8f9f7524b4396cc520c1a8a20d7fcfabe2f0a5fc Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Thu, 4 Jun 2020 08:06:21 +0000 Subject: [PATCH 20/75] Add 'no option forceclose' to http keep-alive rules --- core/src/main/java/com/cloud/network/HAProxyConfigurator.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 9ccc99f6f572..94a4c065e61b 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -629,7 +629,7 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv result.add(sb.toString()); if (keepAliveEnabled) { sb = new StringBuilder(); - sb.append("\t").append("option http-keep-alive"); + sb.append("\t").append("no option forceclose"); result.add(sb.toString()); } else { sb = new StringBuilder(); @@ -654,7 +654,6 @@ private String generateStatsRule(final LoadBalancerConfigCommand lbCmd, final St rule.append("\n\tmode http"); if (lbCmd.keepAliveEnabled) { s_logger.info("Haproxy option http-keep-alive enabled"); - rule.append("\n\toption http-keep-alive"); } else { s_logger.info("Haproxy option httpclose enabled"); rule.append("\n\toption httpclose"); From 757be267f4f2da8ba153cefdb9009d2a7dfdf18e Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 5 Jun 2020 13:57:31 +0000 Subject: [PATCH 21/75] LB configs: Enable/disable haproxy socket --- .../cloudstack/network/lb/LoadBalancerConfigKey.java | 2 ++ .../main/java/com/cloud/network/HAProxyConfigurator.java | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index 2ed34d76c8a6..817ca534a0bd 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -31,6 +31,8 @@ public enum LoadBalancerConfigKey { LbStatsAuth(Category.Stats, "lb.stats.auth", "LB stats auth", String.class, "admin1:AdMiN123", "Enable statistics with authentication and grant access to an account, default is 'admin1:AdMiN123'", Scope.Network, Scope.Vpc), + GlobalStatsSocket(Category.Stats, "global.stats.socket", "Stats socket enabled/disabled", Boolean.class, "false", "Binds a UNIX socket to /var/run/haproxy.socket, default is 'false'", Scope.Network, Scope.Vpc), + LbTimeoutConnect(Category.General, "lb.timeout.connect", "Maximum time (in ms) to wait for a connection to succeed", Long.class, "5000", "Set the maximum time to wait for a connection attempt to a server to succeed.", Scope.Network, Scope.Vpc, Scope.LoadBalancerRule), LbTimeoutServer(Category.General, "lb.timeout.server", "Maximum inactivity time (in ms) on server side", Long.class, "50000", "Set the maximum inactivity time on the server side.", Scope.Network, Scope.Vpc, Scope.LoadBalancerRule), diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 94a4c065e61b..1fef88824898 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -686,7 +686,7 @@ public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { } final List result = new ArrayList(); - final List gSection = Arrays.asList(globalSection); + List gSection = new ArrayList(Arrays.asList(globalSection)); // note that this is overwritten on the String in the static ArrayList String maxconn = networkLbConfigsMap.get(LoadBalancerConfigKey.GlobalMaxConn.key()) != null ? networkLbConfigsMap.get(LoadBalancerConfigKey.GlobalMaxConn.key()) : @@ -697,6 +697,12 @@ public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { networkLbConfigsMap.get(LoadBalancerConfigKey.GlobalMaxPipes.key()) : Long.toString(Long.parseLong(maxconn) / 4); gSection.set(3, "\tmaxpipes " + maxPipes); + + String statsSocket = networkLbConfigsMap.get(LoadBalancerConfigKey.GlobalStatsSocket.key()); + if (statsSocket != null && statsSocket.equalsIgnoreCase("true")) { + gSection.add("\tstats socket /var/run/haproxy.socket"); + } + if (s_logger.isDebugEnabled()) { for (final String s : gSection) { s_logger.debug("global section: " + s); From 9c6fa85519072f434f774b76241364a820599a56 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 8 Jun 2020 08:03:48 +0000 Subject: [PATCH 22/75] LB: remove console.log from ui --- ui/scripts/ui-custom/lbConfigs.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui/scripts/ui-custom/lbConfigs.js b/ui/scripts/ui-custom/lbConfigs.js index 812f79b26f23..d95066943038 100644 --- a/ui/scripts/ui-custom/lbConfigs.js +++ b/ui/scripts/ui-custom/lbConfigs.js @@ -190,8 +190,6 @@ $.extend(config, { displayname: config.name }); -console.log(config.name); -console.log(config.defaultvalue); if (config.defaultvalue == "") { $.extend(config, { defaultvalue: "" From 7a1a2a92e1ca2060dcb11d09ec1a8a2928ff1191 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 10 Jun 2020 13:29:08 +0000 Subject: [PATCH 23/75] Create table load_balancer_config in schema-41400to41500.sql --- .../META-INF/db/schema-41310to41400.sql | 21 ------------------ .../META-INF/db/schema-41400to41500.sql | 22 +++++++++++++++++++ 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41310to41400.sql b/engine/schema/src/main/resources/META-INF/db/schema-41310to41400.sql index c80f4589219c..baa7bcf96178 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41310to41400.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41310to41400.sql @@ -379,24 +379,3 @@ CREATE TABLE IF NOT EXISTS `cloud`.`kubernetes_cluster_details` ( PRIMARY KEY(`id`), CONSTRAINT `fk_kubernetes_cluster_details__cluster_id` FOREIGN KEY `fk_kubernetes_cluster_details__cluster_id`(`cluster_id`) REFERENCES `kubernetes_cluster`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `cloud`.`load_balancer_config` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `uuid` varchar(40) DEFAULT NULL, - `scope` varchar(20) DEFAULT NULL COMMENT 'The scope of this config, Vpc/Network/LoadBalancer', - `network_id` bigint(20) unsigned DEFAULT NULL, - `vpc_id` bigint(20) unsigned DEFAULT NULL, - `load_balancer_id` bigint(20) unsigned DEFAULT NULL, - `name` varchar(255) NOT NULL, - `value` varchar(255) DEFAULT NULL, - `created` datetime NOT NULL COMMENT 'date created', - `removed` datetime DEFAULT NULL COMMENT 'date removed', - PRIMARY KEY (`id`), - UNIQUE KEY `id_UNIQUE` (`id`), - KEY `fk_load_balancer_config_network_id` (`network_id`), - KEY `fk_load_balancer_config_vpc_id` (`vpc_id`), - KEY `fk_load_balancer_config_loadbalancer_id` (`load_balancer_id`), - CONSTRAINT `fk_load_balancer_config_network_id` FOREIGN KEY (`network_id`) REFERENCES `networks` (`id`) ON DELETE CASCADE, - CONSTRAINT `fk_load_balancer_config_vpc_id` FOREIGN KEY (`vpc_id`) REFERENCES `vpc` (`id`) ON DELETE CASCADE, - CONSTRAINT `fk_load_balancer_config_loadbalancer_id` FOREIGN KEY (`load_balancer_id`) REFERENCES `load_balancing_rules` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql b/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql index e87ac077ce68..eafdfc6dbe11 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql @@ -833,3 +833,25 @@ INSERT INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_vers -- Fix OS category for Guest OS 'Other PV Virtio-SCSI (64-bit)' UPDATE `cloud`.`guest_os` SET category_id = 7 WHERE id = 275 AND display_name = 'Other PV Virtio-SCSI (64-bit)'; + +-- Table for customized load balancer configurations +CREATE TABLE IF NOT EXISTS `cloud`.`load_balancer_config` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `uuid` varchar(40) DEFAULT NULL, + `scope` varchar(20) DEFAULT NULL COMMENT 'The scope of this config, Vpc/Network/LoadBalancer', + `network_id` bigint(20) unsigned DEFAULT NULL, + `vpc_id` bigint(20) unsigned DEFAULT NULL, + `load_balancer_id` bigint(20) unsigned DEFAULT NULL, + `name` varchar(255) NOT NULL, + `value` varchar(255) DEFAULT NULL, + `created` datetime NOT NULL COMMENT 'date created', + `removed` datetime DEFAULT NULL COMMENT 'date removed', + PRIMARY KEY (`id`), + UNIQUE KEY `id_UNIQUE` (`id`), + KEY `fk_load_balancer_config_network_id` (`network_id`), + KEY `fk_load_balancer_config_vpc_id` (`vpc_id`), + KEY `fk_load_balancer_config_loadbalancer_id` (`load_balancer_id`), + CONSTRAINT `fk_load_balancer_config_network_id` FOREIGN KEY (`network_id`) REFERENCES `networks` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_load_balancer_config_vpc_id` FOREIGN KEY (`vpc_id`) REFERENCES `vpc` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_load_balancer_config_loadbalancer_id` FOREIGN KEY (`load_balancer_id`) REFERENCES `load_balancing_rules` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; From 0df8cc71a7987f7fdbbbfb54f47a28449a967058 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 10 Jun 2020 12:57:30 +0000 Subject: [PATCH 24/75] LB transparent mode --- .../network/lb/LoadBalancerConfigKey.java | 2 ++ .../VirtualRoutingResource.java | 1 - .../facade/LoadBalancerConfigItem.java | 19 ++++++++++++++- .../model/LoadBalancerRule.java | 11 ++++++++- .../cloud/network/HAProxyConfigurator.java | 12 ++++++++++ .../debian/opt/cloud/bin/cs/CsLoadBalancer.py | 23 +++++++++++++++++++ 6 files changed, 65 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index 817ca534a0bd..99e927701490 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -43,6 +43,8 @@ public enum LoadBalancerConfigKey { LbHttpKeepalive(Category.LoadBalancer, "lb.http.keepalive", "LB http keepalive enabled/disabled", Boolean.class, "", "Enable or disable HTTP keep-alive, default is inherited from network offering", Scope.LoadBalancerRule), + LbTransparent(Category.LoadBalancer, "lb.transparent.mode", "LB transparent mode; works only if network/rule configs are both 'true'", Boolean.class, "false", "Enable or disable transparent mode, default is 'false'", Scope.Network, Scope.Vpc, Scope.LoadBalancerRule), + GlobalMaxConn(Category.LoadBalancer, "global.maxconn", "LB max connection", Long.class, "4096", "Maximum per process number of concurrent connections, default is '4096'", Scope.Network, Scope.Vpc), GlobalMaxPipes(Category.LoadBalancer, "global.maxpipes", "LB max pipes", Long.class, "", "Maximum number of per process pipes, default is 'maxconn/4'", Scope.Network, Scope.Vpc), diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java index 2d03f2144574..839f34ac658d 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java @@ -522,7 +522,6 @@ private Answer execute(AggregationControlCommand cmd) { sb.append(c.getAggregateCommand()); } } - s_logger.debug("AggregationControlCommand configuration is :\n" + sb.toString()); // TODO replace with applyConfig with a stop on fail String cfgFileName = "VR-"+ UUID.randomUUID().toString() + ".cfg"; diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/LoadBalancerConfigItem.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/LoadBalancerConfigItem.java index b943125d0a4a..5c3714b447c7 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/LoadBalancerConfigItem.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/LoadBalancerConfigItem.java @@ -19,11 +19,15 @@ package com.cloud.agent.resource.virtualnetwork.facade; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import org.apache.cloudstack.network.lb.LoadBalancerConfigKey; + import com.cloud.agent.api.routing.LoadBalancerConfigCommand; import com.cloud.agent.api.routing.NetworkElementCommand; +import com.cloud.agent.api.to.LoadBalancerConfigTO; import com.cloud.agent.resource.virtualnetwork.ConfigItem; import com.cloud.agent.resource.virtualnetwork.VRScripts; import com.cloud.agent.resource.virtualnetwork.model.ConfigBase; @@ -57,6 +61,19 @@ public List generateConfig(final NetworkElementCommand cmd) { final LoadBalancerRule loadBalancerRule = new LoadBalancerRule(configuration, tmpCfgFilePath, tmpCfgFileName, addRules, removeRules, statRules, routerIp); + boolean isTransparent = false; + final LoadBalancerConfigTO[] networkLbConfigs = command.getNetworkLbConfigs(); + HashMap networkLbConfigsMap = new HashMap(); + if (networkLbConfigs != null) { + for (LoadBalancerConfigTO networkLbConfig: networkLbConfigs) { + if (networkLbConfig.getName().equals(LoadBalancerConfigKey.LbTransparent.key())) { + isTransparent = "true".equalsIgnoreCase(networkLbConfig.getValue()); + break; + } + } + } + loadBalancerRule.setIsTransparent(isTransparent); + final List rules = new LinkedList(); rules.add(loadBalancerRule); @@ -71,4 +88,4 @@ protected List generateConfigItems(final ConfigBase configuration) { return super.generateConfigItems(configuration); } -} \ No newline at end of file +} diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/LoadBalancerRule.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/LoadBalancerRule.java index e3b6e45e147e..fa6a997f23ff 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/LoadBalancerRule.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/LoadBalancerRule.java @@ -25,6 +25,7 @@ public class LoadBalancerRule { private String[] configuration; private String tmpCfgFilePath; private String tmpCfgFileName; + private Boolean isTransparent; private String[] addRules; private String[] removeRules; @@ -70,6 +71,14 @@ public void setTmpCfgFileName(final String tmpCfgFileName) { this.tmpCfgFileName = tmpCfgFileName; } + public void setIsTransparent(final Boolean isTransparent) { + this.isTransparent = isTransparent; + } + + public Boolean isTransparent() { + return isTransparent; + } + public String[] getAddRules() { return addRules; } @@ -101,4 +110,4 @@ public String getRouterIp() { public void setRouterIp(final String routerIp) { this.routerIp = routerIp; } -} \ No newline at end of file +} diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 1fef88824898..23ac8e5de793 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -638,6 +638,13 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv } } + if ("true".equalsIgnoreCase(networkLbConfigsMap.get(LoadBalancerConfigKey.LbTransparent.key())) + && "true".equalsIgnoreCase(lbConfigsMap.get(LoadBalancerConfigKey.LbTransparent.key()))) { + sb = new StringBuilder(); + sb.append("\t").append("source 0.0.0.0 usesrc clientip"); + result.add(sb.toString()); + } + result.add(blankLine); return result; } @@ -703,6 +710,11 @@ public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { gSection.add("\tstats socket /var/run/haproxy.socket"); } + if ("true".equalsIgnoreCase(networkLbConfigsMap.get(LoadBalancerConfigKey.LbTransparent.key()))) { + gSection.set(5, "\tuser root"); + gSection.set(6, "\tgroup root"); + } + if (s_logger.isDebugEnabled()) { for (final String s : gSection) { s_logger.debug("global section: " + s); diff --git a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py index d12aa853ed3d..02d28514b9b5 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py @@ -57,6 +57,7 @@ def process(self): remove_rules = self.dbag['config'][0]['remove_rules'] stat_rules = self.dbag['config'][0]['stat_rules'] self._configure_firewall(add_rules, remove_rules, stat_rules) + self._configure_firewall_for_transparent(self.dbag['config'][0]['is_transparent']) def _configure_firewall(self, add_rules, remove_rules, stat_rules): firewall = self.config.get_fw() @@ -82,3 +83,25 @@ def _configure_firewall(self, add_rules, remove_rules, stat_rules): ip = path[0] port = path[1] firewall.append(["filter", "", "-A INPUT -p tcp -m tcp -d %s --dport %s -m state --state NEW -j ACCEPT" % (ip, port)]) + + def _configure_firewall_for_transparent(self, is_transparent): + tableNo = 99 + firewall = self.config.get_fw() + if is_transparent is None or is_transparent == False: + if ["mangle", "", "-A PREROUTING -p tcp -m socket -j DIVERT"] in firewall: + firewall.remove(["mangle", "", "-A PREROUTING -p tcp -m socket -j DIVERT"]) + firewall.remove(["mangle", "", "-A DIVERT -j MARK --set-xmark %s/0xffffffff" % hex(tableNo)]) + firewall.remove(["mangle", "", "-A DIVERT -j ACCEPT"]) + firewall.remove(["mangle", "", "-N DIVERT"]) + if CsHelper.execute("ip rule show fwmark %s lookup %s" % (tableNo, tableNo)): + CsHelper.execute("ip route del local 0.0.0.0/0 dev lo table %s" % tableNo) + CsHelper.execute("ip rule del fwmark %s lookup %s" % (tableNo, tableNo)) + elif is_transparent == True: + if ["mangle", "", "-A PREROUTING -p tcp -m socket -j DIVERT"] not in firewall: + firewall.append(["mangle", "", "-N DIVERT"]) + firewall.append(["mangle", "", "-A PREROUTING -p tcp -m socket -j DIVERT"]) + firewall.append(["mangle", "", "-A DIVERT -j MARK --set-xmark %s/0xffffffff" % hex(tableNo)]) + firewall.append(["mangle", "", "-A DIVERT -j ACCEPT"]) + if not CsHelper.execute("ip rule show fwmark %s lookup %s" % (tableNo, tableNo)): + CsHelper.execute("ip rule add fwmark %s lookup %s" % (tableNo, tableNo)) + CsHelper.execute("ip route add local 0.0.0.0/0 dev lo table %s" % tableNo) From f52a60901053d1a195a528f8280459effdbe967e Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 10 Jun 2020 12:58:19 +0000 Subject: [PATCH 25/75] LB: generate separated list for frontend and backend --- .../cloud/network/HAProxyConfigurator.java | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 23ac8e5de793..abc293e7ee7c 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -485,6 +485,9 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv } } + final List frontendConfigs = new ArrayList(); + final List backendConfigs = new ArrayList(); + final List result = new ArrayList(); // add line like this: "listen 65_37_141_30-80\n\tbind 65.37.141.30:80" sb = new StringBuilder(); @@ -492,28 +495,28 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv result.add(sb.toString()); sb = new StringBuilder(); sb.append("\tbind ").append(publicIP).append(":").append(publicPort); - result.add(sb.toString()); + frontendConfigs.add(sb.toString()); sb = new StringBuilder(); sb.append("\t").append("balance ").append(algorithm); - result.add(sb.toString()); + backendConfigs.add(sb.toString()); String timeoutConnect = lbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutConnect.key()); if (timeoutConnect != null) { sb = new StringBuilder(); sb.append("\t").append("timeout connect " + timeoutConnect); - result.add(sb.toString()); + backendConfigs.add(sb.toString()); } String timeoutClient = lbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutClient.key()); if (timeoutClient != null) { sb = new StringBuilder(); sb.append("\t").append("timeout client " + timeoutClient); - result.add(sb.toString()); + frontendConfigs.add(sb.toString()); } String timeoutServer = lbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutServer.key()); if (timeoutServer != null) { sb = new StringBuilder(); sb.append("\t").append("timeout server " + timeoutServer); - result.add(sb.toString()); + backendConfigs.add(sb.toString()); } if (lbConfigsMap.get(LoadBalancerConfigKey.LbMaxConn.key()) != null) { @@ -521,7 +524,7 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv if (maxConnValue > 0) { sb = new StringBuilder(); sb.append("\tmaxconn ").append(maxConnValue); - result.add(sb.toString()); + frontendConfigs.add(sb.toString()); } } if (lbConfigsMap.get(LoadBalancerConfigKey.LbFullConn.key()) != null) { @@ -529,7 +532,7 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv if (fullConnValue > 0) { sb = new StringBuilder(); sb.append("\tfullconn ").append(fullConnValue); - result.add(sb.toString()); + backendConfigs.add(sb.toString()); } } @@ -597,13 +600,13 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv } } if (httpbasedStickiness) { - result.addAll(dstWithCookieSubRule); + backendConfigs.addAll(dstWithCookieSubRule); } else { - result.addAll(dstSubRule); + backendConfigs.addAll(dstSubRule); } - result.add(stickinessSubRule); + backendConfigs.add(stickinessSubRule); } else { - result.addAll(dstSubRule); + backendConfigs.addAll(dstSubRule); } if (stickinessSubRule != null && !destsAvailable) { s_logger.warn("Haproxy stickiness policy for lb rule: " + lbTO.getSrcIp() + ":" + lbTO.getSrcPort() + ": Not Applied, cause: backends are unavailable"); @@ -626,15 +629,15 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv if (http || httpbasedStickiness) { sb = new StringBuilder(); sb.append("\t").append("mode http"); - result.add(sb.toString()); + frontendConfigs.add(sb.toString()); if (keepAliveEnabled) { sb = new StringBuilder(); sb.append("\t").append("no option forceclose"); - result.add(sb.toString()); + frontendConfigs.add(sb.toString()); } else { sb = new StringBuilder(); sb.append("\t").append("option httpclose"); - result.add(sb.toString()); + frontendConfigs.add(sb.toString()); } } @@ -642,9 +645,11 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv && "true".equalsIgnoreCase(lbConfigsMap.get(LoadBalancerConfigKey.LbTransparent.key()))) { sb = new StringBuilder(); sb.append("\t").append("source 0.0.0.0 usesrc clientip"); - result.add(sb.toString()); + backendConfigs.add(sb.toString()); } + result.addAll(frontendConfigs); + result.addAll(backendConfigs); result.add(blankLine); return result; } From ea66b3641466c9c314c1ccfeb8d343e77131abdd Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 10 Jun 2020 12:58:35 +0000 Subject: [PATCH 26/75] LB transparent mode: use different backend for local network --- .../routing/LoadBalancerConfigCommand.java | 8 ++++ .../facade/LoadBalancerConfigItem.java | 1 + .../model/LoadBalancerRule.java | 9 ++++ .../cloud/network/HAProxyConfigurator.java | 47 +++++++++++++++---- .../network/router/CommandSetupHelper.java | 1 + 5 files changed, 56 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java b/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java index 99c342fe28d1..6ca9cfe30ed1 100644 --- a/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java +++ b/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java @@ -46,6 +46,7 @@ public class LoadBalancerConfigCommand extends NetworkElementCommand { public boolean keepAliveEnabled = false; NicTO nic; Long vpcId; + String networkCidr; protected LoadBalancerConfigCommand() { } @@ -94,4 +95,11 @@ public void setNetworkLbConfigs(List networkLbConf } } + public void setNetworkCidr(String networkCidr) { + this.networkCidr = networkCidr; + } + + public String getNetworkCidr() { + return networkCidr; + } } diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/LoadBalancerConfigItem.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/LoadBalancerConfigItem.java index 5c3714b447c7..b34416c9f146 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/LoadBalancerConfigItem.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/LoadBalancerConfigItem.java @@ -73,6 +73,7 @@ public List generateConfig(final NetworkElementCommand cmd) { } } loadBalancerRule.setIsTransparent(isTransparent); + loadBalancerRule.setNetworkCidr(command.getNetworkCidr()); final List rules = new LinkedList(); rules.add(loadBalancerRule); diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/LoadBalancerRule.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/LoadBalancerRule.java index fa6a997f23ff..1834e6c4e4d2 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/LoadBalancerRule.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/LoadBalancerRule.java @@ -26,6 +26,7 @@ public class LoadBalancerRule { private String tmpCfgFilePath; private String tmpCfgFileName; private Boolean isTransparent; + private String networkCidr; private String[] addRules; private String[] removeRules; @@ -110,4 +111,12 @@ public String getRouterIp() { public void setRouterIp(final String routerIp) { this.routerIp = routerIp; } + + public void setNetworkCidr(String networkCidr) { + this.networkCidr = networkCidr; + } + + public String getNetworkCidr() { + return networkCidr; + } } diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index abc293e7ee7c..f5fd6a031443 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -470,7 +470,7 @@ private String getLbSubRuleForStickiness(final LoadBalancerTO lbTO) { return sb.toString(); } - private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliveEnabled, HashMap networkLbConfigsMap) { + private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliveEnabled, final String networkCidr, HashMap networkLbConfigsMap) { StringBuilder sb = new StringBuilder(); final String poolName = sb.append(lbTO.getSrcIp().replace(".", "_")).append('-').append(lbTO.getSrcPort()).toString(); final String publicIP = lbTO.getSrcIp(); @@ -487,12 +487,9 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv final List frontendConfigs = new ArrayList(); final List backendConfigs = new ArrayList(); - + final List backendConfigsForHttp = new ArrayList(); final List result = new ArrayList(); - // add line like this: "listen 65_37_141_30-80\n\tbind 65.37.141.30:80" - sb = new StringBuilder(); - sb.append("listen ").append(poolName); - result.add(sb.toString()); + sb = new StringBuilder(); sb.append("\tbind ").append(publicIP).append(":").append(publicPort); frontendConfigs.add(sb.toString()); @@ -630,26 +627,56 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv sb = new StringBuilder(); sb.append("\t").append("mode http"); frontendConfigs.add(sb.toString()); + backendConfigsForHttp.add(sb.toString()); if (keepAliveEnabled) { sb = new StringBuilder(); sb.append("\t").append("no option forceclose"); frontendConfigs.add(sb.toString()); + backendConfigsForHttp.add(sb.toString()); } else { sb = new StringBuilder(); sb.append("\t").append("option httpclose"); frontendConfigs.add(sb.toString()); + backendConfigsForHttp.add(sb.toString()); } } + boolean isTransparent = false; if ("true".equalsIgnoreCase(networkLbConfigsMap.get(LoadBalancerConfigKey.LbTransparent.key())) && "true".equalsIgnoreCase(lbConfigsMap.get(LoadBalancerConfigKey.LbTransparent.key()))) { + isTransparent = true; + } + + if (isTransparent) { + sb = new StringBuilder(); + sb.append("frontend ").append(poolName); + result.add(sb.toString()); + result.addAll(frontendConfigs); + sb = new StringBuilder(); + sb.append("\tacl local_subnet src ").append(networkCidr); + sb.append("\n\tuse_backend ").append(poolName).append("-backend-local if local_subnet"); + sb.append("\n\tdefault_backend ").append(poolName).append("-backend"); + sb.append("\n\n"); + sb.append("backend ").append(poolName).append("-backend"); + result.add(sb.toString()); + result.addAll(backendConfigsForHttp); + result.addAll(backendConfigs); sb = new StringBuilder(); sb.append("\t").append("source 0.0.0.0 usesrc clientip"); - backendConfigs.add(sb.toString()); + sb.append("\n\n"); + sb.append("backend ").append(poolName).append("-backend-local"); + result.add(sb.toString()); + result.addAll(backendConfigsForHttp); + result.addAll(backendConfigs); + } else { + // add line like this: "listen 65_37_141_30-80\n\tbind 65.37.141.30:80" + sb = new StringBuilder(); + sb.append("listen ").append(poolName); + result.add(sb.toString()); + result.addAll(frontendConfigs); + result.addAll(backendConfigs); } - result.addAll(frontendConfigs); - result.addAll(backendConfigs); result.add(blankLine); return result; } @@ -790,7 +817,7 @@ public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { if (lbTO.isRevoked()) { continue; } - final List poolRules = getRulesForPool(lbTO, lbCmd.keepAliveEnabled, networkLbConfigsMap); + final List poolRules = getRulesForPool(lbTO, lbCmd.keepAliveEnabled, lbCmd.getNetworkCidr(), networkLbConfigsMap); result.addAll(poolRules); has_listener = true; } diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index 63f83e4b7a15..a94c1d651cf1 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -347,6 +347,7 @@ public void createApplyLoadBalancingRulesCommands(final List final LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lbs, routerPublicIp, _routerControlHelper.getRouterIpInNetwork(guestNetworkId, router.getId()), router.getPrivateIpAddress(), _itMgr.toNicTO(nicProfile, router.getHypervisorType()), router.getVpcId(), maxconn, offering.isKeepAliveEnabled()); + cmd.setNetworkCidr(guestNetwork.getCidr()); if (router.getVpcId() != null) { cmd.setNetworkLbConfigs(_lbConfigMgr.getVpcLbConfigs(router.getVpcId())); } else { From e44c8f6f8efd749bf4433784bdf21689176c2cd5 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 17 Jun 2020 15:02:30 +0000 Subject: [PATCH 27/75] LB transparent mode: remove from network config --- .../network/lb/LoadBalancerConfigKey.java | 2 +- .../api/routing/LoadBalancerConfigCommand.java | 9 +++++++++ .../facade/LoadBalancerConfigItem.java | 18 +----------------- .../com/cloud/network/HAProxyConfigurator.java | 14 +++++++------- .../java/com/cloud/api/ApiResponseHelper.java | 7 ++++--- .../network/router/CommandSetupHelper.java | 16 ++++++++++++++++ 6 files changed, 38 insertions(+), 28 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index 99e927701490..e3e29d31fe66 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -43,7 +43,7 @@ public enum LoadBalancerConfigKey { LbHttpKeepalive(Category.LoadBalancer, "lb.http.keepalive", "LB http keepalive enabled/disabled", Boolean.class, "", "Enable or disable HTTP keep-alive, default is inherited from network offering", Scope.LoadBalancerRule), - LbTransparent(Category.LoadBalancer, "lb.transparent.mode", "LB transparent mode; works only if network/rule configs are both 'true'", Boolean.class, "false", "Enable or disable transparent mode, default is 'false'", Scope.Network, Scope.Vpc, Scope.LoadBalancerRule), + LbTransparent(Category.LoadBalancer, "lb.transparent.mode", "LB transparent mode enabled/disabled", Boolean.class, "false", "Enable or disable transparent mode, default is 'false'", Scope.LoadBalancerRule), GlobalMaxConn(Category.LoadBalancer, "global.maxconn", "LB max connection", Long.class, "4096", "Maximum per process number of concurrent connections, default is '4096'", Scope.Network, Scope.Vpc), diff --git a/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java b/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java index 6ca9cfe30ed1..a6337b562d4a 100644 --- a/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java +++ b/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java @@ -46,6 +46,7 @@ public class LoadBalancerConfigCommand extends NetworkElementCommand { public boolean keepAliveEnabled = false; NicTO nic; Long vpcId; + Boolean isTransparent; String networkCidr; protected LoadBalancerConfigCommand() { @@ -95,6 +96,14 @@ public void setNetworkLbConfigs(List networkLbConf } } + public void setIsTransparent(final Boolean isTransparent) { + this.isTransparent = isTransparent; + } + + public Boolean isTransparent() { + return isTransparent; + } + public void setNetworkCidr(String networkCidr) { this.networkCidr = networkCidr; } diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/LoadBalancerConfigItem.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/LoadBalancerConfigItem.java index b34416c9f146..64da21286cf5 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/LoadBalancerConfigItem.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/LoadBalancerConfigItem.java @@ -19,15 +19,11 @@ package com.cloud.agent.resource.virtualnetwork.facade; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import org.apache.cloudstack.network.lb.LoadBalancerConfigKey; - import com.cloud.agent.api.routing.LoadBalancerConfigCommand; import com.cloud.agent.api.routing.NetworkElementCommand; -import com.cloud.agent.api.to.LoadBalancerConfigTO; import com.cloud.agent.resource.virtualnetwork.ConfigItem; import com.cloud.agent.resource.virtualnetwork.VRScripts; import com.cloud.agent.resource.virtualnetwork.model.ConfigBase; @@ -60,19 +56,7 @@ public List generateConfig(final NetworkElementCommand cmd) { final String[] statRules = allRules[LoadBalancerConfigurator.STATS]; final LoadBalancerRule loadBalancerRule = new LoadBalancerRule(configuration, tmpCfgFilePath, tmpCfgFileName, addRules, removeRules, statRules, routerIp); - - boolean isTransparent = false; - final LoadBalancerConfigTO[] networkLbConfigs = command.getNetworkLbConfigs(); - HashMap networkLbConfigsMap = new HashMap(); - if (networkLbConfigs != null) { - for (LoadBalancerConfigTO networkLbConfig: networkLbConfigs) { - if (networkLbConfig.getName().equals(LoadBalancerConfigKey.LbTransparent.key())) { - isTransparent = "true".equalsIgnoreCase(networkLbConfig.getValue()); - break; - } - } - } - loadBalancerRule.setIsTransparent(isTransparent); + loadBalancerRule.setIsTransparent(command.isTransparent()); loadBalancerRule.setNetworkCidr(command.getNetworkCidr()); final List rules = new LinkedList(); diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index f5fd6a031443..977b0845e86f 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -485,6 +485,11 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv } } + boolean isTransparent = false; + if ("true".equalsIgnoreCase(lbConfigsMap.get(LoadBalancerConfigKey.LbTransparent.key()))) { + isTransparent = true; + } + final List frontendConfigs = new ArrayList(); final List backendConfigs = new ArrayList(); final List backendConfigsForHttp = new ArrayList(); @@ -641,12 +646,6 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv } } - boolean isTransparent = false; - if ("true".equalsIgnoreCase(networkLbConfigsMap.get(LoadBalancerConfigKey.LbTransparent.key())) - && "true".equalsIgnoreCase(lbConfigsMap.get(LoadBalancerConfigKey.LbTransparent.key()))) { - isTransparent = true; - } - if (isTransparent) { sb = new StringBuilder(); sb.append("frontend ").append(poolName); @@ -742,7 +741,8 @@ public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { gSection.add("\tstats socket /var/run/haproxy.socket"); } - if ("true".equalsIgnoreCase(networkLbConfigsMap.get(LoadBalancerConfigKey.LbTransparent.key()))) { + // run haproxy as root + if (lbCmd.isTransparent()) { gSection.set(5, "\tuser root"); gSection.set(6, "\tgroup root"); } diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index 9748ebd33190..ff428ee088fe 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -1014,10 +1014,11 @@ public LoadBalancerConfigResponse createLoadBalancerConfigResponse(LoadBalancerC response.setCreated(config.getCreated()); LoadBalancerConfigKey configKey = LoadBalancerConfigKey.getConfigsByScopeAndName(config.getScope(), config.getName()); if (configKey == null) { - throw new CloudRuntimeException(String.format("Unable to determine the load balancer config for scope %s and name %s", config.getScope(), config.getName())); + s_logger.warn(String.format("Unable to determine the load balancer config for scope %s and name %s", config.getScope(), config.getName())); + } else { + response.setDescription(configKey.displayText()); + response.setDefaultValue(configKey.defaultValue()); } - response.setDescription(configKey.displayText()); - response.setDefaultValue(configKey.defaultValue()); response.setObjectName("loadbalancerconfig"); return response; } diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index a94c1d651cf1..785f259b2c18 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -27,6 +27,7 @@ import javax.inject.Inject; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.network.lb.LoadBalancerConfigKey; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -56,6 +57,7 @@ import com.cloud.agent.api.to.DhcpTO; import com.cloud.agent.api.to.FirewallRuleTO; import com.cloud.agent.api.to.IpAddressTO; +import com.cloud.agent.api.to.LoadBalancerConfigTO; import com.cloud.agent.api.to.LoadBalancerTO; import com.cloud.agent.api.to.NetworkACLTO; import com.cloud.agent.api.to.NicTO; @@ -347,6 +349,20 @@ public void createApplyLoadBalancingRulesCommands(final List final LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lbs, routerPublicIp, _routerControlHelper.getRouterIpInNetwork(guestNetworkId, router.getId()), router.getPrivateIpAddress(), _itMgr.toNicTO(nicProfile, router.getHypervisorType()), router.getVpcId(), maxconn, offering.isKeepAliveEnabled()); + boolean isTransparent = false; + for (final LoadBalancerTO lbTO : lbs) { + final LoadBalancerConfigTO[] lbConfigs = lbTO.getLbConfigs(); + for (LoadBalancerConfigTO lbConfig: lbConfigs) { + if (lbConfig.getName().equals(LoadBalancerConfigKey.LbTransparent.key())) { + isTransparent = "true".equalsIgnoreCase(lbConfig.getValue()); + break; + } + } + if (isTransparent) { + break; + } + } + cmd.setIsTransparent(isTransparent); cmd.setNetworkCidr(guestNetwork.getCidr()); if (router.getVpcId() != null) { cmd.setNetworkLbConfigs(_lbConfigMgr.getVpcLbConfigs(router.getVpcId())); From f50330cf3e7ae0c98532f2fb34e1c719aba7e6ba Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 17 Jun 2020 16:24:11 +0000 Subject: [PATCH 28/75] Lb transparent: fix test failures in core/ --- .../com/cloud/agent/api/routing/LoadBalancerConfigCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java b/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java index a6337b562d4a..8640db98ad80 100644 --- a/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java +++ b/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java @@ -46,7 +46,7 @@ public class LoadBalancerConfigCommand extends NetworkElementCommand { public boolean keepAliveEnabled = false; NicTO nic; Long vpcId; - Boolean isTransparent; + Boolean isTransparent = false; String networkCidr; protected LoadBalancerConfigCommand() { From 156c4f4f63e0ad284e9204109dc14dfec323d50e Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 17 Jun 2020 18:59:27 +0000 Subject: [PATCH 29/75] LB SSL offloading --- .../cloud/agent/api/to/LoadBalancerTO.java | 4 ++ .../facade/LoadBalancerConfigItem.java | 2 + .../model/LoadBalancerRule.java | 56 +++++++++++++++++++ .../cloud/network/HAProxyConfigurator.java | 32 ++++++++++- .../network/LoadBalancerConfigurator.java | 3 + .../network/element/VirtualRouterElement.java | 2 + .../network/router/CommandSetupHelper.java | 3 +- .../debian/opt/cloud/bin/cs/CsLoadBalancer.py | 16 ++++++ 8 files changed, 116 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java b/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java index 770c3199cf8b..c245d7c5970c 100644 --- a/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java +++ b/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java @@ -224,6 +224,10 @@ public LbSslCert getSslCert() { return this.sslCert; } + public void setLbSslCert(LbSslCert sslCert) { + this.sslCert = sslCert; + } + public String getSrcIpVlan() { return srcIpVlan; } diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/LoadBalancerConfigItem.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/LoadBalancerConfigItem.java index 64da21286cf5..69f0b20203a5 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/LoadBalancerConfigItem.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/LoadBalancerConfigItem.java @@ -58,6 +58,8 @@ public List generateConfig(final NetworkElementCommand cmd) { final LoadBalancerRule loadBalancerRule = new LoadBalancerRule(configuration, tmpCfgFilePath, tmpCfgFileName, addRules, removeRules, statRules, routerIp); loadBalancerRule.setIsTransparent(command.isTransparent()); loadBalancerRule.setNetworkCidr(command.getNetworkCidr()); + final LoadBalancerRule.SslCertEntry[] sslCerts = cfgtr.generateSslCertEntries(command); + loadBalancerRule.setSslCerts(sslCerts); final List rules = new LinkedList(); rules.add(loadBalancerRule); diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/LoadBalancerRule.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/LoadBalancerRule.java index 1834e6c4e4d2..445e1ed18d96 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/LoadBalancerRule.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/LoadBalancerRule.java @@ -27,6 +27,7 @@ public class LoadBalancerRule { private String tmpCfgFileName; private Boolean isTransparent; private String networkCidr; + private SslCertEntry[] sslCerts; private String[] addRules; private String[] removeRules; @@ -34,6 +35,53 @@ public class LoadBalancerRule { private String routerIp; + public static class SslCertEntry { + private String name; + private String cert; + private String key; + private String chain; + private String password; + + public SslCertEntry(String name, String cert, String key, String chain, String password) { + this.name = name; + this.cert = cert; + this.key = key; + this.chain = chain; + this.password = password; + } + + public void setName(String name) { + this.name = name; + } + public String getName() { + return name; + } + public void setCert(String cert) { + this.cert = cert; + } + public String getCert() { + return cert; + } + public void setKey(String key) { + this.key = key; + } + public String getKey() { + return key; + } + public void setChain(String chain) { + this.chain = chain; + } + public String getChain() { + return chain; + } + public void setPassword(String password) { + this.password = password; + } + public String getPassword() { + return password; + } + } + public LoadBalancerRule() { // Empty constructor for (de)serialization } @@ -119,4 +167,12 @@ public void setNetworkCidr(String networkCidr) { public String getNetworkCidr() { return networkCidr; } + + public SslCertEntry[] getSslCerts() { + return sslCerts; + } + + public void setSslCerts(final SslCertEntry[] sslCerts) { + this.sslCerts = sslCerts; + } } diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 977b0845e86f..37d0adf57992 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -37,6 +37,8 @@ import com.cloud.agent.api.to.LoadBalancerTO.DestinationTO; import com.cloud.agent.api.to.LoadBalancerTO.StickinessPolicyTO; import com.cloud.agent.api.to.PortForwardingRuleTO; +import com.cloud.agent.resource.virtualnetwork.model.LoadBalancerRule.SslCertEntry; +import com.cloud.network.lb.LoadBalancingRule.LbSslCert; import com.cloud.network.rules.LbStickinessMethod.StickinessMethodType; import com.cloud.utils.Pair; import com.cloud.utils.net.NetUtils; @@ -490,6 +492,11 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv isTransparent = true; } + boolean sslOffloading = false; + if (lbTO.getLbProtocol().equals(NetUtils.SSL_PROTO) && lbTO.getSslCert() != null) { + sslOffloading = true; + } + final List frontendConfigs = new ArrayList(); final List backendConfigs = new ArrayList(); final List backendConfigsForHttp = new ArrayList(); @@ -497,6 +504,10 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv sb = new StringBuilder(); sb.append("\tbind ").append(publicIP).append(":").append(publicPort); + if (sslOffloading) { + sb.append(" ssl crt /etc/ssl/private/").append(poolName).append(".pem"); + sb.append("\n\thttp-request add-header X-Forwarded-Proto https"); + } frontendConfigs.add(sb.toString()); sb = new StringBuilder(); sb.append("\t").append("balance ").append(algorithm); @@ -628,7 +639,7 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv keepAliveEnabled = false; } - if (http || httpbasedStickiness) { + if (http || httpbasedStickiness || sslOffloading) { sb = new StringBuilder(); sb.append("\t").append("mode http"); frontendConfigs.add(sb.toString()); @@ -869,4 +880,23 @@ public String[][] generateFwRules(final LoadBalancerConfigCommand lbCmd) { return result; } + + @Override + public SslCertEntry[] generateSslCertEntries(LoadBalancerConfigCommand lbCmd) { + final Set sslCertEntries = new HashSet(); + for (final LoadBalancerTO lbTO : lbCmd.getLoadBalancers()) { + if (lbTO.getSslCert() != null) { + final LbSslCert cert = lbTO.getSslCert(); + if (cert.isRevoked()) { + continue; + } + StringBuilder sb = new StringBuilder(); + final String name = sb.append(lbTO.getSrcIp().replace(".", "_")).append('-').append(lbTO.getSrcPort()).toString(); + final SslCertEntry sslCertEntry = new SslCertEntry(name, cert.getCert(), cert.getKey(), cert.getChain(), cert.getPassword()); + sslCertEntries.add(sslCertEntry); + } + } + final SslCertEntry[] result = sslCertEntries.toArray(new SslCertEntry[sslCertEntries.size()]); + return result; + } } diff --git a/core/src/main/java/com/cloud/network/LoadBalancerConfigurator.java b/core/src/main/java/com/cloud/network/LoadBalancerConfigurator.java index 0e19b1e606e9..8814f60b0714 100644 --- a/core/src/main/java/com/cloud/network/LoadBalancerConfigurator.java +++ b/core/src/main/java/com/cloud/network/LoadBalancerConfigurator.java @@ -23,6 +23,7 @@ import com.cloud.agent.api.routing.LoadBalancerConfigCommand; import com.cloud.agent.api.to.PortForwardingRuleTO; +import com.cloud.agent.resource.virtualnetwork.model.LoadBalancerRule.SslCertEntry; public interface LoadBalancerConfigurator { public final static int ADD = 0; @@ -34,4 +35,6 @@ public interface LoadBalancerConfigurator { public String[] generateConfiguration(LoadBalancerConfigCommand lbCmd); public String[][] generateFwRules(LoadBalancerConfigCommand lbCmd); + + public SslCertEntry[] generateSslCertEntries(LoadBalancerConfigCommand lbCmd); } diff --git a/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java b/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java index bbc6aa77b790..13be11b3c433 100644 --- a/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java @@ -535,6 +535,8 @@ private static Map> setCapabilities() { lbCapabilities.put(Capability.SupportedProtocols, "tcp, udp, tcp-proxy"); lbCapabilities.put(Capability.SupportedStickinessMethods, getHAProxyStickinessCapability()); lbCapabilities.put(Capability.LbSchemes, LoadBalancerContainer.Scheme.Public.toString()); + // Supports SSL offloading + lbCapabilities.put(Capability.SslTermination, "true"); // specifies that LB rules can support autoscaling and the list of // counters it supports diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index 785f259b2c18..97bece2df727 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -94,10 +94,10 @@ import com.cloud.network.dao.Site2SiteVpnGatewayDao; import com.cloud.network.dao.Site2SiteVpnGatewayVO; import com.cloud.network.dao.VpnUserDao; +import com.cloud.network.lb.LoadBalancerConfigManager; import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; -import com.cloud.network.lb.LoadBalancerConfigManager; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRuleVO; @@ -320,6 +320,7 @@ public void createApplyLoadBalancingRulesCommands(final List final List destinations = rule.getDestinations(); final List stickinessPolicies = rule.getStickinessPolicies(); final LoadBalancerTO lb = new LoadBalancerTO(uuid, srcIp, srcPort, protocol, algorithm, revoked, false, inline, destinations, stickinessPolicies); + lb.setLbSslCert(rule.getLbSslCert()); lb.setLbProtocol(lb_protocol); lb.setLbConfigs(_lbConfigMgr.getRuleLbConfigs(rule.getId())); lbs[i++] = lb; diff --git a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py index 02d28514b9b5..aca8caae7b91 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py @@ -34,6 +34,10 @@ def process(self): return if 'configuration' not in self.dbag['config'][0].keys(): return + + ssl_certs = self.dbag['config'][0]['ssl_certs'] + self._create_pem_for_sslcert(ssl_certs) + config = self.dbag['config'][0]['configuration'] file1 = CsFile(HAPROXY_CONF_T) file1.empty() @@ -105,3 +109,15 @@ def _configure_firewall_for_transparent(self, is_transparent): if not CsHelper.execute("ip rule show fwmark %s lookup %s" % (tableNo, tableNo)): CsHelper.execute("ip rule add fwmark %s lookup %s" % (tableNo, tableNo)) CsHelper.execute("ip route add local 0.0.0.0/0 dev lo table %s" % tableNo) + + def _create_pem_for_sslcert(self, ssl_certs): + logging.debug("CsLoadBalancer:: removing all pem files in /etc/ssl/private and creating new pem files") + CsHelper.execute("rm -rf /etc/ssl/private/*.pem") + for cert in ssl_certs: + file = CsFile("/etc/ssl/private/%s.pem" % cert['name']) + file.empty() + file.add("%s\n" % cert['cert'].replace("\r\n","\n")) + if 'chain' in cert.keys(): + file.add("%s\n" % cert['chain'].replace("\r\n","\n")) + file.add("%s\n" % cert['key'].replace("\r\n","\n")) + file.commit() From 1e7dd8fa6a547cb643165c334afbbf6a8efbd3da Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Thu, 18 Jun 2020 09:02:31 +0000 Subject: [PATCH 30/75] Lb SSL offloading: fix test failures in core/ --- core/src/main/java/com/cloud/network/HAProxyConfigurator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 37d0adf57992..52b395db67a8 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -493,7 +493,7 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv } boolean sslOffloading = false; - if (lbTO.getLbProtocol().equals(NetUtils.SSL_PROTO) && lbTO.getSslCert() != null) { + if (lbTO.getSslCert() != null && lbTO.getLbProtocol() != null && lbTO.getLbProtocol().equals(NetUtils.SSL_PROTO)) { sslOffloading = true; } From 68036f7c02b693da3f77b29bceb9642f279dcf08 Mon Sep 17 00:00:00 2001 From: Rakesh Venkatesh Date: Thu, 18 Jun 2020 14:09:52 +0000 Subject: [PATCH 31/75] CLSTACK-6898 - Enable HTTP2 support in LB Provide a load balancer rule which enables http2 support in haproxy load balancer --- .../apache/cloudstack/network/lb/LoadBalancerConfigKey.java | 2 ++ core/src/main/java/com/cloud/network/HAProxyConfigurator.java | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index e3e29d31fe66..f2530cb7bd14 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -41,6 +41,8 @@ public enum LoadBalancerConfigKey { LbHttp(Category.LoadBalancer, "lb.http", "LB http enabled/disabled", Boolean.class, "true for port 80; false for other ports", "If LB is http, default is 'true' for port 80 and 'false' for others'", Scope.LoadBalancerRule), + LbHttp2(Category.LoadBalancer, "lb.http2", "Enable/disable HTTP2 support", Boolean.class, "false", "Enable or disable HTTP2 support in HAproxy", Scope.LoadBalancerRule), + LbHttpKeepalive(Category.LoadBalancer, "lb.http.keepalive", "LB http keepalive enabled/disabled", Boolean.class, "", "Enable or disable HTTP keep-alive, default is inherited from network offering", Scope.LoadBalancerRule), LbTransparent(Category.LoadBalancer, "lb.transparent.mode", "LB transparent mode enabled/disabled", Boolean.class, "false", "Enable or disable transparent mode, default is 'false'", Scope.LoadBalancerRule), diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 52b395db67a8..dec546be154c 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -506,6 +506,10 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv sb.append("\tbind ").append(publicIP).append(":").append(publicPort); if (sslOffloading) { sb.append(" ssl crt /etc/ssl/private/").append(poolName).append(".pem"); + // check for http2 support + if ("true".equalsIgnoreCase(lbConfigsMap.get(LoadBalancerConfigKey.LbHttp2.key()))) { + sb.append(" alpn h2,http/1.1"); + } sb.append("\n\thttp-request add-header X-Forwarded-Proto https"); } frontendConfigs.add(sb.toString()); From ece2b9be45fa159660acfd6650b810a11f4be602 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 19 Jun 2020 05:55:46 +0000 Subject: [PATCH 32/75] UI for SSL offloading --- ui/scripts/lbCertificatePolicy.js | 42 ++++++++++++++++++------------- ui/scripts/network.js | 18 +++++++++++-- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/ui/scripts/lbCertificatePolicy.js b/ui/scripts/lbCertificatePolicy.js index c9af682465c7..79225c318d8b 100644 --- a/ui/scripts/lbCertificatePolicy.js +++ b/ui/scripts/lbCertificatePolicy.js @@ -67,7 +67,7 @@ data: $.map(items, function(item) { return { id: item.id, - description: item.id + description: item.name }; }) }); @@ -86,18 +86,18 @@ fields: certid }, after: function(args) { - // Remove fields not applicable to sticky method + // Remove fields not applicable to certificate args.$form.find('.form-item:hidden').remove(); var data = cloudStack.serializeForm(args.$form); - /* $item indicates that this is an existing sticky rule; - re-create sticky rule with new parameters */ + /* $item indicates that this is an existing certificate; + remove it and assign new certificate */ if ($item) { var $loading = $('
').addClass('loading-overlay'); $loading.prependTo($item); - cloudStack.lbStickyPolicy.actions.recreate( + cloudStack.lbCertificatePolicy.actions.recreate( $item.data('multi-custom-data').id, $item.data('multi-custom-data').lbRuleID, data, @@ -145,19 +145,19 @@ } }); }, - 'delete': function(stickyRuleID, complete, error) { + 'delete': function(lbRuleID, complete, error) { $.ajax({ - url: createURL('deleteLBStickinessPolicy'), + url: createURL('removeCertFromLoadBalancer'), data: { - id: stickyRuleID + lbruleid: lbRuleID }, success: function(json) { cloudStack.ui.notifications.add({ - desc: 'Remove previous LB sticky rule', + desc: 'Remove previous LB Certificate', section: 'Network', poll: pollAsyncJobResult, _custom: { - jobId: json.deleteLBstickinessrruleresponse.jobid + jobId: json.removecertfromloadbalancerresponse.jobid } }, complete, {}, @@ -172,9 +172,9 @@ } }); }, - recreate: function(stickyRuleID, lbRuleID, data, complete, error) { - var addStickyPolicy = function() { - cloudStack.lbStickyPolicy.actions.add( + recreate: function(certId, lbRuleID, data, complete, error) { + var addCertificatePolicy = function() { + cloudStack.lbCertificatePolicy.actions.add( lbRuleID, data, complete, @@ -182,11 +182,19 @@ ); }; - // Delete existing rule - if (data.methodname !== 'None') { - addStickyPolicy(); + if (certId && certId == data.certificate) { + cloudStack.dialog.notice({ + message: _l('Certificate is not changed') + }); + $(window).trigger('cloudStack.fullRefresh'); } else { - cloudStack.lbStickyPolicy.actions['delete'](stickyRuleID, complete, error); + if (certId) { + // Delete existing certificate + cloudStack.lbCertificatePolicy.actions['delete'](lbRuleID, complete, error); + setTimeout(addCertificatePolicy, 2000); + } else { + addCertificatePolicy(); + } } } } diff --git a/ui/scripts/network.js b/ui/scripts/network.js index ed4e4edb4a5a..ef6f43463d5d 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -4119,6 +4119,9 @@ }); // Get SSL Certificate data + if (lbRule.protocol != "ssl") { + lbRule._hideFields.push('sslcertificate'); + }; $.ajax({ url: createURL('listSslCerts'), data: { @@ -4127,8 +4130,18 @@ }, async: false, success: function(json) { - if (json.listsslcertsresponse != null) { - lbRule._hideFields.push('sslcertificate'); + var sslcert = json.listsslcertsresponse.sslcert ? + json.listsslcertsresponse.sslcert[0] : null; + + if (sslcert) { + sslCertData = { + id: sslcert.id, + lbRuleID: lbRule.id + }; + } else { + sslCertData = { + lbRuleID: lbRule.id + }; } } }); @@ -4188,6 +4201,7 @@ name: 7 }, sticky: stickyData, + sslcertificate: sslCertData, autoScale: { lbRuleID: lbRule.id } From 30052e47c7d3d2dea011231ad15afd15c88b09d8 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 19 Jun 2020 05:56:10 +0000 Subject: [PATCH 33/75] LB SSL offloading: Fix issue when remove cert from lb --- core/src/main/java/com/cloud/network/HAProxyConfigurator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index dec546be154c..38c71e339a37 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -493,7 +493,8 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv } boolean sslOffloading = false; - if (lbTO.getSslCert() != null && lbTO.getLbProtocol() != null && lbTO.getLbProtocol().equals(NetUtils.SSL_PROTO)) { + if (lbTO.getSslCert() != null && ! lbTO.getSslCert().isRevoked() + && lbTO.getLbProtocol() != null && lbTO.getLbProtocol().equals(NetUtils.SSL_PROTO)) { sslOffloading = true; } From 78eabc157ebd1c401a8f992b2d868b4f9183d452 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 19 Jun 2020 20:40:39 +0000 Subject: [PATCH 34/75] add forced to AssignCertToLoadBalancerCmd --- .../network/lb/LoadBalancingRulesService.java | 2 +- .../AssignCertToLoadBalancerCmd.java | 36 ++++++++++++++++++- .../RemoveCertFromLoadBalancerCmd.java | 25 +++++++++++++ .../lb/LoadBalancingRulesManagerImpl.java | 11 ++++-- ui/scripts/lbCertificatePolicy.js | 34 ++++++++++-------- 5 files changed, 89 insertions(+), 19 deletions(-) diff --git a/api/src/main/java/com/cloud/network/lb/LoadBalancingRulesService.java b/api/src/main/java/com/cloud/network/lb/LoadBalancingRulesService.java index 50b39d2f3382..8d44f036b697 100644 --- a/api/src/main/java/com/cloud/network/lb/LoadBalancingRulesService.java +++ b/api/src/main/java/com/cloud/network/lb/LoadBalancingRulesService.java @@ -102,7 +102,7 @@ LoadBalancer createPublicLoadBalancerRule(String xId, String name, String descri boolean applyLoadBalancerConfig(long lbRuleId) throws ResourceUnavailableException; - boolean assignCertToLoadBalancer(long lbRuleId, Long certId); + boolean assignCertToLoadBalancer(long lbRuleId, Long certId, boolean forced); boolean removeCertFromLoadBalancer(long lbRuleId); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/AssignCertToLoadBalancerCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/AssignCertToLoadBalancerCmd.java index 663815106e51..38b586f1dff2 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/AssignCertToLoadBalancerCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/AssignCertToLoadBalancerCmd.java @@ -20,6 +20,7 @@ import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiCommandJobType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; @@ -60,11 +61,16 @@ public class AssignCertToLoadBalancerCmd extends BaseAsyncCmd { description = "the ID of the certificate") Long certId; + @Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN, required = false, + description = "Force assign the certificate. If there is a certificate bound to the LB, it will be removed") + private Boolean forced; + + @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { //To change body of implemented methods use File | Settings | File Templates. - if (_lbService.assignCertToLoadBalancer(getLbRuleId(), getCertId())) { + if (_lbService.assignCertToLoadBalancer(getLbRuleId(), getCertId(), isForced())) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); } else { @@ -103,4 +109,32 @@ public Long getCertId() { public Long getLbRuleId() { return lbRuleId; } + + public boolean isForced() { + return (forced != null) ? forced : false; + } + + @Override + public ApiCommandJobType getInstanceType() { + return ApiCommandJobType.LoadBalancerRule; + } + + @Override + public Long getInstanceId() { + return lbRuleId; + } + + @Override + public String getSyncObjType() { + return BaseAsyncCmd.networkSyncObject; + } + + @Override + public Long getSyncObjId() { + LoadBalancer lb = _entityMgr.findById(LoadBalancer.class, getLbRuleId()); + if (lb == null) { + return null; + } + return lb.getNetworkId(); + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/RemoveCertFromLoadBalancerCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/RemoveCertFromLoadBalancerCmd.java index d794384b4fa1..c9ca72b44973 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/RemoveCertFromLoadBalancerCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/RemoveCertFromLoadBalancerCmd.java @@ -19,6 +19,7 @@ import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiCommandJobType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; @@ -90,4 +91,28 @@ public long getEntityOwnerId() { public Long getLbRuleId() { return this.lbRuleId; } + + @Override + public ApiCommandJobType getInstanceType() { + return ApiCommandJobType.LoadBalancerRule; + } + + @Override + public Long getInstanceId() { + return lbRuleId; + } + + @Override + public String getSyncObjType() { + return BaseAsyncCmd.networkSyncObject; + } + + @Override + public Long getSyncObjId() { + LoadBalancer lb = _entityMgr.findById(LoadBalancer.class, getLbRuleId()); + if (lb == null) { + return null; + } + return lb.getNetworkId(); + } } diff --git a/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index d2b6305c1ff1..8ce5b2f73023 100644 --- a/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -1176,7 +1176,7 @@ public LbSslCert getLbSslCert(long lbRuleId) { @Override @DB @ActionEvent(eventType = EventTypes.EVENT_LB_CERT_ASSIGN, eventDescription = "assigning certificate to load balancer", async = true) - public boolean assignCertToLoadBalancer(long lbRuleId, Long certId) { + public boolean assignCertToLoadBalancer(long lbRuleId, Long certId, boolean forced) { CallContext caller = CallContext.current(); LoadBalancerVO loadBalancer = _lbDao.findById(Long.valueOf(lbRuleId)); @@ -1203,8 +1203,13 @@ public boolean assignCertToLoadBalancer(long lbRuleId, Long certId) { //check if the lb is already bound LoadBalancerCertMapVO certMapRule = _lbCertMapDao.findByLbRuleId(loadBalancer.getId()); - if (certMapRule != null) - throw new InvalidParameterValueException("Another certificate is already bound to the LB"); + if (certMapRule != null) { + if (! forced) { + throw new InvalidParameterValueException("Another certificate is already bound to the LB"); + } + s_logger.debug("Another certificate is already bound to the LB, removing it"); + removeCertFromLoadBalancer(lbRuleId); + } //check for correct port if (loadBalancer.getLbProtocol() == null || !(loadBalancer.getLbProtocol().equals(NetUtils.SSL_PROTO))) diff --git a/ui/scripts/lbCertificatePolicy.js b/ui/scripts/lbCertificatePolicy.js index 79225c318d8b..ab72a09d6acc 100644 --- a/ui/scripts/lbCertificatePolicy.js +++ b/ui/scripts/lbCertificatePolicy.js @@ -65,15 +65,20 @@ var items = json.listsslcertsresponse.sslcert; args.response.success({ data: $.map(items, function(item) { - return { - id: item.id, - description: item.name - }; - }) + return { + id: item.id, + description: item.name + }; + }) }); } }); } + }, + forced: { + label: 'Force Assign', + isBoolean: true, + isChecked: false } }; @@ -83,7 +88,14 @@ form: { title: 'Configure Certificate', desc: 'Please complete the following fields', - fields: certid + fields: certid, + preFilter: function(args) { + if ($item) { + var certId = $item.data('multi-custom-data').id; + var $cert = args.$form.find('select[name=certificate]'); + $cert.val(certId); + } + } }, after: function(args) { // Remove fields not applicable to certificate @@ -123,7 +135,7 @@ $.ajax({ url: createURL('assignCertToLoadBalancer'), - data: {certid: data.certificate, lbruleid: lbRuleID}, + data: {certid: data.certificate, lbruleid: lbRuleID, forced: data.forced == "on"}, success: function(json) { cloudStack.ui.notifications.add({ desc: 'Add new LB Certificate', @@ -188,13 +200,7 @@ }); $(window).trigger('cloudStack.fullRefresh'); } else { - if (certId) { - // Delete existing certificate - cloudStack.lbCertificatePolicy.actions['delete'](lbRuleID, complete, error); - setTimeout(addCertificatePolicy, 2000); - } else { - addCertificatePolicy(); - } + addCertificatePolicy(); } } } From 1584234b7af5ad7bbd135e94b8df6a0df721c442 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Sat, 20 Jun 2020 09:57:47 +0000 Subject: [PATCH 35/75] Update LB protocol --- .../network/lb/LoadBalancingRulesManagerImpl.java | 11 ++++++++++- .../com/cloud/network/router/NetworkHelperImpl.java | 5 +++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index 8ce5b2f73023..77e1460dea2e 100644 --- a/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -2092,6 +2092,7 @@ public LoadBalancer updateLoadBalancerRule(UpdateLoadBalancerRuleCmd cmd) { LoadBalancerVO lbBackup = _lbDao.findById(lbRuleId); String customId = cmd.getCustomId(); Boolean forDisplay = cmd.getDisplay(); + String protocol = cmd.getLbProtocol(); if (lb == null) { throw new InvalidParameterValueException("Unable to find lb rule by id=" + lbRuleId); @@ -2120,6 +2121,10 @@ public LoadBalancer updateLoadBalancerRule(UpdateLoadBalancerRuleCmd cmd) { lb.setDisplay(forDisplay); } + if (protocol != null) { + lb.setLbProtocol(protocol); + } + // Validate rule in LB provider LoadBalancingRule rule = getLoadBalancerRuleToApply(lb); if (!validateLbRule(rule)) { @@ -2130,7 +2135,8 @@ public LoadBalancer updateLoadBalancerRule(UpdateLoadBalancerRuleCmd cmd) { boolean success = _lbDao.update(lbRuleId, lb); // If algorithm is changed, have to reapply the lb config - if ((algorithm != null) && (tmplbVo.getAlgorithm().compareTo(algorithm) != 0)){ + if ((algorithm != null && tmplbVo.getAlgorithm().compareTo(algorithm) != 0) + || (protocol != null && ! tmplbVo.getLbProtocol().equalsIgnoreCase(protocol))) { try { lb.setState(FirewallRule.State.Add); _lbDao.persist(lb); @@ -2151,6 +2157,9 @@ public LoadBalancer updateLoadBalancerRule(UpdateLoadBalancerRuleCmd cmd) { if (lbBackup.getAlgorithm() != null) { lb.setAlgorithm(lbBackup.getAlgorithm()); } + if (lbBackup.getLbProtocol() != null) { + lb.setLbProtocol(lbBackup.getLbProtocol()); + } lb.setState(lbBackup.getState()); _lbDao.update(lb.getId(), lb); _lbDao.persist(lb); diff --git a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java index 39b3f0da0e73..90e8e7accc98 100644 --- a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java +++ b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java @@ -799,6 +799,11 @@ public boolean validateHAProxyLBRule(final LoadBalancingRule rule) { return false; } + List lbProtocols = Arrays.asList("tcp", "udp", "tcp-proxy", "ssl"); + if (! lbProtocols.contains(rule.getLbProtocol())) { + throw new InvalidParameterValueException("protocol " + rule.getLbProtocol() + " is not in valid protocols " + lbProtocols); + } + for (final LoadBalancingRule.LbStickinessPolicy stickinessPolicy : rule.getStickinessPolicies()) { final List> paramsList = stickinessPolicy.getParams(); From 81125fceda409300e81279d59ec89445ab7fd33a Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 22 Jun 2020 07:30:16 +0000 Subject: [PATCH 36/75] UI: add 'none' to dropdown so that remove lb certificate --- ui/scripts/lbCertificatePolicy.js | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/ui/scripts/lbCertificatePolicy.js b/ui/scripts/lbCertificatePolicy.js index ab72a09d6acc..c893a37e086c 100644 --- a/ui/scripts/lbCertificatePolicy.js +++ b/ui/scripts/lbCertificatePolicy.js @@ -63,13 +63,18 @@ return; } var items = json.listsslcertsresponse.sslcert; + var data = [{ + id: 'none', + description: '---None---' + }]; + $.map(items, function(item) { + data.push({ + id: item.id, + description: item.name + }); + }); args.response.success({ - data: $.map(items, function(item) { - return { - id: item.id, - description: item.name - }; - }) + data: data }); } }); @@ -199,6 +204,14 @@ message: _l('Certificate is not changed') }); $(window).trigger('cloudStack.fullRefresh'); + } else if (certId == null && data.certificate == 'none') { + cloudStack.dialog.notice({ + message: _l('Certificate is not assigned') + }); + $(window).trigger('cloudStack.fullRefresh'); + } else if (certId && data.certificate == 'none') { + // Delete existing certificate + cloudStack.lbCertificatePolicy.actions['delete'](lbRuleID, complete, error); } else { addCertificatePolicy(); } From 3e089fe4664147121cd414d16b263e26e039cfc4 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 22 Jun 2020 12:11:27 +0000 Subject: [PATCH 37/75] LB: Add lb.backend.https (it will use 'check ssl verify none' instead of 'check' for backend servers in haproxy.cfg) --- .../cloudstack/network/lb/LoadBalancerConfigKey.java | 2 ++ .../main/java/com/cloud/network/HAProxyConfigurator.java | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index f2530cb7bd14..cfeefd1d925a 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -45,6 +45,8 @@ public enum LoadBalancerConfigKey { LbHttpKeepalive(Category.LoadBalancer, "lb.http.keepalive", "LB http keepalive enabled/disabled", Boolean.class, "", "Enable or disable HTTP keep-alive, default is inherited from network offering", Scope.LoadBalancerRule), + LbBackendHttps(Category.LoadBalancer, "lb.backend.https", "If backend server is https", Boolean.class, "false", "If backend server is https. If yes, use 'check ssl verify none' instead of 'check'", Scope.LoadBalancerRule), + LbTransparent(Category.LoadBalancer, "lb.transparent.mode", "LB transparent mode enabled/disabled", Boolean.class, "false", "Enable or disable transparent mode, default is 'false'", Scope.LoadBalancerRule), GlobalMaxConn(Category.LoadBalancer, "global.maxconn", "LB max connection", Long.class, "4096", "Maximum per process number of concurrent connections, default is '4096'", Scope.Network, Scope.Vpc), diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 38c71e339a37..66176788c80d 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -573,8 +573,12 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv .append(" ") .append(dest.getDestIp()) .append(":") - .append(dest.getDestPort()) - .append(" check"); + .append(dest.getDestPort()); + if ("true".equalsIgnoreCase(lbConfigsMap.get(LoadBalancerConfigKey.LbBackendHttps.key()))) { + sb.append(" check ssl verify none"); + } else { + sb.append(" check"); + } if (lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxConn.key()) != null) { long maxConnEach = Long.parseLong(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxConn.key())); From fdb416eef1f08642df676b8c0b23c75591e0e38e Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 24 Jun 2020 22:21:10 +0000 Subject: [PATCH 38/75] LB SSL offloading: (1) move certs to /etc/ssl/cloudstack; (2)UI bug fixes; (3) create pem only when ssl offloading is enabled --- .../com/cloud/network/HAProxyConfigurator.java | 5 ++++- .../debian/opt/cloud/bin/cs/CsLoadBalancer.py | 17 ++++++++++++----- ui/scripts/lbCertificatePolicy.js | 13 +++++++++---- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 66176788c80d..94f6024264e9 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -506,7 +506,7 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv sb = new StringBuilder(); sb.append("\tbind ").append(publicIP).append(":").append(publicPort); if (sslOffloading) { - sb.append(" ssl crt /etc/ssl/private/").append(poolName).append(".pem"); + sb.append(" ssl crt /etc/ssl/cloudstack/").append(poolName).append(".pem"); // check for http2 support if ("true".equalsIgnoreCase(lbConfigsMap.get(LoadBalancerConfigKey.LbHttp2.key()))) { sb.append(" alpn h2,http/1.1"); @@ -899,6 +899,9 @@ public SslCertEntry[] generateSslCertEntries(LoadBalancerConfigCommand lbCmd) { if (cert.isRevoked()) { continue; } + if (lbTO.getLbProtocol() == null || ! lbTO.getLbProtocol().equals(NetUtils.SSL_PROTO)) { + continue; + } StringBuilder sb = new StringBuilder(); final String name = sb.append(lbTO.getSrcIp().replace(".", "_")).append('-').append(lbTO.getSrcPort()).toString(); final SslCertEntry sslCertEntry = new SslCertEntry(name, cert.getCert(), cert.getKey(), cert.getChain(), cert.getPassword()); diff --git a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py index aca8caae7b91..5d1f2863a353 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py @@ -16,6 +16,7 @@ # under the License. import logging import os.path +from os import listdir import re from cs.CsDatabag import CsDataBag from CsProcess import CsProcess @@ -35,8 +36,8 @@ def process(self): if 'configuration' not in self.dbag['config'][0].keys(): return - ssl_certs = self.dbag['config'][0]['ssl_certs'] - self._create_pem_for_sslcert(ssl_certs) + if 'ssl_certs' in self.dbag['config'][0].keys(): + self._create_pem_for_sslcert(self.dbag['config'][0]['ssl_certs']) config = self.dbag['config'][0]['configuration'] file1 = CsFile(HAPROXY_CONF_T) @@ -111,13 +112,19 @@ def _configure_firewall_for_transparent(self, is_transparent): CsHelper.execute("ip route add local 0.0.0.0/0 dev lo table %s" % tableNo) def _create_pem_for_sslcert(self, ssl_certs): - logging.debug("CsLoadBalancer:: removing all pem files in /etc/ssl/private and creating new pem files") - CsHelper.execute("rm -rf /etc/ssl/private/*.pem") + dir_certs = "/etc/ssl/cloudstack" + logging.debug("CsLoadBalancer:: creating new pem files in %s and cleaning up it" % dir_certs) + CsHelper.execute("mkdir -p %s" % dir_certs) + cert_names = [] for cert in ssl_certs: - file = CsFile("/etc/ssl/private/%s.pem" % cert['name']) + cert_names.append(cert['name'] + ".pem") + file = CsFile("%s/%s.pem" % (dir_certs, cert['name'])) file.empty() file.add("%s\n" % cert['cert'].replace("\r\n","\n")) if 'chain' in cert.keys(): file.add("%s\n" % cert['chain'].replace("\r\n","\n")) file.add("%s\n" % cert['key'].replace("\r\n","\n")) file.commit() + for f in listdir(dir_certs): + if f not in cert_names: + CsHelper.execute("rm %s/%s" % (dir_certs, f)) diff --git a/ui/scripts/lbCertificatePolicy.js b/ui/scripts/lbCertificatePolicy.js index c893a37e086c..a851bf48bc92 100644 --- a/ui/scripts/lbCertificatePolicy.js +++ b/ui/scripts/lbCertificatePolicy.js @@ -25,6 +25,7 @@ var certid = { certificate: { label: 'label.certificate.name', + required: true, select: function(args) { var data = {}; var item = {}; @@ -64,7 +65,7 @@ } var items = json.listsslcertsresponse.sslcert; var data = [{ - id: 'none', + id: 'None', description: '---None---' }]; $.map(items, function(item) { @@ -98,7 +99,11 @@ if ($item) { var certId = $item.data('multi-custom-data').id; var $cert = args.$form.find('select[name=certificate]'); - $cert.val(certId); + if (certId) { + $cert.val(certId); + } else { + $cert.val("None"); + } } } }, @@ -204,12 +209,12 @@ message: _l('Certificate is not changed') }); $(window).trigger('cloudStack.fullRefresh'); - } else if (certId == null && data.certificate == 'none') { + } else if (certId == null && data.certificate == 'None') { cloudStack.dialog.notice({ message: _l('Certificate is not assigned') }); $(window).trigger('cloudStack.fullRefresh'); - } else if (certId && data.certificate == 'none') { + } else if (certId && data.certificate == 'None') { // Delete existing certificate cloudStack.lbCertificatePolicy.actions['delete'](lbRuleID, complete, error); } else { From 2bd2c562ce732adade60e18a4883560c3e8db0cd Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 26 Jun 2020 07:07:21 +0000 Subject: [PATCH 39/75] LB SSL Offloading: create global constant SSL_CERTS_DIR, add tune.ssl.default-dh-param --- .../java/com/cloud/network/HAProxyConfigurator.java | 5 +++-- systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py | 12 ++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 94f6024264e9..b9feb0bfa2b7 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -48,12 +48,13 @@ public class HAProxyConfigurator implements LoadBalancerConfigurator { private static final Logger s_logger = Logger.getLogger(HAProxyConfigurator.class); private static final String blankLine = "\t "; private static String[] globalSection = {"global", "\tlog 127.0.0.1:3914 local0 warning", "\tmaxconn 4096", "\tmaxpipes 1024", "\tchroot /var/lib/haproxy", - "\tuser haproxy", "\tgroup haproxy", "\tdaemon"}; + "\tuser haproxy", "\tgroup haproxy", "\tdaemon", "\ttune.ssl.default-dh-param 2048"}; private static String[] defaultsSection = {"defaults", "\tlog global", "\tmode tcp", "\toption dontlognull", "\tretries 3", "\toption redispatch", "\toption forwardfor", "\toption forceclose", "\ttimeout connect 5000", "\ttimeout client 50000", "\ttimeout server 50000"}; private static String[] defaultListen = {"listen vmops", "\tbind 0.0.0.0:9", "\toption transparent"}; + private static final String SSL_CERTS_DIR = "/etc/ssl/cloudstack/"; @Override public String[] generateConfiguration(final List fwRules) { @@ -506,7 +507,7 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv sb = new StringBuilder(); sb.append("\tbind ").append(publicIP).append(":").append(publicPort); if (sslOffloading) { - sb.append(" ssl crt /etc/ssl/cloudstack/").append(poolName).append(".pem"); + sb.append(" ssl crt ").append(SSL_CERTS_DIR).append(poolName).append(".pem"); // check for http2 support if ("true".equalsIgnoreCase(lbConfigsMap.get(LoadBalancerConfigKey.LbHttp2.key()))) { sb.append(" alpn h2,http/1.1"); diff --git a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py index 5d1f2863a353..1a5e37b09219 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py @@ -26,6 +26,8 @@ HAPROXY_CONF_T = "/etc/haproxy/haproxy.cfg.new" HAPROXY_CONF_P = "/etc/haproxy/haproxy.cfg" +SSL_CERTS_DIR = "/etc/ssl/cloudstack/" +CsHelper.execute("mkdir -p %s" % SSL_CERTS_DIR) class CsLoadBalancer(CsDataBag): """ Manage Load Balancer entries """ @@ -112,19 +114,17 @@ def _configure_firewall_for_transparent(self, is_transparent): CsHelper.execute("ip route add local 0.0.0.0/0 dev lo table %s" % tableNo) def _create_pem_for_sslcert(self, ssl_certs): - dir_certs = "/etc/ssl/cloudstack" - logging.debug("CsLoadBalancer:: creating new pem files in %s and cleaning up it" % dir_certs) - CsHelper.execute("mkdir -p %s" % dir_certs) + logging.debug("CsLoadBalancer:: creating new pem files in %s and cleaning up it" % SSL_CERTS_DIR) cert_names = [] for cert in ssl_certs: cert_names.append(cert['name'] + ".pem") - file = CsFile("%s/%s.pem" % (dir_certs, cert['name'])) + file = CsFile("%s/%s.pem" % (SSL_CERTS_DIR, cert['name'])) file.empty() file.add("%s\n" % cert['cert'].replace("\r\n","\n")) if 'chain' in cert.keys(): file.add("%s\n" % cert['chain'].replace("\r\n","\n")) file.add("%s\n" % cert['key'].replace("\r\n","\n")) file.commit() - for f in listdir(dir_certs): + for f in listdir(SSL_CERTS_DIR): if f not in cert_names: - CsHelper.execute("rm %s/%s" % (dir_certs, f)) + CsHelper.execute("rm -rf %s/%s" % (SSL_CERTS_DIR, f)) From 23fdf4b0308fcf7dd0a2f0f1e33a84b7b215f8fd Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 23 Jun 2020 19:56:35 +0000 Subject: [PATCH 40/75] health check for LB configs --- .../VirtualNetworkApplianceManagerImpl.java | 72 +++++++++++++++++-- .../root/health_checks/haproxy_check.py | 25 +++++-- 2 files changed, 88 insertions(+), 9 deletions(-) diff --git a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 1103ff9c0589..98053dd2142b 100644 --- a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -33,6 +33,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.TimeZone; import java.util.concurrent.BlockingQueue; @@ -62,6 +63,7 @@ import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO; import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.cloudstack.network.lb.LoadBalancerConfigKey; import org.apache.cloudstack.network.topology.NetworkTopology; import org.apache.cloudstack.network.topology.NetworkTopologyContext; import org.apache.cloudstack.utils.identity.ManagementServerNode; @@ -161,6 +163,7 @@ import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.LBStickinessPolicyDao; import com.cloud.network.dao.LBStickinessPolicyVO; +import com.cloud.network.dao.LoadBalancerConfigDao; import com.cloud.network.dao.LoadBalancerDao; import com.cloud.network.dao.LoadBalancerVMMapDao; import com.cloud.network.dao.LoadBalancerVMMapVO; @@ -193,6 +196,7 @@ import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.network.rules.LoadBalancerConfig; import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.PortForwardingRuleVO; @@ -286,6 +290,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V @Inject private DataCenterDao _dcDao; @Inject protected VlanDao _vlanDao; @Inject private FirewallRulesDao _rulesDao; + @Inject private LoadBalancerConfigDao _lbConfigDao; @Inject private LoadBalancerDao _loadBalancerDao; @Inject private LoadBalancerVMMapDao _loadBalancerVMMapDao; @Inject protected IPAddressDao _ipAddressDao; @@ -1741,27 +1746,72 @@ private String getStickinessPolicies(long loadBalancingRuleId) { } private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final StringBuilder loadBalancingData) { + List networkLbConfigs = null; + if (routerJoinVO.getNetworkId() == 0) { + return; + } else { + Network network = _networkDao.findById(routerJoinVO.getNetworkId()); + if (network.getTrafficType() != TrafficType.Guest) { + return; + } + } + if (routerJoinVO.getVpcId() != 0) { + networkLbConfigs = _lbConfigDao.listByVpcId(routerJoinVO.getVpcId()); + } else { + networkLbConfigs = _lbConfigDao.listByNetworkId(routerJoinVO.getNetworkId()); + } + HashMap networkLbConfigsMap = new HashMap(); + if (networkLbConfigs != null) { + for (LoadBalancerConfig networkLbConfig: networkLbConfigs) { + networkLbConfigsMap.put(networkLbConfig.getName(), networkLbConfig.getValue()); + } + } + Optional lbConfig = Optional.ofNullable(networkLbConfigsMap.get(LoadBalancerConfigKey.GlobalMaxConn.key())); + String globalMaxConn = lbConfig.isPresent() ? lbConfig.get() : null; + List loadBalancerVOs = this.getLBRules(routerJoinVO); for (FirewallRuleVO firewallRuleVO : loadBalancerVOs) { + List lbConfigs = _lbConfigDao.listByLoadBalancerId(firewallRuleVO.getId()); + final HashMap lbConfigsMap = new HashMap(); + if (lbConfigs != null) { + for (LoadBalancerConfig config: lbConfigs) { + lbConfigsMap.put(config.getName(), config.getValue()); + } + } + lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbTransparent.key())); + String isTransparent = lbConfig.isPresent() ? lbConfig.get() : null; + lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbHttp.key())); + String isHttp = lbConfig.isPresent() ? lbConfig.get() : null; + lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbHttpKeepalive.key())); + String isHttpKeepalive = lbConfig.isPresent() ? lbConfig.get() : null; + List vmMapVOs = _loadBalancerVMMapDao.listByLoadBalancerId(firewallRuleVO.getId(), false); if (vmMapVOs.size() > 0) { final NetworkOffering offering = _networkOfferingDao.findById(_networkDao.findById(routerJoinVO.getNetworkId()).getNetworkOfferingId()); - if (offering.getConcurrentConnections() == null) { - loadBalancingData.append("maxconn=").append(_configDao.getValue(Config.NetworkLBHaproxyMaxConn.key())); + if (globalMaxConn != null) { + loadBalancingData.append("global.maxconn=").append(globalMaxConn); + } else if (offering.getConcurrentConnections() == null) { + loadBalancingData.append("global.maxconn=").append(_configDao.getValue(Config.NetworkLBHaproxyMaxConn.key())); } else { - loadBalancingData.append("maxconn=").append(offering.getConcurrentConnections().toString()); + loadBalancingData.append("global.maxconn=").append(offering.getConcurrentConnections().toString()); } loadBalancingData.append(",sourcePortStart=").append(firewallRuleVO.getSourcePortStart()) .append(",sourcePortEnd=").append(firewallRuleVO.getSourcePortEnd()); if (firewallRuleVO instanceof LoadBalancerVO) { LoadBalancerVO loadBalancerVO = (LoadBalancerVO) firewallRuleVO; - loadBalancingData.append(",sourceIp=").append(_ipAddressDao.findById(loadBalancerVO.getSourceIpAddressId()).getAddress().toString()) + String sourceIp = _ipAddressDao.findById(loadBalancerVO.getSourceIpAddressId()).getAddress().toString(); + loadBalancingData.append(",sourceIp=").append(sourceIp) .append(",destPortStart=").append(loadBalancerVO.getDefaultPortStart()) .append(",destPortEnd=").append(loadBalancerVO.getDefaultPortEnd()) .append(",algorithm=").append(loadBalancerVO.getAlgorithm()) .append(",protocol=").append(loadBalancerVO.getLbProtocol()); + final LbSslCert sslCert = _lbMgr.getLbSslCert(firewallRuleVO.getId()); + if (sslCert != null && ! sslCert.isRevoked()) { + loadBalancingData.append(",sslcert=").append(sourceIp.replace(".", "_")).append('-') + .append(loadBalancerVO.getSourcePortStart()).append(".pem"); + } } else if (firewallRuleVO instanceof ApplicationLoadBalancerRuleVO) { ApplicationLoadBalancerRuleVO appLoadBalancerVO = (ApplicationLoadBalancerRuleVO) firewallRuleVO; loadBalancingData.append(",sourceIp=").append(appLoadBalancerVO.getSourceIp()) @@ -1771,7 +1821,19 @@ private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final Stri .append(",protocol=").append(appLoadBalancerVO.getLbProtocol()); } loadBalancingData.append(",stickiness=").append(getStickinessPolicies(firewallRuleVO.getId())); - loadBalancingData.append(",keepAliveEnabled=").append(offering.isKeepAliveEnabled()).append(",vmIps="); + if (isHttp != null) { + loadBalancingData.append(",http=").append(isHttp); + } + if (isHttpKeepalive != null) { + loadBalancingData.append(",keepAliveEnabled=").append(isHttpKeepalive); + } else { + loadBalancingData.append(",keepAliveEnabled=").append(offering.isKeepAliveEnabled()); + } + if (isTransparent != null) { + loadBalancingData.append(",transparent=").append(isTransparent); + } + + loadBalancingData.append(",vmIps="); for (LoadBalancerVMMapVO vmMapVO : vmMapVOs) { loadBalancingData.append(vmMapVO.getInstanceIp()).append(" "); } diff --git a/systemvm/debian/root/health_checks/haproxy_check.py b/systemvm/debian/root/health_checks/haproxy_check.py index 56e0ce7d0b0d..48d9395c970e 100644 --- a/systemvm/debian/root/health_checks/haproxy_check.py +++ b/systemvm/debian/root/health_checks/haproxy_check.py @@ -21,8 +21,8 @@ def checkMaxconn(haproxyData, haCfgSections): - if "maxconn" in haproxyData and "maxconn" in haCfgSections["global"]: - if haproxyData["maxconn"] != haCfgSections["global"]["maxconn"][0].strip(): + if "global.maxconn" in haproxyData and "maxconn" in haCfgSections["global"]: + if haproxyData["global.maxconn"] != haCfgSections["global"]["maxconn"][0].strip(): print "global maxconn mismatch occured" return False @@ -36,12 +36,27 @@ def checkLoadBalance(haproxyData, haCfgSections): formatPort(lbSec["sourcePortStart"], lbSec["sourcePortEnd"]) secName = "listen " + srcServer - - if secName not in haCfgSections: + secFrontend = "frontend " + srcServer + secBackend = "backend " + srcServer + "-backend" + cfgSection = None + + if "transparent" in lbSec and lbSec["transparent"].lower() == 'true': + if secFrontend not in haCfgSections: + print "Missing section for load balancing " + secFrontend + "\n" + correct = False + elif secBackend not in haCfgSections: + print "Missing section for load balancing " + secBackend + "\n" + correct = False + else: + cfgSection = haCfgSections[secFrontend] + cfgSection.update(haCfgSections[secBackend]) + elif secName not in haCfgSections: print "Missing section for load balancing " + secName + "\n" correct = False else: cfgSection = haCfgSections[secName] + + if cfgSection: if "server" in cfgSection: if lbSec["algorithm"] != cfgSection["balance"][0]: print "Incorrect balance method for " + secName + \ @@ -50,6 +65,8 @@ def checkLoadBalance(haproxyData, haCfgSections): correct = False bindStr = lbSec["sourceIp"] + ":" + formatPort(lbSec["sourcePortStart"], lbSec["sourcePortEnd"]) + if lbSec.has_key("sslcert"): + bindStr += " ssl crt /etc/ssl/private/" + lbSec["sslcert"] if cfgSection["bind"][0] != bindStr: print "Incorrect bind string found. Expected " + bindStr + " but found " + cfgSection["bind"][0] + "." correct = False From d6c1251095b82327a9b45591f7a2576c2de7d48a Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 24 Jun 2020 07:37:12 +0000 Subject: [PATCH 41/75] haproxy check: global and defaults --- .../VirtualNetworkApplianceManagerImpl.java | 40 ++++++++++++++----- .../root/health_checks/haproxy_check.py | 33 +++++++++++++-- 2 files changed, 59 insertions(+), 14 deletions(-) diff --git a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 98053dd2142b..b3c301fe80ff 100644 --- a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -1768,8 +1768,36 @@ private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final Stri } Optional lbConfig = Optional.ofNullable(networkLbConfigsMap.get(LoadBalancerConfigKey.GlobalMaxConn.key())); String globalMaxConn = lbConfig.isPresent() ? lbConfig.get() : null; + lbConfig = Optional.ofNullable(networkLbConfigsMap.get(LoadBalancerConfigKey.GlobalMaxPipes.key())); + String globalMaxPipes = lbConfig.isPresent() ? lbConfig.get() : null; + final NetworkOffering offering = _networkOfferingDao.findById(_networkDao.findById(routerJoinVO.getNetworkId()).getNetworkOfferingId());; List loadBalancerVOs = this.getLBRules(routerJoinVO); + if (loadBalancerVOs.size() > 0) { + String globalMaxConnFinal; + if (globalMaxConn != null) { + globalMaxConnFinal = globalMaxConn; + } else if (offering.getConcurrentConnections() == null) { + globalMaxConnFinal = _configDao.getValue(Config.NetworkLBHaproxyMaxConn.key()); + } else { + globalMaxConnFinal = offering.getConcurrentConnections().toString(); + } + loadBalancingData.append("global.maxconn=").append(globalMaxConnFinal); + String globalMaxPipesFinal; + if (globalMaxPipes != null) { + globalMaxPipesFinal = globalMaxPipes; + } else { + globalMaxPipesFinal = Long.toString(Long.parseLong(globalMaxConnFinal) / 4); + } + loadBalancingData.append(",global.maxpipes=").append(globalMaxPipesFinal); + lbConfig = Optional.ofNullable(networkLbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutConnect.key())); + loadBalancingData.append(",default.timeout.connect=").append(lbConfig.isPresent() ? lbConfig.get() : 5000); + lbConfig = Optional.ofNullable(networkLbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutServer.key())); + loadBalancingData.append(",default.timeout.server=").append(lbConfig.isPresent() ? lbConfig.get() : 50000); + lbConfig = Optional.ofNullable(networkLbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutClient.key())); + loadBalancingData.append(",default.timeout.client=").append(lbConfig.isPresent() ? lbConfig.get() : 50000); + loadBalancingData.append(";"); + } for (FirewallRuleVO firewallRuleVO : loadBalancerVOs) { List lbConfigs = _lbConfigDao.listByLoadBalancerId(firewallRuleVO.getId()); final HashMap lbConfigsMap = new HashMap(); @@ -1787,17 +1815,7 @@ private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final Stri List vmMapVOs = _loadBalancerVMMapDao.listByLoadBalancerId(firewallRuleVO.getId(), false); if (vmMapVOs.size() > 0) { - - final NetworkOffering offering = _networkOfferingDao.findById(_networkDao.findById(routerJoinVO.getNetworkId()).getNetworkOfferingId()); - if (globalMaxConn != null) { - loadBalancingData.append("global.maxconn=").append(globalMaxConn); - } else if (offering.getConcurrentConnections() == null) { - loadBalancingData.append("global.maxconn=").append(_configDao.getValue(Config.NetworkLBHaproxyMaxConn.key())); - } else { - loadBalancingData.append("global.maxconn=").append(offering.getConcurrentConnections().toString()); - } - - loadBalancingData.append(",sourcePortStart=").append(firewallRuleVO.getSourcePortStart()) + loadBalancingData.append("sourcePortStart=").append(firewallRuleVO.getSourcePortStart()) .append(",sourcePortEnd=").append(firewallRuleVO.getSourcePortEnd()); if (firewallRuleVO instanceof LoadBalancerVO) { LoadBalancerVO loadBalancerVO = (LoadBalancerVO) firewallRuleVO; diff --git a/systemvm/debian/root/health_checks/haproxy_check.py b/systemvm/debian/root/health_checks/haproxy_check.py index 48d9395c970e..b20801bcb6f8 100644 --- a/systemvm/debian/root/health_checks/haproxy_check.py +++ b/systemvm/debian/root/health_checks/haproxy_check.py @@ -20,18 +20,44 @@ from utility import getHealthChecksData, formatPort -def checkMaxconn(haproxyData, haCfgSections): +def checkGlobal(haproxyData, haCfgSections): if "global.maxconn" in haproxyData and "maxconn" in haCfgSections["global"]: if haproxyData["global.maxconn"] != haCfgSections["global"]["maxconn"][0].strip(): print "global maxconn mismatch occured" return False + if "global.maxpipes" in haproxyData and "maxpipes" in haCfgSections["global"]: + if haproxyData["global.maxpipes"] != haCfgSections["global"]["maxpipes"][0].strip(): + print "global maxpipes mismatch occured" + return False return True +def checkDefaults(haproxyData, haCfgSections): + if "timeout" in haCfgSections["defaults"]: + timeouts = haCfgSections["defaults"]["timeout"] + if "default.timeout.connect" in haproxyData: + timeout = "connect %s" % haproxyData["default.timeout.connect"] + if timeout not in timeouts: + print "default timeout connect mismatch occured" + return False + if "default.timeout.server" in haproxyData: + timeout = "server %s" % haproxyData["default.timeout.server"] + if timeout not in timeouts: + print "default timeout server mismatch occured" + return False + if "default.timeout.client" in haproxyData: + timeout = "client %s" % haproxyData["default.timeout.client"] + if timeout not in timeouts: + print "default timeout client mismatch occured" + return False + + return True def checkLoadBalance(haproxyData, haCfgSections): correct = True for lbSec in haproxyData: + if "global.maxconn" in lbSec: # Ignore first part (global and default settings) + continue; srcServer = lbSec["sourceIp"].replace('.', '_') + "-" + \ formatPort(lbSec["sourcePortStart"], lbSec["sourcePortEnd"]) @@ -136,10 +162,11 @@ def main(): currSectionDict[lineSec[0]].append(lineSec[1] if len(lineSec) > 1 else '') - checkMaxConn = checkMaxconn(haproxyData[0], haCfgSections) + checkGlobalResult = checkGlobal(haproxyData[0], haCfgSections) + checkDefaultsResult = checkDefaults(haproxyData[0], haCfgSections) checkLbRules = checkLoadBalance(haproxyData, haCfgSections) - if checkMaxConn and checkLbRules: + if checkGlobalResult and checkDefaultsResult and checkLbRules: print "All checks pass" exit(0) else: From 9f3438400735648d0fb050289cd0c6dad32b977f Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Thu, 25 Jun 2020 21:08:21 +0000 Subject: [PATCH 42/75] move /etc/ssl/private/ to /etc/ssl/cloudstack/ --- systemvm/debian/root/health_checks/haproxy_check.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/systemvm/debian/root/health_checks/haproxy_check.py b/systemvm/debian/root/health_checks/haproxy_check.py index b20801bcb6f8..e1b34302d438 100644 --- a/systemvm/debian/root/health_checks/haproxy_check.py +++ b/systemvm/debian/root/health_checks/haproxy_check.py @@ -19,6 +19,7 @@ from os import sys, path from utility import getHealthChecksData, formatPort +SSL_CERTS_DIR = "/etc/ssl/cloudstack/" def checkGlobal(haproxyData, haCfgSections): if "global.maxconn" in haproxyData and "maxconn" in haCfgSections["global"]: @@ -92,7 +93,7 @@ def checkLoadBalance(haproxyData, haCfgSections): bindStr = lbSec["sourceIp"] + ":" + formatPort(lbSec["sourcePortStart"], lbSec["sourcePortEnd"]) if lbSec.has_key("sslcert"): - bindStr += " ssl crt /etc/ssl/private/" + lbSec["sslcert"] + bindStr += " ssl crt " + SSL_CERTS_DIR + lbSec["sslcert"] if cfgSection["bind"][0] != bindStr: print "Incorrect bind string found. Expected " + bindStr + " but found " + cfgSection["bind"][0] + "." correct = False From d7c48f4c2b6acc45b816c41290fbe5fa58f1b7f2 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 1 Jul 2020 09:21:32 +0000 Subject: [PATCH 43/75] LB haproxy check: fix check failure after VR restart --- systemvm/debian/opt/cloud/bin/vr_cfg.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/systemvm/debian/opt/cloud/bin/vr_cfg.sh b/systemvm/debian/opt/cloud/bin/vr_cfg.sh index 619ec5c44836..00a22c83bda7 100755 --- a/systemvm/debian/opt/cloud/bin/vr_cfg.sh +++ b/systemvm/debian/opt/cloud/bin/vr_cfg.sh @@ -68,7 +68,7 @@ while read line; do if [ "$line" == "" ]; then break fi - echo $line >> $file + echo "$line" >> $file done log_it "VR config: create file success" From edd8e0ed0512db8249e98dfe564adf07fe9054ad Mon Sep 17 00:00:00 2001 From: Rakesh Venkatesh Date: Wed, 1 Jul 2020 10:59:51 +0000 Subject: [PATCH 44/75] CLSTACK-7838 - Fix haproxy configs for servers Validate the haproxy lb.server values with the data stored in the json field --- .../VirtualNetworkApplianceManagerImpl.java | 35 +++++++++++++------ .../root/health_checks/haproxy_check.py | 23 +++++++++++- 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index b3c301fe80ff..5adc4740ef81 100644 --- a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -33,6 +33,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.TimeZone; @@ -1767,9 +1768,9 @@ private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final Stri } } Optional lbConfig = Optional.ofNullable(networkLbConfigsMap.get(LoadBalancerConfigKey.GlobalMaxConn.key())); - String globalMaxConn = lbConfig.isPresent() ? lbConfig.get() : null; + String globalMaxConn = lbConfig.orElse(null); lbConfig = Optional.ofNullable(networkLbConfigsMap.get(LoadBalancerConfigKey.GlobalMaxPipes.key())); - String globalMaxPipes = lbConfig.isPresent() ? lbConfig.get() : null; + String globalMaxPipes = lbConfig.orElse(null); final NetworkOffering offering = _networkOfferingDao.findById(_networkDao.findById(routerJoinVO.getNetworkId()).getNetworkOfferingId());; List loadBalancerVOs = this.getLBRules(routerJoinVO); @@ -1784,11 +1785,8 @@ private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final Stri } loadBalancingData.append("global.maxconn=").append(globalMaxConnFinal); String globalMaxPipesFinal; - if (globalMaxPipes != null) { - globalMaxPipesFinal = globalMaxPipes; - } else { - globalMaxPipesFinal = Long.toString(Long.parseLong(globalMaxConnFinal) / 4); - } + globalMaxPipesFinal = Objects.requireNonNullElseGet(globalMaxPipes, + () -> Long.toString(Long.parseLong(globalMaxConnFinal) / 4)); loadBalancingData.append(",global.maxpipes=").append(globalMaxPipesFinal); lbConfig = Optional.ofNullable(networkLbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutConnect.key())); loadBalancingData.append(",default.timeout.connect=").append(lbConfig.isPresent() ? lbConfig.get() : 5000); @@ -1807,11 +1805,19 @@ private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final Stri } } lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbTransparent.key())); - String isTransparent = lbConfig.isPresent() ? lbConfig.get() : null; + String isTransparent = lbConfig.orElse(null); lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbHttp.key())); - String isHttp = lbConfig.isPresent() ? lbConfig.get() : null; + String isHttp = lbConfig.orElse(null); lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbHttpKeepalive.key())); - String isHttpKeepalive = lbConfig.isPresent() ? lbConfig.get() : null; + String isHttpKeepalive = lbConfig.orElse(null); + lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxConn.key())); + + // Process lb.server values + String serverMaxconn = lbConfig.orElse(null); + lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMinConn.key())); + String serverMinconn = lbConfig.orElse(null); + lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxQueue.key())); + String serverMaxqueue = lbConfig.orElse(null); List vmMapVOs = _loadBalancerVMMapDao.listByLoadBalancerId(firewallRuleVO.getId(), false); if (vmMapVOs.size() > 0) { @@ -1850,6 +1856,15 @@ private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final Stri if (isTransparent != null) { loadBalancingData.append(",transparent=").append(isTransparent); } + if (serverMaxconn != null) { + loadBalancingData.append(",server.maxconn=").append(serverMaxconn); + } + if (serverMinconn != null) { + loadBalancingData.append(",server.minconn=").append(serverMinconn); + } + if (serverMaxqueue != null) { + loadBalancingData.append(",server.maxqueue=").append(serverMaxqueue); + } loadBalancingData.append(",vmIps="); for (LoadBalancerVMMapVO vmMapVO : vmMapVOs) { diff --git a/systemvm/debian/root/health_checks/haproxy_check.py b/systemvm/debian/root/health_checks/haproxy_check.py index e1b34302d438..b8a4bb4d7ce4 100644 --- a/systemvm/debian/root/health_checks/haproxy_check.py +++ b/systemvm/debian/root/health_checks/haproxy_check.py @@ -54,11 +54,31 @@ def checkDefaults(haproxyData, haCfgSections): return True +def checkServerValues(haproxyData, serverSections): + serverArray = serverSections[0].split(" ") + + if "maxconn" in serverArray and "server.maxconn" in haproxyData: + maxconnServer = serverArray[serverArray.index("maxconn") + 1] + if maxconnServer != haproxyData["server.maxconn"]: + return False + + if "minconn" in serverArray and "server.minconn" in haproxyData: + minconnServer = serverArray[serverArray.index("minconn") + 1] + if minconnServer != haproxyData["server.minconn"]: + return False + + if "maxqueue" in serverArray and "server.maxqueue" in haproxyData: + maxqueueServer = serverArray[serverArray.index("maxqueue") + 1] + if maxqueueServer != haproxyData["server.maxqueue"]: + return False + + return True + def checkLoadBalance(haproxyData, haCfgSections): correct = True for lbSec in haproxyData: if "global.maxconn" in lbSec: # Ignore first part (global and default settings) - continue; + continue srcServer = lbSec["sourceIp"].replace('.', '_') + "-" + \ formatPort(lbSec["sourcePortStart"], lbSec["sourcePortEnd"]) @@ -85,6 +105,7 @@ def checkLoadBalance(haproxyData, haCfgSections): if cfgSection: if "server" in cfgSection: + correct = checkServerValues(haproxyData, cfgSection["server"]) if lbSec["algorithm"] != cfgSection["balance"][0]: print "Incorrect balance method for " + secName + \ "Expected : " + lbSec["algorithm"] + \ From efcbcbffefae2deea93e89e2e909616f95317348 Mon Sep 17 00:00:00 2001 From: Rakesh Venkatesh Date: Wed, 1 Jul 2020 13:47:36 +0000 Subject: [PATCH 45/75] Code refactor --- .../VirtualNetworkApplianceManagerImpl.java | 2 +- .../root/health_checks/haproxy_check.py | 41 ++++++++++++------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 5adc4740ef81..a422beacbd4b 100644 --- a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -1810,9 +1810,9 @@ private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final Stri String isHttp = lbConfig.orElse(null); lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbHttpKeepalive.key())); String isHttpKeepalive = lbConfig.orElse(null); - lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxConn.key())); // Process lb.server values + lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxConn.key())); String serverMaxconn = lbConfig.orElse(null); lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMinConn.key())); String serverMinconn = lbConfig.orElse(null); diff --git a/systemvm/debian/root/health_checks/haproxy_check.py b/systemvm/debian/root/health_checks/haproxy_check.py index b8a4bb4d7ce4..6353006d8e48 100644 --- a/systemvm/debian/root/health_checks/haproxy_check.py +++ b/systemvm/debian/root/health_checks/haproxy_check.py @@ -55,24 +55,37 @@ def checkDefaults(haproxyData, haCfgSections): return True def checkServerValues(haproxyData, serverSections): + correct = True serverArray = serverSections[0].split(" ") - if "maxconn" in serverArray and "server.maxconn" in haproxyData: - maxconnServer = serverArray[serverArray.index("maxconn") + 1] - if maxconnServer != haproxyData["server.maxconn"]: - return False + if "server.maxconn" in haproxyData: + if "maxconn" not in serverArray: + print("maxconn value is missing in line %s" % serverSections) + correct = False + else: + maxconnServer = serverArray[serverArray.index("maxconn") + 1] + if maxconnServer != haproxyData["server.maxconn"]: + correct = False - if "minconn" in serverArray and "server.minconn" in haproxyData: - minconnServer = serverArray[serverArray.index("minconn") + 1] - if minconnServer != haproxyData["server.minconn"]: - return False + if "server.minconn" in haproxyData: + if "minconn" not in serverArray: + print("minconn value is missing in line %s" % serverSections) + correct = False + else: + minconnServer = serverArray[serverArray.index("minconn") + 1] + if minconnServer != haproxyData["server.minconn"]: + correct = False - if "maxqueue" in serverArray and "server.maxqueue" in haproxyData: - maxqueueServer = serverArray[serverArray.index("maxqueue") + 1] - if maxqueueServer != haproxyData["server.maxqueue"]: - return False + if "server.maxqueue" in haproxyData: + if "maxqueue" not in serverArray: + print("maxqueue value is missing in line %s" % serverSections) + correct = False + else: + maxqueueServer = serverArray[serverArray.index("maxqueue") + 1] + if maxqueueServer != haproxyData["server.maxqueue"]: + correct = False - return True + return correct def checkLoadBalance(haproxyData, haCfgSections): correct = True @@ -105,7 +118,7 @@ def checkLoadBalance(haproxyData, haCfgSections): if cfgSection: if "server" in cfgSection: - correct = checkServerValues(haproxyData, cfgSection["server"]) + correct = checkServerValues(lbSec, cfgSection["server"]) if lbSec["algorithm"] != cfgSection["balance"][0]: print "Incorrect balance method for " + secName + \ "Expected : " + lbSec["algorithm"] + \ From 61ba9116fdd6cac9a7826e9184553696042fe770 Mon Sep 17 00:00:00 2001 From: Rakesh Venkatesh Date: Fri, 3 Jul 2020 11:48:49 +0000 Subject: [PATCH 46/75] add lb rule checks --- .../VirtualNetworkApplianceManagerImpl.java | 18 ++++++++-- .../root/health_checks/haproxy_check.py | 35 ++++++++++++++++++- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index a422beacbd4b..391a49c3d747 100644 --- a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -1789,11 +1789,11 @@ private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final Stri () -> Long.toString(Long.parseLong(globalMaxConnFinal) / 4)); loadBalancingData.append(",global.maxpipes=").append(globalMaxPipesFinal); lbConfig = Optional.ofNullable(networkLbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutConnect.key())); - loadBalancingData.append(",default.timeout.connect=").append(lbConfig.isPresent() ? lbConfig.get() : 5000); + loadBalancingData.append(",default.timeout.connect=").append(lbConfig.orElse(LoadBalancerConfigKey.LbTimeoutConnect.defaultValue())); lbConfig = Optional.ofNullable(networkLbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutServer.key())); - loadBalancingData.append(",default.timeout.server=").append(lbConfig.isPresent() ? lbConfig.get() : 50000); + loadBalancingData.append(",default.timeout.server=").append(lbConfig.orElse(LoadBalancerConfigKey.LbTimeoutServer.defaultValue())); lbConfig = Optional.ofNullable(networkLbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutClient.key())); - loadBalancingData.append(",default.timeout.client=").append(lbConfig.isPresent() ? lbConfig.get() : 50000); + loadBalancingData.append(",default.timeout.client=").append(lbConfig.orElse(LoadBalancerConfigKey.LbTimeoutClient.defaultValue())); loadBalancingData.append(";"); } for (FirewallRuleVO firewallRuleVO : loadBalancerVOs) { @@ -1811,6 +1811,12 @@ private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final Stri lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbHttpKeepalive.key())); String isHttpKeepalive = lbConfig.orElse(null); + // process lb values + lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbMaxConn.key())); + String lbMaxConn = lbConfig.orElse(null); + lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbFullConn.key())); + String lbFullConn = lbConfig.orElse(null); + // Process lb.server values lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxConn.key())); String serverMaxconn = lbConfig.orElse(null); @@ -1856,6 +1862,12 @@ private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final Stri if (isTransparent != null) { loadBalancingData.append(",transparent=").append(isTransparent); } + if (lbMaxConn != null) { + loadBalancingData.append(",lb.maxconn=").append(lbMaxConn); + } + if (lbFullConn != null) { + loadBalancingData.append(",lb.fullconn=").append(lbFullConn); + } if (serverMaxconn != null) { loadBalancingData.append(",server.maxconn=").append(serverMaxconn); } diff --git a/systemvm/debian/root/health_checks/haproxy_check.py b/systemvm/debian/root/health_checks/haproxy_check.py index 6353006d8e48..0b6d37bcb89f 100644 --- a/systemvm/debian/root/health_checks/haproxy_check.py +++ b/systemvm/debian/root/health_checks/haproxy_check.py @@ -54,6 +54,38 @@ def checkDefaults(haproxyData, haCfgSections): return True +def checkLbValues(lbSection, cfgSection): + correct = True + if "lb.maxconn" in lbSection: + if "maxconn" not in cfgSection: + print("maxconn value is missing in %s" % cfgSection) + correct = False + else: + if cfgSection["maxconn"][0] != lbSection["lb.maxconn"]: + print("maxconn value in %s doesnt match with %s" % (lbSection, cfgSection)) + correct = False + + if "lb.fullconn" in lbSection: + if "fullconn" not in cfgSection: + print("fullconn value missing in %s" % cfgSection) + correct = False + else: + if cfgSection["fullconn"][0] != lbSection["lb.fullconn"]: + print("fullconn value in %s doesnt match with %s" % (lbSection, cfgSection)) + + if "http" in lbSection: + if "mode" not in cfgSection: + print("mode http is enabled but not configured in haproxy rule %s" % cfgSection) + correct = False + else: + print("cfgsection mode is %s" % cfgSection["mode"][0]) + print("lbsection mode is %s" % lbSection["http"]) + if lbSection["http"] == 'true' and cfgSection["mode"][0] != 'http': + print("http mode value mismatch in rule %s" % cfgSection) + correct = False + + return correct + def checkServerValues(haproxyData, serverSections): correct = True serverArray = serverSections[0].split(" ") @@ -117,8 +149,9 @@ def checkLoadBalance(haproxyData, haCfgSections): cfgSection = haCfgSections[secName] if cfgSection: + correct = correct and checkLbValues(lbSec, cfgSection) if "server" in cfgSection: - correct = checkServerValues(lbSec, cfgSection["server"]) + correct = correct and checkServerValues(lbSec, cfgSection["server"]) if lbSec["algorithm"] != cfgSection["balance"][0]: print "Incorrect balance method for " + secName + \ "Expected : " + lbSec["algorithm"] + \ From a3bbacb4dbfc1ea79404b8534a9bfbb9632515b7 Mon Sep 17 00:00:00 2001 From: Rakesh Venkatesh Date: Mon, 6 Jul 2020 11:50:50 +0000 Subject: [PATCH 47/75] add frontend/backend checks --- .../VirtualNetworkApplianceManagerImpl.java | 76 ++++++++++++------- .../root/health_checks/haproxy_check.py | 52 ++++++++++++- 2 files changed, 95 insertions(+), 33 deletions(-) diff --git a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 391a49c3d747..80e4e07d1b3e 100644 --- a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -1811,20 +1811,6 @@ private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final Stri lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbHttpKeepalive.key())); String isHttpKeepalive = lbConfig.orElse(null); - // process lb values - lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbMaxConn.key())); - String lbMaxConn = lbConfig.orElse(null); - lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbFullConn.key())); - String lbFullConn = lbConfig.orElse(null); - - // Process lb.server values - lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxConn.key())); - String serverMaxconn = lbConfig.orElse(null); - lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMinConn.key())); - String serverMinconn = lbConfig.orElse(null); - lbConfig = Optional.ofNullable(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxQueue.key())); - String serverMaxqueue = lbConfig.orElse(null); - List vmMapVOs = _loadBalancerVMMapDao.listByLoadBalancerId(firewallRuleVO.getId(), false); if (vmMapVOs.size() > 0) { loadBalancingData.append("sourcePortStart=").append(firewallRuleVO.getSourcePortStart()) @@ -1862,21 +1848,7 @@ private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final Stri if (isTransparent != null) { loadBalancingData.append(",transparent=").append(isTransparent); } - if (lbMaxConn != null) { - loadBalancingData.append(",lb.maxconn=").append(lbMaxConn); - } - if (lbFullConn != null) { - loadBalancingData.append(",lb.fullconn=").append(lbFullConn); - } - if (serverMaxconn != null) { - loadBalancingData.append(",server.maxconn=").append(serverMaxconn); - } - if (serverMinconn != null) { - loadBalancingData.append(",server.minconn=").append(serverMinconn); - } - if (serverMaxqueue != null) { - loadBalancingData.append(",server.maxqueue=").append(serverMaxqueue); - } + updateLbValues(lbConfigsMap, loadBalancingData); loadBalancingData.append(",vmIps="); for (LoadBalancerVMMapVO vmMapVO : vmMapVOs) { @@ -1887,6 +1859,52 @@ private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final Stri } } + private void updateLbValues(final HashMap lbConfigsMap, StringBuilder loadBalancingData) { + String lbMaxConn = lbConfigsMap.getOrDefault(LoadBalancerConfigKey.LbMaxConn.key(), null); + String lbFullConn = lbConfigsMap.getOrDefault(LoadBalancerConfigKey.LbFullConn.key(), null); + String lbTimeoutConnect = lbConfigsMap.getOrDefault(LoadBalancerConfigKey.LbTimeoutConnect.key(), null); + String lbTimeoutServer = lbConfigsMap.getOrDefault(LoadBalancerConfigKey.LbTimeoutServer.key(), null); + String lbTimeoutClient = lbConfigsMap.getOrDefault(LoadBalancerConfigKey.LbTimeoutClient.key(), null); + String lbBackendHttps = lbConfigsMap.getOrDefault(LoadBalancerConfigKey.LbBackendHttps.key(), null); + String lbHttp2 = lbConfigsMap.getOrDefault(LoadBalancerConfigKey.LbHttp2.key(), null); + + // Process lb.server values + String serverMaxconn = lbConfigsMap.getOrDefault(LoadBalancerConfigKey.LbServerMaxConn.key(), null); + String serverMinconn = lbConfigsMap.getOrDefault(LoadBalancerConfigKey.LbServerMinConn.key(), null); + String serverMaxqueue = lbConfigsMap.getOrDefault(LoadBalancerConfigKey.LbServerMaxQueue.key(), null); + + if (lbMaxConn != null) { + loadBalancingData.append(",lb.maxconn=").append(lbMaxConn); + } + if (lbFullConn != null) { + loadBalancingData.append(",lb.fullconn=").append(lbFullConn); + } + if (lbTimeoutConnect != null) { + loadBalancingData.append(",lb.timeout.connect=").append(lbTimeoutConnect); + } + if (lbTimeoutServer != null) { + loadBalancingData.append(",lb.timeout.server=").append(lbTimeoutServer); + } + if (lbTimeoutClient != null) { + loadBalancingData.append(",lb.timeout.client=").append(lbTimeoutClient); + } + if (lbBackendHttps != null) { + loadBalancingData.append(",lb.backend.https=").append(lbBackendHttps); + } + if (lbHttp2 != null) { + loadBalancingData.append(",http2=").append(lbHttp2); + } + if (serverMaxconn != null) { + loadBalancingData.append(",server.maxconn=").append(serverMaxconn); + } + if (serverMinconn != null) { + loadBalancingData.append(",server.minconn=").append(serverMinconn); + } + if (serverMaxqueue != null) { + loadBalancingData.append(",server.maxqueue=").append(serverMaxqueue); + } + } + private Map getRouterHealthChecksConfig(final DomainRouterVO router) { Map data = new HashMap<>(); List routerJoinVOs = domainRouterJoinDao.searchByIds(router.getId()); diff --git a/systemvm/debian/root/health_checks/haproxy_check.py b/systemvm/debian/root/health_checks/haproxy_check.py index 0b6d37bcb89f..31a89d998f76 100644 --- a/systemvm/debian/root/health_checks/haproxy_check.py +++ b/systemvm/debian/root/health_checks/haproxy_check.py @@ -54,7 +54,21 @@ def checkDefaults(haproxyData, haCfgSections): return True -def checkLbValues(lbSection, cfgSection): +def checkFrontendLbValues(lbSection, cfgSection): + correct = True + if "lb.timeout.client" in lbSection: + if "timeout" not in cfgSection: + print("timeout is enabled but not configured in haproxy rule %s" % cfgSection) + correct = False + else: + timeout = "client %s" % lbSection["lb.timeout.client"] + if timeout not in cfgSection["timeout"]: + print("timeout client section is not configured in rule %s" % cfgSection) + correct = False + + return correct + +def checkBackendLbValues(lbSection, cfgSection): correct = True if "lb.maxconn" in lbSection: if "maxconn" not in cfgSection: @@ -78,12 +92,33 @@ def checkLbValues(lbSection, cfgSection): print("mode http is enabled but not configured in haproxy rule %s" % cfgSection) correct = False else: - print("cfgsection mode is %s" % cfgSection["mode"][0]) - print("lbsection mode is %s" % lbSection["http"]) if lbSection["http"] == 'true' and cfgSection["mode"][0] != 'http': print("http mode value mismatch in rule %s" % cfgSection) correct = False + if "lb.timeout.connect" in lbSection: + if "timeout" not in cfgSection: + print("timeout is enabled but not configured in haproxy rule %s" % cfgSection) + correct = False + else: + timeout = "connect %s" % lbSection["lb.timeout.connect"] + if timeout not in cfgSection["timeout"]: + print("timeout connect section is not configured in rule %s" % cfgSection) + correct = False + + if "lb.timeout.server" in lbSection: + if "timeout" not in cfgSection: + print("timeout is enabled but not configured in haproxy rule %s" % cfgSection) + correct = False + else: + timeout = "server %s" % lbSection["lb.timeout.server"] + if timeout not in cfgSection["timeout"]: + print("timeout server section is not configured in rule %s" % cfgSection) + correct = False + + if "transparent" not in lbSection: + correct = checkFrontendLbValues(lbSection, cfgSection) + return correct def checkServerValues(haproxyData, serverSections): @@ -117,6 +152,11 @@ def checkServerValues(haproxyData, serverSections): if maxqueueServer != haproxyData["server.maxqueue"]: correct = False + if "lb.backend.https" in haproxyData: + if "ssl verify none" not in serverSections[0]: + print("backend https is enabled but not configured in %s" % serverSections[0]) + correct = False + return correct def checkLoadBalance(haproxyData, haCfgSections): @@ -141,6 +181,8 @@ def checkLoadBalance(haproxyData, haCfgSections): correct = False else: cfgSection = haCfgSections[secFrontend] + if cfgSection is not None: + correct = checkFrontendLbValues(lbSec, cfgSection) cfgSection.update(haCfgSections[secBackend]) elif secName not in haCfgSections: print "Missing section for load balancing " + secName + "\n" @@ -149,8 +191,8 @@ def checkLoadBalance(haproxyData, haCfgSections): cfgSection = haCfgSections[secName] if cfgSection: - correct = correct and checkLbValues(lbSec, cfgSection) if "server" in cfgSection: + correct = correct and checkBackendLbValues(lbSec, cfgSection) correct = correct and checkServerValues(lbSec, cfgSection["server"]) if lbSec["algorithm"] != cfgSection["balance"][0]: print "Incorrect balance method for " + secName + \ @@ -161,6 +203,8 @@ def checkLoadBalance(haproxyData, haCfgSections): bindStr = lbSec["sourceIp"] + ":" + formatPort(lbSec["sourcePortStart"], lbSec["sourcePortEnd"]) if lbSec.has_key("sslcert"): bindStr += " ssl crt " + SSL_CERTS_DIR + lbSec["sslcert"] + if "http2" in lbSec and lbSec["http2"].lower() == 'true': + bindStr += " alpn h2,http/1.1" if cfgSection["bind"][0] != bindStr: print "Incorrect bind string found. Expected " + bindStr + " but found " + cfgSection["bind"][0] + "." correct = False From ee75cab048b6802ac2a4c79b0309c3009b9e14d1 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 8 Jul 2020 09:34:19 +0000 Subject: [PATCH 48/75] haproxy check: set sslcert only if lb protocol is 'ssl' --- .../router/VirtualNetworkApplianceManagerImpl.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 80e4e07d1b3e..7c687d2964cf 100644 --- a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -1823,10 +1823,12 @@ private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final Stri .append(",destPortEnd=").append(loadBalancerVO.getDefaultPortEnd()) .append(",algorithm=").append(loadBalancerVO.getAlgorithm()) .append(",protocol=").append(loadBalancerVO.getLbProtocol()); - final LbSslCert sslCert = _lbMgr.getLbSslCert(firewallRuleVO.getId()); - if (sslCert != null && ! sslCert.isRevoked()) { - loadBalancingData.append(",sslcert=").append(sourceIp.replace(".", "_")).append('-') - .append(loadBalancerVO.getSourcePortStart()).append(".pem"); + if (loadBalancerVO.getLbProtocol() != null && loadBalancerVO.getLbProtocol().equals(NetUtils.SSL_PROTO)) { + final LbSslCert sslCert = _lbMgr.getLbSslCert(firewallRuleVO.getId()); + if (sslCert != null && ! sslCert.isRevoked()) { + loadBalancingData.append(",sslcert=").append(sourceIp.replace(".", "_")).append('-') + .append(loadBalancerVO.getSourcePortStart()).append(".pem"); + } } } else if (firewallRuleVO instanceof ApplicationLoadBalancerRuleVO) { ApplicationLoadBalancerRuleVO appLoadBalancerVO = (ApplicationLoadBalancerRuleVO) firewallRuleVO; From e205c2242f1d7408c07983db834a6a212d1d87d7 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 8 Jul 2020 15:07:22 +0000 Subject: [PATCH 49/75] haproxy check: http2 is enabled only if ssl offloading is enabled --- systemvm/debian/root/health_checks/haproxy_check.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/systemvm/debian/root/health_checks/haproxy_check.py b/systemvm/debian/root/health_checks/haproxy_check.py index 31a89d998f76..f2d260d39fd6 100644 --- a/systemvm/debian/root/health_checks/haproxy_check.py +++ b/systemvm/debian/root/health_checks/haproxy_check.py @@ -203,8 +203,8 @@ def checkLoadBalance(haproxyData, haCfgSections): bindStr = lbSec["sourceIp"] + ":" + formatPort(lbSec["sourcePortStart"], lbSec["sourcePortEnd"]) if lbSec.has_key("sslcert"): bindStr += " ssl crt " + SSL_CERTS_DIR + lbSec["sslcert"] - if "http2" in lbSec and lbSec["http2"].lower() == 'true': - bindStr += " alpn h2,http/1.1" + if "http2" in lbSec and lbSec["http2"].lower() == 'true': + bindStr += " alpn h2,http/1.1" if cfgSection["bind"][0] != bindStr: print "Incorrect bind string found. Expected " + bindStr + " but found " + cfgSection["bind"][0] + "." correct = False From 95f56957f4a5227f20eb104e31d1fa9abf5e5e4f Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 8 Jul 2020 20:33:37 +0000 Subject: [PATCH 50/75] haproxy check: 'mode http' is enabled in some conditions --- .../VirtualNetworkApplianceManagerImpl.java | 2 ++ .../root/health_checks/haproxy_check.py | 19 ++++++++----------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 7c687d2964cf..0a381a649091 100644 --- a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -1841,6 +1841,8 @@ private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final Stri loadBalancingData.append(",stickiness=").append(getStickinessPolicies(firewallRuleVO.getId())); if (isHttp != null) { loadBalancingData.append(",http=").append(isHttp); + } else if (firewallRuleVO.getSourcePortStart() == NetUtils.HTTP_PORT) { + loadBalancingData.append(",http=").append(true); } if (isHttpKeepalive != null) { loadBalancingData.append(",keepAliveEnabled=").append(isHttpKeepalive); diff --git a/systemvm/debian/root/health_checks/haproxy_check.py b/systemvm/debian/root/health_checks/haproxy_check.py index f2d260d39fd6..8a46004438da 100644 --- a/systemvm/debian/root/health_checks/haproxy_check.py +++ b/systemvm/debian/root/health_checks/haproxy_check.py @@ -87,15 +87,6 @@ def checkBackendLbValues(lbSection, cfgSection): if cfgSection["fullconn"][0] != lbSection["lb.fullconn"]: print("fullconn value in %s doesnt match with %s" % (lbSection, cfgSection)) - if "http" in lbSection: - if "mode" not in cfgSection: - print("mode http is enabled but not configured in haproxy rule %s" % cfgSection) - correct = False - else: - if lbSection["http"] == 'true' and cfgSection["mode"][0] != 'http': - print("http mode value mismatch in rule %s" % cfgSection) - correct = False - if "lb.timeout.connect" in lbSection: if "timeout" not in cfgSection: print("timeout is enabled but not configured in haproxy rule %s" % cfgSection) @@ -209,11 +200,17 @@ def checkLoadBalance(haproxyData, haCfgSections): print "Incorrect bind string found. Expected " + bindStr + " but found " + cfgSection["bind"][0] + "." correct = False - if (lbSec["sourcePortStart"] == "80" and lbSec["sourcePortEnd"] == "80" and lbSec["keepAliveEnabled"] == "false") \ - or (lbSec["stickiness"].find("AppCookie") != -1 or lbSec["stickiness"].find("LbCookie") != -1): + if ("http" in lbSec and lbSec["http"] == 'true') \ + or lbSec.has_key("sslcert") \ + or lbSec["stickiness"].find("AppCookie") != -1 \ + or lbSec["stickiness"].find("LbCookie") != -1: if not ("mode" in cfgSection and cfgSection["mode"][0] == "http"): print "Expected HTTP mode but not found" correct = False + if lbSec["keepAliveEnabled"] == "false" \ + and not ("option" in cfgSection and cfgSection["option"][0] == "httpclose"): + print "Expected 'option httpclose' but not found" + correct = False expectedServerIps = lbSec["vmIps"].split(" ") for expectedServerIp in expectedServerIps: From 4f92d50ca0f6253564080c8fe7c96d63c7bed47d Mon Sep 17 00:00:00 2001 From: Sina Kashipazha Date: Mon, 6 Jul 2020 13:35:33 +0200 Subject: [PATCH 51/75] Add configuration for ssl customization. --- .../cloudstack/network/lb/LoadBalancerConfigKey.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index cfeefd1d925a..022454fa03d4 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -61,7 +61,9 @@ public enum LoadBalancerConfigKey { LbServerMinConn(Category.LoadBalancer, "lb.server.minconn", "LB minimum connection per server", Long.class, "", "LB minimum connection per server, default is ''", Scope.LoadBalancerRule), - LbServerMaxQueue(Category.LoadBalancer, "lb.server.maxqueue", "Max conn wait in queue per server", Long.class, "<0 means unlimited in haproxy>", "Maximum number of connections which will wait in queue for this server, default is ''", Scope.LoadBalancerRule); + LbServerMaxQueue(Category.LoadBalancer, "lb.server.maxqueue", "Max conn wait in queue per server", Long.class, "<0 means unlimited in haproxy>", "Maximum number of connections which will wait in queue for this server, default is ''", Scope.LoadBalancerRule), + + LbSslConfiguration(Category.LoadBalancer, "lb.ssl.configuration", "SSL configuration, could be 'none', 'old' or 'intermediate'", String.class, "none", "if 'none', no SSL configurations will be added, if 'old', refer to https://ssl-config.mozilla.org/#server=haproxy&server-version=1.8.17&config=old&openssl-version=1.0.2l if 'intermediate', refer to https://ssl-config.mozilla.org/#server=haproxy&server-version=1.8.17&config=intermediate&openssl-version=1.0.2l default value is 'none'", Scope.LoadBalancerRule); public static enum Category { General, Advanced, Stats, LoadBalancer @@ -197,6 +199,13 @@ public static Pair validate(Scope scope, String k return new Pair(null, "Please enter either 'true' or 'false' for parameter " + key); } } + + if(key.equals("lb.ssl.configuration")){ + if ( !("none".equalsIgnoreCase(value) || "old".equalsIgnoreCase(value) || "intermediate".equalsIgnoreCase(value)) ){ + return new Pair<>(null, "Please enter either 'none', 'old' or 'intermediate' for parameter " + key); + } + } + return new Pair(config, null); } } From dfc6ccee14dcd241c66419f51d5eec4b6478df9c Mon Sep 17 00:00:00 2001 From: Sina Kashipazha Date: Mon, 6 Jul 2020 16:50:23 +0200 Subject: [PATCH 52/75] Port changes from 4.7.1. --- .../cloud/network/HAProxyConfigurator.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index b9feb0bfa2b7..6dd82a409371 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -56,6 +56,18 @@ public class HAProxyConfigurator implements LoadBalancerConfigurator { private static String[] defaultListen = {"listen vmops", "\tbind 0.0.0.0:9", "\toption transparent"}; private static final String SSL_CERTS_DIR = "/etc/ssl/cloudstack/"; + // https://ssl-config.mozilla.org/#server=haproxy&version=1.8&config=old&openssl=1.1.1d&guideline=5.4 + private static String sslConfigurationOld = "\n\tssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA" + + "\n\tssl-default-bind-options no-sslv3 no-tls-tickets" + + "\n\n\tssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA" + + "\n\tssl-default-server-options no-sslv3 no-tls-tickets"; + + // https://ssl-config.mozilla.org/#server=haproxy&version=1.8&config=intermediate&openssl=1.1.1d&guideline=5.4 + private static String sslConfigurationIntermediate = "\n\tssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384" + + "\n\tssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets" + + "\n\n\tssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384" + + "\n\tssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets"; + @Override public String[] generateConfiguration(final List fwRules) { // Group the rules by publicip:publicport @@ -768,6 +780,15 @@ public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { gSection.set(6, "\tgroup root"); } + String sslConfiguration = LoadBalancerConfigKey.LbSslConfiguration.key(); + if (sslConfiguration != null && sslConfiguration.equalsIgnoreCase("old")){ + gSection.add(sslConfigurationOld); + gSection.add("\n\tssl-dh-param-file /root/dhparam.pem.old"); + } else if (sslConfiguration == null || ! sslConfiguration.equalsIgnoreCase("none")){ + gSection.add(sslConfigurationIntermediate); + gSection.add("\n\tssl-dh-param-file /root/dhparam.pem.intermediate"); + } + if (s_logger.isDebugEnabled()) { for (final String s : gSection) { s_logger.debug("global section: " + s); From 76b78ac213df19e7034c25336acb8eaa0844cbeb Mon Sep 17 00:00:00 2001 From: Sina Kashipazha Date: Fri, 10 Jul 2020 05:57:28 +0200 Subject: [PATCH 53/75] Move old and intermediate configuration to HAProxy frontend. --- .../cloud/network/HAProxyConfigurator.java | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 6dd82a409371..1ffa7d0437e5 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -56,17 +56,15 @@ public class HAProxyConfigurator implements LoadBalancerConfigurator { private static String[] defaultListen = {"listen vmops", "\tbind 0.0.0.0:9", "\toption transparent"}; private static final String SSL_CERTS_DIR = "/etc/ssl/cloudstack/"; - // https://ssl-config.mozilla.org/#server=haproxy&version=1.8&config=old&openssl=1.1.1d&guideline=5.4 - private static String sslConfigurationOld = "\n\tssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA" + - "\n\tssl-default-bind-options no-sslv3 no-tls-tickets" + - "\n\n\tssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA" + - "\n\tssl-default-server-options no-sslv3 no-tls-tickets"; - - // https://ssl-config.mozilla.org/#server=haproxy&version=1.8&config=intermediate&openssl=1.1.1d&guideline=5.4 - private static String sslConfigurationIntermediate = "\n\tssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384" + - "\n\tssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets" + - "\n\n\tssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384" + - "\n\tssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets"; + private static String sslConfigurationOld = "no-sslv3 no-tls-tickets ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256" + + ":ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256" + + ":DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA" + + ":ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256" + + ":AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA"; + + private static String sslConfigurationIntermediate = "no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets ciphers ECDHE-ECDSA-AES128-GCM-SHA256" + + ":ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305" + + ":DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; @Override public String[] generateConfiguration(final List fwRules) { @@ -524,6 +522,14 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv if ("true".equalsIgnoreCase(lbConfigsMap.get(LoadBalancerConfigKey.LbHttp2.key()))) { sb.append(" alpn h2,http/1.1"); } + + // Sina + String lbSslConfiguration = lbConfigsMap.get(LoadBalancerConfigKey.LbSslConfiguration.key()); + if ("old".equalsIgnoreCase(lbSslConfiguration)) { + sb.append(" ").append(sslConfigurationOld); + } else if ("intermediate".equalsIgnoreCase(lbSslConfiguration)) { + sb.append(" ").append(sslConfigurationIntermediate); + } sb.append("\n\thttp-request add-header X-Forwarded-Proto https"); } frontendConfigs.add(sb.toString()); @@ -780,15 +786,6 @@ public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { gSection.set(6, "\tgroup root"); } - String sslConfiguration = LoadBalancerConfigKey.LbSslConfiguration.key(); - if (sslConfiguration != null && sslConfiguration.equalsIgnoreCase("old")){ - gSection.add(sslConfigurationOld); - gSection.add("\n\tssl-dh-param-file /root/dhparam.pem.old"); - } else if (sslConfiguration == null || ! sslConfiguration.equalsIgnoreCase("none")){ - gSection.add(sslConfigurationIntermediate); - gSection.add("\n\tssl-dh-param-file /root/dhparam.pem.intermediate"); - } - if (s_logger.isDebugEnabled()) { for (final String s : gSection) { s_logger.debug("global section: " + s); From 4f0b35da9a26e3aee47a4323a52ebe481c845356 Mon Sep 17 00:00:00 2001 From: Sina Kashipazha Date: Sat, 11 Jul 2020 00:46:57 +0200 Subject: [PATCH 54/75] Fixed missed ssl restriction of haproxy. --- .../cloud/network/HAProxyConfigurator.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 1ffa7d0437e5..787d10a8f383 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -56,13 +56,13 @@ public class HAProxyConfigurator implements LoadBalancerConfigurator { private static String[] defaultListen = {"listen vmops", "\tbind 0.0.0.0:9", "\toption transparent"}; private static final String SSL_CERTS_DIR = "/etc/ssl/cloudstack/"; - private static String sslConfigurationOld = "no-sslv3 no-tls-tickets ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256" + + private static String sslConfigurationOld = " no-sslv3 no-tls-tickets ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256" + ":ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256" + ":DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA" + ":ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256" + ":AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA"; - private static String sslConfigurationIntermediate = "no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets ciphers ECDHE-ECDSA-AES128-GCM-SHA256" + + private static String sslConfigurationIntermediate = " no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets ciphers ECDHE-ECDSA-AES128-GCM-SHA256" + ":ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305" + ":DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; @@ -483,6 +483,16 @@ private String getLbSubRuleForStickiness(final LoadBalancerTO lbTO) { return sb.toString(); } + private String getCustomizedSslConfigs(HashMap lbConfigsMap){ + String lbSslConfiguration = lbConfigsMap.get(LoadBalancerConfigKey.LbSslConfiguration.key()); + if ("old".equalsIgnoreCase(lbSslConfiguration)) { + return sslConfigurationOld; + } else if ("intermediate".equalsIgnoreCase(lbSslConfiguration)) { + return sslConfigurationIntermediate; + } + return ""; + } + private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliveEnabled, final String networkCidr, HashMap networkLbConfigsMap) { StringBuilder sb = new StringBuilder(); final String poolName = sb.append(lbTO.getSrcIp().replace(".", "_")).append('-').append(lbTO.getSrcPort()).toString(); @@ -523,13 +533,8 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv sb.append(" alpn h2,http/1.1"); } - // Sina - String lbSslConfiguration = lbConfigsMap.get(LoadBalancerConfigKey.LbSslConfiguration.key()); - if ("old".equalsIgnoreCase(lbSslConfiguration)) { - sb.append(" ").append(sslConfigurationOld); - } else if ("intermediate".equalsIgnoreCase(lbSslConfiguration)) { - sb.append(" ").append(sslConfigurationIntermediate); - } + sb.append(getCustomizedSslConfigs(lbConfigsMap)); + sb.append("\n\thttp-request add-header X-Forwarded-Proto https"); } frontendConfigs.add(sb.toString()); @@ -599,6 +604,9 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv sb.append(" check"); } + sb.append(getCustomizedSslConfigs(lbConfigsMap)); + + if (lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxConn.key()) != null) { long maxConnEach = Long.parseLong(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxConn.key())); if (maxConnEach > 0) { From fc623c10202fa08db5ca111c731aec54e59dcc35 Mon Sep 17 00:00:00 2001 From: Sina Kashipazha Date: Mon, 13 Jul 2020 17:55:08 +0200 Subject: [PATCH 55/75] Added Global setting configuration. --- .../network/lb/LoadBalancerConfigKey.java | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index 022454fa03d4..490640f232e2 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -20,10 +20,13 @@ import java.util.LinkedHashMap; import java.util.Map; +import com.cloud.network.rules.LoadBalancer; import com.cloud.network.rules.LoadBalancerConfig.Scope; import com.cloud.utils.Pair; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; -public enum LoadBalancerConfigKey { +public enum LoadBalancerConfigKey implements Configurable { LbStatsEnable(Category.Stats, "lb.stats.enable", "LB stats enable", Boolean.class, "true", "Enable statistics reporting with default settings, default is 'true'", Scope.Network, Scope.Vpc), @@ -63,7 +66,22 @@ public enum LoadBalancerConfigKey { LbServerMaxQueue(Category.LoadBalancer, "lb.server.maxqueue", "Max conn wait in queue per server", Long.class, "<0 means unlimited in haproxy>", "Maximum number of connections which will wait in queue for this server, default is ''", Scope.LoadBalancerRule), - LbSslConfiguration(Category.LoadBalancer, "lb.ssl.configuration", "SSL configuration, could be 'none', 'old' or 'intermediate'", String.class, "none", "if 'none', no SSL configurations will be added, if 'old', refer to https://ssl-config.mozilla.org/#server=haproxy&server-version=1.8.17&config=old&openssl-version=1.0.2l if 'intermediate', refer to https://ssl-config.mozilla.org/#server=haproxy&server-version=1.8.17&config=intermediate&openssl-version=1.0.2l default value is 'none'", Scope.LoadBalancerRule); + LbSslConfiguration(Category.LoadBalancer, "lb.ssl.configuration", "SSL configuration, could be 'none', 'old' or 'intermediate'", String.class, "none" , "if 'none', no SSL configurations will be added, if 'old', refer to https://ssl-config.mozilla.org/#server=haproxy&server-version=1.8.17&config=old&openssl-version=1.0.2l if 'intermediate', refer to https://ssl-config.mozilla.org/#server=haproxy&server-version=1.8.17&config=intermediate&openssl-version=1.0.2l default value is 'none'", Scope.LoadBalancerRule); + + private static final String DefaultValueOfSSLCustomizationCK = "default.value.of.ssl.customization"; + + private static final ConfigKey DefaultValueOfSALCustomization = new ConfigKey<>("Advanced", String.class, DefaultValueOfSSLCustomizationCK, "none", + "Control default value of load balancer ssl customization", true, ConfigKey.Scope.Global); + + @Override + public String getConfigComponentName() { + return LoadBalancerConfigKey.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[]{DefaultValueOfSALCustomization}; + } public static enum Category { General, Advanced, Stats, LoadBalancer @@ -104,6 +122,8 @@ public String displayText() { } public String defaultValue() { + if(key().equals("lb.ssl.configuration")) + return DefaultValueOfSALCustomization.value(); return _defaultValue; } From 3a581851ebcab44deb56a477cd9af274a3e0b1fb Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 13 Jul 2020 22:02:13 +0000 Subject: [PATCH 56/75] Move global setting from api to engine/components-api --- .../network/lb/LoadBalancerConfigKey.java | 28 +++---------------- .../routing/LoadBalancerConfigCommand.java | 1 + .../cloud/network/HAProxyConfigurator.java | 19 ++++++++----- .../network/lb/LoadBalancerConfigManager.java | 11 +++++++- .../lb/LoadBalancerConfigManagerImpl.java | 12 ++++++++ .../network/router/CommandSetupHelper.java | 1 + 6 files changed, 40 insertions(+), 32 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index 490640f232e2..bb862f050eb9 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -20,13 +20,10 @@ import java.util.LinkedHashMap; import java.util.Map; -import com.cloud.network.rules.LoadBalancer; import com.cloud.network.rules.LoadBalancerConfig.Scope; import com.cloud.utils.Pair; -import org.apache.cloudstack.framework.config.ConfigKey; -import org.apache.cloudstack.framework.config.Configurable; -public enum LoadBalancerConfigKey implements Configurable { +public enum LoadBalancerConfigKey { LbStatsEnable(Category.Stats, "lb.stats.enable", "LB stats enable", Boolean.class, "true", "Enable statistics reporting with default settings, default is 'true'", Scope.Network, Scope.Vpc), @@ -66,22 +63,7 @@ public enum LoadBalancerConfigKey implements Configurable { LbServerMaxQueue(Category.LoadBalancer, "lb.server.maxqueue", "Max conn wait in queue per server", Long.class, "<0 means unlimited in haproxy>", "Maximum number of connections which will wait in queue for this server, default is ''", Scope.LoadBalancerRule), - LbSslConfiguration(Category.LoadBalancer, "lb.ssl.configuration", "SSL configuration, could be 'none', 'old' or 'intermediate'", String.class, "none" , "if 'none', no SSL configurations will be added, if 'old', refer to https://ssl-config.mozilla.org/#server=haproxy&server-version=1.8.17&config=old&openssl-version=1.0.2l if 'intermediate', refer to https://ssl-config.mozilla.org/#server=haproxy&server-version=1.8.17&config=intermediate&openssl-version=1.0.2l default value is 'none'", Scope.LoadBalancerRule); - - private static final String DefaultValueOfSSLCustomizationCK = "default.value.of.ssl.customization"; - - private static final ConfigKey DefaultValueOfSALCustomization = new ConfigKey<>("Advanced", String.class, DefaultValueOfSSLCustomizationCK, "none", - "Control default value of load balancer ssl customization", true, ConfigKey.Scope.Global); - - @Override - public String getConfigComponentName() { - return LoadBalancerConfigKey.class.getSimpleName(); - } - - @Override - public ConfigKey[] getConfigKeys() { - return new ConfigKey[]{DefaultValueOfSALCustomization}; - } + LbSslConfiguration(Category.LoadBalancer, "lb.ssl.configuration", "SSL configuration, could be 'none', 'old' or 'intermediate'", String.class, "Inherited from global setting" , "if 'none', no SSL configurations will be added, if 'old', refer to https://ssl-config.mozilla.org/#server=haproxy&server-version=1.8.17&config=old&openssl-version=1.0.2l if 'intermediate', refer to https://ssl-config.mozilla.org/#server=haproxy&server-version=1.8.17&config=intermediate&openssl-version=1.0.2l default value is 'none'", Scope.LoadBalancerRule); public static enum Category { General, Advanced, Stats, LoadBalancer @@ -122,8 +104,6 @@ public String displayText() { } public String defaultValue() { - if(key().equals("lb.ssl.configuration")) - return DefaultValueOfSALCustomization.value(); return _defaultValue; } @@ -220,8 +200,8 @@ public static Pair validate(Scope scope, String k } } - if(key.equals("lb.ssl.configuration")){ - if ( !("none".equalsIgnoreCase(value) || "old".equalsIgnoreCase(value) || "intermediate".equalsIgnoreCase(value)) ){ + if (LbSslConfiguration.key().equals(key)) { + if (! "none".equalsIgnoreCase(value) && ! "old".equalsIgnoreCase(value) && ! "intermediate".equalsIgnoreCase(value)) { return new Pair<>(null, "Please enter either 'none', 'old' or 'intermediate' for parameter " + key); } } diff --git a/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java b/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java index 8640db98ad80..2445c8e77b60 100644 --- a/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java +++ b/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java @@ -43,6 +43,7 @@ public class LoadBalancerConfigCommand extends NetworkElementCommand { public String lbStatsUri = "/admin?stats"; public String maxconn = ""; public String lbProtocol; + public String lbSslConfiguration = ""; public boolean keepAliveEnabled = false; NicTO nic; Long vpcId; diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 787d10a8f383..12beb702d902 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -483,8 +483,11 @@ private String getLbSubRuleForStickiness(final LoadBalancerTO lbTO) { return sb.toString(); } - private String getCustomizedSslConfigs(HashMap lbConfigsMap){ + private String getCustomizedSslConfigs(HashMap lbConfigsMap, final LoadBalancerConfigCommand lbCmd){ String lbSslConfiguration = lbConfigsMap.get(LoadBalancerConfigKey.LbSslConfiguration.key()); + if (lbSslConfiguration == null) { + lbSslConfiguration = lbCmd.lbSslConfiguration; + } if ("old".equalsIgnoreCase(lbSslConfiguration)) { return sslConfigurationOld; } else if ("intermediate".equalsIgnoreCase(lbSslConfiguration)) { @@ -493,7 +496,7 @@ private String getCustomizedSslConfigs(HashMap lbConfigsMap){ return ""; } - private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliveEnabled, final String networkCidr, HashMap networkLbConfigsMap) { + private List getRulesForPool(final LoadBalancerTO lbTO, final LoadBalancerConfigCommand lbCmd, HashMap networkLbConfigsMap) { StringBuilder sb = new StringBuilder(); final String poolName = sb.append(lbTO.getSrcIp().replace(".", "_")).append('-').append(lbTO.getSrcPort()).toString(); final String publicIP = lbTO.getSrcIp(); @@ -533,7 +536,7 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv sb.append(" alpn h2,http/1.1"); } - sb.append(getCustomizedSslConfigs(lbConfigsMap)); + sb.append(getCustomizedSslConfigs(lbConfigsMap, lbCmd)); sb.append("\n\thttp-request add-header X-Forwarded-Proto https"); } @@ -604,8 +607,9 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv sb.append(" check"); } - sb.append(getCustomizedSslConfigs(lbConfigsMap)); - + if (sslOffloading) { + sb.append(getCustomizedSslConfigs(lbConfigsMap, lbCmd)); + } if (lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxConn.key()) != null) { long maxConnEach = Long.parseLong(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxConn.key())); @@ -668,6 +672,7 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv http = true; } + boolean keepAliveEnabled = lbCmd.keepAliveEnabled; String cfgLbHttpKeepalive = lbConfigsMap.get(LoadBalancerConfigKey.LbHttpKeepalive.key()); if (cfgLbHttpKeepalive != null && cfgLbHttpKeepalive.equalsIgnoreCase("true")) { keepAliveEnabled = true; @@ -699,7 +704,7 @@ private List getRulesForPool(final LoadBalancerTO lbTO, boolean keepAliv result.add(sb.toString()); result.addAll(frontendConfigs); sb = new StringBuilder(); - sb.append("\tacl local_subnet src ").append(networkCidr); + sb.append("\tacl local_subnet src ").append(lbCmd.getNetworkCidr()); sb.append("\n\tuse_backend ").append(poolName).append("-backend-local if local_subnet"); sb.append("\n\tdefault_backend ").append(poolName).append("-backend"); sb.append("\n\n"); @@ -864,7 +869,7 @@ public String[] generateConfiguration(final LoadBalancerConfigCommand lbCmd) { if (lbTO.isRevoked()) { continue; } - final List poolRules = getRulesForPool(lbTO, lbCmd.keepAliveEnabled, lbCmd.getNetworkCidr(), networkLbConfigsMap); + final List poolRules = getRulesForPool(lbTO, lbCmd, networkLbConfigsMap); result.addAll(poolRules); has_listener = true; } diff --git a/engine/components-api/src/main/java/com/cloud/network/lb/LoadBalancerConfigManager.java b/engine/components-api/src/main/java/com/cloud/network/lb/LoadBalancerConfigManager.java index f2ce1dd87ecc..b09b67ea2b24 100644 --- a/engine/components-api/src/main/java/com/cloud/network/lb/LoadBalancerConfigManager.java +++ b/engine/components-api/src/main/java/com/cloud/network/lb/LoadBalancerConfigManager.java @@ -19,8 +19,17 @@ import java.util.List; import com.cloud.network.rules.LoadBalancerConfig; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; -public interface LoadBalancerConfigManager { +public interface LoadBalancerConfigManager extends Configurable { + + static final String DefaultLbSSLConfigurationCK = "default.lb.ssl.configuration"; + + static final ConfigKey DefaultLbSSLConfiguration = new ConfigKey<>("Advanced", String.class, + DefaultLbSSLConfigurationCK, "none", + "Default value of load balancer ssl configuration, could be 'none', 'old' or 'intermediate'", + true, ConfigKey.Scope.Global); List getNetworkLbConfigs(Long networkId); diff --git a/server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java b/server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java index 341262821f7a..a661c61ed1ab 100644 --- a/server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java +++ b/server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java @@ -52,6 +52,7 @@ import org.apache.cloudstack.api.command.user.loadbalancer.ReplaceLoadBalancerConfigsCmd; import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLoadBalancerConfigCmd; import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.network.lb.LoadBalancerConfigKey; import org.apache.log4j.Logger; @@ -384,4 +385,15 @@ private boolean applyLbConfigsForNetwork(Long networkId) { throw new CloudRuntimeException("Failed to apply LB configs in virtual router on network: " + networkId); } } + + @Override + public String getConfigComponentName() { + return LoadBalancerConfigManager.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[]{ DefaultLbSSLConfiguration }; + } + } diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index 97bece2df727..230802e906b8 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -374,6 +374,7 @@ public void createApplyLoadBalancingRulesCommands(final List cmd.lbStatsUri = _configDao.getValue(Config.NetworkLBHaproxyStatsUri.key()); cmd.lbStatsAuth = _configDao.getValue(Config.NetworkLBHaproxyStatsAuth.key()); cmd.lbStatsPort = _configDao.getValue(Config.NetworkLBHaproxyStatsPort.key()); + cmd.lbSslConfiguration = _configDao.getValue("default.lb.ssl.configuration"); cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, _routerControlHelper.getRouterControlIp(router.getId())); cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, _routerControlHelper.getRouterIpInNetwork(guestNetworkId, router.getId())); From 9a6e8d45807388b35a164289083126c06e344ff8 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 14 Jul 2020 07:41:11 +0000 Subject: [PATCH 57/75] fix haproxy check --- systemvm/debian/root/health_checks/haproxy_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/systemvm/debian/root/health_checks/haproxy_check.py b/systemvm/debian/root/health_checks/haproxy_check.py index 8a46004438da..a2889b485b84 100644 --- a/systemvm/debian/root/health_checks/haproxy_check.py +++ b/systemvm/debian/root/health_checks/haproxy_check.py @@ -196,7 +196,7 @@ def checkLoadBalance(haproxyData, haCfgSections): bindStr += " ssl crt " + SSL_CERTS_DIR + lbSec["sslcert"] if "http2" in lbSec and lbSec["http2"].lower() == 'true': bindStr += " alpn h2,http/1.1" - if cfgSection["bind"][0] != bindStr: + if not cfgSection["bind"][0].startswith(bindStr): print "Incorrect bind string found. Expected " + bindStr + " but found " + cfgSection["bind"][0] + "." correct = False From 6237ba2c0abc2af7dfbeb8056f63cd9e45b1f598 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 14 Jul 2020 19:04:18 +0000 Subject: [PATCH 58/75] Add enum LoadBalancerConfig.SSLConfiguration --- .../network/rules/LoadBalancerConfig.java | 34 +++++++++++++++++++ .../network/lb/LoadBalancerConfigKey.java | 5 +-- .../cloud/network/HAProxyConfigurator.java | 5 +-- .../ConfigurationManagerImpl.java | 10 ++++++ 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/com/cloud/network/rules/LoadBalancerConfig.java b/api/src/main/java/com/cloud/network/rules/LoadBalancerConfig.java index 41cc96b66454..1cfe3b051694 100644 --- a/api/src/main/java/com/cloud/network/rules/LoadBalancerConfig.java +++ b/api/src/main/java/com/cloud/network/rules/LoadBalancerConfig.java @@ -16,13 +16,47 @@ // under the License. package com.cloud.network.rules; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; public interface LoadBalancerConfig extends Identity, InternalIdentity { + public enum SSLConfiguration { + NONE("none"), OLD("old"), INTERMEDIATE("intermediate"); + + String _config; + + SSLConfiguration(String config) { + _config = config; + } + + @Override + public String toString() { + return _config; + } + + public static boolean validate(String value) { + for (SSLConfiguration config : SSLConfiguration.values()) { + if (config.toString().equals(value)) { + return true; + } + } + return false; + } + + public static List getValues() { + ArrayList values = new ArrayList(); + for (SSLConfiguration config : SSLConfiguration.values()) { + values.add(config.toString()); + } + return values; + } + } + public enum Scope { Network, Vpc, LoadBalancerRule; } diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index bb862f050eb9..b4b63bb2d595 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -20,6 +20,7 @@ import java.util.LinkedHashMap; import java.util.Map; +import com.cloud.network.rules.LoadBalancerConfig.SSLConfiguration; import com.cloud.network.rules.LoadBalancerConfig.Scope; import com.cloud.utils.Pair; @@ -201,8 +202,8 @@ public static Pair validate(Scope scope, String k } if (LbSslConfiguration.key().equals(key)) { - if (! "none".equalsIgnoreCase(value) && ! "old".equalsIgnoreCase(value) && ! "intermediate".equalsIgnoreCase(value)) { - return new Pair<>(null, "Please enter either 'none', 'old' or 'intermediate' for parameter " + key); + if (value == null || ! SSLConfiguration.validate(value.toLowerCase())) { + return new Pair<>(null, "Please enter valid value in " + String.join(",", SSLConfiguration.getValues()) + " for parameter " + key); } } diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 12beb702d902..7c42ac812040 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -38,6 +38,7 @@ import com.cloud.agent.api.to.LoadBalancerTO.StickinessPolicyTO; import com.cloud.agent.api.to.PortForwardingRuleTO; import com.cloud.agent.resource.virtualnetwork.model.LoadBalancerRule.SslCertEntry; +import com.cloud.network.rules.LoadBalancerConfig.SSLConfiguration; import com.cloud.network.lb.LoadBalancingRule.LbSslCert; import com.cloud.network.rules.LbStickinessMethod.StickinessMethodType; import com.cloud.utils.Pair; @@ -488,9 +489,9 @@ private String getCustomizedSslConfigs(HashMap lbConfigsMap, fin if (lbSslConfiguration == null) { lbSslConfiguration = lbCmd.lbSslConfiguration; } - if ("old".equalsIgnoreCase(lbSslConfiguration)) { + if (SSLConfiguration.OLD.toString().equalsIgnoreCase(lbSslConfiguration)) { return sslConfigurationOld; - } else if ("intermediate".equalsIgnoreCase(lbSslConfiguration)) { + } else if (SSLConfiguration.INTERMEDIATE.toString().equalsIgnoreCase(lbSslConfiguration)) { return sslConfigurationIntermediate; } return ""; diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 9b272d668717..cfc83cc9ebbb 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -183,6 +183,8 @@ import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO; import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.lb.LoadBalancerConfigManager; +import com.cloud.network.rules.LoadBalancerConfig.SSLConfiguration; import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.vpc.VpcManager; import com.cloud.offering.DiskOffering; @@ -880,6 +882,14 @@ private String validateConfigurationValue(final String name, String value, final return errMsg; } + if (LoadBalancerConfigManager.DefaultLbSSLConfiguration.key().equalsIgnoreCase(name)) { + if (org.apache.commons.lang3.StringUtils.isBlank(value) || ! SSLConfiguration.validate(value.toLowerCase())) { + final String msg = "Please enter valid value in " + String.join(",", SSLConfiguration.getValues()); + s_logger.error(msg); + throw new InvalidParameterValueException(msg); + } + } + if (value == null) { if (type.equals(Boolean.class)) { return "Please enter either 'true' or 'false'."; From 668a189d576e7937a52cedb5551cbed99222564d Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 21 Jul 2020 19:37:05 +0000 Subject: [PATCH 59/75] fix pycodestyle failures with CsLoadBalancer.py and haproxy_check.py --- .../debian/opt/cloud/bin/cs/CsLoadBalancer.py | 11 ++++---- .../root/health_checks/haproxy_check.py | 25 +++++++++++-------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py index 1a5e37b09219..7d2d3173d718 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py @@ -29,6 +29,7 @@ SSL_CERTS_DIR = "/etc/ssl/cloudstack/" CsHelper.execute("mkdir -p %s" % SSL_CERTS_DIR) + class CsLoadBalancer(CsDataBag): """ Manage Load Balancer entries """ @@ -94,7 +95,7 @@ def _configure_firewall(self, add_rules, remove_rules, stat_rules): def _configure_firewall_for_transparent(self, is_transparent): tableNo = 99 firewall = self.config.get_fw() - if is_transparent is None or is_transparent == False: + if is_transparent is None or not is_transparent: if ["mangle", "", "-A PREROUTING -p tcp -m socket -j DIVERT"] in firewall: firewall.remove(["mangle", "", "-A PREROUTING -p tcp -m socket -j DIVERT"]) firewall.remove(["mangle", "", "-A DIVERT -j MARK --set-xmark %s/0xffffffff" % hex(tableNo)]) @@ -103,7 +104,7 @@ def _configure_firewall_for_transparent(self, is_transparent): if CsHelper.execute("ip rule show fwmark %s lookup %s" % (tableNo, tableNo)): CsHelper.execute("ip route del local 0.0.0.0/0 dev lo table %s" % tableNo) CsHelper.execute("ip rule del fwmark %s lookup %s" % (tableNo, tableNo)) - elif is_transparent == True: + elif is_transparent: if ["mangle", "", "-A PREROUTING -p tcp -m socket -j DIVERT"] not in firewall: firewall.append(["mangle", "", "-N DIVERT"]) firewall.append(["mangle", "", "-A PREROUTING -p tcp -m socket -j DIVERT"]) @@ -120,10 +121,10 @@ def _create_pem_for_sslcert(self, ssl_certs): cert_names.append(cert['name'] + ".pem") file = CsFile("%s/%s.pem" % (SSL_CERTS_DIR, cert['name'])) file.empty() - file.add("%s\n" % cert['cert'].replace("\r\n","\n")) + file.add("%s\n" % cert['cert'].replace("\r\n", "\n")) if 'chain' in cert.keys(): - file.add("%s\n" % cert['chain'].replace("\r\n","\n")) - file.add("%s\n" % cert['key'].replace("\r\n","\n")) + file.add("%s\n" % cert['chain'].replace("\r\n", "\n")) + file.add("%s\n" % cert['key'].replace("\r\n", "\n")) file.commit() for f in listdir(SSL_CERTS_DIR): if f not in cert_names: diff --git a/systemvm/debian/root/health_checks/haproxy_check.py b/systemvm/debian/root/health_checks/haproxy_check.py index a2889b485b84..6a68188c2d80 100644 --- a/systemvm/debian/root/health_checks/haproxy_check.py +++ b/systemvm/debian/root/health_checks/haproxy_check.py @@ -21,6 +21,7 @@ SSL_CERTS_DIR = "/etc/ssl/cloudstack/" + def checkGlobal(haproxyData, haCfgSections): if "global.maxconn" in haproxyData and "maxconn" in haCfgSections["global"]: if haproxyData["global.maxconn"] != haCfgSections["global"]["maxconn"][0].strip(): @@ -33,27 +34,29 @@ def checkGlobal(haproxyData, haCfgSections): return True + def checkDefaults(haproxyData, haCfgSections): if "timeout" in haCfgSections["defaults"]: timeouts = haCfgSections["defaults"]["timeout"] if "default.timeout.connect" in haproxyData: timeout = "connect %s" % haproxyData["default.timeout.connect"] if timeout not in timeouts: - print "default timeout connect mismatch occured" - return False + print "default timeout connect mismatch occured" + return False if "default.timeout.server" in haproxyData: timeout = "server %s" % haproxyData["default.timeout.server"] if timeout not in timeouts: - print "default timeout server mismatch occured" - return False + print "default timeout server mismatch occured" + return False if "default.timeout.client" in haproxyData: timeout = "client %s" % haproxyData["default.timeout.client"] if timeout not in timeouts: - print "default timeout client mismatch occured" - return False + print "default timeout client mismatch occured" + return False return True + def checkFrontendLbValues(lbSection, cfgSection): correct = True if "lb.timeout.client" in lbSection: @@ -68,6 +71,7 @@ def checkFrontendLbValues(lbSection, cfgSection): return correct + def checkBackendLbValues(lbSection, cfgSection): correct = True if "lb.maxconn" in lbSection: @@ -112,6 +116,7 @@ def checkBackendLbValues(lbSection, cfgSection): return correct + def checkServerValues(haproxyData, serverSections): correct = True serverArray = serverSections[0].split(" ") @@ -150,14 +155,14 @@ def checkServerValues(haproxyData, serverSections): return correct + def checkLoadBalance(haproxyData, haCfgSections): correct = True for lbSec in haproxyData: if "global.maxconn" in lbSec: # Ignore first part (global and default settings) continue srcServer = lbSec["sourceIp"].replace('.', '_') + "-" + \ - formatPort(lbSec["sourcePortStart"], - lbSec["sourcePortEnd"]) + formatPort(lbSec["sourcePortStart"], lbSec["sourcePortEnd"]) secName = "listen " + srcServer secFrontend = "frontend " + srcServer secBackend = "backend " + srcServer + "-backend" @@ -192,7 +197,7 @@ def checkLoadBalance(haproxyData, haCfgSections): correct = False bindStr = lbSec["sourceIp"] + ":" + formatPort(lbSec["sourcePortStart"], lbSec["sourcePortEnd"]) - if lbSec.has_key("sslcert"): + if "sslcert" in lbSec: bindStr += " ssl crt " + SSL_CERTS_DIR + lbSec["sslcert"] if "http2" in lbSec and lbSec["http2"].lower() == 'true': bindStr += " alpn h2,http/1.1" @@ -201,7 +206,7 @@ def checkLoadBalance(haproxyData, haCfgSections): correct = False if ("http" in lbSec and lbSec["http"] == 'true') \ - or lbSec.has_key("sslcert") \ + or "sslcert" in lbSec \ or lbSec["stickiness"].find("AppCookie") != -1 \ or lbSec["stickiness"].find("LbCookie") != -1: if not ("mode" in cfgSection and cfgSection["mode"][0] == "http"): From f98e575528d405c6b622ab12b8947c79388f689c Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Thu, 13 Aug 2020 16:50:32 +0000 Subject: [PATCH 60/75] lb config: fix NPE with test_loadbalance.py --- .../main/java/com/cloud/network/router/NetworkHelperImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java index 90e8e7accc98..32ee9981ceb1 100644 --- a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java +++ b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java @@ -800,7 +800,7 @@ public boolean validateHAProxyLBRule(final LoadBalancingRule rule) { } List lbProtocols = Arrays.asList("tcp", "udp", "tcp-proxy", "ssl"); - if (! lbProtocols.contains(rule.getLbProtocol())) { + if (rule.getLbProtocol() != null && ! lbProtocols.contains(rule.getLbProtocol())) { throw new InvalidParameterValueException("protocol " + rule.getLbProtocol() + " is not in valid protocols " + lbProtocols); } From c9e4b703a88869f0af3638ac232955c01f8a34a1 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 23 Sep 2020 09:55:48 +0000 Subject: [PATCH 61/75] Move some files from com.cloud to org.apache.cloudstack --- .../agent/api/to/LoadBalancerConfigTO.java | 2 +- .../com/cloud/agent/api/to/LoadBalancerTO.java | 3 ++- .../java/org/apache/cloudstack/api/BaseCmd.java | 2 +- .../cloudstack/api/ResponseGenerator.java | 2 +- .../AssignCertToLoadBalancerCmd.java | 1 + .../CreateLoadBalancerConfigCmd.java | 9 +++++---- .../DeleteLoadBalancerConfigCmd.java | 5 +++-- .../ListLoadBalancerConfigsCmd.java | 6 +++--- .../ReplaceLoadBalancerConfigsCmd.java | 5 +++-- .../UpdateLoadBalancerConfigCmd.java | 5 +++-- .../response/LoadBalancerConfigResponse.java | 2 +- .../network/lb}/LoadBalancerConfig.java | 2 +- .../network/lb/LoadBalancerConfigKey.java | 5 +++-- .../network/lb/LoadBalancerConfigService.java | 4 +--- .../api/routing/LoadBalancerConfigCommand.java | 3 ++- .../com/cloud/network/HAProxyConfigurator.java | 2 +- .../network/lb/LoadBalancerConfigManager.java | 3 +-- .../network/dao/LoadBalancerConfigDao.java | 3 ++- .../network/dao/LoadBalancerConfigDaoImpl.java | 3 ++- .../cloud/network/dao/LoadBalancerConfigVO.java | 2 +- .../java/com/cloud/api/ApiResponseHelper.java | 2 +- .../configuration/ConfigurationManagerImpl.java | 4 ++-- .../network/router/CommandSetupHelper.java | 2 +- .../VirtualNetworkApplianceManagerImpl.java | 2 +- .../lb/LoadBalancerConfigManagerImpl.java | 17 ++++++++--------- 25 files changed, 51 insertions(+), 45 deletions(-) rename api/src/main/java/{com/cloud/network/rules => org/apache/cloudstack/network/lb}/LoadBalancerConfig.java (98%) rename api/src/main/java/{com/cloud => org/apache/cloudstack}/network/lb/LoadBalancerConfigService.java (95%) rename engine/components-api/src/main/java/{com/cloud => org/apache/cloudstack}/network/lb/LoadBalancerConfigManager.java (95%) rename server/src/main/java/{com/cloud => org/apache/cloudstack}/network/lb/LoadBalancerConfigManagerImpl.java (95%) diff --git a/api/src/main/java/com/cloud/agent/api/to/LoadBalancerConfigTO.java b/api/src/main/java/com/cloud/agent/api/to/LoadBalancerConfigTO.java index 82102426f1be..3973a197fcc4 100644 --- a/api/src/main/java/com/cloud/agent/api/to/LoadBalancerConfigTO.java +++ b/api/src/main/java/com/cloud/agent/api/to/LoadBalancerConfigTO.java @@ -16,7 +16,7 @@ // under the License. package com.cloud.agent.api.to; -import com.cloud.network.rules.LoadBalancerConfig; +import org.apache.cloudstack.network.lb.LoadBalancerConfig; public class LoadBalancerConfigTO { private String name; diff --git a/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java b/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java index c245d7c5970c..13b2f16ba2df 100644 --- a/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java +++ b/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java @@ -33,9 +33,10 @@ import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; import com.cloud.network.lb.LoadBalancingRule.LbSslCert; import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; -import com.cloud.network.rules.LoadBalancerConfig; import com.cloud.utils.Pair; +import org.apache.cloudstack.network.lb.LoadBalancerConfig; + public class LoadBalancerTO { String uuid; String srcIp; diff --git a/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java b/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java index 06dc345132f7..e21d07fc690d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java @@ -39,6 +39,7 @@ import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService; import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService; +import org.apache.cloudstack.network.lb.LoadBalancerConfigService; import org.apache.cloudstack.query.QueryService; import org.apache.cloudstack.storage.ImageStoreService; import org.apache.cloudstack.usage.UsageService; @@ -57,7 +58,6 @@ import com.cloud.network.VpcVirtualNetworkApplianceService; import com.cloud.network.as.AutoScaleService; import com.cloud.network.firewall.FirewallService; -import com.cloud.network.lb.LoadBalancerConfigService; import com.cloud.network.lb.LoadBalancingRulesService; import com.cloud.network.rules.RulesService; import com.cloud.network.security.SecurityGroupService; diff --git a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java index 6ec6534ab378..ba19fda2230c 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java @@ -130,6 +130,7 @@ import org.apache.cloudstack.backup.BackupSchedule; import org.apache.cloudstack.config.Configuration; import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; +import org.apache.cloudstack.network.lb.LoadBalancerConfig; import org.apache.cloudstack.region.PortableIp; import org.apache.cloudstack.region.PortableIpRange; import org.apache.cloudstack.region.Region; @@ -171,7 +172,6 @@ import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.HealthCheckPolicy; import com.cloud.network.rules.LoadBalancer; -import com.cloud.network.rules.LoadBalancerConfig; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.StaticNatRule; import com.cloud.network.rules.StickinessPolicy; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/AssignCertToLoadBalancerCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/AssignCertToLoadBalancerCmd.java index 38b586f1dff2..37a3d0668a5f 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/AssignCertToLoadBalancerCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/AssignCertToLoadBalancerCmd.java @@ -62,6 +62,7 @@ public class AssignCertToLoadBalancerCmd extends BaseAsyncCmd { Long certId; @Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN, required = false, + since = "4.15", description = "Force assign the certificate. If there is a certificate bound to the LB, it will be removed") private Boolean forced; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerConfigCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerConfigCmd.java index a1ef03b047ff..fa6eb5adf77b 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerConfigCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerConfigCmd.java @@ -28,22 +28,23 @@ import org.apache.cloudstack.api.response.LoadBalancerConfigResponse; import org.apache.cloudstack.api.response.NetworkResponse; import org.apache.cloudstack.api.response.VpcResponse; +import org.apache.cloudstack.network.lb.LoadBalancerConfig; +import org.apache.cloudstack.network.lb.LoadBalancerConfig.Scope; import org.apache.log4j.Logger; import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.Network; import com.cloud.network.rules.LoadBalancer; -import com.cloud.network.rules.LoadBalancerConfig; -import com.cloud.network.rules.LoadBalancerConfig.Scope; import com.cloud.network.vpc.Vpc; @APICommand(name = "createLoadBalancerConfig", description = "Creates a load balancer config", responseObject = LoadBalancerConfigResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.15", authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) public class CreateLoadBalancerConfigCmd extends BaseAsyncCreateCmd { - public static final Logger s_logger = Logger.getLogger(CreateLoadBalancerConfigCmd.class.getName()); + public static final Logger LOGGER = Logger.getLogger(CreateLoadBalancerConfigCmd.class.getName()); private static final String s_name = "createloadbalancerconfigresponse"; @@ -147,7 +148,7 @@ public void execute() { } lbConfigResponse.setResponseName(getCommandName()); } catch (Exception ex) { - s_logger.warn("Failed to create LB config due to exception ", ex); + LOGGER.warn("Failed to create LB config due to exception ", ex); } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/DeleteLoadBalancerConfigCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/DeleteLoadBalancerConfigCmd.java index aedd26390017..0ebe4d0b1162 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/DeleteLoadBalancerConfigCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/DeleteLoadBalancerConfigCmd.java @@ -25,21 +25,22 @@ import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.LoadBalancerConfigResponse; import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.network.lb.LoadBalancerConfig; import org.apache.log4j.Logger; import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.Network; import com.cloud.network.rules.FirewallRule; -import com.cloud.network.rules.LoadBalancerConfig; import com.cloud.network.vpc.Vpc; @APICommand(name = "deleteLoadBalancerConfig", description = "Deletes a load balancer config.", responseObject = SuccessResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.15", authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) public class DeleteLoadBalancerConfigCmd extends BaseAsyncCmd { - public static final Logger s_logger = Logger.getLogger(DeleteLoadBalancerConfigCmd.class.getName()); + public static final Logger LOGGER = Logger.getLogger(DeleteLoadBalancerConfigCmd.class.getName()); private static final String s_name = "deleteloadbalancerconfigresponse"; ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerConfigsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerConfigsCmd.java index e83edbaef926..b38ef94a795d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerConfigsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerConfigsCmd.java @@ -29,16 +29,16 @@ import org.apache.cloudstack.api.response.LoadBalancerConfigResponse; import org.apache.cloudstack.api.response.NetworkResponse; import org.apache.cloudstack.api.response.VpcResponse; +import org.apache.cloudstack.network.lb.LoadBalancerConfig; import org.apache.log4j.Logger; -import com.cloud.network.rules.LoadBalancerConfig; - @APICommand(name = "listLoadBalancerConfigs", description = "Lists load balancer configs.", responseObject = LoadBalancerConfigResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.15", authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) public class ListLoadBalancerConfigsCmd extends BaseListCmd { - public static final Logger s_logger = Logger.getLogger(ListLoadBalancerConfigsCmd.class.getName()); + public static final Logger LOGGER = Logger.getLogger(ListLoadBalancerConfigsCmd.class.getName()); private static final String s_name = "listloadbalancerconfigsresponse"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ReplaceLoadBalancerConfigsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ReplaceLoadBalancerConfigsCmd.java index 8e997f4629a3..bd8c44921763 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ReplaceLoadBalancerConfigsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ReplaceLoadBalancerConfigsCmd.java @@ -30,21 +30,22 @@ import org.apache.cloudstack.api.response.NetworkResponse; import org.apache.cloudstack.api.response.SuccessResponse; import org.apache.cloudstack.api.response.VpcResponse; +import org.apache.cloudstack.network.lb.LoadBalancerConfig; import org.apache.commons.collections.MapUtils; import org.apache.log4j.Logger; import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.Network; -import com.cloud.network.rules.LoadBalancerConfig; import com.cloud.network.vpc.Vpc; @APICommand(name = "replaceLoadBalancerConfigs", description = "Replaces load balancer configs of vpc/network/rule", responseObject = SuccessResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.15", authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) public class ReplaceLoadBalancerConfigsCmd extends BaseAsyncCmd { - public static final Logger s_logger = Logger.getLogger(ReplaceLoadBalancerConfigsCmd.class.getName()); + public static final Logger LOGGER = Logger.getLogger(ReplaceLoadBalancerConfigsCmd.class.getName()); private static final String s_name = "replaceloadbalancerconfigsresponse"; ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLoadBalancerConfigCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLoadBalancerConfigCmd.java index 97c1c1e7b026..a006d2d3b5fe 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLoadBalancerConfigCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLoadBalancerConfigCmd.java @@ -24,21 +24,22 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.LoadBalancerConfigResponse; +import org.apache.cloudstack.network.lb.LoadBalancerConfig; import org.apache.log4j.Logger; import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.Network; import com.cloud.network.rules.FirewallRule; -import com.cloud.network.rules.LoadBalancerConfig; import com.cloud.network.vpc.Vpc; @APICommand(name = "updateLoadBalancerConfig", description = "Updates a load balancer config", responseObject = LoadBalancerConfigResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.15", authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) public class UpdateLoadBalancerConfigCmd extends BaseAsyncCmd { - public static final Logger s_logger = Logger.getLogger(UpdateLoadBalancerConfigCmd.class.getName()); + public static final Logger LOGGER = Logger.getLogger(UpdateLoadBalancerConfigCmd.class.getName()); private static final String s_name = "updateloadbalancerconfigresponse"; ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/response/LoadBalancerConfigResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/LoadBalancerConfigResponse.java index 2ba96fcea84f..3c2633b07fa7 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/LoadBalancerConfigResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/LoadBalancerConfigResponse.java @@ -21,8 +21,8 @@ import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; +import org.apache.cloudstack.network.lb.LoadBalancerConfig; -import com.cloud.network.rules.LoadBalancerConfig; import com.cloud.serializer.Param; import com.google.gson.annotations.SerializedName; diff --git a/api/src/main/java/com/cloud/network/rules/LoadBalancerConfig.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfig.java similarity index 98% rename from api/src/main/java/com/cloud/network/rules/LoadBalancerConfig.java rename to api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfig.java index 1cfe3b051694..31943b4378e5 100644 --- a/api/src/main/java/com/cloud/network/rules/LoadBalancerConfig.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfig.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.rules; +package org.apache.cloudstack.network.lb; import java.util.ArrayList; import java.util.Date; diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index b4b63bb2d595..7830f33adaa3 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -20,8 +20,9 @@ import java.util.LinkedHashMap; import java.util.Map; -import com.cloud.network.rules.LoadBalancerConfig.SSLConfiguration; -import com.cloud.network.rules.LoadBalancerConfig.Scope; +import org.apache.cloudstack.network.lb.LoadBalancerConfig.SSLConfiguration; +import org.apache.cloudstack.network.lb.LoadBalancerConfig.Scope; + import com.cloud.utils.Pair; public enum LoadBalancerConfigKey { diff --git a/api/src/main/java/com/cloud/network/lb/LoadBalancerConfigService.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigService.java similarity index 95% rename from api/src/main/java/com/cloud/network/lb/LoadBalancerConfigService.java rename to api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigService.java index c650210b3521..be02ba225523 100644 --- a/api/src/main/java/com/cloud/network/lb/LoadBalancerConfigService.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigService.java @@ -14,12 +14,10 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.lb; +package org.apache.cloudstack.network.lb; import java.util.List; -import com.cloud.network.rules.LoadBalancerConfig; - import org.apache.cloudstack.api.command.user.loadbalancer.CreateLoadBalancerConfigCmd; import org.apache.cloudstack.api.command.user.loadbalancer.DeleteLoadBalancerConfigCmd; import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerConfigsCmd; diff --git a/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java b/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java index 2445c8e77b60..e87bef6ab183 100644 --- a/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java +++ b/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java @@ -22,7 +22,8 @@ import com.cloud.agent.api.to.LoadBalancerConfigTO; import com.cloud.agent.api.to.LoadBalancerTO; import com.cloud.agent.api.to.NicTO; -import com.cloud.network.rules.LoadBalancerConfig; + +import org.apache.cloudstack.network.lb.LoadBalancerConfig; import java.util.ArrayList; import java.util.List; diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index 7c42ac812040..e382b6dc2b20 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -29,6 +29,7 @@ import java.util.Optional; import org.apache.cloudstack.network.lb.LoadBalancerConfigKey; +import org.apache.cloudstack.network.lb.LoadBalancerConfig.SSLConfiguration; import org.apache.log4j.Logger; import com.cloud.agent.api.routing.LoadBalancerConfigCommand; @@ -38,7 +39,6 @@ import com.cloud.agent.api.to.LoadBalancerTO.StickinessPolicyTO; import com.cloud.agent.api.to.PortForwardingRuleTO; import com.cloud.agent.resource.virtualnetwork.model.LoadBalancerRule.SslCertEntry; -import com.cloud.network.rules.LoadBalancerConfig.SSLConfiguration; import com.cloud.network.lb.LoadBalancingRule.LbSslCert; import com.cloud.network.rules.LbStickinessMethod.StickinessMethodType; import com.cloud.utils.Pair; diff --git a/engine/components-api/src/main/java/com/cloud/network/lb/LoadBalancerConfigManager.java b/engine/components-api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManager.java similarity index 95% rename from engine/components-api/src/main/java/com/cloud/network/lb/LoadBalancerConfigManager.java rename to engine/components-api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManager.java index b09b67ea2b24..ed90b4ef675b 100644 --- a/engine/components-api/src/main/java/com/cloud/network/lb/LoadBalancerConfigManager.java +++ b/engine/components-api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManager.java @@ -14,11 +14,10 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.lb; +package org.apache.cloudstack.network.lb; import java.util.List; -import com.cloud.network.rules.LoadBalancerConfig; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; diff --git a/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDao.java b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDao.java index 19a318b1750e..64a88432bae8 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDao.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDao.java @@ -18,9 +18,10 @@ import java.util.List; -import com.cloud.network.rules.LoadBalancerConfig.Scope; import com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.network.lb.LoadBalancerConfig.Scope; + public interface LoadBalancerConfigDao extends GenericDao { List listByNetworkId(Long networkId); diff --git a/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDaoImpl.java index 59cb53d0c819..4f6ac9d599c6 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDaoImpl.java @@ -19,7 +19,8 @@ import java.util.ArrayList; import java.util.List; -import com.cloud.network.rules.LoadBalancerConfig.Scope; +import org.apache.cloudstack.network.lb.LoadBalancerConfig.Scope; + import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; diff --git a/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigVO.java b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigVO.java index fd0690b33a07..77f602e43f66 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigVO.java @@ -16,7 +16,6 @@ // under the License. package com.cloud.network.dao; -import com.cloud.network.rules.LoadBalancerConfig; import com.cloud.utils.db.GenericDao; import java.util.Date; @@ -29,6 +28,7 @@ import javax.persistence.Transient; import org.apache.cloudstack.api.InternalIdentity; +import org.apache.cloudstack.network.lb.LoadBalancerConfig; import org.apache.cloudstack.network.lb.LoadBalancerConfigKey; @Entity diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index ff428ee088fe..0e393d5620eb 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -163,6 +163,7 @@ import org.apache.cloudstack.framework.jobs.AsyncJobManager; import org.apache.cloudstack.management.ManagementServerHost; import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; +import org.apache.cloudstack.network.lb.LoadBalancerConfig; import org.apache.cloudstack.network.lb.LoadBalancerConfigKey; import org.apache.cloudstack.region.PortableIp; import org.apache.cloudstack.region.PortableIpRange; @@ -272,7 +273,6 @@ import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.HealthCheckPolicy; import com.cloud.network.rules.LoadBalancer; -import com.cloud.network.rules.LoadBalancerConfig; import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.PortForwardingRuleVO; diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index cfc83cc9ebbb..9ac09e19c2b7 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -87,6 +87,8 @@ import org.apache.cloudstack.framework.messagebus.MessageBus; import org.apache.cloudstack.framework.messagebus.MessageSubscriber; import org.apache.cloudstack.framework.messagebus.PublishScope; +import org.apache.cloudstack.network.lb.LoadBalancerConfigManager; +import org.apache.cloudstack.network.lb.LoadBalancerConfig.SSLConfiguration; import org.apache.cloudstack.region.PortableIp; import org.apache.cloudstack.region.PortableIpDao; import org.apache.cloudstack.region.PortableIpRange; @@ -183,8 +185,6 @@ import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO; import com.cloud.network.dao.PhysicalNetworkVO; -import com.cloud.network.lb.LoadBalancerConfigManager; -import com.cloud.network.rules.LoadBalancerConfig.SSLConfiguration; import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.vpc.VpcManager; import com.cloud.offering.DiskOffering; diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index 230802e906b8..612c7800a064 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -28,6 +28,7 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.network.lb.LoadBalancerConfigKey; +import org.apache.cloudstack.network.lb.LoadBalancerConfigManager; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -94,7 +95,6 @@ import com.cloud.network.dao.Site2SiteVpnGatewayDao; import com.cloud.network.dao.Site2SiteVpnGatewayVO; import com.cloud.network.dao.VpnUserDao; -import com.cloud.network.lb.LoadBalancerConfigManager; import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; diff --git a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 0a381a649091..39bcf55d90c0 100644 --- a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -64,6 +64,7 @@ import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO; import org.apache.cloudstack.lb.dao.ApplicationLoadBalancerRuleDao; import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.cloudstack.network.lb.LoadBalancerConfig; import org.apache.cloudstack.network.lb.LoadBalancerConfigKey; import org.apache.cloudstack.network.topology.NetworkTopology; import org.apache.cloudstack.network.topology.NetworkTopologyContext; @@ -197,7 +198,6 @@ import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRuleVO; -import com.cloud.network.rules.LoadBalancerConfig; import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.PortForwardingRuleVO; diff --git a/server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java b/server/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManagerImpl.java similarity index 95% rename from server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java rename to server/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManagerImpl.java index a661c61ed1ab..d53aca830ed8 100644 --- a/server/src/main/java/com/cloud/network/lb/LoadBalancerConfigManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManagerImpl.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.network.lb; +package org.apache.cloudstack.network.lb; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -34,8 +34,7 @@ import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkServiceMapDao; import com.cloud.network.dao.NetworkVO; -import com.cloud.network.rules.LoadBalancerConfig; -import com.cloud.network.rules.LoadBalancerConfig.Scope; +import com.cloud.network.lb.LoadBalancingRulesManager; import com.cloud.network.rules.LoadBalancerContainer.Scheme; import com.cloud.network.vpc.VpcVO; import com.cloud.network.vpc.dao.VpcDao; @@ -53,11 +52,11 @@ import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLoadBalancerConfigCmd; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.framework.config.ConfigKey; -import org.apache.cloudstack.network.lb.LoadBalancerConfigKey; +import org.apache.cloudstack.network.lb.LoadBalancerConfig.Scope; import org.apache.log4j.Logger; public class LoadBalancerConfigManagerImpl extends ManagerBase implements LoadBalancerConfigService, LoadBalancerConfigManager { - private static final Logger s_logger = Logger.getLogger(LoadBalancerConfigManagerImpl.class); + private static final Logger LOGGER = Logger.getLogger(LoadBalancerConfigManagerImpl.class); @Inject LoadBalancerConfigDao _lbConfigDao; @@ -135,7 +134,7 @@ public List searchForLoadBalancerConfigs(ListLoadB configs = _lbConfigDao.search(sc, null); } if (cmd.listAll()) { - s_logger.debug("Adding config keys for scope " + scope); + LOGGER.debug("Adding config keys for scope " + scope); Map configsMap = new LinkedHashMap(); for (LoadBalancerConfigVO config : configs) { configsMap.put(config.getName(), config); @@ -371,17 +370,17 @@ private void applyLbConfigsForNetwork(Long networkId, Long vpcId, Long loadBalan private boolean applyLbConfigsForNetwork(Long networkId) { if (!_ntwkSrvcDao.canProviderSupportServiceInNetwork(networkId, Service.Lb, Provider.VirtualRouter) && !_ntwkSrvcDao.canProviderSupportServiceInNetwork(networkId, Service.Lb, Provider.VPCVirtualRouter)) { - s_logger.info("Lb is not supported or not provided by VirtualRouter/VpcVirtualRouter in network " + networkId); + LOGGER.info("Lb is not supported or not provided by VirtualRouter/VpcVirtualRouter in network " + networkId); return false; } try { if (!_lbMgr.applyLoadBalancersForNetwork(networkId, Scheme.Public)) { - s_logger.warn("Failed to apply LB configs of network id=" + networkId); + LOGGER.warn("Failed to apply LB configs of network id=" + networkId); return false; } return true; } catch (ResourceUnavailableException ex) { - s_logger.error("Failed to apply LB configs in virtual router on network: " + networkId, ex); + LOGGER.error("Failed to apply LB configs in virtual router on network: " + networkId, ex); throw new CloudRuntimeException("Failed to apply LB configs in virtual router on network: " + networkId); } } From d7b51ec2895e5efa980c3149522776be5adf86d7 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 20 May 2020 09:19:59 +0000 Subject: [PATCH 62/75] LB config: set uuid instead of id in response --- .../cloudstack/api/ResponseGenerator.java | 2 + .../ListLoadBalancerConfigsCmd.java | 5 +- .../java/com/cloud/api/ApiResponseHelper.java | 54 ++++++++++++++++--- 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java index ba19fda2230c..0bc150c456b9 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java @@ -264,6 +264,8 @@ public interface ResponseGenerator { LoadBalancerConfigResponse createLoadBalancerConfigResponse(LoadBalancerConfig config); + List createLoadBalancerConfigResponse(List configs); + LBStickinessResponse createLBStickinessPolicyResponse(List stickinessPolicies, LoadBalancer lb); LBStickinessResponse createLBStickinessPolicyResponse(StickinessPolicy stickinessPolicy, LoadBalancer lb); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerConfigsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerConfigsCmd.java index b38ef94a795d..e2b907e8ecb3 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerConfigsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerConfigsCmd.java @@ -133,10 +133,7 @@ public void execute() { ListResponse response = new ListResponse(); List lbConfigResponses = new ArrayList(); if (configs != null) { - for (LoadBalancerConfig config : configs) { - LoadBalancerConfigResponse lbConfigResponse = _responseGenerator.createLoadBalancerConfigResponse(config); - lbConfigResponses.add(lbConfigResponse); - } + lbConfigResponses = _responseGenerator.createLoadBalancerConfigResponse(configs); response.setResponses(lbConfigResponses); } response.setResponseName(getCommandName()); diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index 0e393d5620eb..4d5907083875 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -995,6 +995,48 @@ public LoadBalancerResponse createLoadBalancerResponse(LoadBalancer loadBalancer @Override public LoadBalancerConfigResponse createLoadBalancerConfigResponse(LoadBalancerConfig config) { + Network network = null; + Vpc vpc = null; + LoadBalancer lb = null; + if (config.getNetworkId() != null) { + network = ApiDBUtils.findNetworkById(config.getNetworkId()); + } + if (config.getVpcId() != null) { + vpc = ApiDBUtils.findVpcById(config.getVpcId()); + } + if (config.getLoadBalancerId() != null) { + lb = ApiDBUtils.findLoadBalancerById(config.getLoadBalancerId()); + } + return setLoadBalancerConfigResponse(network, vpc, lb, config); + } + + @Override + public List createLoadBalancerConfigResponse(List configs) { + List lbConfigResponses = new ArrayList(); + if (configs == null || configs.size() == 0) { + return lbConfigResponses; + } + LoadBalancerConfig config = configs.get(0); + Network network = null; + Vpc vpc = null; + LoadBalancer lb = null; + if (config.getNetworkId() != null) { + network = ApiDBUtils.findNetworkById(config.getNetworkId()); + } + if (config.getVpcId() != null) { + vpc = ApiDBUtils.findVpcById(config.getVpcId()); + } + if (config.getLoadBalancerId() != null) { + lb = ApiDBUtils.findLoadBalancerById(config.getLoadBalancerId()); + } + for (LoadBalancerConfig lbConfig : configs) { + LoadBalancerConfigResponse lbConfigResponse = setLoadBalancerConfigResponse(network, vpc, lb, lbConfig); + lbConfigResponses.add(lbConfigResponse); + } + return lbConfigResponses; + } + + private LoadBalancerConfigResponse setLoadBalancerConfigResponse(Network network, Vpc vpc, LoadBalancer lb, LoadBalancerConfig config) { LoadBalancerConfigResponse response = new LoadBalancerConfigResponse(); if (config.getUuid() != null) { response.setId(config.getUuid()); @@ -1002,14 +1044,14 @@ public LoadBalancerConfigResponse createLoadBalancerConfigResponse(LoadBalancerC response.setName(config.getName()); response.setValue(config.getValue()); response.setScope(String.valueOf(config.getScope())); - if (config.getNetworkId() != null) { - response.setNetworkId(String.valueOf(config.getNetworkId())); //TODO SHOULD BE UUID + if (network != null) { + response.setNetworkId(network.getUuid()); } - if (config.getVpcId() != null) { - response.setVpcId(String.valueOf(config.getVpcId())); //UUID + if (vpc != null) { + response.setVpcId(vpc.getUuid()); } - if (config.getLoadBalancerId() != null) { - response.setLoadBalancerId(String.valueOf(config.getLoadBalancerId())); //UUID + if (lb != null) { + response.setLoadBalancerId(lb.getUuid()); } response.setCreated(config.getCreated()); LoadBalancerConfigKey configKey = LoadBalancerConfigKey.getConfigsByScopeAndName(config.getScope(), config.getName()); From 95c1a9b40906f352b5ada11a328de04699b5af51 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Thu, 18 Jun 2020 14:22:08 +0000 Subject: [PATCH 63/75] LB config: add method validateParameters --- .../lb/LoadBalancerConfigManagerImpl.java | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/server/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManagerImpl.java b/server/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManagerImpl.java index d53aca830ed8..28658ea320b3 100644 --- a/server/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManagerImpl.java @@ -168,10 +168,7 @@ public LoadBalancerConfig createLoadBalancerConfig(CreateLoadBalancerConfigCmd c if (scope == null) { throw new InvalidParameterValueException("Invalid scope " + scopeStr); } - Pair res = LoadBalancerConfigKey.validate(scope, name, value); - if (res.second() != null) { - throw new InvalidParameterValueException(res.second()); - } + LoadBalancerConfigKey configKey = validateParameters(scope, name, value); checkPermission(scope, networkId, vpcId, loadBalancerId); @@ -182,7 +179,7 @@ public LoadBalancerConfig createLoadBalancerConfig(CreateLoadBalancerConfigCmd c } else { throw new InvalidParameterValueException("config " + name + " already exists, please add forced=true or update it instead"); } } - LoadBalancerConfigVO config = _lbConfigDao.persist(new LoadBalancerConfigVO(scope, networkId, vpcId, loadBalancerId, res.first(), value)); + LoadBalancerConfigVO config = _lbConfigDao.persist(new LoadBalancerConfigVO(scope, networkId, vpcId, loadBalancerId, configKey, value)); applyLbConfigsForNetwork(config.getNetworkId(), config.getVpcId(), config.getLoadBalancerId()); @@ -215,10 +212,7 @@ public LoadBalancerConfig updateLoadBalancerConfig(UpdateLoadBalancerConfigCmd c throw new InvalidParameterValueException("Cannot find load balancer config by id " + id); } //validate parameters - Pair res = LoadBalancerConfigKey.validate(config.getScope(), config.getName(), value); - if (res.second() != null) { - throw new InvalidParameterValueException(res.second()); - } + LoadBalancerConfigKey configKey = validateParameters(config.getScope(), config.getName(), value); checkPermission(config); config.setValue(value); @@ -246,19 +240,16 @@ public List replaceLoadBalancerConfigs(ReplaceLoad if (scope == null) { throw new InvalidParameterValueException("Invalid scope " + scopeStr); } - checkPermission(scope, networkId, vpcId, loadBalancerId); - List configs = new ArrayList(); for (Object obj : configList.keySet()) { String name = String.valueOf(obj); String value = (String) configList.get(name); - Pair res = LoadBalancerConfigKey.validate(scope, name, value); - if (res.second() != null) { - throw new InvalidParameterValueException(res.second()); - } - configs.add(new LoadBalancerConfigVO(scope, networkId, vpcId, loadBalancerId, res.first(), value)); + LoadBalancerConfigKey configKey = validateParameters(scope, name, value); + configs.add(new LoadBalancerConfigVO(scope, networkId, vpcId, loadBalancerId, configKey, value)); } + checkPermission(scope, networkId, vpcId, loadBalancerId); + configs = _lbConfigDao.saveConfigs(configs); applyLbConfigsForNetwork(networkId, vpcId, loadBalancerId); @@ -266,6 +257,14 @@ public List replaceLoadBalancerConfigs(ReplaceLoad return configs; } + private LoadBalancerConfigKey validateParameters(Scope scope, String name, String value) { + Pair res = LoadBalancerConfigKey.validate(scope, name, value); + if (res.second() != null) { + throw new InvalidParameterValueException(res.second()); + } + return res.first(); + } + private void checkPermission(LoadBalancerConfigVO config) { checkPermission(config.getScope(), config.getNetworkId(), config.getVpcId(), config.getLoadBalancerId()); } From 26ccc8e6ce9576d508e6bd425ceab3402fa7f4c6 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 10 Nov 2020 14:40:14 +0000 Subject: [PATCH 64/75] #4141: Support config list like "config[0].global.maxconn=XXX" Testing: ``` (local) mgt01 > replace loadbalancerconfigs networkid=bfdf8e5a-86bc-4dcf-9279-10482ffcb8ed scope=Network config[0].global.maxconn=5002 config[0].global.maxpipes=5003 { "accountid": "e3a80e2d-0977-11eb-8a7f-069b900033a6", "cmd": "org.apache.cloudstack.api.command.user.loadbalancer.ReplaceLoadBalancerConfigsCmd", "completed": "2020-11-10T14:42:40+0000", "created": "2020-11-10T14:42:28+0000", "jobid": "0ea21420-6c48-40c1-9f5f-3fddceac1b0d", "jobprocstatus": 0, "jobresult": { "success": true }, "jobresultcode": 0, "jobresulttype": "object", "jobstatus": 1, "userid": "e3a8b95f-0977-11eb-8a7f-069b900033a6" } ``` --- .../ReplaceLoadBalancerConfigsCmd.java | 19 +++++-------------- .../lb/LoadBalancerConfigManagerImpl.java | 7 +++---- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ReplaceLoadBalancerConfigsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ReplaceLoadBalancerConfigsCmd.java index bd8c44921763..ac10a9c13891 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ReplaceLoadBalancerConfigsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ReplaceLoadBalancerConfigsCmd.java @@ -17,7 +17,6 @@ package org.apache.cloudstack.api.command.user.loadbalancer; import java.util.Collection; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -31,7 +30,6 @@ import org.apache.cloudstack.api.response.SuccessResponse; import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.network.lb.LoadBalancerConfig; -import org.apache.commons.collections.MapUtils; import org.apache.log4j.Logger; import com.cloud.event.EventTypes; @@ -78,8 +76,8 @@ public class ReplaceLoadBalancerConfigsCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.CONFIG, type = CommandType.MAP, - description = "configs list, Example: config[0].name=timout&config[0].value=60000") - private Map configList; + description = "configs list, Example: config[0].global.maxconn=40960") + private Map configList; ///////////////////////////////////////////////////// @@ -102,20 +100,13 @@ public Long getLoadBalancerId() { return loadBalancerId; } - public Map getConfigList() { + public Map getConfigList() { if (configList == null || configList.isEmpty()) { return null; } - Map configMap = new HashMap<>(); - if (MapUtils.isNotEmpty(configList)) { - for (Map config : (Collection>)configList.values()) { - String name = config.get("name"); - String value = config.get("value"); - configMap.put(name, value); - } - } - return configMap; + Collection paramsCollection = configList.values(); + return (Map) (paramsCollection.toArray())[0]; } ///////////////////////////////////////////////////// diff --git a/server/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManagerImpl.java b/server/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManagerImpl.java index 28658ea320b3..34ee9037d8ba 100644 --- a/server/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManagerImpl.java @@ -230,7 +230,7 @@ public List replaceLoadBalancerConfigs(ReplaceLoad Long networkId = cmd.getNetworkId(); Long vpcId = cmd.getVpcId(); Long loadBalancerId = cmd.getLoadBalancerId(); - Map configList = cmd.getConfigList(); + Map configList = cmd.getConfigList(); if (configList == null) { throw new InvalidParameterValueException("Invalid config list"); } @@ -241,9 +241,8 @@ public List replaceLoadBalancerConfigs(ReplaceLoad throw new InvalidParameterValueException("Invalid scope " + scopeStr); } List configs = new ArrayList(); - for (Object obj : configList.keySet()) { - String name = String.valueOf(obj); - String value = (String) configList.get(name); + for (String name : configList.keySet()) { + String value = configList.get(name); LoadBalancerConfigKey configKey = validateParameters(scope, name, value); configs.add(new LoadBalancerConfigVO(scope, networkId, vpcId, loadBalancerId, configKey, value)); } From 454b660c8bde27318fcb0db235209368c485b43d Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 28 Sep 2020 20:35:21 +0000 Subject: [PATCH 65/75] #4141 LB config: Fix spring-server-core-managers-context.xml --- .../cloudstack/core/spring-server-core-managers-context.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml b/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml index ab0ddcd0dac4..4900372eb40c 100644 --- a/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml +++ b/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml @@ -139,7 +139,7 @@ - + From 1ccff8298166d66479d303b5be9196c23c8d0814 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 11 Nov 2020 08:20:28 +0000 Subject: [PATCH 66/75] #4141: return empty list if config is null --- .../main/java/com/cloud/agent/api/to/LoadBalancerTO.java | 5 +++-- .../cloud/agent/api/routing/LoadBalancerConfigCommand.java | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java b/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java index 13b2f16ba2df..270c903a1bb6 100644 --- a/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java +++ b/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java @@ -187,8 +187,9 @@ public LoadBalancerConfigTO[] getLbConfigs() { } public void setLbConfigs(List lbConfigs) { - if (lbConfigs == null) { - lbConfigs = new ArrayList(); + if (lbConfigs == null || lbConfigs.size() == 0) { + this.lbConfigs = new LoadBalancerConfigTO[0]; + return; } this.lbConfigs = new LoadBalancerConfigTO[lbConfigs.size()]; int i = 0; diff --git a/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java b/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java index e87bef6ab183..4ef7c6ae2fb8 100644 --- a/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java +++ b/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java @@ -25,7 +25,6 @@ import org.apache.cloudstack.network.lb.LoadBalancerConfig; -import java.util.ArrayList; import java.util.List; /** @@ -88,8 +87,9 @@ public LoadBalancerConfigTO[] getNetworkLbConfigs() { } public void setNetworkLbConfigs(List networkLbConfigs) { - if (networkLbConfigs == null) { - networkLbConfigs = new ArrayList(); + if (networkLbConfigs == null || networkLbConfigs.size() == 0) { + this.networkLbConfigs = new LoadBalancerConfigTO[0]; + return; } this.networkLbConfigs = new LoadBalancerConfigTO[networkLbConfigs.size()]; int i = 0; From 9d303ed9d729b2779e2a5b1ff1c576463c78f7cc Mon Sep 17 00:00:00 2001 From: Rakesh Venkatesh Date: Mon, 23 Nov 2020 09:27:52 +0000 Subject: [PATCH 67/75] #4141 Ignore case for protocol name in LB rules --- .../command/user/loadbalancer/CreateLoadBalancerRuleCmd.java | 2 +- tools/marvin/marvin/lib/base.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java index 283da3cd8e41..d6f1b56620c7 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java @@ -255,7 +255,7 @@ public List getSourceCidrList() { } public String getLbProtocol() { - return lbProtocol; + return lbProtocol != null ? lbProtocol.toLowerCase().trim() : null; } ///////////////////////////////////////////////////// diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py index 6bb7b669096c..2e691bf60797 100755 --- a/tools/marvin/marvin/lib/base.py +++ b/tools/marvin/marvin/lib/base.py @@ -2597,6 +2597,7 @@ def create(cls, apiclient, services, ipaddressid=None, accountid=None, cmd.algorithm = services["alg"] cmd.privateport = services["privateport"] cmd.publicport = services["publicport"] + cmd.protocol = services["protocol"] if "openfirewall" in services: cmd.openfirewall = services["openfirewall"] From 6e2e86ba679e4de9eaec570ff953f4582f6e2b9e Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 4 Jan 2021 12:11:52 +0000 Subject: [PATCH 68/75] #4141 LB config: fix many 'mkdir -p /etc/ssl/cloudstack/' in /var/log/cloud.log --- systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py index 7d2d3173d718..c9bed13eafac 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py @@ -26,8 +26,8 @@ HAPROXY_CONF_T = "/etc/haproxy/haproxy.cfg.new" HAPROXY_CONF_P = "/etc/haproxy/haproxy.cfg" +IP_ROUTE_TABLE_NUMBER_FOR_TRANSPARENCY = 99 SSL_CERTS_DIR = "/etc/ssl/cloudstack/" -CsHelper.execute("mkdir -p %s" % SSL_CERTS_DIR) class CsLoadBalancer(CsDataBag): @@ -93,7 +93,7 @@ def _configure_firewall(self, add_rules, remove_rules, stat_rules): firewall.append(["filter", "", "-A INPUT -p tcp -m tcp -d %s --dport %s -m state --state NEW -j ACCEPT" % (ip, port)]) def _configure_firewall_for_transparent(self, is_transparent): - tableNo = 99 + tableNo = IP_ROUTE_TABLE_NUMBER_FOR_TRANSPARENCY firewall = self.config.get_fw() if is_transparent is None or not is_transparent: if ["mangle", "", "-A PREROUTING -p tcp -m socket -j DIVERT"] in firewall: @@ -116,6 +116,8 @@ def _configure_firewall_for_transparent(self, is_transparent): def _create_pem_for_sslcert(self, ssl_certs): logging.debug("CsLoadBalancer:: creating new pem files in %s and cleaning up it" % SSL_CERTS_DIR) + if not os.path.exists(SSL_CERTS_DIR): + CsHelper.execute("mkdir -p %s" % SSL_CERTS_DIR) cert_names = [] for cert in ssl_certs: cert_names.append(cert['name'] + ".pem") From 9f1860c4531b3c48f369f22109d69f432fe3d933 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 20 Jan 2021 13:37:39 +0000 Subject: [PATCH 69/75] LB config: String values should not contain whitespace --- .../cloudstack/network/lb/LoadBalancerConfigKey.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index 7830f33adaa3..04e4614d3afa 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -23,6 +23,8 @@ import org.apache.cloudstack.network.lb.LoadBalancerConfig.SSLConfiguration; import org.apache.cloudstack.network.lb.LoadBalancerConfig.Scope; +import org.apache.commons.lang3.StringUtils; + import com.cloud.utils.Pair; public enum LoadBalancerConfigKey { @@ -202,6 +204,12 @@ public static Pair validate(Scope scope, String k } } + if (type.equals(String.class)) { + if (StringUtils.containsWhitespace(value)) { + return new Pair<>(null, "Please enter valid value without whitespace characters for parameter " + key); + } + } + if (LbSslConfiguration.key().equals(key)) { if (value == null || ! SSLConfiguration.validate(value.toLowerCase())) { return new Pair<>(null, "Please enter valid value in " + String.join(",", SSLConfiguration.getValues()) + " for parameter " + key); From 39e7def4f38a26bf4d9446003179e1970fe2503a Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 20 Jan 2021 19:56:35 +0000 Subject: [PATCH 70/75] LB: verify haproxy config before haproxy restart/reload --- systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py index c9bed13eafac..b04b4f78da97 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py @@ -51,6 +51,11 @@ def process(self): file1.commit() file2 = CsFile(HAPROXY_CONF_P) if not file2.compareOrder(file1): + # Verify new haproxy config before haproxy restart/reload + haproxy_err = self._verify_haproxy_config(HAPROXY_CONF_T) + if haproxy_err: + raise Exception("haproxy config is invalid with error \n%s" % haproxy_err); + CsHelper.copy(HAPROXY_CONF_T, HAPROXY_CONF_P) proc = CsProcess(['/run/haproxy.pid']) @@ -131,3 +136,11 @@ def _create_pem_for_sslcert(self, ssl_certs): for f in listdir(SSL_CERTS_DIR): if f not in cert_names: CsHelper.execute("rm -rf %s/%s" % (SSL_CERTS_DIR, f)) + + def _verify_haproxy_config(self, config): + ret = CsHelper.execute2("haproxy -c -f %s" % config) + if ret.returncode: + stdout, stderr = ret.communicate() + logging.error("haproxy config is invalid with error: %s" % stderr) + return stderr + return "" From 24c120677eaf0a7e77abfe1f6d90150a57804688 Mon Sep 17 00:00:00 2001 From: Rakesh Venkatesh Date: Tue, 26 Jan 2021 14:20:42 +0100 Subject: [PATCH 71/75] Load balancer configurations using HAProxy Ported from https://github.com/apache/cloudstack-primate/pull/778 This is the UI change needed for confgiuring load balancer rules using haproxy and also adding ssl certificated to load balancer rules Load balancer configs are avaiable at two scopes. one at the network level under "LB Configs" tab and another under each load balancer rule and can be configured by clicking on "Configuration" button. The SSL certificates can be added only for load balancer rules with ssl protocols To apply global load balancing configurations, navigate to "Networks" -> LB Configs --- ui/public/locales/en.json | 12 + ui/src/config/section/network.js | 4 + ui/src/views/network/LbConfigTab.vue | 341 +++++++++++++++++++ ui/src/views/network/LoadBalancing.vue | 444 ++++++++++++++++++++++++- 4 files changed, 800 insertions(+), 1 deletion(-) create mode 100644 ui/src/views/network/LbConfigTab.vue diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 5b1cc6a95178..e8658cbcbe3d 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -634,6 +634,7 @@ "label.crosszones": "Cross Zones", "label.currency": "Currency", "label.current": "isCurrent", +"label.currentsslcert": "Current SSL Certificate", "label.currentpassword": "Current Password", "label.custom": "Custom", "label.custom.disk.offering": "Custom Disk Offering", @@ -1217,6 +1218,11 @@ "label.lb.algorithm.roundrobin": "Round-robin", "label.lb.algorithm.source": "Source", "label.lb.cookie": "LbCookie", +"label.lb.config": "LB Configs", +"label.lb.configuration": "Configuration", +"label.lb.config.value": "Value", +"label.lb.config.name": "Lb Config name", +"label.lb.config.default.value": "Default value", "label.lb.protocol.http": "HTTP", "label.lb.protocol.ssl": "SSL", "label.lb.protocol.tcp.proxy": "TCP-proxy", @@ -1977,6 +1983,7 @@ "label.ssh.port": "SSH Port", "label.sshkeypair": "New SSH Key Pair", "label.sshkeypairs": "SSH keypairs", +"label.ssl": "SSL", "label.sslcertificates": "SSL Certificates", "label.standard.us.keyboard": "Standard (US) keyboard", "label.start": "Start", @@ -2460,6 +2467,7 @@ "message.add.ip.range.direct.network": "Add an IP range to direct network in zone ", "message.add.ip.range.to.pod": "

Add an IP range to pod:

", "message.add.iprange.processing": "Adding IP Range...", +"message.add.lbconfig.processing": "Adding new load balancer config", "message.add.load.balancer": "Add a load balancer to zone", "message.add.load.balancer.under.ip": "The load balancer rule has been added under IP:", "message.add.network": "Add a new network for zone: ", @@ -2852,6 +2860,7 @@ "message.failed.to.add": "Failed to add", "message.failed.to.assign.vms": "Failed to assign VMs", "message.failed.to.remove": "Failed to remove", +"message.failed.to.remove.lbconfig": "Failed to remove load balancer config", "message.generate.keys": "Please confirm that you would like to generate new keys for this user.", "message.gslb.delete.confirm": "Please confirm you want to delete this GSLB", "message.gslb.lb.remove.confirm": "Please confirm you want to remove load balancing from GSLB", @@ -3019,6 +3028,8 @@ "message.remove.instance.failed": "Failed to remove instance", "message.remove.instance.processing": "Removing...", "message.remove.iprange.processing": "Removing IP Range...", +"message.remove.lbconfig.processing": "Removing load balancer config", +"message.remove.lbconfig.failed": "Failed to remove Load Balancer Config", "message.remove.ldap": "Are you sure you want to delete the LDAP configuration?", "message.remove.nic.processing": "Removing NIC...", "message.remove.port.forward.failed": "Removing Port Forwarding rule failed", @@ -3139,6 +3150,7 @@ "message.success.remove.instance.rule": "Successfully removed instance from rule", "message.success.remove.ip": "Successfully removed IP", "message.success.remove.iprange": "Successfully removed IP Range", +"message.success.remove.lbconfig": "Successfully removed load balancer config", "message.success.remove.nic": "Successfully removed", "message.success.remove.port.forward": "Successfully removed Port Forwarding rule", "message.success.remove.rule": "Successfully deleted rule", diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js index 29b57e2f3f5d..3aaf81369c62 100644 --- a/ui/src/config/section/network.js +++ b/ui/src/config/section/network.js @@ -45,6 +45,10 @@ export default { name: 'egress.rules', component: () => import('@/views/network/EgressRulesTab.vue'), show: (record) => { return record.type === 'Isolated' && !('vpcid' in record) && 'listEgressFirewallRules' in store.getters.apis } + }, { + name: 'lb.config', + component: () => import('@/views/network/LbConfigTab.vue'), + show: (record) => { return record.type === 'Isolated' && !('vpcid' in record) && 'listEgressFirewallRules' in store.getters.apis } }, { name: 'public.ip.addresses', component: () => import('@/views/network/IpAddressesTab.vue'), diff --git a/ui/src/views/network/LbConfigTab.vue b/ui/src/views/network/LbConfigTab.vue new file mode 100644 index 000000000000..53d75ea2d16e --- /dev/null +++ b/ui/src/views/network/LbConfigTab.vue @@ -0,0 +1,341 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + + + + + + \ No newline at end of file diff --git a/ui/src/views/network/LoadBalancing.vue b/ui/src/views/network/LoadBalancing.vue index ea991329b79c..560d1c084592 100644 --- a/ui/src/views/network/LoadBalancing.vue +++ b/ui/src/views/network/LoadBalancing.vue @@ -50,8 +50,15 @@ {{ $t('label.tcp.proxy') }} {{ $t('label.tcp') }} {{ $t('label.udp') }} + {{ $t('label.ssl') }}
+
+
{{ $t('label.sslcertificates') }}
+ + SSl Certificate + +
{{ $t('label.add.vms') }}
@@ -82,6 +89,16 @@ {{ returnStickinessLabel(record.id) }} + + @@ -396,6 +534,7 @@ export default { data () { return { loading: true, + visible: true, lbRules: [], newTagsForm: this.$form.createForm(this), tagsModalVisible: false, @@ -428,7 +567,8 @@ export default { publicport: '', protocol: 'tcp', virtualmachineid: [], - vmguestip: [] + vmguestip: [], + sslcert: '' }, addVmModalVisible: false, addVmModalLoading: false, @@ -438,6 +578,34 @@ export default { totalCount: 0, page: 1, pageSize: 10, + lbConfigs: [], + savedLbConfigs: [], + totalCountLbConfig: 0, + sslcerts: { + loading: false, + data: [] + }, + selectedSsl: { + name: '', + id: null + }, + addSslCertModalVisible: false, + showAssignedSsl: false, + addLbConfigVisible: false, + addLbConfigModalLoading: false, + currentAccountId: null, + assignedSslCert: 'None', + buttonVisible: false, + deleteSslButtonVisible: true, + addSslButtonVisible: true, + lbConfig: { + scope: 'LoadBalancerRule', + name: '', + description: null, + defaultvalue: null, + value: null, + forced: 'true' + }, columns: [ { title: this.$t('label.name'), @@ -467,6 +635,14 @@ export default { title: this.$t('label.action.configure.stickiness'), scopedSlots: { customRender: 'stickiness' } }, + { + title: this.$t('label.lb.configuration'), + scopedSlots: { customRender: 'configuration' } + }, + { + title: this.$t('label.sslcertificates'), + scopedSlots: { customRender: 'sslcert' } + }, { title: this.$t('label.add.vms'), scopedSlots: { customRender: 'add' } @@ -476,6 +652,28 @@ export default { scopedSlots: { customRender: 'actions' } } ], + lbconfigColumns: [ + { + title: this.$t('label.lb.config.name'), + dataIndex: 'name' + }, + { + title: this.$t('label.description'), + dataIndex: 'description' + }, + { + title: this.$t('label.lb.config.default.value'), + dataIndex: 'defaultvalue' + }, + { + title: this.$t('label.lb.config.value'), + dataIndex: 'value' + }, + { + title: this.$t('label.action'), + scopedSlots: { customRender: 'actions' } + } + ], tiers: { loading: false, data: [] @@ -614,6 +812,242 @@ export default { }) }) }, + fetchSslCerts () { + this.sslcerts.loading = true + this.sslcerts.data = [] + // Firt get the account id + api('listAccounts', { + name: this.resource.account, + domainid: this.resource.domainid + }).then(json => { + const accounts = json.listaccountsresponse.account || [] + if (accounts.length > 0) { + // Now fetch all the ssl certs for this account + this.currentAccountId = accounts[0].id + api('listSslCerts', { + accountid: this.currentAccountId + }).then(json => { + if (json.listsslcertsresponse.sslcert && json.listsslcertsresponse.sslcert.length > 0) { + this.selectedSsl.name = json.listsslcertsresponse.sslcert[0].name + this.selectedSsl.id = json.listsslcertsresponse.sslcert[0].id + json.listsslcertsresponse.sslcert.forEach(entry => this.sslcerts.data.push(entry)) + } + }).catch(error => { + this.$notifyError(error) + }) + } + }).catch(error => { + this.$notifyError(error) + }).finally(() => { + this.sslcerts.loading = false + }) + if (this.selectedRule !== null) { + this.getCurrentlyAssignedSslCert() + } + }, + getCurrentlyAssignedSslCert () { + api('listSslCerts', { + accountid: this.currentAccountId, + lbruleid: this.selectedRule.id + }).then(json => { + if (json.listsslcertsresponse.sslcert && json.listsslcertsresponse.sslcert.length > 0) { + this.assignedSslCert = json.listsslcertsresponse.sslcert[0].name + this.deleteSslButtonVisible = true + } else { + this.assignedSslCert = 'None' + this.deleteSslButtonVisible = false + } + }).catch(error => { + this.$notifyError(error) + }) + }, + selectssl (e) { + this.selectedSsl.id = e + }, + handleAddSslCert (data) { + this.addSslCert(data, this.selectedSsl.id) + }, + addSslTolbRule () { + this.visible = false + this.addSslCert(this.selectedRule.id, this.selectedSsl.id) + }, + addSslCert (lbRuleId, certId) { + this.disableSslAddDeleteButtons() + api('assignCertToLoadBalancer', { + lbruleid: lbRuleId, + certid: certId, + forced: true + }).then(response => { + this.$pollJob({ + jobId: response.assigncerttoloadbalancerresponse.jobid, + successMessage: `Successfully assigned Ssl certificate`, + successMethod: () => { + if (this.selectedRule !== null) { + this.getCurrentlyAssignedSslCert() + } + this.enableSslAddDeleteButtons() + }, + errorMessage: 'Failed to assign ssl certificate', + errorMethod: () => { + }, + loadingMessage: `Assigning ssl certificate...`, + catchMessage: 'Error encountered while fetching async job result addSslTolbRule', + catchMethod: (e) => { + this.closeModal() + } + }) + }).catch(error => { + this.$notifyError(error) + }).finally(() => { + }) + }, + removeSslFromLbRule () { + this.disableSslAddDeleteButtons() + api('removeCertFromLoadBalancer', { + lbruleid: this.selectedRule.id + }).then(response => { + this.$pollJob({ + jobId: response.removecertfromloadbalancerresponse.jobid, + successMessage: `Successfully removed Ssl certificate`, + successMethod: () => { + this.visible = true + this.getCurrentlyAssignedSslCert() + this.enableSslAddDeleteButtons() + }, + errorMessage: 'Failed to remove ssl certificate', + errorMethod: () => { + this.visible = true + }, + loadingMessage: `Removing ssl certificate...`, + catchMessage: 'Error encountered while fetching async job result', + catchMethod: () => { + this.closeModal() + } + }) + }).catch(error => { + this.$notifyError(error) + }).finally(() => { + }) + }, + populateValues () { + for (let i = 0; i < this.lbConfigs.length; i++) { + if (this.lbConfig.name === this.lbConfigs[i].name) { + this.lbConfig.description = this.lbConfigs[i].description + this.lbConfig.defaultvalue = this.lbConfigs[i].defaultvalue + } + } + }, + enableSslAddDeleteButtons () { + this.deleteSslButtonVisible = true + this.addSslButtonVisible = true + }, + disableSslAddDeleteButtons () { + this.addSslButtonVisible = false + this.deleteSslButtonVisible = false + }, + handleDeleteLoadBalancerConfig (rule) { + this.addLbConfigModalLoading = true + api('deleteLoadBalancerConfig', { + id: rule.id + }).then(response => { + this.$pollJob({ + jobId: response.deleteloadbalancerconfigresponse.jobid, + successMessage: `Successfully removed load balancer config`, + successMethod: () => { + this.fetchSavedLbConfigs() + }, + errorMessage: 'Failed to remove load balancer config', + errorMethod: () => { + this.fetchSavedLbConfigs() + }, + loadingMessage: `Removing load balancer config...`, + catchMessage: 'Error encountered while fetching async job result', + catchMethod: () => { + this.fetchSavedLbConfigs() + } + }) + }).catch(error => { + this.$notifyError(error) + this.fetchSavedLbConfigs() + }) + }, + handleOpenAddConfiguration () { + api('listLoadBalancerConfigs', { + listAll: true, + scope: 'LoadBalancerRule', + loadbalancerid: this.selectedRule.id + }).then(response => { + this.lbConfigs = response.listloadbalancerconfigsresponse.loadbalancerconfig + this.addLbConfigVisible = true + const tempLbConfig = response.listloadbalancerconfigsresponse.loadbalancerconfig[0] + this.lbConfig.name = tempLbConfig.name + this.lbConfig.description = tempLbConfig.description + this.lbConfig.defaultvalue = tempLbConfig.defaultvalue + }).catch(error => { + this.$notifyError(error) + this.closeModal() + }) + this.fetchSavedLbConfigs() + }, + handleAddNewLbConfig () { + if (!this.lbConfig.value) { + this.$refs.lbconfigValue.classList.add('error') + return + } else { + this.$refs.lbconfigValue.classList.remove('error') + } + this.addLbConfigModalLoading = true + api('createLoadBalancerConfig', { + scope: 'LoadBalancerRule', + name: this.lbConfig.name, + value: this.lbConfig.value, + forced: 'true', + loadbalancerid: this.selectedRule.id + }).then(response => { + this.$pollJob({ + jobId: response.createloadbalancerconfigresponse.jobid, + successMessage: this.$t('message.success.create.lbconfig'), + successMethod: () => { + this.fetchSavedLbConfigs() + }, + errorMessage: this.$t('message.failed.to.remove.lbconfig'), + errorMethod: () => { + this.fetchSavedLbConfigs() + }, + loadingMessage: this.$t('message.add.lbconfig.processing'), + catchMessage: this.$t('error.fetching.async.job.result'), + catchMethod: () => { + this.fetchSavedLbConfigs() + } + }) + this.addLbConfigModalLoading = true + }).catch(error => { + this.$notifyError(error) + this.fetchSavedLbConfigs() + }) + this.lbConfig.value = null + }, + fetchSavedLbConfigs () { + api('listLoadBalancerConfigs', { + scope: 'LoadBalancerRule', + loadbalancerid: this.selectedRule.id + }).then(response => { + this.savedLbConfigs = response.listloadbalancerconfigsresponse.loadbalancerconfig + this.totalCountLbConfig = response.listloadbalancerconfigsresponse.count || 0 + }).catch(error => { + this.$notifyError(error) + this.loading = false + }) + this.addLbConfigModalLoading = false + }, + handleOpenAddSslCertModal () { + this.addSslCertModalVisible = true + if (this.selectedRule) { + this.showAssignedSsl = true + this.buttonVisible = true + } + this.fetchSslCerts() + }, returnAlgorithmName (name) { switch (name) { case 'leastconn': @@ -1076,6 +1510,9 @@ export default { successMethod: () => { this.parentFetchData() this.parentToggleLoading() + if (this.selectedSsl.id !== null) { + this.handleAddSslCert(data) + } this.fetchData() this.closeModal() }, @@ -1145,6 +1582,11 @@ export default { this.newRule.virtualmachineid = [] this.newTagsForm.resetFields() this.stickinessPolicyForm.resetFields() + this.addLbConfigVisible = false + this.addSslCertModalVisible = false + this.showAssignedSsl = false + this.buttonVisible = false + this.savedLbConfigs = [] }, handleChangePage (page, pageSize) { this.page = page From 2f07a1f8867c8c276adfa4445ba602d0f28d40a7 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 17 Feb 2021 09:01:00 +0000 Subject: [PATCH 72/75] LB: fix pylint check failure --- systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py index b04b4f78da97..ca05f51fc2ca 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsLoadBalancer.py @@ -54,7 +54,7 @@ def process(self): # Verify new haproxy config before haproxy restart/reload haproxy_err = self._verify_haproxy_config(HAPROXY_CONF_T) if haproxy_err: - raise Exception("haproxy config is invalid with error \n%s" % haproxy_err); + raise Exception("haproxy config is invalid with error \n%s" % haproxy_err) CsHelper.copy(HAPROXY_CONF_T, HAPROXY_CONF_P) From 56908470264dae47911064226ec700d827a6b25f Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 8 Mar 2021 13:04:28 +0000 Subject: [PATCH 73/75] LB: fix ui npm lint error --- ui/src/views/network/LbConfigTab.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/views/network/LbConfigTab.vue b/ui/src/views/network/LbConfigTab.vue index 53d75ea2d16e..eb783037704a 100644 --- a/ui/src/views/network/LbConfigTab.vue +++ b/ui/src/views/network/LbConfigTab.vue @@ -338,4 +338,4 @@ export default { .pagination { margin-top: 20px; } - \ No newline at end of file + From fd8e6b2c68f554b814c9108e9b09156837bed889 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 15 Mar 2021 14:35:24 +0000 Subject: [PATCH 74/75] LB config: move sql to schema-41510to41600.sql --- .../META-INF/db/schema-41400to41500.sql | 22 ------------------- .../META-INF/db/schema-41510to41600.sql | 22 +++++++++++++++++++ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql b/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql index 40e7fc185a80..9ead785c0c43 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql @@ -843,25 +843,3 @@ UPDATE `cloud`.`data_center` JOIN (SELECT COUNT(1) AS count FROM `cloud`.`data_c -- Fix description of volume.stats.interval which is in milliseconds not seconds UPDATE `cloud`.`configuration` SET `description` = 'Interval (in milliseconds) to report volume statistics' WHERE `name` = 'volume.stats.interval'; - --- Table for customized load balancer configurations -CREATE TABLE IF NOT EXISTS `cloud`.`load_balancer_config` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `uuid` varchar(40) DEFAULT NULL, - `scope` varchar(20) DEFAULT NULL COMMENT 'The scope of this config, Vpc/Network/LoadBalancer', - `network_id` bigint(20) unsigned DEFAULT NULL, - `vpc_id` bigint(20) unsigned DEFAULT NULL, - `load_balancer_id` bigint(20) unsigned DEFAULT NULL, - `name` varchar(255) NOT NULL, - `value` varchar(255) DEFAULT NULL, - `created` datetime NOT NULL COMMENT 'date created', - `removed` datetime DEFAULT NULL COMMENT 'date removed', - PRIMARY KEY (`id`), - UNIQUE KEY `id_UNIQUE` (`id`), - KEY `fk_load_balancer_config_network_id` (`network_id`), - KEY `fk_load_balancer_config_vpc_id` (`vpc_id`), - KEY `fk_load_balancer_config_loadbalancer_id` (`load_balancer_id`), - CONSTRAINT `fk_load_balancer_config_network_id` FOREIGN KEY (`network_id`) REFERENCES `networks` (`id`) ON DELETE CASCADE, - CONSTRAINT `fk_load_balancer_config_vpc_id` FOREIGN KEY (`vpc_id`) REFERENCES `vpc` (`id`) ON DELETE CASCADE, - CONSTRAINT `fk_load_balancer_config_loadbalancer_id` FOREIGN KEY (`load_balancer_id`) REFERENCES `load_balancing_rules` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41510to41600.sql b/engine/schema/src/main/resources/META-INF/db/schema-41510to41600.sql index 7168f883db67..90e94e187d77 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41510to41600.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41510to41600.sql @@ -301,3 +301,25 @@ from left join `cloud`.`resource_count` secondary_storage_count ON domain.id = secondary_storage_count.domain_id and secondary_storage_count.type = 'secondary_storage'; + +-- Table for customized load balancer configurations +CREATE TABLE IF NOT EXISTS `cloud`.`load_balancer_config` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `uuid` varchar(40) DEFAULT NULL, + `scope` varchar(20) DEFAULT NULL COMMENT 'The scope of this config, Vpc/Network/LoadBalancer', + `network_id` bigint(20) unsigned DEFAULT NULL, + `vpc_id` bigint(20) unsigned DEFAULT NULL, + `load_balancer_id` bigint(20) unsigned DEFAULT NULL, + `name` varchar(255) NOT NULL, + `value` varchar(255) DEFAULT NULL, + `created` datetime NOT NULL COMMENT 'date created', + `removed` datetime DEFAULT NULL COMMENT 'date removed', + PRIMARY KEY (`id`), + UNIQUE KEY `id_UNIQUE` (`id`), + KEY `fk_load_balancer_config_network_id` (`network_id`), + KEY `fk_load_balancer_config_vpc_id` (`vpc_id`), + KEY `fk_load_balancer_config_loadbalancer_id` (`load_balancer_id`), + CONSTRAINT `fk_load_balancer_config_network_id` FOREIGN KEY (`network_id`) REFERENCES `networks` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_load_balancer_config_vpc_id` FOREIGN KEY (`vpc_id`) REFERENCES `vpc` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_load_balancer_config_loadbalancer_id` FOREIGN KEY (`load_balancer_id`) REFERENCES `load_balancing_rules` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; From f5e5d0cf49f6b21b89844a206e53db23161d9aac Mon Sep 17 00:00:00 2001 From: Sina Kashipazha Date: Thu, 15 Jul 2021 09:27:42 +0200 Subject: [PATCH 75/75] Refactored the code, regarding the code change suggetions by GutoVeronezi. --- .../cloud/agent/api/to/LoadBalancerTO.java | 3 +- .../AssignCertToLoadBalancerCmd.java | 8 +- .../CreateLoadBalancerConfigCmd.java | 36 +-- .../CreateLoadBalancerRuleCmd.java | 3 +- .../DeleteLoadBalancerConfigCmd.java | 44 +--- .../ListLoadBalancerConfigsCmd.java | 3 +- .../user/loadbalancer/LoadBalancerHelper.java | 68 ++++++ .../RemoveCertFromLoadBalancerCmd.java | 5 +- .../ReplaceLoadBalancerConfigsCmd.java | 30 +-- .../UpdateLoadBalancerConfigCmd.java | 53 +---- .../network/lb/LoadBalancerConfigKey.java | 10 +- .../routing/LoadBalancerConfigCommand.java | 3 +- .../cloud/network/HAProxyConfigurator.java | 209 ++++++++---------- .../dao/LoadBalancerConfigDaoImpl.java | 20 +- .../com/cloud/utils/db/SearchCriteria.java | 7 + .../java/com/cloud/api/ApiResponseHelper.java | 4 +- .../VirtualNetworkApplianceManagerImpl.java | 47 ++-- .../lb/LoadBalancerConfigManagerImpl.java | 10 +- 18 files changed, 241 insertions(+), 322 deletions(-) create mode 100644 api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/LoadBalancerHelper.java diff --git a/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java b/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java index 270c903a1bb6..fe4c3d396e86 100644 --- a/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java +++ b/api/src/main/java/com/cloud/agent/api/to/LoadBalancerTO.java @@ -36,6 +36,7 @@ import com.cloud.utils.Pair; import org.apache.cloudstack.network.lb.LoadBalancerConfig; +import org.springframework.util.CollectionUtils; public class LoadBalancerTO { String uuid; @@ -187,7 +188,7 @@ public LoadBalancerConfigTO[] getLbConfigs() { } public void setLbConfigs(List lbConfigs) { - if (lbConfigs == null || lbConfigs.size() == 0) { + if (CollectionUtils.isEmpty(lbConfigs)) { this.lbConfigs = new LoadBalancerConfigTO[0]; return; } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/AssignCertToLoadBalancerCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/AssignCertToLoadBalancerCmd.java index 37a3d0668a5f..63012cf65252 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/AssignCertToLoadBalancerCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/AssignCertToLoadBalancerCmd.java @@ -17,6 +17,7 @@ // under the License. package org.apache.cloudstack.api.command.user.loadbalancer; +import org.apache.commons.lang3.BooleanUtils; import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; @@ -112,7 +113,7 @@ public Long getLbRuleId() { } public boolean isForced() { - return (forced != null) ? forced : false; + return BooleanUtils.toBoolean(forced); } @Override @@ -133,9 +134,6 @@ public String getSyncObjType() { @Override public Long getSyncObjId() { LoadBalancer lb = _entityMgr.findById(LoadBalancer.class, getLbRuleId()); - if (lb == null) { - return null; - } - return lb.getNetworkId(); + return (lb != null )? lb.getNetworkId(): null; } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerConfigCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerConfigCmd.java index fa6eb5adf77b..c6f63413eb22 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerConfigCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerConfigCmd.java @@ -20,7 +20,6 @@ import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; -import org.apache.cloudstack.api.BaseAsyncCmd; import org.apache.cloudstack.api.BaseAsyncCreateCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; @@ -30,6 +29,7 @@ import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.network.lb.LoadBalancerConfig; import org.apache.cloudstack.network.lb.LoadBalancerConfig.Scope; +import org.apache.commons.lang3.BooleanUtils; import org.apache.log4j.Logger; import com.cloud.event.EventTypes; @@ -123,7 +123,7 @@ public String getValue() { } public boolean isForced() { - return (forced != null) ? forced : false; + return BooleanUtils.toBoolean(forced); } ///////////////////////////////////////////////////// @@ -138,9 +138,8 @@ public String getCommandName() { @Override public void execute() { - LoadBalancerConfig config = null; try { - config = _entityMgr.findById(LoadBalancerConfig.class, getEntityId()); + LoadBalancerConfig config = _entityMgr.findById(LoadBalancerConfig.class, getEntityId()); LoadBalancerConfigResponse lbConfigResponse = new LoadBalancerConfigResponse(); if (config != null) { lbConfigResponse = _responseGenerator.createLoadBalancerConfigResponse(config); @@ -165,41 +164,22 @@ public void create() { @Override public String getSyncObjType() { - if (networkId != null) { - return BaseAsyncCmd.networkSyncObject; - } else if (vpcId != null) { - return BaseAsyncCmd.vpcSyncObject; - } - return null; + return LoadBalancerHelper.getSyncObjType(networkId, vpcId); } @Override public Long getSyncObjId() { - if (networkId != null) { - return getNetworkId(); - } else if (vpcId != null) { - return getVpcId(); - } - return null; + return LoadBalancerHelper.getSyncObjId(networkId, vpcId); } @Override public long getEntityOwnerId() { if (Scope.Network.name().equalsIgnoreCase(scope) && networkId != null) { - Network network = _entityMgr.findById(Network.class, networkId); - if (network != null) { - return network.getAccountId(); - } + return LoadBalancerHelper.getEntityOwnerId(_entityMgr, Network.class, networkId); } else if (Scope.Vpc.name().equalsIgnoreCase(scope) && vpcId != null) { - Vpc vpc = _entityMgr.findById(Vpc.class, vpcId); - if (vpc != null) { - return vpc.getAccountId(); - } + return LoadBalancerHelper.getEntityOwnerId(_entityMgr, Vpc.class, vpcId); } else if (Scope.LoadBalancerRule.name().equalsIgnoreCase(scope) && loadBalancerId != null) { - LoadBalancer lb = _entityMgr.findById(LoadBalancer.class, loadBalancerId); - if (lb != null) { - return lb.getAccountId(); - } + return LoadBalancerHelper.getEntityOwnerId(_entityMgr, LoadBalancer.class, loadBalancerId); } throw new InvalidParameterValueException("Unable to find the entity owner"); } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java index d6f1b56620c7..044cbe414e2b 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java @@ -33,6 +33,7 @@ import org.apache.cloudstack.api.response.NetworkResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.cloudstack.context.CallContext; +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import com.cloud.dc.DataCenter; @@ -255,7 +256,7 @@ public List getSourceCidrList() { } public String getLbProtocol() { - return lbProtocol != null ? lbProtocol.toLowerCase().trim() : null; + return StringUtils.trim(StringUtils.lowerCase(lbProtocol)); } ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/DeleteLoadBalancerConfigCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/DeleteLoadBalancerConfigCmd.java index 0ebe4d0b1162..addc9357865a 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/DeleteLoadBalancerConfigCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/DeleteLoadBalancerConfigCmd.java @@ -84,57 +84,19 @@ public void execute() { @Override public String getSyncObjType() { - LoadBalancerConfig config = _entityMgr.findById(LoadBalancerConfig.class, getId()); - if (config == null) { - throw new InvalidParameterValueException("Unable to find load balancer config: " + id); - } - if (config.getNetworkId() != null) { - return BaseAsyncCmd.networkSyncObject; - } else if (config.getVpcId() != null) { - return BaseAsyncCmd.vpcSyncObject; - } - return null; + return LoadBalancerHelper.getSyncObjType(_entityMgr, getId()); } @Override public Long getSyncObjId() { - LoadBalancerConfig config = _entityMgr.findById(LoadBalancerConfig.class, getId()); - if (config == null) { - throw new InvalidParameterValueException("Unable to find load balancer config: " + id); - } - if (config.getNetworkId() != null) { - return config.getNetworkId(); - } else if (config.getVpcId() != null) { - return config.getVpcId(); - } - return null; + return LoadBalancerHelper.getSyncObjId(_entityMgr, getId()); } @Override public long getEntityOwnerId() { - LoadBalancerConfig config = _entityMgr.findById(LoadBalancerConfig.class, getId()); - if (config != null) { - if (config.getNetworkId() != null) { - Network network = _entityMgr.findById(Network.class, config.getNetworkId()); - if (network != null) { - return network.getAccountId(); - } - } else if (config.getVpcId() != null) { - Vpc vpc = _entityMgr.findById(Vpc.class, config.getVpcId()); - if (vpc != null) { - return vpc.getAccountId(); - } - } else if (config.getLoadBalancerId() != null) { - FirewallRule rule = _entityMgr.findById(FirewallRule.class, config.getLoadBalancerId()); - if (rule != null) { - return rule.getAccountId(); - } - } - } - throw new InvalidParameterValueException("Unable to find the entity owner"); + return LoadBalancerHelper.getEntityOwnerId(_entityMgr, getId()); } - @Override public String getEventType() { return EventTypes.EVENT_LOAD_BALANCER_CONFIG_DELETE; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerConfigsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerConfigsCmd.java index e2b907e8ecb3..450f1b836f48 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerConfigsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ListLoadBalancerConfigsCmd.java @@ -30,6 +30,7 @@ import org.apache.cloudstack.api.response.NetworkResponse; import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.network.lb.LoadBalancerConfig; +import org.apache.commons.lang3.BooleanUtils; import org.apache.log4j.Logger; @APICommand(name = "listLoadBalancerConfigs", description = "Lists load balancer configs.", @@ -115,7 +116,7 @@ public String getName() { } public boolean listAll() { - return listAll == null ? false : listAll; + return BooleanUtils.toBoolean(listAll); } // /////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/LoadBalancerHelper.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/LoadBalancerHelper.java new file mode 100644 index 000000000000..7c4d31ee2b45 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/LoadBalancerHelper.java @@ -0,0 +1,68 @@ +package org.apache.cloudstack.api.command.user.loadbalancer; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.Network; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.vpc.Vpc; +import com.cloud.user.OwnedBy; +import com.cloud.utils.db.EntityManager; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.network.lb.LoadBalancerConfig; + + +public interface LoadBalancerHelper { + + static LoadBalancerConfig findConfigById(EntityManager entityMgr, Long id){ + LoadBalancerConfig config = entityMgr.findById(LoadBalancerConfig.class, id); + if (config == null) { + throw new InvalidParameterValueException("Unable to find load balancer config: " + id); + } + return config; + } + + static String getSyncObjType(EntityManager entityMgr, Long id){ + LoadBalancerConfig config = findConfigById(entityMgr, id); + return getSyncObjType(config.getNetworkId(), config.getVpcId()); + } + + static String getSyncObjType(Long networkId, Long vpcId){ + if (networkId != null) { + return BaseAsyncCmd.networkSyncObject; + } else if (vpcId != null) { + return BaseAsyncCmd.vpcSyncObject; + } + return null; + } + + static Long getSyncObjId(EntityManager entityMgr, Long id){ + LoadBalancerConfig config = findConfigById(entityMgr, id); + return getSyncObjId(config.getNetworkId(), config.getVpcId()); + } + + // Cause vpcId might be null, this method might return null + static Long getSyncObjId(Long networkId, Long vpcId){ + if (networkId != null) + return networkId; + return vpcId; + } + + static long getEntityOwnerId(EntityManager entityMgr , Class entityType, Long id){ + T t = entityMgr.findById(entityType, id); + if (t != null) { + return t.getAccountId(); + } + throw new InvalidParameterValueException("Unable to find the entity owner"); + } + + static long getEntityOwnerId(EntityManager entityMgr, Long id) { + LoadBalancerConfig config = findConfigById(entityMgr, id); + if (config.getNetworkId() != null) { + return LoadBalancerHelper.getEntityOwnerId(entityMgr, Network.class, config.getNetworkId()); + } else if (config.getVpcId() != null) { + return LoadBalancerHelper.getEntityOwnerId(entityMgr, Vpc.class, config.getVpcId()); + } else if (config.getLoadBalancerId() != null) { + return LoadBalancerHelper.getEntityOwnerId(entityMgr, FirewallRule.class, config.getLoadBalancerId()); + } + throw new InvalidParameterValueException("Unable to find the entity owner"); + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/RemoveCertFromLoadBalancerCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/RemoveCertFromLoadBalancerCmd.java index c9ca72b44973..73aac758e636 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/RemoveCertFromLoadBalancerCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/RemoveCertFromLoadBalancerCmd.java @@ -110,9 +110,6 @@ public String getSyncObjType() { @Override public Long getSyncObjId() { LoadBalancer lb = _entityMgr.findById(LoadBalancer.class, getLbRuleId()); - if (lb == null) { - return null; - } - return lb.getNetworkId(); + return (lb != null )? lb.getNetworkId(): null; } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ReplaceLoadBalancerConfigsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ReplaceLoadBalancerConfigsCmd.java index ac10a9c13891..469ebc7206c4 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ReplaceLoadBalancerConfigsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/ReplaceLoadBalancerConfigsCmd.java @@ -30,10 +30,10 @@ import org.apache.cloudstack.api.response.SuccessResponse; import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.network.lb.LoadBalancerConfig; +import org.apache.commons.collections.MapUtils; import org.apache.log4j.Logger; import com.cloud.event.EventTypes; -import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.Network; import com.cloud.network.vpc.Vpc; @@ -101,7 +101,7 @@ public Long getLoadBalancerId() { } public Map getConfigList() { - if (configList == null || configList.isEmpty()) { + if (MapUtils.isEmpty(configList)) { return null; } @@ -127,38 +127,20 @@ public void execute() { @Override public String getSyncObjType() { - if (networkId != null) { - return BaseAsyncCmd.networkSyncObject; - } else if (vpcId != null) { - return BaseAsyncCmd.vpcSyncObject; - } - return null; + return LoadBalancerHelper.getSyncObjType(networkId, vpcId); } @Override public Long getSyncObjId() { - if (networkId != null) { - return networkId; - } else if (vpcId != null) { - return vpcId; - } - return null; + return LoadBalancerHelper.getSyncObjId(networkId, vpcId); } @Override public long getEntityOwnerId() { if (networkId != null) { - Network network = _entityMgr.findById(Network.class, networkId); - if (network != null) { - return network.getAccountId(); - } - } else if (vpcId != null) { - Vpc vpc = _entityMgr.findById(Vpc.class, vpcId); - if (vpc != null) { - return vpc.getAccountId(); - } + return LoadBalancerHelper.getEntityOwnerId(_entityMgr, Network.class, networkId); } - throw new InvalidParameterValueException("Unable to find the entity owner"); + return LoadBalancerHelper.getEntityOwnerId(_entityMgr, Vpc.class, vpcId); } @Override diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLoadBalancerConfigCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLoadBalancerConfigCmd.java index a006d2d3b5fe..d6c756903be7 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLoadBalancerConfigCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/UpdateLoadBalancerConfigCmd.java @@ -83,65 +83,28 @@ public String getCommandName() { @Override public void execute() { LoadBalancerConfig result = _lbConfigService.updateLoadBalancerConfig(this); - if (result != null) { - LoadBalancerConfigResponse response = _responseGenerator.createLoadBalancerConfigResponse(result); - response.setResponseName(getCommandName()); - this.setResponseObject(response); - } else { + if (result == null) { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update load balancer config"); } + + LoadBalancerConfigResponse response = _responseGenerator.createLoadBalancerConfigResponse(result); + response.setResponseName(getCommandName()); + this.setResponseObject(response); } @Override public String getSyncObjType() { - LoadBalancerConfig config = _entityMgr.findById(LoadBalancerConfig.class, getId()); - if (config == null) { - throw new InvalidParameterValueException("Unable to find load balancer config: " + id); - } - if (config.getNetworkId() != null) { - return BaseAsyncCmd.networkSyncObject; - } else if (config.getVpcId() != null) { - return BaseAsyncCmd.vpcSyncObject; - } - return null; + return LoadBalancerHelper.getSyncObjType(_entityMgr, getId()); } @Override public Long getSyncObjId() { - LoadBalancerConfig config = _entityMgr.findById(LoadBalancerConfig.class, getId()); - if (config == null) { - throw new InvalidParameterValueException("Unable to find load balancer config: " + id); - } - if (config.getNetworkId() != null) { - return config.getNetworkId(); - } else if (config.getVpcId() != null) { - return config.getVpcId(); - } - return null; + return LoadBalancerHelper.getSyncObjId(_entityMgr, getId()); } @Override public long getEntityOwnerId() { - LoadBalancerConfig config = _entityMgr.findById(LoadBalancerConfig.class, getId()); - if (config != null) { - if (config.getNetworkId() != null) { - Network network = _entityMgr.findById(Network.class, config.getNetworkId()); - if (network != null) { - return network.getAccountId(); - } - } else if (config.getVpcId() != null) { - Vpc vpc = _entityMgr.findById(Vpc.class, config.getVpcId()); - if (vpc != null) { - return vpc.getAccountId(); - } - } else if (config.getLoadBalancerId() != null) { - FirewallRule rule = _entityMgr.findById(FirewallRule.class, config.getLoadBalancerId()); - if (rule != null) { - return rule.getAccountId(); - } - } - } - throw new InvalidParameterValueException("Unable to find the entity owner"); + return LoadBalancerHelper.getEntityOwnerId(_entityMgr, getId()); } @Override diff --git a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java index 04e4614d3afa..4455e7fbd7db 100644 --- a/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java +++ b/api/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigKey.java @@ -145,10 +145,7 @@ public static Map getConfigsByScope(Scope scope) public static LoadBalancerConfigKey getConfigsByScopeAndName(Scope scope, String name) { Map configs = Configs.get(scope); - if (configs.keySet().contains(name)) { - return configs.get(name); - } - return null; + return configs.get(name); } public static Scope getScopeFromString(String scope) { @@ -194,9 +191,8 @@ public static Pair validate(Scope scope, String k errMsg = "Please enter a valid long value for parameter " + key; Long.parseLong(value); } - } catch (final Exception e) { - // catching generic exception as some throws NullPointerException and some throws NumberFormatExcpeion - return new Pair(null, errMsg); + } catch (final NullPointerException|NumberFormatException e) { + return new Pair<>(null, errMsg); } if (type.equals(Boolean.class)) { if (!(value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false"))) { diff --git a/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java b/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java index 4ef7c6ae2fb8..63d8197a4c25 100644 --- a/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java +++ b/core/src/main/java/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java @@ -24,6 +24,7 @@ import com.cloud.agent.api.to.NicTO; import org.apache.cloudstack.network.lb.LoadBalancerConfig; +import org.springframework.util.CollectionUtils; import java.util.List; @@ -87,7 +88,7 @@ public LoadBalancerConfigTO[] getNetworkLbConfigs() { } public void setNetworkLbConfigs(List networkLbConfigs) { - if (networkLbConfigs == null || networkLbConfigs.size() == 0) { + if (CollectionUtils.isEmpty(networkLbConfigs)) { this.networkLbConfigs = new LoadBalancerConfigTO[0]; return; } diff --git a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java index e382b6dc2b20..2b9889ea2f0e 100644 --- a/core/src/main/java/com/cloud/network/HAProxyConfigurator.java +++ b/core/src/main/java/com/cloud/network/HAProxyConfigurator.java @@ -497,6 +497,35 @@ private String getCustomizedSslConfigs(HashMap lbConfigsMap, fin return ""; } + private String generateRule(HashMap lbConfigsMap, String prefix, String key){ + return generateRule(lbConfigsMap, "\t", prefix, key, false); + } + + private String generateLongRule(HashMap lbConfigsMap, String splitter, String prefix, String key){ + return generateRule(lbConfigsMap, splitter, prefix, key, true); + } + + private String generateLongRule(HashMap lbConfigsMap, String prefix, String key){ + return generateLongRule(lbConfigsMap, "\t", prefix, key); + } + + private String generateRule(HashMap lbConfigsMap, String splitter, String prefix, String key, boolean isLong){ + String value = lbConfigsMap.get(key); + + if(value == null){ + return ""; + } + + if( isLong ){ + if (Long.parseLong(value) > 0) { + return String.format("%s%s %s", splitter, prefix, value); + } + return ""; + } + + return String.format("%s%s %s", splitter, prefix, value); + } + private List getRulesForPool(final LoadBalancerTO lbTO, final LoadBalancerConfigCommand lbCmd, HashMap networkLbConfigsMap) { StringBuilder sb = new StringBuilder(); final String poolName = sb.append(lbTO.getSrcIp().replace(".", "_")).append('-').append(lbTO.getSrcPort()).toString(); @@ -505,28 +534,23 @@ private List getRulesForPool(final LoadBalancerTO lbTO, final LoadBalanc final String algorithm = lbTO.getAlgorithm(); final LoadBalancerConfigTO[] lbConfigs = lbTO.getLbConfigs(); - final HashMap lbConfigsMap = new HashMap(); + final HashMap lbConfigsMap = new HashMap<>(); + if (lbConfigs != null) { - for (LoadBalancerConfigTO lbConfig: lbConfigs) { - lbConfigsMap.put(lbConfig.getName(), lbConfig.getValue()); - } + Arrays.stream(lbConfigs) + .forEach( + lbConfig -> lbConfigsMap.put(lbConfig.getName(), lbConfig.getValue())); } - boolean isTransparent = false; - if ("true".equalsIgnoreCase(lbConfigsMap.get(LoadBalancerConfigKey.LbTransparent.key()))) { - isTransparent = true; - } + boolean isTransparent = "true".equalsIgnoreCase(lbConfigsMap.get(LoadBalancerConfigKey.LbTransparent.key())); - boolean sslOffloading = false; - if (lbTO.getSslCert() != null && ! lbTO.getSslCert().isRevoked() - && lbTO.getLbProtocol() != null && lbTO.getLbProtocol().equals(NetUtils.SSL_PROTO)) { - sslOffloading = true; - } + boolean sslOffloading = lbTO.getSslCert() != null && !lbTO.getSslCert().isRevoked() + && lbTO.getLbProtocol() != null && lbTO.getLbProtocol().equals(NetUtils.SSL_PROTO); - final List frontendConfigs = new ArrayList(); - final List backendConfigs = new ArrayList(); - final List backendConfigsForHttp = new ArrayList(); - final List result = new ArrayList(); + final List frontendConfigs = new ArrayList<>(); + final List backendConfigs = new ArrayList<>(); + final List backendConfigsForHttp = new ArrayList<>(); + final List result = new ArrayList<>(); sb = new StringBuilder(); sb.append("\tbind ").append(publicIP).append(":").append(publicPort); @@ -542,51 +566,37 @@ private List getRulesForPool(final LoadBalancerTO lbTO, final LoadBalanc sb.append("\n\thttp-request add-header X-Forwarded-Proto https"); } frontendConfigs.add(sb.toString()); + sb = new StringBuilder(); sb.append("\t").append("balance ").append(algorithm); backendConfigs.add(sb.toString()); - String timeoutConnect = lbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutConnect.key()); - if (timeoutConnect != null) { - sb = new StringBuilder(); - sb.append("\t").append("timeout connect " + timeoutConnect); - backendConfigs.add(sb.toString()); - } - String timeoutClient = lbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutClient.key()); - if (timeoutClient != null) { - sb = new StringBuilder(); - sb.append("\t").append("timeout client " + timeoutClient); - frontendConfigs.add(sb.toString()); - } - String timeoutServer = lbConfigsMap.get(LoadBalancerConfigKey.LbTimeoutServer.key()); - if (timeoutServer != null) { - sb = new StringBuilder(); - sb.append("\t").append("timeout server " + timeoutServer); - backendConfigs.add(sb.toString()); - } + backendConfigs.add( + generateRule(lbConfigsMap, "timeout connect", LoadBalancerConfigKey.LbTimeoutConnect.key())); - if (lbConfigsMap.get(LoadBalancerConfigKey.LbMaxConn.key()) != null) { - long maxConnValue = Long.parseLong(lbConfigsMap.get(LoadBalancerConfigKey.LbMaxConn.key())); - if (maxConnValue > 0) { - sb = new StringBuilder(); - sb.append("\tmaxconn ").append(maxConnValue); - frontendConfigs.add(sb.toString()); - } - } - if (lbConfigsMap.get(LoadBalancerConfigKey.LbFullConn.key()) != null) { - long fullConnValue = Long.parseLong(lbConfigsMap.get(LoadBalancerConfigKey.LbFullConn.key())); - if (fullConnValue > 0) { - sb = new StringBuilder(); - sb.append("\tfullconn ").append(fullConnValue); - backendConfigs.add(sb.toString()); - } - } + backendConfigs.add( + generateRule(lbConfigsMap, "timeout server", LoadBalancerConfigKey.LbTimeoutServer.key())); + + backendConfigs.add( + generateLongRule(lbConfigsMap, "fullconn", LoadBalancerConfigKey.LbFullConn.key())); + + backendConfigs + .removeIf(e -> e.equals("")); + + frontendConfigs.add( + generateRule(lbConfigsMap, "timeout client", LoadBalancerConfigKey.LbTimeoutClient.key())); + + frontendConfigs.add( + generateLongRule(lbConfigsMap, "maxconn", LoadBalancerConfigKey.LbMaxConn.key())); + + frontendConfigs + .removeIf(e -> e.equals("")); int i = 0; - Boolean destsAvailable = false; + boolean destsAvailable = false; final String stickinessSubRule = getLbSubRuleForStickiness(lbTO); - final List dstSubRule = new ArrayList(); - final List dstWithCookieSubRule = new ArrayList(); + final List dstSubRule = new ArrayList<>(); + final List dstWithCookieSubRule = new ArrayList<>(); for (final DestinationTO dest : lbTO.getDestinations()) { // add line like this: "server 65_37_141_30-80_3 10.1.1.4:80 check" if (dest.isRevoked()) { @@ -597,11 +607,12 @@ private List getRulesForPool(final LoadBalancerTO lbTO, final LoadBalanc .append("server ") .append(poolName) .append("_") - .append(Integer.toString(i++)) + .append(i++) .append(" ") .append(dest.getDestIp()) .append(":") .append(dest.getDestPort()); + if ("true".equalsIgnoreCase(lbConfigsMap.get(LoadBalancerConfigKey.LbBackendHttps.key()))) { sb.append(" check ssl verify none"); } else { @@ -612,24 +623,10 @@ private List getRulesForPool(final LoadBalancerTO lbTO, final LoadBalanc sb.append(getCustomizedSslConfigs(lbConfigsMap, lbCmd)); } - if (lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxConn.key()) != null) { - long maxConnEach = Long.parseLong(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxConn.key())); - if (maxConnEach > 0) { - sb.append(" maxconn ").append(maxConnEach); - } - } - if (lbConfigsMap.get(LoadBalancerConfigKey.LbServerMinConn.key()) != null) { - long minConnEach = Long.parseLong(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMinConn.key())); - if (minConnEach > 0) { - sb.append(" minconn ").append(minConnEach); - } - } - if (lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxQueue.key()) != null) { - long maxQueueEach = Long.parseLong(lbConfigsMap.get(LoadBalancerConfigKey.LbServerMaxQueue.key())); - if (maxQueueEach > 0) { - sb.append(" maxqueue ").append(maxQueueEach); - } - } + sb.append(generateLongRule(lbConfigsMap, " ", "maxconn", LoadBalancerConfigKey.LbServerMaxConn.key())) + .append(generateLongRule(lbConfigsMap, " ", "minconn", LoadBalancerConfigKey.LbServerMinConn.key())) + .append(generateLongRule(lbConfigsMap, " ", "maxqueue", LoadBalancerConfigKey.LbServerMaxQueue.key())); + if(lbTO.getLbProtocol() != null && lbTO.getLbProtocol().equals("tcp-proxy")) { sb.append(" send-proxy"); } @@ -641,19 +638,20 @@ private List getRulesForPool(final LoadBalancerTO lbTO, final LoadBalanc destsAvailable = true; } - Boolean httpbasedStickiness = false; + boolean httpBasedStickiness = false; /* attach stickiness sub rule only if the destinations are available */ - if (stickinessSubRule != null && destsAvailable == true) { + if (stickinessSubRule != null && destsAvailable) { for (final StickinessPolicyTO stickinessPolicy : lbTO.getStickinessPolicies()) { if (stickinessPolicy == null) { continue; } if (StickinessMethodType.LBCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName()) || StickinessMethodType.AppCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName())) { - httpbasedStickiness = true; + httpBasedStickiness = true; + break; } } - if (httpbasedStickiness) { + if (httpBasedStickiness) { backendConfigs.addAll(dstWithCookieSubRule); } else { backendConfigs.addAll(dstSubRule); @@ -667,43 +665,35 @@ private List getRulesForPool(final LoadBalancerTO lbTO, final LoadBalanc } boolean http = false; String cfgLbHttp = lbConfigsMap.get(LoadBalancerConfigKey.LbHttp.key()); + if (publicPort == NetUtils.HTTP_PORT && cfgLbHttp == null) { http = true; - } else if (cfgLbHttp != null && cfgLbHttp.equalsIgnoreCase("true")) { + } else if ("true".equalsIgnoreCase(cfgLbHttp)) { http = true; } boolean keepAliveEnabled = lbCmd.keepAliveEnabled; String cfgLbHttpKeepalive = lbConfigsMap.get(LoadBalancerConfigKey.LbHttpKeepalive.key()); - if (cfgLbHttpKeepalive != null && cfgLbHttpKeepalive.equalsIgnoreCase("true")) { - keepAliveEnabled = true; - } else if (cfgLbHttpKeepalive != null && cfgLbHttpKeepalive.equalsIgnoreCase("false")) { - keepAliveEnabled = false; + + if ("true".equalsIgnoreCase(cfgLbHttpKeepalive) || "false".equalsIgnoreCase(cfgLbHttpKeepalive)) { + keepAliveEnabled = Boolean.parseBoolean(cfgLbHttpKeepalive); } - if (http || httpbasedStickiness || sslOffloading) { - sb = new StringBuilder(); - sb.append("\t").append("mode http"); - frontendConfigs.add(sb.toString()); - backendConfigsForHttp.add(sb.toString()); - if (keepAliveEnabled) { - sb = new StringBuilder(); - sb.append("\t").append("no option forceclose"); - frontendConfigs.add(sb.toString()); - backendConfigsForHttp.add(sb.toString()); - } else { - sb = new StringBuilder(); - sb.append("\t").append("option httpclose"); - frontendConfigs.add(sb.toString()); - backendConfigsForHttp.add(sb.toString()); - } + if (http || httpBasedStickiness || sslOffloading) { + + frontendConfigs.add("\tmode http"); + backendConfigsForHttp.add("\tmode http"); + + String keepAliveLine = keepAliveEnabled ? "\tno option forceclose" : "\toption httpclose"; + + frontendConfigs.add(keepAliveLine); + backendConfigsForHttp.add(keepAliveLine); } if (isTransparent) { - sb = new StringBuilder(); - sb.append("frontend ").append(poolName); - result.add(sb.toString()); + result.add(String.format("frontend %s", poolName)); result.addAll(frontendConfigs); + sb = new StringBuilder(); sb.append("\tacl local_subnet src ").append(lbCmd.getNetworkCidr()); sb.append("\n\tuse_backend ").append(poolName).append("-backend-local if local_subnet"); @@ -711,25 +701,22 @@ private List getRulesForPool(final LoadBalancerTO lbTO, final LoadBalanc sb.append("\n\n"); sb.append("backend ").append(poolName).append("-backend"); result.add(sb.toString()); + result.addAll(backendConfigsForHttp); result.addAll(backendConfigs); - sb = new StringBuilder(); - sb.append("\t").append("source 0.0.0.0 usesrc clientip"); - sb.append("\n\n"); - sb.append("backend ").append(poolName).append("-backend-local"); - result.add(sb.toString()); + + result.add(String.format("\tsource 0.0.0.0 usesrc clientip\n\nbackend %s-backend-local", poolName)); + result.addAll(backendConfigsForHttp); - result.addAll(backendConfigs); } else { // add line like this: "listen 65_37_141_30-80\n\tbind 65.37.141.30:80" - sb = new StringBuilder(); - sb.append("listen ").append(poolName); - result.add(sb.toString()); + result.add(String.format("listen %s", poolName)); result.addAll(frontendConfigs); - result.addAll(backendConfigs); } + result.addAll(backendConfigs); result.add(blankLine); + return result; } diff --git a/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDaoImpl.java index 4f6ac9d599c6..a62473092705 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/LoadBalancerConfigDaoImpl.java @@ -96,21 +96,11 @@ public void removeByLoadBalancerId(Long loadBalancerId) { @Override public LoadBalancerConfigVO findConfig(Scope scope, Long networkId, Long vpcId, Long loadBalancerId, String name) { SearchCriteria sc = AllFieldsSearch.create(); - if (scope != null) { - sc.setParameters("scope", scope); - } - if (networkId != null) { - sc.setParameters("networkId", networkId); - } - if (vpcId != null) { - sc.setParameters("vpcId", vpcId); - } - if (loadBalancerId != null) { - sc.setParameters("loadBalancerId", loadBalancerId); - } - if (name != null) { - sc.setParameters("name", name); - } + sc.setParametersIfNotNull("scope", scope); + sc.setParametersIfNotNull("networkId", networkId); + sc.setParametersIfNotNull("vpcId", vpcId); + sc.setParametersIfNotNull("loadBalancerId", loadBalancerId); + sc.setParametersIfNotNull("name", name); return findOneBy(sc); } diff --git a/framework/db/src/main/java/com/cloud/utils/db/SearchCriteria.java b/framework/db/src/main/java/com/cloud/utils/db/SearchCriteria.java index 608f715018c8..98567ceb9aa2 100644 --- a/framework/db/src/main/java/com/cloud/utils/db/SearchCriteria.java +++ b/framework/db/src/main/java/com/cloud/utils/db/SearchCriteria.java @@ -18,6 +18,7 @@ import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -157,6 +158,12 @@ public List getSelectFields() { return fields; } + public void setParametersIfNotNull(String conditionName, Object... params) { + if( !Arrays.asList(params).contains(null)){ + setParameters(conditionName, params); + } + } + public void setParameters(String conditionName, Object... params) { assert _conditions.contains(new Condition(conditionName)) || _additionals.contains(new Condition(conditionName)) : "Couldn't find " + conditionName; _params.put(conditionName, params); diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index 14a1345e0d9e..04b0cc75764a 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -1062,8 +1062,8 @@ public LoadBalancerConfigResponse createLoadBalancerConfigResponse(LoadBalancerC @Override public List createLoadBalancerConfigResponse(List configs) { - List lbConfigResponses = new ArrayList(); - if (configs == null || configs.size() == 0) { + List lbConfigResponses = new ArrayList<>(); + if (CollectionUtils.isEmpty(configs)) { return lbConfigResponses; } LoadBalancerConfig config = configs.get(0); diff --git a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 6d6a63f8e643..cf3c591817a1 100644 --- a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -1840,6 +1840,13 @@ private void updateWithLbRules(final DomainRouterJoinVO routerJoinVO, final Stri } } + private String generateKeyValuePairOrEmptyString(String key, String value){ + if (value == null) + return ""; + + return String.format(",%s=%s", key, value); + } + private void updateLbValues(final HashMap lbConfigsMap, StringBuilder loadBalancingData) { String lbMaxConn = lbConfigsMap.getOrDefault(LoadBalancerConfigKey.LbMaxConn.key(), null); String lbFullConn = lbConfigsMap.getOrDefault(LoadBalancerConfigKey.LbFullConn.key(), null); @@ -1854,36 +1861,16 @@ private void updateLbValues(final HashMap lbConfigsMap, StringBu String serverMinconn = lbConfigsMap.getOrDefault(LoadBalancerConfigKey.LbServerMinConn.key(), null); String serverMaxqueue = lbConfigsMap.getOrDefault(LoadBalancerConfigKey.LbServerMaxQueue.key(), null); - if (lbMaxConn != null) { - loadBalancingData.append(",lb.maxconn=").append(lbMaxConn); - } - if (lbFullConn != null) { - loadBalancingData.append(",lb.fullconn=").append(lbFullConn); - } - if (lbTimeoutConnect != null) { - loadBalancingData.append(",lb.timeout.connect=").append(lbTimeoutConnect); - } - if (lbTimeoutServer != null) { - loadBalancingData.append(",lb.timeout.server=").append(lbTimeoutServer); - } - if (lbTimeoutClient != null) { - loadBalancingData.append(",lb.timeout.client=").append(lbTimeoutClient); - } - if (lbBackendHttps != null) { - loadBalancingData.append(",lb.backend.https=").append(lbBackendHttps); - } - if (lbHttp2 != null) { - loadBalancingData.append(",http2=").append(lbHttp2); - } - if (serverMaxconn != null) { - loadBalancingData.append(",server.maxconn=").append(serverMaxconn); - } - if (serverMinconn != null) { - loadBalancingData.append(",server.minconn=").append(serverMinconn); - } - if (serverMaxqueue != null) { - loadBalancingData.append(",server.maxqueue=").append(serverMaxqueue); - } + loadBalancingData.append(generateKeyValuePairOrEmptyString("lb.maxconn", lbMaxConn)) + .append(generateKeyValuePairOrEmptyString("lb.fullconn", lbFullConn)) + .append(generateKeyValuePairOrEmptyString("lb.timeout.connect", lbTimeoutConnect)) + .append(generateKeyValuePairOrEmptyString("lb.timeout.server", lbTimeoutServer)) + .append(generateKeyValuePairOrEmptyString("lb.timeout.client", lbTimeoutClient)) + .append(generateKeyValuePairOrEmptyString("lb.backend.https", lbBackendHttps)) + .append(generateKeyValuePairOrEmptyString("http2", lbHttp2)) + .append(generateKeyValuePairOrEmptyString("server.maxconn", serverMaxconn)) + .append(generateKeyValuePairOrEmptyString("server.minconn", serverMinconn)) + .append(generateKeyValuePairOrEmptyString("server.maxqueue", serverMaxqueue)); } private Map getRouterHealthChecksConfig(final DomainRouterVO router) { diff --git a/server/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManagerImpl.java b/server/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManagerImpl.java index 34ee9037d8ba..7623e25d3884 100644 --- a/server/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/network/lb/LoadBalancerConfigManagerImpl.java @@ -53,6 +53,7 @@ import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.network.lb.LoadBalancerConfig.Scope; +import org.apache.commons.lang3.ObjectUtils; import org.apache.log4j.Logger; public class LoadBalancerConfigManagerImpl extends ManagerBase implements LoadBalancerConfigService, LoadBalancerConfigManager { @@ -129,8 +130,8 @@ public List searchForLoadBalancerConfigs(ListLoadB if (name != null) { sc.addAnd("name", SearchCriteria.Op.EQ, name); } - List configs = new ArrayList(); - if (id != null || networkId != null || vpcId != null || loadBalancerId != null) { + List configs = new ArrayList<>(); + if ( ObjectUtils.anyNotNull( id, networkId, vpcId, loadBalancerId)) { configs = _lbConfigDao.search(sc, null); } if (cmd.listAll()) { @@ -281,12 +282,9 @@ private void checkPermission(Scope scope, Long networkId, Long vpcId, Long loadB } throw new InvalidParameterValueException("networkId is required"); } - if (vpcId != null || loadBalancerId != null) { + if (ObjectUtils.anyNotNull( vpcId, loadBalancerId)) { throw new InvalidParameterValueException("vpcId and loadBalancerId should be null if scope is Network"); } - if (networkId == null) { - throw new InvalidParameterValueException("networkId is required"); - } NetworkVO network = _networkDao.findById(networkId); if (network == null) { throw new InvalidParameterValueException("Cannot find network by id " + networkId);