diff --git a/agent/src/main/java/com/cloud/agent/Agent.java b/agent/src/main/java/com/cloud/agent/Agent.java index 979bce2c4356..cec0c4e9c729 100644 --- a/agent/src/main/java/com/cloud/agent/Agent.java +++ b/agent/src/main/java/com/cloud/agent/Agent.java @@ -78,8 +78,8 @@ import com.cloud.agent.api.MaintainCommand; import com.cloud.agent.api.MigrateAgentConnectionAnswer; import com.cloud.agent.api.MigrateAgentConnectionCommand; -import com.cloud.agent.api.PingAnswer; import com.cloud.agent.api.NetworkUsageCommand; +import com.cloud.agent.api.PingAnswer; import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.ReadyCommand; import com.cloud.agent.api.ShutdownCommand; diff --git a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 3b396f7f1421..3e01bc89fa4c 100755 --- a/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/main/java/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -23,6 +23,7 @@ import java.util.Comparator; import java.util.Date; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -187,6 +188,9 @@ @Component public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implements SnapshotManager, SnapshotApiService, Configurable { + + private static final String KVM_STORAGE_SNAPSHOT_DETAIL = "kvmStorageSnapshot"; + private static final String KVM_FILE_BASED_STORAGE_SNAPSHOT_DETAIL = "kvmFileBasedStorageSnapshot"; @Inject VMTemplateDao _templateDao; @Inject @@ -712,8 +716,8 @@ public Snapshot backupSnapshotFromVmSnapshot(Long snapshotId, Long vmId, Long vo private void updateSnapshotInfo(Long volumeId, Long vmSnapshotId, VMSnapshotVO vmSnapshot, SnapshotVO snapshot, SnapshotDataStoreVO snapshotOnPrimaryStore, StoragePoolVO storagePool) { - if ((storagePool.getPoolType() == StoragePoolType.NetworkFilesystem || storagePool.getPoolType() == StoragePoolType.Filesystem) && vmSnapshot.getType() == VMSnapshot.Type.Disk) { - List vmSnapshotDetails = vmSnapshotDetailsDao.findDetails(vmSnapshotId, "kvmStorageSnapshot"); + if (isFileBasedKvmPrimaryPool(storagePool.getPoolType()) && vmSnapshot.getType() == VMSnapshot.Type.Disk) { + List vmSnapshotDetails = getVmSnapshotVolumeDetails(vmSnapshotId); for (VMSnapshotDetailsVO vmSnapshotDetailsVO : vmSnapshotDetails) { SnapshotInfo sInfo = snapshotDataFactory.getSnapshot(Long.parseLong(vmSnapshotDetailsVO.getValue()), storagePool.getId(), DataStoreRole.Primary); if (sInfo.getVolumeId() == volumeId) { @@ -731,6 +735,30 @@ private void updateSnapshotInfo(Long volumeId, Long vmSnapshotId, VMSnapshotVO v } } + private boolean isFileBasedKvmPrimaryPool(StoragePoolType poolType) { + return poolType == StoragePoolType.NetworkFilesystem + || poolType == StoragePoolType.Filesystem + || poolType == StoragePoolType.SharedMountPoint; + } + + private List getVmSnapshotVolumeDetails(Long vmSnapshotId) { + List details = new ArrayList<>(); + Set uniqueSnapshotIds = new LinkedHashSet<>(); + for (String detailName : List.of(KVM_STORAGE_SNAPSHOT_DETAIL, KVM_FILE_BASED_STORAGE_SNAPSHOT_DETAIL)) { + List found = vmSnapshotDetailsDao.findDetails(vmSnapshotId, detailName); + if (CollectionUtils.isEmpty(found)) { + continue; + } + for (VMSnapshotDetailsVO detail : found) { + if (detail == null || !uniqueSnapshotIds.add(detail.getValue())) { + continue; + } + details.add(detail); + } + } + return details; + } + @Override public SnapshotVO getParentSnapshot(VolumeInfo volume) { long preId = _snapshotDao.getLastSnapshot(volume.getId(), DataStoreRole.Primary); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index df07f5daf188..19d124e1d225 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -443,6 +443,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir private static final String VM_IMPORT_DEFAULT_TEMPLATE_NAME = "system-default-vm-import-dummy-template.iso"; private static final String KVM_VM_IMPORT_DEFAULT_TEMPLATE_NAME = "kvm-default-vm-import-dummy-template"; + private static final String KVM_STORAGE_SNAPSHOT_DETAIL = "kvmStorageSnapshot"; + private static final String KVM_FILE_BASED_STORAGE_SNAPSHOT_DETAIL = "kvmFileBasedStorageSnapshot"; @Inject private EntityManager _entityMgr; @@ -10731,7 +10733,10 @@ public Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceAlloc throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create vm snapshot: " + e.getMessage(), e); } - List listSnapshots = vmSnapshotDetailsDao.findDetails(vmSnapshot.getId(), "kvmFileBasedStorageSnapshot"); + List listSnapshots = getVmSnapshotVolumeDetails(vmSnapshot.getId()); + if (CollectionUtils.isEmpty(listSnapshots)) { + throw new CloudRuntimeException("Could not find volume snapshots mapped to VM snapshot"); + } Integer countOfCloneVM = cmd.getCount(); for (int cnt = 1; cnt <= countOfCloneVM; cnt++) { @@ -10850,6 +10855,24 @@ public Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceAlloc return null; } + private List getVmSnapshotVolumeDetails(Long vmSnapshotId) { + List details = new ArrayList<>(); + Set uniqueSnapshotIds = new LinkedHashSet<>(); + for (String detailName : List.of(KVM_STORAGE_SNAPSHOT_DETAIL, KVM_FILE_BASED_STORAGE_SNAPSHOT_DETAIL)) { + List found = vmSnapshotDetailsDao.findDetails(vmSnapshotId, detailName); + if (CollectionUtils.isEmpty(found)) { + continue; + } + for (VMSnapshotDetailsVO detail : found) { + if (detail == null || !uniqueSnapshotIds.add(detail.getValue())) { + continue; + } + details.add(detail); + } + } + return details; + } + public UserVm createCloneVM(CloneVMCmd cmd, Long rootVolumeId) throws ConcurrentOperationException, ResourceAllocationException, InsufficientCapacityException, ResourceUnavailableException { //network configurations and check, then create the template UserVm curVm = cmd.getTargetVM(); diff --git a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java index f8f2299faa0c..0e9926fad0d2 100644 --- a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java @@ -210,7 +210,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { private static final List forceConvertToPoolAllowedTypes = Arrays.asList(Storage.StoragePoolType.NetworkFilesystem, Storage.StoragePoolType.Filesystem, - Storage.StoragePoolType.SharedMountPoint); + Storage.StoragePoolType.SharedMountPoint, Storage.StoragePoolType.RBD); ConfigKey ConvertVmwareInstanceToKvmExtraParamsAllowed = new ConfigKey<>(Boolean.class, "convert.vmware.instance.to.kvm.extra.params.allowed", diff --git a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java index 1e0fe3189c1b..a580105d52a5 100644 --- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java +++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java @@ -27,6 +27,7 @@ import java.util.Map; import java.util.Map.Entry; +import io.netty.util.IllegalReferenceCountException; import org.apache.cloudstack.storage.template.UploadEntity; import org.apache.cloudstack.utils.imagestore.ImageStoreUtil; import org.apache.commons.lang3.StringUtils; @@ -61,7 +62,6 @@ import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException; import io.netty.handler.codec.http.multipart.InterfaceHttpData; import io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType; -import io.netty.util.IllegalReferenceCountException; import io.netty.util.CharsetUtil; public class HttpUploadServerHandler extends SimpleChannelInboundHandler { @@ -85,7 +85,7 @@ enum UploadHeader { SIGNATURE("x-signature"), METADATA("x-metadata"), EXPIRES("x-expires"), - HOST("x-host"), + HOST("x-forwarded-host"), CONTENT_LENGTH("content-length"); private final String name; @@ -127,7 +127,9 @@ public HttpUploadServerHandler(NfsSecondaryStorageResource storageResource) { @Override public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { - destroyDecoder(); + if (decoder != null) { + decoder.cleanFiles(); + } requestProcessed = false; } diff --git a/ui/package.json b/ui/package.json index bc0a7ec8baa2..70501ab48e74 100644 --- a/ui/package.json +++ b/ui/package.json @@ -103,14 +103,14 @@ "eslint-plugin-vue": "^7.0.0", "less": "^3.0.4", "less-loader": "^5.0.0", - "nan": "2.18.0", - "node-gyp": "10.0.1", "sass": "^1.49.9", "sass-loader": "^8.0.2", "uglifyjs-webpack-plugin": "^2.2.0", "vue-jest": "^5.0.0-0", "vue-svg-loader": "^0.17.0-beta.2", - "webpack": "^4.46.0" + "webpack": "^4.46.0", + "node-gyp": "10.0.1", + "nan": "2.18.0" }, "resolutions": { "nan": "2.18.0" diff --git a/ui/public/locales/ko_KR.json b/ui/public/locales/ko_KR.json index 3ab8272b59ad..cc89ae0b0e1e 100644 --- a/ui/public/locales/ko_KR.json +++ b/ui/public/locales/ko_KR.json @@ -404,7 +404,7 @@ "label.all.available.data": "\uc0ac\uc6a9 \uac00\ub2a5\ud55c \ubaa8\ub4e0 \ub370\uc774\ud130", "label.all.ipv6": "\ubaa8\ub4e0 IPv6", "label.all.zone": "\ubaa8\ub4e0 Zones", -"label.allocated": "\ud560\ub2f9\ub428", +"label.allocated": "\ud560\ub2f9", "label.allocatedonly": "\ud560\ub2f9", "label.allocationstate": "\ud560\ub2f9 \uc0c1\ud0dc", "label.allow": "\ud5c8\uc6a9", @@ -2367,7 +2367,7 @@ "label.snapshot": "\uc2a4\ub0c5\uc0f7", "label.snapshot.name": "\uc2a4\ub0c5\uc0f7 \uc774\ub984", "label.snapshotlimit": "\uc2a4\ub0c5\uc0f7 \uc81c\ud55c", -"label.snapshotmemory": "\uc2a4\ub0c5\uc0f7 \uba54\ubaa8\ub9ac", +"label.snapshotmemory": "\uba54\ubaa8\ub9ac \uc2a4\ub0c5\uc0f7", "label.snapshotpolicy": "\uc2a4\ub0c5\uc0f7 \uc815\ucc45", "label.snapshotpolicies": "\uc2a4\ub0c5\uc0f7 \uc815\ucc45", "label.snapshots": "\uc2a4\ub0c5\uc0f7", @@ -2725,7 +2725,7 @@ "label.use.kubectl.access.cluster": "\ud074\ub7ec\uc2a4\ud130\uc5d0 \uc561\uc138\uc2a4\ud558\uae30\uc704\ud55c kubectl \ubc0f kubeconfig \ud30c\uc77c", "label.use.local.timezone": "\ub85c\uceec \uc2dc\uac04\ub300 \uc0ac\uc6a9", "label.use.router.ip.resolver": "\uac00\uc0c1 \ub77c\uc6b0\ud130 IP\ub97c Resolver\ub85c \uc0ac\uc6a9", -"label.used": "\uc0ac\uc6a9\ub428", +"label.used": "\uc0ac\uc6a9", "label.usehttps": "HTTPS \uc0ac\uc6a9", "label.usenewdiskoffering": "\ub514\uc2a4\ud06c \uc624\ud37c\ub9c1\uc744 \ubcc0\uacbd\ud558\uc2dc\uaca0\uc2b5\ub2c8\uae4c?", "label.user": "\uc0ac\uc6a9\uc790", @@ -4315,6 +4315,7 @@ "GB*Month": "GB * \uc6d4", "IP*Month": "IP * \uc6d4\uac04", "Policy*Month": "\uc815\ucc45 * \uc6d4", + "label.desktop.service": "\ub370\uc2a4\ud06c\ud1b1", "title.desktop.cluster": "\ud074\ub7ec\uc2a4\ud130", "title.desktop.controller": "\ucee8\ud2b8\ub864\ub7ec \ud15c\ud50c\ub9bf", @@ -4861,6 +4862,8 @@ "backup.schedule.delete": "\ubc31\uc5c5 \uc77c\uc815 \uc0ad\uc81c", "backup.usage.metric": "\ubc31\uc5c5 \uc0ac\uc6a9\ub7c9 \uba54\ud2b8\ub9ad", "backup.offering.edit": "\ubc31\uc5c5 \uc624\ud37c\ub9c1 \ud3b8\uc9d1", +"backup.repository.add": "\ubc31\uc5c5 \uc800\uc7a5\uc18c \ucd94\uac00", +"backup.repository.update": "\ubc31\uc5c5 \uc800\uc7a5\uc18c \ud3b8\uc9d1", "physical.nvpcontroller.add": "\ubb3c\ub9ac NVP\ucee8\ud2b8\ub864\ub7ec \ucd94\uac00", "physical.nvpcontroller.delete": "\ubb3c\ub9ac NVP\ucee8\ud2b8\ub864\ub7ec \uc0ad\uc81c", "physical.nvpcontroller.configure": "\ubb3c\ub9ac NVP\ucee8\ud2b8\ub864\ub7ec \uad6c\uc131", diff --git a/ui/src/components/page/GlobalLayout.vue b/ui/src/components/page/GlobalLayout.vue index 0f244ebff999..6817c13ee1eb 100644 --- a/ui/src/components/page/GlobalLayout.vue +++ b/ui/src/components/page/GlobalLayout.vue @@ -13,36 +13,24 @@ - -