package org.ovirt.engine.ui.uicommonweb.models.storage;
import static org.ovirt.engine.ui.uicommonweb.Linq.where;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import org.ovirt.engine.core.common.action.ImportVmParameters;
import org.ovirt.engine.core.common.action.VdcActionParametersBase;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.businessentities.Cluster;
import org.ovirt.engine.core.common.businessentities.Quota;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.network.ExternalVnicProfileMapping;
import org.ovirt.engine.core.common.businessentities.network.VmNetworkInterface;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.ui.frontend.ErrorTranslator;
import org.ovirt.engine.ui.frontend.Frontend;
import org.ovirt.engine.ui.uicommonweb.UICommand;
import org.ovirt.engine.ui.uicommonweb.dataprovider.AsyncDataProvider;
import org.ovirt.engine.ui.uicommonweb.models.vms.register.RegisterVmData;
import org.ovirt.engine.ui.uicommonweb.models.vms.register.VnicProfileMappingEntity;
import org.ovirt.engine.ui.uicommonweb.models.vms.register.VnicProfileMappingModel;
import org.ovirt.engine.ui.uicompat.ConstantsManager;
import org.ovirt.engine.ui.uicompat.EventArgs;
import org.ovirt.engine.ui.uicompat.IEventListener;
public class RegisterVmModel extends RegisterEntityModel<VM, RegisterVmData> {
public static final String VNIC_PROFILE_MAPPING_COMMAND = "vnicProfileMapping"; //$NON-NLS-1$
private static final String NEWLINE = "\n"; //$NON-NLS-1$
private static final Predicate<RegisterVmData> REASSIGN_MACS_PREDICATE = rvd -> rvd.getReassignMacs().getEntity();
private static final Predicate<RegisterVmData> NOT_REASSIGN_MACS_PREDICATE = REASSIGN_MACS_PREDICATE.negate();
private VnicProfileMappingModel vnicProfileMappingModel;
private UICommand vnicProfileMappingCommand;
private Map<Cluster, Set<VnicProfileMappingEntity>> externalVnicProfilesPerTargetCluster;
public RegisterVmModel() {
super();
this.externalVnicProfilesPerTargetCluster = new HashMap<>();
}
@Override
public void initialize() {
addVnicProfileMappingCommand();
getCluster().getItemsChangedEvent().addListener((ev, sender, args) -> postClustersInit());
super.initialize();
}
private void addVnicProfileMappingCommand() {
final UICommand vnicProfileMappingCommand = createVnicProfileMappingCommand();
getCommands().add(vnicProfileMappingCommand);
}
private void postClustersInit() {
validateAllMacs();
for (final RegisterVmData registerVmData : getEntities().getItems()) {
final IEventListener<EventArgs> validateMacsListener =
(ev, sender, args) -> validateVmMacs(Collections.singletonList(registerVmData));
registerVmData.getReassignMacs().getEntityChangedEvent().addListener(validateMacsListener);
registerVmData.getCluster().getSelectedItemChangedEvent().addListener(validateMacsListener);
}
}
private void validateAllMacs() {
validateVmMacs(getEntities().getItems());
}
private void validateVmMacs(final Collection<RegisterVmData> registerVmData) {
final Collection<RegisterVmData> vmsToBeValidated = getVmsForMacValidation(registerVmData);
clearVmMacsWarningOnReassignedVms(registerVmData);
if (vmsToBeValidated.isEmpty()) {
return;
}
final Map<Guid, List<VM>> vmsByClusterId = mapVmsByTargetClusterId(vmsToBeValidated);
AsyncDataProvider.getInstance().validateVmMacs(
new AsyncQuery<>(
returnValue -> processVmMacsValidationResult(vmsToBeValidated, returnValue)),
vmsByClusterId);
}
private void processVmMacsValidationResult(
Collection<RegisterVmData> vmsToBeValidated,
Map<Guid, List<List<String>>> validationResult) {
for (RegisterVmData vmData : vmsToBeValidated) {
final List<List<String>> vmMessages = validationResult.get(vmData.getVm().getId());
if (vmMessages == null) {
continue;
}
final String translatedMessage = translateMessages(vmMessages);
updateVmWithMacsValidationResult(vmData, translatedMessage);
}
}
private void updateVmWithMacsValidationResult(RegisterVmData vmData, String translatedMessage) {
if (translatedMessage.isEmpty()) {
clearVmMacsWarning(vmData);
} else {
setVmMacsWarning(vmData, translatedMessage, Boolean.TRUE);
}
}
private void setVmMacsWarning(RegisterVmData vmData, String message, Boolean isValid) {
vmData.setWarning(message);
vmData.getBadMacsExist().setEntity(isValid);
}
private void clearVmMacsWarning(RegisterVmData vmData) {
setVmMacsWarning(vmData, null, Boolean.FALSE);
}
private void clearVmMacsWarningOnReassignedVms(Collection<RegisterVmData> registerVmData) {
final Collection<RegisterVmData> vmsToBeReassigned = where(registerVmData, REASSIGN_MACS_PREDICATE);
for (RegisterVmData vmData : vmsToBeReassigned) {
clearVmMacsWarning(vmData);
}
}
private Collection<RegisterVmData> getVmsForMacValidation(Collection<RegisterVmData> registerVmData) {
return where(registerVmData, NOT_REASSIGN_MACS_PREDICATE);
}
private Map<Guid, List<VM>> mapVmsByTargetClusterId(Collection<RegisterVmData> vms) {
final Map<Guid, List<VM>> result = new HashMap<>();
for (RegisterVmData vmData : vms) {
final Guid clusterId = vmData.getCluster().getSelectedItem().getId();
final List<VM> clusterVms;
if (result.containsKey(clusterId)) {
clusterVms = result.get(clusterId);
} else {
clusterVms = new ArrayList<>();
result.put(clusterId, clusterVms);
}
clusterVms.add(vmData.getVm());
}
return result;
}
private String translateMessages(List<List<String>> vmMessages) {
StringBuilder stringBuilder = new StringBuilder();
final ErrorTranslator appErrorsTranslator = Frontend.getInstance().getAppErrorsTranslator();
for (List<String> vmMessage : vmMessages) {
if (vmMessage.isEmpty()) {
continue;
}
for (String translatedMessage : appErrorsTranslator.translateErrorText(new ArrayList<>(vmMessage))) {
stringBuilder.append(translatedMessage);
}
stringBuilder.append(NEWLINE);
}
return stringBuilder.toString();
}
private UICommand createVnicProfileMappingCommand() {
vnicProfileMappingCommand = new UICommand(VNIC_PROFILE_MAPPING_COMMAND, this);
vnicProfileMappingCommand.setTitle(ConstantsManager.getInstance().getConstants().vnicProfilesMapping());
return vnicProfileMappingCommand;
}
@Override
public void executeCommand(UICommand command) {
super.executeCommand(command);
if (command == getVnicProfileMappingCommand()) {
onVnicProfileMap();
}
}
private void onVnicProfileMap() {
if (getWindow() != null) {
return;
}
createVnicProfileMappingsModel();
setWindow(vnicProfileMappingModel);
}
private void createVnicProfileMappingsModel() {
updateExternalVnicProfilesPerTargetCluster();
vnicProfileMappingModel = new VnicProfileMappingModel(
RegisterVmModel.this,
externalVnicProfilesPerTargetCluster);
vnicProfileMappingModel.initialize();
}
private void updateExternalVnicProfilesPerTargetCluster() {
final Map<Cluster, Set<VnicProfileMappingEntity>> result = new HashMap<>();
for (RegisterVmData registerVmData : getEntities().getItems()) {
final Cluster cluster = registerVmData.getCluster().getSelectedItem();
final Set<VnicProfileMappingEntity> clusterVnicProfileMappings;
if (result.containsKey(cluster)) {
clusterVnicProfileMappings = result.get(cluster);
} else {
clusterVnicProfileMappings = new HashSet<>();
result.put(cluster, clusterVnicProfileMappings);
}
final Set<VnicProfileMappingEntity> previousClusterVnicProfileMappings;
if (externalVnicProfilesPerTargetCluster.containsKey(cluster)) {
previousClusterVnicProfileMappings = externalVnicProfilesPerTargetCluster.get(cluster);
} else {
previousClusterVnicProfileMappings = new HashSet<>();
}
final Set<VnicProfileMappingEntity> vmVnicProfiles =
getNewVnicProfileMappings(registerVmData, previousClusterVnicProfileMappings);
clusterVnicProfileMappings.addAll(vmVnicProfiles);
}
externalVnicProfilesPerTargetCluster = result;
}
private Set<VnicProfileMappingEntity> getNewVnicProfileMappings(RegisterVmData registerVmData,
Set<VnicProfileMappingEntity> previousClusterVnicProfileMappings) {
final Set<VnicProfileMappingEntity> result = new HashSet<>();
for (VmNetworkInterface vnic : registerVmData.getEntity().getInterfaces()) {
final VnicProfileMappingEntity newMapping =
new VnicProfileMappingEntity(vnic.getNetworkName(), vnic.getVnicProfileName(), null);
final VnicProfileMappingEntity mapping =
previousClusterVnicProfileMappings
.stream()
.filter(x -> x.equals(newMapping))
.findFirst()
.orElse(newMapping);
result.add(mapping);
}
return result;
}
protected void onSave() {
ArrayList<VdcActionParametersBase> parameters = new ArrayList<>();
for (RegisterVmData registerVmData : getEntities().getItems()) {
VM vm = registerVmData.getEntity();
Cluster cluster = registerVmData.getCluster().getSelectedItem();
ImportVmParameters params = new ImportVmParameters(
getExternalVnicProfileMappings(cluster),
registerVmData.getReassignMacs().getEntity());
params.setContainerId(vm.getId());
params.setStorageDomainId(getStorageDomainId());
params.setImagesExistOnTargetStorageDomain(true);
params.setClusterId(cluster != null ? cluster.getId() : null);
if (isQuotaEnabled()) {
Quota quota = registerVmData.getClusterQuota().getSelectedItem();
params.setQuotaId(quota != null ? quota.getId() : null);
params.setDiskMap(vm.getDiskMap());
updateDiskQuotas(new ArrayList<>(params.getDiskMap().values()));
}
parameters.add(params);
}
startProgress();
Frontend.getInstance().runMultipleAction(VdcActionType.ImportVmFromConfiguration, parameters, result -> {
stopProgress();
cancel();
}, this);
}
private Collection<ExternalVnicProfileMapping> getExternalVnicProfileMappings(Cluster cluster) {
final Set<VnicProfileMappingEntity> vnicProfileMappingEntities = getClusterVnicProfileMappingEntities(cluster);
final Collection<ExternalVnicProfileMapping> result = new ArrayList<>(vnicProfileMappingEntities.size());
for (VnicProfileMappingEntity vnicProfileMappingEntity : vnicProfileMappingEntities) {
result.add(vnicProfileMappingEntity.getExternalVnicProfileMapping());
}
return result;
}
private Set<VnicProfileMappingEntity> getClusterVnicProfileMappingEntities(Cluster cluster) {
final Set<VnicProfileMappingEntity> result = externalVnicProfilesPerTargetCluster.get(cluster);
if (result == null) {
return new HashSet<>();
} else {
return result;
}
}
public UICommand getVnicProfileMappingCommand() {
return vnicProfileMappingCommand;
}
}