package org.ovirt.engine.api.restapi.resource; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import org.ovirt.engine.api.common.util.LinkHelper; import org.ovirt.engine.api.model.Disk; import org.ovirt.engine.api.model.Link; import org.ovirt.engine.api.model.Snapshot; import org.ovirt.engine.api.model.Snapshots; import org.ovirt.engine.api.model.VM; import org.ovirt.engine.api.resource.SnapshotResource; import org.ovirt.engine.api.resource.SnapshotsResource; import org.ovirt.engine.core.common.action.CreateAllSnapshotsFromVmParameters; import org.ovirt.engine.core.common.action.MergeSnapshotParamenters; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.businessentities.DiskImage; import org.ovirt.engine.core.common.queries.GetAllDisksByVmIdParameters; import org.ovirt.engine.core.common.queries.VdcQueryType; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.NGuid; public class BackendSnapshotsResource extends AbstractBackendCollectionResource<Snapshot, DiskImage> implements SnapshotsResource { protected Guid parentId; public BackendSnapshotsResource(Guid parentId) { super(Snapshot.class, DiskImage.class); this.parentId = parentId; } @Override public Snapshots list() { return mapCollection(getDisks()); } @Override public Response add(Snapshot snapshot) { validateParameters(snapshot, "description"); CreateAllSnapshotsFromVmParameters snapshotParams = new CreateAllSnapshotsFromVmParameters(parentId, snapshot.getDescription()); snapshotParams.setDisksList(getDrives()); return performCreation(VdcActionType.CreateAllSnapshotsFromVm, snapshotParams, getEntityIdResolver(snapshot.getDescription())); } @Override public Response performRemove(String id) { for (DiskImage diskImage : getDisks()) { Map<NGuid, NGuid> parents = getParentage(diskImage); for (DiskImage snapshotImage : diskImage.getSnapshots()) { Guid sourceVmSnapshotId = new Guid(snapshotImage.getvm_snapshot_id().getUuid()); if (id.equals(sourceVmSnapshotId.toString())) { NGuid dest = findSnapshotParent(sourceVmSnapshotId, parents); if (dest != null) { return performAction(VdcActionType.MergeSnapshot, new MergeSnapshotParamenters(sourceVmSnapshotId, dest, parentId)); } break; } } } notFound(); return null; } private NGuid findSnapshotParent(Guid snapshotId, Map<NGuid, NGuid> parents) { for (NGuid parentId : parents.keySet()) { if (parents.get(parentId).equals(snapshotId)) { return parentId; } } return null; } @Override @SingleEntityResource public SnapshotResource getSnapshotSubResource(String id) { return inject(new BackendSnapshotResource(id, parentId, this)); } public Snapshot addParents(Snapshot model) { model.setVm(new VM()); model.getVm().setId(parentId.toString()); return model; } protected ArrayList<String> getDrives() { List<DiskImage> disks = getDisks(); ArrayList<String> drives = new ArrayList<String>(); for (DiskImage disk : disks) { drives.add(disk.getinternal_drive_mapping()); } return drives; } protected List<DiskImage> getDisks() { return getBackendCollection(VdcQueryType.GetAllDisksByVmId, new GetAllDisksByVmIdParameters(parentId)); } protected Snapshots mapCollection(List<DiskImage> diskImages) { Map<String, Snapshot> snapshots = new LinkedHashMap<String, Snapshot>(); for (DiskImage diskImage : diskImages) { Map<NGuid, NGuid> parents = getParentage(diskImage); for (DiskImage snapshotImage : diskImage.getSnapshots()) { Snapshot candidate = map(snapshotImage, diskImage); if (!snapshots.containsKey(candidate.getId())) { snapshots.put(candidate.getId(), addLinks(candidate)); addPrevLink(candidate, parents.get(snapshotImage.getvm_snapshot_id())); } } } Snapshots collection = new Snapshots(); collection.getSnapshots().addAll(snapshots.values()); return collection; } protected Snapshot map(DiskImage snapshot, DiskImage diskImage) { Snapshot template = null; if (diskImage != null) { template = new Snapshot(); Disk disk = new Disk(); disk.setId(diskImage.getId().toString()); VM vm = new VM(); vm.setId(parentId.toString()); disk.setVm(vm); template.setDisk(disk); } return super.map(snapshot, template); } protected Map<NGuid, NGuid> getParentage(DiskImage diskImage) { Map<Guid, NGuid> images = new HashMap<Guid, NGuid>(); for (DiskImage snapshotImage : diskImage.getSnapshots()) { images.put(snapshotImage.getId(), snapshotImage.getvm_snapshot_id()); } Map<NGuid, NGuid> parents = new HashMap<NGuid, NGuid>(); for (DiskImage snapshotImage : diskImage.getSnapshots()) { if (!(Guid.Empty.equals(snapshotImage.getParentId())) && images.containsKey(snapshotImage.getParentId())) { parents.put(snapshotImage.getvm_snapshot_id(), images.get(snapshotImage.getParentId())); } } return parents; } protected void addPrevLink(Snapshot snapshot, NGuid id) { if (id != null) { UriBuilder uriBuilder = LinkHelper.getUriBuilder(getUriInfo(), snapshot.getVm()).path("snapshots"); Link prev = new Link(); prev.setRel("prev"); prev.setHref(uriBuilder.clone().path(id.toString()).build().toString()); snapshot.getLinks().add(prev); } } public DiskImage lookupEntityByDescription(String description) { for (DiskImage diskImage : getDisks()) { for (DiskImage snapshotImage : diskImage.getSnapshots()) { if (description.equals(snapshotImage.getdescription())) { return snapshotImage; } } } return null; } public EntityIdResolver getEntityIdResolver(String description) { return new DiskImageIdResolver(description); } protected class DiskImageIdResolver extends EntityIdResolver { private String description; DiskImageIdResolver() {} DiskImageIdResolver(String description) { this.description = description; } @Override public DiskImage lookupEntity(Guid id) { return lookupEntityByDescription(description); } } }