diff --git a/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java b/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java index 78d189c3bf1d..9ed2df1d79b8 100644 --- a/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java +++ b/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java @@ -26,6 +26,7 @@ import org.apache.cloudstack.api.command.user.backup.ListBackupOfferingsCmd; import org.apache.cloudstack.api.command.user.backup.ListBackupsCmd; import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.ValidatedConfigKey; import org.apache.cloudstack.framework.config.Configurable; import com.cloud.utils.Pair; @@ -42,10 +43,11 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer "false", "Is backup and recovery framework enabled.", false, ConfigKey.Scope.Zone); - ConfigKey BackupProviderPlugin = new ConfigKey<>("Advanced", String.class, + ConfigKey BackupProviderPlugin = new ValidatedConfigKey<>("Advanced", String.class, "backup.framework.provider.plugin", "dummy", - "The backup and recovery provider plugin.", true, ConfigKey.Scope.Zone, BackupFrameworkEnabled.key()); + "The backup and recovery provider plugin. Valid plugin values: dummy, veeam, networker and nas", + true, ConfigKey.Scope.Zone, BackupFrameworkEnabled.key(), value -> validateBackupProviderConfig((String)value)); ConfigKey BackupSyncPollingInterval = new ConfigKey<>("Advanced", Long.class, "backup.framework.sync.interval", @@ -148,4 +150,14 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer boolean deleteBackup(final Long backupId, final Boolean forced); BackupOffering updateBackupOffering(UpdateBackupOfferingCmd updateBackupOfferingCmd); + + static void validateBackupProviderConfig(String value) { + if (value != null && (value.contains(",") || value.trim().contains(" "))) { + throw new IllegalArgumentException("Multiple backup provider plugins are not supported. Please provide a single plugin value."); + } + List validPlugins = List.of("dummy", "veeam", "networker", "nas"); + if (value != null && !validPlugins.contains(value.toLowerCase())) { + throw new IllegalArgumentException("Invalid backup provider plugin: " + value + ". Valid plugin values are: " + String.join(", ", validPlugins)); + } + } } diff --git a/framework/config/src/main/java/org/apache/cloudstack/framework/config/ValidatedConfigKey.java b/framework/config/src/main/java/org/apache/cloudstack/framework/config/ValidatedConfigKey.java new file mode 100644 index 000000000000..4fcbe4151d30 --- /dev/null +++ b/framework/config/src/main/java/org/apache/cloudstack/framework/config/ValidatedConfigKey.java @@ -0,0 +1,38 @@ +// 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.framework.config; + +import java.util.function.Consumer; + +public class ValidatedConfigKey extends ConfigKey { + private final Consumer validator; + + public ValidatedConfigKey(String category, Class type, String name, String defaultValue, String description, boolean dynamic, Scope scope, String parent, Consumer validator) { + super(category, type, name, defaultValue, description, dynamic, scope, parent); + this.validator = validator; + } + + public Consumer getValidator() { + return validator; + } + + public void validateValue(String value) { + if (validator != null) { + validator.accept((T) value); + } + } +} diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 3a4bdf8afec5..eb138bb10b00 100644 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -107,6 +107,7 @@ import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; +import org.apache.cloudstack.framework.config.ValidatedConfigKey; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.config.dao.ConfigurationGroupDao; import org.apache.cloudstack.framework.config.dao.ConfigurationSubGroupDao; @@ -716,6 +717,12 @@ public String updateConfiguration(final long userId, final String name, final St throw new InvalidParameterValueException(validationMsg); } + ConfigKey configKey = _configDepot.get(name); + if (configKey instanceof ValidatedConfigKey) { + ValidatedConfigKey validatedConfigKey = (ValidatedConfigKey) configKey; + validatedConfigKey.validateValue(value); + } + // 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 diff --git a/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java b/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java index dc2677a507f0..49fdc4e68814 100644 --- a/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java @@ -972,10 +972,11 @@ public BackupProvider getBackupProvider(final String name) { if (StringUtils.isEmpty(name)) { throw new CloudRuntimeException("Invalid backup provider name provided"); } - if (!backupProvidersMap.containsKey(name)) { + String[] backupProviderNames = name.split(","); + if (!backupProvidersMap.containsKey(backupProviderNames[0])) { throw new CloudRuntimeException("Failed to find backup provider by the name: " + name); } - return backupProvidersMap.get(name); + return backupProvidersMap.get(backupProviderNames[0]); } @Override