package org.ovirt.engine.core.bll;
import java.text.MessageFormat;
import java.util.List;
import org.ovirt.engine.core.bll.storage.StorageHandlingCommandBase;
import org.ovirt.engine.core.bll.utils.VersionSupport;
import org.ovirt.engine.core.common.AuditLogType;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.action.VdcReturnValueBase;
import org.ovirt.engine.core.common.action.VdsActionParameters;
import org.ovirt.engine.core.common.action.VdsGroupOperationParameters;
import org.ovirt.engine.core.common.businessentities.NetworkStatus;
import org.ovirt.engine.core.common.businessentities.StorageType;
import org.ovirt.engine.core.common.businessentities.VDS;
import org.ovirt.engine.core.common.businessentities.VDSGroup;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VMStatus;
import org.ovirt.engine.core.common.businessentities.VdsSelectionAlgorithm;
import org.ovirt.engine.core.common.businessentities.VdsStatic;
import org.ovirt.engine.core.common.businessentities.network;
import org.ovirt.engine.core.common.businessentities.network_cluster;
import org.ovirt.engine.core.common.businessentities.storage_pool;
import org.ovirt.engine.core.common.config.Config;
import org.ovirt.engine.core.common.config.ConfigValues;
import org.ovirt.engine.core.common.interfaces.SearchType;
import org.ovirt.engine.core.common.queries.SearchParameters;
import org.ovirt.engine.core.common.queries.VdcQueryType;
import org.ovirt.engine.core.common.validation.group.UpdateEntity;
import org.ovirt.engine.core.compat.StringHelper;
import org.ovirt.engine.core.dal.VdcBllMessages;
import org.ovirt.engine.core.dal.dbbroker.DbFacade;
import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector;
import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableBase;
public class UpdateVdsGroupCommand<T extends VdsGroupOperationParameters> extends
VdsGroupOperationCommandBase<T> {
public UpdateVdsGroupCommand(T parameters) {
super(parameters);
}
@Override
protected void executeCommand() {
// YAIRPOSTGRES - this code should be split to several blocks of run in new transaction + set states
VDSGroup oldGroup = DbFacade.getInstance().getVdsGroupDAO().get(
getParameters().getVdsGroup().getID());
CheckMaxMemoryOverCommitValue();
DbFacade.getInstance().getVdsGroupDAO().update(getParameters().getVdsGroup());
if (oldGroup.getstorage_pool_id() != null
&& !oldGroup.getstorage_pool_id().equals(getVdsGroup().getstorage_pool_id())
|| oldGroup.getstorage_pool_id() == null
&& getVdsGroup().getstorage_pool_id() != null) {
for (VdsStatic vds : DbFacade.getInstance().getVdsStaticDAO().getAllForVdsGroup(oldGroup.getID())) {
VdsActionParameters parameters = new VdsActionParameters(vds.getId());
if (oldGroup.getstorage_pool_id() != null) {
VdcReturnValueBase removeVdsSpmIdReturn =
Backend.getInstance().runInternalAction(VdcActionType.RemoveVdsSpmId,
parameters);
if (!removeVdsSpmIdReturn.getSucceeded()) {
setSucceeded(false);
getReturnValue().setFault(removeVdsSpmIdReturn.getFault());
return;
}
}
if (getVdsGroup().getstorage_pool_id() != null) {
VdcReturnValueBase addVdsSpmIdReturn =
Backend.getInstance().runInternalAction(VdcActionType.AddVdsSpmId, parameters);
if (!addVdsSpmIdReturn.getSucceeded()) {
setSucceeded(false);
getReturnValue().setFault(addVdsSpmIdReturn.getFault());
return;
}
}
}
}
// when changing data center we check that default networks exists in
// cluster
List<network> networks = DbFacade.getInstance().getNetworkDAO()
.getAllForCluster(getVdsGroup().getID());
boolean exists = false;
String managementNetwork = Config.<String> GetValue(ConfigValues.ManagementNetwork);
for (network net : networks) {
if (StringHelper.EqOp(net.getname(), managementNetwork)) {
exists = true;
}
}
if (!exists) {
if (getVdsGroup().getstorage_pool_id() != null) {
List<network> storagePoolNets = DbFacade
.getInstance()
.getNetworkDAO()
.getAllForDataCenter(
getVdsGroup().getstorage_pool_id()
.getValue());
for (network net : storagePoolNets) {
if (StringHelper.EqOp(net.getname(), managementNetwork)) {
DbFacade.getInstance().getNetworkClusterDAO().save(
new network_cluster(getVdsGroup().getID(), net.getId(),
NetworkStatus.Operational.getValue(), true));
}
}
}
}
setSucceeded(true);
}
@Override
public AuditLogType getAuditLogTypeValue() {
if (getParameters().getIsInternalCommand()) {
return getSucceeded() ? AuditLogType.SYSTEM_UPDATE_VDS_GROUP
: AuditLogType.SYSTEM_UPDATE_VDS_GROUP_FAILED;
} else {
return getSucceeded() ? AuditLogType.USER_UPDATE_VDS_GROUP
: AuditLogType.USER_UPDATE_VDS_GROUP_FAILED;
}
}
@Override
protected boolean canDoAction() {
boolean result = super.canDoAction();
getReturnValue().getCanDoActionMessages()
.add(VdcBllMessages.VAR__ACTION__UPDATE.toString());
VDSGroup oldGroup = DbFacade.getInstance().getVdsGroupDAO().get(getVdsGroup().getID());
// check that if name was changed, it was done to the same cluster
VDSGroup groupWithName = DbFacade.getInstance().getVdsGroupDAO().getByName(
getVdsGroup().getname());
if (oldGroup != null && !StringHelper.EqOp(oldGroup.getname(), getVdsGroup().getname())) {
if (groupWithName != null && !groupWithName.getID().equals(getVdsGroup().getID())) {
addCanDoActionMessage(VdcBllMessages.VDS_GROUP_CANNOT_DO_ACTION_NAME_IN_USE);
result = false;
}
}
if (oldGroup == null) {
addCanDoActionMessage(VdcBllMessages.VDS_CLUSTER_IS_NOT_VALID);
result = false;
}
// If both original Cpu and new Cpu are null, don't check Cpu validity
if (result && (oldGroup.getcpu_name() != null || getVdsGroup().getcpu_name() != null)) {
// Check that cpu exist
if (!CpuFlagsManagerHandler.CheckIfCpusExist(getVdsGroup().getcpu_name(), getVdsGroup()
.getcompatibility_version())) {
addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_CPU_NOT_FOUND);
addCanDoActionMessage(VdcBllMessages.VAR__TYPE__CLUSTER);
result = false;
} else {
// if cpu changed from intel to amd (or backwards) and there are
// vds in this cluster, cannot update
if (!StringHelper.isNullOrEmpty(oldGroup.getcpu_name())
&& !CpuFlagsManagerHandler.CheckIfCpusSameManufacture(oldGroup
.getcpu_name(), getVdsGroup().getcpu_name(), getVdsGroup()
.getcompatibility_version())
&& DbFacade.getInstance().getVdsStaticDAO().getAllForVdsGroup(getVdsGroup().getID())
.size() > 0) {
addCanDoActionMessage(VdcBllMessages.VDS_GROUP_CANNOT_UPDATE_CPU_ILLEGAL);
result = false;
}
}
}
if (result && !VersionSupport.checkVersionSupported(getVdsGroup()
.getcompatibility_version())) {
addCanDoActionMessage(VersionSupport.getUnsupportedVersionMessage());
result = false;
}
// decreasing of compatibility version is not allowed
if (result && getVdsGroup().getcompatibility_version().compareTo(
oldGroup.getcompatibility_version()) < 0) {
result = false;
getReturnValue()
.getCanDoActionMessages()
.add(VdcBllMessages.ACTION_TYPE_FAILED_CANNOT_DECREASE_COMPATIBILITY_VERSION
.toString());
}
if (result) {
SearchParameters p = new SearchParameters(MessageFormat.format(
StorageHandlingCommandBase.UpVdssInCluster, oldGroup.getname()),
SearchType.VDS);
p.setMaxCount(Integer.MAX_VALUE);
Iterable<VDS> clusterUpVdss = (Iterable<VDS>) Backend.getInstance()
.runInternalQuery(VdcQueryType.Search, p).getReturnValue();
for (VDS vds : clusterUpVdss) {
if (!VersionSupport.checkClusterVersionSupported(
getVdsGroup().getcompatibility_version(), vds)) {
result = false;
getReturnValue()
.getCanDoActionMessages()
.add(VdcBllMessages.VDS_GROUP_CANNOT_UPDATE_COMPATIBILITY_VERSION_WITH_LOWER_HOSTS
.toString());
break;
} else if (CpuFlagsManagerHandler.missingServerCpuFlags(getVdsGroup()
.getcpu_name(), vds.getcpu_flags(), getVdsGroup()
.getcompatibility_version()) != null) {
getReturnValue().getCanDoActionMessages().add(
VdcBllMessages.VDS_GROUP_CANNOT_UPDATE_CPU_WITH_LOWER_HOSTS
.toString());
result = false;
break;
}
}
}
if (result && (oldGroup.getstorage_pool_id() != null
&& !oldGroup.getstorage_pool_id().equals(getVdsGroup().getstorage_pool_id()))) {
addCanDoActionMessage(VdcBllMessages.VDS_GROUP_CANNOT_CHANGE_STORAGE_POOL);
result = false;
}
if (result) {
SearchParameters searchParams = new SearchParameters("vms: cluster = "
+ oldGroup.getname(), SearchType.VM);
searchParams.setMaxCount(Integer.MAX_VALUE);
List<VM> vmList = (List) Backend.getInstance()
.runInternalQuery(VdcQueryType.Search, searchParams).getReturnValue();
int notDownVms = 0;
int suspendedVms = 0;
for (VM vm : vmList) {
// the search can return vm from cluster with similar name
// so it's critical to check that
// the vm cluster id is the same as the cluster.id
if (!vm.getvds_group_id().equals(oldGroup.getID())) {
continue;
}
VMStatus vmStatus = vm.getstatus();
if (vmStatus == VMStatus.Suspended) {
suspendedVms++;
}
if (vmStatus != VMStatus.Down) {
notDownVms++;
}
}
if (notDownVms > 0
&& !oldGroup.getcompatibility_version().equals(getVdsGroup().getcompatibility_version())) {
result = false;
addCanDoActionMessage(VdcBllMessages.VDS_GROUP_CANNOT_UPDATE_COMPATIBILITY_VERSION_WITH_RUNNING_VMS);
}
boolean sameCpuNames = StringHelper.EqOp(oldGroup.getcpu_name(), getVdsGroup().getcpu_name());
if (result && !sameCpuNames) {
if (suspendedVms > 0) {
addCanDoActionMessage(VdcBllMessages.VDS_GROUP_CANNOT_UPDATE_CPU_WITH_SUSPENDED_VMS);
result = false;
} else if (notDownVms > 0) {
int compareResult =
CpuFlagsManagerHandler.compareCpuLevels(getVdsGroup().getcpu_name(),
oldGroup.getcpu_name(),
oldGroup.getcompatibility_version());
if (compareResult < 0) {
addCanDoActionMessage(VdcBllMessages.VDS_GROUP_CANNOT_LOWER_CPU_LEVEL);
result = false;
} else if (compareResult > 0) {// Upgrade of CPU in same compability level is allowed if there
// are running VMs - but we should warn they
// cannot not be hibernated
AuditLogableBase logable = new AuditLogableBase();
logable.AddCustomValue("VdsGroup", getParameters().getVdsGroup().getname());
AuditLogDirector.log(logable,
AuditLogType.CANNOT_HIBERNATE_RUNNING_VMS_AFTER_CLUSTER_CPU_UPGRADE);
}
}
}
}
if (result && getVdsGroup().getstorage_pool_id() != null) {
storage_pool storagePool = DbFacade.getInstance().getStoragePoolDAO().get(
getVdsGroup().getstorage_pool_id().getValue());
if (oldGroup.getstorage_pool_id() == null && storagePool.getstorage_pool_type() == StorageType.LOCALFS) {
// we allow only one cluster in localfs data center
if (!DbFacade
.getInstance()
.getVdsGroupDAO().getAllForStoragePool(
getVdsGroup().getstorage_pool_id().getValue()).isEmpty()) {
getReturnValue()
.getCanDoActionMessages()
.add(VdcBllMessages.VDS_GROUP_CANNOT_ADD_MORE_THEN_ONE_HOST_TO_LOCAL_STORAGE
.toString());
result = false;
}
// selection algorithm must be set to none in localfs
else if (getVdsGroup().getselection_algorithm() != VdsSelectionAlgorithm.None) {
getReturnValue()
.getCanDoActionMessages()
.add(VdcBllMessages.VDS_GROUP_SELECTION_ALGORITHM_MUST_BE_SET_TO_NONE_ON_LOCAL_STORAGE
.toString());
result = false;
}
else if(VDSGroup.DEFAULT_VDS_GROUP_ID.equals(getVdsGroup().getID())) {
addCanDoActionMessage(VdcBllMessages.DEFAULT_CLUSTER_CANNOT_BE_ON_LOCALFS);
result = false;
}
}
}
if (result) {
result = validateMetrics();
}
return result;
}
@Override
protected List<Class<?>> getValidationGroups() {
addValidationGroup(UpdateEntity.class);
return super.getValidationGroups();
}
}