package org.ovirt.engine.api.restapi.resource; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import org.ovirt.engine.api.model.Action; import org.ovirt.engine.api.model.BaseResource; import org.ovirt.engine.api.model.Disk; import org.ovirt.engine.api.model.StorageDomain; import org.ovirt.engine.api.model.Vm; import org.ovirt.engine.api.model.Vms; import org.ovirt.engine.api.resource.ActionResource; import org.ovirt.engine.api.resource.AssignedPermissionsResource; import org.ovirt.engine.api.resource.CreationResource; import org.ovirt.engine.api.resource.DiskResource; import org.ovirt.engine.api.resource.StatisticsResource; import org.ovirt.engine.api.restapi.types.DiskMapper; import org.ovirt.engine.api.restapi.util.LinkHelper; import org.ovirt.engine.core.common.VdcObjectType; import org.ovirt.engine.core.common.action.AmendImageGroupVolumesCommandParameters; import org.ovirt.engine.core.common.action.ExportRepoImageParameters; import org.ovirt.engine.core.common.action.MoveDiskParameters; import org.ovirt.engine.core.common.action.MoveDisksParameters; import org.ovirt.engine.core.common.action.MoveOrCopyImageGroupParameters; import org.ovirt.engine.core.common.action.RemoveDiskParameters; import org.ovirt.engine.core.common.action.StorageJobCommandParameters; import org.ovirt.engine.core.common.action.VdcActionParametersBase; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.businessentities.storage.ImageOperation; import org.ovirt.engine.core.common.businessentities.storage.QcowCompat; import org.ovirt.engine.core.common.queries.GetPermissionsForObjectParameters; import org.ovirt.engine.core.common.queries.IdQueryParameters; import org.ovirt.engine.core.common.queries.VdcQueryReturnValue; import org.ovirt.engine.core.common.queries.VdcQueryType; import org.ovirt.engine.core.compat.Guid; public class BackendDiskResource extends AbstractBackendActionableResource<Disk, org.ovirt.engine.core.common.businessentities.storage.Disk> implements DiskResource { protected BackendDiskResource(String id) { super(id, Disk.class, org.ovirt.engine.core.common.businessentities.storage.Disk.class); } @Override public CreationResource getCreationResource(String ids) { return inject(new BackendCreationResource(ids)); } @Override public StatisticsResource getStatisticsResource() { QueryIdResolver<Guid> resolver = new QueryIdResolver<>(VdcQueryType.GetDiskByDiskId, IdQueryParameters.class); DiskStatisticalQuery query = new DiskStatisticalQuery(resolver, newModel(id)); return inject(new BackendStatisticsResource<>(entityType, guid, query)); } @Override public AssignedPermissionsResource getPermissionsResource() { return inject(new BackendAssignedPermissionsResource(guid, VdcQueryType.GetPermissionsForObject, new GetPermissionsForObjectParameters(guid), Disk.class, VdcObjectType.Disk)); } @Override public Response export(Action action) { validateParameters(action, "storageDomain.id|name"); return doAction(VdcActionType.ExportRepoImage, new ExportRepoImageParameters(guid, getStorageDomainId(action)), action); } @Override public Disk update(Disk incoming) { // If the QCOW version is specified, then perform the update: if (incoming.isSetQcowVersion()) { return performUpdate( incoming, new QueryIdResolver<>(VdcQueryType.GetDiskByDiskId, IdQueryParameters.class), VdcActionType.AmendImageGroupVolumes, new UpdateParametersProvider()); } // If the QCOW version isn't specified, then just retrieve the disk: return get(); } protected class UpdateParametersProvider implements ParametersProvider<Disk, org.ovirt.engine.core.common.businessentities.storage.Disk> { public VdcActionParametersBase getParameters( Disk incoming, org.ovirt.engine.core.common.businessentities.storage.Disk entity) { QcowCompat qcowCompat = DiskMapper.mapQcowVersion(incoming.getQcowVersion()); return new AmendImageGroupVolumesCommandParameters(guid, qcowCompat); } } @Override public ActionResource getActionResource(String action, String oid) { return inject(new BackendActionResource(action, oid)); } @Override public Response move(Action action) { validateParameters(action, "storageDomain.id|name"); Guid storageDomainId = getStorageDomainId(action); Disk disk = get(); Guid imageId = getDiskImageId(disk.getImageId()); Guid sourceStorageDomainId = getSourceStorageDomainId(disk); MoveDiskParameters innerParams = new MoveDiskParameters( imageId, sourceStorageDomainId, storageDomainId); innerParams.setImageGroupID(asGuid(disk.getId())); MoveDisksParameters params = new MoveDisksParameters(Collections.singletonList(innerParams)); return doAction(VdcActionType.MoveDisks, params, action); } protected Guid getSourceStorageDomainId(Disk disk) { if (disk.isSetStorageDomains()) { StorageDomain storageDomain = disk.getStorageDomains().getStorageDomains().get(0); if (storageDomain != null) { return asGuid(storageDomain.getId()); } } return null; } protected Guid getDiskImageId(String id) { if (id == null) { return null; } return asGuid(id); } @Override public Response copy(Action action) { validateParameters(action, "storageDomain.id|name"); Guid storageDomainId = getStorageDomainId(action); Disk disk = get(); Guid imageId = getDiskImageId(disk.getImageId()); Guid sourceStorageDomainId = getSourceStorageDomainId(disk); MoveOrCopyImageGroupParameters params = new MoveOrCopyImageGroupParameters(imageId, sourceStorageDomainId, storageDomainId, ImageOperation.Copy); params.setImageGroupID(asGuid(disk.getId())); Disk actionDisk = action.getDisk(); if (actionDisk != null) { String name = actionDisk.getName(); String alias = actionDisk.getAlias(); if (name != null && !StringUtils.isEmpty(name)) { params.setNewAlias(name); } else if (alias != null && !StringUtils.isEmpty(alias)) { params.setNewAlias(alias); } } return doAction(VdcActionType.MoveOrCopyDisk, params, action); } @Override public Disk get() { return performGet(VdcQueryType.GetDiskByDiskId, new IdQueryParameters(guid)); } @Override protected Disk doPopulate(Disk model, org.ovirt.engine.core.common.businessentities.storage.Disk entity) { // Populate the references to the VMs that are using this disk: List<org.ovirt.engine.core.common.businessentities.VM> vms = new ArrayList<>(1); VdcQueryReturnValue result = runQuery(VdcQueryType.GetVmsByDiskGuid, new IdQueryParameters(entity.getId())); if (result.getSucceeded()) { Map<Boolean, List<org.ovirt.engine.core.common.businessentities.VM>> map = result.getReturnValue(); if (MapUtils.isNotEmpty(map)) { for (List<org.ovirt.engine.core.common.businessentities.VM> list : map.values()) { vms.addAll(list); } } } if (CollectionUtils.isNotEmpty(vms)) { Vms modelVms = new Vms(); for (org.ovirt.engine.core.common.businessentities.VM vm : vms) { Vm modelVm = new Vm(); modelVm.setId(vm.getId().toString()); modelVms.getVms().add(modelVm); } model.setVms(modelVms); } return model; } @Override public Response remove() { get(); return performAction(VdcActionType.RemoveDisk, new RemoveDiskParameters(guid)); } @Override public Response sparsify(Action action) { Disk disk = get(); if (disk == null) { throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); } Guid imageId = getDiskImageId(disk.getImageId()); StorageJobCommandParameters params = new StorageJobCommandParameters(imageId); return doAction(VdcActionType.SparsifyImage, params, action); } protected Disk addLinks(Disk model, Class<? extends BaseResource> suggestedParent, String... subCollectionMembersToExclude) { // Currently the method that adds the links doesn't take into account that links need to be added also to // elements of lists, so whe need to add them explicitly: Disk disk = super.addLinks(model, suggestedParent, subCollectionMembersToExclude); if (disk.isSetStorageDomains()) { disk.getStorageDomains().getStorageDomains().forEach( storageDomain -> LinkHelper.addLinks(storageDomain, null, false) ); } return disk; } }