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

<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="VolumeEncryptionConversionHostLeaseHelper" class="org.zstack.storage.encrypt.VolumeEncryptionConversionHostLeaseHelper"/>

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

Expand Down
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,
ReturnValueCompletion<VolumeBackupEncryptionConversionContext> completion);

void commitVolumeBackupEncryptionConversion(VolumeBackupEncryptionConversionContext context);

void rollbackVolumeBackupEncryptionConversion(VolumeBackupEncryptionConversionContext context);

void afterVolumeBackupEncryptionConversionCommitted(VolumeBackupEncryptionConversionContext context);
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -926,20 +926,11 @@ protected void handle(ConvertVolumeEncryptionOnPrimaryStorageMsg msg) {
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 converting volume[uuid:%s] encryption on local primary storage[uuid:%s]",
msg.getVolume().getUuid(), self.getUuid()));
String hostUuid;
try {
hostUuid = resolveHostForConvertVolumeEncryption(msg);
} catch (OperationFailureException e) {
reply.setError(e.getErrorCode());
bus.reply(msg, reply);
return;
}
Expand All @@ -959,6 +950,40 @@ public void fail(ErrorCode errorCode) {
});
}

private String resolveHostForConvertVolumeEncryption(ConvertVolumeEncryptionOnPrimaryStorageMsg msg) {
String hostUuid = msg.getHostUuid();
if (StringUtils.isBlank(hostUuid)) {
throw new OperationFailureException(operr(
"convert volume encryption on local primary storage[uuid:%s] requires hostUuid for volume[uuid:%s]",
self.getUuid(), msg.getVolume().getUuid()));
}

String actualHostUuid = Q.New(LocalStorageResourceRefVO.class)
.eq(LocalStorageResourceRefVO_.resourceUuid, msg.getVolume().getUuid())
.eq(LocalStorageResourceRefVO_.resourceType, VolumeVO.class.getSimpleName())
.eq(LocalStorageResourceRefVO_.primaryStorageUuid, self.getUuid())
.select(LocalStorageResourceRefVO_.hostUuid)
.findValue();
if (StringUtils.isBlank(actualHostUuid) || !hostUuid.equals(actualHostUuid)) {
throw new OperationFailureException(operr(
"volume[uuid:%s] on local primary storage[uuid:%s] belongs to host[uuid:%s], cannot convert encryption on host[uuid:%s]",
msg.getVolume().getUuid(), self.getUuid(), actualHostUuid, hostUuid));
}

boolean hostReady = Q.New(HostVO.class)
.eq(HostVO_.uuid, hostUuid)
.eq(HostVO_.status, HostStatus.Connected)
.eq(HostVO_.state, HostState.Enabled)
.isExists();
if (!hostReady) {
throw new OperationFailureException(operr(
"host[uuid:%s] is not enabled and connected for converting volume[uuid:%s] encryption on local primary storage[uuid:%s]",
hostUuid, msg.getVolume().getUuid(), self.getUuid()));
}

return hostUuid;
}

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 @@ -2351,7 +2351,13 @@ public void run(MessageReply reply) {
@Override
public void handle(PrimaryStorageInventory inv, ConvertVolumeEncryptionOnPrimaryStorageMsg msg,
ReturnValueCompletion<ConvertVolumeEncryptionOnPrimaryStorageReply> completion) {
HostInventory host = nfsFactory.getConnectedHostForOperation(inv).get(0);
HostInventory host;
try {
host = resolveHostForConvertVolumeEncryption(inv, msg.getHostUuid());
} catch (OperationFailureException e) {
completion.fail(e.getErrorCode());
return;
}
ConvertVolumeEncryptionCmd cmd = new ConvertVolumeEncryptionCmd();
cmd.setUuid(inv.getUuid());
cmd.volumeUuid = msg.getVolume().getUuid();
Expand Down Expand Up @@ -2387,6 +2393,38 @@ public void run(MessageReply reply) {
});
}

private HostInventory resolveHostForConvertVolumeEncryption(PrimaryStorageInventory inv, String hostUuid) {
if (StringUtils.isBlank(hostUuid)) {
throw new OperationFailureException(operr(
"convert volume encryption on NFS primary storage[uuid:%s] requires hostUuid",
inv.getUuid()));
}

HostVO host = Q.New(HostVO.class)
.eq(HostVO_.uuid, hostUuid)
.eq(HostVO_.status, HostStatus.Connected)
.eq(HostVO_.state, HostState.Enabled)
.find();
if (host == null || !inv.getAttachedClusterUuids().contains(host.getClusterUuid())) {
throw new OperationFailureException(operr(
"host[uuid:%s] is not an enabled connected host attached to NFS primary storage[uuid:%s]",
hostUuid, inv.getUuid()));
}

PrimaryStorageHostStatus status = Q.New(PrimaryStorageHostRefVO.class)
.eq(PrimaryStorageHostRefVO_.primaryStorageUuid, inv.getUuid())
.eq(PrimaryStorageHostRefVO_.hostUuid, hostUuid)
.select(PrimaryStorageHostRefVO_.status)
.findValue();
if (status != PrimaryStorageHostStatus.Connected) {
throw new OperationFailureException(operr(
"host[uuid:%s] is not connected to NFS primary storage[uuid:%s]",
hostUuid, inv.getUuid()));
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

return HostInventory.valueOf(host);
}

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
@@ -0,0 +1,64 @@
package org.zstack.storage.encrypt;

import org.zstack.header.volume.VolumeBackupEncryptionConversionContext;
import org.zstack.header.volume.VolumeBackupEncryptionConversionExtensionPoint;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;

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

public class VolumeBackupEncryptionConversionExtensionHelper {
private static final CLogger logger = Utils.getLogger(VolumeBackupEncryptionConversionExtensionHelper.class);

public static class Context {
private final VolumeBackupEncryptionConversionExtensionPoint extension;
private final VolumeBackupEncryptionConversionContext context;

public Context(VolumeBackupEncryptionConversionExtensionPoint extension,
VolumeBackupEncryptionConversionContext context) {
this.extension = extension;
this.context = context;
}
}

public Context makeContext(VolumeBackupEncryptionConversionExtensionPoint extension,
VolumeBackupEncryptionConversionContext context) {
return new Context(extension, context);
}

public void commit(List<Context> contexts) {
for (Context context : safeContexts(contexts)) {
context.extension.commitVolumeBackupEncryptionConversion(context.context);
}
}

public void rollback(List<Context> contexts, String volumeUuid) {
List<Context> reversed = new ArrayList<>(safeContexts(contexts));
Collections.reverse(reversed);
for (Context context : reversed) {
try {
context.extension.rollbackVolumeBackupEncryptionConversion(context.context);
} catch (RuntimeException e) {
logger.warn(String.format("failed to rollback volume backup encryption conversion for volume[uuid:%s]: %s",
volumeUuid, e.getMessage()), e);
}
}
}

public void cleanupCommitted(List<Context> contexts, String volumeUuid) {
for (Context context : safeContexts(contexts)) {
try {
context.extension.afterVolumeBackupEncryptionConversionCommitted(context.context);
} catch (RuntimeException e) {
logger.warn(String.format("failed to run volume backup encryption conversion cleanup for volume[uuid:%s]: %s",
volumeUuid, e.getMessage()), e);
}
}
}

private List<Context> safeContexts(List<Context> contexts) {
return contexts == null ? Collections.emptyList() : contexts;
}
}
Loading