mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
CLOUDSTACK-741: Granular Global Parameters
Signed-off-by: Abhinandan Prateek <aprateek@apache.org>
This commit is contained in:
parent
81e1ba3bb4
commit
eae22d2ffa
@ -23,8 +23,7 @@ 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.ConfigurationResponse;
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
import org.apache.cloudstack.api.response.*;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.configuration.Configuration;
|
||||
@ -46,6 +45,13 @@ public class ListCfgsByCmd extends BaseListCmd {
|
||||
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "lists configuration by name")
|
||||
private String configName;
|
||||
|
||||
@Parameter(name=ApiConstants.SCOPE, type = CommandType.STRING, description = "scope(zone/cluster/pool/account) of the parameter that needs to be updated")
|
||||
private String scope;
|
||||
|
||||
@Parameter(name=ApiConstants.ID, type = CommandType.UUID, entityType = {ZoneResponse.class, ClusterResponse.class, StoragePoolResponse.class, AccountResponse.class}, description = "corresponding ID of the scope")
|
||||
private Long id;
|
||||
|
||||
|
||||
// ///////////////////////////////////////////////////
|
||||
// ///////////////// Accessors ///////////////////////
|
||||
// ///////////////////////////////////////////////////
|
||||
@ -58,6 +64,15 @@ public class ListCfgsByCmd extends BaseListCmd {
|
||||
return configName;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Long getPageSizeVal() {
|
||||
Long pageSizeVal = 500L;
|
||||
@ -85,6 +100,11 @@ public class ListCfgsByCmd extends BaseListCmd {
|
||||
for (Configuration cfg : result.first()) {
|
||||
ConfigurationResponse cfgResponse = _responseGenerator.createConfigurationResponse(cfg);
|
||||
cfgResponse.setObjectName("configuration");
|
||||
if (scope != null) {
|
||||
cfgResponse.setScope(scope);
|
||||
} else {
|
||||
cfgResponse.setScope("global");
|
||||
}
|
||||
configResponses.add(cfgResponse);
|
||||
}
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.ConfigurationResponse;
|
||||
import org.apache.cloudstack.api.response.*;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.configuration.Configuration;
|
||||
@ -43,6 +43,12 @@ public class UpdateCfgCmd extends BaseCmd {
|
||||
@Parameter(name=ApiConstants.VALUE, type=CommandType.STRING, description="the value of the configuration", length=4095)
|
||||
private String value;
|
||||
|
||||
@Parameter(name=ApiConstants.SCOPE, type = CommandType.STRING, description = "scope(zone/cluster/pool/account) of the parameter that needs to be updated")
|
||||
private String scope;
|
||||
|
||||
@Parameter(name=ApiConstants.ID, type = CommandType.UUID, entityType = {ZoneResponse.class, ClusterResponse.class, StoragePoolResponse.class, AccountResponse.class}, description = "corresponding ID of the scope")
|
||||
private Long id;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@ -55,6 +61,14 @@ public class UpdateCfgCmd extends BaseCmd {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@ -75,6 +89,12 @@ public class UpdateCfgCmd extends BaseCmd {
|
||||
if (cfg != null) {
|
||||
ConfigurationResponse response = _responseGenerator.createConfigurationResponse(cfg);
|
||||
response.setResponseName(getCommandName());
|
||||
if (scope != null) {
|
||||
response.setScope(scope);
|
||||
response.setValue(value);
|
||||
} else {
|
||||
response.setScope("global");
|
||||
}
|
||||
this.setResponseObject(response);
|
||||
} else {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update config");
|
||||
|
||||
@ -32,9 +32,13 @@ public class ConfigurationResponse extends BaseResponse {
|
||||
@SerializedName(ApiConstants.VALUE) @Param(description="the value of the configuration")
|
||||
private String value;
|
||||
|
||||
@SerializedName(ApiConstants.SCOPE) @Param(description="scope(zone/cluster/pool/account) of the parameter that needs to be updated")
|
||||
private String scope;
|
||||
|
||||
@SerializedName(ApiConstants.DESCRIPTION) @Param(description="the description of the configuration")
|
||||
private String description;
|
||||
|
||||
|
||||
public String getCategory() {
|
||||
return category;
|
||||
}
|
||||
@ -66,4 +70,12 @@ public class ConfigurationResponse extends BaseResponse {
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public void setScope(String scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,89 @@
|
||||
// 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.test;
|
||||
|
||||
import com.cloud.configuration.Configuration;
|
||||
import com.cloud.configuration.ConfigurationService;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.resource.ResourceService;
|
||||
import com.cloud.server.ManagementService;
|
||||
import com.cloud.utils.Pair;
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.cloudstack.api.ResponseGenerator;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd;
|
||||
import org.apache.cloudstack.api.response.ConfigurationResponse;
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ListCfgCmdTest extends TestCase{
|
||||
|
||||
private ListCfgsByCmd listCfgsByCmd;
|
||||
private ManagementService mgr;
|
||||
private ResponseGenerator responseGenerator;
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
responseGenerator = Mockito.mock(ResponseGenerator.class);
|
||||
mgr = Mockito.mock(ManagementService.class);
|
||||
listCfgsByCmd = new ListCfgsByCmd();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSuccess() {
|
||||
|
||||
Configuration cfg = Mockito.mock(Configuration.class);
|
||||
listCfgsByCmd._mgr = mgr;
|
||||
listCfgsByCmd._responseGenerator = responseGenerator;
|
||||
|
||||
|
||||
|
||||
List<Configuration> configList = new ArrayList<Configuration>();
|
||||
configList.add(cfg);
|
||||
|
||||
Pair<List<? extends Configuration>, Integer> result = new Pair<List<? extends Configuration>, Integer>(configList, 1);
|
||||
|
||||
try {
|
||||
Mockito.when(
|
||||
mgr.searchForConfigurations(listCfgsByCmd))
|
||||
.thenReturn(result);
|
||||
}catch (Exception e){
|
||||
Assert.fail("Received exception when success expected " + e.getMessage());
|
||||
}
|
||||
ConfigurationResponse cfgResponse = new ConfigurationResponse();
|
||||
cfgResponse.setName("Test case");
|
||||
Mockito.when(responseGenerator.createConfigurationResponse(cfg)).thenReturn(cfgResponse);
|
||||
|
||||
listCfgsByCmd.execute();
|
||||
Mockito.verify(responseGenerator).createConfigurationResponse(cfg);
|
||||
|
||||
ListResponse<ConfigurationResponse> actualResponse = (ListResponse<ConfigurationResponse>) listCfgsByCmd.getResponseObject();
|
||||
Assert.assertEquals(cfgResponse, actualResponse.getResponses().get(0));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,116 @@
|
||||
// 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.test;
|
||||
|
||||
import com.cloud.configuration.Configuration;
|
||||
import com.cloud.configuration.ConfigurationService;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.resource.ResourceService;
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.cloudstack.api.ResponseGenerator;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
|
||||
import org.apache.cloudstack.api.response.ConfigurationResponse;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
public class UpdateCfgCmdTest extends TestCase{
|
||||
|
||||
private UpdateCfgCmd updateCfgCmd;
|
||||
private ConfigurationService configService;
|
||||
private ResponseGenerator responseGenerator;
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
responseGenerator = Mockito.mock(ResponseGenerator.class);
|
||||
configService = Mockito.mock(ConfigurationService.class);
|
||||
updateCfgCmd = new UpdateCfgCmd();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteForEmptyResult() {
|
||||
updateCfgCmd._configService = configService;
|
||||
|
||||
try {
|
||||
updateCfgCmd.execute();
|
||||
} catch (ServerApiException exception) {
|
||||
Assert.assertEquals("Failed to update config",
|
||||
exception.getDescription());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteForNullResult() {
|
||||
|
||||
updateCfgCmd._configService = configService;
|
||||
|
||||
try {
|
||||
Mockito.when(
|
||||
configService.updateConfiguration(updateCfgCmd))
|
||||
.thenReturn(null);
|
||||
} catch (InvalidParameterValueException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (IllegalArgumentException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
updateCfgCmd.execute();
|
||||
} catch (ServerApiException exception) {
|
||||
Assert.assertEquals("Failed to update config",
|
||||
exception.getDescription());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateSuccess() {
|
||||
|
||||
Configuration cfg = Mockito.mock(Configuration.class);
|
||||
updateCfgCmd._configService = configService;
|
||||
updateCfgCmd._responseGenerator = responseGenerator;
|
||||
|
||||
try {
|
||||
Mockito.when(
|
||||
configService.updateConfiguration(updateCfgCmd))
|
||||
.thenReturn(cfg);
|
||||
}catch (Exception e){
|
||||
Assert.fail("Received exception when success expected " + e.getMessage());
|
||||
}
|
||||
|
||||
ConfigurationResponse response = new ConfigurationResponse();
|
||||
response.setName("Test case");
|
||||
Mockito.when(responseGenerator.createConfigurationResponse(cfg)).thenReturn(response);
|
||||
|
||||
updateCfgCmd.execute();
|
||||
Mockito.verify(responseGenerator).createConfigurationResponse(cfg);
|
||||
ConfigurationResponse actualResponse = (ConfigurationResponse) updateCfgCmd.getResponseObject();
|
||||
Assert.assertEquals(response, actualResponse);
|
||||
Assert.assertEquals("updateconfigurationresponse", response.getResponseName());
|
||||
}
|
||||
|
||||
}
|
||||
@ -25,4 +25,5 @@ public interface StoragePoolDetailsDao extends GenericDao<StoragePoolDetailVO, L
|
||||
|
||||
void update(long poolId, Map<String, String> details);
|
||||
Map<String, String> getDetails(long poolId);
|
||||
StoragePoolDetailVO findDetail(long poolId, String name);
|
||||
}
|
||||
|
||||
@ -16,9 +16,7 @@
|
||||
// under the License.
|
||||
package com.cloud.configuration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
|
||||
|
||||
@ -339,7 +337,7 @@ public enum Config {
|
||||
//disabling lb as cluster sync does not work with distributed cluster
|
||||
AgentLbEnable("Advanced", ManagementServer.class, Boolean.class, "agent.lb.enabled", "false", "If agent load balancing enabled in cluster setup", null),
|
||||
SubDomainNetworkAccess("Advanced", NetworkManager.class, Boolean.class, "allow.subdomain.network.access", "true", "Allow subdomains to use networks dedicated to their parent domain(s)", null),
|
||||
UseExternalDnsServers("Advanced", NetworkManager.class, Boolean.class, "use.external.dns", "false", "Bypass internal dns, use external dns1 and dns2", null),
|
||||
UseExternalDnsServers("Advanced", NetworkManager.class, Boolean.class, "use.external.dns", "false", "Bypass internal dns, use external dns1 and dns2", null, ConfigurationParameterScope.zone.toString()),
|
||||
EncodeApiResponse("Advanced", ManagementServer.class, Boolean.class, "encode.api.response", "false", "Do URL encoding for the api response, false by default", null),
|
||||
DnsBasicZoneUpdates("Advanced", NetworkManager.class, String.class, "network.dns.basiczone.updates", "all", "This parameter can take 2 values: all (default) and pod. It defines if DHCP/DNS requests have to be send to all dhcp servers in cloudstack, or only to the one in the same pod", "all,pod"),
|
||||
|
||||
@ -412,6 +410,35 @@ public enum Config {
|
||||
private final String _defaultValue;
|
||||
private final String _description;
|
||||
private final String _range;
|
||||
private final String _scope; // Parameter can be at different levels (Zone/cluster/pool/account), by default every parameter is at global
|
||||
|
||||
public static enum ConfigurationParameterScope {
|
||||
global,
|
||||
zone,
|
||||
cluster,
|
||||
pool,
|
||||
account
|
||||
}
|
||||
|
||||
private static final HashMap<String, List<Config>> _scopeLevelConfigsMap = new HashMap<String, List<Config>>();
|
||||
static {
|
||||
_scopeLevelConfigsMap.put(ConfigurationParameterScope.zone.toString(), new ArrayList<Config>());
|
||||
_scopeLevelConfigsMap.put(ConfigurationParameterScope.cluster.toString(), new ArrayList<Config>());
|
||||
_scopeLevelConfigsMap.put(ConfigurationParameterScope.pool.toString(), new ArrayList<Config>());
|
||||
_scopeLevelConfigsMap.put(ConfigurationParameterScope.account.toString(), new ArrayList<Config>());
|
||||
_scopeLevelConfigsMap.put(ConfigurationParameterScope.global.toString(), new ArrayList<Config>());
|
||||
|
||||
for (Config c : Config.values()) {
|
||||
//Creating group of parameters per each level (zone/cluster/pool/account)
|
||||
StringTokenizer tokens = new StringTokenizer(c.getScope(), ",");
|
||||
while (tokens.hasMoreTokens()) {
|
||||
String scope = tokens.nextToken().trim();
|
||||
List<Config> currentConfigs = _scopeLevelConfigsMap.get(scope);
|
||||
currentConfigs.add(c);
|
||||
_scopeLevelConfigsMap.put(scope, currentConfigs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final HashMap<String, List<Config>> _configs = new HashMap<String, List<Config>>();
|
||||
static {
|
||||
@ -447,6 +474,17 @@ public enum Config {
|
||||
_defaultValue = defaultValue;
|
||||
_description = description;
|
||||
_range = range;
|
||||
_scope = ConfigurationParameterScope.global.toString();
|
||||
}
|
||||
private Config(String category, Class<?> componentClass, Class<?> type, String name, String defaultValue, String description, String range, String scope) {
|
||||
_category = category;
|
||||
_componentClass = componentClass;
|
||||
_type = type;
|
||||
_name = name;
|
||||
_defaultValue = defaultValue;
|
||||
_description = description;
|
||||
_range = range;
|
||||
_scope = scope;
|
||||
}
|
||||
|
||||
public String getCategory() {
|
||||
@ -473,6 +511,10 @@ public enum Config {
|
||||
return _componentClass;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return _scope;
|
||||
}
|
||||
|
||||
public String getComponent() {
|
||||
if (_componentClass == ManagementServer.class) {
|
||||
return "management-server";
|
||||
@ -530,4 +572,8 @@ public enum Config {
|
||||
}
|
||||
return categories;
|
||||
}
|
||||
|
||||
public static List<Config> getConfigListByScope(String scope) {
|
||||
return _scopeLevelConfigsMap.get(scope);
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ public interface ConfigurationManager extends ConfigurationService, Manager {
|
||||
* @param name
|
||||
* @param value
|
||||
*/
|
||||
void updateConfiguration(long userId, String name, String category, String value);
|
||||
void updateConfiguration(long userId, String name, String category, String value, String scope, Long id);
|
||||
|
||||
/**
|
||||
* Creates a new service offering
|
||||
|
||||
@ -39,6 +39,7 @@ import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.InitialDirContext;
|
||||
|
||||
import com.cloud.dc.dao.*;
|
||||
import org.apache.cloudstack.acl.SecurityChecker;
|
||||
import org.apache.cloudstack.api.ApiConstants.LDAPParams;
|
||||
import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
|
||||
@ -78,20 +79,13 @@ import com.cloud.dc.DataCenter.NetworkType;
|
||||
import com.cloud.dc.DataCenterIpAddressVO;
|
||||
import com.cloud.dc.DataCenterLinkLocalIpAddressVO;
|
||||
import com.cloud.dc.DataCenterVO;
|
||||
import com.cloud.dc.DcDetailVO;
|
||||
import com.cloud.dc.HostPodVO;
|
||||
import com.cloud.dc.Pod;
|
||||
import com.cloud.dc.PodVlanMapVO;
|
||||
import com.cloud.dc.Vlan;
|
||||
import com.cloud.dc.Vlan.VlanType;
|
||||
import com.cloud.dc.VlanVO;
|
||||
import com.cloud.dc.dao.AccountVlanMapDao;
|
||||
import com.cloud.dc.dao.ClusterDao;
|
||||
import com.cloud.dc.dao.DataCenterDao;
|
||||
import com.cloud.dc.dao.DataCenterIpAddressDao;
|
||||
import com.cloud.dc.dao.DataCenterLinkLocalIpAddressDao;
|
||||
import com.cloud.dc.dao.HostPodDao;
|
||||
import com.cloud.dc.dao.PodVlanMapDao;
|
||||
import com.cloud.dc.dao.VlanDao;
|
||||
import com.cloud.deploy.DataCenterDeployment;
|
||||
import com.cloud.domain.Domain;
|
||||
import com.cloud.domain.DomainVO;
|
||||
@ -188,6 +182,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
@Inject
|
||||
DataCenterDao _zoneDao;
|
||||
@Inject
|
||||
DcDetailsDao _zoneDetailsDao;
|
||||
@Inject
|
||||
DomainDao _domainDao;
|
||||
@Inject
|
||||
SwiftDao _swiftDao;
|
||||
@ -327,15 +323,37 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
|
||||
@Override
|
||||
@DB
|
||||
public void updateConfiguration(long userId, String name, String category, String value) {
|
||||
public void updateConfiguration(long userId, String name, String category, String value, String scope, Long resourceId) {
|
||||
|
||||
String validationMsg = validateConfigurationValue(name, value);
|
||||
String validationMsg = validateConfigurationValue(name, value, scope);
|
||||
|
||||
if (validationMsg != null) {
|
||||
s_logger.error("Invalid configuration option, name: " + name + ", value:" + value);
|
||||
throw new InvalidParameterValueException(validationMsg);
|
||||
}
|
||||
|
||||
// If scope of the parameter is given then it needs to be updated in the corresponding details table,
|
||||
// if scope is mentioned as global or not mentioned then it is normal global parameter updation
|
||||
if (scope != null && !scope.isEmpty() && !Config.ConfigurationParameterScope.global.toString().equalsIgnoreCase(scope)) {
|
||||
if (Config.ConfigurationParameterScope.zone.toString().equalsIgnoreCase(scope)) {
|
||||
DataCenterVO zone = _zoneDao.findById(resourceId);
|
||||
if (zone == null) {
|
||||
throw new InvalidParameterValueException("unable to find zone by id " + resourceId);
|
||||
}
|
||||
DcDetailVO dcDetailVO = _zoneDetailsDao.findDetail(resourceId, name.toLowerCase());
|
||||
if (dcDetailVO == null) {
|
||||
dcDetailVO = new DcDetailVO(dcDetailVO.getId(), name, value);
|
||||
_zoneDetailsDao.persist(dcDetailVO);
|
||||
} else {
|
||||
dcDetailVO.setValue(value);
|
||||
_zoneDetailsDao.update(resourceId, dcDetailVO);
|
||||
}
|
||||
} else {
|
||||
s_logger.error("TO Do for the remaining levels (cluster/pool/account)");
|
||||
throw new InvalidParameterValueException("The scope "+ scope +" yet to be implemented");
|
||||
}
|
||||
}
|
||||
|
||||
// Execute all updates in a single transaction
|
||||
Transaction txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
@ -440,6 +458,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
Long userId = UserContext.current().getCallerUserId();
|
||||
String name = cmd.getCfgName();
|
||||
String value = cmd.getValue();
|
||||
String scope = cmd.getScope();
|
||||
Long id = cmd.getId();
|
||||
UserContext.current().setEventDetails(" Name: " + name + " New Value: " + (((name.toLowerCase()).contains("password")) ? "*****" :
|
||||
(((value == null) ? "" : value))));
|
||||
// check if config value exists
|
||||
@ -456,7 +476,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
value = null;
|
||||
}
|
||||
|
||||
updateConfiguration(userId, name, config.getCategory(), value);
|
||||
updateConfiguration(userId, name, config.getCategory(), value, scope, id);
|
||||
String updatedValue = _configDao.getValue(name);
|
||||
if ((value == null && updatedValue == null) || updatedValue.equalsIgnoreCase(value)) {
|
||||
return _configDao.findByName(name);
|
||||
@ -466,13 +486,20 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
}
|
||||
}
|
||||
|
||||
private String validateConfigurationValue(String name, String value) {
|
||||
private String validateConfigurationValue(String name, String value, String scope) {
|
||||
|
||||
Config c = Config.getConfig(name);
|
||||
if (c == null) {
|
||||
s_logger.error("Missing configuration variable " + name + " in configuration table");
|
||||
return "Invalid configuration variable.";
|
||||
}
|
||||
String configScope = c.getScope();
|
||||
if (scope != null && !scope.isEmpty()) {
|
||||
if (!configScope.contains(scope)) {
|
||||
s_logger.error("Invalid scope " + scope + " for the parameter " + name);
|
||||
return "Invalid scope for the parameter.";
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> type = c.getType();
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
package com.cloud.configuration.dao;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.configuration.ConfigurationVO;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
@ -40,6 +40,7 @@ import javax.ejb.Local;
|
||||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.server.ConfigurationServer;
|
||||
import org.apache.cloudstack.api.command.admin.router.UpgradeRouterCmd;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.springframework.stereotype.Component;
|
||||
@ -286,6 +287,8 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V
|
||||
@Inject
|
||||
ConfigurationManager _configMgr;
|
||||
@Inject
|
||||
ConfigurationServer _configServer;
|
||||
@Inject
|
||||
ServiceOfferingDao _serviceOfferingDao = null;
|
||||
@Inject
|
||||
UserVmDao _userVmDao;
|
||||
@ -2094,7 +2097,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V
|
||||
|
||||
boolean useExtDns = !dnsProvided;
|
||||
/* For backward compatibility */
|
||||
String use_external_dns = _configDao.getValue(Config.UseExternalDnsServers.key());
|
||||
String use_external_dns = _configServer.getConfigValue(Config.UseExternalDnsServers.key(), Config.ConfigurationParameterScope.zone.toString(), dc.getId());
|
||||
if (use_external_dns != null && use_external_dns.equals("true")) {
|
||||
useExtDns = true;
|
||||
}
|
||||
|
||||
@ -16,6 +16,9 @@
|
||||
// under the License.
|
||||
package com.cloud.server;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.configuration.ConfigurationVO;
|
||||
import com.cloud.exception.InternalErrorException;
|
||||
|
||||
/**
|
||||
@ -30,4 +33,6 @@ public interface ConfigurationServer {
|
||||
*/
|
||||
public void persistDefaultValues() throws InternalErrorException;
|
||||
public void updateKeyPairs();
|
||||
public String getConfigValue(String name, String scope, Long resourceId);
|
||||
public List<ConfigurationVO> getConfigListByScope(String scope, Long resourceId);
|
||||
}
|
||||
|
||||
@ -36,28 +36,29 @@ import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.configuration.*;
|
||||
import com.cloud.dc.*;
|
||||
import com.cloud.dc.dao.DcDetailsDao;
|
||||
import com.cloud.user.*;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.cloud.configuration.Config;
|
||||
import com.cloud.configuration.ConfigurationVO;
|
||||
import com.cloud.configuration.Resource;
|
||||
import com.cloud.configuration.Resource.ResourceOwnerType;
|
||||
import com.cloud.configuration.Resource.ResourceType;
|
||||
import com.cloud.configuration.ResourceCountVO;
|
||||
import com.cloud.configuration.dao.ConfigurationDao;
|
||||
import com.cloud.configuration.dao.ResourceCountDao;
|
||||
import com.cloud.dc.DataCenter.NetworkType;
|
||||
import com.cloud.dc.DataCenterVO;
|
||||
import com.cloud.dc.HostPodVO;
|
||||
import com.cloud.dc.VlanVO;
|
||||
import com.cloud.dc.dao.DataCenterDao;
|
||||
import com.cloud.dc.dao.HostPodDao;
|
||||
import com.cloud.dc.dao.VlanDao;
|
||||
@ -91,9 +92,6 @@ import com.cloud.service.dao.ServiceOfferingDao;
|
||||
import com.cloud.storage.DiskOfferingVO;
|
||||
import com.cloud.storage.dao.DiskOfferingDao;
|
||||
import com.cloud.test.IPRangeConfig;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountVO;
|
||||
import com.cloud.user.User;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
import com.cloud.utils.PasswordGenerator;
|
||||
import com.cloud.utils.PropertiesUtil;
|
||||
@ -127,6 +125,11 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio
|
||||
@Inject private ResourceCountDao _resourceCountDao;
|
||||
@Inject private NetworkOfferingServiceMapDao _ntwkOfferingServiceMapDao;
|
||||
@Inject private IdentityDao _identityDao;
|
||||
@Inject private DcDetailsDao _dcDetailsDao;
|
||||
@Inject private ClusterDetailsDao _clusterDetailsDao;
|
||||
@Inject private StoragePoolDetailsDao _storagePoolDetailsDao;
|
||||
@Inject private AccountDetailsDao _accountDetailsDao;
|
||||
|
||||
|
||||
public ConfigurationServerImpl() {
|
||||
setRunLevel(ComponentLifecycle.RUN_LEVEL_FRAMEWORK_BOOTSTRAP);
|
||||
@ -672,6 +675,76 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConfigValue(String name, String scope, Long resourceId) {
|
||||
// If either of scope or resourceId is null then return global config value otherwise return value at the scope
|
||||
Config c = Config.getConfig(name);
|
||||
if (c == null) {
|
||||
throw new CloudRuntimeException("Missing configuration variable " + name + " in configuration table");
|
||||
}
|
||||
String configScope = c.getScope();
|
||||
if (scope != null && !scope.isEmpty()) {
|
||||
if (!configScope.contains(scope)) {
|
||||
throw new CloudRuntimeException("Invalid scope " + scope + " for the parameter " + name );
|
||||
}
|
||||
if (resourceId != null) {
|
||||
switch (Config.ConfigurationParameterScope.valueOf(scope)) {
|
||||
case zone: DataCenterVO zone = _zoneDao.findById(resourceId);
|
||||
if (zone == null) {
|
||||
throw new InvalidParameterValueException("unable to find zone by id " + resourceId);
|
||||
}
|
||||
DcDetailVO dcDetailVO = _dcDetailsDao.findDetail(resourceId, name);
|
||||
if (dcDetailVO != null && dcDetailVO.getValue() != null) {
|
||||
return dcDetailVO.getValue();
|
||||
} break;
|
||||
|
||||
case cluster: ClusterDetailsVO cluster = _clusterDetailsDao.findById(resourceId);
|
||||
if (cluster == null) {
|
||||
throw new InvalidParameterValueException("unable to find cluster by id " + resourceId);
|
||||
}
|
||||
ClusterDetailsVO clusterDetailsVO = _clusterDetailsDao.findDetail(resourceId, name);
|
||||
if (clusterDetailsVO != null && clusterDetailsVO.getValue() != null) {
|
||||
return clusterDetailsVO.getValue();
|
||||
} break;
|
||||
|
||||
case pool: StoragePoolDetailVO pool = _storagePoolDetailsDao.findById(resourceId);
|
||||
if (pool == null) {
|
||||
throw new InvalidParameterValueException("unable to find storage pool by id " + resourceId);
|
||||
}
|
||||
StoragePoolDetailVO storagePoolDetailVO = _storagePoolDetailsDao.findDetail(resourceId, name);
|
||||
if (storagePoolDetailVO != null && storagePoolDetailVO.getValue() != null) {
|
||||
return storagePoolDetailVO.getValue();
|
||||
} break;
|
||||
|
||||
case account: AccountDetailVO account = _accountDetailsDao.findById(resourceId);
|
||||
if (account == null) {
|
||||
throw new InvalidParameterValueException("unable to find account by id " + resourceId);
|
||||
}
|
||||
AccountDetailVO accountDetailVO = _accountDetailsDao.findDetail(resourceId, name);
|
||||
if (accountDetailVO != null && accountDetailVO.getValue() != null) {
|
||||
return accountDetailVO.getValue();
|
||||
} break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
return _configDao.getValue(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConfigurationVO> getConfigListByScope(String scope, Long resourceId) {
|
||||
|
||||
// Getting the list of parameters defined at the scope
|
||||
List<Config> configList = Config.getConfigListByScope(scope);
|
||||
List<ConfigurationVO> configVOList = new ArrayList<ConfigurationVO>();
|
||||
for (Config param:configList){
|
||||
ConfigurationVO configVo = _configDao.findByName(param.toString());
|
||||
configVo.setValue(getConfigValue(param.toString(), scope, resourceId));
|
||||
configVOList.add(configVo);
|
||||
}
|
||||
return configVOList;
|
||||
}
|
||||
|
||||
private void writeKeyToDisk(String key, String keyPath) {
|
||||
File keyfile = new File(keyPath);
|
||||
if (!keyfile.exists()) {
|
||||
|
||||
@ -44,6 +44,7 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.configuration.*;
|
||||
import com.cloud.storage.dao.*;
|
||||
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
@ -106,10 +107,6 @@ import com.cloud.capacity.CapacityVO;
|
||||
import com.cloud.capacity.dao.CapacityDao;
|
||||
import com.cloud.capacity.dao.CapacityDaoImpl.SummedCapacity;
|
||||
import com.cloud.cluster.ClusterManager;
|
||||
import com.cloud.configuration.Config;
|
||||
import com.cloud.configuration.Configuration;
|
||||
import com.cloud.configuration.ConfigurationManager;
|
||||
import com.cloud.configuration.ConfigurationVO;
|
||||
import com.cloud.configuration.dao.ConfigurationDao;
|
||||
import com.cloud.consoleproxy.ConsoleProxyManagementState;
|
||||
import com.cloud.consoleproxy.ConsoleProxyManager;
|
||||
@ -381,6 +378,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
@Inject
|
||||
S3Manager _s3Mgr;
|
||||
|
||||
@Inject
|
||||
ConfigurationServer _configServer;
|
||||
|
||||
private final ScheduledExecutorService _eventExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("EventChecker"));
|
||||
private final ScheduledExecutorService _alertExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("AlertChecker"));
|
||||
private KeystoreManager _ksMgr;
|
||||
@ -1038,6 +1038,22 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
||||
Object name = cmd.getConfigName();
|
||||
Object category = cmd.getCategory();
|
||||
Object keyword = cmd.getKeyword();
|
||||
Long id = cmd.getId();
|
||||
String scope = cmd.getScope();
|
||||
|
||||
if (scope!= null && !scope.isEmpty()) {
|
||||
// getting the list of parameters at requested scope
|
||||
try {
|
||||
Config.ConfigurationParameterScope.valueOf(scope.toLowerCase());
|
||||
} catch (Exception e ) {
|
||||
throw new InvalidParameterValueException("Invalid scope " + scope + " while listing configuration parameters");
|
||||
}
|
||||
if (id == null) {
|
||||
throw new InvalidParameterValueException("Invalid id null, id is needed corresponding to the scope");
|
||||
}
|
||||
List<ConfigurationVO> configList = _configServer.getConfigListByScope(scope, id);
|
||||
return new Pair<List<? extends Configuration>, Integer>(configList, configList.size());
|
||||
}
|
||||
|
||||
if (keyword != null) {
|
||||
SearchCriteria<ConfigurationVO> ssc = _configDao.createSearchCriteria();
|
||||
|
||||
@ -72,4 +72,13 @@ public class StoragePoolDetailsDaoImpl extends GenericDaoBase<StoragePoolDetailV
|
||||
|
||||
return detailsMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoragePoolDetailVO findDetail(long poolId, String name) {
|
||||
SearchCriteria<StoragePoolDetailVO> sc = PoolSearch.create();
|
||||
sc.setParameters("pool", poolId);
|
||||
sc.setParameters("name", name);
|
||||
|
||||
return findOneIncludingRemovedBy(sc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@ import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import com.cloud.configuration.ConfigurationVO;
|
||||
import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
|
||||
import org.apache.cloudstack.api.command.admin.ldap.LDAPConfigCmd;
|
||||
import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd;
|
||||
@ -425,9 +426,9 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu
|
||||
* @see com.cloud.configuration.ConfigurationManager#updateConfiguration(long, java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void updateConfiguration(long userId, String name, String category, String value) {
|
||||
public void updateConfiguration(long userId, String name, String category, String value, String scope, Long resourceId) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
||||
85
test/integration/smoke/test_UpdateCfg.py
Normal file
85
test/integration/smoke/test_UpdateCfg.py
Normal file
@ -0,0 +1,85 @@
|
||||
# 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.
|
||||
""" P1 tests for updating the granular Configuration parameter with scope and resource id provided.
|
||||
"""
|
||||
#Import Local Modules
|
||||
import marvin
|
||||
from marvin.cloudstackTestCase import *
|
||||
from marvin.cloudstackAPI import *
|
||||
from marvin.remoteSSHClient import remoteSSHClient
|
||||
from marvin.integration.lib.utils import *
|
||||
from marvin.integration.lib.base import *
|
||||
from marvin.integration.lib.common import *
|
||||
from nose.plugins.attrib import attr
|
||||
#Import System modules
|
||||
import unittest
|
||||
import hashlib
|
||||
import random
|
||||
|
||||
class TestUpdateConfigWithScope(cloudstackTestCase):
|
||||
"""
|
||||
This test updates the value of a configuration parameter
|
||||
which is at zone level(scope)
|
||||
"""
|
||||
def setUp(self):
|
||||
"""
|
||||
CloudStack internally saves its passwords in md5 form and that is how we
|
||||
specify it in the API. Python's hashlib library helps us to quickly hash
|
||||
strings as follows
|
||||
"""
|
||||
mdf = hashlib.md5()
|
||||
mdf.update('password')
|
||||
mdf_pass = mdf.hexdigest()
|
||||
|
||||
self.apiClient = self.testClient.getApiClient() #Get ourselves an API client
|
||||
|
||||
|
||||
|
||||
def test_UpdateConfigParamWithScope(self):
|
||||
|
||||
updateConfigurationCmd = updateConfiguration.updateConfigurationCmd()
|
||||
updateConfigurationCmd.name = "use.external.dns"
|
||||
updateConfigurationCmd.value = "true"
|
||||
updateConfigurationCmd.scope = "zone"
|
||||
updateConfigurationCmd.id = 1
|
||||
|
||||
updateConfigurationResponse = self.apiClient.updateConfiguration(updateConfigurationCmd)
|
||||
self.debug("updated the parameter %s with value %s"%(updateConfigurationResponse.name, updateConfigurationResponse.value))
|
||||
|
||||
listConfigurationsCmd = listConfigurations.listConfigurationsCmd()
|
||||
listConfigurationsCmd.cfgName = updateConfigurationResponse.name
|
||||
listConfigurationsCmd.scope = "zone"
|
||||
listConfigurationsCmd.id = 1
|
||||
listConfigurationsResponse = self.apiClient.listConfigurations(listConfigurationsCmd)
|
||||
|
||||
self.assertNotEqual(len(listConfigurationsResponse), 0, "Check if the list API \
|
||||
returns a non-empty response")
|
||||
|
||||
configParam = listConfigurationsResponse[0]
|
||||
|
||||
self.assertEqual(configParam.value, updateConfigurationResponse.value, "Check if the update API returned \
|
||||
is the same as the one we got in the list API")
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
|
||||
updateConfigurationCmd = updateConfiguration.updateConfigurationCmd()
|
||||
updateConfigurationCmd.name = "use.external.dns"
|
||||
updateConfigurationCmd.value = "false"
|
||||
updateConfigurationCmd.scope = "zone"
|
||||
updateConfigurationCmd.id = 1
|
||||
self.apiClient.updateConfiguration(updateConfigurationCmd)
|
||||
Loading…
x
Reference in New Issue
Block a user