package org.ovirt.engine.core.bll; import java.util.Collections; import java.util.List; import javax.inject.Inject; import org.ovirt.engine.core.bll.context.CommandContext; import org.ovirt.engine.core.bll.tasks.CommandCoordinatorUtil; import org.ovirt.engine.core.bll.tasks.interfaces.CommandCallback; import org.ovirt.engine.core.bll.utils.PermissionSubject; import org.ovirt.engine.core.common.VdcObjectType; import org.ovirt.engine.core.common.action.ExtendImageSizeParameters; import org.ovirt.engine.core.common.action.MergeParameters; import org.ovirt.engine.core.common.action.RefreshVolumeParameters; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.action.VdcReturnValueBase; import org.ovirt.engine.core.common.businessentities.storage.ImageStatus; import org.ovirt.engine.core.compat.CommandStatus; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dao.ImageDao; @InternalCommandAttribute @NonTransactiveCommandAttribute public class MergeExtendCommand<T extends MergeParameters> extends CommandBase<T> { @Inject private ImageDao imageDao; public MergeExtendCommand(T parameters, CommandContext cmdContext) { super(parameters, cmdContext); } @Override public void executeCommand() { if (getParameters().getBaseImage().hasRawBlock()) { if (getParameters().getTopImage().getSize() != getParameters().getBaseImage().getSize()) { // Only raw base volumes on block storage need explicit extension extendImageSize(); } else if (getParameters().getBaseImage().getImageStatus() == ImageStatus.ILLEGAL) { // Refresh the image in case this is a Live Merge recovery from an execution that // extended the volume and updated the database but was unable to refresh the host. refreshImageOnHost(); } else { log.info("Base and top image sizes are the same; no extension required"); setCommandStatus(CommandStatus.SUCCEEDED); } } else { if (getParameters().getTopImage().getSize() != getParameters().getBaseImage().getSize()) { updateSizeInDb(); } else { log.info("Base and top image sizes are the same; no image size update required"); } setCommandStatus(CommandStatus.SUCCEEDED); } setSucceeded(true); } private void extendImageSize() { Guid diskImageId = getParameters().getBaseImage().getImageId(); long sizeInBytes = getParameters().getTopImage().getSize(); log.info("Extending size of base volume {} to {} bytes", diskImageId, sizeInBytes); ExtendImageSizeParameters parameters = new ExtendImageSizeParameters(diskImageId, sizeInBytes, true); parameters.setStoragePoolId(getParameters().getBaseImage().getStoragePoolId()); parameters.setStorageDomainId(getParameters().getBaseImage().getStorageIds().get(0)); parameters.setImageGroupID(getParameters().getBaseImage().getId()); parameters.setParentCommand(VdcActionType.MergeExtend); parameters.setParentParameters(getParameters()); CommandCoordinatorUtil.executeAsyncCommand( VdcActionType.ExtendImageSize, parameters, cloneContextAndDetachFromParent()); } private void refreshImageOnHost() { log.info("Refreshing volume {} on host {}", getParameters().getBaseImage().getImageId(), getParameters().getVdsId()); RefreshVolumeParameters parameters = new RefreshVolumeParameters( getParameters().getVdsId(), getParameters().getStoragePoolId(), getParameters().getStorageDomainId(), getParameters().getImageGroupId(), getParameters().getBaseImage().getImageId()); parameters.setParentCommand(VdcActionType.MergeExtend); parameters.setParentParameters(getParameters()); VdcReturnValueBase returnValue = runInternalAction(VdcActionType.RefreshVolume, parameters); setSucceeded(returnValue.getSucceeded()); if (!getSucceeded()) { log.error("Error refreshing volume {} on host {}, VMs using the volume" + " should be restarted to detect the new size."); } setCommandStatus(getSucceeded() ? CommandStatus.SUCCEEDED : CommandStatus.FAILED); } private void updateSizeInDb() { Guid diskImage = getParameters().getBaseImage().getImageId(); long sizeInBytes = getParameters().getTopImage().getSize(); log.info("Updating size of image {} to {}", diskImage, sizeInBytes); imageDao.updateImageSize(diskImage, sizeInBytes); } @Override public List<PermissionSubject> getPermissionCheckSubjects() { return Collections.singletonList(new PermissionSubject(getParameters().getStorageDomainId(), VdcObjectType.Storage, getActionType().getActionGroup())); } @Override public CommandCallback getCallback() { return new ConcurrentChildCommandsExecutionCallback(); } }