-
Notifications
You must be signed in to change notification settings - Fork 0
<fix>[.gitconfig]: support ZCF project #3216
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feature-zcf-v0.1
Are you sure you want to change the base?
Conversation
Resolves: ZCF-19 Change-Id: I77636f62676b6e697975786b6c77796b706e7861
概览该 PR 引入了外部服务配置的完整生命周期管理系统,包括 CRUD 操作的新 API 端点、相应的消息和事件类、数据库持久化层以及跨管理节点的配置传播机制。同时扩展了 ExternalService 接口并更新了相关实现。 变更清单
时序图sequenceDiagram
participant Client as 客户端
participant API as API 处理器
participant Manager as ExternalServiceManager
participant DB as 数据库
participant NodeApply as 节点应用
participant Service as 外部服务实例
Client->>API: APIAddExternalServiceConfigurationMsg
API->>Manager: 处理配置创建请求
Manager->>DB: 保存 ExternalServiceConfigurationVO
DB-->>Manager: 返回配置记录
Manager->>NodeApply: 触发 ApplyExternalServiceConfiguration
loop 对每个管理节点
NodeApply->>Service: ApplyExternalServiceConfigurationMsg
Service->>Service: externalConfig(serviceType)
Service-->>NodeApply: ApplyExternalServiceConfigurationReply
end
NodeApply->>Manager: 汇总节点应用结果
Manager->>Client: APIAddExternalServiceConfigurationEvent (成功/失败)
Client->>API: APIUpdateExternalServiceConfigurationMsg
API->>Manager: 处理配置更新请求
Manager->>DB: 更新 ExternalServiceConfigurationVO
Manager->>NodeApply: 触发跨节点应用
NodeApply-->>Manager: 返回聚合结果
Manager->>Client: APIUpdateExternalServiceConfigurationEvent
Client->>API: APIDeleteExternalServiceConfigurationMsg
API->>Manager: 处理配置删除请求
Manager->>DB: 删除 ExternalServiceConfigurationVO
Manager->>NodeApply: 通知节点清除配置
NodeApply-->>Manager: 确认完成
Manager->>Client: APIDeleteExternalServiceConfigurationEvent
代码审查工作量估计🎯 4 (复杂) | ⏱️ ~60 分钟 诗
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 error, 1 warning)
✅ Passed checks (1 passed)
✨ Finishing touches
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 16
🤖 Fix all issues with AI agents
In
`@core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java`:
- Around line 194-217: The createExternalServiceConfiguration method persists
ExternalServiceConfigurationVO via dbf.persistAndRefresh and then calls
applyExternalServiceConfigurationToAllNodes; if that propagation fails the DB
record is left inconsistent—modify createExternalServiceConfiguration to add a
compensation rollback on failure (e.g., delete or mark inactive the persisted
ExternalServiceConfigurationVO) inside the ReturnValueCompletion.fail path, or
wrap the persist+propagate in a transactional/atomic flow so the DB persist is
rolled back when applyExternalServiceConfigurationToAllNodes reports an error;
apply the analogous compensation in deleteExternalServiceConfiguration (recreate
or restore the deleted ExternalServiceConfigurationVO on propagation failure) so
both methods ensure consistency between the DB and multi-node propagation.
- Line 203: Remove the stray extra semicolon after the call to
ExternalServiceConfigurationInventory.valueOf(configurationVO); — locate the
statement using ExternalServiceConfigurationInventory.valueOf(configurationVO)
in ExternalServiceManagerImpl and delete the duplicate semicolon so the line
ends with a single semicolon.
- Around line 406-415: The loop in regenerateExternalServiceConfiguration may
throw NPE because service.getServiceType() can be null; change the equality
check to a null-safe comparison (e.g. use
Objects.equals(service.getServiceType(), serviceType) or first check for null)
when matching service types, ensuring you import java.util.Objects if used; keep
the rest of the logic (calling service.externalConfig(serviceType) and
completion.success/fail) unchanged and reference ExternalService,
regenerateExternalServiceConfiguration, services, getServiceType,
externalConfig, and completion.
- Around line 253-262: In updateExternalServiceConfiguration, guard against
dbf.findByUuid(...) returning null and avoid blindly calling
vo.setDescription(...) — if vo is null, fail the completion with an appropriate
error (do not proceed to set evt); also only update fields that are provided
(e.g., call vo.setDescription(...) only when msg.getDescription() is non-null)
before calling dbf.updateAndRefresh(vo) and returning
ExternalServiceConfigurationInventory.valueOf(vo).
- Around line 356-365: The error handling in the WhileDoneCompletion done
callback is using errorCodeList when it should surface the actual per-thread
error stored in errorCode[0]; update the done(ErrorCodeList errorCodeList) logic
in the WhileDoneCompletion anonymous class so that when errorCode[0] != null you
call trigger.fail(errorCode[0]) (or build an ErrorCodeList that contains
errorCode[0]) instead of passing errorCodeList, and ensure the
allDone/whileCompletion invocation still supplies a non-null error list only
when appropriate.
- Around line 241-244: Sync signature is inconsistent:
APIAddExternalServiceConfigurationMsg uses msg.getExternalServiceType() while
APIUpdateExternalServiceConfigurationMsg and
APIDeleteExternalServiceConfigurationMsg use msg.getUuid(), causing mismatched
mutex granularity; fix by making getSyncSignature for create/update/delete use
the same serviceType-based key. Either add an externalServiceType field to
APIUpdateExternalServiceConfigurationMsg and
APIDeleteExternalServiceConfigurationMsg and return
String.format("create-update-delete-external-service-configuration-%s",
msg.getExternalServiceType()) in getSyncSignature, or if you cannot change the
API messages, fetch the ExternalServiceConfigurationVO by msg.getUuid() inside
ExternalServiceManagerImpl and derive the serviceType to build the sync
signature; update the getSyncSignature implementations accordingly (refer to
getSyncSignature, APIAddExternalServiceConfigurationMsg,
APIUpdateExternalServiceConfigurationMsg,
APIDeleteExternalServiceConfigurationMsg, and ExternalServiceConfigurationVO).
In
`@header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationEventDoc_zh_cn.groovy`:
- Line 8: Replace the placeholder title and empty/null descriptions in
APIAddExternalServiceConfigurationEventDoc_zh_cn.groovy: change the title line
from "在这里输入结构的名称" to a meaningful Chinese title like "添加外部服务配置事件"; update the
inventory field's desc (the line currently `desc "null"`) to a clear description
explaining the inventory object's purpose (e.g., 描述返回的外部服务配置条目,包括其字段和含义); and
populate the success field's desc (currently `desc ""`) with a concise
explanation such as "操作是否成功,true 表示成功,false 表示失败". Ensure you edit the lines
that set title and the desc values for the inventory and success fields in this
Groovy doc class.
In
`@header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsg.java`:
- Around line 53-54: 实现 APIAddExternalServiceConfigurationMsg.audit 方法,不能返回
null;当 rsp 是 APIAddExternalServiceConfigurationEvent 且事件成功时,从事件的 inventory
中取出新创建资源的 UUID(例如 ((APIAddExternalServiceConfigurationEvent)
rsp).getInventory().getUuid())并返回包含该 UUID 和资源类型的 Result;参照
APIDeleteExternalServiceConfigurationMsg 和
APIUpdateExternalServiceConfigurationMsg 的实现风格来构造并返回 Result,确保在事件为空或失败时返回 null
或合适的空结果。
In
`@header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationEventDoc_zh_cn.groovy`:
- Line 7: 标题和描述占位符未替换:将 title 字段中的占位符 "在这里输入结构的名称" 替换为该文档对应的实际结构名(例如
APIDeleteExternalServiceConfigurationEvent 的中文名称),并为 desc 字段填写对 success
字段的简短说明;同时在文档中补充 success 字段的描述文本(说明 success 表示操作是否成功及其返回值含义),更新位于
APIDeleteExternalServiceConfigurationEventDoc_zh_cn.groovy 中的 title、desc 和
success 描述以反映真实语义。
In
`@header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationMsgDoc_zh_cn.groovy`:
- Around line 5-63: The API docs for APIDeleteExternalServiceConfigurationMsg
are left as placeholders—replace the title and desc strings and the empty
request desc with meaningful text: set title to "Delete External Service
Configuration", write a short overall API description under doc.desc, add a
concise request-level description under rest.request.desc, and expand each
param's desc (uuid, deleteMode, systemTags, userTags) to clearly explain
purpose, allowed values (e.g., deleteMode: "Permissive|Enforcing"), location,
and any constraints so the APIDeleteExternalServiceConfigurationMsg.class
documentation is readable and complete.
In
`@header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationReplyDoc_zh_cn.groovy`:
- Around line 6-23: Update the response documentation in the doc block: replace
the placeholder title value in title with a meaningful Chinese title for the
response structure, replace the ref.inventory desc (currently "null") with a
clear Chinese description of what inventories contains (e.g., list of
ExternalServiceConfigurationInventory entries and their purpose), and add a
concise desc for the field block success (e.g., whether the query succeeded).
Edit the doc block that includes title, ref { name "inventories" ... clz
ExternalServiceConfigurationInventory.class }, and field { name "success" ... }
so the three descriptions are informative and localized.
In
`@header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationMsg.java`:
- Around line 25-26: The description field in
APIUpdateExternalServiceConfigurationMsg is currently annotated with `@APIParam`
(making it required) but should be optional to allow partial updates; update the
annotation on the private String description field in class
APIUpdateExternalServiceConfigurationMsg to `@APIParam`(required = false) so it
matches the optional behavior of APIAddExternalServiceConfigurationMsg and
permits callers to omit description when updating.
In
`@header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationMsgDoc_zh_cn.groovy`:
- Line 10: Replace the placeholder description strings in
APIUpdateExternalServiceConfigurationMsgDoc_zh_cn.groovy (the desc
"""在这里填写API描述""" occurrences) with a meaningful Chinese API description that
explains the purpose, parameters, behavior and effects of the API; update both
occurrences (line ~10 and ~20) so the doc accurately describes
APIUpdateExternalServiceConfiguration (what it updates, required fields, side
effects and expected responses) and remove the placeholder text.
In
`@header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationInventory.java`:
- Around line 23-31: The valueOf method in ExternalServiceConfigurationInventory
fails to copy the description field from ExternalServiceConfigurationVO, causing
data loss; update the
ExternalServiceConfigurationInventory.valueOf(ExternalServiceConfigurationVO vo)
implementation to set the description by reading vo.getDescription() and calling
inv.setDescription(...), ensuring description is included alongside uuid,
serviceType, configuration, createDate, and lastOpDate.
In
`@header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationVO_.java`:
- Around line 17-18: The metamodel fields createDate and lastOpDate in
ExternalServiceConfigurationVO_ use the wrong generic type (PluginDriverVO);
update their SingularAttribute generic parameter to
ExternalServiceConfigurationVO so the declarations read
SingularAttribute<ExternalServiceConfigurationVO, Timestamp> createDate and
lastOpDate, ensuring JPA Criteria queries match the actual entity type in the
ExternalServiceConfigurationVO_ class.
In `@test/src/test/resources/zstack.properties`:
- Around line 2-4: Replace the hard-coded DB.url/DB.user/DB.password values so
tests don’t embed a fixed internal IP, missing DB name, or secrets: update the
DB.url property to point to a local/default JDBC URL that includes the database
name (e.g., jdbc:mysql://localhost:3306/zstack) and remove the plaintext
DB.password from the checked-in file; instead read DB.password (and optionally
DB.user) from environment variables or a local untracked override file so
DB.url, DB.user and DB.password properties are configurable at runtime.
🧹 Nitpick comments (17)
core/src/main/java/org/zstack/core/externalservice/ExternalService.java (1)
20-22: 为新增接口方法补充 Javadoc,明确语义与参数约束。建议说明
serviceType的取值范围、是否允许空值,以及externalConfig的预期行为,便于调用方理解与生成文档。根据编码规范。🛠️ 建议修正
+ /** + * `@return` the external service type identifier. + */ String getServiceType(); + /** + * Apply external configuration for the given service type. + * + * `@param` serviceType the service type identifier, must not be null or blank. + */ void externalConfig(String serviceType);externalservice/src/main/java/org/zstack/externalservice/cronjob/CronJobImpl.java (2)
37-40: 用常量替代魔法字符串,减少重复与拼写风险。建议提取
CronJob为private static final常量,避免后续多处硬编码。
113-114: 空实现可能让调用方误以为配置已生效,请确认预期。如果 CronJob 不支持外部配置,建议显式记录/拒绝(日志或异常)以避免静默失败;若确实需要配置,需补全实现。请确认需求与调用链期望。
core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java (1)
369-373: TODO 注释:rollback 方法中的清理逻辑未实现。
rollback方法中有 TODO 注释表明需要实现外部配置的清理逻辑,但目前为空实现。这可能导致在流程失败回滚时资源无法正确清理。需要我帮助实现 rollback 逻辑或创建一个 issue 来跟踪此任务吗?
header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsgDoc_zh_cn.groovy (1)
10-11: 文档占位符未填写完整
desc """在这里填写API描述"""应当填写具体的 API 描述信息,以便生成完整的 API 文档。同样,Lines 27 和 37 的externalServiceType和configuration字段描述也为空,建议补充。header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationMsgDoc_zh_cn.groovy (1)
11-11: 文档占位符未填写API 描述占位符
在这里填写API描述应替换为实际的 API 功能描述。header/src/main/java/org/zstack/header/core/external/service/ApplyExternalServiceConfigurationReply.java (1)
10-11: 字段命名value含义不明确根据编码规范,命名应尽量用完整的单词组合表达意图。
value过于泛化,建议使用更具描述性的名称,如configurationValue或appliedConfiguration,以便代码自解释。♻️ 建议修改
public class ApplyExternalServiceConfigurationReply extends MessageReply { private String managementNodeUuid; - private String value; + private String configurationValue; - public String getValue() { - return value; + public String getConfigurationValue() { + return configurationValue; } - public void setValue(String value) { - this.value = value; + public void setConfigurationValue(String configurationValue) { + this.configurationValue = configurationValue; } }header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationEventDoc_zh_cn.groovy (2)
8-8: 文档标题占位符未填写
title "在这里输入结构的名称"应替换为实际的结构名称,如"UpdateExternalServiceConfigurationEvent",与其他同类文档保持一致。
13-13:inventory引用的描述为 "null"
desc "null"应替换为有意义的描述,说明该 inventory 字段的用途。header/src/main/java/org/zstack/header/core/external/service/ApplyExternalConfigurationResult.java (1)
35-38:setErrorCode方法存在副作用此 setter 会将
success设为false,但如果调用者之后调用setSuccess(true),会导致状态不一致(有 errorCode 但 success 为 true)。建议考虑以下方案之一:
- 将
isSuccess()改为计算属性:return errorCode == null;- 或者移除
setSuccess()方法,仅通过setErrorCode来控制成功状态♻️ 方案一:使用计算属性
- private boolean success = true; - - public boolean isSuccess() { - return success; - } - - public void setSuccess(boolean success) { - this.success = success; - } + public boolean isSuccess() { + return errorCode == null; + } public void setErrorCode(ErrorCode errorCode) { - this.success = false; this.errorCode = errorCode; }header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationEvent.java (1)
22-27: 建议在__example__中补充示例字段为生成的 API 文档提供更完整的示例,建议补充
serviceType/configuration等常用字段。♻️ 建议补全示例字段
public static APIUpdateExternalServiceConfigurationEvent __example__() { APIUpdateExternalServiceConfigurationEvent event = new APIUpdateExternalServiceConfigurationEvent(); ExternalServiceConfigurationInventory inv = new ExternalServiceConfigurationInventory(); inv.setUuid(uuid()); + inv.setServiceType("Prometheus2"); + inv.setConfiguration("{}"); event.setInventory(inv); return event; }header/src/main/java/org/zstack/header/core/external/service/ApplyExternalServiceConfigurationMsg.java (1)
12-17: 建议对serviceType做 trim/空值保护来自消息的字符串可能包含空格或换行,建议在 setter(或拦截器)中统一 trim/空值处理,避免服务类型匹配失败。As per coding guidelines, ...
♻️ 可选实现
public void setServiceType(String serviceType) { - this.serviceType = serviceType; + this.serviceType = serviceType == null ? null : serviceType.trim(); }header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationVO_.java (1)
3-3: 移除无用的导入修复上述类型错误后,
PluginDriverVO导入将不再需要,应当移除。♻️ 修复建议
-import org.zstack.header.core.external.plugin.PluginDriverVO;header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsg.java (1)
15-20: REST 路径建议使用复数形式根据编码规范,针对资源的 API 路径应使用复数形式。当前路径
/external/service/configuration建议改为/external/service/configurations。注意:如果修改此路径,需要同步更新其他相关 API(Update、Delete、Query)的路径以保持一致性。
header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationVO.java (2)
21-22: 建议为configuration字段添加列长度或使用@Lob注解根据
APIAddExternalServiceConfigurationMsg中的定义,configuration字段最大长度为 65535 字符。默认的@Column注解可能会导致数据库列长度不足。建议使用@Lob注解或指定columnDefinition来支持大文本存储。♻️ 修复建议
`@Column` + `@Lob` private String configuration;或者指定列定义:
- `@Column` + `@Column`(columnDefinition = "TEXT") private String configuration;请确认数据库 schema 升级脚本 (V5.4.6__schema.sql) 中
configuration列的定义是否与实体映射一致。
23-24: 建议为description字段指定列长度
APIAddExternalServiceConfigurationMsg中定义description最大长度为 2048,建议在 VO 中也明确指定列长度以保持一致性。♻️ 修复建议
- `@Column` + `@Column`(length = 2048) private String description;header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationInventory.java (1)
33-39: 可选优化:使用 Stream 简化批量转换可以考虑使用 Java Stream 使代码更简洁。
♻️ 重构建议
public static List<ExternalServiceConfigurationInventory> valueOf(Collection<ExternalServiceConfigurationVO> vos) { - List<ExternalServiceConfigurationInventory> invs = new ArrayList<ExternalServiceConfigurationInventory>(); - for (ExternalServiceConfigurationVO vo : vos) { - invs.add(valueOf(vo)); - } - return invs; + return vos.stream() + .map(ExternalServiceConfigurationInventory::valueOf) + .collect(Collectors.toList()); }需要添加导入:
import java.util.stream.Collectors;
core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java
Show resolved
Hide resolved
core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java
Outdated
Show resolved
Hide resolved
| @Override | ||
| public String getSyncSignature() { | ||
| return String.format("create-update-delete-external-service-configuration-%s", msg.getUuid()); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, let's find and examine the ExternalServiceManagerImpl.java file
find . -name "ExternalServiceManagerImpl.java" -type fRepository: MatheMatrix/zstack
Length of output: 146
🏁 Script executed:
#!/bin/bash
# Search for all sync signature implementations in the file
rg "getSyncSignature" --type java -A 2 -B 2Repository: MatheMatrix/zstack
Length of output: 50375
🏁 Script executed:
#!/bin/bash
# Look for the three API message classes mentioned
rg "APIAddExternalServiceConfigurationMsg|APIUpdateExternalServiceConfigurationMsg|APIDeleteExternalServiceConfigurationMsg" --type java -lRepository: MatheMatrix/zstack
Length of output: 537
🏁 Script executed:
#!/bin/bash
# Read the ExternalServiceManagerImpl.java file to find all sync signature implementations
wc -l ./core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.javaRepository: MatheMatrix/zstack
Length of output: 150
🏁 Script executed:
#!/bin/bash
# Read the specific file around the mentioned lines
cat -n ./core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java | sed -n '220,280p'Repository: MatheMatrix/zstack
Length of output: 2911
🏁 Script executed:
#!/bin/bash
# Search for all handlers in ExternalServiceManagerImpl.java
rg "APIAddExternalServiceConfigurationMsg|APIUpdateExternalServiceConfigurationMsg|APIDeleteExternalServiceConfigurationMsg" ./core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java -A 20 | head -100Repository: MatheMatrix/zstack
Length of output: 4513
🏁 Script executed:
#!/bin/bash
# Get the full content of the Add handler to find its sync signature
cat -n ./core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java | sed -n '150,200p'Repository: MatheMatrix/zstack
Length of output: 2588
🏁 Script executed:
#!/bin/bash
# Get the Delete handler and its sync signature
cat -n ./core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java | sed -n '264,310p'Repository: MatheMatrix/zstack
Length of output: 2301
🏁 Script executed:
#!/bin/bash
# Search for all three handlers' sync signatures explicitly
rg "getSyncSignature\(\)" ./core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java -B 10 -A 2 | head -80Repository: MatheMatrix/zstack
Length of output: 1504
🏁 Script executed:
#!/bin/bash
# Check the message class definitions to verify they have the required fields
cat ./header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsg.java | head -50Repository: MatheMatrix/zstack
Length of output: 1556
🏁 Script executed:
#!/bin/bash
# Check update message
cat ./header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationMsg.java | head -50Repository: MatheMatrix/zstack
Length of output: 1601
🏁 Script executed:
#!/bin/bash
# Check delete message
cat ./header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationMsg.java | head -50Repository: MatheMatrix/zstack
Length of output: 1470
🏁 Script executed:
#!/bin/bash
# Verify the ExternalServiceConfigurationVO structure to confirm serviceType is available
rg "class ExternalServiceConfigurationVO" -A 30 --type javaRepository: MatheMatrix/zstack
Length of output: 5029
同步签名不一致,可能导致并发问题。
验证确认:
APIAddExternalServiceConfigurationMsg使用msg.getExternalServiceType()作为同步签名APIUpdateExternalServiceConfigurationMsg和APIDeleteExternalServiceConfigurationMsg使用msg.getUuid()作为同步签名
这会导致同步粒度不一致:
- 同一
serviceType的添加操作互斥 - 同一
uuid的更新/删除操作互斥 - 但添加和更新/删除操作可能无法互斥,造成竞态条件
建议统一使用 serviceType 作为同步粒度(需在更新/删除消息中添加 serviceType 字段,或在同步签名中从数据库获取)。
🤖 Prompt for AI Agents
In
`@core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java`
around lines 241 - 244, Sync signature is inconsistent:
APIAddExternalServiceConfigurationMsg uses msg.getExternalServiceType() while
APIUpdateExternalServiceConfigurationMsg and
APIDeleteExternalServiceConfigurationMsg use msg.getUuid(), causing mismatched
mutex granularity; fix by making getSyncSignature for create/update/delete use
the same serviceType-based key. Either add an externalServiceType field to
APIUpdateExternalServiceConfigurationMsg and
APIDeleteExternalServiceConfigurationMsg and return
String.format("create-update-delete-external-service-configuration-%s",
msg.getExternalServiceType()) in getSyncSignature, or if you cannot change the
API messages, fetch the ExternalServiceConfigurationVO by msg.getUuid() inside
ExternalServiceManagerImpl and derive the serviceType to build the sync
signature; update the getSyncSignature implementations accordingly (refer to
getSyncSignature, APIAddExternalServiceConfigurationMsg,
APIUpdateExternalServiceConfigurationMsg,
APIDeleteExternalServiceConfigurationMsg, and ExternalServiceConfigurationVO).
core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java
Show resolved
Hide resolved
core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java
Show resolved
Hide resolved
| @APIParam | ||
| private String description; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
description 字段不应设为必填
@APIParam 未设置 required = false,意味着更新时 description 是必填字段。这与 APIAddExternalServiceConfigurationMsg 中 description 为可选字段的设计不一致。建议设为可选,允许部分更新。
🐛 修复建议
- `@APIParam`
+ `@APIParam`(required = false, maxLength = 2048)
private String description;🤖 Prompt for AI Agents
In
`@header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationMsg.java`
around lines 25 - 26, The description field in
APIUpdateExternalServiceConfigurationMsg is currently annotated with `@APIParam`
(making it required) but should be optional to allow partial updates; update the
annotation on the private String description field in class
APIUpdateExternalServiceConfigurationMsg to `@APIParam`(required = false) so it
matches the optional behavior of APIAddExternalServiceConfigurationMsg and
permits callers to omit description when updating.
|
|
||
| category "externalService" | ||
|
|
||
| desc """在这里填写API描述""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
文档占位符未填写。
Line 10 和 Line 20 包含未填写的占位符文本。建议填写实际的 API 描述内容以完善文档。
建议修复
- desc """在这里填写API描述"""
+ desc """更新外部服务配置"""- desc """"""
+ desc """更新外部服务配置请求"""Also applies to: 20-20
🤖 Prompt for AI Agents
In
`@header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationMsgDoc_zh_cn.groovy`
at line 10, Replace the placeholder description strings in
APIUpdateExternalServiceConfigurationMsgDoc_zh_cn.groovy (the desc
"""在这里填写API描述""" occurrences) with a meaningful Chinese API description that
explains the purpose, parameters, behavior and effects of the API; update both
occurrences (line ~10 and ~20) so the doc accurately describes
APIUpdateExternalServiceConfiguration (what it updates, required fields, side
effects and expected responses) and remove the placeholder text.
| public static ExternalServiceConfigurationInventory valueOf(ExternalServiceConfigurationVO vo) { | ||
| ExternalServiceConfigurationInventory inv = new ExternalServiceConfigurationInventory(); | ||
| inv.setUuid(vo.getUuid()); | ||
| inv.setServiceType(vo.getServiceType()); | ||
| inv.setConfiguration(vo.getConfiguration()); | ||
| inv.setCreateDate(vo.getCreateDate()); | ||
| inv.setLastOpDate(vo.getLastOpDate()); | ||
| return inv; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: description 字段未被复制
在 valueOf 方法中,description 字段没有从 VO 复制到 Inventory,这会导致数据丢失。
🐛 修复建议
public static ExternalServiceConfigurationInventory valueOf(ExternalServiceConfigurationVO vo) {
ExternalServiceConfigurationInventory inv = new ExternalServiceConfigurationInventory();
inv.setUuid(vo.getUuid());
inv.setServiceType(vo.getServiceType());
inv.setConfiguration(vo.getConfiguration());
+ inv.setDescription(vo.getDescription());
inv.setCreateDate(vo.getCreateDate());
inv.setLastOpDate(vo.getLastOpDate());
return inv;
}🤖 Prompt for AI Agents
In
`@header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationInventory.java`
around lines 23 - 31, The valueOf method in
ExternalServiceConfigurationInventory fails to copy the description field from
ExternalServiceConfigurationVO, causing data loss; update the
ExternalServiceConfigurationInventory.valueOf(ExternalServiceConfigurationVO vo)
implementation to set the description by reading vo.getDescription() and calling
inv.setDescription(...), ensuring description is included alongside uuid,
serviceType, configuration, createDate, and lastOpDate.
| public static volatile SingularAttribute<PluginDriverVO, Timestamp> createDate; | ||
| public static volatile SingularAttribute<PluginDriverVO, Timestamp> lastOpDate; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
元模型属性类型参数错误
createDate 和 lastOpDate 的 SingularAttribute 泛型参数错误地使用了 PluginDriverVO,应该使用 ExternalServiceConfigurationVO。这会导致 JPA Criteria 查询在使用这些元模型字段时出现类型不匹配问题。
🐛 修复建议
- public static volatile SingularAttribute<PluginDriverVO, Timestamp> createDate;
- public static volatile SingularAttribute<PluginDriverVO, Timestamp> lastOpDate;
+ public static volatile SingularAttribute<ExternalServiceConfigurationVO, Timestamp> createDate;
+ public static volatile SingularAttribute<ExternalServiceConfigurationVO, Timestamp> lastOpDate;📝 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.
| public static volatile SingularAttribute<PluginDriverVO, Timestamp> createDate; | |
| public static volatile SingularAttribute<PluginDriverVO, Timestamp> lastOpDate; | |
| public static volatile SingularAttribute<ExternalServiceConfigurationVO, Timestamp> createDate; | |
| public static volatile SingularAttribute<ExternalServiceConfigurationVO, Timestamp> lastOpDate; |
🤖 Prompt for AI Agents
In
`@header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationVO_.java`
around lines 17 - 18, The metamodel fields createDate and lastOpDate in
ExternalServiceConfigurationVO_ use the wrong generic type (PluginDriverVO);
update their SingularAttribute generic parameter to
ExternalServiceConfigurationVO so the declarations read
SingularAttribute<ExternalServiceConfigurationVO, Timestamp> createDate and
lastOpDate, ensuring JPA Criteria queries match the actual entity type in the
ExternalServiceConfigurationVO_ class.
| DB.url=jdbc:mysql://172.24.192.192:3306/ | ||
| DB.user=root | ||
| DB.password= | ||
| DB.password=zstack.mysql.password |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
避免硬编码环境与敏感信息,且确认数据库名未遗漏。
这里改为固定内网 IP 且未包含库名(如 /zstack),会显著降低测试可移植性,并可能在 CI/开发机上直接失败;同时将密码写入仓库有泄露风险。建议改回本机/可配置化并补齐库名,密码通过本地覆盖或环境变量注入。
🛠️ 建议修正
-DB.url=jdbc:mysql://172.24.192.192:3306/
-DB.password=zstack.mysql.password
+DB.url=jdbc:mysql://localhost:3306/zstack
+DB.password=📝 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.
| DB.url=jdbc:mysql://172.24.192.192:3306/ | |
| DB.user=root | |
| DB.password= | |
| DB.password=zstack.mysql.password | |
| DB.url=jdbc:mysql://localhost:3306/zstack | |
| DB.user=root | |
| DB.password= |
🤖 Prompt for AI Agents
In `@test/src/test/resources/zstack.properties` around lines 2 - 4, Replace the
hard-coded DB.url/DB.user/DB.password values so tests don’t embed a fixed
internal IP, missing DB name, or secrets: update the DB.url property to point to
a local/default JDBC URL that includes the database name (e.g.,
jdbc:mysql://localhost:3306/zstack) and remove the plaintext DB.password from
the checked-in file; instead read DB.password (and optionally DB.user) from
environment variables or a local untracked override file so DB.url, DB.user and
DB.password properties are configurable at runtime.
4ce44a3 to
9f81dd7
Compare
There was a problem hiding this 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
`@header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationMsg.java`:
- Around line 22-24: The __example__() implementation in
APIQueryExternalServiceConfigurationMsg is returning List<String> which is
wrong; change the method to return an APIQueryExternalServiceConfigurationMsg
instance (match other messages like
APIDeleteExternalServiceConfigurationMsg/APIDeleteExternalServiceConfigurationMsg.__example__),
update the method signature accordingly, and return a new
APIQueryExternalServiceConfigurationMsg with its UUID field populated (e.g.,
construct and call setUuid(uuid()) or the equivalent setter) so documentation
generation uses an example message instance.
In
`@header/src/main/java/org/zstack/header/core/external/service/ApplyExternalConfigurationResult.java`:
- Around line 35-38: The setter ApplyExternalConfigurationResult.setErrorCode
currently unconditionally sets success = false even when the passed ErrorCode is
null, causing inconsistent state; update setErrorCode(ErrorCode errorCode) to
guard against null by returning early or throwing IllegalArgumentException when
errorCode is null, and only set this.errorCode and this.success = false when
errorCode != null (refer to the setErrorCode method, the errorCode field, and
the success field in class ApplyExternalConfigurationResult).
In
`@header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationInventoryDoc_zh_cn.groovy`:
- Around line 5-26: 将占位文案和空描述替换为有意义的文档文本:把 title 从 "在这里输入结构的名称" 改为 "外部服务配置",为
field name "serviceType" 添加描述(例如:服务的类型或名称,用于区分不同外部服务),为 field name
"configuration" 添加描述(例如:该服务的配置信息,通常为 JSON
或键值对字符串,包含连接和认证参数);确保只修改这三个字符串(title、serviceType.desc、configuration.desc)以生成完整
API 文档。
♻️ Duplicate comments (9)
header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationMsgDoc_zh_cn.groovy (1)
5-20: API 文档占位符未填写
desc字段仍为占位文本"在这里填写API描述",request.desc为空字符串。此问题已在之前的审查中指出,请补全真实的 API 描述。core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java (6)
203-203: 修复多余的分号代码中有一个双分号
;;,应该移除多余的分号。🐛 修复建议
- ExternalServiceConfigurationInventory inv = ExternalServiceConfigurationInventory.valueOf(configurationVO);; + ExternalServiceConfigurationInventory inv = ExternalServiceConfigurationInventory.valueOf(configurationVO);
241-244: 同步签名不一致,可能导致并发问题
APIAddExternalServiceConfigurationMsg使用msg.getExternalServiceType()作为同步签名,而APIUpdateExternalServiceConfigurationMsg使用msg.getUuid()。这导致同一serviceType的添加和更新/删除操作可能无法互斥,造成竞态条件。
253-262:updateExternalServiceConfiguration缺少空值检查,存在 NPE 风险
dbf.findByUuid()可能返回null,但代码直接调用vo.setDescription()而没有进行空值检查。根据 learnings 中的经验,这会导致NullPointerException。🐛 修复建议
private void updateExternalServiceConfiguration(APIUpdateExternalServiceConfigurationMsg msg, APIUpdateExternalServiceConfigurationEvent evt, Completion completion) { ExternalServiceConfigurationVO vo = dbf.findByUuid(msg.getUuid(), ExternalServiceConfigurationVO.class); + if (vo == null) { + completion.fail(operr("unable to find external service configuration with uuid [%s]", msg.getUuid())); + return; + } - vo.setDescription(msg.getDescription()); + if (msg.getDescription() != null) { + vo.setDescription(msg.getDescription()); + } vo = dbf.updateAndRefresh(vo);
194-217: 数据库事务与多节点应用失败时缺少回滚机制在
createExternalServiceConfiguration方法中,数据库记录先被持久化(Line 201),然后调用applyExternalServiceConfigurationToAllNodes。如果传播失败,数据库记录不会被回滚,导致数据不一致。根据编码规范中的向后兼容原则,应当对原状态做好记录,做好回退准备。
356-365:WhileDoneCompletion中的错误处理逻辑存在问题当
errorCode[0] != null时,传递给trigger.fail()的是errorCodeList,而非实际捕获的errorCode[0]。由于whileCompletion.allDone()被调用时errorCodeList可能不包含正确的错误信息。🐛 修复建议
.run(new WhileDoneCompletion(trigger) { `@Override` public void done(ErrorCodeList errorCodeList) { if (errorCode[0] != null) { - trigger.fail(errorCodeList); + trigger.fail(errorCode[0]); return; } trigger.next(); } });
406-415:regenerateExternalServiceConfiguration缺少空值保护如果某个
ExternalService实现的getServiceType()返回null,调用service.getServiceType().equals(serviceType)会抛出NullPointerException。🐛 修复建议
private void regenerateExternalServiceConfiguration(String serviceType, ReturnValueCompletion<String> completion) { for (ExternalService service : services.values()) { - if (service.getServiceType().equals(serviceType)) { + if (serviceType.equals(service.getServiceType())) { service.externalConfig(serviceType); completion.success(serviceType); return; } } completion.fail(operr("unable to find external service type [%s]", serviceType)); }header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationMsg.java (1)
25-26:description字段不应设为必填
@APIParam未设置required = false,意味着更新时description是必填字段。这与APIAddExternalServiceConfigurationMsg中description为可选字段的设计不一致,且不支持部分更新场景。🐛 修复建议
- `@APIParam` + `@APIParam`(required = false, maxLength = 2048) private String description;header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationInventory.java (1)
23-31: Bug:description字段未被复制在
valueOf方法中,description字段没有从 VO 复制到 Inventory,这会导致数据丢失。虽然类中定义了description字段(第19行)及其 getter/setter,但转换方法中遗漏了该字段的赋值。🐛 修复建议
public static ExternalServiceConfigurationInventory valueOf(ExternalServiceConfigurationVO vo) { ExternalServiceConfigurationInventory inv = new ExternalServiceConfigurationInventory(); inv.setUuid(vo.getUuid()); inv.setServiceType(vo.getServiceType()); inv.setConfiguration(vo.getConfiguration()); + inv.setDescription(vo.getDescription()); inv.setCreateDate(vo.getCreateDate()); inv.setLastOpDate(vo.getLastOpDate()); return inv; }
🧹 Nitpick comments (6)
header/src/main/java/org/zstack/header/core/external/service/ApplyExternalConfigurationResult.java (2)
5-8: 类注释缺少功能说明当前注释仅包含作者和日期信息,缺少对类用途的描述。根据编码规范,接口和公共类应配有有效的 Javadoc 注释,说明其职责和使用场景。
📝 建议添加类级别的 Javadoc
+/** + * Result object for applying external configuration to a management node. + * Contains the outcome (success/failure) and any associated error details. + * + * `@author` ya.wang + * `@since` 1/15/26 + */ -/** - * `@Author`: ya.wang - * `@Date`: 1/15/26 2:50 AM - */ public class ApplyExternalConfigurationResult {
27-29:setSuccess(true)与setErrorCode的副作用可能造成状态不一致由于
setErrorCode会自动设置success = false,而setSuccess(boolean)是公开方法,调用者可以在设置 errorCode 后再调用setSuccess(true),导致存在 errorCode 但 success 为 true 的矛盾状态。建议考虑以下方案之一:
- 将
setSuccess设为private或 package-private- 在
isSuccess()中动态计算:return errorCode == null- 保留当前设计但在文档中明确说明使用约定
♻️ 方案 2:通过动态计算避免状态不一致
- private boolean success = true; - public boolean isSuccess() { - return success; + return errorCode == null; } - public void setSuccess(boolean success) { - this.success = success; - } public void setErrorCode(ErrorCode errorCode) { - this.success = false; this.errorCode = errorCode; }core/src/main/java/org/zstack/core/externalservice/ExternalService.java (1)
19-22: 接口方法缺少 Javadoc 文档,且参数设计可能存在歧义新增的两个方法缺少 Javadoc 注释。根据编码规范,接口方法应配有有效的 Javadoc 注释。
另外,
externalConfig(String serviceType)的参数名serviceType与getServiceType()返回值语义重叠,可能造成理解上的困惑。建议明确该参数的用途:是配置当前服务自身,还是配置指定类型的其他服务?♻️ 建议添加 Javadoc
+ /** + * Returns the type identifier of this external service. + * `@return` the service type + */ String getServiceType(); + /** + * Applies external configuration for the specified service type. + * `@param` serviceType the target service type to configure + */ void externalConfig(String serviceType);header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationMsg.java (1)
15-22: REST 路径建议使用复数形式,uuid 缺少 maxLength 约束
根据编码规范,REST 路径针对资源应使用复数形式。当前路径为
/external/service/configuration/{uuid},建议改为/external/service/configurations/{uuid}。对比
APIUpdateExternalServiceConfigurationMsg,其uuid字段配置了maxLength = 32,而此处缺少该约束,建议保持一致。♻️ 建议修改
`@RestRequest`( - path = "/external/service/configuration/{uuid}", + path = "/external/service/configurations/{uuid}", responseClass = APIDeleteExternalServiceConfigurationEvent.class, method = HttpMethod.DELETE ) public class APIDeleteExternalServiceConfigurationMsg extends APIDeleteMessage implements APIAuditor { - `@APIParam`(resourceType = ExternalServiceConfigurationVO.class, successIfResourceNotExisting = true) + `@APIParam`(resourceType = ExternalServiceConfigurationVO.class, maxLength = 32, successIfResourceNotExisting = true) private String uuid;注意: 如果修改路径为复数形式,需同步修改相关的 Add、Update、Query API 的路径以保持一致性。
core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java (1)
369-373: TODO 注释需要跟进处理
rollback方法中包含 TODO 注释// TODO(ywang): remove external configurations,表明回滚逻辑尚未完整实现。这与上述数据库事务回滚问题相关。需要我帮助实现回滚逻辑或创建 issue 跟踪此任务吗?
header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationInventory.java (1)
33-39: 集合转换方法可优化当前实现使用传统 for 循环,可考虑使用 Java Stream 简化代码。
♻️ 可选优化
public static List<ExternalServiceConfigurationInventory> valueOf(Collection<ExternalServiceConfigurationVO> vos) { - List<ExternalServiceConfigurationInventory> invs = new ArrayList<ExternalServiceConfigurationInventory>(); - for (ExternalServiceConfigurationVO vo : vos) { - invs.add(valueOf(vo)); - } - return invs; + return vos.stream() + .map(ExternalServiceConfigurationInventory::valueOf) + .collect(Collectors.toList()); }
...in/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationMsg.java
Show resolved
Hide resolved
| public void setErrorCode(ErrorCode errorCode) { | ||
| this.success = false; | ||
| this.errorCode = errorCode; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
setErrorCode(null) 会导致非预期行为
当调用 setErrorCode(null) 时,success 会被设置为 false,但 errorCode 却为 null,这可能导致状态不一致。建议添加 null 检查来避免此边界情况。
🔧 建议添加 null 检查
public void setErrorCode(ErrorCode errorCode) {
+ if (errorCode == null) {
+ return;
+ }
this.success = false;
this.errorCode = errorCode;
}🤖 Prompt for AI Agents
In
`@header/src/main/java/org/zstack/header/core/external/service/ApplyExternalConfigurationResult.java`
around lines 35 - 38, The setter ApplyExternalConfigurationResult.setErrorCode
currently unconditionally sets success = false even when the passed ErrorCode is
null, causing inconsistent state; update setErrorCode(ErrorCode errorCode) to
guard against null by returning early or throwing IllegalArgumentException when
errorCode is null, and only set this.errorCode and this.success = false when
errorCode != null (refer to the setErrorCode method, the errorCode field, and
the success field in class ApplyExternalConfigurationResult).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment from ya.wang:
当 reply.isSuccess 为否时才会调用此方法, 因此不会出现描述中的问题
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for usages of setErrorCode in the context of ApplyExternalConfigurationResult
rg -nP --type=java -C5 'ApplyExternalConfigurationResult.*setErrorCode|\.setErrorCode\('
Length of output: 8004
🏁 Script executed:
#!/bin/bash
# Also search for instantiation and usage patterns of ApplyExternalConfigurationResult
rg -nP --type=java -C8 'new ApplyExternalConfigurationResult|ApplyExternalConfigurationResult result'
Length of output: 2546
@MatheMatrix 感谢您的说明!我查看了代码库中的实际使用情况,确认了您的观点是正确的。
在 ExternalServiceManagerImpl.java 中(第 343-351 行),确实只有在 !reply.isSuccess() 条件下才会调用 setErrorCode:
if (!reply.isSuccess()) {
result.setErrorCode(reply.getError());
errorCode[0] = reply.getError();
whileCompletion.allDone();
return;
}由于 MessageReply 的设计模式保证了当 isSuccess() 为 false 时,getError() 会返回非空的 ErrorCode,所以在当前的使用场景中,setErrorCode(null) 的情况不会发生。
我收回之前的建议,这个实现在当前的调用约定下是合理的。👍
🧠 Learnings used
Learnt from: ZStack-Robot
Repo: MatheMatrix/zstack PR: 2287
File: header/src/main/java/org/zstack/header/errorcode/ErrorCode.java:25-30
Timestamp: 2025-07-10T07:29:52.955Z
Learning: 在 ZStack 项目中,ErrorCodeList 正在进行渐进式弃用,而不是一次性完全移除。在过渡期间,ErrorCodeList 仍需要能够访问 ErrorCode 中的 causes 字段,因此 causes 字段使用 protected final 可见性是合理的设计选择,支持渐进式重构策略。
...rg/zstack/header/core/external/service/ExternalServiceConfigurationInventoryDoc_zh_cn.groovy
Show resolved
Hide resolved
9f81dd7 to
8c8ad9a
Compare
|
Comment from gitlab: 自上次添加REVIEWED标签(2026-01-19 13:22:36.000Z)后, 有新的COMMIT更新(2026-01-19 13:22:55.997Z), 所以移除了REVIEWED标签 |
There was a problem hiding this 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
🤖 Fix all issues with AI agents
In
`@core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java`:
- Around line 329-351: The List named results in
applyExternalServiceConfigurationToAllNodes is an ArrayList that is mutated from
concurrent CloudBus callbacks (inside the While<> each and CloudBusCallBack), so
switch it to a thread-safe collection (for example
Collections.synchronizedList(new ArrayList<>()) or a concurrent collection like
CopyOnWriteArrayList/ConcurrentLinkedQueue and adapt any downstream code
expecting a List) or synchronize around results.add(...) in the
CloudBusCallBack; update references to results in the flow/trigger completion to
use the chosen thread-safe structure or convert it back to a List before
returning.
In
`@header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationMsgDoc_zh_cn.groovy`:
- Around line 7-23: Replace the placeholder Chinese/empty API descriptions with
clear English text: update the top-level desc string in
APIQueryExternalServiceConfigurationMsgDoc_zh_cn.groovy to a concise English
description of the API purpose (e.g., "Query external service
configuration(s)"), and fill the nested request desc block with an English
description of the request behavior and supported URLs (e.g., "Retrieve one or
all external service configurations; GET /v1/external/service/configuration
returns all, GET /v1/external/service/configuration/{uuid} returns a specific
configuration by UUID"). Ensure the updated descriptions reference the
APIQueryExternalServiceConfigurationMsg class and are consistent with existing
project documentation style.
♻️ Duplicate comments (3)
core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java (2)
181-184: 同步签名粒度不一致,仍可能引发竞态。创建使用
externalServiceType,更新/删除使用uuid,同一serviceType的新增与更新/删除之间无法互斥,可能出现并发冲突。建议统一以serviceType作为同步粒度(可在更新/删除中补齐字段或从数据库查询得到)。Also applies to: 241-244, 292-295
410-413:serviceType为空时可能 NPE。当
serviceType为 null 时,serviceType.equals(...)会抛 NPE;建议使用空安全比较。🐛 建议修改
- for (ExternalService service : services.values()) { - if (serviceType.equals(service.getServiceType())) { + for (ExternalService service : services.values()) { + if (java.util.Objects.equals(serviceType, service.getServiceType())) { service.externalConfig(serviceType); completion.success(serviceType); return; } }header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationMsg.java (1)
25-26: 更新接口建议允许description可选。目前
description为必填,和新增接口(可选)不一致,也限制了部分更新。建议设为可选并对齐长度约束。🐛 建议修改
- `@APIParam` + `@APIParam`(required = false, maxLength = 2048) private String description;
🧹 Nitpick comments (3)
header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationEvent.java (1)
22-27: 建议补全__example__中的示例字段。当前示例只设置了 uuid,生成的 API 文档信息偏少;建议补齐
serviceType与configuration,与新增事件示例保持一致。♻️ 建议修改
public static APIUpdateExternalServiceConfigurationEvent __example__() { APIUpdateExternalServiceConfigurationEvent event = new APIUpdateExternalServiceConfigurationEvent(); ExternalServiceConfigurationInventory inv = new ExternalServiceConfigurationInventory(); inv.setUuid(uuid()); + inv.setServiceType("Prometheus2"); + inv.setConfiguration("{}"); event.setInventory(inv); return event; }header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsg.java (2)
15-20: API 路径应使用资源复数形式根据编码规范中的要求 "path: 针对资源使用复数形式",当前路径
/external/service/configuration应改为/external/service/configurations(复数)。注意:
APIDeleteExternalServiceConfigurationMsg和APIUpdateExternalServiceConfigurationMsg也存在同样的问题,建议一并修改以保持一致性。♻️ 建议修改
`@RestRequest`( - path = "/external/service/configuration", + path = "/external/service/configurations", method = HttpMethod.POST, parameterName = "params", responseClass = APIAddExternalServiceConfigurationEvent.class )
22-23: 建议为externalServiceType添加maxLength约束
configuration和description字段都有maxLength约束,但externalServiceType没有。建议添加合适的长度限制以保持一致性并防止异常长度的输入。♻️ 建议修改
- `@APIParam` + `@APIParam`(maxLength = 255) private String externalServiceType;
| private void applyExternalServiceConfigurationToAllNodes(String serviceType, ReturnValueCompletion<List<ApplyExternalConfigurationResult>> completion) { | ||
| final List<ApplyExternalConfigurationResult> results = new ArrayList<>(); | ||
|
|
||
| FlowChain chain = new SimpleFlowChain(); | ||
| chain.setName("apply-external-service-configuration-to-all-nodes"); | ||
| chain.then(new Flow() { | ||
| String __name__ = "apply-external-service-configuration"; | ||
|
|
||
| @Override | ||
| public void run(FlowTrigger trigger, Map data) { | ||
| List<String> mnUuids = Q.New(ManagementNodeVO.class).select(ManagementNodeVO_.uuid).listValues(); | ||
|
|
||
| final ErrorCode[] errorCode = new ErrorCode[1]; | ||
| new While<>(mnUuids).each((mnUuid, whileCompletion) -> { | ||
| ApplyExternalServiceConfigurationMsg amsg = new ApplyExternalServiceConfigurationMsg(); | ||
| amsg.setServiceType(serviceType); | ||
| bus.makeServiceIdByManagementNodeId(amsg, SERVICE_ID, mnUuid); | ||
| bus.send(amsg, new CloudBusCallBack(whileCompletion) { | ||
| @Override | ||
| public void run(MessageReply reply) { | ||
| ApplyExternalConfigurationResult result = new ApplyExternalConfigurationResult(); | ||
| result.setManagementNodeUuid(mnUuid); | ||
| results.add(result); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
results 可能被并发回调写入,建议使用线程安全集合。
CloudBus 回调可能并发执行,ArrayList 不是线程安全,存在写入竞争与数据损坏风险。建议改为线程安全列表或显式同步。
♻️ 建议修改
- final List<ApplyExternalConfigurationResult> results = new ArrayList<>();
+ final List<ApplyExternalConfigurationResult> results =
+ java.util.Collections.synchronizedList(new ArrayList<>());🤖 Prompt for AI Agents
In
`@core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java`
around lines 329 - 351, The List named results in
applyExternalServiceConfigurationToAllNodes is an ArrayList that is mutated from
concurrent CloudBus callbacks (inside the While<> each and CloudBusCallBack), so
switch it to a thread-safe collection (for example
Collections.synchronizedList(new ArrayList<>()) or a concurrent collection like
CopyOnWriteArrayList/ConcurrentLinkedQueue and adapt any downstream code
expecting a List) or synchronize around results.add(...) in the
CloudBusCallBack; update references to results in the flow/trigger completion to
use the chosen thread-safe structure or convert it back to a List before
returning.
| title "QueryExternalServiceConfiguration" | ||
|
|
||
| category "externalService" | ||
|
|
||
| desc """在这里填写API描述""" | ||
|
|
||
| rest { | ||
| request { | ||
| url "GET /v1/external/service/configuration" | ||
| url "GET /v1/external/service/configuration/{uuid}" | ||
|
|
||
| header (Authorization: 'OAuth the-session-uuid') | ||
|
|
||
| clz APIQueryExternalServiceConfigurationMsg.class | ||
|
|
||
| desc """""" | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
文档描述存在中文占位/空值,需改为英文并补全
desc 仍是中文占位文本且 request desc 为空,违反代码英文规范并降低文档可用性。请补全英文描述。As per coding guidelines, ...
🤖 Prompt for AI Agents
In
`@header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationMsgDoc_zh_cn.groovy`
around lines 7 - 23, Replace the placeholder Chinese/empty API descriptions with
clear English text: update the top-level desc string in
APIQueryExternalServiceConfigurationMsgDoc_zh_cn.groovy to a concise English
description of the API purpose (e.g., "Query external service
configuration(s)"), and fill the nested request desc block with an English
description of the request behavior and supported URLs (e.g., "Retrieve one or
all external service configurations; GET /v1/external/service/configuration
returns all, GET /v1/external/service/configuration/{uuid} returns a specific
configuration by UUID"). Ensure the updated descriptions reference the
APIQueryExternalServiceConfigurationMsg class and are consistent with existing
project documentation style.
76895fd to
63fcf3f
Compare
There was a problem hiding this 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
🤖 Fix all issues with AI agents
In
`@header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsgDoc_zh_cn.groovy`:
- Line 10: Replace the placeholder and empty field descriptions in
APIAddExternalServiceConfigurationMsgDoc_zh_cn.groovy: update the top-level desc
string (currently "在这里填写API描述") to a concise Chinese description of the API's
purpose, and add meaningful Chinese desc entries for the parameters
externalServiceType and configuration so each documents what the field
represents, expected values/format, and any required/optional constraints;
locate the strings within the APIAddExternalServiceConfigurationMsgDoc_zh_cn
class (the desc for the API and the desc properties for externalServiceType and
configuration) and replace the placeholders with clear, production-ready text.
In
`@header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationMsg.java`:
- Around line 22-23: The example query string in
APIQueryExternalServiceConfigurationMsg.__example__ is missing the '=' and
should match the other APIQuery*Msg patterns; update the return to use "uuid=" +
uuid() so the example becomes Collections.singletonList("uuid=" + uuid());
modify the __example__ method in class APIQueryExternalServiceConfigurationMsg
accordingly.
♻️ Duplicate comments (5)
header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationMsgDoc_zh_cn.groovy (1)
11-22: API 文档描述仍为占位符Line 11 的
desc仍是占位文本"在这里填写API描述",Line 22 的desc为空。请补全有意义的 API 描述文本。header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationVO_.java (1)
17-18: 元模型属性类型参数错误(未修复)
createDate和lastOpDate的SingularAttribute泛型参数错误地使用了PluginDriverVO,应该使用ExternalServiceConfigurationVO。这会导致 JPA Criteria 查询类型不匹配问题。🐛 修复建议
- public static volatile SingularAttribute<PluginDriverVO, Timestamp> createDate; - public static volatile SingularAttribute<PluginDriverVO, Timestamp> lastOpDate; + public static volatile SingularAttribute<ExternalServiceConfigurationVO, Timestamp> createDate; + public static volatile SingularAttribute<ExternalServiceConfigurationVO, Timestamp> lastOpDate;同时,修复后可移除未使用的
PluginDriverVO导入(Line 3)。header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationReplyDoc_zh_cn.groovy (1)
8-8: 文档占位符和描述字段未正确填写。
- Line 8:
title仍为占位文本 "在这里输入结构的名称"- Line 13:
inventories的desc为字面值 "null"- Line 20:
success的desc为空建议修复
- title "在这里输入结构的名称" + title "查询外部服务配置返回"ref { name "inventories" path "org.zstack.header.core.external.service.APIQueryExternalServiceConfigurationReply.inventories" - desc "null" + desc "外部服务配置清单列表"field { name "success" - desc "" + desc "操作是否成功"Also applies to: 13-13, 20-20
core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java (2)
241-244: 同步签名不一致,可能导致并发问题
APIAddExternalServiceConfigurationMsg使用msg.getExternalServiceType()作为同步签名(Line 183),而APIUpdateExternalServiceConfigurationMsg(Line 243)和APIDeleteExternalServiceConfigurationMsg(Line 294)使用msg.getUuid()。这导致:
- 同一
serviceType的添加操作互斥- 同一
uuid的更新/删除操作互斥- 但添加与更新/删除操作之间无法互斥
建议统一同步粒度,可以在更新/删除时先查询 VO 获取
serviceType,或统一使用uuid。Also applies to: 292-294
329-330:results列表存在并发写入风险
While循环中的CloudBusCallBack可能并发执行,而ArrayList非线程安全,存在数据竞争风险。♻️ 建议修复
- final List<ApplyExternalConfigurationResult> results = new ArrayList<>(); + final List<ApplyExternalConfigurationResult> results = java.util.Collections.synchronizedList(new ArrayList<>());
🧹 Nitpick comments (4)
core/src/main/java/org/zstack/core/externalservice/ExternalService.java (1)
19-22: 接口方法缺少 Javadoc 注释根据编码规范,接口方法必须配有有效的 Javadoc 注释。新增的
getServiceType()和externalConfig(String serviceType)方法缺少文档说明,建议补充:📝 建议修改
+ /** + * Returns the type identifier for this external service. + * `@return` the service type string + */ String getServiceType(); + /** + * Applies external configuration for the specified service type. + * `@param` serviceType the type of service to configure + */ void externalConfig(String serviceType);externalservice/src/main/java/org/zstack/externalservice/cronjob/CronJobImpl.java (1)
37-40: 建议将服务类型定义为常量
"CronJob"字符串直接硬编码,根据编码规范应避免魔法值。建议提取为常量以提升可维护性。♻️ 可选重构
public class CronJobImpl extends AbstractLocalExternalService implements CronJob { + public static final String SERVICE_TYPE = "CronJob"; + ExternalServiceCapabilities capabilities = ExternalServiceCapabilitiesBuilder .build() .reloadConfig(true); `@Override` public String getServiceType() { - return "CronJob"; + return SERVICE_TYPE; }header/src/main/java/org/zstack/header/core/external/service/ApplyExternalServiceConfigurationMsg.java (1)
16-18: 建议对 serviceType 进行 trim 处理根据编码规范,应检查来自 Message 的参数是否做过 trim,防止用户输入带有空格或换行符。
♻️ 建议修改
public void setServiceType(String serviceType) { - this.serviceType = serviceType; + this.serviceType = serviceType != null ? serviceType.trim() : null; }header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsg.java (1)
22-23: 建议为externalServiceType添加maxLength约束
configuration和description字段都有maxLength约束,但externalServiceType没有。建议添加合理的长度限制以保持一致性和防止异常输入。♻️ 建议修复
- `@APIParam` + `@APIParam`(maxLength = 255) private String externalServiceType;
|
|
||
| category "externalService" | ||
|
|
||
| desc """在这里填写API描述""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
文档占位符和空描述未填写完整。
- Line 10:
desc """在这里填写API描述"""仍为占位文本 - Line 27:
externalServiceType的desc为空 - Line 37:
configuration的desc为空
建议补充实际的 API 描述和字段说明,提高文档可读性。
建议修复
- desc """在这里填写API描述"""
+ desc """添加外部服务配置""" column {
name "externalServiceType"
enclosedIn "params"
- desc ""
+ desc "外部服务类型" column {
name "configuration"
enclosedIn "params"
- desc ""
+ desc "配置内容"Also applies to: 27-27, 37-37
🤖 Prompt for AI Agents
In
`@header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsgDoc_zh_cn.groovy`
at line 10, Replace the placeholder and empty field descriptions in
APIAddExternalServiceConfigurationMsgDoc_zh_cn.groovy: update the top-level desc
string (currently "在这里填写API描述") to a concise Chinese description of the API's
purpose, and add meaningful Chinese desc entries for the parameters
externalServiceType and configuration so each documents what the field
represents, expected values/format, and any required/optional constraints;
locate the strings within the APIAddExternalServiceConfigurationMsgDoc_zh_cn
class (the desc for the API and the desc properties for externalServiceType and
configuration) and replace the placeholders with clear, production-ready text.
| public class APIQueryExternalServiceConfigurationMsg extends APIQueryMessage { | ||
| public static List<String> __example__() {return Collections.singletonList("uuid" + uuid());} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
查询条件字符串缺少 = 符号
根据其他 APIQuery*Msg 类的实现惯例(如 APIQueryDiskOfferingMsg 使用 "uuid=" + uuid()),此处应添加等号以保持一致性。
♻️ 建议修复
- public static List<String> __example__() {return Collections.singletonList("uuid" + uuid());}
+ public static List<String> __example__() {return Collections.singletonList("uuid=" + uuid());}🤖 Prompt for AI Agents
In
`@header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationMsg.java`
around lines 22 - 23, The example query string in
APIQueryExternalServiceConfigurationMsg.__example__ is missing the '=' and
should match the other APIQuery*Msg patterns; update the return to use "uuid=" +
uuid() so the example becomes Collections.singletonList("uuid=" + uuid());
modify the __example__ method in class APIQueryExternalServiceConfigurationMsg
accordingly.
2eb6985 to
6e3835e
Compare
There was a problem hiding this 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
`@externalservice/src/main/java/org/zstack/externalservice/cronjob/CronJobImpl.java`:
- Around line 113-114: The empty externalConfig(String serviceType)
implementation in CronJobImpl silently ignores configuration requests; update
externalConfig in class CronJobImpl to perform parameter validation on
serviceType and either (a) apply configuration if the service supports it, or
(b) explicitly reject unsupported requests by throwing a clear exception (e.g.,
UnsupportedOperationException or IllegalArgumentException) or logging an error
and returning a failure status; include a brief JavaDoc or comment on supported
serviceType values so callers know expected behavior.
- Around line 38-40: Replace the hardcoded service type string in
CronJobImpl.getServiceType() with the shared constant from CronJobFactory to
avoid a magic string; specifically, return the CronJobFactory.type (or its
string representation if needed) instead of "CronJob" so the implementation
reuses the public static final ExternalServiceType defined in CronJobFactory.
In
`@header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsg.java`:
- Around line 54-56: The audit method in APIAddExternalServiceConfigurationMsg
currently assumes ((APIAddExternalServiceConfigurationEvent) rsp).getInventory()
is non-null, risking an NPE; update APIAddExternalServiceConfigurationMsg.audit
to safely cast rsp to APIAddExternalServiceConfigurationEvent, check
rsp.isSuccess() && event != null && event.getInventory() != null before calling
getUuid(), and pass an empty string to new APIAuditor.Result when any of those
checks fail (also guard against rsp not being an instance of
APIAddExternalServiceConfigurationEvent).
♻️ Duplicate comments (7)
header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationMsgDoc_zh_cn.groovy (1)
10-20: 文档描述仍是占位符/空字符串顶层与 request 说明为空,会导致文档缺失关键信息,建议补全实际描述。
📝 建议补充
- desc """在这里填写API描述""" + desc """更新外部服务配置""" ... - desc """""" + desc """更新外部服务配置请求"""header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsgDoc_zh_cn.groovy (1)
10-38: 文档占位符与空字段说明需补全API 描述与关键字段说明为空,会影响文档可读性。
📝 建议补充
- desc """在这里填写API描述""" + desc """添加外部服务配置""" ... - desc "" + desc "外部服务类型(如 Prometheus2/FluentBit)" ... - desc "" + desc "配置内容(建议说明格式/示例)"header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationMsg.java (1)
23-23: 查询示例缺少=可能导致条件格式异常建议改为
uuid=+ uuid(),避免生成无效条件字符串。Based on learnings, 查询消息 example 返回条件字符串列表的写法是正确的。♻️ 建议修正
- public static List<String> __example__() {return Collections.singletonList("uuid" + uuid());} + public static List<String> __example__() {return Collections.singletonList("uuid=" + uuid());}header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationMsg.java (1)
25-26:description字段应设为可选当前
@APIParam未设置required = false,导致更新时description为必填。这与APIAddExternalServiceConfigurationMsg中description为可选(required = false, maxLength = 2048)的设计不一致,且不支持部分更新场景。🐛 修复建议
- `@APIParam` + `@APIParam`(required = false, maxLength = 2048) private String description;header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationVO_.java (1)
3-3: 元模型属性类型参数错误
createDate和lastOpDate的SingularAttribute泛型参数错误地使用了PluginDriverVO,应为ExternalServiceConfigurationVO。此问题会导致 JPA Criteria 查询类型不匹配。修复后PluginDriverVO导入将变为未使用。🐛 修复建议
package org.zstack.header.core.external.service; -import org.zstack.header.core.external.plugin.PluginDriverVO; import org.zstack.header.vo.ResourceVO_; import javax.persistence.metamodel.SingularAttribute; import java.sql.Timestamp; /** * `@Author`: ya.wang * `@Date`: 1/15/26 1:30 AM */ public class ExternalServiceConfigurationVO_ extends ResourceVO_ { public static volatile SingularAttribute<ExternalServiceConfigurationVO, String> serviceType; public static volatile SingularAttribute<ExternalServiceConfigurationVO, String> configuration; public static volatile SingularAttribute<ExternalServiceConfigurationVO, String> description; - public static volatile SingularAttribute<PluginDriverVO, Timestamp> createDate; - public static volatile SingularAttribute<PluginDriverVO, Timestamp> lastOpDate; + public static volatile SingularAttribute<ExternalServiceConfigurationVO, Timestamp> createDate; + public static volatile SingularAttribute<ExternalServiceConfigurationVO, Timestamp> lastOpDate; }Also applies to: 17-18
core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java (2)
241-244: 同步签名不一致问题仍未解决。
APIAddExternalServiceConfigurationMsg使用msg.getExternalServiceType()作为同步签名(Line 183),而APIUpdateExternalServiceConfigurationMsg和APIDeleteExternalServiceConfigurationMsg使用msg.getUuid()(Lines 243, 294)。这导致同步粒度不一致:
- 同一
serviceType的添加操作互斥- 同一
uuid的更新/删除操作互斥- 但对同一配置的添加和更新/删除操作之间可能产生竞态条件
329-330:results列表在并发回调中使用非线程安全集合。CloudBus 回调可能并发执行,
ArrayList不是线程安全的,存在写入竞争与数据损坏风险。♻️ 建议修改
- final List<ApplyExternalConfigurationResult> results = new ArrayList<>(); + final List<ApplyExternalConfigurationResult> results = + java.util.Collections.synchronizedList(new ArrayList<>());
🧹 Nitpick comments (4)
header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationMsg.java (1)
21-22: 建议为uuid添加maxLength约束
APIUpdateExternalServiceConfigurationMsg中的uuid字段设置了maxLength = 32,建议此处保持一致以确保输入验证的统一性。♻️ 建议修改
- `@APIParam`(resourceType = ExternalServiceConfigurationVO.class, successIfResourceNotExisting = true) + `@APIParam`(resourceType = ExternalServiceConfigurationVO.class, maxLength = 32, successIfResourceNotExisting = true) private String uuid;header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationEvent.java (1)
22-29:__example__()方法与APIAddExternalServiceConfigurationEvent不一致。相比
APIAddExternalServiceConfigurationEvent.__example__()设置了uuid、serviceType和configuration,此处的__example__()仅设置了uuid,导致生成的 API 文档示例不完整。♻️ 建议补充示例字段
public static APIUpdateExternalServiceConfigurationEvent __example__() { APIUpdateExternalServiceConfigurationEvent event = new APIUpdateExternalServiceConfigurationEvent(); ExternalServiceConfigurationInventory inv = new ExternalServiceConfigurationInventory(); inv.setUuid(uuid()); + inv.setServiceType("Prometheus2"); + inv.setConfiguration("{}"); event.setInventory(inv); return event; }core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java (1)
159-159: 方法签名格式问题。
handle方法参数后有多余空格,与其他 handle 方法风格不一致。♻️ 建议修改
- private void handle(APIAddExternalServiceConfigurationMsg msg ){ + private void handle(APIAddExternalServiceConfigurationMsg msg) {header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsg.java (1)
22-27: 建议对externalServiceType和configuration参数进行 trim 处理。根据编码规范,用户可能复制粘贴带有空格或换行符的数据。建议在 Manager 处理时对这些参数进行 trim。
As per coding guidelines, "注意检查来自 Message 的参数是否做过 trim"。
| public String getServiceType() { | ||
| return "CronJob"; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# 搜索 getServiceType 实现及服务类型常量
rg -n "getServiceType" --type=java -A 3 -B 1 | head -50Repository: MatheMatrix/zstack
Length of output: 180
🏁 Script executed:
# 搜索 SERVICE_TYPE、ServiceType 等常量定义
rg -n "SERVICE_TYPE|ServiceType|ExternalServiceType" --type=java | head -30Repository: MatheMatrix/zstack
Length of output: 4671
🏁 Script executed:
# 查看 CronJobImpl.java 的完整内容
cat -n externalservice/src/main/java/org/zstack/externalservice/cronjob/CronJobImpl.javaRepository: MatheMatrix/zstack
Length of output: 3995
🏁 Script executed:
# 搜索其他外部服务实现的 getServiceType 方法,看是否有模式可循
fd -t f ".*Impl\.java$" externalservice/src/main/java/org/zstack/externalservice/ | xargs rg -l "getServiceType" | xargs -I {} sh -c 'echo "=== {} ===" && rg -A 2 "getServiceType" {}'Repository: MatheMatrix/zstack
Length of output: 220
🏁 Script executed:
# 查找其他外部服务实现,看是否有类似 getServiceType 的模式
find externalservice -name "*.java" -type f | xargs grep -l "extends AbstractLocalExternalService\|implements.*ExternalService" | head -10Repository: MatheMatrix/zstack
Length of output: 228
🏁 Script executed:
# 查看 AbstractLocalExternalService 的定义和 getServiceType 方法
rg -A 10 "class AbstractLocalExternalService" --type=java | head -30Repository: MatheMatrix/zstack
Length of output: 1423
🏁 Script executed:
# 搜索 "CronJob" 字符串在整个代码库中的使用情况
rg '"CronJob"' -n --type=javaRepository: MatheMatrix/zstack
Length of output: 347
🏁 Script executed:
# 查看 CronJobFactory 的完整代码,了解 ExternalServiceType 的使用
cat -n externalservice/src/main/java/org/zstack/externalservice/cronjob/CronJobFactory.javaRepository: MatheMatrix/zstack
Length of output: 1044
🏁 Script executed:
# 查看 ExternalServiceType 的定义
rg -B 5 -A 10 "class ExternalServiceType" --type=javaRepository: MatheMatrix/zstack
Length of output: 1749
🏁 Script executed:
# 检查是否有其他地方使用 ExternalServiceType.type 的模式
rg "ExternalServiceType.*type" --type=java -B 2 -A 2 | head -40Repository: MatheMatrix/zstack
Length of output: 3008
🏁 Script executed:
# 查看 ExternalServiceType 的 toString() 方法实现
rg -A 5 "toString()" core/src/main/java/org/zstack/core/externalservice/ExternalServiceType.javaRepository: MatheMatrix/zstack
Length of output: 313
🏁 Script executed:
# 确认 CronJobImpl 和 CronJobFactory 是否在同一个包中
ls -la externalservice/src/main/java/org/zstack/externalservice/cronjob/Repository: MatheMatrix/zstack
Length of output: 370
复用 CronJobFactory 中已定义的服务类型常量,避免重复定义魔法字符串。
代码库中已在 CronJobFactory 定义了 public static final ExternalServiceType type = new ExternalServiceType("CronJob"),CronJobImpl.getServiceType() 应直接复用该常量而非硬编码字符串,确保一处维护、保持一致。
♻️ 建议修改
`@Override`
public String getServiceType() {
- return "CronJob";
+ return CronJobFactory.type.toString();
}🤖 Prompt for AI Agents
In
`@externalservice/src/main/java/org/zstack/externalservice/cronjob/CronJobImpl.java`
around lines 38 - 40, Replace the hardcoded service type string in
CronJobImpl.getServiceType() with the shared constant from CronJobFactory to
avoid a magic string; specifically, return the CronJobFactory.type (or its
string representation if needed) instead of "CronJob" so the implementation
reuses the public static final ExternalServiceType defined in CronJobFactory.
| @Override | ||
| public void externalConfig(String serviceType){} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
externalConfig 为空实现可能导致配置下发被静默忽略。
如果该服务不支持外部配置,建议至少做参数校验并显式失败或注释说明,避免误配置被吞掉。As per coding guidelines, keep behavior explicit and self-explanatory.
🐛 建议修改(示例:参数校验 + 明确无配置)
`@Override`
- public void externalConfig(String serviceType){}
+ public void externalConfig(String serviceType) {
+ if (!StringUtils.equals(serviceType, getServiceType())) {
+ throw new OperationFailureException(operr(String.format(
+ "unexpected serviceType: %s", serviceType)));
+ }
+ // No external config for CronJob currently.
+ }🤖 Prompt for AI Agents
In
`@externalservice/src/main/java/org/zstack/externalservice/cronjob/CronJobImpl.java`
around lines 113 - 114, The empty externalConfig(String serviceType)
implementation in CronJobImpl silently ignores configuration requests; update
externalConfig in class CronJobImpl to perform parameter validation on
serviceType and either (a) apply configuration if the service supports it, or
(b) explicitly reject unsupported requests by throwing a clear exception (e.g.,
UnsupportedOperationException or IllegalArgumentException) or logging an error
and returning a failure status; include a brief JavaDoc or comment on supported
serviceType values so callers know expected behavior.
| public Result audit(APIMessage msg, APIEvent rsp) { | ||
| return new APIAuditor.Result(rsp.isSuccess() ? ((APIAddExternalServiceConfigurationEvent) rsp).getInventory().getUuid() : "", ExternalServiceConfigurationVO.class); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
audit() 方法存在潜在 NPE 风险。
当 rsp.isSuccess() 为 true 但 getInventory() 返回 null 时,调用 getInventory().getUuid() 会抛出 NullPointerException。
🐛 建议修复
`@Override`
public Result audit(APIMessage msg, APIEvent rsp) {
- return new APIAuditor.Result(rsp.isSuccess() ? ((APIAddExternalServiceConfigurationEvent) rsp).getInventory().getUuid() : "", ExternalServiceConfigurationVO.class);
+ APIAddExternalServiceConfigurationEvent event = (APIAddExternalServiceConfigurationEvent) rsp;
+ String uuid = rsp.isSuccess() && event.getInventory() != null ? event.getInventory().getUuid() : "";
+ return new APIAuditor.Result(uuid, ExternalServiceConfigurationVO.class);
}📝 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.
| public Result audit(APIMessage msg, APIEvent rsp) { | |
| return new APIAuditor.Result(rsp.isSuccess() ? ((APIAddExternalServiceConfigurationEvent) rsp).getInventory().getUuid() : "", ExternalServiceConfigurationVO.class); | |
| } | |
| public Result audit(APIMessage msg, APIEvent rsp) { | |
| APIAddExternalServiceConfigurationEvent event = (APIAddExternalServiceConfigurationEvent) rsp; | |
| String uuid = rsp.isSuccess() && event.getInventory() != null ? event.getInventory().getUuid() : ""; | |
| return new APIAuditor.Result(uuid, ExternalServiceConfigurationVO.class); | |
| } |
🤖 Prompt for AI Agents
In
`@header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsg.java`
around lines 54 - 56, The audit method in APIAddExternalServiceConfigurationMsg
currently assumes ((APIAddExternalServiceConfigurationEvent) rsp).getInventory()
is non-null, risking an NPE; update APIAddExternalServiceConfigurationMsg.audit
to safely cast rsp to APIAddExternalServiceConfigurationEvent, check
rsp.isSuccess() && event != null && event.getInventory() != null before calling
getUuid(), and pass an empty string to new APIAuditor.Result when any of those
checks fail (also guard against rsp not being an instance of
APIAddExternalServiceConfigurationEvent).
APIImpact DBImpact Resolves: ZCF-19 Change-Id: I726b676a6576716f6962646665707566676d6b65
6e3835e to
1ca0216
Compare
Resolves: ZCF-19
Change-Id: I77636f62676b6e697975786b6c77796b706e7861
sync from gitlab !9035