Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,18 @@ public DataTO getDestData() {
return destData;
}

public void setSrcDetails(Map<String, String> details) {
srcDetails = details;
}

public Map<String, String> getSrcDetails() {
return srcDetails;
}

public void setDestDetails(Map<String, String> details) {
destDetails = details;
}

public Map<String, String> getDestDetails() {
return destDetails;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@
import com.cloud.storage.StoragePool;

public interface PrimaryDataStoreDriver extends DataStoreDriver {
enum QualityOfServiceState { MIGRATION, NO_MIGRATION }

String BASIC_CREATE = "basicCreate";
String BASIC_DELETE = "basicDelete";
String BASIC_DELETE_FAILURE = "basicDeleteFailure";
String BASIC_DELETE_BY_FOLDER = "basicDeleteByFolder";
String BASIC_GRANT_ACCESS = "basicGrantAccess";
String BASIC_REVOKE_ACCESS = "basicRevokeAccess";
String BASIC_IQN = "basicIqn";
Expand Down Expand Up @@ -67,4 +70,6 @@ public interface PrimaryDataStoreDriver extends DataStoreDriver {
void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CreateCmdResult> callback);

void revertSnapshot(SnapshotInfo snapshotOnImageStore, SnapshotInfo snapshotOnPrimaryStore, AsyncCompletionCallback<CommandResult> callback);

void handleQualityOfServiceForVolumeMigration(VolumeInfo volumeInfo, QualityOfServiceState qualityOfServiceState);
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -1517,67 +1517,114 @@ public Answer createTemplateFromSnapshot(final CopyCommand cmd) {
}
}

private boolean isManaged(Map<String, String> options) {
if (options == null) {
return false;
}

String iqn = options.get(DiskTO.IQN);

if (iqn == null || iqn.trim().length() == 0) {
return false;
}

String storageHost = options.get(DiskTO.STORAGE_HOST);

if (storageHost == null || storageHost.trim().length() == 0) {
return false;
}

return true;
}

boolean isCreateManagedVolumeFromManagedSnapshot(Map<String, String> volumeOptions, Map<String, String> snapshotOptions) {
return isManaged(volumeOptions) && isManaged(snapshotOptions);
}

boolean isCreateNonManagedVolumeFromManagedSnapshot(Map<String, String> volumeOptions, Map<String, String> snapshotOptions) {
return !isManaged(volumeOptions) && isManaged(snapshotOptions);
}

@Override
public Answer createVolumeFromSnapshot(final CopyCommand cmd) {
final Connection conn = hypervisorResource.getConnection();
final DataTO srcData = cmd.getSrcTO();
final SnapshotObjectTO snapshot = (SnapshotObjectTO) srcData;
final DataTO destData = cmd.getDestTO();
final DataStoreTO imageStore = srcData.getDataStore();
Connection conn = hypervisorResource.getConnection();

DataTO srcData = cmd.getSrcTO();
SnapshotObjectTO snapshot = (SnapshotObjectTO)srcData;
DataStoreTO imageStore = srcData.getDataStore();
DataTO destData = cmd.getDestTO();

if (srcData.getDataStore() instanceof PrimaryDataStoreTO && destData.getDataStore() instanceof PrimaryDataStoreTO) {
return createVolumeFromSnapshot2(cmd);
if (isCreateManagedVolumeFromManagedSnapshot(cmd.getOptions2(), cmd.getOptions())) {
return createManagedVolumeFromManagedSnapshot(cmd);
}

if (isCreateNonManagedVolumeFromManagedSnapshot(cmd.getOptions2(), cmd.getOptions())) {
return createNonManagedVolumeFromManagedSnapshot(cmd);
}

if (!(imageStore instanceof NfsTO)) {
return new CopyCmdAnswer("unsupported protocol");
}

final NfsTO nfsImageStore = (NfsTO) imageStore;
final String primaryStorageNameLabel = destData.getDataStore().getUuid();
final String secondaryStorageUrl = nfsImageStore.getUrl();
final int wait = cmd.getWait();
NfsTO nfsImageStore = (NfsTO)imageStore;
String primaryStorageNameLabel = destData.getDataStore().getUuid();
String secondaryStorageUrl = nfsImageStore.getUrl();

int wait = cmd.getWait();
boolean result = false;

// Generic error message.
String details = null;
String volumeUUID = null;
String details;
String volumeUUID;

if (secondaryStorageUrl == null) {
details += " because the URL passed: " + secondaryStorageUrl + " is invalid.";
details = "The URL passed in 'null'.";

return new CopyCmdAnswer(details);
}

try {
final SR primaryStorageSR = hypervisorResource.getSRByNameLabelandHost(conn, primaryStorageNameLabel);
SR primaryStorageSR = hypervisorResource.getSRByNameLabelandHost(conn, primaryStorageNameLabel);

if (primaryStorageSR == null) {
throw new InternalErrorException("Could not create volume from snapshot because the primary Storage SR could not be created from the name label: " +
primaryStorageNameLabel);
throw new InternalErrorException("Could not create volume from snapshot because the primary storage SR could not be " +
"created from the name label: " + primaryStorageNameLabel);
}

// Get the absolute path of the snapshot on the secondary storage.
String snapshotInstallPath = snapshot.getPath();
final int index = snapshotInstallPath.lastIndexOf(nfsImageStore.getPathSeparator());
final String snapshotName = snapshotInstallPath.substring(index + 1);
int index = snapshotInstallPath.lastIndexOf(nfsImageStore.getPathSeparator());
String snapshotName = snapshotInstallPath.substring(index + 1);

if (!snapshotName.startsWith("VHD-") && !snapshotName.endsWith(".vhd")) {
snapshotInstallPath = snapshotInstallPath + ".vhd";
}
final URI snapshotURI = new URI(secondaryStorageUrl + nfsImageStore.getPathSeparator() + snapshotInstallPath);
final String snapshotPath = snapshotURI.getHost() + ":" + snapshotURI.getPath();
final String srUuid = primaryStorageSR.getUuid(conn);

URI snapshotURI = new URI(secondaryStorageUrl + nfsImageStore.getPathSeparator() + snapshotInstallPath);
String snapshotPath = snapshotURI.getHost() + ":" + snapshotURI.getPath();
String srUuid = primaryStorageSR.getUuid(conn);

volumeUUID = copy_vhd_from_secondarystorage(conn, snapshotPath, srUuid, wait);
result = true;
final VDI volume = VDI.getByUuid(conn, volumeUUID);
final VDI.Record vdir = volume.getRecord(conn);
final VolumeObjectTO newVol = new VolumeObjectTO();

VDI volume = VDI.getByUuid(conn, volumeUUID);
VDI.Record vdir = volume.getRecord(conn);
VolumeObjectTO newVol = new VolumeObjectTO();

newVol.setPath(volumeUUID);
newVol.setSize(vdir.virtualSize);

return new CopyCmdAnswer(newVol);
} catch (final XenAPIException e) {
details += " due to " + e.toString();
details = "Exception due to " + e.toString();

s_logger.warn(details, e);
} catch (final Exception e) {
details += " due to " + e.getMessage();
details = "Exception due to " + e.getMessage();

s_logger.warn(details, e);
}

if (!result) {
// Is this logged at a higher level?
s_logger.error(details);
Expand All @@ -1587,7 +1634,7 @@ public Answer createVolumeFromSnapshot(final CopyCommand cmd) {
return new CopyCmdAnswer(details);
}

protected Answer createVolumeFromSnapshot2(final CopyCommand cmd) {
Answer createManagedVolumeFromManagedSnapshot(final CopyCommand cmd) {
try {
final Connection conn = hypervisorResource.getConnection();

Expand Down Expand Up @@ -1632,6 +1679,51 @@ protected Answer createVolumeFromSnapshot2(final CopyCommand cmd) {
}
}

Answer createNonManagedVolumeFromManagedSnapshot(final CopyCommand cmd) {
Connection conn = hypervisorResource.getConnection();
SR srcSr = null;

try {
Map<String, String> srcOptions = cmd.getOptions();

String src_iScsiName = srcOptions.get(DiskTO.IQN);
String srcStorageHost = srcOptions.get(DiskTO.STORAGE_HOST);
String srcChapInitiatorUsername = srcOptions.get(DiskTO.CHAP_INITIATOR_USERNAME);
String srcChapInitiatorSecret = srcOptions.get(DiskTO.CHAP_INITIATOR_SECRET);

srcSr = hypervisorResource.getIscsiSR(conn, src_iScsiName, srcStorageHost, src_iScsiName,
srcChapInitiatorUsername, srcChapInitiatorSecret, false);

// there should only be one VDI in this SR
VDI srcVdi = srcSr.getVDIs(conn).iterator().next();

DataTO destData = cmd.getDestTO();
String primaryStorageNameLabel = destData.getDataStore().getUuid();

SR destSr = hypervisorResource.getSRByNameLabelandHost(conn, primaryStorageNameLabel);

VDI vdiCopy = srcVdi.copy(conn, destSr);

VolumeObjectTO newVol = new VolumeObjectTO();

newVol.setSize(vdiCopy.getVirtualSize(conn));
newVol.setPath(vdiCopy.getUuid(conn));
newVol.setFormat(ImageFormat.VHD);

return new CopyCmdAnswer(newVol);
}
catch (Exception ex) {
s_logger.warn("Failed to copy snapshot to volume: " + ex.toString(), ex);

return new CopyCmdAnswer(ex.getMessage());
}
finally {
if (srcSr != null) {
hypervisorResource.removeSR(conn, srcSr);
}
}
}

@Override
public Answer deleteSnapshot(final DeleteCommand cmd) {
final SnapshotObjectTO snapshot = (SnapshotObjectTO) cmd.getData();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -787,8 +787,12 @@ public Answer createVolumeFromSnapshot(final CopyCommand cmd) {
final VolumeObjectTO volume = (VolumeObjectTO)destData;
final DataStoreTO imageStore = srcData.getDataStore();

if (srcData.getDataStore() instanceof PrimaryDataStoreTO && destData.getDataStore() instanceof PrimaryDataStoreTO) {
return createVolumeFromSnapshot2(cmd);
if (isCreateManagedVolumeFromManagedSnapshot(cmd.getOptions2(), cmd.getOptions())) {
return createManagedVolumeFromManagedSnapshot(cmd);
}

if (isCreateNonManagedVolumeFromManagedSnapshot(cmd.getOptions2(), cmd.getOptions())) {
return createNonManagedVolumeFromManagedSnapshot(cmd);
}

if (!(imageStore instanceof NfsTO)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.storage.MigrateVolumeAnswer;
import com.cloud.agent.api.storage.MigrateVolumeCommand;
import com.cloud.agent.api.to.DiskTO;
import com.cloud.agent.api.to.StorageFilerTO;
import com.cloud.hypervisor.xenserver.resource.XenServer610Resource;
import com.cloud.resource.CommandWrapper;
Expand All @@ -39,35 +40,59 @@

@ResourceWrapper(handles = MigrateVolumeCommand.class)
public final class XenServer610MigrateVolumeCommandWrapper extends CommandWrapper<MigrateVolumeCommand, Answer, XenServer610Resource> {

private static final Logger s_logger = Logger.getLogger(XenServer610MigrateVolumeCommandWrapper.class);
private static final Logger LOGGER = Logger.getLogger(XenServer610MigrateVolumeCommandWrapper.class);

@Override
public Answer execute(final MigrateVolumeCommand command, final XenServer610Resource xenServer610Resource) {
final Connection connection = xenServer610Resource.getConnection();
final String volumeUUID = command.getVolumePath();
final StorageFilerTO poolTO = command.getPool();
Connection connection = xenServer610Resource.getConnection();
String srcVolumeUuid = command.getVolumePath();
SR destPool = null;
Map<String, String> destDetails = command.getDestDetails();

try {
final String uuid = poolTO.getUuid();
final SR destinationPool = xenServer610Resource.getStorageRepository(connection, uuid);
final VDI srcVolume = xenServer610Resource.getVDIbyUuid(connection, volumeUUID);
final Map<String, String> other = new HashMap<String, String>();
VDI srcVolume = xenServer610Resource.getVDIbyUuid(connection, srcVolumeUuid);

if (destDetails != null && Boolean.parseBoolean(destDetails.get(DiskTO.MANAGED))) {
String iScsiName = destDetails.get(DiskTO.IQN);
String storageHost = destDetails.get(DiskTO.STORAGE_HOST);
String chapInitiatorUsername = destDetails.get(DiskTO.CHAP_INITIATOR_USERNAME);
String chapInitiatorSecret = destDetails.get(DiskTO.CHAP_INITIATOR_SECRET);

destPool = xenServer610Resource.getIscsiSR(connection, iScsiName, storageHost, iScsiName,
chapInitiatorUsername, chapInitiatorSecret, false);
}
else {
StorageFilerTO destPoolTO = command.getPool();
String destPoolUuid = destPoolTO.getUuid();

destPool = xenServer610Resource.getStorageRepository(connection, destPoolUuid);
}

Map<String, String> other = new HashMap<>();

other.put("live", "true");

// Live migrate the vdi across pool.
final Task task = srcVolume.poolMigrateAsync(connection, destinationPool, other);
final long timeout = xenServer610Resource.getMigrateWait() * 1000L;
// Live migrate the VDI.
Task task = srcVolume.poolMigrateAsync(connection, destPool, other);

long timeout = xenServer610Resource.getMigrateWait() * 1000L;

xenServer610Resource.waitForTask(connection, task, 1000, timeout);
xenServer610Resource.checkForSuccess(connection, task);

final VDI dvdi = Types.toVDI(task, connection);
VDI destVdi = Types.toVDI(task, connection);

return new MigrateVolumeAnswer(command, true, null, destVdi.getUuid(connection));
} catch (Exception ex) {
if (destDetails != null && Boolean.parseBoolean(destDetails.get(DiskTO.MANAGED)) && destPool != null) {
xenServer610Resource.removeSR(connection, destPool);
}

String msg = "Caught exception " + ex.getClass().getName() + " due to the following: " + ex.toString();

LOGGER.error(msg, ex);

return new MigrateVolumeAnswer(command, true, null, dvdi.getUuid(connection));
} catch (final Exception e) {
final String msg = "Catch Exception " + e.getClass().getName() + " due to " + e.toString();
s_logger.error(msg, e);
return new MigrateVolumeAnswer(command, false, msg, null);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,9 @@ public void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> cal

}

@Override
public void handleQualityOfServiceForVolumeMigration(VolumeInfo volumeInfo, QualityOfServiceState qualityOfServiceState) {}

//this method will utilize the volume details table to add third party volume properties
public void updateVolumeDetails(VolumeVO volume, FileSystem esvolume) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,4 +385,7 @@ public void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> cal

callback.complete(result);
}

@Override
public void handleQualityOfServiceForVolumeMigration(VolumeInfo volumeInfo, QualityOfServiceState qualityOfServiceState) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -206,4 +206,7 @@ public boolean canCopy(DataObject srcData, DataObject destData) {

@Override
public void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {}

@Override
public void handleQualityOfServiceForVolumeMigration(VolumeInfo volumeInfo, QualityOfServiceState qualityOfServiceState) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.apache.cloudstack.framework.async.AsyncRpcContext;
Expand Down Expand Up @@ -227,6 +228,10 @@ public void copyAsync(DataObject srcdata, DataObject destData, AsyncCompletionCa
public void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
}

@Override
public void handleQualityOfServiceForVolumeMigration(VolumeInfo volumeInfo, QualityOfServiceState qualityOfServiceState) {
}

@Override
public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CreateCmdResult> callback) {
}
Expand Down
Loading