/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.db.client.upgrade.callbacks;
import java.net.URI;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.model.Volume;
import com.emc.storageos.db.client.model.Volume.ReplicationState;
import com.emc.storageos.db.client.upgrade.BaseCustomMigrationCallback;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
import com.emc.storageos.svcs.errorhandling.resources.MigrationCallbackException;
/**
* Upgrade callback class when upgrading from 2.3 to a later
* release that makes sure any detached full copies are no
* longer associated with a source volume and are removed
* from the full copies list of the source volume.
*/
public class FullCopyVolumeDetachedStateMigration extends BaseCustomMigrationCallback {
private static final Logger s_logger = LoggerFactory.getLogger(FullCopyVolumeDetachedStateMigration.class);
@Override
public void process() throws MigrationCallbackException {
initializeVolumeFields();
}
/**
* For all full copy volume that is in the detached state, make sure
* that it's associated source volume field is null and that it is
* removed from the full copies list of the source.
*/
private void initializeVolumeFields() {
s_logger.info("Updating detached full copy volumes.");
DbClient dbClient = this.getDbClient();
List<URI> volumeURIs = dbClient.queryByType(Volume.class, true);
Iterator<Volume> volumes =
dbClient.queryIterativeObjects(Volume.class, volumeURIs);
while (volumes.hasNext()) {
Volume volume = volumes.next();
boolean volumeUpdated = false;
s_logger.info("Examining Volume (id={}) for upgrade", volume.getId().toString());
String replicaState = volume.getReplicaState();
// Check if the replicate state is detached.
if ((NullColumnValueGetter.isNotNullValue(replicaState)) &&
(ReplicationState.DETACHED.name().equals(replicaState))) {
URI sourceURI = volume.getAssociatedSourceVolume();
if (!NullColumnValueGetter.isNullURI(sourceURI)) {
// We make sure the associated source volume is null.
// This change was made in ViPR 2.3 for Jira 12659, but
// the 2.3 upgrade callback never marked the associated
// source volume null for existing, detached full copies
// in the database, which all full copies were prior to 2.3.
// See class FullCopyVolumeReplicaStateMigration.
s_logger.info("Setting associated source volume to null");
volume.setAssociatedSourceVolume(NullColumnValueGetter.getNullURI());
volumeUpdated = true;
}
}
// For any volume that has full copies, make sure none of those full copies
// are in a detached state.
HashSet<String> fullCopiesToRemove = new HashSet<String>();
StringSet fullCopies = volume.getFullCopies();
if (fullCopies != null) {
for (String fullCopyId : fullCopies) {
Volume fullCopy = dbClient.queryObject(Volume.class, URI.create(fullCopyId));
if (fullCopy != null) {
replicaState = fullCopy.getReplicaState();
// Check if the replicate state is detached.
if ((NullColumnValueGetter.isNotNullValue(replicaState)) &&
(ReplicationState.DETACHED.name().equals(replicaState))) {
fullCopiesToRemove.add(fullCopyId);
}
} else {
fullCopiesToRemove.add(fullCopyId);
}
}
// Existing, detached full copies in the database should be
// removed from the full copies list of their source volume.
// This is the change for Jira 12766 (COP-13552) which is
// made in the Darth (2.4) ViPR release.
s_logger.info("Removing {} from full copies list of source volume {}:{}", fullCopiesToRemove, volume.getId());
fullCopies.removeAll(fullCopiesToRemove);
volumeUpdated = true;
}
// Persist the changes if necessary.
if (volumeUpdated) {
dbClient.persistObject(volume);
}
}
}
}