package org.ovirt.engine.core.bll; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.inject.Inject; import org.apache.commons.lang.StringUtils; import org.ovirt.engine.core.bll.context.CommandContext; import org.ovirt.engine.core.bll.network.cluster.AddClusterNetworkClusterValidator; import org.ovirt.engine.core.bll.network.cluster.DefaultManagementNetworkFinder; import org.ovirt.engine.core.bll.network.cluster.NetworkClusterValidatorBase; import org.ovirt.engine.core.bll.scheduling.SchedulingManager; import org.ovirt.engine.core.bll.validator.InClusterUpgradeValidator; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.FeatureSupported; import org.ovirt.engine.core.common.action.ManagementNetworkOnClusterOperationParameters; import org.ovirt.engine.core.common.businessentities.ArchitectureType; import org.ovirt.engine.core.common.businessentities.Cluster; import org.ovirt.engine.core.common.businessentities.MigrateOnErrorOptions; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.VM; import org.ovirt.engine.core.common.businessentities.VmNumaNode; import org.ovirt.engine.core.common.businessentities.network.Network; import org.ovirt.engine.core.common.businessentities.network.NetworkCluster; import org.ovirt.engine.core.common.businessentities.network.NetworkStatus; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.common.network.DefaultSwitchType; import org.ovirt.engine.core.common.network.SwitchType; import org.ovirt.engine.core.common.scheduling.ClusterPolicy; import org.ovirt.engine.core.common.utils.customprop.SimpleCustomPropertiesUtil; import org.ovirt.engine.core.common.utils.customprop.ValidationError; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogable; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableImpl; import org.ovirt.engine.core.dao.ClusterDao; import org.ovirt.engine.core.dao.VdsDao; import org.ovirt.engine.core.dao.VmDao; import org.ovirt.engine.core.dao.VmNumaNodeDao; import org.ovirt.engine.core.dao.network.InterfaceDao; import org.ovirt.engine.core.dao.network.NetworkDao; public abstract class ClusterOperationCommandBase<T extends ManagementNetworkOnClusterOperationParameters> extends ClusterCommandBase<T> { // If the CPU thresholds are set to -1 then we should get the value from the configuration public static final int GET_CPU_THRESHOLDS_FROM_CONFIGURATION = -1; @Inject private NetworkDao networkDao; @Inject private SchedulingManager schedulingManager; @Inject private InClusterUpgradeValidator upgradeValidator; @Inject private VdsDao vdsDao; @Inject private ClusterDao clusterDao; @Inject private VmNumaNodeDao vmNumaNodeDao; @Inject private VmDao vmDao; @Inject private InterfaceDao interfaceDao; @Inject private DefaultManagementNetworkFinder defaultManagementNetworkFinder; private Network managementNetwork; protected ClusterOperationCommandBase(Guid commandId) { super(commandId); } public ClusterOperationCommandBase(T parameters, CommandContext commandContext) { super(parameters, commandContext); } @Override public Cluster getCluster() { return getParameters().getCluster(); } /** * Get the cluster object as it is in database before update * * @return Current cluster object before database update, or null if not existing */ public Cluster getPrevCluster() { return super.getCluster(); } protected Guid getManagementNetworkId() { return getParameters().getManagementNetworkId(); } protected Network getManagementNetworkById() { final Guid managementNetworkId = getManagementNetworkId(); return networkDao.get(managementNetworkId); } @Override protected void setActionMessageParameters() { addValidationMessage(EngineMessage.VAR__TYPE__CLUSTER); } protected ArchitectureType getArchitecture() { if (StringUtils.isNotEmpty(getCluster().getCpuName())) { return getCpuFlagsManagerHandler().getArchitectureByCpuName(getCluster().getCpuName(), getCluster().getCompatibilityVersion()); } else if (getCluster().getArchitecture() == null) { return ArchitectureType.undefined; } return getCluster().getArchitecture(); } protected void updateMigrateOnError() { if (getCluster() != null && getCluster().getMigrateOnError() == null) { boolean isMigrationSupported = FeatureSupported.isMigrationSupported(getArchitecture(), getCluster().getCompatibilityVersion()); MigrateOnErrorOptions migrateOnError = isMigrationSupported ? MigrateOnErrorOptions.YES : MigrateOnErrorOptions.NO; getCluster().setMigrateOnError(migrateOnError); } } protected void checkMaxMemoryOverCommitValue() { if (getCluster().getMaxVdsMemoryOverCommit() <= 0) { getCluster().setMaxVdsMemoryOverCommit(100); } } protected boolean isAllowClusterWithVirtGluster() { Boolean allowVirGluster = Config.<Boolean> getValue(ConfigValues.AllowClusterWithVirtGlusterEnabled); return allowVirGluster; } protected boolean validateClusterPolicy(Cluster oldCluster) { Cluster newCluster = getCluster(); boolean alreadyInUpgradeMode = oldCluster != null && oldCluster.isInUpgradeMode(); ClusterPolicy clusterPolicy = getClusterPolicy(newCluster); if (clusterPolicy == null) { return false; } newCluster.setClusterPolicyId(clusterPolicy.getId()); if (alreadyInUpgradeMode && !newCluster.isInUpgradeMode()) { // Check if we can safely stop the cluster upgrade final List<VDS> hosts = vdsDao.getAllForCluster(getClusterId()); if (!validate(getUpgradeValidator().isUpgradeDone(hosts))) { return false; } } else if (!alreadyInUpgradeMode && newCluster.isInUpgradeMode()) { final List<VDS> hosts = vdsDao.getAllForCluster(getClusterId()); final List<VM> vms = vmDao.getAllForCluster(getClusterId()); populateVMNUMAInfo(vms); if (!validate(getUpgradeValidator().isUpgradePossible(hosts, vms))) { return false; } } Map<String, String> customPropertiesRegexMap = getSchedulingManager().getCustomPropertiesRegexMap(clusterPolicy); updateClusterPolicyProperties(getCluster(), clusterPolicy, customPropertiesRegexMap); List<ValidationError> validationErrors = SimpleCustomPropertiesUtil.getInstance().validateProperties(customPropertiesRegexMap, getCluster().getClusterPolicyProperties()); if (!validationErrors.isEmpty()) { SimpleCustomPropertiesUtil.getInstance().handleCustomPropertiesError(validationErrors, getReturnValue().getValidationMessages()); return false; } return true; } private ClusterPolicy getClusterPolicy(final Cluster cluster) { ClusterPolicy clusterPolicy = null; if (cluster == null){ return null; } if (cluster.getClusterPolicyId() != null) { clusterPolicy = getSchedulingManager().getClusterPolicy(cluster.getClusterPolicyId()); } if (clusterPolicy == null) { clusterPolicy = getSchedulingManager().getClusterPolicy(cluster.getClusterPolicyName()) .orElseGet(() -> getSchedulingManager().getDefaultClusterPolicy()); } return clusterPolicy; } private void populateVMNUMAInfo(final List<VM> vms) { // Populate numa nodes with a mass update final Map<Guid, List<VmNumaNode>> numaNodes = vmNumaNodeDao.getVmNumaNodeInfoByClusterId(getClusterId()); for (final VM vm : vms) { if (numaNodes.containsKey(vm.getId())) { vm.setvNumaNodeList(numaNodes.get(vm.getId())); } } } /** * Updates cluster policy parameters map to contain all default cluster properties and remove properties that * doesn't exist in the valid custom properties. * * @param customPropertiesRegexMap * - custom properties for all policy unit in cluster policy */ private void updateClusterPolicyProperties(Cluster cluster, ClusterPolicy clusterPolicy, Map<String, String> customPropertiesRegexMap) { if (cluster.getClusterPolicyProperties() == null) { cluster.setClusterPolicyProperties(new LinkedHashMap<>()); } Map<String, String> clusterPolicyProperties = cluster.getClusterPolicyProperties(); List<String> toRemoveKeysList = new ArrayList<>(); if (clusterPolicy.getParameterMap() != null) { for (Entry<String, String> entry : clusterPolicy.getParameterMap().entrySet()) { if (!clusterPolicyProperties.containsKey(entry.getKey())) { clusterPolicyProperties.put(entry.getKey(), entry.getValue()); } } for (String key : clusterPolicyProperties.keySet()) { if (!customPropertiesRegexMap.containsKey(key)) { toRemoveKeysList.add(key); } } for (String key : toRemoveKeysList) { clusterPolicyProperties.remove(key); } } } protected boolean isClusterUnique(String clusterName) { List<Cluster> clusters = clusterDao.getByName(clusterName, true); return clusters == null || clusters.isEmpty(); } protected void alertIfFencingDisabled() { if (!getCluster().getFencingPolicy().isFencingEnabled()) { AuditLogable alb = new AuditLogableImpl(); alb.setClusterId(getCluster().getId()); alb.setClusterName(getCluster().getName()); alb.setRepeatable(true); auditLogDirector.log(alb, AuditLogType.FENCE_DISABLED_IN_CLUSTER_POLICY); } } protected SchedulingManager getSchedulingManager() { return schedulingManager; } protected InClusterUpgradeValidator getUpgradeValidator() { return upgradeValidator; } protected void setDefaultSwitchTypeIfNeeded() { Cluster cluster = getCluster(); if (cluster.getRequiredSwitchTypeForCluster() == null) { SwitchType defaultSwitchType = DefaultSwitchType.getDefaultSwitchType(cluster.getCompatibilityVersion()); cluster.setRequiredSwitchTypeForCluster(defaultSwitchType); } } protected boolean validateManagementNetwork() { if (getManagementNetworkId() == null) { return findDefaultManagementNetwork(); } else { return validateInputManagementNetwork(); } } protected boolean findDefaultManagementNetwork() { managementNetwork = defaultManagementNetworkFinder.findDefaultManagementNetwork(getCluster().getStoragePoolId()); if (managementNetwork == null) { addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_DEFAULT_MANAGEMENT_NETWORK_NOT_FOUND); return false; } return true; } protected boolean findInputManagementNetwork() { managementNetwork = getManagementNetworkById(); if (managementNetwork == null) { addValidationMessage(EngineMessage.NETWORK_NOT_EXISTS); return false; } return true; } protected NetworkDao getNetworkDao() { return networkDao; } private boolean validateInputManagementNetwork() { if (!findInputManagementNetwork()) { return false; } final NetworkClusterValidatorBase networkClusterValidator = createNetworkClusterValidator(); return validateInputManagementNetwork(networkClusterValidator); } private AddClusterNetworkClusterValidator createNetworkClusterValidator() { final NetworkCluster networkCluster = createManagementNetworkCluster(); return new AddClusterNetworkClusterValidator( interfaceDao, getNetworkDao(), vdsDao, networkCluster); } protected NetworkCluster createManagementNetworkCluster() { return new NetworkCluster( getClusterId(), managementNetwork.getId(), NetworkStatus.OPERATIONAL, true, true, true, true, false, true); } protected Network getManagementNetwork() { return managementNetwork; } protected abstract boolean validateInputManagementNetwork(NetworkClusterValidatorBase networkClusterValidator); }