/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.scaleio; import java.net.URI; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.BlockSnapshot; import com.emc.storageos.db.client.model.StoragePool; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.exceptions.DeviceControllerErrors; import com.emc.storageos.exceptions.DeviceControllerException; import com.emc.storageos.scaleio.api.restapi.ScaleIORestClient; import com.emc.storageos.scaleio.api.restapi.response.ScaleIOSnapshotVolumeResponse; import com.emc.storageos.svcs.errorhandling.model.ServiceCoded; import com.emc.storageos.volumecontroller.DefaultSnapshotOperations; import com.emc.storageos.volumecontroller.TaskCompleter; import com.emc.storageos.volumecontroller.impl.ControllerUtils; import com.google.common.base.Strings; import com.google.common.collect.Lists; public class ScaleIOSnapshotOperations extends DefaultSnapshotOperations { private static Logger log = LoggerFactory.getLogger(ScaleIOSnapshotOperations.class); private DbClient dbClient; private ScaleIOHandleFactory scaleIOHandleFactory; public void setDbClient(DbClient dbClient) { this.dbClient = dbClient; } @SuppressWarnings("UnusedDeclaration") public void setScaleIOHandleFactory(ScaleIOHandleFactory scaleIOHandleFactory) { this.scaleIOHandleFactory = scaleIOHandleFactory; } @Override public void createSingleVolumeSnapshot(StorageSystem storage, URI snapshot, Boolean createInactive, Boolean readOnly, TaskCompleter taskCompleter) throws DeviceControllerException { try { ScaleIORestClient scaleIOHandle = scaleIOHandleFactory.using(dbClient).getClientHandle(storage); BlockSnapshot blockSnapshot = dbClient.queryObject(BlockSnapshot.class, snapshot); Volume parent = dbClient.queryObject(Volume.class, blockSnapshot.getParent().getURI()); String systemId = scaleIOHandle.getSystemId(); ScaleIOSnapshotVolumeResponse result = scaleIOHandle.snapshotVolume(parent.getNativeId(), blockSnapshot.getLabel(), systemId); String nativeId = result.getVolumeIdList().get(0); ScaleIOHelper.updateSnapshotWithSnapshotVolumeResult(dbClient, blockSnapshot, systemId, nativeId, storage); dbClient.persistObject(blockSnapshot); ScaleIOHelper.updateStoragePoolCapacity(dbClient, scaleIOHandle, blockSnapshot); taskCompleter.ready(dbClient); } catch (Exception e) { log.error("Encountered an exception", e); ServiceCoded code = DeviceControllerErrors.scaleio.encounteredAnExceptionFromScaleIOOperation("createSingleVolumeSnapshot", e.getMessage()); taskCompleter.error(dbClient, code); } } @Override public void createGroupSnapshots(StorageSystem storage, List<URI> snapshotList, Boolean createInactive, Boolean readOnly, TaskCompleter taskCompleter) throws DeviceControllerException { try { ScaleIORestClient scaleIOHandle = scaleIOHandleFactory.using(dbClient).getClientHandle(storage); List<BlockSnapshot> blockSnapshots = dbClient.queryObject(BlockSnapshot.class, snapshotList); Map<String, String> parent2snap = new HashMap<>(); Set<URI> poolsToUpdate = new HashSet<>(); for (BlockSnapshot blockSnapshot : blockSnapshots) { Volume parent = dbClient.queryObject(Volume.class, blockSnapshot.getParent().getURI()); parent2snap.put(parent.getNativeId(), blockSnapshot.getLabel()); poolsToUpdate.add(parent.getPool()); } String systemId = scaleIOHandle.getSystemId(); ScaleIOSnapshotVolumeResponse result = scaleIOHandle.snapshotMultiVolume(parent2snap, systemId); List<String> nativeIds = result.getVolumeIdList(); Map<String, String> snapNameIdMap = scaleIOHandle.getVolumes(nativeIds); ScaleIOHelper.updateSnapshotsWithSnapshotMultiVolumeResult(dbClient, blockSnapshots, systemId, snapNameIdMap, result.getSnapshotGroupId(), storage); dbClient.persistObject(blockSnapshots); List<StoragePool> pools = dbClient.queryObject(StoragePool.class, Lists.newArrayList(poolsToUpdate)); for (StoragePool pool : pools) { ScaleIOHelper.updateStoragePoolCapacity(dbClient, scaleIOHandle, pool, storage); } taskCompleter.ready(dbClient); } catch (Exception e) { log.error("Encountered an exception", e); ServiceCoded code = DeviceControllerErrors.scaleio.encounteredAnExceptionFromScaleIOOperation("createGroupVolumeSnapshot", e.getMessage()); taskCompleter.error(dbClient, code); } } @Override public void activateSingleVolumeSnapshot(StorageSystem storage, URI snapshot, TaskCompleter taskCompleter) throws DeviceControllerException { throw new UnsupportedOperationException("Not supported"); } @Override public void activateGroupSnapshots(StorageSystem storage, URI snapshot, TaskCompleter taskCompleter) throws DeviceControllerException { throw new UnsupportedOperationException("Not supported"); } @Override public void deleteSingleVolumeSnapshot(StorageSystem storage, URI snapshot, TaskCompleter taskCompleter) throws DeviceControllerException { try { ScaleIORestClient scaleIOHandle = scaleIOHandleFactory.using(dbClient).getClientHandle(storage); BlockSnapshot blockSnapshot = dbClient.queryObject(BlockSnapshot.class, snapshot); if (blockSnapshot != null && !blockSnapshot.getInactive() && // If the blockSnapshot.nativeId is not filled in then the // snapshot create may have failed somehow, so we'll allow // this case to be marked as success, so that the inactive // state against the BlockSnapshot object can be set. !Strings.isNullOrEmpty(blockSnapshot.getNativeId())) { scaleIOHandle.removeVolume(blockSnapshot.getNativeId()); } if (blockSnapshot != null) { blockSnapshot.setInactive(true); dbClient.updateObject(blockSnapshot); ScaleIOHelper.updateStoragePoolCapacity(dbClient, scaleIOHandle, blockSnapshot); } taskCompleter.ready(dbClient); } catch (Exception e) { log.error("Encountered an exception", e); ServiceCoded code = DeviceControllerErrors.scaleio.encounteredAnExceptionFromScaleIOOperation("deleteSingleVolumeSnapshot", e.getMessage()); taskCompleter.error(dbClient, code); } } @Override public void deleteGroupSnapshots(StorageSystem storage, URI snapshot, TaskCompleter taskCompleter) throws DeviceControllerException { try { ScaleIORestClient scaleIOHandle = scaleIOHandleFactory.using(dbClient).getClientHandle(storage); BlockSnapshot blockSnapshot = dbClient.queryObject(BlockSnapshot.class, snapshot); Set<URI> poolsToUpdate = new HashSet<>(); scaleIOHandle.removeConsistencyGroupSnapshot(blockSnapshot.getSnapsetLabel()); List<BlockSnapshot> groupSnapshots = ControllerUtils.getSnapshotsPartOfReplicationGroup(blockSnapshot, dbClient); for (BlockSnapshot groupSnapshot : groupSnapshots) { Volume parent = dbClient.queryObject(Volume.class, groupSnapshot.getParent().getURI()); poolsToUpdate.add(parent.getPool()); groupSnapshot.setInactive(true); } dbClient.updateObject(groupSnapshots); List<StoragePool> pools = dbClient.queryObject(StoragePool.class, Lists.newArrayList(poolsToUpdate)); for (StoragePool pool : pools) { ScaleIOHelper.updateStoragePoolCapacity(dbClient, scaleIOHandle, pool, storage); } taskCompleter.ready(dbClient); } catch (Exception e) { log.error("Encountered an exception", e); ServiceCoded code = DeviceControllerErrors.scaleio.encounteredAnExceptionFromScaleIOOperation("deleteGroupSnapshots", e.getMessage()); taskCompleter.error(dbClient, code); } } @Override public void establishVolumeSnapshotGroupRelation(StorageSystem storage, URI sourceVolume, URI snapshot, TaskCompleter taskCompleter) throws DeviceControllerException { throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported(); } }