package org.ovirt.engine.core.common.utils.customprop; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.ovirt.engine.core.common.businessentities.VmBase; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.common.utils.exceptions.InitializationException; import org.ovirt.engine.core.compat.StringHelper; import org.ovirt.engine.core.compat.Version; /** * Helper methods to help parse and validate custom VM (predefined and user defined) properties. These methods are used * by vdsbroker and bll modules * */ public class VmPropertiesUtils extends CustomPropertiesUtils { private static final VmPropertiesUtils instance = new VmPropertiesUtils(); private Map<Version, Map<String, String>> predefinedProperties; private Map<Version, Map<String, String>> userdefinedProperties; private Map<Version, Map<String, String>> allVmProperties; public static VmPropertiesUtils getInstance() { return instance; } public void init() throws InitializationException { try { predefinedProperties = new HashMap<>(); userdefinedProperties = new HashMap<>(); allVmProperties = new HashMap<>(); Set<Version> versions = getSupportedClusterLevels(); for (Version version : versions) { predefinedProperties.put(version, new HashMap<String, String>()); userdefinedProperties.put(version, new HashMap<String, String>()); allVmProperties.put(version, new HashMap<String, String>()); parsePropertiesRegex(getPredefinedVMProperties(version), predefinedProperties.get(version)); parsePropertiesRegex(getUserdefinedVMProperties(version), userdefinedProperties.get(version)); allVmProperties.get(version).putAll(predefinedProperties.get(version)); allVmProperties.get(version).putAll(userdefinedProperties.get(version)); } } catch (Throwable ex) { throw new InitializationException(ex); } } public String getUserdefinedVMProperties(Version version) { return Config.<String> getValue(ConfigValues.UserDefinedVMProperties, version.getValue()); } public String getPredefinedVMProperties(Version version) { return Config.<String> getValue(ConfigValues.PredefinedVMProperties, version.getValue()); } public static class VMCustomProperties { private final String predefinedProperties; private final String userDefinedProperties; public VMCustomProperties(String predefinedProperties, String userDefinedProperties) { this.predefinedProperties = predefinedProperties; this.userDefinedProperties = userDefinedProperties; } public String getPredefinedProperties() { return predefinedProperties; } public String getUseDefinedProperties() { return userDefinedProperties; } } /** * Parses a string containing user defined and predefined custom properties and returns VMCustomProperties object * that contains the properties separated to two strings - one for the predefined properties and one for the user * defined properties */ public VMCustomProperties parseProperties(Version version, String propertiesStr) { HashMap<String, String> userDefinedPropertiesMap = new HashMap<>(); HashMap<String, String> predefinedPropertiesMap = new HashMap<>(); convertCustomPropertiesStrToMaps(version, propertiesStr, predefinedPropertiesMap, userDefinedPropertiesMap); return new VMCustomProperties(convertProperties(predefinedPropertiesMap), convertProperties(userDefinedPropertiesMap)); } /** * Validates a properties field value (checks if its format matches key1=val1;key2=val2;....) * * @return a list of validation errors. if there are no errors - the list will be empty */ public List<ValidationError> validateVmProperties(Version version, String properties) { if (syntaxErrorInProperties(properties)) { return invalidSyntaxValidationError; } return validateProperties(allVmProperties.get(version), convertProperties(properties)); } /** * Get a map containing all the VM custom properties * * @return map containing the VM custom properties */ public Map<String, String> getVMProperties(Version version, VmBase vmBase) { separateCustomPropertiesToUserAndPredefined(version, vmBase); Map<String, String> map = new HashMap<>(); getPredefinedProperties(version, vmBase, map); getUserDefinedProperties(version, vmBase, map); return map; } public Map<Version, Map<String, String>> getAllVmProperties() { return allVmProperties; } private void getPredefinedProperties(Version version, VmBase vmBase, Map<String, String> propertiesMap) { String predefinedProperties = vmBase.getPredefinedProperties(); getVMProperties(version, propertiesMap, predefinedProperties); } private void getUserDefinedProperties(Version version, VmBase vmBase, Map<String, String> propertiesMap) { String UserDefinedProperties = vmBase.getUserDefinedProperties(); getVMProperties(version, propertiesMap, UserDefinedProperties); } /** * Converts VM properties field value (either UserDefined or defined) to a map containing property names & values * * @param propertiesMap * map that will hold the conversion result * @param vmPropertiesFieldValue * the string value that contains the properties */ private void getVMProperties(Version version, Map<String, String> propertiesMap, String vmPropertiesFieldValue) { // format of properties is key1=val1,key2=val2,key3=val3,key4=val4 if (StringHelper.isNullOrEmpty(vmPropertiesFieldValue)) { return; } propertiesMap.putAll(convertProperties(vmPropertiesFieldValue, allVmProperties.get(version))); } protected boolean keyExistsInVersion(Map<Version, Map<String, String>> propertiesMap, Version version, String key) { return propertiesMap.get(version).containsKey(key); } private void convertCustomPropertiesStrToMaps(Version version, String propertiesValue, Map<String, String> predefinedPropertiesMap, Map<String, String> userDefinedPropertiesMap) { Map<String, String> propertiesMap = convertProperties(propertiesValue, allVmProperties.get(version)); Set<Entry<String, String>> propertiesEntries = propertiesMap.entrySet(); // Go over all the properties - if the key of the property exists in the // predefined key set - // add it to the predefined map, otherwise - add it to the user defined // map Set<String> predefinedPropertiesKeys = predefinedProperties.get(version).keySet(); Set<String> userdefinedPropertiesKeys = userdefinedProperties.get(version).keySet(); for (Entry<String, String> propertiesEntry : propertiesEntries) { String propertyKey = propertiesEntry.getKey(); String propertyValue = StringHelper.defaultString(propertiesEntry.getValue()); if (predefinedPropertiesKeys.contains(propertyKey)) { predefinedPropertiesMap.put(propertyKey, propertyValue); } if (userdefinedPropertiesKeys.contains(propertyKey)) { userDefinedPropertiesMap.put(propertyKey, propertyValue); } } } /** * Composes custom properties string from predefined properties and user defined properties strings */ public String customProperties(String predefinedProperties, String userDefinedProperties) { String predefined = predefinedProperties == null ? "" : predefinedProperties; String userDefined = userDefinedProperties == null ? "" : userDefinedProperties; StringBuilder result = new StringBuilder(); result.append(predefined); if (!predefined.isEmpty() && !userDefined.isEmpty()) { result.append(PROPERTIES_DELIMETER); } result.append(userDefined); return result.toString(); } public void separateCustomPropertiesToUserAndPredefined(Version version, VmBase vmBase) { String customProperties = vmBase.getCustomProperties(); VMCustomProperties properties = parseProperties(version, customProperties); vmBase.setPredefinedProperties(properties.getPredefinedProperties()); vmBase.setUserDefinedProperties(properties.getUseDefinedProperties()); } /** * Returns the string describing format of VM properties specification * * @return the string describing format of VM properties specification */ public String getVmPropSpec() { return VALIDATION_STR; } public boolean validateVmProperties(Version version, String properties, List<String> message) { List<ValidationError> validationErrors = validateVmProperties(version, properties); if (!validationErrors.isEmpty()) { handleCustomPropertiesError(validationErrors, message); return false; } return true; } }