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',
Comment on lines +35 to +36

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) 可以重复;重试或并发执行 attach 时会插入多条相同关系,导致查询和 detach 语义不确定。

     `createDate` ...,
+    UNIQUE KEY `ukSchedulerJobGroupZoneRef` (`schedulerJobGroupUuid`, `zoneUuid`),
     CONSTRAINT ...

Also applies to: 40-40

🤖 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 35 - 36, 在该表的建表定义中为
schedulerJobGroupUuid 和 zoneUuid 增加联合唯一约束,确保同一绑定关系只能存在一条记录;同时在对应的升级脚本位置保持一致约束定义。

`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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="conf/db/upgrade/V4.7.0.4__schema.sql"

echo "== file exists =="
git ls-files "$file"

echo
echo "== line count =="
wc -l "$file"

echo
echo "== relevant excerpt =="
sed -n '1,120p' "$file"

echo
echo "== search for same table / historical backfill / zero-date usage =="
rg -n "lastOpDate|createDate|0000-00-00|CURRENT_TIMESTAMP|ON UPDATE CURRENT_TIMESTAMP|CREATE TABLE|ALTER TABLE" conf/db/upgrade -S

Repository: MatheMatrix/zstack

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="conf/db/upgrade/V4.7.0.4__schema.sql"

echo "== target excerpt =="
nl -ba "$file" | sed -n '1,120p'

echo
echo "== nearby upgrade files mentioning the same columns =="
rg -n "lastOpDate|createDate|0000-00-00|CURRENT_TIMESTAMP|ON UPDATE CURRENT_TIMESTAMP" conf/db/upgrade/V4.7.0*.sql conf/db/upgrade/V4.6*.sql conf/db/upgrade/V4.5*.sql -S

echo
echo "== table creation / historical backfill markers in target file =="
rg -n "CREATE TABLE|INSERT INTO|UPDATE |ALTER TABLE|PROCEDURE|FUNCTION|BEGIN|END" "$file" -S

Repository: MatheMatrix/zstack

Length of output: 217


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="conf/db/upgrade/V4.7.0.4__schema.sql"

python3 - <<'PY'
from pathlib import Path
p = Path("conf/db/upgrade/V4.7.0.4__schema.sql")
print("exists:", p.exists())
print("lines:", sum(1 for _ in p.open()))
print("== target excerpt ==")
for i, line in enumerate(p.open(), 1):
    if i <= 120:
        print(f"{i:4d}: {line.rstrip()}")
PY

echo
echo "== exact matches in target file =="
rg -n "lastOpDate|createDate|0000-00-00|CURRENT_TIMESTAMP|ON UPDATE CURRENT_TIMESTAMP|CREATE TABLE|ALTER TABLE|INSERT INTO|PROCEDURE|FUNCTION" "$file" -S

echo
echo "== nearby version scripts in same area =="
rg -n "0000-00-00|CURRENT_TIMESTAMP|ON UPDATE CURRENT_TIMESTAMP" conf/db/upgrade/V4.7*.sql conf/db/upgrade/V4.6*.sql conf/db/upgrade/V4.5*.sql -S

Repository: MatheMatrix/zstack

Length of output: 11815


将零日期默认值改成当前时间默认值。
createDatelastOpDate 这里都还在用 0000-00-00 00:00:00,严格 SQL 模式下会直接失败;改成 createDate DEFAULT CURRENT_TIMESTAMPlastOpDate DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

🤖 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
createDate and lastOpDate column definitions in the schema migration to use
DEFAULT CURRENT_TIMESTAMP instead of the zero-date default; preserve ON UPDATE
CURRENT_TIMESTAMP for lastOpDate.

Sources: Path instructions, Learnings

CONSTRAINT `fkSchedulerJobGroupZoneRefVOSchedulerJobGroupVO` FOREIGN KEY (`schedulerJobGroupUuid`) REFERENCES SchedulerJobGroupVO (`uuid`) ON DELETE CASCADE,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2 changes: 2 additions & 0 deletions sdk/src/main/java/SourceClassMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ public class SourceClassMap {
put("org.zstack.header.scheduler.SchedulerJobGroupInventory", "org.zstack.sdk.SchedulerJobGroupInventory");
put("org.zstack.header.scheduler.SchedulerJobGroupJobRefInventory", "org.zstack.sdk.SchedulerJobGroupJobRefInventory");
put("org.zstack.header.scheduler.SchedulerJobGroupSchedulerTriggerRefInventory", "org.zstack.sdk.SchedulerJobGroupSchedulerTriggerRefInventory");
put("org.zstack.header.scheduler.SchedulerJobGroupZoneRefInventory", "org.zstack.sdk.SchedulerJobGroupZoneRefInventory");
put("org.zstack.header.scheduler.SchedulerJobHistoryInventory", "org.zstack.sdk.SchedulerJobHistoryInventory");
put("org.zstack.header.scheduler.SchedulerJobInventory", "org.zstack.sdk.SchedulerJobInventory");
put("org.zstack.header.scheduler.SchedulerJobSchedulerTriggerInventory", "org.zstack.sdk.SchedulerJobSchedulerTriggerInventory");
Expand Down Expand Up @@ -1094,6 +1095,7 @@ public class SourceClassMap {
put("org.zstack.sdk.SchedulerJobGroupInventory", "org.zstack.header.scheduler.SchedulerJobGroupInventory");
put("org.zstack.sdk.SchedulerJobGroupJobRefInventory", "org.zstack.header.scheduler.SchedulerJobGroupJobRefInventory");
put("org.zstack.sdk.SchedulerJobGroupSchedulerTriggerRefInventory", "org.zstack.header.scheduler.SchedulerJobGroupSchedulerTriggerRefInventory");
put("org.zstack.sdk.SchedulerJobGroupZoneRefInventory", "org.zstack.header.scheduler.SchedulerJobGroupZoneRefInventory");
put("org.zstack.sdk.SchedulerJobHistoryInventory", "org.zstack.header.scheduler.SchedulerJobHistoryInventory");
put("org.zstack.sdk.SchedulerJobInventory", "org.zstack.header.scheduler.SchedulerJobInventory");
put("org.zstack.sdk.SchedulerJobSchedulerTriggerInventory", "org.zstack.header.scheduler.SchedulerJobSchedulerTriggerInventory");
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.SchedulerJobGroupZoneRefInventory;

public class AttachSchedulerJobGroupToZoneResult {
public SchedulerJobGroupZoneRefInventory inventory;
public void setInventory(SchedulerJobGroupZoneRefInventory inventory) {
this.inventory = inventory;
}
public SchedulerJobGroupZoneRefInventory 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;
}

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



public class SchedulerJobGroupZoneRefInventory {

public java.lang.Long id;
public void setId(java.lang.Long id) {
this.id = id;
}
public java.lang.Long getId() {
return this.id;
}

public java.lang.String schedulerJobGroupUuid;
public void setSchedulerJobGroupUuid(java.lang.String schedulerJobGroupUuid) {
this.schedulerJobGroupUuid = schedulerJobGroupUuid;
}
public java.lang.String getSchedulerJobGroupUuid() {
return this.schedulerJobGroupUuid;
}

public java.lang.String zoneUuid;
public void setZoneUuid(java.lang.String zoneUuid) {
this.zoneUuid = zoneUuid;
}
public java.lang.String getZoneUuid() {
return this.zoneUuid;
}

public java.sql.Timestamp createDate;
public void setCreateDate(java.sql.Timestamp createDate) {
this.createDate = createDate;
}
public java.sql.Timestamp getCreateDate() {
return this.createDate;
}

public java.sql.Timestamp lastOpDate;
public void setLastOpDate(java.sql.Timestamp lastOpDate) {
this.lastOpDate = lastOpDate;
}
public java.sql.Timestamp getLastOpDate() {
return this.lastOpDate;
}

}
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())
}
}

}