config: fix ManagementServer scope

Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
Abhishek Kumar 2025-02-19 17:20:26 +05:30
parent 00d1dbc363
commit fb82ca3c91
13 changed files with 275 additions and 8 deletions

View File

@ -19,23 +19,24 @@ package org.apache.cloudstack.api.command.admin.config;
import java.util.ArrayList;
import java.util.List;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.ClusterResponse;
import org.apache.cloudstack.api.response.ConfigurationResponse;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ImageStoreResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ManagementServerResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.config.Configuration;
import org.apache.commons.lang3.StringUtils;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.utils.Pair;
@ -94,6 +95,13 @@ public class ListCfgsByCmd extends BaseListCmd {
description = "The ID of the Image Store to update the parameter value for corresponding image store")
private Long imageStoreId;
@Parameter(name = ApiConstants.MANAGEMENT_SERVER_ID,
type = CommandType.UUID,
entityType = ManagementServerResponse.class,
description = "the ID of the Management Server to update the parameter value for corresponding management server",
since = "4.23.0")
private Long managementServerId;
@Parameter(name = ApiConstants.GROUP, type = CommandType.STRING, description = "Lists configuration by group name (primarily used for UI)", since = "4.18.0")
private String groupName;
@ -139,6 +147,10 @@ public class ListCfgsByCmd extends BaseListCmd {
return imageStoreId;
}
public Long getManagementServerId() {
return managementServerId;
}
public String getGroupName() {
return groupName;
}
@ -200,6 +212,9 @@ public class ListCfgsByCmd extends BaseListCmd {
if (getImageStoreId() != null){
cfgResponse.setScope("imagestore");
}
if (getManagementServerId() != null){
cfgResponse.setScope("managementserver");
}
}
@Override

View File

@ -24,6 +24,7 @@ import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ImageStoreResponse;
import org.apache.cloudstack.api.response.ManagementServerResponse;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.api.response.AccountResponse;
@ -84,6 +85,13 @@ public class ResetCfgCmd extends BaseCmd {
description = "The ID of the Image Store to reset the parameter value for corresponding image store")
private Long imageStoreId;
@Parameter(name = ApiConstants.MANAGEMENT_SERVER_ID,
type = CommandType.UUID,
entityType = ManagementServerResponse.class,
description = "the ID of the Management Server to update the parameter value for corresponding management server",
since = "4.23.0")
private Long managementServerId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -116,6 +124,10 @@ public class ResetCfgCmd extends BaseCmd {
return imageStoreId;
}
public Long getManagementServerId() {
return managementServerId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@ -149,6 +161,9 @@ public class ResetCfgCmd extends BaseCmd {
if (getImageStoreId() != null) {
response.setScope(ConfigKey.Scope.ImageStore.name());
}
if (getManagementServerId() != null) {
response.setScope(ConfigKey.Scope.ManagementServer.name());
}
response.setValue(cfg.second());
this.setResponseObject(response);
} else {

View File

@ -30,6 +30,7 @@ import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.ClusterResponse;
import org.apache.cloudstack.api.response.ConfigurationResponse;
import org.apache.cloudstack.api.response.ImageStoreResponse;
import org.apache.cloudstack.api.response.ManagementServerResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.config.Configuration;
@ -88,6 +89,13 @@ public class UpdateCfgCmd extends BaseCmd {
validations = ApiArgValidator.PositiveNumber)
private Long imageStoreId;
@Parameter(name = ApiConstants.MANAGEMENT_SERVER_ID,
type = CommandType.UUID,
entityType = ManagementServerResponse.class,
description = "the ID of the Management Server to update the parameter value for corresponding management server",
since = "4.23.0")
private Long managementServerId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -112,7 +120,7 @@ public class UpdateCfgCmd extends BaseCmd {
return clusterId;
}
public Long getStoragepoolId() {
public Long getStoragePoolId() {
return storagePoolId;
}
@ -128,6 +136,10 @@ public class UpdateCfgCmd extends BaseCmd {
return imageStoreId;
}
public Long getManagementServerId() {
return managementServerId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@ -182,7 +194,7 @@ public class UpdateCfgCmd extends BaseCmd {
if (getClusterId() != null) {
response.setScope("cluster");
}
if (getStoragepoolId() != null) {
if (getStoragePoolId() != null) {
response.setScope("storagepool");
}
if (getAccountId() != null) {

View File

@ -116,6 +116,7 @@
<bean id="loadBalancerVMMapDaoImpl" class="com.cloud.network.dao.LoadBalancerVMMapDaoImpl" />
<bean id="loadBalancerCertMapDaoImpl" class="com.cloud.network.dao.LoadBalancerCertMapDaoImpl" />
<bean id="managementServerHostDaoImpl" class="com.cloud.cluster.dao.ManagementServerHostDaoImpl" />
<bean id="managementServerHostDetailsDaoImpl" class="com.cloud.cluster.dao.ManagementServerHostDetailsDaoImpl" />
<bean id="managementServerHostPeerDaoImpl" class="com.cloud.cluster.dao.ManagementServerHostPeerDaoImpl" />
<bean id="managementServerHostPeerJoinDaoImpl" class="com.cloud.cluster.dao.ManagementServerHostPeerJoinDaoImpl" />
<bean id="managementServerStatusDaoImpl" class="com.cloud.cluster.dao.ManagementServerStatusDaoImpl" />

View File

@ -118,6 +118,18 @@ CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc_offerings','conserve_mode', 'tin
--- Disable/enable NICs
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.nics','enabled', 'TINYINT(1) NOT NULL DEFAULT 1 COMMENT ''Indicates whether the NIC is enabled or not'' ');
-- Add management_server_details table to allow ManagementServer scope configs
CREATE TABLE IF NOT EXISTS `management_server_details` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`management_server_id` bigint unsigned NOT NULL COMMENT 'management server the detail is related to',
`name` varchar(255) NOT NULL COMMENT 'name of the detail',
`value` varchar(255) NOT NULL,
`display` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'True if the detail can be displayed to the end user',
PRIMARY KEY (`id`),
CONSTRAINT `fk_management_server_details__management_server_id` FOREIGN KEY `fk_management_server_details__management_server_id`(`management_server_id`) REFERENCES `mshost`(`id`) ON DELETE CASCADE,
KEY `i_management_server_details__name__value` (`name`(128),`value`(128))
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Add checkpoint tracking fields to backups table for incremental backup support
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.backups', 'from_checkpoint_id', 'VARCHAR(255) DEFAULT NULL COMMENT "Previous active checkpoint id for incremental backups"');
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.backups', 'to_checkpoint_id', 'VARCHAR(255) DEFAULT NULL COMMENT "New checkpoint id created for the next incremental backup"');

View File

@ -48,6 +48,12 @@
<artifactId>cloud-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-schema</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,87 @@
// 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.cluster;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.apache.cloudstack.api.ResourceDetail;
@Entity
@Table(name = "management_server_details")
public class ManagementServerHostDetailVO implements ResourceDetail {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
long id;
@Column(name = "management_server_id")
long resourceId;
@Column(name = "name")
String name;
@Column(name = "value")
String value;
@Column(name = "display")
private boolean display = true;
public ManagementServerHostDetailVO(long poolId, String name, String value, boolean display) {
this.resourceId = poolId;
this.name = name;
this.value = value;
this.display = display;
}
public ManagementServerHostDetailVO() {
}
@Override
public long getId() {
return id;
}
@Override
public long getResourceId() {
return resourceId;
}
@Override
public String getName() {
return name;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String getValue() {
return value;
}
@Override
public boolean isDisplay() {
return display;
}
}

View File

@ -0,0 +1,27 @@
// 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.cluster.dao;
import org.apache.cloudstack.resourcedetail.ResourceDetailsDao;
import com.cloud.cluster.ManagementServerHostDetailVO;
import com.cloud.utils.db.GenericDao;
public interface ManagementServerHostDetailsDao extends GenericDao<ManagementServerHostDetailVO, Long>, ResourceDetailsDao<ManagementServerHostDetailVO> {
}

View File

@ -0,0 +1,46 @@
// 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.cluster.dao;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.ScopedConfigStorage;
import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
import com.cloud.cluster.ManagementServerHostDetailVO;
public class ManagementServerHostDetailsDaoImpl extends ResourceDetailsDaoBase<ManagementServerHostDetailVO> implements ManagementServerHostDetailsDao, ScopedConfigStorage {
public ManagementServerHostDetailsDaoImpl() {
}
@Override
public ConfigKey.Scope getScope() {
return ConfigKey.Scope.ManagementServer;
}
@Override
public String getConfigValue(long id, String key) {
ManagementServerHostDetailVO vo = findDetail(id, key);
return vo == null ? null : vo.getValue();
}
@Override
public void addDetail(long resourceId, String key, String value, boolean display) {
super.addDetail(new ManagementServerHostDetailVO(resourceId, key, value, display));
}
}

View File

@ -160,6 +160,9 @@ import com.cloud.api.query.dao.NetworkOfferingJoinDao;
import com.cloud.api.query.vo.NetworkOfferingJoinVO;
import com.cloud.capacity.CapacityManager;
import com.cloud.capacity.dao.CapacityDao;
import com.cloud.cluster.ManagementServerHostVO;
import com.cloud.cluster.dao.ManagementServerHostDao;
import com.cloud.cluster.dao.ManagementServerHostDetailsDao;
import com.cloud.configuration.Resource.ResourceType;
import com.cloud.dc.AccountVlanMapVO;
import com.cloud.dc.ClusterDetailsDao;
@ -469,6 +472,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
@Inject
ImageStoreDetailsDao _imageStoreDetailsDao;
@Inject
ManagementServerHostDao managementServerHostDao;
@Inject
ManagementServerHostDetailsDao managementServerHostDetailsDao;
@Inject
MessageBus messageBus;
@Inject
AgentManager _agentManager;
@ -885,6 +892,13 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
}
break;
case ManagementServer:
final ManagementServerHostVO managementServer = managementServerHostDao.findById(resourceId);
Preconditions.checkState(managementServer != null);
resourceType = ApiCommandResourceType.ManagementServer;
managementServerHostDetailsDao.addDetail(resourceId, name, value, true);
break;
default:
throw new InvalidParameterValueException("Scope provided is invalid");
}
@ -1032,8 +1046,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
String value = cmd.getValue();
final Long zoneId = cmd.getZoneId();
final Long clusterId = cmd.getClusterId();
final Long storagepoolId = cmd.getStoragepoolId();
final Long storagepoolId = cmd.getStoragePoolId();
final Long imageStoreId = cmd.getImageStoreId();
final Long managementServerId = cmd.getManagementServerId();
Long accountId = cmd.getAccountId();
Long domainId = cmd.getDomainId();
// check if config value exists
@ -1113,6 +1128,11 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
id = imageStoreId;
paramCountCheck++;
}
if (managementServerId != null) {
scope = ConfigKey.Scope.ManagementServer.toString();
id = managementServerId;
paramCountCheck++;
}
if (paramCountCheck > 1) {
throw new InvalidParameterValueException("cannot handle multiple IDs, provide only one ID corresponding to the scope");
@ -1168,6 +1188,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
final Long accountId = cmd.getAccountId();
final Long domainId = cmd.getDomainId();
final Long imageStoreId = cmd.getImageStoreId();
final Long managementServerId = cmd.getManagementServerId();
ConfigKey<?> configKey = null;
Optional optionalValue;
String defaultValue;
@ -1201,6 +1222,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
scopeMap.put(ConfigKey.Scope.Account.toString(), accountId);
scopeMap.put(ConfigKey.Scope.StoragePool.toString(), storagepoolId);
scopeMap.put(ConfigKey.Scope.ImageStore.toString(), imageStoreId);
scopeMap.put(ConfigKey.Scope.ManagementServer.toString(), managementServerId);
ParamCountPair paramCountPair = getParamCount(scopeMap);
id = paramCountPair.getId();
@ -1297,6 +1319,16 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
newValue = optionalValue.isPresent() ? optionalValue.get().toString() : defaultValue;
break;
case ManagementServer:
final ManagementServerHostVO managementServer = managementServerHostDao.findById(id);
if (managementServer == null) {
throw new InvalidParameterValueException("unable to find management server by id " + id);
}
managementServerHostDetailsDao.removeDetail(id, name);
optionalValue = Optional.ofNullable(configKey != null ? configKey.valueIn(id) : config.getValue());
newValue = optionalValue.isPresent() ? optionalValue.get().toString() : defaultValue;
break;
default:
if (!_configDao.update(name, category, defaultValue)) {
logger.error("Failed to reset configuration option, name: {}, defaultValue: {}", name, defaultValue);

View File

@ -2362,6 +2362,7 @@ public class ManagementServerImpl extends MutualExclusiveIdsManagerBase implemen
final Long clusterId = cmd.getClusterId();
final Long storagepoolId = cmd.getStoragepoolId();
final Long imageStoreId = cmd.getImageStoreId();
final Long managementServerId = cmd.getManagementServerId();
Long accountId = cmd.getAccountId();
Long domainId = cmd.getDomainId();
final String groupName = cmd.getGroupName();
@ -2415,6 +2416,11 @@ public class ManagementServerImpl extends MutualExclusiveIdsManagerBase implemen
id = imageStoreId;
paramCountCheck++;
}
if (managementServerId != null) {
scope = ConfigKey.Scope.ManagementServer;
id = managementServerId;
paramCountCheck++;
}
if (paramCountCheck > 1) {
throw new InvalidParameterValueException("cannot handle multiple IDs, provide only one ID corresponding to the scope");

View File

@ -87,6 +87,7 @@ export default {
}
},
created () {
console.log('---------------', this.$route.meta.name)
switch (this.$route.meta.name) {
case 'account':
this.scopeKey = 'accountid'
@ -106,6 +107,9 @@ export default {
case 'imagestore':
this.scopeKey = 'imagestoreuuid'
break
case 'managementserver':
this.scopeKey = 'managementserverid'
break
default:
this.scopeKey = ''
}

View File

@ -39,6 +39,10 @@ export default {
name: 'details',
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
},
{
name: 'settings',
component: shallowRef(defineAsyncComponent(() => import('@/components/view/SettingsTab.vue')))
},
{
name: 'management.server.peers',
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/ManagementServerPeerTab.vue')))