package org.ovirt.engine.core.bll.network.vm;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.inject.Inject;
import org.ovirt.engine.core.bll.QueriesCommandBase;
import org.ovirt.engine.core.bll.ValidationResult;
import org.ovirt.engine.core.bll.network.macpool.MacPoolPerCluster;
import org.ovirt.engine.core.bll.network.macpool.ReadMacPool;
import org.ovirt.engine.core.bll.network.vm.mac.VmMacsValidation;
import org.ovirt.engine.core.bll.network.vm.mac.VmMacsValidationsFactory;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.common.queries.ValidateVmMacsParameters;
import org.ovirt.engine.core.compat.Guid;
/**
* Validates the MAC addresses of the given VMs.
* <p/>
* The result is a Map with a VM id as the key and violation messages (that are related to the VM) as the values.
*
* Each value is a group consisting of inner groups, where each inner group holds a violation message and its
* replacement entries. The use for multiple groups over a single flat group is to make sure there aren't any
* overlapping replacement entries.
*
* @param <P>
* the query parameter type
*/
public class ValidateVmMacsQuery<P extends ValidateVmMacsParameters> extends QueriesCommandBase<P> {
@Inject
private MacPoolPerCluster macPoolPerCluster;
@Inject
private VmMacsValidationsFactory vmMacsValidationsFactory;
public ValidateVmMacsQuery(P parameters) {
super(parameters);
}
@Override
protected void executeQueryCommand() {
// Map with a VM id as the key and violation messages (that are related to the VM) as the values.
final Map<Guid, List<List<String>>> result = new HashMap<>();
for (Entry<Guid, List<VM>> clusterEntry : getParameters().getVmsByCluster().entrySet()) {
final Guid clusterId = clusterEntry.getKey();
final List<VM> clusterVms = clusterEntry.getValue();
final ReadMacPool macPool = macPoolPerCluster.getMacPoolForCluster(clusterId);
final List<VmMacsValidation> vmMacsValidations =
vmMacsValidationsFactory.createVmMacsValidationList(clusterId, macPool);
clusterVms.forEach(vm -> result.put(vm.getId(), validateVm(vm, vmMacsValidations)));
}
getQueryReturnValue().setReturnValue(result);
}
/**
* Applies the given validations to the VM.
*
* @return a list of violations where each violation consists of the <code>EngineMessage</code> and the details
* related to it. In case all validations are valid an empty list would be returned.
*/
private List<List<String>> validateVm(VM vm, Collection<VmMacsValidation> vmMacsValidations) {
return vmMacsValidations
.stream()
.map(vmMacsValidation -> vmMacsValidation.validate(vm))
.filter(((Predicate<ValidationResult>) ValidationResult::isValid).negate())
.map(this::extractViolationDetails)
.collect(Collectors.toCollection(ArrayList::new));
}
private List<String> extractViolationDetails(ValidationResult validationResult) {
final List<String> violationDetails =
validationResult.getMessages()
.stream()
.map(EngineMessage::name)
.collect(Collectors.toCollection(ArrayList::new));
violationDetails.addAll(validationResult.getVariableReplacements());
return violationDetails;
}
}