From c296180aa0bce3e07da99ae9dcc19e160580042f Mon Sep 17 00:00:00 2001 From: "hanyu.liang" Date: Fri, 3 Jul 2026 16:27:42 +0800 Subject: [PATCH] [zone]: set first created zone as default When isDefault is omitted, zone creation now enters the default-zone queue. If no zone exists, the new zone becomes default before persistence. Backfill one default zone during 5.5.28 upgrade for deployments where zones already exist but none is marked default. DBImpact Test: ZoneCase Test: SQL backfill on scratch schema Resolves: ZSTAC-75952 Change-Id: Ia4844f7a37d823508d16a74f06ec2333f50b4d07 --- .../zstack/compute/zone/ZoneManagerImpl.java | 6 +++- conf/db/upgrade/V5.5.28__schema.sql | 32 +++++++++++++++++++ .../test/integration/compute/ZoneCase.groovy | 30 +++++++++++++---- 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/compute/src/main/java/org/zstack/compute/zone/ZoneManagerImpl.java b/compute/src/main/java/org/zstack/compute/zone/ZoneManagerImpl.java index 1537ed30318..e806761229d 100755 --- a/compute/src/main/java/org/zstack/compute/zone/ZoneManagerImpl.java +++ b/compute/src/main/java/org/zstack/compute/zone/ZoneManagerImpl.java @@ -152,6 +152,10 @@ private ZoneInventory createZoneFromApiMessage(APICreateZoneMsg msg) { new SQLBatch() { @Override protected void scripts() { + if (msg.getDefault() == null && !q(ZoneVO.class).isExists()) { + finalVO.setDefault(true); + } + if (finalVO.isDefault()) { sql(ZoneVO.class) .set(ZoneVO_.isDefault, false) @@ -181,7 +185,7 @@ private void createDefaultManagementNetworkIpVersionTagIfAbsent(String zoneUuid) } private void createZone(APICreateZoneMsg msg, ReturnValueCompletion completion) { - if (msg.getDefault() == null || !msg.getDefault()) { + if (msg.getDefault() != null && !msg.getDefault()) { completion.success(createZoneFromApiMessage(msg)); return; } diff --git a/conf/db/upgrade/V5.5.28__schema.sql b/conf/db/upgrade/V5.5.28__schema.sql index b30064a2a08..cc96f27fdf0 100644 --- a/conf/db/upgrade/V5.5.28__schema.sql +++ b/conf/db/upgrade/V5.5.28__schema.sql @@ -199,6 +199,38 @@ WHERE NOT EXISTS ( AND st.tag LIKE 'managementNetwork::ipVersion::%' ); +-- ZSTAC-75952: backfill one default zone for deployments affected by zone creation without isDefault. +DROP PROCEDURE IF EXISTS backfill_default_zone_if_absent; +DELIMITER $$ +CREATE PROCEDURE backfill_default_zone_if_absent() +BEGIN + DECLARE default_zone_count BIGINT DEFAULT 0; + DECLARE first_zone_uuid VARCHAR(32) DEFAULT NULL; + + SELECT COUNT(*) INTO default_zone_count + FROM `zstack`.`ZoneVO` + WHERE `isDefault` = 1; + + IF default_zone_count = 0 THEN + SET first_zone_uuid = ( + SELECT `uuid` + FROM `zstack`.`ZoneVO` + ORDER BY `createDate` ASC, `uuid` ASC + LIMIT 1 + ); + + IF first_zone_uuid IS NOT NULL THEN + UPDATE `zstack`.`ZoneEO` + SET `isDefault` = 1 + WHERE `uuid` = first_zone_uuid; + END IF; + END IF; +END $$ +DELIMITER ; + +CALL backfill_default_zone_if_absent(); +DROP PROCEDURE IF EXISTS backfill_default_zone_if_absent; + ALTER TABLE `zstack`.`ConsoleProxyAgentVO` ADD COLUMN `consoleProxyOverriddenIpv4` varchar(255) DEFAULT NULL; ALTER TABLE `zstack`.`ConsoleProxyAgentVO` ADD COLUMN `consoleProxyOverriddenIpv6` varchar(255) DEFAULT NULL; diff --git a/test/src/test/groovy/org/zstack/test/integration/compute/ZoneCase.groovy b/test/src/test/groovy/org/zstack/test/integration/compute/ZoneCase.groovy index 67e86160548..c8a864c8c41 100644 --- a/test/src/test/groovy/org/zstack/test/integration/compute/ZoneCase.groovy +++ b/test/src/test/groovy/org/zstack/test/integration/compute/ZoneCase.groovy @@ -10,12 +10,13 @@ import org.zstack.testlib.EnvSpec import org.zstack.testlib.SubCase /** - * 1. test create zone as default zone - * 2. test batch create zone as default zone - * 3. test update zone to default zone - * 4. test batch update zone to default zone - * 5. test query default zone - * 6. test delete default zone + * 1. test first created zone defaults to default zone + * 2. test create zone as default zone + * 3. test batch create zone as default zone + * 4. test update zone to default zone + * 5. test batch update zone to default zone + * 6. test query default zone + * 7. test delete default zone */ class ZoneCase extends SubCase { EnvSpec env @@ -33,6 +34,7 @@ class ZoneCase extends SubCase { @Override void test() { env.create { + testFirstCreatedZoneDefaultsToDefaultZone() testCreateZoneAsDefaultZone() testBatchCreateZoneAsDefaultZone() testUpdateZoneToDefaultZone() @@ -48,6 +50,22 @@ class ZoneCase extends SubCase { env.delete() } + void testFirstCreatedZoneDefaultsToDefaultZone() { + ZoneInventory zone = createZone { + name = "first-zone" + description = "first-zone" + } as ZoneInventory + + assert zone.isDefault + assert Q.New(ZoneVO.class) + .eq(ZoneVO_.uuid, zone.uuid) + .eq(ZoneVO_.isDefault, true) + .isExists() + assert Q.New(ZoneVO.class) + .eq(ZoneVO_.isDefault, true) + .count() == 1 + } + void testCreateZoneAsDefaultZone() { ZoneInventory zone = createZone { name = "zone1"