package org.ovirt.engine.core.bll; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.hibernate.annotations.common.util.StringHelper; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.VdcObjectType; import org.ovirt.engine.core.common.action.ChangeVMClusterParameters; import org.ovirt.engine.core.common.businessentities.VDSGroup; import org.ovirt.engine.core.common.businessentities.VM; import org.ovirt.engine.core.common.businessentities.VmNetworkInterface; import org.ovirt.engine.core.common.businessentities.network; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.VdcBllMessages; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.ovirt.engine.core.utils.ObjectIdentityChecker; import org.ovirt.engine.core.utils.linq.LinqUtils; import org.ovirt.engine.core.utils.linq.Predicate; @SuppressWarnings("serial") public class ChangeVMClusterCommand<T extends ChangeVMClusterParameters> extends VmCommand<T> { private VDSGroup targetCluster; private boolean dedicatedHostWasCleared; public ChangeVMClusterCommand(T params) { super(params); setVmId(params.getVmId()); } @Override protected boolean canDoAction() { // Set parameters for messeging. addCanDoActionMessage(VdcBllMessages.VAR__ACTION__UPDATE); addCanDoActionMessage(VdcBllMessages.VAR__TYPE__VM__CLUSTER); VM vm = getVm(); if (vm == null) { addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_VM_NOT_EXIST); return false; } else { if (ObjectIdentityChecker.CanUpdateField(vm, "vds_group_id", vm.getstatus())) { targetCluster = DbFacade.getInstance().getVdsGroupDAO().get(getParameters().getClusterId()); if (targetCluster == null) { addCanDoActionMessage(VdcBllMessages.VM_CLUSTER_IS_NOT_VALID); return false; } // Check that the target cluster is in the same data center. if (!targetCluster.getstorage_pool_id().equals(vm.getstorage_pool_id())) { addCanDoActionMessage(VdcBllMessages.VM_CANNOT_MOVE_TO_CLUSTER_IN_OTHER_STORAGE_POOL); return false; } List<VmNetworkInterface> interfaces = DbFacade.getInstance().getVmNetworkInterfaceDAO() .getAllForVm(getParameters().getVmId()); // Get if the cluster chosen got limit of nics. boolean limitNumOfNics = Config.<Boolean> GetValue(ConfigValues.LimitNumberOfNetworkInterfaces, targetCluster.getcompatibility_version() .getValue() .toString()); // If so , check if nic count has exceeded and print appropriate // message. if (limitNumOfNics) { // Check that the number of interfaces does not exceed // limit. // Necessary only for version 2.2. boolean numOfNicsLegal = validateNumberOfNics(interfaces, null); if (!numOfNicsLegal) { addCanDoActionMessage(VdcBllMessages.NETWORK_INTERFACE_EXITED_MAX_INTERFACES); return false; } } // Check the destination cluster have all the networks that the VM use List<network> networks = DbFacade.getInstance().getNetworkDAO().getAllForCluster(getParameters().getClusterId()); StringBuilder missingNets = new StringBuilder(); for (VmNetworkInterface iface: interfaces) { if (!StringHelper.isEmpty(iface.getNetworkName())) { boolean exists = false; for (network net: networks) { if (net.getname().equals(iface.getNetworkName())) { exists = true; break; } } if (!exists) { if (missingNets.length() > 0) { missingNets.append(", "); } missingNets.append(iface.getNetworkName()); } } } if (missingNets.length() > 0) { addCanDoActionMessage(VdcBllMessages.MOVE_VM_CLUSTER_MISSING_NETWORK); addCanDoActionMessage(String.format("$networks %1$s", missingNets.toString())); return false; } // Check if VM static parameters are compatible for new cluster. boolean isCpuSocketsValid = AddVmCommand.CheckCpuSockets( vm.getStaticData().getnum_of_sockets(), vm.getStaticData().getcpu_per_socket(), targetCluster.getcompatibility_version() .getValue(), getReturnValue().getCanDoActionMessages()); if (!isCpuSocketsValid) { return false; } } else { addCanDoActionMessage(VdcBllMessages.VM_STATUS_NOT_VALID_FOR_UPDATE); return false; } } return true; } @Override protected void executeCommand() { // check that the cluster are not the same VM vm = getVm(); if (vm.getvds_group_id().equals(getParameters().getClusterId())) { setSucceeded(true); return; } // update vm interfaces List<network> networks = DbFacade.getInstance().getNetworkDAO() .getAllForCluster(getParameters().getClusterId()); List<VmNetworkInterface> interfaces = DbFacade.getInstance().getVmNetworkInterfaceDAO() .getAllForVm(getParameters().getVmId()); for (final VmNetworkInterface iface : interfaces) { network net = LinqUtils.firstOrNull(networks, new Predicate<network>() { @Override public boolean eval(network n) { return iface.getNetworkName().equals(n.getname()); } }); // if network not exists in cluster we remove the network to // interface connection if (net == null) { iface.setNetworkName(null); DbFacade.getInstance().getVmNetworkInterfaceDAO().update(iface); } } if (vm.getdedicated_vm_for_vds() != null) { vm.setdedicated_vm_for_vds(null); dedicatedHostWasCleared = true; } vm.setvds_group_id(getParameters().getClusterId()); DbFacade.getInstance().getVmStaticDAO().update(vm.getStaticData()); setSucceeded(true); } @Override public AuditLogType getAuditLogTypeValue() { return getSucceeded() ? dedicatedHostWasCleared ? AuditLogType.USER_UPDATE_VM_CLUSTER_DEFAULT_HOST_CLEARED : AuditLogType.USER_UPDATE_VM : AuditLogType.USER_FAILED_UPDATE_VM; } @Override public Map<Guid, VdcObjectType> getPermissionCheckSubjects() { Map<Guid, VdcObjectType> map = new HashMap<Guid, VdcObjectType>(2); map.put(getParameters().getVmId(), VdcObjectType.VM); map.put(getParameters().getClusterId(), VdcObjectType.VdsGroups); return Collections.unmodifiableMap(map); } }