diff --git a/conf/db/zsv/V5.1.0__schema.sql b/conf/db/zsv/V5.1.0__schema.sql index b0da7cea469..9ae3076078b 100644 --- a/conf/db/zsv/V5.1.0__schema.sql +++ b/conf/db/zsv/V5.1.0__schema.sql @@ -260,3 +260,8 @@ CREATE TABLE IF NOT EXISTS `zstack`.`ResNotifyWebhookRefVO` ( CONSTRAINT `fk_ResNotifyWebhookRefVO_ResNotifySubscriptionVO` FOREIGN KEY (`uuid`) REFERENCES `ResNotifySubscriptionVO`(`uuid`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DELETE shadow FROM ImageCacheShadowVO shadow + LEFT JOIN PrimaryStorageEO ps ON shadow.primaryStorageUuid = ps.uuid + WHERE ps.uuid IS NULL; +CALL ADD_CONSTRAINT('ImageCacheShadowVO', 'fkImageCacheShadowVOPrimaryStorageEOCascade', 'primaryStorageUuid', 'PrimaryStorageEO', 'uuid', 'CASCADE'); diff --git a/test/src/test/groovy/org/zstack/test/integration/storage/primary/local/CleanImageCacheOnLocalPrimaryStorageCase.groovy b/test/src/test/groovy/org/zstack/test/integration/storage/primary/local/CleanImageCacheOnLocalPrimaryStorageCase.groovy index 13a1e0db080..496d9fc6a1e 100644 --- a/test/src/test/groovy/org/zstack/test/integration/storage/primary/local/CleanImageCacheOnLocalPrimaryStorageCase.groovy +++ b/test/src/test/groovy/org/zstack/test/integration/storage/primary/local/CleanImageCacheOnLocalPrimaryStorageCase.groovy @@ -2,8 +2,11 @@ package org.zstack.test.integration.storage.primary.local import org.springframework.http.HttpEntity import org.zstack.compute.vm.VmGlobalConfig +import org.zstack.core.db.DatabaseFacade import org.zstack.core.db.Q +import org.zstack.header.image.ImageConstant.ImageMediaType import org.zstack.header.network.service.NetworkServiceType +import org.zstack.header.storage.primary.ImageCacheState import org.zstack.header.storage.primary.ImageCacheShadowVO import org.zstack.header.storage.primary.ImageCacheShadowVO_ import org.zstack.header.storage.primary.ImageCacheVO @@ -15,6 +18,7 @@ import org.zstack.sdk.ApplianceVmInventory import org.zstack.sdk.ImageInventory import org.zstack.sdk.PrimaryStorageInventory import org.zstack.sdk.VmInstanceInventory +import org.zstack.sdk.ZoneInventory import org.zstack.storage.primary.PrimaryStorageGlobalConfig import org.zstack.storage.primary.local.LocalStorageKvmBackend import org.zstack.test.integration.storage.StorageTest @@ -24,6 +28,7 @@ import org.zstack.utils.data.SizeUnit import org.zstack.utils.gson.JSONObjectUtil import org.zstack.utils.path.PathUtil +import java.sql.Timestamp import java.util.concurrent.TimeUnit /** @@ -171,6 +176,7 @@ class CleanImageCacheOnLocalPrimaryStorageCase extends SubCase{ void test() { env.create { testDelete() + testDeleteLocalStorageCascadesImageCacheShadow() } } @@ -224,4 +230,40 @@ class CleanImageCacheOnLocalPrimaryStorageCase extends SubCase{ .isExists() } } -} \ No newline at end of file + + void testDeleteLocalStorageCascadesImageCacheShadow() { + ZoneInventory zone = env.inventoryByName("zone") + PrimaryStorageInventory shadowPs = addLocalPrimaryStorage { + name = "shadow-cascade-local" + url = "/local_ps_shadow" + zoneUuid = zone.uuid + } + + DatabaseFacade dbf = bean(DatabaseFacade.class) + ImageCacheShadowVO shadow = new ImageCacheShadowVO() + shadow.primaryStorageUuid = shadowPs.uuid + shadow.imageUuid = "test-image-cache-shadow" + shadow.installUrl = "hostUuid://test-host//local_ps_shadow/imagecache/test-image-cache-shadow.qcow2" + shadow.mediaType = ImageMediaType.RootVolumeTemplate + shadow.size = SizeUnit.GIGABYTE.toByte(1) + shadow.state = ImageCacheState.ready + shadow.md5sum = "" + shadow.createDate = new Timestamp(System.currentTimeMillis()) + shadow.lastOpDate = shadow.createDate + dbf.persist(shadow) + + long beforeDelete = Q.New(ImageCacheShadowVO.class) + .eq(ImageCacheShadowVO_.primaryStorageUuid, shadowPs.uuid) + .count() + assert beforeDelete == 1 : "ImageCacheShadowVO 测试数据未创建: expected=1 actual=${beforeDelete} primaryStorageUuid=${shadowPs.uuid}" + + deletePrimaryStorage { + uuid = shadowPs.uuid + } + + long afterDelete = Q.New(ImageCacheShadowVO.class) + .eq(ImageCacheShadowVO_.primaryStorageUuid, shadowPs.uuid) + .count() + assert afterDelete == 0 : "删除本地存储后 ImageCacheShadowVO 未级联删除: expected=0 actual=${afterDelete} primaryStorageUuid=${shadowPs.uuid}" + } +}