diff --git a/api/src/main/java/org/apache/cloudstack/config/ApiServiceConfiguration.java b/api/src/main/java/org/apache/cloudstack/config/ApiServiceConfiguration.java index a4aa860487f..113b97f43c8 100644 --- a/api/src/main/java/org/apache/cloudstack/config/ApiServiceConfiguration.java +++ b/api/src/main/java/org/apache/cloudstack/config/ApiServiceConfiguration.java @@ -16,10 +16,15 @@ // under the License. package org.apache.cloudstack.config; +import com.cloud.exception.InvalidParameterValueException; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class ApiServiceConfiguration implements Configurable { + protected static Logger LOGGER = LogManager.getLogger(ApiServiceConfiguration.class); public static final ConfigKey ManagementServerAddresses = new ConfigKey<>(String.class, "host", "Advanced", "localhost", "The ip address of management server. This can also accept comma separated addresses.", true, ConfigKey.Scope.Global, null, null, null, null, null, ConfigKey.Kind.CSV, null); public static final ConfigKey ApiServletPath = new ConfigKey("Advanced", String.class, "endpoint.url", "http://localhost:8080/client/api", "API end point. Can be used by CS components/services deployed remotely, for sending CS API requests", true); @@ -29,6 +34,20 @@ public class ApiServiceConfiguration implements Configurable { "true", "Are the source checks on API calls enabled (true) or not (false)? See api.allowed.source.cidr.list", true, ConfigKey.Scope.Global); public static final ConfigKey ApiAllowedSourceCidrList = new ConfigKey<>(String.class, "api.allowed.source.cidr.list", "Advanced", "0.0.0.0/0,::/0", "Comma separated list of IPv4/IPv6 CIDRs from which API calls can be performed. Can be set on Global and Account levels.", true, ConfigKey.Scope.Account, null, null, null, null, null, ConfigKey.Kind.CSV, null); + + + public static void validateEndpointUrl() { + String csUrl = getApiServletPathValue(); + if (StringUtils.isBlank(csUrl) || StringUtils.containsAny(csUrl, "localhost", "127.0.0.1", "[::1]")) { + LOGGER.error("Global setting [{}] cannot contain localhost or be blank. Current value: {}", ApiServletPath.key(), csUrl); + throw new InvalidParameterValueException("Unable to complete this operation. Contact your cloud admin."); + } + } + + public static String getApiServletPathValue() { + return ApiServletPath.value(); + } + @Override public String getConfigComponentName() { return ApiServiceConfiguration.class.getSimpleName(); diff --git a/api/src/test/java/org/apache/cloudstack/config/ApiServiceConfigurationTest.java b/api/src/test/java/org/apache/cloudstack/config/ApiServiceConfigurationTest.java new file mode 100644 index 00000000000..4e96af3ead4 --- /dev/null +++ b/api/src/test/java/org/apache/cloudstack/config/ApiServiceConfigurationTest.java @@ -0,0 +1,95 @@ +// 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.config; + +import com.cloud.exception.InvalidParameterValueException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class ApiServiceConfigurationTest { + + private static final String LOCALHOST = "http://localhost"; + + private static final String ENDPOINT_URL = "https://acs.clouds.com/client/api"; + + private static final String WHITE_SPACE = " "; + + private static final String BLANK_STRING = ""; + + private static final String NULL_STRING = null; + + private static final String LOCALHOST_IP = "127.0.0.1"; + + @Test(expected = InvalidParameterValueException.class) + public void validateEndpointUrlTestIfEndpointUrlContainLocalhostShouldThrowInvalidParameterValueException() { + try (MockedStatic apiServiceConfigurationMockedStatic = Mockito.mockStatic(ApiServiceConfiguration.class)) { + apiServiceConfigurationMockedStatic.when(ApiServiceConfiguration::getApiServletPathValue).thenReturn(LOCALHOST); + apiServiceConfigurationMockedStatic.when(ApiServiceConfiguration::validateEndpointUrl).thenCallRealMethod(); + ApiServiceConfiguration.validateEndpointUrl(); + } + } + + @Test + public void validateEndpointUrlTestIfEndpointUrlContainLocalhostShouldNotThrowInvalidParameterValueException() { + try (MockedStatic apiServiceConfigurationMockedStatic = Mockito.mockStatic(ApiServiceConfiguration.class)) { + apiServiceConfigurationMockedStatic.when(ApiServiceConfiguration::getApiServletPathValue).thenReturn(ENDPOINT_URL); + apiServiceConfigurationMockedStatic.when(ApiServiceConfiguration::validateEndpointUrl).thenCallRealMethod(); + ApiServiceConfiguration.validateEndpointUrl(); + } + } + + @Test(expected = InvalidParameterValueException.class) + public void validateEndpointUrlTestIfEndpointUrlIsNullShouldThrowInvalidParameterValueException() { + try (MockedStatic apiServiceConfigurationMockedStatic = Mockito.mockStatic(ApiServiceConfiguration.class)) { + apiServiceConfigurationMockedStatic.when(ApiServiceConfiguration::getApiServletPathValue).thenReturn(NULL_STRING); + apiServiceConfigurationMockedStatic.when(ApiServiceConfiguration::validateEndpointUrl).thenCallRealMethod(); + ApiServiceConfiguration.validateEndpointUrl(); + } + } + + @Test(expected = InvalidParameterValueException.class) + public void validateEndpointUrlTestIfEndpointUrlIsBlankShouldThrowInvalidParameterValueException() { + try (MockedStatic apiServiceConfigurationMockedStatic = Mockito.mockStatic(ApiServiceConfiguration.class)) { + apiServiceConfigurationMockedStatic.when(ApiServiceConfiguration::getApiServletPathValue).thenReturn(BLANK_STRING); + apiServiceConfigurationMockedStatic.when(ApiServiceConfiguration::validateEndpointUrl).thenCallRealMethod(); + ApiServiceConfiguration.validateEndpointUrl(); + } + } + + @Test(expected = InvalidParameterValueException.class) + public void validateEndpointUrlTestIfEndpointUrlIsWhiteSpaceShouldThrowInvalidParameterValueException() { + try (MockedStatic apiServiceConfigurationMockedStatic = Mockito.mockStatic(ApiServiceConfiguration.class)) { + apiServiceConfigurationMockedStatic.when(ApiServiceConfiguration::getApiServletPathValue).thenReturn(WHITE_SPACE); + apiServiceConfigurationMockedStatic.when(ApiServiceConfiguration::validateEndpointUrl).thenCallRealMethod(); + ApiServiceConfiguration.validateEndpointUrl(); + } + } + + @Test(expected = InvalidParameterValueException.class) + public void validateEndpointUrlTestIfEndpointUrlContainLocalhostIpShouldThrowInvalidParameterValueException() { + try (MockedStatic apiServiceConfigurationMockedStatic = Mockito.mockStatic(ApiServiceConfiguration.class)) { + apiServiceConfigurationMockedStatic.when(ApiServiceConfiguration::getApiServletPathValue).thenReturn(LOCALHOST_IP); + apiServiceConfigurationMockedStatic.when(ApiServiceConfiguration::validateEndpointUrl).thenCallRealMethod(); + ApiServiceConfiguration.validateEndpointUrl(); + } + } +} diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java index 213657db073..422c9072fbf 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java @@ -905,15 +905,6 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne return response; } - private void validateEndpointUrl() { - String csUrl = ApiServiceConfiguration.ApiServletPath.value(); - if (csUrl == null || csUrl.contains("localhost")) { - String error = String.format("Global setting %s has to be set to the Management Server's API end point", - ApiServiceConfiguration.ApiServletPath.key()); - throw new InvalidParameterValueException(error); - } - } - private DataCenter validateAndGetZoneForKubernetesCreateParameters(Long zoneId, Long networkId) { DataCenter zone = dataCenterDao.findById(zoneId); if (zone == null) { @@ -1008,7 +999,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne } private void validateManagedKubernetesClusterCreateParameters(final CreateKubernetesClusterCmd cmd) throws CloudRuntimeException { - validateEndpointUrl(); + ApiServiceConfiguration.validateEndpointUrl(); final String name = cmd.getName(); final Long zoneId = cmd.getZoneId(); final Long kubernetesVersionId = cmd.getKubernetesVersionId(); @@ -1308,7 +1299,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne KubernetesVersionManagerImpl.MINIMUN_AUTOSCALER_SUPPORTED_VERSION )); } - validateEndpointUrl(); + ApiServiceConfiguration.validateEndpointUrl(); if (minSize == null || maxSize == null) { throw new InvalidParameterValueException("Autoscaling requires minsize and maxsize to be passed"); @@ -1413,7 +1404,7 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne private void validateKubernetesClusterUpgradeParameters(UpgradeKubernetesClusterCmd cmd) { // Validate parameters - validateEndpointUrl(); + ApiServiceConfiguration.validateEndpointUrl(); final Long kubernetesClusterId = cmd.getId(); final Long upgradeVersionId = cmd.getKubernetesVersionId(); diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterActionWorker.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterActionWorker.java index baf717612f8..cd334954946 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterActionWorker.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterActionWorker.java @@ -685,7 +685,7 @@ public class KubernetesClusterActionWorker { try { String command = String.format("sudo %s/%s -u '%s' -k '%s' -s '%s'", - scriptPath, deploySecretsScriptFilename, ApiServiceConfiguration.ApiServletPath.value(), keys[0], keys[1]); + scriptPath, deploySecretsScriptFilename, ApiServiceConfiguration.getApiServletPathValue(), keys[0], keys[1]); Account account = accountDao.findById(kubernetesCluster.getAccountId()); if (account != null && account.getType() == Account.Type.PROJECT) { String projectId = projectService.findByProjectAccountId(account.getId()).getUuid(); diff --git a/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java b/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java index 90380b77e44..232c4a6bd68 100644 --- a/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java +++ b/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java @@ -512,7 +512,6 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage String apiKey = user.getApiKey(); String secretKey = user.getSecretKey(); - String csUrl = ApiServiceConfiguration.ApiServletPath.value(); if (apiKey == null) { throw new InvalidParameterValueException("apiKey for user: " + user.getUsername() + " is empty. Please generate it"); @@ -522,9 +521,7 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage throw new InvalidParameterValueException("secretKey for user: " + user.getUsername() + " is empty. Please generate it"); } - if (csUrl == null || csUrl.contains("localhost")) { - throw new InvalidParameterValueException(String.format("Global setting %s has to be set to the Management Server's API end point", ApiServiceConfiguration.ApiServletPath.key())); - } + ApiServiceConfiguration.validateEndpointUrl(); } @Override @ActionEvent(eventType = EventTypes.EVENT_AUTOSCALEVMPROFILE_CREATE, eventDescription = "creating autoscale vm profile", create = true) 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 5ceebf06dd8..df60553bb8e 100644 --- a/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -337,7 +337,6 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements String apiKey = null; String secretKey = null; - String csUrl = ApiServiceConfiguration.ApiServletPath.value(); Network.Provider provider = getLoadBalancerServiceProvider(lb); if (Network.Provider.Netscaler.equals(provider)) { Long autoscaleUserId = autoScaleVmProfile.getAutoScaleUserId(); @@ -358,13 +357,12 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements throw new InvalidParameterValueException("secretKey for user: " + user.getUsername() + " is empty. Please generate it"); } - if (csUrl == null || csUrl.contains("localhost")) { - throw new InvalidParameterValueException(String.format("Global setting %s has to be set to the Management Server's API end point", ApiServiceConfiguration.ApiServletPath.key())); - } + ApiServiceConfiguration.validateEndpointUrl(); } LbAutoScaleVmProfile lbAutoScaleVmProfile = - new LbAutoScaleVmProfile(autoScaleVmProfile, apiKey, secretKey, csUrl, zoneId, domainId, serviceOfferingId, templateId, vmName, lbNetworkUuid); + new LbAutoScaleVmProfile(autoScaleVmProfile, apiKey, secretKey, ApiServiceConfiguration.getApiServletPathValue(), zoneId, domainId, serviceOfferingId, templateId, + vmName, lbNetworkUuid); return new LbAutoScaleVmGroup(vmGroup, autoScalePolicies, lbAutoScaleVmProfile, currentState); }