package org.ovirt.engine.core.bll.validator.gluster; import java.util.List; import org.ovirt.engine.core.bll.ValidationResult; import org.ovirt.engine.core.common.asynctasks.gluster.GlusterAsyncTask; import org.ovirt.engine.core.common.asynctasks.gluster.GlusterTaskType; import org.ovirt.engine.core.common.businessentities.gluster.GlusterBrickEntity; import org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeEntity; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.ovirt.engine.core.dao.gluster.GlusterBrickDao; /** * Helps to validate the details of the bricks. * */ public class GlusterBrickValidator { /** * Checks that all brick ids passed are valid, also updating the bricks with server name and brick directory using * the brick objects obtained from the volume. * * @param bricks * The bricks to validate * @return true if all bricks have valid ids, else false */ public ValidationResult canRemoveBrick(List<GlusterBrickEntity> bricks, GlusterVolumeEntity volumeEntity, int replicaCount, boolean forceRemove) { if (replicaCount == 0) { replicaCount = volumeEntity.getReplicaCount(); } if (bricks.isEmpty()) { return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_BRICKS_REQUIRED); } if (volumeEntity.getBricks().size() == 1 || volumeEntity.getBricks().size() <= bricks.size()) { return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_CAN_NOT_REMOVE_ALL_BRICKS_FROM_VOLUME); } if (volumeEntity.getVolumeType().isReplicatedType()) { if (replicaCount == volumeEntity.getReplicaCount() - 1 && !forceRemove) { return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_CAN_NOT_REDUCE_REPLICA_COUNT_WITH_DATA_MIGRATION); } else if (replicaCount < volumeEntity.getReplicaCount() - 1) { return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_CAN_NOT_REDUCE_REPLICA_COUNT_MORE_THAN_ONE); } else if (replicaCount > volumeEntity.getReplicaCount()) { return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_CAN_NOT_INCREASE_REPLICA_COUNT); } } for (GlusterBrickEntity brick : bricks) { if (brick.getId(false) == null && brick.getQualifiedName() == null) { return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_BRICKS_REQUIRED); } GlusterBrickEntity brickFromVolume = volumeEntity.getBrickWithId(brick.getId()); if (brickFromVolume == null) { brickFromVolume = volumeEntity.getBrickWithQualifiedName(brick.getQualifiedName()); } if (brickFromVolume == null) { return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_GLUSTER_BRICK_INVALID); } else { // Fill required details from volume data brick.setId(brickFromVolume.getId()); brick.setServerName(brickFromVolume.getServerName()); brick.setBrickDirectory(brickFromVolume.getBrickDirectory()); } } if (!forceRemove) { return canRebalance(volumeEntity); } else { return ValidationResult.VALID; } } public ValidationResult canRebalance(GlusterVolumeEntity volumeEntity) { int replicaCount = 1; List<GlusterBrickEntity> bricks = volumeEntity.getBricks(); if (volumeEntity.getVolumeType().isReplicatedType()) { replicaCount = volumeEntity.getReplicaCount(); } int brickIndex = 0; int replicaIndex = 0; while (brickIndex < bricks.size()) { for (replicaIndex = 0; replicaIndex < replicaCount; replicaIndex++) { if (bricks.get(brickIndex + replicaIndex).isOnline()) { brickIndex = brickIndex + replicaCount; break; } } if (replicaIndex == replicaCount) { return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_ONE_OR_MORE_BRICKS_ARE_DOWN); } } return ValidationResult.VALID; } public ValidationResult canStopOrCommitRemoveBrick(GlusterVolumeEntity volumeEntity, List<GlusterBrickEntity> paramBricks) { GlusterAsyncTask asyncTask = volumeEntity.getAsyncTask(); if (asyncTask == null || asyncTask.getType() != GlusterTaskType.REMOVE_BRICK) { return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_GLUSTER_VOLUME_INVALID_TASK_TYPE); } if (paramBricks.isEmpty()) { return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_BRICKS_REQUIRED); } List<GlusterBrickEntity> bricksForTask = getGlusterBrickDao().getGlusterVolumeBricksByTaskId(asyncTask.getTaskId()); if (paramBricks.size() != bricksForTask.size() || !areBricksInTheList(volumeEntity, paramBricks, bricksForTask)) { return new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_GLUSTER_VOLUME_REMOVE_BRICKS_PARAMS_INVALID, String.format("$validBricks [%s]", getValidBrickNames(bricksForTask))); } return ValidationResult.VALID; } private boolean areBricksInTheList(GlusterVolumeEntity volumeEntity, final List<GlusterBrickEntity> bricks, final List<GlusterBrickEntity> searchBricks) { boolean found = false; for (GlusterBrickEntity paramBrick : bricks) { GlusterBrickEntity paramBrickFromVolume = volumeEntity.getBrickWithId(paramBrick.getId()); if (paramBrickFromVolume == null) { paramBrickFromVolume = volumeEntity.getBrickWithQualifiedName(paramBrick.getQualifiedName()); } // reset the flag for next round found = false; for (GlusterBrickEntity brick : searchBricks) { if (paramBrickFromVolume == null || paramBrickFromVolume.getId() == null) { return false; } // If parameter brick directory matches with any brick no need to continue further to check if (paramBrickFromVolume.getId().equals(brick.getId())) { found = true; break; } } if (!found) { return false; } } return found; } public GlusterBrickDao getGlusterBrickDao() { return DbFacade.getInstance().getGlusterBrickDao(); } private String getValidBrickNames(List<GlusterBrickEntity> bricksForTask) { if (bricksForTask.size() == 0) { return ""; } StringBuilder builder = new StringBuilder(); for (GlusterBrickEntity brick : bricksForTask) { builder.append(brick.getQualifiedName()); builder.append(", "); } return builder.substring(0, builder.length() - 2).toString(); } }