package org.ovirt.engine.api.restapi.resource.gluster; import java.net.URI; import java.util.ArrayList; import java.util.List; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; import org.ovirt.engine.api.model.Action; import org.ovirt.engine.api.model.Cluster; import org.ovirt.engine.api.model.Fault; import org.ovirt.engine.api.model.GlusterBrick; import org.ovirt.engine.api.model.GlusterBricks; import org.ovirt.engine.api.model.GlusterVolume; import org.ovirt.engine.api.resource.ActionResource; import org.ovirt.engine.api.resource.gluster.GlusterBrickResource; import org.ovirt.engine.api.resource.gluster.GlusterBricksResource; import org.ovirt.engine.api.restapi.logging.Messages; import org.ovirt.engine.api.restapi.resource.AbstractBackendCollectionResource; import org.ovirt.engine.api.restapi.resource.BackendActionResource; import org.ovirt.engine.api.restapi.util.ParametersHelper; import org.ovirt.engine.core.common.action.VdcActionParametersBase; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.action.VdcReturnValueBase; import org.ovirt.engine.core.common.action.gluster.GlusterVolumeBricksActionParameters; import org.ovirt.engine.core.common.action.gluster.GlusterVolumeRemoveBricksParameters; 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.GlusterVolumeAdvancedDetails; import org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeEntity; import org.ovirt.engine.core.common.job.JobExecutionStatus; import org.ovirt.engine.core.common.queries.IdQueryParameters; import org.ovirt.engine.core.common.queries.VdcQueryType; import org.ovirt.engine.core.common.queries.gluster.GlusterVolumeAdvancedDetailsParameters; import org.ovirt.engine.core.compat.Guid; public class BackendGlusterBricksResource extends AbstractBackendCollectionResource<GlusterBrick, GlusterBrickEntity> implements GlusterBricksResource { public static final String REPLICA_COUNT = "replica_count"; public static final String STRIPE_COUNT = "stripe_count"; private BackendGlusterVolumeResource parent; public BackendGlusterBricksResource() { super(GlusterBrick.class, GlusterBrickEntity.class); } public BackendGlusterBricksResource(BackendGlusterVolumeResource parent) { super(GlusterBrick.class, GlusterBrickEntity.class); setParent(parent); } @SuppressWarnings("unchecked") @Override public GlusterBricks list() { List<GlusterBrickEntity> bricks = getBackendCollection(VdcQueryType.GetGlusterVolumeBricks, new IdQueryParameters(asGuid(getVolumeId()))); GlusterBricks bricksModel = mapCollection(bricks); return addActions(bricksModel); } private GlusterBricks mapCollection(List<GlusterBrickEntity> entities) { GlusterBricks collection = new GlusterBricks(); for (GlusterBrickEntity entity : entities) { collection.getGlusterBricks().add(addLinks(populate(map(entity), entity), Cluster.class)); } return collection; } @Override protected GlusterBrick addParents(GlusterBrick glusterBrick) { GlusterVolume volume = new GlusterVolume(); parent.addParents(volume); glusterBrick.setGlusterVolume(volume); return glusterBrick; } private List<GlusterBrickEntity> mapBricks(Guid volumeId, GlusterBricks glusterBricks) { List<GlusterBrickEntity> bricks = new ArrayList<>(); if (glusterBricks.getGlusterBricks().size() > 0) { for (GlusterBrick brick : glusterBricks.getGlusterBricks()) { GlusterBrickEntity brickEntity = getMapper(GlusterBrick.class, GlusterBrickEntity.class).map(brick, null); brickEntity.setVolumeId(volumeId); bricks.add(brickEntity); } } return bricks; } @Override public Response add(GlusterBricks bricks) { for (GlusterBrick brick : bricks.getGlusterBricks()) { validateParameters(brick, "serverId", "brickDir"); } List<GlusterBrickEntity> brickEntities = mapBricks(asGuid(getVolumeId()), bricks); int replicaCount = ParametersHelper.getIntegerParameter(httpHeaders, uriInfo, REPLICA_COUNT, 0, 0); int stripeCount = ParametersHelper.getIntegerParameter(httpHeaders, uriInfo, STRIPE_COUNT, 0, 0); return performCreationMultiple(VdcActionType.AddBricksToGlusterVolume, new GlusterVolumeBricksActionParameters(asGuid(getVolumeId()), brickEntities, replicaCount, stripeCount, isForce()), new QueryIdResolver<>(VdcQueryType.GetGlusterBrickById, IdQueryParameters.class)); } private String getVolumeId() { return parent.get().getId(); } @SuppressWarnings("unchecked") protected GlusterBricks resolveCreatedList(VdcReturnValueBase result, EntityIdResolver<Guid> entityResolver) { try { GlusterBricks bricks = new GlusterBricks(); for (Guid id : (List<Guid>) result.getActionReturnValue()) { GlusterBrickEntity created = entityResolver.resolve(id); bricks.getGlusterBricks().add(addLinks(populate(map(created), created))); } return bricks; } catch (Exception e) { // we tolerate a failure in the entity resolution // as the substantive action (entity creation) has // already succeeded e.printStackTrace(); return null; } } protected Response performCreationMultiple(VdcActionType task, VdcActionParametersBase taskParams, EntityIdResolver<Guid> entityResolver) { VdcReturnValueBase createResult; try { createResult = doAction(task, taskParams); } catch (Exception e) { return handleError(e, false); } GlusterBricks model = resolveCreatedList(createResult, entityResolver); Response response = null; if (model == null) { response = Response.status(ACCEPTED_STATUS).build(); } else { response = Response.created(URI.create(getUriInfo().getPath())).entity(model).build(); } return response; } @Override public Response remove(Action action) { GlusterBricks bricks = action.getBricks(); if (bricks.getGlusterBricks().size() > 0) { for (GlusterBrick brick : bricks.getGlusterBricks()) { validateParameters(brick, "id|name"); } } int replicaCount = ParametersHelper.getIntegerParameter(httpHeaders, uriInfo, REPLICA_COUNT, 0, 0); GlusterVolumeRemoveBricksParameters params = toParameters(bricks); params.setReplicaCount(replicaCount); GlusterVolumeEntity volume = getEntity(GlusterVolumeEntity.class, VdcQueryType.GetGlusterVolumeById, new IdQueryParameters(asGuid(getVolumeId())), ""); if (volume.getAsyncTask() != null && volume.getAsyncTask().getType() == GlusterTaskType.REMOVE_BRICK && volume.getAsyncTask().getStatus() == JobExecutionStatus.FINISHED) { return performAction(VdcActionType.CommitRemoveGlusterVolumeBricks, params); } else { return performAction(VdcActionType.GlusterVolumeRemoveBricks, params); } } @Override public GlusterBrickResource getBrickResource(String brickId) { return inject(new BackendGlusterBrickResource(brickId, this)); } public BackendGlusterVolumeResource getParent() { return parent; } public void setParent(BackendGlusterVolumeResource parent) { this.parent = parent; } @Override protected GlusterBrick doPopulate(GlusterBrick model, GlusterBrickEntity entity) { return populateAdvancedDetails(model, entity); } protected GlusterBrick populateAdvancedDetails(GlusterBrick model, GlusterBrickEntity entity) { GlusterVolumeEntity volumeEntity = getEntity(GlusterVolumeEntity.class, VdcQueryType.GetGlusterVolumeById, new IdQueryParameters(entity.getVolumeId()), null, true); GlusterVolumeAdvancedDetails detailsEntity = getEntity(GlusterVolumeAdvancedDetails.class, VdcQueryType.GetGlusterVolumeAdvancedDetails, new GlusterVolumeAdvancedDetailsParameters(volumeEntity.getClusterId(), volumeEntity.getId(), entity.getId(), true), null, true); model = getMapper(GlusterVolumeAdvancedDetails.class, GlusterBrick.class) .map(detailsEntity, model); return model; } private GlusterVolumeRemoveBricksParameters toParameters(GlusterBricks bricks) { GlusterVolumeRemoveBricksParameters params = new GlusterVolumeRemoveBricksParameters(); List<GlusterBrickEntity> entityBricks = new ArrayList<>(); for (GlusterBrick brick : bricks.getGlusterBricks()) { GlusterBrickEntity entity = new GlusterBrickEntity(); entity.setBrickDirectory(brick.getBrickDir()); entity.setVolumeId(asGuid(getVolumeId())); if (brick.getName() != null) { String[] arr = brick.getName().split("\\:"); if (arr.length > 1) { entity.setServerName(arr[0]); entity.setBrickDirectory(arr[1]); } else { continue; } } if (brick.getId() != null) { entity.setId(asGuid(brick.getId())); } entityBricks.add(entity); } params.setVolumeId(asGuid(getVolumeId())); params.setBricks(entityBricks); params.setCommandType(VdcActionType.StartRemoveGlusterVolumeBricks); return params; } private void validateBrickNames(Action action) { List<GlusterBrick> bricks = action.getBricks().getGlusterBricks(); for (GlusterBrick brick : bricks) { if (brick.getName() == null || brick.getName().equals("")) { Fault fault = new Fault(); fault.setReason(localize(Messages.INCOMPLETE_PARAMS_REASON)); throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) .entity(fault) .build()); } } } @Override public Response migrate(Action action) { validateParameters(action, "bricks"); validateBrickNames(action); GlusterVolumeRemoveBricksParameters params = toParameters(action.getBricks()); return performAction(VdcActionType.StartRemoveGlusterVolumeBricks, params, action, false); } @Override public Response stopMigrate(Action action) { validateParameters(action, "bricks"); validateBrickNames(action); GlusterVolumeRemoveBricksParameters params = toParameters(action.getBricks()); return performAction(VdcActionType.StopRemoveGlusterVolumeBricks, params, action, false); } @Override public Response activate(Action action) { validateParameters(action, "bricks"); validateBrickNames(action); GlusterVolumeEntity volume = getEntity(GlusterVolumeEntity.class, VdcQueryType.GetGlusterVolumeById, new IdQueryParameters(asGuid(getVolumeId())), ""); if (volume.getAsyncTask() != null && volume.getAsyncTask().getType() == GlusterTaskType.REMOVE_BRICK && volume.getAsyncTask().getStatus() == JobExecutionStatus.FINISHED) { return stopMigrate(action); } else { Fault fault = new Fault(); fault.setReason(localize(Messages.CANNOT_ACTIVATE_UNLESS_MIGRATION_COMPLETED)); throw new WebApplicationException(Response.status(Response.Status.CONFLICT) .entity(fault) .build()); } } @Override public ActionResource getActionResource(String action, String id) { return inject(new BackendActionResource(action, id)); } }