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
1 change: 1 addition & 0 deletions conf/springConfigXml/VolumeManager.xml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@

<bean id="VolumeEncryptedSecretHelper" class="org.zstack.storage.encrypt.VolumeEncryptedSecretHelper"/>
<bean id="VolumeEncryptedTrashCleanupHelper" class="org.zstack.storage.encrypt.VolumeEncryptedTrashCleanupHelper"/>
<bean id="VolumeBackupEncryptionConversionExtensionHelper" class="org.zstack.storage.encrypt.VolumeBackupEncryptionConversionExtensionHelper"/>

<bean id="VolumeSnapshotEncryptionHelper" class="org.zstack.storage.encrypt.VolumeSnapshotEncryptionHelper"/>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.zstack.header.storage.primary;

import org.zstack.header.message.NeedReplyMessage;
import org.zstack.header.volume.VolumeInventory;

import java.util.ArrayList;
import java.util.List;

public class RollbackVolumeEncryptionOnPrimaryStorageMsg extends NeedReplyMessage implements PrimaryStorageMessage {
private String hostUuid;
private VolumeInventory volume;
private List<ConvertVolumeEncryptionOnPrimaryStorageMsg.VolumeEncryptionConversionItem> items = new ArrayList<>();

@Override
public String getPrimaryStorageUuid() {
return volume.getPrimaryStorageUuid();
}

public String getHostUuid() {
return hostUuid;
}

public void setHostUuid(String hostUuid) {
this.hostUuid = hostUuid;
}

public VolumeInventory getVolume() {
return volume;
}

public void setVolume(VolumeInventory volume) {
this.volume = volume;
}

public List<ConvertVolumeEncryptionOnPrimaryStorageMsg.VolumeEncryptionConversionItem> getItems() {
return items;
}

public void setItems(List<ConvertVolumeEncryptionOnPrimaryStorageMsg.VolumeEncryptionConversionItem> items) {
this.items = items;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.zstack.header.storage.primary;

import org.zstack.header.message.MessageReply;

public class RollbackVolumeEncryptionOnPrimaryStorageReply extends MessageReply {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.zstack.header.volume;

public class VolumeBackupEncryptionConversionContext {
private String volumeUuid;
private boolean targetEncrypted;
private Object extensionData;

public String getVolumeUuid() {
return volumeUuid;
}

public void setVolumeUuid(String volumeUuid) {
this.volumeUuid = volumeUuid;
}

public boolean isTargetEncrypted() {
return targetEncrypted;
}

public void setTargetEncrypted(boolean targetEncrypted) {
this.targetEncrypted = targetEncrypted;
}

public Object getExtensionData() {
return extensionData;
}

public void setExtensionData(Object extensionData) {
this.extensionData = extensionData;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.zstack.header.volume;

import org.zstack.header.core.ReturnValueCompletion;

public interface VolumeBackupEncryptionConversionExtensionPoint {
void prepareVolumeBackupEncryptionConversion(VolumeInventory volume, boolean encrypted, String hostUuid,
ReturnValueCompletion<VolumeBackupEncryptionConversionContext> completion);

void commitVolumeBackupEncryptionConversion(VolumeBackupEncryptionConversionContext context);

void rollbackVolumeBackupEncryptionConversion(VolumeBackupEncryptionConversionContext context);

void afterVolumeBackupEncryptionConversionCommitted(VolumeBackupEncryptionConversionContext context);
}
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,12 @@ public static class ReplaceLuksRbdRsp extends AgentResponse {
public Long actualSize;
}

public static class RollbackLuksRbdCmd extends AgentCommand {
public String installPath;
public String targetInstallPath;
public String sourceTrashInstallPath;
}

public static class SwapInPlaceLuksRbdCmd extends AgentCommand {
public String installPath;
public String temporaryInstallPath;
Expand Down Expand Up @@ -1455,6 +1461,7 @@ public int compareTo(SnapInfo snapInfo) {
public static final String KVM_HOST_LUKS_RESIZE_PATH = "/ceph/primarystorage/kvmhost/luksresize";
public static final String KVM_HOST_LUKS_CONVERT_PATH = "/ceph/primarystorage/kvmhost/luksconvert";
public static final String LUKS_REPLACE_VOLUME_PATH = "/ceph/primarystorage/volume/luksreplace";
public static final String LUKS_ROLLBACK_CONVERT_PATH = "/ceph/primarystorage/volume/luksconvert/rollback";
public static final String LUKS_SWAP_IN_PLACE_PATH = "/ceph/primarystorage/volume/luksswapinplace";
public static final String KVM_HOST_IMAGESTORE_ENCRYPTED_DOWNLOAD_PATH = "/ceph/primarystorage/kvmhost/imagestore/encrypteddownload";
public static final String FLATTEN_PATH = "/ceph/primarystorage/volume/flatten";
Expand Down Expand Up @@ -3673,6 +3680,54 @@ public void fail(ErrorCode errorCode) {
});
}

@Override
protected void handle(RollbackVolumeEncryptionOnPrimaryStorageMsg msg) {
RollbackVolumeEncryptionOnPrimaryStorageReply reply = new RollbackVolumeEncryptionOnPrimaryStorageReply();
if (msg.getItems() == null || msg.getItems().size() != 1) {
reply.setError(operr(
"ceph rollback volume encryption conversion requires volume snapshots to be merged before rollback; volume[uuid:%s] has %s rollback items",
msg.getVolume().getUuid(), msg.getItems() == null ? 0 : msg.getItems().size()));
bus.reply(msg, reply);
return;
}

ConvertVolumeEncryptionOnPrimaryStorageMsg.VolumeEncryptionConversionItem item = msg.getItems().get(0);
if (!VolumeVO.class.getSimpleName().equals(item.getResourceType())) {
reply.setError(operr(
"ceph rollback volume encryption conversion only supports the active volume after snapshots are merged, but got resource[type:%s, uuid:%s]",
item.getResourceType(), item.getResourceUuid()));
bus.reply(msg, reply);
return;
}

if (StringUtils.isBlank(item.getSourceInstallPath()) || item.getSourceInstallPath().contains("@")) {
reply.setError(operr(
"ceph rollback volume encryption conversion requires an active RBD source path, but got source path[%s]",
item.getSourceInstallPath()));
bus.reply(msg, reply);
return;
}

RollbackLuksRbdCmd rcmd = new RollbackLuksRbdCmd();
rcmd.installPath = item.getSourceInstallPath();
rcmd.targetInstallPath = item.getTargetInstallPath();
rcmd.sourceTrashInstallPath = item.getSourceTrashInstallPath();

httpCall(LUKS_ROLLBACK_CONVERT_PATH, rcmd, AgentResponse.class,
new ReturnValueCompletion<AgentResponse>(msg) {
@Override
public void fail(ErrorCode err) {
reply.setError(err);
bus.reply(msg, reply);
}

@Override
public void success(AgentResponse ret) {
bus.reply(msg, reply);
}
});
}

@Override
protected void handle(final DownloadIsoToPrimaryStorageMsg msg) {
final DownloadIsoToPrimaryStorageReply reply = new DownloadIsoToPrimaryStorageReply();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,8 @@ public void handleLocalMessage(Message msg) {
handle((EncryptVolumeBitsOnPrimaryStorageMsg) msg);
} else if (msg instanceof ConvertVolumeEncryptionOnPrimaryStorageMsg) {
handle((ConvertVolumeEncryptionOnPrimaryStorageMsg) msg);
} else if (msg instanceof RollbackVolumeEncryptionOnPrimaryStorageMsg) {
handle((RollbackVolumeEncryptionOnPrimaryStorageMsg) msg);
} else {
super.handleLocalMessage(msg);
}
Expand Down Expand Up @@ -959,6 +961,48 @@ public void fail(ErrorCode errorCode) {
});
}

protected void handle(RollbackVolumeEncryptionOnPrimaryStorageMsg msg) {
RollbackVolumeEncryptionOnPrimaryStorageReply reply = new RollbackVolumeEncryptionOnPrimaryStorageReply();
if (msg.getVolume() == null || StringUtils.isBlank(msg.getVolume().getUuid())) {
reply.setError(operr("rollback volume encryption on local primary storage[uuid:%s] requires volume with non-blank uuid",
self.getUuid()));
bus.reply(msg, reply);
return;
}

String hostUuid = StringUtils.isNotBlank(msg.getHostUuid()) ?
msg.getHostUuid() : null;
if (StringUtils.isBlank(hostUuid)) {
try {
hostUuid = getHostUuidByResourceUuid(msg.getVolume().getUuid());
} catch (OperationFailureException e) {
reply.setError(e.getErrorCode());
bus.reply(msg, reply);
return;
}
}
if (StringUtils.isBlank(hostUuid)) {
reply.setError(operr("cannot determine host for rolling back volume[uuid:%s] encryption conversion on local primary storage[uuid:%s]",
msg.getVolume().getUuid(), self.getUuid()));
bus.reply(msg, reply);
return;
}

LocalStorageHypervisorBackend bkd = getHypervisorBackendFactoryByHostUuid(hostUuid).getHypervisorBackend(self);
bkd.handle(msg, hostUuid, new ReturnValueCompletion<RollbackVolumeEncryptionOnPrimaryStorageReply>(msg) {
@Override
public void success(RollbackVolumeEncryptionOnPrimaryStorageReply returnValue) {
bus.reply(msg, returnValue);
}

@Override
public void fail(ErrorCode errorCode) {
reply.setError(errorCode);
bus.reply(msg, reply);
}
});
}

private void handle(EncryptVolumeBitsOnPrimaryStorageMsg msg) {
if (StringUtils.isBlank(msg.getHostUuid()) || StringUtils.isBlank(msg.getVolumeUuid())) {
EncryptVolumeBitsOnPrimaryStorageReply reply = new EncryptVolumeBitsOnPrimaryStorageReply();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,6 @@ abstract void createEmptyVolumeWithBackingFile(VolumeInventory volume, String ho
abstract void handle(EncryptVolumeBitsOnPrimaryStorageMsg msg, ReturnValueCompletion<EncryptVolumeBitsOnPrimaryStorageReply> completion);

abstract void handle(ConvertVolumeEncryptionOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion<ConvertVolumeEncryptionOnPrimaryStorageReply> completion);

abstract void handle(RollbackVolumeEncryptionOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion<RollbackVolumeEncryptionOnPrimaryStorageReply> completion);
}
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,14 @@ public static class ConvertVolumeEncryptionRsp extends AgentResponse {
public Map<String, Long> actualSizes;
}

public static class RollbackVolumeEncryptionCmd extends AgentCommand implements Serializable {
public String volumeUuid;
public List<ConvertVolumeEncryptionOnPrimaryStorageMsg.VolumeEncryptionConversionItem> items;
}

public static class RollbackVolumeEncryptionRsp extends AgentResponse {
}

public static class GetPhysicalCapacityCmd extends AgentCommand {
private String hostUuid;

Expand Down Expand Up @@ -1097,6 +1105,7 @@ public static class PrefixRebaseBackingFilesRsp extends LocalStorageKvmBackend.A
public static final String PREFIX_REBASE_BACKING_FILES_PATH = "/localstorage/snapshot/prefixrebasebackingfiles";
public static final String ENCRYPT_VOLUME_BITS_PATH = "/localstorage/volume/encryptinplace";
public static final String CONVERT_VOLUME_ENCRYPTION_PATH = "/localstorage/volume/convertencryption";
public static final String ROLLBACK_VOLUME_ENCRYPTION_PATH = "/localstorage/volume/convertencryption/rollback";

public LocalStorageKvmBackend() {
}
Expand Down Expand Up @@ -4183,6 +4192,28 @@ public void fail(ErrorCode errorCode) {
});
}

@Override
void handle(RollbackVolumeEncryptionOnPrimaryStorageMsg msg, String hostUuid,
ReturnValueCompletion<RollbackVolumeEncryptionOnPrimaryStorageReply> completion) {
RollbackVolumeEncryptionCmd cmd = new RollbackVolumeEncryptionCmd();
cmd.volumeUuid = msg.getVolume().getUuid();
cmd.items = msg.getItems();

httpCall(ROLLBACK_VOLUME_ENCRYPTION_PATH, hostUuid, cmd, RollbackVolumeEncryptionRsp.class,
new ReturnValueCompletion<RollbackVolumeEncryptionRsp>(completion) {
@Override
public void success(RollbackVolumeEncryptionRsp rsp) {
completion.success(new RollbackVolumeEncryptionOnPrimaryStorageReply());
}

@Override
public void fail(ErrorCode errorCode) {
completion.fail(operr("failed to rollback volume[uuid:%s] encryption conversion on local storage host[uuid:%s]: %s",
msg.getVolume().getUuid(), hostUuid, errorCode));
}
});
}

private String prepareVolumeEncryptedDek(String hostUuid, VolumeInventory volume, boolean required) {
if (!required) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ protected void handleLocalMessage(Message msg) {
handle((EncryptVolumeBitsOnPrimaryStorageMsg) msg);
} else if (msg instanceof ConvertVolumeEncryptionOnPrimaryStorageMsg) {
handle((ConvertVolumeEncryptionOnPrimaryStorageMsg) msg);
} else if (msg instanceof RollbackVolumeEncryptionOnPrimaryStorageMsg) {
handle((RollbackVolumeEncryptionOnPrimaryStorageMsg) msg);
} else {
super.handleLocalMessage(msg);
}
Expand Down Expand Up @@ -169,6 +171,30 @@ public void fail(ErrorCode errorCode) {
});
}

protected void handle(RollbackVolumeEncryptionOnPrimaryStorageMsg msg) {
RollbackVolumeEncryptionOnPrimaryStorageReply reply = new RollbackVolumeEncryptionOnPrimaryStorageReply();
NfsPrimaryStorageBackend backend = getUsableBackend();
if (backend == null) {
reply.setError(operr("the NFS primary storage[uuid:%s, name:%s] cannot find any usable host to rollback volume[uuid:%s] encryption conversion",
self.getUuid(), self.getName(), msg.getVolume().getUuid()));
bus.reply(msg, reply);
return;
}

backend.handle(getSelfInventory(), msg, new ReturnValueCompletion<RollbackVolumeEncryptionOnPrimaryStorageReply>(msg) {
@Override
public void success(RollbackVolumeEncryptionOnPrimaryStorageReply returnValue) {
bus.reply(msg, returnValue);
}

@Override
public void fail(ErrorCode errorCode) {
reply.setError(errorCode);
bus.reply(msg, reply);
}
});
}

private void handle(EncryptVolumeBitsOnPrimaryStorageMsg msg) {
NfsPrimaryStorageBackend backend = getUsableBackend();
if (backend == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ public interface NfsPrimaryStorageBackend {

void handle(PrimaryStorageInventory inv, ConvertVolumeEncryptionOnPrimaryStorageMsg msg, ReturnValueCompletion<ConvertVolumeEncryptionOnPrimaryStorageReply> completion);

void handle(PrimaryStorageInventory inv, RollbackVolumeEncryptionOnPrimaryStorageMsg msg, ReturnValueCompletion<RollbackVolumeEncryptionOnPrimaryStorageReply> completion);

void getPhysicalCapacity(PrimaryStorageInventory inv, ReturnValueCompletion<PhysicalCapacityUsage> completion);

void checkIsBitsExisting(PrimaryStorageInventory inv, String installPath, ReturnValueCompletion<Boolean> completion);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ public class NfsPrimaryStorageKVMBackend implements NfsPrimaryStorageBackend,
public static final String CREATE_VOLUME_FROM_TEMPLATE_PATH = "/nfsprimarystorage/sftp/createvolumefromtemplate";
public static final String ENCRYPT_VOLUME_BITS_PATH = "/nfsprimarystorage/volume/encryptinplace";
public static final String CONVERT_VOLUME_ENCRYPTION_PATH = "/nfsprimarystorage/volume/convertencryption";
public static final String ROLLBACK_VOLUME_ENCRYPTION_PATH = "/nfsprimarystorage/volume/convertencryption/rollback";
public static final String GET_QCOW2_HASH_VALUE_PATH = "/nfsprimarystorage/getqcow2hash";
public static final String WRITE_VM_METADATA_PATH = "/nfsprimarystorage/vm/metadata/write";

Expand Down Expand Up @@ -2387,6 +2388,40 @@ public void run(MessageReply reply) {
});
}

@Override
public void handle(PrimaryStorageInventory inv, RollbackVolumeEncryptionOnPrimaryStorageMsg msg,
ReturnValueCompletion<RollbackVolumeEncryptionOnPrimaryStorageReply> completion) {
HostInventory host = nfsFactory.getConnectedHostForOperation(inv).get(0);
RollbackVolumeEncryptionCmd cmd = new RollbackVolumeEncryptionCmd();
cmd.setUuid(inv.getUuid());
cmd.volumeUuid = msg.getVolume().getUuid();
cmd.items = msg.getItems();

KVMHostAsyncHttpCallMsg hmsg = new KVMHostAsyncHttpCallMsg();
hmsg.setCommand(cmd);
hmsg.setPath(ROLLBACK_VOLUME_ENCRYPTION_PATH);
hmsg.setHostUuid(host.getUuid());
bus.makeTargetServiceIdByResourceUuid(hmsg, HostConstant.SERVICE_ID, host.getUuid());
bus.send(hmsg, new CloudBusCallBack(completion) {
@Override
public void run(MessageReply reply) {
if (!reply.isSuccess()) {
completion.fail(reply.getError());
return;
}

RollbackVolumeEncryptionRsp rsp = ((KVMHostAsyncHttpCallReply) reply).toResponse(RollbackVolumeEncryptionRsp.class);
if (!rsp.isSuccess()) {
completion.fail(operr("failed to rollback volume[uuid:%s] encryption conversion on NFS primary storage[uuid:%s] via host[uuid:%s]: %s",
msg.getVolume().getUuid(), inv.getUuid(), host.getUuid(), rsp.getError()));
return;
}

completion.success(new RollbackVolumeEncryptionOnPrimaryStorageReply());
}
});
}

private String prepareVolumeEncryptedDek(String hostUuid, VolumeInventory volume, boolean required) {
if (!required) {
return null;
Expand Down
Loading