From bc5cb731521b861eed0e925c0c6679b519a8ee5b Mon Sep 17 00:00:00 2001 From: "zhong.zhou" Date: Sun, 14 Jun 2026 16:01:17 +0800 Subject: [PATCH 1/4] [storage]: support backup key restore inheritance Resolves: ZSV-261 Change-Id: Iff94981e12e216380d980869b951f0d38105de87 --- .../ceph/primary/CephPrimaryStorageBase.java | 14 ++++++++++++++ .../DummyVolumeEncryptedResourceKeyBackend.java | 15 +++++++++++++++ .../encrypt/VolumeEncryptedInitialExtension.java | 7 +++++++ .../VolumeEncryptedResourceKeyBackend.java | 6 ++++++ 4 files changed, 42 insertions(+) diff --git a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java index 007f457afb3..71144d8e524 100755 --- a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java +++ b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java @@ -463,6 +463,19 @@ public static class KVMHostLuksConvertCmd implements Serializable { public Long virtualSize; } + public static class KVMHostImageStoreEncryptedDownloadCmd implements Serializable { + public String psUuid; + public String hostname; + public String backupStorageInstallPath; + public String primaryStorageInstallPath; + public int concurrency; + public String keyProviderUuid; + public Integer keyVersion; + public String cipher; + @NoLogging + public String encryptedDek; + } + public static class KVMHostEncryptInPlaceCmd implements Serializable { public String psUuid; @NoLogging @@ -1420,6 +1433,7 @@ public int compareTo(SnapInfo snapInfo) { public static final String KVM_HOST_LUKS_ENCRYPT_IN_PLACE_PATH = "/ceph/primarystorage/kvmhost/encryptinplace"; 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 KVM_HOST_IMAGESTORE_ENCRYPTED_DOWNLOAD_PATH = "/ceph/primarystorage/kvmhost/imagestore/encrypteddownload"; public static final String FLATTEN_PATH = "/ceph/primarystorage/volume/flatten"; public static final String SFTP_DOWNLOAD_PATH = "/ceph/primarystorage/sftpbackupstorage/download"; public static final String SFTP_UPLOAD_PATH = "/ceph/primarystorage/sftpbackupstorage/upload"; diff --git a/storage/src/main/java/org/zstack/storage/encrypt/DummyVolumeEncryptedResourceKeyBackend.java b/storage/src/main/java/org/zstack/storage/encrypt/DummyVolumeEncryptedResourceKeyBackend.java index ef4a8da276b..e7b7c45c53c 100644 --- a/storage/src/main/java/org/zstack/storage/encrypt/DummyVolumeEncryptedResourceKeyBackend.java +++ b/storage/src/main/java/org/zstack/storage/encrypt/DummyVolumeEncryptedResourceKeyBackend.java @@ -56,6 +56,11 @@ public boolean checkTemporarySnapshotImageKeyProviderAttached(String imageUuid) return false; } + @Override + public boolean checkBackupKeyProviderAttached(String backupUuid) { + return false; + } + @Override public void copyVolumeKeyToSnapshot(String volumeUuid, String snapshotUuid) { logger.debug(String.format("ignore copy volume[uuid:%s] key to snapshot[uuid:%s]", volumeUuid, snapshotUuid)); @@ -86,6 +91,16 @@ public void copyVolumeKeyToBackup(String volumeUuid, String backupUuid) { logger.debug(String.format("ignore copy volume[uuid:%s] key to backup[uuid:%s]", volumeUuid, backupUuid)); } + @Override + public void copyBackupKeyToTemporarySnapshotImage(String backupUuid, String imageUuid) { + logger.debug(String.format("ignore copy backup[uuid:%s] key to temporary snapshot image[uuid:%s]", backupUuid, imageUuid)); + } + + @Override + public void copyBackupKeyToVolume(String backupUuid, String volumeUuid) { + logger.debug(String.format("ignore copy backup[uuid:%s] key to volume[uuid:%s]", backupUuid, volumeUuid)); + } + @Override public String defaultKeyProviderUuid() { return null; diff --git a/storage/src/main/java/org/zstack/storage/encrypt/VolumeEncryptedInitialExtension.java b/storage/src/main/java/org/zstack/storage/encrypt/VolumeEncryptedInitialExtension.java index f407283f3e6..2a8b714d298 100644 --- a/storage/src/main/java/org/zstack/storage/encrypt/VolumeEncryptedInitialExtension.java +++ b/storage/src/main/java/org/zstack/storage/encrypt/VolumeEncryptedInitialExtension.java @@ -80,6 +80,13 @@ private void inheritTemporaryRootVolumeKeyFromOrigin(InstantiateVolumeMsg msg, V return; } + // A backup or snapshot temporary image can already provide the target root + // volume key. Keep that key as the source of truth; falling back to the + // origin root would overwrite it or fail if the origin key binding is gone. + if (volumeEncryptedResourceKeyBackend.checkVolumeKeyProviderAttached(volume.getUuid())) { + return; + } + String originVolumeUuid = ((InstantiateTemporaryRootVolumeMsg) msg).getOriginVolumeUuid(); if (StringUtils.isBlank(originVolumeUuid)) { return; diff --git a/storage/src/main/java/org/zstack/storage/encrypt/VolumeEncryptedResourceKeyBackend.java b/storage/src/main/java/org/zstack/storage/encrypt/VolumeEncryptedResourceKeyBackend.java index 1093f728c4a..a76326ed247 100644 --- a/storage/src/main/java/org/zstack/storage/encrypt/VolumeEncryptedResourceKeyBackend.java +++ b/storage/src/main/java/org/zstack/storage/encrypt/VolumeEncryptedResourceKeyBackend.java @@ -40,6 +40,8 @@ public interface VolumeEncryptedResourceKeyBackend { boolean checkTemporarySnapshotImageKeyProviderAttached(String imageUuid); + boolean checkBackupKeyProviderAttached(String backupUuid); + void copyVolumeKeyToSnapshot(String volumeUuid, String snapshotUuid); void copySnapshotKeyToVolume(String snapshotUuid, String volumeUuid); @@ -52,6 +54,10 @@ public interface VolumeEncryptedResourceKeyBackend { void copyVolumeKeyToBackup(String volumeUuid, String backupUuid); + void copyBackupKeyToTemporarySnapshotImage(String backupUuid, String imageUuid); + + void copyBackupKeyToVolume(String backupUuid, String volumeUuid); + /** * Global default key provider uuid, or null (e.g. NONE / crypto not installed). */ From 90f7f34c5d082bd006ce22fb0776e5dd440ae8e6 Mon Sep 17 00:00:00 2001 From: "zhong.zhou" Date: Sat, 20 Jun 2026 23:49:38 +0800 Subject: [PATCH 2/4] [storage]: support encrypted clone upload Resolves: ZSV-12473 Change-Id: I2b78b72d2126bc51978e9dc4299b304a735bbe35 --- .../storage/primary/MediatorUploadParam.java | 3 + .../ceph/primary/CephPrimaryStorageBase.java | 21 +++ .../primary/CephPrimaryStorageFactory.java | 165 +++++++++++++++++- .../primary/UploadBitsToBackupStorageMsg.java | 27 +++ 4 files changed, 213 insertions(+), 3 deletions(-) diff --git a/header/src/main/java/org/zstack/header/storage/primary/MediatorUploadParam.java b/header/src/main/java/org/zstack/header/storage/primary/MediatorUploadParam.java index e52473c6cae..adf30b92cce 100644 --- a/header/src/main/java/org/zstack/header/storage/primary/MediatorUploadParam.java +++ b/header/src/main/java/org/zstack/header/storage/primary/MediatorUploadParam.java @@ -8,4 +8,7 @@ public class MediatorUploadParam implements MediatorParam { public String primaryStorageInstallPath; public String backupStorageInstallPath; public String backupStorageUuid; + public Boolean encrypted; + public String encryptedDek; + public String encryptedHostUuid; } diff --git a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java index 71144d8e524..2c0c16de09b 100755 --- a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java +++ b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java @@ -476,6 +476,23 @@ public static class KVMHostImageStoreEncryptedDownloadCmd implements Serializabl public String encryptedDek; } + public static class KVMHostImageStoreEncryptedUploadCmd implements Serializable { + public String psUuid; + public String hostname; + public String primaryStorageInstallPath; + public String imageUuid; + public String description; + public int concurrency; + @NoLogging + public String encryptedDek; + } + + public static class KVMHostImageStoreEncryptedUploadRsp extends KVMAgentCommands.AgentResponse { + public String backupStorageInstallPath; + public Long size; + public Long actualSize; + } + public static class KVMHostEncryptInPlaceCmd implements Serializable { public String psUuid; @NoLogging @@ -1434,6 +1451,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 KVM_HOST_IMAGESTORE_ENCRYPTED_DOWNLOAD_PATH = "/ceph/primarystorage/kvmhost/imagestore/encrypteddownload"; + public static final String KVM_HOST_IMAGESTORE_ENCRYPTED_UPLOAD_PATH = "/ceph/primarystorage/kvmhost/imagestore/encryptedupload"; public static final String FLATTEN_PATH = "/ceph/primarystorage/volume/flatten"; public static final String SFTP_DOWNLOAD_PATH = "/ceph/primarystorage/sftpbackupstorage/download"; public static final String SFTP_UPLOAD_PATH = "/ceph/primarystorage/sftpbackupstorage/upload"; @@ -5209,6 +5227,9 @@ private void uploadBitsToBackupStorage(final UploadBitsToBackupStorageMsg msg, f param.primaryStorageUuid = msg.getPrimaryStorageUuid(); param.primaryStorageInstallPath = msg.getPrimaryStorageInstallPath(); param.backupStorageInstallPath = msg.getBackupStorageInstallPath(); + param.encrypted = msg.getEncrypted(); + param.encryptedDek = msg.getEncryptedDek(); + param.encryptedHostUuid = msg.getEncryptedHostUuid(); mediator.param = param; mediator.upload(new ReturnValueCompletion(msg) { @Override diff --git a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageFactory.java b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageFactory.java index be10a80ed48..f9fba1594ce 100755 --- a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageFactory.java +++ b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageFactory.java @@ -34,6 +34,7 @@ import org.zstack.header.configuration.userconfig.InstanceOfferingUserConfig; import org.zstack.header.configuration.userconfig.InstanceOfferingUserConfigValidator; import org.zstack.header.core.Completion; +import org.zstack.header.core.ReturnValueCompletion; import org.zstack.header.core.WhileDoneCompletion; import org.zstack.header.core.workflow.*; import org.zstack.header.errorcode.ErrorCode; @@ -41,6 +42,7 @@ import org.zstack.header.errorcode.OperationFailureException; import org.zstack.header.exception.CloudRuntimeException; import org.zstack.header.host.HostCanonicalEvents; +import org.zstack.header.host.HostConstant; import org.zstack.header.host.HostStatus; import org.zstack.header.host.HostVO; import org.zstack.header.host.HostVO_; @@ -58,6 +60,7 @@ import org.zstack.storage.ceph.primary.KVMCephVolumeTO.MonInfo; import org.zstack.storage.ceph.primary.capacity.CephOsdGroupCapacityHelper; import org.zstack.storage.ceph.primary.capacity.CephPrimaryCapacityUpdater; +import org.zstack.storage.encrypt.VolumeSnapshotEncryptionHelper; import org.zstack.storage.snapshot.MarkRootVolumeAsSnapshotExtension; import org.zstack.storage.snapshot.PostMarkRootVolumeAsSnapshotExtension; import org.zstack.tag.SystemTagCreator; @@ -116,6 +119,8 @@ public class CephPrimaryStorageFactory implements PrimaryStorageFactory, CephCap private StorageTrash trash; @Autowired private EventFacade evtf; + @Autowired + private VolumeSnapshotEncryptionHelper snapshotEncryptionHelper; private Future imageCacheCleanupThread; @@ -568,11 +573,18 @@ public boolean stop() { @Override public WorkflowTemplate createTemplateFromVolumeSnapshot(final ParamIn paramIn) { WorkflowTemplate template = new WorkflowTemplate(); - template.setCreateTemporaryTemplate(new NoRollbackFlow() { + template.setCreateTemporaryTemplate(new Flow() { String __name__ = "create-temporary-template"; + String temporaryInstallPath; + @Override public void run(final FlowTrigger trigger, final Map data) { + if (Boolean.TRUE.equals(paramIn.getSnapshot().getEncrypted())) { + createEncryptedTemporaryTemplate(trigger, data); + return; + } + SyncVolumeSizeMsg msg = new SyncVolumeSizeMsg(); msg.setVolumeUuid(paramIn.getSnapshot().getVolumeUuid()); bus.makeTargetServiceIdByResourceUuid(msg, VolumeConstant.SERVICE_ID, paramIn.getSnapshot().getVolumeUuid()); @@ -591,6 +603,68 @@ public void run(MessageReply reply) { } }); } + + @Override + public void rollback(FlowRollback trigger, Map data) { + if (StringUtils.isNotBlank(temporaryInstallPath)) { + DeleteVolumeBitsOnPrimaryStorageMsg msg = new DeleteVolumeBitsOnPrimaryStorageMsg(); + msg.setPrimaryStorageUuid(paramIn.getPrimaryStorageUuid()); + msg.setInstallPath(temporaryInstallPath); + bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, paramIn.getPrimaryStorageUuid()); + bus.send(msg); + } + + trigger.rollback(); + } + + private void createEncryptedTemporaryTemplate(final FlowTrigger trigger, final Map data) { + String hostUuid = findConnectedHostForCephLuks(paramIn.getPrimaryStorageUuid()); + String encryptedDek; + try { + encryptedDek = snapshotEncryptionHelper.prepareTemporarySnapshotImageEncryptedDek( + hostUuid, + paramIn.getSnapshot().getUuid(), + paramIn.getImage().getUuid(), + true); + } catch (OperationFailureException e) { + trigger.fail(e.getErrorCode()); + return; + } + if (StringUtils.isBlank(encryptedDek)) { + trigger.fail(operr("cannot prepare LUKS encryptedDek for encrypted temporary snapshot image[uuid:%s] from snapshot[uuid:%s] on host[uuid:%s]", + paramIn.getImage().getUuid(), paramIn.getSnapshot().getUuid(), hostUuid)); + return; + } + + temporaryInstallPath = makeTemporaryTemplateInstallPath(paramIn); + CephPrimaryStorageBase.KVMHostLuksCloneCmd cmd = new CephPrimaryStorageBase.KVMHostLuksCloneCmd(); + cmd.psUuid = paramIn.getPrimaryStorageUuid(); + cmd.srcPath = paramIn.getSnapshot().getPrimaryStorageInstallPath(); + cmd.dstPath = temporaryInstallPath; + cmd.encryptedDek = encryptedDek; + + httpCallToKvmHost(hostUuid, + CephPrimaryStorageBase.KVM_HOST_LUKS_CLONE_PATH, + cmd, + CephPrimaryStorageBase.KVMHostLuksRsp.class, + new ReturnValueCompletion(trigger) { + @Override + public void success(CephPrimaryStorageBase.KVMHostLuksRsp rsp) { + ParamOut out = (ParamOut) data.get(ParamOut.class); + out.setActualSize(rsp.actualSize == null ? paramIn.getSnapshot().getSize() : rsp.actualSize); + out.setSize(paramIn.getSnapshot().getSize()); + data.put("cephEncryptedTemporaryInstallPath", temporaryInstallPath); + data.put("cephEncryptedDek", encryptedDek); + data.put("cephEncryptedHostUuid", hostUuid); + trigger.next(); + } + + @Override + public void fail(ErrorCode errorCode) { + trigger.fail(errorCode); + } + }); + } }); template.setUploadToBackupStorage(new Flow() { @@ -611,13 +685,18 @@ public void run(final FlowTrigger trigger, Map data) { } String bsInstallPath = ((BackupStorageAskInstallPathReply)ar).getInstallPath(); + String encryptedTemporaryInstallPath = (String) data.get("cephEncryptedTemporaryInstallPath"); UploadBitsToBackupStorageMsg msg = new UploadBitsToBackupStorageMsg(); msg.setPrimaryStorageUuid(paramIn.getPrimaryStorageUuid()); - msg.setPrimaryStorageInstallPath(paramIn.getSnapshot().getPrimaryStorageInstallPath()); + msg.setPrimaryStorageInstallPath(encryptedTemporaryInstallPath == null ? + paramIn.getSnapshot().getPrimaryStorageInstallPath() : encryptedTemporaryInstallPath); msg.setBackupStorageUuid(paramIn.getBackupStorageUuid()); msg.setBackupStorageInstallPath(bsInstallPath); msg.setImageUuid(paramIn.getImage().getUuid()); + msg.setEncrypted(paramIn.getSnapshot().getEncrypted()); + msg.setEncryptedDek((String) data.get("cephEncryptedDek")); + msg.setEncryptedHostUuid((String) data.get("cephEncryptedHostUuid")); bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, paramIn.getPrimaryStorageUuid()); bus.send(msg, new CloudBusCallBack(trigger) { @Override @@ -648,11 +727,91 @@ public void rollback(FlowRollback trigger, Map data) { } }); - template.setDeleteTemporaryTemplate(new NopeFlow()); + template.setDeleteTemporaryTemplate(new NoRollbackFlow() { + String __name__ = "delete-temporary-template"; + + @Override + public void run(FlowTrigger trigger, Map data) { + String temporaryInstallPath = (String) data.get("cephEncryptedTemporaryInstallPath"); + if (StringUtils.isBlank(temporaryInstallPath)) { + trigger.next(); + return; + } + + DeleteVolumeBitsOnPrimaryStorageMsg msg = new DeleteVolumeBitsOnPrimaryStorageMsg(); + msg.setPrimaryStorageUuid(paramIn.getPrimaryStorageUuid()); + msg.setInstallPath(temporaryInstallPath); + bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, paramIn.getPrimaryStorageUuid()); + bus.send(msg); + trigger.next(); + } + }); return template; } + private String makeTemporaryTemplateInstallPath(ParamIn paramIn) { + String installPath = paramIn.getSnapshot().getPrimaryStorageInstallPath(); + String path = installPath.startsWith("ceph://") ? installPath.substring("ceph://".length()) : installPath; + int idx = path.indexOf("/"); + if (idx < 0) { + throw new OperationFailureException(operr("invalid ceph snapshot install path[%s]", installPath)); + } + + return String.format("ceph://%s/%s", path.substring(0, idx), paramIn.getImage().getUuid()); + } + + private String findConnectedHostForCephLuks(String primaryStorageUuid) { + List connectedHostUuids = Q.New(PrimaryStorageHostRefVO.class) + .eq(PrimaryStorageHostRefVO_.primaryStorageUuid, primaryStorageUuid) + .eq(PrimaryStorageHostRefVO_.status, PrimaryStorageHostStatus.Connected) + .select(PrimaryStorageHostRefVO_.hostUuid) + .listValues(); + String hostUuid = connectedHostUuids.isEmpty() ? null : Q.New(HostVO.class) + .eq(HostVO_.hypervisorType, KVMConstant.KVM_HYPERVISOR_TYPE) + .in(HostVO_.uuid, connectedHostUuids) + .select(HostVO_.uuid) + .limit(1) + .findValue(); + if (StringUtils.isBlank(hostUuid)) { + throw new OperationFailureException(operr( + "cannot find a connected KVM host attached to ceph primary storage[uuid:%s] to run LUKS RBD operation", + primaryStorageUuid)); + } + return hostUuid; + } + + private void httpCallToKvmHost(String hostUuid, String path, Object cmd, Class retClass, + ReturnValueCompletion completion) { + KVMHostAsyncHttpCallMsg msg = new KVMHostAsyncHttpCallMsg(); + msg.setCommand(cmd); + msg.setPath(path); + msg.setHostUuid(hostUuid); + msg.setNoStatusCheck(true); + bus.makeTargetServiceIdByResourceUuid(msg, HostConstant.SERVICE_ID, hostUuid); + bus.send(msg, new CloudBusCallBack(completion) { + @Override + public void run(MessageReply reply) { + if (!reply.isSuccess()) { + completion.fail(reply.getError()); + return; + } + + KVMHostAsyncHttpCallReply kreply = reply.castReply(); + T rsp = kreply.toResponse(retClass); + if (rsp == null) { + completion.fail(operr("kvm host[uuid:%s] returned null reply for ceph luks path[%s]", hostUuid, path)); + return; + } + if (!rsp.isSuccess()) { + completion.fail(operr("kvm host[uuid:%s] ceph luks path[%s] failed", hostUuid, path).withException(rsp.getError())); + return; + } + completion.success(rsp); + } + }); + } + @Override public String createTemplateFromVolumeSnapshotPrimaryStorageType() { return CephConstants.CEPH_PRIMARY_STORAGE_TYPE; diff --git a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/UploadBitsToBackupStorageMsg.java b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/UploadBitsToBackupStorageMsg.java index 80d105d85f1..9e693980a8c 100755 --- a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/UploadBitsToBackupStorageMsg.java +++ b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/UploadBitsToBackupStorageMsg.java @@ -12,6 +12,9 @@ public class UploadBitsToBackupStorageMsg extends NeedReplyMessage implements Pr private String backupStorageUuid; private String backupStorageInstallPath; private String imageUuid; + private Boolean encrypted; + private String encryptedDek; + private String encryptedHostUuid; @Override public String getPrimaryStorageUuid() { @@ -53,4 +56,28 @@ public String getImageUuid() { public void setImageUuid(String imageUuid) { this.imageUuid = imageUuid; } + + public Boolean getEncrypted() { + return encrypted; + } + + public void setEncrypted(Boolean encrypted) { + this.encrypted = encrypted; + } + + public String getEncryptedDek() { + return encryptedDek; + } + + public void setEncryptedDek(String encryptedDek) { + this.encryptedDek = encryptedDek; + } + + public String getEncryptedHostUuid() { + return encryptedHostUuid; + } + + public void setEncryptedHostUuid(String encryptedHostUuid) { + this.encryptedHostUuid = encryptedHostUuid; + } } From 970d3f78e41c06cfe7804b6ecde23b33f59f11b8 Mon Sep 17 00:00:00 2001 From: "zhong.zhou" Date: Mon, 22 Jun 2026 14:12:12 +0800 Subject: [PATCH 3/4] [storage]: drop unrelated backup key inheritance changes Resolves: ZSV-12473 Change-Id: Ifcfb943d26a5bb4319a3bdbb5e9576524d8ef51e --- .../ceph/primary/CephPrimaryStorageBase.java | 14 -------------- .../DummyVolumeEncryptedResourceKeyBackend.java | 15 --------------- .../encrypt/VolumeEncryptedInitialExtension.java | 7 ------- .../VolumeEncryptedResourceKeyBackend.java | 6 ------ 4 files changed, 42 deletions(-) diff --git a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java index 2c0c16de09b..637f3ac7e25 100755 --- a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java +++ b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java @@ -463,19 +463,6 @@ public static class KVMHostLuksConvertCmd implements Serializable { public Long virtualSize; } - public static class KVMHostImageStoreEncryptedDownloadCmd implements Serializable { - public String psUuid; - public String hostname; - public String backupStorageInstallPath; - public String primaryStorageInstallPath; - public int concurrency; - public String keyProviderUuid; - public Integer keyVersion; - public String cipher; - @NoLogging - public String encryptedDek; - } - public static class KVMHostImageStoreEncryptedUploadCmd implements Serializable { public String psUuid; public String hostname; @@ -1450,7 +1437,6 @@ public int compareTo(SnapInfo snapInfo) { public static final String KVM_HOST_LUKS_ENCRYPT_IN_PLACE_PATH = "/ceph/primarystorage/kvmhost/encryptinplace"; 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 KVM_HOST_IMAGESTORE_ENCRYPTED_DOWNLOAD_PATH = "/ceph/primarystorage/kvmhost/imagestore/encrypteddownload"; public static final String KVM_HOST_IMAGESTORE_ENCRYPTED_UPLOAD_PATH = "/ceph/primarystorage/kvmhost/imagestore/encryptedupload"; public static final String FLATTEN_PATH = "/ceph/primarystorage/volume/flatten"; public static final String SFTP_DOWNLOAD_PATH = "/ceph/primarystorage/sftpbackupstorage/download"; diff --git a/storage/src/main/java/org/zstack/storage/encrypt/DummyVolumeEncryptedResourceKeyBackend.java b/storage/src/main/java/org/zstack/storage/encrypt/DummyVolumeEncryptedResourceKeyBackend.java index e7b7c45c53c..ef4a8da276b 100644 --- a/storage/src/main/java/org/zstack/storage/encrypt/DummyVolumeEncryptedResourceKeyBackend.java +++ b/storage/src/main/java/org/zstack/storage/encrypt/DummyVolumeEncryptedResourceKeyBackend.java @@ -56,11 +56,6 @@ public boolean checkTemporarySnapshotImageKeyProviderAttached(String imageUuid) return false; } - @Override - public boolean checkBackupKeyProviderAttached(String backupUuid) { - return false; - } - @Override public void copyVolumeKeyToSnapshot(String volumeUuid, String snapshotUuid) { logger.debug(String.format("ignore copy volume[uuid:%s] key to snapshot[uuid:%s]", volumeUuid, snapshotUuid)); @@ -91,16 +86,6 @@ public void copyVolumeKeyToBackup(String volumeUuid, String backupUuid) { logger.debug(String.format("ignore copy volume[uuid:%s] key to backup[uuid:%s]", volumeUuid, backupUuid)); } - @Override - public void copyBackupKeyToTemporarySnapshotImage(String backupUuid, String imageUuid) { - logger.debug(String.format("ignore copy backup[uuid:%s] key to temporary snapshot image[uuid:%s]", backupUuid, imageUuid)); - } - - @Override - public void copyBackupKeyToVolume(String backupUuid, String volumeUuid) { - logger.debug(String.format("ignore copy backup[uuid:%s] key to volume[uuid:%s]", backupUuid, volumeUuid)); - } - @Override public String defaultKeyProviderUuid() { return null; diff --git a/storage/src/main/java/org/zstack/storage/encrypt/VolumeEncryptedInitialExtension.java b/storage/src/main/java/org/zstack/storage/encrypt/VolumeEncryptedInitialExtension.java index 2a8b714d298..f407283f3e6 100644 --- a/storage/src/main/java/org/zstack/storage/encrypt/VolumeEncryptedInitialExtension.java +++ b/storage/src/main/java/org/zstack/storage/encrypt/VolumeEncryptedInitialExtension.java @@ -80,13 +80,6 @@ private void inheritTemporaryRootVolumeKeyFromOrigin(InstantiateVolumeMsg msg, V return; } - // A backup or snapshot temporary image can already provide the target root - // volume key. Keep that key as the source of truth; falling back to the - // origin root would overwrite it or fail if the origin key binding is gone. - if (volumeEncryptedResourceKeyBackend.checkVolumeKeyProviderAttached(volume.getUuid())) { - return; - } - String originVolumeUuid = ((InstantiateTemporaryRootVolumeMsg) msg).getOriginVolumeUuid(); if (StringUtils.isBlank(originVolumeUuid)) { return; diff --git a/storage/src/main/java/org/zstack/storage/encrypt/VolumeEncryptedResourceKeyBackend.java b/storage/src/main/java/org/zstack/storage/encrypt/VolumeEncryptedResourceKeyBackend.java index a76326ed247..1093f728c4a 100644 --- a/storage/src/main/java/org/zstack/storage/encrypt/VolumeEncryptedResourceKeyBackend.java +++ b/storage/src/main/java/org/zstack/storage/encrypt/VolumeEncryptedResourceKeyBackend.java @@ -40,8 +40,6 @@ public interface VolumeEncryptedResourceKeyBackend { boolean checkTemporarySnapshotImageKeyProviderAttached(String imageUuid); - boolean checkBackupKeyProviderAttached(String backupUuid); - void copyVolumeKeyToSnapshot(String volumeUuid, String snapshotUuid); void copySnapshotKeyToVolume(String snapshotUuid, String volumeUuid); @@ -54,10 +52,6 @@ public interface VolumeEncryptedResourceKeyBackend { void copyVolumeKeyToBackup(String volumeUuid, String backupUuid); - void copyBackupKeyToTemporarySnapshotImage(String backupUuid, String imageUuid); - - void copyBackupKeyToVolume(String backupUuid, String volumeUuid); - /** * Global default key provider uuid, or null (e.g. NONE / crypto not installed). */ From c81653f7da68055ba5ef5b1bfdab59f3f8c916e1 Mon Sep 17 00:00:00 2001 From: "zhong.zhou" Date: Mon, 22 Jun 2026 17:35:11 +0800 Subject: [PATCH 4/4] [storage]: remove backup upload changes from clone fix Resolves: ZSV-12473 Change-Id: I6f6a8bccffe7b94df8c27617376008a9db14e17b --- .../storage/primary/MediatorUploadParam.java | 3 - .../ceph/primary/CephPrimaryStorageBase.java | 21 --- .../primary/CephPrimaryStorageFactory.java | 165 +----------------- .../primary/UploadBitsToBackupStorageMsg.java | 27 --- 4 files changed, 3 insertions(+), 213 deletions(-) diff --git a/header/src/main/java/org/zstack/header/storage/primary/MediatorUploadParam.java b/header/src/main/java/org/zstack/header/storage/primary/MediatorUploadParam.java index adf30b92cce..e52473c6cae 100644 --- a/header/src/main/java/org/zstack/header/storage/primary/MediatorUploadParam.java +++ b/header/src/main/java/org/zstack/header/storage/primary/MediatorUploadParam.java @@ -8,7 +8,4 @@ public class MediatorUploadParam implements MediatorParam { public String primaryStorageInstallPath; public String backupStorageInstallPath; public String backupStorageUuid; - public Boolean encrypted; - public String encryptedDek; - public String encryptedHostUuid; } diff --git a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java index 637f3ac7e25..007f457afb3 100755 --- a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java +++ b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java @@ -463,23 +463,6 @@ public static class KVMHostLuksConvertCmd implements Serializable { public Long virtualSize; } - public static class KVMHostImageStoreEncryptedUploadCmd implements Serializable { - public String psUuid; - public String hostname; - public String primaryStorageInstallPath; - public String imageUuid; - public String description; - public int concurrency; - @NoLogging - public String encryptedDek; - } - - public static class KVMHostImageStoreEncryptedUploadRsp extends KVMAgentCommands.AgentResponse { - public String backupStorageInstallPath; - public Long size; - public Long actualSize; - } - public static class KVMHostEncryptInPlaceCmd implements Serializable { public String psUuid; @NoLogging @@ -1437,7 +1420,6 @@ public int compareTo(SnapInfo snapInfo) { public static final String KVM_HOST_LUKS_ENCRYPT_IN_PLACE_PATH = "/ceph/primarystorage/kvmhost/encryptinplace"; 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 KVM_HOST_IMAGESTORE_ENCRYPTED_UPLOAD_PATH = "/ceph/primarystorage/kvmhost/imagestore/encryptedupload"; public static final String FLATTEN_PATH = "/ceph/primarystorage/volume/flatten"; public static final String SFTP_DOWNLOAD_PATH = "/ceph/primarystorage/sftpbackupstorage/download"; public static final String SFTP_UPLOAD_PATH = "/ceph/primarystorage/sftpbackupstorage/upload"; @@ -5213,9 +5195,6 @@ private void uploadBitsToBackupStorage(final UploadBitsToBackupStorageMsg msg, f param.primaryStorageUuid = msg.getPrimaryStorageUuid(); param.primaryStorageInstallPath = msg.getPrimaryStorageInstallPath(); param.backupStorageInstallPath = msg.getBackupStorageInstallPath(); - param.encrypted = msg.getEncrypted(); - param.encryptedDek = msg.getEncryptedDek(); - param.encryptedHostUuid = msg.getEncryptedHostUuid(); mediator.param = param; mediator.upload(new ReturnValueCompletion(msg) { @Override diff --git a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageFactory.java b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageFactory.java index f9fba1594ce..be10a80ed48 100755 --- a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageFactory.java +++ b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageFactory.java @@ -34,7 +34,6 @@ import org.zstack.header.configuration.userconfig.InstanceOfferingUserConfig; import org.zstack.header.configuration.userconfig.InstanceOfferingUserConfigValidator; import org.zstack.header.core.Completion; -import org.zstack.header.core.ReturnValueCompletion; import org.zstack.header.core.WhileDoneCompletion; import org.zstack.header.core.workflow.*; import org.zstack.header.errorcode.ErrorCode; @@ -42,7 +41,6 @@ import org.zstack.header.errorcode.OperationFailureException; import org.zstack.header.exception.CloudRuntimeException; import org.zstack.header.host.HostCanonicalEvents; -import org.zstack.header.host.HostConstant; import org.zstack.header.host.HostStatus; import org.zstack.header.host.HostVO; import org.zstack.header.host.HostVO_; @@ -60,7 +58,6 @@ import org.zstack.storage.ceph.primary.KVMCephVolumeTO.MonInfo; import org.zstack.storage.ceph.primary.capacity.CephOsdGroupCapacityHelper; import org.zstack.storage.ceph.primary.capacity.CephPrimaryCapacityUpdater; -import org.zstack.storage.encrypt.VolumeSnapshotEncryptionHelper; import org.zstack.storage.snapshot.MarkRootVolumeAsSnapshotExtension; import org.zstack.storage.snapshot.PostMarkRootVolumeAsSnapshotExtension; import org.zstack.tag.SystemTagCreator; @@ -119,8 +116,6 @@ public class CephPrimaryStorageFactory implements PrimaryStorageFactory, CephCap private StorageTrash trash; @Autowired private EventFacade evtf; - @Autowired - private VolumeSnapshotEncryptionHelper snapshotEncryptionHelper; private Future imageCacheCleanupThread; @@ -573,18 +568,11 @@ public boolean stop() { @Override public WorkflowTemplate createTemplateFromVolumeSnapshot(final ParamIn paramIn) { WorkflowTemplate template = new WorkflowTemplate(); - template.setCreateTemporaryTemplate(new Flow() { + template.setCreateTemporaryTemplate(new NoRollbackFlow() { String __name__ = "create-temporary-template"; - String temporaryInstallPath; - @Override public void run(final FlowTrigger trigger, final Map data) { - if (Boolean.TRUE.equals(paramIn.getSnapshot().getEncrypted())) { - createEncryptedTemporaryTemplate(trigger, data); - return; - } - SyncVolumeSizeMsg msg = new SyncVolumeSizeMsg(); msg.setVolumeUuid(paramIn.getSnapshot().getVolumeUuid()); bus.makeTargetServiceIdByResourceUuid(msg, VolumeConstant.SERVICE_ID, paramIn.getSnapshot().getVolumeUuid()); @@ -603,68 +591,6 @@ public void run(MessageReply reply) { } }); } - - @Override - public void rollback(FlowRollback trigger, Map data) { - if (StringUtils.isNotBlank(temporaryInstallPath)) { - DeleteVolumeBitsOnPrimaryStorageMsg msg = new DeleteVolumeBitsOnPrimaryStorageMsg(); - msg.setPrimaryStorageUuid(paramIn.getPrimaryStorageUuid()); - msg.setInstallPath(temporaryInstallPath); - bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, paramIn.getPrimaryStorageUuid()); - bus.send(msg); - } - - trigger.rollback(); - } - - private void createEncryptedTemporaryTemplate(final FlowTrigger trigger, final Map data) { - String hostUuid = findConnectedHostForCephLuks(paramIn.getPrimaryStorageUuid()); - String encryptedDek; - try { - encryptedDek = snapshotEncryptionHelper.prepareTemporarySnapshotImageEncryptedDek( - hostUuid, - paramIn.getSnapshot().getUuid(), - paramIn.getImage().getUuid(), - true); - } catch (OperationFailureException e) { - trigger.fail(e.getErrorCode()); - return; - } - if (StringUtils.isBlank(encryptedDek)) { - trigger.fail(operr("cannot prepare LUKS encryptedDek for encrypted temporary snapshot image[uuid:%s] from snapshot[uuid:%s] on host[uuid:%s]", - paramIn.getImage().getUuid(), paramIn.getSnapshot().getUuid(), hostUuid)); - return; - } - - temporaryInstallPath = makeTemporaryTemplateInstallPath(paramIn); - CephPrimaryStorageBase.KVMHostLuksCloneCmd cmd = new CephPrimaryStorageBase.KVMHostLuksCloneCmd(); - cmd.psUuid = paramIn.getPrimaryStorageUuid(); - cmd.srcPath = paramIn.getSnapshot().getPrimaryStorageInstallPath(); - cmd.dstPath = temporaryInstallPath; - cmd.encryptedDek = encryptedDek; - - httpCallToKvmHost(hostUuid, - CephPrimaryStorageBase.KVM_HOST_LUKS_CLONE_PATH, - cmd, - CephPrimaryStorageBase.KVMHostLuksRsp.class, - new ReturnValueCompletion(trigger) { - @Override - public void success(CephPrimaryStorageBase.KVMHostLuksRsp rsp) { - ParamOut out = (ParamOut) data.get(ParamOut.class); - out.setActualSize(rsp.actualSize == null ? paramIn.getSnapshot().getSize() : rsp.actualSize); - out.setSize(paramIn.getSnapshot().getSize()); - data.put("cephEncryptedTemporaryInstallPath", temporaryInstallPath); - data.put("cephEncryptedDek", encryptedDek); - data.put("cephEncryptedHostUuid", hostUuid); - trigger.next(); - } - - @Override - public void fail(ErrorCode errorCode) { - trigger.fail(errorCode); - } - }); - } }); template.setUploadToBackupStorage(new Flow() { @@ -685,18 +611,13 @@ public void run(final FlowTrigger trigger, Map data) { } String bsInstallPath = ((BackupStorageAskInstallPathReply)ar).getInstallPath(); - String encryptedTemporaryInstallPath = (String) data.get("cephEncryptedTemporaryInstallPath"); UploadBitsToBackupStorageMsg msg = new UploadBitsToBackupStorageMsg(); msg.setPrimaryStorageUuid(paramIn.getPrimaryStorageUuid()); - msg.setPrimaryStorageInstallPath(encryptedTemporaryInstallPath == null ? - paramIn.getSnapshot().getPrimaryStorageInstallPath() : encryptedTemporaryInstallPath); + msg.setPrimaryStorageInstallPath(paramIn.getSnapshot().getPrimaryStorageInstallPath()); msg.setBackupStorageUuid(paramIn.getBackupStorageUuid()); msg.setBackupStorageInstallPath(bsInstallPath); msg.setImageUuid(paramIn.getImage().getUuid()); - msg.setEncrypted(paramIn.getSnapshot().getEncrypted()); - msg.setEncryptedDek((String) data.get("cephEncryptedDek")); - msg.setEncryptedHostUuid((String) data.get("cephEncryptedHostUuid")); bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, paramIn.getPrimaryStorageUuid()); bus.send(msg, new CloudBusCallBack(trigger) { @Override @@ -727,91 +648,11 @@ public void rollback(FlowRollback trigger, Map data) { } }); - template.setDeleteTemporaryTemplate(new NoRollbackFlow() { - String __name__ = "delete-temporary-template"; - - @Override - public void run(FlowTrigger trigger, Map data) { - String temporaryInstallPath = (String) data.get("cephEncryptedTemporaryInstallPath"); - if (StringUtils.isBlank(temporaryInstallPath)) { - trigger.next(); - return; - } - - DeleteVolumeBitsOnPrimaryStorageMsg msg = new DeleteVolumeBitsOnPrimaryStorageMsg(); - msg.setPrimaryStorageUuid(paramIn.getPrimaryStorageUuid()); - msg.setInstallPath(temporaryInstallPath); - bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, paramIn.getPrimaryStorageUuid()); - bus.send(msg); - trigger.next(); - } - }); + template.setDeleteTemporaryTemplate(new NopeFlow()); return template; } - private String makeTemporaryTemplateInstallPath(ParamIn paramIn) { - String installPath = paramIn.getSnapshot().getPrimaryStorageInstallPath(); - String path = installPath.startsWith("ceph://") ? installPath.substring("ceph://".length()) : installPath; - int idx = path.indexOf("/"); - if (idx < 0) { - throw new OperationFailureException(operr("invalid ceph snapshot install path[%s]", installPath)); - } - - return String.format("ceph://%s/%s", path.substring(0, idx), paramIn.getImage().getUuid()); - } - - private String findConnectedHostForCephLuks(String primaryStorageUuid) { - List connectedHostUuids = Q.New(PrimaryStorageHostRefVO.class) - .eq(PrimaryStorageHostRefVO_.primaryStorageUuid, primaryStorageUuid) - .eq(PrimaryStorageHostRefVO_.status, PrimaryStorageHostStatus.Connected) - .select(PrimaryStorageHostRefVO_.hostUuid) - .listValues(); - String hostUuid = connectedHostUuids.isEmpty() ? null : Q.New(HostVO.class) - .eq(HostVO_.hypervisorType, KVMConstant.KVM_HYPERVISOR_TYPE) - .in(HostVO_.uuid, connectedHostUuids) - .select(HostVO_.uuid) - .limit(1) - .findValue(); - if (StringUtils.isBlank(hostUuid)) { - throw new OperationFailureException(operr( - "cannot find a connected KVM host attached to ceph primary storage[uuid:%s] to run LUKS RBD operation", - primaryStorageUuid)); - } - return hostUuid; - } - - private void httpCallToKvmHost(String hostUuid, String path, Object cmd, Class retClass, - ReturnValueCompletion completion) { - KVMHostAsyncHttpCallMsg msg = new KVMHostAsyncHttpCallMsg(); - msg.setCommand(cmd); - msg.setPath(path); - msg.setHostUuid(hostUuid); - msg.setNoStatusCheck(true); - bus.makeTargetServiceIdByResourceUuid(msg, HostConstant.SERVICE_ID, hostUuid); - bus.send(msg, new CloudBusCallBack(completion) { - @Override - public void run(MessageReply reply) { - if (!reply.isSuccess()) { - completion.fail(reply.getError()); - return; - } - - KVMHostAsyncHttpCallReply kreply = reply.castReply(); - T rsp = kreply.toResponse(retClass); - if (rsp == null) { - completion.fail(operr("kvm host[uuid:%s] returned null reply for ceph luks path[%s]", hostUuid, path)); - return; - } - if (!rsp.isSuccess()) { - completion.fail(operr("kvm host[uuid:%s] ceph luks path[%s] failed", hostUuid, path).withException(rsp.getError())); - return; - } - completion.success(rsp); - } - }); - } - @Override public String createTemplateFromVolumeSnapshotPrimaryStorageType() { return CephConstants.CEPH_PRIMARY_STORAGE_TYPE; diff --git a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/UploadBitsToBackupStorageMsg.java b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/UploadBitsToBackupStorageMsg.java index 9e693980a8c..80d105d85f1 100755 --- a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/UploadBitsToBackupStorageMsg.java +++ b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/UploadBitsToBackupStorageMsg.java @@ -12,9 +12,6 @@ public class UploadBitsToBackupStorageMsg extends NeedReplyMessage implements Pr private String backupStorageUuid; private String backupStorageInstallPath; private String imageUuid; - private Boolean encrypted; - private String encryptedDek; - private String encryptedHostUuid; @Override public String getPrimaryStorageUuid() { @@ -56,28 +53,4 @@ public String getImageUuid() { public void setImageUuid(String imageUuid) { this.imageUuid = imageUuid; } - - public Boolean getEncrypted() { - return encrypted; - } - - public void setEncrypted(Boolean encrypted) { - this.encrypted = encrypted; - } - - public String getEncryptedDek() { - return encryptedDek; - } - - public void setEncryptedDek(String encryptedDek) { - this.encryptedDek = encryptedDek; - } - - public String getEncryptedHostUuid() { - return encryptedHostUuid; - } - - public void setEncryptedHostUuid(String encryptedHostUuid) { - this.encryptedHostUuid = encryptedHostUuid; - } }