diff --git a/.gitconfig/hooks/commit-msg b/.gitconfig/hooks/commit-msg
index 26e2a97ba80..1e8c0a00b6b 100755
--- a/.gitconfig/hooks/commit-msg
+++ b/.gitconfig/hooks/commit-msg
@@ -132,7 +132,7 @@ def check_commit_msg(file_path):
FAIL = False
jira_patterns = [r"\bZSTAC-\d+\b", r"\bZSTACK-\d+\b", r"\bMINI-\d+\b",
- r"\bZOPS-\d+\b", r"\bZHCI-\d+\b", r"\bZSV-\d+\b"]
+ r"\bZOPS-\d+\b", r"\bZHCI-\d+\b", r"\bZSV-\d+\b", r"\bZCF-\d+\b"]
with open(file_path, 'r', encoding='utf8') as f:
lines = f.readlines()
full_lines = len(lines)
diff --git a/.gitconfig/hooks/prepare-commit-msg b/.gitconfig/hooks/prepare-commit-msg
index 28656de1be6..b6c4864a0c3 100755
--- a/.gitconfig/hooks/prepare-commit-msg
+++ b/.gitconfig/hooks/prepare-commit-msg
@@ -286,7 +286,7 @@ def get_tags(changed_folders, changed_paths):
def get_jiras():
jiras = []
jira_patterns = [r"\bZSTAC-\d+\b", r"\bZSTACK-\d+\b", r"\bMINI-\d+\b",
- r"\bZOPS-\d+\b", r"\bZHCI-\d+\b", r"\bZSV-\d+\b"]
+ r"\bZOPS-\d+\b", r"\bZHCI-\d+\b", r"\bZSV-\d+\b", r"\bZCF-\d+\b"]
bashCommand = "git rev-parse --abbrev-ref HEAD"
process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE)
diff --git a/conf/db/upgrade/V5.4.8__schema.sql b/conf/db/upgrade/V5.4.8__schema.sql
new file mode 100644
index 00000000000..c25be82bd70
--- /dev/null
+++ b/conf/db/upgrade/V5.4.8__schema.sql
@@ -0,0 +1,10 @@
+-- Add ExternalServiceConfiguration table
+CREATE TABLE IF NOT EXISTS `zstack`.`ExternalServiceConfigurationVO` (
+ `uuid` varchar(32) NOT NULL UNIQUE,
+ `serviceType` varchar(32) NOT NULL,
+ `configuration` text DEFAULT NULL,
+ `description` varchar(2048) DEFAULT NULL,
+ `lastOpDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `createDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
+ PRIMARY KEY (`uuid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
\ No newline at end of file
diff --git a/conf/persistence.xml b/conf/persistence.xml
index 33f4326f407..67362864053 100755
--- a/conf/persistence.xml
+++ b/conf/persistence.xml
@@ -222,5 +222,6 @@
org.zstack.header.network.l3.L3NetworkSequenceNumberVO
org.zstack.network.hostNetworkInterface.PhysicalSwitchVO
org.zstack.network.hostNetworkInterface.PhysicalSwitchPortVO
+ org.zstack.header.core.external.service.ExternalServiceConfigurationVO
diff --git a/conf/serviceConfig/externalService.xml b/conf/serviceConfig/externalService.xml
index cb2f6c05d86..ae96366aa8a 100644
--- a/conf/serviceConfig/externalService.xml
+++ b/conf/serviceConfig/externalService.xml
@@ -9,4 +9,21 @@
org.zstack.header.core.external.service.APIReloadExternalServiceMsg
+
+
+ org.zstack.header.core.external.service.APIAddExternalServiceConfigurationMsg
+
+
+
+ org.zstack.header.core.external.service.APIQueryExternalServiceConfigurationMsg
+ query
+
+
+
+ org.zstack.header.core.external.service.APIUpdateExternalServiceConfigurationMsg
+
+
+
+ org.zstack.header.core.external.service.APIDeleteExternalServiceConfigurationMsg
+
diff --git a/core/src/main/java/org/zstack/core/externalservice/ExternalService.java b/core/src/main/java/org/zstack/core/externalservice/ExternalService.java
index 2b816f00337..406b167f5ae 100755
--- a/core/src/main/java/org/zstack/core/externalservice/ExternalService.java
+++ b/core/src/main/java/org/zstack/core/externalservice/ExternalService.java
@@ -16,4 +16,8 @@ public interface ExternalService {
ExternalServiceCapabilities getExternalServiceCapabilities();
void reload();
+
+ String getServiceType();
+
+ void externalConfig(String serviceType);
}
diff --git a/core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java b/core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java
index b953329dc39..b62c060079d 100755
--- a/core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java
+++ b/core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java
@@ -1,19 +1,36 @@
package org.zstack.core.externalservice;
import org.springframework.beans.factory.annotation.Autowired;
+import org.zstack.core.CoreGlobalProperty;
+import org.zstack.core.GlobalProperty;
+import org.zstack.core.Platform;
+import org.zstack.core.asyncbatch.While;
import org.zstack.core.cloudbus.CloudBus;
+import org.zstack.core.cloudbus.CloudBusCallBack;
+import org.zstack.core.db.DatabaseFacade;
+import org.zstack.core.db.Q;
+import org.zstack.core.thread.ChainTask;
+import org.zstack.core.thread.SyncTaskChain;
+import org.zstack.core.thread.ThreadFacade;
+import org.zstack.core.workflow.SimpleFlowChain;
import org.zstack.header.AbstractService;
-import org.zstack.header.core.external.service.APIGetExternalServicesMsg;
-import org.zstack.header.core.external.service.APIGetExternalServicesReply;
-import org.zstack.header.core.external.service.APIReloadExternalServiceEvent;
-import org.zstack.header.core.external.service.APIReloadExternalServiceMsg;
-import org.zstack.header.core.external.service.ExternalServiceInventory;
-import org.zstack.header.core.external.service.ExternalServiceStatus;
+import org.zstack.header.core.Completion;
+import org.zstack.header.core.ReturnValueCompletion;
+import org.zstack.header.core.WhileDoneCompletion;
+import org.zstack.header.core.external.service.*;
+import org.zstack.header.core.workflow.*;
+import org.zstack.header.errorcode.ErrorCode;
+import org.zstack.header.errorcode.ErrorCodeList;
import org.zstack.header.errorcode.OperationFailureException;
+import org.zstack.header.managementnode.ManagementNodeVO;
+import org.zstack.header.managementnode.ManagementNodeVO_;
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.Message;
+import org.zstack.header.message.MessageReply;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
@@ -23,6 +40,10 @@
public class ExternalServiceManagerImpl extends AbstractService implements ExternalServiceManager {
@Autowired
public CloudBus bus;
+ @Autowired
+ private DatabaseFacade dbf;
+ @Autowired
+ private ThreadFacade thdf;
private final Map services = new ConcurrentHashMap<>();
@@ -71,8 +92,8 @@ public boolean stop() {
public void handleMessage(Message msg) {
if (msg instanceof APIMessage) {
handleApiMessage((APIMessage) msg);
- } else {
- bus.dealWithUnknownMessage(msg);
+ } else {
+ handleLocalMessage(msg);
}
}
@@ -81,6 +102,20 @@ public void handleApiMessage(APIMessage msg) {
handle((APIGetExternalServicesMsg) msg);
} else if (msg instanceof APIReloadExternalServiceMsg) {
handle((APIReloadExternalServiceMsg) msg);
+ } else if (msg instanceof APIAddExternalServiceConfigurationMsg){
+ handle((APIAddExternalServiceConfigurationMsg) msg);
+ } else if (msg instanceof APIUpdateExternalServiceConfigurationMsg) {
+ handle((APIUpdateExternalServiceConfigurationMsg) msg);
+ } else if (msg instanceof APIDeleteExternalServiceConfigurationMsg) {
+ handle((APIDeleteExternalServiceConfigurationMsg) msg);
+ } else {
+ bus.dealWithUnknownMessage(msg);
+ }
+ }
+
+ private void handleLocalMessage(Message msg) {
+ if (msg instanceof ApplyExternalServiceConfigurationMsg) {
+ handle((ApplyExternalServiceConfigurationMsg) msg);
} else {
bus.dealWithUnknownMessage(msg);
}
@@ -117,12 +152,283 @@ private void handle(APIGetExternalServicesMsg msg) {
inv.setName(name);
inv.setStatus(service.isAlive() ? ExternalServiceStatus.RUNNING.toString() : ExternalServiceStatus.STOPPED.toString());
inv.setCapabilities(service.getExternalServiceCapabilities());
+ inv.setServiceType(service.getServiceType());
reply.getInventories().add(inv);
});
bus.reply(msg, reply);
}
+ private void handle(APIAddExternalServiceConfigurationMsg msg ){
+ APIAddExternalServiceConfigurationEvent event = new APIAddExternalServiceConfigurationEvent(msg.getId());
+
+ thdf.chainSubmit(new ChainTask(msg) {
+ @Override
+ public void run(SyncTaskChain chain) {
+ createExternalServiceConfiguration(msg, event, new Completion(chain) {
+ @Override
+ public void success() {
+ bus.publish(event);
+ chain.next();
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ event.setError(errorCode);
+ bus.publish(event);
+ chain.next();
+ }
+ });
+ }
+
+ @Override
+ public String getSyncSignature() {
+ return String.format("create-update-delete-external-service-configuration-%s", msg.getExternalServiceType());
+ }
+
+ @Override
+ public String getName() {
+ return String.format("create-external-service-configuration-type-%s", msg.getExternalServiceType());
+ }
+ });
+
+ }
+
+ private void createExternalServiceConfiguration(APIAddExternalServiceConfigurationMsg msg, APIAddExternalServiceConfigurationEvent evt, Completion completion) {
+ // create db record
+ ExternalServiceConfigurationVO configurationVO = new ExternalServiceConfigurationVO();
+ configurationVO.setUuid(Platform.getUuid());
+ configurationVO.setServiceType(msg.getExternalServiceType());
+ configurationVO.setConfiguration(msg.getConfiguration());
+ configurationVO.setDescription(msg.getDescription());
+ configurationVO = dbf.persistAndRefresh(configurationVO);
+
+ ExternalServiceConfigurationInventory inv = ExternalServiceConfigurationInventory.valueOf(configurationVO);
+
+ applyExternalServiceConfigurationToAllNodes(configurationVO.getServiceType(), new ReturnValueCompletion>(completion) {
+ @Override
+ public void success(List returnValue) {
+ evt.setInventory(inv);
+ completion.success();
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ completion.fail(errorCode);
+ }
+ });
+ }
+
+ private void handle(APIUpdateExternalServiceConfigurationMsg msg){
+ APIUpdateExternalServiceConfigurationEvent event = new APIUpdateExternalServiceConfigurationEvent(msg.getId());
+
+ thdf.chainSubmit(new ChainTask(msg) {
+ @Override
+ public void run(SyncTaskChain chain) {
+ updateExternalServiceConfiguration(msg, event, new Completion(chain) {
+ @Override
+ public void success() {
+ bus.publish(event);
+ chain.next();
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ event.setError(errorCode);
+ bus.publish(event);
+ chain.next();
+ }
+ });
+ }
+
+ @Override
+ public String getSyncSignature() {
+ return String.format("create-update-delete-external-service-configuration-%s", msg.getUuid());
+ }
+
+ @Override
+ public String getName() {
+ return String.format("update-external-service-configuration-%s", msg.getUuid());
+ }
+ });
+ }
+
+ 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;
+ }
+
+ if (msg.getDescription() != null) {
+ vo.setDescription(msg.getDescription());
+ }
+ vo = dbf.updateAndRefresh(vo);
+
+ evt.setInventory(ExternalServiceConfigurationInventory.valueOf(vo));
+ completion.success();
+ }
+
+ private void handle(APIDeleteExternalServiceConfigurationMsg msg) {
+ APIDeleteExternalServiceConfigurationEvent event = new APIDeleteExternalServiceConfigurationEvent(msg.getId());
+
+ thdf.chainSubmit(new ChainTask(msg) {
+ @Override
+ public void run(SyncTaskChain chain) {
+ deleteExternalServiceConfiguration(msg, event, new Completion(chain) {
+ @Override
+ public void success() {
+ bus.publish(event);
+ chain.next();
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ event.setError(errorCode);
+ bus.publish(event);
+ chain.next();
+ }
+ });
+ }
+
+ @Override
+ public String getSyncSignature() {
+ return String.format("create-update-delete-external-service-configuration-%s", msg.getUuid());
+ }
+
+ @Override
+ public String getName() {
+ return String.format("delete-external-service-configuration-%s", msg.getUuid());
+ }
+ });
+ }
+
+ private void deleteExternalServiceConfiguration(APIDeleteExternalServiceConfigurationMsg msg, APIDeleteExternalServiceConfigurationEvent evt, Completion completion) {
+ // delete db record
+ ExternalServiceConfigurationVO vo = dbf.findByUuid(msg.getUuid(), ExternalServiceConfigurationVO.class);
+ String serviceType;
+ if (vo != null) {
+ serviceType = vo.getServiceType();
+ dbf.remove(vo);
+ } else {
+ completion.success();
+ return;
+ }
+
+ applyExternalServiceConfigurationToAllNodes(serviceType, new ReturnValueCompletion>(completion) {
+ @Override
+ public void success(List returnValue) {
+ completion.success();
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ completion.fail(errorCode);
+ }
+ });
+ }
+
+ private void applyExternalServiceConfigurationToAllNodes(String serviceType, ReturnValueCompletion> completion) {
+ final List results = Collections.synchronizedList(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 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);
+
+ if (!reply.isSuccess()) {
+ result.setErrorCode(reply.getError());
+ errorCode[0] = reply.getError();
+ whileCompletion.allDone();
+ return;
+ }
+ whileCompletion.done();
+ }
+ });
+ }).run(new WhileDoneCompletion(trigger) {
+ @Override
+ public void done(ErrorCodeList errorCodeList) {
+ if (errorCode[0] != null) {
+ trigger.fail(errorCode[0]);
+ return;
+ }
+ trigger.next();
+ }
+ });
+ }
+
+ @Override
+ public void rollback(FlowRollback trigger, Map data) {
+ trigger.rollback();
+ }
+ }).done(new FlowDoneHandler(completion) {
+ @Override
+ public void handle(Map data) {
+ completion.success(results);
+ }
+ }).error(new FlowErrorHandler(completion) {
+ @Override
+ public void handle(ErrorCode errCode, Map data) {
+ completion.fail(errCode);
+ }
+ }).start();
+ }
+
+ private void handle(ApplyExternalServiceConfigurationMsg msg) {
+ ApplyExternalServiceConfigurationReply reply = new ApplyExternalServiceConfigurationReply();
+
+ regenerateExternalServiceConfiguration(msg.getServiceType(), new ReturnValueCompletion(msg) {
+ @Override
+ public void success(String returnValue) {
+ reply.setValue(returnValue);
+ reply.setManagementNodeUuid(Platform.getManagementServerId());
+ bus.reply(msg, reply);
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ reply.setError(errorCode);
+ bus.reply(msg, reply);
+ }
+ });
+ }
+
+ private void regenerateExternalServiceConfiguration(String serviceType, ReturnValueCompletion completion) {
+ if (CoreGlobalProperty.UNIT_TEST_ON) {
+ completion.success(serviceType);
+ return;
+ }
+ for (ExternalService service : services.values()) {
+ if (serviceType.equals(service.getServiceType())) {
+ try{
+ service.externalConfig(serviceType);
+ completion.success(serviceType);
+ } catch (Exception e) {
+ completion.fail(operr("failed to apply external service configuration for type [%s]: %s", serviceType, e.getMessage()));
+ }
+ return;
+ }
+ }
+ completion.fail(operr("unable to find external service type [%s]", serviceType));
+ }
+
@Override
public String getId() {
return bus.makeLocalServiceId(SERVICE_ID);
diff --git a/externalservice/src/main/java/org/zstack/externalservice/cronjob/CronJobImpl.java b/externalservice/src/main/java/org/zstack/externalservice/cronjob/CronJobImpl.java
index 4bd6c1d7788..5d78b6f1b67 100755
--- a/externalservice/src/main/java/org/zstack/externalservice/cronjob/CronJobImpl.java
+++ b/externalservice/src/main/java/org/zstack/externalservice/cronjob/CronJobImpl.java
@@ -33,6 +33,12 @@ public String getName() {
return String.format("cron-job-on-machine-%s", Platform.getManagementServerIp());
}
+
+ @Override
+ public String getServiceType() {
+ return "CronJob";
+ }
+
@Override
public void start() {
if (isAlive()) {
@@ -103,4 +109,7 @@ protected void scripts() {
}
}.execute();
}
+
+ @Override
+ public void externalConfig(String serviceType){}
}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationEvent.java b/header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationEvent.java
new file mode 100644
index 00000000000..7341efed929
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationEvent.java
@@ -0,0 +1,34 @@
+package org.zstack.header.core.external.service;
+
+import org.zstack.header.message.APIEvent;
+import org.zstack.header.rest.RestResponse;
+
+/**
+ * @Author: ya.wang
+ * @Date: 1/15/26 12:48 AM
+ */
+@RestResponse(allTo = "inventory")
+public class APIAddExternalServiceConfigurationEvent extends APIEvent {
+
+ private ExternalServiceConfigurationInventory inventory;
+
+ public APIAddExternalServiceConfigurationEvent() {}
+
+ public APIAddExternalServiceConfigurationEvent(String apiId) { super(apiId);}
+
+ public void setInventory(ExternalServiceConfigurationInventory inventory) {this.inventory = inventory;}
+
+ public ExternalServiceConfigurationInventory getInventory() {return inventory;}
+
+ public static APIAddExternalServiceConfigurationEvent __example__() {
+ APIAddExternalServiceConfigurationEvent event = new APIAddExternalServiceConfigurationEvent();
+ ExternalServiceConfigurationInventory inv = new ExternalServiceConfigurationInventory();
+
+ inv.setUuid(uuid());
+ inv.setServiceType("Prometheus2");
+ inv.setConfiguration("{}");
+ event.setInventory(inv);
+
+ return event;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationEventDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationEventDoc_zh_cn.groovy
new file mode 100644
index 00000000000..825f5eeb350
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationEventDoc_zh_cn.groovy
@@ -0,0 +1,32 @@
+package org.zstack.header.core.external.service
+
+import org.zstack.header.core.external.service.ExternalServiceConfigurationInventory
+import org.zstack.header.errorcode.ErrorCode
+
+doc {
+
+ title "添加外部服务配置返回"
+
+ ref {
+ name "inventory"
+ path "org.zstack.header.core.external.service.APIAddExternalServiceConfigurationEvent.inventory"
+ desc "外部服务配置详情"
+ type "ExternalServiceConfigurationInventory"
+ since "5.4.6"
+ clz ExternalServiceConfigurationInventory.class
+ }
+ field {
+ name "success"
+ desc "操作是否成功"
+ type "boolean"
+ since "5.4.6"
+ }
+ ref {
+ name "error"
+ path "org.zstack.header.core.external.service.APIAddExternalServiceConfigurationEvent.error"
+ desc "错误码,若不为null,则表示操作失败, 操作成功时该字段为null",false
+ type "ErrorCode"
+ since "5.4.6"
+ clz ErrorCode.class
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsg.java b/header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsg.java
new file mode 100644
index 00000000000..a6983f464db
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsg.java
@@ -0,0 +1,66 @@
+package org.zstack.header.core.external.service;
+
+import org.springframework.http.HttpMethod;
+import org.zstack.header.message.APICreateMessage;
+import org.zstack.header.message.APIEvent;
+import org.zstack.header.message.APIMessage;
+import org.zstack.header.message.APIParam;
+import org.zstack.header.other.APIAuditor;
+import org.zstack.header.rest.RestRequest;
+
+/**
+ * @Author: ya.wang
+ * @Date: 1/15/26 12:43 AM
+ */
+@RestRequest(
+ path = "/external/service/configuration",
+ method = HttpMethod.POST,
+ parameterName = "params",
+ responseClass = APIAddExternalServiceConfigurationEvent.class
+)
+public class APIAddExternalServiceConfigurationMsg extends APICreateMessage implements APIAuditor {
+ @APIParam
+ private String externalServiceType;
+ @APIParam(maxLength = 65535)
+ private String configuration;
+ @APIParam(maxLength = 2048, required = false)
+ private String description;
+
+ public String getExternalServiceType() {
+ return externalServiceType;
+ }
+
+ public void setExternalServiceType(String externalServiceType) {
+ this.externalServiceType = externalServiceType;
+ }
+
+ public String getConfiguration() {
+ return configuration;
+ }
+
+ public void setConfiguration(String configuration) {
+ this.configuration = configuration;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ @Override
+ public Result audit(APIMessage msg, APIEvent rsp) {
+ APIAddExternalServiceConfigurationEvent evt = (APIAddExternalServiceConfigurationEvent) rsp;
+ return new Result(rsp.isSuccess() ? evt.getInventory().getUuid(): "", ExternalServiceConfigurationVO.class);
+ }
+
+ public static APIAddExternalServiceConfigurationMsg __example__() {
+ APIAddExternalServiceConfigurationMsg msg = new APIAddExternalServiceConfigurationMsg();
+ msg.setExternalServiceType("Prometheus2");
+ msg.setConfiguration("{}");
+ msg.setDescription("description");
+ return msg;
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsgDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsgDoc_zh_cn.groovy
new file mode 100644
index 00000000000..b00beed805c
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/APIAddExternalServiceConfigurationMsgDoc_zh_cn.groovy
@@ -0,0 +1,94 @@
+package org.zstack.header.core.external.service
+
+import org.zstack.header.core.external.service.APIAddExternalServiceConfigurationEvent
+
+doc {
+ title "AddExternalServiceConfiguration"
+
+ category "externalService"
+
+ desc """新建外部服务配置"""
+
+ rest {
+ request {
+ url "POST /v1/external/service/configuration"
+
+ header (Authorization: 'OAuth the-session-uuid')
+
+ clz APIAddExternalServiceConfigurationMsg.class
+
+ desc """"""
+
+ params {
+
+ column {
+ name "externalServiceType"
+ enclosedIn "params"
+ desc "外部服务类型, 例如 Prometheus2"
+ location "body"
+ type "String"
+ optional false
+ since "5.4.6"
+ }
+ column {
+ name "configuration"
+ enclosedIn "params"
+ desc "外部服务配置, 使用 json 格式"
+ location "body"
+ type "String"
+ optional false
+ since "5.4.6"
+ }
+ column {
+ name "description"
+ enclosedIn "params"
+ desc "资源的详细描述"
+ location "body"
+ type "String"
+ optional true
+ since "5.4.6"
+ }
+ column {
+ name "resourceUuid"
+ enclosedIn "params"
+ desc "资源UUID"
+ location "body"
+ type "String"
+ optional true
+ since "5.4.6"
+ }
+ column {
+ name "tagUuids"
+ enclosedIn "params"
+ desc "标签UUID列表"
+ location "body"
+ type "List"
+ optional true
+ since "5.4.6"
+ }
+ column {
+ name "systemTags"
+ enclosedIn ""
+ desc "系统标签"
+ location "body"
+ type "List"
+ optional true
+ since "5.4.6"
+ }
+ column {
+ name "userTags"
+ enclosedIn ""
+ desc "用户标签"
+ location "body"
+ type "List"
+ optional true
+ since "5.4.6"
+ }
+ }
+ }
+
+ response {
+ clz APIAddExternalServiceConfigurationEvent.class
+ }
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationEvent.java b/header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationEvent.java
new file mode 100644
index 00000000000..d7ac0bf2f65
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationEvent.java
@@ -0,0 +1,21 @@
+package org.zstack.header.core.external.service;
+
+import org.zstack.header.message.APIEvent;
+import org.zstack.header.rest.RestResponse;
+
+/**
+ * @Author: ya.wang
+ * @Date: 1/15/26 1:47 AM
+ */
+@RestResponse
+public class APIDeleteExternalServiceConfigurationEvent extends APIEvent {
+ public APIDeleteExternalServiceConfigurationEvent() {}
+
+ public APIDeleteExternalServiceConfigurationEvent(String apiId) { super(apiId); }
+
+ public static APIDeleteExternalServiceConfigurationEvent __example__() {
+ APIDeleteExternalServiceConfigurationEvent event = new APIDeleteExternalServiceConfigurationEvent();
+ event.setSuccess(true);
+ return event;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationEventDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationEventDoc_zh_cn.groovy
new file mode 100644
index 00000000000..8f509bec85f
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationEventDoc_zh_cn.groovy
@@ -0,0 +1,23 @@
+package org.zstack.header.core.external.service
+
+import org.zstack.header.errorcode.ErrorCode
+
+doc {
+
+ title "删除外部服务配置返回"
+
+ field {
+ name "success"
+ desc "操作是否成功"
+ type "boolean"
+ since "5.4.6"
+ }
+ ref {
+ name "error"
+ path "org.zstack.header.core.external.service.APIDeleteExternalServiceConfigurationEvent.error"
+ desc "错误码,若不为null,则表示操作失败, 操作成功时该字段为null",false
+ type "ErrorCode"
+ since "5.4.6"
+ clz ErrorCode.class
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationMsg.java b/header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationMsg.java
new file mode 100644
index 00000000000..b04729437f2
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationMsg.java
@@ -0,0 +1,42 @@
+package org.zstack.header.core.external.service;
+
+import org.springframework.http.HttpMethod;
+import org.zstack.header.message.APIDeleteMessage;
+import org.zstack.header.message.APIEvent;
+import org.zstack.header.message.APIMessage;
+import org.zstack.header.message.APIParam;
+import org.zstack.header.other.APIAuditor;
+import org.zstack.header.rest.RestRequest;
+
+/**
+ * @Author: ya.wang
+ * @Date: 1/15/26 1:44 AM
+ */
+@RestRequest(
+ path = "/external/service/configuration/{uuid}",
+ responseClass = APIDeleteExternalServiceConfigurationEvent.class,
+ method = HttpMethod.DELETE
+)
+public class APIDeleteExternalServiceConfigurationMsg extends APIDeleteMessage implements APIAuditor {
+ @APIParam(resourceType = ExternalServiceConfigurationVO.class, successIfResourceNotExisting = true)
+ private String uuid;
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ @Override
+ public Result audit(APIMessage msg, APIEvent rsp) {
+ return new APIAuditor.Result(((APIDeleteExternalServiceConfigurationMsg)msg).getUuid(), ExternalServiceConfigurationVO.class);
+ }
+
+ public static APIDeleteExternalServiceConfigurationMsg __example__() {
+ APIDeleteExternalServiceConfigurationMsg msg = new APIDeleteExternalServiceConfigurationMsg();
+ msg.setUuid(uuid());
+ return msg;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationMsgDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationMsgDoc_zh_cn.groovy
new file mode 100644
index 00000000000..803c56a695b
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/APIDeleteExternalServiceConfigurationMsgDoc_zh_cn.groovy
@@ -0,0 +1,67 @@
+package org.zstack.header.core.external.service
+
+import org.zstack.header.core.external.service.APIDeleteExternalServiceConfigurationEvent
+
+doc {
+ title "DeleteExternalServiceConfiguration"
+
+ category "externalService"
+
+ desc """删除外部服务配置"""
+
+ rest {
+ request {
+ url "DELETE /v1/external/service/configuration/{uuid}"
+
+ header (Authorization: 'OAuth the-session-uuid')
+
+ clz APIDeleteExternalServiceConfigurationMsg.class
+
+ desc """"""
+
+ params {
+
+ column {
+ name "uuid"
+ enclosedIn ""
+ desc "资源的UUID,唯一标示该资源"
+ location "url"
+ type "String"
+ optional false
+ since "5.4.6"
+ }
+ column {
+ name "deleteMode"
+ enclosedIn ""
+ desc "删除模式(Permissive / Enforcing,Permissive)"
+ location "body"
+ type "String"
+ optional true
+ since "5.4.6"
+ }
+ column {
+ name "systemTags"
+ enclosedIn ""
+ desc "系统标签"
+ location "body"
+ type "List"
+ optional true
+ since "5.4.6"
+ }
+ column {
+ name "userTags"
+ enclosedIn ""
+ desc "用户标签"
+ location "body"
+ type "List"
+ optional true
+ since "5.4.6"
+ }
+ }
+ }
+
+ response {
+ clz APIDeleteExternalServiceConfigurationEvent.class
+ }
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationMsg.java b/header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationMsg.java
new file mode 100644
index 00000000000..1ec870e2b86
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationMsg.java
@@ -0,0 +1,24 @@
+package org.zstack.header.core.external.service;
+
+import org.springframework.http.HttpMethod;
+import org.zstack.header.query.APIQueryMessage;
+import org.zstack.header.query.AutoQuery;
+import org.zstack.header.rest.RestRequest;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @Author: ya.wang
+ * @Date: 1/15/26 1:36 AM
+ */
+@AutoQuery(replyClass = APIQueryExternalServiceConfigurationReply.class, inventoryClass = ExternalServiceConfigurationInventory.class)
+@RestRequest(
+ path = "/external/service/configuration",
+ optionalPaths = {"/external/service/configuration/{uuid}"},
+ method = HttpMethod.GET,
+ responseClass = APIQueryExternalServiceConfigurationReply.class
+)
+public class APIQueryExternalServiceConfigurationMsg extends APIQueryMessage {
+ public static List __example__() {return Collections.singletonList("uuid=" + uuid());}
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationMsgDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationMsgDoc_zh_cn.groovy
new file mode 100644
index 00000000000..767e650f547
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationMsgDoc_zh_cn.groovy
@@ -0,0 +1,31 @@
+package org.zstack.header.core.external.service
+
+import org.zstack.header.core.external.service.APIQueryExternalServiceConfigurationReply
+import org.zstack.header.query.APIQueryMessage
+
+doc {
+ title "QueryExternalServiceConfiguration"
+
+ category "externalService"
+
+ desc """查询外部服务配置"""
+
+ 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 """"""
+
+ params APIQueryMessage.class
+ }
+
+ response {
+ clz APIQueryExternalServiceConfigurationReply.class
+ }
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationReply.java b/header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationReply.java
new file mode 100644
index 00000000000..87456312eeb
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationReply.java
@@ -0,0 +1,32 @@
+package org.zstack.header.core.external.service;
+
+import org.zstack.header.query.APIQueryReply;
+import org.zstack.header.rest.RestResponse;
+
+import java.util.List;
+
+import static org.zstack.utils.CollectionDSL.list;
+
+/**
+ * @Author: ya.wang
+ * @Date: 1/15/26 1:39 AM
+ */
+@RestResponse(allTo = "inventories")
+public class APIQueryExternalServiceConfigurationReply extends APIQueryReply {
+ private List inventories;
+
+ public List getInventories() {return inventories;}
+
+ public void setInventories(List inventories) {this.inventories = inventories;}
+
+ public static APIQueryExternalServiceConfigurationReply __example__() {
+ APIQueryExternalServiceConfigurationReply reply = new APIQueryExternalServiceConfigurationReply();
+ ExternalServiceConfigurationInventory inv = new ExternalServiceConfigurationInventory();
+
+ inv.setUuid(uuid());
+ inv.setServiceType("Prometheus2");
+ inv.setConfiguration("{}");
+ reply.setInventories(list(inv));
+ return reply;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationReplyDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationReplyDoc_zh_cn.groovy
new file mode 100644
index 00000000000..3b68159d976
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/APIQueryExternalServiceConfigurationReplyDoc_zh_cn.groovy
@@ -0,0 +1,32 @@
+package org.zstack.header.core.external.service
+
+import org.zstack.header.core.external.service.ExternalServiceConfigurationInventory
+import org.zstack.header.errorcode.ErrorCode
+
+doc {
+
+ title "在这里输入结构的名称"
+
+ ref {
+ name "inventories"
+ path "org.zstack.header.core.external.service.APIQueryExternalServiceConfigurationReply.inventories"
+ desc "null"
+ type "List"
+ since "5.4.6"
+ clz ExternalServiceConfigurationInventory.class
+ }
+ field {
+ name "success"
+ desc ""
+ type "boolean"
+ since "5.4.6"
+ }
+ ref {
+ name "error"
+ path "org.zstack.header.core.external.service.APIQueryExternalServiceConfigurationReply.error"
+ desc "错误码,若不为null,则表示操作失败, 操作成功时该字段为null",false
+ type "ErrorCode"
+ since "5.4.6"
+ clz ErrorCode.class
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationEvent.java b/header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationEvent.java
new file mode 100644
index 00000000000..c7e5dae73b5
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationEvent.java
@@ -0,0 +1,30 @@
+package org.zstack.header.core.external.service;
+
+import org.zstack.header.message.APIEvent;
+import org.zstack.header.rest.RestResponse;
+
+/**
+ * @Author: ya.wang
+ * @Date: 1/15/26 1:53 AM
+ */
+@RestResponse(allTo = "inventory")
+public class APIUpdateExternalServiceConfigurationEvent extends APIEvent {
+ private ExternalServiceConfigurationInventory inventory;
+
+ public APIUpdateExternalServiceConfigurationEvent() {}
+
+ public APIUpdateExternalServiceConfigurationEvent(String apiId) { super(apiId); }
+
+ public ExternalServiceConfigurationInventory getInventory() {return inventory;}
+
+ public void setInventory(ExternalServiceConfigurationInventory inventory) {this.inventory = inventory;}
+
+ public static APIUpdateExternalServiceConfigurationEvent __example__() {
+ APIUpdateExternalServiceConfigurationEvent event = new APIUpdateExternalServiceConfigurationEvent();
+ ExternalServiceConfigurationInventory inv = new ExternalServiceConfigurationInventory();
+
+ inv.setUuid(uuid());
+ event.setInventory(inv);
+ return event;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationEventDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationEventDoc_zh_cn.groovy
new file mode 100644
index 00000000000..44efa37caf5
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationEventDoc_zh_cn.groovy
@@ -0,0 +1,32 @@
+package org.zstack.header.core.external.service
+
+import org.zstack.header.core.external.service.ExternalServiceConfigurationInventory
+import org.zstack.header.errorcode.ErrorCode
+
+doc {
+
+ title "更新外部服务配置"
+
+ ref {
+ name "inventory"
+ path "org.zstack.header.core.external.service.APIUpdateExternalServiceConfigurationEvent.inventory"
+ desc "null"
+ type "ExternalServiceConfigurationInventory"
+ since "5.4.6"
+ clz ExternalServiceConfigurationInventory.class
+ }
+ field {
+ name "success"
+ desc ""
+ type "boolean"
+ since "5.4.6"
+ }
+ ref {
+ name "error"
+ path "org.zstack.header.core.external.service.APIUpdateExternalServiceConfigurationEvent.error"
+ desc "错误码,若不为null,则表示操作失败, 操作成功时该字段为null",false
+ type "ErrorCode"
+ since "5.4.6"
+ clz ErrorCode.class
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationMsg.java b/header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationMsg.java
new file mode 100644
index 00000000000..518bb0e55be
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationMsg.java
@@ -0,0 +1,55 @@
+package org.zstack.header.core.external.service;
+
+import org.springframework.http.HttpMethod;
+import org.zstack.header.message.APIEvent;
+import org.zstack.header.message.APIMessage;
+import org.zstack.header.message.APIParam;
+import org.zstack.header.other.APIAuditor;
+import org.zstack.header.rest.RestRequest;
+
+/**
+ * @Author: ya.wang
+ * @Date: 1/15/26 1:49 AM
+ */
+@RestRequest(
+ path = "/external/service/configuration/{uuid}",
+ isAction = true,
+ method = HttpMethod.PUT,
+ responseClass = APIUpdateExternalServiceConfigurationEvent.class
+)
+public class APIUpdateExternalServiceConfigurationMsg extends APIMessage implements APIAuditor {
+ @APIParam(resourceType = ExternalServiceConfigurationVO.class, maxLength = 32, operationTarget = true)
+ private String uuid;
+
+
+ @APIParam
+ private String description;
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ @Override
+ public Result audit(APIMessage msg, APIEvent rsp) {
+ return new APIAuditor.Result(((APIUpdateExternalServiceConfigurationMsg)msg).getUuid(), ExternalServiceConfigurationVO.class);
+ }
+
+ public static APIUpdateExternalServiceConfigurationMsg __example__() {
+ APIUpdateExternalServiceConfigurationMsg msg = new APIUpdateExternalServiceConfigurationMsg();
+ msg.setUuid(uuid());
+ msg.setDescription("description");
+ return msg;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationMsgDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationMsgDoc_zh_cn.groovy
new file mode 100644
index 00000000000..53087e362e8
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/APIUpdateExternalServiceConfigurationMsgDoc_zh_cn.groovy
@@ -0,0 +1,67 @@
+package org.zstack.header.core.external.service
+
+import org.zstack.header.core.external.service.APIUpdateExternalServiceConfigurationEvent
+
+doc {
+ title "UpdateExternalServiceConfiguration"
+
+ category "externalService"
+
+ desc """在这里填写API描述"""
+
+ rest {
+ request {
+ url "PUT /v1/external/service/configuration/{uuid}"
+
+ header (Authorization: 'OAuth the-session-uuid')
+
+ clz APIUpdateExternalServiceConfigurationMsg.class
+
+ desc """"""
+
+ params {
+
+ column {
+ name "uuid"
+ enclosedIn "updateExternalServiceConfiguration"
+ desc "资源的UUID,唯一标示该资源"
+ location "url"
+ type "String"
+ optional false
+ since "5.4.6"
+ }
+ column {
+ name "description"
+ enclosedIn "updateExternalServiceConfiguration"
+ desc "资源的详细描述"
+ location "body"
+ type "String"
+ optional false
+ since "5.4.6"
+ }
+ column {
+ name "systemTags"
+ enclosedIn ""
+ desc "系统标签"
+ location "body"
+ type "List"
+ optional true
+ since "5.4.6"
+ }
+ column {
+ name "userTags"
+ enclosedIn ""
+ desc "用户标签"
+ location "body"
+ type "List"
+ optional true
+ since "5.4.6"
+ }
+ }
+ }
+
+ response {
+ clz APIUpdateExternalServiceConfigurationEvent.class
+ }
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/core/external/service/ApplyExternalConfigurationResult.java b/header/src/main/java/org/zstack/header/core/external/service/ApplyExternalConfigurationResult.java
new file mode 100644
index 00000000000..66a75a20cc9
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/ApplyExternalConfigurationResult.java
@@ -0,0 +1,39 @@
+package org.zstack.header.core.external.service;
+
+import org.zstack.header.errorcode.ErrorCode;
+
+/**
+ * @Author: ya.wang
+ * @Date: 1/15/26 2:50 AM
+ */
+public class ApplyExternalConfigurationResult {
+
+ private String managementNodeUuid;
+ private ErrorCode errorCode;
+ private boolean success = true;
+
+ public String getManagementNodeUuid() {
+ return managementNodeUuid;
+ }
+
+ public void setManagementNodeUuid(String managementNodeUuid) {
+ this.managementNodeUuid = managementNodeUuid;
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public void setSuccess(boolean success) {
+ this.success = success;
+ }
+
+ public ErrorCode getErrorCode() {
+ return errorCode;
+ }
+
+ public void setErrorCode(ErrorCode errorCode) {
+ this.success = false;
+ this.errorCode = errorCode;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/ApplyExternalServiceConfigurationMsg.java b/header/src/main/java/org/zstack/header/core/external/service/ApplyExternalServiceConfigurationMsg.java
new file mode 100644
index 00000000000..dd82db96f72
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/ApplyExternalServiceConfigurationMsg.java
@@ -0,0 +1,19 @@
+package org.zstack.header.core.external.service;
+
+import org.zstack.header.message.NeedReplyMessage;
+
+/**
+ * @Author: ya.wang
+ * @Date: 1/15/26 2:59 AM
+ */
+public class ApplyExternalServiceConfigurationMsg extends NeedReplyMessage {
+ private String serviceType;
+
+ public String getServiceType() {
+ return serviceType;
+ }
+
+ public void setServiceType(String serviceType) {
+ this.serviceType = serviceType;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/ApplyExternalServiceConfigurationReply.java b/header/src/main/java/org/zstack/header/core/external/service/ApplyExternalServiceConfigurationReply.java
new file mode 100644
index 00000000000..08c25e04266
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/ApplyExternalServiceConfigurationReply.java
@@ -0,0 +1,28 @@
+package org.zstack.header.core.external.service;
+
+import org.zstack.header.message.MessageReply;
+
+/**
+ * @Author: ya.wang
+ * @Date: 1/15/26 3:26 AM
+ */
+public class ApplyExternalServiceConfigurationReply extends MessageReply {
+ private String managementNodeUuid;
+ private String value;
+
+ public String getManagementNodeUuid() {
+ return managementNodeUuid;
+ }
+
+ public void setManagementNodeUuid(String managementNodeUuid) {
+ this.managementNodeUuid = managementNodeUuid;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationInventory.java b/header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationInventory.java
new file mode 100644
index 00000000000..b21bba8ad81
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationInventory.java
@@ -0,0 +1,88 @@
+package org.zstack.header.core.external.service;
+
+import org.zstack.header.search.Inventory;
+
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @Author: ya.wang
+ * @Date: 1/15/26 1:31 AM
+ */
+@Inventory(mappingVOClass = ExternalServiceConfigurationVO.class)
+public class ExternalServiceConfigurationInventory {
+ private String uuid;
+ private String serviceType;
+ private String configuration;
+ private String description;
+ private Timestamp createDate;
+ private Timestamp lastOpDate;
+
+ 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;
+ }
+
+ public static List valueOf(Collection vos) {
+ List invs = new ArrayList();
+ for (ExternalServiceConfigurationVO vo : vos) {
+ invs.add(valueOf(vo));
+ }
+ return invs;
+ }
+
+ public Timestamp getLastOpDate() {
+ return lastOpDate;
+ }
+
+ public void setLastOpDate(Timestamp lastOpDate) {
+ this.lastOpDate = lastOpDate;
+ }
+
+ public Timestamp getCreateDate() {
+ return createDate;
+ }
+
+ public void setCreateDate(Timestamp createDate) {
+ this.createDate = createDate;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getConfiguration() {
+ return configuration;
+ }
+
+ public void setConfiguration(String configuration) {
+ this.configuration = configuration;
+ }
+
+ public String getServiceType() {
+ return serviceType;
+ }
+
+ public void setServiceType(String serviceType) {
+ this.serviceType = serviceType;
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationInventoryDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationInventoryDoc_zh_cn.groovy
new file mode 100644
index 00000000000..127384df528
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationInventoryDoc_zh_cn.groovy
@@ -0,0 +1,45 @@
+package org.zstack.header.core.external.service
+
+import java.sql.Timestamp
+
+doc {
+
+ title "外部服务配置"
+
+ field {
+ name "uuid"
+ desc "资源的UUID,唯一标示该资源"
+ type "String"
+ since "5.4.6"
+ }
+ field {
+ name "serviceType"
+ desc "外部服务类型, 如 Prometheus2, FluentBitServer"
+ type "String"
+ since "5.4.6"
+ }
+ field {
+ name "configuration"
+ desc "外部服务配置, 使用 json 格式"
+ type "String"
+ since "5.4.6"
+ }
+ field {
+ name "description"
+ desc "资源的详细描述"
+ type "String"
+ since "5.4.6"
+ }
+ field {
+ name "createDate"
+ desc "创建时间"
+ type "Timestamp"
+ since "5.4.6"
+ }
+ field {
+ name "lastOpDate"
+ desc "最后一次修改时间"
+ type "Timestamp"
+ since "5.4.6"
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationVO.java b/header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationVO.java
new file mode 100644
index 00000000000..86f6ade106d
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationVO.java
@@ -0,0 +1,72 @@
+package org.zstack.header.core.external.service;
+
+import org.zstack.header.vo.ResourceVO;
+import org.zstack.header.vo.ToInventory;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.PreUpdate;
+import javax.persistence.Table;
+import java.sql.Timestamp;
+
+/**
+ * @Author: ya.wang
+ * @Date: 1/15/26 1:25 AM
+ */
+@Entity
+@Table
+public class ExternalServiceConfigurationVO extends ResourceVO implements ToInventory {
+ @Column
+ private String serviceType;
+ @Column
+ private String configuration;
+ @Column
+ private String description;
+ @Column
+ private Timestamp createDate;
+ @Column
+ private Timestamp lastOpDate;
+
+ public String getServiceType() {
+ return serviceType;
+ }
+
+ @PreUpdate
+ private void preUpdate() { lastOpDate = null; }
+
+ public void setServiceType(String serviceType) {
+ this.serviceType = serviceType;
+ }
+
+ public String getConfiguration() {
+ return configuration;
+ }
+
+ public void setConfiguration(String configuration) {
+ this.configuration = configuration;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public Timestamp getCreateDate() {
+ return createDate;
+ }
+
+ public void setCreateDate(Timestamp createDate) {
+ this.createDate = createDate;
+ }
+
+ public Timestamp getLastOpDate() {
+ return lastOpDate;
+ }
+
+ public void setLastOpDate(Timestamp lastOpDate) {
+ this.lastOpDate = lastOpDate;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationVO_.java b/header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationVO_.java
new file mode 100644
index 00000000000..5b7d0fb7342
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/core/external/service/ExternalServiceConfigurationVO_.java
@@ -0,0 +1,19 @@
+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 serviceType;
+ public static volatile SingularAttribute configuration;
+ public static volatile SingularAttribute description;
+ public static volatile SingularAttribute createDate;
+ public static volatile SingularAttribute lastOpDate;
+}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/ExternalServiceInventory.java b/header/src/main/java/org/zstack/header/core/external/service/ExternalServiceInventory.java
index e1b14c73baa..bddfad86a84 100644
--- a/header/src/main/java/org/zstack/header/core/external/service/ExternalServiceInventory.java
+++ b/header/src/main/java/org/zstack/header/core/external/service/ExternalServiceInventory.java
@@ -4,6 +4,7 @@ public class ExternalServiceInventory {
private String name;
private String status;
private ExternalServiceCapabilities capabilities;
+ private String serviceType;
public String getName() {
return name;
@@ -29,6 +30,14 @@ public void setCapabilities(ExternalServiceCapabilities capabilities) {
this.capabilities = capabilities;
}
+ public String getServiceType() {
+ return serviceType;
+ }
+
+ public void setServiceType(String serviceType) {
+ this.serviceType = serviceType;
+ }
+
public static ExternalServiceInventory __example__() {
ExternalServiceInventory inv = new ExternalServiceInventory();
inv.setName("prometheus");
@@ -36,6 +45,7 @@ public static ExternalServiceInventory __example__() {
ExternalServiceCapabilities cap = new ExternalServiceCapabilities();
cap.setReloadConfig(true);
inv.setCapabilities(cap);
+ inv.setServiceType("Prometheus2");
return inv;
}
}
diff --git a/header/src/main/java/org/zstack/header/core/external/service/RBACInfo.java b/header/src/main/java/org/zstack/header/core/external/service/RBACInfo.java
index 21b5c6b03e0..4537d62ee06 100644
--- a/header/src/main/java/org/zstack/header/core/external/service/RBACInfo.java
+++ b/header/src/main/java/org/zstack/header/core/external/service/RBACInfo.java
@@ -9,7 +9,11 @@ public void permissions() {
permissionBuilder()
.adminOnlyAPIs(
APIGetExternalServicesMsg.class,
- APIReloadExternalServiceMsg.class
+ APIReloadExternalServiceMsg.class,
+ APIAddExternalServiceConfigurationMsg.class,
+ APIQueryExternalServiceConfigurationMsg.class,
+ APIUpdateExternalServiceConfigurationMsg.class,
+ APIDeleteExternalServiceConfigurationMsg.class
).build();
}
diff --git a/sdk/src/main/java/SourceClassMap.java b/sdk/src/main/java/SourceClassMap.java
index 976ae5d4e48..8ad3e20530f 100644
--- a/sdk/src/main/java/SourceClassMap.java
+++ b/sdk/src/main/java/SourceClassMap.java
@@ -244,6 +244,7 @@ public class SourceClassMap {
put("org.zstack.header.console.ConsoleProxyAgentInventory", "org.zstack.sdk.ConsoleProxyAgentInventory");
put("org.zstack.header.core.external.plugin.PluginDriverInventory", "org.zstack.sdk.PluginDriverInventory");
put("org.zstack.header.core.external.service.ExternalServiceCapabilities", "org.zstack.sdk.ExternalServiceCapabilities");
+ put("org.zstack.header.core.external.service.ExternalServiceConfigurationInventory", "org.zstack.sdk.ExternalServiceConfigurationInventory");
put("org.zstack.header.core.external.service.ExternalServiceInventory", "org.zstack.sdk.ExternalServiceInventory");
put("org.zstack.header.core.progress.ChainInfo", "org.zstack.sdk.ChainInfo");
put("org.zstack.header.core.progress.PendingTaskInfo", "org.zstack.sdk.PendingTaskInfo");
@@ -1045,6 +1046,7 @@ public class SourceClassMap {
put("org.zstack.sdk.ExternalPrimaryStorageInventory", "org.zstack.header.storage.addon.primary.ExternalPrimaryStorageInventory");
put("org.zstack.sdk.ExternalServiceCapabilities", "org.zstack.header.core.external.service.ExternalServiceCapabilities");
put("org.zstack.sdk.ExternalServiceCapabilitiesBuilder", "org.zstack.core.externalservice.ExternalServiceCapabilitiesBuilder");
+ put("org.zstack.sdk.ExternalServiceConfigurationInventory", "org.zstack.header.core.external.service.ExternalServiceConfigurationInventory");
put("org.zstack.sdk.ExternalServiceInventory", "org.zstack.header.core.external.service.ExternalServiceInventory");
put("org.zstack.sdk.FaultToleranceVmGroupInventory", "org.zstack.faulttolerance.entity.FaultToleranceVmGroupInventory");
put("org.zstack.sdk.FcHbaDeviceInventory", "org.zstack.storage.device.hba.FcHbaDeviceInventory");
diff --git a/sdk/src/main/java/org/zstack/sdk/AddExternalServiceConfigurationAction.java b/sdk/src/main/java/org/zstack/sdk/AddExternalServiceConfigurationAction.java
new file mode 100644
index 00000000000..10fdd3a583d
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/AddExternalServiceConfigurationAction.java
@@ -0,0 +1,113 @@
+package org.zstack.sdk;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.zstack.sdk.*;
+
+public class AddExternalServiceConfigurationAction extends AbstractAction {
+
+ private static final HashMap parameterMap = new HashMap<>();
+
+ private static final HashMap nonAPIParameterMap = new HashMap<>();
+
+ public static class Result {
+ public ErrorCode error;
+ public org.zstack.sdk.AddExternalServiceConfigurationResult value;
+
+ public Result throwExceptionIfError() {
+ if (error != null) {
+ throw new ApiException(
+ String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details)
+ );
+ }
+
+ return this;
+ }
+ }
+
+ @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
+ public java.lang.String externalServiceType;
+
+ @Param(required = true, maxLength = 65535, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
+ public java.lang.String configuration;
+
+ @Param(required = false, maxLength = 2048, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
+ public java.lang.String description;
+
+ @Param(required = false)
+ public java.lang.String resourceUuid;
+
+ @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
+ public java.util.List tagUuids;
+
+ @Param(required = false)
+ public java.util.List systemTags;
+
+ @Param(required = false)
+ public java.util.List userTags;
+
+ @Param(required = false)
+ public String sessionId;
+
+ @Param(required = false)
+ public String accessKeyId;
+
+ @Param(required = false)
+ public String accessKeySecret;
+
+ @Param(required = false)
+ public String requestIp;
+
+ @NonAPIParam
+ public long timeout = -1;
+
+ @NonAPIParam
+ public long pollingInterval = -1;
+
+
+ private Result makeResult(ApiResult res) {
+ Result ret = new Result();
+ if (res.error != null) {
+ ret.error = res.error;
+ return ret;
+ }
+
+ org.zstack.sdk.AddExternalServiceConfigurationResult value = res.getResult(org.zstack.sdk.AddExternalServiceConfigurationResult.class);
+ ret.value = value == null ? new org.zstack.sdk.AddExternalServiceConfigurationResult() : value;
+
+ return ret;
+ }
+
+ public Result call() {
+ ApiResult res = ZSClient.call(this);
+ return makeResult(res);
+ }
+
+ public void call(final Completion completion) {
+ ZSClient.call(this, new InternalCompletion() {
+ @Override
+ public void complete(ApiResult res) {
+ completion.complete(makeResult(res));
+ }
+ });
+ }
+
+ protected Map getParameterMap() {
+ return parameterMap;
+ }
+
+ protected Map getNonAPIParameterMap() {
+ return nonAPIParameterMap;
+ }
+
+ protected RestInfo getRestInfo() {
+ RestInfo info = new RestInfo();
+ info.httpMethod = "POST";
+ info.path = "/external/service/configuration";
+ info.needSession = true;
+ info.needPoll = true;
+ info.parameterName = "params";
+ return info;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/AddExternalServiceConfigurationResult.java b/sdk/src/main/java/org/zstack/sdk/AddExternalServiceConfigurationResult.java
new file mode 100644
index 00000000000..743bd847d7e
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/AddExternalServiceConfigurationResult.java
@@ -0,0 +1,14 @@
+package org.zstack.sdk;
+
+import org.zstack.sdk.ExternalServiceConfigurationInventory;
+
+public class AddExternalServiceConfigurationResult {
+ public ExternalServiceConfigurationInventory inventory;
+ public void setInventory(ExternalServiceConfigurationInventory inventory) {
+ this.inventory = inventory;
+ }
+ public ExternalServiceConfigurationInventory getInventory() {
+ return this.inventory;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/DeleteExternalServiceConfigurationAction.java b/sdk/src/main/java/org/zstack/sdk/DeleteExternalServiceConfigurationAction.java
new file mode 100644
index 00000000000..0d5d2841098
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/DeleteExternalServiceConfigurationAction.java
@@ -0,0 +1,104 @@
+package org.zstack.sdk;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.zstack.sdk.*;
+
+public class DeleteExternalServiceConfigurationAction extends AbstractAction {
+
+ private static final HashMap parameterMap = new HashMap<>();
+
+ private static final HashMap nonAPIParameterMap = new HashMap<>();
+
+ public static class Result {
+ public ErrorCode error;
+ public org.zstack.sdk.DeleteExternalServiceConfigurationResult value;
+
+ public Result throwExceptionIfError() {
+ if (error != null) {
+ throw new ApiException(
+ String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details)
+ );
+ }
+
+ return this;
+ }
+ }
+
+ @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
+ public java.lang.String uuid;
+
+ @Param(required = false)
+ public java.lang.String deleteMode = "Permissive";
+
+ @Param(required = false)
+ public java.util.List systemTags;
+
+ @Param(required = false)
+ public java.util.List userTags;
+
+ @Param(required = false)
+ public String sessionId;
+
+ @Param(required = false)
+ public String accessKeyId;
+
+ @Param(required = false)
+ public String accessKeySecret;
+
+ @Param(required = false)
+ public String requestIp;
+
+ @NonAPIParam
+ public long timeout = -1;
+
+ @NonAPIParam
+ public long pollingInterval = -1;
+
+
+ private Result makeResult(ApiResult res) {
+ Result ret = new Result();
+ if (res.error != null) {
+ ret.error = res.error;
+ return ret;
+ }
+
+ org.zstack.sdk.DeleteExternalServiceConfigurationResult value = res.getResult(org.zstack.sdk.DeleteExternalServiceConfigurationResult.class);
+ ret.value = value == null ? new org.zstack.sdk.DeleteExternalServiceConfigurationResult() : value;
+
+ return ret;
+ }
+
+ public Result call() {
+ ApiResult res = ZSClient.call(this);
+ return makeResult(res);
+ }
+
+ public void call(final Completion completion) {
+ ZSClient.call(this, new InternalCompletion() {
+ @Override
+ public void complete(ApiResult res) {
+ completion.complete(makeResult(res));
+ }
+ });
+ }
+
+ protected Map getParameterMap() {
+ return parameterMap;
+ }
+
+ protected Map getNonAPIParameterMap() {
+ return nonAPIParameterMap;
+ }
+
+ protected RestInfo getRestInfo() {
+ RestInfo info = new RestInfo();
+ info.httpMethod = "DELETE";
+ info.path = "/external/service/configuration/{uuid}";
+ info.needSession = true;
+ info.needPoll = true;
+ info.parameterName = "";
+ return info;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/DeleteExternalServiceConfigurationResult.java b/sdk/src/main/java/org/zstack/sdk/DeleteExternalServiceConfigurationResult.java
new file mode 100644
index 00000000000..22f9163d915
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/DeleteExternalServiceConfigurationResult.java
@@ -0,0 +1,7 @@
+package org.zstack.sdk;
+
+
+
+public class DeleteExternalServiceConfigurationResult {
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/ExternalServiceConfigurationInventory.java b/sdk/src/main/java/org/zstack/sdk/ExternalServiceConfigurationInventory.java
new file mode 100644
index 00000000000..05d6ca9e276
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/ExternalServiceConfigurationInventory.java
@@ -0,0 +1,55 @@
+package org.zstack.sdk;
+
+
+
+public class ExternalServiceConfigurationInventory {
+
+ public java.lang.String uuid;
+ public void setUuid(java.lang.String uuid) {
+ this.uuid = uuid;
+ }
+ public java.lang.String getUuid() {
+ return this.uuid;
+ }
+
+ public java.lang.String serviceType;
+ public void setServiceType(java.lang.String serviceType) {
+ this.serviceType = serviceType;
+ }
+ public java.lang.String getServiceType() {
+ return this.serviceType;
+ }
+
+ public java.lang.String configuration;
+ public void setConfiguration(java.lang.String configuration) {
+ this.configuration = configuration;
+ }
+ public java.lang.String getConfiguration() {
+ return this.configuration;
+ }
+
+ public java.lang.String description;
+ public void setDescription(java.lang.String description) {
+ this.description = description;
+ }
+ public java.lang.String getDescription() {
+ return this.description;
+ }
+
+ public java.sql.Timestamp createDate;
+ public void setCreateDate(java.sql.Timestamp createDate) {
+ this.createDate = createDate;
+ }
+ public java.sql.Timestamp getCreateDate() {
+ return this.createDate;
+ }
+
+ public java.sql.Timestamp lastOpDate;
+ public void setLastOpDate(java.sql.Timestamp lastOpDate) {
+ this.lastOpDate = lastOpDate;
+ }
+ public java.sql.Timestamp getLastOpDate() {
+ return this.lastOpDate;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/ExternalServiceInventory.java b/sdk/src/main/java/org/zstack/sdk/ExternalServiceInventory.java
index 8882e2f1f49..7f57fa5da36 100644
--- a/sdk/src/main/java/org/zstack/sdk/ExternalServiceInventory.java
+++ b/sdk/src/main/java/org/zstack/sdk/ExternalServiceInventory.java
@@ -28,4 +28,12 @@ public ExternalServiceCapabilities getCapabilities() {
return this.capabilities;
}
+ public java.lang.String serviceType;
+ public void setServiceType(java.lang.String serviceType) {
+ this.serviceType = serviceType;
+ }
+ public java.lang.String getServiceType() {
+ return this.serviceType;
+ }
+
}
diff --git a/sdk/src/main/java/org/zstack/sdk/QueryExternalServiceConfigurationAction.java b/sdk/src/main/java/org/zstack/sdk/QueryExternalServiceConfigurationAction.java
new file mode 100644
index 00000000000..af5641707a7
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/QueryExternalServiceConfigurationAction.java
@@ -0,0 +1,75 @@
+package org.zstack.sdk;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.zstack.sdk.*;
+
+public class QueryExternalServiceConfigurationAction extends QueryAction {
+
+ private static final HashMap parameterMap = new HashMap<>();
+
+ private static final HashMap nonAPIParameterMap = new HashMap<>();
+
+ public static class Result {
+ public ErrorCode error;
+ public org.zstack.sdk.QueryExternalServiceConfigurationResult value;
+
+ public Result throwExceptionIfError() {
+ if (error != null) {
+ throw new ApiException(
+ String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details)
+ );
+ }
+
+ return this;
+ }
+ }
+
+
+
+ private Result makeResult(ApiResult res) {
+ Result ret = new Result();
+ if (res.error != null) {
+ ret.error = res.error;
+ return ret;
+ }
+
+ org.zstack.sdk.QueryExternalServiceConfigurationResult value = res.getResult(org.zstack.sdk.QueryExternalServiceConfigurationResult.class);
+ ret.value = value == null ? new org.zstack.sdk.QueryExternalServiceConfigurationResult() : value;
+
+ return ret;
+ }
+
+ public Result call() {
+ ApiResult res = ZSClient.call(this);
+ return makeResult(res);
+ }
+
+ public void call(final Completion completion) {
+ ZSClient.call(this, new InternalCompletion() {
+ @Override
+ public void complete(ApiResult res) {
+ completion.complete(makeResult(res));
+ }
+ });
+ }
+
+ protected Map getParameterMap() {
+ return parameterMap;
+ }
+
+ protected Map getNonAPIParameterMap() {
+ return nonAPIParameterMap;
+ }
+
+ protected RestInfo getRestInfo() {
+ RestInfo info = new RestInfo();
+ info.httpMethod = "GET";
+ info.path = "/external/service/configuration";
+ info.needSession = true;
+ info.needPoll = false;
+ info.parameterName = "";
+ return info;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/QueryExternalServiceConfigurationResult.java b/sdk/src/main/java/org/zstack/sdk/QueryExternalServiceConfigurationResult.java
new file mode 100644
index 00000000000..4697f0cc1fb
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/QueryExternalServiceConfigurationResult.java
@@ -0,0 +1,22 @@
+package org.zstack.sdk;
+
+
+
+public class QueryExternalServiceConfigurationResult {
+ public java.util.List inventories;
+ public void setInventories(java.util.List inventories) {
+ this.inventories = inventories;
+ }
+ public java.util.List getInventories() {
+ return this.inventories;
+ }
+
+ public java.lang.Long total;
+ public void setTotal(java.lang.Long total) {
+ this.total = total;
+ }
+ public java.lang.Long getTotal() {
+ return this.total;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/UpdateExternalServiceConfigurationAction.java b/sdk/src/main/java/org/zstack/sdk/UpdateExternalServiceConfigurationAction.java
new file mode 100644
index 00000000000..7e930bb9f4c
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/UpdateExternalServiceConfigurationAction.java
@@ -0,0 +1,104 @@
+package org.zstack.sdk;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.zstack.sdk.*;
+
+public class UpdateExternalServiceConfigurationAction extends AbstractAction {
+
+ private static final HashMap parameterMap = new HashMap<>();
+
+ private static final HashMap nonAPIParameterMap = new HashMap<>();
+
+ public static class Result {
+ public ErrorCode error;
+ public org.zstack.sdk.UpdateExternalServiceConfigurationResult value;
+
+ public Result throwExceptionIfError() {
+ if (error != null) {
+ throw new ApiException(
+ String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details)
+ );
+ }
+
+ return this;
+ }
+ }
+
+ @Param(required = true, maxLength = 32, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
+ public java.lang.String uuid;
+
+ @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
+ public java.lang.String description;
+
+ @Param(required = false)
+ public java.util.List systemTags;
+
+ @Param(required = false)
+ public java.util.List userTags;
+
+ @Param(required = false)
+ public String sessionId;
+
+ @Param(required = false)
+ public String accessKeyId;
+
+ @Param(required = false)
+ public String accessKeySecret;
+
+ @Param(required = false)
+ public String requestIp;
+
+ @NonAPIParam
+ public long timeout = -1;
+
+ @NonAPIParam
+ public long pollingInterval = -1;
+
+
+ private Result makeResult(ApiResult res) {
+ Result ret = new Result();
+ if (res.error != null) {
+ ret.error = res.error;
+ return ret;
+ }
+
+ org.zstack.sdk.UpdateExternalServiceConfigurationResult value = res.getResult(org.zstack.sdk.UpdateExternalServiceConfigurationResult.class);
+ ret.value = value == null ? new org.zstack.sdk.UpdateExternalServiceConfigurationResult() : value;
+
+ return ret;
+ }
+
+ public Result call() {
+ ApiResult res = ZSClient.call(this);
+ return makeResult(res);
+ }
+
+ public void call(final Completion completion) {
+ ZSClient.call(this, new InternalCompletion() {
+ @Override
+ public void complete(ApiResult res) {
+ completion.complete(makeResult(res));
+ }
+ });
+ }
+
+ protected Map getParameterMap() {
+ return parameterMap;
+ }
+
+ protected Map getNonAPIParameterMap() {
+ return nonAPIParameterMap;
+ }
+
+ protected RestInfo getRestInfo() {
+ RestInfo info = new RestInfo();
+ info.httpMethod = "PUT";
+ info.path = "/external/service/configuration/{uuid}";
+ info.needSession = true;
+ info.needPoll = true;
+ info.parameterName = "updateExternalServiceConfiguration";
+ return info;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/UpdateExternalServiceConfigurationResult.java b/sdk/src/main/java/org/zstack/sdk/UpdateExternalServiceConfigurationResult.java
new file mode 100644
index 00000000000..e00d4bc9fcb
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/UpdateExternalServiceConfigurationResult.java
@@ -0,0 +1,14 @@
+package org.zstack.sdk;
+
+import org.zstack.sdk.ExternalServiceConfigurationInventory;
+
+public class UpdateExternalServiceConfigurationResult {
+ public ExternalServiceConfigurationInventory inventory;
+ public void setInventory(ExternalServiceConfigurationInventory inventory) {
+ this.inventory = inventory;
+ }
+ public ExternalServiceConfigurationInventory getInventory() {
+ return this.inventory;
+ }
+
+}
diff --git a/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy b/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy
index 34cf02a9ff5..986c1fe7617 100644
--- a/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy
+++ b/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy
@@ -1367,6 +1367,33 @@ abstract class ApiHelper {
}
+ def addExternalServiceConfiguration(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.AddExternalServiceConfigurationAction.class) Closure c) {
+ def a = new org.zstack.sdk.AddExternalServiceConfigurationAction()
+ 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 addFiSecSecurityMachine(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.AddFiSecSecurityMachineAction.class) Closure c) {
def a = new org.zstack.sdk.AddFiSecSecurityMachineAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
@@ -14273,6 +14300,33 @@ abstract class ApiHelper {
}
+ def deleteExternalServiceConfiguration(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.DeleteExternalServiceConfigurationAction.class) Closure c) {
+ def a = new org.zstack.sdk.DeleteExternalServiceConfigurationAction()
+ 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 deleteFirewall(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.DeleteFirewallAction.class) Closure c) {
def a = new org.zstack.sdk.DeleteFirewallAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
@@ -30427,6 +30481,35 @@ abstract class ApiHelper {
}
+ def queryExternalServiceConfiguration(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.QueryExternalServiceConfigurationAction.class) Closure c) {
+ def a = new org.zstack.sdk.QueryExternalServiceConfigurationAction()
+ 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())
+ }
+ }
+
+
def queryFaultToleranceVm(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.QueryFaultToleranceVmAction.class) Closure c) {
def a = new org.zstack.sdk.QueryFaultToleranceVmAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
@@ -43467,6 +43550,33 @@ abstract class ApiHelper {
}
+ def updateExternalServiceConfiguration(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.UpdateExternalServiceConfigurationAction.class) Closure c) {
+ def a = new org.zstack.sdk.UpdateExternalServiceConfigurationAction()
+ 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 updateFactoryModeState(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.UpdateFactoryModeStateAction.class) Closure c) {
def a = new org.zstack.sdk.UpdateFactoryModeStateAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid