From 5cb279b6f105e687166788b563c302df7735276f Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Tue, 30 Dec 2025 15:37:32 +0530 Subject: [PATCH 1/5] ui: fix test delivery params in create webhook form (#12318) Signed-off-by: Abhishek Kumar --- ui/src/components/view/TestWebhookDeliveryView.vue | 2 +- ui/src/views/tools/CreateWebhook.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/components/view/TestWebhookDeliveryView.vue b/ui/src/components/view/TestWebhookDeliveryView.vue index ebebe722e99..2bb154f3900 100644 --- a/ui/src/components/view/TestWebhookDeliveryView.vue +++ b/ui/src/components/view/TestWebhookDeliveryView.vue @@ -186,7 +186,7 @@ export default { params.payloadUrl = this.payloadUrl } if (this.sslVerification) { - params.payload = this.sslVerification + params.sslVerification = this.sslVerification } if (this.secretKey) { params.secretKey = this.secretKey diff --git a/ui/src/views/tools/CreateWebhook.vue b/ui/src/views/tools/CreateWebhook.vue index 7d687c7d983..2b437471977 100644 --- a/ui/src/views/tools/CreateWebhook.vue +++ b/ui/src/views/tools/CreateWebhook.vue @@ -135,7 +135,7 @@ From 10dcbd76f0fdd2e0eb0674e04e211a3788c8ad89 Mon Sep 17 00:00:00 2001 From: Rene Peinthor Date: Wed, 31 Dec 2025 10:55:54 +0100 Subject: [PATCH 2/5] linstor: Provide /dev/drbd/by-res/ resource paths to CloudStack (#12300) --- plugins/storage/volume/linstor/CHANGELOG.md | 17 +++------ .../kvm/storage/LinstorStorageAdaptor.java | 7 ++-- .../storage/datastore/util/LinstorUtil.java | 35 +++++++++++++++---- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/plugins/storage/volume/linstor/CHANGELOG.md b/plugins/storage/volume/linstor/CHANGELOG.md index 7da3516955d..47d1ddeb06c 100644 --- a/plugins/storage/volume/linstor/CHANGELOG.md +++ b/plugins/storage/volume/linstor/CHANGELOG.md @@ -5,22 +5,24 @@ All notable changes to Linstor CloudStack plugin will be documented in this file The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2025-12-18] + +### Changed +- Provide /dev/drbd/by-res/ resource paths to CloudStack for usage. + ## [2025-10-03] ### Changed - - Revert qcow2 snapshot now use sparse/discard options to convert on thin devices. ## [2025-08-05] ### Fixed - - getVolumeStats wasn't correctly working if multiple Linstor clusters/primary storages are used. ## [2025-07-01] ### Fixed - - Regression in 4.19.3 and 4.21.0 with templates from snapshots ## [2025-05-07] @@ -31,25 +33,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [2025-03-13] ### Fixed - - Implemented missing delete datastore, to correctly cleanup on datastore removal ## [2025-02-21] ### Fixed - - Always try to delete cs-...-rst resource before doing a snapshot backup ## [2025-01-27] ### Fixed - - Use of multiple primary storages on the same linstor controller ## [2025-01-20] ### Fixed - - Volume snapshots on zfs used the wrong dataset path to hide/unhide snapdev ## [2024-12-19] @@ -60,13 +58,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [2024-12-13] ### Fixed - - Linstor heartbeat check now also ask linstor-controller if there is no connection between nodes ## [2024-12-11] ### Fixed - - Only set allow-two-primaries if a live migration is performed ## [2024-10-28] @@ -79,17 +75,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [2024-10-14] ### Added - - Support for ISO direct download to primary storage ## [2024-10-04] ### Added - - Enable qemu discard="unmap" for Linstor block disks ## [2024-08-27] ### Changed - - Allow two primaries(+protocol c) is now set on resource-connection level instead of rd diff --git a/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java b/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java index a664e7ed03b..1fe318e5163 100644 --- a/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java +++ b/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java @@ -232,7 +232,7 @@ public class LinstorStorageAdaptor implements StorageAdaptor { makeResourceAvailable(api, foundRscName, false); if (!resources.isEmpty() && !resources.get(0).getVolumes().isEmpty()) { - final String devPath = resources.get(0).getVolumes().get(0).getDevicePath(); + final String devPath = LinstorUtil.getDevicePathFromResource(resources.get(0)); logger.info("Linstor: Created drbd device: " + devPath); final KVMPhysicalDisk kvmDisk = new KVMPhysicalDisk(devPath, name, pool); kvmDisk.setFormat(QemuImg.PhysicalDiskFormat.RAW); @@ -455,8 +455,9 @@ public class LinstorStorageAdaptor implements StorageAdaptor { private Optional getResourceByPathOrName( final List resources, String path) { return resources.stream() - .filter(rsc -> getLinstorRscName(path).equalsIgnoreCase(rsc.getName()) || rsc.getVolumes().stream() - .anyMatch(v -> path.equals(v.getDevicePath()))) + .filter(rsc -> getLinstorRscName(path).equalsIgnoreCase(rsc.getName()) || + path.equals(LinstorUtil.formatDrbdByResDevicePath(rsc.getName())) || + rsc.getVolumes().stream().anyMatch(v -> path.equals(v.getDevicePath()))) .findFirst(); } diff --git a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java index 9c3c9d32611..4196c12b116 100644 --- a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java +++ b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java @@ -264,6 +264,16 @@ public class LinstorUtil { return false; } + /** + * Format the device path for DRBD resources. + * @param rscName + * @return + */ + public static String formatDrbdByResDevicePath(String rscName) + { + return String.format("/dev/drbd/by-res/%s/0", rscName); + } + /** * Try to get the device path for the given resource name. * This could be made a bit more direct after java-linstor api is fixed for layer data subtypes. @@ -283,12 +293,7 @@ public class LinstorUtil { null); for (ResourceWithVolumes rsc : resources) { if (!rsc.getVolumes().isEmpty()) { - // CloudStack resource always only have 1 volume - String devicePath = rsc.getVolumes().get(0).getDevicePath(); - if (devicePath != null && !devicePath.isEmpty()) { - LOGGER.debug("getDevicePath: {} -> {}", rscName, devicePath); - return devicePath; - } + return LinstorUtil.getDevicePathFromResource(rsc); } } @@ -297,6 +302,24 @@ public class LinstorUtil { throw new CloudRuntimeException("Linstor: " + errMsg); } + /** + * Check if the resource has DRBD or not and deliver the correct device path. + * @param rsc + * @return + */ + public static String getDevicePathFromResource(ResourceWithVolumes rsc) { + if (!rsc.getVolumes().isEmpty()) { + // CloudStack resource always only have 1 volume + if (rsc.getLayerObject().getDrbd() != null) { + return formatDrbdByResDevicePath(rsc.getName()); + } else { + return rsc.getVolumes().get(0).getDevicePath(); + } + } + throw new CloudRuntimeException( + String.format("getDevicePath: Resource %s/%s doesn't have volumes", rsc.getNodeName(), rsc.getName())); + } + public static ApiCallRcList applyAuxProps(DevelopersApi api, String rscName, String dispName, String vmName) throws ApiException { From 4f749378551b3035ff0617f6f8df1fe3618b9c27 Mon Sep 17 00:00:00 2001 From: Suresh Kumar Anaparti Date: Fri, 2 Jan 2026 14:04:59 +0530 Subject: [PATCH 3/5] Event typo fix (#12350) --- .../ObjectInDataStoreStateMachine.java | 6 +-- .../manager/StorageCacheManagerImpl.java | 2 +- .../motion/AncientDataMotionStrategy.java | 4 +- .../StorageSystemDataMotionStrategy.java | 12 ++--- .../image/SecondaryStorageServiceImpl.java | 4 +- .../storage/image/TemplateServiceImpl.java | 14 +++--- .../snapshot/DefaultSnapshotStrategy.java | 2 +- .../storage/snapshot/SnapshotServiceImpl.java | 12 ++--- .../datastore/DataObjectManagerImpl.java | 8 ++-- .../ObjectInDataStoreManagerImpl.java | 16 +++---- .../storage/volume/VolumeObject.java | 2 +- .../storage/volume/VolumeServiceImpl.java | 48 +++++++++---------- .../storage/volume/VolumeObjectTest.java | 4 +- .../motion/StorPoolDataMotionStrategy.java | 4 +- .../snapshot/StorPoolSnapshotStrategy.java | 2 +- 15 files changed, 68 insertions(+), 72 deletions(-) diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java index a8e80313768..d4ca163e4e6 100644 --- a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java +++ b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java @@ -33,9 +33,9 @@ public interface ObjectInDataStoreStateMachine extends StateObject entry : volumeToPool.entrySet()) { VolumeInfo volume = entry.getKey(); snapshotMgr.cleanupSnapshotsByVolume(volume.getId()); - volume.processEvent(Event.OperationSuccessed); + volume.processEvent(Event.OperationSucceeded); } future.complete(res); } @@ -2431,7 +2431,7 @@ public class VolumeServiceImpl implements VolumeService { } } else { - vo.processEvent(Event.OperationSuccessed, result.getAnswer()); + vo.processEvent(Event.OperationSucceeded, result.getAnswer()); if (vo.getSize() != null) { // publish usage events @@ -2551,7 +2551,7 @@ public class VolumeServiceImpl implements VolumeService { } try { - volume.processEvent(Event.OperationSuccessed); + volume.processEvent(Event.OperationSucceeded); } catch (Exception e) { logger.debug("Failed to change volume state (after resize success)", e); } @@ -2640,7 +2640,7 @@ public class VolumeServiceImpl implements VolumeService { if (volume.getState() == State.NotUploaded || volume.getState() == State.UploadInProgress) { VolumeObject volObj = (VolumeObject)volFactory.getVolume(volume.getId()); - volObj.processEvent(Event.OperationSuccessed); + volObj.processEvent(Event.OperationSucceeded); } if (volInfo.getSize() > 0) { diff --git a/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeObjectTest.java b/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeObjectTest.java index 58f47a5db64..5701bc49e15 100644 --- a/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeObjectTest.java +++ b/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeObjectTest.java @@ -147,7 +147,7 @@ public class VolumeObjectTest extends TestCase{ expectedResult.put(ObjectInDataStoreStateMachine.Event.MigrationRequested, Volume.Event.CopyRequested); expectedResult.put(ObjectInDataStoreStateMachine.Event.DestroyRequested, Volume.Event.DestroyRequested); expectedResult.put(ObjectInDataStoreStateMachine.Event.ExpungeRequested, Volume.Event.ExpungingRequested); - expectedResult.put(ObjectInDataStoreStateMachine.Event.OperationSuccessed, Volume.Event.OperationSucceeded); + expectedResult.put(ObjectInDataStoreStateMachine.Event.OperationSucceeded, Volume.Event.OperationSucceeded); expectedResult.put(ObjectInDataStoreStateMachine.Event.MigrationCopySucceeded, Volume.Event.MigrationCopySucceeded); expectedResult.put(ObjectInDataStoreStateMachine.Event.OperationFailed, Volume.Event.OperationFailed); expectedResult.put(ObjectInDataStoreStateMachine.Event.MigrationCopyFailed, Volume.Event.MigrationCopyFailed); @@ -168,7 +168,7 @@ public class VolumeObjectTest extends TestCase{ expectedResult.put(ObjectInDataStoreStateMachine.Event.MigrationCopyRequested, Volume.Event.MigrationCopyRequested); expectedResult.put(ObjectInDataStoreStateMachine.Event.DestroyRequested, Volume.Event.DestroyRequested); expectedResult.put(ObjectInDataStoreStateMachine.Event.ExpungeRequested, Volume.Event.ExpungingRequested); - expectedResult.put(ObjectInDataStoreStateMachine.Event.OperationSuccessed, Volume.Event.OperationSucceeded); + expectedResult.put(ObjectInDataStoreStateMachine.Event.OperationSucceeded, Volume.Event.OperationSucceeded); expectedResult.put(ObjectInDataStoreStateMachine.Event.MigrationCopySucceeded, Volume.Event.MigrationCopySucceeded); expectedResult.put(ObjectInDataStoreStateMachine.Event.OperationFailed, Volume.Event.OperationFailed); expectedResult.put(ObjectInDataStoreStateMachine.Event.MigrationCopyFailed, Volume.Event.MigrationCopyFailed); diff --git a/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/motion/StorPoolDataMotionStrategy.java b/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/motion/StorPoolDataMotionStrategy.java index aa972d44343..5a4802ab264 100644 --- a/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/motion/StorPoolDataMotionStrategy.java +++ b/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/motion/StorPoolDataMotionStrategy.java @@ -453,8 +453,8 @@ public class StorPoolDataMotionStrategy implements DataMotionStrategy { VolumeInfo destVolumeInfo = entry.getValue(); if (success) { - srcVolumeInfo.processEvent(Event.OperationSuccessed); - destVolumeInfo.processEvent(Event.OperationSuccessed); + srcVolumeInfo.processEvent(Event.OperationSucceeded); + destVolumeInfo.processEvent(Event.OperationSucceeded); _volumeDao.updateUuid(srcVolumeInfo.getId(), destVolumeInfo.getId()); diff --git a/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java b/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java index 5ec86df91e1..8a51e2672ea 100644 --- a/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java +++ b/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/snapshot/StorPoolSnapshotStrategy.java @@ -201,7 +201,7 @@ public class StorPoolSnapshotStrategy implements SnapshotStrategy { if (parent.getPath() != null && parent.getPath().equalsIgnoreCase(snapshot.getPath())) { logger.debug("for empty delta snapshot, only mark it as destroyed in db"); snapshot.processEvent(Event.DestroyRequested); - snapshot.processEvent(Event.OperationSuccessed); + snapshot.processEvent(Event.OperationSucceeded); deleted = true; if (!resultIsSet) { result = true; From 77cb0827d354af69766de2052715410201684b95 Mon Sep 17 00:00:00 2001 From: YoulongChen <30854794+YLChen-007@users.noreply.github.com> Date: Mon, 5 Jan 2026 14:58:34 +0800 Subject: [PATCH 4/5] Refactor XML parsing to use safer document builders in multiple classes (#12129) Co-authored-by: chenyoulong20g@ict.ac.cn --- .../LibvirtMigrateVolumeCommandWrapper.java | 5 ++-- .../java/com/cloud/test/DatabaseConfig.java | 2 +- .../utils/cisco/n1kv/vsm/VsmCommand.java | 23 ++++++++++--------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateVolumeCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateVolumeCommandWrapper.java index c0630f97886..22e35f53c05 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateVolumeCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateVolumeCommandWrapper.java @@ -42,6 +42,7 @@ import org.apache.cloudstack.storage.datastore.client.ScaleIOGatewayClient; import org.apache.cloudstack.storage.datastore.util.ScaleIOUtil; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.cloudstack.utils.security.ParserUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.libvirt.Connect; @@ -216,7 +217,7 @@ public class LibvirtMigrateVolumeCommandWrapper extends CommandWrapper> params) { try { // Create the document and root element. - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilderFactory docFactory = ParserUtils.getSaferDocumentBuilderFactory(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); DOMImplementation domImpl = docBuilder.getDOMImplementation(); Document doc = createDocument(domImpl); @@ -166,7 +167,7 @@ public class VsmCommand { public static String getDeletePortProfile(String portName) { try { // Create the document and root element. - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilderFactory docFactory = ParserUtils.getSaferDocumentBuilderFactory(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); DOMImplementation domImpl = docBuilder.getDOMImplementation(); Document doc = createDocument(domImpl); @@ -199,7 +200,7 @@ public class VsmCommand { public static String getAddPolicyMap(String name, int averageRate, int maxRate, int burstRate) { try { // Create the document and root element. - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilderFactory docFactory = ParserUtils.getSaferDocumentBuilderFactory(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); DOMImplementation domImpl = docBuilder.getDOMImplementation(); Document doc = createDocument(domImpl); @@ -232,7 +233,7 @@ public class VsmCommand { public static String getDeletePolicyMap(String name) { try { // Create the document and root element. - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilderFactory docFactory = ParserUtils.getSaferDocumentBuilderFactory(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); DOMImplementation domImpl = docBuilder.getDOMImplementation(); Document doc = createDocument(domImpl); @@ -265,7 +266,7 @@ public class VsmCommand { public static String getServicePolicy(String policyMap, String portProfile, boolean attach) { try { // Create the document and root element. - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilderFactory docFactory = ParserUtils.getSaferDocumentBuilderFactory(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); DOMImplementation domImpl = docBuilder.getDOMImplementation(); Document doc = createDocument(domImpl); @@ -297,7 +298,7 @@ public class VsmCommand { public static String getPortProfile(String name) { try { - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilderFactory docFactory = ParserUtils.getSaferDocumentBuilderFactory(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); DOMImplementation domImpl = docBuilder.getDOMImplementation(); Document doc = createDocument(domImpl); @@ -334,7 +335,7 @@ public class VsmCommand { public static String getPolicyMap(String name) { try { - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilderFactory docFactory = ParserUtils.getSaferDocumentBuilderFactory(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); DOMImplementation domImpl = docBuilder.getDOMImplementation(); Document doc = createDocument(domImpl); @@ -367,7 +368,7 @@ public class VsmCommand { public static String getHello() { try { - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilderFactory docFactory = ParserUtils.getSaferDocumentBuilderFactory(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); DOMImplementation domImpl = docBuilder.getDOMImplementation(); @@ -395,7 +396,7 @@ public class VsmCommand { public static String getVServiceNode(String vlanId, String ipAddr) { try { // Create the document and root element. - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilderFactory docFactory = ParserUtils.getSaferDocumentBuilderFactory(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); DOMImplementation domImpl = docBuilder.getDOMImplementation(); Document doc = createDocument(domImpl); From ca64406a8805a9292641c49efe5443b080e73f6a Mon Sep 17 00:00:00 2001 From: Manoj Kumar Date: Mon, 5 Jan 2026 12:49:03 +0530 Subject: [PATCH 5/5] replace momentjs with dayjs and use watch instead of update (#12351) --- ui/src/components/view/DateTimeFilter.vue | 43 +++++++++++------------ 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/ui/src/components/view/DateTimeFilter.vue b/ui/src/components/view/DateTimeFilter.vue index aca958f58f7..efac3b43eee 100644 --- a/ui/src/components/view/DateTimeFilter.vue +++ b/ui/src/components/view/DateTimeFilter.vue @@ -61,7 +61,7 @@