Skip to content

<feature>[vpc-dns]: support vpc router dns records#4040

Open
zstack-robot-2 wants to merge 1 commit into
5.4.7-nexavmfrom
sync/hongbo.liu/5.4.7-nexavm
Open

<feature>[vpc-dns]: support vpc router dns records#4040
zstack-robot-2 wants to merge 1 commit into
5.4.7-nexavmfrom
sync/hongbo.liu/5.4.7-nexavm

Conversation

@zstack-robot-2
Copy link
Copy Markdown
Collaborator

Add DNS record API messages, SDK actions, schema, and i18n.

Validate domain names and private VPC IP ranges for writes.

Resolves: ZSTAC-85249

Change-Id: I56c4a542e16d4c8ca36fd32cd824f1ebce750008

sync from gitlab !9936

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

Review Change Stack

Walkthrough

新增 VPC 路由器 DNS 记录表及外键索引;实现域名校验工具并添加单元测试;在测试库加入 4 个 DNS 记录相关 DSL 方法;补充中/英文国际化提示文案。

变更内容

VPC 路由器 DNS 记录管理

层 / 文件(s) 摘要
数据库架构和约束
conf/db/upgrade/V5.4.7__schema.sql
新增 VpcRouterDnsRecordVO 表以存储 DNS 记录,包含自增主键、VPC 路由器和 HA 组外键、记录类型/域名/IP 字段、时间戳及关键索引,支持级联删除。
域名校验与单元测试
utils/src/main/java/org/zstack/utils/network/NetworkUtils.java, utils/src/test/java/org/zstack/utils/test/TestNetworkUtils.java
添加域名长度常量和 isDomainName() 方法,验证域名的总长度(≤253)和单个标签长度(≤63),并新增单元测试覆盖合法域名与多种非法输入场景。
国际化消息配置
conf/i18n/messages_en_US.properties, conf/i18n/messages_zh_CN.properties
新增中英文 i18n 消息键,覆盖域名/IPv4 格式校验、IP 私网范围校验、路由器状态校验、DNS 记录计数限制与同步失败等提示。
DNS 记录 API 测试辅助方法
testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy
在 ApiHelper DSL 中新增 4 个方法:addDnsRecordToVpcRouterremoveDnsRecordFromVpcRouterupdateDnsRecordToVpcRoutergetVpcRouterDnsRecord,支持会话设置、闭包委托与可选 ApiPath 路径追踪。

🎯 代码审查工作量评估

🎯 3 (中等) | ⏱️ ~20 分钟

诗歌

🐰 我在草丛里数记录,轻声唱,
域名与标签都排好队,整整齐齐长,
路由器的表里悄悄装下星光,
测试与文案把细节都照亮,
小兔鼓掌,代码落地成章。

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR标题完全符合要求的格式 [scope]: ,包含feature类型、vpc-dns范围,描述清晰准确且长度50字符在72字符限制内。
Description check ✅ Passed PR描述与变更集高度相关,清晰说明了添加DNS记录API消息、SDK操作、schema和国际化支持,以及域名和VPC私网IP范围验证。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sync/hongbo.liu/5.4.7-nexavm

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

Copy link
Copy Markdown

@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: 1

🤖 Prompt for all review comments with 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.

Inline comments:
In `@utils/src/test/java/org/zstack/utils/test/TestNetworkUtils.java`:
- Line 52: In TestNetworkUtils replace the Chinese-containing test string used
in the assertion so it doesn't violate encoding rules: change the assert that
calls NetworkUtils.isDomainName(...) in the TestNetworkUtils test to use a
non-ASCII but non-Chinese example (e.g. "münchen.local") to keep the
invalid-domain coverage while removing Chinese characters; update the literal
inside the assertFalse call referencing NetworkUtils.isDomainName to the chosen
sample.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: http://open.zstack.ai:20001/code-reviews/zstack-cloud.yaml (via .coderabbit.yaml)

Review profile: CHILL

Plan: Pro

Run ID: 935f6b1b-0b68-4b55-857b-aeb85352e623

📥 Commits

Reviewing files that changed from the base of the PR and between fe035a0 and a4e2fd1.

⛔ Files ignored due to path filters (11)
  • conf/i18n.json is excluded by !**/*.json
  • sdk/src/main/java/org/zstack/sdk/AddDnsRecordToVpcRouterAction.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/AddDnsRecordToVpcRouterResult.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/QueryVpcRouterDnsRecordAction.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/QueryVpcRouterDnsRecordResult.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/RemoveDnsRecordFromVpcRouterAction.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/RemoveDnsRecordFromVpcRouterResult.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/UpdateDnsRecordToVpcRouterAction.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/UpdateDnsRecordToVpcRouterResult.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/VpcRouterDnsRecordInventory.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/VpcRouterVmInventory.java is excluded by !sdk/**
📒 Files selected for processing (6)
  • conf/db/upgrade/V5.4.7__schema.sql
  • conf/i18n/messages_en_US.properties
  • conf/i18n/messages_zh_CN.properties
  • testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy
  • utils/src/main/java/org/zstack/utils/network/NetworkUtils.java
  • utils/src/test/java/org/zstack/utils/test/TestNetworkUtils.java

assertFalse(NetworkUtils.isDomainName(null));
assertFalse(NetworkUtils.isDomainName("*.app.local"));
assertFalse(NetworkUtils.isDomainName("db_prod.local"));
assertFalse(NetworkUtils.isDomainName("中文.local"));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

测试字符串包含中文,违反仓库通用编码规范。

Line 52 的 "中文.local" 建议替换为不含中文的非法域名样例(例如 "münchen.local"),既保留“非 ASCII 非法输入”覆盖,也符合规范。

💡 建议修改
-        assertFalse(NetworkUtils.isDomainName("中文.local"));
+        assertFalse(NetworkUtils.isDomainName("münchen.local"));

As per coding guidelines: "代码里不应当有中文,包括报错、注释等都应当使用正确的、无拼写错误的英文来写".

🤖 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 `@utils/src/test/java/org/zstack/utils/test/TestNetworkUtils.java` at line 52,
In TestNetworkUtils replace the Chinese-containing test string used in the
assertion so it doesn't violate encoding rules: change the assert that calls
NetworkUtils.isDomainName(...) in the TestNetworkUtils test to use a non-ASCII
but non-Chinese example (e.g. "münchen.local") to keep the invalid-domain
coverage while removing Chinese characters; update the literal inside the
assertFalse call referencing NetworkUtils.isDomainName to the chosen sample.

Comment thread conf/i18n/messages_en_US.properties Outdated
# args: msg.getDns()
dns[%s]\ is\ not\ a\ IP\ address = dns[{0}] is not a IP address

# at: src/main/java/org/zstack/vpc/VpcApiInterceptor.java:627
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Comment from shixin.ruan:

这个文件是脚本自动生成的。不要让ai修改i18n文件

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Comment from 刘洪波:

done.

Add DNS record API messages, SDK actions, schema, and i18n.

Validate domain names and private VPC IP ranges for writes.

Resolves: ZSTAC-85249

Change-Id: I56c4a542e16d4c8ca36fd32cd824f1ebce750008
@MatheMatrix MatheMatrix force-pushed the sync/hongbo.liu/5.4.7-nexavm branch from a4e2fd1 to 1066edf Compare May 22, 2026 03:45
Copy link
Copy Markdown

@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: 2

🧹 Nitpick comments (1)
testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy (1)

56086-56086: ⚡ Quick win

魔法值:字符串字面量 "apipath" 应定义为常量

根据编码规范要求避免使用魔法值,系统属性名称 "apipath" 在四个方法中重复出现,应提取为类级常量。

♻️ 建议改进
private static final String API_PATH_PROPERTY = "apipath"

// 然后在方法中使用:
if (System.getProperty(API_PATH_PROPERTY) != null) {
    // ...
}

Also applies to: 56111-56111, 56136-56136, 56163-56163

🤖 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 `@testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy` at line 56086,
Replace the repeated magic string literal "apipath" with a class-level constant
in ApiHelper (e.g., declare private static final String API_PATH_PROPERTY =
"apipath") and update all occurrences of System.getProperty("apipath") in the
file to use System.getProperty(API_PATH_PROPERTY); specifically change each
check like System.getProperty("apipath") != null in the methods where it appears
(the four occurrences shown as System.getProperty("apipath") in the diff) to
reference API_PATH_PROPERTY instead to eliminate the magic value.
🤖 Prompt for all review comments with 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.

Inline comments:
In `@conf/db/upgrade/V5.4.7__schema.sql`:
- Around line 8-9: Change the TIMESTAMP default for the createDate column so it
does not use '0000-00-00 00:00:00' or DEFAULT CURRENT_TIMESTAMP when another
TIMESTAMP (lastOpDate) uses ON UPDATE CURRENT_TIMESTAMP; update the createDate
definition to use a non-zero sentinel like '2000-01-01 00:00:00' (e.g.,
`createDate TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:00'`) and keep
lastOpDate as `TIMESTAMP ... ON UPDATE CURRENT_TIMESTAMP`, and rely on the JPA
`@PrePersist` logic in the Java entity to set the real creation timestamp.

In `@testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy`:
- Around line 56079-56179: The four methods addDnsRecordToVpcRouter,
removeDnsRecordFromVpcRouter, updateDnsRecordToVpcRouter and
getVpcRouterDnsRecord duplicate the same request/response/tracking logic;
extract the common flow into a reusable helper (e.g., executeApiAction) that
accepts an action instance, sets sessionId, applies the closure
delegate/strategy, ensures apiId via Platform.uuid, runs ApiPathTracker, calls
errorOut(action.call()) and records Test.apiPaths[action.class.name]; keep
getVpcRouterDnsRecord’s special a.conditions = a.conditions.collect {
it.toString() } before invoking the helper or provide a pre-call hook so the
conversion still happens.

---

Nitpick comments:
In `@testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy`:
- Line 56086: Replace the repeated magic string literal "apipath" with a
class-level constant in ApiHelper (e.g., declare private static final String
API_PATH_PROPERTY = "apipath") and update all occurrences of
System.getProperty("apipath") in the file to use
System.getProperty(API_PATH_PROPERTY); specifically change each check like
System.getProperty("apipath") != null in the methods where it appears (the four
occurrences shown as System.getProperty("apipath") in the diff) to reference
API_PATH_PROPERTY instead to eliminate the magic value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: http://open.zstack.ai:20001/code-reviews/zstack-cloud.yaml (via .coderabbit.yaml)

Review profile: CHILL

Plan: Pro

Run ID: b3ddddfa-4c5f-47df-b498-ddcb3f85b95f

📥 Commits

Reviewing files that changed from the base of the PR and between a4e2fd1 and 1066edf.

⛔ Files ignored due to path filters (11)
  • conf/i18n.json is excluded by !**/*.json
  • sdk/src/main/java/org/zstack/sdk/AddDnsRecordToVpcRouterAction.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/AddDnsRecordToVpcRouterResult.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/QueryVpcRouterDnsRecordAction.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/QueryVpcRouterDnsRecordResult.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/RemoveDnsRecordFromVpcRouterAction.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/RemoveDnsRecordFromVpcRouterResult.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/UpdateDnsRecordToVpcRouterAction.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/UpdateDnsRecordToVpcRouterResult.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/VpcRouterDnsRecordInventory.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/VpcRouterVmInventory.java is excluded by !sdk/**
📒 Files selected for processing (6)
  • conf/db/upgrade/V5.4.7__schema.sql
  • conf/i18n/messages_en_US.properties
  • conf/i18n/messages_zh_CN.properties
  • testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy
  • utils/src/main/java/org/zstack/utils/network/NetworkUtils.java
  • utils/src/test/java/org/zstack/utils/test/TestNetworkUtils.java
✅ Files skipped from review due to trivial changes (2)
  • conf/i18n/messages_zh_CN.properties
  • conf/i18n/messages_en_US.properties

Comment on lines +8 to +9
`createDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
`lastOpDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

修复 createDate 的默认值以避免 MySQL 5.7 兼容性问题。

根据编码规范,不应使用 DEFAULT '0000-00-00 00:00:00'。此外,根据仓库历史经验,在 MySQL 5.7 且 explicit_defaults_for_timestamp=OFF 的环境下,当表中已有一个 TIMESTAMP 列带 ON UPDATE CURRENT_TIMESTAMP(如 Line 9 的 lastOpDate)时,第二个 TIMESTAMP 列(如 Line 8 的 createDate)不能使用 DEFAULT CURRENT_TIMESTAMP,否则会触发 MySQL Error 1293。

应将 createDate 的默认值改为 '2000-01-01 00:00:00' 这样的非零哨兵值,并依赖 JPA 的 @PrePersist 在 Java 层为新记录设置真实的创建时间戳。

🔧 建议修改
-    `createDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
+    `createDate` TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:00',

Based on learnings: if a table already contains a TIMESTAMP column defined with ON UPDATE CURRENT_TIMESTAMP (e.g., lastOpDate), then 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' and rely on JPA PrePersist to set the real creation timestamp.

📝 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
`createDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
`lastOpDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
`createDate` TIMESTAMP NOT NULL DEFAULT '2000-01-01 00:00:00',
`lastOpDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00' 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/V5.4.7__schema.sql` around lines 8 - 9, Change the TIMESTAMP
default for the createDate column so it does not use '0000-00-00 00:00:00' or
DEFAULT CURRENT_TIMESTAMP when another TIMESTAMP (lastOpDate) uses ON UPDATE
CURRENT_TIMESTAMP; update the createDate definition to use a non-zero sentinel
like '2000-01-01 00:00:00' (e.g., `createDate TIMESTAMP NOT NULL DEFAULT
'2000-01-01 00:00:00'`) and keep lastOpDate as `TIMESTAMP ... ON UPDATE
CURRENT_TIMESTAMP`, and rely on the JPA `@PrePersist` logic in the Java entity to
set the real creation timestamp.

Comment on lines +56079 to +56179
def addDnsRecordToVpcRouter(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.AddDnsRecordToVpcRouterAction.class) Closure c) {
def a = new org.zstack.sdk.AddDnsRecordToVpcRouterAction()
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 removeDnsRecordFromVpcRouter(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.RemoveDnsRecordFromVpcRouterAction.class) Closure c) {
def a = new org.zstack.sdk.RemoveDnsRecordFromVpcRouterAction()
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 updateDnsRecordToVpcRouter(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.UpdateDnsRecordToVpcRouterAction.class) Closure c) {
def a = new org.zstack.sdk.UpdateDnsRecordToVpcRouterAction()
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 getVpcRouterDnsRecord(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.QueryVpcRouterDnsRecordAction.class) Closure c) {
def a = new org.zstack.sdk.QueryVpcRouterDnsRecordAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
c.resolveStrategy = Closure.OWNER_FIRST
c.delegate = a
c()

a.conditions = a.conditions.collect { it.toString() }

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())
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

严重代码重复:四个方法结构几乎完全相同

这四个方法除了 SDK Action 类型不同外,逻辑完全一致(getVpcRouterDnsRecord 仅多一行 conditions 转换)。根据编码规范要求避免代码重复,应重构为通用方法。

♻️ 建议的重构方案

提取公共逻辑到泛型方法:

private <T> def executeApiAction(T action, Closure c) {
    action.sessionId = Test.currentEnvSpec?.session?.uuid
    c.resolveStrategy = Closure.OWNER_FIRST
    c.delegate = action
    c()

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

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

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

def addDnsRecordToVpcRouter(`@DelegatesTo`(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.AddDnsRecordToVpcRouterAction.class) Closure c) {
    executeApiAction(new org.zstack.sdk.AddDnsRecordToVpcRouterAction(), c)
}

def removeDnsRecordFromVpcRouter(`@DelegatesTo`(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.RemoveDnsRecordFromVpcRouterAction.class) Closure c) {
    executeApiAction(new org.zstack.sdk.RemoveDnsRecordFromVpcRouterAction(), c)
}

def updateDnsRecordToVpcRouter(`@DelegatesTo`(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.UpdateDnsRecordToVpcRouterAction.class) Closure c) {
    executeApiAction(new org.zstack.sdk.UpdateDnsRecordToVpcRouterAction(), c)
}

def getVpcRouterDnsRecord(`@DelegatesTo`(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.QueryVpcRouterDnsRecordAction.class) Closure c) {
    def a = new org.zstack.sdk.QueryVpcRouterDnsRecordAction()
    a.sessionId = Test.currentEnvSpec?.session?.uuid
    c.resolveStrategy = Closure.OWNER_FIRST
    c.delegate = a
    c()
    a.conditions = a.conditions.collect { it.toString() }
    
    // 重用后续逻辑或再抽取
    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())
    }
}
🤖 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 `@testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy` around lines 56079
- 56179, The four methods addDnsRecordToVpcRouter, removeDnsRecordFromVpcRouter,
updateDnsRecordToVpcRouter and getVpcRouterDnsRecord duplicate the same
request/response/tracking logic; extract the common flow into a reusable helper
(e.g., executeApiAction) that accepts an action instance, sets sessionId,
applies the closure delegate/strategy, ensures apiId via Platform.uuid, runs
ApiPathTracker, calls errorOut(action.call()) and records
Test.apiPaths[action.class.name]; keep getVpcRouterDnsRecord’s special
a.conditions = a.conditions.collect { it.toString() } before invoking the helper
or provide a pre-call hook so the conversion still happens.

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