package org.ovirt.engine.core.bll;
import java.util.Arrays;
import java.util.List;
import javax.inject.Inject;
import org.ovirt.engine.core.bll.tasks.CommandCoordinatorUtil;
import org.ovirt.engine.core.bll.tasks.interfaces.CommandCallback;
import org.ovirt.engine.core.common.action.MaintenanceVdsParameters;
import org.ovirt.engine.core.common.businessentities.CommandEntity;
import org.ovirt.engine.core.common.businessentities.VdsDynamic;
import org.ovirt.engine.core.common.businessentities.VdsStatic;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterBrickEntity;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterStatus;
import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
import org.ovirt.engine.core.common.vdscommands.VdsIdVDSCommandParametersBase;
import org.ovirt.engine.core.common.vdscommands.gluster.GlusterServiceVDSParameters;
import org.ovirt.engine.core.compat.CommandStatus;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dao.VdsDynamicDao;
import org.ovirt.engine.core.dao.VdsStaticDao;
import org.ovirt.engine.core.dao.gluster.GlusterBrickDao;
import org.ovirt.engine.core.vdsbroker.ResourceManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* {@code HostMaintenanceCallback} monitors the transition of host to maintenance mode. Once the host is moved to
* maintenance mode, the callback will stop Gluster services on the host so that maintenance activities can be done on
* the host.
*/
public class HostMaintenanceCallback implements CommandCallback {
private String hostName;
private static final Logger log = LoggerFactory.getLogger(HostMaintenanceCallback.class);
@Inject
private ResourceManager resourceManager;
@Inject
private VdsStaticDao vdsStaticDao;
@Inject
private VdsDynamicDao vdsDynamicDao;
@Inject
private GlusterBrickDao glusterBrickDao;
@Override
public void doPolling(Guid cmdId, List<Guid> childCmdIds) {
MaintenanceVdsCommand<MaintenanceVdsParameters> maintenanceCommand =
CommandCoordinatorUtil.retrieveCommand(cmdId);
evaluateMaintenanceHostCommandProgress(maintenanceCommand);
}
@Override
public void onFailed(Guid cmdId, List<Guid> childCmdIds) {
CommandCoordinatorUtil.removeAllCommandsInHierarchy(cmdId);
}
@Override
public void onSucceeded(Guid cmdId, List<Guid> childCmdIds) {
CommandCoordinatorUtil.removeAllCommandsInHierarchy(cmdId);
}
/**
* Evaluates the host status in regards to maintenance status: The host must move to {@code VDSStatus.Maintenance}
* in order to stop gluster service
*
* @param maintenanceCommand
* The root command
*/
private void evaluateMaintenanceHostCommandProgress(
MaintenanceVdsCommand<MaintenanceVdsParameters> maintenanceCommand) {
MaintenanceVdsParameters parameters = maintenanceCommand.getParameters();
VdsDynamic host = vdsDynamicDao.get(parameters.getVdsId());
switch (host.getStatus()) {
// Wait till moving to maintenance ends
case PreparingForMaintenance:
break;
// Stop Gluster processes
case Maintenance:
log.info("Host '{}' is on maintenance mode. Stoping all gluster services.",
getHostName(parameters.getVdsId()));
stopGlusterServices(parameters.getVdsId());
maintenanceCommand.setCommandStatus(CommandStatus.SUCCEEDED);
break;
// Any other status implies maintenance action failed, and the callback cannot proceed with stopping gluster's services
default:
if (isMaintenanceCommandExecuted(maintenanceCommand)) {
log.info("Host '{}' failed to move to maintenance mode. Could not stop Gluster services.",
getHostName(parameters.getVdsId()));
maintenanceCommand.setCommandStatus(CommandStatus.FAILED);
}
break;
}
}
private boolean isMaintenanceCommandExecuted(MaintenanceVdsCommand<MaintenanceVdsParameters> maintenanceCommand) {
CommandEntity maintenanceCmd = CommandCoordinatorUtil.getCommandEntity(maintenanceCommand.getCommandId());
return maintenanceCmd != null && maintenanceCmd.isExecuted();
}
private void stopGlusterServices(Guid vdsId) {
// Stop glusterd service first
boolean succeeded = resourceManager.runVdsCommand(VDSCommandType.ManageGlusterService,
new GlusterServiceVDSParameters(vdsId, Arrays.asList("glusterd"), "stop")).getSucceeded();
if (succeeded) {
// Stop other gluster related processes on the node
succeeded = resourceManager.runVdsCommand(VDSCommandType.StopGlusterProcesses,
new VdsIdVDSCommandParametersBase(vdsId)).getSucceeded();
// Mark the bricks as DOWN on this node
if (succeeded) {
List<GlusterBrickEntity> bricks = glusterBrickDao.getGlusterVolumeBricksByServerId(vdsId);
bricks.forEach(brick -> brick.setStatus(GlusterStatus.DOWN));
glusterBrickDao.updateBrickStatuses(bricks);
}
}
if (!succeeded) {
log.error("Failed to stop gluster services while moving the host '{}' to maintenance", getHostName(vdsId));
}
}
private String getHostName(Guid hostId) {
if (hostName == null) {
VdsStatic host = vdsStaticDao.get(hostId);
hostName = host == null ? null : host.getName();
}
return hostName;
}
}