diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/disk/image/GetAllDisksByStorageDomainIdQuery.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/disk/image/GetAllDisksByStorageDomainIdQuery.java index bd8716802a2..3f5d2c3613d 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/disk/image/GetAllDisksByStorageDomainIdQuery.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/storage/disk/image/GetAllDisksByStorageDomainIdQuery.java @@ -30,7 +30,11 @@ public GetAllDisksByStorageDomainIdQuery(P parameters, EngineContext engineConte @Override protected void executeQueryCommand() { StorageDomain storageDomain = storageDomainDao.get(getParameters().getId()); - if (storageDomain.getStorageType().isCinderDomain()) { + // Cinder and Managed Block Storage domains store one volume per disk + // with no qcow2 snapshot chain to aggregate, so they take the simple + // listing path. SPM-managed domains need the snapshot-aggregation + // pass to fold the snapshot chain into per-disk rows. + if (storageDomain.getStorageType().isVendorManagedBlock()) { List diskImages = diskImageDao.getAllForStorageDomain(getParameters().getId()); getQueryReturnValue().setReturnValue(diskImages); } else { diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/validator/storage/StorageDomainValidator.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/validator/storage/StorageDomainValidator.java index afeccc0a317..08ad9591efc 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/validator/storage/StorageDomainValidator.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/validator/storage/StorageDomainValidator.java @@ -97,7 +97,7 @@ public ValidationResult domainIsValidDestination() { } public ValidationResult isDomainWithinThresholds() { - if (storageDomain.getStorageType().isCinderDomain()) { + if (storageDomain.getStorageType().isVendorManagedBlock()) { return ValidationResult.VALID; } StorageDomainDynamic dynamicData = storageDomain.getStorageDynamicData(); @@ -207,7 +207,7 @@ private double getTotalSizeForMerge(Collection subchains, ActionTy * Validate space for new, empty disks. Used for a new Active Image. */ public ValidationResult hasSpaceForNewDisks(Collection diskImages) { - if (storageDomain.getStorageType().isCinderDomain()) { + if (storageDomain.getStorageType().isVendorManagedBlock()) { return ValidationResult.VALID; } Long availableSize = storageDomain.getAvailableDiskSizeInBytes(); @@ -220,7 +220,7 @@ public ValidationResult hasSpaceForNewDisks(Collection diskImages) { * Validate space for a cloned disk with the collapse option. */ public ValidationResult hasSpaceForClonedDisks(Collection diskImages) { - if (storageDomain.getStorageType().isCinderDomain()) { + if (storageDomain.getStorageType().isVendorManagedBlock()) { return ValidationResult.VALID; } Long availableSize = storageDomain.getAvailableDiskSizeInBytes(); @@ -230,7 +230,7 @@ public ValidationResult hasSpaceForClonedDisks(Collection diskImages) } public ValidationResult hasSpaceForMerge(List subchains, ActionType snapshotActionType) { - if (storageDomain.getStorageType().isCinderDomain() || storageDomain.getStorageType().isManagedBlockStorage()) { + if (storageDomain.getStorageType().isVendorManagedBlock()) { return ValidationResult.VALID; } Long availableSize = storageDomain.getAvailableDiskSizeInBytes(); @@ -243,7 +243,7 @@ public ValidationResult hasSpaceForMerge(List subchains, ActionTyp * Validate space for cloned disks without the collapse option. Every snapshot will be cloned. */ public ValidationResult hasSpaceForDisksWithSnapshots(Collection diskImages) { - if (storageDomain.getStorageType().isCinderDomain()) { + if (storageDomain.getStorageType().isVendorManagedBlock()) { return ValidationResult.VALID; } Long availableSize = storageDomain.getAvailableDiskSizeInBytes(); @@ -259,7 +259,7 @@ public ValidationResult hasSpaceForDisksWithSnapshots(Collection disk * so there's no method for this. */ public ValidationResult hasSpaceForAllDisks(Collection newDiskImages, Collection clonedDiskImages) { - if (storageDomain.getStorageType().isCinderDomain()) { + if (storageDomain.getStorageType().isVendorManagedBlock()) { return ValidationResult.VALID; } Long availableSize = storageDomain.getAvailableDiskSizeInBytes(); diff --git a/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/validator/storage/StorageDomainValidatorFreeSpaceTest.java b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/validator/storage/StorageDomainValidatorFreeSpaceTest.java index 08f19fb7959..30e0987d2e7 100644 --- a/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/validator/storage/StorageDomainValidatorFreeSpaceTest.java +++ b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/validator/storage/StorageDomainValidatorFreeSpaceTest.java @@ -58,10 +58,17 @@ public static Stream createParams() { sd.setStorageType(storageType); sd.setAvailableDiskSize(107); // GB + boolean shortCircuitForVendorManaged = storageType.isManagedBlockStorage(); + boolean isValidForNew = shortCircuitForVendorManaged + || volumeFormat == VolumeFormat.COW || volumeType == VolumeType.Sparse; + boolean isValidForCloned = shortCircuitForVendorManaged + || volumeFormat == VolumeFormat.RAW && volumeType == VolumeType.Sparse; + boolean isValidForSnapshots = shortCircuitForVendorManaged + || volumeFormat == VolumeFormat.RAW && volumeType == VolumeType.Sparse; params.add(Arguments.of(disk, sd, - volumeFormat == VolumeFormat.RAW && volumeType == VolumeType.Sparse, - volumeFormat == VolumeFormat.COW || volumeType == VolumeType.Sparse, - volumeFormat == VolumeFormat.RAW && volumeType == VolumeType.Sparse + isValidForCloned, + isValidForNew, + isValidForSnapshots )); } } diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/storage/StorageType.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/storage/StorageType.java index 24c10f3ef14..d840d9185c4 100644 --- a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/storage/StorageType.java +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/storage/StorageType.java @@ -85,4 +85,28 @@ public boolean isCinderDomain() { public boolean isManagedBlockStorage() { return this == MANAGED_BLOCK_STORAGE; } + + /** + * Returns true for any vendor-managed-block storage backend + * (Cinder, Managed Block Storage), where the volume lifecycle + * is owned by the storage backend rather than by the SPM. Both + * have one volume per disk with no qcow2 snapshot chain to + * aggregate, and both use vendor-side capacity accounting, which + * is why they take the same code path across the engine. + * + * Many places historically checked only {@code isCinderDomain()} + * and never got the parallel {@code isManagedBlockStorage()} + * added when MBS landed, causing MBS domains to fall through to + * SPM-style code paths that don't match their semantics. This + * helper names the combined case and replaces the partially- + * applied checks. + * + * When Cinder is fully removed (CentOS Stream 10 already dropped + * it) this helper collapses to {@code isManagedBlockStorage()} + * and the {@code isCinderDomain} machinery can be deleted as a + * single follow-up. + */ + public boolean isVendorManagedBlock() { + return isCinderDomain() || isManagedBlockStorage(); + } }