@@ -477,9 +477,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
477477
478478 private long _defaultPageSize = Long .parseLong (Config .DefaultPageSize .getDefaultValue ());
479479 private static final String DOMAIN_NAME_PATTERN = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\ .)+[A-Za-z]{1,63}$" ;
480- private Set <String > configValuesForValidation = new HashSet <String >();
481- private Set <String > weightBasedParametersForValidation = new HashSet <String >();
482- private Set <String > overprovisioningFactorsForValidation = new HashSet <String >();
480+ private Set <String > configValuesForValidation = new HashSet <>();
481+ private Set <String > weightBasedParametersForValidation = new HashSet <>();
482+ private Set <String > overprovisioningFactorsForValidation = new HashSet <>();
483483
484484 public static final ConfigKey <Boolean > SystemVMUseLocalStorage = new ConfigKey <Boolean >(Boolean .class , "system.vm.use.local.storage" , "Advanced" , "false" ,
485485 "Indicates whether to use local storage pools or shared storage pools for system VMs." , false , ConfigKey .Scope .Zone , null );
@@ -577,7 +577,7 @@ protected void populateConfigValuesForValidationSet() {
577577 configValuesForValidation .add (UnmanagedVMsManager .ConvertVmwareInstanceToKvmTimeout .key ());
578578 }
579579
580- private void weightBasedParametersForValidation () {
580+ protected void weightBasedParametersForValidation () {
581581 weightBasedParametersForValidation .add (AlertManager .CPUCapacityThreshold .key ());
582582 weightBasedParametersForValidation .add (AlertManager .StorageAllocatedCapacityThreshold .key ());
583583 weightBasedParametersForValidation .add (AlertManager .StorageCapacityThreshold .key ());
@@ -599,7 +599,7 @@ private void weightBasedParametersForValidation() {
599599 weightBasedParametersForValidation .add (ClusterDrsService .ClusterDrsImbalanceSkipThreshold .key ());
600600 }
601601
602- private void overProvisioningFactorsForValidation () {
602+ protected void overProvisioningFactorsForValidation () {
603603 overprovisioningFactorsForValidation .add (CapacityManager .MemOverprovisioningFactor .key ());
604604 overprovisioningFactorsForValidation .add (CapacityManager .CpuOverprovisioningFactor .key ());
605605 overprovisioningFactorsForValidation .add (CapacityManager .StorageOverprovisioningFactor .key ());
@@ -649,7 +649,7 @@ protected void validateIpAddressRelatedConfigValues(final String configName, fin
649649 }
650650 }
651651 if (err ) {
652- throw new InvalidParameterValueException ("Invalid IP address value(s) specified for the config value" );
652+ throw new InvalidParameterValueException ("Invalid IP address value(s) specified for the config value. " );
653653 }
654654 }
655655
@@ -691,9 +691,8 @@ public boolean stop() {
691691 @ DB
692692 public String updateConfiguration (final long userId , final String name , final String category , String value , final String scope , final Long resourceId ) {
693693 final String validationMsg = validateConfigurationValue (name , value , scope );
694-
695694 if (validationMsg != null ) {
696- logger .error ("Invalid configuration option, name: " + name + ", value:" + value );
695+ logger .error ("Invalid value [{}] for configuration [{}] due to [{}]. " , value , name , validationMsg );
697696 throw new InvalidParameterValueException (validationMsg );
698697 }
699698
@@ -956,8 +955,6 @@ public Configuration updateConfiguration(final UpdateCfgCmd cmd) throws InvalidP
956955 category = config .getCategory ();
957956 }
958957
959- validateIpAddressRelatedConfigValues (name , value );
960-
961958 if (value == null ) {
962959 return _configDao .findByName (name );
963960 }
@@ -1192,14 +1189,21 @@ public Pair<Configuration, String> resetConfiguration(final ResetCfgCmd cmd) thr
11921189 return new Pair <Configuration , String >(_configDao .findByName (name ), newValue );
11931190 }
11941191
1195- protected String validateConfigurationValue (final String name , String value , final String scope ) {
1192+ /**
1193+ * Validates whether a value is valid for the specified configuration. This includes type and range validation.
1194+ * @param name name of the configuration.
1195+ * @param value value to validate.
1196+ * @param scope scope of the configuration.
1197+ * @return null if the value is valid; otherwise, returns an error message.
1198+ */
1199+ protected String validateConfigurationValue (String name , String value , String scope ) {
11961200 final ConfigurationVO cfg = _configDao .findByName (name );
11971201 if (cfg == null ) {
11981202 logger .error ("Missing configuration variable " + name + " in configuration table" );
11991203 return "Invalid configuration variable." ;
12001204 }
12011205
1202- final String configScope = cfg .getScope ();
1206+ String configScope = cfg .getScope ();
12031207 if (scope != null ) {
12041208 if (!configScope .contains (scope ) &&
12051209 !(ENABLE_ACCOUNT_SETTINGS_FOR_DOMAIN .value () && configScope .contains (ConfigKey .Scope .Account .toString ()) &&
@@ -1208,11 +1212,11 @@ protected String validateConfigurationValue(final String name, String value, fin
12081212 return "Invalid scope id provided for the parameter " + name ;
12091213 }
12101214 }
1211- Class <?> type = null ;
1212- final Config configuration = Config .getConfig (name );
1215+ Class <?> type ;
1216+ Config configuration = Config .getConfig (name );
12131217 if (configuration == null ) {
12141218 logger .warn ("Did not find configuration " + name + " in Config.java. Perhaps moved to ConfigDepot" );
1215- final ConfigKey <?> configKey = _configDepot .get (name );
1219+ ConfigKey <?> configKey = _configDepot .get (name );
12161220 if (configKey == null ) {
12171221 logger .warn ("Did not find configuration " + name + " in ConfigDepot too." );
12181222 return null ;
@@ -1221,144 +1225,161 @@ protected String validateConfigurationValue(final String name, String value, fin
12211225 } else {
12221226 type = configuration .getType ();
12231227 }
1224- //no need to validate further if a
1225- //config can have null value.
1226- String errMsg = null ;
1227- try {
1228- if (type .equals (Integer .class )) {
1229- errMsg = "There was error in trying to parse value: " + value + ". Please enter a valid integer value for parameter " + name ;
1230- Integer .parseInt (value );
1231- } else if (type .equals (Float .class )) {
1232- errMsg = "There was error in trying to parse value: " + value + ". Please enter a valid float value for parameter " + name ;
1233- Float .parseFloat (value );
1234- } else if (type .equals (Long .class )) {
1235- errMsg = "There was error in trying to parse value: " + value + ". Please enter a valid long value for parameter " + name ;
1236- Long .parseLong (value );
1237- }
1238- } catch (final Exception e ) {
1239- // catching generic exception as some throws NullPointerException and some throws NumberFormatExcpeion
1240- logger .error (errMsg );
1241- return errMsg ;
1228+
1229+ boolean isTypeValid = validateValueType (value , type );
1230+ if (!isTypeValid ) {
1231+ return String .format ("Value [%s] is not a valid [%s]." , value , type );
12421232 }
12431233
1244- if (value == null ) {
1245- if (type .equals (Boolean .class )) {
1246- return "Please enter either 'true' or 'false'." ;
1247- }
1248- if (overprovisioningFactorsForValidation .contains (name )) {
1249- final String msg = "value cannot be null for the parameter " + name ;
1250- logger .error (msg );
1251- return msg ;
1252- }
1253- return null ;
1234+ return validateValueRange (name , value , type , configuration );
1235+ }
1236+
1237+ /**
1238+ * Returns whether a value is valid for a configuration of the provided type.
1239+ * Valid configuration values are:
1240+ *
1241+ * <ul>
1242+ * <li>String: any value, including null;</li>
1243+ * <li>Character: any value, including null;</li>
1244+ * <li>Boolean: strings that equal "true" or "false" (case-sensitive);</li>
1245+ * <li>Integer, Short, Long: strings that contain a valid int/short/long;</li>
1246+ * <li>Float, Double: strings that contain a valid float/double, except infinity.</li>
1247+ * </ul>
1248+ *
1249+ * If a type isn't listed here, then the value will be considered invalid.
1250+ * @param value value to validate.
1251+ * @param type type of the configuration.
1252+ * @return boolean indicating whether the value is valid.
1253+ */
1254+ protected boolean validateValueType (String value , Class <?> type ) {
1255+ if (type == String .class || type == Character .class ) {
1256+ return true ;
12541257 }
12551258
1256- value = value .trim ();
12571259 try {
1258- if (overprovisioningFactorsForValidation .contains (name ) && Float .parseFloat (value ) <= 0f ) {
1259- final String msg = name + " should be greater than 0" ;
1260- logger .error (msg );
1261- throw new InvalidParameterValueException (msg );
1260+ if (type == Boolean .class ) {
1261+ return value .equals ("true" ) || value .equals ("false" );
1262+ } else if (type == Integer .class ) {
1263+ Integer .parseInt (value );
1264+ } else if (type == Long .class ) {
1265+ Long .parseLong (value );
1266+ } else if (type == Short .class ) {
1267+ Short .parseShort (value );
1268+ } else if (type == Float .class ) {
1269+ float floatValue = Float .parseFloat (value );
1270+ return !Float .isInfinite (floatValue );
1271+ } else if (type == Double .class ) {
1272+ double doubleValue = Double .parseDouble (value );
1273+ return !Double .isInfinite (doubleValue );
1274+ } else {
1275+ return false ;
12621276 }
1263- } catch (final NumberFormatException e ) {
1264- final String msg = "There was an error trying to parse the float value for: " + name ;
1265- logger .error (msg );
1266- throw new InvalidParameterValueException (msg );
1277+ return true ;
1278+ } catch (NullPointerException | NumberFormatException e ) {
1279+ return false ;
12671280 }
1281+ }
12681282
1269- if (type .equals (Boolean .class )) {
1270- if (!(value .equals ("true" ) || value .equals ("false" ))) {
1271- logger .error ("Configuration variable " + name + " is expecting true or false instead of " + value );
1272- return "Please enter either 'true' or 'false'." ;
1283+ /**
1284+ * If the specified configuration contains a range, validates if the value is in that range. If it doesn't contain
1285+ * a range, any value is considered valid.
1286+ * The value must be previously checked by `validateValueType` so there aren't casting exceptions here.
1287+ * @param name name of the configuration.
1288+ * @param value value to validate.
1289+ * @param type type of the value.
1290+ * @param configuration if the configuration uses Config instead of ConfigKey, the Config object; null otherwise.
1291+ * @return if the value is valid, returns null; if not, returns an error message.
1292+ */
1293+ protected String validateValueRange (String name , String value , Class <?> type , Config configuration ) {
1294+ if (type .equals (Float .class )) {
1295+ Float val = Float .parseFloat (value );
1296+ if (overprovisioningFactorsForValidation .contains (name ) && val <= 0f ) {
1297+ return String .format ("Value for configuration [%s] should be greater than 0." , name );
1298+ } else if (weightBasedParametersForValidation .contains (name ) && (val < 0f || val > 1f )) {
1299+ return String .format ("Please enter a value between 0 and 1 for the configuration parameter: [%s]." , name );
12731300 }
1274- return null ;
12751301 }
12761302
12771303 if (type .equals (Integer .class )) {
1278- try {
1279- final int val = Integer .parseInt (value );
1280- if (NetworkModel .MACIdentifier .key ().equalsIgnoreCase (name )) {
1281- //The value need to be between 0 to 255 because the mac generation needs a value of 8 bit
1282- //0 value is considered as disable.
1283- if (val < 0 || val > 255 ){
1284- throw new InvalidParameterValueException (name + " value should be between 0 and 255. 0 value will disable this feature" );
1285- }
1304+ int val = Integer .parseInt (value );
1305+ if (NetworkModel .MACIdentifier .key ().equalsIgnoreCase (name )) {
1306+ // The value needs to be between 0 to 255 because the MAC generation needs a value of 8 bits
1307+ // 0 is considered as disabled.
1308+ if (val < 0 || val > 255 ){
1309+ return String .format ("[%s] value should be between 0 and 255. 0 value will disable this feature." , name );
12861310 }
1287-
1288- if (UnmanagedVMsManager .ThreadsOnMSToImportVMwareVMFiles .key ().equalsIgnoreCase (name ) || UnmanagedVMsManager . ThreadsOnKVMHostToImportVMwareVMFiles . key (). equalsIgnoreCase ( name )) {
1289- if ( val > 10 ) {
1290- throw new InvalidParameterValueException ( "Please enter a value between 0 and 10 for the configuration parameter: " + name + ", -1 will disable it" );
1291- }
1311+ }
1312+ if (UnmanagedVMsManager .ThreadsOnMSToImportVMwareVMFiles .key ().equalsIgnoreCase (name ) ||
1313+ UnmanagedVMsManager . ThreadsOnKVMHostToImportVMwareVMFiles . key (). equalsIgnoreCase ( name ) ) {
1314+ if ( val < -1 || val > 10 ) {
1315+ return String . format ( "Please enter a value between -1 and 10 for the configuration parameter: [%s]. -1 will disable it." , name );
12921316 }
1293-
1294- if (configValuesForValidation .contains (name )) {
1295- if (val <= 0 ) {
1296- throw new InvalidParameterValueException ("Please enter a positive value for the configuration parameter:" + name );
1297- }
1298- if ("vm.password.length" .equalsIgnoreCase (name ) && val < 6 ) {
1299- throw new InvalidParameterValueException ("Please enter a value greater than 5 for the configuration parameter:" + name );
1300- }
1301- if ("remote.access.vpn.psk.length" .equalsIgnoreCase (name )) {
1302- if (val < 8 ) {
1303- throw new InvalidParameterValueException ("Please enter a value greater than 7 for the configuration parameter:" + name );
1304- }
1305- if (val > 256 ) {
1306- throw new InvalidParameterValueException ("Please enter a value less than 257 for the configuration parameter:" + name );
1307- }
1308- }
1309- if (UserDataManager .VM_USERDATA_MAX_LENGTH_STRING .equalsIgnoreCase (name )) {
1310- if (val > 1048576 ) {
1311- throw new InvalidParameterValueException ("Please enter a value less than 1048576 for the configuration parameter:" + name );
1312- }
1313- }
1317+ } else if (configValuesForValidation .contains (name )) {
1318+ if (val <= 0 ) {
1319+ return String .format ("Please enter a positive value for the configuration parameter: [%s]." , name );
13141320 }
1315- } catch (final NumberFormatException e ) {
1316- logger .error ("There was an error trying to parse the integer value for configuration parameter: " + name );
1317- throw new InvalidParameterValueException ("There was an error trying to parse the integer value for configuration parameter: " + name );
1318- }
1319- }
1320-
1321- if (type .equals (Float .class )) {
1322- try {
1323- final Float val = Float .parseFloat (value );
1324- if (weightBasedParametersForValidation .contains (name ) && (val < 0f || val > 1f )) {
1325- throw new InvalidParameterValueException ("Please enter a value between 0 and 1 for the configuration parameter: " + name );
1321+ if ("vm.password.length" .equalsIgnoreCase (name ) && val < 6 ) {
1322+ return String .format ("Please enter a value greater than 5 for the configuration parameter: [%s]." , name );
1323+ }
1324+ if ("remote.access.vpn.psk.length" .equalsIgnoreCase (name ) && (val < 8 || val > 256 )) {
1325+ return String .format ("Please enter a value greater than 7 and less than 257 for the configuration parameter: [%s]." , name );
1326+ }
1327+ if (UserDataManager .VM_USERDATA_MAX_LENGTH_STRING .equalsIgnoreCase (name ) && val > 1048576 ) {
1328+ return String .format ("Please enter a value less than 1048577 for the configuration parameter: [%s]." , name );
13261329 }
1327- } catch (final NumberFormatException e ) {
1328- logger .error ("There was an error trying to parse the float value for configuration parameter: " + name );
1329- throw new InvalidParameterValueException ("There was an error trying to parse the float value for configuration parameter: " + name );
13301330 }
13311331 }
13321332
13331333 if (type .equals (String .class )) {
1334- if (name . equalsIgnoreCase ( SecStorageAllowedInternalDownloadSites .key ()) && StringUtils .isNotEmpty (value )) {
1334+ if (SecStorageAllowedInternalDownloadSites .key (). equalsIgnoreCase ( name ) && StringUtils .isNotEmpty (value )) {
13351335 final String [] cidrs = value .split ("," );
13361336 for (final String cidr : cidrs ) {
13371337 if (!NetUtils .isValidIp4 (cidr ) && !NetUtils .isValidIp6 (cidr ) && !NetUtils .getCleanIp4Cidr (cidr ).equals (cidr )) {
1338- logger .error (String .format ("Invalid CIDR %s value specified for the config %s" , cidr , name ));
1339- throw new InvalidParameterValueException (String .format ("Invalid CIDR %s value specified for the config %s" , cidr , name ));
1338+ return String .format ("Invalid CIDR %s value specified for the config %s." , cidr , name );
13401339 }
13411340 }
13421341 }
13431342 }
13441343
1345- if (configuration == null ) {
1346- //range validation has to be done per case basis, for now
1347- //return in case of Configkey parameters
1348- return null ;
1349- }
1344+ validateIpAddressRelatedConfigValues (name , value );
13501345
1351- if (configuration . getRange () == null ) {
1346+ if (! shouldValidateConfigRange ( name , value , configuration ) ) {
13521347 return null ;
13531348 }
1354- String [] range = configuration .getRange ().split ("," );
13551349
1356- if (type .equals (String .class )) {
1357- return validateIfStringValueIsInRange (name , value , range );
1358- } else if (type .equals (Integer .class )) {
1350+ String [] range = configuration .getRange ().split ("," );
1351+ if (type .equals (Integer .class )) {
13591352 return validateIfIntValueIsInRange (name , value , range [0 ]);
13601353 }
1361- return String .format ("Invalid value for configuration [%s]." , name );
1354+ return validateIfStringValueIsInRange (name , value , range );
1355+ }
1356+
1357+ /**
1358+ * Returns a boolean indicating whether a Config's range should be validated. It should not be validated when:</br>
1359+ * <ul>
1360+ * <li>The value is null;</li>
1361+ * <li>The configuration uses ConfigKey instead of Config;</li>
1362+ * <li>The Config does not have a specified range.</li>
1363+ * </ul>
1364+ */
1365+ protected boolean shouldValidateConfigRange (String name , String value , Config configuration ) {
1366+ if (value == null ) {
1367+ logger .debug ("Not proceeding with configuration [{}]'s range validation, as its provided value is null." , name );
1368+ return false ;
1369+ }
1370+
1371+ if (configuration == null ) {
1372+ logger .debug ("Not proceeding with configuration [{}]'s range validation, as it uses ConfigKey instead of Config." , name );
1373+ return false ;
1374+ }
1375+
1376+ if (configuration .getRange () == null ) {
1377+ logger .debug ("Not proceeding with configuration [{}]'s range validation, as it does not have a specified range." , name );
1378+ return false ;
1379+ }
1380+
1381+ logger .debug ("Proceeding with configuration [{}]'s range validation." , name );
1382+ return true ;
13621383 }
13631384
13641385 /**
0 commit comments