Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion conf/db/upgrade/V4.7.0.4__schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,14 @@ CREATE TABLE IF NOT EXISTS `zstack`.`L2NetworkHostRefVO` (
UNIQUE KEY `ukL2NetworkHost` (`l2NetworkUuid`,`hostUuid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `zstack`.`L2NetworkClusterRefVO` ADD COLUMN `l2ProviderType` varchar(32) default NULL;
ALTER TABLE `zstack`.`L2NetworkClusterRefVO` ADD COLUMN `l2ProviderType` varchar(32) default NULL;

CREATE TABLE IF NOT EXISTS `zstack`.`SchedulerJobGroupZoneRefVO` (
`id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT,
`schedulerJobGroupUuid` varchar(32) NOT NULL COMMENT 'uuid of schedulerJobGroupUuid',
`zoneUuid` varchar(32) NOT NULL COMMENT 'uuid of zone',
`lastOpDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
`createDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
Comment on lines +37 to +38

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

时间戳默认值使用了非法的零值日期。

lastOpDatecreateDate都使用了DEFAULT '0000-00-00 00:00:00'。路径规范要求禁止使用该零值默认值,改用DEFAULT CURRENT_TIMESTAMP;但由于lastOpDate已设置ON UPDATE CURRENT_TIMESTAMP,若两列同时使用CURRENT_TIMESTAMP将在 MySQL 5.7(explicit_defaults_for_timestamp=OFF)环境下触发 Error 1293。建议让lastOpDate使用DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,而createDate改用非CURRENT_TIMESTAMP的合法哨兵值(如'2000-01-01 00:00:00')代替零值日期,避免在启用NO_ZERO_DATE的 SQL 模式下建表失败。

🔧 建议修复
-    `lastOpDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
-    `createDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
+    `lastOpDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    `createDate` timestamp NOT NULL DEFAULT '2000-01-01 00:00:00',

Based on learnings and path instructions: "Do not use DEFAULT 0000-00-00 00:00:00, use DEFAULT CURRENT_TIMESTAMP instead" 以及 "any second TIMESTAMP column (e.g., createDate) must NOT use DEFAULT CURRENT_TIMESTAMP ... Use a non-CURRENT_TIMESTAMP sentinel default such as '2000-01-01 00:00:00'".

📝 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
`lastOpDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
`createDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`lastOpDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`createDate` timestamp NOT NULL DEFAULT '2000-01-01 00:00:00',
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@conf/db/upgrade/V4.7.0.4__schema.sql` around lines 37 - 38, Update the
timestamp defaults in the schema definition: change lastOpDate to DEFAULT
CURRENT_TIMESTAMP while retaining ON UPDATE CURRENT_TIMESTAMP, and replace
createDate’s zero-date default with a valid non-CURRENT_TIMESTAMP sentinel such
as '2000-01-01 00:00:00'.

Sources: Path instructions, Learnings

CONSTRAINT `fkSchedulerJobGroupZoneRefVOSchedulerJobGroupVO` FOREIGN KEY (`schedulerJobGroupUuid`) REFERENCES SchedulerJobGroupVO (`uuid`) ON DELETE CASCADE,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Comment on lines +33 to +41

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

缺少 (schedulerJobGroupUuid, zoneUuid) 唯一约束,可能导致重复挂载记录。

表中未对schedulerJobGroupUuidzoneUuid的组合添加唯一索引,并发或重复调用挂载 API 可能插入多条重复的关联记录。

🔧 建议修复
     CONSTRAINT `fkSchedulerJobGroupZoneRefVOSchedulerJobGroupVO` FOREIGN KEY (`schedulerJobGroupUuid`) REFERENCES SchedulerJobGroupVO (`uuid`) ON DELETE CASCADE,
+    UNIQUE KEY `uk_schedulerJobGroup_zone` (`schedulerJobGroupUuid`, `zoneUuid`),
     PRIMARY KEY  (`id`)
📝 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
CREATE TABLE IF NOT EXISTS `zstack`.`SchedulerJobGroupZoneRefVO` (
`id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT,
`schedulerJobGroupUuid` varchar(32) NOT NULL COMMENT 'uuid of schedulerJobGroupUuid',
`zoneUuid` varchar(32) NOT NULL COMMENT 'uuid of zone',
`lastOpDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
`createDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
CONSTRAINT `fkSchedulerJobGroupZoneRefVOSchedulerJobGroupVO` FOREIGN KEY (`schedulerJobGroupUuid`) REFERENCES SchedulerJobGroupVO (`uuid`) ON DELETE CASCADE,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `zstack`.`SchedulerJobGroupZoneRefVO` (
`id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT,
`schedulerJobGroupUuid` varchar(32) NOT NULL COMMENT 'uuid of schedulerJobGroupUuid',
`zoneUuid` varchar(32) NOT NULL COMMENT 'uuid of zone',
`lastOpDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
`createDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
CONSTRAINT `fkSchedulerJobGroupZoneRefVOSchedulerJobGroupVO` FOREIGN KEY (`schedulerJobGroupUuid`) REFERENCES SchedulerJobGroupVO (`uuid`) ON DELETE CASCADE,
UNIQUE KEY `uk_schedulerJobGroup_zone` (`schedulerJobGroupUuid`, `zoneUuid`),
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@conf/db/upgrade/V4.7.0.4__schema.sql` around lines 33 - 41, 在创建表
SchedulerJobGroupZoneRefVO 时,为 schedulerJobGroupUuid 与 zoneUuid
添加组合唯一约束,确保同一调度任务组与区域只能存在一条关联记录;保留现有主键及外键定义不变。

2 changes: 1 addition & 1 deletion conf/db/upgrade/V4.7.0__schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -422,4 +422,4 @@ DELIMITER ;
CALL UpdateHygonClusterVmCpuModeConfig();
DROP PROCEDURE IF EXISTS UpdateHygonClusterVmCpuModeConfig;

UPDATE GlobalConfigVO set `value` = 'InfoSec' where `value` = 'infoSec' and category ='encrypt' and name = 'encrypt.driver';
UPDATE GlobalConfigVO set `value` = 'InfoSec' where `value` = 'infoSec' and category ='encrypt' and name = 'encrypt.driver';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

为升级脚本限定固定的 zstack schema。

当前 SQL 未限定表所属 schema;当升级连接未设置默认数据库,或默认数据库不是 zstack 时,语句可能失败或更新错误的表。请改为显式引用 zstack.\GlobalConfigVO``。

Based on learnings:conf/db/upgrade 下的升级脚本必须使用固定的 zstack schema 并限定表名。

建议修改
-UPDATE GlobalConfigVO set `value` = 'InfoSec' where `value` = 'infoSec' and category ='encrypt' and name = 'encrypt.driver';
+UPDATE zstack.`GlobalConfigVO` set `value` = 'InfoSec' where `value` = 'infoSec' and category ='encrypt' and name = 'encrypt.driver';
📝 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
UPDATE GlobalConfigVO set `value` = 'InfoSec' where `value` = 'infoSec' and category ='encrypt' and name = 'encrypt.driver';
UPDATE zstack.`GlobalConfigVO` set `value` = 'InfoSec' where `value` = 'infoSec' and category ='encrypt' and name = 'encrypt.driver';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@conf/db/upgrade/V4.7.0__schema.sql` at line 425, Update the GlobalConfigVO
UPDATE statement in the upgrade script to explicitly reference the fixed zstack
schema as zstack.`GlobalConfigVO`, while preserving the existing value,
category, and name conditions.

Source: Learnings

Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public Result throwExceptionIfError() {
@Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String backupStorageUuid;

@Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
@Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String instanceOfferingUuid;

@Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
Expand Down Expand Up @@ -70,6 +70,15 @@ public Result throwExceptionIfError() {
@Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.util.List dataVolumeSystemTags;

@Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.Integer cpuNum;

@Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.Long memorySize;

@Param(required = false, validValues = {"InstantStart","CreateStopped"}, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String strategy = "InstantStart";

@Param(required = false)
public java.lang.String defaultL3NetworkUuid;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ public Result throwExceptionIfError() {
@Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String backupStorageUuid;

@Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public boolean instantStart = false;

@Param(required = false)
public java.util.List systemTags;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package org.zstack.sdk;

import java.util.HashMap;
import java.util.Map;
import org.zstack.sdk.*;

public class AttachSchedulerJobGroupToZoneAction extends AbstractAction {

private static final HashMap<String, Parameter> parameterMap = new HashMap<>();

private static final HashMap<String, Parameter> nonAPIParameterMap = new HashMap<>();

public static class Result {
public ErrorCode error;
public org.zstack.sdk.AttachSchedulerJobGroupToZoneResult value;

public Result throwExceptionIfError() {
if (error != null) {
throw new ApiException(
String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details)
);
}

return this;
}
}

@Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String schedulerJobGroupUuid;

@Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String zoneUuid;

@Param(required = false)
public java.util.List systemTags;

@Param(required = false)
public java.util.List userTags;

@Param(required = false)
public String sessionId;

@Param(required = false)
public String accessKeyId;

@Param(required = false)
public String accessKeySecret;

@Param(required = false)
public String requestIp;

@NonAPIParam
public long timeout = -1;

@NonAPIParam
public long pollingInterval = -1;


private Result makeResult(ApiResult res) {
Result ret = new Result();
if (res.error != null) {
ret.error = res.error;
return ret;
}

org.zstack.sdk.AttachSchedulerJobGroupToZoneResult value = res.getResult(org.zstack.sdk.AttachSchedulerJobGroupToZoneResult.class);
ret.value = value == null ? new org.zstack.sdk.AttachSchedulerJobGroupToZoneResult() : value;

return ret;
}

public Result call() {
ApiResult res = ZSClient.call(this);
return makeResult(res);
}

public void call(final Completion<Result> completion) {
ZSClient.call(this, new InternalCompletion() {
@Override
public void complete(ApiResult res) {
completion.complete(makeResult(res));
}
});
}

protected Map<String, Parameter> getParameterMap() {
return parameterMap;
}

protected Map<String, Parameter> getNonAPIParameterMap() {
return nonAPIParameterMap;
}

protected RestInfo getRestInfo() {
RestInfo info = new RestInfo();
info.httpMethod = "POST";
info.path = "/scheduler/zone/{zoneUuid}/scheduler-job-group/{schedulerJobGroupUuid}";
info.needSession = true;
info.needPoll = true;
info.parameterName = "params";
return info;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.zstack.sdk;

import org.zstack.sdk.SchedulerJobGroupInventory;

public class AttachSchedulerJobGroupToZoneResult {
public SchedulerJobGroupInventory inventory;
public void setInventory(SchedulerJobGroupInventory inventory) {
this.inventory = inventory;
}
public SchedulerJobGroupInventory getInventory() {
return this.inventory;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package org.zstack.sdk;

import java.util.HashMap;
import java.util.Map;
import org.zstack.sdk.*;

public class DetachSchedulerJobGroupFromZoneAction extends AbstractAction {

private static final HashMap<String, Parameter> parameterMap = new HashMap<>();

private static final HashMap<String, Parameter> nonAPIParameterMap = new HashMap<>();

public static class Result {
public ErrorCode error;
public org.zstack.sdk.DetachSchedulerJobGroupFromZoneResult value;

public Result throwExceptionIfError() {
if (error != null) {
throw new ApiException(
String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details)
);
}

return this;
}
}

@Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String schedulerJobGroupUuid;

@Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String zoneUuid;

@Param(required = false)
public java.util.List systemTags;

@Param(required = false)
public java.util.List userTags;

@Param(required = false)
public String sessionId;

@Param(required = false)
public String accessKeyId;

@Param(required = false)
public String accessKeySecret;

@Param(required = false)
public String requestIp;

@NonAPIParam
public long timeout = -1;

@NonAPIParam
public long pollingInterval = -1;


private Result makeResult(ApiResult res) {
Result ret = new Result();
if (res.error != null) {
ret.error = res.error;
return ret;
}

org.zstack.sdk.DetachSchedulerJobGroupFromZoneResult value = res.getResult(org.zstack.sdk.DetachSchedulerJobGroupFromZoneResult.class);
ret.value = value == null ? new org.zstack.sdk.DetachSchedulerJobGroupFromZoneResult() : value;

return ret;
}

public Result call() {
ApiResult res = ZSClient.call(this);
return makeResult(res);
}

public void call(final Completion<Result> completion) {
ZSClient.call(this, new InternalCompletion() {
@Override
public void complete(ApiResult res) {
completion.complete(makeResult(res));
}
});
}

protected Map<String, Parameter> getParameterMap() {
return parameterMap;
}

protected Map<String, Parameter> getNonAPIParameterMap() {
return nonAPIParameterMap;
}

protected RestInfo getRestInfo() {
RestInfo info = new RestInfo();
info.httpMethod = "DELETE";
info.path = "/scheduler/zone/{zoneUuid}/scheduler-job-group/{schedulerJobGroupUuid}";
info.needSession = true;
info.needPoll = true;
info.parameterName = "";
return info;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.zstack.sdk;

import org.zstack.sdk.SchedulerJobGroupInventory;

public class DetachSchedulerJobGroupFromZoneResult {
public SchedulerJobGroupInventory inventory;
public void setInventory(SchedulerJobGroupInventory inventory) {
this.inventory = inventory;
}
public SchedulerJobGroupInventory getInventory() {
return this.inventory;
}

}
51 changes: 51 additions & 0 deletions testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -47843,5 +47843,56 @@ abstract class ApiHelper {
}
}

def attachSchedulerJobGroupToZone(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.AttachSchedulerJobGroupToZoneAction.class) Closure c) {
def a = new org.zstack.sdk.AttachSchedulerJobGroupToZoneAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
c.resolveStrategy = Closure.OWNER_FIRST
c.delegate = a
c()


if (System.getProperty("apipath") != null) {
if (a.apiId == null) {
a.apiId = Platform.uuid
}

def tracker = new ApiPathTracker(a.apiId)
def out = errorOut(a.call())
def path = tracker.getApiPath()
if (!path.isEmpty()) {
Test.apiPaths[a.class.name] = path.join(" --->\n")
}

return out
} else {
return errorOut(a.call())
}
}

def detachSchedulerJobGroupFromZone(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.DetachSchedulerJobGroupFromZoneAction.class) Closure c) {
def a = new org.zstack.sdk.DetachSchedulerJobGroupFromZoneAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
c.resolveStrategy = Closure.OWNER_FIRST
c.delegate = a
c()


if (System.getProperty("apipath") != null) {
if (a.apiId == null) {
a.apiId = Platform.uuid
}

def tracker = new ApiPathTracker(a.apiId)
def out = errorOut(a.call())
def path = tracker.getApiPath()
if (!path.isEmpty()) {
Test.apiPaths[a.class.name] = path.join(" --->\n")
}

return out
} else {
return errorOut(a.call())
}
}

}