diff --git a/compute/src/main/java/org/zstack/compute/vm/devices/VmTpmExtensions.java b/compute/src/main/java/org/zstack/compute/vm/devices/VmTpmExtensions.java index 4b25befa82f..5c5baf10732 100644 --- a/compute/src/main/java/org/zstack/compute/vm/devices/VmTpmExtensions.java +++ b/compute/src/main/java/org/zstack/compute/vm/devices/VmTpmExtensions.java @@ -1,12 +1,18 @@ package org.zstack.compute.vm.devices; import org.springframework.beans.factory.annotation.Autowired; +import org.zstack.compute.vm.BuildVmSpecExtensionPoint; import org.zstack.header.vm.CreateVmInstanceMsg; +import org.zstack.header.vm.DiskAO; import org.zstack.header.vm.VmInstanceCreateExtensionPoint; +import org.zstack.header.vm.VmInstanceSpec; import org.zstack.header.vm.VmInstanceVO; import org.zstack.header.vm.devices.VmDevicesSpec; -public class VmTpmExtensions implements VmInstanceCreateExtensionPoint { +import static org.zstack.header.vm.VmInstanceConstant.NVRAM_DEFAULT_SIZE; + +public class VmTpmExtensions implements VmInstanceCreateExtensionPoint, + BuildVmSpecExtensionPoint { @Autowired private VmTpmManager vmTpmManager; @@ -24,4 +30,17 @@ public void afterPersistVmInstanceVO(VmInstanceVO vo, CreateVmInstanceMsg msg) { vmTpmManager.persistTpmVO(null, vo.getUuid()); } + + @Override + public void afterBuildVmSpec(VmInstanceSpec spec) { + String vmUuid = spec.getVmInventory().getUuid(); + if (!vmTpmManager.needRegisterNvram(vmUuid)) { + return; + } + + DiskAO nvramSpec = new DiskAO(); + nvramSpec.setSize(NVRAM_DEFAULT_SIZE); + nvramSpec.setName("nvram-of-VM-" + vmUuid); + spec.setNvRamSpec(nvramSpec); + } } diff --git a/compute/src/main/java/org/zstack/compute/vm/devices/VmTpmManager.java b/compute/src/main/java/org/zstack/compute/vm/devices/VmTpmManager.java index a37e57d8426..6381bf4b10d 100644 --- a/compute/src/main/java/org/zstack/compute/vm/devices/VmTpmManager.java +++ b/compute/src/main/java/org/zstack/compute/vm/devices/VmTpmManager.java @@ -1,17 +1,29 @@ package org.zstack.compute.vm.devices; import org.springframework.beans.factory.annotation.Autowired; +import org.zstack.compute.vm.VmSystemTags; import org.zstack.core.Platform; import org.zstack.core.db.DatabaseFacade; +import org.zstack.core.db.Q; +import org.zstack.header.image.ImageBootMode; import org.zstack.header.tpm.entity.TpmVO; +import org.zstack.header.tpm.entity.TpmVO_; +import org.zstack.resourceconfig.ResourceConfig; +import org.zstack.resourceconfig.ResourceConfigFacade; import org.zstack.utils.Utils; import org.zstack.utils.logging.CLogger; +import java.util.Objects; + +import static org.zstack.compute.vm.VmGlobalConfig.ENABLE_UEFI_SECURE_BOOT; + public class VmTpmManager { private static final CLogger logger = Utils.getLogger(VmTpmManager.class); @Autowired private DatabaseFacade databaseFacade; + @Autowired + private ResourceConfigFacade resourceConfigFacade; public TpmVO persistTpmVO(String tpmUuid, String vmUuid) { if (tpmUuid == null) { @@ -26,4 +38,29 @@ public TpmVO persistTpmVO(String tpmUuid, String vmUuid) { logger.debug("Persisted TpmVO for VM " + vmUuid + " with uuid=" + tpm.getUuid()); return tpm; } + + public boolean needRegisterNvram(String vmUuid) { + boolean tpmExists = Q.New(TpmVO.class) + .eq(TpmVO_.vmInstanceUuid, vmUuid) + .isExists(); + if (tpmExists) { + return true; + } + + String bootMode = VmSystemTags.BOOT_MODE.getTokenByResourceUuid(vmUuid, VmSystemTags.BOOT_MODE_TOKEN); + if (!isUefiBootMode(bootMode)) { + return false; + } + + ResourceConfig resourceConfig = resourceConfigFacade.getResourceConfig(ENABLE_UEFI_SECURE_BOOT.getIdentity()); + return resourceConfig.getResourceConfigValue(vmUuid, Boolean.class) == Boolean.TRUE; + } + + /** + * @param bootMode boot mode, null is Legacy + */ + public static boolean isUefiBootMode(String bootMode) { + return Objects.equals(bootMode, ImageBootMode.UEFI.toString()) + || Objects.equals(bootMode, ImageBootMode.UEFI_WITH_CSM.toString()); + } } diff --git a/conf/persistence.xml b/conf/persistence.xml index ff82022f554..5a1b855d9e8 100755 --- a/conf/persistence.xml +++ b/conf/persistence.xml @@ -18,6 +18,8 @@ org.zstack.resourceconfig.ResourceConfigVO org.zstack.header.managementnode.ManagementNodeVO org.zstack.header.managementnode.ManagementNodeContextVO + org.zstack.header.tpm.entity.TpmHostRefVO + org.zstack.header.tpm.entity.TpmVO org.zstack.header.zone.ZoneVO org.zstack.header.zone.ZoneEO org.zstack.header.cluster.ClusterVO diff --git a/conf/springConfigXml/Kvm.xml b/conf/springConfigXml/Kvm.xml index 9536f559eb3..16cd80fadf9 100755 --- a/conf/springConfigXml/Kvm.xml +++ b/conf/springConfigXml/Kvm.xml @@ -261,6 +261,7 @@ + diff --git a/conf/springConfigXml/VmInstanceManager.xml b/conf/springConfigXml/VmInstanceManager.xml index 6786f86c780..1ac69cd5e1c 100755 --- a/conf/springConfigXml/VmInstanceManager.xml +++ b/conf/springConfigXml/VmInstanceManager.xml @@ -285,6 +285,7 @@ + diff --git a/header/src/main/java/org/zstack/header/vm/VmInstanceConstant.java b/header/src/main/java/org/zstack/header/vm/VmInstanceConstant.java index 9d0efdd77f1..64520fada14 100755 --- a/header/src/main/java/org/zstack/header/vm/VmInstanceConstant.java +++ b/header/src/main/java/org/zstack/header/vm/VmInstanceConstant.java @@ -1,6 +1,7 @@ package org.zstack.header.vm; import org.zstack.header.configuration.PythonClass; +import org.zstack.utils.data.SizeUnit; @PythonClass public interface VmInstanceConstant { @@ -25,6 +26,8 @@ public interface VmInstanceConstant { String SHUTDOWN_DETAIL_BY_GUEST = "by guest"; String SHUTDOWN_DETAIL_FINISHED = "finished"; + long NVRAM_DEFAULT_SIZE = SizeUnit.MEGABYTE.toByte(1); + enum Params { VmInstanceSpec, AttachingVolumeInventory, diff --git a/header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java b/header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java index 18620a65fad..95ccdc22bf2 100755 --- a/header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java +++ b/header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java @@ -405,6 +405,7 @@ public void setCandidatePrimaryStorageUuidsForDataVolume(List candidateP private List deprecatedDisksSpecs = new ArrayList<>(); private VmCustomSpecificationStruct vmCustomSpecification; private VmDevicesSpec devicesSpec; + private DiskAO nvRamSpec; public DiskAO getRootDisk() { return rootDisk; @@ -446,6 +447,14 @@ public void setDevicesSpec(VmDevicesSpec devicesSpec) { this.devicesSpec = devicesSpec; } + public DiskAO getNvRamSpec() { + return nvRamSpec; + } + + public void setNvRamSpec(DiskAO nvRamSpec) { + this.nvRamSpec = nvRamSpec; + } + public boolean isSkipIpAllocation() { return skipIpAllocation; } diff --git a/header/src/main/java/org/zstack/header/volume/VolumeType.java b/header/src/main/java/org/zstack/header/volume/VolumeType.java index e373e5aef98..88cf6af349e 100755 --- a/header/src/main/java/org/zstack/header/volume/VolumeType.java +++ b/header/src/main/java/org/zstack/header/volume/VolumeType.java @@ -4,5 +4,6 @@ public enum VolumeType { Root, Data, Memory, - Cache + Cache, + NVRAM, } diff --git a/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java b/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java index 6ec7e3429b7..16865309ec0 100755 --- a/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java +++ b/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java @@ -2068,6 +2068,7 @@ public static class StartVmCmd extends vdiCmd implements VmAddOnsCmd { private List cdRoms = new ArrayList<>(); private List dataVolumes; private List cacheVolumes; + private VolumeTO nvRam; private List nics; private TpmTO tpm; private long timeout; @@ -2549,6 +2550,14 @@ public void setCacheVolumes(List cacheVolumes) { this.cacheVolumes = cacheVolumes; } + public VolumeTO getNvRam() { + return nvRam; + } + + public void setNvRam(VolumeTO nvRam) { + this.nvRam = nvRam; + } + public List getNics() { return nics; } diff --git a/plugin/kvm/src/main/java/org/zstack/kvm/efi/KvmSecureBootExtensions.java b/plugin/kvm/src/main/java/org/zstack/kvm/efi/KvmSecureBootExtensions.java index 138fbda2d6d..8cb982484f7 100644 --- a/plugin/kvm/src/main/java/org/zstack/kvm/efi/KvmSecureBootExtensions.java +++ b/plugin/kvm/src/main/java/org/zstack/kvm/efi/KvmSecureBootExtensions.java @@ -2,45 +2,88 @@ import org.springframework.beans.factory.annotation.Autowired; import org.zstack.compute.vm.VmGlobalConfig; +import org.zstack.compute.vm.devices.VmTpmManager; +import org.zstack.core.cloudbus.CloudBus; +import org.zstack.core.cloudbus.CloudBusCallBack; +import org.zstack.core.db.Q; +import org.zstack.core.workflow.SimpleFlowChain; +import org.zstack.header.core.Completion; +import org.zstack.header.core.workflow.FlowDoneHandler; +import org.zstack.header.core.workflow.FlowErrorHandler; +import org.zstack.header.core.workflow.FlowRollback; +import org.zstack.header.core.workflow.FlowTrigger; +import org.zstack.header.core.workflow.NoRollbackFlow; import org.zstack.header.errorcode.ErrorCode; -import org.zstack.header.image.ImageBootMode; +import org.zstack.header.identity.AccountResourceRefVO; +import org.zstack.header.identity.AccountResourceRefVO_; +import org.zstack.header.message.MessageReply; +import org.zstack.header.vm.DiskAO; +import org.zstack.header.vm.PreVmInstantiateResourceExtensionPoint; import org.zstack.header.vm.VmInstanceSpec; +import org.zstack.header.vm.VmInstantiateResourceException; +import org.zstack.header.volume.CreateVolumeMsg; +import org.zstack.header.volume.CreateVolumeReply; +import org.zstack.header.volume.DeleteVolumeMsg; +import org.zstack.header.volume.InstantiateVolumeMsg; +import org.zstack.header.volume.VolumeConstant; +import org.zstack.header.volume.VolumeDeletionPolicyManager; +import org.zstack.header.volume.VolumeInventory; +import org.zstack.header.volume.VolumeType; +import org.zstack.header.volume.VolumeVO; +import org.zstack.header.volume.VolumeVO_; import org.zstack.kvm.KVMAgentCommands; import org.zstack.kvm.KVMGlobalConfig; import org.zstack.kvm.KVMHostInventory; import org.zstack.kvm.KVMStartVmExtensionPoint; +import org.zstack.kvm.VolumeTO; import org.zstack.resourceconfig.ResourceConfig; import org.zstack.resourceconfig.ResourceConfigFacade; import org.zstack.utils.Utils; import org.zstack.utils.logging.CLogger; +import java.util.Map; import java.util.Objects; +import static org.zstack.core.Platform.operr; import static org.zstack.kvm.KVMConstant.EDK_VERSION_NONE; -public class KvmSecureBootExtensions implements KVMStartVmExtensionPoint { +public class KvmSecureBootExtensions implements KVMStartVmExtensionPoint, + PreVmInstantiateResourceExtensionPoint { private static final CLogger logger = Utils.getLogger(KvmSecureBootExtensions.class); + @Autowired + private CloudBus bus; @Autowired private ResourceConfigFacade resourceConfigFacade; @Override public void beforeStartVmOnKvm(KVMHostInventory host, VmInstanceSpec spec, KVMAgentCommands.StartVmCmd cmd) { - if (!isUefiBootMode(cmd.getBootMode())) { - return; - } + if (isUefiBootMode(cmd.getBootMode())) { + ResourceConfig resourceConfig; + resourceConfig = resourceConfigFacade.getResourceConfig(VmGlobalConfig.ENABLE_UEFI_SECURE_BOOT.getIdentity()); + cmd.setSecureBoot(resourceConfig.getResourceConfigValue(spec.getVmInventory().getUuid(), Boolean.class)); - ResourceConfig resourceConfig; - resourceConfig = resourceConfigFacade.getResourceConfig(VmGlobalConfig.ENABLE_UEFI_SECURE_BOOT.getIdentity()); - cmd.setSecureBoot(resourceConfig.getResourceConfigValue(spec.getVmInventory().getUuid(), Boolean.class)); + resourceConfig = resourceConfigFacade.getResourceConfig(KVMGlobalConfig.VM_EDK_VERSION_CONFIG.getIdentity()); + final String edkVersion = resourceConfig.getResourceConfigValue(spec.getVmInventory().getUuid(), String.class); + if (!Objects.equals(edkVersion, EDK_VERSION_NONE)) { + cmd.setEdkVersion(edkVersion); + } + } - resourceConfig = resourceConfigFacade.getResourceConfig(KVMGlobalConfig.VM_EDK_VERSION_CONFIG.getIdentity()); - final String edkVersion = resourceConfig.getResourceConfigValue(spec.getVmInventory().getUuid(), String.class); - if (!Objects.equals(edkVersion, EDK_VERSION_NONE)) { - cmd.setEdkVersion(edkVersion); + if (spec.getNvRamSpec() != null) { + prepareNvRamToStartVmCmd(cmd, spec.getNvRamSpec(), host); } } + private void prepareNvRamToStartVmCmd(KVMAgentCommands.StartVmCmd cmd, DiskAO nvRamSpec, KVMHostInventory host) { + VolumeVO vo = Q.New(VolumeVO.class) + .eq(VolumeVO_.uuid, nvRamSpec.getSourceUuid()) + .find(); + VolumeInventory nvRamVolume = VolumeInventory.valueOf(vo); + VolumeTO volume = VolumeTO.valueOfWithOutExtension(nvRamVolume, host, null); + cmd.setNvRam(volume); + } + @Override public void startVmOnKvmSuccess(KVMHostInventory host, VmInstanceSpec spec) { // do-nothing @@ -52,6 +95,208 @@ public void startVmOnKvmFailed(KVMHostInventory host, VmInstanceSpec spec, Error } private boolean isUefiBootMode(String bootMode) { - return bootMode.equals(ImageBootMode.UEFI.toString()) || bootMode.equals(ImageBootMode.UEFI_WITH_CSM.toString()); + return VmTpmManager.isUefiBootMode(bootMode); + } + + @Override + public void preBeforeInstantiateVmResource(VmInstanceSpec spec) throws VmInstantiateResourceException { + // do-nothing + } + + @Override + public void preInstantiateVmResource(VmInstanceSpec spec, Completion completion) { + final DiskAO nvRamSpec = spec.getNvRamSpec(); + boolean needRegisterNvRam = nvRamSpec != null; + + String nvRamVolumeUuid = Q.New(VolumeVO.class) + .eq(VolumeVO_.vmInstanceUuid, spec.getVmInventory().getUuid()) + .eq(VolumeVO_.type, VolumeType.NVRAM) + .select(VolumeVO_.uuid) + .findValue(); + if (needRegisterNvRam == (nvRamVolumeUuid != null)) { + if (nvRamVolumeUuid != null) { + nvRamSpec.setSourceUuid(nvRamVolumeUuid); + } + completion.success(); // TODO make sure status is Ready + return; + } + + if (needRegisterNvRam) { + nvRamSpec.setPrimaryStorageUuid(Q.New(VolumeVO.class) + .eq(VolumeVO_.type, VolumeType.Root) + .eq(VolumeVO_.vmInstanceUuid, spec.getVmInventory().getUuid()) + .select(VolumeVO_.primaryStorageUuid) + .findValue()); + + NvRamVolumeContext context = new NvRamVolumeContext(); + context.vmUuid = spec.getVmInventory().getUuid(); + context.nvRamSpec = nvRamSpec; + context.spec = spec; + createNvRamVolume(context, new Completion(completion) { + @Override + public void success() { + nvRamSpec.setSourceUuid(context.inventory.getUuid()); + completion.success(); + } + + @Override + public void fail(ErrorCode errorCode) { + completion.fail(errorCode); + } + }); + return; + } + + deleteNvramVolumeIfExists(spec.getVmInventory().getUuid(), new Completion(completion) { + @Override + public void success() { + completion.success(); + } + + @Override + public void fail(ErrorCode errorCode) { + logger.warn("failed to delete NVRAM but still continue: " + errorCode.getReadableDetails()); + completion.success(); + } + }); + } + + @Override + public void preReleaseVmResource(VmInstanceSpec spec, Completion completion) { + deleteNvramVolumeIfExists(spec.getVmInventory().getUuid(), completion); + } + + static class NvRamVolumeContext { + String vmUuid; + DiskAO nvRamSpec; + VmInstanceSpec spec; + + VolumeInventory inventory; + } + + @SuppressWarnings("rawtypes") + private void createNvRamVolume(NvRamVolumeContext context, Completion completion) { + SimpleFlowChain chain = new SimpleFlowChain(); + chain.setChainName("create-nvram-volume-for-vm-" + context.vmUuid); + chain.then(new NoRollbackFlow() { + String __name__ = "create-nvram-volume"; + + @Override + public void run(FlowTrigger trigger, Map data) { + String accountUuid = Q.New(AccountResourceRefVO.class) + .eq(AccountResourceRefVO_.resourceUuid, context.vmUuid) + .select(AccountResourceRefVO_.accountUuid) + .findValue(); + + CreateVolumeMsg msg = new CreateVolumeMsg(); + msg.setAccountUuid(accountUuid); + msg.setSize(context.nvRamSpec.getSize()); + msg.setVmInstanceUuid(context.vmUuid); + msg.setPrimaryStorageUuid(context.nvRamSpec.getPrimaryStorageUuid()); + + // NVRAM is raw type (*.fd) in libvirt 8.0.0 + // and qcow2 in libvirt 8.1.0+ (soon) + msg.setFormat(VolumeConstant.VOLUME_FORMAT_RAW); + msg.setName(context.nvRamSpec.getName()); + msg.setVolumeType(VolumeType.NVRAM.toString()); + + bus.makeLocalServiceId(msg, VolumeConstant.SERVICE_ID); + bus.send(msg, new CloudBusCallBack(completion) { + @Override + public void run(MessageReply reply) { + if (reply.isSuccess()) { + CreateVolumeReply castReply = reply.castReply(); + context.inventory = castReply.getInventory(); + trigger.next(); + return; + } + trigger.fail(operr("failed to create NVRAM volume") + .withOpaque("vm.uuid", context.vmUuid) + .withCause(reply.getError())); + } + }); + } + + @Override + public void rollback(FlowRollback trigger, Map data) { + deleteNvramVolumeIfExists(context.vmUuid, new Completion(trigger) { + @Override + public void success() { + trigger.rollback(); + } + + @Override + public void fail(ErrorCode errorCode) { + logger.warn("failed to delete NVRAM but still continue: " + errorCode.getReadableDetails()); + trigger.rollback(); + } + }); + } + }).then(new NoRollbackFlow() { + String __name__ = "instantiate-nvram-volume"; + + @Override + public void run(FlowTrigger trigger, Map data) { + InstantiateVolumeMsg msg = new InstantiateVolumeMsg(); + msg.setHostUuid(context.spec.getDestHost().getUuid()); + msg.setPrimaryStorageUuid(context.nvRamSpec.getPrimaryStorageUuid()); + msg.setVolumeUuid(context.inventory.getUuid()); + + bus.makeTargetServiceIdByResourceUuid(msg, VolumeConstant.SERVICE_ID, msg.getVolumeUuid()); + bus.send(msg, new CloudBusCallBack(completion) { + @Override + public void run(MessageReply reply) { + if (reply.isSuccess()) { + trigger.next(); + return; + } + trigger.fail(operr("failed to instantiate NVRAM volume") + .withOpaque("vm.uuid", context.vmUuid) + .withCause(reply.getError())); + } + }); + } + }).done(new FlowDoneHandler(completion) { + @Override + public void handle(Map data) { + completion.success(); + } + }).error(new FlowErrorHandler(completion) { + @Override + public void handle(ErrorCode errCode, Map data) { + completion.fail(errCode); + } + }).start(); + } + + private void deleteNvramVolumeIfExists(String vmUuid, Completion completion) { + String volumeUuid = Q.New(VolumeVO.class) + .eq(VolumeVO_.vmInstanceUuid, vmUuid) + .eq(VolumeVO_.type, VolumeType.NVRAM) + .select(VolumeVO_.uuid) + .findValue(); + if (volumeUuid == null) { + completion.success(); + return; + } + + DeleteVolumeMsg msg = new DeleteVolumeMsg(); + msg.setDetachBeforeDeleting(false); + msg.setUuid(volumeUuid); + msg.setDeletionPolicy(VolumeDeletionPolicyManager.VolumeDeletionPolicy.Direct.toString()); + bus.makeTargetServiceIdByResourceUuid(msg, VolumeConstant.SERVICE_ID, volumeUuid); + bus.send(msg, new CloudBusCallBack(completion) { + @Override + public void run(MessageReply reply) { + if (reply.isSuccess()) { + completion.success(); + return; + } + completion.fail(operr("failed to delete NVRAM volume") + .withOpaque("vm.uuid", vmUuid) + .withOpaque("volume.uuid", volumeUuid) + .withCause(reply.getError())); + } + }); } } diff --git a/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java index e8d268e518a..998bf3b9417 100755 --- a/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java +++ b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java @@ -33,6 +33,7 @@ import org.zstack.header.exception.CloudRuntimeException; import org.zstack.header.host.*; import org.zstack.header.image.ImageBackupStorageRefInventory; +import org.zstack.header.image.ImageConstant; import org.zstack.header.image.ImageConstant.ImageMediaType; import org.zstack.header.image.ImageInventory; import org.zstack.header.image.ImageStatus; @@ -202,6 +203,7 @@ public static class CreateEmptyVolumeCmd extends AgentCommand { private String name; private String volumeUuid; private String backingFile; + private String format; public String getBackingFile() { return backingFile; @@ -211,6 +213,14 @@ public void setBackingFile(String backingFile) { this.backingFile = backingFile; } + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + public String getInstallUrl() { return installUrl; } @@ -963,6 +973,10 @@ public String makeDataVolumeInstallUrl(String volUuid) { return PathUtil.join(self.getUrl(), PrimaryStoragePathMaker.makeDataVolumeInstallPath(volUuid)); } + public String makeNvRamVolumeInstallUrl(String volUuid) { + return PathUtil.join(self.getUrl(), PrimaryStoragePathMaker.makeNvRamVolumeInstallPath(volUuid)); + } + public boolean isCachedImageUrl(String path){ return path.startsWith(PathUtil.join(self.getUrl(), PrimaryStoragePathMaker.getCachedImageInstallDir())); } @@ -1254,7 +1268,7 @@ public void success(VolumeStats returnValue) { VolumeInventory vol = msg.getVolume(); vol.setInstallPath(returnValue.getInstallPath()); vol.setActualSize(returnValue.getActualSize()); - vol.setFormat(VolumeConstant.VOLUME_FORMAT_QCOW2); + vol.setFormat(returnValue.getFormat()); if (returnValue.getSize() != null) { vol.setSize(returnValue.getSize()); } @@ -1279,7 +1293,9 @@ public void createEmptyVolumeWithBackingFile(final VolumeInventory volume, final cmd.setAccountUuid(acntMgr.getOwnerAccountUuidOfResource(volume.getUuid())); if (volume.getInstallPath() != null && !volume.getInstallPath().equals("")) { cmd.setInstallUrl(volume.getInstallPath()); + cmd.setFormat(ImageConstant.QCOW2_FORMAT_STRING); } else { + cmd.setFormat(ImageConstant.QCOW2_FORMAT_STRING); if (VolumeType.Root.toString().equals(volume.getType())) { cmd.setInstallUrl(makeRootVolumeInstallUrl(volume)); } else if (VolumeType.Data.toString().equals(volume.getType())) { @@ -1288,6 +1304,9 @@ public void createEmptyVolumeWithBackingFile(final VolumeInventory volume, final cmd.setInstallUrl(makeMemoryVolumeInstallUrl(volume)); } else if (VolumeType.Cache.toString().equals(volume.getType())) { cmd.setInstallUrl(makeDataVolumeInstallUrl(volume.getUuid())); + } else if (VolumeType.NVRAM.toString().equals(volume.getType())) { + cmd.setInstallUrl(makeNvRamVolumeInstallUrl(volume.getUuid())); + cmd.setFormat(ImageConstant.RAW_FORMAT_STRING); } } cmd.setName(volume.getName()); @@ -1298,7 +1317,9 @@ public void createEmptyVolumeWithBackingFile(final VolumeInventory volume, final httpCall(CREATE_EMPTY_VOLUME_PATH, hostUuid, cmd, CreateEmptyVolumeRsp.class, new ReturnValueCompletion(completion) { @Override public void success(CreateEmptyVolumeRsp returnValue) { - completion.success(new VolumeStats(cmd.getInstallUrl(), returnValue.actualSize, returnValue.size)); + final VolumeStats stats = new VolumeStats(cmd.getInstallUrl(), returnValue.actualSize, returnValue.size); + stats.setFormat(cmd.getFormat()); + completion.success(stats); } @Override diff --git a/storage/src/main/java/org/zstack/storage/primary/PrimaryStoragePathMaker.java b/storage/src/main/java/org/zstack/storage/primary/PrimaryStoragePathMaker.java index 7ef4b4dcd24..a4346f3e28c 100755 --- a/storage/src/main/java/org/zstack/storage/primary/PrimaryStoragePathMaker.java +++ b/storage/src/main/java/org/zstack/storage/primary/PrimaryStoragePathMaker.java @@ -43,6 +43,10 @@ public static String makeDataVolumeInstallPath(String volUuid) { return PathUtil.join("dataVolumes", "acct-" + getAccountUuidOfResource(volUuid), "vol-" + volUuid, volUuid + ".qcow2"); } + public static String makeNvRamVolumeInstallPath(String volUuid) { + return PathUtil.join("nvRam", "acct-" + getAccountUuidOfResource(volUuid), "vol-" + volUuid, volUuid + ".xfs"); + } + public static String makeImageFromSnapshotWorkspacePath(String imageUuid) { return PathUtil.join("snapshotWorkspace", String.format("image-%s", imageUuid)); } diff --git a/storage/src/main/java/org/zstack/storage/volume/VolumeBase.java b/storage/src/main/java/org/zstack/storage/volume/VolumeBase.java index 272d75d7a09..286fed030c3 100755 --- a/storage/src/main/java/org/zstack/storage/volume/VolumeBase.java +++ b/storage/src/main/java/org/zstack/storage/volume/VolumeBase.java @@ -551,7 +551,8 @@ public void fail(ErrorCode errorCode) { } else if (msg instanceof InstantiateMemoryVolumeMsg) { instantiateMemoryVolume(msg, trigger); } else { - instantiateDataVolume(msg, trigger); + // include: data volume, NVRAM, TpmState + instantiateOtherVolume(msg, trigger); } } } @@ -593,7 +594,7 @@ private void instantiateRootVolume(InstantiateRootVolumeMsg msg, FlowTrigger tri doInstantiateVolume(imsg, trigger); } - private void instantiateDataVolume(InstantiateVolumeMsg msg, FlowTrigger trigger) { + private void instantiateOtherVolume(InstantiateVolumeMsg msg, FlowTrigger trigger) { InstantiateVolumeOnPrimaryStorageMsg imsg = new InstantiateVolumeOnPrimaryStorageMsg(); prepareMsg(msg, imsg); doInstantiateVolume(imsg, trigger); diff --git a/test/src/test/resources/springConfigXml/Kvm.xml b/test/src/test/resources/springConfigXml/Kvm.xml index 462aa352dc8..4e57880a7ce 100755 --- a/test/src/test/resources/springConfigXml/Kvm.xml +++ b/test/src/test/resources/springConfigXml/Kvm.xml @@ -260,6 +260,7 @@ +