/* * Copyright (c) 2016 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.vnxunity; import static com.emc.storageos.db.client.constraint.AlternateIdConstraint.Factory.getVolumesByAssociatedId; import java.net.URI; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.model.BlockSnapshot; import com.emc.storageos.db.client.model.DataObject.Flag; import com.emc.storageos.db.client.model.DiscoveredDataObject; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.model.TenantOrg; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.db.client.util.CustomQueryUtility; import com.emc.storageos.db.client.util.NullColumnValueGetter; import com.emc.storageos.exceptions.DeviceControllerErrors; import com.emc.storageos.exceptions.DeviceControllerException; import com.emc.storageos.svcs.errorhandling.model.ServiceError; import com.emc.storageos.vnxe.VNXeApiClient; import com.emc.storageos.vnxe.models.Snap; import com.emc.storageos.vnxe.models.VNXeCommandJob; import com.emc.storageos.volumecontroller.TaskCompleter; import com.emc.storageos.volumecontroller.impl.ControllerServiceImpl; import com.emc.storageos.volumecontroller.impl.ControllerUtils; import com.emc.storageos.volumecontroller.impl.job.QueueJob; import com.emc.storageos.volumecontroller.impl.smis.SmisConstants; import com.emc.storageos.volumecontroller.impl.vnxe.VNXeSnapshotOperation; import com.emc.storageos.volumecontroller.impl.vnxe.job.VNXeBlockSnapshotCreateJob; import com.emc.storageos.volumecontroller.impl.vnxunity.job.VNXUnityCreateCGSnapshotJob; import com.emc.storageos.volumecontroller.impl.vnxunity.job.VNXUnityRestoreSnapshotJob; public class VNXUnitySnapshotOperations extends VNXeSnapshotOperation { private static final Logger log = LoggerFactory.getLogger(VNXUnitySnapshotOperations.class); @Override protected VNXeApiClient getVnxeClient(StorageSystem storage) { VNXeApiClient client = _clientFactory.getUnityClient(storage.getIpAddress(), storage.getPortNumber(), storage.getUsername(), storage.getPassword()); return client; } @Override public void createSingleVolumeSnapshot(StorageSystem storage, URI snapshot, Boolean createInactive, Boolean readOnly, TaskCompleter taskCompleter) throws DeviceControllerException { try { BlockSnapshot snapshotObj = _dbClient.queryObject(BlockSnapshot.class, snapshot); if (readOnly) { snapshotObj.setIsReadOnly(readOnly); _dbClient.updateObject(snapshotObj); } Volume volume = _dbClient.queryObject(Volume.class, snapshotObj.getParent()); TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, volume.getTenant().getURI()); String tenantName = tenant.getLabel(); String snapLabelToUse = _nameGenerator.generate(tenantName, snapshotObj.getLabel(), snapshot.toString(), '-', SmisConstants.MAX_SNAPSHOT_NAME_LENGTH); VNXeApiClient apiClient = getVnxeClient(storage); VNXeCommandJob job = apiClient.createSnap(volume.getNativeId(), snapLabelToUse, readOnly); if (job != null) { ControllerServiceImpl.enqueueJob( new QueueJob(new VNXeBlockSnapshotCreateJob(job.getId(), storage.getId(), !createInactive, taskCompleter))); } } catch (Exception ex) { log.error("Create volume snapshot got the exception", ex); ServiceError error = DeviceControllerErrors.vnxe.jobFailed("CreateVolumeSnapshot", ex.getMessage()); taskCompleter.error(_dbClient, error); } } @Override public void deleteSingleVolumeSnapshot(StorageSystem storage, URI snapshot, TaskCompleter taskCompleter) throws DeviceControllerException { try { BlockSnapshot snap = _dbClient.queryObject(BlockSnapshot.class, snapshot); VNXeApiClient apiClient = getVnxeClient(storage); Snap lunSnap = apiClient.getSnapshot(snap.getNativeId()); if (lunSnap != null) { apiClient.deleteSnap(lunSnap.getId()); } snap.setInactive(true); snap.setIsSyncActive(false); _dbClient.updateObject(snap); taskCompleter.ready(_dbClient); } catch (Exception ex) { log.error("Delete volume snapshot got the exception", ex); ServiceError error = DeviceControllerErrors.vnxe.jobFailed("DeleteSnapshot", ex.getMessage()); taskCompleter.error(_dbClient, error); } } @Override public void createGroupSnapshots(StorageSystem storage, List<URI> snapshotList, Boolean createInactive, Boolean readOnly, TaskCompleter taskCompleter) throws DeviceControllerException { try { URI snapshot = snapshotList.get(0); BlockSnapshot snapshotObj = _dbClient.queryObject(BlockSnapshot.class, snapshot); Volume volume = _dbClient.queryObject(Volume.class, snapshotObj.getParent()); boolean inApplication = false; if (volume.getApplication(_dbClient) != null) { inApplication = true; } else if (volume.checkInternalFlags(Flag.INTERNAL_OBJECT)){ // Check if it is VPLEX backend volume and if the vplex volume is in an application final List<Volume> vplexVolumes = CustomQueryUtility .queryActiveResourcesByConstraint(_dbClient, Volume.class, getVolumesByAssociatedId(volume.getId().toString())); for (Volume vplexVolume : vplexVolumes) { if (vplexVolume.getApplication(_dbClient) != null) { inApplication = true; break; } } } String groupName = volume.getReplicationGroupInstance(); String snapLabelToUse = null; if (NullColumnValueGetter.isNotNullValue(groupName)) { String snapsetLabel = snapshotObj.getSnapsetLabel(); if (inApplication) { // When in application, it could have more than one CGs in the same application, when creating // snapshot on the application, the snapset label would be the same for all volumes in the application. // if we use the same name to create snapshot for multiple CGs, it would fail. snapLabelToUse = String.format("%s-%s", snapsetLabel, groupName); } else { snapLabelToUse = snapsetLabel; } VNXeApiClient apiClient = getVnxeClient(storage); String cgId = apiClient.getConsistencyGroupIdByName(groupName); VNXeCommandJob job = apiClient.createSnap(cgId, snapLabelToUse, readOnly); if (job != null) { ControllerServiceImpl.enqueueJob( new QueueJob(new VNXUnityCreateCGSnapshotJob(job.getId(), storage.getId(), readOnly, taskCompleter))); } } else { String errorMsg = "Unable to find consistency group id when creating snapshot"; log.error(errorMsg); ServiceError error = DeviceControllerErrors.vnxe.jobFailed("CreateCGSnapshot", errorMsg); taskCompleter.error(_dbClient, error); } } catch (Exception ex) { log.error("Create volume snapshot got the exception", ex); ServiceError error = DeviceControllerErrors.vnxe.jobFailed("CreateCGSnapshot", ex.getMessage()); taskCompleter.error(_dbClient, error); } } @Override public void deleteGroupSnapshots(StorageSystem storage, URI snapshot, TaskCompleter taskCompleter) throws DeviceControllerException { try { BlockSnapshot snapshotObj = _dbClient.queryObject(BlockSnapshot.class, snapshot); VNXeApiClient apiClient = getVnxeClient(storage); String groupId = snapshotObj.getReplicationGroupInstance(); Snap snapGroup = apiClient.getSnapshot(groupId); if (snapGroup != null) { apiClient.deleteSnap(groupId); } List<BlockSnapshot> snaps = ControllerUtils.getSnapshotsPartOfReplicationGroup(snapshotObj, _dbClient); if (snaps != null) { for (BlockSnapshot snap : snaps) { snap.setInactive(true); snap.setIsSyncActive(false); _dbClient.updateObject(snap); } } taskCompleter.ready(_dbClient); } catch (Exception ex) { log.error("Delete group snapshot got the exception", ex); ServiceError error = DeviceControllerErrors.vnxe.jobFailed("DeletGroupSnapshot", ex.getMessage()); taskCompleter.error(_dbClient, error); } } @Override public void restoreSingleVolumeSnapshot(StorageSystem storage, URI volume, URI snapshot, TaskCompleter taskCompleter) throws DeviceControllerException { try { BlockSnapshot snapshotObj = _dbClient.queryObject(BlockSnapshot.class, snapshot); VNXeApiClient apiClient = getVnxeClient(storage); Snap snap = apiClient.getSnapshot(snapshotObj.getNativeId()); // Error out if the snapshot is attached if (snap.isAttached()) { log.error("Snapshot {})is exported and cannot be used for restore, please unexport it first", snapshotObj.getLabel()); ServiceError error = DeviceControllerErrors.vnxe.cannotRestoreAttachedSnapshot(snapshotObj.getLabel()); taskCompleter.error(_dbClient, error); } VNXeCommandJob job = apiClient.restoreSnap(snap.getId()); if (job != null) { ControllerServiceImpl.enqueueJob( new QueueJob(new VNXUnityRestoreSnapshotJob(job.getId(), storage.getId(), taskCompleter))); } } catch (Exception ex) { log.error("Restore snapshot got the exception", ex); ServiceError error = DeviceControllerErrors.vnxe.jobFailed("RestoreSnapshotJob", ex.getMessage()); taskCompleter.error(_dbClient, error); } } @Override public void restoreGroupSnapshots(StorageSystem storage, URI volume, URI snapshot, TaskCompleter taskCompleter) throws DeviceControllerException { try { BlockSnapshot snapshotObj = _dbClient.queryObject(BlockSnapshot.class, snapshot); VNXeApiClient apiClient = getVnxeClient(storage); Snap groupSnap = apiClient.getSnapshot(snapshotObj.getReplicationGroupInstance()); Snap snap = apiClient.getSnapshot(snapshotObj.getNativeId()); // Error out if the snapshot is attached if (snap.isAttached()) { log.error("Snapshot {})is exported and cannot be used for restore", snapshotObj.getLabel()); ServiceError error = DeviceControllerErrors.vnxe.cannotRestoreAttachedSnapshot(snapshotObj.getLabel()); taskCompleter.error(_dbClient, error); } VNXeCommandJob job = apiClient.restoreSnap(groupSnap.getId()); if (job != null) { ControllerServiceImpl.enqueueJob( new QueueJob(new VNXUnityRestoreSnapshotJob(job.getId(), storage.getId(), taskCompleter))); } } catch (Exception ex) { log.error("Restore group snapshot got the exception", ex); ServiceError error = DeviceControllerErrors.vnxe.jobFailed("RestoreSnapshotJob", ex.getMessage()); taskCompleter.error(_dbClient, error); } } }