package org.ovirt.engine.core.bll.scheduling.commands;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import javax.inject.Inject;
import org.ovirt.engine.core.bll.CommandBase;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.scheduling.arem.AffinityRulesUtils;
import org.ovirt.engine.core.bll.utils.PermissionSubject;
import org.ovirt.engine.core.common.VdcObjectType;
import org.ovirt.engine.core.common.businessentities.VdsStatic;
import org.ovirt.engine.core.common.businessentities.VmStatic;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.common.scheduling.AffinityGroup;
import org.ovirt.engine.core.common.scheduling.parameters.AffinityGroupCRUDParameters;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dao.VdsStaticDao;
import org.ovirt.engine.core.dao.VmStaticDao;
import org.ovirt.engine.core.dao.scheduling.AffinityGroupDao;
public abstract class AffinityGroupCRUDCommand extends CommandBase<AffinityGroupCRUDParameters> {
private static final String Entity_VM = "VM";
private static final String Entity_VDS = "VDS";
@Inject
private VmStaticDao vmStaticDao;
@Inject
private VdsStaticDao vdsStaticDao;
@Inject
private AffinityGroupDao affinityGroupDao;
AffinityGroup affinityGroup = null;
public AffinityGroupCRUDCommand(AffinityGroupCRUDParameters parameters, CommandContext cmdContext) {
super(parameters, cmdContext);
}
@Override
protected void init() {
super.init();
if (getAffinityGroup() != null) {
setClusterId(getAffinityGroup().getClusterId());
addCustomValue("affinityGroupName", getAffinityGroup().getName());
}
}
protected boolean validateParameters() {
if (getCluster() == null) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_INVALID_CLUSTER_FOR_AFFINITY_GROUP);
}
if (getParameters().getAffinityGroup().getVmIds() != null) {
VmStatic vmStatic = null;
Set<Guid> vmSet = new HashSet<>();
for (Guid vmId : getParameters().getAffinityGroup().getVmIds()) {
vmStatic = vmStaticDao.get(vmId);
if (vmStatic == null) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_INVALID_ENTITY_FOR_AFFINITY_GROUP, String
.format("$entity %s", Entity_VM));
}
if (!Objects.equals(vmStatic.getClusterId(), getClusterId())) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_ENTITY_NOT_IN_AFFINITY_GROUP_CLUSTER, String
.format("$entity %s", Entity_VM));
}
if (vmSet.contains(vmStatic.getId())) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_DUPLICATE_ENTITY_IN_AFFINITY_GROUP, String
.format("$entity %s", Entity_VM));
} else {
vmSet.add(vmStatic.getId());
}
}
}
if (getParameters().getAffinityGroup().getVdsIds() != null) {
VdsStatic vdsStatic = null;
Set<Guid> vdsSet = new HashSet<>();
for (Guid vdsId : getParameters().getAffinityGroup().getVdsIds()) {
vdsStatic = vdsStaticDao.get(vdsId);
if (vdsStatic == null) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_INVALID_ENTITY_FOR_AFFINITY_GROUP, String
.format("$entity %s", Entity_VDS));
}
if (!Objects.equals(vdsStatic.getClusterId(), getClusterId())) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_ENTITY_NOT_IN_AFFINITY_GROUP_CLUSTER, String
.format("$entity %s", Entity_VDS));
}
if (vdsSet.contains(vdsStatic.getId())) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_DUPLICATE_ENTITY_IN_AFFINITY_GROUP, String
.format("$entity %s", Entity_VDS));
} else {
vdsSet.add(vdsStatic.getId());
}
}
}
return affinityGroupsWithoutConflict(getParameters().getAffinityGroup());
}
private boolean affinityGroupsWithoutConflict(AffinityGroup affinityGroup) {
List<AffinityGroup> affinityGroups =
affinityGroupDao.getAllAffinityGroupsByClusterId(affinityGroup.getClusterId());
// Replace the existing affinity group by the updated copy
for (Iterator<AffinityGroup> it = affinityGroups.iterator(); it.hasNext(); ) {
AffinityGroup g = it.next();
if (g.getId().equals(affinityGroup.getId())) {
it.remove();
}
}
affinityGroups.add(affinityGroup);
List<AffinityRulesUtils.AffinityGroupConflicts> conflicts = AffinityRulesUtils
.checkForAffinityGroupHostsConflict(affinityGroups);
for (AffinityRulesUtils.AffinityGroupConflicts conflict : conflicts) {
String affinityGroupsNames = AffinityRulesUtils.getAffinityGroupsNames(conflict.getAffinityGroups());
String hosts = conflict.getHosts().stream()
.map(id -> id.toString())
.collect(Collectors.joining(","));
String vms = conflict.getVms().stream()
.map(id -> id.toString())
.collect(Collectors.joining(","));
if (conflict.getType().canBeSaved()) {
addCustomValue("AffinityGroups", affinityGroupsNames);
addCustomValue("Hosts", hosts);
addCustomValue("Vms", vms);
auditLogDirector.log(this, conflict.getAuditLogType());
} else {
if (conflict.isVmToVmAffinity()) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_AFFINITY_RULES_COLLISION,
String.format("$UnifiedAffinityGroups %1$s", vms),
String.format("$negativeAR %1$s", affinityGroupsNames),
String.format("$Vms %1$s", conflict.getNegativeVms().stream()
.map(id -> id.toString())
.collect(Collectors.joining(",")))
);
} else {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_AFFINITY_HOSTS_RULES_COLLISION,
String.format("AffinityGroups: %1$s", affinityGroupsNames),
String.format("Hosts: %1$s", hosts),
String.format("Vms: %1$s", vms)
);
}
}
}
return true;
}
protected AffinityGroup getAffinityGroup() {
if (affinityGroup == null) {
affinityGroup = affinityGroupDao.get(getParameters().getAffinityGroupId());
}
return affinityGroup;
}
@Override
public List<PermissionSubject> getPermissionCheckSubjects() {
return Collections.singletonList(new PermissionSubject(getClusterId(),
VdcObjectType.Cluster,
getActionType().getActionGroup()));
}
@Override
public Guid getClusterId() {
return getAffinityGroup().getClusterId();
}
@Override
protected void setActionMessageParameters() {
addValidationMessage(EngineMessage.VAR__TYPE__AFFINITY_GROUP);
}
}