/*
* Copyright (c) 2014 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.vnxe.job;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.URIUtil;
import com.emc.storageos.db.client.constraint.ContainmentConstraint;
import com.emc.storageos.db.client.constraint.URIQueryResultList;
import com.emc.storageos.db.client.model.FileShare;
import com.emc.storageos.db.client.model.NamedURI;
import com.emc.storageos.db.client.model.OpStatusMap;
import com.emc.storageos.db.client.model.Snapshot;
import com.emc.storageos.services.OperationTypeEnum;
import com.emc.storageos.vnxe.VNXeApiClient;
import com.emc.storageos.vnxe.models.VNXeFileSystemSnap;
import com.emc.storageos.volumecontroller.JobContext;
import com.emc.storageos.volumecontroller.TaskCompleter;
import com.emc.storageos.volumecontroller.impl.FileDeviceController;
import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator;
public class VNXeRestoreFileSystemSnapshotJob extends VNXeJob {
private static final long serialVersionUID = 154563020105138725L;
private static final Logger _logger = LoggerFactory.getLogger(VNXeCreateFileSystemSnapshotJob.class);
public VNXeRestoreFileSystemSnapshotJob(String jobId, URI storageSystemUri, TaskCompleter taskCompleter) {
super(jobId, storageSystemUri, taskCompleter, "restoreFileSystemSnapshot");
}
/**
* Called to update the job status when the file system snapshot restore job completes.
*
* @param jobContext The job context.
*/
@Override
public void updateStatus(JobContext jobContext) throws Exception {
DbClient dbClient = jobContext.getDbClient();
try {
if (_status == JobStatus.IN_PROGRESS) {
return;
}
String opId = getTaskCompleter().getOpId();
StringBuilder logMsgBuilder = new StringBuilder(String.format("Updating status of job %s to %s", opId, _status.name()));
VNXeApiClient vnxeApiClient = getVNXeClient(jobContext);
URI snapId = getTaskCompleter().getId();
Snapshot snapshotObj = dbClient.queryObject(Snapshot.class, snapId);
URI fsUri = snapshotObj.getParent().getURI();
FileShare fsObj = dbClient.queryObject(FileShare.class, fsUri);
String event = null;
if (_status == JobStatus.SUCCESS && snapshotObj != null) {
syncSnapshots(dbClient, fsObj, vnxeApiClient);
event = String.format(
"Restore file system snapshot successfully for URI: %s", getTaskCompleter().getId());
} else if (_status == JobStatus.FAILED && snapshotObj != null) {
event = String.format(
"Task %s failed to restore file system snapshot: %s", opId, snapshotObj.getName());
logMsgBuilder.append("\n");
logMsgBuilder.append(event);
} else {
logMsgBuilder.append(String.format("Could not find the snapshot:%s", snapId.toString()));
}
_logger.info(logMsgBuilder.toString());
FileDeviceController.recordFileDeviceOperation(dbClient, OperationTypeEnum.RESTORE_FILE_SNAPSHOT, _isSuccess,
event, "", fsObj, snapId);
} catch (Exception e) {
_logger.error("Caught an exception while trying to updateStatus for VNXeRestoreFileSystemSnapshotJob", e);
setErrorStatus("Encountered an internal error during file system snapshot restore job status processing : " + e.getMessage());
} finally {
super.updateStatus(jobContext);
}
}
private void syncSnapshots(DbClient dbClient, FileShare fsObj,
VNXeApiClient vnxeApiClient) {
// Retrieve all snapshots from DB that belong to this file system
URIQueryResultList results = new URIQueryResultList();
dbClient.queryByConstraint(ContainmentConstraint.
Factory.getFileshareSnapshotConstraint(fsObj.getId()), results);
// Setup snapshot name-object map
Map<String, Snapshot> snapshotsInDB = new ConcurrentHashMap<String, Snapshot>();
while (results.iterator().hasNext()) {
URI uri = results.iterator().next();
Snapshot snap = dbClient.queryObject(Snapshot.class, uri);
String nativeId = snap.getNativeId();
if (nativeId == null || nativeId.isEmpty()) {
// no nativeId set in the snap, remove it from db.
snap.setInactive(true);
dbClient.persistObject(snap);
_logger.info("No nativeId, removing the snapshot: {}", snap.getId());
continue;
} else {
snapshotsInDB.put(nativeId, snap);
}
}
// Retrieve list of valid snapshot names from the device
List<VNXeFileSystemSnap> snapshots = vnxeApiClient.getFileSystemSnaps(fsObj.getNativeId());
List<String> snapIdsOnDevice = new ArrayList<String>();
for (VNXeFileSystemSnap snap : snapshots) {
snapIdsOnDevice.add(snap.getId());
}
// Iterate through the snapshots in the DB and if name not found in
// the list returned by the device, mark snapshot in DB as inactive
Set<String> snapshotNativeIds = snapshotsInDB.keySet();
for (String snapshotId : snapshotNativeIds) {
if (!snapIdsOnDevice.contains(snapshotId)) {
_logger.info("Removing the snapshot: {}", snapshotId);
snapshotsInDB.get(snapshotId).setInactive(true);
dbClient.persistObject(snapshotsInDB.get(snapshotId));
}
}
// Iterate through the snapshot list from device and if a
// snapshot is found on the device but not in the DB, add the
// newly discovered snapshot to the DB.
for (VNXeFileSystemSnap snap : snapshots) {
if (!snapshotNativeIds.contains(snap.getId())) {
_logger.info("adding the snapshot: {}", snap.getId());
Snapshot newSnap = new Snapshot();
newSnap.setCreationTime(Calendar.getInstance());
newSnap.setId(URIUtil.createId(Snapshot.class));
newSnap.setParent(new NamedURI(fsObj.getId(), fsObj.getLabel()));
newSnap.setLabel(snap.getName());
newSnap.setOpStatus(new OpStatusMap());
newSnap.setProject(new NamedURI(fsObj.getProject().getURI(), fsObj.getProject().getName()));
newSnap.setNativeId(snap.getId());
try {
newSnap.setNativeGuid(NativeGUIDGenerator.generateNativeGuid(dbClient, newSnap));
} catch (IOException e) {
_logger.info("Exception while setting snap's nativeGUID");
}
}
}
}
}