package org.ovirt.engine.core.bll;
import java.util.List;
import java.util.Map.Entry;
import javax.inject.Inject;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.job.ExecutionContext;
import org.ovirt.engine.core.bll.job.ExecutionHandler;
import org.ovirt.engine.core.common.AuditLogType;
import org.ovirt.engine.core.common.action.SetNonOperationalVdsParameters;
import org.ovirt.engine.core.common.businessentities.NonOperationalReason;
import org.ovirt.engine.core.common.businessentities.VDSStatus;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterBrickEntity;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterStatus;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.dao.gluster.GlusterBrickDao;
import org.ovirt.engine.core.utils.threadpool.ThreadPoolUtil;
/**
* This command will try to migrate all the vds vms (if needed) and move the vds
* to Non-Operational state
*/
@SuppressWarnings("serial")
@NonTransactiveCommandAttribute
public class SetNonOperationalVdsCommand<T extends SetNonOperationalVdsParameters> extends MaintenanceVdsCommand<T> {
@Inject
private GlusterBrickDao glusterBrickDao;
public SetNonOperationalVdsCommand(T parameters, CommandContext commandContext) {
super(parameters, commandContext);
setStorageDomainId(parameters.getStorageDomainId());
}
/**
* Note: it's ok that this method isn't marked as async command even though it triggers
* migrations as sub-commands, because those migrations are executed as different jobs
*/
@Override
protected void executeCommand() {
setVdsStatus(VDSStatus.NonOperational, getParameters().getNonOperationalReason());
if (getCluster() != null && getCluster().supportsGlusterService()) {
updateBrickStatusDown();
}
// if host failed to recover, no point in sending migrate, as it would fail.
if (getParameters().getNonOperationalReason() != NonOperationalReason.TIMEOUT_RECOVERING_FROM_CRASH) {
orderListOfRunningVmsOnVds(getVdsId());
ThreadPoolUtil.execute(() -> {
// migrate vms according to cluster migrateOnError option
switch (getCluster().getMigrateOnError()) {
case YES:
migrateAllVms(getExecutionContext());
break;
case HA_ONLY:
migrateAllVms(getExecutionContext(), true);
break;
default:
break;
}
});
}
if (getParameters().getNonOperationalReason() == NonOperationalReason.NETWORK_UNREACHABLE) {
log.error("Host '{}' is set to Non-Operational, it is missing the following networks: '{}'",
getVds().getName(), getParameters().getCustomLogValues().get("Networks"));
}
if (getParameters().getNonOperationalReason() == NonOperationalReason.VM_NETWORK_IS_BRIDGELESS) {
log.error("Host '{}' is set to Non-Operational, the following networks are implemented as non-VM"
+ " instead of a VM networks: '{}'",
getVds().getName(), getParameters().getCustomLogValues().get("Networks"));
}
setSucceeded(true);
}
private void updateBrickStatusDown() {
List<GlusterBrickEntity> brickEntities = glusterBrickDao.getGlusterVolumeBricksByServerId(getVdsId());
for (GlusterBrickEntity brick : brickEntities) {
brick.setStatus(GlusterStatus.DOWN);
}
glusterBrickDao.updateBrickStatuses(brickEntities);
}
@Override
protected CommandContext createMigrateVmContext(ExecutionContext parentContext, VM vm) {
return ExecutionHandler.createInternalJobContext(getContext());
}
@Override
protected boolean validate() {
if (getVds() == null) {
return failValidation(EngineMessage.VDS_INVALID_SERVER_ID);
}
return true;
}
@Override
public AuditLogType getAuditLogTypeValue() {
for (Entry<String, String> e : getParameters().getCustomLogValues().entrySet()) {
addCustomValue(e.getKey(), e.getValue());
}
switch (getParameters().getNonOperationalReason()) {
case NETWORK_UNREACHABLE:
return getSucceeded() ? AuditLogType.VDS_SET_NONOPERATIONAL_NETWORK
: AuditLogType.VDS_SET_NONOPERATIONAL_FAILED;
case STORAGE_DOMAIN_UNREACHABLE:
return getSucceeded() ? AuditLogType.VDS_SET_NONOPERATIONAL_DOMAIN
: AuditLogType.VDS_SET_NONOPERATIONAL_DOMAIN_FAILED;
case TIMEOUT_RECOVERING_FROM_CRASH:
return AuditLogType.VDS_RECOVER_FAILED;
case KVM_NOT_RUNNING:
return AuditLogType.VDS_RUN_IN_NO_KVM_MODE;
case VERSION_INCOMPATIBLE_WITH_CLUSTER:
return AuditLogType.VDS_VERSION_NOT_SUPPORTED_FOR_CLUSTER;
case CLUSTER_VERSION_INCOMPATIBLE_WITH_CLUSTER:
return AuditLogType.VDS_CLUSTER_VERSION_NOT_SUPPORTED;
case VM_NETWORK_IS_BRIDGELESS:
return AuditLogType.VDS_SET_NON_OPERATIONAL_VM_NETWORK_IS_BRIDGELESS;
case GLUSTER_COMMAND_FAILED:
return AuditLogType.GLUSTER_COMMAND_FAILED;
case GLUSTER_HOST_UUID_NOT_FOUND:
return AuditLogType.GLUSTER_HOST_UUID_NOT_FOUND;
case GLUSTER_HOST_UUID_ALREADY_EXISTS:
return AuditLogType.GLUSTER_HOST_UUID_ALREADY_EXISTS;
case EMULATED_MACHINES_INCOMPATIBLE_WITH_CLUSTER:
return AuditLogType.EMULATED_MACHINES_INCOMPATIBLE_WITH_CLUSTER;
case EMULATED_MACHINES_INCOMPATIBLE_WITH_CLUSTER_LEVEL:
return AuditLogType.EMULATED_MACHINES_INCOMPATIBLE_WITH_CLUSTER_LEVEL;
case RNG_SOURCES_INCOMPATIBLE_WITH_CLUSTER:
return AuditLogType.RNG_SOURCES_INCOMPATIBLE_WITH_CLUSTER;
case MIXING_RHEL_VERSIONS_IN_CLUSTER:
return AuditLogType.MIXING_RHEL_VERSIONS_IN_CLUSTER;
case UNTRUSTED:
return AuditLogType.VDS_UNTRUSTED;
case HOST_FEATURES_INCOMPATIBILE_WITH_CLUSTER:
return AuditLogType.HOST_FEATURES_INCOMPATIBILE_WITH_CLUSTER;
case LIBRBD_PACKAGE_NOT_AVAILABLE:
return AuditLogType.NO_LIBRBD_PACKAGE_AVAILABLE_ON_VDS;
case VDS_CANNOT_CONNECT_TO_GLUSTERFS:
return AuditLogType.VDS_CANNOT_CONNECT_TO_GLUSTERFS;
default:
return getSucceeded() ? AuditLogType.VDS_SET_NONOPERATIONAL : AuditLogType.VDS_SET_NONOPERATIONAL_FAILED;
}
}
}