Skip to content

fix(ai): add DB migration for per-vendor GPU quota#3353

Open
zstack-robot-1 wants to merge 2 commits into5.5.6from
sync/ye.zou/fix/ZSTAC-73546
Open

fix(ai): add DB migration for per-vendor GPU quota#3353
zstack-robot-1 wants to merge 2 commits into5.5.6from
sync/ye.zou/fix/ZSTAC-73546

Conversation

@zstack-robot-1
Copy link
Collaborator

Resolves: ZSTAC-73546

Target: 5.5.6

sync from gitlab !9182

AlanJager and others added 2 commits February 9, 2026 11:07
ZSTAC-82069

Delete orphan GpuDeviceSpecVO records where the parent PciDeviceSpecVO
type is not a GPU device type. This cleans up stale data caused by
device type changes from GPU to non-GPU during ZSTAC-81489 GPU detection
refactoring.

GpuDeviceSpecVO uses @PrimaryKeyJoinColumn inheritance from PciDeviceSpecVO.
Only records with GPU device types should exist in the child table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Migrate existing container.gpu.video.ram.size QuotaVO rows to
container.gpu.video.ram.size.nvidia using INSERT IGNORE to support
backward-compatible per-vendor GPU quota rollout.

ZSTAC-73546

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Feb 13, 2026

概览

本次变更在数据库升级脚本中添加了一个新的存储过程,用于将通用的 GPU 配额记录迁移为 NVIDIA 厂商特定的配额记录,通过遍历现有配额条目并插入对应的厂商标记版本来实现数据模式转换。

变更

文件/目录 摘要
数据库升级脚本
conf/db/upgrade/V5.5.6__schema.sql
新增 MigrateGpuQuotaPerVendor() 存储过程,遍历 container.gpu.video.ram.size 配额记录并将其转换为 NVIDIA 厂商特定的配额记录(container.gpu.video.ram.size.nvidia),包含复制的身份字段、时间戳和配额值,执行后删除该过程。

代码审查工作量评估

🎯 2 (Simple) | ⏱️ ~12 分钟

🐰 数据库里有个魔法程序,
GPU 配额一声号令,
NVIDIA 的身份穿上了,
供应商之分从此明朗,
过程完毕挥手再见,
数据迁移顺利成章!✨

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (9 files):

⚔️ conf/db/upgrade/V5.5.6__schema.sql (content)
⚔️ identity/src/main/java/org/zstack/identity/QuotaUtil.java (content)
⚔️ longjob/src/main/java/org/zstack/longjob/LongJobManagerImpl.java (content)
⚔️ network/src/main/java/org/zstack/network/service/DhcpExtension.java (content)
⚔️ plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmFacadeImpl.java (content)
⚔️ plugin/flatNetworkProvider/src/main/java/org/zstack/network/service/flat/FlatUserdataBackend.java (content)
⚔️ sdk/src/main/java/org/zstack/sdk/GpuAllocateStatus.java (content)
⚔️ search/src/main/java/org/zstack/query/MysqlQueryBuilderImpl3.java (content)
⚔️ search/src/main/java/org/zstack/query/QueryFacadeImpl.java (content)

These conflicts must be resolved before merging into 5.5.6.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title follows the required format '[scope]: ' with 50 characters (under 72 limit) and accurately describes the main change of adding a DB migration for per-vendor GPU quota.
Description check ✅ Passed The pull request description references the related JIRA issue (ZSTAC-73546), specifies the target version (5.5.6), and notes the source (gitlab !9182), all of which relate to the changeset's purpose of migrating GPU quota configurations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sync/ye.zou/fix/ZSTAC-73546
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch sync/ye.zou/fix/ZSTAC-73546
  • Create stacked PR with resolved conflicts
  • Post resolved changes as copyable diffs in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@conf/db/upgrade/V5.5.6__schema.sql`:
- Around line 184-192: The DELETE should wrap identifiers in backticks and
explicitly include NULL 'type' rows; update the statement targeting
GpuDeviceSpecVO and PciDeviceSpecVO (references to `GpuDeviceSpecVO`,
`PciDeviceSpecVO`, `p`.`type`, `g`.`uuid`, `p`.`uuid`) to use backticks for all
table and column names and change the predicate to treat NULL as non-GPU (e.g.
replace the NOT IN(...) check with a condition that also matches `p`.`type` IS
NULL so rows where `p`.`type` is NULL are deleted).
- Around line 205-228: Wrap all table and column identifiers in the migration
procedure with backticks to avoid reserved-word conflicts: update the DECLARE
cur CURSOR FOR SELECT to use `QuotaVO` and backticked columns (`identityUuid`,
`identityType`, `value`, `name`), update the WHERE clause to `WHERE \`name\` =
'container.gpu.video.ram.size'`, and change the INSERT IGNORE INTO to `INSERT
IGNORE INTO \`QuotaVO\` (\`uuid\`, \`name\`, \`identityUuid\`, \`identityType\`,
\`value\`, \`lastOpDate\`, \`createDate\`) VALUES (...)` (also backtick the
literal column names such as `container.gpu.video.ram.size.nvidia` where used);
ensure every occurrence of QuotaVO and its columns in this procedure (cursor,
FETCH, INSERT) is backticked.
- Around line 199-235: Add idempotency and guard against re-creation: drop the
procedure before creating it, wrap identifiers with backticks, and change the
INSERT logic to only insert when the (name, identityUuid, identityType) tuple
does not already exist. Specifically, add DROP PROCEDURE IF EXISTS
MigrateGpuQuotaPerVendor; before CREATE PROCEDURE MigrateGpuQuotaPerVendor(),
use backticks for `QuotaVO`, `uuid`, `name`, `identityUuid`, `identityType`,
`value`, `lastOpDate`, `createDate`, and replace the INSERT IGNORE INTO QuotaVO
... VALUES(...) with an INSERT INTO `QuotaVO`
(`uuid`,`name`,`identityUuid`,`identityType`,`value`,`lastOpDate`,`createDate`)
SELECT REPLACE(UUID(),'-',''), 'container.gpu.video.ram.size.nvidia',
v_identity_uuid, v_identity_type, v_value, NOW(), NOW() FROM DUAL WHERE NOT
EXISTS (SELECT 1 FROM `QuotaVO` q WHERE
q.`name`='container.gpu.video.ram.size.nvidia' AND
q.`identityUuid`=v_identity_uuid AND q.`identityType`=v_identity_type); keep the
rest of the cursor logic and the final DROP PROCEDURE IF EXISTS call.

Comment on lines +184 to +192
DELETE g FROM GpuDeviceSpecVO g
INNER JOIN PciDeviceSpecVO p ON g.uuid = p.uuid
WHERE p.type NOT IN (
'GPU_Video_Controller',
'GPU_3D_Controller',
'GPU_Processing_Accelerators',
'GPU_Co_Processor',
'GPU_Communication_Controller'
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

DELETE 语句需要反引号并补齐 NULL 类型的清理

当前语句未对表/列名加反引号,且 NOT IN 不匹配 NULL,会导致 typeNULL 的非 GPU 行未被清理。建议补齐反引号并显式处理 NULL

🛠️ 建议修改
-DELETE g FROM GpuDeviceSpecVO g
-INNER JOIN PciDeviceSpecVO p ON g.uuid = p.uuid
-WHERE p.type NOT IN (
+DELETE g FROM `GpuDeviceSpecVO` g
+INNER JOIN `PciDeviceSpecVO` p ON g.`uuid` = p.`uuid`
+WHERE (p.`type` NOT IN (
     'GPU_Video_Controller',
     'GPU_3D_Controller',
     'GPU_Processing_Accelerators',
     'GPU_Co_Processor',
     'GPU_Communication_Controller'
-);
+) OR p.`type` IS NULL);

As per coding guidelines, 所有表名和列名必须使用反引号包裹(例如:WHERE system = 1),以避免 MySQL 8.0 / GreatSQL 保留关键字冲突导致的语法错误

🤖 Prompt for AI Agents
In `@conf/db/upgrade/V5.5.6__schema.sql` around lines 184 - 192, The DELETE should
wrap identifiers in backticks and explicitly include NULL 'type' rows; update
the statement targeting GpuDeviceSpecVO and PciDeviceSpecVO (references to
`GpuDeviceSpecVO`, `PciDeviceSpecVO`, `p`.`type`, `g`.`uuid`, `p`.`uuid`) to use
backticks for all table and column names and change the predicate to treat NULL
as non-GPU (e.g. replace the NOT IN(...) check with a condition that also
matches `p`.`type` IS NULL so rows where `p`.`type` is NULL are deleted).

Comment on lines +199 to +235
CREATE PROCEDURE MigrateGpuQuotaPerVendor()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE v_identity_uuid VARCHAR(32);
DECLARE v_identity_type VARCHAR(255);
DECLARE v_value BIGINT;
DECLARE cur CURSOR FOR
SELECT identityUuid, identityType, value
FROM QuotaVO
WHERE name = 'container.gpu.video.ram.size';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

OPEN cur;
read_loop: LOOP
FETCH cur INTO v_identity_uuid, v_identity_type, v_value;
IF done THEN
LEAVE read_loop;
END IF;

INSERT IGNORE INTO QuotaVO (uuid, name, identityUuid, identityType, value, lastOpDate, createDate)
VALUES (
REPLACE(UUID(), '-', ''),
'container.gpu.video.ram.size.nvidia',
v_identity_uuid,
v_identity_type,
v_value,
NOW(),
NOW()
);
END LOOP;
CLOSE cur;
END$$

DELIMITER ;

CALL MigrateGpuQuotaPerVendor();
DROP PROCEDURE IF EXISTS MigrateGpuQuotaPerVendor;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find QuotaVO table definition and constraints
rg -n 'CREATE TABLE.*QuotaVO|CREATE TABLE.*`QuotaVO`' -A 20 -g '*.sql'

Repository: MatheMatrix/zstack

Length of output: 1660


🏁 Script executed:

#!/bin/bash
# Search for any UNIQUE or KEY constraints related to QuotaVO
rg -n 'QuotaVO' -B 5 -A 10 -g '*.sql' | rg -A 10 'PRIMARY KEY|UNIQUE|KEY'

Repository: MatheMatrix/zstack

Length of output: 5723


🏁 Script executed:

#!/bin/bash
# Check the specific upgrade file for context
find . -name 'V5.5.6__schema.sql' -type f | head -5

Repository: MatheMatrix/zstack

Length of output: 98


🏁 Script executed:

#!/bin/bash
# Look for MigrateGpuQuotaPerVendor procedure in the upgrade file
rg -n 'MigrateGpuQuotaPerVendor' -B 5 -A 40 conf/db/upgrade/V5.5.6__schema.sql

Repository: MatheMatrix/zstack

Length of output: 1557


存储过程缺少前置删除检查,且缺乏幂等性保证

CREATE PROCEDURE 未在前置执行 DROP IF EXISTS,若升级中断后重跑会导致执行失败。同时 INSERT IGNOREuuid 采用自动生成且约束在整行上,无法确保业务逻辑的幂等性。当重复执行时,相同的 nameidentityUuididentityType 组合会被重复插入。

此外,表名和列名未使用反引号包裹,违反编码规范。

建议修改
+DROP PROCEDURE IF EXISTS MigrateGpuQuotaPerVendor;
 DELIMITER $$
 
 CREATE PROCEDURE MigrateGpuQuotaPerVendor()
 BEGIN
-    DECLARE cur CURSOR FOR
-        SELECT identityUuid, identityType, value
-        FROM QuotaVO
-        WHERE name = 'container.gpu.video.ram.size';
+    DECLARE cur CURSOR FOR
+        SELECT identityUuid, identityType, value
+        FROM `QuotaVO`
+        WHERE `name` = 'container.gpu.video.ram.size';
     DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
 
     OPEN cur;
     read_loop: LOOP
         FETCH cur INTO v_identity_uuid, v_identity_type, v_value;
         IF done THEN
             LEAVE read_loop;
         END IF;
 
-        INSERT IGNORE INTO QuotaVO (uuid, name, identityUuid, identityType, value, lastOpDate, createDate)
-        VALUES (
-            REPLACE(UUID(), '-', ''),
-            'container.gpu.video.ram.size.nvidia',
-            v_identity_uuid,
-            v_identity_type,
-            v_value,
-            NOW(),
-            NOW()
-        );
+        INSERT INTO `QuotaVO` (`uuid`, `name`, `identityUuid`, `identityType`, `value`, `lastOpDate`, `createDate`)
+        SELECT
+            REPLACE(UUID(), '-', ''),
+            'container.gpu.video.ram.size.nvidia',
+            v_identity_uuid,
+            v_identity_type,
+            v_value,
+            NOW(),
+            NOW()
+        FROM DUAL
+        WHERE NOT EXISTS (
+            SELECT 1
+            FROM `QuotaVO`
+            WHERE `name` = 'container.gpu.video.ram.size.nvidia'
+              AND `identityUuid` = v_identity_uuid
+              AND `identityType` = v_identity_type
+        );
🤖 Prompt for AI Agents
In `@conf/db/upgrade/V5.5.6__schema.sql` around lines 199 - 235, Add idempotency
and guard against re-creation: drop the procedure before creating it, wrap
identifiers with backticks, and change the INSERT logic to only insert when the
(name, identityUuid, identityType) tuple does not already exist. Specifically,
add DROP PROCEDURE IF EXISTS MigrateGpuQuotaPerVendor; before CREATE PROCEDURE
MigrateGpuQuotaPerVendor(), use backticks for `QuotaVO`, `uuid`, `name`,
`identityUuid`, `identityType`, `value`, `lastOpDate`, `createDate`, and replace
the INSERT IGNORE INTO QuotaVO ... VALUES(...) with an INSERT INTO `QuotaVO`
(`uuid`,`name`,`identityUuid`,`identityType`,`value`,`lastOpDate`,`createDate`)
SELECT REPLACE(UUID(),'-',''), 'container.gpu.video.ram.size.nvidia',
v_identity_uuid, v_identity_type, v_value, NOW(), NOW() FROM DUAL WHERE NOT
EXISTS (SELECT 1 FROM `QuotaVO` q WHERE
q.`name`='container.gpu.video.ram.size.nvidia' AND
q.`identityUuid`=v_identity_uuid AND q.`identityType`=v_identity_type); keep the
rest of the cursor logic and the final DROP PROCEDURE IF EXISTS call.

Comment on lines +205 to +228
DECLARE cur CURSOR FOR
SELECT identityUuid, identityType, value
FROM QuotaVO
WHERE name = 'container.gpu.video.ram.size';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

OPEN cur;
read_loop: LOOP
FETCH cur INTO v_identity_uuid, v_identity_type, v_value;
IF done THEN
LEAVE read_loop;
END IF;

INSERT IGNORE INTO QuotaVO (uuid, name, identityUuid, identityType, value, lastOpDate, createDate)
VALUES (
REPLACE(UUID(), '-', ''),
'container.gpu.video.ram.size.nvidia',
v_identity_uuid,
v_identity_type,
v_value,
NOW(),
NOW()
);
END LOOP;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

迁移过程内的表/列名同样需要反引号

过程里的 QuotaVO 与字段名同样未加反引号,建议按规范补齐,避免保留字冲突与跨版本兼容问题。

🛠️ 建议修改
-    DECLARE cur CURSOR FOR
-        SELECT identityUuid, identityType, value
-        FROM QuotaVO
-        WHERE name = 'container.gpu.video.ram.size';
+    DECLARE cur CURSOR FOR
+        SELECT `identityUuid`, `identityType`, `value`
+        FROM `QuotaVO`
+        WHERE `name` = 'container.gpu.video.ram.size';
...
-        INSERT IGNORE INTO QuotaVO (uuid, name, identityUuid, identityType, value, lastOpDate, createDate)
+        INSERT IGNORE INTO `QuotaVO` (`uuid`, `name`, `identityUuid`, `identityType`, `value`, `lastOpDate`, `createDate`)

As per coding guidelines, 所有表名和列名必须使用反引号包裹(例如:WHERE system = 1),以避免 MySQL 8.0 / GreatSQL 保留关键字冲突导致的语法错误

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
DECLARE cur CURSOR FOR
SELECT identityUuid, identityType, value
FROM QuotaVO
WHERE name = 'container.gpu.video.ram.size';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
read_loop: LOOP
FETCH cur INTO v_identity_uuid, v_identity_type, v_value;
IF done THEN
LEAVE read_loop;
END IF;
INSERT IGNORE INTO QuotaVO (uuid, name, identityUuid, identityType, value, lastOpDate, createDate)
VALUES (
REPLACE(UUID(), '-', ''),
'container.gpu.video.ram.size.nvidia',
v_identity_uuid,
v_identity_type,
v_value,
NOW(),
NOW()
);
END LOOP;
DECLARE cur CURSOR FOR
SELECT `identityUuid`, `identityType`, `value`
FROM `QuotaVO`
WHERE `name` = 'container.gpu.video.ram.size';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
read_loop: LOOP
FETCH cur INTO v_identity_uuid, v_identity_type, v_value;
IF done THEN
LEAVE read_loop;
END IF;
INSERT IGNORE INTO `QuotaVO` (`uuid`, `name`, `identityUuid`, `identityType`, `value`, `lastOpDate`, `createDate`)
VALUES (
REPLACE(UUID(), '-', ''),
'container.gpu.video.ram.size.nvidia',
v_identity_uuid,
v_identity_type,
v_value,
NOW(),
NOW()
);
END LOOP;
🤖 Prompt for AI Agents
In `@conf/db/upgrade/V5.5.6__schema.sql` around lines 205 - 228, Wrap all table
and column identifiers in the migration procedure with backticks to avoid
reserved-word conflicts: update the DECLARE cur CURSOR FOR SELECT to use
`QuotaVO` and backticked columns (`identityUuid`, `identityType`, `value`,
`name`), update the WHERE clause to `WHERE \`name\` =
'container.gpu.video.ram.size'`, and change the INSERT IGNORE INTO to `INSERT
IGNORE INTO \`QuotaVO\` (\`uuid\`, \`name\`, \`identityUuid\`, \`identityType\`,
\`value\`, \`lastOpDate\`, \`createDate\`) VALUES (...)` (also backtick the
literal column names such as `container.gpu.video.ram.size.nvidia` where used);
ensure every occurrence of QuotaVO and its columns in this procedure (cursor,
FETCH, INSERT) is backticked.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants