Skip to content
Open
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 @@ -89,7 +89,12 @@ public ResizeVolumeAnswer execute(final StorPoolResizeVolumeCommand command, fin
return new ResizeVolumeAnswer(command, false, error);
} finally {
if (!command.isAttached() && volPath != null) {
StorPoolStorageAdaptor.attachOrDetachVolume("detach", "volume", volPath);
// a failed detach must not replace the answer of the resize
try {
StorPoolStorageAdaptor.attachOrDetachVolume("detach", "volume", volPath);
} catch (final Exception e) {
logger.warn("Could not detach volume " + volPath + " after resize due to: " + e.getMessage());
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import org.apache.commons.lang3.StringUtils;
import org.libvirt.LibvirtException;

import com.cloud.agent.api.Answer;
import com.cloud.agent.api.storage.StorPoolSetVolumeEncryptionAnswer;
import com.cloud.agent.api.storage.StorPoolSetVolumeEncryptionCommand;
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
Expand Down Expand Up @@ -72,7 +71,9 @@ public StorPoolSetVolumeEncryptionAnswer execute(StorPoolSetVolumeEncryptionComm
}
logger.debug(String.format("StorPoolSetVolumeEncryptionCommandWrapper disk=%s", disk));
} catch (Exception e) {
new Answer(command, e);
String err = String.format("Could not encrypt volume [%s] due to: %s", volume.getPath(), e.getMessage());
logger.error(err, e);
return new StorPoolSetVolumeEncryptionAnswer(command, false, err);
} finally {
StorPoolStorageAdaptor.attachOrDetachVolume("detach", "volume", volume.getPath());
volume.clearPassphrase();
Expand All @@ -83,13 +84,16 @@ public StorPoolSetVolumeEncryptionAnswer execute(StorPoolSetVolumeEncryptionComm
private KVMPhysicalDisk encryptRootDisk(StorPoolSetVolumeEncryptionCommand command, VolumeObjectTO volume,
String srcVolumeName, KVMStoragePool pool, KVMPhysicalDisk disk) {
StorPoolStorageAdaptor.attachOrDetachVolume("attach", "snapshot", srcVolumeName);
KVMPhysicalDisk srcVolume = pool.getPhysicalDisk(srcVolumeName);
disk = copyPhysicalDisk(srcVolume, disk, command.getWait() * 1000, null, volume.getPassphrase());
disk.setQemuEncryptFormat(QemuObject.EncryptFormat.LUKS);
disk.setFormat(QemuImg.PhysicalDiskFormat.RAW);
volume.setEncryptFormat(disk.getQemuEncryptFormat().toString());
StorPoolStorageAdaptor.attachOrDetachVolume("detach", "snapshot", srcVolumeName);
return disk;
try {
KVMPhysicalDisk srcVolume = pool.getPhysicalDisk(srcVolumeName);
disk = copyPhysicalDisk(srcVolume, disk, command.getWait() * 1000, null, volume.getPassphrase());
disk.setQemuEncryptFormat(QemuObject.EncryptFormat.LUKS);
disk.setFormat(QemuImg.PhysicalDiskFormat.RAW);
volume.setEncryptFormat(disk.getQemuEncryptFormat().toString());
return disk;
} finally {
StorPoolStorageAdaptor.attachOrDetachVolume("detach", "snapshot", srcVolumeName);
}
}

private void encryptDataDisk(VolumeObjectTO volume, KVMPhysicalDisk disk) throws CryptSetupException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@
import org.apache.commons.lang3.StringUtils;

import com.cloud.agent.api.Answer;
import com.cloud.agent.api.storage.ResizeVolumeAnswer;
import com.cloud.agent.api.storage.StorPoolBackupSnapshotCommand;
import com.cloud.agent.api.storage.StorPoolBackupTemplateFromSnapshotCommand;
import com.cloud.agent.api.storage.StorPoolCopyVolumeToSecondaryCommand;
Expand All @@ -107,7 +106,6 @@
import com.cloud.agent.api.to.DataTO;
import com.cloud.agent.api.to.StorageFilerTO;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
Expand Down Expand Up @@ -142,6 +140,9 @@

public class StorPoolPrimaryDataStoreDriver implements PrimaryDataStoreDriver {

// space reserved on the StorPool volume for the LUKS header of encrypted volumes
static final long LUKS_HEADER_SIZE = 2097152;

protected Logger logger = LogManager.getLogger(getClass());

@Inject
Expand Down Expand Up @@ -299,7 +300,7 @@ public void createAsync(DataStore dataStore, DataObject data, AsyncCompletionCal
try {
VolumeInfo vinfo = (VolumeInfo)data;
String name = vinfo.getUuid();
Long size = vinfo.getPassphraseId() == null ? vinfo.getSize() : vinfo.getSize() + 2097152;
Long size = getStorPoolVolumeSize(vinfo, vinfo.getSize());
Long vmId = vinfo.getInstanceId();

SpConnectionDesc conn = StorPoolUtil.getSpConnection(dataStore.getUuid(), dataStore.getId(), storagePoolDetailsDao, primaryStoreDao);
Expand All @@ -320,11 +321,13 @@ public void createAsync(DataStore dataStore, DataObject data, AsyncCompletionCal

if (vinfo.getPassphraseId() != null) {
VolumeObjectTO volume = updateVolumeObjectTO(vinfo, resp);
answer = createEncryptedVolume(dataStore, data, vinfo, size, volume, null, true);
answer = createEncryptedVolume(data, vinfo, volume, null, true, conn);
} else {
answer = new Answer(null, true, null);
}
updateStoragePool(dataStore.getId(), size);
if (answer.getResult()) {
updateStoragePool(dataStore.getId(), size);
}
StorPoolUtil.spLog("StorpoolPrimaryDataStoreDriver.createAsync volume: name=%s, uuid=%s, isAttached=%s vm=%s, payload=%s, template: %s", volumeName, vinfo.getUuid(), vinfo.isAttachedVM(), vinfo.getAttachedVmName(), vinfo.getpayload(), conn.getTemplateName());
} else {
answer = new Answer(null, false, String.format("Could not create StorPool volume %s. Error: %s", name, resp.getError()));
Expand Down Expand Up @@ -366,7 +369,8 @@ private void updateVolume(DataStore dataStore, String path, VolumeInfo vinfo) {
volumeDao.update(volume.getId(), volume);
}

private StorPoolSetVolumeEncryptionAnswer createEncryptedVolume(DataStore dataStore, DataObject data, VolumeInfo vinfo, Long size, VolumeObjectTO volume, String parentName, boolean isDataDisk) {
private StorPoolSetVolumeEncryptionAnswer createEncryptedVolume(DataObject data, VolumeInfo vinfo, VolumeObjectTO volume, String parentName, boolean isDataDisk,
SpConnectionDesc conn) {
StorPoolSetVolumeEncryptionAnswer ans;
EndPoint ep = null;
if (parentName == null) {
Expand All @@ -384,14 +388,28 @@ private StorPoolSetVolumeEncryptionAnswer createEncryptedVolume(DataStore dataSt
ans = new StorPoolSetVolumeEncryptionAnswer(null, false, "Could not find a host with volume encryption");
} else {
StorPoolSetVolumeEncryptionCommand cmd = new StorPoolSetVolumeEncryptionCommand(volume, parentName, isDataDisk);
ans = (StorPoolSetVolumeEncryptionAnswer) ep.sendMessage(cmd);
if (ans.getResult()) {
updateStoragePool(dataStore.getId(), size);
Answer answer = ep.sendMessage(cmd);
if (answer instanceof StorPoolSetVolumeEncryptionAnswer) {
ans = (StorPoolSetVolumeEncryptionAnswer) answer;
} else {
ans = new StorPoolSetVolumeEncryptionAnswer(cmd, false, answer != null ? answer.getDetails() : "Could not encrypt the volume, a null answer was returned");
}
}
if (!ans.getResult()) {
deleteVolumeAfterFailedEncryption(volume, conn);
}
return ans;
}

private void deleteVolumeAfterFailedEncryption(VolumeObjectTO volume, SpConnectionDesc conn) {
String name = StorPoolStorageAdaptor.getVolumeNameFromPath(volume.getPath(), true);
StorPoolUtil.spLog("Deleting StorPool volume %s, because it could not be encrypted", name);
SpApiResponse resp = StorPoolUtil.volumeDelete(name, conn);
if (resp.getError() != null) {
logger.warn("Could not delete StorPool volume {} after a failed encryption due to {}", name, resp.getError());
}
}

@Override
public void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
String path = null;
Expand Down Expand Up @@ -429,7 +447,7 @@ private String resizeVolume(DataObject data, String path, VolumeObject vol) {
}
if (err != null) {
// try restoring volume to its initial size
SpApiResponse response = StorPoolUtil.volumeUpdate(name, oldSize, true, oldMaxIops, conn);
SpApiResponse response = StorPoolUtil.volumeUpdate(name, getStorPoolVolumeSize(vol, oldSize), true, oldMaxIops, conn);
if (response.getError() != null) {
logger.debug(String.format("Could not resize StorPool volume %s back to its original size. Error: %s", name, response.getError()));
}
Expand All @@ -444,23 +462,29 @@ private String resizeVolume(DataObject data, String path, VolumeObject vol) {
}

private void updateVolumeWithTheNewSize(VolumeObject vol, ResizeVolumePayload payload) {
long oldSize = vol.getSize();
vol.setSize(payload.newSize);
vol.update();
if (payload.newMaxIops != null) {
VolumeVO volume = volumeDao.findById(vol.getId());
volume.setMaxIops(payload.newMaxIops);
volumeDao.update(volume.getId(), volume);
}
updateStoragePool(vol.getPoolId(), payload.newSize - vol.getSize());
updateStoragePool(vol.getPoolId(), payload.newSize - oldSize);
}

private String notifyQemuForTheNewSize(DataObject data, String err, VolumeObject vol, ResizeVolumePayload payload)
throws StorageUnavailableException {
private String notifyQemuForTheNewSize(DataObject data, String err, VolumeObject vol, ResizeVolumePayload payload) {
StoragePool pool = (StoragePool)data.getDataStore();

StorPoolResizeVolumeCommand resizeCmd = new StorPoolResizeVolumeCommand(vol.getPath(), new StorageFilerTO(pool), vol.getSize(), payload.newSize, payload.shrinkOk,
payload.instanceName, payload.hosts == null ? false : true);
ResizeVolumeAnswer answer = (ResizeVolumeAnswer) storageMgr.sendToPool(pool, payload.hosts, resizeCmd);
// any failure is returned as an error, so the StorPool volume is restored to its initial size
Answer answer;
try {
answer = storageMgr.sendToPool(pool, payload.hosts, resizeCmd);
} catch (Exception e) {
return String.format("Could not send the resize command for volume [%s] due to: %s", vol.getPath(), e.getMessage());
}

if (answer == null || !answer.getResult()) {
err = answer != null ? answer.getDetails() : "return a null answer, resize failed for unknown reason";
Expand All @@ -482,7 +506,7 @@ private String updateStorPoolVolume(VolumeObject vol, ResizeVolumePayload payloa
}
SpApiResponse resp = new SpApiResponse();
if (tier != null || template != null) {
resp = updateVolumeByStorPoolQoS(payload, conn, name, tier, template);
resp = updateVolumeByStorPoolQoS(vol, payload, conn, name, tier, template);
} else {
resp = updateVolumeByOffering(vol, payload, conn, name);
}
Expand All @@ -492,24 +516,32 @@ private String updateStorPoolVolume(VolumeObject vol, ResizeVolumePayload payloa
return err;
}

private static SpApiResponse updateVolumeByStorPoolQoS(ResizeVolumePayload payload, SpConnectionDesc conn, String name, String tier, String template) {
private static SpApiResponse updateVolumeByStorPoolQoS(VolumeObject vol, ResizeVolumePayload payload, SpConnectionDesc conn, String name, String tier, String template) {
Map<String, String> tags = StorPoolHelper.addStorPoolTags(null, null, null, null, tier);
StorPoolVolumeDef spVolume = new StorPoolVolumeDef(name, payload.newSize, tags, null, null, template, null, null,
StorPoolVolumeDef spVolume = new StorPoolVolumeDef(name, getStorPoolVolumeSize(vol, payload.newSize), tags, null, null, template, null, null,
payload.shrinkOk);
return StorPoolUtil.volumeUpdate(spVolume, conn);
}

private static SpApiResponse updateVolumeByOffering(VolumeObject vol, ResizeVolumePayload payload, SpConnectionDesc conn, String name) {
long maxIops = payload.newMaxIops == null ? Long.valueOf(0) : payload.newMaxIops;
Long newSize = getStorPoolVolumeSize(vol, payload.newSize);

StorPoolVolumeDef spVolume = new StorPoolVolumeDef(name, payload.newSize, null, null, maxIops, null, null, null,
StorPoolVolumeDef spVolume = new StorPoolVolumeDef(name, newSize, null, null, maxIops, null, null, null,
payload.shrinkOk);
StorPoolUtil.spLog(
"StorpoolPrimaryDataStoreDriverImpl.resize: name=%s, uuid=%s, oldSize=%d, newSize=%s, shrinkOk=%s, maxIops=%s",
name, vol.getUuid(), vol.getSize(), payload.newSize, payload.shrinkOk, maxIops);
name, vol.getUuid(), vol.getSize(), newSize, payload.shrinkOk, maxIops);
return StorPoolUtil.volumeUpdate(spVolume, conn);
}

static Long getStorPoolVolumeSize(VolumeInfo vol, Long size) {
if (size == null || vol.getPassphraseId() == null) {
return size;
}
return size + LUKS_HEADER_SIZE;
}

@Override
public void deleteAsync(DataStore dataStore, DataObject data, AsyncCompletionCallback<CommandResult> callback) {
String err = null;
Expand Down Expand Up @@ -872,11 +904,10 @@ public void copyAsync(DataObject srcData, DataObject dstData, AsyncCompletionCal
vinfo.getDataStore().getId(), storagePoolDetailsDao, primaryStoreDao);

Long snapshotSize = templStoragePoolVO.getTemplateSize();
boolean withoutEncryption = vinfo.getPassphraseId() == null;
long size = withoutEncryption ? vinfo.getSize() : vinfo.getSize() + 2097152;
long size = getStorPoolVolumeSize(vinfo, vinfo.getSize());
if (snapshotSize != null && size < snapshotSize) {
StorPoolUtil.spLog(String.format("provided size is too small for snapshot. Provided %d, snapshot %d. Using snapshot size", size, snapshotSize));
size = withoutEncryption ? snapshotSize : snapshotSize + 2097152;
size = getStorPoolVolumeSize(vinfo, snapshotSize);
}
StorPoolUtil.spLog(String.format("volume size is: %d", size));
Long vmId = vinfo.getInstanceId();
Expand Down Expand Up @@ -909,20 +940,22 @@ public void copyAsync(DataObject srcData, DataObject dstData, AsyncCompletionCal
resp = StorPoolUtil.volumeCreate(volumeDef, conn);

if (resp.getError() == null) {
updateStoragePool(dstData.getDataStore().getId(), vinfo.getSize());
updateVolumePoolType(vinfo);

if (withoutEncryption) {
if (vinfo.getPassphraseId() == null) {
VolumeObjectTO to = updateVolumeObjectTO(vinfo, resp);
answer = new CopyCmdAnswer(to);
} else {
VolumeObjectTO volume = updateVolumeObjectTO(vinfo, resp);
String snapshotPath = StorPoolUtil.devPath(parentName.split("~")[1]);
answer = createEncryptedVolume(dstData.getDataStore(), dstData, vinfo, size, volume, snapshotPath, false);
answer = createEncryptedVolume(dstData, vinfo, volume, snapshotPath, false, conn);
if (answer.getResult()) {
answer = new CopyCmdAnswer(((StorPoolSetVolumeEncryptionAnswer) answer).getVolume());
}
}
if (answer.getResult()) {
updateStoragePool(dstData.getDataStore().getId(), vinfo.getSize());
}
} else {
err = String.format("Could not create Storpool volume %s. Error: %s", name, resp.getError());
}
Expand Down
Loading
Loading